diff options
author | Andreas Klebinger <klebinger.andreas@gmx.at> | 2022-06-08 18:07:30 +0200 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2022-08-08 16:46:37 -0400 |
commit | 742292e461e4040faecf3482349a4574a9184239 (patch) | |
tree | 3d54ae153d7b0afd041a16c4c083718e7e6901f3 /compiler | |
parent | 20457d775885d6c3df020d204da9a7acfb3c2e5a (diff) | |
download | haskell-742292e461e4040faecf3482349a4574a9184239.tar.gz |
dataToTag#: Skip runtime tag check if argument is infered tagged
This addresses one part of #21710.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/GHC/Stg/InferTags/Rewrite.hs | 18 | ||||
-rw-r--r-- | compiler/GHC/StgToCmm/Expr.hs | 30 |
2 files changed, 37 insertions, 11 deletions
diff --git a/compiler/GHC/Stg/InferTags/Rewrite.hs b/compiler/GHC/Stg/InferTags/Rewrite.hs index 340ff2fff0..a9a7677e40 100644 --- a/compiler/GHC/Stg/InferTags/Rewrite.hs +++ b/compiler/GHC/Stg/InferTags/Rewrite.hs @@ -20,6 +20,7 @@ where import GHC.Prelude +import GHC.Builtin.PrimOps ( PrimOp(..) ) import GHC.Types.Id import GHC.Types.Name import GHC.Types.Unique.Supply @@ -346,6 +347,19 @@ fvArgs args = do type IsScrut = Bool +rewriteArgs :: [StgArg] -> RM [StgArg] +rewriteArgs = mapM rewriteArg +rewriteArg :: StgArg -> RM StgArg +rewriteArg (StgVarArg v) = StgVarArg <$!> rewriteId v +rewriteArg (lit@StgLitArg{}) = return lit + +-- Attach a tagSig if it's tagged +rewriteId :: Id -> RM Id +rewriteId v = do + is_tagged <- isTagged v + if is_tagged then return $! setIdTagSig v (TagSig TagProper) + else return v + rewriteExpr :: IsScrut -> InferStgExpr -> RM TgStgExpr rewriteExpr _ (e@StgCase {}) = rewriteCase e rewriteExpr _ (e@StgLet {}) = rewriteLet e @@ -355,8 +369,11 @@ rewriteExpr _ e@(StgConApp {}) = rewriteConApp e rewriteExpr isScrut e@(StgApp {}) = rewriteApp isScrut e rewriteExpr _ (StgLit lit) = return $! (StgLit lit) +rewriteExpr _ (StgOpApp op@(StgPrimOp DataToTagOp) args res_ty) = do + (StgOpApp op) <$!> rewriteArgs args <*> pure res_ty rewriteExpr _ (StgOpApp op args res_ty) = return $! (StgOpApp op args res_ty) + rewriteCase :: InferStgExpr -> RM TgStgExpr rewriteCase (StgCase scrut bndr alt_type alts) = withBinder NotTopLevel bndr $ @@ -415,6 +432,7 @@ rewriteApp True (StgApp f []) = do -- isTagged looks at more than the result of our analysis. -- So always update here if useful. let f' = if f_tagged + -- TODO: We might consisder using a subst env instead of setting the sig only for select places. then setIdTagSig f (TagSig TagProper) else f return $! StgApp f' [] diff --git a/compiler/GHC/StgToCmm/Expr.hs b/compiler/GHC/StgToCmm/Expr.hs index 0e7c52f68d..030655c8e2 100644 --- a/compiler/GHC/StgToCmm/Expr.hs +++ b/compiler/GHC/StgToCmm/Expr.hs @@ -76,6 +76,8 @@ cgExpr (StgOpApp (StgPrimOp SeqOp) [StgVarArg a, _] _res_ty) = -- dataToTag# :: a -> Int# -- See Note [dataToTag# magic] in GHC.Core.Opt.ConstantFold +-- TODO: There are some more optimization ideas for this code path +-- in #21710 cgExpr (StgOpApp (StgPrimOp DataToTagOp) [StgVarArg a] _res_ty) = do platform <- getPlatform emitComment (mkFastString "dataToTag#") @@ -92,15 +94,7 @@ cgExpr (StgOpApp (StgPrimOp DataToTagOp) [StgVarArg a] _res_ty) = do -- the constructor index is too large to fit in the pointer and therefore -- we must look in the info table. See Note [Tagging big families]. - slow_path <- getCode $ do - tmp <- newTemp (bWord platform) - _ <- withSequel (AssignTo [tmp] False) (cgIdApp a []) - profile <- getProfile - align_check <- stgToCmmAlignCheck <$> getStgToCmmConfig - emitAssign (CmmLocal result_reg) - $ getConstrTag profile align_check (cmmUntag platform (CmmReg (CmmLocal tmp))) - - fast_path <- getCode $ do + (fast_path :: CmmAGraph) <- getCode $ do -- Return the constructor index from the pointer tag return_ptr_tag <- getCode $ do emitAssign (CmmLocal result_reg) @@ -113,8 +107,22 @@ cgExpr (StgOpApp (StgPrimOp DataToTagOp) [StgVarArg a] _res_ty) = do $ getConstrTag profile align_check (cmmUntag platform amode) emit =<< mkCmmIfThenElse' is_too_big_tag return_info_tag return_ptr_tag (Just False) - - emit =<< mkCmmIfThenElse' is_tagged fast_path slow_path (Just True) + -- If we know the argument is already tagged there is no need to generate code to evaluate it + -- so we skip straight to the fast path. If we don't know if there is a tag we take the slow + -- path which evaluates the argument before fetching the tag. + case (idTagSig_maybe a) of + Just sig + | isTaggedSig sig + -> emit fast_path + _ -> do + slow_path <- getCode $ do + tmp <- newTemp (bWord platform) + _ <- withSequel (AssignTo [tmp] False) (cgIdApp a []) + profile <- getProfile + align_check <- stgToCmmAlignCheck <$> getStgToCmmConfig + emitAssign (CmmLocal result_reg) + $ getConstrTag profile align_check (cmmUntag platform (CmmReg (CmmLocal tmp))) + emit =<< mkCmmIfThenElse' is_tagged fast_path slow_path (Just True) emitReturn [CmmReg $ CmmLocal result_reg] |