SpecConstr duplicating computations
In some (very rare) cases, SpecConstr can actually duplicate let bindings.
When SpecConstr sees something like
let tuple = (let x = expensive in x, simple)
case tuple of
(a,b) -> a + a
it records the value of tuple, and replaces the case with
(let x = expensive in x) + (let x = expensive in x)
Usually we wouldn't notice this, because the Simplifier would let-float expensive out of the tuple before SpecConstr runs. In some cases though, the tuple constructor will only be exposed after specialisation happens.
To test, compile TSpecConstr_DoubleInline with
ghc TSpecConstr_DoubleInline.hs -O2 -fspec-constr -dverbose-core2core -fforce-recomp -dppr-case-as-let -dsuppress-all | less
and search for the SpecConstr pass. The first specialisation is
$srecursive_sf3
$srecursive_sf3 =
\ sc_seR sc_seS sc_seT sc_seU ->
let {
a'_sep
a'_sep =
(let { I# x_adP ~ _ <- expensive sc_seR } in I# (*# x_adP 2),
sc_seR) } in
let {
ds_seq
ds_seq =
recursive
(: sc_seR (: sc_seR (: sc_seS sc_seT)))
(sc_seR,
let { I# x_adP ~ _ <- expensive sc_seR } in I# (*# x_adP 2)) } in
(let { (p_XdA, q_Xdu) ~ _ <- ds_seq } in
let { I# x_ae7 ~ _ <- p_XdA } in
let { I# y_aeb ~ _
<- let { I# x_adP ~ _ <- expensive sc_seR } in I# (*# x_adP 2)
} in
I# (+# x_ae7 y_aeb),
let { (p_adg, q_XdA) ~ _ <- ds_seq } in
let { I# x_ae7 ~ _ <- q_XdA } in
let { I# y_aeb ~ _ <- sc_seR } in I# (+# x_ae7 y_aeb))
With three calls to expensive. If you look at the -ddump-prep, one of the calls is simplified out, but there is still one too many at the end.
This is happening on at least 7.4.1 and head.
Trac metadata
Trac field | Value |
---|---|
Version | |
Type | Bug |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | Compiler |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | |
Operating system | |
Architecture |