summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core/Opt/Simplify.hs
diff options
context:
space:
mode:
authorSebastian Graf <sebastian.graf@kit.edu>2021-06-22 14:02:49 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-06-27 14:57:39 -0400
commitd7758da490db3cc662dbebdac4397b4b2c38d0f0 (patch)
treeee8da5279b12a0ca2999789e92dea81b1552df67 /compiler/GHC/Core/Opt/Simplify.hs
parent3e71874b32725cb0bd95f6a7effc77190a860b3e (diff)
downloadhaskell-d7758da490db3cc662dbebdac4397b4b2c38d0f0.tar.gz
Simplifier: Do Cast W/W for INLINE strong loop-breakers
Strong loop-breakers never inline, INLINE pragma or not. Hence they should be treated as if there was no INLINE pragma on them. Also not doing Cast W/W for INLINE strong loop-breakers will trip up Strictness W/W, because it treats them as if there was no INLINE pragma. Subsequently, that will lead to a panic once Strictness W/W will no longer do eta-expansion, as we discovered while implementing !5814. I also renamed to `unfoldingInfo` to `realUnfoldingInfo` and redefined `unfoldingInfo` to zap the unfolding it returns in case of a strong loop-breaker. Now the naming and semantics is symmetrical to `idUnfolding`/`realIdUnfolding`. Now there was no more reason for `hasInlineUnfolding` to operate on `Id`, because the zapping of strong loop-breaker unfoldings moved from `idUnfolding` to `unfoldingInfo`, so I refactored it to take `IdInfo` and call it both from the Simplifier and WorkWrap, making it utterly clear that both checks are equivalent.
Diffstat (limited to 'compiler/GHC/Core/Opt/Simplify.hs')
-rw-r--r--compiler/GHC/Core/Opt/Simplify.hs30
1 files changed, 16 insertions, 14 deletions
diff --git a/compiler/GHC/Core/Opt/Simplify.hs b/compiler/GHC/Core/Opt/Simplify.hs
index d1ca3e3f9c..6c7379faa2 100644
--- a/compiler/GHC/Core/Opt/Simplify.hs
+++ b/compiler/GHC/Core/Opt/Simplify.hs
@@ -544,14 +544,17 @@ Wrinkles
Notice that the stable unfolding moves to the worker! Now demand analysis
will work fine on $wf, whereas it has trouble with the original f.
c.f. Note [Worker/wrapper for INLINABLE functions] in GHC.Core.Opt.WorkWrap.
+ This point also applies to strong loopbreakers with INLINE pragmas, see
+ wrinkle (4).
-4. We should /not/ do cast w/w for INLINE functions (hence isInlineUnfolding in
- tryCastWorkerWrapper) becuase they'll be inlined, cast and all anyway. And
- if we do cast w/w for an INLINE function with arity zero, we get something
- really silly: we inline that "worker" right back into the wrapper! Worse than
- a no-op, because we haev then lost the stable unfolding.
+4. We should /not/ do cast w/w for non-loop-breaker INLINE functions (hence
+ hasInlineUnfolding in tryCastWorkerWrapper, which responds False to
+ loop-breakers) because they'll definitely be inlined anyway, cast and
+ all. And if we do cast w/w for an INLINE function with arity zero, we get
+ something really silly: we inline that "worker" right back into the wrapper!
+ Worse than a no-op, because we have then lost the stable unfolding.
-Both these wrinkles are exactly like worker/wrapper for strictness analysis:
+All these wrinkles are exactly like worker/wrapper for strictness analysis:
f is the wrapper and must inline like crazy
$wf is the worker and must carry f's original pragma
See Note [Worker/wrapper for INLINABLE functions]
@@ -600,10 +603,10 @@ tryCastWorkerWrapper env top_lvl old_bndr occ_info bndr (Cast rhs co)
| not (isJoinId bndr) -- Not for join points
, not (isDFunId bndr) -- nor DFuns; cast w/w is no help, and we can't transform
-- a DFunUnfolding in mk_worker_unfolding
- , not (exprIsTrivial rhs) -- Not x = y |> co; Wrinkle 1
- , not (isInlineUnfolding unf) -- Not INLINE things: Wrinkle 4
- , not (isUnliftedType rhs_ty) -- Not if rhs has an unlifted type;
- -- see Note [Cast w/w: unlifted]
+ , not (exprIsTrivial rhs) -- Not x = y |> co; Wrinkle 1
+ , not (hasInlineUnfolding info) -- Not INLINE things: Wrinkle 4
+ , not (isUnliftedType rhs_ty) -- Not if rhs has an unlifted type;
+ -- see Note [Cast w/w: unlifted]
= do { (rhs_floats, work_rhs) <- prepareRhs mode top_lvl occ_fs rhs
; uniq <- getUniqueM
; let work_name = mkSystemVarName uniq occ_fs
@@ -637,7 +640,6 @@ tryCastWorkerWrapper env top_lvl old_bndr occ_info bndr (Cast rhs co)
occ_fs = getOccFS bndr
rhs_ty = coercionLKind co
info = idInfo bndr
- unf = unfoldingInfo info
worker_info = vanillaIdInfo `setDmdSigInfo` dmdSigInfo info
`setCprSigInfo` cprSigInfo info
@@ -654,8 +656,8 @@ tryCastWorkerWrapper env top_lvl old_bndr occ_info bndr (Cast rhs co)
-- Non-stable case: use work_rhs
-- Wrinkle 3 of Note [Cast worker/wrapper]
mk_worker_unfolding work_id work_rhs
- = case unf of
- CoreUnfolding { uf_tmpl = unf_rhs, uf_src = src }
+ = case realUnfoldingInfo info of -- NB: the real one, even for loop-breakers
+ unf@(CoreUnfolding { uf_tmpl = unf_rhs, uf_src = src })
| isStableSource src -> return (unf { uf_tmpl = mkCast unf_rhs (mkSymCo co) })
_ -> mkLetUnfolding (sm_uf_opts mode) top_lvl InlineRhs work_id work_rhs
@@ -895,7 +897,7 @@ completeBind env top_lvl mb_cont old_bndr new_bndr new_rhs
| otherwise
= assert (isId new_bndr) $
do { let old_info = idInfo old_bndr
- old_unf = unfoldingInfo old_info
+ old_unf = realUnfoldingInfo old_info
occ_info = occInfo old_info
mode = getMode env