diff options
Diffstat (limited to 'compiler/simplStg')
-rw-r--r-- | compiler/simplStg/RepType.hs | 2 | ||||
-rw-r--r-- | compiler/simplStg/SimplStg.hs | 70 | ||||
-rw-r--r-- | compiler/simplStg/StgCse.hs | 38 | ||||
-rw-r--r-- | compiler/simplStg/StgStats.hs | 2 | ||||
-rw-r--r-- | compiler/simplStg/UnariseStg.hs | 77 |
5 files changed, 101 insertions, 88 deletions
diff --git a/compiler/simplStg/RepType.hs b/compiler/simplStg/RepType.hs index 2acc815125..694aa4ebf7 100644 --- a/compiler/simplStg/RepType.hs +++ b/compiler/simplStg/RepType.hs @@ -23,6 +23,8 @@ module RepType #include "HsVersions.h" +import GhcPrelude + import BasicTypes (Arity, RepArity) import DataCon import Outputable diff --git a/compiler/simplStg/SimplStg.hs b/compiler/simplStg/SimplStg.hs index 4943f525af..36bf5101d6 100644 --- a/compiler/simplStg/SimplStg.hs +++ b/compiler/simplStg/SimplStg.hs @@ -10,93 +10,67 @@ module SimplStg ( stg2stg ) where #include "HsVersions.h" +import GhcPrelude + import StgSyn -import CostCentre ( CollectedCCs ) -import SCCfinal ( stgMassageForProfiling ) import StgLint ( lintStgTopBindings ) import StgStats ( showStgStats ) import UnariseStg ( unarise ) import StgCse ( stgCse ) import DynFlags -import Module ( Module ) import ErrUtils -import SrcLoc -import UniqSupply ( mkSplitUniqSupply, splitUniqSupply ) +import UniqSupply ( mkSplitUniqSupply ) import Outputable import Control.Monad stg2stg :: DynFlags -- includes spec of what stg-to-stg passes to do - -> Module -- module name (profiling only) -> [StgTopBinding] -- input... - -> IO ( [StgTopBinding] -- output program... - , CollectedCCs) -- cost centre information (declared and used) + -> IO [StgTopBinding] -- output program -stg2stg dflags module_name binds +stg2stg dflags binds = do { showPass dflags "Stg2Stg" ; us <- mkSplitUniqSupply 'g' - ; when (dopt Opt_D_verbose_stg2stg dflags) - (putLogMsg dflags NoReason SevDump noSrcSpan - (defaultDumpStyle dflags) (text "VERBOSE STG-TO-STG:")) - - ; (binds', us', ccs) <- end_pass us "Stg2Stg" ([],[],[]) binds - -- Do the main business! - ; let (us0, us1) = splitUniqSupply us' - ; (processed_binds, _, cost_centres) - <- foldM do_stg_pass (binds', us0, ccs) (getStgToDo dflags) - ; dumpIfSet_dyn dflags Opt_D_dump_stg "Pre unarise:" - (pprStgTopBindings processed_binds) + (pprStgTopBindings binds) - ; let un_binds = unarise us1 processed_binds + ; stg_linter False "Pre-unarise" binds + ; let un_binds = unarise us binds + ; stg_linter True "Unarise" un_binds ; dumpIfSet_dyn dflags Opt_D_dump_stg "STG syntax:" (pprStgTopBindings un_binds) - ; return (un_binds, cost_centres) - } + ; foldM do_stg_pass un_binds (getStgToDo dflags) + } where - stg_linter = if gopt Opt_DoStgLinting dflags - then lintStgTopBindings - else ( \ _whodunnit binds -> binds ) + stg_linter unarised + | gopt Opt_DoStgLinting dflags = lintStgTopBindings dflags unarised + | otherwise = \ _whodunnit _binds -> return () ------------------------------------------- - do_stg_pass (binds, us, ccs) to_do + do_stg_pass binds to_do = case to_do of D_stg_stats -> - trace (showStgStats binds) - end_pass us "StgStats" ccs binds - - StgDoMassageForProfiling -> - {-# SCC "ProfMassage" #-} - let - (us1, us2) = splitUniqSupply us - (collected_CCs, binds3) - = stgMassageForProfiling dflags module_name us1 binds - in - end_pass us2 "ProfMassage" collected_CCs binds3 + trace (showStgStats binds) (return binds) StgCSE -> {-# SCC "StgCse" #-} let binds' = stgCse binds in - end_pass us "StgCse" ccs binds' + end_pass "StgCse" binds' - end_pass us2 what ccs binds2 + end_pass what binds2 = do -- report verbosely, if required dumpIfSet_dyn dflags Opt_D_verbose_stg2stg what - (vcat (map ppr binds2)) - let linted_binds = stg_linter what binds2 - return (linted_binds, us2, ccs) - -- return: processed binds - -- UniqueSupply for the next guy to use - -- cost-centres to be declared/registered (specialised) - -- add to description of what's happened (reverse order) + (pprStgTopBindings binds2) + stg_linter True what binds2 + return binds2 -- ----------------------------------------------------------------------------- -- StgToDo: abstraction of stg-to-stg passes to run. @@ -104,14 +78,12 @@ stg2stg dflags module_name binds -- | Optional Stg-to-Stg passes. data StgToDo = StgCSE - | StgDoMassageForProfiling -- should be (next to) last | D_stg_stats -- | Which optional Stg-to-Stg passes to run. Depends on flags, ways etc. getStgToDo :: DynFlags -> [StgToDo] getStgToDo dflags = [ StgCSE | gopt Opt_StgCSE dflags] ++ - [ StgDoMassageForProfiling | WayProf `elem` ways dflags] ++ [ D_stg_stats | stg_stats ] where stg_stats = gopt Opt_StgStats dflags diff --git a/compiler/simplStg/StgCse.hs b/compiler/simplStg/StgCse.hs index 6bd6adc7ec..1ae1213960 100644 --- a/compiler/simplStg/StgCse.hs +++ b/compiler/simplStg/StgCse.hs @@ -5,9 +5,9 @@ Note [CSE for Stg] ~~~~~~~~~~~~~~~~~~ This module implements a simple common subexpression elimination pass for STG. This is useful because there are expressions that we want to common up (because -they are operational equivalent), but that we cannot common up in Core, because +they are operationally equivalent), but that we cannot common up in Core, because their types differ. -This was original reported as #9291. +This was originally reported as #9291. There are two types of common code occurrences that we aim for, see note [Case 1: CSEing allocated closures] and @@ -16,7 +16,7 @@ note [Case 2: CSEing case binders] below. Note [Case 1: CSEing allocated closures] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The fist kind of CSE opportunity we aim for is generated by this Haskell code: +The first kind of CSE opportunity we aim for is generated by this Haskell code: bar :: a -> (Either Int a, Either Bool a) bar x = (Right x, Right x) @@ -70,6 +70,8 @@ and nothing stops us from transforming that to -} module StgCse (stgCse) where +import GhcPrelude + import DataCon import Id import StgSyn @@ -78,7 +80,7 @@ import VarEnv import CoreSyn (AltCon(..)) import Data.List (mapAccumL) import Data.Maybe (fromMaybe) -import TrieMap +import CoreMap import NameEnv import Control.Monad( (>=>) ) @@ -137,7 +139,7 @@ data CseEnv = CseEnv -- * If we remove `let x = Con z` because `let y = Con z` is in scope, -- we note this here as x ↦ y. , ce_bndrMap :: IdEnv OutId - -- If we come across a case expression case x as b of … with a trivial + -- ^ If we come across a case expression case x as b of … with a trivial -- binder, we add b ↦ x to this. -- This map is *only* used when looking something up in the ce_conAppMap. -- See Note [Trivial case scrutinee] @@ -217,7 +219,7 @@ substVar env id = fromMaybe id $ lookupVarEnv (ce_subst env) id -- Functions to enter binders --- This is much simpler than the requivalent code in CoreSubst: +-- This is much simpler than the equivalent code in CoreSubst: -- * We do not substitute type variables, and -- * There is nothing relevant in IdInfo at this stage -- that needs substitutions. @@ -300,7 +302,7 @@ stgCseExpr env (StgCase scrut bndr ty alts) env2 | StgApp trivial_scrut [] <- scrut' = addTrivCaseBndr bndr trivial_scrut env1 -- See Note [Trivial case scrutinee] | otherwise = env1 - alts' = map (stgCseAlt env2 bndr') alts + alts' = map (stgCseAlt env2 ty bndr') alts -- A constructor application. @@ -327,14 +329,24 @@ stgCseExpr env (StgLetNoEscape binds body) -- Case alternatives -- Extend the CSE environment -stgCseAlt :: CseEnv -> OutId -> InStgAlt -> OutStgAlt -stgCseAlt env case_bndr (DataAlt dataCon, args, rhs) +stgCseAlt :: CseEnv -> AltType -> OutId -> InStgAlt -> OutStgAlt +stgCseAlt env ty case_bndr (DataAlt dataCon, args, rhs) = let (env1, args') = substBndrs env args - env2 = addDataCon case_bndr dataCon (map StgVarArg args') env1 + env2 + -- To avoid dealing with unboxed sums StgCse runs after unarise and + -- should maintain invariants listed in Note [Post-unarisation + -- invariants]. One of the invariants is that some binders are not + -- used (unboxed tuple case binders) which is what we check with + -- `stgCaseBndrInScope` here. If the case binder is not in scope we + -- don't add it to the CSE env. See also #15300. + | stgCaseBndrInScope ty True -- CSE runs after unarise + = addDataCon case_bndr dataCon (map StgVarArg args') env1 + | otherwise + = env1 -- see note [Case 2: CSEing case binders] rhs' = stgCseExpr env2 rhs in (DataAlt dataCon, args', rhs') -stgCseAlt env _ (altCon, args, rhs) +stgCseAlt env _ _ (altCon, args, rhs) = let (env1, args') = substBndrs env args rhs' = stgCseExpr env1 rhs in (altCon, args', rhs') @@ -362,7 +374,7 @@ stgCsePairs env0 ((b,e):pairs) mbCons = maybe id (:) -- The RHS of a binding. --- If it is an constructor application, either short-cut it or extend the environment +-- If it is a constructor application, either short-cut it or extend the environment stgCseRhs :: CseEnv -> OutId -> InStgRhs -> (Maybe (OutId, OutStgRhs), CseEnv) stgCseRhs env bndr (StgRhsCon ccs dataCon args) | Just other_bndr <- envLookup dataCon args' env @@ -438,7 +450,7 @@ we first replace v with r2. Next we want to replace Right r2 with r1. But the ce_conAppMap contains Right a! Therefore, we add r1 ↦ x to ce_bndrMap when analysing the outer case, and use -this subsitution before looking Right r2 up in ce_conAppMap, and everything +this substitution before looking Right r2 up in ce_conAppMap, and everything works out. Note [Free variables of an StgClosure] diff --git a/compiler/simplStg/StgStats.hs b/compiler/simplStg/StgStats.hs index 3f75ae23fa..712ec2d22e 100644 --- a/compiler/simplStg/StgStats.hs +++ b/compiler/simplStg/StgStats.hs @@ -27,6 +27,8 @@ module StgStats ( showStgStats ) where #include "HsVersions.h" +import GhcPrelude + import StgSyn import Id (Id) diff --git a/compiler/simplStg/UnariseStg.hs b/compiler/simplStg/UnariseStg.hs index 2e8fbda02b..5c271c2ea0 100644 --- a/compiler/simplStg/UnariseStg.hs +++ b/compiler/simplStg/UnariseStg.hs @@ -196,20 +196,22 @@ module UnariseStg (unarise) where #include "HsVersions.h" +import GhcPrelude + import BasicTypes import CoreSyn import DataCon import FastString (FastString, mkFastString) import Id -import Literal (Literal (..)) -import MkCore (aBSENT_ERROR_ID) +import Literal +import MkCore (aBSENT_SUM_FIELD_ERROR_ID) import MkId (voidPrimId, voidArgId) import MonadUtils (mapAccumLM) import Outputable import RepType import StgSyn import Type -import TysPrim (intPrimTy) +import TysPrim (intPrimTy,wordPrimTy,word64PrimTy) import TysWiredIn import UniqSupply import Util @@ -332,7 +334,7 @@ unariseExpr _ e@StgLam{} = pprPanic "unariseExpr: found lambda" (ppr e) unariseExpr rho (StgCase scrut bndr alt_ty alts) - -- a tuple/sum binders in the scrutinee can always be eliminated + -- tuple/sum binders in the scrutinee can always be eliminated | StgApp v [] <- scrut , Just (MultiVal xs) <- lookupVarEnv rho v = elimCase rho xs bndr alt_ty alts @@ -349,7 +351,8 @@ unariseExpr rho (StgCase scrut bndr alt_ty alts) = do scrut' <- unariseExpr rho scrut alts' <- unariseAlts rho alt_ty bndr alts return (StgCase scrut' bndr alt_ty alts') - -- bndr will be dead after unarise + -- bndr may have a unboxed sum/tuple type but it will be + -- dead after unarise (checked in StgLint) unariseExpr rho (StgLet bind e) = StgLet <$> unariseBinding rho bind <*> unariseExpr rho e @@ -475,7 +478,7 @@ unariseSumAlt rho _ (DEFAULT, _, e) unariseSumAlt rho args (DataAlt sumCon, bs, e) = do let rho' = mapSumIdBinders bs args rho e' <- unariseExpr rho' e - return ( LitAlt (MachInt (fromIntegral (dataConTag sumCon))), [], e' ) + return ( LitAlt (LitNumber LitNumInt (fromIntegral (dataConTag sumCon)) intPrimTy), [], e' ) unariseSumAlt _ scrt alt = pprPanic "unariseSumAlt" (ppr scrt $$ ppr alt) @@ -561,7 +564,7 @@ mkUbxSum dc ty_args args0 tag = dataConTag dc layout' = layoutUbxSum sum_slots (mapMaybe (typeSlotTy . stgArgType) args0) - tag_arg = StgLitArg (MachInt (fromIntegral tag)) + tag_arg = StgLitArg (LitNumber LitNumInt (fromIntegral tag) intPrimTy) arg_idxs = IM.fromList (zipEqual "mkUbxSum" layout' args0) mkTupArgs :: Int -> [SlotTy] -> IM.IntMap StgArg -> [StgArg] @@ -574,9 +577,10 @@ mkUbxSum dc ty_args args0 = slotRubbishArg slot : mkTupArgs (arg_idx + 1) slots_left arg_map slotRubbishArg :: SlotTy -> StgArg - slotRubbishArg PtrSlot = StgVarArg aBSENT_ERROR_ID - slotRubbishArg WordSlot = StgLitArg (MachWord 0) - slotRubbishArg Word64Slot = StgLitArg (MachWord64 0) + slotRubbishArg PtrSlot = StgVarArg aBSENT_SUM_FIELD_ERROR_ID + -- See Note [aBSENT_SUM_FIELD_ERROR_ID] in MkCore + slotRubbishArg WordSlot = StgLitArg (LitNumber LitNumWord 0 wordPrimTy) + slotRubbishArg Word64Slot = StgLitArg (LitNumber LitNumWord64 0 word64PrimTy) slotRubbishArg FloatSlot = StgLitArg (MachFloat 0) slotRubbishArg DoubleSlot = StgLitArg (MachDouble 0) in @@ -640,6 +644,35 @@ So in short, when we have a void id, in argument position of a DataCon application. -} +unariseArgBinder + :: Bool -- data con arg? + -> UnariseEnv -> Id -> UniqSM (UnariseEnv, [Id]) +unariseArgBinder is_con_arg rho x = + case typePrimRep (idType x) of + [] + | is_con_arg + -> return (extendRho rho x (MultiVal []), []) + | otherwise -- fun arg, do not remove void binders + -> return (extendRho rho x (MultiVal []), [voidArgId]) + + [rep] + -- Arg represented as single variable, but original type may still be an + -- unboxed sum/tuple, e.g. (# Void# | Void# #). + -- + -- While not unarising the binder in this case does not break any programs + -- (because it unarises to a single variable), it triggers StgLint as we + -- break the the post-unarisation invariant that says unboxed tuple/sum + -- binders should vanish. See Note [Post-unarisation invariants]. + | isUnboxedSumType (idType x) || isUnboxedTupleType (idType x) + -> do x' <- mkId (mkFastString "us") (primRepToType rep) + return (extendRho rho x (MultiVal [StgVarArg x']), [x']) + | otherwise + -> return (rho, [x]) + + reps -> do + xs <- mkIds (mkFastString "us") (map primRepToType reps) + return (extendRho rho x (MultiVal (map StgVarArg xs)), xs) + -------------------------------------------------------------------------------- -- | MultiVal a function argument. Never returns an empty list. @@ -658,16 +691,9 @@ unariseFunArgs = concatMap . unariseFunArg unariseFunArgBinders :: UnariseEnv -> [Id] -> UniqSM (UnariseEnv, [Id]) unariseFunArgBinders rho xs = second concat <$> mapAccumLM unariseFunArgBinder rho xs -unariseFunArgBinder :: UnariseEnv -> Id -> UniqSM (UnariseEnv, [Id]) -- Result list of binders is never empty -unariseFunArgBinder rho x = - case typePrimRep (idType x) of - [] -> return (extendRho rho x (MultiVal []), [voidArgId]) - -- NB: do not remove void binders - [_] -> return (rho, [x]) - reps -> do - xs <- mkIds (mkFastString "us") (map primRepToType reps) - return (extendRho rho x (MultiVal (map StgVarArg xs)), xs) +unariseFunArgBinder :: UnariseEnv -> Id -> UniqSM (UnariseEnv, [Id]) +unariseFunArgBinder = unariseArgBinder False -------------------------------------------------------------------------------- @@ -682,7 +708,9 @@ unariseConArg rho (StgVarArg x) = -- Here realWorld# is not in the envt, but -- is a void, and so should be eliminated | otherwise -> [StgVarArg x] -unariseConArg _ arg = [arg] -- We have no void literals +unariseConArg _ arg@(StgLitArg lit) = + ASSERT(not (isVoidTy (literalType lit))) -- We have no void literals + [arg] unariseConArgs :: UnariseEnv -> [InStgArg] -> [OutStgArg] unariseConArgs = concatMap . unariseConArg @@ -690,13 +718,10 @@ unariseConArgs = concatMap . unariseConArg unariseConArgBinders :: UnariseEnv -> [Id] -> UniqSM (UnariseEnv, [Id]) unariseConArgBinders rho xs = second concat <$> mapAccumLM unariseConArgBinder rho xs +-- Different from `unariseFunArgBinder`: result list of binders may be empty. +-- See DataCon applications case in Note [Post-unarisation invariants]. unariseConArgBinder :: UnariseEnv -> Id -> UniqSM (UnariseEnv, [Id]) -unariseConArgBinder rho x = - case typePrimRep (idType x) of - [_] -> return (rho, [x]) - reps -> do - xs <- mkIds (mkFastString "us") (map primRepToType reps) - return (extendRho rho x (MultiVal (map StgVarArg xs)), xs) +unariseConArgBinder = unariseArgBinder True unariseFreeVars :: UnariseEnv -> [InId] -> [OutId] unariseFreeVars rho fvs |