CorePrep does not actually freshen all local Ids
Item (6) of Note [CorePrep overview]
says
6. Clone all local Ids.
This means that all such Ids are unique, rather than the
weaker guarantee of no clashes which the simplifier provides.
And that is what the code generator needs.
We don't clone TyVars or CoVars. The code gen doesn't need that,
and doing so would be tiresome because then we'd need
to substitute in types and coercions.
But that doesn't really appear to be true. For one, !9089 exposed a bug, where we get code like this (prior to, and) after CorePrep
let go_123 x y = joinrec go_123 x y = ... in jump go_123 x y;
in ... go_123 ...
The joinrec-bound unique should have been cloned, but isn't. At first I thought it was simple to fix, because the NonRec case of cpeBind
eagerly clones the binder but passes down the unaltered CpeEnv
to cpePair
:
= do { (env1, bndr1) <- cpCloneBndr env bndr
; let dmd = idDemandInfo bndr
is_unlifted = isUnliftedType (idType bndr)
; (floats, rhs1) <- cpePair top_lvl NonRecursive
dmd is_unlifted
env bndr1 rhs
Note how line 1 clones the binder, but passes the unextended env
to cpePair
in line 6.
Instead cloning should happen after the call to cpePair
, because bndr
is not in scope until then. (I tried the alternative of simply passing down env1
which didn't work either.)
But while implementing the fix, I noticed that we don't get back any in-scope information from cpePair
! That means that a program like the following will not clone the inner j_1
:
let f x = let j_1 x = ... in j_1 42
g x = let j_1 x = ... in j_1 64
in ...
because when cloning inside g
we will have forgotten that we've seen j_1
in f
.
CorePrep only seems to guarantee there is no shadowing, not that Ids are globally unique! But the latter is what CodeGen needs, and I think StgCSE assumes global uniqueness, too. At least it seems to be responsible for the strange reuse of the label .LX0
in !9089.
Puzzling. Did I miss something?