diff options
Diffstat (limited to 'compiler/GHC/Core/Tidy.hs')
-rw-r--r-- | compiler/GHC/Core/Tidy.hs | 108 |
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 |