summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core/Tidy.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Core/Tidy.hs')
-rw-r--r--compiler/GHC/Core/Tidy.hs108
1 files changed, 94 insertions, 14 deletions
diff --git a/compiler/GHC/Core/Tidy.hs b/compiler/GHC/Core/Tidy.hs
index 63473ca68a..3f6c212f49 100644
--- a/compiler/GHC/Core/Tidy.hs
+++ b/compiler/GHC/Core/Tidy.hs
@@ -19,10 +19,9 @@ import GHC.Core
import GHC.Core.Type
import GHC.Core.Seq ( seqUnfolding )
-import GHC.Core.Utils ( computeCbvInfo )
import GHC.Types.Id
import GHC.Types.Id.Info
-import GHC.Types.Demand ( zapDmdEnvSig )
+import GHC.Types.Demand ( zapDmdEnvSig, isStrUsedDmd )
import GHC.Core.Coercion ( tidyCo )
import GHC.Types.Var
import GHC.Types.Var.Env
@@ -35,6 +34,12 @@ import GHC.Types.Tickish
import GHC.Data.Maybe
import GHC.Utils.Misc
import Data.List (mapAccumL)
+-- import GHC.Utils.Trace
+import GHC.Utils.Outputable
+import GHC.Types.RepType (typePrimRep)
+import GHC.Utils.Panic
+import GHC.Types.Basic (isMarkedCbv, CbvMark (..))
+import GHC.Core.Utils (shouldUseCbvForId)
{-
************************************************************************
@@ -68,11 +73,16 @@ tidyBind env (Rec prs)
-- Note [Attaching CBV Marks to ids]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- Before tidy, function arguments which have a call-by-value semantics are identified
--- by having an `OtherCon[]` unfolding. During tidy, we transform this information into CBV (call-by-value)
--- marks. The marks themselves then are put onto the function id itself.
+-- See Note [CBV Function Ids] for the *why*.
+-- Before tidy, we turn all worker functions into worker like ids.
+-- This way we can later tell if we can assume the existence of a wrapper. This also applies to
+-- specialized versions of functions generated by SpecConstr for which we, in a sense,
+-- consider the unspecialized version to be the wrapper.
+-- During tidy we take the demands on the arguments for these ids and compute
+-- CBV (call-by-value) semantics for each individual argument.
+-- The marks themselves then are put onto the function id itself.
-- This means the code generator can get the full calling convention by only looking at the function
--- itself without having to inspect the RHS for potential argument unfoldings.
+-- itself without having to inspect the RHS.
--
-- The actual logic is in tidyCbvInfo and takes:
-- * The function id
@@ -84,9 +94,9 @@ tidyBind env (Rec prs)
--
-- Not that we *have* to look at the untidied rhs.
-- During tidying some knot-tying occurs which can blow up
--- if we look at the types of the arguments, but here we dont:
--- we only check if the manifest lambdas have OtherCon unfoldings
--- and these remain valid post tidy.
+-- if we look at the post-tidy types of the arguments here.
+-- However we only care if the types are unlifted and that doesn't change during tidy.
+-- so we can just look at the untidied types.
--
-- If the id is boot-exported we don't use a cbv calling convention via marks,
-- as the boot file won't contain them. Which means code calling boot-exported
@@ -95,21 +105,91 @@ tidyBind env (Rec prs)
-- To be able to avoid this we pass a set of boot exported ids for this module around.
-- For non top level ids we can skip this. Local ids are never boot-exported
-- as boot files don't have unfoldings. So there this isn't a concern.
--- See also Note [Strict Worker Ids]
+-- See also Note [CBV Function Ids]
--- See Note [Attaching CBV Marks to ids]
+-- See Note [CBV Function Ids]
tidyCbvInfoTop :: HasDebugCallStack => NameSet -> Id -> CoreExpr -> Id
tidyCbvInfoTop boot_exports id rhs
-- Can't change calling convention for boot exported things
| elemNameSet (idName id) boot_exports = id
| otherwise = computeCbvInfo id rhs
--- See Note [Attaching CBV Marks to ids]
+-- See Note [CBV Function Ids]
tidyCbvInfoLocal :: HasDebugCallStack => Id -> CoreExpr -> Id
tidyCbvInfoLocal id rhs
| otherwise = computeCbvInfo id rhs
+-- | For a binding we:
+-- * Look at the args
+-- * Mark any argument as call-by-value if:
+-- - It's argument to a worker and demanded strictly
+-- - Unless it's an unlifted type already
+-- * Update the id
+-- See Note [CBV Function Ids]
+-- See Note [Attaching CBV Marks to ids]
+
+computeCbvInfo :: HasCallStack
+ => Id -- The function
+ -> CoreExpr -- It's RHS
+ -> Id
+-- computeCbvInfo fun_id rhs = fun_id
+computeCbvInfo fun_id rhs
+ | (isWorkerLike || isJoinId fun_id) && (valid_unlifted_worker val_args)
+ =
+ -- pprTrace "computeCbvInfo"
+ -- (text "fun" <+> ppr fun_id $$
+ -- text "arg_tys" <+> ppr (map idType val_args) $$
+
+ -- text "prim_rep" <+> ppr (map typePrimRep_maybe $ map idType val_args) $$
+ -- text "rrarg" <+> ppr (map isRuntimeVar val_args) $$
+ -- text "cbv_marks" <+> ppr cbv_marks $$
+ -- text "out_id" <+> ppr cbv_bndr $$
+ -- ppr rhs)
+ cbv_bndr
+ | otherwise = fun_id
+ where
+ val_args = filter isId . fst $ collectBinders rhs
+ cbv_marks =
+ -- CBV marks are only set during tidy so none should be present already.
+ assertPpr (maybe True null $ idCbvMarks_maybe fun_id) (ppr fun_id <+> (ppr $ idCbvMarks_maybe fun_id) $$ ppr rhs) $
+ map mkMark val_args
+ cbv_bndr
+ | valid_unlifted_worker val_args
+ , any isMarkedCbv cbv_marks
+ -- seqList to avoid retaining the original rhs
+ = cbv_marks `seqList` setIdCbvMarks fun_id cbv_marks
+ | otherwise =
+ -- pprTraceDebug "tidyCbvInfo: Worker seems to take unboxed tuple/sum types!" (ppr fun_id <+> ppr rhs)
+ asNonWorkerLikeId fun_id
+ -- We don't set CBV marks on functions which take unboxed tuples or sums as arguments.
+ -- Doing so would require us to compute the result of unarise here in order to properly determine
+ -- argument positions at runtime.
+ -- In practice this doesn't matter much. Most "interesting" functions will get a W/W split which will eliminate
+ -- unboxed tuple arguments, and unboxed sums are rarely used. But we could change this in the future and support
+ -- unboxed sums/tuples as well.
+ valid_unlifted_worker args =
+ -- pprTrace "valid_unlifted" (ppr fun_id $$ ppr args) $
+ all isSingleUnarisedArg args
+ isSingleUnarisedArg v
+ | isUnboxedSumType ty = False
+ | isUnboxedTupleType ty = isSimplePrimRep (typePrimRep ty)
+ | otherwise = isSimplePrimRep (typePrimRep ty)
+ where
+ ty = idType v
+ isSimplePrimRep [] = True
+ isSimplePrimRep [_] = True
+ isSimplePrimRep _ = False
+
+ mkMark arg
+ | not $ shouldUseCbvForId arg = NotMarkedCbv
+ -- We can only safely use cbv for strict arguments
+ | (isStrUsedDmd (idDemandInfo arg))
+ , not (isDeadEndId fun_id) = MarkedCbv
+ | otherwise = NotMarkedCbv
+
+ isWorkerLike = isWorkerLikeId fun_id
+
------------ Expressions --------------
tidyExpr :: TidyEnv -> CoreExpr -> CoreExpr
tidyExpr env (Var v) = Var (tidyVarOcc env v)
@@ -215,7 +295,7 @@ tidyIdBndr env@(tidy_env, var_env) id
`setOneShotInfo` oneShotInfo old_info
old_info = idInfo id
old_unf = realUnfoldingInfo old_info
- new_unf = zapUnfolding old_unf -- See Note [Preserve evaluatedness]
+ new_unf = trimUnfolding old_unf -- See Note [Preserve evaluatedness]
in
((tidy_env', var_env'), id')
}
@@ -266,7 +346,7 @@ tidyLetBndr rec_tidy_env env@(tidy_env, var_env) id
old_unf = realUnfoldingInfo old_info
new_unf | isStableUnfolding old_unf = tidyUnfolding rec_tidy_env old_unf old_unf
- | otherwise = zapUnfolding old_unf
+ | otherwise = trimUnfolding old_unf
-- See Note [Preserve evaluatedness]
in