summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorAndreas Klebinger <klebinger.andreas@gmx.at>2022-06-08 18:07:30 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-08-08 16:46:37 -0400
commit742292e461e4040faecf3482349a4574a9184239 (patch)
tree3d54ae153d7b0afd041a16c4c083718e7e6901f3 /compiler
parent20457d775885d6c3df020d204da9a7acfb3c2e5a (diff)
downloadhaskell-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.hs18
-rw-r--r--compiler/GHC/StgToCmm/Expr.hs30
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]