packages feed

ghc-lib 0.20191201 → 0.20200102

raw patch · 115 files changed

+9034/−8675 lines, 115 filesdep ~ghc-lib-parser

Dependency ranges changed: ghc-lib-parser

Files

+ compiler/GHC/CoreToStg.hs view
@@ -0,0 +1,939 @@+{-# LANGUAGE CPP, DeriveFunctor #-}++--+-- (c) The GRASP/AQUA Project, Glasgow University, 1993-1998+--++--------------------------------------------------------------+-- Converting Core to STG Syntax+--------------------------------------------------------------++-- And, as we have the info in hand, we may convert some lets to+-- let-no-escapes.++module GHC.CoreToStg ( coreToStg ) where++#include "HsVersions.h"++import GhcPrelude++import CoreSyn+import CoreUtils        ( exprType, findDefault, isJoinBind+                        , exprIsTickedString_maybe )+import CoreArity        ( manifestArity )+import GHC.Stg.Syntax++import Type+import GHC.Types.RepType+import TyCon+import MkId             ( coercionTokenId )+import Id+import IdInfo+import DataCon+import CostCentre+import VarEnv+import Module+import Name             ( isExternalName, nameOccName, nameModule_maybe )+import OccName          ( occNameFS )+import BasicTypes       ( Arity )+import TysWiredIn       ( unboxedUnitDataCon, unitDataConId )+import Literal+import Outputable+import MonadUtils+import FastString+import Util+import DynFlags+import ForeignCall+import Demand           ( isUsedOnce )+import PrimOp           ( PrimCall(..), primOpWrapperId )+import SrcLoc           ( mkGeneralSrcSpan )++import Data.List.NonEmpty (nonEmpty, toList)+import Data.Maybe    (fromMaybe)+import Control.Monad (ap)++-- Note [Live vs free]+-- ~~~~~~~~~~~~~~~~~~~+--+-- The two are not the same. Liveness is an operational property rather+-- than a semantic one. A variable is live at a particular execution+-- point if it can be referred to directly again. In particular, a dead+-- variable's stack slot (if it has one):+--+--           - should be stubbed to avoid space leaks, and+--           - may be reused for something else.+--+-- There ought to be a better way to say this. Here are some examples:+--+--         let v = [q] \[x] -> e+--         in+--         ...v...  (but no q's)+--+-- Just after the `in', v is live, but q is dead. If the whole of that+-- let expression was enclosed in a case expression, thus:+--+--         case (let v = [q] \[x] -> e in ...v...) of+--                 alts[...q...]+--+-- (ie `alts' mention `q'), then `q' is live even after the `in'; because+-- we'll return later to the `alts' and need it.+--+-- Let-no-escapes make this a bit more interesting:+--+--         let-no-escape v = [q] \ [x] -> e+--         in+--         ...v...+--+-- Here, `q' is still live at the `in', because `v' is represented not by+-- a closure but by the current stack state.  In other words, if `v' is+-- live then so is `q'. Furthermore, if `e' mentions an enclosing+-- let-no-escaped variable, then its free variables are also live if `v' is.++-- Note [What are these SRTs all about?]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Consider the Core program,+--+--     fibs = go 1 1+--       where go a b = let c = a + c+--                      in c : go b c+--     add x = map (\y -> x*y) fibs+--+-- In this case we have a CAF, 'fibs', which is quite large after evaluation and+-- has only one possible user, 'add'. Consequently, we want to ensure that when+-- all references to 'add' die we can garbage collect any bit of 'fibs' that we+-- have evaluated.+--+-- However, how do we know whether there are any references to 'fibs' still+-- around? Afterall, the only reference to it is buried in the code generated+-- for 'add'. The answer is that we record the CAFs referred to by a definition+-- in its info table, namely a part of it known as the Static Reference Table+-- (SRT).+--+-- Since SRTs are so common, we use a special compact encoding for them in: we+-- produce one table containing a list of CAFs in a module and then include a+-- bitmap in each info table describing which entries of this table the closure+-- references.+--+-- See also: commentary/rts/storage/gc/CAFs on the GHC Wiki.++-- Note [What is a non-escaping let]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- NB: Nowadays this is recognized by the occurrence analyser by turning a+-- "non-escaping let" into a join point. The following is then an operational+-- account of join points.+--+-- Consider:+--+--     let x = fvs \ args -> e+--     in+--         if ... then x else+--            if ... then x else ...+--+-- `x' is used twice (so we probably can't unfold it), but when it is+-- entered, the stack is deeper than it was when the definition of `x'+-- happened.  Specifically, if instead of allocating a closure for `x',+-- we saved all `x's fvs on the stack, and remembered the stack depth at+-- that moment, then whenever we enter `x' we can simply set the stack+-- pointer(s) to these remembered (compile-time-fixed) values, and jump+-- to the code for `x'.+--+-- All of this is provided x is:+--   1. non-updatable;+--   2. guaranteed to be entered before the stack retreats -- ie x is not+--      buried in a heap-allocated closure, or passed as an argument to+--      something;+--   3. all the enters have exactly the right number of arguments,+--      no more no less;+--   4. all the enters are tail calls; that is, they return to the+--      caller enclosing the definition of `x'.+--+-- Under these circumstances we say that `x' is non-escaping.+--+-- An example of when (4) does not hold:+--+--     let x = ...+--     in case x of ...alts...+--+-- Here, `x' is certainly entered only when the stack is deeper than when+-- `x' is defined, but here it must return to ...alts... So we can't just+-- adjust the stack down to `x''s recalled points, because that would lost+-- alts' context.+--+-- Things can get a little more complicated.  Consider:+--+--     let y = ...+--     in let x = fvs \ args -> ...y...+--     in ...x...+--+-- Now, if `x' is used in a non-escaping way in ...x..., and `y' is used in a+-- non-escaping way in ...y..., then `y' is non-escaping.+--+-- `x' can even be recursive!  Eg:+--+--     letrec x = [y] \ [v] -> if v then x True else ...+--     in+--         ...(x b)...++-- Note [Cost-centre initialization plan]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Previously `coreToStg` was initializing cost-centre stack fields as `noCCS`,+-- and the fields were then fixed by a separate pass `stgMassageForProfiling`.+-- We now initialize these correctly. The initialization works like this:+--+--   - For non-top level bindings always use `currentCCS`.+--+--   - For top-level bindings, check if the binding is a CAF+--+--     - CAF:      If -fcaf-all is enabled, create a new CAF just for this CAF+--                 and use it. Note that these new cost centres need to be+--                 collected to be able to generate cost centre initialization+--                 code, so `coreToTopStgRhs` now returns `CollectedCCs`.+--+--                 If -fcaf-all is not enabled, use "all CAFs" cost centre.+--+--     - Non-CAF:  Top-level (static) data is not counted in heap profiles; nor+--                 do we set CCCS from it; so we just slam in+--                 dontCareCostCentre.++-- --------------------------------------------------------------+-- Setting variable info: top-level, binds, RHSs+-- --------------------------------------------------------------++coreToStg :: DynFlags -> Module -> CoreProgram+          -> ([StgTopBinding], CollectedCCs)+coreToStg dflags this_mod pgm+  = (pgm', final_ccs)+  where+    (_, (local_ccs, local_cc_stacks), pgm')+      = coreTopBindsToStg dflags this_mod emptyVarEnv emptyCollectedCCs pgm++    prof = WayProf `elem` ways dflags++    final_ccs+      | prof && gopt Opt_AutoSccsOnIndividualCafs dflags+      = (local_ccs,local_cc_stacks)  -- don't need "all CAFs" CC+      | prof+      = (all_cafs_cc:local_ccs, all_cafs_ccs:local_cc_stacks)+      | otherwise+      = emptyCollectedCCs++    (all_cafs_cc, all_cafs_ccs) = getAllCAFsCC this_mod++coreTopBindsToStg+    :: DynFlags+    -> Module+    -> IdEnv HowBound           -- environment for the bindings+    -> CollectedCCs+    -> CoreProgram+    -> (IdEnv HowBound, CollectedCCs, [StgTopBinding])++coreTopBindsToStg _      _        env ccs []+  = (env, ccs, [])+coreTopBindsToStg dflags this_mod env ccs (b:bs)+  = (env2, ccs2, b':bs')+  where+        (env1, ccs1, b' ) =+          coreTopBindToStg dflags this_mod env ccs b+        (env2, ccs2, bs') =+          coreTopBindsToStg dflags this_mod env1 ccs1 bs++coreTopBindToStg+        :: DynFlags+        -> Module+        -> IdEnv HowBound+        -> CollectedCCs+        -> CoreBind+        -> (IdEnv HowBound, CollectedCCs, StgTopBinding)++coreTopBindToStg _ _ env ccs (NonRec id e)+  | Just str <- exprIsTickedString_maybe e+  -- top-level string literal+  -- See Note [CoreSyn top-level string literals] in CoreSyn+  = let+        env' = extendVarEnv env id how_bound+        how_bound = LetBound TopLet 0+    in (env', ccs, StgTopStringLit id str)++coreTopBindToStg dflags this_mod env ccs (NonRec id rhs)+  = let+        env'      = extendVarEnv env id how_bound+        how_bound = LetBound TopLet $! manifestArity rhs++        (stg_rhs, ccs') =+            initCts dflags env $+              coreToTopStgRhs dflags ccs this_mod (id,rhs)++        bind = StgTopLifted $ StgNonRec id stg_rhs+    in+    assertConsistentCafInfo dflags id bind (ppr bind)+      -- NB: previously the assertion printed 'rhs' and 'bind'+      --     as well as 'id', but that led to a black hole+      --     where printing the assertion error tripped the+      --     assertion again!+    (env', ccs', bind)++coreTopBindToStg dflags this_mod env ccs (Rec pairs)+  = ASSERT( not (null pairs) )+    let+        binders = map fst pairs++        extra_env' = [ (b, LetBound TopLet $! manifestArity rhs)+                     | (b, rhs) <- pairs ]+        env' = extendVarEnvList env extra_env'++        -- generate StgTopBindings and CAF cost centres created for CAFs+        (ccs', stg_rhss)+          = initCts dflags env' $ do+               mapAccumLM (\ccs rhs -> do+                            (rhs', ccs') <-+                              coreToTopStgRhs dflags ccs this_mod rhs+                            return (ccs', rhs'))+                          ccs+                          pairs++        bind = StgTopLifted $ StgRec (zip binders stg_rhss)+    in+    assertConsistentCafInfo dflags (head binders) bind (ppr binders)+    (env', ccs', bind)++-- | CAF consistency issues will generally result in segfaults and are quite+-- difficult to debug (see #16846). We enable checking of the+-- 'consistentCafInfo' invariant with @-dstg-lint@ to increase the chance that+-- we catch these issues.+assertConsistentCafInfo :: DynFlags -> Id -> StgTopBinding -> SDoc -> a -> a+assertConsistentCafInfo dflags id bind err_doc result+  | gopt Opt_DoStgLinting dflags || debugIsOn+  , not $ consistentCafInfo id bind = pprPanic "assertConsistentCafInfo" err_doc+  | otherwise = result++-- Assertion helper: this checks that the CafInfo on the Id matches+-- what CoreToStg has figured out about the binding's SRT.  The+-- CafInfo will be exact in all cases except when CorePrep has+-- floated out a binding, in which case it will be approximate.+consistentCafInfo :: Id -> StgTopBinding -> Bool+consistentCafInfo id bind+  = WARN( not (exact || is_sat_thing) , ppr id <+> ppr id_marked_caffy <+> ppr binding_is_caffy )+    safe+  where+    safe  = id_marked_caffy || not binding_is_caffy+    exact = id_marked_caffy == binding_is_caffy+    id_marked_caffy  = mayHaveCafRefs (idCafInfo id)+    binding_is_caffy = topStgBindHasCafRefs bind+    is_sat_thing = occNameFS (nameOccName (idName id)) == fsLit "sat"++coreToTopStgRhs+        :: DynFlags+        -> CollectedCCs+        -> Module+        -> (Id,CoreExpr)+        -> CtsM (StgRhs, CollectedCCs)++coreToTopStgRhs dflags ccs this_mod (bndr, rhs)+  = do { new_rhs <- coreToStgExpr rhs++       ; let (stg_rhs, ccs') =+               mkTopStgRhs dflags this_mod ccs bndr new_rhs+             stg_arity =+               stgRhsArity stg_rhs++       ; return (ASSERT2( arity_ok stg_arity, mk_arity_msg stg_arity) stg_rhs,+                 ccs') }+  where+        -- It's vital that the arity on a top-level Id matches+        -- the arity of the generated STG binding, else an importing+        -- module will use the wrong calling convention+        --      (#2844 was an example where this happened)+        -- NB1: we can't move the assertion further out without+        --      blocking the "knot" tied in coreTopBindsToStg+        -- NB2: the arity check is only needed for Ids with External+        --      Names, because they are externally visible.  The CorePrep+        --      pass introduces "sat" things with Local Names and does+        --      not bother to set their Arity info, so don't fail for those+    arity_ok stg_arity+       | isExternalName (idName bndr) = id_arity == stg_arity+       | otherwise                    = True+    id_arity  = idArity bndr+    mk_arity_msg stg_arity+        = vcat [ppr bndr,+                text "Id arity:" <+> ppr id_arity,+                text "STG arity:" <+> ppr stg_arity]++-- ---------------------------------------------------------------------------+-- Expressions+-- ---------------------------------------------------------------------------++coreToStgExpr+        :: CoreExpr+        -> CtsM StgExpr++-- The second and third components can be derived in a simple bottom up pass, not+-- dependent on any decisions about which variables will be let-no-escaped or+-- not.  The first component, that is, the decorated expression, may then depend+-- on these components, but it in turn is not scrutinised as the basis for any+-- decisions.  Hence no black holes.++-- No LitInteger's or LitNatural's should be left by the time this is called.+-- CorePrep should have converted them all to a real core representation.+coreToStgExpr (Lit (LitNumber LitNumInteger _ _)) = panic "coreToStgExpr: LitInteger"+coreToStgExpr (Lit (LitNumber LitNumNatural _ _)) = panic "coreToStgExpr: LitNatural"+coreToStgExpr (Lit l)      = return (StgLit l)+coreToStgExpr (App (Lit LitRubbish) _some_unlifted_type)+  -- We lower 'LitRubbish' to @()@ here, which is much easier than doing it in+  -- a STG to Cmm pass.+  = coreToStgExpr (Var unitDataConId)+coreToStgExpr (Var v)      = coreToStgApp v               [] []+coreToStgExpr (Coercion _) = coreToStgApp coercionTokenId [] []++coreToStgExpr expr@(App _ _)+  = coreToStgApp f args ticks+  where+    (f, args, ticks) = myCollectArgs expr++coreToStgExpr expr@(Lam _ _)+  = let+        (args, body) = myCollectBinders expr+        args'        = filterStgBinders args+    in+    extendVarEnvCts [ (a, LambdaBound) | a <- args' ] $ do+    body' <- coreToStgExpr body+    let+        result_expr = case nonEmpty args' of+          Nothing     -> body'+          Just args'' -> StgLam args'' body'++    return result_expr++coreToStgExpr (Tick tick expr)+  = do case tick of+         HpcTick{}    -> return ()+         ProfNote{}   -> return ()+         SourceNote{} -> return ()+         Breakpoint{} -> panic "coreToStgExpr: breakpoint should not happen"+       expr2 <- coreToStgExpr expr+       return (StgTick tick expr2)++coreToStgExpr (Cast expr _)+  = coreToStgExpr expr++-- Cases require a little more real work.++coreToStgExpr (Case scrut _ _ [])+  = coreToStgExpr scrut+    -- See Note [Empty case alternatives] in CoreSyn If the case+    -- alternatives are empty, the scrutinee must diverge or raise an+    -- exception, so we can just dive into it.+    --+    -- Of course this may seg-fault if the scrutinee *does* return.  A+    -- belt-and-braces approach would be to move this case into the+    -- code generator, and put a return point anyway that calls a+    -- runtime system error function.+++coreToStgExpr (Case scrut bndr _ alts) = do+    alts2 <- extendVarEnvCts [(bndr, LambdaBound)] (mapM vars_alt alts)+    scrut2 <- coreToStgExpr scrut+    return (StgCase scrut2 bndr (mkStgAltType bndr alts) alts2)+  where+    vars_alt (con, binders, rhs)+      | DataAlt c <- con, c == unboxedUnitDataCon+      = -- This case is a bit smelly.+        -- See Note [Nullary unboxed tuple] in Type.hs+        -- where a nullary tuple is mapped to (State# World#)+        ASSERT( null binders )+        do { rhs2 <- coreToStgExpr rhs+           ; return (DEFAULT, [], rhs2)  }+      | otherwise+      = let     -- Remove type variables+            binders' = filterStgBinders binders+        in+        extendVarEnvCts [(b, LambdaBound) | b <- binders'] $ do+        rhs2 <- coreToStgExpr rhs+        return (con, binders', rhs2)++coreToStgExpr (Let bind body) = do+    coreToStgLet bind body++coreToStgExpr e = pprPanic "coreToStgExpr" (ppr e)++mkStgAltType :: Id -> [CoreAlt] -> AltType+mkStgAltType bndr alts+  | isUnboxedTupleType bndr_ty || isUnboxedSumType bndr_ty+  = MultiValAlt (length prim_reps)  -- always use MultiValAlt for unboxed tuples++  | otherwise+  = case prim_reps of+      [LiftedRep] -> case tyConAppTyCon_maybe (unwrapType bndr_ty) of+        Just tc+          | isAbstractTyCon tc -> look_for_better_tycon+          | isAlgTyCon tc      -> AlgAlt tc+          | otherwise          -> ASSERT2( _is_poly_alt_tycon tc, ppr tc )+                                  PolyAlt+        Nothing                -> PolyAlt+      [unlifted] -> PrimAlt unlifted+      not_unary  -> MultiValAlt (length not_unary)+  where+   bndr_ty   = idType bndr+   prim_reps = typePrimRep bndr_ty++   _is_poly_alt_tycon tc+        =  isFunTyCon tc+        || isPrimTyCon tc   -- "Any" is lifted but primitive+        || isFamilyTyCon tc -- Type family; e.g. Any, or arising from strict+                            -- function application where argument has a+                            -- type-family type++   -- Sometimes, the TyCon is a AbstractTyCon which may not have any+   -- constructors inside it.  Then we may get a better TyCon by+   -- grabbing the one from a constructor alternative+   -- if one exists.+   look_for_better_tycon+        | ((DataAlt con, _, _) : _) <- data_alts =+                AlgAlt (dataConTyCon con)+        | otherwise =+                ASSERT(null data_alts)+                PolyAlt+        where+                (data_alts, _deflt) = findDefault alts++-- ---------------------------------------------------------------------------+-- Applications+-- ---------------------------------------------------------------------------++coreToStgApp :: Id            -- Function+             -> [CoreArg]     -- Arguments+             -> [Tickish Id]  -- Debug ticks+             -> CtsM StgExpr+coreToStgApp f args ticks = do+    (args', ticks') <- coreToStgArgs args+    how_bound <- lookupVarCts f++    let+        n_val_args       = valArgCount args++        -- Mostly, the arity info of a function is in the fn's IdInfo+        -- But new bindings introduced by CoreSat may not have no+        -- arity info; it would do us no good anyway.  For example:+        --      let f = \ab -> e in f+        -- No point in having correct arity info for f!+        -- Hence the hasArity stuff below.+        -- NB: f_arity is only consulted for LetBound things+        f_arity   = stgArity f how_bound+        saturated = f_arity <= n_val_args++        res_ty = exprType (mkApps (Var f) args)+        app = case idDetails f of+                DataConWorkId dc+                  | saturated    -> StgConApp dc args'+                                      (dropRuntimeRepArgs (fromMaybe [] (tyConAppArgs_maybe res_ty)))++                -- Some primitive operator that might be implemented as a library call.+                -- As described in Note [Primop wrappers] in PrimOp.hs, here we+                -- turn unsaturated primop applications into applications of+                -- the primop's wrapper.+                PrimOpId op+                  | saturated    -> StgOpApp (StgPrimOp op) args' res_ty+                  | otherwise    -> StgApp (primOpWrapperId op) args'++                -- A call to some primitive Cmm function.+                FCallId (CCall (CCallSpec (StaticTarget _ lbl (Just pkgId) True)+                                          PrimCallConv _))+                                 -> ASSERT( saturated )+                                    StgOpApp (StgPrimCallOp (PrimCall lbl pkgId)) args' res_ty++                -- A regular foreign call.+                FCallId call     -> ASSERT( saturated )+                                    StgOpApp (StgFCallOp call (idType f)) args' res_ty++                TickBoxOpId {}   -> pprPanic "coreToStg TickBox" $ ppr (f,args')+                _other           -> StgApp f args'++        tapp = foldr StgTick app (ticks ++ ticks')++    -- Forcing these fixes a leak in the code generator, noticed while+    -- profiling for trac #4367+    app `seq` return tapp++-- ---------------------------------------------------------------------------+-- Argument lists+-- This is the guy that turns applications into A-normal form+-- ---------------------------------------------------------------------------++coreToStgArgs :: [CoreArg] -> CtsM ([StgArg], [Tickish Id])+coreToStgArgs []+  = return ([], [])++coreToStgArgs (Type _ : args) = do     -- Type argument+    (args', ts) <- coreToStgArgs args+    return (args', ts)++coreToStgArgs (Coercion _ : args)  -- Coercion argument; replace with place holder+  = do { (args', ts) <- coreToStgArgs args+       ; return (StgVarArg coercionTokenId : args', ts) }++coreToStgArgs (Tick t e : args)+  = ASSERT( not (tickishIsCode t) )+    do { (args', ts) <- coreToStgArgs (e : args)+       ; return (args', t:ts) }++coreToStgArgs (arg : args) = do         -- Non-type argument+    (stg_args, ticks) <- coreToStgArgs args+    arg' <- coreToStgExpr arg+    let+        (aticks, arg'') = stripStgTicksTop tickishFloatable arg'+        stg_arg = case arg'' of+                       StgApp v []        -> StgVarArg v+                       StgConApp con [] _ -> StgVarArg (dataConWorkId con)+                       StgLit lit         -> StgLitArg lit+                       _                  -> pprPanic "coreToStgArgs" (ppr arg)++        -- WARNING: what if we have an argument like (v `cast` co)+        --          where 'co' changes the representation type?+        --          (This really only happens if co is unsafe.)+        -- Then all the getArgAmode stuff in CgBindery will set the+        -- cg_rep of the CgIdInfo based on the type of v, rather+        -- than the type of 'co'.+        -- This matters particularly when the function is a primop+        -- or foreign call.+        -- Wanted: a better solution than this hacky warning++    dflags <- getDynFlags+    let+        arg_rep = typePrimRep (exprType arg)+        stg_arg_rep = typePrimRep (stgArgType stg_arg)+        bad_args = not (primRepsCompatible dflags arg_rep stg_arg_rep)++    WARN( bad_args, text "Dangerous-looking argument. Probable cause: bad unsafeCoerce#" $$ ppr arg )+     return (stg_arg : stg_args, ticks ++ aticks)+++-- ---------------------------------------------------------------------------+-- The magic for lets:+-- ---------------------------------------------------------------------------++coreToStgLet+         :: CoreBind     -- bindings+         -> CoreExpr     -- body+         -> CtsM StgExpr -- new let++coreToStgLet bind body = do+    (bind2, body2)+       <- do++          ( bind2, env_ext)+                <- vars_bind bind++          -- Do the body+          extendVarEnvCts env_ext $ do+             body2 <- coreToStgExpr body++             return (bind2, body2)++        -- Compute the new let-expression+    let+        new_let | isJoinBind bind = StgLetNoEscape noExtFieldSilent bind2 body2+                | otherwise       = StgLet noExtFieldSilent bind2 body2++    return new_let+  where+    mk_binding binder rhs+        = (binder, LetBound NestedLet (manifestArity rhs))++    vars_bind :: CoreBind+              -> CtsM (StgBinding,+                       [(Id, HowBound)])  -- extension to environment++    vars_bind (NonRec binder rhs) = do+        rhs2 <- coreToStgRhs (binder,rhs)+        let+            env_ext_item = mk_binding binder rhs++        return (StgNonRec binder rhs2, [env_ext_item])++    vars_bind (Rec pairs)+      =    let+                binders = map fst pairs+                env_ext = [ mk_binding b rhs+                          | (b,rhs) <- pairs ]+           in+           extendVarEnvCts env_ext $ do+              rhss2 <- mapM coreToStgRhs pairs+              return (StgRec (binders `zip` rhss2), env_ext)++coreToStgRhs :: (Id,CoreExpr)+             -> CtsM StgRhs++coreToStgRhs (bndr, rhs) = do+    new_rhs <- coreToStgExpr rhs+    return (mkStgRhs bndr new_rhs)++-- Generate a top-level RHS. Any new cost centres generated for CAFs will be+-- appended to `CollectedCCs` argument.+mkTopStgRhs :: DynFlags -> Module -> CollectedCCs+            -> Id -> StgExpr -> (StgRhs, CollectedCCs)++mkTopStgRhs dflags this_mod ccs bndr rhs+  | StgLam bndrs body <- rhs+  = -- StgLam can't have empty arguments, so not CAF+    ( StgRhsClosure noExtFieldSilent+                    dontCareCCS+                    ReEntrant+                    (toList bndrs) body+    , ccs )++  | StgConApp con args _ <- unticked_rhs+  , -- Dynamic StgConApps are updatable+    not (isDllConApp dflags this_mod con args)+  = -- CorePrep does this right, but just to make sure+    ASSERT2( not (isUnboxedTupleCon con || isUnboxedSumCon con)+           , ppr bndr $$ ppr con $$ ppr args)+    ( StgRhsCon dontCareCCS con args, ccs )++  -- Otherwise it's a CAF, see Note [Cost-centre initialization plan].+  | gopt Opt_AutoSccsOnIndividualCafs dflags+  = ( StgRhsClosure noExtFieldSilent+                    caf_ccs+                    upd_flag [] rhs+    , collectCC caf_cc caf_ccs ccs )++  | otherwise+  = ( StgRhsClosure noExtFieldSilent+                    all_cafs_ccs+                    upd_flag [] rhs+    , ccs )++  where+    unticked_rhs = stripStgTicksTopE (not . tickishIsCode) rhs++    upd_flag | isUsedOnce (idDemandInfo bndr) = SingleEntry+             | otherwise                      = Updatable++    -- CAF cost centres generated for -fcaf-all+    caf_cc = mkAutoCC bndr modl+    caf_ccs = mkSingletonCCS caf_cc+           -- careful: the binder might be :Main.main,+           -- which doesn't belong to module mod_name.+           -- bug #249, tests prof001, prof002+    modl | Just m <- nameModule_maybe (idName bndr) = m+         | otherwise = this_mod++    -- default CAF cost centre+    (_, all_cafs_ccs) = getAllCAFsCC this_mod++-- Generate a non-top-level RHS. Cost-centre is always currentCCS,+-- see Note [Cost-centre initialzation plan].+mkStgRhs :: Id -> StgExpr -> StgRhs+mkStgRhs bndr rhs+  | StgLam bndrs body <- rhs+  = StgRhsClosure noExtFieldSilent+                  currentCCS+                  ReEntrant+                  (toList bndrs) body++  | isJoinId bndr -- must be a nullary join point+  = ASSERT(idJoinArity bndr == 0)+    StgRhsClosure noExtFieldSilent+                  currentCCS+                  ReEntrant -- ignored for LNE+                  [] rhs++  | StgConApp con args _ <- unticked_rhs+  = StgRhsCon currentCCS con args++  | otherwise+  = StgRhsClosure noExtFieldSilent+                  currentCCS+                  upd_flag [] rhs+  where+    unticked_rhs = stripStgTicksTopE (not . tickishIsCode) rhs++    upd_flag | isUsedOnce (idDemandInfo bndr) = SingleEntry+             | otherwise                      = Updatable++  {-+    SDM: disabled.  Eval/Apply can't handle functions with arity zero very+    well; and making these into simple non-updatable thunks breaks other+    assumptions (namely that they will be entered only once).++    upd_flag | isPAP env rhs  = ReEntrant+             | otherwise      = Updatable++-- Detect thunks which will reduce immediately to PAPs, and make them+-- non-updatable.  This has several advantages:+--+--         - the non-updatable thunk behaves exactly like the PAP,+--+--         - the thunk is more efficient to enter, because it is+--           specialised to the task.+--+--         - we save one update frame, one stg_update_PAP, one update+--           and lots of PAP_enters.+--+--         - in the case where the thunk is top-level, we save building+--           a black hole and furthermore the thunk isn't considered to+--           be a CAF any more, so it doesn't appear in any SRTs.+--+-- We do it here, because the arity information is accurate, and we need+-- to do it before the SRT pass to save the SRT entries associated with+-- any top-level PAPs.++isPAP env (StgApp f args) = listLengthCmp args arity == LT -- idArity f > length args+                              where+                                 arity = stgArity f (lookupBinding env f)+isPAP env _               = False++-}++{- ToDo:+          upd = if isOnceDem dem+                    then (if isNotTop toplev+                            then SingleEntry    -- HA!  Paydirt for "dem"+                            else+                     (if debugIsOn then trace "WARNING: SE CAFs unsupported, forcing UPD instead" else id) $+                     Updatable)+                else Updatable+        -- For now we forbid SingleEntry CAFs; they tickle the+        -- ASSERT in rts/Storage.c line 215 at newCAF() re mut_link,+        -- and I don't understand why.  There's only one SE_CAF (well,+        -- only one that tickled a great gaping bug in an earlier attempt+        -- at ClosureInfo.getEntryConvention) in the whole of nofib,+        -- specifically Main.lvl6 in spectral/cryptarithm2.+        -- So no great loss.  KSW 2000-07.+-}++-- ---------------------------------------------------------------------------+-- A monad for the core-to-STG pass+-- ---------------------------------------------------------------------------++-- There's a lot of stuff to pass around, so we use this CtsM+-- ("core-to-STG monad") monad to help.  All the stuff here is only passed+-- *down*.++newtype CtsM a = CtsM+    { unCtsM :: DynFlags -- Needed for checking for bad coercions in coreToStgArgs+             -> IdEnv HowBound+             -> a+    }+    deriving (Functor)++data HowBound+  = ImportBound         -- Used only as a response to lookupBinding; never+                        -- exists in the range of the (IdEnv HowBound)++  | LetBound            -- A let(rec) in this module+        LetInfo         -- Whether top level or nested+        Arity           -- Its arity (local Ids don't have arity info at this point)++  | LambdaBound         -- Used for both lambda and case+  deriving (Eq)++data LetInfo+  = TopLet              -- top level things+  | NestedLet+  deriving (Eq)++-- For a let(rec)-bound variable, x, we record LiveInfo, the set of+-- variables that are live if x is live.  This LiveInfo comprises+--         (a) dynamic live variables (ones with a non-top-level binding)+--         (b) static live variabes (CAFs or things that refer to CAFs)+--+-- For "normal" variables (a) is just x alone.  If x is a let-no-escaped+-- variable then x is represented by a code pointer and a stack pointer+-- (well, one for each stack).  So all of the variables needed in the+-- execution of x are live if x is, and are therefore recorded in the+-- LetBound constructor; x itself *is* included.+--+-- The set of dynamic live variables is guaranteed ot have no further+-- let-no-escaped variables in it.++-- The std monad functions:++initCts :: DynFlags -> IdEnv HowBound -> CtsM a -> a+initCts dflags env m = unCtsM m dflags env++++{-# INLINE thenCts #-}+{-# INLINE returnCts #-}++returnCts :: a -> CtsM a+returnCts e = CtsM $ \_ _ -> e++thenCts :: CtsM a -> (a -> CtsM b) -> CtsM b+thenCts m k = CtsM $ \dflags env+  -> unCtsM (k (unCtsM m dflags env)) dflags env++instance Applicative CtsM where+    pure = returnCts+    (<*>) = ap++instance Monad CtsM where+    (>>=)  = thenCts++instance HasDynFlags CtsM where+    getDynFlags = CtsM $ \dflags _ -> dflags++-- Functions specific to this monad:++extendVarEnvCts :: [(Id, HowBound)] -> CtsM a -> CtsM a+extendVarEnvCts ids_w_howbound expr+   =    CtsM $   \dflags env+   -> unCtsM expr dflags (extendVarEnvList env ids_w_howbound)++lookupVarCts :: Id -> CtsM HowBound+lookupVarCts v = CtsM $ \_ env -> lookupBinding env v++lookupBinding :: IdEnv HowBound -> Id -> HowBound+lookupBinding env v = case lookupVarEnv env v of+                        Just xx -> xx+                        Nothing -> ASSERT2( isGlobalId v, ppr v ) ImportBound++getAllCAFsCC :: Module -> (CostCentre, CostCentreStack)+getAllCAFsCC this_mod =+    let+      span = mkGeneralSrcSpan (mkFastString "<entire-module>") -- XXX do better+      all_cafs_cc  = mkAllCafsCC this_mod span+      all_cafs_ccs = mkSingletonCCS all_cafs_cc+    in+      (all_cafs_cc, all_cafs_ccs)++-- Misc.++filterStgBinders :: [Var] -> [Var]+filterStgBinders bndrs = filter isId bndrs++myCollectBinders :: Expr Var -> ([Var], Expr Var)+myCollectBinders expr+  = go [] expr+  where+    go bs (Lam b e)          = go (b:bs) e+    go bs (Cast e _)         = go bs e+    go bs e                  = (reverse bs, e)++-- | Precondition: argument expression is an 'App', and there is a 'Var' at the+-- head of the 'App' chain.+myCollectArgs :: CoreExpr -> (Id, [CoreArg], [Tickish Id])+myCollectArgs expr+  = go expr [] []+  where+    go (Var v)          as ts = (v, as, ts)+    go (App f a)        as ts = go f (a:as) ts+    go (Tick t e)       as ts = ASSERT( all isTypeArg as )+                                go e as (t:ts) -- ticks can appear in type apps+    go (Cast e _)       as ts = go e as ts+    go (Lam b e)        as ts+       | isTyVar b            = go e as ts -- Note [Collect args]+    go _                _  _  = pprPanic "CoreToStg.myCollectArgs" (ppr expr)++-- Note [Collect args]+-- ~~~~~~~~~~~~~~~~~~~+--+-- This big-lambda case occurred following a rather obscure eta expansion.+-- It all seems a bit yukky to me.++stgArity :: Id -> HowBound -> Arity+stgArity _ (LetBound _ arity) = arity+stgArity f ImportBound        = idArity f+stgArity _ LambdaBound        = 0
+ compiler/GHC/CoreToStg/Prep.hs view
@@ -0,0 +1,1733 @@+{-+(c) The University of Glasgow, 1994-2006+++Core pass to saturate constructors and PrimOps+-}++{-# LANGUAGE BangPatterns, CPP, MultiWayIf #-}++module GHC.CoreToStg.Prep (+      corePrepPgm, corePrepExpr, cvtLitInteger, cvtLitNatural,+      lookupMkIntegerName, lookupIntegerSDataConName,+      lookupMkNaturalName, lookupNaturalSDataConName+  ) where++#include "HsVersions.h"++import GhcPrelude++import OccurAnal++import HscTypes+import PrelNames+import MkId             ( realWorldPrimId )+import CoreUtils+import CoreArity+import CoreFVs+import CoreMonad        ( CoreToDo(..) )+import CoreLint         ( endPassIO )+import CoreSyn+import CoreSubst+import MkCore hiding( FloatBind(..) )   -- We use our own FloatBind here+import Type+import Literal+import Coercion+import TcEnv+import TyCon+import Demand+import Var+import VarSet+import VarEnv+import Id+import IdInfo+import TysWiredIn+import DataCon+import BasicTypes+import Module+import UniqSupply+import Maybes+import OrdList+import ErrUtils+import DynFlags+import Util+import Outputable+import GHC.Platform+import FastString+import Name             ( NamedThing(..), nameSrcSpan )+import SrcLoc           ( SrcSpan(..), realSrcLocSpan, mkRealSrcLoc )+import Data.Bits+import MonadUtils       ( mapAccumLM )+import Data.List        ( mapAccumL )+import Control.Monad+import CostCentre       ( CostCentre, ccFromThisModule )+import qualified Data.Set as S++{-+-- ---------------------------------------------------------------------------+-- Note [CorePrep Overview]+-- ---------------------------------------------------------------------------++The goal of this pass is to prepare for code generation.++1.  Saturate constructor applications.++2.  Convert to A-normal form; that is, function arguments+    are always variables.++    * Use case for strict arguments:+        f E ==> case E of x -> f x+        (where f is strict)++    * Use let for non-trivial lazy arguments+        f E ==> let x = E in f x+        (were f is lazy and x is non-trivial)++3.  Similarly, convert any unboxed lets into cases.+    [I'm experimenting with leaving 'ok-for-speculation'+     rhss in let-form right up to this point.]++4.  Ensure that *value* lambdas only occur as the RHS of a binding+    (The code generator can't deal with anything else.)+    Type lambdas are ok, however, because the code gen discards them.++5.  [Not any more; nuked Jun 2002] Do the seq/par munging.++6.  Clone all local Ids.+    This means that all such Ids are unique, rather than the+    weaker guarantee of no clashes which the simplifier provides.+    And that is what the code generator needs.++    We don't clone TyVars or CoVars. The code gen doesn't need that,+    and doing so would be tiresome because then we'd need+    to substitute in types and coercions.++7.  Give each dynamic CCall occurrence a fresh unique; this is+    rather like the cloning step above.++8.  Inject bindings for the "implicit" Ids:+        * Constructor wrappers+        * Constructor workers+    We want curried definitions for all of these in case they+    aren't inlined by some caller.++9.  Replace (lazy e) by e.  See Note [lazyId magic] in MkId.hs+    Also replace (noinline e) by e.++10. Convert (LitInteger i t) into the core representation+    for the Integer i. Normally this uses mkInteger, but if+    we are using the integer-gmp implementation then there is a+    special case where we use the S# constructor for Integers that+    are in the range of Int.++11. Same for LitNatural.++12. Uphold tick consistency while doing this: We move ticks out of+    (non-type) applications where we can, and make sure that we+    annotate according to scoping rules when floating.++13. Collect cost centres (including cost centres in unfoldings) if we're in+    profiling mode. We have to do this here beucase we won't have unfoldings+    after this pass (see `zapUnfolding` and Note [Drop unfoldings and rules].++This is all done modulo type applications and abstractions, so that+when type erasure is done for conversion to STG, we don't end up with+any trivial or useless bindings.+++Note [CorePrep invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Here is the syntax of the Core produced by CorePrep:++    Trivial expressions+       arg ::= lit |  var+              | arg ty  |  /\a. arg+              | truv co  |  /\c. arg  |  arg |> co++    Applications+       app ::= lit  |  var  |  app arg  |  app ty  | app co | app |> co++    Expressions+       body ::= app+              | let(rec) x = rhs in body     -- Boxed only+              | case body of pat -> body+              | /\a. body | /\c. body+              | body |> co++    Right hand sides (only place where value lambdas can occur)+       rhs ::= /\a.rhs  |  \x.rhs  |  body++We define a synonym for each of these non-terminals.  Functions+with the corresponding name produce a result in that syntax.+-}++type CpeArg  = CoreExpr    -- Non-terminal 'arg'+type CpeApp  = CoreExpr    -- Non-terminal 'app'+type CpeBody = CoreExpr    -- Non-terminal 'body'+type CpeRhs  = CoreExpr    -- Non-terminal 'rhs'++{-+************************************************************************+*                                                                      *+                Top level stuff+*                                                                      *+************************************************************************+-}++corePrepPgm :: HscEnv -> Module -> ModLocation -> CoreProgram -> [TyCon]+            -> IO (CoreProgram, S.Set CostCentre)+corePrepPgm hsc_env this_mod mod_loc binds data_tycons =+    withTiming dflags+               (text "CorePrep"<+>brackets (ppr this_mod))+               (const ()) $ do+    us <- mkSplitUniqSupply 's'+    initialCorePrepEnv <- mkInitialCorePrepEnv dflags hsc_env++    let cost_centres+          | WayProf `elem` ways dflags+          = collectCostCentres this_mod binds+          | otherwise+          = S.empty++        implicit_binds = mkDataConWorkers dflags mod_loc data_tycons+            -- NB: we must feed mkImplicitBinds through corePrep too+            -- so that they are suitably cloned and eta-expanded++        binds_out = initUs_ us $ do+                      floats1 <- corePrepTopBinds initialCorePrepEnv binds+                      floats2 <- corePrepTopBinds initialCorePrepEnv implicit_binds+                      return (deFloatTop (floats1 `appendFloats` floats2))++    endPassIO hsc_env alwaysQualify CorePrep binds_out []+    return (binds_out, cost_centres)+  where+    dflags = hsc_dflags hsc_env++corePrepExpr :: DynFlags -> HscEnv -> CoreExpr -> IO CoreExpr+corePrepExpr dflags hsc_env expr =+    withTiming dflags (text "CorePrep [expr]") (const ()) $ do+    us <- mkSplitUniqSupply 's'+    initialCorePrepEnv <- mkInitialCorePrepEnv dflags hsc_env+    let new_expr = initUs_ us (cpeBodyNF initialCorePrepEnv expr)+    dumpIfSet_dyn dflags Opt_D_dump_prep "CorePrep" FormatCore (ppr new_expr)+    return new_expr++corePrepTopBinds :: CorePrepEnv -> [CoreBind] -> UniqSM Floats+-- Note [Floating out of top level bindings]+corePrepTopBinds initialCorePrepEnv binds+  = go initialCorePrepEnv binds+  where+    go _   []             = return emptyFloats+    go env (bind : binds) = do (env', floats, maybe_new_bind)+                                 <- cpeBind TopLevel env bind+                               MASSERT(isNothing maybe_new_bind)+                                 -- Only join points get returned this way by+                                 -- cpeBind, and no join point may float to top+                               floatss <- go env' binds+                               return (floats `appendFloats` floatss)++mkDataConWorkers :: DynFlags -> ModLocation -> [TyCon] -> [CoreBind]+-- See Note [Data constructor workers]+-- c.f. Note [Injecting implicit bindings] in TidyPgm+mkDataConWorkers dflags mod_loc data_tycons+  = [ NonRec id (tick_it (getName data_con) (Var id))+                                -- The ice is thin here, but it works+    | tycon <- data_tycons,     -- CorePrep will eta-expand it+      data_con <- tyConDataCons tycon,+      let id = dataConWorkId data_con+    ]+ where+   -- If we want to generate debug info, we put a source note on the+   -- worker. This is useful, especially for heap profiling.+   tick_it name+     | debugLevel dflags == 0                = id+     | RealSrcSpan span <- nameSrcSpan name  = tick span+     | Just file <- ml_hs_file mod_loc       = tick (span1 file)+     | otherwise                             = tick (span1 "???")+     where tick span  = Tick (SourceNote span $ showSDoc dflags (ppr name))+           span1 file = realSrcLocSpan $ mkRealSrcLoc (mkFastString file) 1 1++{-+Note [Floating out of top level bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+NB: we do need to float out of top-level bindings+Consider        x = length [True,False]+We want to get+                s1 = False : []+                s2 = True  : s1+                x  = length s2++We return a *list* of bindings, because we may start with+        x* = f (g y)+where x is demanded, in which case we want to finish with+        a = g y+        x* = f a+And then x will actually end up case-bound++Note [CafInfo and floating]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+What happens when we try to float bindings to the top level?  At this+point all the CafInfo is supposed to be correct, and we must make certain+that is true of the new top-level bindings.  There are two cases+to consider++a) The top-level binding is marked asCafRefs.  In that case we are+   basically fine.  The floated bindings had better all be lazy lets,+   so they can float to top level, but they'll all have HasCafRefs+   (the default) which is safe.++b) The top-level binding is marked NoCafRefs.  This really happens+   Example.  CoreTidy produces+      $fApplicativeSTM [NoCafRefs] = D:Alternative retry# ...blah...+   Now CorePrep has to eta-expand to+      $fApplicativeSTM = let sat = \xy. retry x y+                         in D:Alternative sat ...blah...+   So what we *want* is+      sat [NoCafRefs] = \xy. retry x y+      $fApplicativeSTM [NoCafRefs] = D:Alternative sat ...blah...++   So, gruesomely, we must set the NoCafRefs flag on the sat bindings,+   *and* substitute the modified 'sat' into the old RHS.++   It should be the case that 'sat' is itself [NoCafRefs] (a value, no+   cafs) else the original top-level binding would not itself have been+   marked [NoCafRefs].  The DEBUG check in CoreToStg for+   consistentCafInfo will find this.++This is all very gruesome and horrible. It would be better to figure+out CafInfo later, after CorePrep.  We'll do that in due course.+Meanwhile this horrible hack works.++Note [Join points and floating]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Join points can float out of other join points but not out of value bindings:++  let z =+    let  w = ... in -- can float+    join k = ... in -- can't float+    ... jump k ...+  join j x1 ... xn =+    let  y = ... in -- can float (but don't want to)+    join h = ... in -- can float (but not much point)+    ... jump h ...+  in ...++Here, the jump to h remains valid if h is floated outward, but the jump to k+does not.++We don't float *out* of join points. It would only be safe to float out of+nullary join points (or ones where the arguments are all either type arguments+or dead binders). Nullary join points aren't ever recursive, so they're always+effectively one-shot functions, which we don't float out of. We *could* float+join points from nullary join points, but there's no clear benefit at this+stage.++Note [Data constructor workers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Create any necessary "implicit" bindings for data con workers.  We+create the rather strange (non-recursive!) binding++        $wC = \x y -> $wC x y++i.e. a curried constructor that allocates.  This means that we can+treat the worker for a constructor like any other function in the rest+of the compiler.  The point here is that CoreToStg will generate a+StgConApp for the RHS, rather than a call to the worker (which would+give a loop).  As Lennart says: the ice is thin here, but it works.++Hmm.  Should we create bindings for dictionary constructors?  They are+always fully applied, and the bindings are just there to support+partial applications. But it's easier to let them through.+++Note [Dead code in CorePrep]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Imagine that we got an input program like this (see #4962):++  f :: Show b => Int -> (Int, b -> Maybe Int -> Int)+  f x = (g True (Just x) + g () (Just x), g)+    where+      g :: Show a => a -> Maybe Int -> Int+      g _ Nothing = x+      g y (Just z) = if z > 100 then g y (Just (z + length (show y))) else g y unknown++After specialisation and SpecConstr, we would get something like this:++  f :: Show b => Int -> (Int, b -> Maybe Int -> Int)+  f x = (g$Bool_True_Just x + g$Unit_Unit_Just x, g)+    where+      {-# RULES g $dBool = g$Bool+                g $dUnit = g$Unit #-}+      g = ...+      {-# RULES forall x. g$Bool True (Just x) = g$Bool_True_Just x #-}+      g$Bool = ...+      {-# RULES forall x. g$Unit () (Just x) = g$Unit_Unit_Just x #-}+      g$Unit = ...+      g$Bool_True_Just = ...+      g$Unit_Unit_Just = ...++Note that the g$Bool and g$Unit functions are actually dead code: they+are only kept alive by the occurrence analyser because they are+referred to by the rules of g, which is being kept alive by the fact+that it is used (unspecialised) in the returned pair.++However, at the CorePrep stage there is no way that the rules for g+will ever fire, and it really seems like a shame to produce an output+program that goes to the trouble of allocating a closure for the+unreachable g$Bool and g$Unit functions.++The way we fix this is to:+ * In cloneBndr, drop all unfoldings/rules++ * In deFloatTop, run a simple dead code analyser on each top-level+   RHS to drop the dead local bindings. For that call to OccAnal, we+   disable the binder swap, else the occurrence analyser sometimes+   introduces new let bindings for cased binders, which lead to the bug+   in #5433.++The reason we don't just OccAnal the whole output of CorePrep is that+the tidier ensures that all top-level binders are GlobalIds, so they+don't show up in the free variables any longer. So if you run the+occurrence analyser on the output of CoreTidy (or later) you e.g. turn+this program:++  Rec {+  f = ... f ...+  }++Into this one:++  f = ... f ...++(Since f is not considered to be free in its own RHS.)+++************************************************************************+*                                                                      *+                The main code+*                                                                      *+************************************************************************+-}++cpeBind :: TopLevelFlag -> CorePrepEnv -> CoreBind+        -> UniqSM (CorePrepEnv,+                   Floats,         -- Floating value bindings+                   Maybe CoreBind) -- Just bind' <=> returned new bind; no float+                                   -- Nothing <=> added bind' to floats instead+cpeBind top_lvl env (NonRec bndr rhs)+  | not (isJoinId bndr)+  = do { (_, bndr1) <- cpCloneBndr env bndr+       ; let dmd         = idDemandInfo bndr+             is_unlifted = isUnliftedType (idType bndr)+       ; (floats, rhs1) <- cpePair top_lvl NonRecursive+                                   dmd is_unlifted+                                   env bndr1 rhs+       -- See Note [Inlining in CorePrep]+       ; if exprIsTrivial rhs1 && isNotTopLevel top_lvl+            then return (extendCorePrepEnvExpr env bndr rhs1, floats, Nothing)+            else do {++       ; let new_float = mkFloat dmd is_unlifted bndr1 rhs1++       ; return (extendCorePrepEnv env bndr bndr1,+                 addFloat floats new_float,+                 Nothing) }}++  | otherwise -- A join point; see Note [Join points and floating]+  = ASSERT(not (isTopLevel top_lvl)) -- can't have top-level join point+    do { (_, bndr1) <- cpCloneBndr env bndr+       ; (bndr2, rhs1) <- cpeJoinPair env bndr1 rhs+       ; return (extendCorePrepEnv env bndr bndr2,+                 emptyFloats,+                 Just (NonRec bndr2 rhs1)) }++cpeBind top_lvl env (Rec pairs)+  | not (isJoinId (head bndrs))+  = do { (env', bndrs1) <- cpCloneBndrs env bndrs+       ; stuff <- zipWithM (cpePair top_lvl Recursive topDmd False env')+                           bndrs1 rhss++       ; let (floats_s, rhss1) = unzip stuff+             all_pairs = foldrOL add_float (bndrs1 `zip` rhss1)+                                           (concatFloats floats_s)++       ; return (extendCorePrepEnvList env (bndrs `zip` bndrs1),+                 unitFloat (FloatLet (Rec all_pairs)),+                 Nothing) }++  | otherwise -- See Note [Join points and floating]+  = do { (env', bndrs1) <- cpCloneBndrs env bndrs+       ; pairs1 <- zipWithM (cpeJoinPair env') bndrs1 rhss++       ; let bndrs2 = map fst pairs1+       ; return (extendCorePrepEnvList env' (bndrs `zip` bndrs2),+                 emptyFloats,+                 Just (Rec pairs1)) }+  where+    (bndrs, rhss) = unzip pairs++        -- Flatten all the floats, and the current+        -- group into a single giant Rec+    add_float (FloatLet (NonRec b r)) prs2 = (b,r) : prs2+    add_float (FloatLet (Rec prs1))   prs2 = prs1 ++ prs2+    add_float b                       _    = pprPanic "cpeBind" (ppr b)++---------------+cpePair :: TopLevelFlag -> RecFlag -> Demand -> Bool+        -> CorePrepEnv -> OutId -> CoreExpr+        -> UniqSM (Floats, CpeRhs)+-- Used for all bindings+-- The binder is already cloned, hence an OutId+cpePair top_lvl is_rec dmd is_unlifted env bndr rhs+  = ASSERT(not (isJoinId bndr)) -- those should use cpeJoinPair+    do { (floats1, rhs1) <- cpeRhsE env rhs++       -- See if we are allowed to float this stuff out of the RHS+       ; (floats2, rhs2) <- float_from_rhs floats1 rhs1++       -- Make the arity match up+       ; (floats3, rhs3)+            <- if manifestArity rhs1 <= arity+               then return (floats2, cpeEtaExpand arity rhs2)+               else WARN(True, text "CorePrep: silly extra arguments:" <+> ppr bndr)+                               -- Note [Silly extra arguments]+                    (do { v <- newVar (idType bndr)+                        ; let float = mkFloat topDmd False v rhs2+                        ; return ( addFloat floats2 float+                                 , cpeEtaExpand arity (Var v)) })++        -- Wrap floating ticks+       ; let (floats4, rhs4) = wrapTicks floats3 rhs3++       ; return (floats4, rhs4) }+  where+    platform = targetPlatform (cpe_dynFlags env)++    arity = idArity bndr        -- We must match this arity++    ---------------------+    float_from_rhs floats rhs+      | isEmptyFloats floats = return (emptyFloats, rhs)+      | isTopLevel top_lvl   = float_top    floats rhs+      | otherwise            = float_nested floats rhs++    ---------------------+    float_nested floats rhs+      | wantFloatNested is_rec dmd is_unlifted floats rhs+                  = return (floats, rhs)+      | otherwise = dontFloat floats rhs++    ---------------------+    float_top floats rhs        -- Urhgh!  See Note [CafInfo and floating]+      | mayHaveCafRefs (idCafInfo bndr)+      , allLazyTop floats+      = return (floats, rhs)++      -- So the top-level binding is marked NoCafRefs+      | Just (floats', rhs') <- canFloatFromNoCaf platform floats rhs+      = return (floats', rhs')++      | otherwise+      = dontFloat floats rhs++dontFloat :: Floats -> CpeRhs -> UniqSM (Floats, CpeBody)+-- Non-empty floats, but do not want to float from rhs+-- So wrap the rhs in the floats+-- But: rhs1 might have lambdas, and we can't+--      put them inside a wrapBinds+dontFloat floats1 rhs+  = do { (floats2, body) <- rhsToBody rhs+        ; return (emptyFloats, wrapBinds floats1 $+                               wrapBinds floats2 body) }++{- Note [Silly extra arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we had this+        f{arity=1} = \x\y. e+We *must* match the arity on the Id, so we have to generate+        f' = \x\y. e+        f  = \x. f' x++It's a bizarre case: why is the arity on the Id wrong?  Reason+(in the days of __inline_me__):+        f{arity=0} = __inline_me__ (let v = expensive in \xy. e)+When InlineMe notes go away this won't happen any more.  But+it seems good for CorePrep to be robust.+-}++---------------+cpeJoinPair :: CorePrepEnv -> JoinId -> CoreExpr+            -> UniqSM (JoinId, CpeRhs)+-- Used for all join bindings+-- No eta-expansion: see Note [Do not eta-expand join points] in SimplUtils+cpeJoinPair env bndr rhs+  = ASSERT(isJoinId bndr)+    do { let Just join_arity = isJoinId_maybe bndr+             (bndrs, body)   = collectNBinders join_arity rhs++       ; (env', bndrs') <- cpCloneBndrs env bndrs++       ; body' <- cpeBodyNF env' body -- Will let-bind the body if it starts+                                      -- with a lambda++       ; let rhs'  = mkCoreLams bndrs' body'+             bndr' = bndr `setIdUnfolding` evaldUnfolding+                          `setIdArity` count isId bndrs+                            -- See Note [Arity and join points]++       ; return (bndr', rhs') }++{-+Note [Arity and join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Up to now, we've allowed a join point to have an arity greater than its join+arity (minus type arguments), since this is what's useful for eta expansion.+However, for code gen purposes, its arity must be exactly the number of value+arguments it will be called with, and it must have exactly that many value+lambdas. Hence if there are extra lambdas we must let-bind the body of the RHS:++  join j x y z = \w -> ... in ...+    =>+  join j x y z = (let f = \w -> ... in f) in ...++This is also what happens with Note [Silly extra arguments]. Note that it's okay+for us to mess with the arity because a join point is never exported.+-}++-- ---------------------------------------------------------------------------+--              CpeRhs: produces a result satisfying CpeRhs+-- ---------------------------------------------------------------------------++cpeRhsE :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs)+-- If+--      e  ===>  (bs, e')+-- then+--      e = let bs in e'        (semantically, that is!)+--+-- For example+--      f (g x)   ===>   ([v = g x], f v)++cpeRhsE _env expr@(Type {})      = return (emptyFloats, expr)+cpeRhsE _env expr@(Coercion {})  = return (emptyFloats, expr)+cpeRhsE env (Lit (LitNumber LitNumInteger i _))+    = cpeRhsE env (cvtLitInteger (cpe_dynFlags env) (getMkIntegerId env)+                   (cpe_integerSDataCon env) i)+cpeRhsE env (Lit (LitNumber LitNumNatural i _))+    = cpeRhsE env (cvtLitNatural (cpe_dynFlags env) (getMkNaturalId env)+                   (cpe_naturalSDataCon env) i)+cpeRhsE _env expr@(Lit {}) = return (emptyFloats, expr)+cpeRhsE env expr@(Var {})  = cpeApp env expr+cpeRhsE env expr@(App {}) = cpeApp env expr++cpeRhsE env (Let bind body)+  = do { (env', bind_floats, maybe_bind') <- cpeBind NotTopLevel env bind+       ; (body_floats, body') <- cpeRhsE env' body+       ; let expr' = case maybe_bind' of Just bind' -> Let bind' body'+                                         Nothing    -> body'+       ; return (bind_floats `appendFloats` body_floats, expr') }++cpeRhsE env (Tick tickish expr)+  | tickishPlace tickish == PlaceNonLam && tickish `tickishScopesLike` SoftScope+  = do { (floats, body) <- cpeRhsE env expr+         -- See [Floating Ticks in CorePrep]+       ; return (unitFloat (FloatTick tickish) `appendFloats` floats, body) }+  | otherwise+  = do { body <- cpeBodyNF env expr+       ; return (emptyFloats, mkTick tickish' body) }+  where+    tickish' | Breakpoint n fvs <- tickish+             -- See also 'substTickish'+             = Breakpoint n (map (getIdFromTrivialExpr . lookupCorePrepEnv env) fvs)+             | otherwise+             = tickish++cpeRhsE env (Cast expr co)+   = do { (floats, expr') <- cpeRhsE env expr+        ; return (floats, Cast expr' co) }++cpeRhsE env expr@(Lam {})+   = do { let (bndrs,body) = collectBinders expr+        ; (env', bndrs') <- cpCloneBndrs env bndrs+        ; body' <- cpeBodyNF env' body+        ; return (emptyFloats, mkLams bndrs' body') }++cpeRhsE env (Case scrut bndr ty alts)+  = do { (floats, scrut') <- cpeBody env scrut+       ; (env', bndr2) <- cpCloneBndr env bndr+       ; let alts'+                 -- This flag is intended to aid in debugging strictness+                 -- analysis bugs. These are particularly nasty to chase down as+                 -- they may manifest as segmentation faults. When this flag is+                 -- enabled we instead produce an 'error' expression to catch+                 -- the case where a function we think should bottom+                 -- unexpectedly returns.+               | gopt Opt_CatchBottoms (cpe_dynFlags env)+               , not (altsAreExhaustive alts)+               = addDefault alts (Just err)+               | otherwise = alts+               where err = mkRuntimeErrorApp rUNTIME_ERROR_ID ty+                                             "Bottoming expression returned"+       ; alts'' <- mapM (sat_alt env') alts'+       ; return (floats, Case scrut' bndr2 ty alts'') }+  where+    sat_alt env (con, bs, rhs)+       = do { (env2, bs') <- cpCloneBndrs env bs+            ; rhs' <- cpeBodyNF env2 rhs+            ; return (con, bs', rhs') }++cvtLitInteger :: DynFlags -> Id -> Maybe DataCon -> Integer -> CoreExpr+-- Here we convert a literal Integer to the low-level+-- representation. Exactly how we do this depends on the+-- library that implements Integer.  If it's GMP we+-- use the S# data constructor for small literals.+-- See Note [Integer literals] in Literal+cvtLitInteger dflags _ (Just sdatacon) i+  | inIntRange dflags i -- Special case for small integers+    = mkConApp sdatacon [Lit (mkLitInt dflags i)]++cvtLitInteger dflags mk_integer _ i+    = mkApps (Var mk_integer) [isNonNegative, ints]+  where isNonNegative = if i < 0 then mkConApp falseDataCon []+                                 else mkConApp trueDataCon  []+        ints = mkListExpr intTy (f (abs i))+        f 0 = []+        f x = let low  = x .&. mask+                  high = x `shiftR` bits+              in mkConApp intDataCon [Lit (mkLitInt dflags low)] : f high+        bits = 31+        mask = 2 ^ bits - 1++cvtLitNatural :: DynFlags -> Id -> Maybe DataCon -> Integer -> CoreExpr+-- Here we convert a literal Natural to the low-level+-- representation.+-- See Note [Natural literals] in Literal+cvtLitNatural dflags _ (Just sdatacon) i+  | inWordRange dflags i -- Special case for small naturals+    = mkConApp sdatacon [Lit (mkLitWord dflags i)]++cvtLitNatural dflags mk_natural _ i+    = mkApps (Var mk_natural) [words]+  where words = mkListExpr wordTy (f i)+        f 0 = []+        f x = let low  = x .&. mask+                  high = x `shiftR` bits+              in mkConApp wordDataCon [Lit (mkLitWord dflags low)] : f high+        bits = 32+        mask = 2 ^ bits - 1++-- ---------------------------------------------------------------------------+--              CpeBody: produces a result satisfying CpeBody+-- ---------------------------------------------------------------------------++-- | Convert a 'CoreExpr' so it satisfies 'CpeBody', without+-- producing any floats (any generated floats are immediately+-- let-bound using 'wrapBinds').  Generally you want this, esp.+-- when you've reached a binding form (e.g., a lambda) and+-- floating any further would be incorrect.+cpeBodyNF :: CorePrepEnv -> CoreExpr -> UniqSM CpeBody+cpeBodyNF env expr+  = do { (floats, body) <- cpeBody env expr+       ; return (wrapBinds floats body) }++-- | Convert a 'CoreExpr' so it satisfies 'CpeBody'; also produce+-- a list of 'Floats' which are being propagated upwards.  In+-- fact, this function is used in only two cases: to+-- implement 'cpeBodyNF' (which is what you usually want),+-- and in the case when a let-binding is in a case scrutinee--here,+-- we can always float out:+--+--      case (let x = y in z) of ...+--      ==> let x = y in case z of ...+--+cpeBody :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeBody)+cpeBody env expr+  = do { (floats1, rhs) <- cpeRhsE env expr+       ; (floats2, body) <- rhsToBody rhs+       ; return (floats1 `appendFloats` floats2, body) }++--------+rhsToBody :: CpeRhs -> UniqSM (Floats, CpeBody)+-- Remove top level lambdas by let-binding++rhsToBody (Tick t expr)+  | tickishScoped t == NoScope  -- only float out of non-scoped annotations+  = do { (floats, expr') <- rhsToBody expr+       ; return (floats, mkTick t expr') }++rhsToBody (Cast e co)+        -- You can get things like+        --      case e of { p -> coerce t (\s -> ...) }+  = do { (floats, e') <- rhsToBody e+       ; return (floats, Cast e' co) }++rhsToBody expr@(Lam {})+  | Just no_lam_result <- tryEtaReducePrep bndrs body+  = return (emptyFloats, no_lam_result)+  | all isTyVar bndrs           -- Type lambdas are ok+  = return (emptyFloats, expr)+  | otherwise                   -- Some value lambdas+  = do { fn <- newVar (exprType expr)+       ; let rhs   = cpeEtaExpand (exprArity expr) expr+             float = FloatLet (NonRec fn rhs)+       ; return (unitFloat float, Var fn) }+  where+    (bndrs,body) = collectBinders expr++rhsToBody expr = return (emptyFloats, expr)++++-- ---------------------------------------------------------------------------+--              CpeApp: produces a result satisfying CpeApp+-- ---------------------------------------------------------------------------++data ArgInfo = CpeApp  CoreArg+             | CpeCast Coercion+             | CpeTick (Tickish Id)++{- Note [runRW arg]+~~~~~~~~~~~~~~~~~~~+If we got, say+   runRW# (case bot of {})+which happened in #11291, we do /not/ want to turn it into+   (case bot of {}) realWorldPrimId#+because that gives a panic in CoreToStg.myCollectArgs, which expects+only variables in function position.  But if we are sure to make+runRW# strict (which we do in MkId), this can't happen+-}++cpeApp :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs)+-- May return a CpeRhs because of saturating primops+cpeApp top_env expr+  = do { let (terminal, args, depth) = collect_args expr+       ; cpe_app top_env terminal args depth+       }++  where+    -- We have a nested data structure of the form+    -- e `App` a1 `App` a2 ... `App` an, convert it into+    -- (e, [CpeApp a1, CpeApp a2, ..., CpeApp an], depth)+    -- We use 'ArgInfo' because we may also need to+    -- record casts and ticks.  Depth counts the number+    -- of arguments that would consume strictness information+    -- (so, no type or coercion arguments.)+    collect_args :: CoreExpr -> (CoreExpr, [ArgInfo], Int)+    collect_args e = go e [] 0+      where+        go (App fun arg)      as !depth+            = go fun (CpeApp arg : as)+                (if isTyCoArg arg then depth else depth + 1)+        go (Cast fun co)      as depth+            = go fun (CpeCast co : as) depth+        go (Tick tickish fun) as depth+            | tickishPlace tickish == PlaceNonLam+            && tickish `tickishScopesLike` SoftScope+            = go fun (CpeTick tickish : as) depth+        go terminal as depth = (terminal, as, depth)++    cpe_app :: CorePrepEnv+            -> CoreExpr+            -> [ArgInfo]+            -> Int+            -> UniqSM (Floats, CpeRhs)+    cpe_app env (Var f) (CpeApp Type{} : CpeApp arg : args) depth+        | f `hasKey` lazyIdKey          -- Replace (lazy a) with a, and+       || f `hasKey` noinlineIdKey      -- Replace (noinline a) with a+        -- Consider the code:+        --+        --      lazy (f x) y+        --+        -- We need to make sure that we need to recursively collect arguments on+        -- "f x", otherwise we'll float "f x" out (it's not a variable) and+        -- end up with this awful -ddump-prep:+        --+        --      case f x of f_x {+        --        __DEFAULT -> f_x y+        --      }+        --+        -- rather than the far superior "f x y".  Test case is par01.+        = let (terminal, args', depth') = collect_args arg+          in cpe_app env terminal (args' ++ args) (depth + depth' - 1)+    cpe_app env (Var f) [CpeApp _runtimeRep@Type{}, CpeApp _type@Type{}, CpeApp arg] 1+        | f `hasKey` runRWKey+        -- See Note [runRW magic]+        -- Replace (runRW# f) by (f realWorld#), beta reducing if possible (this+        -- is why we return a CorePrepEnv as well)+        = case arg of+            Lam s body -> cpe_app (extendCorePrepEnv env s realWorldPrimId) body [] 0+            _          -> cpe_app env arg [CpeApp (Var realWorldPrimId)] 1+    cpe_app env (Var v) args depth+      = do { v1 <- fiddleCCall v+           ; let e2 = lookupCorePrepEnv env v1+                 hd = getIdFromTrivialExpr_maybe e2+           -- NB: depth from collect_args is right, because e2 is a trivial expression+           -- and thus its embedded Id *must* be at the same depth as any+           -- Apps it is under are type applications only (c.f.+           -- exprIsTrivial).  But note that we need the type of the+           -- expression, not the id.+           ; (app, floats) <- rebuild_app args e2 (exprType e2) emptyFloats stricts+           ; mb_saturate hd app floats depth }+        where+          stricts = case idStrictness v of+                            StrictSig (DmdType _ demands _)+                              | listLengthCmp demands depth /= GT -> demands+                                    -- length demands <= depth+                              | otherwise                         -> []+                -- If depth < length demands, then we have too few args to+                -- satisfy strictness  info so we have to  ignore all the+                -- strictness info, e.g. + (error "urk")+                -- Here, we can't evaluate the arg strictly, because this+                -- partial application might be seq'd++        -- We inlined into something that's not a var and has no args.+        -- Bounce it back up to cpeRhsE.+    cpe_app env fun [] _ = cpeRhsE env fun++        -- N-variable fun, better let-bind it+    cpe_app env fun args depth+      = do { (fun_floats, fun') <- cpeArg env evalDmd fun ty+                          -- The evalDmd says that it's sure to be evaluated,+                          -- so we'll end up case-binding it+           ; (app, floats) <- rebuild_app args fun' ty fun_floats []+           ; mb_saturate Nothing app floats depth }+        where+          ty = exprType fun++    -- Saturate if necessary+    mb_saturate head app floats depth =+       case head of+         Just fn_id -> do { sat_app <- maybeSaturate fn_id app depth+                          ; return (floats, sat_app) }+         _other              -> return (floats, app)++    -- Deconstruct and rebuild the application, floating any non-atomic+    -- arguments to the outside.  We collect the type of the expression,+    -- the head of the application, and the number of actual value arguments,+    -- all of which are used to possibly saturate this application if it+    -- has a constructor or primop at the head.+    rebuild_app+        :: [ArgInfo]                  -- The arguments (inner to outer)+        -> CpeApp+        -> Type+        -> Floats+        -> [Demand]+        -> UniqSM (CpeApp, Floats)+    rebuild_app [] app _ floats ss = do+      MASSERT(null ss) -- make sure we used all the strictness info+      return (app, floats)+    rebuild_app (a : as) fun' fun_ty floats ss = case a of+      CpeApp arg@(Type arg_ty) ->+        rebuild_app as (App fun' arg) (piResultTy fun_ty arg_ty) floats ss+      CpeApp arg@(Coercion {}) ->+        rebuild_app as (App fun' arg) (funResultTy fun_ty) floats ss+      CpeApp arg -> do+        let (ss1, ss_rest)  -- See Note [lazyId magic] in MkId+               = case (ss, isLazyExpr arg) of+                   (_   : ss_rest, True)  -> (topDmd, ss_rest)+                   (ss1 : ss_rest, False) -> (ss1,    ss_rest)+                   ([],            _)     -> (topDmd, [])+            (arg_ty, res_ty) = expectJust "cpeBody:collect_args" $+                               splitFunTy_maybe fun_ty+        (fs, arg') <- cpeArg top_env ss1 arg arg_ty+        rebuild_app as (App fun' arg') res_ty (fs `appendFloats` floats) ss_rest+      CpeCast co ->+        let ty2 = coercionRKind co+        in rebuild_app as (Cast fun' co) ty2 floats ss+      CpeTick tickish ->+        -- See [Floating Ticks in CorePrep]+        rebuild_app as fun' fun_ty (addFloat floats (FloatTick tickish)) ss++isLazyExpr :: CoreExpr -> Bool+-- See Note [lazyId magic] in MkId+isLazyExpr (Cast e _)              = isLazyExpr e+isLazyExpr (Tick _ e)              = isLazyExpr e+isLazyExpr (Var f `App` _ `App` _) = f `hasKey` lazyIdKey+isLazyExpr _                       = False++{- Note [runRW magic]+~~~~~~~~~~~~~~~~~~~~~+Some definitions, for instance @runST@, must have careful control over float out+of the bindings in their body. Consider this use of @runST@,++    f x = runST ( \ s -> let (a, s')  = newArray# 100 [] s+                             (_, s'') = fill_in_array_or_something a x s'+                         in freezeArray# a s'' )++If we inline @runST@, we'll get:++    f x = let (a, s')  = newArray# 100 [] realWorld#{-NB-}+              (_, s'') = fill_in_array_or_something a x s'+          in freezeArray# a s''++And now if we allow the @newArray#@ binding to float out to become a CAF,+we end up with a result that is totally and utterly wrong:++    f = let (a, s')  = newArray# 100 [] realWorld#{-NB-} -- YIKES!!!+        in \ x ->+            let (_, s'') = fill_in_array_or_something a x s'+            in freezeArray# a s''++All calls to @f@ will share a {\em single} array! Clearly this is nonsense and+must be prevented.++This is what @runRW#@ gives us: by being inlined extremely late in the+optimization (right before lowering to STG, in CorePrep), we can ensure that+no further floating will occur. This allows us to safely inline things like+@runST@, which are otherwise needlessly expensive (see #10678 and #5916).++'runRW' is defined (for historical reasons) in GHC.Magic, with a NOINLINE+pragma.  It is levity-polymorphic.++    runRW# :: forall (r1 :: RuntimeRep). (o :: TYPE r)+           => (State# RealWorld -> (# State# RealWorld, o #))+                              -> (# State# RealWorld, o #)++It needs no special treatment in GHC except this special inlining here+in CorePrep (and in ByteCodeGen).++-- ---------------------------------------------------------------------------+--      CpeArg: produces a result satisfying CpeArg+-- ---------------------------------------------------------------------------++Note [ANF-ising literal string arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Consider a program like,++    data Foo = Foo Addr#++    foo = Foo "turtle"#++When we go to ANFise this we might think that we want to float the string+literal like we do any other non-trivial argument. This would look like,++    foo = u\ [] case "turtle"# of s { __DEFAULT__ -> Foo s }++However, this 1) isn't necessary since strings are in a sense "trivial"; and 2)+wreaks havoc on the CAF annotations that we produce here since we the result+above is caffy since it is updateable. Ideally at some point in the future we+would like to just float the literal to the top level as suggested in #11312,++    s = "turtle"#+    foo = Foo s++However, until then we simply add a special case excluding literals from the+floating done by cpeArg.+-}++-- | Is an argument okay to CPE?+okCpeArg :: CoreExpr -> Bool+-- Don't float literals. See Note [ANF-ising literal string arguments].+okCpeArg (Lit _) = False+-- Do not eta expand a trivial argument+okCpeArg expr    = not (exprIsTrivial expr)++-- This is where we arrange that a non-trivial argument is let-bound+cpeArg :: CorePrepEnv -> Demand+       -> CoreArg -> Type -> UniqSM (Floats, CpeArg)+cpeArg env dmd arg arg_ty+  = do { (floats1, arg1) <- cpeRhsE env arg     -- arg1 can be a lambda+       ; (floats2, arg2) <- if want_float floats1 arg1+                            then return (floats1, arg1)+                            else dontFloat floats1 arg1+                -- Else case: arg1 might have lambdas, and we can't+                --            put them inside a wrapBinds++       ; if okCpeArg arg2+         then do { v <- newVar arg_ty+                 ; let arg3      = cpeEtaExpand (exprArity arg2) arg2+                       arg_float = mkFloat dmd is_unlifted v arg3+                 ; return (addFloat floats2 arg_float, varToCoreExpr v) }+         else return (floats2, arg2)+       }+  where+    is_unlifted = isUnliftedType arg_ty+    want_float  = wantFloatNested NonRecursive dmd is_unlifted++{-+Note [Floating unlifted arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider    C (let v* = expensive in v)++where the "*" indicates "will be demanded".  Usually v will have been+inlined by now, but let's suppose it hasn't (see #2756).  Then we+do *not* want to get++     let v* = expensive in C v++because that has different strictness.  Hence the use of 'allLazy'.+(NB: the let v* turns into a FloatCase, in mkLocalNonRec.)+++------------------------------------------------------------------------------+-- Building the saturated syntax+-- ---------------------------------------------------------------------------++Note [Eta expansion of hasNoBinding things in CorePrep]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+maybeSaturate deals with eta expanding to saturate things that can't deal with+unsaturated applications (identified by 'hasNoBinding', currently just+foreign calls and unboxed tuple/sum constructors).++Note that eta expansion in CorePrep is very fragile due to the "prediction" of+CAFfyness made by TidyPgm (see Note [CAFfyness inconsistencies due to eta+expansion in CorePrep] in TidyPgm for details.  We previously saturated primop+applications here as well but due to this fragility (see #16846) we now deal+with this another way, as described in Note [Primop wrappers] in PrimOp.++It's quite likely that eta expansion of constructor applications will+eventually break in a similar way to how primops did. We really should+eliminate this case as well.+-}++maybeSaturate :: Id -> CpeApp -> Int -> UniqSM CpeRhs+maybeSaturate fn expr n_args+  | hasNoBinding fn        -- There's no binding+  = return sat_expr++  | otherwise+  = return expr+  where+    fn_arity     = idArity fn+    excess_arity = fn_arity - n_args+    sat_expr     = cpeEtaExpand excess_arity expr++{-+************************************************************************+*                                                                      *+                Simple CoreSyn operations+*                                                                      *+************************************************************************+-}++{-+-- -----------------------------------------------------------------------------+--      Eta reduction+-- -----------------------------------------------------------------------------++Note [Eta expansion]+~~~~~~~~~~~~~~~~~~~~~+Eta expand to match the arity claimed by the binder Remember,+CorePrep must not change arity++Eta expansion might not have happened already, because it is done by+the simplifier only when there at least one lambda already.++NB1:we could refrain when the RHS is trivial (which can happen+    for exported things).  This would reduce the amount of code+    generated (a little) and make things a little words for+    code compiled without -O.  The case in point is data constructor+    wrappers.++NB2: we have to be careful that the result of etaExpand doesn't+   invalidate any of the assumptions that CorePrep is attempting+   to establish.  One possible cause is eta expanding inside of+   an SCC note - we're now careful in etaExpand to make sure the+   SCC is pushed inside any new lambdas that are generated.++Note [Eta expansion and the CorePrep invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It turns out to be much much easier to do eta expansion+*after* the main CorePrep stuff.  But that places constraints+on the eta expander: given a CpeRhs, it must return a CpeRhs.++For example here is what we do not want:+                f = /\a -> g (h 3)      -- h has arity 2+After ANFing we get+                f = /\a -> let s = h 3 in g s+and now we do NOT want eta expansion to give+                f = /\a -> \ y -> (let s = h 3 in g s) y++Instead CoreArity.etaExpand gives+                f = /\a -> \y -> let s = h 3 in g s y++-}++cpeEtaExpand :: Arity -> CpeRhs -> CpeRhs+cpeEtaExpand arity expr+  | arity == 0 = expr+  | otherwise  = etaExpand arity expr++{-+-- -----------------------------------------------------------------------------+--      Eta reduction+-- -----------------------------------------------------------------------------++Why try eta reduction?  Hasn't the simplifier already done eta?+But the simplifier only eta reduces if that leaves something+trivial (like f, or f Int).  But for deLam it would be enough to+get to a partial application:+        case x of { p -> \xs. map f xs }+    ==> case x of { p -> map f }+-}++-- When updating this function, make sure it lines up with+-- CoreUtils.tryEtaReduce!+tryEtaReducePrep :: [CoreBndr] -> CoreExpr -> Maybe CoreExpr+tryEtaReducePrep bndrs expr@(App _ _)+  | ok_to_eta_reduce f+  , n_remaining >= 0+  , and (zipWith ok bndrs last_args)+  , not (any (`elemVarSet` fvs_remaining) bndrs)+  , exprIsHNF remaining_expr   -- Don't turn value into a non-value+                               -- else the behaviour with 'seq' changes+  = Just remaining_expr+  where+    (f, args) = collectArgs expr+    remaining_expr = mkApps f remaining_args+    fvs_remaining = exprFreeVars remaining_expr+    (remaining_args, last_args) = splitAt n_remaining args+    n_remaining = length args - length bndrs++    ok bndr (Var arg) = bndr == arg+    ok _    _         = False++    -- We can't eta reduce something which must be saturated.+    ok_to_eta_reduce (Var f) = not (hasNoBinding f)+    ok_to_eta_reduce _       = False -- Safe. ToDo: generalise+++tryEtaReducePrep bndrs (Tick tickish e)+  | tickishFloatable tickish+  = fmap (mkTick tickish) $ tryEtaReducePrep bndrs e++tryEtaReducePrep _ _ = Nothing++{-+************************************************************************+*                                                                      *+                Floats+*                                                                      *+************************************************************************++Note [Pin demand info on floats]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We pin demand info on floated lets, so that we can see the one-shot thunks.+-}++data FloatingBind+  = FloatLet CoreBind    -- Rhs of bindings are CpeRhss+                         -- They are always of lifted type;+                         -- unlifted ones are done with FloatCase++ | FloatCase+      Id CpeBody+      Bool              -- The bool indicates "ok-for-speculation"++ -- | See Note [Floating Ticks in CorePrep]+ | FloatTick (Tickish Id)++data Floats = Floats OkToSpec (OrdList FloatingBind)++instance Outputable FloatingBind where+  ppr (FloatLet b) = ppr b+  ppr (FloatCase b r ok) = brackets (ppr ok) <+> ppr b <+> equals <+> ppr r+  ppr (FloatTick t) = ppr t++instance Outputable Floats where+  ppr (Floats flag fs) = text "Floats" <> brackets (ppr flag) <+>+                         braces (vcat (map ppr (fromOL fs)))++instance Outputable OkToSpec where+  ppr OkToSpec    = text "OkToSpec"+  ppr IfUnboxedOk = text "IfUnboxedOk"+  ppr NotOkToSpec = text "NotOkToSpec"++-- Can we float these binds out of the rhs of a let?  We cache this decision+-- to avoid having to recompute it in a non-linear way when there are+-- deeply nested lets.+data OkToSpec+   = OkToSpec           -- Lazy bindings of lifted type+   | IfUnboxedOk        -- A mixture of lazy lifted bindings and n+                        -- ok-to-speculate unlifted bindings+   | NotOkToSpec        -- Some not-ok-to-speculate unlifted bindings++mkFloat :: Demand -> Bool -> Id -> CpeRhs -> FloatingBind+mkFloat dmd is_unlifted bndr rhs+  | use_case  = FloatCase bndr rhs (exprOkForSpeculation rhs)+  | is_hnf    = FloatLet (NonRec bndr                       rhs)+  | otherwise = FloatLet (NonRec (setIdDemandInfo bndr dmd) rhs)+                   -- See Note [Pin demand info on floats]+  where+    is_hnf    = exprIsHNF rhs+    is_strict = isStrictDmd dmd+    use_case  = is_unlifted || is_strict && not is_hnf+                -- Don't make a case for a value binding,+                -- even if it's strict.  Otherwise we get+                --      case (\x -> e) of ...!++emptyFloats :: Floats+emptyFloats = Floats OkToSpec nilOL++isEmptyFloats :: Floats -> Bool+isEmptyFloats (Floats _ bs) = isNilOL bs++wrapBinds :: Floats -> CpeBody -> CpeBody+wrapBinds (Floats _ binds) body+  = foldrOL mk_bind body binds+  where+    mk_bind (FloatCase bndr rhs _) body = mkDefaultCase rhs bndr body+    mk_bind (FloatLet bind)        body = Let bind body+    mk_bind (FloatTick tickish)    body = mkTick tickish body++addFloat :: Floats -> FloatingBind -> Floats+addFloat (Floats ok_to_spec floats) new_float+  = Floats (combine ok_to_spec (check new_float)) (floats `snocOL` new_float)+  where+    check (FloatLet _) = OkToSpec+    check (FloatCase _ _ ok_for_spec)+        | ok_for_spec  =  IfUnboxedOk+        | otherwise    =  NotOkToSpec+    check FloatTick{}  = OkToSpec+        -- The ok-for-speculation flag says that it's safe to+        -- float this Case out of a let, and thereby do it more eagerly+        -- We need the top-level flag because it's never ok to float+        -- an unboxed binding to the top level++unitFloat :: FloatingBind -> Floats+unitFloat = addFloat emptyFloats++appendFloats :: Floats -> Floats -> Floats+appendFloats (Floats spec1 floats1) (Floats spec2 floats2)+  = Floats (combine spec1 spec2) (floats1 `appOL` floats2)++concatFloats :: [Floats] -> OrdList FloatingBind+concatFloats = foldr (\ (Floats _ bs1) bs2 -> appOL bs1 bs2) nilOL++combine :: OkToSpec -> OkToSpec -> OkToSpec+combine NotOkToSpec _ = NotOkToSpec+combine _ NotOkToSpec = NotOkToSpec+combine IfUnboxedOk _ = IfUnboxedOk+combine _ IfUnboxedOk = IfUnboxedOk+combine _ _           = OkToSpec++deFloatTop :: Floats -> [CoreBind]+-- For top level only; we don't expect any FloatCases+deFloatTop (Floats _ floats)+  = foldrOL get [] floats+  where+    get (FloatLet b) bs = occurAnalyseRHSs b : bs+    get (FloatCase var body _) bs  =+      occurAnalyseRHSs (NonRec var body) : bs+    get b _ = pprPanic "corePrepPgm" (ppr b)++    -- See Note [Dead code in CorePrep]+    occurAnalyseRHSs (NonRec x e) = NonRec x (occurAnalyseExpr_NoBinderSwap e)+    occurAnalyseRHSs (Rec xes)    = Rec [(x, occurAnalyseExpr_NoBinderSwap e) | (x, e) <- xes]++---------------------------------------------------------------------------++canFloatFromNoCaf :: Platform -> Floats -> CpeRhs -> Maybe (Floats, CpeRhs)+       -- Note [CafInfo and floating]+canFloatFromNoCaf platform (Floats ok_to_spec fs) rhs+  | OkToSpec <- ok_to_spec           -- Worth trying+  , Just (subst, fs') <- go (emptySubst, nilOL) (fromOL fs)+  = Just (Floats OkToSpec fs', subst_expr subst rhs)+  | otherwise+  = Nothing+  where+    subst_expr = substExpr (text "CorePrep")++    go :: (Subst, OrdList FloatingBind) -> [FloatingBind]+       -> Maybe (Subst, OrdList FloatingBind)++    go (subst, fbs_out) [] = Just (subst, fbs_out)++    go (subst, fbs_out) (FloatLet (NonRec b r) : fbs_in)+      | rhs_ok r+      = go (subst', fbs_out `snocOL` new_fb) fbs_in+      where+        (subst', b') = set_nocaf_bndr subst b+        new_fb = FloatLet (NonRec b' (subst_expr subst r))++    go (subst, fbs_out) (FloatLet (Rec prs) : fbs_in)+      | all rhs_ok rs+      = go (subst', fbs_out `snocOL` new_fb) fbs_in+      where+        (bs,rs) = unzip prs+        (subst', bs') = mapAccumL set_nocaf_bndr subst bs+        rs' = map (subst_expr subst') rs+        new_fb = FloatLet (Rec (bs' `zip` rs'))++    go (subst, fbs_out) (ft@FloatTick{} : fbs_in)+      = go (subst, fbs_out `snocOL` ft) fbs_in++    go _ _ = Nothing      -- Encountered a caffy binding++    ------------+    set_nocaf_bndr subst bndr+      = (extendIdSubst subst bndr (Var bndr'), bndr')+      where+        bndr' = bndr `setIdCafInfo` NoCafRefs++    ------------+    rhs_ok :: CoreExpr -> Bool+    -- We can only float to top level from a NoCaf thing if+    -- the new binding is static. However it can't mention+    -- any non-static things or it would *already* be Caffy+    rhs_ok = rhsIsStatic platform (\_ -> False)+                         (\_nt i -> pprPanic "rhsIsStatic" (integer i))+                         -- Integer or Natural literals should not show up++wantFloatNested :: RecFlag -> Demand -> Bool -> Floats -> CpeRhs -> Bool+wantFloatNested is_rec dmd is_unlifted floats rhs+  =  isEmptyFloats floats+  || isStrictDmd dmd+  || is_unlifted+  || (allLazyNested is_rec floats && exprIsHNF rhs)+        -- Why the test for allLazyNested?+        --      v = f (x `divInt#` y)+        -- we don't want to float the case, even if f has arity 2,+        -- because floating the case would make it evaluated too early++allLazyTop :: Floats -> Bool+allLazyTop (Floats OkToSpec _) = True+allLazyTop _                   = False++allLazyNested :: RecFlag -> Floats -> Bool+allLazyNested _      (Floats OkToSpec    _) = True+allLazyNested _      (Floats NotOkToSpec _) = False+allLazyNested is_rec (Floats IfUnboxedOk _) = isNonRec is_rec++{-+************************************************************************+*                                                                      *+                Cloning+*                                                                      *+************************************************************************+-}++-- ---------------------------------------------------------------------------+--                      The environment+-- ---------------------------------------------------------------------------++-- Note [Inlining in CorePrep]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- There is a subtle but important invariant that must be upheld in the output+-- of CorePrep: there are no "trivial" updatable thunks.  Thus, this Core+-- is impermissible:+--+--      let x :: ()+--          x = y+--+-- (where y is a reference to a GLOBAL variable).  Thunks like this are silly:+-- they can always be profitably replaced by inlining x with y. Consequently,+-- the code generator/runtime does not bother implementing this properly+-- (specifically, there is no implementation of stg_ap_0_upd_info, which is the+-- stack frame that would be used to update this thunk.  The "0" means it has+-- zero free variables.)+--+-- In general, the inliner is good at eliminating these let-bindings.  However,+-- there is one case where these trivial updatable thunks can arise: when+-- we are optimizing away 'lazy' (see Note [lazyId magic], and also+-- 'cpeRhsE'.)  Then, we could have started with:+--+--      let x :: ()+--          x = lazy @ () y+--+-- which is a perfectly fine, non-trivial thunk, but then CorePrep will+-- drop 'lazy', giving us 'x = y' which is trivial and impermissible.+-- The solution is CorePrep to have a miniature inlining pass which deals+-- with cases like this.  We can then drop the let-binding altogether.+--+-- Why does the removal of 'lazy' have to occur in CorePrep?+-- The gory details are in Note [lazyId magic] in MkId, but the+-- main reason is that lazy must appear in unfoldings (optimizer+-- output) and it must prevent call-by-value for catch# (which+-- is implemented by CorePrep.)+--+-- An alternate strategy for solving this problem is to have the+-- inliner treat 'lazy e' as a trivial expression if 'e' is trivial.+-- We decided not to adopt this solution to keep the definition+-- of 'exprIsTrivial' simple.+--+-- There is ONE caveat however: for top-level bindings we have+-- to preserve the binding so that we float the (hacky) non-recursive+-- binding for data constructors; see Note [Data constructor workers].+--+-- Note [CorePrep inlines trivial CoreExpr not Id]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Why does cpe_env need to be an IdEnv CoreExpr, as opposed to an+-- IdEnv Id?  Naively, we might conjecture that trivial updatable thunks+-- as per Note [Inlining in CorePrep] always have the form+-- 'lazy @ SomeType gbl_id'.  But this is not true: the following is+-- perfectly reasonable Core:+--+--      let x :: ()+--          x = lazy @ (forall a. a) y @ Bool+--+-- When we inline 'x' after eliminating 'lazy', we need to replace+-- occurrences of 'x' with 'y @ bool', not just 'y'.  Situations like+-- this can easily arise with higher-rank types; thus, cpe_env must+-- map to CoreExprs, not Ids.++data CorePrepEnv+  = CPE { cpe_dynFlags        :: DynFlags+        , cpe_env             :: IdEnv CoreExpr   -- Clone local Ids+        -- ^ This environment is used for three operations:+        --+        --      1. To support cloning of local Ids so that they are+        --      all unique (see item (6) of CorePrep overview).+        --+        --      2. To support beta-reduction of runRW, see+        --      Note [runRW magic] and Note [runRW arg].+        --+        --      3. To let us inline trivial RHSs of non top-level let-bindings,+        --      see Note [lazyId magic], Note [Inlining in CorePrep]+        --      and Note [CorePrep inlines trivial CoreExpr not Id] (#12076)+        , cpe_mkIntegerId     :: Id+        , cpe_mkNaturalId     :: Id+        , cpe_integerSDataCon :: Maybe DataCon+        , cpe_naturalSDataCon :: Maybe DataCon+    }++lookupMkIntegerName :: DynFlags -> HscEnv -> IO Id+lookupMkIntegerName dflags hsc_env+    = guardIntegerUse dflags $ liftM tyThingId $+      lookupGlobal hsc_env mkIntegerName++lookupMkNaturalName :: DynFlags -> HscEnv -> IO Id+lookupMkNaturalName dflags hsc_env+    = guardNaturalUse dflags $ liftM tyThingId $+      lookupGlobal hsc_env mkNaturalName++-- See Note [The integer library] in PrelNames+lookupIntegerSDataConName :: DynFlags -> HscEnv -> IO (Maybe DataCon)+lookupIntegerSDataConName dflags hsc_env = case integerLibrary dflags of+    IntegerGMP -> guardIntegerUse dflags $ liftM (Just . tyThingDataCon) $+                  lookupGlobal hsc_env integerSDataConName+    IntegerSimple -> return Nothing++lookupNaturalSDataConName :: DynFlags -> HscEnv -> IO (Maybe DataCon)+lookupNaturalSDataConName dflags hsc_env = case integerLibrary dflags of+    IntegerGMP -> guardNaturalUse dflags $ liftM (Just . tyThingDataCon) $+                  lookupGlobal hsc_env naturalSDataConName+    IntegerSimple -> return Nothing++-- | Helper for 'lookupMkIntegerName', 'lookupIntegerSDataConName'+guardIntegerUse :: DynFlags -> IO a -> IO a+guardIntegerUse dflags act+  | thisPackage dflags == primUnitId+  = return $ panic "Can't use Integer in ghc-prim"+  | thisPackage dflags == integerUnitId+  = return $ panic "Can't use Integer in integer-*"+  | otherwise = act++-- | Helper for 'lookupMkNaturalName', 'lookupNaturalSDataConName'+--+-- Just like we can't use Integer literals in `integer-*`, we can't use Natural+-- literals in `base`. If we do, we get interface loading error for GHC.Natural.+guardNaturalUse :: DynFlags -> IO a -> IO a+guardNaturalUse dflags act+  | thisPackage dflags == primUnitId+  = return $ panic "Can't use Natural in ghc-prim"+  | thisPackage dflags == integerUnitId+  = return $ panic "Can't use Natural in integer-*"+  | thisPackage dflags == baseUnitId+  = return $ panic "Can't use Natural in base"+  | otherwise = act++mkInitialCorePrepEnv :: DynFlags -> HscEnv -> IO CorePrepEnv+mkInitialCorePrepEnv dflags hsc_env+    = do mkIntegerId <- lookupMkIntegerName dflags hsc_env+         mkNaturalId <- lookupMkNaturalName dflags hsc_env+         integerSDataCon <- lookupIntegerSDataConName dflags hsc_env+         naturalSDataCon <- lookupNaturalSDataConName dflags hsc_env+         return $ CPE {+                      cpe_dynFlags = dflags,+                      cpe_env = emptyVarEnv,+                      cpe_mkIntegerId = mkIntegerId,+                      cpe_mkNaturalId = mkNaturalId,+                      cpe_integerSDataCon = integerSDataCon,+                      cpe_naturalSDataCon = naturalSDataCon+                  }++extendCorePrepEnv :: CorePrepEnv -> Id -> Id -> CorePrepEnv+extendCorePrepEnv cpe id id'+    = cpe { cpe_env = extendVarEnv (cpe_env cpe) id (Var id') }++extendCorePrepEnvExpr :: CorePrepEnv -> Id -> CoreExpr -> CorePrepEnv+extendCorePrepEnvExpr cpe id expr+    = cpe { cpe_env = extendVarEnv (cpe_env cpe) id expr }++extendCorePrepEnvList :: CorePrepEnv -> [(Id,Id)] -> CorePrepEnv+extendCorePrepEnvList cpe prs+    = cpe { cpe_env = extendVarEnvList (cpe_env cpe)+                        (map (\(id, id') -> (id, Var id')) prs) }++lookupCorePrepEnv :: CorePrepEnv -> Id -> CoreExpr+lookupCorePrepEnv cpe id+  = case lookupVarEnv (cpe_env cpe) id of+        Nothing  -> Var id+        Just exp -> exp++getMkIntegerId :: CorePrepEnv -> Id+getMkIntegerId = cpe_mkIntegerId++getMkNaturalId :: CorePrepEnv -> Id+getMkNaturalId = cpe_mkNaturalId++------------------------------------------------------------------------------+-- Cloning binders+-- ---------------------------------------------------------------------------++cpCloneBndrs :: CorePrepEnv -> [InVar] -> UniqSM (CorePrepEnv, [OutVar])+cpCloneBndrs env bs = mapAccumLM cpCloneBndr env bs++cpCloneBndr  :: CorePrepEnv -> InVar -> UniqSM (CorePrepEnv, OutVar)+cpCloneBndr env bndr+  | not (isId bndr)+  = return (env, bndr)++  | otherwise+  = do { bndr' <- clone_it bndr++       -- Drop (now-useless) rules/unfoldings+       -- See Note [Drop unfoldings and rules]+       -- and Note [Preserve evaluatedness] in CoreTidy+       ; let unfolding' = zapUnfolding (realIdUnfolding bndr)+                          -- Simplifier will set the Id's unfolding++             bndr'' = bndr' `setIdUnfolding`      unfolding'+                            `setIdSpecialisation` emptyRuleInfo++       ; return (extendCorePrepEnv env bndr bndr'', bndr'') }+  where+    clone_it bndr+      | isLocalId bndr, not (isCoVar bndr)+      = do { uniq <- getUniqueM; return (setVarUnique bndr uniq) }+      | otherwise   -- Top level things, which we don't want+                    -- to clone, have become GlobalIds by now+                    -- And we don't clone tyvars, or coercion variables+      = return bndr++{- Note [Drop unfoldings and rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to drop the unfolding/rules on every Id:++  - We are now past interface-file generation, and in the+    codegen pipeline, so we really don't need full unfoldings/rules++  - The unfolding/rule may be keeping stuff alive that we'd like+    to discard.  See  Note [Dead code in CorePrep]++  - Getting rid of unnecessary unfoldings reduces heap usage++  - We are changing uniques, so if we didn't discard unfoldings/rules+    we'd have to substitute in them++HOWEVER, we want to preserve evaluated-ness;+see Note [Preserve evaluatedness] in CoreTidy.+-}++------------------------------------------------------------------------------+-- Cloning ccall Ids; each must have a unique name,+-- to give the code generator a handle to hang it on+-- ---------------------------------------------------------------------------++fiddleCCall :: Id -> UniqSM Id+fiddleCCall id+  | isFCallId id = (id `setVarUnique`) <$> getUniqueM+  | otherwise    = return id++------------------------------------------------------------------------------+-- Generating new binders+-- ---------------------------------------------------------------------------++newVar :: Type -> UniqSM Id+newVar ty+ = seqType ty `seq` do+     uniq <- getUniqueM+     return (mkSysLocalOrCoVar (fsLit "sat") uniq ty)+++------------------------------------------------------------------------------+-- Floating ticks+-- ---------------------------------------------------------------------------+--+-- Note [Floating Ticks in CorePrep]+--+-- It might seem counter-intuitive to float ticks by default, given+-- that we don't actually want to move them if we can help it. On the+-- other hand, nothing gets very far in CorePrep anyway, and we want+-- to preserve the order of let bindings and tick annotations in+-- relation to each other. For example, if we just wrapped let floats+-- when they pass through ticks, we might end up performing the+-- following transformation:+--+--   src<...> let foo = bar in baz+--   ==>  let foo = src<...> bar in src<...> baz+--+-- Because the let-binding would float through the tick, and then+-- immediately materialize, achieving nothing but decreasing tick+-- accuracy. The only special case is the following scenario:+--+--   let foo = src<...> (let a = b in bar) in baz+--   ==>  let foo = src<...> bar; a = src<...> b in baz+--+-- Here we would not want the source tick to end up covering "baz" and+-- therefore refrain from pushing ticks outside. Instead, we copy them+-- into the floating binds (here "a") in cpePair. Note that where "b"+-- or "bar" are (value) lambdas we have to push the annotations+-- further inside in order to uphold our rules.+--+-- All of this is implemented below in @wrapTicks@.++-- | Like wrapFloats, but only wraps tick floats+wrapTicks :: Floats -> CoreExpr -> (Floats, CoreExpr)+wrapTicks (Floats flag floats0) expr =+    (Floats flag (toOL $ reverse floats1), foldr mkTick expr (reverse ticks1))+  where (floats1, ticks1) = foldlOL go ([], []) $ floats0+        -- Deeply nested constructors will produce long lists of+        -- redundant source note floats here. We need to eliminate+        -- those early, as relying on mkTick to spot it after the fact+        -- can yield O(n^3) complexity [#11095]+        go (floats, ticks) (FloatTick t)+          = ASSERT(tickishPlace t == PlaceNonLam)+            (floats, if any (flip tickishContains t) ticks+                     then ticks else t:ticks)+        go (floats, ticks) f+          = (foldr wrap f (reverse ticks):floats, ticks)++        wrap t (FloatLet bind)    = FloatLet (wrapBind t bind)+        wrap t (FloatCase b r ok) = FloatCase b (mkTick t r) ok+        wrap _ other              = pprPanic "wrapTicks: unexpected float!"+                                             (ppr other)+        wrapBind t (NonRec binder rhs) = NonRec binder (mkTick t rhs)+        wrapBind t (Rec pairs)         = Rec (mapSnd (mkTick t) pairs)++------------------------------------------------------------------------------+-- Collecting cost centres+-- ---------------------------------------------------------------------------++-- | Collect cost centres defined in the current module, including those in+-- unfoldings.+collectCostCentres :: Module -> CoreProgram -> S.Set CostCentre+collectCostCentres mod_name+  = foldl' go_bind S.empty+  where+    go cs e = case e of+      Var{} -> cs+      Lit{} -> cs+      App e1 e2 -> go (go cs e1) e2+      Lam _ e -> go cs e+      Let b e -> go (go_bind cs b) e+      Case scrt _ _ alts -> go_alts (go cs scrt) alts+      Cast e _ -> go cs e+      Tick (ProfNote cc _ _) e ->+        go (if ccFromThisModule cc mod_name then S.insert cc cs else cs) e+      Tick _ e -> go cs e+      Type{} -> cs+      Coercion{} -> cs++    go_alts = foldl' (\cs (_con, _bndrs, e) -> go cs e)++    go_bind :: S.Set CostCentre -> CoreBind -> S.Set CostCentre+    go_bind cs (NonRec b e) =+      go (maybe cs (go cs) (get_unf b)) e+    go_bind cs (Rec bs) =+      foldl' (\cs' (b, e) -> go (maybe cs' (go cs') (get_unf b)) e) cs bs++    -- Unfoldings may have cost centres that in the original definion are+    -- optimized away, see #5889.+    get_unf = maybeUnfoldingTemplate . realIdUnfolding
compiler/GHC/HsToCore/PmCheck/Oracle.hs view
@@ -90,14 +90,14 @@   dflags <- getDynFlags   printer <- mkPrintUnqualifiedDs   liftIO $ dumpIfSet_dyn_printer printer dflags-            Opt_D_dump_ec_trace (text herald $$ (nest 2 doc))+            Opt_D_dump_ec_trace "" FormatText (text herald $$ (nest 2 doc))  -- | Generate a fresh `Id` of a given type mkPmId :: Type -> DsM Id mkPmId ty = getUniqueM >>= \unique ->   let occname = mkVarOccFS $ fsLit "pm"       name    = mkInternalName unique occname noSrcSpan-  in  return (mkLocalId name ty)+  in  return (mkLocalIdOrCoVar name ty)  ----------------------------------------------- -- * Caching possible matches of a COMPLETE set@@ -508,7 +508,7 @@   unique <- getUniqueM   let occname = mkVarOccFS (fsLit ("pm_"++show unique))       idname  = mkInternalName unique occname noSrcSpan-  return (mkLocalId idname pred_ty)+  return (mkLocalIdOrCoVar idname pred_ty)  -- | Add some extra type constraints to the 'TyState'; return 'Nothing' if we -- find a contradiction (e.g. @Int ~ Bool@).
+ compiler/GHC/Stg/CSE.hs view
@@ -0,0 +1,483 @@+{-# LANGUAGE TypeFamilies #-}++{-|+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 operationally equivalent), but that we cannot common up in Core, because+their types differ.+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+note [Case 2: CSEing case binders] below.+++Note [Case 1: CSEing allocated closures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+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)++which produces this Core:++    bar :: forall a. a -> (Either Int a, Either Bool a)+    bar @a x = (Right @Int @a x, Right @Bool @a x)++where the two components of the tuple are different terms, and cannot be+commoned up (easily). On the STG level we have++    bar [x] = let c1 = Right [x]+                  c2 = Right [x]+              in (c1,c2)++and now it is obvious that we can write++    bar [x] = let c1 = Right [x]+              in (c1,c1)++instead.+++Note [Case 2: CSEing case binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The second kind of CSE opportunity we aim for is more interesting, and+came up in #9291 and #5344: The Haskell code++    foo :: Either Int a -> Either Bool a+    foo (Right x) = Right x+    foo _         = Left False++produces this Core++    foo :: forall a. Either Int a -> Either Bool a+    foo @a e = case e of b { Left n -> …+                           , Right x -> Right @Bool @a x }++where we cannot CSE `Right @Bool @a x` with the case binder `b` as they have+different types. But in STG we have++    foo [e] = case e of b { Left [n] -> …+                          , Right [x] -> Right [x] }++and nothing stops us from transforming that to++    foo [e] = case e of b { Left [n] -> …+                          , Right [x] -> b}+++Note [StgCse after unarisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider two unboxed sum terms:++    (# 1 | #) :: (# Int | Int# #)+    (# 1 | #) :: (# Int | Int  #)++These two terms are not equal as they unarise to different unboxed+tuples. However if we run StgCse before Unarise, it'll think the two+terms (# 1 | #) are equal, and replace one of these with a binder to+the other. That's bad -- #15300.++Solution: do unarise first.++-}++module GHC.Stg.CSE (stgCse) where++import GhcPrelude++import DataCon+import Id+import GHC.Stg.Syntax+import Outputable+import VarEnv+import CoreSyn (AltCon(..))+import Data.List (mapAccumL)+import Data.Maybe (fromMaybe)+import CoreMap+import NameEnv+import Control.Monad( (>=>) )++--------------+-- The Trie --+--------------++-- A lookup trie for data constructor applications, i.e.+-- keys of type `(DataCon, [StgArg])`, following the patterns in TrieMap.++data StgArgMap a = SAM+    { sam_var :: DVarEnv a+    , sam_lit :: LiteralMap a+    }++instance TrieMap StgArgMap where+    type Key StgArgMap = StgArg+    emptyTM  = SAM { sam_var = emptyTM+                   , sam_lit = emptyTM }+    lookupTM (StgVarArg var) = sam_var >.> lkDFreeVar var+    lookupTM (StgLitArg lit) = sam_lit >.> lookupTM lit+    alterTM  (StgVarArg var) f m = m { sam_var = sam_var m |> xtDFreeVar var f }+    alterTM  (StgLitArg lit) f m = m { sam_lit = sam_lit m |> alterTM lit f }+    foldTM k m = foldTM k (sam_var m) . foldTM k (sam_lit m)+    mapTM f (SAM {sam_var = varm, sam_lit = litm}) =+        SAM { sam_var = mapTM f varm, sam_lit = mapTM f litm }++newtype ConAppMap a = CAM { un_cam :: DNameEnv (ListMap StgArgMap a) }++instance TrieMap ConAppMap where+    type Key ConAppMap = (DataCon, [StgArg])+    emptyTM  = CAM emptyTM+    lookupTM (dataCon, args) = un_cam >.> lkDNamed dataCon >=> lookupTM args+    alterTM  (dataCon, args) f m =+        m { un_cam = un_cam m |> xtDNamed dataCon |>> alterTM args f }+    foldTM k = un_cam >.> foldTM (foldTM k)+    mapTM f  = un_cam >.> mapTM (mapTM f) >.> CAM++-----------------+-- The CSE Env --+-----------------++-- | The CSE environment. See note [CseEnv Example]+data CseEnv = CseEnv+    { ce_conAppMap :: ConAppMap OutId+        -- ^ The main component of the environment is the trie that maps+        --   data constructor applications (with their `OutId` arguments)+        --   to an in-scope name that can be used instead.+        --   This name is always either a let-bound variable or a case binder.+    , ce_subst     :: IdEnv OutId+        -- ^ This substitution is applied to the code as we traverse it.+        --   Entries have one of two reasons:+        --+        --   * The input might have shadowing (see Note [Shadowing]), so we have+        --     to rename some binders as we traverse the tree.+        --   * 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+        --   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]+    , ce_in_scope  :: InScopeSet+        -- ^ The third component is an in-scope set, to rename away any+        --   shadowing binders+    }++{-|+Note [CseEnv Example]+~~~~~~~~~~~~~~~~~~~~~+The following tables shows how the CseEnvironment changes as code is traversed,+as well as the changes to that code.++  InExpr                         OutExpr+     conAppMap                   subst          in_scope+  ───────────────────────────────────────────────────────────+  -- empty                       {}             {}+  case … as a of {Con x y ->     case … as a of {Con x y ->+  -- Con x y ↦ a                 {}             {a,x,y}+  let b = Con x y                (removed)+  -- Con x y ↦ a                 b↦a            {a,x,y,b}+  let c = Bar a                  let c = Bar a+  -- Con x y ↦ a, Bar a ↦ c      b↦a            {a,x,y,b,c}+  let c = some expression        let c' = some expression+  -- Con x y ↦ a, Bar a ↦ c      b↦a, c↦c',     {a,x,y,b,c,c'}+  let d = Bar b                  (removed)+  -- Con x y ↦ a, Bar a ↦ c      b↦a, c↦c', d↦c {a,x,y,b,c,c',d}+  (a, b, c d)                    (a, a, c' c)+-}++initEnv :: InScopeSet -> CseEnv+initEnv in_scope = CseEnv+    { ce_conAppMap = emptyTM+    , ce_subst     = emptyVarEnv+    , ce_bndrMap   = emptyVarEnv+    , ce_in_scope  = in_scope+    }++envLookup :: DataCon -> [OutStgArg] -> CseEnv -> Maybe OutId+envLookup dataCon args env = lookupTM (dataCon, args') (ce_conAppMap env)+  where args' = map go args -- See Note [Trivial case scrutinee]+        go (StgVarArg v  ) = StgVarArg (fromMaybe v $ lookupVarEnv (ce_bndrMap env) v)+        go (StgLitArg lit) = StgLitArg lit++addDataCon :: OutId -> DataCon -> [OutStgArg] -> CseEnv -> CseEnv+-- do not bother with nullary data constructors, they are static anyways+addDataCon _ _ [] env = env+addDataCon bndr dataCon args env = env { ce_conAppMap = new_env }+  where+    new_env = insertTM (dataCon, args) bndr (ce_conAppMap env)++forgetCse :: CseEnv -> CseEnv+forgetCse env = env { ce_conAppMap = emptyTM }+    -- See note [Free variables of an StgClosure]++addSubst :: OutId -> OutId -> CseEnv -> CseEnv+addSubst from to env+    = env { ce_subst = extendVarEnv (ce_subst env) from to }++addTrivCaseBndr :: OutId -> OutId -> CseEnv -> CseEnv+addTrivCaseBndr from to env+    = env { ce_bndrMap = extendVarEnv (ce_bndrMap env) from to }++substArgs :: CseEnv -> [InStgArg] -> [OutStgArg]+substArgs env = map (substArg env)++substArg :: CseEnv -> InStgArg -> OutStgArg+substArg env (StgVarArg from) = StgVarArg (substVar env from)+substArg _   (StgLitArg lit)  = StgLitArg lit++substVar :: CseEnv -> InId -> OutId+substVar env id = fromMaybe id $ lookupVarEnv (ce_subst env) id++-- Functions to enter binders++-- 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.+-- Therefore, no special treatment for a recursive group is required.++substBndr :: CseEnv -> InId -> (CseEnv, OutId)+substBndr env old_id+  = (new_env, new_id)+  where+    new_id = uniqAway (ce_in_scope env) old_id+    no_change = new_id == old_id+    env' = env { ce_in_scope = ce_in_scope env `extendInScopeSet` new_id }+    new_env | no_change = env'+            | otherwise = env' { ce_subst = extendVarEnv (ce_subst env) old_id new_id }++substBndrs :: CseEnv -> [InVar] -> (CseEnv, [OutVar])+substBndrs env bndrs = mapAccumL substBndr env bndrs++substPairs :: CseEnv -> [(InVar, a)] -> (CseEnv, [(OutVar, a)])+substPairs env bndrs = mapAccumL go env bndrs+  where go env (id, x) = let (env', id') = substBndr env id+                         in (env', (id', x))++-- Main entry point++stgCse :: [InStgTopBinding] -> [OutStgTopBinding]+stgCse binds = snd $ mapAccumL stgCseTopLvl emptyInScopeSet binds++-- Top level bindings.+--+-- We do not CSE these, as top-level closures are allocated statically anyways.+-- Also, they might be exported.+-- But we still have to collect the set of in-scope variables, otherwise+-- uniqAway might shadow a top-level closure.++stgCseTopLvl :: InScopeSet -> InStgTopBinding -> (InScopeSet, OutStgTopBinding)+stgCseTopLvl in_scope t@(StgTopStringLit _ _) = (in_scope, t)+stgCseTopLvl in_scope (StgTopLifted (StgNonRec bndr rhs))+    = (in_scope'+      , StgTopLifted (StgNonRec bndr (stgCseTopLvlRhs in_scope rhs)))+  where in_scope' = in_scope `extendInScopeSet` bndr++stgCseTopLvl in_scope (StgTopLifted (StgRec eqs))+    = ( in_scope'+      , StgTopLifted (StgRec [ (bndr, stgCseTopLvlRhs in_scope' rhs) | (bndr, rhs) <- eqs ]))+  where in_scope' = in_scope `extendInScopeSetList` [ bndr | (bndr, _) <- eqs ]++stgCseTopLvlRhs :: InScopeSet -> InStgRhs -> OutStgRhs+stgCseTopLvlRhs in_scope (StgRhsClosure ext ccs upd args body)+    = let body' = stgCseExpr (initEnv in_scope) body+      in  StgRhsClosure ext ccs upd args body'+stgCseTopLvlRhs _ (StgRhsCon ccs dataCon args)+    = StgRhsCon ccs dataCon args++------------------------------+-- The actual AST traversal --+------------------------------++-- Trivial cases+stgCseExpr :: CseEnv -> InStgExpr -> OutStgExpr+stgCseExpr env (StgApp fun args)+    = StgApp fun' args'+  where fun' = substVar env fun+        args' = substArgs env args+stgCseExpr _ (StgLit lit)+    = StgLit lit+stgCseExpr env (StgOpApp op args tys)+    = StgOpApp op args' tys+  where args' = substArgs env args+stgCseExpr _ (StgLam _ _)+    = pprPanic "stgCseExp" (text "StgLam")+stgCseExpr env (StgTick tick body)+    = let body' = stgCseExpr env body+      in StgTick tick body'+stgCseExpr env (StgCase scrut bndr ty alts)+    = mkStgCase scrut' bndr' ty alts'+  where+    scrut' = stgCseExpr env scrut+    (env1, bndr') = substBndr env bndr+    env2 | StgApp trivial_scrut [] <- scrut' = addTrivCaseBndr bndr trivial_scrut env1+                 -- See Note [Trivial case scrutinee]+         | otherwise                         = env1+    alts' = map (stgCseAlt env2 ty bndr') alts+++-- A constructor application.+-- To be removed by a variable use when found in the CSE environment+stgCseExpr env (StgConApp dataCon args tys)+    | Just bndr' <- envLookup dataCon args' env+    = StgApp bndr' []+    | otherwise+    = StgConApp dataCon args' tys+  where args' = substArgs env args++-- Let bindings+-- The binding might be removed due to CSE (we do not want trivial bindings on+-- the STG level), so use the smart constructor `mkStgLet` to remove the binding+-- if empty.+stgCseExpr env (StgLet ext binds body)+    = let (binds', env') = stgCseBind env binds+          body' = stgCseExpr env' body+      in mkStgLet (StgLet ext) binds' body'+stgCseExpr env (StgLetNoEscape ext binds body)+    = let (binds', env') = stgCseBind env binds+          body' = stgCseExpr env' body+      in mkStgLet (StgLetNoEscape ext) binds' body'++-- Case alternatives+-- Extend the CSE environment+stgCseAlt :: CseEnv -> AltType -> OutId -> InStgAlt -> OutStgAlt+stgCseAlt env ty case_bndr (DataAlt dataCon, args, rhs)+    = let (env1, args') = substBndrs env args+          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)+    = let (env1, args') = substBndrs env args+          rhs' = stgCseExpr env1 rhs+      in (altCon, args', rhs')++-- Bindings+stgCseBind :: CseEnv -> InStgBinding -> (Maybe OutStgBinding, CseEnv)+stgCseBind env (StgNonRec b e)+    = let (env1, b') = substBndr env b+      in case stgCseRhs env1 b' e of+        (Nothing,      env2) -> (Nothing,                env2)+        (Just (b2,e'), env2) -> (Just (StgNonRec b2 e'), env2)+stgCseBind env (StgRec pairs)+    = let (env1, pairs1) = substPairs env pairs+      in case stgCsePairs env1 pairs1 of+        ([],     env2) -> (Nothing, env2)+        (pairs2, env2) -> (Just (StgRec pairs2), env2)++stgCsePairs :: CseEnv -> [(OutId, InStgRhs)] -> ([(OutId, OutStgRhs)], CseEnv)+stgCsePairs env [] = ([], env)+stgCsePairs env0 ((b,e):pairs)+  = let (pairMB, env1) = stgCseRhs env0 b e+        (pairs', env2) = stgCsePairs env1 pairs+    in (pairMB `mbCons` pairs', env2)+  where+    mbCons = maybe id (:)++-- The RHS of a binding.+-- 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+    = let env' = addSubst bndr other_bndr env+      in (Nothing, env')+    | otherwise+    = let env' = addDataCon bndr dataCon args' env+            -- see note [Case 1: CSEing allocated closures]+          pair = (bndr, StgRhsCon ccs dataCon args')+      in (Just pair, env')+  where args' = substArgs env args+stgCseRhs env bndr (StgRhsClosure ext ccs upd args body)+    = let (env1, args') = substBndrs env args+          env2 = forgetCse env1 -- See note [Free variables of an StgClosure]+          body' = stgCseExpr env2 body+      in (Just (substVar env bndr, StgRhsClosure ext ccs upd args' body'), env)+++mkStgCase :: StgExpr -> OutId -> AltType -> [StgAlt] -> StgExpr+mkStgCase scrut bndr ty alts | all isBndr alts = scrut+                             | otherwise       = StgCase scrut bndr ty alts++  where+    -- see Note [All alternatives are the binder]+    isBndr (_, _, StgApp f []) = f == bndr+    isBndr _                   = False+++-- Utilities++-- | This function short-cuts let-bindings that are now obsolete+mkStgLet :: (a -> b -> b) -> Maybe a -> b -> b+mkStgLet _      Nothing      body = body+mkStgLet stgLet (Just binds) body = stgLet binds body+++{-+Note [All alternatives are the binder]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++When all alternatives simply refer to the case binder, then we do not have+to bother with the case expression at all (#13588). CoreSTG does this as well,+but sometimes, types get into the way:++    newtype T = MkT Int+    f :: (Int, Int) -> (T, Int)+    f (x, y) = (MkT x, y)++Core cannot just turn this into++    f p = p++as this would not be well-typed. But to STG, where MkT is no longer in the way,+we can.++Note [Trivial case scrutinee]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to be able to handle nested reconstruction of constructors as in++    nested :: Either Int (Either Int a) -> Either Bool (Either Bool a)+    nested (Right (Right v)) = Right (Right v)+    nested _ = Left True++So if we come across++    case x of r1+      Right a -> case a of r2+              Right b -> let v = Right b+                         in Right v++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 substitution before looking Right r2 up in ce_conAppMap, and everything+works out.++Note [Free variables of an StgClosure]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+StgClosures (function and thunks) have an explicit list of free variables:++foo [x] =+    let not_a_free_var = Left [x]+    let a_free_var = Right [x]+    let closure = \[x a_free_var] -> \[y] -> bar y (Left [x]) a_free_var+    in closure++If we were to CSE `Left [x]` in the body of `closure` with `not_a_free_var`,+then the list of free variables would be wrong, so for now, we do not CSE+across such a closure, simply because I (Joachim) was not sure about possible+knock-on effects. If deemed safe and worth the slight code complication of+re-calculating this list during or after this pass, this can surely be done.+-}
+ compiler/GHC/Stg/FVs.hs view
@@ -0,0 +1,130 @@+-- | Free variable analysis on STG terms.+module GHC.Stg.FVs (+    annTopBindingsFreeVars,+    annBindingFreeVars+  ) where++import GhcPrelude++import GHC.Stg.Syntax+import Id+import VarSet+import CoreSyn    ( Tickish(Breakpoint) )+import Outputable+import Util++import Data.Maybe ( mapMaybe )++newtype Env+  = Env+  { locals :: IdSet+  }++emptyEnv :: Env+emptyEnv = Env emptyVarSet++addLocals :: [Id] -> Env -> Env+addLocals bndrs env+  = env { locals = extendVarSetList (locals env) bndrs }++-- | Annotates a top-level STG binding group with its free variables.+annTopBindingsFreeVars :: [StgTopBinding] -> [CgStgTopBinding]+annTopBindingsFreeVars = map go+  where+    go (StgTopStringLit id bs) = StgTopStringLit id bs+    go (StgTopLifted bind)+      = StgTopLifted (annBindingFreeVars bind)++-- | Annotates an STG binding with its free variables.+annBindingFreeVars :: StgBinding -> CgStgBinding+annBindingFreeVars = fst . binding emptyEnv emptyDVarSet++boundIds :: StgBinding -> [Id]+boundIds (StgNonRec b _) = [b]+boundIds (StgRec pairs)  = map fst pairs++-- Note [Tracking local binders]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- 'locals' contains non-toplevel, non-imported binders.+-- We maintain the set in 'expr', 'alt' and 'rhs', which are the only+-- places where new local binders are introduced.+-- Why do it there rather than in 'binding'? Two reasons:+--+--   1. We call 'binding' from 'annTopBindingsFreeVars', which would+--      add top-level bindings to the 'locals' set.+--   2. In the let(-no-escape) case, we need to extend the environment+--      prior to analysing the body, but we also need the fvs from the+--      body to analyse the RHSs. No way to do this without some+--      knot-tying.++-- | This makes sure that only local, non-global free vars make it into the set.+mkFreeVarSet :: Env -> [Id] -> DIdSet+mkFreeVarSet env = mkDVarSet . filter (`elemVarSet` locals env)++args :: Env -> [StgArg] -> DIdSet+args env = mkFreeVarSet env . mapMaybe f+  where+    f (StgVarArg occ) = Just occ+    f _               = Nothing++binding :: Env -> DIdSet -> StgBinding -> (CgStgBinding, DIdSet)+binding env body_fv (StgNonRec bndr r) = (StgNonRec bndr r', fvs)+  where+    -- See Note [Tracking local binders]+    (r', rhs_fvs) = rhs env r+    fvs = delDVarSet body_fv bndr `unionDVarSet` rhs_fvs+binding env body_fv (StgRec pairs) = (StgRec pairs', fvs)+  where+    -- See Note [Tracking local binders]+    bndrs = map fst pairs+    (rhss, rhs_fvss) = mapAndUnzip (rhs env . snd) pairs+    pairs' = zip bndrs rhss+    fvs = delDVarSetList (unionDVarSets (body_fv:rhs_fvss)) bndrs++expr :: Env -> StgExpr -> (CgStgExpr, DIdSet)+expr env = go+  where+    go (StgApp occ as)+      = (StgApp occ as, unionDVarSet (args env as) (mkFreeVarSet env [occ]))+    go (StgLit lit) = (StgLit lit, emptyDVarSet)+    go (StgConApp dc as tys) = (StgConApp dc as tys, args env as)+    go (StgOpApp op as ty) = (StgOpApp op as ty, args env as)+    go StgLam{} = pprPanic "StgFVs: StgLam" empty+    go (StgCase scrut bndr ty alts) = (StgCase scrut' bndr ty alts', fvs)+      where+        (scrut', scrut_fvs) = go scrut+        -- See Note [Tracking local binders]+        (alts', alt_fvss) = mapAndUnzip (alt (addLocals [bndr] env)) alts+        alt_fvs = unionDVarSets alt_fvss+        fvs = delDVarSet (unionDVarSet scrut_fvs alt_fvs) bndr+    go (StgLet ext bind body) = go_bind (StgLet ext) bind body+    go (StgLetNoEscape ext bind body) = go_bind (StgLetNoEscape ext) bind body+    go (StgTick tick e) = (StgTick tick e', fvs')+      where+        (e', fvs) = go e+        fvs' = unionDVarSet (tickish tick) fvs+        tickish (Breakpoint _ ids) = mkDVarSet ids+        tickish _                  = emptyDVarSet++    go_bind dc bind body = (dc bind' body', fvs)+      where+        -- See Note [Tracking local binders]+        env' = addLocals (boundIds bind) env+        (body', body_fvs) = expr env' body+        (bind', fvs) = binding env' body_fvs bind++rhs :: Env -> StgRhs -> (CgStgRhs, DIdSet)+rhs env (StgRhsClosure _ ccs uf bndrs body)+  = (StgRhsClosure fvs ccs uf bndrs body', fvs)+  where+    -- See Note [Tracking local binders]+    (body', body_fvs) = expr (addLocals bndrs env) body+    fvs = delDVarSetList body_fvs bndrs+rhs env (StgRhsCon ccs dc as) = (StgRhsCon ccs dc as, args env as)++alt :: Env -> StgAlt -> (CgStgAlt, DIdSet)+alt env (con, bndrs, e) = ((con, bndrs, e'), fvs)+  where+    -- See Note [Tracking local binders]+    (e', rhs_fvs) = expr (addLocals bndrs env) e+    fvs = delDVarSetList rhs_fvs bndrs
+ compiler/GHC/Stg/Lift.hs view
@@ -0,0 +1,258 @@+{-# LANGUAGE CPP #-}++-- | Implements a selective lambda lifter, running late in the optimisation+-- pipeline.+--+-- If you are interested in the cost model that is employed to decide whether+-- to lift a binding or not, look at "GHC.Stg.Lift.Analysis".+-- "GHC.Stg.Lift.Monad" contains the transformation monad that hides away some+-- plumbing of the transformation.+module GHC.Stg.Lift+   (+    -- * Late lambda lifting in STG+    -- $note+   stgLiftLams+   )+where++#include "HsVersions.h"++import GhcPrelude++import BasicTypes+import DynFlags+import Id+import IdInfo+import GHC.Stg.FVs ( annBindingFreeVars )+import GHC.Stg.Lift.Analysis+import GHC.Stg.Lift.Monad+import GHC.Stg.Syntax+import Outputable+import UniqSupply+import Util+import VarSet+import Control.Monad ( when )+import Data.Maybe ( isNothing )++-- Note [Late lambda lifting in STG]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- $note+-- See also the <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page>+-- and #9476.+--+-- The basic idea behind lambda lifting is to turn locally defined functions+-- into top-level functions. Free variables are then passed as additional+-- arguments at *call sites* instead of having a closure allocated for them at+-- *definition site*. Example:+--+-- @+--    let x = ...; y = ... in+--    let f = {x y} \a -> a + x + y in+--    let g = {f x} \b -> f b + x in+--    g 5+-- @+--+-- Lambda lifting @f@ would+--+--   1. Turn @f@'s free variables into formal parameters+--   2. Update @f@'s call site within @g@ to @f x y b@+--   3. Update @g@'s closure: Add @y@ as an additional free variable, while+--      removing @f@, because @f@ no longer allocates and can be floated to+--      top-level.+--   4. Actually float the binding of @f@ to top-level, eliminating the @let@+--      in the process.+--+-- This results in the following program (with free var annotations):+--+-- @+--    f x y a = a + x + y;+--    let x = ...; y = ... in+--    let g = {x y} \b -> f x y b + x in+--    g 5+-- @+--+-- This optimisation is all about lifting only when it is beneficial to do so.+-- The above seems like a worthwhile lift, judging from heap allocation:+-- We eliminate @f@'s closure, saving to allocate a closure with 2 words, while+-- not changing the size of @g@'s closure.+--+-- You can probably sense that there's some kind of cost model at play here.+-- And you are right! But we also employ a couple of other heuristics for the+-- lifting decision which are outlined in "GHC.Stg.Lift.Analysis#when".+--+-- The transformation is done in "GHC.Stg.Lift", which calls out to+-- 'GHC.Stg.Lift.Analysis.goodToLift' for its lifting decision.  It relies on+-- "GHC.Stg.Lift.Monad", which abstracts some subtle STG invariants into a+-- monadic substrate.+--+-- Suffice to say: We trade heap allocation for stack allocation.+-- The additional arguments have to passed on the stack (or in registers,+-- depending on architecture) every time we call the function to save a single+-- heap allocation when entering the let binding. Nofib suggests a mean+-- improvement of about 1% for this pass, so it seems like a worthwhile thing to+-- do. Compile-times went up by 0.6%, so all in all a very modest change.+--+-- For a concrete example, look at @spectral/atom@. There's a call to 'zipWith'+-- that is ultimately compiled to something like this+-- (module desugaring/lowering to actual STG):+--+-- @+--    propagate dt = ...;+--    runExperiment ... =+--      let xs = ... in+--      let ys = ... in+--      let go = {dt go} \xs ys -> case (xs, ys) of+--            ([], []) -> []+--            (x:xs', y:ys') -> propagate dt x y : go xs' ys'+--      in go xs ys+-- @+--+-- This will lambda lift @go@ to top-level, speeding up the resulting program+-- by roughly one percent:+--+-- @+--    propagate dt = ...;+--    go dt xs ys = case (xs, ys) of+--      ([], []) -> []+--      (x:xs', y:ys') -> propagate dt x y : go dt xs' ys'+--    runExperiment ... =+--      let xs = ... in+--      let ys = ... in+--      in go dt xs ys+-- @++++-- | Lambda lifts bindings to top-level deemed worth lifting (see 'goodToLift').+--+-- (Mostly) textbook instance of the lambda lifting transformation, selecting+-- which bindings to lambda lift by consulting 'goodToLift'.+stgLiftLams :: DynFlags -> UniqSupply -> [InStgTopBinding] -> [OutStgTopBinding]+stgLiftLams dflags us = runLiftM dflags us . foldr liftTopLvl (pure ())++liftTopLvl :: InStgTopBinding -> LiftM () -> LiftM ()+liftTopLvl (StgTopStringLit bndr lit) rest = withSubstBndr bndr $ \bndr' -> do+  addTopStringLit bndr' lit+  rest+liftTopLvl (StgTopLifted bind) rest = do+  let is_rec = isRec $ fst $ decomposeStgBinding bind+  when is_rec startBindingGroup+  let bind_w_fvs = annBindingFreeVars bind+  withLiftedBind TopLevel (tagSkeletonTopBind bind_w_fvs) NilSk $ \mb_bind' -> do+    -- We signal lifting of a binding through returning Nothing.+    -- Should never happen for a top-level binding, though, since we are already+    -- at top-level.+    case mb_bind' of+      Nothing -> pprPanic "StgLiftLams" (text "Lifted top-level binding")+      Just bind' -> addLiftedBinding bind'+    when is_rec endBindingGroup+    rest++withLiftedBind+  :: TopLevelFlag+  -> LlStgBinding+  -> Skeleton+  -> (Maybe OutStgBinding -> LiftM a)+  -> LiftM a+withLiftedBind top_lvl bind scope k+  | isTopLevel top_lvl+  = withCaffyness (is_caffy pairs) go+  | otherwise+  = go+  where+    (rec, pairs) = decomposeStgBinding bind+    is_caffy = any (mayHaveCafRefs . idCafInfo . binderInfoBndr . fst)+    go = withLiftedBindPairs top_lvl rec pairs scope (k . fmap (mkStgBinding rec))++withLiftedBindPairs+  :: TopLevelFlag+  -> RecFlag+  -> [(BinderInfo, LlStgRhs)]+  -> Skeleton+  -> (Maybe [(Id, OutStgRhs)] -> LiftM a)+  -> LiftM a+withLiftedBindPairs top rec pairs scope k = do+  let (infos, rhss) = unzip pairs+  let bndrs = map binderInfoBndr infos+  expander <- liftedIdsExpander+  dflags <- getDynFlags+  case goodToLift dflags top rec expander pairs scope of+    -- @abs_ids@ is the set of all variables that need to become parameters.+    Just abs_ids -> withLiftedBndrs abs_ids bndrs $ \bndrs' -> do+      -- Within this block, all binders in @bndrs@ will be noted as lifted, so+      -- that the return value of @liftedIdsExpander@ in this context will also+      -- expand the bindings in @bndrs@ to their free variables.+      -- Now we can recurse into the RHSs and see if we can lift any further+      -- bindings. We pass the set of expanded free variables (thus OutIds) on+      -- to @liftRhs@ so that it can add them as parameter binders.+      when (isRec rec) startBindingGroup+      rhss' <- traverse (liftRhs (Just abs_ids)) rhss+      let pairs' = zip bndrs' rhss'+      addLiftedBinding (mkStgBinding rec pairs')+      when (isRec rec) endBindingGroup+      k Nothing+    Nothing -> withSubstBndrs bndrs $ \bndrs' -> do+      -- Don't lift the current binding, but possibly some bindings in their+      -- RHSs.+      rhss' <- traverse (liftRhs Nothing) rhss+      let pairs' = zip bndrs' rhss'+      k (Just pairs')++liftRhs+  :: Maybe (DIdSet)+  -- ^ @Just former_fvs@ <=> this RHS was lifted and we have to add @former_fvs@+  -- as lambda binders, discarding all free vars.+  -> LlStgRhs+  -> LiftM OutStgRhs+liftRhs mb_former_fvs rhs@(StgRhsCon ccs con args)+  = ASSERT2(isNothing mb_former_fvs, text "Should never lift a constructor" $$ ppr rhs)+    StgRhsCon ccs con <$> traverse liftArgs args+liftRhs Nothing (StgRhsClosure _ ccs upd infos body) = do+  -- This RHS wasn't lifted.+  withSubstBndrs (map binderInfoBndr infos) $ \bndrs' ->+    StgRhsClosure noExtFieldSilent ccs upd bndrs' <$> liftExpr body+liftRhs (Just former_fvs) (StgRhsClosure _ ccs upd infos body) = do+  -- This RHS was lifted. Insert extra binders for @former_fvs@.+  withSubstBndrs (map binderInfoBndr infos) $ \bndrs' -> do+    let bndrs'' = dVarSetElems former_fvs ++ bndrs'+    StgRhsClosure noExtFieldSilent ccs upd bndrs'' <$> liftExpr body++liftArgs :: InStgArg -> LiftM OutStgArg+liftArgs a@(StgLitArg _) = pure a+liftArgs (StgVarArg occ) = do+  ASSERTM2( not <$> isLifted occ, text "StgArgs should never be lifted" $$ ppr occ )+  StgVarArg <$> substOcc occ++liftExpr :: LlStgExpr -> LiftM OutStgExpr+liftExpr (StgLit lit) = pure (StgLit lit)+liftExpr (StgTick t e) = StgTick t <$> liftExpr e+liftExpr (StgApp f args) = do+  f' <- substOcc f+  args' <- traverse liftArgs args+  fvs' <- formerFreeVars f+  let top_lvl_args = map StgVarArg fvs' ++ args'+  pure (StgApp f' top_lvl_args)+liftExpr (StgConApp con args tys) = StgConApp con <$> traverse liftArgs args <*> pure tys+liftExpr (StgOpApp op args ty) = StgOpApp op <$> traverse liftArgs args <*> pure ty+liftExpr (StgLam _ _) = pprPanic "stgLiftLams" (text "StgLam")+liftExpr (StgCase scrut info ty alts) = do+  scrut' <- liftExpr scrut+  withSubstBndr (binderInfoBndr info) $ \bndr' -> do+    alts' <- traverse liftAlt alts+    pure (StgCase scrut' bndr' ty alts')+liftExpr (StgLet scope bind body)+  = withLiftedBind NotTopLevel bind scope $ \mb_bind' -> do+      body' <- liftExpr body+      case mb_bind' of+        Nothing -> pure body' -- withLiftedBindPairs decided to lift it and already added floats+        Just bind' -> pure (StgLet noExtFieldSilent bind' body')+liftExpr (StgLetNoEscape scope bind body)+  = withLiftedBind NotTopLevel bind scope $ \mb_bind' -> do+      body' <- liftExpr body+      case mb_bind' of+        Nothing -> pprPanic "stgLiftLams" (text "Should never decide to lift LNEs")+        Just bind' -> pure (StgLetNoEscape noExtFieldSilent bind' body')++liftAlt :: LlStgAlt -> LiftM OutStgAlt+liftAlt (con, infos, rhs) = withSubstBndrs (map binderInfoBndr infos) $ \bndrs' ->+  (,,) con bndrs' <$> liftExpr rhs
+ compiler/GHC/Stg/Lift/Analysis.hs view
@@ -0,0 +1,565 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DataKinds #-}++-- | Provides the heuristics for when it's beneficial to lambda lift bindings.+-- Most significantly, this employs a cost model to estimate impact on heap+-- allocations, by looking at an STG expression's 'Skeleton'.+module GHC.Stg.Lift.Analysis (+    -- * #when# When to lift+    -- $when++    -- * #clogro# Estimating closure growth+    -- $clogro++    -- * AST annotation+    Skeleton(..), BinderInfo(..), binderInfoBndr,+    LlStgBinding, LlStgExpr, LlStgRhs, LlStgAlt, tagSkeletonTopBind,+    -- * Lifting decision+    goodToLift,+    closureGrowth -- Exported just for the docs+  ) where++import GhcPrelude++import BasicTypes+import Demand+import DynFlags+import Id+import SMRep ( WordOff )+import GHC.Stg.Syntax+import qualified GHC.StgToCmm.ArgRep  as StgToCmm.ArgRep+import qualified GHC.StgToCmm.Closure as StgToCmm.Closure+import qualified GHC.StgToCmm.Layout  as StgToCmm.Layout+import Outputable+import Util+import VarSet++import Data.Maybe ( mapMaybe )++-- Note [When to lift]+-- ~~~~~~~~~~~~~~~~~~~+-- $when+-- The analysis proceeds in two steps:+--+--   1. It tags the syntax tree with analysis information in the form of+--      'BinderInfo' at each binder and 'Skeleton's at each let-binding+--      by 'tagSkeletonTopBind' and friends.+--   2. The resulting syntax tree is treated by the "GHC.Stg.Lift"+--      module, calling out to 'goodToLift' to decide if a binding is worthwhile+--      to lift.+--      'goodToLift' consults argument occurrence information in 'BinderInfo'+--      and estimates 'closureGrowth', for which it needs the 'Skeleton'.+--+-- So the annotations from 'tagSkeletonTopBind' ultimately fuel 'goodToLift',+-- which employs a number of heuristics to identify and exclude lambda lifting+-- opportunities deemed non-beneficial:+--+--  [Top-level bindings] can't be lifted.+--  [Thunks] and data constructors shouldn't be lifted in order not to destroy+--    sharing.+--  [Argument occurrences] #arg_occs# of binders prohibit them to be lifted.+--    Doing the lift would re-introduce the very allocation at call sites that+--    we tried to get rid off in the first place. We capture analysis+--    information in 'BinderInfo'. Note that we also consider a nullary+--    application as argument occurrence, because it would turn into an n-ary+--    partial application created by a generic apply function. This occurs in+--    CPS-heavy code like the CS benchmark.+--  [Join points] should not be lifted, simply because there's no reduction in+--    allocation to be had.+--  [Abstracting over join points] destroys join points, because they end up as+--    arguments to the lifted function.+--  [Abstracting over known local functions] turns a known call into an unknown+--    call (e.g. some @stg_ap_*@), which is generally slower. Can be turned off+--    with @-fstg-lift-lams-known@.+--  [Calling convention] Don't lift when the resulting function would have a+--    higher arity than available argument registers for the calling convention.+--    Can be influenced with @-fstg-lift-(non)rec-args(-any)@.+--  [Closure growth] introduced when former free variables have to be available+--    at call sites may actually lead to an increase in overall allocations+--  resulting from a lift. Estimating closure growth is described in+--  "GHC.Stg.Lift.Analysis#clogro" and is what most of this module is ultimately+--  concerned with.+--+-- There's a <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page> with+-- some more background and history.++-- Note [Estimating closure growth]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- $clogro+-- We estimate closure growth by abstracting the syntax tree into a 'Skeleton',+-- capturing only syntactic details relevant to 'closureGrowth', such as+--+--   * 'ClosureSk', representing closure allocation.+--   * 'RhsSk', representing a RHS of a binding and how many times it's called+--     by an appropriate 'DmdShell'.+--   * 'AltSk', 'BothSk' and 'NilSk' for choice, sequence and empty element.+--+-- This abstraction is mostly so that the main analysis function 'closureGrowth'+-- can stay simple and focused. Also, skeletons tend to be much smaller than+-- the syntax tree they abstract, so it makes sense to construct them once and+-- and operate on them instead of the actual syntax tree.+--+-- A more detailed treatment of computing closure growth, including examples,+-- can be found in the paper referenced from the+-- <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page>.++llTrace :: String -> SDoc -> a -> a+llTrace _ _ c = c+-- llTrace a b c = pprTrace a b c++type instance BinderP      'LiftLams = BinderInfo+type instance XRhsClosure  'LiftLams = DIdSet+type instance XLet         'LiftLams = Skeleton+type instance XLetNoEscape 'LiftLams = Skeleton++freeVarsOfRhs :: (XRhsClosure pass ~ DIdSet) => GenStgRhs pass -> DIdSet+freeVarsOfRhs (StgRhsCon _ _ args) = mkDVarSet [ id | StgVarArg id <- args ]+freeVarsOfRhs (StgRhsClosure fvs _ _ _ _) = fvs++-- | Captures details of the syntax tree relevant to the cost model, such as+-- closures, multi-shot lambdas and case expressions.+data Skeleton+  = ClosureSk !Id !DIdSet {- ^ free vars -} !Skeleton+  | RhsSk !DmdShell {- ^ how often the RHS was entered -} !Skeleton+  | AltSk !Skeleton !Skeleton+  | BothSk !Skeleton !Skeleton+  | NilSk++bothSk :: Skeleton -> Skeleton -> Skeleton+bothSk NilSk b = b+bothSk a NilSk = a+bothSk a b     = BothSk a b++altSk :: Skeleton -> Skeleton -> Skeleton+altSk NilSk b = b+altSk a NilSk = a+altSk a b     = AltSk a b++rhsSk :: DmdShell -> Skeleton -> Skeleton+rhsSk _        NilSk = NilSk+rhsSk body_dmd skel  = RhsSk body_dmd skel++-- | The type used in binder positions in 'GenStgExpr's.+data BinderInfo+  = BindsClosure !Id !Bool -- ^ Let(-no-escape)-bound thing with a flag+                           --   indicating whether it occurs as an argument+                           --   or in a nullary application+                           --   (see "GHC.Stg.Lift.Analysis#arg_occs").+  | BoringBinder !Id       -- ^ Every other kind of binder++-- | Gets the bound 'Id' out a 'BinderInfo'.+binderInfoBndr :: BinderInfo -> Id+binderInfoBndr (BoringBinder bndr)   = bndr+binderInfoBndr (BindsClosure bndr _) = bndr++-- | Returns 'Nothing' for 'BoringBinder's and 'Just' the flag indicating+-- occurrences as argument or in a nullary applications otherwise.+binderInfoOccursAsArg :: BinderInfo -> Maybe Bool+binderInfoOccursAsArg BoringBinder{}     = Nothing+binderInfoOccursAsArg (BindsClosure _ b) = Just b++instance Outputable Skeleton where+  ppr NilSk = text ""+  ppr (AltSk l r) = vcat+    [ text "{ " <+> ppr l+    , text "ALT"+    , text "  " <+> ppr r+    , text "}"+    ]+  ppr (BothSk l r) = ppr l $$ ppr r+  ppr (ClosureSk f fvs body) = ppr f <+> ppr fvs $$ nest 2 (ppr body)+  ppr (RhsSk body_dmd body) = hcat+    [ text "λ["+    , ppr str+    , text ", "+    , ppr use+    , text "]. "+    , ppr body+    ]+    where+      str+        | isStrictDmd body_dmd = '1'+        | otherwise = '0'+      use+        | isAbsDmd body_dmd = '0'+        | isUsedOnce body_dmd = '1'+        | otherwise = 'ω'++instance Outputable BinderInfo where+  ppr = ppr . binderInfoBndr++instance OutputableBndr BinderInfo where+  pprBndr b = pprBndr b . binderInfoBndr+  pprPrefixOcc = pprPrefixOcc . binderInfoBndr+  pprInfixOcc = pprInfixOcc . binderInfoBndr+  bndrIsJoin_maybe = bndrIsJoin_maybe . binderInfoBndr++mkArgOccs :: [StgArg] -> IdSet+mkArgOccs = mkVarSet . mapMaybe stg_arg_var+  where+    stg_arg_var (StgVarArg occ) = Just occ+    stg_arg_var _               = Nothing++-- | Tags every binder with its 'BinderInfo' and let bindings with their+-- 'Skeleton's.+tagSkeletonTopBind :: CgStgBinding -> LlStgBinding+-- NilSk is OK when tagging top-level bindings. Also, top-level things are never+-- lambda-lifted, so no need to track their argument occurrences. They can also+-- never be let-no-escapes (thus we pass False).+tagSkeletonTopBind bind = bind'+  where+    (_, _, _, bind') = tagSkeletonBinding False NilSk emptyVarSet bind++-- | Tags binders of an 'StgExpr' with its 'BinderInfo' and let bindings with+-- their 'Skeleton's. Additionally, returns its 'Skeleton' and the set of binder+-- occurrences in argument and nullary application position+-- (cf. "GHC.Stg.Lift.Analysis#arg_occs").+tagSkeletonExpr :: CgStgExpr -> (Skeleton, IdSet, LlStgExpr)+tagSkeletonExpr (StgLit lit)+  = (NilSk, emptyVarSet, StgLit lit)+tagSkeletonExpr (StgConApp con args tys)+  = (NilSk, mkArgOccs args, StgConApp con args tys)+tagSkeletonExpr (StgOpApp op args ty)+  = (NilSk, mkArgOccs args, StgOpApp op args ty)+tagSkeletonExpr (StgApp f args)+  = (NilSk, arg_occs, StgApp f args)+  where+    arg_occs+      -- This checks for nullary applications, which we treat the same as+      -- argument occurrences, see "GHC.Stg.Lift.Analysis#arg_occs".+      | null args = unitVarSet f+      | otherwise = mkArgOccs args+tagSkeletonExpr (StgLam _ _) = pprPanic "stgLiftLams" (text "StgLam")+tagSkeletonExpr (StgCase scrut bndr ty alts)+  = (skel, arg_occs, StgCase scrut' bndr' ty alts')+  where+    (scrut_skel, scrut_arg_occs, scrut') = tagSkeletonExpr scrut+    (alt_skels, alt_arg_occss, alts') = mapAndUnzip3 tagSkeletonAlt alts+    skel = bothSk scrut_skel (foldr altSk NilSk alt_skels)+    arg_occs = unionVarSets (scrut_arg_occs:alt_arg_occss) `delVarSet` bndr+    bndr' = BoringBinder bndr+tagSkeletonExpr (StgTick t e)+  = (skel, arg_occs, StgTick t e')+  where+    (skel, arg_occs, e') = tagSkeletonExpr e+tagSkeletonExpr (StgLet _ bind body) = tagSkeletonLet False body bind+tagSkeletonExpr (StgLetNoEscape _ bind body) = tagSkeletonLet True body bind++mkLet :: Bool -> Skeleton -> LlStgBinding -> LlStgExpr -> LlStgExpr+mkLet True = StgLetNoEscape+mkLet _    = StgLet++tagSkeletonLet+  :: Bool+  -- ^ Is the binding a let-no-escape?+  -> CgStgExpr+  -- ^ Let body+  -> CgStgBinding+  -- ^ Binding group+  -> (Skeleton, IdSet, LlStgExpr)+  -- ^ RHS skeletons, argument occurrences and annotated binding+tagSkeletonLet is_lne body bind+  = (let_skel, arg_occs, mkLet is_lne scope bind' body')+  where+    (body_skel, body_arg_occs, body') = tagSkeletonExpr body+    (let_skel, arg_occs, scope, bind')+      = tagSkeletonBinding is_lne body_skel body_arg_occs bind++tagSkeletonBinding+  :: Bool+  -- ^ Is the binding a let-no-escape?+  -> Skeleton+  -- ^ Let body skeleton+  -> IdSet+  -- ^ Argument occurrences in the body+  -> CgStgBinding+  -- ^ Binding group+  -> (Skeleton, IdSet, Skeleton, LlStgBinding)+  -- ^ Let skeleton, argument occurrences, scope skeleton of binding and+  --   the annotated binding+tagSkeletonBinding is_lne body_skel body_arg_occs (StgNonRec bndr rhs)+  = (let_skel, arg_occs, scope, bind')+  where+    (rhs_skel, rhs_arg_occs, rhs') = tagSkeletonRhs bndr rhs+    arg_occs = (body_arg_occs `unionVarSet` rhs_arg_occs) `delVarSet` bndr+    bind_skel+      | is_lne    = rhs_skel -- no closure is allocated for let-no-escapes+      | otherwise = ClosureSk bndr (freeVarsOfRhs rhs) rhs_skel+    let_skel = bothSk body_skel bind_skel+    occurs_as_arg = bndr `elemVarSet` body_arg_occs+    -- Compared to the recursive case, this exploits the fact that @bndr@ is+    -- never free in @rhs@.+    scope = body_skel+    bind' = StgNonRec (BindsClosure bndr occurs_as_arg) rhs'+tagSkeletonBinding is_lne body_skel body_arg_occs (StgRec pairs)+  = (let_skel, arg_occs, scope, StgRec pairs')+  where+    (bndrs, _) = unzip pairs+    -- Local recursive STG bindings also regard the defined binders as free+    -- vars. We want to delete those for our cost model, as these are known+    -- calls anyway when we add them to the same top-level recursive group as+    -- the top-level binding currently being analysed.+    skel_occs_rhss' = map (uncurry tagSkeletonRhs) pairs+    rhss_arg_occs = map sndOf3 skel_occs_rhss'+    scope_occs = unionVarSets (body_arg_occs:rhss_arg_occs)+    arg_occs = scope_occs `delVarSetList` bndrs+    -- @skel_rhss@ aren't yet wrapped in closures. We'll do that in a moment,+    -- but we also need the un-wrapped skeletons for calculating the @scope@+    -- of the group, as the outer closures don't contribute to closure growth+    -- when we lift this specific binding.+    scope = foldr (bothSk . fstOf3) body_skel skel_occs_rhss'+    -- Now we can build the actual Skeleton for the expression just by+    -- iterating over each bind pair.+    (bind_skels, pairs') = unzip (zipWith single_bind bndrs skel_occs_rhss')+    let_skel = foldr bothSk body_skel bind_skels+    single_bind bndr (skel_rhs, _, rhs') = (bind_skel, (bndr', rhs'))+      where+        -- Here, we finally add the closure around each @skel_rhs@.+        bind_skel+          | is_lne    = skel_rhs -- no closure is allocated for let-no-escapes+          | otherwise = ClosureSk bndr fvs skel_rhs+        fvs = freeVarsOfRhs rhs' `dVarSetMinusVarSet` mkVarSet bndrs+        bndr' = BindsClosure bndr (bndr `elemVarSet` scope_occs)++tagSkeletonRhs :: Id -> CgStgRhs -> (Skeleton, IdSet, LlStgRhs)+tagSkeletonRhs _ (StgRhsCon ccs dc args)+  = (NilSk, mkArgOccs args, StgRhsCon ccs dc args)+tagSkeletonRhs bndr (StgRhsClosure fvs ccs upd bndrs body)+  = (rhs_skel, body_arg_occs, StgRhsClosure fvs ccs upd bndrs' body')+  where+    bndrs' = map BoringBinder bndrs+    (body_skel, body_arg_occs, body') = tagSkeletonExpr body+    rhs_skel = rhsSk (rhsDmdShell bndr) body_skel++-- | How many times will the lambda body of the RHS bound to the given+-- identifier be evaluated, relative to its defining context? This function+-- computes the answer in form of a 'DmdShell'.+rhsDmdShell :: Id -> DmdShell+rhsDmdShell bndr+  | is_thunk = oneifyDmd ds+  | otherwise = peelManyCalls (idArity bndr) cd+  where+    is_thunk = idArity bndr == 0+    -- Let's pray idDemandInfo is still OK after unarise...+    (ds, cd) = toCleanDmd (idDemandInfo bndr)++tagSkeletonAlt :: CgStgAlt -> (Skeleton, IdSet, LlStgAlt)+tagSkeletonAlt (con, bndrs, rhs)+  = (alt_skel, arg_occs, (con, map BoringBinder bndrs, rhs'))+  where+    (alt_skel, alt_arg_occs, rhs') = tagSkeletonExpr rhs+    arg_occs = alt_arg_occs `delVarSetList` bndrs++-- | Combines several heuristics to decide whether to lambda-lift a given+-- @let@-binding to top-level. See "GHC.Stg.Lift.Analysis#when" for details.+goodToLift+  :: DynFlags+  -> TopLevelFlag+  -> RecFlag+  -> (DIdSet -> DIdSet) -- ^ An expander function, turning 'InId's into+                        -- 'OutId's. See 'GHC.Stg.Lift.Monad.liftedIdsExpander'.+  -> [(BinderInfo, LlStgRhs)]+  -> Skeleton+  -> Maybe DIdSet       -- ^ @Just abs_ids@ <=> This binding is beneficial to+                        -- lift and @abs_ids@ are the variables it would+                        -- abstract over+goodToLift dflags top_lvl rec_flag expander pairs scope = decide+  [ ("top-level", isTopLevel top_lvl) -- keep in sync with Note [When to lift]+  , ("memoized", any_memoized)+  , ("argument occurrences", arg_occs)+  , ("join point", is_join_point)+  , ("abstracts join points", abstracts_join_ids)+  , ("abstracts known local function", abstracts_known_local_fun)+  , ("args spill on stack", args_spill_on_stack)+  , ("increases allocation", inc_allocs)+  ] where+      decide deciders+        | not (fancy_or deciders)+        = llTrace "stgLiftLams:lifting"+                  (ppr bndrs <+> ppr abs_ids $$+                   ppr allocs $$+                   ppr scope) $+          Just abs_ids+        | otherwise+        = Nothing+      ppr_deciders = vcat . map (text . fst) . filter snd+      fancy_or deciders+        = llTrace "stgLiftLams:goodToLift" (ppr bndrs $$ ppr_deciders deciders) $+          any snd deciders++      bndrs = map (binderInfoBndr . fst) pairs+      bndrs_set = mkVarSet bndrs+      rhss = map snd pairs++      -- First objective: Calculate @abs_ids@, e.g. the former free variables+      -- the lifted binding would abstract over. We have to merge the free+      -- variables of all RHS to get the set of variables that will have to be+      -- passed through parameters.+      fvs = unionDVarSets (map freeVarsOfRhs rhss)+      -- To lift the binding to top-level, we want to delete the lifted binders+      -- themselves from the free var set. Local let bindings track recursive+      -- occurrences in their free variable set. We neither want to apply our+      -- cost model to them (see 'tagSkeletonRhs'), nor pass them as parameters+      -- when lifted, as these are known calls. We call the resulting set the+      -- identifiers we abstract over, thus @abs_ids@. These are all 'OutId's.+      -- We will save the set in 'LiftM.e_expansions' for each of the variables+      -- if we perform the lift.+      abs_ids = expander (delDVarSetList fvs bndrs)++      -- We don't lift updatable thunks or constructors+      any_memoized = any is_memoized_rhs rhss+      is_memoized_rhs StgRhsCon{} = True+      is_memoized_rhs (StgRhsClosure _ _ upd _ _) = isUpdatable upd++      -- Don't lift binders occurring as arguments. This would result in complex+      -- argument expressions which would have to be given a name, reintroducing+      -- the very allocation at each call site that we wanted to get rid off in+      -- the first place.+      arg_occs = or (mapMaybe (binderInfoOccursAsArg . fst) pairs)++      -- These don't allocate anyway.+      is_join_point = any isJoinId bndrs++      -- Abstracting over join points/let-no-escapes spoils them.+      abstracts_join_ids = any isJoinId (dVarSetElems abs_ids)++      -- Abstracting over known local functions that aren't floated themselves+      -- turns a known, fast call into an unknown, slow call:+      --+      --    let f x = ...+      --        g y = ... f x ... -- this was a known call+      --    in g 4+      --+      -- After lifting @g@, but not @f@:+      --+      --    l_g f y = ... f y ... -- this is now an unknown call+      --    let f x = ...+      --    in l_g f 4+      --+      -- We can abuse the results of arity analysis for this:+      -- idArity f > 0 ==> known+      known_fun id = idArity id > 0+      abstracts_known_local_fun+        = not (liftLamsKnown dflags) && any known_fun (dVarSetElems abs_ids)++      -- Number of arguments of a RHS in the current binding group if we decide+      -- to lift it+      n_args+        = length+        . StgToCmm.Closure.nonVoidIds -- void parameters don't appear in Cmm+        . (dVarSetElems abs_ids ++)+        . rhsLambdaBndrs+      max_n_args+        | isRec rec_flag = liftLamsRecArgs dflags+        | otherwise      = liftLamsNonRecArgs dflags+      -- We have 5 hardware registers on x86_64 to pass arguments in. Any excess+      -- args are passed on the stack, which means slow memory accesses+      args_spill_on_stack+        | Just n <- max_n_args = maximum (map n_args rhss) > n+        | otherwise = False++      -- We only perform the lift if allocations didn't increase.+      -- Note that @clo_growth@ will be 'infinity' if there was positive growth+      -- under a multi-shot lambda.+      -- Also, abstracting over LNEs is unacceptable. LNEs might return+      -- unlifted tuples, which idClosureFootprint can't cope with.+      inc_allocs = abstracts_join_ids || allocs > 0+      allocs = clo_growth + mkIntWithInf (negate closuresSize)+      -- We calculate and then add up the size of each binding's closure.+      -- GHC does not currently share closure environments, and we either lift+      -- the entire recursive binding group or none of it.+      closuresSize = sum $ flip map rhss $ \rhs ->+        closureSize dflags+        . dVarSetElems+        . expander+        . flip dVarSetMinusVarSet bndrs_set+        $ freeVarsOfRhs rhs+      clo_growth = closureGrowth expander (idClosureFootprint dflags) bndrs_set abs_ids scope++rhsLambdaBndrs :: LlStgRhs -> [Id]+rhsLambdaBndrs StgRhsCon{} = []+rhsLambdaBndrs (StgRhsClosure _ _ _ bndrs _) = map binderInfoBndr bndrs++-- | The size in words of a function closure closing over the given 'Id's,+-- including the header.+closureSize :: DynFlags -> [Id] -> WordOff+closureSize dflags ids = words + sTD_HDR_SIZE dflags+  -- We go through sTD_HDR_SIZE rather than fixedHdrSizeW so that we don't+  -- optimise differently when profiling is enabled.+  where+    (words, _, _)+      -- Functions have a StdHeader (as opposed to ThunkHeader).+      = StgToCmm.Layout.mkVirtHeapOffsets dflags StgToCmm.Layout.StdHeader+      . StgToCmm.Closure.addIdReps+      . StgToCmm.Closure.nonVoidIds+      $ ids++-- | The number of words a single 'Id' adds to a closure's size.+-- Note that this can't handle unboxed tuples (which may still be present in+-- let-no-escapes, even after Unarise), in which case+-- @'GHC.StgToCmm.Closure.idPrimRep'@ will crash.+idClosureFootprint:: DynFlags -> Id -> WordOff+idClosureFootprint dflags+  = StgToCmm.ArgRep.argRepSizeW dflags+  . StgToCmm.ArgRep.idArgRep++-- | @closureGrowth expander sizer f fvs@ computes the closure growth in words+-- as a result of lifting @f@ to top-level. If there was any growing closure+-- under a multi-shot lambda, the result will be 'infinity'.+-- Also see "GHC.Stg.Lift.Analysis#clogro".+closureGrowth+  :: (DIdSet -> DIdSet)+  -- ^ Expands outer free ids that were lifted to their free vars+  -> (Id -> Int)+  -- ^ Computes the closure footprint of an identifier+  -> IdSet+  -- ^ Binding group for which lifting is to be decided+  -> DIdSet+  -- ^ Free vars of the whole binding group prior to lifting it. These must be+  --   available at call sites if we decide to lift the binding group.+  -> Skeleton+  -- ^ Abstraction of the scope of the function+  -> IntWithInf+  -- ^ Closure growth. 'infinity' indicates there was growth under a+  --   (multi-shot) lambda.+closureGrowth expander sizer group abs_ids = go+  where+    go NilSk = 0+    go (BothSk a b) = go a + go b+    go (AltSk a b) = max (go a) (go b)+    go (ClosureSk _ clo_fvs rhs)+      -- If no binder of the @group@ occurs free in the closure, the lifting+      -- won't have any effect on it and we can omit the recursive call.+      | n_occs == 0 = 0+      -- Otherwise, we account the cost of allocating the closure and add it to+      -- the closure growth of its RHS.+      | otherwise   = mkIntWithInf cost + go rhs+      where+        n_occs = sizeDVarSet (clo_fvs' `dVarSetIntersectVarSet` group)+        -- What we close over considering prior lifting decisions+        clo_fvs' = expander clo_fvs+        -- Variables that would additionally occur free in the closure body if+        -- we lift @f@+        newbies = abs_ids `minusDVarSet` clo_fvs'+        -- Lifting @f@ removes @f@ from the closure but adds all @newbies@+        cost = foldDVarSet (\id size -> sizer id + size) 0 newbies - n_occs+    go (RhsSk body_dmd body)+      -- The conservative assumption would be that+      --   1. Every RHS with positive growth would be called multiple times,+      --      modulo thunks.+      --   2. Every RHS with negative growth wouldn't be called at all.+      --+      -- In the first case, we'd have to return 'infinity', while in the+      -- second case, we'd have to return 0. But we can do far better+      -- considering information from the demand analyser, which provides us+      -- with conservative estimates on minimum and maximum evaluation+      -- cardinality. The @body_dmd@ part of 'RhsSk' is the result of+      -- 'rhsDmdShell' and accurately captures the cardinality of the RHSs body+      -- relative to its defining context.+      | isAbsDmd body_dmd   = 0+      | cg <= 0             = if isStrictDmd body_dmd then cg else 0+      | isUsedOnce body_dmd = cg+      | otherwise           = infinity+      where+        cg = go body
+ compiler/GHC/Stg/Lift/Monad.hs view
@@ -0,0 +1,348 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies #-}++-- | Hides away distracting bookkeeping while lambda lifting into a 'LiftM'+-- monad.+module GHC.Stg.Lift.Monad (+    decomposeStgBinding, mkStgBinding,+    Env (..),+    -- * #floats# Handling floats+    -- $floats+    FloatLang (..), collectFloats, -- Exported just for the docs+    -- * Transformation monad+    LiftM, runLiftM, withCaffyness,+    -- ** Adding bindings+    startBindingGroup, endBindingGroup, addTopStringLit, addLiftedBinding,+    -- ** Substitution and binders+    withSubstBndr, withSubstBndrs, withLiftedBndr, withLiftedBndrs,+    -- ** Occurrences+    substOcc, isLifted, formerFreeVars, liftedIdsExpander+  ) where++#include "HsVersions.h"++import GhcPrelude++import BasicTypes+import CostCentre ( isCurrentCCS, dontCareCCS )+import DynFlags+import FastString+import Id+import IdInfo+import Name+import Outputable+import OrdList+import GHC.Stg.Subst+import GHC.Stg.Syntax+import Type+import UniqSupply+import Util+import VarEnv+import VarSet++import Control.Arrow ( second )+import Control.Monad.Trans.Class+import Control.Monad.Trans.RWS.Strict ( RWST, runRWST )+import qualified Control.Monad.Trans.RWS.Strict as RWS+import Control.Monad.Trans.Cont ( ContT (..) )+import Data.ByteString ( ByteString )++-- | @uncurry 'mkStgBinding' . 'decomposeStgBinding' = id@+decomposeStgBinding :: GenStgBinding pass -> (RecFlag, [(BinderP pass, GenStgRhs pass)])+decomposeStgBinding (StgRec pairs) = (Recursive, pairs)+decomposeStgBinding (StgNonRec bndr rhs) = (NonRecursive, [(bndr, rhs)])++mkStgBinding :: RecFlag -> [(BinderP pass, GenStgRhs pass)] -> GenStgBinding pass+mkStgBinding Recursive = StgRec+mkStgBinding NonRecursive = uncurry StgNonRec . head++-- | Environment threaded around in a scoped, @Reader@-like fashion.+data Env+  = Env+  { e_dflags     :: !DynFlags+  -- ^ Read-only.+  , e_subst      :: !Subst+  -- ^ We need to track the renamings of local 'InId's to their lifted 'OutId',+  -- because shadowing might make a closure's free variables unavailable at its+  -- call sites. Consider:+  -- @+  --    let f y = x + y in let x = 4 in f x+  -- @+  -- Here, @f@ can't be lifted to top-level, because its free variable @x@ isn't+  -- available at its call site.+  , e_expansions :: !(IdEnv DIdSet)+  -- ^ Lifted 'Id's don't occur as free variables in any closure anymore, because+  -- they are bound at the top-level. Every occurrence must supply the formerly+  -- free variables of the lifted 'Id', so they in turn become free variables of+  -- the call sites. This environment tracks this expansion from lifted 'Id's to+  -- their free variables.+  --+  -- 'InId's to 'OutId's.+  --+  -- Invariant: 'Id's not present in this map won't be substituted.+  , e_in_caffy_context :: !Bool+  -- ^ Are we currently analysing within a caffy context (e.g. the containing+  -- top-level binder's 'idCafInfo' is 'MayHaveCafRefs')? If not, we can safely+  -- assume that functions we lift out aren't caffy either.+  }++emptyEnv :: DynFlags -> Env+emptyEnv dflags = Env dflags emptySubst emptyVarEnv False+++-- Note [Handling floats]+-- ~~~~~~~~~~~~~~~~~~~~~~+-- $floats+-- Consider the following expression:+--+-- @+--     f x =+--       let g y = ... f y ...+--       in g x+-- @+--+-- What happens when we want to lift @g@? Normally, we'd put the lifted @l_g@+-- binding above the binding for @f@:+--+-- @+--     g f y = ... f y ...+--     f x = g f x+-- @+--+-- But this very unnecessarily turns a known call to @f@ into an unknown one, in+-- addition to complicating matters for the analysis.+-- Instead, we'd really like to put both functions in the same recursive group,+-- thereby preserving the known call:+--+-- @+--     Rec {+--       g y = ... f y ...+--       f x = g x+--     }+-- @+--+-- But we don't want this to happen for just /any/ binding. That would create+-- possibly huge recursive groups in the process, calling for an occurrence+-- analyser on STG.+-- So, we need to track when we lift a binding out of a recursive RHS and add+-- the binding to the same recursive group as the enclosing recursive binding+-- (which must have either already been at the top-level or decided to be+-- lifted itself in order to preserve the known call).+--+-- This is done by expressing this kind of nesting structure as a 'Writer' over+-- @['FloatLang']@ and flattening this expression in 'runLiftM' by a call to+-- 'collectFloats'.+-- API-wise, the analysis will not need to know about the whole 'FloatLang'+-- business and will just manipulate it indirectly through actions in 'LiftM'.++-- | We need to detect when we are lifting something out of the RHS of a+-- recursive binding (c.f. "GHC.Stg.Lift.Monad#floats"), in which case that+-- binding needs to be added to the same top-level recursive group. This+-- requires we detect a certain nesting structure, which is encoded by+-- 'StartBindingGroup' and 'EndBindingGroup'.+--+-- Although 'collectFloats' will only ever care if the current binding to be+-- lifted (through 'LiftedBinding') will occur inside such a binding group or+-- not, e.g. doesn't care about the nesting level as long as its greater than 0.+data FloatLang+  = StartBindingGroup+  | EndBindingGroup+  | PlainTopBinding OutStgTopBinding+  | LiftedBinding OutStgBinding++instance Outputable FloatLang where+  ppr StartBindingGroup = char '('+  ppr EndBindingGroup = char ')'+  ppr (PlainTopBinding StgTopStringLit{}) = text "<str>"+  ppr (PlainTopBinding (StgTopLifted b)) = ppr (LiftedBinding b)+  ppr (LiftedBinding bind) = (if isRec rec then char 'r' else char 'n') <+> ppr (map fst pairs)+    where+      (rec, pairs) = decomposeStgBinding bind++-- | Flattens an expression in @['FloatLang']@ into an STG program, see #floats.+-- Important pre-conditions: The nesting of opening 'StartBindinGroup's and+-- closing 'EndBindinGroup's is balanced. Also, it is crucial that every binding+-- group has at least one recursive binding inside. Otherwise there's no point+-- in announcing the binding group in the first place and an @ASSERT@ will+-- trigger.+collectFloats :: [FloatLang] -> [OutStgTopBinding]+collectFloats = go (0 :: Int) []+  where+    go 0 [] [] = []+    go _ _ [] = pprPanic "collectFloats" (text "unterminated group")+    go n binds (f:rest) = case f of+      StartBindingGroup -> go (n+1) binds rest+      EndBindingGroup+        | n == 0 -> pprPanic "collectFloats" (text "no group to end")+        | n == 1 -> StgTopLifted (merge_binds binds) : go 0 [] rest+        | otherwise -> go (n-1) binds rest+      PlainTopBinding top_bind+        | n == 0 -> top_bind : go n binds rest+        | otherwise -> pprPanic "collectFloats" (text "plain top binding inside group")+      LiftedBinding bind+        | n == 0 -> StgTopLifted (rm_cccs bind) : go n binds rest+        | otherwise -> go n (bind:binds) rest++    map_rhss f = uncurry mkStgBinding . second (map (second f)) . decomposeStgBinding+    rm_cccs = map_rhss removeRhsCCCS+    merge_binds binds = ASSERT( any is_rec binds )+                        StgRec (concatMap (snd . decomposeStgBinding . rm_cccs) binds)+    is_rec StgRec{} = True+    is_rec _ = False++-- | Omitting this makes for strange closure allocation schemes that crash the+-- GC.+removeRhsCCCS :: GenStgRhs pass -> GenStgRhs pass+removeRhsCCCS (StgRhsClosure ext ccs upd bndrs body)+  | isCurrentCCS ccs+  = StgRhsClosure ext dontCareCCS upd bndrs body+removeRhsCCCS (StgRhsCon ccs con args)+  | isCurrentCCS ccs+  = StgRhsCon dontCareCCS con args+removeRhsCCCS rhs = rhs++-- | The analysis monad consists of the following 'RWST' components:+--+--     * 'Env': Reader-like context. Contains a substitution, info about how+--       how lifted identifiers are to be expanded into applications and details+--       such as 'DynFlags' and a flag helping with determining if a lifted+--       binding is caffy.+--+--     * @'OrdList' 'FloatLang'@: Writer output for the resulting STG program.+--+--     * No pure state component+--+--     * But wrapping around 'UniqSM' for generating fresh lifted binders.+--       (The @uniqAway@ approach could give the same name to two different+--       lifted binders, so this is necessary.)+newtype LiftM a+  = LiftM { unwrapLiftM :: RWST Env (OrdList FloatLang) () UniqSM a }+  deriving (Functor, Applicative, Monad)++instance HasDynFlags LiftM where+  getDynFlags = LiftM (RWS.asks e_dflags)++instance MonadUnique LiftM where+  getUniqueSupplyM = LiftM (lift getUniqueSupplyM)+  getUniqueM = LiftM (lift getUniqueM)+  getUniquesM = LiftM (lift getUniquesM)++runLiftM :: DynFlags -> UniqSupply -> LiftM () -> [OutStgTopBinding]+runLiftM dflags us (LiftM m) = collectFloats (fromOL floats)+  where+    (_, _, floats) = initUs_ us (runRWST m (emptyEnv dflags) ())++-- | Assumes a given caffyness for the execution of the passed action, which+-- influences the 'cafInfo' of lifted bindings.+withCaffyness :: Bool -> LiftM a -> LiftM a+withCaffyness caffy action+  = LiftM (RWS.local (\e -> e { e_in_caffy_context = caffy }) (unwrapLiftM action))++-- | Writes a plain 'StgTopStringLit' to the output.+addTopStringLit :: OutId -> ByteString -> LiftM ()+addTopStringLit id = LiftM . RWS.tell . unitOL . PlainTopBinding . StgTopStringLit id++-- | Starts a recursive binding group. See #floats# and 'collectFloats'.+startBindingGroup :: LiftM ()+startBindingGroup = LiftM $ RWS.tell $ unitOL $ StartBindingGroup++-- | Ends a recursive binding group. See #floats# and 'collectFloats'.+endBindingGroup :: LiftM ()+endBindingGroup = LiftM $ RWS.tell $ unitOL $ EndBindingGroup++-- | Lifts a binding to top-level. Depending on whether it's declared inside+-- a recursive RHS (see #floats# and 'collectFloats'), this might be added to+-- an existing recursive top-level binding group.+addLiftedBinding :: OutStgBinding -> LiftM ()+addLiftedBinding = LiftM . RWS.tell . unitOL . LiftedBinding++-- | Takes a binder and a continuation which is called with the substituted+-- binder. The continuation will be evaluated in a 'LiftM' context in which that+-- binder is deemed in scope. Think of it as a 'RWS.local' computation: After+-- the continuation finishes, the new binding won't be in scope anymore.+withSubstBndr :: Id -> (Id -> LiftM a) -> LiftM a+withSubstBndr bndr inner = LiftM $ do+  subst <- RWS.asks e_subst+  let (bndr', subst') = substBndr bndr subst+  RWS.local (\e -> e { e_subst = subst' }) (unwrapLiftM (inner bndr'))++-- | See 'withSubstBndr'.+withSubstBndrs :: Traversable f => f Id -> (f Id -> LiftM a) -> LiftM a+withSubstBndrs = runContT . traverse (ContT . withSubstBndr)++-- | Similarly to 'withSubstBndr', this function takes a set of variables to+-- abstract over, the binder to lift (and generate a fresh, substituted name+-- for) and a continuation in which that fresh, lifted binder is in scope.+--+-- It takes care of all the details involved with copying and adjusting the+-- binder, fresh name generation and caffyness.+withLiftedBndr :: DIdSet -> Id -> (Id -> LiftM a) -> LiftM a+withLiftedBndr abs_ids bndr inner = do+  uniq <- getUniqueM+  let str = "$l" ++ occNameString (getOccName bndr)+  let ty = mkLamTypes (dVarSetElems abs_ids) (idType bndr)+  -- When the enclosing top-level binding is not caffy, then the lifted+  -- binding will not be caffy either. If we don't recognize this, non-caffy+  -- things call caffy things and then codegen screws up.+  in_caffy_ctxt <- LiftM (RWS.asks e_in_caffy_context)+  let caf_info = if in_caffy_ctxt then MayHaveCafRefs else NoCafRefs+  let bndr'+        -- See Note [transferPolyIdInfo] in Id.hs. We need to do this at least+        -- for arity information.+        = transferPolyIdInfo bndr (dVarSetElems abs_ids)+        -- Otherwise we confuse code gen if bndr was not caffy: the new bndr is+        -- assumed to be caffy and will need an SRT. Transitive call sites might+        -- not be caffy themselves and subsequently will miss a static link+        -- field in their closure. Chaos ensues.+        . flip setIdCafInfo caf_info+        . mkSysLocal (mkFastString str) uniq+        $ ty+  LiftM $ RWS.local+    (\e -> e+      { e_subst = extendSubst bndr bndr' $ extendInScope bndr' $ e_subst e+      , e_expansions = extendVarEnv (e_expansions e) bndr abs_ids+      })+    (unwrapLiftM (inner bndr'))++-- | See 'withLiftedBndr'.+withLiftedBndrs :: Traversable f => DIdSet -> f Id -> (f Id -> LiftM a) -> LiftM a+withLiftedBndrs abs_ids = runContT . traverse (ContT . withLiftedBndr abs_ids)++-- | Substitutes a binder /occurrence/, which was brought in scope earlier by+-- 'withSubstBndr'\/'withLiftedBndr'.+substOcc :: Id -> LiftM Id+substOcc id = LiftM (RWS.asks (lookupIdSubst id . e_subst))++-- | Whether the given binding was decided to be lambda lifted.+isLifted :: InId -> LiftM Bool+isLifted bndr = LiftM (RWS.asks (elemVarEnv bndr . e_expansions))++-- | Returns an empty list for a binding that was not lifted and the list of all+-- local variables the binding abstracts over (so, exactly the additional+-- arguments at adjusted call sites) otherwise.+formerFreeVars :: InId -> LiftM [OutId]+formerFreeVars f = LiftM $ do+  expansions <- RWS.asks e_expansions+  pure $ case lookupVarEnv expansions f of+    Nothing -> []+    Just fvs -> dVarSetElems fvs++-- | Creates an /expander function/ for the current set of lifted binders.+-- This expander function will replace any 'InId' by their corresponding 'OutId'+-- and, in addition, will expand any lifted binders by the former free variables+-- it abstracts over.+liftedIdsExpander :: LiftM (DIdSet -> DIdSet)+liftedIdsExpander = LiftM $ do+  expansions <- RWS.asks e_expansions+  subst <- RWS.asks e_subst+  -- We use @noWarnLookupIdSubst@ here in order to suppress "not in scope"+  -- warnings generated by 'lookupIdSubst' due to local bindings within RHS.+  -- These are not in the InScopeSet of @subst@ and extending the InScopeSet in+  -- @goodToLift@/@closureGrowth@ before passing it on to @expander@ is too much+  -- trouble.+  let go set fv = case lookupVarEnv expansions fv of+        Nothing -> extendDVarSet set (noWarnLookupIdSubst fv subst) -- Not lifted+        Just fvs' -> unionDVarSet set fvs'+  let expander fvs = foldl' go emptyDVarSet (dVarSetElems fvs)+  pure expander
+ compiler/GHC/Stg/Lint.hs view
@@ -0,0 +1,396 @@+{- |+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++A lint pass to check basic STG invariants:++- Variables should be defined before used.++- Let bindings should not have unboxed types (unboxed bindings should only+  appear in case), except when they're join points (see Note [CoreSyn let/app+  invariant] and #14117).++- If linting after unarisation, invariants listed in Note [Post-unarisation+  invariants].++Because we don't have types and coercions in STG we can't really check types+here.++Some history:++StgLint used to check types, but it never worked and so it was disabled in 2000+with this note:++    WARNING:+    ~~~~~~~~++    This module has suffered bit-rot; it is likely to yield lint errors+    for Stg code that is currently perfectly acceptable for code+    generation.  Solution: don't use it!  (KSW 2000-05).++Since then there were some attempts at enabling it again, as summarised in+#14787. It's finally decided that we remove all type checking and only look for+basic properties listed above.+-}++{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, TypeFamilies,+  DeriveFunctor #-}++module GHC.Stg.Lint ( lintStgTopBindings ) where++import GhcPrelude++import GHC.Stg.Syntax++import DynFlags+import Bag              ( Bag, emptyBag, isEmptyBag, snocBag, bagToList )+import BasicTypes       ( TopLevelFlag(..), isTopLevel )+import CostCentre       ( isCurrentCCS )+import Id               ( Id, idType, isJoinId, idName )+import VarSet+import DataCon+import CoreSyn          ( AltCon(..) )+import Name             ( getSrcLoc, nameIsLocalOrFrom )+import ErrUtils         ( MsgDoc, Severity(..), mkLocMessage )+import Type+import GHC.Types.RepType+import SrcLoc+import Outputable+import Module           ( Module )+import qualified ErrUtils as Err+import Control.Applicative ((<|>))+import Control.Monad++lintStgTopBindings :: forall a . (OutputablePass a, BinderP a ~ Id)+                   => DynFlags+                   -> Module -- ^ module being compiled+                   -> Bool   -- ^ have we run Unarise yet?+                   -> String -- ^ who produced the STG?+                   -> [GenStgTopBinding a]+                   -> IO ()++lintStgTopBindings dflags this_mod unarised whodunnit binds+  = {-# SCC "StgLint" #-}+    case initL this_mod unarised top_level_binds (lint_binds binds) of+      Nothing  ->+        return ()+      Just msg -> do+        putLogMsg dflags NoReason Err.SevDump noSrcSpan+          (defaultDumpStyle dflags)+          (vcat [ text "*** Stg Lint ErrMsgs: in" <+>+                        text whodunnit <+> text "***",+                  msg,+                  text "*** Offending Program ***",+                  pprGenStgTopBindings binds,+                  text "*** End of Offense ***"])+        Err.ghcExit dflags 1+  where+    -- Bring all top-level binds into scope because CoreToStg does not generate+    -- bindings in dependency order (so we may see a use before its definition).+    top_level_binds = mkVarSet (bindersOfTopBinds binds)++    lint_binds :: [GenStgTopBinding a] -> LintM ()++    lint_binds [] = return ()+    lint_binds (bind:binds) = do+        binders <- lint_bind bind+        addInScopeVars binders $+            lint_binds binds++    lint_bind (StgTopLifted bind) = lintStgBinds TopLevel bind+    lint_bind (StgTopStringLit v _) = return [v]++lintStgArg :: StgArg -> LintM ()+lintStgArg (StgLitArg _) = return ()+lintStgArg (StgVarArg v) = lintStgVar v++lintStgVar :: Id -> LintM ()+lintStgVar id = checkInScope id++lintStgBinds+    :: (OutputablePass a, BinderP a ~ Id)+    => TopLevelFlag -> GenStgBinding a -> LintM [Id] -- Returns the binders+lintStgBinds top_lvl (StgNonRec binder rhs) = do+    lint_binds_help top_lvl (binder,rhs)+    return [binder]++lintStgBinds top_lvl (StgRec pairs)+  = addInScopeVars binders $ do+        mapM_ (lint_binds_help top_lvl) pairs+        return binders+  where+    binders = [b | (b,_) <- pairs]++lint_binds_help+    :: (OutputablePass a, BinderP a ~ Id)+    => TopLevelFlag+    -> (Id, GenStgRhs a)+    -> LintM ()+lint_binds_help top_lvl (binder, rhs)+  = addLoc (RhsOf binder) $ do+        when (isTopLevel top_lvl) (checkNoCurrentCCS rhs)+        lintStgRhs rhs+        -- Check binder doesn't have unlifted type or it's a join point+        checkL (isJoinId binder || not (isUnliftedType (idType binder)))+               (mkUnliftedTyMsg binder rhs)++-- | Top-level bindings can't inherit the cost centre stack from their+-- (static) allocation site.+checkNoCurrentCCS+    :: (OutputablePass a, BinderP a ~ Id)+    => GenStgRhs a+    -> LintM ()+checkNoCurrentCCS rhs@(StgRhsClosure _ ccs _ _ _)+  | isCurrentCCS ccs+  = addErrL (text "Top-level StgRhsClosure with CurrentCCS" $$ ppr rhs)+checkNoCurrentCCS rhs@(StgRhsCon ccs _ _)+  | isCurrentCCS ccs+  = addErrL (text "Top-level StgRhsCon with CurrentCCS" $$ ppr rhs)+checkNoCurrentCCS _+  = return ()++lintStgRhs :: (OutputablePass a, BinderP a ~ Id) => GenStgRhs a -> LintM ()++lintStgRhs (StgRhsClosure _ _ _ [] expr)+  = lintStgExpr expr++lintStgRhs (StgRhsClosure _ _ _ binders expr)+  = addLoc (LambdaBodyOf binders) $+      addInScopeVars binders $+        lintStgExpr expr++lintStgRhs rhs@(StgRhsCon _ con args) = do+    when (isUnboxedTupleCon con || isUnboxedSumCon con) $+      addErrL (text "StgRhsCon is an unboxed tuple or sum application" $$+               ppr rhs)+    mapM_ lintStgArg args+    mapM_ checkPostUnariseConArg args++lintStgExpr :: (OutputablePass a, BinderP a ~ Id) => GenStgExpr a -> LintM ()++lintStgExpr (StgLit _) = return ()++lintStgExpr (StgApp fun args) = do+    lintStgVar fun+    mapM_ lintStgArg args++lintStgExpr app@(StgConApp con args _arg_tys) = do+    -- unboxed sums should vanish during unarise+    lf <- getLintFlags+    when (lf_unarised lf && isUnboxedSumCon con) $+      addErrL (text "Unboxed sum after unarise:" $$+               ppr app)+    mapM_ lintStgArg args+    mapM_ checkPostUnariseConArg args++lintStgExpr (StgOpApp _ args _) =+    mapM_ lintStgArg args++lintStgExpr lam@(StgLam _ _) =+    addErrL (text "Unexpected StgLam" <+> ppr lam)++lintStgExpr (StgLet _ binds body) = do+    binders <- lintStgBinds NotTopLevel binds+    addLoc (BodyOfLetRec binders) $+      addInScopeVars binders $+        lintStgExpr body++lintStgExpr (StgLetNoEscape _ binds body) = do+    binders <- lintStgBinds NotTopLevel binds+    addLoc (BodyOfLetRec binders) $+      addInScopeVars binders $+        lintStgExpr body++lintStgExpr (StgTick _ expr) = lintStgExpr expr++lintStgExpr (StgCase scrut bndr alts_type alts) = do+    lintStgExpr scrut++    lf <- getLintFlags+    let in_scope = stgCaseBndrInScope alts_type (lf_unarised lf)++    addInScopeVars [bndr | in_scope] (mapM_ lintAlt alts)++lintAlt+    :: (OutputablePass a, BinderP a ~ Id)+    => (AltCon, [Id], GenStgExpr a) -> LintM ()++lintAlt (DEFAULT, _, rhs) =+    lintStgExpr rhs++lintAlt (LitAlt _, _, rhs) =+    lintStgExpr rhs++lintAlt (DataAlt _, bndrs, rhs) = do+    mapM_ checkPostUnariseBndr bndrs+    addInScopeVars bndrs (lintStgExpr rhs)++{-+************************************************************************+*                                                                      *+Utilities+*                                                                      *+************************************************************************+-}++bindersOf :: BinderP a ~ Id => GenStgBinding a -> [Id]+bindersOf (StgNonRec binder _) = [binder]+bindersOf (StgRec pairs)       = [binder | (binder, _) <- pairs]++bindersOfTop :: BinderP a ~ Id => GenStgTopBinding a -> [Id]+bindersOfTop (StgTopLifted bind) = bindersOf bind+bindersOfTop (StgTopStringLit binder _) = [binder]++bindersOfTopBinds :: BinderP a ~ Id => [GenStgTopBinding a] -> [Id]+bindersOfTopBinds = foldr ((++) . bindersOfTop) []++{-+************************************************************************+*                                                                      *+The Lint monad+*                                                                      *+************************************************************************+-}++newtype LintM a = LintM+    { unLintM :: Module+              -> LintFlags+              -> [LintLocInfo]     -- Locations+              -> IdSet             -- Local vars in scope+              -> Bag MsgDoc        -- Error messages so far+              -> (a, Bag MsgDoc)   -- Result and error messages (if any)+    }+    deriving (Functor)++data LintFlags = LintFlags { lf_unarised :: !Bool+                             -- ^ have we run the unariser yet?+                           }++data LintLocInfo+  = RhsOf Id            -- The variable bound+  | LambdaBodyOf [Id]   -- The lambda-binder+  | BodyOfLetRec [Id]   -- One of the binders++dumpLoc :: LintLocInfo -> (SrcSpan, SDoc)+dumpLoc (RhsOf v) =+  (srcLocSpan (getSrcLoc v), text " [RHS of " <> pp_binders [v] <> char ']' )+dumpLoc (LambdaBodyOf bs) =+  (srcLocSpan (getSrcLoc (head bs)), text " [in body of lambda with binders " <> pp_binders bs <> char ']' )++dumpLoc (BodyOfLetRec bs) =+  (srcLocSpan (getSrcLoc (head bs)), text " [in body of letrec with binders " <> pp_binders bs <> char ']' )+++pp_binders :: [Id] -> SDoc+pp_binders bs+  = sep (punctuate comma (map pp_binder bs))+  where+    pp_binder b+      = hsep [ppr b, dcolon, ppr (idType b)]++initL :: Module -> Bool -> IdSet -> LintM a -> Maybe MsgDoc+initL this_mod unarised locals (LintM m) = do+  let (_, errs) = m this_mod (LintFlags unarised) [] locals emptyBag+  if isEmptyBag errs then+      Nothing+  else+      Just (vcat (punctuate blankLine (bagToList errs)))++instance Applicative LintM where+      pure a = LintM $ \_mod _lf _loc _scope errs -> (a, errs)+      (<*>) = ap+      (*>)  = thenL_++instance Monad LintM where+    (>>=) = thenL+    (>>)  = (*>)++thenL :: LintM a -> (a -> LintM b) -> LintM b+thenL m k = LintM $ \mod lf loc scope errs+  -> case unLintM m mod lf loc scope errs of+      (r, errs') -> unLintM (k r) mod lf loc scope errs'++thenL_ :: LintM a -> LintM b -> LintM b+thenL_ m k = LintM $ \mod lf loc scope errs+  -> case unLintM m mod lf loc scope errs of+      (_, errs') -> unLintM k mod lf loc scope errs'++checkL :: Bool -> MsgDoc -> LintM ()+checkL True  _   = return ()+checkL False msg = addErrL msg++-- Case alts shouldn't have unboxed sum, unboxed tuple, or void binders.+checkPostUnariseBndr :: Id -> LintM ()+checkPostUnariseBndr bndr = do+    lf <- getLintFlags+    when (lf_unarised lf) $+      forM_ (checkPostUnariseId bndr) $ \unexpected ->+        addErrL $+          text "After unarisation, binder " <>+          ppr bndr <> text " has " <> text unexpected <> text " type " <>+          ppr (idType bndr)++-- Arguments shouldn't have sum, tuple, or void types.+checkPostUnariseConArg :: StgArg -> LintM ()+checkPostUnariseConArg arg = case arg of+    StgLitArg _ ->+      return ()+    StgVarArg id -> do+      lf <- getLintFlags+      when (lf_unarised lf) $+        forM_ (checkPostUnariseId id) $ \unexpected ->+          addErrL $+            text "After unarisation, arg " <>+            ppr id <> text " has " <> text unexpected <> text " type " <>+            ppr (idType id)++-- Post-unarisation args and case alt binders should not have unboxed tuple,+-- unboxed sum, or void types. Return what the binder is if it is one of these.+checkPostUnariseId :: Id -> Maybe String+checkPostUnariseId id =+    let+      id_ty = idType id+      is_sum, is_tuple, is_void :: Maybe String+      is_sum = guard (isUnboxedSumType id_ty) >> return "unboxed sum"+      is_tuple = guard (isUnboxedTupleType id_ty) >> return "unboxed tuple"+      is_void = guard (isVoidTy id_ty) >> return "void"+    in+      is_sum <|> is_tuple <|> is_void++addErrL :: MsgDoc -> LintM ()+addErrL msg = LintM $ \_mod _lf loc _scope errs -> ((), addErr errs msg loc)++addErr :: Bag MsgDoc -> MsgDoc -> [LintLocInfo] -> Bag MsgDoc+addErr errs_so_far msg locs+  = errs_so_far `snocBag` mk_msg locs+  where+    mk_msg (loc:_) = let (l,hdr) = dumpLoc loc+                     in  mkLocMessage SevWarning l (hdr $$ msg)+    mk_msg []      = msg++addLoc :: LintLocInfo -> LintM a -> LintM a+addLoc extra_loc m = LintM $ \mod lf loc scope errs+   -> unLintM m mod lf (extra_loc:loc) scope errs++addInScopeVars :: [Id] -> LintM a -> LintM a+addInScopeVars ids m = LintM $ \mod lf loc scope errs+ -> let+        new_set = mkVarSet ids+    in unLintM m mod lf loc (scope `unionVarSet` new_set) errs++getLintFlags :: LintM LintFlags+getLintFlags = LintM $ \_mod lf _loc _scope errs -> (lf, errs)++checkInScope :: Id -> LintM ()+checkInScope id = LintM $ \mod _lf loc scope errs+ -> if nameIsLocalOrFrom mod (idName id) && not (id `elemVarSet` scope) then+        ((), addErr errs (hsep [ppr id, dcolon, ppr (idType id),+                                text "is out of scope"]) loc)+    else+        ((), errs)++mkUnliftedTyMsg :: OutputablePass a => Id -> GenStgRhs a -> SDoc+mkUnliftedTyMsg binder rhs+  = (text "Let(rec) binder" <+> quotes (ppr binder) <+>+     text "has unlifted type" <+> quotes (ppr (idType binder)))+    $$+    (text "RHS:" <+> ppr rhs)
+ compiler/GHC/Stg/Pipeline.hs view
@@ -0,0 +1,141 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++\section[SimplStg]{Driver for simplifying @STG@ programs}+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}++module GHC.Stg.Pipeline ( stg2stg ) where++#include "HsVersions.h"++import GhcPrelude++import GHC.Stg.Syntax++import GHC.Stg.Lint     ( lintStgTopBindings )+import GHC.Stg.Stats    ( showStgStats )+import GHC.Stg.Unarise  ( unarise )+import GHC.Stg.CSE      ( stgCse )+import GHC.Stg.Lift     ( stgLiftLams )+import Module           ( Module )++import DynFlags+import ErrUtils+import UniqSupply+import Outputable+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.State.Strict++newtype StgM a = StgM { _unStgM :: StateT Char IO a }+  deriving (Functor, Applicative, Monad, MonadIO)++instance MonadUnique StgM where+  getUniqueSupplyM = StgM $ do { mask <- get+                               ; liftIO $! mkSplitUniqSupply mask}+  getUniqueM = StgM $ do { mask <- get+                         ; liftIO $! uniqFromMask mask}++runStgM :: Char -> StgM a -> IO a+runStgM mask (StgM m) = evalStateT m mask++stg2stg :: DynFlags                  -- includes spec of what stg-to-stg passes to do+        -> Module                    -- module being compiled+        -> [StgTopBinding]           -- input program+        -> IO [StgTopBinding]        -- output program++stg2stg dflags this_mod binds+  = do  { dump_when Opt_D_dump_stg "STG:" binds+        ; showPass dflags "Stg2Stg"+        -- Do the main business!+        ; binds' <- runStgM 'g' $+            foldM do_stg_pass binds (getStgToDo dflags)++        ; dump_when Opt_D_dump_stg_final "Final STG:" binds'++        ; return binds'+   }++  where+    stg_linter unarised+      | gopt Opt_DoStgLinting dflags+      = lintStgTopBindings dflags this_mod unarised+      | otherwise+      = \ _whodunnit _binds -> return ()++    -------------------------------------------+    do_stg_pass :: [StgTopBinding] -> StgToDo -> StgM [StgTopBinding]+    do_stg_pass binds to_do+      = case to_do of+          StgDoNothing ->+            return binds++          StgStats ->+            trace (showStgStats binds) (return binds)++          StgCSE -> do+            let binds' = {-# SCC "StgCse" #-} stgCse binds+            end_pass "StgCse" binds'++          StgLiftLams -> do+            us <- getUniqueSupplyM+            let binds' = {-# SCC "StgLiftLams" #-} stgLiftLams dflags us binds+            end_pass "StgLiftLams" binds'++          StgUnarise -> do+            us <- getUniqueSupplyM+            liftIO (stg_linter False "Pre-unarise" binds)+            let binds' = unarise us binds+            liftIO (dump_when Opt_D_dump_stg_unarised "Unarised STG:" binds')+            liftIO (stg_linter True "Unarise" binds')+            return binds'++    dump_when flag header binds+      = dumpIfSet_dyn dflags flag header FormatSTG (pprStgTopBindings binds)++    end_pass what binds2+      = liftIO $ do -- report verbosely, if required+          dumpIfSet_dyn dflags Opt_D_verbose_stg2stg what+            FormatSTG (vcat (map ppr binds2))+          stg_linter False what binds2+          return binds2++-- -----------------------------------------------------------------------------+-- StgToDo:  abstraction of stg-to-stg passes to run.++-- | Optional Stg-to-Stg passes.+data StgToDo+  = StgCSE+  -- ^ Common subexpression elimination+  | StgLiftLams+  -- ^ Lambda lifting closure variables, trading stack/register allocation for+  -- heap allocation+  | StgStats+  | StgUnarise+  -- ^ Mandatory unarise pass, desugaring unboxed tuple and sum binders+  | StgDoNothing+  -- ^ Useful for building up 'getStgToDo'+  deriving Eq++-- | Which Stg-to-Stg passes to run. Depends on flags, ways etc.+getStgToDo :: DynFlags -> [StgToDo]+getStgToDo dflags =+  filter (/= StgDoNothing)+    [ mandatory StgUnarise+    -- Important that unarisation comes first+    -- See Note [StgCse after unarisation] in GHC.Stg.CSE+    , optional Opt_StgCSE StgCSE+    , optional Opt_StgLiftLams StgLiftLams+    , optional Opt_StgStats StgStats+    ] where+      optional opt = runWhen (gopt opt dflags)+      mandatory = id++runWhen :: Bool -> StgToDo -> StgToDo+runWhen True todo = todo+runWhen _    _    = StgDoNothing
+ compiler/GHC/Stg/Stats.hs view
@@ -0,0 +1,173 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[StgStats]{Gathers statistical information about programs}+++The program gather statistics about+\begin{enumerate}+\item number of boxed cases+\item number of unboxed cases+\item number of let-no-escapes+\item number of non-updatable lets+\item number of updatable lets+\item number of applications+\item number of primitive applications+\item number of closures (does not include lets bound to constructors)+\item number of free variables in closures+%\item number of top-level functions+%\item number of top-level CAFs+\item number of constructors+\end{enumerate}+-}++{-# LANGUAGE CPP #-}++module GHC.Stg.Stats ( showStgStats ) where++#include "HsVersions.h"++import GhcPrelude++import GHC.Stg.Syntax++import Id (Id)+import Panic++import Data.Map (Map)+import qualified Data.Map as Map++data CounterType+  = Literals+  | Applications+  | ConstructorApps+  | PrimitiveApps+  | LetNoEscapes+  | StgCases+  | FreeVariables+  | ConstructorBinds Bool{-True<=>top-level-}+  | ReEntrantBinds   Bool{-ditto-}+  | SingleEntryBinds Bool{-ditto-}+  | UpdatableBinds   Bool{-ditto-}+  deriving (Eq, Ord)++type Count      = Int+type StatEnv    = Map CounterType Count++emptySE :: StatEnv+emptySE = Map.empty++combineSE :: StatEnv -> StatEnv -> StatEnv+combineSE = Map.unionWith (+)++combineSEs :: [StatEnv] -> StatEnv+combineSEs = foldr combineSE emptySE++countOne :: CounterType -> StatEnv+countOne c = Map.singleton c 1++{-+************************************************************************+*                                                                      *+\subsection{Top-level list of bindings (a ``program'')}+*                                                                      *+************************************************************************+-}++showStgStats :: [StgTopBinding] -> String++showStgStats prog+  = "STG Statistics:\n\n"+    ++ concat (map showc (Map.toList (gatherStgStats prog)))+  where+    showc (x,n) = (showString (s x) . shows n) "\n"++    s Literals                = "Literals                   "+    s Applications            = "Applications               "+    s ConstructorApps         = "ConstructorApps            "+    s PrimitiveApps           = "PrimitiveApps              "+    s LetNoEscapes            = "LetNoEscapes               "+    s StgCases                = "StgCases                   "+    s FreeVariables           = "FreeVariables              "+    s (ConstructorBinds True) = "ConstructorBinds_Top       "+    s (ReEntrantBinds True)   = "ReEntrantBinds_Top         "+    s (SingleEntryBinds True) = "SingleEntryBinds_Top       "+    s (UpdatableBinds True)   = "UpdatableBinds_Top         "+    s (ConstructorBinds _)    = "ConstructorBinds_Nested    "+    s (ReEntrantBinds _)      = "ReEntrantBindsBinds_Nested "+    s (SingleEntryBinds _)    = "SingleEntryBinds_Nested    "+    s (UpdatableBinds _)      = "UpdatableBinds_Nested      "++gatherStgStats :: [StgTopBinding] -> StatEnv+gatherStgStats binds = combineSEs (map statTopBinding binds)++{-+************************************************************************+*                                                                      *+\subsection{Bindings}+*                                                                      *+************************************************************************+-}++statTopBinding :: StgTopBinding -> StatEnv+statTopBinding (StgTopStringLit _ _) = countOne Literals+statTopBinding (StgTopLifted bind) = statBinding True bind++statBinding :: Bool -- True <=> top-level; False <=> nested+            -> StgBinding+            -> StatEnv++statBinding top (StgNonRec b rhs)+  = statRhs top (b, rhs)++statBinding top (StgRec pairs)+  = combineSEs (map (statRhs top) pairs)++statRhs :: Bool -> (Id, StgRhs) -> StatEnv++statRhs top (_, StgRhsCon _ _ _)+  = countOne (ConstructorBinds top)++statRhs top (_, StgRhsClosure _ _ u _ body)+  = statExpr body `combineSE`+    countOne (+      case u of+        ReEntrant   -> ReEntrantBinds   top+        Updatable   -> UpdatableBinds   top+        SingleEntry -> SingleEntryBinds top+    )++{-+************************************************************************+*                                                                      *+\subsection{Expressions}+*                                                                      *+************************************************************************+-}++statExpr :: StgExpr -> StatEnv++statExpr (StgApp _ _)     = countOne Applications+statExpr (StgLit _)       = countOne Literals+statExpr (StgConApp _ _ _)= countOne ConstructorApps+statExpr (StgOpApp _ _ _) = countOne PrimitiveApps+statExpr (StgTick _ e)    = statExpr e++statExpr (StgLetNoEscape _ binds body)+  = statBinding False{-not top-level-} binds    `combineSE`+    statExpr body                               `combineSE`+    countOne LetNoEscapes++statExpr (StgLet _ binds body)+  = statBinding False{-not top-level-} binds    `combineSE`+    statExpr body++statExpr (StgCase expr _ _ alts)+  = statExpr expr       `combineSE`+    stat_alts alts      `combineSE`+    countOne StgCases+  where+    stat_alts alts+        = combineSEs (map statExpr [ e | (_,_,e) <- alts ])++statExpr (StgLam {}) = panic "statExpr StgLam"
+ compiler/GHC/Stg/Subst.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE CPP #-}++module GHC.Stg.Subst where++#include "HsVersions.h"++import GhcPrelude++import Id+import VarEnv+import Control.Monad.Trans.State.Strict+import Outputable+import Util++-- | A renaming substitution from 'Id's to 'Id's. Like 'RnEnv2', but not+-- maintaining pairs of substitutions. Like @"CoreSubst".'CoreSubst.Subst'@, but+-- with the domain being 'Id's instead of entire 'CoreExpr'.+data Subst = Subst InScopeSet IdSubstEnv++type IdSubstEnv = IdEnv Id++-- | @emptySubst = 'mkEmptySubst' 'emptyInScopeSet'@+emptySubst :: Subst+emptySubst = mkEmptySubst emptyInScopeSet++-- | Constructs a new 'Subst' assuming the variables in the given 'InScopeSet'+-- are in scope.+mkEmptySubst :: InScopeSet -> Subst+mkEmptySubst in_scope = Subst in_scope emptyVarEnv++-- | Substitutes an 'Id' for another one according to the 'Subst' given in a way+-- that avoids shadowing the 'InScopeSet', returning the result and an updated+-- 'Subst' that should be used by subsequent substitutions.+substBndr :: Id -> Subst -> (Id, Subst)+substBndr id (Subst in_scope env)+  = (new_id, Subst new_in_scope new_env)+  where+    new_id = uniqAway in_scope id+    no_change = new_id == id -- in case nothing shadowed+    new_in_scope = in_scope `extendInScopeSet` new_id+    new_env+      | no_change = delVarEnv env id+      | otherwise = extendVarEnv env id new_id++-- | @substBndrs = runState . traverse (state . substBndr)@+substBndrs :: Traversable f => f Id -> Subst -> (f Id, Subst)+substBndrs = runState . traverse (state . substBndr)++-- | Substitutes an occurrence of an identifier for its counterpart recorded+-- in the 'Subst'.+lookupIdSubst :: HasCallStack => Id -> Subst -> Id+lookupIdSubst id (Subst in_scope env)+  | not (isLocalId id) = id+  | Just id' <- lookupVarEnv env id = id'+  | Just id' <- lookupInScope in_scope id = id'+  | otherwise = WARN( True, text "StgSubst.lookupIdSubst" <+> ppr id $$ ppr in_scope)+                id++-- | Substitutes an occurrence of an identifier for its counterpart recorded+-- in the 'Subst'. Does not generate a debug warning if the identifier to+-- to substitute wasn't in scope.+noWarnLookupIdSubst :: HasCallStack => Id -> Subst -> Id+noWarnLookupIdSubst id (Subst in_scope env)+  | not (isLocalId id) = id+  | Just id' <- lookupVarEnv env id = id'+  | Just id' <- lookupInScope in_scope id = id'+  | otherwise = id++-- | Add the 'Id' to the in-scope set and remove any existing substitutions for+-- it.+extendInScope :: Id -> Subst -> Subst+extendInScope id (Subst in_scope env) = Subst (in_scope `extendInScopeSet` id) env++-- | Add a substitution for an 'Id' to the 'Subst': you must ensure that the+-- in-scope set is such that TyCoSubst Note [The substitution invariant]+-- holds after extending the substitution like this.+extendSubst :: Id -> Id -> Subst -> Subst+extendSubst id new_id (Subst in_scope env)+  = ASSERT2( new_id `elemInScopeSet` in_scope, ppr id <+> ppr new_id $$ ppr in_scope )+    Subst in_scope (extendVarEnv env id new_id)
+ compiler/GHC/Stg/Syntax.hs view
@@ -0,0 +1,871 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++Shared term graph (STG) syntax for spineless-tagless code generation+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++This data type represents programs just before code generation (conversion to+@Cmm@): basically, what we have is a stylised form of @CoreSyntax@, the style+being one that happens to be ideally suited to spineless tagless code+generation.+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ConstraintKinds #-}++module GHC.Stg.Syntax (+        StgArg(..),++        GenStgTopBinding(..), GenStgBinding(..), GenStgExpr(..), GenStgRhs(..),+        GenStgAlt, AltType(..),++        StgPass(..), BinderP, XRhsClosure, XLet, XLetNoEscape,+        NoExtFieldSilent, noExtFieldSilent,+        OutputablePass,++        UpdateFlag(..), isUpdatable,++        -- a set of synonyms for the vanilla parameterisation+        StgTopBinding, StgBinding, StgExpr, StgRhs, StgAlt,++        -- a set of synonyms for the code gen parameterisation+        CgStgTopBinding, CgStgBinding, CgStgExpr, CgStgRhs, CgStgAlt,++        -- a set of synonyms for the lambda lifting parameterisation+        LlStgTopBinding, LlStgBinding, LlStgExpr, LlStgRhs, LlStgAlt,++        -- a set of synonyms to distinguish in- and out variants+        InStgArg,  InStgTopBinding,  InStgBinding,  InStgExpr,  InStgRhs,  InStgAlt,+        OutStgArg, OutStgTopBinding, OutStgBinding, OutStgExpr, OutStgRhs, OutStgAlt,++        -- StgOp+        StgOp(..),++        -- utils+        topStgBindHasCafRefs, stgArgHasCafRefs, stgRhsArity,+        isDllConApp,+        stgArgType,+        stripStgTicksTop, stripStgTicksTopE,+        stgCaseBndrInScope,++        pprStgBinding, pprGenStgTopBindings, pprStgTopBindings+    ) where++#include "HsVersions.h"++import GhcPrelude++import CoreSyn     ( AltCon, Tickish )+import CostCentre  ( CostCentreStack )+import Data.ByteString ( ByteString )+import Data.Data   ( Data )+import Data.List   ( intersperse )+import DataCon+import DynFlags+import ForeignCall ( ForeignCall )+import Id+import IdInfo      ( mayHaveCafRefs )+import VarSet+import Literal     ( Literal, literalType )+import Module      ( Module )+import Outputable+import Packages    ( isDllName )+import GHC.Platform+import PprCore     ( {- instances -} )+import PrimOp      ( PrimOp, PrimCall )+import TyCon       ( PrimRep(..), TyCon )+import Type        ( Type )+import GHC.Types.RepType     ( typePrimRep1 )+import Util++import Data.List.NonEmpty ( NonEmpty, toList )++{-+************************************************************************+*                                                                      *+GenStgBinding+*                                                                      *+************************************************************************++As usual, expressions are interesting; other things are boring. Here are the+boring things (except note the @GenStgRhs@), parameterised with respect to+binder and occurrence information (just as in @CoreSyn@):+-}++-- | A top-level binding.+data GenStgTopBinding pass+-- See Note [CoreSyn top-level string literals]+  = StgTopLifted (GenStgBinding pass)+  | StgTopStringLit Id ByteString++data GenStgBinding pass+  = StgNonRec (BinderP pass) (GenStgRhs pass)+  | StgRec    [(BinderP pass, GenStgRhs pass)]++{-+************************************************************************+*                                                                      *+StgArg+*                                                                      *+************************************************************************+-}++data StgArg+  = StgVarArg  Id+  | StgLitArg  Literal++-- | Does this constructor application refer to anything in a different+-- *Windows* DLL?+-- If so, we can't allocate it statically+isDllConApp :: DynFlags -> Module -> DataCon -> [StgArg] -> Bool+isDllConApp dflags this_mod con args+ | platformOS (targetPlatform dflags) == OSMinGW32+    = isDllName dflags this_mod (dataConName con) || any is_dll_arg args+ | otherwise = False+  where+    -- NB: typePrimRep1 is legit because any free variables won't have+    -- unlifted type (there are no unlifted things at top level)+    is_dll_arg :: StgArg -> Bool+    is_dll_arg (StgVarArg v) =  isAddrRep (typePrimRep1 (idType v))+                             && isDllName dflags this_mod (idName v)+    is_dll_arg _             = False++-- True of machine addresses; these are the things that don't work across DLLs.+-- The key point here is that VoidRep comes out False, so that a top level+-- nullary GADT constructor is False for isDllConApp+--+--    data T a where+--      T1 :: T Int+--+-- gives+--+--    T1 :: forall a. (a~Int) -> T a+--+-- and hence the top-level binding+--+--    $WT1 :: T Int+--    $WT1 = T1 Int (Coercion (Refl Int))+--+-- The coercion argument here gets VoidRep+isAddrRep :: PrimRep -> Bool+isAddrRep AddrRep     = True+isAddrRep LiftedRep   = True+isAddrRep UnliftedRep = True+isAddrRep _           = False++-- | Type of an @StgArg@+--+-- Very half baked because we have lost the type arguments.+stgArgType :: StgArg -> Type+stgArgType (StgVarArg v)   = idType v+stgArgType (StgLitArg lit) = literalType lit+++-- | Strip ticks of a given type from an STG expression.+stripStgTicksTop :: (Tickish Id -> Bool) -> GenStgExpr p -> ([Tickish Id], GenStgExpr p)+stripStgTicksTop p = go []+   where go ts (StgTick t e) | p t = go (t:ts) e+         go ts other               = (reverse ts, other)++-- | Strip ticks of a given type from an STG expression returning only the expression.+stripStgTicksTopE :: (Tickish Id -> Bool) -> GenStgExpr p -> GenStgExpr p+stripStgTicksTopE p = go+   where go (StgTick t e) | p t = go e+         go other               = other++-- | Given an alt type and whether the program is unarised, return whether the+-- case binder is in scope.+--+-- Case binders of unboxed tuple or unboxed sum type always dead after the+-- unariser has run. See Note [Post-unarisation invariants].+stgCaseBndrInScope :: AltType -> Bool {- ^ unarised? -} -> Bool+stgCaseBndrInScope alt_ty unarised =+    case alt_ty of+      AlgAlt _      -> True+      PrimAlt _     -> True+      MultiValAlt _ -> not unarised+      PolyAlt       -> True++{-+************************************************************************+*                                                                      *+STG expressions+*                                                                      *+************************************************************************++The @GenStgExpr@ data type is parameterised on binder and occurrence info, as+before.++************************************************************************+*                                                                      *+GenStgExpr+*                                                                      *+************************************************************************++An application is of a function to a list of atoms (not expressions).+Operationally, we want to push the arguments on the stack and call the function.+(If the arguments were expressions, we would have to build their closures+first.)++There is no constructor for a lone variable; it would appear as @StgApp var []@.+-}++data GenStgExpr pass+  = StgApp+        Id       -- function+        [StgArg] -- arguments; may be empty++{-+************************************************************************+*                                                                      *+StgConApp and StgPrimApp --- saturated applications+*                                                                      *+************************************************************************++There are specialised forms of application, for constructors, primitives, and+literals.+-}++  | StgLit      Literal++        -- StgConApp is vital for returning unboxed tuples or sums+        -- which can't be let-bound+  | StgConApp   DataCon+                [StgArg] -- Saturated+                [Type]   -- See Note [Types in StgConApp] in GHC.Stg.Unarise++  | StgOpApp    StgOp    -- Primitive op or foreign call+                [StgArg] -- Saturated.+                Type     -- Result type+                         -- We need to know this so that we can+                         -- assign result registers++{-+************************************************************************+*                                                                      *+StgLam+*                                                                      *+************************************************************************++StgLam is used *only* during CoreToStg's work. Before CoreToStg has finished it+encodes (\x -> e) as (let f = \x -> e in f) TODO: Encode this via an extension+to GenStgExpr à la TTG.+-}++  | StgLam+        (NonEmpty (BinderP pass))+        StgExpr    -- Body of lambda++{-+************************************************************************+*                                                                      *+GenStgExpr: case-expressions+*                                                                      *+************************************************************************++This has the same boxed/unboxed business as Core case expressions.+-}++  | StgCase+        (GenStgExpr pass) -- the thing to examine+        (BinderP pass) -- binds the result of evaluating the scrutinee+        AltType+        [GenStgAlt pass]+                    -- The DEFAULT case is always *first*+                    -- if it is there at all++{-+************************************************************************+*                                                                      *+GenStgExpr: let(rec)-expressions+*                                                                      *+************************************************************************++The various forms of let(rec)-expression encode most of the interesting things+we want to do.++-   let-closure x = [free-vars] [args] expr in e++  is equivalent to++    let x = (\free-vars -> \args -> expr) free-vars++  @args@ may be empty (and is for most closures). It isn't under circumstances+  like this:++    let x = (\y -> y+z)++  This gets mangled to++    let-closure x = [z] [y] (y+z)++  The idea is that we compile code for @(y+z)@ in an environment in which @z@ is+  bound to an offset from Node, and `y` is bound to an offset from the stack+  pointer.++  (A let-closure is an @StgLet@ with a @StgRhsClosure@ RHS.)++-   let-constructor x = Constructor [args] in e++  (A let-constructor is an @StgLet@ with a @StgRhsCon@ RHS.)++- Letrec-expressions are essentially the same deal as let-closure/+  let-constructor, so we use a common structure and distinguish between them+  with an @is_recursive@ boolean flag.++-   let-unboxed u = <an arbitrary arithmetic expression in unboxed values> in e++  All the stuff on the RHS must be fully evaluated. No function calls either!++  (We've backed away from this toward case-expressions with suitably-magical+  alts ...)++- Advanced stuff here! Not to start with, but makes pattern matching generate+  more efficient code.++    let-escapes-not fail = expr+    in e'++  Here the idea is that @e'@ guarantees not to put @fail@ in a data structure,+  or pass it to another function. All @e'@ will ever do is tail-call @fail@.+  Rather than build a closure for @fail@, all we need do is to record the stack+  level at the moment of the @let-escapes-not@; then entering @fail@ is just a+  matter of adjusting the stack pointer back down to that point and entering the+  code for it.++  Another example:++    f x y = let z = huge-expression in+            if y==1 then z else+            if y==2 then z else+            1++  (A let-escapes-not is an @StgLetNoEscape@.)++- We may eventually want:++    let-literal x = Literal in e++And so the code for let(rec)-things:+-}++  | StgLet+        (XLet pass)+        (GenStgBinding pass)    -- right hand sides (see below)+        (GenStgExpr pass)       -- body++  | StgLetNoEscape+        (XLetNoEscape pass)+        (GenStgBinding pass)    -- right hand sides (see below)+        (GenStgExpr pass)       -- body++{-+*************************************************************************+*                                                                      *+GenStgExpr: hpc, scc and other debug annotations+*                                                                      *+*************************************************************************++Finally for @hpc@ expressions we introduce a new STG construct.+-}++  | StgTick+    (Tickish Id)+    (GenStgExpr pass)       -- sub expression++-- END of GenStgExpr++{-+************************************************************************+*                                                                      *+STG right-hand sides+*                                                                      *+************************************************************************++Here's the rest of the interesting stuff for @StgLet@s; the first flavour is for+closures:+-}++data GenStgRhs pass+  = StgRhsClosure+        (XRhsClosure pass) -- ^ Extension point for non-global free var+                           --   list just before 'CodeGen'.+        CostCentreStack    -- ^ CCS to be attached (default is CurrentCCS)+        !UpdateFlag        -- ^ 'ReEntrant' | 'Updatable' | 'SingleEntry'+        [BinderP pass]     -- ^ arguments; if empty, then not a function;+                           --   as above, order is important.+        (GenStgExpr pass)  -- ^ body++{-+An example may be in order.  Consider:++  let t = \x -> \y -> ... x ... y ... p ... q in e++Pulling out the free vars and stylising somewhat, we get the equivalent:++  let t = (\[p,q] -> \[x,y] -> ... x ... y ... p ...q) p q++Stg-operationally, the @[x,y]@ are on the stack, the @[p,q]@ are offsets from+@Node@ into the closure, and the code ptr for the closure will be exactly that+in parentheses above.++The second flavour of right-hand-side is for constructors (simple but+important):+-}++  | StgRhsCon+        CostCentreStack -- CCS to be attached (default is CurrentCCS).+                        -- Top-level (static) ones will end up with+                        -- DontCareCCS, because we don't count static+                        -- data in heap profiles, and we don't set CCCS+                        -- from static closure.+        DataCon         -- Constructor. Never an unboxed tuple or sum, as those+                        -- are not allocated.+        [StgArg]        -- Args++-- | Used as a data type index for the stgSyn AST+data StgPass+  = Vanilla+  | LiftLams+  | CodeGen++-- | Like 'GHC.Hs.Extension.NoExtField', but with an 'Outputable' instance that+-- returns 'empty'.+data NoExtFieldSilent = NoExtFieldSilent+  deriving (Data, Eq, Ord)++instance Outputable NoExtFieldSilent where+  ppr _ = empty++-- | Used when constructing a term with an unused extension point that should+-- not appear in pretty-printed output at all.+noExtFieldSilent :: NoExtFieldSilent+noExtFieldSilent = NoExtFieldSilent+-- TODO: Maybe move this to GHC.Hs.Extension? I'm not sure about the+-- implications on build time...++-- TODO: Do we really want to the extension point type families to have a closed+-- domain?+type family BinderP (pass :: StgPass)+type instance BinderP 'Vanilla = Id+type instance BinderP 'CodeGen = Id++type family XRhsClosure (pass :: StgPass)+type instance XRhsClosure 'Vanilla = NoExtFieldSilent+-- | Code gen needs to track non-global free vars+type instance XRhsClosure 'CodeGen = DIdSet++type family XLet (pass :: StgPass)+type instance XLet 'Vanilla = NoExtFieldSilent+type instance XLet 'CodeGen = NoExtFieldSilent++type family XLetNoEscape (pass :: StgPass)+type instance XLetNoEscape 'Vanilla = NoExtFieldSilent+type instance XLetNoEscape 'CodeGen = NoExtFieldSilent++stgRhsArity :: StgRhs -> Int+stgRhsArity (StgRhsClosure _ _ _ bndrs _)+  = ASSERT( all isId bndrs ) length bndrs+  -- The arity never includes type parameters, but they should have gone by now+stgRhsArity (StgRhsCon _ _ _) = 0++-- Note [CAF consistency]+-- ~~~~~~~~~~~~~~~~~~~~~~+--+-- `topStgBindHasCafRefs` is only used by an assert (`consistentCafInfo` in+-- `CoreToStg`) to make sure CAF-ness predicted by `TidyPgm` is consistent with+-- reality.+--+-- Specifically, if the RHS mentions any Id that itself is marked+-- `MayHaveCafRefs`; or if the binding is a top-level updateable thunk; then the+-- `Id` for the binding should be marked `MayHaveCafRefs`. The potential trouble+-- is that `TidyPgm` computed the CAF info on the `Id` but some transformations+-- have taken place since then.++topStgBindHasCafRefs :: GenStgTopBinding pass -> Bool+topStgBindHasCafRefs (StgTopLifted (StgNonRec _ rhs))+  = topRhsHasCafRefs rhs+topStgBindHasCafRefs (StgTopLifted (StgRec binds))+  = any topRhsHasCafRefs (map snd binds)+topStgBindHasCafRefs StgTopStringLit{}+  = False++topRhsHasCafRefs :: GenStgRhs pass -> Bool+topRhsHasCafRefs (StgRhsClosure _ _ upd _ body)+  = -- See Note [CAF consistency]+    isUpdatable upd || exprHasCafRefs body+topRhsHasCafRefs (StgRhsCon _ _ args)+  = any stgArgHasCafRefs args++exprHasCafRefs :: GenStgExpr pass -> Bool+exprHasCafRefs (StgApp f args)+  = stgIdHasCafRefs f || any stgArgHasCafRefs args+exprHasCafRefs StgLit{}+  = False+exprHasCafRefs (StgConApp _ args _)+  = any stgArgHasCafRefs args+exprHasCafRefs (StgOpApp _ args _)+  = any stgArgHasCafRefs args+exprHasCafRefs (StgLam _ body)+  = exprHasCafRefs body+exprHasCafRefs (StgCase scrt _ _ alts)+  = exprHasCafRefs scrt || any altHasCafRefs alts+exprHasCafRefs (StgLet _ bind body)+  = bindHasCafRefs bind || exprHasCafRefs body+exprHasCafRefs (StgLetNoEscape _ bind body)+  = bindHasCafRefs bind || exprHasCafRefs body+exprHasCafRefs (StgTick _ expr)+  = exprHasCafRefs expr++bindHasCafRefs :: GenStgBinding pass -> Bool+bindHasCafRefs (StgNonRec _ rhs)+  = rhsHasCafRefs rhs+bindHasCafRefs (StgRec binds)+  = any rhsHasCafRefs (map snd binds)++rhsHasCafRefs :: GenStgRhs pass -> Bool+rhsHasCafRefs (StgRhsClosure _ _ _ _ body)+  = exprHasCafRefs body+rhsHasCafRefs (StgRhsCon _ _ args)+  = any stgArgHasCafRefs args++altHasCafRefs :: GenStgAlt pass -> Bool+altHasCafRefs (_, _, rhs) = exprHasCafRefs rhs++stgArgHasCafRefs :: StgArg -> Bool+stgArgHasCafRefs (StgVarArg id)+  = stgIdHasCafRefs id+stgArgHasCafRefs _+  = False++stgIdHasCafRefs :: Id -> Bool+stgIdHasCafRefs id =+  -- We are looking for occurrences of an Id that is bound at top level, and may+  -- have CAF refs. At this point (after TidyPgm) top-level Ids (whether+  -- imported or defined in this module) are GlobalIds, so the test is easy.+  isGlobalId id && mayHaveCafRefs (idCafInfo id)++{-+************************************************************************+*                                                                      *+STG case alternatives+*                                                                      *+************************************************************************++Very like in @CoreSyntax@ (except no type-world stuff).++The type constructor is guaranteed not to be abstract; that is, we can see its+representation. This is important because the code generator uses it to+determine return conventions etc. But it's not trivial where there's a module+loop involved, because some versions of a type constructor might not have all+the constructors visible. So mkStgAlgAlts (in CoreToStg) ensures that it gets+the TyCon from the constructors or literals (which are guaranteed to have the+Real McCoy) rather than from the scrutinee type.+-}++type GenStgAlt pass+  = (AltCon,          -- alts: data constructor,+     [BinderP pass],  -- constructor's parameters,+     GenStgExpr pass) -- ...right-hand side.++data AltType+  = PolyAlt             -- Polymorphic (a lifted type variable)+  | MultiValAlt Int     -- Multi value of this arity (unboxed tuple or sum)+                        -- the arity could indeed be 1 for unary unboxed tuple+                        -- or enum-like unboxed sums+  | AlgAlt      TyCon   -- Algebraic data type; the AltCons will be DataAlts+  | PrimAlt     PrimRep -- Primitive data type; the AltCons (if any) will be LitAlts++{-+************************************************************************+*                                                                      *+The Plain STG parameterisation+*                                                                      *+************************************************************************++This happens to be the only one we use at the moment.+-}++type StgTopBinding = GenStgTopBinding 'Vanilla+type StgBinding    = GenStgBinding    'Vanilla+type StgExpr       = GenStgExpr       'Vanilla+type StgRhs        = GenStgRhs        'Vanilla+type StgAlt        = GenStgAlt        'Vanilla++type LlStgTopBinding = GenStgTopBinding 'LiftLams+type LlStgBinding    = GenStgBinding    'LiftLams+type LlStgExpr       = GenStgExpr       'LiftLams+type LlStgRhs        = GenStgRhs        'LiftLams+type LlStgAlt        = GenStgAlt        'LiftLams++type CgStgTopBinding = GenStgTopBinding 'CodeGen+type CgStgBinding    = GenStgBinding    'CodeGen+type CgStgExpr       = GenStgExpr       'CodeGen+type CgStgRhs        = GenStgRhs        'CodeGen+type CgStgAlt        = GenStgAlt        'CodeGen++{- Many passes apply a substitution, and it's very handy to have type+   synonyms to remind us whether or not the substitution has been applied.+   See CoreSyn for precedence in Core land+-}++type InStgTopBinding  = StgTopBinding+type InStgBinding     = StgBinding+type InStgArg         = StgArg+type InStgExpr        = StgExpr+type InStgRhs         = StgRhs+type InStgAlt         = StgAlt+type OutStgTopBinding = StgTopBinding+type OutStgBinding    = StgBinding+type OutStgArg        = StgArg+type OutStgExpr       = StgExpr+type OutStgRhs        = StgRhs+type OutStgAlt        = StgAlt++{-++************************************************************************+*                                                                      *+UpdateFlag+*                                                                      *+************************************************************************++This is also used in @LambdaFormInfo@ in the @ClosureInfo@ module.++A @ReEntrant@ closure may be entered multiple times, but should not be updated+or blackholed. An @Updatable@ closure should be updated after evaluation (and+may be blackholed during evaluation). A @SingleEntry@ closure will only be+entered once, and so need not be updated but may safely be blackholed.+-}++data UpdateFlag = ReEntrant | Updatable | SingleEntry++instance Outputable UpdateFlag where+    ppr u = char $ case u of+                       ReEntrant   -> 'r'+                       Updatable   -> 'u'+                       SingleEntry -> 's'++isUpdatable :: UpdateFlag -> Bool+isUpdatable ReEntrant   = False+isUpdatable SingleEntry = False+isUpdatable Updatable   = True++{-+************************************************************************+*                                                                      *+StgOp+*                                                                      *+************************************************************************++An StgOp allows us to group together PrimOps and ForeignCalls. It's quite useful+to move these around together, notably in StgOpApp and COpStmt.+-}++data StgOp+  = StgPrimOp  PrimOp++  | StgPrimCallOp PrimCall++  | StgFCallOp ForeignCall Type+        -- The Type, which is obtained from the foreign import declaration+        -- itself, is needed by the stg-to-cmm pass to determine the offset to+        -- apply to unlifted boxed arguments in GHC.StgToCmm.Foreign. See Note+        -- [Unlifted boxed arguments to foreign calls]++{-+************************************************************************+*                                                                      *+Pretty-printing+*                                                                      *+************************************************************************++Robin Popplestone asked for semi-colon separators on STG binds; here's hoping he+likes terminators instead...  Ditto for case alternatives.+-}++type OutputablePass pass =+  ( Outputable (XLet pass)+  , Outputable (XLetNoEscape pass)+  , Outputable (XRhsClosure pass)+  , OutputableBndr (BinderP pass)+  )++pprGenStgTopBinding+  :: OutputablePass pass => GenStgTopBinding pass -> SDoc+pprGenStgTopBinding (StgTopStringLit bndr str)+  = hang (hsep [pprBndr LetBind bndr, equals])+        4 (pprHsBytes str <> semi)+pprGenStgTopBinding (StgTopLifted bind)+  = pprGenStgBinding bind++pprGenStgBinding+  :: OutputablePass pass => GenStgBinding pass -> SDoc++pprGenStgBinding (StgNonRec bndr rhs)+  = hang (hsep [pprBndr LetBind bndr, equals])+        4 (ppr rhs <> semi)++pprGenStgBinding (StgRec pairs)+  = vcat [ text "Rec {"+         , vcat (intersperse blankLine (map ppr_bind pairs))+         , text "end Rec }" ]+  where+    ppr_bind (bndr, expr)+      = hang (hsep [pprBndr LetBind bndr, equals])+             4 (ppr expr <> semi)++pprGenStgTopBindings+  :: (OutputablePass pass) => [GenStgTopBinding pass] -> SDoc+pprGenStgTopBindings binds+  = vcat $ intersperse blankLine (map pprGenStgTopBinding binds)++pprStgBinding :: StgBinding -> SDoc+pprStgBinding = pprGenStgBinding++pprStgTopBindings :: [StgTopBinding] -> SDoc+pprStgTopBindings = pprGenStgTopBindings++instance Outputable StgArg where+    ppr = pprStgArg++instance OutputablePass pass => Outputable (GenStgTopBinding pass) where+    ppr = pprGenStgTopBinding++instance OutputablePass pass => Outputable (GenStgBinding pass) where+    ppr = pprGenStgBinding++instance OutputablePass pass => Outputable (GenStgExpr pass) where+    ppr = pprStgExpr++instance OutputablePass pass => Outputable (GenStgRhs pass) where+    ppr rhs = pprStgRhs rhs++pprStgArg :: StgArg -> SDoc+pprStgArg (StgVarArg var) = ppr var+pprStgArg (StgLitArg con) = ppr con++pprStgExpr :: OutputablePass pass => GenStgExpr pass -> SDoc+-- special case+pprStgExpr (StgLit lit)     = ppr lit++-- general case+pprStgExpr (StgApp func args)+  = hang (ppr func) 4 (sep (map (ppr) args))++pprStgExpr (StgConApp con args _)+  = hsep [ ppr con, brackets (interppSP args) ]++pprStgExpr (StgOpApp op args _)+  = hsep [ pprStgOp op, brackets (interppSP args)]++pprStgExpr (StgLam bndrs body)+  = sep [ char '\\' <+> ppr_list (map (pprBndr LambdaBind) (toList bndrs))+            <+> text "->",+         pprStgExpr body ]+  where ppr_list = brackets . fsep . punctuate comma++-- special case: let v = <very specific thing>+--               in+--               let ...+--               in+--               ...+--+-- Very special!  Suspicious! (SLPJ)++{-+pprStgExpr (StgLet srt (StgNonRec bndr (StgRhsClosure cc bi free_vars upd_flag args rhs))+                        expr@(StgLet _ _))+  = ($$)+      (hang (hcat [text "let { ", ppr bndr, ptext (sLit " = "),+                          ppr cc,+                          pp_binder_info bi,+                          text " [", whenPprDebug (interppSP free_vars), ptext (sLit "] \\"),+                          ppr upd_flag, text " [",+                          interppSP args, char ']'])+            8 (sep [hsep [ppr rhs, text "} in"]]))+      (ppr expr)+-}++-- special case: let ... in let ...++pprStgExpr (StgLet ext bind expr@StgLet{})+  = ($$)+      (sep [hang (text "let" <+> ppr ext <+> text "{")+                2 (hsep [pprGenStgBinding bind, text "} in"])])+      (ppr expr)++-- general case+pprStgExpr (StgLet ext bind expr)+  = sep [hang (text "let" <+> ppr ext <+> text "{") 2 (pprGenStgBinding bind),+           hang (text "} in ") 2 (ppr expr)]++pprStgExpr (StgLetNoEscape ext bind expr)+  = sep [hang (text "let-no-escape" <+> ppr ext <+> text "{")+                2 (pprGenStgBinding bind),+           hang (text "} in ")+                2 (ppr expr)]++pprStgExpr (StgTick tickish expr)+  = sdocWithDynFlags $ \dflags ->+    if gopt Opt_SuppressTicks dflags+    then pprStgExpr expr+    else sep [ ppr tickish, pprStgExpr expr ]+++-- Don't indent for a single case alternative.+pprStgExpr (StgCase expr bndr alt_type [alt])+  = sep [sep [text "case",+           nest 4 (hsep [pprStgExpr expr,+             whenPprDebug (dcolon <+> ppr alt_type)]),+           text "of", pprBndr CaseBind bndr, char '{'],+           pprStgAlt False alt,+           char '}']++pprStgExpr (StgCase expr bndr alt_type alts)+  = sep [sep [text "case",+           nest 4 (hsep [pprStgExpr expr,+             whenPprDebug (dcolon <+> ppr alt_type)]),+           text "of", pprBndr CaseBind bndr, char '{'],+           nest 2 (vcat (map (pprStgAlt True) alts)),+           char '}']+++pprStgAlt :: OutputablePass pass => Bool -> GenStgAlt pass -> SDoc+pprStgAlt indent (con, params, expr)+  | indent    = hang altPattern 4 (ppr expr <> semi)+  | otherwise = sep [altPattern, ppr expr <> semi]+    where+      altPattern = (hsep [ppr con, sep (map (pprBndr CasePatBind) params), text "->"])+++pprStgOp :: StgOp -> SDoc+pprStgOp (StgPrimOp  op)   = ppr op+pprStgOp (StgPrimCallOp op)= ppr op+pprStgOp (StgFCallOp op _) = ppr op++instance Outputable AltType where+  ppr PolyAlt         = text "Polymorphic"+  ppr (MultiValAlt n) = text "MultiAlt" <+> ppr n+  ppr (AlgAlt tc)     = text "Alg"    <+> ppr tc+  ppr (PrimAlt tc)    = text "Prim"   <+> ppr tc++pprStgRhs :: OutputablePass pass => GenStgRhs pass -> SDoc++pprStgRhs (StgRhsClosure ext cc upd_flag args body)+  = sdocWithDynFlags $ \dflags ->+    hang (hsep [if gopt Opt_SccProfilingOn dflags then ppr cc else empty,+                if not $ gopt Opt_SuppressStgExts dflags+                  then ppr ext else empty,+                char '\\' <> ppr upd_flag, brackets (interppSP args)])+         4 (ppr body)++pprStgRhs (StgRhsCon cc con args)+  = hcat [ ppr cc,+           space, ppr con, text "! ", brackets (interppSP args)]
+ compiler/GHC/Stg/Unarise.hs view
@@ -0,0 +1,769 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-2012++Note [Unarisation]+~~~~~~~~~~~~~~~~~~+The idea of this pass is to translate away *all* unboxed-tuple and unboxed-sum+binders. So for example:++  f (x :: (# Int, Bool #)) = f x + f (# 1, True #)++  ==>++  f (x1 :: Int) (x2 :: Bool) = f x1 x2 + f 1 True++It is important that we do this at the STG level and NOT at the Core level+because it would be very hard to make this pass Core-type-preserving. In this+example the type of 'f' changes, for example.++STG fed to the code generators *must* be unarised because the code generators do+not support unboxed tuple and unboxed sum binders natively.++In more detail: (see next note for unboxed sums)++Suppose that a variable x : (# t1, t2 #).++  * At the binding site for x, make up fresh vars  x1:t1, x2:t2++  * Extend the UnariseEnv   x :-> MultiVal [x1,x2]++  * Replace the binding with a curried binding for x1,x2++       Lambda:   \x.e                ==>   \x1 x2. e+       Case alt: MkT a b x c d -> e  ==>   MkT a b x1 x2 c d -> e++  * Replace argument occurrences with a sequence of args via a lookup in+    UnariseEnv++       f a b x c d   ==>   f a b x1 x2 c d++  * Replace tail-call occurrences with an unboxed tuple via a lookup in+    UnariseEnv++       x  ==>  (# x1, x2 #)++    So, for example++       f x = x    ==>   f x1 x2 = (# x1, x2 #)++  * We /always/ eliminate a case expression when++       - It scrutinises an unboxed tuple or unboxed sum++       - The scrutinee is a variable (or when it is an explicit tuple, but the+         simplifier eliminates those)++    The case alternative (there can be only one) can be one of these two+    things:++      - An unboxed tuple pattern. e.g.++          case v of x { (# x1, x2, x3 #) -> ... }++        Scrutinee has to be in form `(# t1, t2, t3 #)` so we just extend the+        environment with++          x :-> MultiVal [t1,t2,t3]+          x1 :-> UnaryVal t1, x2 :-> UnaryVal t2, x3 :-> UnaryVal t3++      - A DEFAULT alternative. Just the same, without the bindings for x1,x2,x3++By the end of this pass, we only have unboxed tuples in return positions.+Unboxed sums are completely eliminated, see next note.++Note [Translating unboxed sums to unboxed tuples]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Unarise also eliminates unboxed sum binders, and translates unboxed sums in+return positions to unboxed tuples. We want to overlap fields of a sum when+translating it to a tuple to have efficient memory layout. When translating a+sum pattern to a tuple pattern, we need to translate it so that binders of sum+alternatives will be mapped to right arguments after the term translation. So+translation of sum DataCon applications to tuple DataCon applications and+translation of sum patterns to tuple patterns need to be in sync.++These translations work like this. Suppose we have++  (# x1 | | ... #) :: (# t1 | t2 | ... #)++remember that t1, t2 ... can be sums and tuples too. So we first generate+layouts of those. Then we "merge" layouts of each alternative, which gives us a+sum layout with best overlapping possible.++Layout of a flat type 'ty1' is just [ty1].+Layout of a tuple is just concatenation of layouts of its fields.++For layout of a sum type,++  - We first get layouts of all alternatives.+  - We sort these layouts based on their "slot types".+  - We merge all the alternatives.++For example, say we have (# (# Int#, Char #) | (# Int#, Int# #) | Int# #)++  - Layouts of alternatives: [ [Word, Ptr], [Word, Word], [Word] ]+  - Sorted: [ [Ptr, Word], [Word, Word], [Word] ]+  - Merge all alternatives together: [ Ptr, Word, Word ]++We add a slot for the tag to the first position. So our tuple type is++  (# Tag#, Any, Word#, Word# #)+  (we use Any for pointer slots)++Now, any term of this sum type needs to generate a tuple of this type instead.+The translation works by simply putting arguments to first slots that they fit+in. Suppose we had++  (# (# 42#, 'c' #) | | #)++42# fits in Word#, 'c' fits in Any, so we generate this application:++  (# 1#, 'c', 42#, rubbish #)++Another example using the same type: (# | (# 2#, 3# #) | #). 2# fits in Word#,+3# fits in Word #, so we get:++  (# 2#, rubbish, 2#, 3# #).++Note [Types in StgConApp]+~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have this unboxed sum term:++  (# 123 | #)++What will be the unboxed tuple representation? We can't tell without knowing the+type of this term. For example, these are all valid tuples for this:++  (# 1#, 123 #)          -- when type is (# Int | String #)+  (# 1#, 123, rubbish #) -- when type is (# Int | Float# #)+  (# 1#, 123, rubbish, rubbish #)+                         -- when type is (# Int | (# Int, Int, Int #) #)++So we pass type arguments of the DataCon's TyCon in StgConApp to decide what+layout to use. Note that unlifted values can't be let-bound, so we don't need+types in StgRhsCon.++Note [UnariseEnv can map to literals]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To avoid redundant case expressions when unarising unboxed sums, UnariseEnv+needs to map variables to literals too. Suppose we have this Core:++  f (# x | #)++  ==> (CorePrep)++  case (# x | #) of y {+    _ -> f y+  }++  ==> (MultiVal)++  case (# 1#, x #) of [x1, x2] {+    _ -> f x1 x2+  }++To eliminate this case expression we need to map x1 to 1# in UnariseEnv:++  x1 :-> UnaryVal 1#, x2 :-> UnaryVal x++so that `f x1 x2` becomes `f 1# x`.++Note [Unarisation and arity]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Because of unarisation, the arity that will be recorded in the generated info+table for an Id may be larger than the idArity. Instead we record what we call+the RepArity, which is the Arity taking into account any expanded arguments, and+corresponds to the number of (possibly-void) *registers* arguments will arrive+in.++Note [Post-unarisation invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+STG programs after unarisation have these invariants:++  * No unboxed sums at all.++  * No unboxed tuple binders. Tuples only appear in return position.++  * DataCon applications (StgRhsCon and StgConApp) don't have void arguments.+    This means that it's safe to wrap `StgArg`s of DataCon applications with+    `GHC.StgToCmm.Env.NonVoid`, for example.++  * Alt binders (binders in patterns) are always non-void.++  * Binders always have zero (for void arguments) or one PrimRep.+-}++{-# LANGUAGE CPP, TupleSections #-}++module GHC.Stg.Unarise (unarise) where++#include "HsVersions.h"++import GhcPrelude++import BasicTypes+import CoreSyn+import DataCon+import FastString (FastString, mkFastString)+import Id+import Literal+import MkCore (aBSENT_SUM_FIELD_ERROR_ID)+import MkId (voidPrimId, voidArgId)+import MonadUtils (mapAccumLM)+import Outputable+import GHC.Types.RepType+import GHC.Stg.Syntax+import Type+import TysPrim (intPrimTy,wordPrimTy,word64PrimTy)+import TysWiredIn+import UniqSupply+import Util+import VarEnv++import Data.Bifunctor (second)+import Data.Maybe (mapMaybe)+import qualified Data.IntMap as IM++--------------------------------------------------------------------------------++-- | A mapping from binders to the Ids they were expanded/renamed to.+--+--   x :-> MultiVal [a,b,c] in rho+--+-- iff  x's typePrimRep is not a singleton, or equivalently+--      x's type is an unboxed tuple, sum or void.+--+--    x :-> UnaryVal x'+--+-- iff x's RepType is UnaryRep or equivalently+--     x's type is not unboxed tuple, sum or void.+--+-- So+--     x :-> MultiVal [a] in rho+-- means x is represented by singleton tuple.+--+--     x :-> MultiVal [] in rho+-- means x is void.+--+-- INVARIANT: OutStgArgs in the range only have NvUnaryTypes+--            (i.e. no unboxed tuples, sums or voids)+--+type UnariseEnv = VarEnv UnariseVal++data UnariseVal+  = MultiVal [OutStgArg] -- MultiVal to tuple. Can be empty list (void).+  | UnaryVal OutStgArg   -- See NOTE [Renaming during unarisation].++instance Outputable UnariseVal where+  ppr (MultiVal args) = text "MultiVal" <+> ppr args+  ppr (UnaryVal arg)   = text "UnaryVal" <+> ppr arg++-- | Extend the environment, checking the UnariseEnv invariant.+extendRho :: UnariseEnv -> Id -> UnariseVal -> UnariseEnv+extendRho rho x (MultiVal args)+  = ASSERT(all (isNvUnaryType . stgArgType) args)+    extendVarEnv rho x (MultiVal args)+extendRho rho x (UnaryVal val)+  = ASSERT(isNvUnaryType (stgArgType val))+    extendVarEnv rho x (UnaryVal val)++--------------------------------------------------------------------------------++unarise :: UniqSupply -> [StgTopBinding] -> [StgTopBinding]+unarise us binds = initUs_ us (mapM (unariseTopBinding emptyVarEnv) binds)++unariseTopBinding :: UnariseEnv -> StgTopBinding -> UniqSM StgTopBinding+unariseTopBinding rho (StgTopLifted bind)+  = StgTopLifted <$> unariseBinding rho bind+unariseTopBinding _ bind@StgTopStringLit{} = return bind++unariseBinding :: UnariseEnv -> StgBinding -> UniqSM StgBinding+unariseBinding rho (StgNonRec x rhs)+  = StgNonRec x <$> unariseRhs rho rhs+unariseBinding rho (StgRec xrhss)+  = StgRec <$> mapM (\(x, rhs) -> (x,) <$> unariseRhs rho rhs) xrhss++unariseRhs :: UnariseEnv -> StgRhs -> UniqSM StgRhs+unariseRhs rho (StgRhsClosure ext ccs update_flag args expr)+  = do (rho', args1) <- unariseFunArgBinders rho args+       expr' <- unariseExpr rho' expr+       return (StgRhsClosure ext ccs update_flag args1 expr')++unariseRhs rho (StgRhsCon ccs con args)+  = ASSERT(not (isUnboxedTupleCon con || isUnboxedSumCon con))+    return (StgRhsCon ccs con (unariseConArgs rho args))++--------------------------------------------------------------------------------++unariseExpr :: UnariseEnv -> StgExpr -> UniqSM StgExpr++unariseExpr rho e@(StgApp f [])+  = case lookupVarEnv rho f of+      Just (MultiVal args)  -- Including empty tuples+        -> return (mkTuple args)+      Just (UnaryVal (StgVarArg f'))+        -> return (StgApp f' [])+      Just (UnaryVal (StgLitArg f'))+        -> return (StgLit f')+      Nothing+        -> return e++unariseExpr rho e@(StgApp f args)+  = return (StgApp f' (unariseFunArgs rho args))+  where+    f' = case lookupVarEnv rho f of+           Just (UnaryVal (StgVarArg f')) -> f'+           Nothing -> f+           err -> pprPanic "unariseExpr - app2" (ppr e $$ ppr err)+               -- Can't happen because 'args' is non-empty, and+               -- a tuple or sum cannot be applied to anything++unariseExpr _ (StgLit l)+  = return (StgLit l)++unariseExpr rho (StgConApp dc args ty_args)+  | Just args' <- unariseMulti_maybe rho dc args ty_args+  = return (mkTuple args')++  | otherwise+  , let args' = unariseConArgs rho args+  = return (StgConApp dc args' (map stgArgType args'))++unariseExpr rho (StgOpApp op args ty)+  = return (StgOpApp op (unariseFunArgs rho args) ty)++unariseExpr _ e@StgLam{}+  = pprPanic "unariseExpr: found lambda" (ppr e)++unariseExpr rho (StgCase scrut bndr alt_ty alts)+  -- 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++  -- Handle strict lets for tuples and sums:+  --   case (# a,b #) of r -> rhs+  -- and analogously for sums+  | StgConApp dc args ty_args <- scrut+  , Just args' <- unariseMulti_maybe rho dc args ty_args+  = elimCase rho args' bndr alt_ty alts++  -- general case+  | otherwise+  = do scrut' <- unariseExpr rho scrut+       alts'  <- unariseAlts rho alt_ty bndr alts+       return (StgCase scrut' bndr alt_ty alts')+                       -- bndr may have a unboxed sum/tuple type but it will be+                       -- dead after unarise (checked in GHC.Stg.Lint)++unariseExpr rho (StgLet ext bind e)+  = StgLet ext <$> unariseBinding rho bind <*> unariseExpr rho e++unariseExpr rho (StgLetNoEscape ext bind e)+  = StgLetNoEscape ext <$> unariseBinding rho bind <*> unariseExpr rho e++unariseExpr rho (StgTick tick e)+  = StgTick tick <$> unariseExpr rho e++-- Doesn't return void args.+unariseMulti_maybe :: UnariseEnv -> DataCon -> [InStgArg] -> [Type] -> Maybe [OutStgArg]+unariseMulti_maybe rho dc args ty_args+  | isUnboxedTupleCon dc+  = Just (unariseConArgs rho args)++  | isUnboxedSumCon dc+  , let args1 = ASSERT(isSingleton args) (unariseConArgs rho args)+  = Just (mkUbxSum dc ty_args args1)++  | otherwise+  = Nothing++--------------------------------------------------------------------------------++elimCase :: UnariseEnv+         -> [OutStgArg] -- non-void args+         -> InId -> AltType -> [InStgAlt] -> UniqSM OutStgExpr++elimCase rho args bndr (MultiValAlt _) [(_, bndrs, rhs)]+  = do let rho1 = extendRho rho bndr (MultiVal args)+           rho2+             | isUnboxedTupleBndr bndr+             = mapTupleIdBinders bndrs args rho1+             | otherwise+             = ASSERT(isUnboxedSumBndr bndr)+               if null bndrs then rho1+                             else mapSumIdBinders bndrs args rho1++       unariseExpr rho2 rhs++elimCase rho args bndr (MultiValAlt _) alts+  | isUnboxedSumBndr bndr+  = do let (tag_arg : real_args) = args+       tag_bndr <- mkId (mkFastString "tag") tagTy+          -- this won't be used but we need a binder anyway+       let rho1 = extendRho rho bndr (MultiVal args)+           scrut' = case tag_arg of+                      StgVarArg v     -> StgApp v []+                      StgLitArg l     -> StgLit l++       alts' <- unariseSumAlts rho1 real_args alts+       return (StgCase scrut' tag_bndr tagAltTy alts')++elimCase _ args bndr alt_ty alts+  = pprPanic "elimCase - unhandled case"+      (ppr args <+> ppr bndr <+> ppr alt_ty $$ ppr alts)++--------------------------------------------------------------------------------++unariseAlts :: UnariseEnv -> AltType -> InId -> [StgAlt] -> UniqSM [StgAlt]+unariseAlts rho (MultiValAlt n) bndr [(DEFAULT, [], e)]+  | isUnboxedTupleBndr bndr+  = do (rho', ys) <- unariseConArgBinder rho bndr+       e' <- unariseExpr rho' e+       return [(DataAlt (tupleDataCon Unboxed n), ys, e')]++unariseAlts rho (MultiValAlt n) bndr [(DataAlt _, ys, e)]+  | isUnboxedTupleBndr bndr+  = do (rho', ys1) <- unariseConArgBinders rho ys+       MASSERT(ys1 `lengthIs` n)+       let rho'' = extendRho rho' bndr (MultiVal (map StgVarArg ys1))+       e' <- unariseExpr rho'' e+       return [(DataAlt (tupleDataCon Unboxed n), ys1, e')]++unariseAlts _ (MultiValAlt _) bndr alts+  | isUnboxedTupleBndr bndr+  = pprPanic "unariseExpr: strange multi val alts" (ppr alts)++-- In this case we don't need to scrutinize the tag bit+unariseAlts rho (MultiValAlt _) bndr [(DEFAULT, _, rhs)]+  | isUnboxedSumBndr bndr+  = do (rho_sum_bndrs, sum_bndrs) <- unariseConArgBinder rho bndr+       rhs' <- unariseExpr rho_sum_bndrs rhs+       return [(DataAlt (tupleDataCon Unboxed (length sum_bndrs)), sum_bndrs, rhs')]++unariseAlts rho (MultiValAlt _) bndr alts+  | isUnboxedSumBndr bndr+  = do (rho_sum_bndrs, scrt_bndrs@(tag_bndr : real_bndrs)) <- unariseConArgBinder rho bndr+       alts' <- unariseSumAlts rho_sum_bndrs (map StgVarArg real_bndrs) alts+       let inner_case = StgCase (StgApp tag_bndr []) tag_bndr tagAltTy alts'+       return [ (DataAlt (tupleDataCon Unboxed (length scrt_bndrs)),+                 scrt_bndrs,+                 inner_case) ]++unariseAlts rho _ _ alts+  = mapM (\alt -> unariseAlt rho alt) alts++unariseAlt :: UnariseEnv -> StgAlt -> UniqSM StgAlt+unariseAlt rho (con, xs, e)+  = do (rho', xs') <- unariseConArgBinders rho xs+       (con, xs',) <$> unariseExpr rho' e++--------------------------------------------------------------------------------++-- | Make alternatives that match on the tag of a sum+-- (i.e. generate LitAlts for the tag)+unariseSumAlts :: UnariseEnv+               -> [StgArg] -- sum components _excluding_ the tag bit.+               -> [StgAlt] -- original alternative with sum LHS+               -> UniqSM [StgAlt]+unariseSumAlts env args alts+  = do alts' <- mapM (unariseSumAlt env args) alts+       return (mkDefaultLitAlt alts')++unariseSumAlt :: UnariseEnv+              -> [StgArg] -- sum components _excluding_ the tag bit.+              -> StgAlt   -- original alternative with sum LHS+              -> UniqSM StgAlt+unariseSumAlt rho _ (DEFAULT, _, e)+  = ( DEFAULT, [], ) <$> unariseExpr rho e++unariseSumAlt rho args (DataAlt sumCon, bs, e)+  = do let rho' = mapSumIdBinders bs args rho+       e' <- unariseExpr rho' e+       return ( LitAlt (LitNumber LitNumInt (fromIntegral (dataConTag sumCon)) intPrimTy), [], e' )++unariseSumAlt _ scrt alt+  = pprPanic "unariseSumAlt" (ppr scrt $$ ppr alt)++--------------------------------------------------------------------------------++mapTupleIdBinders+  :: [InId]       -- Un-processed binders of a tuple alternative.+                  -- Can have void binders.+  -> [OutStgArg]  -- Arguments that form the tuple (after unarisation).+                  -- Can't have void args.+  -> UnariseEnv+  -> UnariseEnv+mapTupleIdBinders ids args0 rho0+  = ASSERT(not (any (isVoidTy . stgArgType) args0))+    let+      ids_unarised :: [(Id, [PrimRep])]+      ids_unarised = map (\id -> (id, typePrimRep (idType id))) ids++      map_ids :: UnariseEnv -> [(Id, [PrimRep])] -> [StgArg] -> UnariseEnv+      map_ids rho [] _  = rho+      map_ids rho ((x, x_reps) : xs) args =+        let+          x_arity = length x_reps+          (x_args, args') =+            ASSERT(args `lengthAtLeast` x_arity)+            splitAt x_arity args++          rho'+            | x_arity == 1+            = ASSERT(x_args `lengthIs` 1)+              extendRho rho x (UnaryVal (head x_args))+            | otherwise+            = extendRho rho x (MultiVal x_args)+        in+          map_ids rho' xs args'+    in+      map_ids rho0 ids_unarised args0++mapSumIdBinders+  :: [InId]      -- Binder of a sum alternative (remember that sum patterns+                 -- only have one binder, so this list should be a singleton)+  -> [OutStgArg] -- Arguments that form the sum (NOT including the tag).+                 -- Can't have void args.+  -> UnariseEnv+  -> UnariseEnv++mapSumIdBinders [id] args rho0+  = ASSERT(not (any (isVoidTy . stgArgType) args))+    let+      arg_slots = map primRepSlot $ concatMap (typePrimRep . stgArgType) args+      id_slots  = map primRepSlot $ typePrimRep (idType id)+      layout1   = layoutUbxSum arg_slots id_slots+    in+      if isMultiValBndr id+        then extendRho rho0 id (MultiVal [ args !! i | i <- layout1 ])+        else ASSERT(layout1 `lengthIs` 1)+             extendRho rho0 id (UnaryVal (args !! head layout1))++mapSumIdBinders ids sum_args _+  = pprPanic "mapSumIdBinders" (ppr ids $$ ppr sum_args)++-- | Build a unboxed sum term from arguments of an alternative.+--+-- Example, for (# x | #) :: (# (# #) | Int #) we call+--+--   mkUbxSum (# _ | #) [ (# #), Int ] [ voidPrimId ]+--+-- which returns+--+--   [ 1#, rubbish ]+--+mkUbxSum+  :: DataCon      -- Sum data con+  -> [Type]       -- Type arguments of the sum data con+  -> [OutStgArg]  -- Actual arguments of the alternative.+  -> [OutStgArg]  -- Final tuple arguments+mkUbxSum dc ty_args args0+  = let+      (_ : sum_slots) = ubxSumRepType (map typePrimRep ty_args)+        -- drop tag slot++      tag = dataConTag dc++      layout'  = layoutUbxSum sum_slots (mapMaybe (typeSlotTy . stgArgType) args0)+      tag_arg  = StgLitArg (LitNumber LitNumInt (fromIntegral tag) intPrimTy)+      arg_idxs = IM.fromList (zipEqual "mkUbxSum" layout' args0)++      mkTupArgs :: Int -> [SlotTy] -> IM.IntMap StgArg -> [StgArg]+      mkTupArgs _ [] _+        = []+      mkTupArgs arg_idx (slot : slots_left) arg_map+        | Just stg_arg <- IM.lookup arg_idx arg_map+        = stg_arg : mkTupArgs (arg_idx + 1) slots_left arg_map+        | otherwise+        = slotRubbishArg slot : mkTupArgs (arg_idx + 1) slots_left arg_map++      slotRubbishArg :: SlotTy -> StgArg+      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 (LitFloat 0)+      slotRubbishArg DoubleSlot = StgLitArg (LitDouble 0)+    in+      tag_arg : mkTupArgs 0 sum_slots arg_idxs++--------------------------------------------------------------------------------++{-+For arguments (StgArg) and binders (Id) we have two kind of unarisation:++  - When unarising function arg binders and arguments, we don't want to remove+    void binders and arguments. For example,++      f :: (# (# #), (# #) #) -> Void# -> RealWorld# -> ...+      f x y z = <body>++    Here after unarise we should still get a function with arity 3. Similarly+    in the call site we shouldn't remove void arguments:++      f (# (# #), (# #) #) voidId rw++    When unarising <body>, we extend the environment with these binders:++      x :-> MultiVal [], y :-> MultiVal [], z :-> MultiVal []++    Because their rep types are `MultiRep []` (aka. void). This means that when+    we see `x` in a function argument position, we actually replace it with a+    void argument. When we see it in a DataCon argument position, we just get+    rid of it, because DataCon applications in STG are always saturated.++  - When unarising case alternative binders we remove void binders, but we+    still update the environment the same way, because those binders may be+    used in the RHS. Example:++      case x of y {+        (# x1, x2, x3 #) -> <RHS>+      }++    We know that y can't be void, because we don't scrutinize voids, so x will+    be unarised to some number of arguments, and those arguments will have at+    least one non-void thing. So in the rho we will have something like:++      x :-> MultiVal [xu1, xu2]++    Now, after we eliminate void binders in the pattern, we get exactly the same+    number of binders, and extend rho again with these:++      x1 :-> UnaryVal xu1+      x2 :-> MultiVal [] -- x2 is void+      x3 :-> UnaryVal xu2++    Now when we see x2 in a function argument position or in return position, we+    generate void#. In constructor argument position, we just remove it.++So in short, when we have a void id,++  - We keep it if it's a lambda argument binder or+                       in argument position of an application.++  - We remove it if it's a DataCon field binder or+                         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.+unariseFunArg :: UnariseEnv -> StgArg -> [StgArg]+unariseFunArg rho (StgVarArg x) =+  case lookupVarEnv rho x of+    Just (MultiVal [])  -> [voidArg]   -- NB: do not remove void args+    Just (MultiVal as)  -> as+    Just (UnaryVal arg) -> [arg]+    Nothing             -> [StgVarArg x]+unariseFunArg _ arg = [arg]++unariseFunArgs :: UnariseEnv -> [StgArg] -> [StgArg]+unariseFunArgs = concatMap . unariseFunArg++unariseFunArgBinders :: UnariseEnv -> [Id] -> UniqSM (UnariseEnv, [Id])+unariseFunArgBinders rho xs = second concat <$> mapAccumLM unariseFunArgBinder rho xs++-- Result list of binders is never empty+unariseFunArgBinder :: UnariseEnv -> Id -> UniqSM (UnariseEnv, [Id])+unariseFunArgBinder = unariseArgBinder False++--------------------------------------------------------------------------------++-- | MultiVal a DataCon argument. Returns an empty list when argument is void.+unariseConArg :: UnariseEnv -> InStgArg -> [OutStgArg]+unariseConArg rho (StgVarArg x) =+  case lookupVarEnv rho x of+    Just (UnaryVal arg) -> [arg]+    Just (MultiVal as) -> as      -- 'as' can be empty+    Nothing+      | isVoidTy (idType x) -> [] -- e.g. C realWorld#+                                  -- Here realWorld# is not in the envt, but+                                  -- is a void, and so should be eliminated+      | otherwise -> [StgVarArg x]+unariseConArg _ arg@(StgLitArg lit) =+    ASSERT(not (isVoidTy (literalType lit)))  -- We have no void literals+    [arg]++unariseConArgs :: UnariseEnv -> [InStgArg] -> [OutStgArg]+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 = unariseArgBinder True++--------------------------------------------------------------------------------++mkIds :: FastString -> [UnaryType] -> UniqSM [Id]+mkIds fs tys = mapM (mkId fs) tys++mkId :: FastString -> UnaryType -> UniqSM Id+mkId = mkSysLocalM++isMultiValBndr :: Id -> Bool+isMultiValBndr id+  | [_] <- typePrimRep (idType id)+  = False+  | otherwise+  = True++isUnboxedSumBndr :: Id -> Bool+isUnboxedSumBndr = isUnboxedSumType . idType++isUnboxedTupleBndr :: Id -> Bool+isUnboxedTupleBndr = isUnboxedTupleType . idType++mkTuple :: [StgArg] -> StgExpr+mkTuple args = StgConApp (tupleDataCon Unboxed (length args)) args (map stgArgType args)++tagAltTy :: AltType+tagAltTy = PrimAlt IntRep++tagTy :: Type+tagTy = intPrimTy++voidArg :: StgArg+voidArg = StgVarArg voidPrimId++mkDefaultLitAlt :: [StgAlt] -> [StgAlt]+-- We have an exhauseive list of literal alternatives+--    1# -> e1+--    2# -> e2+-- Since they are exhaustive, we can replace one with DEFAULT, to avoid+-- generating a final test. Remember, the DEFAULT comes first if it exists.+mkDefaultLitAlt [] = pprPanic "elimUbxSumExpr.mkDefaultAlt" (text "Empty alts")+mkDefaultLitAlt alts@((DEFAULT, _, _) : _) = alts+mkDefaultLitAlt ((LitAlt{}, [], rhs) : alts) = (DEFAULT, [], rhs) : alts+mkDefaultLitAlt alts = pprPanic "mkDefaultLitAlt" (text "Not a lit alt:" <+> ppr alts)
compiler/GHC/StgToCmm.hs view
@@ -30,7 +30,7 @@ import CmmUtils import CLabel -import StgSyn+import GHC.Stg.Syntax import DynFlags import ErrUtils @@ -38,7 +38,7 @@ import CostCentre import Id import IdInfo-import RepType+import GHC.Types.RepType import DataCon import TyCon import Module@@ -147,7 +147,7 @@ cgTopRhs dflags _rec bndr (StgRhsCon _cc con args)   = cgTopRhsCon dflags bndr con (assertNonVoidStgArgs args)       -- con args are always non-void,-      -- see Note [Post-unarisation invariants] in UnariseStg+      -- see Note [Post-unarisation invariants] in GHC.Stg.Unarise  cgTopRhs dflags rec bndr (StgRhsClosure fvs cc upd_flag args body)   = ASSERT(isEmptyDVarSet fvs)    -- There should be no free variables
compiler/GHC/StgToCmm/Bind.hs view
@@ -36,7 +36,7 @@ import CmmInfo import CmmUtils import CLabel-import StgSyn+import GHC.Stg.Syntax import CostCentre import Id import IdInfo@@ -206,7 +206,7 @@   = withNewTickyCounterCon (idName id) $     buildDynCon id True cc con (assertNonVoidStgArgs args)       -- con args are always non-void,-      -- see Note [Post-unarisation invariants] in UnariseStg+      -- see Note [Post-unarisation invariants] in GHC.Stg.Unarise  {- See Note [GC recovery] in compiler/GHC.StgToCmm/Closure.hs -} cgRhs id (StgRhsClosure fvs cc upd_flag args body)@@ -275,7 +275,7 @@    , let (_, _, params_w_offsets) = mkVirtConstrOffsets dflags (addIdReps (assertNonVoidIds params))                                    -- pattern binders are always non-void,-                                   -- see Note [Post-unarisation invariants] in UnariseStg+                                   -- see Note [Post-unarisation invariants] in GHC.Stg.Unarise   , Just the_offset <- assocMaybe params_w_offsets (NonVoid selectee)    , let offset_into_int = bytesToWordsRoundUp dflags the_offset
compiler/GHC/StgToCmm/Bind.hs-boot view
@@ -1,6 +1,6 @@ module GHC.StgToCmm.Bind where  import GHC.StgToCmm.Monad( FCode )-import StgSyn( CgStgBinding )+import GHC.Stg.Syntax( CgStgBinding )  cgBind :: CgStgBinding -> FCode ()
compiler/GHC/StgToCmm/Closure.hs view
@@ -66,7 +66,7 @@  import GhcPrelude -import StgSyn+import GHC.Stg.Syntax import SMRep import Cmm import PprCmmExpr() -- For Outputable instances@@ -82,7 +82,7 @@ import TyCoRep import TcType import TyCon-import RepType+import GHC.Types.RepType import BasicTypes import Outputable import DynFlags@@ -142,7 +142,7 @@  -- | Used in places where some invariant ensures that all these Ids are -- non-void; e.g. constructor field binders in case expressions.--- See Note [Post-unarisation invariants] in UnariseStg.+-- See Note [Post-unarisation invariants] in GHC.Stg.Unarise. assertNonVoidIds :: [Id] -> [NonVoid Id] assertNonVoidIds ids = ASSERT(not (any (isVoidTy . idType) ids))                        coerce ids@@ -152,7 +152,7 @@  -- | Used in places where some invariant ensures that all these arguments are -- non-void; e.g. constructor arguments.--- See Note [Post-unarisation invariants] in UnariseStg.+-- See Note [Post-unarisation invariants] in GHC.Stg.Unarise. assertNonVoidStgArgs :: [StgArg] -> [NonVoid StgArg] assertNonVoidStgArgs args = ASSERT(not (any (isVoidTy . stgArgType) args))                             coerce args@@ -169,7 +169,7 @@ -- See Note [Post-unarisation invariants] idPrimRep :: Id -> PrimRep idPrimRep id = typePrimRep1 (idType id)-    -- See also Note [VoidRep] in RepType+    -- See also Note [VoidRep] in GHC.Types.RepType  -- | Assumes that Ids have one PrimRep, which holds after unarisation. -- See Note [Post-unarisation invariants]@@ -362,20 +362,19 @@ --    * big, otherwise. -- -- Small families can have the constructor tag in the tag bits.--- Big families only use the tag value 1 to represent evaluatedness.+-- Big families always use the tag values 1..mAX_PTR_TAG to represent+-- evaluatedness, the last one lumping together all overflowing ones. -- We don't have very many tag bits: for example, we have 2 bits on -- x86-32 and 3 bits on x86-64.+--+-- Also see Note [Tagging big families] in GHC.StgToCmm.Expr  isSmallFamily :: DynFlags -> Int -> Bool isSmallFamily dflags fam_size = fam_size <= mAX_PTR_TAG dflags  tagForCon :: DynFlags -> DataCon -> DynTag-tagForCon dflags con-  | isSmallFamily dflags fam_size = con_tag-  | otherwise                     = 1-  where-    con_tag  = dataConTag con -- NB: 1-indexed-    fam_size = tyConFamilySize (dataConTyCon con)+tagForCon dflags con = min (dataConTag con) (mAX_PTR_TAG dflags)+-- NB: 1-indexed  tagForArity :: DynFlags -> RepArity -> DynTag tagForArity dflags arity
compiler/GHC/StgToCmm/DataCon.hs view
@@ -19,7 +19,7 @@  import GhcPrelude -import StgSyn+import GHC.Stg.Syntax import CoreSyn  ( AltCon(..) )  import GHC.StgToCmm.Monad@@ -40,7 +40,7 @@ import DynFlags import FastString import Id-import RepType (countConRepArgs)+import GHC.Types.RepType (countConRepArgs) import Literal import PrelInfo import Outputable
compiler/GHC/StgToCmm/Env.hs view
@@ -41,7 +41,7 @@ import MkGraph import Name import Outputable-import StgSyn+import GHC.Stg.Syntax import Type import TysPrim import UniqFM
compiler/GHC/StgToCmm/Expr.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP, BangPatterns #-}  ----------------------------------------------------------------------------- --@@ -28,28 +28,30 @@ import GHC.StgToCmm.Utils import GHC.StgToCmm.Closure -import StgSyn+import GHC.Stg.Syntax  import MkGraph import BlockId-import Cmm+import Cmm hiding ( succ ) import CmmInfo import CoreSyn import DataCon+import DynFlags         ( mAX_PTR_TAG ) import ForeignCall import Id import PrimOp import TyCon import Type             ( isUnliftedType )-import RepType          ( isVoidTy, countConRepArgs )+import GHC.Types.RepType          ( isVoidTy, countConRepArgs ) import CostCentre       ( CostCentreStack, currentCCS ) import Maybes import Util import FastString import Outputable -import Control.Monad (unless,void)-import Control.Arrow (first)+import Control.Monad ( unless, void )+import Control.Arrow ( first )+import Data.List     ( partition )  ------------------------------------------------------------------------ --              cgExpr: the main function@@ -570,7 +572,7 @@ isSimpleOp :: StgOp -> [StgArg] -> FCode Bool -- True iff the op cannot block or allocate isSimpleOp (StgFCallOp (CCall (CCallSpec _ _ safe)) _) _ = return $! not (playSafe safe)--- dataToTag# evalautes its argument, see Note [dataToTag#] in primops.txt.pp+-- dataToTag# evaluates its argument, see Note [dataToTag#] in primops.txt.pp isSimpleOp (StgPrimOp DataToTagOp) _ = return False isSimpleOp (StgPrimOp op) stg_args                  = do     arg_exprs <- getNonVoidArgAmodes stg_args@@ -583,7 +585,7 @@ chooseReturnBndrs :: Id -> AltType -> [CgStgAlt] -> [NonVoid Id] -- These are the binders of a case that are assigned by the evaluation of the -- scrutinee.--- They're non-void, see Note [Post-unarisation invariants] in UnariseStg.+-- They're non-void, see Note [Post-unarisation invariants] in GHC.Stg.Unarise. chooseReturnBndrs bndr (PrimAlt _) _alts   = assertNonVoidIds [bndr] @@ -631,30 +633,153 @@          ; (mb_deflt, branches) <- cgAlgAltRhss gc_plan bndr alts -        ; let fam_sz   = tyConFamilySize tycon-              bndr_reg = CmmLocal (idToReg dflags bndr)+        ; let !fam_sz   = tyConFamilySize tycon+              !bndr_reg = CmmLocal (idToReg dflags bndr)+              !ptag_expr = cmmConstrTag1 dflags (CmmReg bndr_reg)+              !branches' = first succ <$> branches+              !maxpt = mAX_PTR_TAG dflags+              (!via_ptr, !via_info) = partition ((< maxpt) . fst) branches'+              !small = isSmallFamily dflags fam_sz -                    -- Is the constructor tag in the node reg?-        ; if isSmallFamily dflags fam_sz-          then do-                let   -- Yes, bndr_reg has constr. tag in ls bits-                   tag_expr = cmmConstrTag1 dflags (CmmReg bndr_reg)-                   branches' = [(tag+1,branch) | (tag,branch) <- branches]-                emitSwitch tag_expr branches' mb_deflt 1 fam_sz+                -- Is the constructor tag in the node reg?+                -- See Note [Tagging big families]+        ; if small || null via_info+           then -- Yes, bndr_reg has constructor tag in ls bits+               emitSwitch ptag_expr branches' mb_deflt 1+                 (if small then fam_sz else maxpt) -           else -- No, get tag from info table-                let -- Note that ptr _always_ has tag 1-                    -- when the family size is big enough-                    untagged_ptr = cmmRegOffB bndr_reg (-1)-                    tag_expr = getConstrTag dflags (untagged_ptr)-                in emitSwitch tag_expr branches mb_deflt 0 (fam_sz - 1)+           else -- No, the get exact tag from info table when mAX_PTR_TAG+                -- See Note [Double switching for big families]+              do+                let !untagged_ptr = cmmUntag dflags (CmmReg bndr_reg)+                    !itag_expr = getConstrTag dflags untagged_ptr+                    !info0 = first pred <$> via_info+                if null via_ptr then+                  emitSwitch itag_expr info0 mb_deflt 0 (fam_sz - 1)+                else do+                  infos_lbl <- newBlockId+                  infos_scp <- getTickScope +                  let spillover = (maxpt, (mkBranch infos_lbl, infos_scp))++                  (mb_shared_deflt, mb_shared_branch) <- case mb_deflt of+                      (Just (stmts, scp)) ->+                          do lbl <- newBlockId+                             return ( Just (mkLabel lbl scp <*> stmts, scp)+                                    , Just (mkBranch lbl, scp))+                      _ -> return (Nothing, Nothing)+                  -- Switch on pointer tag+                  emitSwitch ptag_expr (spillover : via_ptr) mb_shared_deflt 1 maxpt+                  join_lbl <- newBlockId+                  emit (mkBranch join_lbl)+                  -- Switch on info table tag+                  emitLabel infos_lbl+                  emitSwitch itag_expr info0 mb_shared_branch+                    (maxpt - 1) (fam_sz - 1)+                  emitLabel join_lbl+         ; return AssignedDirectly }  cgAlts _ _ _ _ = panic "cgAlts"         -- UbxTupAlt and PolyAlt have only one alternative +-- Note [Double switching for big families]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- An algebraic data type can have a n >= 0 summands+-- (or alternatives), which are identified (labeled) by+-- constructors. In memory they are kept apart by tags+-- (see Note [Data constructor dynamic tags] in GHC.StgToCmm.Closure).+-- Due to the characteristics of the platform that+-- contribute to the alignment of memory objects, there+-- is a natural limit of information about constructors+-- that can be encoded in the pointer tag. When the mapping+-- of constructors to the pointer tag range 1..mAX_PTR_TAG+-- is not injective, then we have a "big data type", also+-- called a "big (constructor) family" in the literature.+-- Constructor tags residing in the info table are injective,+-- but considerably more expensive to obtain, due to additional+-- memory access(es).+--+-- When doing case analysis on a value of a "big data type"+-- we need two nested switch statements to make up for the lack+-- of injectivity of pointer tagging, also taking the info+-- table tag into account. The exact mechanism is described next.+--+-- In the general case, switching on big family alternatives+-- is done by two nested switch statements. According to+-- Note [Tagging big families], the outer switch+-- looks at the pointer tag and the inner dereferences the+-- pointer and switches on the info table tag.+--+-- We can handle a simple case first, namely when none+-- of the case alternatives mention a constructor having+-- a pointer tag of 1..mAX_PTR_TAG-1. In this case we+-- simply emit a switch on the info table tag.+-- Note that the other simple case is when all mentioned+-- alternatives lie in 1..mAX_PTR_TAG-1, in which case we can+-- switch on the ptr tag only, just like in the small family case.+--+-- There is a single intricacy with a nested switch:+-- Both should branch to the same default alternative, and as such+-- avoid duplicate codegen of potentially heavy code. The outer+-- switch generates the actual code with a prepended fresh label,+-- while the inner one only generates a jump to that label.+--+-- For example, let's assume a 64-bit architecture, so that all+-- heap objects are 8-byte aligned, and hence the address of a+-- heap object ends in `000` (three zero bits).+--+-- Then consider the following data type+--+--   > data Big = T0 | T1 | T2 | T3 | T4 | T5 | T6 | T7 | T8+--   Ptr tag:      1    2    3    4    5    6    7    7    7+--   As bits:    001  010  011  100  101  110  111  111  111+--   Info pointer tag (zero based):+--                 0    1    2    3    4    5    6    7    8+--+-- Then     \case T2 -> True; T8 -> True; _ -> False+-- will result in following code (slightly cleaned-up and+-- commented -ddump-cmm-from-stg):+{-+           R1 = _sqI::P64;  -- scrutinee+           if (R1 & 7 != 0) goto cqO; else goto cqP;+       cqP: // global       -- enter+           call (I64[R1])(R1) returns to cqO, args: 8, res: 8, upd: 8;+       cqO: // global       -- already WHNF+           _sqJ::P64 = R1;+           _cqX::P64 = _sqJ::P64 & 7;  -- extract pointer tag+           switch [1 .. 7] _cqX::P64 {+               case 3 : goto cqW;+               case 7 : goto cqR;+               default: {goto cqS;}+           }+       cqR: // global+           _cr2 = I32[I64[_sqJ::P64 & (-8)] - 4]; -- tag from info pointer+           switch [6 .. 8] _cr2::I64 {+               case 8 : goto cr1;+               default: {goto cr0;}+           }+       cr1: // global+           R1 = GHC.Types.True_closure+2;+           call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8;+       cr0: // global     -- technically necessary label+           goto cqS;+       cqW: // global+           R1 = GHC.Types.True_closure+2;+           call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8;+       cqS: // global+           R1 = GHC.Types.False_closure+1;+           call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8;+-}+--+-- For 32-bit systems we only have 2 tag bits in the pointers at our disposal,+-- so the performance win is dubious, especially in face of the increased code+-- size due to double switching. But we can take the viewpoint that 32-bit+-- architectures are not relevant for performance any more, so this can be+-- considered as moot. + -- Note [alg-alt heap check] -- -- In an algebraic case with more than one alternative, we will have@@ -675,6 +800,55 @@ --   x = R1 --   goto L1 ++-- Note [Tagging big families]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Both the big and the small constructor families are tagged,+-- that is, greater unions which overflow the tag space of TAG_BITS+-- (i.e. 3 on 32 resp. 7 constructors on 64 bit archs).+--+-- For example, let's assume a 64-bit architecture, so that all+-- heap objects are 8-byte aligned, and hence the address of a+-- heap object ends in `000` (three zero bits).  Then consider+-- > data Maybe a = Nothing | Just a+-- > data Day a = Mon | Tue | Wed | Thu | Fri | Sat | Sun+-- > data Grade = G1 | G2 | G3 | G4 | G5 | G6 | G7 | G8 | G9 | G10+--+-- Since `Grade` has more than 7 constructors, it counts as a+-- "big data type" (also referred to as "big constructor family" in papers).+-- On the other hand, `Maybe` and `Day` have 7 constructors or fewer, so they+-- are "small data types".+--+-- Then+--   * A pointer to an unevaluated thunk of type `Maybe Int`, `Day` or `Grade` will end in `000`+--   * A tagged pointer to a `Nothing`, `Mon` or `G1` will end in `001`+--   * A tagged pointer to a `Just x`, `Tue` or `G2`  will end in `010`+--   * A tagged pointer to `Wed` or `G3` will end in `011`+--       ...+--   * A tagged pointer to `Sat` or `G6` will end in `110`+--   * A tagged pointer to `Sun` or `G7` or `G8` or `G9` or `G10` will end in `111`+--+-- For big families we employ a mildly clever way of combining pointer and+-- info-table tagging. We use 1..MAX_PTR_TAG-1 as pointer-resident tags where+-- the tags in the pointer and the info table are in a one-to-one+-- relation, whereas tag MAX_PTR_TAG is used as "spill over", signifying+-- we have to fall back and get the precise constructor tag from the+-- info-table.+--+-- Consequently we now cascade switches, because we have to check+-- the pointer tag first, and when it is MAX_PTR_TAG, fetch the precise+-- tag from the info table, and switch on that. The only technically+-- tricky part is that the default case needs (logical) duplication.+-- To do this we emit an extra label for it and branch to that from+-- the second switch. This avoids duplicated codegen. See Trac #14373.+-- See note [Double switching for big families] for the mechanics+-- involved.+--+-- Also see note [Data constructor dynamic tags]+-- and the wiki https://gitlab.haskell.org/ghc/ghc/wikis/commentary/rts/haskell-execution/pointer-tagging+--+ ------------------- cgAlgAltRhss :: (GcPlan,ReturnKind) -> NonVoid Id -> [CgStgAlt]              -> FCode ( Maybe CmmAGraphScoped@@ -708,7 +882,7 @@         maybeAltHeapCheck gc_plan $         do { _ <- bindConArgs con base_reg (assertNonVoidIds bndrs)                     -- alt binders are always non-void,-                    -- see Note [Post-unarisation invariants] in UnariseStg+                    -- see Note [Post-unarisation invariants] in GHC.Stg.Unarise            ; _ <- cgExpr rhs            ; return con }   forkAlts (map cg_alt alts)@@ -736,7 +910,7 @@     do  { (idinfo, fcode_init) <- buildDynCon (dataConWorkId con) False                                      currentCCS con (assertNonVoidStgArgs stg_args)                                      -- con args are always non-void,-                                     -- see Note [Post-unarisation invariants] in UnariseStg+                                     -- see Note [Post-unarisation invariants] in GHC.Stg.Unarise                 -- The first "con" says that the name bound to this                 -- closure is "con", which is a bit of a fudge, but                 -- it only affects profiling (hence the False)
compiler/GHC/StgToCmm/Foreign.hs view
@@ -20,7 +20,7 @@  import GhcPrelude hiding( succ, (<*>) ) -import StgSyn+import GHC.Stg.Syntax import GHC.StgToCmm.Prof (storeCurCCS, ccsType) import GHC.StgToCmm.Env import GHC.StgToCmm.Monad@@ -33,7 +33,7 @@ import CmmUtils import MkGraph import Type-import RepType+import GHC.Types.RepType import CLabel import SMRep import ForeignCall
compiler/GHC/StgToCmm/Heap.hs view
@@ -22,7 +22,7 @@  import GhcPrelude hiding ((<*>)) -import StgSyn+import GHC.Stg.Syntax import CLabel import GHC.StgToCmm.Layout import GHC.StgToCmm.Utils
compiler/GHC/StgToCmm/Layout.hs view
@@ -48,7 +48,7 @@ import CmmUtils import CmmInfo import CLabel-import StgSyn+import GHC.Stg.Syntax import Id import TyCon             ( PrimRep(..), primRepSizeB ) import BasicTypes        ( RepArity )
compiler/GHC/StgToCmm/Prim.hs view
@@ -40,7 +40,7 @@ import BasicTypes import BlockId import MkGraph-import StgSyn+import GHC.Stg.Syntax import Cmm import Module   ( rtsUnitId ) import Type     ( Type, tyConAppTyCon )@@ -1426,10 +1426,17 @@     if ncg && (x86ish || ppc) || llvm     then Left (MO_U_Mul2     (wordWidth dflags))     else Right genericWordMul2Op++  IntMul2Op  -> \_ -> OpDest_CallishHandledLater $+    if ncg && x86ish+    then Left (MO_S_Mul2     (wordWidth dflags))+    else Right genericIntMul2Op+   FloatFabsOp -> \_ -> OpDest_CallishHandledLater $     if (ncg && x86ish || ppc) || llvm     then Left MO_F32_Fabs     else Right $ genericFabsOp W32+   DoubleFabsOp -> \_ -> OpDest_CallishHandledLater $     if (ncg && x86ish || ppc) || llvm     then Left MO_F64_Fabs@@ -1869,6 +1876,31 @@                         topHalf (CmmReg xlyh),                         topHalf (CmmReg r)])] genericWordMul2Op _ _ = panic "genericWordMul2Op"++genericIntMul2Op :: GenericOp+genericIntMul2Op [res_c, res_h, res_l] [arg_x, arg_y]+ = do dflags <- getDynFlags+      -- Implement algorithm from Hacker's Delight, 2nd edition, p.174+      let t = cmmExprType dflags arg_x+      p   <- newTemp t+      -- 1) compute the multiplication as if numbers were unsigned+      let wordMul2 = fromMaybe (panic "Unsupported out-of-line WordMul2Op")+                               (emitPrimOp dflags WordMul2Op [arg_x,arg_y])+      wordMul2 [p,res_l]+      -- 2) correct the high bits of the unsigned result+      let carryFill x = CmmMachOp (MO_S_Shr ww) [x, wwm1]+          sub x y     = CmmMachOp (MO_Sub   ww) [x, y]+          and x y     = CmmMachOp (MO_And   ww) [x, y]+          neq x y     = CmmMachOp (MO_Ne    ww) [x, y]+          f   x y     = (carryFill x) `and` y+          wwm1        = CmmLit (CmmInt (fromIntegral (widthInBits ww - 1)) ww)+          rl x        = CmmReg (CmmLocal x)+          ww          = wordWidth dflags+      emit $ catAGraphs+             [ mkAssign (CmmLocal res_h) (rl p `sub` f arg_x arg_y `sub` f arg_y arg_x)+             , mkAssign (CmmLocal res_c) (rl res_h `neq` carryFill (rl res_l))+             ]+genericIntMul2Op _ _ = panic "genericIntMul2Op"  -- This replicates what we had in libraries/base/GHC/Float.hs: --
compiler/GHC/StgToCmm/Ticky.hs view
@@ -111,7 +111,7 @@ import GHC.StgToCmm.Utils import GHC.StgToCmm.Monad -import StgSyn+import GHC.Stg.Syntax import CmmExpr import MkGraph import CmmUtils
compiler/GHC/StgToCmm/Utils.hs view
@@ -75,7 +75,7 @@ import DynFlags import FastString import Outputable-import RepType+import GHC.Types.RepType  import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as BS8
compiler/cmm/CmmMachOp.hs view
@@ -583,6 +583,7 @@    | MO_UF_Conv Width +  | MO_S_Mul2    Width   | MO_S_QuotRem Width   | MO_U_QuotRem Width   | MO_U_QuotRem2 Width
compiler/cmm/CmmPipeline.hs view
@@ -45,7 +45,7 @@      tops <- {-# SCC "tops" #-} mapM (cpsTop hsc_env) prog       (srtInfo, cmms) <- {-# SCC "doSRTs" #-} doSRTs dflags srtInfo tops-     dumpWith dflags Opt_D_dump_cmm_cps "Post CPS Cmm" (ppr cmms)+     dumpWith dflags Opt_D_dump_cmm_cps "Post CPS Cmm" FormatCMM (ppr cmms)       return (srtInfo, cmms) @@ -92,7 +92,7 @@                pp <- {-# SCC "minimalProcPointSet" #-} runUniqSM $                   minimalProcPointSet (targetPlatform dflags) call_pps g                dumpWith dflags Opt_D_dump_cmm_proc "Proc points"-                     (ppr l $$ ppr pp $$ ppr g)+                     FormatCMM (ppr l $$ ppr pp $$ ppr g)                return pp              else                return call_pps@@ -112,15 +112,15 @@         ------------- CAF analysis ----------------------------------------------        let cafEnv = {-# SCC "cafAnal" #-} cafAnal call_pps l g-       dumpWith dflags Opt_D_dump_cmm_caf "CAFEnv" (ppr cafEnv)+       dumpWith dflags Opt_D_dump_cmm_caf "CAFEnv" FormatText (ppr cafEnv)         g <- if splitting_proc_points             then do                ------------- Split into separate procedures -----------------------                let pp_map = {-# SCC "procPointAnalysis" #-}                             procPointAnalysis proc_points g-               dumpWith dflags Opt_D_dump_cmm_procmap "procpoint map" $-                    ppr pp_map+               dumpWith dflags Opt_D_dump_cmm_procmap "procpoint map"+                  FormatCMM (ppr pp_map)                g <- {-# SCC "splitAtProcPoints" #-} runUniqSM $                     splitAtProcPoints dflags l call_pps proc_points pp_map                                       (CmmProc h l v g)@@ -151,7 +151,7 @@         dump = dumpGraph dflags          dumps flag name-           = mapM_ (dumpWith dflags flag name . ppr)+           = mapM_ (dumpWith dflags flag name FormatCMM . ppr)          condPass flag pass g dumpflag dumpname =             if gopt flag dflags@@ -347,7 +347,7 @@ dumpGraph :: DynFlags -> DumpFlag -> String -> CmmGraph -> IO () dumpGraph dflags flag name g = do   when (gopt Opt_DoCmmLinting dflags) $ do_lint g-  dumpWith dflags flag name (ppr g)+  dumpWith dflags flag name FormatCMM (ppr g)  where   do_lint g = case cmmLintGraph dflags g of                  Just err -> do { fatalErrorMsg dflags err@@ -355,12 +355,13 @@                                 }                  Nothing  -> return () -dumpWith :: DynFlags -> DumpFlag -> String -> SDoc -> IO ()-dumpWith dflags flag txt sdoc = do-  dumpIfSet_dyn dflags flag txt sdoc+dumpWith :: DynFlags -> DumpFlag -> String -> DumpFormat -> SDoc -> IO ()+dumpWith dflags flag txt fmt sdoc = do+  dumpIfSet_dyn dflags flag txt fmt sdoc   when (not (dopt flag dflags)) $     -- If `-ddump-cmm-verbose -ddump-to-file` is specified,     -- dump each Cmm pipeline stage output to a separate file.  #16930     when (dopt Opt_D_dump_cmm_verbose dflags)-      $ dumpSDoc dflags alwaysQualify flag txt sdoc-  dumpIfSet_dyn dflags Opt_D_dump_cmm_verbose_by_proc txt sdoc+      $ dumpAction dflags (mkDumpStyle dflags alwaysQualify)+                   (dumpOptionsFromFlag flag) txt fmt sdoc+  dumpIfSet_dyn dflags Opt_D_dump_cmm_verbose_by_proc txt fmt sdoc
compiler/cmm/CmmUtils.hs view
@@ -71,7 +71,7 @@ import GhcPrelude  import TyCon    ( PrimRep(..), PrimElemRep(..) )-import RepType  ( UnaryType, SlotTy (..), typePrimRep1 )+import GHC.Types.RepType  ( UnaryType, SlotTy (..), typePrimRep1 )  import SMRep import Cmm
compiler/cmm/MkGraph.hs view
@@ -151,7 +151,7 @@ catAGraphs     :: [CmmAGraph] -> CmmAGraph catAGraphs      = concatOL --- | created a sequence "goto id; id:" as an AGraph+-- | creates a sequence "goto id; id:" as an AGraph mkLabel        :: BlockId -> CmmTickScope -> CmmAGraph mkLabel bid scp = unitOL (CgLabel bid scp) @@ -159,7 +159,7 @@ mkMiddle        :: CmmNode O O -> CmmAGraph mkMiddle middle = unitOL (CgStmt middle) --- | created a closed AGraph from a given node+-- | creates a closed AGraph from a given node mkLast         :: CmmNode O C -> CmmAGraph mkLast last     = unitOL (CgLast last) 
compiler/cmm/PprC.hs view
@@ -825,6 +825,7 @@         (MO_AtomicWrite w) -> ptext (sLit $ atomicWriteLabel w)         (MO_UF_Conv w)  -> ptext (sLit $ word2FloatLabel w) +        MO_S_Mul2     {} -> unsupported         MO_S_QuotRem  {} -> unsupported         MO_U_QuotRem  {} -> unsupported         MO_U_QuotRem2 {} -> unsupported
compiler/coreSyn/CoreLint.hs view
@@ -47,7 +47,7 @@ import Coercion import SrcLoc import Type-import RepType+import GHC.Types.RepType import TyCoRep       -- checks validity of types/coercions import TyCoSubst import TyCoFVs@@ -259,8 +259,10 @@                -> CoreProgram -> [CoreRule]                -> IO () dumpPassResult dflags unqual mb_flag hdr extra_info binds rules-  = do { forM_ mb_flag $ \flag ->-           Err.dumpSDoc dflags unqual flag (showSDoc dflags hdr) dump_doc+  = do { forM_ mb_flag $ \flag -> do+           let sty = mkDumpStyle dflags unqual+           dumpAction dflags sty (dumpOptionsFromFlag flag)+              (showSDoc dflags hdr) FormatCore dump_doc           -- Report result size          -- This has the side effect of forcing the intermediate to be evaluated@@ -2367,7 +2369,7 @@                             2 (pprBndr LetBind id_occ)     bad_global id_bnd = isGlobalId id_occ                      && isLocalId id_bnd-                     && not (isWiredInName (idName id_occ))+                     && not (isWiredIn id_occ)        -- 'bad_global' checks for the case where an /occurrence/ is        -- a GlobalId, but there is an enclosing binding fora a LocalId.        -- NB: the in-scope variables are mostly LocalIds, checked by lintIdBndr,
− compiler/coreSyn/CorePrep.hs
@@ -1,1734 +0,0 @@-{--(c) The University of Glasgow, 1994-2006---Core pass to saturate constructors and PrimOps--}--{-# LANGUAGE BangPatterns, CPP, MultiWayIf #-}--module CorePrep (-      corePrepPgm, corePrepExpr, cvtLitInteger, cvtLitNatural,-      lookupMkIntegerName, lookupIntegerSDataConName,-      lookupMkNaturalName, lookupNaturalSDataConName-  ) where--#include "HsVersions.h"--import GhcPrelude--import OccurAnal--import HscTypes-import PrelNames-import MkId             ( realWorldPrimId )-import CoreUtils-import CoreArity-import CoreFVs-import CoreMonad        ( CoreToDo(..) )-import CoreLint         ( endPassIO )-import CoreSyn-import CoreSubst-import MkCore hiding( FloatBind(..) )   -- We use our own FloatBind here-import Type-import Literal-import Coercion-import TcEnv-import TyCon-import Demand-import Var-import VarSet-import VarEnv-import Id-import IdInfo-import TysWiredIn-import DataCon-import BasicTypes-import Module-import UniqSupply-import Maybes-import OrdList-import ErrUtils-import DynFlags-import Util-import Pair-import Outputable-import GHC.Platform-import FastString-import Name             ( NamedThing(..), nameSrcSpan )-import SrcLoc           ( SrcSpan(..), realSrcLocSpan, mkRealSrcLoc )-import Data.Bits-import MonadUtils       ( mapAccumLM )-import Data.List        ( mapAccumL )-import Control.Monad-import CostCentre       ( CostCentre, ccFromThisModule )-import qualified Data.Set as S--{---- ------------------------------------------------------------------------------ Note [CorePrep Overview]--- -----------------------------------------------------------------------------The goal of this pass is to prepare for code generation.--1.  Saturate constructor applications.--2.  Convert to A-normal form; that is, function arguments-    are always variables.--    * Use case for strict arguments:-        f E ==> case E of x -> f x-        (where f is strict)--    * Use let for non-trivial lazy arguments-        f E ==> let x = E in f x-        (were f is lazy and x is non-trivial)--3.  Similarly, convert any unboxed lets into cases.-    [I'm experimenting with leaving 'ok-for-speculation'-     rhss in let-form right up to this point.]--4.  Ensure that *value* lambdas only occur as the RHS of a binding-    (The code generator can't deal with anything else.)-    Type lambdas are ok, however, because the code gen discards them.--5.  [Not any more; nuked Jun 2002] Do the seq/par munging.--6.  Clone all local Ids.-    This means that all such Ids are unique, rather than the-    weaker guarantee of no clashes which the simplifier provides.-    And that is what the code generator needs.--    We don't clone TyVars or CoVars. The code gen doesn't need that,-    and doing so would be tiresome because then we'd need-    to substitute in types and coercions.--7.  Give each dynamic CCall occurrence a fresh unique; this is-    rather like the cloning step above.--8.  Inject bindings for the "implicit" Ids:-        * Constructor wrappers-        * Constructor workers-    We want curried definitions for all of these in case they-    aren't inlined by some caller.--9.  Replace (lazy e) by e.  See Note [lazyId magic] in MkId.hs-    Also replace (noinline e) by e.--10. Convert (LitInteger i t) into the core representation-    for the Integer i. Normally this uses mkInteger, but if-    we are using the integer-gmp implementation then there is a-    special case where we use the S# constructor for Integers that-    are in the range of Int.--11. Same for LitNatural.--12. Uphold tick consistency while doing this: We move ticks out of-    (non-type) applications where we can, and make sure that we-    annotate according to scoping rules when floating.--13. Collect cost centres (including cost centres in unfoldings) if we're in-    profiling mode. We have to do this here beucase we won't have unfoldings-    after this pass (see `zapUnfolding` and Note [Drop unfoldings and rules].--This is all done modulo type applications and abstractions, so that-when type erasure is done for conversion to STG, we don't end up with-any trivial or useless bindings.---Note [CorePrep invariants]-~~~~~~~~~~~~~~~~~~~~~~~~~~-Here is the syntax of the Core produced by CorePrep:--    Trivial expressions-       arg ::= lit |  var-              | arg ty  |  /\a. arg-              | truv co  |  /\c. arg  |  arg |> co--    Applications-       app ::= lit  |  var  |  app arg  |  app ty  | app co | app |> co--    Expressions-       body ::= app-              | let(rec) x = rhs in body     -- Boxed only-              | case body of pat -> body-              | /\a. body | /\c. body-              | body |> co--    Right hand sides (only place where value lambdas can occur)-       rhs ::= /\a.rhs  |  \x.rhs  |  body--We define a synonym for each of these non-terminals.  Functions-with the corresponding name produce a result in that syntax.--}--type CpeArg  = CoreExpr    -- Non-terminal 'arg'-type CpeApp  = CoreExpr    -- Non-terminal 'app'-type CpeBody = CoreExpr    -- Non-terminal 'body'-type CpeRhs  = CoreExpr    -- Non-terminal 'rhs'--{--************************************************************************-*                                                                      *-                Top level stuff-*                                                                      *-************************************************************************--}--corePrepPgm :: HscEnv -> Module -> ModLocation -> CoreProgram -> [TyCon]-            -> IO (CoreProgram, S.Set CostCentre)-corePrepPgm hsc_env this_mod mod_loc binds data_tycons =-    withTiming dflags-               (text "CorePrep"<+>brackets (ppr this_mod))-               (const ()) $ do-    us <- mkSplitUniqSupply 's'-    initialCorePrepEnv <- mkInitialCorePrepEnv dflags hsc_env--    let cost_centres-          | WayProf `elem` ways dflags-          = collectCostCentres this_mod binds-          | otherwise-          = S.empty--        implicit_binds = mkDataConWorkers dflags mod_loc data_tycons-            -- NB: we must feed mkImplicitBinds through corePrep too-            -- so that they are suitably cloned and eta-expanded--        binds_out = initUs_ us $ do-                      floats1 <- corePrepTopBinds initialCorePrepEnv binds-                      floats2 <- corePrepTopBinds initialCorePrepEnv implicit_binds-                      return (deFloatTop (floats1 `appendFloats` floats2))--    endPassIO hsc_env alwaysQualify CorePrep binds_out []-    return (binds_out, cost_centres)-  where-    dflags = hsc_dflags hsc_env--corePrepExpr :: DynFlags -> HscEnv -> CoreExpr -> IO CoreExpr-corePrepExpr dflags hsc_env expr =-    withTiming dflags (text "CorePrep [expr]") (const ()) $ do-    us <- mkSplitUniqSupply 's'-    initialCorePrepEnv <- mkInitialCorePrepEnv dflags hsc_env-    let new_expr = initUs_ us (cpeBodyNF initialCorePrepEnv expr)-    dumpIfSet_dyn dflags Opt_D_dump_prep "CorePrep" (ppr new_expr)-    return new_expr--corePrepTopBinds :: CorePrepEnv -> [CoreBind] -> UniqSM Floats--- Note [Floating out of top level bindings]-corePrepTopBinds initialCorePrepEnv binds-  = go initialCorePrepEnv binds-  where-    go _   []             = return emptyFloats-    go env (bind : binds) = do (env', floats, maybe_new_bind)-                                 <- cpeBind TopLevel env bind-                               MASSERT(isNothing maybe_new_bind)-                                 -- Only join points get returned this way by-                                 -- cpeBind, and no join point may float to top-                               floatss <- go env' binds-                               return (floats `appendFloats` floatss)--mkDataConWorkers :: DynFlags -> ModLocation -> [TyCon] -> [CoreBind]--- See Note [Data constructor workers]--- c.f. Note [Injecting implicit bindings] in TidyPgm-mkDataConWorkers dflags mod_loc data_tycons-  = [ NonRec id (tick_it (getName data_con) (Var id))-                                -- The ice is thin here, but it works-    | tycon <- data_tycons,     -- CorePrep will eta-expand it-      data_con <- tyConDataCons tycon,-      let id = dataConWorkId data_con-    ]- where-   -- If we want to generate debug info, we put a source note on the-   -- worker. This is useful, especially for heap profiling.-   tick_it name-     | debugLevel dflags == 0                = id-     | RealSrcSpan span <- nameSrcSpan name  = tick span-     | Just file <- ml_hs_file mod_loc       = tick (span1 file)-     | otherwise                             = tick (span1 "???")-     where tick span  = Tick (SourceNote span $ showSDoc dflags (ppr name))-           span1 file = realSrcLocSpan $ mkRealSrcLoc (mkFastString file) 1 1--{--Note [Floating out of top level bindings]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-NB: we do need to float out of top-level bindings-Consider        x = length [True,False]-We want to get-                s1 = False : []-                s2 = True  : s1-                x  = length s2--We return a *list* of bindings, because we may start with-        x* = f (g y)-where x is demanded, in which case we want to finish with-        a = g y-        x* = f a-And then x will actually end up case-bound--Note [CafInfo and floating]-~~~~~~~~~~~~~~~~~~~~~~~~~~~-What happens when we try to float bindings to the top level?  At this-point all the CafInfo is supposed to be correct, and we must make certain-that is true of the new top-level bindings.  There are two cases-to consider--a) The top-level binding is marked asCafRefs.  In that case we are-   basically fine.  The floated bindings had better all be lazy lets,-   so they can float to top level, but they'll all have HasCafRefs-   (the default) which is safe.--b) The top-level binding is marked NoCafRefs.  This really happens-   Example.  CoreTidy produces-      $fApplicativeSTM [NoCafRefs] = D:Alternative retry# ...blah...-   Now CorePrep has to eta-expand to-      $fApplicativeSTM = let sat = \xy. retry x y-                         in D:Alternative sat ...blah...-   So what we *want* is-      sat [NoCafRefs] = \xy. retry x y-      $fApplicativeSTM [NoCafRefs] = D:Alternative sat ...blah...--   So, gruesomely, we must set the NoCafRefs flag on the sat bindings,-   *and* substitute the modified 'sat' into the old RHS.--   It should be the case that 'sat' is itself [NoCafRefs] (a value, no-   cafs) else the original top-level binding would not itself have been-   marked [NoCafRefs].  The DEBUG check in CoreToStg for-   consistentCafInfo will find this.--This is all very gruesome and horrible. It would be better to figure-out CafInfo later, after CorePrep.  We'll do that in due course.-Meanwhile this horrible hack works.--Note [Join points and floating]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Join points can float out of other join points but not out of value bindings:--  let z =-    let  w = ... in -- can float-    join k = ... in -- can't float-    ... jump k ...-  join j x1 ... xn =-    let  y = ... in -- can float (but don't want to)-    join h = ... in -- can float (but not much point)-    ... jump h ...-  in ...--Here, the jump to h remains valid if h is floated outward, but the jump to k-does not.--We don't float *out* of join points. It would only be safe to float out of-nullary join points (or ones where the arguments are all either type arguments-or dead binders). Nullary join points aren't ever recursive, so they're always-effectively one-shot functions, which we don't float out of. We *could* float-join points from nullary join points, but there's no clear benefit at this-stage.--Note [Data constructor workers]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Create any necessary "implicit" bindings for data con workers.  We-create the rather strange (non-recursive!) binding--        $wC = \x y -> $wC x y--i.e. a curried constructor that allocates.  This means that we can-treat the worker for a constructor like any other function in the rest-of the compiler.  The point here is that CoreToStg will generate a-StgConApp for the RHS, rather than a call to the worker (which would-give a loop).  As Lennart says: the ice is thin here, but it works.--Hmm.  Should we create bindings for dictionary constructors?  They are-always fully applied, and the bindings are just there to support-partial applications. But it's easier to let them through.---Note [Dead code in CorePrep]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Imagine that we got an input program like this (see #4962):--  f :: Show b => Int -> (Int, b -> Maybe Int -> Int)-  f x = (g True (Just x) + g () (Just x), g)-    where-      g :: Show a => a -> Maybe Int -> Int-      g _ Nothing = x-      g y (Just z) = if z > 100 then g y (Just (z + length (show y))) else g y unknown--After specialisation and SpecConstr, we would get something like this:--  f :: Show b => Int -> (Int, b -> Maybe Int -> Int)-  f x = (g$Bool_True_Just x + g$Unit_Unit_Just x, g)-    where-      {-# RULES g $dBool = g$Bool-                g $dUnit = g$Unit #-}-      g = ...-      {-# RULES forall x. g$Bool True (Just x) = g$Bool_True_Just x #-}-      g$Bool = ...-      {-# RULES forall x. g$Unit () (Just x) = g$Unit_Unit_Just x #-}-      g$Unit = ...-      g$Bool_True_Just = ...-      g$Unit_Unit_Just = ...--Note that the g$Bool and g$Unit functions are actually dead code: they-are only kept alive by the occurrence analyser because they are-referred to by the rules of g, which is being kept alive by the fact-that it is used (unspecialised) in the returned pair.--However, at the CorePrep stage there is no way that the rules for g-will ever fire, and it really seems like a shame to produce an output-program that goes to the trouble of allocating a closure for the-unreachable g$Bool and g$Unit functions.--The way we fix this is to:- * In cloneBndr, drop all unfoldings/rules-- * In deFloatTop, run a simple dead code analyser on each top-level-   RHS to drop the dead local bindings. For that call to OccAnal, we-   disable the binder swap, else the occurrence analyser sometimes-   introduces new let bindings for cased binders, which lead to the bug-   in #5433.--The reason we don't just OccAnal the whole output of CorePrep is that-the tidier ensures that all top-level binders are GlobalIds, so they-don't show up in the free variables any longer. So if you run the-occurrence analyser on the output of CoreTidy (or later) you e.g. turn-this program:--  Rec {-  f = ... f ...-  }--Into this one:--  f = ... f ...--(Since f is not considered to be free in its own RHS.)---************************************************************************-*                                                                      *-                The main code-*                                                                      *-************************************************************************--}--cpeBind :: TopLevelFlag -> CorePrepEnv -> CoreBind-        -> UniqSM (CorePrepEnv,-                   Floats,         -- Floating value bindings-                   Maybe CoreBind) -- Just bind' <=> returned new bind; no float-                                   -- Nothing <=> added bind' to floats instead-cpeBind top_lvl env (NonRec bndr rhs)-  | not (isJoinId bndr)-  = do { (_, bndr1) <- cpCloneBndr env bndr-       ; let dmd         = idDemandInfo bndr-             is_unlifted = isUnliftedType (idType bndr)-       ; (floats, rhs1) <- cpePair top_lvl NonRecursive-                                   dmd is_unlifted-                                   env bndr1 rhs-       -- See Note [Inlining in CorePrep]-       ; if exprIsTrivial rhs1 && isNotTopLevel top_lvl-            then return (extendCorePrepEnvExpr env bndr rhs1, floats, Nothing)-            else do {--       ; let new_float = mkFloat dmd is_unlifted bndr1 rhs1--       ; return (extendCorePrepEnv env bndr bndr1,-                 addFloat floats new_float,-                 Nothing) }}--  | otherwise -- A join point; see Note [Join points and floating]-  = ASSERT(not (isTopLevel top_lvl)) -- can't have top-level join point-    do { (_, bndr1) <- cpCloneBndr env bndr-       ; (bndr2, rhs1) <- cpeJoinPair env bndr1 rhs-       ; return (extendCorePrepEnv env bndr bndr2,-                 emptyFloats,-                 Just (NonRec bndr2 rhs1)) }--cpeBind top_lvl env (Rec pairs)-  | not (isJoinId (head bndrs))-  = do { (env', bndrs1) <- cpCloneBndrs env bndrs-       ; stuff <- zipWithM (cpePair top_lvl Recursive topDmd False env')-                           bndrs1 rhss--       ; let (floats_s, rhss1) = unzip stuff-             all_pairs = foldrOL add_float (bndrs1 `zip` rhss1)-                                           (concatFloats floats_s)--       ; return (extendCorePrepEnvList env (bndrs `zip` bndrs1),-                 unitFloat (FloatLet (Rec all_pairs)),-                 Nothing) }--  | otherwise -- See Note [Join points and floating]-  = do { (env', bndrs1) <- cpCloneBndrs env bndrs-       ; pairs1 <- zipWithM (cpeJoinPair env') bndrs1 rhss--       ; let bndrs2 = map fst pairs1-       ; return (extendCorePrepEnvList env' (bndrs `zip` bndrs2),-                 emptyFloats,-                 Just (Rec pairs1)) }-  where-    (bndrs, rhss) = unzip pairs--        -- Flatten all the floats, and the current-        -- group into a single giant Rec-    add_float (FloatLet (NonRec b r)) prs2 = (b,r) : prs2-    add_float (FloatLet (Rec prs1))   prs2 = prs1 ++ prs2-    add_float b                       _    = pprPanic "cpeBind" (ppr b)------------------cpePair :: TopLevelFlag -> RecFlag -> Demand -> Bool-        -> CorePrepEnv -> OutId -> CoreExpr-        -> UniqSM (Floats, CpeRhs)--- Used for all bindings--- The binder is already cloned, hence an OutId-cpePair top_lvl is_rec dmd is_unlifted env bndr rhs-  = ASSERT(not (isJoinId bndr)) -- those should use cpeJoinPair-    do { (floats1, rhs1) <- cpeRhsE env rhs--       -- See if we are allowed to float this stuff out of the RHS-       ; (floats2, rhs2) <- float_from_rhs floats1 rhs1--       -- Make the arity match up-       ; (floats3, rhs3)-            <- if manifestArity rhs1 <= arity-               then return (floats2, cpeEtaExpand arity rhs2)-               else WARN(True, text "CorePrep: silly extra arguments:" <+> ppr bndr)-                               -- Note [Silly extra arguments]-                    (do { v <- newVar (idType bndr)-                        ; let float = mkFloat topDmd False v rhs2-                        ; return ( addFloat floats2 float-                                 , cpeEtaExpand arity (Var v)) })--        -- Wrap floating ticks-       ; let (floats4, rhs4) = wrapTicks floats3 rhs3--       ; return (floats4, rhs4) }-  where-    platform = targetPlatform (cpe_dynFlags env)--    arity = idArity bndr        -- We must match this arity--    ----------------------    float_from_rhs floats rhs-      | isEmptyFloats floats = return (emptyFloats, rhs)-      | isTopLevel top_lvl   = float_top    floats rhs-      | otherwise            = float_nested floats rhs--    ----------------------    float_nested floats rhs-      | wantFloatNested is_rec dmd is_unlifted floats rhs-                  = return (floats, rhs)-      | otherwise = dontFloat floats rhs--    ----------------------    float_top floats rhs        -- Urhgh!  See Note [CafInfo and floating]-      | mayHaveCafRefs (idCafInfo bndr)-      , allLazyTop floats-      = return (floats, rhs)--      -- So the top-level binding is marked NoCafRefs-      | Just (floats', rhs') <- canFloatFromNoCaf platform floats rhs-      = return (floats', rhs')--      | otherwise-      = dontFloat floats rhs--dontFloat :: Floats -> CpeRhs -> UniqSM (Floats, CpeBody)--- Non-empty floats, but do not want to float from rhs--- So wrap the rhs in the floats--- But: rhs1 might have lambdas, and we can't---      put them inside a wrapBinds-dontFloat floats1 rhs-  = do { (floats2, body) <- rhsToBody rhs-        ; return (emptyFloats, wrapBinds floats1 $-                               wrapBinds floats2 body) }--{- Note [Silly extra arguments]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Suppose we had this-        f{arity=1} = \x\y. e-We *must* match the arity on the Id, so we have to generate-        f' = \x\y. e-        f  = \x. f' x--It's a bizarre case: why is the arity on the Id wrong?  Reason-(in the days of __inline_me__):-        f{arity=0} = __inline_me__ (let v = expensive in \xy. e)-When InlineMe notes go away this won't happen any more.  But-it seems good for CorePrep to be robust.--}------------------cpeJoinPair :: CorePrepEnv -> JoinId -> CoreExpr-            -> UniqSM (JoinId, CpeRhs)--- Used for all join bindings--- No eta-expansion: see Note [Do not eta-expand join points] in SimplUtils-cpeJoinPair env bndr rhs-  = ASSERT(isJoinId bndr)-    do { let Just join_arity = isJoinId_maybe bndr-             (bndrs, body)   = collectNBinders join_arity rhs--       ; (env', bndrs') <- cpCloneBndrs env bndrs--       ; body' <- cpeBodyNF env' body -- Will let-bind the body if it starts-                                      -- with a lambda--       ; let rhs'  = mkCoreLams bndrs' body'-             bndr' = bndr `setIdUnfolding` evaldUnfolding-                          `setIdArity` count isId bndrs-                            -- See Note [Arity and join points]--       ; return (bndr', rhs') }--{--Note [Arity and join points]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Up to now, we've allowed a join point to have an arity greater than its join-arity (minus type arguments), since this is what's useful for eta expansion.-However, for code gen purposes, its arity must be exactly the number of value-arguments it will be called with, and it must have exactly that many value-lambdas. Hence if there are extra lambdas we must let-bind the body of the RHS:--  join j x y z = \w -> ... in ...-    =>-  join j x y z = (let f = \w -> ... in f) in ...--This is also what happens with Note [Silly extra arguments]. Note that it's okay-for us to mess with the arity because a join point is never exported.--}---- ------------------------------------------------------------------------------              CpeRhs: produces a result satisfying CpeRhs--- -----------------------------------------------------------------------------cpeRhsE :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs)--- If---      e  ===>  (bs, e')--- then---      e = let bs in e'        (semantically, that is!)------ For example---      f (g x)   ===>   ([v = g x], f v)--cpeRhsE _env expr@(Type {})      = return (emptyFloats, expr)-cpeRhsE _env expr@(Coercion {})  = return (emptyFloats, expr)-cpeRhsE env (Lit (LitNumber LitNumInteger i _))-    = cpeRhsE env (cvtLitInteger (cpe_dynFlags env) (getMkIntegerId env)-                   (cpe_integerSDataCon env) i)-cpeRhsE env (Lit (LitNumber LitNumNatural i _))-    = cpeRhsE env (cvtLitNatural (cpe_dynFlags env) (getMkNaturalId env)-                   (cpe_naturalSDataCon env) i)-cpeRhsE _env expr@(Lit {}) = return (emptyFloats, expr)-cpeRhsE env expr@(Var {})  = cpeApp env expr-cpeRhsE env expr@(App {}) = cpeApp env expr--cpeRhsE env (Let bind body)-  = do { (env', bind_floats, maybe_bind') <- cpeBind NotTopLevel env bind-       ; (body_floats, body') <- cpeRhsE env' body-       ; let expr' = case maybe_bind' of Just bind' -> Let bind' body'-                                         Nothing    -> body'-       ; return (bind_floats `appendFloats` body_floats, expr') }--cpeRhsE env (Tick tickish expr)-  | tickishPlace tickish == PlaceNonLam && tickish `tickishScopesLike` SoftScope-  = do { (floats, body) <- cpeRhsE env expr-         -- See [Floating Ticks in CorePrep]-       ; return (unitFloat (FloatTick tickish) `appendFloats` floats, body) }-  | otherwise-  = do { body <- cpeBodyNF env expr-       ; return (emptyFloats, mkTick tickish' body) }-  where-    tickish' | Breakpoint n fvs <- tickish-             -- See also 'substTickish'-             = Breakpoint n (map (getIdFromTrivialExpr . lookupCorePrepEnv env) fvs)-             | otherwise-             = tickish--cpeRhsE env (Cast expr co)-   = do { (floats, expr') <- cpeRhsE env expr-        ; return (floats, Cast expr' co) }--cpeRhsE env expr@(Lam {})-   = do { let (bndrs,body) = collectBinders expr-        ; (env', bndrs') <- cpCloneBndrs env bndrs-        ; body' <- cpeBodyNF env' body-        ; return (emptyFloats, mkLams bndrs' body') }--cpeRhsE env (Case scrut bndr ty alts)-  = do { (floats, scrut') <- cpeBody env scrut-       ; (env', bndr2) <- cpCloneBndr env bndr-       ; let alts'-                 -- This flag is intended to aid in debugging strictness-                 -- analysis bugs. These are particularly nasty to chase down as-                 -- they may manifest as segmentation faults. When this flag is-                 -- enabled we instead produce an 'error' expression to catch-                 -- the case where a function we think should bottom-                 -- unexpectedly returns.-               | gopt Opt_CatchBottoms (cpe_dynFlags env)-               , not (altsAreExhaustive alts)-               = addDefault alts (Just err)-               | otherwise = alts-               where err = mkRuntimeErrorApp rUNTIME_ERROR_ID ty-                                             "Bottoming expression returned"-       ; alts'' <- mapM (sat_alt env') alts'-       ; return (floats, Case scrut' bndr2 ty alts'') }-  where-    sat_alt env (con, bs, rhs)-       = do { (env2, bs') <- cpCloneBndrs env bs-            ; rhs' <- cpeBodyNF env2 rhs-            ; return (con, bs', rhs') }--cvtLitInteger :: DynFlags -> Id -> Maybe DataCon -> Integer -> CoreExpr--- Here we convert a literal Integer to the low-level--- representation. Exactly how we do this depends on the--- library that implements Integer.  If it's GMP we--- use the S# data constructor for small literals.--- See Note [Integer literals] in Literal-cvtLitInteger dflags _ (Just sdatacon) i-  | inIntRange dflags i -- Special case for small integers-    = mkConApp sdatacon [Lit (mkLitInt dflags i)]--cvtLitInteger dflags mk_integer _ i-    = mkApps (Var mk_integer) [isNonNegative, ints]-  where isNonNegative = if i < 0 then mkConApp falseDataCon []-                                 else mkConApp trueDataCon  []-        ints = mkListExpr intTy (f (abs i))-        f 0 = []-        f x = let low  = x .&. mask-                  high = x `shiftR` bits-              in mkConApp intDataCon [Lit (mkLitInt dflags low)] : f high-        bits = 31-        mask = 2 ^ bits - 1--cvtLitNatural :: DynFlags -> Id -> Maybe DataCon -> Integer -> CoreExpr--- Here we convert a literal Natural to the low-level--- representation.--- See Note [Natural literals] in Literal-cvtLitNatural dflags _ (Just sdatacon) i-  | inWordRange dflags i -- Special case for small naturals-    = mkConApp sdatacon [Lit (mkLitWord dflags i)]--cvtLitNatural dflags mk_natural _ i-    = mkApps (Var mk_natural) [words]-  where words = mkListExpr wordTy (f i)-        f 0 = []-        f x = let low  = x .&. mask-                  high = x `shiftR` bits-              in mkConApp wordDataCon [Lit (mkLitWord dflags low)] : f high-        bits = 32-        mask = 2 ^ bits - 1---- ------------------------------------------------------------------------------              CpeBody: produces a result satisfying CpeBody--- ------------------------------------------------------------------------------- | Convert a 'CoreExpr' so it satisfies 'CpeBody', without--- producing any floats (any generated floats are immediately--- let-bound using 'wrapBinds').  Generally you want this, esp.--- when you've reached a binding form (e.g., a lambda) and--- floating any further would be incorrect.-cpeBodyNF :: CorePrepEnv -> CoreExpr -> UniqSM CpeBody-cpeBodyNF env expr-  = do { (floats, body) <- cpeBody env expr-       ; return (wrapBinds floats body) }---- | Convert a 'CoreExpr' so it satisfies 'CpeBody'; also produce--- a list of 'Floats' which are being propagated upwards.  In--- fact, this function is used in only two cases: to--- implement 'cpeBodyNF' (which is what you usually want),--- and in the case when a let-binding is in a case scrutinee--here,--- we can always float out:------      case (let x = y in z) of ...---      ==> let x = y in case z of ...----cpeBody :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeBody)-cpeBody env expr-  = do { (floats1, rhs) <- cpeRhsE env expr-       ; (floats2, body) <- rhsToBody rhs-       ; return (floats1 `appendFloats` floats2, body) }-----------rhsToBody :: CpeRhs -> UniqSM (Floats, CpeBody)--- Remove top level lambdas by let-binding--rhsToBody (Tick t expr)-  | tickishScoped t == NoScope  -- only float out of non-scoped annotations-  = do { (floats, expr') <- rhsToBody expr-       ; return (floats, mkTick t expr') }--rhsToBody (Cast e co)-        -- You can get things like-        --      case e of { p -> coerce t (\s -> ...) }-  = do { (floats, e') <- rhsToBody e-       ; return (floats, Cast e' co) }--rhsToBody expr@(Lam {})-  | Just no_lam_result <- tryEtaReducePrep bndrs body-  = return (emptyFloats, no_lam_result)-  | all isTyVar bndrs           -- Type lambdas are ok-  = return (emptyFloats, expr)-  | otherwise                   -- Some value lambdas-  = do { fn <- newVar (exprType expr)-       ; let rhs   = cpeEtaExpand (exprArity expr) expr-             float = FloatLet (NonRec fn rhs)-       ; return (unitFloat float, Var fn) }-  where-    (bndrs,body) = collectBinders expr--rhsToBody expr = return (emptyFloats, expr)------ ------------------------------------------------------------------------------              CpeApp: produces a result satisfying CpeApp--- -----------------------------------------------------------------------------data ArgInfo = CpeApp  CoreArg-             | CpeCast Coercion-             | CpeTick (Tickish Id)--{- Note [runRW arg]-~~~~~~~~~~~~~~~~~~~-If we got, say-   runRW# (case bot of {})-which happened in #11291, we do /not/ want to turn it into-   (case bot of {}) realWorldPrimId#-because that gives a panic in CoreToStg.myCollectArgs, which expects-only variables in function position.  But if we are sure to make-runRW# strict (which we do in MkId), this can't happen--}--cpeApp :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs)--- May return a CpeRhs because of saturating primops-cpeApp top_env expr-  = do { let (terminal, args, depth) = collect_args expr-       ; cpe_app top_env terminal args depth-       }--  where-    -- We have a nested data structure of the form-    -- e `App` a1 `App` a2 ... `App` an, convert it into-    -- (e, [CpeApp a1, CpeApp a2, ..., CpeApp an], depth)-    -- We use 'ArgInfo' because we may also need to-    -- record casts and ticks.  Depth counts the number-    -- of arguments that would consume strictness information-    -- (so, no type or coercion arguments.)-    collect_args :: CoreExpr -> (CoreExpr, [ArgInfo], Int)-    collect_args e = go e [] 0-      where-        go (App fun arg)      as !depth-            = go fun (CpeApp arg : as)-                (if isTyCoArg arg then depth else depth + 1)-        go (Cast fun co)      as depth-            = go fun (CpeCast co : as) depth-        go (Tick tickish fun) as depth-            | tickishPlace tickish == PlaceNonLam-            && tickish `tickishScopesLike` SoftScope-            = go fun (CpeTick tickish : as) depth-        go terminal as depth = (terminal, as, depth)--    cpe_app :: CorePrepEnv-            -> CoreExpr-            -> [ArgInfo]-            -> Int-            -> UniqSM (Floats, CpeRhs)-    cpe_app env (Var f) (CpeApp Type{} : CpeApp arg : args) depth-        | f `hasKey` lazyIdKey          -- Replace (lazy a) with a, and-       || f `hasKey` noinlineIdKey      -- Replace (noinline a) with a-        -- Consider the code:-        ---        --      lazy (f x) y-        ---        -- We need to make sure that we need to recursively collect arguments on-        -- "f x", otherwise we'll float "f x" out (it's not a variable) and-        -- end up with this awful -ddump-prep:-        ---        --      case f x of f_x {-        --        __DEFAULT -> f_x y-        --      }-        ---        -- rather than the far superior "f x y".  Test case is par01.-        = let (terminal, args', depth') = collect_args arg-          in cpe_app env terminal (args' ++ args) (depth + depth' - 1)-    cpe_app env (Var f) [CpeApp _runtimeRep@Type{}, CpeApp _type@Type{}, CpeApp arg] 1-        | f `hasKey` runRWKey-        -- See Note [runRW magic]-        -- Replace (runRW# f) by (f realWorld#), beta reducing if possible (this-        -- is why we return a CorePrepEnv as well)-        = case arg of-            Lam s body -> cpe_app (extendCorePrepEnv env s realWorldPrimId) body [] 0-            _          -> cpe_app env arg [CpeApp (Var realWorldPrimId)] 1-    cpe_app env (Var v) args depth-      = do { v1 <- fiddleCCall v-           ; let e2 = lookupCorePrepEnv env v1-                 hd = getIdFromTrivialExpr_maybe e2-           -- NB: depth from collect_args is right, because e2 is a trivial expression-           -- and thus its embedded Id *must* be at the same depth as any-           -- Apps it is under are type applications only (c.f.-           -- exprIsTrivial).  But note that we need the type of the-           -- expression, not the id.-           ; (app, floats) <- rebuild_app args e2 (exprType e2) emptyFloats stricts-           ; mb_saturate hd app floats depth }-        where-          stricts = case idStrictness v of-                            StrictSig (DmdType _ demands _)-                              | listLengthCmp demands depth /= GT -> demands-                                    -- length demands <= depth-                              | otherwise                         -> []-                -- If depth < length demands, then we have too few args to-                -- satisfy strictness  info so we have to  ignore all the-                -- strictness info, e.g. + (error "urk")-                -- Here, we can't evaluate the arg strictly, because this-                -- partial application might be seq'd--        -- We inlined into something that's not a var and has no args.-        -- Bounce it back up to cpeRhsE.-    cpe_app env fun [] _ = cpeRhsE env fun--        -- N-variable fun, better let-bind it-    cpe_app env fun args depth-      = do { (fun_floats, fun') <- cpeArg env evalDmd fun ty-                          -- The evalDmd says that it's sure to be evaluated,-                          -- so we'll end up case-binding it-           ; (app, floats) <- rebuild_app args fun' ty fun_floats []-           ; mb_saturate Nothing app floats depth }-        where-          ty = exprType fun--    -- Saturate if necessary-    mb_saturate head app floats depth =-       case head of-         Just fn_id -> do { sat_app <- maybeSaturate fn_id app depth-                          ; return (floats, sat_app) }-         _other              -> return (floats, app)--    -- Deconstruct and rebuild the application, floating any non-atomic-    -- arguments to the outside.  We collect the type of the expression,-    -- the head of the application, and the number of actual value arguments,-    -- all of which are used to possibly saturate this application if it-    -- has a constructor or primop at the head.-    rebuild_app-        :: [ArgInfo]                  -- The arguments (inner to outer)-        -> CpeApp-        -> Type-        -> Floats-        -> [Demand]-        -> UniqSM (CpeApp, Floats)-    rebuild_app [] app _ floats ss = do-      MASSERT(null ss) -- make sure we used all the strictness info-      return (app, floats)-    rebuild_app (a : as) fun' fun_ty floats ss = case a of-      CpeApp arg@(Type arg_ty) ->-        rebuild_app as (App fun' arg) (piResultTy fun_ty arg_ty) floats ss-      CpeApp arg@(Coercion {}) ->-        rebuild_app as (App fun' arg) (funResultTy fun_ty) floats ss-      CpeApp arg -> do-        let (ss1, ss_rest)  -- See Note [lazyId magic] in MkId-               = case (ss, isLazyExpr arg) of-                   (_   : ss_rest, True)  -> (topDmd, ss_rest)-                   (ss1 : ss_rest, False) -> (ss1,    ss_rest)-                   ([],            _)     -> (topDmd, [])-            (arg_ty, res_ty) = expectJust "cpeBody:collect_args" $-                               splitFunTy_maybe fun_ty-        (fs, arg') <- cpeArg top_env ss1 arg arg_ty-        rebuild_app as (App fun' arg') res_ty (fs `appendFloats` floats) ss_rest-      CpeCast co ->-        let Pair _ty1 ty2 = coercionKind co-        in rebuild_app as (Cast fun' co) ty2 floats ss-      CpeTick tickish ->-        -- See [Floating Ticks in CorePrep]-        rebuild_app as fun' fun_ty (addFloat floats (FloatTick tickish)) ss--isLazyExpr :: CoreExpr -> Bool--- See Note [lazyId magic] in MkId-isLazyExpr (Cast e _)              = isLazyExpr e-isLazyExpr (Tick _ e)              = isLazyExpr e-isLazyExpr (Var f `App` _ `App` _) = f `hasKey` lazyIdKey-isLazyExpr _                       = False--{- Note [runRW magic]-~~~~~~~~~~~~~~~~~~~~~-Some definitions, for instance @runST@, must have careful control over float out-of the bindings in their body. Consider this use of @runST@,--    f x = runST ( \ s -> let (a, s')  = newArray# 100 [] s-                             (_, s'') = fill_in_array_or_something a x s'-                         in freezeArray# a s'' )--If we inline @runST@, we'll get:--    f x = let (a, s')  = newArray# 100 [] realWorld#{-NB-}-              (_, s'') = fill_in_array_or_something a x s'-          in freezeArray# a s''--And now if we allow the @newArray#@ binding to float out to become a CAF,-we end up with a result that is totally and utterly wrong:--    f = let (a, s')  = newArray# 100 [] realWorld#{-NB-} -- YIKES!!!-        in \ x ->-            let (_, s'') = fill_in_array_or_something a x s'-            in freezeArray# a s''--All calls to @f@ will share a {\em single} array! Clearly this is nonsense and-must be prevented.--This is what @runRW#@ gives us: by being inlined extremely late in the-optimization (right before lowering to STG, in CorePrep), we can ensure that-no further floating will occur. This allows us to safely inline things like-@runST@, which are otherwise needlessly expensive (see #10678 and #5916).--'runRW' is defined (for historical reasons) in GHC.Magic, with a NOINLINE-pragma.  It is levity-polymorphic.--    runRW# :: forall (r1 :: RuntimeRep). (o :: TYPE r)-           => (State# RealWorld -> (# State# RealWorld, o #))-                              -> (# State# RealWorld, o #)--It needs no special treatment in GHC except this special inlining here-in CorePrep (and in ByteCodeGen).---- ------------------------------------------------------------------------------      CpeArg: produces a result satisfying CpeArg--- -----------------------------------------------------------------------------Note [ANF-ising literal string arguments]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--Consider a program like,--    data Foo = Foo Addr#--    foo = Foo "turtle"#--When we go to ANFise this we might think that we want to float the string-literal like we do any other non-trivial argument. This would look like,--    foo = u\ [] case "turtle"# of s { __DEFAULT__ -> Foo s }--However, this 1) isn't necessary since strings are in a sense "trivial"; and 2)-wreaks havoc on the CAF annotations that we produce here since we the result-above is caffy since it is updateable. Ideally at some point in the future we-would like to just float the literal to the top level as suggested in #11312,--    s = "turtle"#-    foo = Foo s--However, until then we simply add a special case excluding literals from the-floating done by cpeArg.--}---- | Is an argument okay to CPE?-okCpeArg :: CoreExpr -> Bool--- Don't float literals. See Note [ANF-ising literal string arguments].-okCpeArg (Lit _) = False--- Do not eta expand a trivial argument-okCpeArg expr    = not (exprIsTrivial expr)---- This is where we arrange that a non-trivial argument is let-bound-cpeArg :: CorePrepEnv -> Demand-       -> CoreArg -> Type -> UniqSM (Floats, CpeArg)-cpeArg env dmd arg arg_ty-  = do { (floats1, arg1) <- cpeRhsE env arg     -- arg1 can be a lambda-       ; (floats2, arg2) <- if want_float floats1 arg1-                            then return (floats1, arg1)-                            else dontFloat floats1 arg1-                -- Else case: arg1 might have lambdas, and we can't-                --            put them inside a wrapBinds--       ; if okCpeArg arg2-         then do { v <- newVar arg_ty-                 ; let arg3      = cpeEtaExpand (exprArity arg2) arg2-                       arg_float = mkFloat dmd is_unlifted v arg3-                 ; return (addFloat floats2 arg_float, varToCoreExpr v) }-         else return (floats2, arg2)-       }-  where-    is_unlifted = isUnliftedType arg_ty-    want_float  = wantFloatNested NonRecursive dmd is_unlifted--{--Note [Floating unlifted arguments]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Consider    C (let v* = expensive in v)--where the "*" indicates "will be demanded".  Usually v will have been-inlined by now, but let's suppose it hasn't (see #2756).  Then we-do *not* want to get--     let v* = expensive in C v--because that has different strictness.  Hence the use of 'allLazy'.-(NB: the let v* turns into a FloatCase, in mkLocalNonRec.)------------------------------------------------------------------------------------ Building the saturated syntax--- -----------------------------------------------------------------------------Note [Eta expansion of hasNoBinding things in CorePrep]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-maybeSaturate deals with eta expanding to saturate things that can't deal with-unsaturated applications (identified by 'hasNoBinding', currently just-foreign calls and unboxed tuple/sum constructors).--Note that eta expansion in CorePrep is very fragile due to the "prediction" of-CAFfyness made by TidyPgm (see Note [CAFfyness inconsistencies due to eta-expansion in CorePrep] in TidyPgm for details.  We previously saturated primop-applications here as well but due to this fragility (see #16846) we now deal-with this another way, as described in Note [Primop wrappers] in PrimOp.--It's quite likely that eta expansion of constructor applications will-eventually break in a similar way to how primops did. We really should-eliminate this case as well.--}--maybeSaturate :: Id -> CpeApp -> Int -> UniqSM CpeRhs-maybeSaturate fn expr n_args-  | hasNoBinding fn        -- There's no binding-  = return sat_expr--  | otherwise-  = return expr-  where-    fn_arity     = idArity fn-    excess_arity = fn_arity - n_args-    sat_expr     = cpeEtaExpand excess_arity expr--{--************************************************************************-*                                                                      *-                Simple CoreSyn operations-*                                                                      *-************************************************************************--}--{---- --------------------------------------------------------------------------------      Eta reduction--- -------------------------------------------------------------------------------Note [Eta expansion]-~~~~~~~~~~~~~~~~~~~~~-Eta expand to match the arity claimed by the binder Remember,-CorePrep must not change arity--Eta expansion might not have happened already, because it is done by-the simplifier only when there at least one lambda already.--NB1:we could refrain when the RHS is trivial (which can happen-    for exported things).  This would reduce the amount of code-    generated (a little) and make things a little words for-    code compiled without -O.  The case in point is data constructor-    wrappers.--NB2: we have to be careful that the result of etaExpand doesn't-   invalidate any of the assumptions that CorePrep is attempting-   to establish.  One possible cause is eta expanding inside of-   an SCC note - we're now careful in etaExpand to make sure the-   SCC is pushed inside any new lambdas that are generated.--Note [Eta expansion and the CorePrep invariants]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-It turns out to be much much easier to do eta expansion-*after* the main CorePrep stuff.  But that places constraints-on the eta expander: given a CpeRhs, it must return a CpeRhs.--For example here is what we do not want:-                f = /\a -> g (h 3)      -- h has arity 2-After ANFing we get-                f = /\a -> let s = h 3 in g s-and now we do NOT want eta expansion to give-                f = /\a -> \ y -> (let s = h 3 in g s) y--Instead CoreArity.etaExpand gives-                f = /\a -> \y -> let s = h 3 in g s y---}--cpeEtaExpand :: Arity -> CpeRhs -> CpeRhs-cpeEtaExpand arity expr-  | arity == 0 = expr-  | otherwise  = etaExpand arity expr--{---- --------------------------------------------------------------------------------      Eta reduction--- -------------------------------------------------------------------------------Why try eta reduction?  Hasn't the simplifier already done eta?-But the simplifier only eta reduces if that leaves something-trivial (like f, or f Int).  But for deLam it would be enough to-get to a partial application:-        case x of { p -> \xs. map f xs }-    ==> case x of { p -> map f }--}---- When updating this function, make sure it lines up with--- CoreUtils.tryEtaReduce!-tryEtaReducePrep :: [CoreBndr] -> CoreExpr -> Maybe CoreExpr-tryEtaReducePrep bndrs expr@(App _ _)-  | ok_to_eta_reduce f-  , n_remaining >= 0-  , and (zipWith ok bndrs last_args)-  , not (any (`elemVarSet` fvs_remaining) bndrs)-  , exprIsHNF remaining_expr   -- Don't turn value into a non-value-                               -- else the behaviour with 'seq' changes-  = Just remaining_expr-  where-    (f, args) = collectArgs expr-    remaining_expr = mkApps f remaining_args-    fvs_remaining = exprFreeVars remaining_expr-    (remaining_args, last_args) = splitAt n_remaining args-    n_remaining = length args - length bndrs--    ok bndr (Var arg) = bndr == arg-    ok _    _         = False--    -- We can't eta reduce something which must be saturated.-    ok_to_eta_reduce (Var f) = not (hasNoBinding f)-    ok_to_eta_reduce _       = False -- Safe. ToDo: generalise---tryEtaReducePrep bndrs (Tick tickish e)-  | tickishFloatable tickish-  = fmap (mkTick tickish) $ tryEtaReducePrep bndrs e--tryEtaReducePrep _ _ = Nothing--{--************************************************************************-*                                                                      *-                Floats-*                                                                      *-************************************************************************--Note [Pin demand info on floats]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-We pin demand info on floated lets, so that we can see the one-shot thunks.--}--data FloatingBind-  = FloatLet CoreBind    -- Rhs of bindings are CpeRhss-                         -- They are always of lifted type;-                         -- unlifted ones are done with FloatCase-- | FloatCase-      Id CpeBody-      Bool              -- The bool indicates "ok-for-speculation"-- -- | See Note [Floating Ticks in CorePrep]- | FloatTick (Tickish Id)--data Floats = Floats OkToSpec (OrdList FloatingBind)--instance Outputable FloatingBind where-  ppr (FloatLet b) = ppr b-  ppr (FloatCase b r ok) = brackets (ppr ok) <+> ppr b <+> equals <+> ppr r-  ppr (FloatTick t) = ppr t--instance Outputable Floats where-  ppr (Floats flag fs) = text "Floats" <> brackets (ppr flag) <+>-                         braces (vcat (map ppr (fromOL fs)))--instance Outputable OkToSpec where-  ppr OkToSpec    = text "OkToSpec"-  ppr IfUnboxedOk = text "IfUnboxedOk"-  ppr NotOkToSpec = text "NotOkToSpec"---- Can we float these binds out of the rhs of a let?  We cache this decision--- to avoid having to recompute it in a non-linear way when there are--- deeply nested lets.-data OkToSpec-   = OkToSpec           -- Lazy bindings of lifted type-   | IfUnboxedOk        -- A mixture of lazy lifted bindings and n-                        -- ok-to-speculate unlifted bindings-   | NotOkToSpec        -- Some not-ok-to-speculate unlifted bindings--mkFloat :: Demand -> Bool -> Id -> CpeRhs -> FloatingBind-mkFloat dmd is_unlifted bndr rhs-  | use_case  = FloatCase bndr rhs (exprOkForSpeculation rhs)-  | is_hnf    = FloatLet (NonRec bndr                       rhs)-  | otherwise = FloatLet (NonRec (setIdDemandInfo bndr dmd) rhs)-                   -- See Note [Pin demand info on floats]-  where-    is_hnf    = exprIsHNF rhs-    is_strict = isStrictDmd dmd-    use_case  = is_unlifted || is_strict && not is_hnf-                -- Don't make a case for a value binding,-                -- even if it's strict.  Otherwise we get-                --      case (\x -> e) of ...!--emptyFloats :: Floats-emptyFloats = Floats OkToSpec nilOL--isEmptyFloats :: Floats -> Bool-isEmptyFloats (Floats _ bs) = isNilOL bs--wrapBinds :: Floats -> CpeBody -> CpeBody-wrapBinds (Floats _ binds) body-  = foldrOL mk_bind body binds-  where-    mk_bind (FloatCase bndr rhs _) body = mkDefaultCase rhs bndr body-    mk_bind (FloatLet bind)        body = Let bind body-    mk_bind (FloatTick tickish)    body = mkTick tickish body--addFloat :: Floats -> FloatingBind -> Floats-addFloat (Floats ok_to_spec floats) new_float-  = Floats (combine ok_to_spec (check new_float)) (floats `snocOL` new_float)-  where-    check (FloatLet _) = OkToSpec-    check (FloatCase _ _ ok_for_spec)-        | ok_for_spec  =  IfUnboxedOk-        | otherwise    =  NotOkToSpec-    check FloatTick{}  = OkToSpec-        -- The ok-for-speculation flag says that it's safe to-        -- float this Case out of a let, and thereby do it more eagerly-        -- We need the top-level flag because it's never ok to float-        -- an unboxed binding to the top level--unitFloat :: FloatingBind -> Floats-unitFloat = addFloat emptyFloats--appendFloats :: Floats -> Floats -> Floats-appendFloats (Floats spec1 floats1) (Floats spec2 floats2)-  = Floats (combine spec1 spec2) (floats1 `appOL` floats2)--concatFloats :: [Floats] -> OrdList FloatingBind-concatFloats = foldr (\ (Floats _ bs1) bs2 -> appOL bs1 bs2) nilOL--combine :: OkToSpec -> OkToSpec -> OkToSpec-combine NotOkToSpec _ = NotOkToSpec-combine _ NotOkToSpec = NotOkToSpec-combine IfUnboxedOk _ = IfUnboxedOk-combine _ IfUnboxedOk = IfUnboxedOk-combine _ _           = OkToSpec--deFloatTop :: Floats -> [CoreBind]--- For top level only; we don't expect any FloatCases-deFloatTop (Floats _ floats)-  = foldrOL get [] floats-  where-    get (FloatLet b) bs = occurAnalyseRHSs b : bs-    get (FloatCase var body _) bs  =-      occurAnalyseRHSs (NonRec var body) : bs-    get b _ = pprPanic "corePrepPgm" (ppr b)--    -- See Note [Dead code in CorePrep]-    occurAnalyseRHSs (NonRec x e) = NonRec x (occurAnalyseExpr_NoBinderSwap e)-    occurAnalyseRHSs (Rec xes)    = Rec [(x, occurAnalyseExpr_NoBinderSwap e) | (x, e) <- xes]-------------------------------------------------------------------------------canFloatFromNoCaf :: Platform -> Floats -> CpeRhs -> Maybe (Floats, CpeRhs)-       -- Note [CafInfo and floating]-canFloatFromNoCaf platform (Floats ok_to_spec fs) rhs-  | OkToSpec <- ok_to_spec           -- Worth trying-  , Just (subst, fs') <- go (emptySubst, nilOL) (fromOL fs)-  = Just (Floats OkToSpec fs', subst_expr subst rhs)-  | otherwise-  = Nothing-  where-    subst_expr = substExpr (text "CorePrep")--    go :: (Subst, OrdList FloatingBind) -> [FloatingBind]-       -> Maybe (Subst, OrdList FloatingBind)--    go (subst, fbs_out) [] = Just (subst, fbs_out)--    go (subst, fbs_out) (FloatLet (NonRec b r) : fbs_in)-      | rhs_ok r-      = go (subst', fbs_out `snocOL` new_fb) fbs_in-      where-        (subst', b') = set_nocaf_bndr subst b-        new_fb = FloatLet (NonRec b' (subst_expr subst r))--    go (subst, fbs_out) (FloatLet (Rec prs) : fbs_in)-      | all rhs_ok rs-      = go (subst', fbs_out `snocOL` new_fb) fbs_in-      where-        (bs,rs) = unzip prs-        (subst', bs') = mapAccumL set_nocaf_bndr subst bs-        rs' = map (subst_expr subst') rs-        new_fb = FloatLet (Rec (bs' `zip` rs'))--    go (subst, fbs_out) (ft@FloatTick{} : fbs_in)-      = go (subst, fbs_out `snocOL` ft) fbs_in--    go _ _ = Nothing      -- Encountered a caffy binding--    -------------    set_nocaf_bndr subst bndr-      = (extendIdSubst subst bndr (Var bndr'), bndr')-      where-        bndr' = bndr `setIdCafInfo` NoCafRefs--    -------------    rhs_ok :: CoreExpr -> Bool-    -- We can only float to top level from a NoCaf thing if-    -- the new binding is static. However it can't mention-    -- any non-static things or it would *already* be Caffy-    rhs_ok = rhsIsStatic platform (\_ -> False)-                         (\_nt i -> pprPanic "rhsIsStatic" (integer i))-                         -- Integer or Natural literals should not show up--wantFloatNested :: RecFlag -> Demand -> Bool -> Floats -> CpeRhs -> Bool-wantFloatNested is_rec dmd is_unlifted floats rhs-  =  isEmptyFloats floats-  || isStrictDmd dmd-  || is_unlifted-  || (allLazyNested is_rec floats && exprIsHNF rhs)-        -- Why the test for allLazyNested?-        --      v = f (x `divInt#` y)-        -- we don't want to float the case, even if f has arity 2,-        -- because floating the case would make it evaluated too early--allLazyTop :: Floats -> Bool-allLazyTop (Floats OkToSpec _) = True-allLazyTop _                   = False--allLazyNested :: RecFlag -> Floats -> Bool-allLazyNested _      (Floats OkToSpec    _) = True-allLazyNested _      (Floats NotOkToSpec _) = False-allLazyNested is_rec (Floats IfUnboxedOk _) = isNonRec is_rec--{--************************************************************************-*                                                                      *-                Cloning-*                                                                      *-************************************************************************--}---- ------------------------------------------------------------------------------                      The environment--- ------------------------------------------------------------------------------- Note [Inlining in CorePrep]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~--- There is a subtle but important invariant that must be upheld in the output--- of CorePrep: there are no "trivial" updatable thunks.  Thus, this Core--- is impermissible:------      let x :: ()---          x = y------ (where y is a reference to a GLOBAL variable).  Thunks like this are silly:--- they can always be profitably replaced by inlining x with y. Consequently,--- the code generator/runtime does not bother implementing this properly--- (specifically, there is no implementation of stg_ap_0_upd_info, which is the--- stack frame that would be used to update this thunk.  The "0" means it has--- zero free variables.)------ In general, the inliner is good at eliminating these let-bindings.  However,--- there is one case where these trivial updatable thunks can arise: when--- we are optimizing away 'lazy' (see Note [lazyId magic], and also--- 'cpeRhsE'.)  Then, we could have started with:------      let x :: ()---          x = lazy @ () y------ which is a perfectly fine, non-trivial thunk, but then CorePrep will--- drop 'lazy', giving us 'x = y' which is trivial and impermissible.--- The solution is CorePrep to have a miniature inlining pass which deals--- with cases like this.  We can then drop the let-binding altogether.------ Why does the removal of 'lazy' have to occur in CorePrep?--- The gory details are in Note [lazyId magic] in MkId, but the--- main reason is that lazy must appear in unfoldings (optimizer--- output) and it must prevent call-by-value for catch# (which--- is implemented by CorePrep.)------ An alternate strategy for solving this problem is to have the--- inliner treat 'lazy e' as a trivial expression if 'e' is trivial.--- We decided not to adopt this solution to keep the definition--- of 'exprIsTrivial' simple.------ There is ONE caveat however: for top-level bindings we have--- to preserve the binding so that we float the (hacky) non-recursive--- binding for data constructors; see Note [Data constructor workers].------ Note [CorePrep inlines trivial CoreExpr not Id]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--- Why does cpe_env need to be an IdEnv CoreExpr, as opposed to an--- IdEnv Id?  Naively, we might conjecture that trivial updatable thunks--- as per Note [Inlining in CorePrep] always have the form--- 'lazy @ SomeType gbl_id'.  But this is not true: the following is--- perfectly reasonable Core:------      let x :: ()---          x = lazy @ (forall a. a) y @ Bool------ When we inline 'x' after eliminating 'lazy', we need to replace--- occurrences of 'x' with 'y @ bool', not just 'y'.  Situations like--- this can easily arise with higher-rank types; thus, cpe_env must--- map to CoreExprs, not Ids.--data CorePrepEnv-  = CPE { cpe_dynFlags        :: DynFlags-        , cpe_env             :: IdEnv CoreExpr   -- Clone local Ids-        -- ^ This environment is used for three operations:-        ---        --      1. To support cloning of local Ids so that they are-        --      all unique (see item (6) of CorePrep overview).-        ---        --      2. To support beta-reduction of runRW, see-        --      Note [runRW magic] and Note [runRW arg].-        ---        --      3. To let us inline trivial RHSs of non top-level let-bindings,-        --      see Note [lazyId magic], Note [Inlining in CorePrep]-        --      and Note [CorePrep inlines trivial CoreExpr not Id] (#12076)-        , cpe_mkIntegerId     :: Id-        , cpe_mkNaturalId     :: Id-        , cpe_integerSDataCon :: Maybe DataCon-        , cpe_naturalSDataCon :: Maybe DataCon-    }--lookupMkIntegerName :: DynFlags -> HscEnv -> IO Id-lookupMkIntegerName dflags hsc_env-    = guardIntegerUse dflags $ liftM tyThingId $-      lookupGlobal hsc_env mkIntegerName--lookupMkNaturalName :: DynFlags -> HscEnv -> IO Id-lookupMkNaturalName dflags hsc_env-    = guardNaturalUse dflags $ liftM tyThingId $-      lookupGlobal hsc_env mkNaturalName---- See Note [The integer library] in PrelNames-lookupIntegerSDataConName :: DynFlags -> HscEnv -> IO (Maybe DataCon)-lookupIntegerSDataConName dflags hsc_env = case integerLibrary dflags of-    IntegerGMP -> guardIntegerUse dflags $ liftM (Just . tyThingDataCon) $-                  lookupGlobal hsc_env integerSDataConName-    IntegerSimple -> return Nothing--lookupNaturalSDataConName :: DynFlags -> HscEnv -> IO (Maybe DataCon)-lookupNaturalSDataConName dflags hsc_env = case integerLibrary dflags of-    IntegerGMP -> guardNaturalUse dflags $ liftM (Just . tyThingDataCon) $-                  lookupGlobal hsc_env naturalSDataConName-    IntegerSimple -> return Nothing---- | Helper for 'lookupMkIntegerName', 'lookupIntegerSDataConName'-guardIntegerUse :: DynFlags -> IO a -> IO a-guardIntegerUse dflags act-  | thisPackage dflags == primUnitId-  = return $ panic "Can't use Integer in ghc-prim"-  | thisPackage dflags == integerUnitId-  = return $ panic "Can't use Integer in integer-*"-  | otherwise = act---- | Helper for 'lookupMkNaturalName', 'lookupNaturalSDataConName'------ Just like we can't use Integer literals in `integer-*`, we can't use Natural--- literals in `base`. If we do, we get interface loading error for GHC.Natural.-guardNaturalUse :: DynFlags -> IO a -> IO a-guardNaturalUse dflags act-  | thisPackage dflags == primUnitId-  = return $ panic "Can't use Natural in ghc-prim"-  | thisPackage dflags == integerUnitId-  = return $ panic "Can't use Natural in integer-*"-  | thisPackage dflags == baseUnitId-  = return $ panic "Can't use Natural in base"-  | otherwise = act--mkInitialCorePrepEnv :: DynFlags -> HscEnv -> IO CorePrepEnv-mkInitialCorePrepEnv dflags hsc_env-    = do mkIntegerId <- lookupMkIntegerName dflags hsc_env-         mkNaturalId <- lookupMkNaturalName dflags hsc_env-         integerSDataCon <- lookupIntegerSDataConName dflags hsc_env-         naturalSDataCon <- lookupNaturalSDataConName dflags hsc_env-         return $ CPE {-                      cpe_dynFlags = dflags,-                      cpe_env = emptyVarEnv,-                      cpe_mkIntegerId = mkIntegerId,-                      cpe_mkNaturalId = mkNaturalId,-                      cpe_integerSDataCon = integerSDataCon,-                      cpe_naturalSDataCon = naturalSDataCon-                  }--extendCorePrepEnv :: CorePrepEnv -> Id -> Id -> CorePrepEnv-extendCorePrepEnv cpe id id'-    = cpe { cpe_env = extendVarEnv (cpe_env cpe) id (Var id') }--extendCorePrepEnvExpr :: CorePrepEnv -> Id -> CoreExpr -> CorePrepEnv-extendCorePrepEnvExpr cpe id expr-    = cpe { cpe_env = extendVarEnv (cpe_env cpe) id expr }--extendCorePrepEnvList :: CorePrepEnv -> [(Id,Id)] -> CorePrepEnv-extendCorePrepEnvList cpe prs-    = cpe { cpe_env = extendVarEnvList (cpe_env cpe)-                        (map (\(id, id') -> (id, Var id')) prs) }--lookupCorePrepEnv :: CorePrepEnv -> Id -> CoreExpr-lookupCorePrepEnv cpe id-  = case lookupVarEnv (cpe_env cpe) id of-        Nothing  -> Var id-        Just exp -> exp--getMkIntegerId :: CorePrepEnv -> Id-getMkIntegerId = cpe_mkIntegerId--getMkNaturalId :: CorePrepEnv -> Id-getMkNaturalId = cpe_mkNaturalId----------------------------------------------------------------------------------- Cloning binders--- -----------------------------------------------------------------------------cpCloneBndrs :: CorePrepEnv -> [InVar] -> UniqSM (CorePrepEnv, [OutVar])-cpCloneBndrs env bs = mapAccumLM cpCloneBndr env bs--cpCloneBndr  :: CorePrepEnv -> InVar -> UniqSM (CorePrepEnv, OutVar)-cpCloneBndr env bndr-  | not (isId bndr)-  = return (env, bndr)--  | otherwise-  = do { bndr' <- clone_it bndr--       -- Drop (now-useless) rules/unfoldings-       -- See Note [Drop unfoldings and rules]-       -- and Note [Preserve evaluatedness] in CoreTidy-       ; let unfolding' = zapUnfolding (realIdUnfolding bndr)-                          -- Simplifier will set the Id's unfolding--             bndr'' = bndr' `setIdUnfolding`      unfolding'-                            `setIdSpecialisation` emptyRuleInfo--       ; return (extendCorePrepEnv env bndr bndr'', bndr'') }-  where-    clone_it bndr-      | isLocalId bndr, not (isCoVar bndr)-      = do { uniq <- getUniqueM; return (setVarUnique bndr uniq) }-      | otherwise   -- Top level things, which we don't want-                    -- to clone, have become GlobalIds by now-                    -- And we don't clone tyvars, or coercion variables-      = return bndr--{- Note [Drop unfoldings and rules]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-We want to drop the unfolding/rules on every Id:--  - We are now past interface-file generation, and in the-    codegen pipeline, so we really don't need full unfoldings/rules--  - The unfolding/rule may be keeping stuff alive that we'd like-    to discard.  See  Note [Dead code in CorePrep]--  - Getting rid of unnecessary unfoldings reduces heap usage--  - We are changing uniques, so if we didn't discard unfoldings/rules-    we'd have to substitute in them--HOWEVER, we want to preserve evaluated-ness;-see Note [Preserve evaluatedness] in CoreTidy.--}----------------------------------------------------------------------------------- Cloning ccall Ids; each must have a unique name,--- to give the code generator a handle to hang it on--- -----------------------------------------------------------------------------fiddleCCall :: Id -> UniqSM Id-fiddleCCall id-  | isFCallId id = (id `setVarUnique`) <$> getUniqueM-  | otherwise    = return id----------------------------------------------------------------------------------- Generating new binders--- -----------------------------------------------------------------------------newVar :: Type -> UniqSM Id-newVar ty- = seqType ty `seq` do-     uniq <- getUniqueM-     return (mkSysLocalOrCoVar (fsLit "sat") uniq ty)------------------------------------------------------------------------------------ Floating ticks--- --------------------------------------------------------------------------------- Note [Floating Ticks in CorePrep]------ It might seem counter-intuitive to float ticks by default, given--- that we don't actually want to move them if we can help it. On the--- other hand, nothing gets very far in CorePrep anyway, and we want--- to preserve the order of let bindings and tick annotations in--- relation to each other. For example, if we just wrapped let floats--- when they pass through ticks, we might end up performing the--- following transformation:------   src<...> let foo = bar in baz---   ==>  let foo = src<...> bar in src<...> baz------ Because the let-binding would float through the tick, and then--- immediately materialize, achieving nothing but decreasing tick--- accuracy. The only special case is the following scenario:------   let foo = src<...> (let a = b in bar) in baz---   ==>  let foo = src<...> bar; a = src<...> b in baz------ Here we would not want the source tick to end up covering "baz" and--- therefore refrain from pushing ticks outside. Instead, we copy them--- into the floating binds (here "a") in cpePair. Note that where "b"--- or "bar" are (value) lambdas we have to push the annotations--- further inside in order to uphold our rules.------ All of this is implemented below in @wrapTicks@.---- | Like wrapFloats, but only wraps tick floats-wrapTicks :: Floats -> CoreExpr -> (Floats, CoreExpr)-wrapTicks (Floats flag floats0) expr =-    (Floats flag (toOL $ reverse floats1), foldr mkTick expr (reverse ticks1))-  where (floats1, ticks1) = foldlOL go ([], []) $ floats0-        -- Deeply nested constructors will produce long lists of-        -- redundant source note floats here. We need to eliminate-        -- those early, as relying on mkTick to spot it after the fact-        -- can yield O(n^3) complexity [#11095]-        go (floats, ticks) (FloatTick t)-          = ASSERT(tickishPlace t == PlaceNonLam)-            (floats, if any (flip tickishContains t) ticks-                     then ticks else t:ticks)-        go (floats, ticks) f-          = (foldr wrap f (reverse ticks):floats, ticks)--        wrap t (FloatLet bind)    = FloatLet (wrapBind t bind)-        wrap t (FloatCase b r ok) = FloatCase b (mkTick t r) ok-        wrap _ other              = pprPanic "wrapTicks: unexpected float!"-                                             (ppr other)-        wrapBind t (NonRec binder rhs) = NonRec binder (mkTick t rhs)-        wrapBind t (Rec pairs)         = Rec (mapSnd (mkTick t) pairs)----------------------------------------------------------------------------------- Collecting cost centres--- ------------------------------------------------------------------------------- | Collect cost centres defined in the current module, including those in--- unfoldings.-collectCostCentres :: Module -> CoreProgram -> S.Set CostCentre-collectCostCentres mod_name-  = foldl' go_bind S.empty-  where-    go cs e = case e of-      Var{} -> cs-      Lit{} -> cs-      App e1 e2 -> go (go cs e1) e2-      Lam _ e -> go cs e-      Let b e -> go (go_bind cs b) e-      Case scrt _ _ alts -> go_alts (go cs scrt) alts-      Cast e _ -> go cs e-      Tick (ProfNote cc _ _) e ->-        go (if ccFromThisModule cc mod_name then S.insert cc cs else cs) e-      Tick _ e -> go cs e-      Type{} -> cs-      Coercion{} -> cs--    go_alts = foldl' (\cs (_con, _bndrs, e) -> go cs e)--    go_bind :: S.Set CostCentre -> CoreBind -> S.Set CostCentre-    go_bind cs (NonRec b e) =-      go (maybe cs (go cs) (get_unf b)) e-    go_bind cs (Rec bs) =-      foldl' (\cs' (b, e) -> go (maybe cs' (go cs') (get_unf b)) e) cs bs--    -- Unfoldings may have cost centres that in the original definion are-    -- optimized away, see #5889.-    get_unf = maybeUnfoldingTemplate . realIdUnfolding
compiler/deSugar/Coverage.hs view
@@ -111,7 +111,8 @@      hashNo <- writeMixEntries dflags mod tickCount entries orig_file2      modBreaks <- mkModBreaks hsc_env mod tickCount entries -     dumpIfSet_dyn dflags Opt_D_dump_ticked "HPC" (pprLHsBinds binds1)+     dumpIfSet_dyn dflags Opt_D_dump_ticked "HPC" FormatHaskell+       (pprLHsBinds binds1)       return (binds1, HpcInfo tickCount hashNo, Just modBreaks) 
compiler/deSugar/Desugar.hs view
@@ -270,7 +270,7 @@        ; case mb_core_expr of             Nothing   -> return ()             Just expr -> dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared"-                         (pprCoreExpr expr)+                         FormatCore (pprCoreExpr expr)         ; return (msgs, mb_core_expr) } 
compiler/deSugar/DsExpr.hs view
@@ -11,7 +11,8 @@ {-# LANGUAGE ViewPatterns #-}  module DsExpr ( dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds-              , dsValBinds, dsLit, dsSyntaxExpr ) where+              , dsValBinds, dsLit, dsSyntaxExpr+              , dsHandleMonadicFailure ) where  #include "HsVersions.h" @@ -918,7 +919,7 @@             ; var   <- selectSimpleMatchVarL pat             ; match <- matchSinglePatVar var (StmtCtxt DoExpr) pat                                       res1_ty (cantFailMatchResult body)-            ; match_code <- handle_failure pat match fail_op+            ; match_code <- dsHandleMonadicFailure pat match fail_op             ; dsSyntaxExpr bind_op [rhs', Lam var match_code] }      go _ (ApplicativeStmt body_ty args mb_join) stmts@@ -940,7 +941,7 @@                    = do { var   <- selectSimpleMatchVarL pat                         ; match <- matchSinglePatVar var (StmtCtxt DoExpr) pat                                    body_ty (cantFailMatchResult body)-                        ; match_code <- handle_failure pat match fail_op+                        ; match_code <- dsHandleMonadicFailure pat match fail_op                         ; return (var:vs, match_code)                         } @@ -990,10 +991,10 @@     go _ (TransStmt {}) _ = panic "dsDo TransStmt"     go _ (XStmtLR nec)  _ = noExtCon nec -handle_failure :: LPat GhcTc -> MatchResult -> SyntaxExpr GhcTc -> DsM CoreExpr+dsHandleMonadicFailure :: LPat GhcTc -> MatchResult -> SyntaxExpr GhcTc -> DsM CoreExpr     -- In a do expression, pattern-match failure just calls     -- the monadic 'fail' rather than throwing an exception-handle_failure pat match fail_op+dsHandleMonadicFailure pat match fail_op   | matchCanFail match   = do { dflags <- getDynFlags        ; fail_msg <- mkStringExpr (mk_fail_msg dflags pat)
compiler/deSugar/DsExpr.hs-boot view
@@ -1,6 +1,6 @@ module DsExpr where-import GHC.Hs      ( HsExpr, LHsExpr, LHsLocalBinds, SyntaxExpr )-import DsMonad     ( DsM )+import GHC.Hs      ( HsExpr, LHsExpr, LHsLocalBinds, LPat, SyntaxExpr )+import DsMonad     ( DsM, MatchResult ) import CoreSyn     ( CoreExpr ) import GHC.Hs.Extension ( GhcTc) @@ -8,3 +8,5 @@ dsLExpr, dsLExprNoLP :: LHsExpr GhcTc -> DsM CoreExpr dsSyntaxExpr :: SyntaxExpr GhcTc -> [CoreExpr] -> DsM CoreExpr dsLocalBinds :: LHsLocalBinds GhcTc -> CoreExpr -> DsM CoreExpr++dsHandleMonadicFailure :: LPat GhcTc -> MatchResult -> SyntaxExpr GhcTc -> DsM CoreExpr
compiler/deSugar/DsForeign.hs view
@@ -31,7 +31,7 @@ import Module import Name import Type-import RepType+import GHC.Types.RepType import TyCon import Coercion import TcEnv@@ -51,7 +51,6 @@ import DynFlags import GHC.Platform import OrdList-import Pair import Util import Hooks import Encoding@@ -156,7 +155,7 @@           -> DsM ([Binding], SDoc, SDoc) dsCImport id co (CLabel cid) cconv _ _ = do    dflags <- getDynFlags-   let ty  = pFst $ coercionKind co+   let ty  = coercionLKind co        fod = case tyConAppTyCon_maybe (dropForAlls ty) of              Just tycon               | tyConUnique tycon == funPtrTyConKey ->@@ -204,7 +203,7 @@         -> DsM ([(Id, Expr TyVar)], SDoc, SDoc) dsFCall fn_id co fcall mDeclHeader = do     let-        ty                   = pFst $ coercionKind co+        ty                   = coercionLKind co         (tv_bndrs, rho)      = tcSplitForAllVarBndrs ty         (arg_tys, io_res_ty) = tcSplitFunTys rho @@ -305,7 +304,7 @@            -> DsM ([(Id, Expr TyVar)], SDoc, SDoc) dsPrimCall fn_id co fcall = do     let-        ty                   = pFst $ coercionKind co+        ty                   = coercionLKind co         (tvs, fun_ty)        = tcSplitForAllTys ty         (arg_tys, io_res_ty) = tcSplitFunTys fun_ty @@ -355,7 +354,7 @@  dsFExport fn_id co ext_name cconv isDyn = do     let-       ty                     = pSnd $ coercionKind co+       ty                     = coercionRKind co        (bndrs, orig_res_ty)   = tcSplitPiTys ty        fe_arg_tys'            = mapMaybe binderRelevantType_maybe bndrs        -- We must use tcSplits here, because we want to see@@ -477,7 +476,7 @@     return ([fed], h_code, c_code)   where-  ty                       = pFst (coercionKind co0)+  ty                       = coercionLKind co0   (tvs,sans_foralls)       = tcSplitForAllTys ty   ([arg_ty], fn_res_ty)    = tcSplitFunTys sans_foralls   Just (io_tc, res_ty)     = tcSplitIOType_maybe fn_res_ty
compiler/deSugar/DsListComp.hs view
@@ -16,7 +16,7 @@  import GhcPrelude -import {-# SOURCE #-} DsExpr ( dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds, dsSyntaxExpr )+import {-# SOURCE #-} DsExpr ( dsHandleMonadicFailure, dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds, dsSyntaxExpr )  import GHC.Hs import TcHsSyn@@ -624,25 +624,8 @@         ; var      <- selectSimpleMatchVarL pat         ; match <- matchSinglePatVar var (StmtCtxt DoExpr) pat                                   res1_ty (cantFailMatchResult body)-        ; match_code <- handle_failure pat match fail_op+        ; match_code <- dsHandleMonadicFailure pat match fail_op         ; dsSyntaxExpr bind_op [rhs', Lam var match_code] }--  where-    -- In a monad comprehension expression, pattern-match failure just calls-    -- the monadic `fail` rather than throwing an exception-    handle_failure pat match fail_op-      | matchCanFail match-        = do { dflags <- getDynFlags-             ; fail_msg <- mkStringExpr (mk_fail_msg dflags pat)-             ; fail_expr <- dsSyntaxExpr fail_op [fail_msg]-             ; extractMatchResult match fail_expr }-      | otherwise-        = extractMatchResult match (error "It can't fail")--    mk_fail_msg :: DynFlags -> Located e -> String-    mk_fail_msg dflags pat-        = "Pattern match failure in monad comprehension at " ++-          showPpr dflags (getLoc pat)  -- Desugar nested monad comprehensions, for example in `then..` constructs --    dsInnerMonadComp quals [a,b,c] ret_op
compiler/deSugar/DsMeta.hs view
@@ -177,7 +177,7 @@     no_warn (L loc (Warning _ thing _))       = notHandledL loc "WARNING and DEPRECATION pragmas" $                     text "Pragma for declaration of" <+> ppr thing-    no_warn _ = panic "repTopDs"+    no_warn (L _ (XWarnDecl nec)) = noExtCon nec     no_doc (L loc _)       = notHandledL loc "Haddock documentation" empty repTopDs (XHsGroup nec) = noExtCon nec@@ -337,7 +337,7 @@        ; return $ Just (loc, dec)        } -repTyClD _ = panic "repTyClD"+repTyClD (L _ (XTyClDecl nec)) = noExtCon nec  ------------------------- repRoleD :: LRoleAnnotDecl GhcRn -> DsM (SrcSpan, Core TH.DecQ)@@ -347,7 +347,7 @@        ; roles2 <- coreList roleTyConName roles1        ; dec <- repRoleAnnotD tycon1 roles2        ; return (loc, dec) }-repRoleD _ = panic "repRoleD"+repRoleD (L _ (XRoleAnnotDecl nec)) = noExtCon nec  ------------------------- repKiSigD :: LStandaloneKindSig GhcRn -> DsM (SrcSpan, Core TH.DecQ)@@ -425,7 +425,7 @@                   ; repDataFamilyD tc1 bndrs kind }        ; return (loc, dec)        }-repFamilyDecl _ = panic "repFamilyDecl"+repFamilyDecl (L _ (XFamilyDecl nec)) = noExtCon nec  -- | Represent result signature of a type family repFamilyResultSig :: FamilyResultSig GhcRn -> DsM (Core TH.FamilyResultSigQ)@@ -446,7 +446,9 @@ repFamilyResultSigToMaybeKind (KindSig _ ki) =     do { ki' <- repLTy ki        ; coreJust kindQTyConName ki' }-repFamilyResultSigToMaybeKind _ = panic "repFamilyResultSigToMaybeKind"+repFamilyResultSigToMaybeKind TyVarSig{} =+    panic "repFamilyResultSigToMaybeKind: unexpected TyVarSig"+repFamilyResultSigToMaybeKind (XFamilyResultSig nec) = noExtCon nec  -- | Represent injectivity annotation of a type family repInjectivityAnn :: Maybe (LInjectivityAnn GhcRn)@@ -490,7 +492,7 @@ repInstD (L loc (ClsInstD { cid_inst = cls_decl }))   = do { dec <- repClsInstD cls_decl        ; return (loc, dec) }-repInstD _ = panic "repInstD"+repInstD (L _ (XInstDecl nec)) = noExtCon nec  repClsInstD :: ClsInstDecl GhcRn -> DsM (Core TH.DecQ) repClsInstD (ClsInstDecl { cid_poly_ty = ty, cid_binds = binds@@ -533,7 +535,7 @@        ; return (loc, dec) }   where     (tvs, cxt, inst_ty) = splitLHsInstDeclTy (dropWildCards ty)-repStandaloneDerivD _ = panic "repStandaloneDerivD"+repStandaloneDerivD (L _ (XDerivDecl nec)) = noExtCon nec  repTyFamInstD :: TyFamInstDecl GhcRn -> DsM (Core TH.DecQ) repTyFamInstD (TyFamInstDecl { tfid_eqn = eqn })@@ -638,7 +640,8 @@     chStr = case mch of             Just (Header _ h) | not raw_cconv -> unpackFS h ++ " "             _ -> ""-repForD decl = notHandled "Foreign declaration" (ppr decl)+repForD decl@(L _ ForeignExport{}) = notHandled "Foreign export" (ppr decl)+repForD (L _ (XForeignDecl nec)) = noExtCon nec  repCCallConv :: CCallConv -> DsM (Core TH.Callconv) repCCallConv CCallConv          = rep2 cCallName []@@ -664,7 +667,7 @@                    ; dec <- rep2 rep_fn [prec', name']                    ; return (loc,dec) }        ; mapM do_one names }-repFixD _ = panic "repFixD"+repFixD (L _ (XFixitySig nec)) = noExtCon nec  repRuleD :: LRuleDecl GhcRn -> DsM (SrcSpan, Core TH.DecQ) repRuleD (L loc (HsRule { rd_name = n@@ -691,17 +694,17 @@                          ; repPragRule n' ty_bndrs' tm_bndrs' lhs' rhs' act' }            ; wrapGenSyms ss rule  }        ; return (loc, rule) }-repRuleD _ = panic "repRuleD"+repRuleD (L _ (XRuleDecl nec)) = noExtCon nec  ruleBndrNames :: LRuleBndr GhcRn -> [Name] ruleBndrNames (L _ (RuleBndr _ n))      = [unLoc n] ruleBndrNames (L _ (RuleBndrSig _ n sig))   | HsWC { hswc_body = HsIB { hsib_ext = vars }} <- sig   = unLoc n : vars-ruleBndrNames (L _ (RuleBndrSig _ _ (HsWC _ (XHsImplicitBndrs _))))-  = panic "ruleBndrNames"-ruleBndrNames (L _ (RuleBndrSig _ _ (XHsWildCardBndrs _)))-  = panic "ruleBndrNames"+ruleBndrNames (L _ (RuleBndrSig _ _ (HsWC _ (XHsImplicitBndrs nec))))+  = noExtCon nec+ruleBndrNames (L _ (RuleBndrSig _ _ (XHsWildCardBndrs nec)))+  = noExtCon nec ruleBndrNames (L _ (XRuleBndr nec)) = noExtCon nec  repRuleBndr :: LRuleBndr GhcRn -> DsM (Core TH.RuleBndrQ)@@ -712,7 +715,7 @@   = do { MkC n'  <- lookupLBinder n        ; MkC ty' <- repLTy (hsSigWcType sig)        ; rep2 typedRuleVarName [n', ty'] }-repRuleBndr _ = panic "repRuleBndr"+repRuleBndr (L _ (XRuleBndr nec)) = noExtCon nec  repAnnD :: LAnnDecl GhcRn -> DsM (SrcSpan, Core TH.DecQ) repAnnD (L loc (HsAnnotation _ _ ann_prov (L _ exp)))@@ -720,7 +723,7 @@        ; exp'   <- repE exp        ; dec    <- repPragAnn target exp'        ; return (loc, dec) }-repAnnD _ = panic "repAnnD"+repAnnD (L _ (XAnnDecl nec)) = noExtCon nec  repAnnProv :: AnnProvenance Name -> DsM (Core TH.AnnTarget) repAnnProv (ValueAnnProvenance (L _ n))@@ -776,7 +779,7 @@          then return c'          else rep2 forallCName ([unC ex_bndrs, unC ctxt', unC c']) } -repC _ = panic "repC"+repC (L _ (XConDecl nec)) = noExtCon nec   repMbContext :: Maybe (LHsContext GhcRn) -> DsM (Core TH.CxtQ)@@ -824,7 +827,7 @@   where     rep_deriv_ty :: LHsType GhcRn -> DsM (Core TH.TypeQ)     rep_deriv_ty ty = repLTy ty-repDerivClause _ = panic "repDerivClause"+repDerivClause (L _ (XHsDerivingClause nec)) = noExtCon nec  rep_sigs_binds :: [LSig GhcRn] -> LHsBinds GhcRn                -> DsM ([GenSymBind], [Core TH.DecQ])@@ -868,7 +871,7 @@ rep_sig (L _   (SCCFunSig {}))        = notHandled "SCC pragmas" empty rep_sig (L loc (CompleteMatchSig _ _st cls mty))   = rep_complete_sig cls mty loc-rep_sig _ = panic "rep_sig"+rep_sig (L _ (XSig nec)) = noExtCon nec  rep_ty_sig :: Name -> SrcSpan -> LHsSigType GhcRn -> Located Name            -> DsM (SrcSpan, Core TH.DecQ)@@ -968,10 +971,10 @@        ; return [(loc, pragma)] }  repInline :: InlineSpec -> DsM (Core TH.Inline)-repInline NoInline  = dataCon noInlineDataConName-repInline Inline    = dataCon inlineDataConName-repInline Inlinable = dataCon inlinableDataConName-repInline spec      = notHandled "repInline" (ppr spec)+repInline NoInline     = dataCon noInlineDataConName+repInline Inline       = dataCon inlineDataConName+repInline Inlinable    = dataCon inlinableDataConName+repInline NoUserInline = notHandled "NOUSERINLINE" empty  repRuleMatch :: RuleMatchInfo -> DsM (Core TH.RuleMatch) repRuleMatch ConLike = dataCon conLikeDataConName@@ -1068,7 +1071,7 @@   = repPlainTV nm repTyVarBndrWithKind (L _ (KindedTyVar _ _ ki)) nm   = repLTy ki >>= repKindedTV nm-repTyVarBndrWithKind _ _ = panic "repTyVarBndrWithKind"+repTyVarBndrWithKind (L _ (XTyVarBndr nec)) _ = noExtCon nec  -- | Represent a type variable binder repTyVarBndr :: LHsTyVarBndr GhcRn -> DsM (Core TH.TyVarBndrQ)@@ -1079,7 +1082,7 @@   = do { nm' <- lookupBinder nm        ; ki' <- repLTy ki        ; repKindedTV nm' ki' }-repTyVarBndr _ = panic "repTyVarBndr"+repTyVarBndr (L _ (XTyVarBndr nec)) = noExtCon nec  -- represent a type context --@@ -1270,7 +1273,7 @@ repE e@(HsRecFld _ f) = case f of   Unambiguous x _ -> repE (HsVar noExtField (noLoc x))   Ambiguous{}     -> notHandled "Ambiguous record selectors" (ppr e)-  XAmbiguousFieldOcc{} -> notHandled "XAmbiguous record selectors" (ppr e)+  XAmbiguousFieldOcc nec -> noExtCon nec          -- Remember, we're desugaring renamer output here, so         -- HsOverlit can definitely occur@@ -1398,6 +1401,7 @@ repE e@(HsPragE _ HsPragCore {} _)   = notHandled "Core annotations" (ppr e) repE e@(HsPragE _ HsPragSCC  {} _)   = notHandled "Cost centres" (ppr e) repE e@(HsPragE _ HsPragTick {} _)   = notHandled "Tick Pragma" (ppr e)+repE (XExpr nec)           = noExtCon nec repE e                     = notHandled "Expression form" (ppr e)  -----------------------------------------------------------------------------@@ -1428,7 +1432,7 @@      ; clause <- repClause ps1 gs ds      ; wrapGenSyms (ss1++ss2) clause }}} repClauseTup (L _ (Match _ _ _ (XGRHSs nec))) = noExtCon nec-repClauseTup _ = panic "repClauseTup"+repClauseTup (L _ (XMatch nec)) = noExtCon nec  repGuards ::  [LGRHS GhcRn (LHsExpr GhcRn)] ->  DsM (Core TH.BodyQ) repGuards [L _ (GRHS _ [] e)]@@ -1449,7 +1453,7 @@        ; rhs' <- addBinds gs $ repLE rhs        ; guarded <- repPatGE (nonEmptyCoreList ss') rhs'        ; return (gs, guarded) }-repLGRHS _ = panic "repLGRHS"+repLGRHS (L _ (XGRHS nec)) = noExtCon nec  repFields :: HsRecordBinds GhcRn -> DsM (Core [TH.Q TH.FieldExp]) repFields (HsRecFields { rec_flds = flds })@@ -1469,7 +1473,8 @@       Unambiguous sel_name _ -> do { fn <- lookupLOcc (L l sel_name)                                    ; e  <- repLE (hsRecFieldArg fld)                                    ; repFieldExp fn e }-      _                      -> notHandled "Ambiguous record updates" (ppr fld)+      Ambiguous{}            -> notHandled "Ambiguous record updates" (ppr fld)+      XAmbiguousFieldOcc nec -> noExtCon nec   @@ -1549,6 +1554,7 @@        ; z <- repRecSt (nonEmptyCoreList rss)        ; (ss2,zs) <- addBinds ss1 (repSts ss)        ; return (ss1++ss2, z : zs) }+repSts (XStmtLR nec : _) = noExtCon nec repSts []    = return ([],[]) repSts other = notHandled "Exotic statement" (ppr other) @@ -1569,8 +1575,7 @@         ; return ([], core_list)         } -repBinds b@(HsIPBinds _ XHsIPBinds {})- = notHandled "Implicit parameter binds extension" (ppr b)+repBinds (HsIPBinds _ (XHsIPBinds nec)) = noExtCon nec  repBinds (HsValBinds _ decs)  = do   { let { bndrs = hsScopedTvBinders decs ++ collectHsValBinders decs }@@ -1584,7 +1589,7 @@         ; core_list <- coreList decQTyConName                                 (de_loc (sort_by_loc prs))         ; return (ss, core_list) }-repBinds b@(XHsLocalBindsLR {}) = notHandled "Local binds extensions" (ppr b)+repBinds (XHsLocalBindsLR nec) = noExtCon nec  rep_implicit_param_bind :: LIPBind GhcRn -> DsM (SrcSpan, Core TH.DecQ) rep_implicit_param_bind (L loc (IPBind _ ename (L _ rhs)))@@ -1595,8 +1600,7 @@       ; rhs' <- repE rhs       ; ipb <- repImplicitParamBind name rhs'       ; return (loc, ipb) }-rep_implicit_param_bind (L _ b@(XIPBind _))- = notHandled "Implicit parameter bind extension" (ppr b)+rep_implicit_param_bind (L _ (XIPBind nec)) = noExtCon nec  rep_implicit_param_name :: HsIPName -> DsM (Core String) rep_implicit_param_name (HsIPName name) = coreStringLit (unpackFS name)@@ -1780,6 +1784,9 @@       ; lam <- addBinds ss (                 do { xs <- repLPs ps; body <- repLE e; repLam xs body })       ; wrapGenSyms ss lam }+repLambda (L _ (Match { m_grhss = GRHSs _ [L _ (GRHS _ [] _)]+                                          (L _ (XHsLocalBindsLR nec)) } ))+ = noExtCon nec  repLambda (L _ m) = notHandled "Guarded lambdas" (pprMatch m) @@ -1840,7 +1847,7 @@                          ; t' <- repLTy (hsSigWcType t)                          ; repPsig p' t' } repP (SplicePat _ splice) = repSplice splice-+repP (XPat nec) = noExtCon nec repP other = notHandled "Exotic pattern" (ppr other)  ----------------------------------------------------------
compiler/deSugar/DsMonad.hs view
@@ -349,8 +349,8 @@         ; return (setIdUnique old_local uniq) }  newPredVarDs :: PredType -> DsM Var-newPredVarDs pred- = newSysLocalDs pred+newPredVarDs+ = mkSysLocalOrCoVarM (fsLit "ds")  -- like newSysLocalDs, but we allow covars  newSysLocalDsNoLP, newSysLocalDs, newFailLocalDs :: Type -> DsM Id newSysLocalDsNoLP  = mk_local (fsLit "ds")@@ -358,8 +358,8 @@ -- this variant should be used when the caller can be sure that the variable type -- is not levity-polymorphic. It is necessary when the type is knot-tied because -- of the fixM used in DsArrows. See Note [Levity polymorphism checking]-newSysLocalDs = mkSysLocalOrCoVarM (fsLit "ds")-newFailLocalDs = mkSysLocalOrCoVarM (fsLit "fail")+newSysLocalDs = mkSysLocalM (fsLit "ds")+newFailLocalDs = mkSysLocalM (fsLit "fail")   -- the fail variable is used only in a situation where we can tell that   -- levity-polymorphism is impossible. 
compiler/ghci/ByteCodeGen.hs view
@@ -37,7 +37,7 @@ import PrimOp import CoreFVs import Type-import RepType+import GHC.Types.RepType import DataCon import TyCon import Util@@ -107,7 +107,8 @@              (panic "ByteCodeGen.byteCodeGen: missing final emitBc?")          dumpIfSet_dyn dflags Opt_D_dump_BCOs-           "Proto-BCOs" (vcat (intersperse (char ' ') (map ppr proto_bcos)))+           "Proto-BCOs" FormatByteCode+           (vcat (intersperse (char ' ') (map ppr proto_bcos)))          cbc <- assembleBCOs hsc_env proto_bcos tycs (map snd stringPtrs)           (case modBreaks of@@ -164,19 +165,19 @@       -- create a totally bogus name for the top-level BCO; this       -- should be harmless, since it's never used for anything       let invented_name  = mkSystemVarName (mkPseudoUniqueE 0) (fsLit "ExprTopLevel")-          invented_id    = Id.mkLocalId invented_name (panic "invented_id's type")        -- the uniques are needed to generate fresh variables when we introduce new       -- let bindings for ticked expressions       us <- mkSplitUniqSupply 'y'       (BcM_State _dflags _us _this_mod _final_ctr mallocd _ _ _, proto_bco)          <- runBc hsc_env us this_mod Nothing emptyVarEnv $-              schemeTopBind (invented_id, simpleFreeVars expr)+              schemeR [] (invented_name, simpleFreeVars expr)        when (notNull mallocd)            (panic "ByteCodeGen.coreExprToBCOs: missing final emitBc?") -      dumpIfSet_dyn dflags Opt_D_dump_BCOs "Proto-BCOs" (ppr proto_bco)+      dumpIfSet_dyn dflags Opt_D_dump_BCOs "Proto-BCOs" FormatByteCode+         (ppr proto_bco)        assembleOneBCO hsc_env proto_bco   where dflags = hsc_dflags hsc_env@@ -321,7 +322,7 @@                        (Right rhs) 0 0 [{-no bitmap-}] False{-not alts-})    | otherwise-  = schemeR [{- No free variables -}] (id, rhs)+  = schemeR [{- No free variables -}] (getName id, rhs)   -- -----------------------------------------------------------------------------@@ -333,13 +334,13 @@ -- removing the free variables and arguments. -- -- Park the resulting BCO in the monad.  Also requires the--- variable to which this value was bound, so as to give the--- resulting BCO a name.+-- name of the variable to which this value was bound,+-- so as to give the resulting BCO a name.  schemeR :: [Id]                 -- Free vars of the RHS, ordered as they                                 -- will appear in the thunk.  Empty for                                 -- top-level things, which have no free vars.-        -> (Id, AnnExpr Id DVarSet)+        -> (Name, AnnExpr Id DVarSet)         -> BcM (ProtoBCO Name) schemeR fvs (nm, rhs) {-@@ -370,7 +371,7 @@  schemeR_wrk     :: [Id]-    -> Id+    -> Name     -> AnnExpr Id DVarSet             -- expression e, for debugging only     -> ([Var], AnnExpr' Var DVarSet)  -- result of collect on e     -> BcM (ProtoBCO Name)@@ -396,7 +397,7 @@          bitmap = mkBitmap dflags bits      body_code <- schemeER_wrk sum_szsb_args p_init body -     emitBc (mkProtoBCO dflags (getName nm) body_code (Right original_body)+     emitBc (mkProtoBCO dflags nm body_code (Right original_body)                  arity bitmap_size bitmap False{-not alts-})  -- introduce break instructions for ticked expressions@@ -575,7 +576,7 @@                      _other -> False           compile_bind d' fvs x rhs size arity off = do-                bco <- schemeR fvs (x,rhs)+                bco <- schemeR fvs (getName x,rhs)                 build_thunk d' fvs size bco off arity           compile_binds =
compiler/ghci/ByteCodeItbls.hs view
@@ -19,7 +19,7 @@ import NameEnv import DataCon          ( DataCon, dataConRepArgTys, dataConIdentity ) import TyCon            ( TyCon, tyConFamilySize, isDataTyCon, tyConDataCons )-import RepType+import GHC.Types.RepType import GHC.StgToCmm.Layout  ( mkVirtConstrSizes ) import GHC.StgToCmm.Closure ( tagForCon, NonVoid (..) ) import Util
compiler/ghci/Debugger.hs view
@@ -91,6 +91,7 @@          Just subst' -> do { dflags <- GHC.getSessionDynFlags                            ; liftIO $                                dumpIfSet_dyn dflags Opt_D_dump_rtti "RTTI"+                                 FormatText                                  (fsep $ [text "RTTI Improvement for", ppr id,                                   text "old substitution:" , ppr subst,                                   text "new substitution:" , ppr subst'])
compiler/ghci/RtClosureInspect.hs view
@@ -33,7 +33,7 @@  import DataCon import Type-import RepType+import GHC.Types.RepType import qualified Unify as U import Var import TcRnMonad
compiler/iface/FlagChecker.hs view
@@ -61,7 +61,7 @@         ticky =           map (`gopt` dflags) [Opt_Ticky, Opt_Ticky_Allocd, Opt_Ticky_LNE, Opt_Ticky_Dyn_Thunk] -        flags = (mainis, safeHs, lang, cpp, paths, prof, ticky)+        flags = ((mainis, safeHs, lang, cpp), (paths, prof, ticky, debugLevel))      in -- pprTrace "flags" (ppr flags) $        computeFingerprint nameio flags
compiler/iface/LoadIface.hs view
@@ -156,7 +156,7 @@   where     nd_doc = text "Need decl for" <+> ppr name     not_found_msg = hang (text "Can't find interface-file declaration for" <+>-                                pprNameSpace (occNameSpace (nameOccName name)) <+> ppr name)+                                pprNameSpace (nameNameSpace name) <+> ppr name)                        2 (vcat [text "Probable cause: bug in .hi-boot file, or inconsistent .hi file",                                 text "Use -ddump-if-trace to get an idea of which file caused the error"])     found_things_msg eps =
compiler/iface/MkIface.hs view
@@ -167,7 +167,7 @@       addFingerprints hsc_env partial_iface      -- Debug printing-    dumpIfSet_dyn (hsc_dflags hsc_env) Opt_D_dump_hi "FINAL INTERFACE" (pprModIface full_iface)+    dumpIfSet_dyn (hsc_dflags hsc_env) Opt_D_dump_hi "FINAL INTERFACE" FormatText (pprModIface full_iface)      return full_iface @@ -311,7 +311,7 @@           mi_doc_hdr     = doc_hdr,           mi_decl_docs   = decl_docs,           mi_arg_docs    = arg_docs,-          mi_final_exts        = () }+          mi_final_exts  = () }   where      cmp_rule     = comparing ifRuleName      -- Compare these lexicographically by OccName, *not* by unique,
compiler/iface/TcIface.hs view
@@ -1321,6 +1321,8 @@     let         scrut_ty   = exprType scrut'         case_bndr' = mkLocalIdOrCoVar case_bndr_name scrut_ty+     -- "OrCoVar" since a coercion can be a scrutinee with -fdefer-type-errors+     -- (e.g. see test T15695). Ticket #17291 covers fixing this problem.         tc_app     = splitTyConApp scrut_ty                 -- NB: Won't always succeed (polymorphic case)                 --     but won't be demanded in those cases@@ -1337,7 +1339,7 @@         ; ty'     <- tcIfaceType ty         ; id_info <- tcIdInfo False {- Don't ignore prags; we are inside one! -}                               NotTopLevel name ty' info-        ; let id = mkLocalIdOrCoVarWithInfo name ty' id_info+        ; let id = mkLocalIdWithInfo name ty' id_info                      `asJoinId_maybe` tcJoinInfo ji         ; rhs' <- tcIfaceExpr rhs         ; body' <- extendIfaceIdEnv [id] (tcIfaceExpr body)@@ -1353,7 +1355,7 @@    tc_rec_bndr (IfLetBndr fs ty _ ji)      = do { name <- newIfaceName (mkVarOccFS fs)           ; ty'  <- tcIfaceType ty-          ; return (mkLocalIdOrCoVar name ty' `asJoinId_maybe` tcJoinInfo ji) }+          ; return (mkLocalId name ty' `asJoinId_maybe` tcJoinInfo ji) }    tc_pair (IfLetBndr _ _ info _, rhs) id      = do { rhs' <- tcIfaceExpr rhs           ; id_info <- tcIdInfo False {- Don't ignore prags; we are inside one! -}@@ -1365,7 +1367,7 @@     -- If debug flag is not set: Ignore source notes     dbgLvl <- fmap debugLevel getDynFlags     case tickish of-      IfaceSource{} | dbgLvl > 0+      IfaceSource{} | dbgLvl == 0                     -> return expr'       _otherwise    -> do         tickish' <- tcIfaceTickish tickish@@ -1733,6 +1735,7 @@   = do  { name <- newIfaceName (mkVarOccFS fs)         ; ty' <- tcIfaceType ty         ; let id = mkLocalIdOrCoVar name ty'+          -- We should not have "OrCoVar" here, this is a bug (#17545)         ; extendIfaceIdEnv [id] (thing_inside id) }  bindIfaceIds :: [IfaceIdBndr] -> ([Id] -> IfL a) -> IfL a
compiler/llvmGen/LlvmCodeGen.hs view
@@ -17,11 +17,8 @@ import LlvmCodeGen.Regs import LlvmMangler -import BlockId import GHC.StgToCmm.CgUtils ( fixStgRegisters ) import Cmm-import CmmUtils-import Hoopl.Block import Hoopl.Collections import PprCmm @@ -31,7 +28,6 @@ import ErrUtils import FastString import Outputable-import UniqSupply import SysTools ( figureLlvmVersion ) import qualified Stream @@ -150,46 +146,16 @@         renderLlvm $ pprLlvmData (concat gss', concat tss) --- | LLVM can't handle entry blocks which loop back to themselves (could be--- seen as an LLVM bug) so we rearrange the code to keep the original entry--- label which branches to a newly generated second label that branches back--- to itself. See: #11649-fixBottom :: RawCmmDecl -> LlvmM RawCmmDecl-fixBottom cp@(CmmProc hdr entry_lbl live g) =-    maybe (pure cp) fix_block $ mapLookup (g_entry g) blk_map-  where-    blk_map = toBlockMap g--    fix_block :: CmmBlock -> LlvmM RawCmmDecl-    fix_block blk-        | (CmmEntry e_lbl tickscp, middle, CmmBranch b_lbl) <- blockSplit blk-        , isEmptyBlock middle-        , e_lbl == b_lbl = do-            new_lbl <- mkBlockId <$> getUniqueM--            let fst_blk =-                    BlockCC (CmmEntry e_lbl tickscp) BNil (CmmBranch new_lbl)-                snd_blk =-                    BlockCC (CmmEntry new_lbl tickscp) BNil (CmmBranch new_lbl)--            pure . CmmProc hdr entry_lbl live . ofBlockMap (g_entry g)-                $ mapFromList [(e_lbl, fst_blk), (new_lbl, snd_blk)]--    fix_block _ = pure cp--fixBottom rcd = pure rcd- -- | Complete LLVM code generation phase for a single top-level chunk of Cmm. cmmLlvmGen ::RawCmmDecl -> LlvmM () cmmLlvmGen cmm@CmmProc{} = do      -- rewrite assignments to global regs     dflags <- getDynFlag id-    fixed_cmm <- fixBottom $-                    {-# SCC "llvm_fix_regs" #-}-                    fixStgRegisters dflags cmm+    let fixed_cmm = {-# SCC "llvm_fix_regs" #-} fixStgRegisters dflags cmm -    dumpIfSetLlvm Opt_D_dump_opt_cmm "Optimised Cmm" (pprCmmGroup [fixed_cmm])+    dumpIfSetLlvm Opt_D_dump_opt_cmm "Optimised Cmm"+      FormatCMM (pprCmmGroup [fixed_cmm])      -- generate llvm code from cmm     llvmBC <- withClearVars $ genLlvmProc fixed_cmm
compiler/llvmGen/LlvmCodeGen/Base.hs view
@@ -337,10 +337,10 @@ getLlvmPlatform = getDynFlag targetPlatform  -- | Dumps the document if the corresponding flag has been set by the user-dumpIfSetLlvm :: DumpFlag -> String -> Outp.SDoc -> LlvmM ()-dumpIfSetLlvm flag hdr doc = do+dumpIfSetLlvm :: DumpFlag -> String -> DumpFormat -> Outp.SDoc -> LlvmM ()+dumpIfSetLlvm flag hdr fmt doc = do   dflags <- getDynFlags-  liftIO $ dumpIfSet_dyn dflags flag hdr doc+  liftIO $ dumpIfSet_dyn dflags flag hdr fmt doc  -- | Prints the given contents to the output handle renderLlvm :: Outp.SDoc -> LlvmM ()@@ -353,7 +353,7 @@                (Outp.mkCodeStyle Outp.CStyle) sdoc      -- Dump, if requested-    dumpIfSetLlvm Opt_D_dump_llvm "LLVM Code" sdoc+    dumpIfSetLlvm Opt_D_dump_llvm "LLVM Code" FormatLLVM sdoc     return ()  -- | Marks a variable as "used"
compiler/llvmGen/LlvmCodeGen/CodeGen.hs view
@@ -66,20 +66,24 @@  -- | Generate code for a list of blocks that make up a complete -- procedure. The first block in the list is expected to be the entry--- point and will get the prologue.+-- point. basicBlocksCodeGen :: LiveGlobalRegs -> [CmmBlock]                       -> LlvmM ([LlvmBasicBlock], [LlvmCmmDecl]) basicBlocksCodeGen _    []                     = panic "no entry block!"-basicBlocksCodeGen live (entryBlock:cmmBlocks)-  = do (prologue, prologueTops) <- funPrologue live (entryBlock:cmmBlocks)+basicBlocksCodeGen live cmmBlocks+  = do -- Emit the prologue+       -- N.B. this must be its own block to ensure that the entry block of the+       -- procedure has no predecessors, as required by the LLVM IR. See #17589+       -- and #11649.+       bid <- newBlockId+       (prologue, prologueTops) <- funPrologue live cmmBlocks+       let entryBlock = BasicBlock bid (fromOL prologue)         -- Generate code-       (BasicBlock bid entry, entryTops) <- basicBlockCodeGen entryBlock        (blocks, topss) <- fmap unzip $ mapM basicBlockCodeGen cmmBlocks         -- Compose-       let entryBlock = BasicBlock bid (fromOL prologue ++ entry)-       return (entryBlock : blocks, prologueTops ++ entryTops ++ concat topss)+       return (entryBlock : blocks, prologueTops ++ concat topss)   -- | Generate code for one block@@ -833,6 +837,7 @@     MO_SubWordC w   -> fsLit $ "llvm.usub.with.overflow."                              ++ showSDoc dflags (ppr $ widthToLlvmInt w) +    MO_S_Mul2    {}  -> unsupported     MO_S_QuotRem {}  -> unsupported     MO_U_QuotRem {}  -> unsupported     MO_U_QuotRem2 {} -> unsupported@@ -1833,7 +1838,10 @@         markStackReg r         return $ toOL [alloc, Store rval reg] -  return (concatOL stmtss, [])+  return (concatOL stmtss `snocOL` jumpToEntry, [])+  where+    entryBlk : _ = cmmBlocks+    jumpToEntry = Branch $ blockIdToLlvm (entryLabel entryBlk)  -- | Function epilogue. Load STG variables to use as argument for call. -- STG Liveness optimisation done here.
compiler/main/CodeOutput.hs view
@@ -212,7 +212,9 @@         createDirectoryIfMissing True (takeDirectory stub_h)          dumpIfSet_dyn dflags Opt_D_dump_foreign-                      "Foreign export header file" stub_h_output_d+                      "Foreign export header file"+                      FormatC+                      stub_h_output_d          -- we need the #includes from the rts package for the stub files         let rts_includes =@@ -230,7 +232,7 @@                 ("#include <HsFFI.h>\n" ++ cplusplus_hdr) cplusplus_ftr          dumpIfSet_dyn dflags Opt_D_dump_foreign-                      "Foreign export stubs" stub_c_output_d+                      "Foreign export stubs" FormatC stub_c_output_d          stub_c_file_exists            <- outputForeignStubs_help stub_c stub_c_output_w
compiler/main/Elf.hs view
@@ -408,15 +408,6 @@ -- | Generate the GAS code to create a Note section -- -- Header fields for notes are 32-bit long (see Note [ELF specification]).------ It seems there is no easy way to force GNU AS to generate a 32-bit word in--- every case. Hence we use .int directive to create them: however "The byte--- order and bit size of the number depends on what kind of target the assembly--- is for." (https://sourceware.org/binutils/docs/as/Int.html#Int)------ If we add new target platforms, we need to check that the generated words--- are 32-bit long, otherwise we need to use platform specific directives to--- force 32-bit .int in asWord32. makeElfNote :: String -> String -> Word32 -> String -> SDoc makeElfNote sectionName noteName typ contents = hcat [     text "\t.section ",@@ -424,6 +415,7 @@     text ",\"\",",     sectionType "note",     text "\n",+    text "\t.balign 4\n",      -- note name length (+ 1 for ending \0)     asWord32 (length noteName + 1),@@ -438,20 +430,20 @@     text "\t.asciz \"",     text noteName,     text "\"\n",-    text "\t.align 4\n",+    text "\t.balign 4\n",      -- note contents (.ascii to avoid ending \0) + padding     text "\t.ascii \"",     text (escape contents),     text "\"\n",-    text "\t.align 4\n"]+    text "\t.balign 4\n"]   where     escape :: String -> String     escape = concatMap (charToC.fromIntegral.ord)      asWord32 :: Show a => a -> SDoc     asWord32 x = hcat [-      text "\t.int ",+      text "\t.4byte ",       text (show x),       text "\n"] 
compiler/main/GHC.hs view
@@ -196,7 +196,7 @@          -- ** Data constructors         DataCon,-        dataConSig, dataConType, dataConTyCon, dataConFieldLabels,+        dataConType, dataConTyCon, dataConFieldLabels,         dataConIsInfix, isVanillaDataCon, dataConUserType,         dataConSrcBangs,         StrictnessMark(..), isMarkedStrict,
compiler/main/HscMain.hs view
@@ -123,16 +123,16 @@ import Desugar import SimplCore import TidyPgm-import CorePrep-import CoreToStg        ( coreToStg )+import GHC.CoreToStg.Prep+import GHC.CoreToStg        ( coreToStg )+import GHC.Stg.Syntax+import GHC.Stg.FVs      ( annTopBindingsFreeVars )+import GHC.Stg.Pipeline ( stg2stg ) import qualified GHC.StgToCmm as StgToCmm ( codeGen )-import StgSyn-import StgFVs           ( annTopBindingsFreeVars ) import CostCentre import ProfInit import TyCon import Name-import SimplStg         ( stg2stg ) import Cmm import CmmParse         ( parseCmmFile ) import CmmBuildInfoTables@@ -356,12 +356,12 @@         POk pst rdr_module -> do             let (warns, errs) = getMessages pst dflags             logWarnings warns-            liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" $-                                   ppr rdr_module-            liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST" $-                                   showAstData NoBlankSrcSpan rdr_module-            liftIO $ dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics" $-                                   ppSourceStats False rdr_module+            liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser"+                        FormatHaskell (ppr rdr_module)+            liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST"+                        FormatHaskell (showAstData NoBlankSrcSpan rdr_module)+            liftIO $ dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics"+                        FormatText (ppSourceStats False rdr_module)             when (not $ isEmptyBag errs) $ throwErrors errs              -- To get the list of extra source files, we take the list@@ -412,8 +412,8 @@     let rn_info = getRenamedStuff tc_result      dflags <- getDynFlags-    liftIO $ dumpIfSet_dyn dflags Opt_D_dump_rn_ast "Renamer" $-                           showAstData NoBlankSrcSpan rn_info+    liftIO $ dumpIfSet_dyn dflags Opt_D_dump_rn_ast "Renamer"+                FormatHaskell (showAstData NoBlankSrcSpan rn_info)      -- Create HIE files     when (gopt Opt_WriteHie dflags) $ do@@ -1456,9 +1456,10 @@             rawcmms0 <- {-# SCC "cmmToRawCmm" #-}                       cmmToRawCmm dflags cmms -            let dump a = do dumpIfSet_dyn dflags Opt_D_dump_cmm_raw "Raw Cmm"-                              (ppr a)-                            return a+            let dump a = do+                  unless (null a) $+                    dumpIfSet_dyn dflags Opt_D_dump_cmm_raw "Raw Cmm" FormatCMM (ppr a)+                  return a                 rawcmms1 = Stream.mapM dump rawcmms0              (output_filename, (_stub_h_exists, stub_c_exists), foreign_fps, ())@@ -1506,13 +1507,15 @@     let dflags = hsc_dflags hsc_env     cmm <- ioMsgMaybe $ parseCmmFile dflags filename     liftIO $ do-        dumpIfSet_dyn dflags Opt_D_dump_cmm_verbose_by_proc "Parsed Cmm" (ppr cmm)+        dumpIfSet_dyn dflags Opt_D_dump_cmm_verbose_by_proc "Parsed Cmm" FormatCMM (ppr cmm)         let -- Make up a module name to give the NCG. We can't pass bottom here             -- lest we reproduce #11784.             mod_name = mkModuleName $ "Cmm$" ++ FilePath.takeFileName filename             cmm_mod = mkModule (thisPackage dflags) mod_name         (_, cmmgroup) <- cmmPipeline hsc_env (emptySRT cmm_mod) cmm-        dumpIfSet_dyn dflags Opt_D_dump_cmm "Output Cmm" (ppr cmmgroup)+        unless (null cmmgroup) $+          dumpIfSet_dyn dflags Opt_D_dump_cmm "Output Cmm"+            FormatCMM (ppr cmmgroup)         rawCmms <- cmmToRawCmm dflags (Stream.yield cmmgroup)         _ <- codeOutput dflags cmm_mod output_filename no_loc NoStubs [] []              rawCmms@@ -1549,20 +1552,23 @@         -- CmmGroup on input may produce many CmmGroups on output due         -- to proc-point splitting). -    let dump1 a = do dumpIfSet_dyn dflags Opt_D_dump_cmm_from_stg-                       "Cmm produced by codegen" (ppr a)-                     return a+    let dump1 a = do+          unless (null a) $+            dumpIfSet_dyn dflags Opt_D_dump_cmm_from_stg+              "Cmm produced by codegen" FormatCMM (ppr a)+          return a          ppr_stream1 = Stream.mapM dump1 cmm_stream -        pipeline_stream-           = {-# SCC "cmmPipeline" #-}-             let run_pipeline = cmmPipeline hsc_env-             in void $ Stream.mapAccumL run_pipeline (emptySRT this_mod) ppr_stream1+        pipeline_stream =+          {-# SCC "cmmPipeline" #-}+          let run_pipeline = cmmPipeline hsc_env+          in void $ Stream.mapAccumL run_pipeline (emptySRT this_mod) ppr_stream1 -        dump2 a = do dumpIfSet_dyn dflags Opt_D_dump_cmm-                        "Output Cmm" (ppr a)-                     return a+        dump2 a = do+          unless (null a) $+            dumpIfSet_dyn dflags Opt_D_dump_cmm "Output Cmm" FormatCMM (ppr a)+          return a          ppr_stream2 = Stream.mapM dump2 pipeline_stream @@ -1853,9 +1859,10 @@          POk pst thing -> do             logWarningsReportErrors (getMessages pst dflags)-            liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" (ppr thing)-            liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST" $-                                   showAstData NoBlankSrcSpan thing+            liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser"+                        FormatHaskell (ppr thing)+            liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST"+                        FormatHaskell (showAstData NoBlankSrcSpan thing)             return thing  
compiler/main/InteractiveEval.hs view
@@ -61,7 +61,7 @@ import CoreFVs    ( orphNamesOfFamInst ) import TyCon import Type             hiding( typeKind )-import RepType+import GHC.Types.RepType import TcType import Constraint import TcOrigin@@ -639,6 +639,7 @@                Just subst -> do                  let dflags = hsc_dflags hsc_env                  dumpIfSet_dyn dflags Opt_D_dump_rtti "RTTI"+                   FormatText                    (fsep [text "RTTI Improvement for", ppr id, equals,                           ppr subst]) 
compiler/main/SysTools/Info.hs view
@@ -231,13 +231,13 @@         -- FreeBSD clang         | any ("FreeBSD clang version" `isInfixOf`) stde =           return Clang-        -- XCode 5.1 clang+        -- Xcode 5.1 clang         | any ("Apple LLVM version 5.1" `isPrefixOf`) stde =           return AppleClang51-        -- XCode 5 clang+        -- Xcode 5 clang         | any ("Apple LLVM version" `isPrefixOf`) stde =           return AppleClang-        -- XCode 4.1 clang+        -- Xcode 4.1 clang         | any ("Apple clang version" `isPrefixOf`) stde =           return AppleClang          -- Unknown linker.
compiler/main/TidyPgm.hs view
@@ -21,7 +21,7 @@ import CoreFVs import CoreTidy import CoreMonad-import CorePrep+import GHC.CoreToStg.Prep import CoreUtils        (rhsIsStatic) import CoreStats        (coreBindsStats, CoreStats(..)) import CoreSeq          (seqBinds)@@ -174,7 +174,7 @@                 | id <- typeEnvIds type_env                 , keep_it id ] -    final_tcs  = filterOut (isWiredInName . getName) tcs+    final_tcs  = filterOut isWiredIn tcs                  -- See Note [Drop wired-in things]     type_env1  = typeEnvFromEntities final_ids final_tcs fam_insts     insts'     = mkFinalClsInsts type_env1 insts@@ -385,10 +385,10 @@               ; final_ids  = [ if omit_prags then trimId id else id                              | id <- bindersOfBinds tidy_binds                              , isExternalName (idName id)-                             , not (isWiredInName (getName id))+                             , not (isWiredIn id)                              ]   -- See Note [Drop wired-in things] -              ; final_tcs      = filterOut (isWiredInName . getName) tcs+              ; final_tcs      = filterOut isWiredIn tcs                                  -- See Note [Drop wired-in things]               ; type_env       = typeEnvFromEntities final_ids final_tcs fam_insts               ; tidy_cls_insts = mkFinalClsInsts type_env cls_insts@@ -417,11 +417,13 @@         ; unless (dopt Opt_D_dump_simpl dflags) $             Err.dumpIfSet_dyn dflags Opt_D_dump_rules               (showSDoc dflags (ppr CoreTidy <+> text "rules"))+              Err.FormatText               (pprRulesForUser dflags tidy_rules)            -- Print one-line size info         ; let cs = coreBindsStats tidy_binds         ; Err.dumpIfSet_dyn dflags Opt_D_dump_core_stats "Core Stats"+            Err.FormatText             (text "Tidy size (terms,types,coercions)"              <+> ppr (moduleName mod) <> colon              <+> int (cs_tm cs)
compiler/nativeGen/AsmCodeGen.hs view
@@ -359,6 +359,7 @@           let platform = targetPlatform dflags           dumpIfSet_dyn dflags                   Opt_D_dump_asm_conflicts "Register conflict graph"+                  FormatText                   $ Color.dotGraph                           (targetRegDotColor platform)                           (Color.trivColorable platform@@ -377,7 +378,9 @@                 $ makeImportsDoc dflags (concat (ngs_imports ngs))         return us'   where-    dump_stats = dumpSDoc dflags alwaysQualify Opt_D_dump_asm_stats "NCG stats"+    dump_stats = dumpAction dflags (mkDumpStyle dflags alwaysQualify)+                   (dumpOptionsFromFlag Opt_D_dump_asm_stats) "NCG stats"+                   FormatText  cmmNativeGenStream :: (Outputable statics, Outputable instr                       ,Outputable jumpDest, Instruction instr)@@ -420,7 +423,7 @@               -- See Note [What is this unwinding business?] in Debug.               let !ldbgs = cmmDebugLink (ngs_labels ngs') (ngs_unwinds ngs') ndbgs               unless (null ldbgs) $-                dumpIfSet_dyn dflags Opt_D_dump_debug "Debug Infos"+                dumpIfSet_dyn dflags Opt_D_dump_debug "Debug Infos" FormatText                   (vcat $ map ppr ldbgs)                -- Accumulate debug information for emission in finishNativeGen.@@ -505,7 +508,7 @@          -- dump native code         dumpIfSet_dyn dflags-                Opt_D_dump_asm "Asm code"+                Opt_D_dump_asm "Asm code" FormatASM                 sdoc  -- | Complete native code generation phase for a single top-level chunk of Cmm.@@ -550,7 +553,7 @@                 cmmToCmm dflags this_mod fixed_cmm          dumpIfSet_dyn dflags-                Opt_D_dump_opt_cmm "Optimised Cmm"+                Opt_D_dump_opt_cmm "Optimised Cmm" FormatCMM                 (pprCmmGroup [opt_cmm])          let cmmCfg = {-# SCC "getCFG" #-}@@ -564,7 +567,7 @@                                         fileIds dbgMap opt_cmm cmmCfg          dumpIfSet_dyn dflags-                Opt_D_dump_asm_native "Native code"+                Opt_D_dump_asm_native "Native code" FormatASM                 (vcat $ map (pprNatCmmDecl ncgImpl) native)          maybeDumpCfg dflags (Just nativeCfgWeights) "CFG Weights - Native" proc_name@@ -582,6 +585,7 @@          dumpIfSet_dyn dflags                 Opt_D_dump_asm_liveness "Liveness annotations added"+                FormatCMM                 (vcat $ map ppr withLiveness)          -- allocate registers@@ -621,10 +625,12 @@                 -- dump out what happened during register allocation                 dumpIfSet_dyn dflags                         Opt_D_dump_asm_regalloc "Registers allocated"+                        FormatCMM                         (vcat $ map (pprNatCmmDecl ncgImpl) alloced)                  dumpIfSet_dyn dflags                         Opt_D_dump_asm_regalloc_stages "Build/spill stages"+                        FormatText                         (vcat   $ map (\(stage, stats)                                         -> text "# --------------------------"                                         $$ text "#  cmm " <> int count <> text " Stage " <> int stage@@ -663,6 +669,7 @@                  dumpIfSet_dyn dflags                         Opt_D_dump_asm_regalloc "Registers allocated"+                        FormatCMM                         (vcat $ map (pprNatCmmDecl ncgImpl) alloced)                  let mPprStats =@@ -697,6 +704,7 @@          when (not $ null nativeCfgWeights) $ dumpIfSet_dyn dflags                 Opt_D_dump_cfg_weights "CFG Update information"+                FormatText                 ( text "stack:" <+> ppr stack_updt_blks $$                   text "linearAlloc:" <+> ppr cfgRegAllocUpdates ) @@ -753,6 +761,7 @@          dumpIfSet_dyn dflags                 Opt_D_dump_asm_expanded "Synthetic instructions expanded"+                FormatCMM                 (vcat $ map (pprNatCmmDecl ncgImpl) expanded)          -- generate unwinding information from cmm@@ -779,6 +788,7 @@         | otherwise         = dumpIfSet_dyn                 dflags Opt_D_dump_cfg_weights msg+                FormatText                 (proc_name <> char ':' $$ pprEdgeWeights cfg)  -- | Make sure all blocks we want the layout algorithm to place have been placed.
compiler/nativeGen/BlockLayout.hs view
@@ -76,7 +76,7 @@   We have a CFG with edge weights based on which we try to place blocks next to   each other. -  Edge weights not only represent likelyhood of control transfer between blocks+  Edge weights not only represent likelihood of control transfer between blocks   but also how much a block would benefit from being placed sequentially after   it's predecessor.   For example blocks which are preceded by an info table are more likely to end
compiler/nativeGen/PPC/CodeGen.hs view
@@ -602,7 +602,7 @@           _ -> case x of                  CmmLit (CmmInt imm _)                    | Just _ <- makeImmediate rep True imm-                   -- subfi ('substract from' with immediate) doesn't exist+                   -- subfi ('subtract from' with immediate) doesn't exist                    -> trivialCode rep True SUBFC y x                  _ -> trivialCodeNoImm' (intFormat rep) SUBF y x @@ -2021,6 +2021,7 @@                     MO_AtomicRead _  -> unsupported                     MO_AtomicWrite _ -> unsupported +                    MO_S_Mul2    {}  -> unsupported                     MO_S_QuotRem {}  -> unsupported                     MO_U_QuotRem {}  -> unsupported                     MO_U_QuotRem2 {} -> unsupported
compiler/nativeGen/SPARC/CodeGen.hs view
@@ -681,6 +681,7 @@         MO_AtomicRead w -> fsLit $ atomicReadLabel w         MO_AtomicWrite w -> fsLit $ atomicWriteLabel w +        MO_S_Mul2    {}  -> unsupported         MO_S_QuotRem {}  -> unsupported         MO_U_QuotRem {}  -> unsupported         MO_U_QuotRem2 {} -> unsupported
compiler/nativeGen/X86/CodeGen.hs view
@@ -2613,6 +2613,26 @@                                 MOV format (OpReg rax) (OpReg reg_l)]                return code         _ -> panic "genCCall: Wrong number of arguments/results for mul2"+    (PrimTarget (MO_S_Mul2 width), [res_c, res_h, res_l]) ->+        case args of+        [arg_x, arg_y] ->+            do (y_reg, y_code) <- getRegOrMem arg_y+               x_code <- getAnyReg arg_x+               reg_tmp <- getNewRegNat II8+               let format = intFormat width+                   reg_h = getRegisterReg platform (CmmLocal res_h)+                   reg_l = getRegisterReg platform (CmmLocal res_l)+                   reg_c = getRegisterReg platform (CmmLocal res_c)+                   code = y_code `appOL`+                          x_code rax `appOL`+                          toOL [ IMUL2 format y_reg+                               , MOV format (OpReg rdx) (OpReg reg_h)+                               , MOV format (OpReg rax) (OpReg reg_l)+                               , SETCC CARRY (OpReg reg_tmp)+                               , MOVZxL II8 (OpReg reg_tmp) (OpReg reg_c)+                               ]+               return code+        _ -> panic "genCCall: Wrong number of arguments/results for imul2"      _ -> if is32Bit          then genCCall32' dflags target dest_regs args@@ -3204,6 +3224,7 @@                MO_UF_Conv _ -> unsupported +              MO_S_Mul2    {}  -> unsupported               MO_S_QuotRem {}  -> unsupported               MO_U_QuotRem {}  -> unsupported               MO_U_QuotRem2 {} -> unsupported
compiler/rename/RnEnv.hs view
@@ -1475,9 +1475,16 @@     lookup_top keep_me       = do { env <- getGlobalRdrEnv            ; let all_gres = lookupGlobalRdrEnv env (rdrNameOcc rdr_name)-           ; let candidates_msg = candidates $ map gre_name-                                             $ filter isLocalGRE-                                             $ globalRdrEnvElts env+                 names_in_scope = -- If rdr_name lacks a binding, only+                                  -- recommend alternatives from related+                                  -- namespaces. See #17593.+                                  filter (\n -> nameSpacesRelated+                                                  (rdrNameSpace rdr_name)+                                                  (nameNameSpace n))+                                $ map gre_name+                                $ filter isLocalGRE+                                $ globalRdrEnvElts env+                 candidates_msg = candidates names_in_scope            ; case filter (keep_me . gre_name) all_gres of                [] | null all_gres -> bale_out_with candidates_msg                   | otherwise     -> bale_out_with local_msg
compiler/rename/RnSource.hs view
@@ -1231,7 +1231,7 @@   the type synonym S. While we know that S depends upon 'Q depends upon Closed,   we have no idea that Closed depends upon Open! -  To accomodate for these situations, we ensure that an instance is checked+  To accommodate for these situations, we ensure that an instance is checked   before every @TyClDecl@ on which it does not depend. That's to say, instances   are checked as early as possible in @tcTyAndClassDecls@. 
compiler/rename/RnSplice.hs view
@@ -40,7 +40,7 @@  import DynFlags import FastString-import ErrUtils         ( dumpIfSet_dyn_printer )+import ErrUtils         ( dumpIfSet_dyn_printer, DumpFormat (..) ) import TcEnv            ( tcMetaTy ) import Hooks import THNames          ( quoteExpName, quotePatName, quoteDecName, quoteTypeName@@ -746,7 +746,7 @@        ; when is_decl $  -- Raw material for -dth-dec-file          do { dflags <- getDynFlags             ; liftIO $ dumpIfSet_dyn_printer alwaysQualify dflags Opt_D_th_dec_file-                                             (spliceCodeDoc loc) } }+                                             "" FormatHaskell (spliceCodeDoc loc) } }   where     -- `-ddump-splices`     spliceDebugDoc :: SrcSpan -> SDoc
compiler/simplCore/FloatOut.hs view
@@ -19,7 +19,7 @@ import CoreMonad        ( FloatOutSwitches(..) )  import DynFlags-import ErrUtils         ( dumpIfSet_dyn )+import ErrUtils         ( dumpIfSet_dyn, DumpFormat (..) ) import Id               ( Id, idArity, idType, isBottomingId,                           isJoinId, isJoinId_maybe ) import SetLevels@@ -174,11 +174,13 @@             } ;          dumpIfSet_dyn dflags Opt_D_verbose_core2core "Levels added:"+                  FormatCore                   (vcat (map ppr annotated_w_levels));          let { (tlets, ntlets, lams) = get_stats (sum_stats fss) };          dumpIfSet_dyn dflags Opt_D_dump_simpl_stats "FloatOut stats:"+                FormatText                 (hcat [ int tlets,  text " Lets floated to top level; ",                         int ntlets, text " Lets floated elsewhere; from ",                         int lams,   text " Lambda groups"]);
compiler/simplCore/SetLevels.hs view
@@ -1658,7 +1658,7 @@      mk_poly_bndr bndr uniq = transferPolyIdInfo bndr abs_vars $         -- Note [transferPolyIdInfo] in Id.hs                              transfer_join_info bndr $-                             mkSysLocalOrCoVar (mkFastString str) uniq poly_ty+                             mkSysLocal (mkFastString str) uniq poly_ty                            where                              str     = "poly_" ++ occNameString (getOccName bndr)                              poly_ty = mkLamTypes abs_vars (CoreSubst.substTy subst (idType bndr))@@ -1693,7 +1693,7 @@       = mkExportedVanillaId (mkSystemVarName uniq (mkFastString "static_ptr"))                             rhs_ty       | otherwise-      = mkSysLocalOrCoVar (mkFastString "lvl") uniq rhs_ty+      = mkSysLocal (mkFastString "lvl") uniq rhs_ty  -- | Clone the binders bound by a single-alternative case. cloneCaseBndrs :: LevelEnv -> Level -> [Var] -> LvlM (LevelEnv, [Var])
compiler/simplCore/SimplCore.hs view
@@ -36,7 +36,7 @@ import FloatOut         ( floatOutwards ) import FamInstEnv import Id-import ErrUtils         ( withTiming, withTimingD )+import ErrUtils         ( withTiming, withTimingD, DumpFormat (..) ) import BasicTypes       ( CompilerPhase(..), isDefaultInlinePragma, defaultInlinePragma ) import VarSet import VarEnv@@ -90,6 +90,7 @@         ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_stats              "Grand total simplifier statistics"+             FormatText              (pprSimplCount stats)         ; return guts2 }@@ -576,6 +577,7 @@                   "Simplifier statistics" (pprSimplCount counts)          ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl "Simplified expression"+                        FormatCore                         (pprCoreExpr expr')          ; return expr'@@ -688,6 +690,7 @@                                      binds                } ;            Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis"+                     FormatCore                      (pprCoreBindings tagged_binds);                  -- Get any new rules, and extend the rule base
compiler/simplCore/SimplMonad.hs view
@@ -141,6 +141,7 @@ traceSmpl herald doc   = do { dflags <- getDynFlags        ; liftIO $ Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_trace "Simpl Trace"+           FormatText            (hang (text herald) 2 doc) }  {-
compiler/simplCore/SimplUtils.hs view
@@ -66,7 +66,6 @@ import OrdList          ( isNilOL ) import MonadUtils import Outputable-import Pair import PrelRules import FastString       ( fsLit ) @@ -297,7 +296,7 @@  addCastTo :: ArgInfo -> OutCoercion -> ArgInfo addCastTo ai co = ai { ai_args = CastBy co : ai_args ai-                     , ai_type = pSnd (coercionKind co) }+                     , ai_type = coercionRKind co }  argInfoAppArgs :: [ArgSpec] -> [OutExpr] argInfoAppArgs []                              = []@@ -407,7 +406,7 @@ contHoleType :: SimplCont -> OutType contHoleType (Stop ty _)                      = ty contHoleType (TickIt _ k)                     = contHoleType k-contHoleType (CastIt co _)                    = pFst (coercionKind co)+contHoleType (CastIt co _)                    = coercionLKind co contHoleType (StrictBind { sc_bndr = b, sc_dup = dup, sc_env = se })   = perhapsSubstTy dup se (idType b) contHoleType (StrictArg { sc_fun = ai })      = funArgTy (ai_type ai)@@ -1801,7 +1800,7 @@            ; let  poly_name = setNameUnique (idName var) uniq           -- Keep same name                   poly_ty   = mkInvForAllTys tvs_here (idType var) -- But new type of course                   poly_id   = transferPolyIdInfo var tvs_here $ -- Note [transferPolyIdInfo] in Id.hs-                              mkLocalIdOrCoVar poly_name poly_ty+                              mkLocalId poly_name poly_ty            ; return (poly_id, mkTyApps (Var poly_id) (mkTyVarTys tvs_here)) }                 -- In the olden days, it was crucial to copy the occInfo of the original var,                 -- because we were looking at occurrence-analysed but as yet unsimplified code!
compiler/simplCore/Simplify.hs view
@@ -50,7 +50,6 @@ import Control.Monad import Outputable import FastString-import Pair import Util import ErrUtils import Module          ( moduleName, pprModuleName )@@ -261,7 +260,8 @@       | not (dopt Opt_D_verbose_core2core dflags)       = thing_inside       | otherwise-      = pprTrace ("SimplBind " ++ what) (ppr old_bndr) thing_inside+      = traceAction dflags ("SimplBind " ++ what)+         (ppr old_bndr) thing_inside  -------------------------- simplLazyBind :: SimplEnv@@ -440,7 +440,7 @@ --            x = Just a -- See Note [prepareRhs] prepareRhs mode top_lvl occ info (Cast rhs co)  -- Note [Float coercions]-  | Pair ty1 _ty2 <- coercionKind co         -- Do *not* do this if rhs has an unlifted type+  | let ty1 = coercionLKind co         -- Do *not* do this if rhs has an unlifted type   , not (isUnliftedType ty1)                 -- see Note [Float coercions (unlifted)]   = do  { (floats, rhs') <- makeTrivialWithInfo mode top_lvl occ sanitised_info rhs         ; return (floats, Cast rhs' co) }@@ -579,7 +579,7 @@           else do         { uniq <- getUniqueM         ; let name = mkSystemVarName uniq occ_fs-              var  = mkLocalIdOrCoVarWithInfo name expr_ty info+              var  = mkLocalIdWithInfo name expr_ty info          -- Now something very like completeBind,         -- but without the postInlineUnconditinoally part@@ -1308,7 +1308,7 @@             -- only needed by `sc_hole_ty` which is often not forced.             -- Consequently it is worthwhile using a lazy pattern match here to             -- avoid unnecessary coercionKind evaluations.-          , ~(Pair hole_ty _) <- coercionKind co+          , let hole_ty = coercionLKind co           = {-#SCC "addCoerce-pushCoTyArg" #-}             do { tail' <- addCoerceM m_co' tail                ; return (cont { sc_arg_ty  = arg_ty'@@ -1319,7 +1319,7 @@         addCoerce co cont@(ApplyToVal { sc_arg = arg, sc_env = arg_se                                       , sc_dup = dup, sc_cont = tail })           | Just (co1, m_co2) <- pushCoValArg co-          , Pair _ new_ty <- coercionKind co1+          , let new_ty = coercionRKind co1           , not (isTypeLevPoly new_ty)  -- Without this check, we get a lev-poly arg                                         -- See Note [Levity polymorphism invariants] in CoreSyn                                         -- test: typecheck/should_run/EtaExpandLevPoly@@ -1794,14 +1794,20 @@     interesting_cont = interestingCallContext env call_cont     active_unf       = activeUnfolding (getMode env) var +    log_inlining doc+      = liftIO $ dumpAction dflags+           (mkUserStyle dflags alwaysQualify AllTheWay)+           (dumpOptionsFromFlag Opt_D_dump_inlinings)+           "" FormatText doc+     dump_inline unfolding cont       | not (dopt Opt_D_dump_inlinings dflags) = return ()       | not (dopt Opt_D_verbose_core2core dflags)       = when (isExternalName (idName var)) $-            liftIO $ printOutputForUser dflags alwaysQualify $+            log_inlining $                 sep [text "Inlining done:", nest 4 (ppr var)]       | otherwise-      = liftIO $ printOutputForUser dflags alwaysQualify $+      = liftIO $ log_inlining $            sep [text "Inlining done: " <> ppr var,                 nest 4 (vcat [text "Inlined fn: " <+> nest 2 (ppr unfolding),                               text "Cont:  " <+> ppr cont])]@@ -2066,17 +2072,21 @@      nodump       | dopt Opt_D_dump_rule_rewrites dflags-      = liftIO $ dumpSDoc dflags alwaysQualify Opt_D_dump_rule_rewrites "" empty+      = liftIO $ do+         touchDumpFile dflags (dumpOptionsFromFlag Opt_D_dump_rule_rewrites)        | dopt Opt_D_dump_rule_firings dflags-      = liftIO $ dumpSDoc dflags alwaysQualify Opt_D_dump_rule_firings "" empty+      = liftIO $ do+         touchDumpFile dflags (dumpOptionsFromFlag Opt_D_dump_rule_firings)        | otherwise       = return ()      log_rule dflags flag hdr details-      = liftIO . dumpSDoc dflags alwaysQualify flag "" $-                   sep [text hdr, nest 4 details]+      = liftIO $ do+         let sty = mkDumpStyle dflags alwaysQualify+         dumpAction dflags sty (dumpOptionsFromFlag flag) "" FormatText $+           sep [text hdr, nest 4 details]  trySeqRules :: SimplEnv             -> OutExpr -> InExpr   -- Scrutinee and RHS@@ -2789,8 +2799,8 @@         where           ppr_with_length list             = ppr list <+> parens (text "length =" <+> ppr (length list))-          strdisp MarkedStrict = "MarkedStrict"-          strdisp NotMarkedStrict = "NotMarkedStrict"+          strdisp MarkedStrict = text "MarkedStrict"+          strdisp NotMarkedStrict = text "NotMarkedStrict"  zapIdOccInfoAndSetEvald :: StrictnessMark -> Id -> Id zapIdOccInfoAndSetEvald str v =
− compiler/simplStg/SimplStg.hs
@@ -1,141 +0,0 @@-{--(c) The GRASP/AQUA Project, Glasgow University, 1993-1998--\section[SimplStg]{Driver for simplifying @STG@ programs}--}--{-# LANGUAGE CPP #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}--module SimplStg ( stg2stg ) where--#include "HsVersions.h"--import GhcPrelude--import StgSyn--import StgLint          ( lintStgTopBindings )-import StgStats         ( showStgStats )-import UnariseStg       ( unarise )-import StgCse           ( stgCse )-import StgLiftLams      ( stgLiftLams )-import Module           ( Module )--import DynFlags-import ErrUtils-import UniqSupply-import Outputable-import Control.Monad-import Control.Monad.IO.Class-import Control.Monad.Trans.State.Strict--newtype StgM a = StgM { _unStgM :: StateT Char IO a }-  deriving (Functor, Applicative, Monad, MonadIO)--instance MonadUnique StgM where-  getUniqueSupplyM = StgM $ do { mask <- get-                               ; liftIO $! mkSplitUniqSupply mask}-  getUniqueM = StgM $ do { mask <- get-                         ; liftIO $! uniqFromMask mask}--runStgM :: Char -> StgM a -> IO a-runStgM mask (StgM m) = evalStateT m mask--stg2stg :: DynFlags                  -- includes spec of what stg-to-stg passes to do-        -> Module                    -- module being compiled-        -> [StgTopBinding]           -- input program-        -> IO [StgTopBinding]        -- output program--stg2stg dflags this_mod binds-  = do  { dump_when Opt_D_dump_stg "STG:" binds-        ; showPass dflags "Stg2Stg"-        -- Do the main business!-        ; binds' <- runStgM 'g' $-            foldM do_stg_pass binds (getStgToDo dflags)--        ; dump_when Opt_D_dump_stg_final "Final STG:" binds'--        ; return binds'-   }--  where-    stg_linter unarised-      | gopt Opt_DoStgLinting dflags-      = lintStgTopBindings dflags this_mod unarised-      | otherwise-      = \ _whodunnit _binds -> return ()--    --------------------------------------------    do_stg_pass :: [StgTopBinding] -> StgToDo -> StgM [StgTopBinding]-    do_stg_pass binds to_do-      = case to_do of-          StgDoNothing ->-            return binds--          StgStats ->-            trace (showStgStats binds) (return binds)--          StgCSE -> do-            let binds' = {-# SCC "StgCse" #-} stgCse binds-            end_pass "StgCse" binds'--          StgLiftLams -> do-            us <- getUniqueSupplyM-            let binds' = {-# SCC "StgLiftLams" #-} stgLiftLams dflags us binds-            end_pass "StgLiftLams" binds'--          StgUnarise -> do-            us <- getUniqueSupplyM-            liftIO (stg_linter False "Pre-unarise" binds)-            let binds' = unarise us binds-            liftIO (dump_when Opt_D_dump_stg_unarised "Unarised STG:" binds')-            liftIO (stg_linter True "Unarise" binds')-            return binds'--    dump_when flag header binds-      = dumpIfSet_dyn dflags flag header (pprStgTopBindings binds)--    end_pass what binds2-      = liftIO $ do -- report verbosely, if required-          dumpIfSet_dyn dflags Opt_D_verbose_stg2stg what-            (vcat (map ppr binds2))-          stg_linter False what binds2-          return binds2---- -------------------------------------------------------------------------------- StgToDo:  abstraction of stg-to-stg passes to run.---- | Optional Stg-to-Stg passes.-data StgToDo-  = StgCSE-  -- ^ Common subexpression elimination-  | StgLiftLams-  -- ^ Lambda lifting closure variables, trading stack/register allocation for-  -- heap allocation-  | StgStats-  | StgUnarise-  -- ^ Mandatory unarise pass, desugaring unboxed tuple and sum binders-  | StgDoNothing-  -- ^ Useful for building up 'getStgToDo'-  deriving Eq---- | Which Stg-to-Stg passes to run. Depends on flags, ways etc.-getStgToDo :: DynFlags -> [StgToDo]-getStgToDo dflags =-  filter (/= StgDoNothing)-    [ mandatory StgUnarise-    -- Important that unarisation comes first-    -- See Note [StgCse after unarisation] in StgCse-    , optional Opt_StgCSE StgCSE-    , optional Opt_StgLiftLams StgLiftLams-    , optional Opt_StgStats StgStats-    ] where-      optional opt = runWhen (gopt opt dflags)-      mandatory = id--runWhen :: Bool -> StgToDo -> StgToDo-runWhen True todo = todo-runWhen _    _    = StgDoNothing
− compiler/simplStg/StgCse.hs
@@ -1,483 +0,0 @@-{-# LANGUAGE TypeFamilies #-}--{-|-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 operationally equivalent), but that we cannot common up in Core, because-their types differ.-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-note [Case 2: CSEing case binders] below.---Note [Case 1: CSEing allocated closures]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-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)--which produces this Core:--    bar :: forall a. a -> (Either Int a, Either Bool a)-    bar @a x = (Right @Int @a x, Right @Bool @a x)--where the two components of the tuple are different terms, and cannot be-commoned up (easily). On the STG level we have--    bar [x] = let c1 = Right [x]-                  c2 = Right [x]-              in (c1,c2)--and now it is obvious that we can write--    bar [x] = let c1 = Right [x]-              in (c1,c1)--instead.---Note [Case 2: CSEing case binders]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-The second kind of CSE opportunity we aim for is more interesting, and-came up in #9291 and #5344: The Haskell code--    foo :: Either Int a -> Either Bool a-    foo (Right x) = Right x-    foo _         = Left False--produces this Core--    foo :: forall a. Either Int a -> Either Bool a-    foo @a e = case e of b { Left n -> …-                           , Right x -> Right @Bool @a x }--where we cannot CSE `Right @Bool @a x` with the case binder `b` as they have-different types. But in STG we have--    foo [e] = case e of b { Left [n] -> …-                          , Right [x] -> Right [x] }--and nothing stops us from transforming that to--    foo [e] = case e of b { Left [n] -> …-                          , Right [x] -> b}---Note [StgCse after unarisation]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Consider two unboxed sum terms:--    (# 1 | #) :: (# Int | Int# #)-    (# 1 | #) :: (# Int | Int  #)--These two terms are not equal as they unarise to different unboxed-tuples. However if we run StgCse before Unarise, it'll think the two-terms (# 1 | #) are equal, and replace one of these with a binder to-the other. That's bad -- #15300.--Solution: do unarise first.---}--module StgCse (stgCse) where--import GhcPrelude--import DataCon-import Id-import StgSyn-import Outputable-import VarEnv-import CoreSyn (AltCon(..))-import Data.List (mapAccumL)-import Data.Maybe (fromMaybe)-import CoreMap-import NameEnv-import Control.Monad( (>=>) )------------------- The Trie --------------------- A lookup trie for data constructor applications, i.e.--- keys of type `(DataCon, [StgArg])`, following the patterns in TrieMap.--data StgArgMap a = SAM-    { sam_var :: DVarEnv a-    , sam_lit :: LiteralMap a-    }--instance TrieMap StgArgMap where-    type Key StgArgMap = StgArg-    emptyTM  = SAM { sam_var = emptyTM-                   , sam_lit = emptyTM }-    lookupTM (StgVarArg var) = sam_var >.> lkDFreeVar var-    lookupTM (StgLitArg lit) = sam_lit >.> lookupTM lit-    alterTM  (StgVarArg var) f m = m { sam_var = sam_var m |> xtDFreeVar var f }-    alterTM  (StgLitArg lit) f m = m { sam_lit = sam_lit m |> alterTM lit f }-    foldTM k m = foldTM k (sam_var m) . foldTM k (sam_lit m)-    mapTM f (SAM {sam_var = varm, sam_lit = litm}) =-        SAM { sam_var = mapTM f varm, sam_lit = mapTM f litm }--newtype ConAppMap a = CAM { un_cam :: DNameEnv (ListMap StgArgMap a) }--instance TrieMap ConAppMap where-    type Key ConAppMap = (DataCon, [StgArg])-    emptyTM  = CAM emptyTM-    lookupTM (dataCon, args) = un_cam >.> lkDNamed dataCon >=> lookupTM args-    alterTM  (dataCon, args) f m =-        m { un_cam = un_cam m |> xtDNamed dataCon |>> alterTM args f }-    foldTM k = un_cam >.> foldTM (foldTM k)-    mapTM f  = un_cam >.> mapTM (mapTM f) >.> CAM---------------------- The CSE Env ------------------------ | The CSE environment. See note [CseEnv Example]-data CseEnv = CseEnv-    { ce_conAppMap :: ConAppMap OutId-        -- ^ The main component of the environment is the trie that maps-        --   data constructor applications (with their `OutId` arguments)-        --   to an in-scope name that can be used instead.-        --   This name is always either a let-bound variable or a case binder.-    , ce_subst     :: IdEnv OutId-        -- ^ This substitution is applied to the code as we traverse it.-        --   Entries have one of two reasons:-        ---        --   * The input might have shadowing (see Note [Shadowing]), so we have-        --     to rename some binders as we traverse the tree.-        --   * 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-        --   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]-    , ce_in_scope  :: InScopeSet-        -- ^ The third component is an in-scope set, to rename away any-        --   shadowing binders-    }--{-|-Note [CseEnv Example]-~~~~~~~~~~~~~~~~~~~~~-The following tables shows how the CseEnvironment changes as code is traversed,-as well as the changes to that code.--  InExpr                         OutExpr-     conAppMap                   subst          in_scope-  ───────────────────────────────────────────────────────────-  -- empty                       {}             {}-  case … as a of {Con x y ->     case … as a of {Con x y ->-  -- Con x y ↦ a                 {}             {a,x,y}-  let b = Con x y                (removed)-  -- Con x y ↦ a                 b↦a            {a,x,y,b}-  let c = Bar a                  let c = Bar a-  -- Con x y ↦ a, Bar a ↦ c      b↦a            {a,x,y,b,c}-  let c = some expression        let c' = some expression-  -- Con x y ↦ a, Bar a ↦ c      b↦a, c↦c',     {a,x,y,b,c,c'}-  let d = Bar b                  (removed)-  -- Con x y ↦ a, Bar a ↦ c      b↦a, c↦c', d↦c {a,x,y,b,c,c',d}-  (a, b, c d)                    (a, a, c' c)--}--initEnv :: InScopeSet -> CseEnv-initEnv in_scope = CseEnv-    { ce_conAppMap = emptyTM-    , ce_subst     = emptyVarEnv-    , ce_bndrMap   = emptyVarEnv-    , ce_in_scope  = in_scope-    }--envLookup :: DataCon -> [OutStgArg] -> CseEnv -> Maybe OutId-envLookup dataCon args env = lookupTM (dataCon, args') (ce_conAppMap env)-  where args' = map go args -- See Note [Trivial case scrutinee]-        go (StgVarArg v  ) = StgVarArg (fromMaybe v $ lookupVarEnv (ce_bndrMap env) v)-        go (StgLitArg lit) = StgLitArg lit--addDataCon :: OutId -> DataCon -> [OutStgArg] -> CseEnv -> CseEnv--- do not bother with nullary data constructors, they are static anyways-addDataCon _ _ [] env = env-addDataCon bndr dataCon args env = env { ce_conAppMap = new_env }-  where-    new_env = insertTM (dataCon, args) bndr (ce_conAppMap env)--forgetCse :: CseEnv -> CseEnv-forgetCse env = env { ce_conAppMap = emptyTM }-    -- See note [Free variables of an StgClosure]--addSubst :: OutId -> OutId -> CseEnv -> CseEnv-addSubst from to env-    = env { ce_subst = extendVarEnv (ce_subst env) from to }--addTrivCaseBndr :: OutId -> OutId -> CseEnv -> CseEnv-addTrivCaseBndr from to env-    = env { ce_bndrMap = extendVarEnv (ce_bndrMap env) from to }--substArgs :: CseEnv -> [InStgArg] -> [OutStgArg]-substArgs env = map (substArg env)--substArg :: CseEnv -> InStgArg -> OutStgArg-substArg env (StgVarArg from) = StgVarArg (substVar env from)-substArg _   (StgLitArg lit)  = StgLitArg lit--substVar :: CseEnv -> InId -> OutId-substVar env id = fromMaybe id $ lookupVarEnv (ce_subst env) id---- Functions to enter binders---- 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.--- Therefore, no special treatment for a recursive group is required.--substBndr :: CseEnv -> InId -> (CseEnv, OutId)-substBndr env old_id-  = (new_env, new_id)-  where-    new_id = uniqAway (ce_in_scope env) old_id-    no_change = new_id == old_id-    env' = env { ce_in_scope = ce_in_scope env `extendInScopeSet` new_id }-    new_env | no_change = env'-            | otherwise = env' { ce_subst = extendVarEnv (ce_subst env) old_id new_id }--substBndrs :: CseEnv -> [InVar] -> (CseEnv, [OutVar])-substBndrs env bndrs = mapAccumL substBndr env bndrs--substPairs :: CseEnv -> [(InVar, a)] -> (CseEnv, [(OutVar, a)])-substPairs env bndrs = mapAccumL go env bndrs-  where go env (id, x) = let (env', id') = substBndr env id-                         in (env', (id', x))---- Main entry point--stgCse :: [InStgTopBinding] -> [OutStgTopBinding]-stgCse binds = snd $ mapAccumL stgCseTopLvl emptyInScopeSet binds---- Top level bindings.------ We do not CSE these, as top-level closures are allocated statically anyways.--- Also, they might be exported.--- But we still have to collect the set of in-scope variables, otherwise--- uniqAway might shadow a top-level closure.--stgCseTopLvl :: InScopeSet -> InStgTopBinding -> (InScopeSet, OutStgTopBinding)-stgCseTopLvl in_scope t@(StgTopStringLit _ _) = (in_scope, t)-stgCseTopLvl in_scope (StgTopLifted (StgNonRec bndr rhs))-    = (in_scope'-      , StgTopLifted (StgNonRec bndr (stgCseTopLvlRhs in_scope rhs)))-  where in_scope' = in_scope `extendInScopeSet` bndr--stgCseTopLvl in_scope (StgTopLifted (StgRec eqs))-    = ( in_scope'-      , StgTopLifted (StgRec [ (bndr, stgCseTopLvlRhs in_scope' rhs) | (bndr, rhs) <- eqs ]))-  where in_scope' = in_scope `extendInScopeSetList` [ bndr | (bndr, _) <- eqs ]--stgCseTopLvlRhs :: InScopeSet -> InStgRhs -> OutStgRhs-stgCseTopLvlRhs in_scope (StgRhsClosure ext ccs upd args body)-    = let body' = stgCseExpr (initEnv in_scope) body-      in  StgRhsClosure ext ccs upd args body'-stgCseTopLvlRhs _ (StgRhsCon ccs dataCon args)-    = StgRhsCon ccs dataCon args----------------------------------- The actual AST traversal ------------------------------------- Trivial cases-stgCseExpr :: CseEnv -> InStgExpr -> OutStgExpr-stgCseExpr env (StgApp fun args)-    = StgApp fun' args'-  where fun' = substVar env fun-        args' = substArgs env args-stgCseExpr _ (StgLit lit)-    = StgLit lit-stgCseExpr env (StgOpApp op args tys)-    = StgOpApp op args' tys-  where args' = substArgs env args-stgCseExpr _ (StgLam _ _)-    = pprPanic "stgCseExp" (text "StgLam")-stgCseExpr env (StgTick tick body)-    = let body' = stgCseExpr env body-      in StgTick tick body'-stgCseExpr env (StgCase scrut bndr ty alts)-    = mkStgCase scrut' bndr' ty alts'-  where-    scrut' = stgCseExpr env scrut-    (env1, bndr') = substBndr env bndr-    env2 | StgApp trivial_scrut [] <- scrut' = addTrivCaseBndr bndr trivial_scrut env1-                 -- See Note [Trivial case scrutinee]-         | otherwise                         = env1-    alts' = map (stgCseAlt env2 ty bndr') alts----- A constructor application.--- To be removed by a variable use when found in the CSE environment-stgCseExpr env (StgConApp dataCon args tys)-    | Just bndr' <- envLookup dataCon args' env-    = StgApp bndr' []-    | otherwise-    = StgConApp dataCon args' tys-  where args' = substArgs env args---- Let bindings--- The binding might be removed due to CSE (we do not want trivial bindings on--- the STG level), so use the smart constructor `mkStgLet` to remove the binding--- if empty.-stgCseExpr env (StgLet ext binds body)-    = let (binds', env') = stgCseBind env binds-          body' = stgCseExpr env' body-      in mkStgLet (StgLet ext) binds' body'-stgCseExpr env (StgLetNoEscape ext binds body)-    = let (binds', env') = stgCseBind env binds-          body' = stgCseExpr env' body-      in mkStgLet (StgLetNoEscape ext) binds' body'---- Case alternatives--- Extend the CSE environment-stgCseAlt :: CseEnv -> AltType -> OutId -> InStgAlt -> OutStgAlt-stgCseAlt env ty case_bndr (DataAlt dataCon, args, rhs)-    = let (env1, args') = substBndrs env args-          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)-    = let (env1, args') = substBndrs env args-          rhs' = stgCseExpr env1 rhs-      in (altCon, args', rhs')---- Bindings-stgCseBind :: CseEnv -> InStgBinding -> (Maybe OutStgBinding, CseEnv)-stgCseBind env (StgNonRec b e)-    = let (env1, b') = substBndr env b-      in case stgCseRhs env1 b' e of-        (Nothing,      env2) -> (Nothing,                env2)-        (Just (b2,e'), env2) -> (Just (StgNonRec b2 e'), env2)-stgCseBind env (StgRec pairs)-    = let (env1, pairs1) = substPairs env pairs-      in case stgCsePairs env1 pairs1 of-        ([],     env2) -> (Nothing, env2)-        (pairs2, env2) -> (Just (StgRec pairs2), env2)--stgCsePairs :: CseEnv -> [(OutId, InStgRhs)] -> ([(OutId, OutStgRhs)], CseEnv)-stgCsePairs env [] = ([], env)-stgCsePairs env0 ((b,e):pairs)-  = let (pairMB, env1) = stgCseRhs env0 b e-        (pairs', env2) = stgCsePairs env1 pairs-    in (pairMB `mbCons` pairs', env2)-  where-    mbCons = maybe id (:)---- The RHS of a binding.--- 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-    = let env' = addSubst bndr other_bndr env-      in (Nothing, env')-    | otherwise-    = let env' = addDataCon bndr dataCon args' env-            -- see note [Case 1: CSEing allocated closures]-          pair = (bndr, StgRhsCon ccs dataCon args')-      in (Just pair, env')-  where args' = substArgs env args-stgCseRhs env bndr (StgRhsClosure ext ccs upd args body)-    = let (env1, args') = substBndrs env args-          env2 = forgetCse env1 -- See note [Free variables of an StgClosure]-          body' = stgCseExpr env2 body-      in (Just (substVar env bndr, StgRhsClosure ext ccs upd args' body'), env)---mkStgCase :: StgExpr -> OutId -> AltType -> [StgAlt] -> StgExpr-mkStgCase scrut bndr ty alts | all isBndr alts = scrut-                             | otherwise       = StgCase scrut bndr ty alts--  where-    -- see Note [All alternatives are the binder]-    isBndr (_, _, StgApp f []) = f == bndr-    isBndr _                   = False----- Utilities---- | This function short-cuts let-bindings that are now obsolete-mkStgLet :: (a -> b -> b) -> Maybe a -> b -> b-mkStgLet _      Nothing      body = body-mkStgLet stgLet (Just binds) body = stgLet binds body---{--Note [All alternatives are the binder]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--When all alternatives simply refer to the case binder, then we do not have-to bother with the case expression at all (#13588). CoreSTG does this as well,-but sometimes, types get into the way:--    newtype T = MkT Int-    f :: (Int, Int) -> (T, Int)-    f (x, y) = (MkT x, y)--Core cannot just turn this into--    f p = p--as this would not be well-typed. But to STG, where MkT is no longer in the way,-we can.--Note [Trivial case scrutinee]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-We want to be able to handle nested reconstruction of constructors as in--    nested :: Either Int (Either Int a) -> Either Bool (Either Bool a)-    nested (Right (Right v)) = Right (Right v)-    nested _ = Left True--So if we come across--    case x of r1-      Right a -> case a of r2-              Right b -> let v = Right b-                         in Right v--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 substitution before looking Right r2 up in ce_conAppMap, and everything-works out.--Note [Free variables of an StgClosure]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-StgClosures (function and thunks) have an explicit list of free variables:--foo [x] =-    let not_a_free_var = Left [x]-    let a_free_var = Right [x]-    let closure = \[x a_free_var] -> \[y] -> bar y (Left [x]) a_free_var-    in closure--If we were to CSE `Left [x]` in the body of `closure` with `not_a_free_var`,-then the list of free variables would be wrong, so for now, we do not CSE-across such a closure, simply because I (Joachim) was not sure about possible-knock-on effects. If deemed safe and worth the slight code complication of-re-calculating this list during or after this pass, this can surely be done.--}
− compiler/simplStg/StgLiftLams.hs
@@ -1,102 +0,0 @@--- | Implements a selective lambda lifter, running late in the optimisation--- pipeline.------ The transformation itself is implemented in "StgLiftLams.Transformation".--- If you are interested in the cost model that is employed to decide whether--- to lift a binding or not, look at "StgLiftLams.Analysis".--- "StgLiftLams.LiftM" contains the transformation monad that hides away some--- plumbing of the transformation.-module StgLiftLams (-    -- * Late lambda lifting in STG-    -- $note-    Transformation.stgLiftLams-  ) where--import qualified StgLiftLams.Transformation as Transformation---- Note [Late lambda lifting in STG]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--- $note--- See also the <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page>--- and #9476.------ The basic idea behind lambda lifting is to turn locally defined functions--- into top-level functions. Free variables are then passed as additional--- arguments at *call sites* instead of having a closure allocated for them at--- *definition site*. Example:------ @---    let x = ...; y = ... in---    let f = {x y} \a -> a + x + y in---    let g = {f x} \b -> f b + x in---    g 5--- @------ Lambda lifting @f@ would------   1. Turn @f@'s free variables into formal parameters---   2. Update @f@'s call site within @g@ to @f x y b@---   3. Update @g@'s closure: Add @y@ as an additional free variable, while---      removing @f@, because @f@ no longer allocates and can be floated to---      top-level.---   4. Actually float the binding of @f@ to top-level, eliminating the @let@---      in the process.------ This results in the following program (with free var annotations):------ @---    f x y a = a + x + y;---    let x = ...; y = ... in---    let g = {x y} \b -> f x y b + x in---    g 5--- @------ This optimisation is all about lifting only when it is beneficial to do so.--- The above seems like a worthwhile lift, judging from heap allocation:--- We eliminate @f@'s closure, saving to allocate a closure with 2 words, while--- not changing the size of @g@'s closure.------ You can probably sense that there's some kind of cost model at play here.--- And you are right! But we also employ a couple of other heuristics for the--- lifting decision which are outlined in "StgLiftLams.Analysis#when".------ The transformation is done in "StgLiftLams.Transformation", which calls out--- to 'StgLiftLams.Analysis.goodToLift' for its lifting decision.--- It relies on "StgLiftLams.LiftM", which abstracts some subtle STG invariants--- into a monadic substrate.------ Suffice to say: We trade heap allocation for stack allocation.--- The additional arguments have to passed on the stack (or in registers,--- depending on architecture) every time we call the function to save a single--- heap allocation when entering the let binding. Nofib suggests a mean--- improvement of about 1% for this pass, so it seems like a worthwhile thing to--- do. Compile-times went up by 0.6%, so all in all a very modest change.------ For a concrete example, look at @spectral/atom@. There's a call to 'zipWith'--- that is ultimately compiled to something like this--- (module desugaring/lowering to actual STG):------ @---    propagate dt = ...;---    runExperiment ... =---      let xs = ... in---      let ys = ... in---      let go = {dt go} \xs ys -> case (xs, ys) of---            ([], []) -> []---            (x:xs', y:ys') -> propagate dt x y : go xs' ys'---      in go xs ys--- @------ This will lambda lift @go@ to top-level, speeding up the resulting program--- by roughly one percent:------ @---    propagate dt = ...;---    go dt xs ys = case (xs, ys) of---      ([], []) -> []---      (x:xs', y:ys') -> propagate dt x y : go dt xs' ys'---    runExperiment ... =---      let xs = ... in---      let ys = ... in---      in go dt xs ys--- @
− compiler/simplStg/StgLiftLams/Analysis.hs
@@ -1,565 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE DataKinds #-}---- | Provides the heuristics for when it's beneficial to lambda lift bindings.--- Most significantly, this employs a cost model to estimate impact on heap--- allocations, by looking at an STG expression's 'Skeleton'.-module StgLiftLams.Analysis (-    -- * #when# When to lift-    -- $when--    -- * #clogro# Estimating closure growth-    -- $clogro--    -- * AST annotation-    Skeleton(..), BinderInfo(..), binderInfoBndr,-    LlStgBinding, LlStgExpr, LlStgRhs, LlStgAlt, tagSkeletonTopBind,-    -- * Lifting decision-    goodToLift,-    closureGrowth -- Exported just for the docs-  ) where--import GhcPrelude--import BasicTypes-import Demand-import DynFlags-import Id-import SMRep ( WordOff )-import StgSyn-import qualified GHC.StgToCmm.ArgRep  as StgToCmm.ArgRep-import qualified GHC.StgToCmm.Closure as StgToCmm.Closure-import qualified GHC.StgToCmm.Layout  as StgToCmm.Layout-import Outputable-import Util-import VarSet--import Data.Maybe ( mapMaybe )---- Note [When to lift]--- ~~~~~~~~~~~~~~~~~~~--- $when--- The analysis proceeds in two steps:------   1. It tags the syntax tree with analysis information in the form of---      'BinderInfo' at each binder and 'Skeleton's at each let-binding---      by 'tagSkeletonTopBind' and friends.---   2. The resulting syntax tree is treated by the "StgLiftLams.Transformation"---      module, calling out to 'goodToLift' to decide if a binding is worthwhile---      to lift.---      'goodToLift' consults argument occurrence information in 'BinderInfo'---      and estimates 'closureGrowth', for which it needs the 'Skeleton'.------ So the annotations from 'tagSkeletonTopBind' ultimately fuel 'goodToLift',--- which employs a number of heuristics to identify and exclude lambda lifting--- opportunities deemed non-beneficial:------  [Top-level bindings] can't be lifted.---  [Thunks] and data constructors shouldn't be lifted in order not to destroy---    sharing.---  [Argument occurrences] #arg_occs# of binders prohibit them to be lifted.---    Doing the lift would re-introduce the very allocation at call sites that---    we tried to get rid off in the first place. We capture analysis---    information in 'BinderInfo'. Note that we also consider a nullary---    application as argument occurrence, because it would turn into an n-ary---    partial application created by a generic apply function. This occurs in---    CPS-heavy code like the CS benchmark.---  [Join points] should not be lifted, simply because there's no reduction in---    allocation to be had.---  [Abstracting over join points] destroys join points, because they end up as---    arguments to the lifted function.---  [Abstracting over known local functions] turns a known call into an unknown---    call (e.g. some @stg_ap_*@), which is generally slower. Can be turned off---    with @-fstg-lift-lams-known@.---  [Calling convention] Don't lift when the resulting function would have a---    higher arity than available argument registers for the calling convention.---    Can be influenced with @-fstg-lift-(non)rec-args(-any)@.---  [Closure growth] introduced when former free variables have to be available---    at call sites may actually lead to an increase in overall allocations---  resulting from a lift. Estimating closure growth is described in---  "StgLiftLams.Analysis#clogro" and is what most of this module is ultimately---  concerned with.------ There's a <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page> with--- some more background and history.---- Note [Estimating closure growth]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--- $clogro--- We estimate closure growth by abstracting the syntax tree into a 'Skeleton',--- capturing only syntactic details relevant to 'closureGrowth', such as------   * 'ClosureSk', representing closure allocation.---   * 'RhsSk', representing a RHS of a binding and how many times it's called---     by an appropriate 'DmdShell'.---   * 'AltSk', 'BothSk' and 'NilSk' for choice, sequence and empty element.------ This abstraction is mostly so that the main analysis function 'closureGrowth'--- can stay simple and focused. Also, skeletons tend to be much smaller than--- the syntax tree they abstract, so it makes sense to construct them once and--- and operate on them instead of the actual syntax tree.------ A more detailed treatment of computing closure growth, including examples,--- can be found in the paper referenced from the--- <https://gitlab.haskell.org/ghc/ghc/wikis/late-lam-lift wiki page>.--llTrace :: String -> SDoc -> a -> a-llTrace _ _ c = c--- llTrace a b c = pprTrace a b c--type instance BinderP      'LiftLams = BinderInfo-type instance XRhsClosure  'LiftLams = DIdSet-type instance XLet         'LiftLams = Skeleton-type instance XLetNoEscape 'LiftLams = Skeleton--freeVarsOfRhs :: (XRhsClosure pass ~ DIdSet) => GenStgRhs pass -> DIdSet-freeVarsOfRhs (StgRhsCon _ _ args) = mkDVarSet [ id | StgVarArg id <- args ]-freeVarsOfRhs (StgRhsClosure fvs _ _ _ _) = fvs---- | Captures details of the syntax tree relevant to the cost model, such as--- closures, multi-shot lambdas and case expressions.-data Skeleton-  = ClosureSk !Id !DIdSet {- ^ free vars -} !Skeleton-  | RhsSk !DmdShell {- ^ how often the RHS was entered -} !Skeleton-  | AltSk !Skeleton !Skeleton-  | BothSk !Skeleton !Skeleton-  | NilSk--bothSk :: Skeleton -> Skeleton -> Skeleton-bothSk NilSk b = b-bothSk a NilSk = a-bothSk a b     = BothSk a b--altSk :: Skeleton -> Skeleton -> Skeleton-altSk NilSk b = b-altSk a NilSk = a-altSk a b     = AltSk a b--rhsSk :: DmdShell -> Skeleton -> Skeleton-rhsSk _        NilSk = NilSk-rhsSk body_dmd skel  = RhsSk body_dmd skel---- | The type used in binder positions in 'GenStgExpr's.-data BinderInfo-  = BindsClosure !Id !Bool -- ^ Let(-no-escape)-bound thing with a flag-                           --   indicating whether it occurs as an argument-                           --   or in a nullary application-                           --   (see "StgLiftLams.Analysis#arg_occs").-  | BoringBinder !Id       -- ^ Every other kind of binder---- | Gets the bound 'Id' out a 'BinderInfo'.-binderInfoBndr :: BinderInfo -> Id-binderInfoBndr (BoringBinder bndr)   = bndr-binderInfoBndr (BindsClosure bndr _) = bndr---- | Returns 'Nothing' for 'BoringBinder's and 'Just' the flag indicating--- occurrences as argument or in a nullary applications otherwise.-binderInfoOccursAsArg :: BinderInfo -> Maybe Bool-binderInfoOccursAsArg BoringBinder{}     = Nothing-binderInfoOccursAsArg (BindsClosure _ b) = Just b--instance Outputable Skeleton where-  ppr NilSk = text ""-  ppr (AltSk l r) = vcat-    [ text "{ " <+> ppr l-    , text "ALT"-    , text "  " <+> ppr r-    , text "}"-    ]-  ppr (BothSk l r) = ppr l $$ ppr r-  ppr (ClosureSk f fvs body) = ppr f <+> ppr fvs $$ nest 2 (ppr body)-  ppr (RhsSk body_dmd body) = hcat-    [ text "λ["-    , ppr str-    , text ", "-    , ppr use-    , text "]. "-    , ppr body-    ]-    where-      str-        | isStrictDmd body_dmd = '1'-        | otherwise = '0'-      use-        | isAbsDmd body_dmd = '0'-        | isUsedOnce body_dmd = '1'-        | otherwise = 'ω'--instance Outputable BinderInfo where-  ppr = ppr . binderInfoBndr--instance OutputableBndr BinderInfo where-  pprBndr b = pprBndr b . binderInfoBndr-  pprPrefixOcc = pprPrefixOcc . binderInfoBndr-  pprInfixOcc = pprInfixOcc . binderInfoBndr-  bndrIsJoin_maybe = bndrIsJoin_maybe . binderInfoBndr--mkArgOccs :: [StgArg] -> IdSet-mkArgOccs = mkVarSet . mapMaybe stg_arg_var-  where-    stg_arg_var (StgVarArg occ) = Just occ-    stg_arg_var _               = Nothing---- | Tags every binder with its 'BinderInfo' and let bindings with their--- 'Skeleton's.-tagSkeletonTopBind :: CgStgBinding -> LlStgBinding--- NilSk is OK when tagging top-level bindings. Also, top-level things are never--- lambda-lifted, so no need to track their argument occurrences. They can also--- never be let-no-escapes (thus we pass False).-tagSkeletonTopBind bind = bind'-  where-    (_, _, _, bind') = tagSkeletonBinding False NilSk emptyVarSet bind---- | Tags binders of an 'StgExpr' with its 'BinderInfo' and let bindings with--- their 'Skeleton's. Additionally, returns its 'Skeleton' and the set of binder--- occurrences in argument and nullary application position--- (cf. "StgLiftLams.Analysis#arg_occs").-tagSkeletonExpr :: CgStgExpr -> (Skeleton, IdSet, LlStgExpr)-tagSkeletonExpr (StgLit lit)-  = (NilSk, emptyVarSet, StgLit lit)-tagSkeletonExpr (StgConApp con args tys)-  = (NilSk, mkArgOccs args, StgConApp con args tys)-tagSkeletonExpr (StgOpApp op args ty)-  = (NilSk, mkArgOccs args, StgOpApp op args ty)-tagSkeletonExpr (StgApp f args)-  = (NilSk, arg_occs, StgApp f args)-  where-    arg_occs-      -- This checks for nullary applications, which we treat the same as-      -- argument occurrences, see "StgLiftLams.Analysis#arg_occs".-      | null args = unitVarSet f-      | otherwise = mkArgOccs args-tagSkeletonExpr (StgLam _ _) = pprPanic "stgLiftLams" (text "StgLam")-tagSkeletonExpr (StgCase scrut bndr ty alts)-  = (skel, arg_occs, StgCase scrut' bndr' ty alts')-  where-    (scrut_skel, scrut_arg_occs, scrut') = tagSkeletonExpr scrut-    (alt_skels, alt_arg_occss, alts') = mapAndUnzip3 tagSkeletonAlt alts-    skel = bothSk scrut_skel (foldr altSk NilSk alt_skels)-    arg_occs = unionVarSets (scrut_arg_occs:alt_arg_occss) `delVarSet` bndr-    bndr' = BoringBinder bndr-tagSkeletonExpr (StgTick t e)-  = (skel, arg_occs, StgTick t e')-  where-    (skel, arg_occs, e') = tagSkeletonExpr e-tagSkeletonExpr (StgLet _ bind body) = tagSkeletonLet False body bind-tagSkeletonExpr (StgLetNoEscape _ bind body) = tagSkeletonLet True body bind--mkLet :: Bool -> Skeleton -> LlStgBinding -> LlStgExpr -> LlStgExpr-mkLet True = StgLetNoEscape-mkLet _    = StgLet--tagSkeletonLet-  :: Bool-  -- ^ Is the binding a let-no-escape?-  -> CgStgExpr-  -- ^ Let body-  -> CgStgBinding-  -- ^ Binding group-  -> (Skeleton, IdSet, LlStgExpr)-  -- ^ RHS skeletons, argument occurrences and annotated binding-tagSkeletonLet is_lne body bind-  = (let_skel, arg_occs, mkLet is_lne scope bind' body')-  where-    (body_skel, body_arg_occs, body') = tagSkeletonExpr body-    (let_skel, arg_occs, scope, bind')-      = tagSkeletonBinding is_lne body_skel body_arg_occs bind--tagSkeletonBinding-  :: Bool-  -- ^ Is the binding a let-no-escape?-  -> Skeleton-  -- ^ Let body skeleton-  -> IdSet-  -- ^ Argument occurrences in the body-  -> CgStgBinding-  -- ^ Binding group-  -> (Skeleton, IdSet, Skeleton, LlStgBinding)-  -- ^ Let skeleton, argument occurrences, scope skeleton of binding and-  --   the annotated binding-tagSkeletonBinding is_lne body_skel body_arg_occs (StgNonRec bndr rhs)-  = (let_skel, arg_occs, scope, bind')-  where-    (rhs_skel, rhs_arg_occs, rhs') = tagSkeletonRhs bndr rhs-    arg_occs = (body_arg_occs `unionVarSet` rhs_arg_occs) `delVarSet` bndr-    bind_skel-      | is_lne    = rhs_skel -- no closure is allocated for let-no-escapes-      | otherwise = ClosureSk bndr (freeVarsOfRhs rhs) rhs_skel-    let_skel = bothSk body_skel bind_skel-    occurs_as_arg = bndr `elemVarSet` body_arg_occs-    -- Compared to the recursive case, this exploits the fact that @bndr@ is-    -- never free in @rhs@.-    scope = body_skel-    bind' = StgNonRec (BindsClosure bndr occurs_as_arg) rhs'-tagSkeletonBinding is_lne body_skel body_arg_occs (StgRec pairs)-  = (let_skel, arg_occs, scope, StgRec pairs')-  where-    (bndrs, _) = unzip pairs-    -- Local recursive STG bindings also regard the defined binders as free-    -- vars. We want to delete those for our cost model, as these are known-    -- calls anyway when we add them to the same top-level recursive group as-    -- the top-level binding currently being analysed.-    skel_occs_rhss' = map (uncurry tagSkeletonRhs) pairs-    rhss_arg_occs = map sndOf3 skel_occs_rhss'-    scope_occs = unionVarSets (body_arg_occs:rhss_arg_occs)-    arg_occs = scope_occs `delVarSetList` bndrs-    -- @skel_rhss@ aren't yet wrapped in closures. We'll do that in a moment,-    -- but we also need the un-wrapped skeletons for calculating the @scope@-    -- of the group, as the outer closures don't contribute to closure growth-    -- when we lift this specific binding.-    scope = foldr (bothSk . fstOf3) body_skel skel_occs_rhss'-    -- Now we can build the actual Skeleton for the expression just by-    -- iterating over each bind pair.-    (bind_skels, pairs') = unzip (zipWith single_bind bndrs skel_occs_rhss')-    let_skel = foldr bothSk body_skel bind_skels-    single_bind bndr (skel_rhs, _, rhs') = (bind_skel, (bndr', rhs'))-      where-        -- Here, we finally add the closure around each @skel_rhs@.-        bind_skel-          | is_lne    = skel_rhs -- no closure is allocated for let-no-escapes-          | otherwise = ClosureSk bndr fvs skel_rhs-        fvs = freeVarsOfRhs rhs' `dVarSetMinusVarSet` mkVarSet bndrs-        bndr' = BindsClosure bndr (bndr `elemVarSet` scope_occs)--tagSkeletonRhs :: Id -> CgStgRhs -> (Skeleton, IdSet, LlStgRhs)-tagSkeletonRhs _ (StgRhsCon ccs dc args)-  = (NilSk, mkArgOccs args, StgRhsCon ccs dc args)-tagSkeletonRhs bndr (StgRhsClosure fvs ccs upd bndrs body)-  = (rhs_skel, body_arg_occs, StgRhsClosure fvs ccs upd bndrs' body')-  where-    bndrs' = map BoringBinder bndrs-    (body_skel, body_arg_occs, body') = tagSkeletonExpr body-    rhs_skel = rhsSk (rhsDmdShell bndr) body_skel---- | How many times will the lambda body of the RHS bound to the given--- identifier be evaluated, relative to its defining context? This function--- computes the answer in form of a 'DmdShell'.-rhsDmdShell :: Id -> DmdShell-rhsDmdShell bndr-  | is_thunk = oneifyDmd ds-  | otherwise = peelManyCalls (idArity bndr) cd-  where-    is_thunk = idArity bndr == 0-    -- Let's pray idDemandInfo is still OK after unarise...-    (ds, cd) = toCleanDmd (idDemandInfo bndr)--tagSkeletonAlt :: CgStgAlt -> (Skeleton, IdSet, LlStgAlt)-tagSkeletonAlt (con, bndrs, rhs)-  = (alt_skel, arg_occs, (con, map BoringBinder bndrs, rhs'))-  where-    (alt_skel, alt_arg_occs, rhs') = tagSkeletonExpr rhs-    arg_occs = alt_arg_occs `delVarSetList` bndrs---- | Combines several heuristics to decide whether to lambda-lift a given--- @let@-binding to top-level. See "StgLiftLams.Analysis#when" for details.-goodToLift-  :: DynFlags-  -> TopLevelFlag-  -> RecFlag-  -> (DIdSet -> DIdSet) -- ^ An expander function, turning 'InId's into-                        -- 'OutId's. See 'StgLiftLams.LiftM.liftedIdsExpander'.-  -> [(BinderInfo, LlStgRhs)]-  -> Skeleton-  -> Maybe DIdSet       -- ^ @Just abs_ids@ <=> This binding is beneficial to-                        -- lift and @abs_ids@ are the variables it would-                        -- abstract over-goodToLift dflags top_lvl rec_flag expander pairs scope = decide-  [ ("top-level", isTopLevel top_lvl) -- keep in sync with Note [When to lift]-  , ("memoized", any_memoized)-  , ("argument occurrences", arg_occs)-  , ("join point", is_join_point)-  , ("abstracts join points", abstracts_join_ids)-  , ("abstracts known local function", abstracts_known_local_fun)-  , ("args spill on stack", args_spill_on_stack)-  , ("increases allocation", inc_allocs)-  ] where-      decide deciders-        | not (fancy_or deciders)-        = llTrace "stgLiftLams:lifting"-                  (ppr bndrs <+> ppr abs_ids $$-                   ppr allocs $$-                   ppr scope) $-          Just abs_ids-        | otherwise-        = Nothing-      ppr_deciders = vcat . map (text . fst) . filter snd-      fancy_or deciders-        = llTrace "stgLiftLams:goodToLift" (ppr bndrs $$ ppr_deciders deciders) $-          any snd deciders--      bndrs = map (binderInfoBndr . fst) pairs-      bndrs_set = mkVarSet bndrs-      rhss = map snd pairs--      -- First objective: Calculate @abs_ids@, e.g. the former free variables-      -- the lifted binding would abstract over. We have to merge the free-      -- variables of all RHS to get the set of variables that will have to be-      -- passed through parameters.-      fvs = unionDVarSets (map freeVarsOfRhs rhss)-      -- To lift the binding to top-level, we want to delete the lifted binders-      -- themselves from the free var set. Local let bindings track recursive-      -- occurrences in their free variable set. We neither want to apply our-      -- cost model to them (see 'tagSkeletonRhs'), nor pass them as parameters-      -- when lifted, as these are known calls. We call the resulting set the-      -- identifiers we abstract over, thus @abs_ids@. These are all 'OutId's.-      -- We will save the set in 'LiftM.e_expansions' for each of the variables-      -- if we perform the lift.-      abs_ids = expander (delDVarSetList fvs bndrs)--      -- We don't lift updatable thunks or constructors-      any_memoized = any is_memoized_rhs rhss-      is_memoized_rhs StgRhsCon{} = True-      is_memoized_rhs (StgRhsClosure _ _ upd _ _) = isUpdatable upd--      -- Don't lift binders occurring as arguments. This would result in complex-      -- argument expressions which would have to be given a name, reintroducing-      -- the very allocation at each call site that we wanted to get rid off in-      -- the first place.-      arg_occs = or (mapMaybe (binderInfoOccursAsArg . fst) pairs)--      -- These don't allocate anyway.-      is_join_point = any isJoinId bndrs--      -- Abstracting over join points/let-no-escapes spoils them.-      abstracts_join_ids = any isJoinId (dVarSetElems abs_ids)--      -- Abstracting over known local functions that aren't floated themselves-      -- turns a known, fast call into an unknown, slow call:-      ---      --    let f x = ...-      --        g y = ... f x ... -- this was a known call-      --    in g 4-      ---      -- After lifting @g@, but not @f@:-      ---      --    l_g f y = ... f y ... -- this is now an unknown call-      --    let f x = ...-      --    in l_g f 4-      ---      -- We can abuse the results of arity analysis for this:-      -- idArity f > 0 ==> known-      known_fun id = idArity id > 0-      abstracts_known_local_fun-        = not (liftLamsKnown dflags) && any known_fun (dVarSetElems abs_ids)--      -- Number of arguments of a RHS in the current binding group if we decide-      -- to lift it-      n_args-        = length-        . StgToCmm.Closure.nonVoidIds -- void parameters don't appear in Cmm-        . (dVarSetElems abs_ids ++)-        . rhsLambdaBndrs-      max_n_args-        | isRec rec_flag = liftLamsRecArgs dflags-        | otherwise      = liftLamsNonRecArgs dflags-      -- We have 5 hardware registers on x86_64 to pass arguments in. Any excess-      -- args are passed on the stack, which means slow memory accesses-      args_spill_on_stack-        | Just n <- max_n_args = maximum (map n_args rhss) > n-        | otherwise = False--      -- We only perform the lift if allocations didn't increase.-      -- Note that @clo_growth@ will be 'infinity' if there was positive growth-      -- under a multi-shot lambda.-      -- Also, abstracting over LNEs is unacceptable. LNEs might return-      -- unlifted tuples, which idClosureFootprint can't cope with.-      inc_allocs = abstracts_join_ids || allocs > 0-      allocs = clo_growth + mkIntWithInf (negate closuresSize)-      -- We calculate and then add up the size of each binding's closure.-      -- GHC does not currently share closure environments, and we either lift-      -- the entire recursive binding group or none of it.-      closuresSize = sum $ flip map rhss $ \rhs ->-        closureSize dflags-        . dVarSetElems-        . expander-        . flip dVarSetMinusVarSet bndrs_set-        $ freeVarsOfRhs rhs-      clo_growth = closureGrowth expander (idClosureFootprint dflags) bndrs_set abs_ids scope--rhsLambdaBndrs :: LlStgRhs -> [Id]-rhsLambdaBndrs StgRhsCon{} = []-rhsLambdaBndrs (StgRhsClosure _ _ _ bndrs _) = map binderInfoBndr bndrs---- | The size in words of a function closure closing over the given 'Id's,--- including the header.-closureSize :: DynFlags -> [Id] -> WordOff-closureSize dflags ids = words + sTD_HDR_SIZE dflags-  -- We go through sTD_HDR_SIZE rather than fixedHdrSizeW so that we don't-  -- optimise differently when profiling is enabled.-  where-    (words, _, _)-      -- Functions have a StdHeader (as opposed to ThunkHeader).-      = StgToCmm.Layout.mkVirtHeapOffsets dflags StgToCmm.Layout.StdHeader-      . StgToCmm.Closure.addIdReps-      . StgToCmm.Closure.nonVoidIds-      $ ids---- | The number of words a single 'Id' adds to a closure's size.--- Note that this can't handle unboxed tuples (which may still be present in--- let-no-escapes, even after Unarise), in which case--- @'GHC.StgToCmm.Closure.idPrimRep'@ will crash.-idClosureFootprint:: DynFlags -> Id -> WordOff-idClosureFootprint dflags-  = StgToCmm.ArgRep.argRepSizeW dflags-  . StgToCmm.ArgRep.idArgRep---- | @closureGrowth expander sizer f fvs@ computes the closure growth in words--- as a result of lifting @f@ to top-level. If there was any growing closure--- under a multi-shot lambda, the result will be 'infinity'.--- Also see "StgLiftLams.Analysis#clogro".-closureGrowth-  :: (DIdSet -> DIdSet)-  -- ^ Expands outer free ids that were lifted to their free vars-  -> (Id -> Int)-  -- ^ Computes the closure footprint of an identifier-  -> IdSet-  -- ^ Binding group for which lifting is to be decided-  -> DIdSet-  -- ^ Free vars of the whole binding group prior to lifting it. These must be-  --   available at call sites if we decide to lift the binding group.-  -> Skeleton-  -- ^ Abstraction of the scope of the function-  -> IntWithInf-  -- ^ Closure growth. 'infinity' indicates there was growth under a-  --   (multi-shot) lambda.-closureGrowth expander sizer group abs_ids = go-  where-    go NilSk = 0-    go (BothSk a b) = go a + go b-    go (AltSk a b) = max (go a) (go b)-    go (ClosureSk _ clo_fvs rhs)-      -- If no binder of the @group@ occurs free in the closure, the lifting-      -- won't have any effect on it and we can omit the recursive call.-      | n_occs == 0 = 0-      -- Otherwise, we account the cost of allocating the closure and add it to-      -- the closure growth of its RHS.-      | otherwise   = mkIntWithInf cost + go rhs-      where-        n_occs = sizeDVarSet (clo_fvs' `dVarSetIntersectVarSet` group)-        -- What we close over considering prior lifting decisions-        clo_fvs' = expander clo_fvs-        -- Variables that would additionally occur free in the closure body if-        -- we lift @f@-        newbies = abs_ids `minusDVarSet` clo_fvs'-        -- Lifting @f@ removes @f@ from the closure but adds all @newbies@-        cost = foldDVarSet (\id size -> sizer id + size) 0 newbies - n_occs-    go (RhsSk body_dmd body)-      -- The conservative assumption would be that-      --   1. Every RHS with positive growth would be called multiple times,-      --      modulo thunks.-      --   2. Every RHS with negative growth wouldn't be called at all.-      ---      -- In the first case, we'd have to return 'infinity', while in the-      -- second case, we'd have to return 0. But we can do far better-      -- considering information from the demand analyser, which provides us-      -- with conservative estimates on minimum and maximum evaluation-      -- cardinality. The @body_dmd@ part of 'RhsSk' is the result of-      -- 'rhsDmdShell' and accurately captures the cardinality of the RHSs body-      -- relative to its defining context.-      | isAbsDmd body_dmd   = 0-      | cg <= 0             = if isStrictDmd body_dmd then cg else 0-      | isUsedOnce body_dmd = cg-      | otherwise           = infinity-      where-        cg = go body
− compiler/simplStg/StgLiftLams/LiftM.hs
@@ -1,348 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE TypeFamilies #-}---- | Hides away distracting bookkeeping while lambda lifting into a 'LiftM'--- monad.-module StgLiftLams.LiftM (-    decomposeStgBinding, mkStgBinding,-    Env (..),-    -- * #floats# Handling floats-    -- $floats-    FloatLang (..), collectFloats, -- Exported just for the docs-    -- * Transformation monad-    LiftM, runLiftM, withCaffyness,-    -- ** Adding bindings-    startBindingGroup, endBindingGroup, addTopStringLit, addLiftedBinding,-    -- ** Substitution and binders-    withSubstBndr, withSubstBndrs, withLiftedBndr, withLiftedBndrs,-    -- ** Occurrences-    substOcc, isLifted, formerFreeVars, liftedIdsExpander-  ) where--#include "HsVersions.h"--import GhcPrelude--import BasicTypes-import CostCentre ( isCurrentCCS, dontCareCCS )-import DynFlags-import FastString-import Id-import IdInfo-import Name-import Outputable-import OrdList-import StgSubst-import StgSyn-import Type-import UniqSupply-import Util-import VarEnv-import VarSet--import Control.Arrow ( second )-import Control.Monad.Trans.Class-import Control.Monad.Trans.RWS.Strict ( RWST, runRWST )-import qualified Control.Monad.Trans.RWS.Strict as RWS-import Control.Monad.Trans.Cont ( ContT (..) )-import Data.ByteString ( ByteString )---- | @uncurry 'mkStgBinding' . 'decomposeStgBinding' = id@-decomposeStgBinding :: GenStgBinding pass -> (RecFlag, [(BinderP pass, GenStgRhs pass)])-decomposeStgBinding (StgRec pairs) = (Recursive, pairs)-decomposeStgBinding (StgNonRec bndr rhs) = (NonRecursive, [(bndr, rhs)])--mkStgBinding :: RecFlag -> [(BinderP pass, GenStgRhs pass)] -> GenStgBinding pass-mkStgBinding Recursive = StgRec-mkStgBinding NonRecursive = uncurry StgNonRec . head---- | Environment threaded around in a scoped, @Reader@-like fashion.-data Env-  = Env-  { e_dflags     :: !DynFlags-  -- ^ Read-only.-  , e_subst      :: !Subst-  -- ^ We need to track the renamings of local 'InId's to their lifted 'OutId',-  -- because shadowing might make a closure's free variables unavailable at its-  -- call sites. Consider:-  -- @-  --    let f y = x + y in let x = 4 in f x-  -- @-  -- Here, @f@ can't be lifted to top-level, because its free variable @x@ isn't-  -- available at its call site.-  , e_expansions :: !(IdEnv DIdSet)-  -- ^ Lifted 'Id's don't occur as free variables in any closure anymore, because-  -- they are bound at the top-level. Every occurrence must supply the formerly-  -- free variables of the lifted 'Id', so they in turn become free variables of-  -- the call sites. This environment tracks this expansion from lifted 'Id's to-  -- their free variables.-  ---  -- 'InId's to 'OutId's.-  ---  -- Invariant: 'Id's not present in this map won't be substituted.-  , e_in_caffy_context :: !Bool-  -- ^ Are we currently analysing within a caffy context (e.g. the containing-  -- top-level binder's 'idCafInfo' is 'MayHaveCafRefs')? If not, we can safely-  -- assume that functions we lift out aren't caffy either.-  }--emptyEnv :: DynFlags -> Env-emptyEnv dflags = Env dflags emptySubst emptyVarEnv False----- Note [Handling floats]--- ~~~~~~~~~~~~~~~~~~~~~~--- $floats--- Consider the following expression:------ @---     f x =---       let g y = ... f y ...---       in g x--- @------ What happens when we want to lift @g@? Normally, we'd put the lifted @l_g@--- binding above the binding for @f@:------ @---     g f y = ... f y ...---     f x = g f x--- @------ But this very unnecessarily turns a known call to @f@ into an unknown one, in--- addition to complicating matters for the analysis.--- Instead, we'd really like to put both functions in the same recursive group,--- thereby preserving the known call:------ @---     Rec {---       g y = ... f y ...---       f x = g x---     }--- @------ But we don't want this to happen for just /any/ binding. That would create--- possibly huge recursive groups in the process, calling for an occurrence--- analyser on STG.--- So, we need to track when we lift a binding out of a recursive RHS and add--- the binding to the same recursive group as the enclosing recursive binding--- (which must have either already been at the top-level or decided to be--- lifted itself in order to preserve the known call).------ This is done by expressing this kind of nesting structure as a 'Writer' over--- @['FloatLang']@ and flattening this expression in 'runLiftM' by a call to--- 'collectFloats'.--- API-wise, the analysis will not need to know about the whole 'FloatLang'--- business and will just manipulate it indirectly through actions in 'LiftM'.---- | We need to detect when we are lifting something out of the RHS of a--- recursive binding (c.f. "StgLiftLams.LiftM#floats"), in which case that--- binding needs to be added to the same top-level recursive group. This--- requires we detect a certain nesting structure, which is encoded by--- 'StartBindingGroup' and 'EndBindingGroup'.------ Although 'collectFloats' will only ever care if the current binding to be--- lifted (through 'LiftedBinding') will occur inside such a binding group or--- not, e.g. doesn't care about the nesting level as long as its greater than 0.-data FloatLang-  = StartBindingGroup-  | EndBindingGroup-  | PlainTopBinding OutStgTopBinding-  | LiftedBinding OutStgBinding--instance Outputable FloatLang where-  ppr StartBindingGroup = char '('-  ppr EndBindingGroup = char ')'-  ppr (PlainTopBinding StgTopStringLit{}) = text "<str>"-  ppr (PlainTopBinding (StgTopLifted b)) = ppr (LiftedBinding b)-  ppr (LiftedBinding bind) = (if isRec rec then char 'r' else char 'n') <+> ppr (map fst pairs)-    where-      (rec, pairs) = decomposeStgBinding bind---- | Flattens an expression in @['FloatLang']@ into an STG program, see #floats.--- Important pre-conditions: The nesting of opening 'StartBindinGroup's and--- closing 'EndBindinGroup's is balanced. Also, it is crucial that every binding--- group has at least one recursive binding inside. Otherwise there's no point--- in announcing the binding group in the first place and an @ASSERT@ will--- trigger.-collectFloats :: [FloatLang] -> [OutStgTopBinding]-collectFloats = go (0 :: Int) []-  where-    go 0 [] [] = []-    go _ _ [] = pprPanic "collectFloats" (text "unterminated group")-    go n binds (f:rest) = case f of-      StartBindingGroup -> go (n+1) binds rest-      EndBindingGroup-        | n == 0 -> pprPanic "collectFloats" (text "no group to end")-        | n == 1 -> StgTopLifted (merge_binds binds) : go 0 [] rest-        | otherwise -> go (n-1) binds rest-      PlainTopBinding top_bind-        | n == 0 -> top_bind : go n binds rest-        | otherwise -> pprPanic "collectFloats" (text "plain top binding inside group")-      LiftedBinding bind-        | n == 0 -> StgTopLifted (rm_cccs bind) : go n binds rest-        | otherwise -> go n (bind:binds) rest--    map_rhss f = uncurry mkStgBinding . second (map (second f)) . decomposeStgBinding-    rm_cccs = map_rhss removeRhsCCCS-    merge_binds binds = ASSERT( any is_rec binds )-                        StgRec (concatMap (snd . decomposeStgBinding . rm_cccs) binds)-    is_rec StgRec{} = True-    is_rec _ = False---- | Omitting this makes for strange closure allocation schemes that crash the--- GC.-removeRhsCCCS :: GenStgRhs pass -> GenStgRhs pass-removeRhsCCCS (StgRhsClosure ext ccs upd bndrs body)-  | isCurrentCCS ccs-  = StgRhsClosure ext dontCareCCS upd bndrs body-removeRhsCCCS (StgRhsCon ccs con args)-  | isCurrentCCS ccs-  = StgRhsCon dontCareCCS con args-removeRhsCCCS rhs = rhs---- | The analysis monad consists of the following 'RWST' components:------     * 'Env': Reader-like context. Contains a substitution, info about how---       how lifted identifiers are to be expanded into applications and details---       such as 'DynFlags' and a flag helping with determining if a lifted---       binding is caffy.------     * @'OrdList' 'FloatLang'@: Writer output for the resulting STG program.------     * No pure state component------     * But wrapping around 'UniqSM' for generating fresh lifted binders.---       (The @uniqAway@ approach could give the same name to two different---       lifted binders, so this is necessary.)-newtype LiftM a-  = LiftM { unwrapLiftM :: RWST Env (OrdList FloatLang) () UniqSM a }-  deriving (Functor, Applicative, Monad)--instance HasDynFlags LiftM where-  getDynFlags = LiftM (RWS.asks e_dflags)--instance MonadUnique LiftM where-  getUniqueSupplyM = LiftM (lift getUniqueSupplyM)-  getUniqueM = LiftM (lift getUniqueM)-  getUniquesM = LiftM (lift getUniquesM)--runLiftM :: DynFlags -> UniqSupply -> LiftM () -> [OutStgTopBinding]-runLiftM dflags us (LiftM m) = collectFloats (fromOL floats)-  where-    (_, _, floats) = initUs_ us (runRWST m (emptyEnv dflags) ())---- | Assumes a given caffyness for the execution of the passed action, which--- influences the 'cafInfo' of lifted bindings.-withCaffyness :: Bool -> LiftM a -> LiftM a-withCaffyness caffy action-  = LiftM (RWS.local (\e -> e { e_in_caffy_context = caffy }) (unwrapLiftM action))---- | Writes a plain 'StgTopStringLit' to the output.-addTopStringLit :: OutId -> ByteString -> LiftM ()-addTopStringLit id = LiftM . RWS.tell . unitOL . PlainTopBinding . StgTopStringLit id---- | Starts a recursive binding group. See #floats# and 'collectFloats'.-startBindingGroup :: LiftM ()-startBindingGroup = LiftM $ RWS.tell $ unitOL $ StartBindingGroup---- | Ends a recursive binding group. See #floats# and 'collectFloats'.-endBindingGroup :: LiftM ()-endBindingGroup = LiftM $ RWS.tell $ unitOL $ EndBindingGroup---- | Lifts a binding to top-level. Depending on whether it's declared inside--- a recursive RHS (see #floats# and 'collectFloats'), this might be added to--- an existing recursive top-level binding group.-addLiftedBinding :: OutStgBinding -> LiftM ()-addLiftedBinding = LiftM . RWS.tell . unitOL . LiftedBinding---- | Takes a binder and a continuation which is called with the substituted--- binder. The continuation will be evaluated in a 'LiftM' context in which that--- binder is deemed in scope. Think of it as a 'RWS.local' computation: After--- the continuation finishes, the new binding won't be in scope anymore.-withSubstBndr :: Id -> (Id -> LiftM a) -> LiftM a-withSubstBndr bndr inner = LiftM $ do-  subst <- RWS.asks e_subst-  let (bndr', subst') = substBndr bndr subst-  RWS.local (\e -> e { e_subst = subst' }) (unwrapLiftM (inner bndr'))---- | See 'withSubstBndr'.-withSubstBndrs :: Traversable f => f Id -> (f Id -> LiftM a) -> LiftM a-withSubstBndrs = runContT . traverse (ContT . withSubstBndr)---- | Similarly to 'withSubstBndr', this function takes a set of variables to--- abstract over, the binder to lift (and generate a fresh, substituted name--- for) and a continuation in which that fresh, lifted binder is in scope.------ It takes care of all the details involved with copying and adjusting the--- binder, fresh name generation and caffyness.-withLiftedBndr :: DIdSet -> Id -> (Id -> LiftM a) -> LiftM a-withLiftedBndr abs_ids bndr inner = do-  uniq <- getUniqueM-  let str = "$l" ++ occNameString (getOccName bndr)-  let ty = mkLamTypes (dVarSetElems abs_ids) (idType bndr)-  -- When the enclosing top-level binding is not caffy, then the lifted-  -- binding will not be caffy either. If we don't recognize this, non-caffy-  -- things call caffy things and then codegen screws up.-  in_caffy_ctxt <- LiftM (RWS.asks e_in_caffy_context)-  let caf_info = if in_caffy_ctxt then MayHaveCafRefs else NoCafRefs-  let bndr'-        -- See Note [transferPolyIdInfo] in Id.hs. We need to do this at least-        -- for arity information.-        = transferPolyIdInfo bndr (dVarSetElems abs_ids)-        -- Otherwise we confuse code gen if bndr was not caffy: the new bndr is-        -- assumed to be caffy and will need an SRT. Transitive call sites might-        -- not be caffy themselves and subsequently will miss a static link-        -- field in their closure. Chaos ensues.-        . flip setIdCafInfo caf_info-        . mkSysLocalOrCoVar (mkFastString str) uniq-        $ ty-  LiftM $ RWS.local-    (\e -> e-      { e_subst = extendSubst bndr bndr' $ extendInScope bndr' $ e_subst e-      , e_expansions = extendVarEnv (e_expansions e) bndr abs_ids-      })-    (unwrapLiftM (inner bndr'))---- | See 'withLiftedBndr'.-withLiftedBndrs :: Traversable f => DIdSet -> f Id -> (f Id -> LiftM a) -> LiftM a-withLiftedBndrs abs_ids = runContT . traverse (ContT . withLiftedBndr abs_ids)---- | Substitutes a binder /occurrence/, which was brought in scope earlier by--- 'withSubstBndr'\/'withLiftedBndr'.-substOcc :: Id -> LiftM Id-substOcc id = LiftM (RWS.asks (lookupIdSubst id . e_subst))---- | Whether the given binding was decided to be lambda lifted.-isLifted :: InId -> LiftM Bool-isLifted bndr = LiftM (RWS.asks (elemVarEnv bndr . e_expansions))---- | Returns an empty list for a binding that was not lifted and the list of all--- local variables the binding abstracts over (so, exactly the additional--- arguments at adjusted call sites) otherwise.-formerFreeVars :: InId -> LiftM [OutId]-formerFreeVars f = LiftM $ do-  expansions <- RWS.asks e_expansions-  pure $ case lookupVarEnv expansions f of-    Nothing -> []-    Just fvs -> dVarSetElems fvs---- | Creates an /expander function/ for the current set of lifted binders.--- This expander function will replace any 'InId' by their corresponding 'OutId'--- and, in addition, will expand any lifted binders by the former free variables--- it abstracts over.-liftedIdsExpander :: LiftM (DIdSet -> DIdSet)-liftedIdsExpander = LiftM $ do-  expansions <- RWS.asks e_expansions-  subst <- RWS.asks e_subst-  -- We use @noWarnLookupIdSubst@ here in order to suppress "not in scope"-  -- warnings generated by 'lookupIdSubst' due to local bindings within RHS.-  -- These are not in the InScopeSet of @subst@ and extending the InScopeSet in-  -- @goodToLift@/@closureGrowth@ before passing it on to @expander@ is too much-  -- trouble.-  let go set fv = case lookupVarEnv expansions fv of-        Nothing -> extendDVarSet set (noWarnLookupIdSubst fv subst) -- Not lifted-        Just fvs' -> unionDVarSet set fvs'-  let expander fvs = foldl' go emptyDVarSet (dVarSetElems fvs)-  pure expander
− compiler/simplStg/StgLiftLams/Transformation.hs
@@ -1,155 +0,0 @@-{-# LANGUAGE CPP #-}---- | (Mostly) textbook instance of the lambda lifting transformation,--- selecting which bindings to lambda lift by consulting 'goodToLift'.-module StgLiftLams.Transformation (stgLiftLams) where--#include "HsVersions.h"--import GhcPrelude--import BasicTypes-import DynFlags-import Id-import IdInfo-import StgFVs ( annBindingFreeVars )-import StgLiftLams.Analysis-import StgLiftLams.LiftM-import StgSyn-import Outputable-import UniqSupply-import Util-import VarSet-import Control.Monad ( when )-import Data.Maybe ( isNothing )---- | Lambda lifts bindings to top-level deemed worth lifting (see 'goodToLift').-stgLiftLams :: DynFlags -> UniqSupply -> [InStgTopBinding] -> [OutStgTopBinding]-stgLiftLams dflags us = runLiftM dflags us . foldr liftTopLvl (pure ())--liftTopLvl :: InStgTopBinding -> LiftM () -> LiftM ()-liftTopLvl (StgTopStringLit bndr lit) rest = withSubstBndr bndr $ \bndr' -> do-  addTopStringLit bndr' lit-  rest-liftTopLvl (StgTopLifted bind) rest = do-  let is_rec = isRec $ fst $ decomposeStgBinding bind-  when is_rec startBindingGroup-  let bind_w_fvs = annBindingFreeVars bind-  withLiftedBind TopLevel (tagSkeletonTopBind bind_w_fvs) NilSk $ \mb_bind' -> do-    -- We signal lifting of a binding through returning Nothing.-    -- Should never happen for a top-level binding, though, since we are already-    -- at top-level.-    case mb_bind' of-      Nothing -> pprPanic "StgLiftLams" (text "Lifted top-level binding")-      Just bind' -> addLiftedBinding bind'-    when is_rec endBindingGroup-    rest--withLiftedBind-  :: TopLevelFlag-  -> LlStgBinding-  -> Skeleton-  -> (Maybe OutStgBinding -> LiftM a)-  -> LiftM a-withLiftedBind top_lvl bind scope k-  | isTopLevel top_lvl-  = withCaffyness (is_caffy pairs) go-  | otherwise-  = go-  where-    (rec, pairs) = decomposeStgBinding bind-    is_caffy = any (mayHaveCafRefs . idCafInfo . binderInfoBndr . fst)-    go = withLiftedBindPairs top_lvl rec pairs scope (k . fmap (mkStgBinding rec))--withLiftedBindPairs-  :: TopLevelFlag-  -> RecFlag-  -> [(BinderInfo, LlStgRhs)]-  -> Skeleton-  -> (Maybe [(Id, OutStgRhs)] -> LiftM a)-  -> LiftM a-withLiftedBindPairs top rec pairs scope k = do-  let (infos, rhss) = unzip pairs-  let bndrs = map binderInfoBndr infos-  expander <- liftedIdsExpander-  dflags <- getDynFlags-  case goodToLift dflags top rec expander pairs scope of-    -- @abs_ids@ is the set of all variables that need to become parameters.-    Just abs_ids -> withLiftedBndrs abs_ids bndrs $ \bndrs' -> do-      -- Within this block, all binders in @bndrs@ will be noted as lifted, so-      -- that the return value of @liftedIdsExpander@ in this context will also-      -- expand the bindings in @bndrs@ to their free variables.-      -- Now we can recurse into the RHSs and see if we can lift any further-      -- bindings. We pass the set of expanded free variables (thus OutIds) on-      -- to @liftRhs@ so that it can add them as parameter binders.-      when (isRec rec) startBindingGroup-      rhss' <- traverse (liftRhs (Just abs_ids)) rhss-      let pairs' = zip bndrs' rhss'-      addLiftedBinding (mkStgBinding rec pairs')-      when (isRec rec) endBindingGroup-      k Nothing-    Nothing -> withSubstBndrs bndrs $ \bndrs' -> do-      -- Don't lift the current binding, but possibly some bindings in their-      -- RHSs.-      rhss' <- traverse (liftRhs Nothing) rhss-      let pairs' = zip bndrs' rhss'-      k (Just pairs')--liftRhs-  :: Maybe (DIdSet)-  -- ^ @Just former_fvs@ <=> this RHS was lifted and we have to add @former_fvs@-  -- as lambda binders, discarding all free vars.-  -> LlStgRhs-  -> LiftM OutStgRhs-liftRhs mb_former_fvs rhs@(StgRhsCon ccs con args)-  = ASSERT2(isNothing mb_former_fvs, text "Should never lift a constructor" $$ ppr rhs)-    StgRhsCon ccs con <$> traverse liftArgs args-liftRhs Nothing (StgRhsClosure _ ccs upd infos body) = do-  -- This RHS wasn't lifted.-  withSubstBndrs (map binderInfoBndr infos) $ \bndrs' ->-    StgRhsClosure noExtFieldSilent ccs upd bndrs' <$> liftExpr body-liftRhs (Just former_fvs) (StgRhsClosure _ ccs upd infos body) = do-  -- This RHS was lifted. Insert extra binders for @former_fvs@.-  withSubstBndrs (map binderInfoBndr infos) $ \bndrs' -> do-    let bndrs'' = dVarSetElems former_fvs ++ bndrs'-    StgRhsClosure noExtFieldSilent ccs upd bndrs'' <$> liftExpr body--liftArgs :: InStgArg -> LiftM OutStgArg-liftArgs a@(StgLitArg _) = pure a-liftArgs (StgVarArg occ) = do-  ASSERTM2( not <$> isLifted occ, text "StgArgs should never be lifted" $$ ppr occ )-  StgVarArg <$> substOcc occ--liftExpr :: LlStgExpr -> LiftM OutStgExpr-liftExpr (StgLit lit) = pure (StgLit lit)-liftExpr (StgTick t e) = StgTick t <$> liftExpr e-liftExpr (StgApp f args) = do-  f' <- substOcc f-  args' <- traverse liftArgs args-  fvs' <- formerFreeVars f-  let top_lvl_args = map StgVarArg fvs' ++ args'-  pure (StgApp f' top_lvl_args)-liftExpr (StgConApp con args tys) = StgConApp con <$> traverse liftArgs args <*> pure tys-liftExpr (StgOpApp op args ty) = StgOpApp op <$> traverse liftArgs args <*> pure ty-liftExpr (StgLam _ _) = pprPanic "stgLiftLams" (text "StgLam")-liftExpr (StgCase scrut info ty alts) = do-  scrut' <- liftExpr scrut-  withSubstBndr (binderInfoBndr info) $ \bndr' -> do-    alts' <- traverse liftAlt alts-    pure (StgCase scrut' bndr' ty alts')-liftExpr (StgLet scope bind body)-  = withLiftedBind NotTopLevel bind scope $ \mb_bind' -> do-      body' <- liftExpr body-      case mb_bind' of-        Nothing -> pure body' -- withLiftedBindPairs decided to lift it and already added floats-        Just bind' -> pure (StgLet noExtFieldSilent bind' body')-liftExpr (StgLetNoEscape scope bind body)-  = withLiftedBind NotTopLevel bind scope $ \mb_bind' -> do-      body' <- liftExpr body-      case mb_bind' of-        Nothing -> pprPanic "stgLiftLams" (text "Should never decide to lift LNEs")-        Just bind' -> pure (StgLetNoEscape noExtFieldSilent bind' body')--liftAlt :: LlStgAlt -> LiftM OutStgAlt-liftAlt (con, infos, rhs) = withSubstBndrs (map binderInfoBndr infos) $ \bndrs' ->-  (,,) con bndrs' <$> liftExpr rhs
− compiler/simplStg/StgStats.hs
@@ -1,173 +0,0 @@-{--(c) The GRASP/AQUA Project, Glasgow University, 1992-1998--\section[StgStats]{Gathers statistical information about programs}---The program gather statistics about-\begin{enumerate}-\item number of boxed cases-\item number of unboxed cases-\item number of let-no-escapes-\item number of non-updatable lets-\item number of updatable lets-\item number of applications-\item number of primitive applications-\item number of closures (does not include lets bound to constructors)-\item number of free variables in closures-%\item number of top-level functions-%\item number of top-level CAFs-\item number of constructors-\end{enumerate}--}--{-# LANGUAGE CPP #-}--module StgStats ( showStgStats ) where--#include "HsVersions.h"--import GhcPrelude--import StgSyn--import Id (Id)-import Panic--import Data.Map (Map)-import qualified Data.Map as Map--data CounterType-  = Literals-  | Applications-  | ConstructorApps-  | PrimitiveApps-  | LetNoEscapes-  | StgCases-  | FreeVariables-  | ConstructorBinds Bool{-True<=>top-level-}-  | ReEntrantBinds   Bool{-ditto-}-  | SingleEntryBinds Bool{-ditto-}-  | UpdatableBinds   Bool{-ditto-}-  deriving (Eq, Ord)--type Count      = Int-type StatEnv    = Map CounterType Count--emptySE :: StatEnv-emptySE = Map.empty--combineSE :: StatEnv -> StatEnv -> StatEnv-combineSE = Map.unionWith (+)--combineSEs :: [StatEnv] -> StatEnv-combineSEs = foldr combineSE emptySE--countOne :: CounterType -> StatEnv-countOne c = Map.singleton c 1--{--************************************************************************-*                                                                      *-\subsection{Top-level list of bindings (a ``program'')}-*                                                                      *-************************************************************************--}--showStgStats :: [StgTopBinding] -> String--showStgStats prog-  = "STG Statistics:\n\n"-    ++ concat (map showc (Map.toList (gatherStgStats prog)))-  where-    showc (x,n) = (showString (s x) . shows n) "\n"--    s Literals                = "Literals                   "-    s Applications            = "Applications               "-    s ConstructorApps         = "ConstructorApps            "-    s PrimitiveApps           = "PrimitiveApps              "-    s LetNoEscapes            = "LetNoEscapes               "-    s StgCases                = "StgCases                   "-    s FreeVariables           = "FreeVariables              "-    s (ConstructorBinds True) = "ConstructorBinds_Top       "-    s (ReEntrantBinds True)   = "ReEntrantBinds_Top         "-    s (SingleEntryBinds True) = "SingleEntryBinds_Top       "-    s (UpdatableBinds True)   = "UpdatableBinds_Top         "-    s (ConstructorBinds _)    = "ConstructorBinds_Nested    "-    s (ReEntrantBinds _)      = "ReEntrantBindsBinds_Nested "-    s (SingleEntryBinds _)    = "SingleEntryBinds_Nested    "-    s (UpdatableBinds _)      = "UpdatableBinds_Nested      "--gatherStgStats :: [StgTopBinding] -> StatEnv-gatherStgStats binds = combineSEs (map statTopBinding binds)--{--************************************************************************-*                                                                      *-\subsection{Bindings}-*                                                                      *-************************************************************************--}--statTopBinding :: StgTopBinding -> StatEnv-statTopBinding (StgTopStringLit _ _) = countOne Literals-statTopBinding (StgTopLifted bind) = statBinding True bind--statBinding :: Bool -- True <=> top-level; False <=> nested-            -> StgBinding-            -> StatEnv--statBinding top (StgNonRec b rhs)-  = statRhs top (b, rhs)--statBinding top (StgRec pairs)-  = combineSEs (map (statRhs top) pairs)--statRhs :: Bool -> (Id, StgRhs) -> StatEnv--statRhs top (_, StgRhsCon _ _ _)-  = countOne (ConstructorBinds top)--statRhs top (_, StgRhsClosure _ _ u _ body)-  = statExpr body `combineSE`-    countOne (-      case u of-        ReEntrant   -> ReEntrantBinds   top-        Updatable   -> UpdatableBinds   top-        SingleEntry -> SingleEntryBinds top-    )--{--************************************************************************-*                                                                      *-\subsection{Expressions}-*                                                                      *-************************************************************************--}--statExpr :: StgExpr -> StatEnv--statExpr (StgApp _ _)     = countOne Applications-statExpr (StgLit _)       = countOne Literals-statExpr (StgConApp _ _ _)= countOne ConstructorApps-statExpr (StgOpApp _ _ _) = countOne PrimitiveApps-statExpr (StgTick _ e)    = statExpr e--statExpr (StgLetNoEscape _ binds body)-  = statBinding False{-not top-level-} binds    `combineSE`-    statExpr body                               `combineSE`-    countOne LetNoEscapes--statExpr (StgLet _ binds body)-  = statBinding False{-not top-level-} binds    `combineSE`-    statExpr body--statExpr (StgCase expr _ _ alts)-  = statExpr expr       `combineSE`-    stat_alts alts      `combineSE`-    countOne StgCases-  where-    stat_alts alts-        = combineSEs (map statExpr [ e | (_,_,e) <- alts ])--statExpr (StgLam {}) = panic "statExpr StgLam"
− compiler/simplStg/UnariseStg.hs
@@ -1,769 +0,0 @@-{--(c) The GRASP/AQUA Project, Glasgow University, 1992-2012--Note [Unarisation]-~~~~~~~~~~~~~~~~~~-The idea of this pass is to translate away *all* unboxed-tuple and unboxed-sum-binders. So for example:--  f (x :: (# Int, Bool #)) = f x + f (# 1, True #)--  ==>--  f (x1 :: Int) (x2 :: Bool) = f x1 x2 + f 1 True--It is important that we do this at the STG level and NOT at the Core level-because it would be very hard to make this pass Core-type-preserving. In this-example the type of 'f' changes, for example.--STG fed to the code generators *must* be unarised because the code generators do-not support unboxed tuple and unboxed sum binders natively.--In more detail: (see next note for unboxed sums)--Suppose that a variable x : (# t1, t2 #).--  * At the binding site for x, make up fresh vars  x1:t1, x2:t2--  * Extend the UnariseEnv   x :-> MultiVal [x1,x2]--  * Replace the binding with a curried binding for x1,x2--       Lambda:   \x.e                ==>   \x1 x2. e-       Case alt: MkT a b x c d -> e  ==>   MkT a b x1 x2 c d -> e--  * Replace argument occurrences with a sequence of args via a lookup in-    UnariseEnv--       f a b x c d   ==>   f a b x1 x2 c d--  * Replace tail-call occurrences with an unboxed tuple via a lookup in-    UnariseEnv--       x  ==>  (# x1, x2 #)--    So, for example--       f x = x    ==>   f x1 x2 = (# x1, x2 #)--  * We /always/ eliminate a case expression when--       - It scrutinises an unboxed tuple or unboxed sum--       - The scrutinee is a variable (or when it is an explicit tuple, but the-         simplifier eliminates those)--    The case alternative (there can be only one) can be one of these two-    things:--      - An unboxed tuple pattern. e.g.--          case v of x { (# x1, x2, x3 #) -> ... }--        Scrutinee has to be in form `(# t1, t2, t3 #)` so we just extend the-        environment with--          x :-> MultiVal [t1,t2,t3]-          x1 :-> UnaryVal t1, x2 :-> UnaryVal t2, x3 :-> UnaryVal t3--      - A DEFAULT alternative. Just the same, without the bindings for x1,x2,x3--By the end of this pass, we only have unboxed tuples in return positions.-Unboxed sums are completely eliminated, see next note.--Note [Translating unboxed sums to unboxed tuples]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Unarise also eliminates unboxed sum binders, and translates unboxed sums in-return positions to unboxed tuples. We want to overlap fields of a sum when-translating it to a tuple to have efficient memory layout. When translating a-sum pattern to a tuple pattern, we need to translate it so that binders of sum-alternatives will be mapped to right arguments after the term translation. So-translation of sum DataCon applications to tuple DataCon applications and-translation of sum patterns to tuple patterns need to be in sync.--These translations work like this. Suppose we have--  (# x1 | | ... #) :: (# t1 | t2 | ... #)--remember that t1, t2 ... can be sums and tuples too. So we first generate-layouts of those. Then we "merge" layouts of each alternative, which gives us a-sum layout with best overlapping possible.--Layout of a flat type 'ty1' is just [ty1].-Layout of a tuple is just concatenation of layouts of its fields.--For layout of a sum type,--  - We first get layouts of all alternatives.-  - We sort these layouts based on their "slot types".-  - We merge all the alternatives.--For example, say we have (# (# Int#, Char #) | (# Int#, Int# #) | Int# #)--  - Layouts of alternatives: [ [Word, Ptr], [Word, Word], [Word] ]-  - Sorted: [ [Ptr, Word], [Word, Word], [Word] ]-  - Merge all alternatives together: [ Ptr, Word, Word ]--We add a slot for the tag to the first position. So our tuple type is--  (# Tag#, Any, Word#, Word# #)-  (we use Any for pointer slots)--Now, any term of this sum type needs to generate a tuple of this type instead.-The translation works by simply putting arguments to first slots that they fit-in. Suppose we had--  (# (# 42#, 'c' #) | | #)--42# fits in Word#, 'c' fits in Any, so we generate this application:--  (# 1#, 'c', 42#, rubbish #)--Another example using the same type: (# | (# 2#, 3# #) | #). 2# fits in Word#,-3# fits in Word #, so we get:--  (# 2#, rubbish, 2#, 3# #).--Note [Types in StgConApp]-~~~~~~~~~~~~~~~~~~~~~~~~~-Suppose we have this unboxed sum term:--  (# 123 | #)--What will be the unboxed tuple representation? We can't tell without knowing the-type of this term. For example, these are all valid tuples for this:--  (# 1#, 123 #)          -- when type is (# Int | String #)-  (# 1#, 123, rubbish #) -- when type is (# Int | Float# #)-  (# 1#, 123, rubbish, rubbish #)-                         -- when type is (# Int | (# Int, Int, Int #) #)--So we pass type arguments of the DataCon's TyCon in StgConApp to decide what-layout to use. Note that unlifted values can't be let-bound, so we don't need-types in StgRhsCon.--Note [UnariseEnv can map to literals]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-To avoid redundant case expressions when unarising unboxed sums, UnariseEnv-needs to map variables to literals too. Suppose we have this Core:--  f (# x | #)--  ==> (CorePrep)--  case (# x | #) of y {-    _ -> f y-  }--  ==> (MultiVal)--  case (# 1#, x #) of [x1, x2] {-    _ -> f x1 x2-  }--To eliminate this case expression we need to map x1 to 1# in UnariseEnv:--  x1 :-> UnaryVal 1#, x2 :-> UnaryVal x--so that `f x1 x2` becomes `f 1# x`.--Note [Unarisation and arity]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~-Because of unarisation, the arity that will be recorded in the generated info-table for an Id may be larger than the idArity. Instead we record what we call-the RepArity, which is the Arity taking into account any expanded arguments, and-corresponds to the number of (possibly-void) *registers* arguments will arrive-in.--Note [Post-unarisation invariants]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-STG programs after unarisation have these invariants:--  * No unboxed sums at all.--  * No unboxed tuple binders. Tuples only appear in return position.--  * DataCon applications (StgRhsCon and StgConApp) don't have void arguments.-    This means that it's safe to wrap `StgArg`s of DataCon applications with-    `GHC.StgToCmm.Env.NonVoid`, for example.--  * Alt binders (binders in patterns) are always non-void.--  * Binders always have zero (for void arguments) or one PrimRep.--}--{-# LANGUAGE CPP, TupleSections #-}--module UnariseStg (unarise) where--#include "HsVersions.h"--import GhcPrelude--import BasicTypes-import CoreSyn-import DataCon-import FastString (FastString, mkFastString)-import 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,wordPrimTy,word64PrimTy)-import TysWiredIn-import UniqSupply-import Util-import VarEnv--import Data.Bifunctor (second)-import Data.Maybe (mapMaybe)-import qualified Data.IntMap as IM-------------------------------------------------------------------------------------- | A mapping from binders to the Ids they were expanded/renamed to.------   x :-> MultiVal [a,b,c] in rho------ iff  x's typePrimRep is not a singleton, or equivalently---      x's type is an unboxed tuple, sum or void.------    x :-> UnaryVal x'------ iff x's RepType is UnaryRep or equivalently---     x's type is not unboxed tuple, sum or void.------ So---     x :-> MultiVal [a] in rho--- means x is represented by singleton tuple.------     x :-> MultiVal [] in rho--- means x is void.------ INVARIANT: OutStgArgs in the range only have NvUnaryTypes---            (i.e. no unboxed tuples, sums or voids)----type UnariseEnv = VarEnv UnariseVal--data UnariseVal-  = MultiVal [OutStgArg] -- MultiVal to tuple. Can be empty list (void).-  | UnaryVal OutStgArg   -- See NOTE [Renaming during unarisation].--instance Outputable UnariseVal where-  ppr (MultiVal args) = text "MultiVal" <+> ppr args-  ppr (UnaryVal arg)   = text "UnaryVal" <+> ppr arg---- | Extend the environment, checking the UnariseEnv invariant.-extendRho :: UnariseEnv -> Id -> UnariseVal -> UnariseEnv-extendRho rho x (MultiVal args)-  = ASSERT(all (isNvUnaryType . stgArgType) args)-    extendVarEnv rho x (MultiVal args)-extendRho rho x (UnaryVal val)-  = ASSERT(isNvUnaryType (stgArgType val))-    extendVarEnv rho x (UnaryVal val)------------------------------------------------------------------------------------unarise :: UniqSupply -> [StgTopBinding] -> [StgTopBinding]-unarise us binds = initUs_ us (mapM (unariseTopBinding emptyVarEnv) binds)--unariseTopBinding :: UnariseEnv -> StgTopBinding -> UniqSM StgTopBinding-unariseTopBinding rho (StgTopLifted bind)-  = StgTopLifted <$> unariseBinding rho bind-unariseTopBinding _ bind@StgTopStringLit{} = return bind--unariseBinding :: UnariseEnv -> StgBinding -> UniqSM StgBinding-unariseBinding rho (StgNonRec x rhs)-  = StgNonRec x <$> unariseRhs rho rhs-unariseBinding rho (StgRec xrhss)-  = StgRec <$> mapM (\(x, rhs) -> (x,) <$> unariseRhs rho rhs) xrhss--unariseRhs :: UnariseEnv -> StgRhs -> UniqSM StgRhs-unariseRhs rho (StgRhsClosure ext ccs update_flag args expr)-  = do (rho', args1) <- unariseFunArgBinders rho args-       expr' <- unariseExpr rho' expr-       return (StgRhsClosure ext ccs update_flag args1 expr')--unariseRhs rho (StgRhsCon ccs con args)-  = ASSERT(not (isUnboxedTupleCon con || isUnboxedSumCon con))-    return (StgRhsCon ccs con (unariseConArgs rho args))------------------------------------------------------------------------------------unariseExpr :: UnariseEnv -> StgExpr -> UniqSM StgExpr--unariseExpr rho e@(StgApp f [])-  = case lookupVarEnv rho f of-      Just (MultiVal args)  -- Including empty tuples-        -> return (mkTuple args)-      Just (UnaryVal (StgVarArg f'))-        -> return (StgApp f' [])-      Just (UnaryVal (StgLitArg f'))-        -> return (StgLit f')-      Nothing-        -> return e--unariseExpr rho e@(StgApp f args)-  = return (StgApp f' (unariseFunArgs rho args))-  where-    f' = case lookupVarEnv rho f of-           Just (UnaryVal (StgVarArg f')) -> f'-           Nothing -> f-           err -> pprPanic "unariseExpr - app2" (ppr e $$ ppr err)-               -- Can't happen because 'args' is non-empty, and-               -- a tuple or sum cannot be applied to anything--unariseExpr _ (StgLit l)-  = return (StgLit l)--unariseExpr rho (StgConApp dc args ty_args)-  | Just args' <- unariseMulti_maybe rho dc args ty_args-  = return (mkTuple args')--  | otherwise-  , let args' = unariseConArgs rho args-  = return (StgConApp dc args' (map stgArgType args'))--unariseExpr rho (StgOpApp op args ty)-  = return (StgOpApp op (unariseFunArgs rho args) ty)--unariseExpr _ e@StgLam{}-  = pprPanic "unariseExpr: found lambda" (ppr e)--unariseExpr rho (StgCase scrut bndr alt_ty alts)-  -- 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--  -- Handle strict lets for tuples and sums:-  --   case (# a,b #) of r -> rhs-  -- and analogously for sums-  | StgConApp dc args ty_args <- scrut-  , Just args' <- unariseMulti_maybe rho dc args ty_args-  = elimCase rho args' bndr alt_ty alts--  -- general case-  | otherwise-  = do scrut' <- unariseExpr rho scrut-       alts'  <- unariseAlts rho alt_ty bndr alts-       return (StgCase scrut' bndr alt_ty alts')-                       -- bndr may have a unboxed sum/tuple type but it will be-                       -- dead after unarise (checked in StgLint)--unariseExpr rho (StgLet ext bind e)-  = StgLet ext <$> unariseBinding rho bind <*> unariseExpr rho e--unariseExpr rho (StgLetNoEscape ext bind e)-  = StgLetNoEscape ext <$> unariseBinding rho bind <*> unariseExpr rho e--unariseExpr rho (StgTick tick e)-  = StgTick tick <$> unariseExpr rho e---- Doesn't return void args.-unariseMulti_maybe :: UnariseEnv -> DataCon -> [InStgArg] -> [Type] -> Maybe [OutStgArg]-unariseMulti_maybe rho dc args ty_args-  | isUnboxedTupleCon dc-  = Just (unariseConArgs rho args)--  | isUnboxedSumCon dc-  , let args1 = ASSERT(isSingleton args) (unariseConArgs rho args)-  = Just (mkUbxSum dc ty_args args1)--  | otherwise-  = Nothing------------------------------------------------------------------------------------elimCase :: UnariseEnv-         -> [OutStgArg] -- non-void args-         -> InId -> AltType -> [InStgAlt] -> UniqSM OutStgExpr--elimCase rho args bndr (MultiValAlt _) [(_, bndrs, rhs)]-  = do let rho1 = extendRho rho bndr (MultiVal args)-           rho2-             | isUnboxedTupleBndr bndr-             = mapTupleIdBinders bndrs args rho1-             | otherwise-             = ASSERT(isUnboxedSumBndr bndr)-               if null bndrs then rho1-                             else mapSumIdBinders bndrs args rho1--       unariseExpr rho2 rhs--elimCase rho args bndr (MultiValAlt _) alts-  | isUnboxedSumBndr bndr-  = do let (tag_arg : real_args) = args-       tag_bndr <- mkId (mkFastString "tag") tagTy-          -- this won't be used but we need a binder anyway-       let rho1 = extendRho rho bndr (MultiVal args)-           scrut' = case tag_arg of-                      StgVarArg v     -> StgApp v []-                      StgLitArg l     -> StgLit l--       alts' <- unariseSumAlts rho1 real_args alts-       return (StgCase scrut' tag_bndr tagAltTy alts')--elimCase _ args bndr alt_ty alts-  = pprPanic "elimCase - unhandled case"-      (ppr args <+> ppr bndr <+> ppr alt_ty $$ ppr alts)------------------------------------------------------------------------------------unariseAlts :: UnariseEnv -> AltType -> InId -> [StgAlt] -> UniqSM [StgAlt]-unariseAlts rho (MultiValAlt n) bndr [(DEFAULT, [], e)]-  | isUnboxedTupleBndr bndr-  = do (rho', ys) <- unariseConArgBinder rho bndr-       e' <- unariseExpr rho' e-       return [(DataAlt (tupleDataCon Unboxed n), ys, e')]--unariseAlts rho (MultiValAlt n) bndr [(DataAlt _, ys, e)]-  | isUnboxedTupleBndr bndr-  = do (rho', ys1) <- unariseConArgBinders rho ys-       MASSERT(ys1 `lengthIs` n)-       let rho'' = extendRho rho' bndr (MultiVal (map StgVarArg ys1))-       e' <- unariseExpr rho'' e-       return [(DataAlt (tupleDataCon Unboxed n), ys1, e')]--unariseAlts _ (MultiValAlt _) bndr alts-  | isUnboxedTupleBndr bndr-  = pprPanic "unariseExpr: strange multi val alts" (ppr alts)---- In this case we don't need to scrutinize the tag bit-unariseAlts rho (MultiValAlt _) bndr [(DEFAULT, _, rhs)]-  | isUnboxedSumBndr bndr-  = do (rho_sum_bndrs, sum_bndrs) <- unariseConArgBinder rho bndr-       rhs' <- unariseExpr rho_sum_bndrs rhs-       return [(DataAlt (tupleDataCon Unboxed (length sum_bndrs)), sum_bndrs, rhs')]--unariseAlts rho (MultiValAlt _) bndr alts-  | isUnboxedSumBndr bndr-  = do (rho_sum_bndrs, scrt_bndrs@(tag_bndr : real_bndrs)) <- unariseConArgBinder rho bndr-       alts' <- unariseSumAlts rho_sum_bndrs (map StgVarArg real_bndrs) alts-       let inner_case = StgCase (StgApp tag_bndr []) tag_bndr tagAltTy alts'-       return [ (DataAlt (tupleDataCon Unboxed (length scrt_bndrs)),-                 scrt_bndrs,-                 inner_case) ]--unariseAlts rho _ _ alts-  = mapM (\alt -> unariseAlt rho alt) alts--unariseAlt :: UnariseEnv -> StgAlt -> UniqSM StgAlt-unariseAlt rho (con, xs, e)-  = do (rho', xs') <- unariseConArgBinders rho xs-       (con, xs',) <$> unariseExpr rho' e-------------------------------------------------------------------------------------- | Make alternatives that match on the tag of a sum--- (i.e. generate LitAlts for the tag)-unariseSumAlts :: UnariseEnv-               -> [StgArg] -- sum components _excluding_ the tag bit.-               -> [StgAlt] -- original alternative with sum LHS-               -> UniqSM [StgAlt]-unariseSumAlts env args alts-  = do alts' <- mapM (unariseSumAlt env args) alts-       return (mkDefaultLitAlt alts')--unariseSumAlt :: UnariseEnv-              -> [StgArg] -- sum components _excluding_ the tag bit.-              -> StgAlt   -- original alternative with sum LHS-              -> UniqSM StgAlt-unariseSumAlt rho _ (DEFAULT, _, e)-  = ( DEFAULT, [], ) <$> unariseExpr rho e--unariseSumAlt rho args (DataAlt sumCon, bs, e)-  = do let rho' = mapSumIdBinders bs args rho-       e' <- unariseExpr rho' e-       return ( LitAlt (LitNumber LitNumInt (fromIntegral (dataConTag sumCon)) intPrimTy), [], e' )--unariseSumAlt _ scrt alt-  = pprPanic "unariseSumAlt" (ppr scrt $$ ppr alt)------------------------------------------------------------------------------------mapTupleIdBinders-  :: [InId]       -- Un-processed binders of a tuple alternative.-                  -- Can have void binders.-  -> [OutStgArg]  -- Arguments that form the tuple (after unarisation).-                  -- Can't have void args.-  -> UnariseEnv-  -> UnariseEnv-mapTupleIdBinders ids args0 rho0-  = ASSERT(not (any (isVoidTy . stgArgType) args0))-    let-      ids_unarised :: [(Id, [PrimRep])]-      ids_unarised = map (\id -> (id, typePrimRep (idType id))) ids--      map_ids :: UnariseEnv -> [(Id, [PrimRep])] -> [StgArg] -> UnariseEnv-      map_ids rho [] _  = rho-      map_ids rho ((x, x_reps) : xs) args =-        let-          x_arity = length x_reps-          (x_args, args') =-            ASSERT(args `lengthAtLeast` x_arity)-            splitAt x_arity args--          rho'-            | x_arity == 1-            = ASSERT(x_args `lengthIs` 1)-              extendRho rho x (UnaryVal (head x_args))-            | otherwise-            = extendRho rho x (MultiVal x_args)-        in-          map_ids rho' xs args'-    in-      map_ids rho0 ids_unarised args0--mapSumIdBinders-  :: [InId]      -- Binder of a sum alternative (remember that sum patterns-                 -- only have one binder, so this list should be a singleton)-  -> [OutStgArg] -- Arguments that form the sum (NOT including the tag).-                 -- Can't have void args.-  -> UnariseEnv-  -> UnariseEnv--mapSumIdBinders [id] args rho0-  = ASSERT(not (any (isVoidTy . stgArgType) args))-    let-      arg_slots = map primRepSlot $ concatMap (typePrimRep . stgArgType) args-      id_slots  = map primRepSlot $ typePrimRep (idType id)-      layout1   = layoutUbxSum arg_slots id_slots-    in-      if isMultiValBndr id-        then extendRho rho0 id (MultiVal [ args !! i | i <- layout1 ])-        else ASSERT(layout1 `lengthIs` 1)-             extendRho rho0 id (UnaryVal (args !! head layout1))--mapSumIdBinders ids sum_args _-  = pprPanic "mapSumIdBinders" (ppr ids $$ ppr sum_args)---- | Build a unboxed sum term from arguments of an alternative.------ Example, for (# x | #) :: (# (# #) | Int #) we call------   mkUbxSum (# _ | #) [ (# #), Int ] [ voidPrimId ]------ which returns------   [ 1#, rubbish ]----mkUbxSum-  :: DataCon      -- Sum data con-  -> [Type]       -- Type arguments of the sum data con-  -> [OutStgArg]  -- Actual arguments of the alternative.-  -> [OutStgArg]  -- Final tuple arguments-mkUbxSum dc ty_args args0-  = let-      (_ : sum_slots) = ubxSumRepType (map typePrimRep ty_args)-        -- drop tag slot--      tag = dataConTag dc--      layout'  = layoutUbxSum sum_slots (mapMaybe (typeSlotTy . stgArgType) args0)-      tag_arg  = StgLitArg (LitNumber LitNumInt (fromIntegral tag) intPrimTy)-      arg_idxs = IM.fromList (zipEqual "mkUbxSum" layout' args0)--      mkTupArgs :: Int -> [SlotTy] -> IM.IntMap StgArg -> [StgArg]-      mkTupArgs _ [] _-        = []-      mkTupArgs arg_idx (slot : slots_left) arg_map-        | Just stg_arg <- IM.lookup arg_idx arg_map-        = stg_arg : mkTupArgs (arg_idx + 1) slots_left arg_map-        | otherwise-        = slotRubbishArg slot : mkTupArgs (arg_idx + 1) slots_left arg_map--      slotRubbishArg :: SlotTy -> StgArg-      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 (LitFloat 0)-      slotRubbishArg DoubleSlot = StgLitArg (LitDouble 0)-    in-      tag_arg : mkTupArgs 0 sum_slots arg_idxs------------------------------------------------------------------------------------{--For arguments (StgArg) and binders (Id) we have two kind of unarisation:--  - When unarising function arg binders and arguments, we don't want to remove-    void binders and arguments. For example,--      f :: (# (# #), (# #) #) -> Void# -> RealWorld# -> ...-      f x y z = <body>--    Here after unarise we should still get a function with arity 3. Similarly-    in the call site we shouldn't remove void arguments:--      f (# (# #), (# #) #) voidId rw--    When unarising <body>, we extend the environment with these binders:--      x :-> MultiVal [], y :-> MultiVal [], z :-> MultiVal []--    Because their rep types are `MultiRep []` (aka. void). This means that when-    we see `x` in a function argument position, we actually replace it with a-    void argument. When we see it in a DataCon argument position, we just get-    rid of it, because DataCon applications in STG are always saturated.--  - When unarising case alternative binders we remove void binders, but we-    still update the environment the same way, because those binders may be-    used in the RHS. Example:--      case x of y {-        (# x1, x2, x3 #) -> <RHS>-      }--    We know that y can't be void, because we don't scrutinize voids, so x will-    be unarised to some number of arguments, and those arguments will have at-    least one non-void thing. So in the rho we will have something like:--      x :-> MultiVal [xu1, xu2]--    Now, after we eliminate void binders in the pattern, we get exactly the same-    number of binders, and extend rho again with these:--      x1 :-> UnaryVal xu1-      x2 :-> MultiVal [] -- x2 is void-      x3 :-> UnaryVal xu2--    Now when we see x2 in a function argument position or in return position, we-    generate void#. In constructor argument position, we just remove it.--So in short, when we have a void id,--  - We keep it if it's a lambda argument binder or-                       in argument position of an application.--  - We remove it if it's a DataCon field binder or-                         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.-unariseFunArg :: UnariseEnv -> StgArg -> [StgArg]-unariseFunArg rho (StgVarArg x) =-  case lookupVarEnv rho x of-    Just (MultiVal [])  -> [voidArg]   -- NB: do not remove void args-    Just (MultiVal as)  -> as-    Just (UnaryVal arg) -> [arg]-    Nothing             -> [StgVarArg x]-unariseFunArg _ arg = [arg]--unariseFunArgs :: UnariseEnv -> [StgArg] -> [StgArg]-unariseFunArgs = concatMap . unariseFunArg--unariseFunArgBinders :: UnariseEnv -> [Id] -> UniqSM (UnariseEnv, [Id])-unariseFunArgBinders rho xs = second concat <$> mapAccumLM unariseFunArgBinder rho xs---- Result list of binders is never empty-unariseFunArgBinder :: UnariseEnv -> Id -> UniqSM (UnariseEnv, [Id])-unariseFunArgBinder = unariseArgBinder False-------------------------------------------------------------------------------------- | MultiVal a DataCon argument. Returns an empty list when argument is void.-unariseConArg :: UnariseEnv -> InStgArg -> [OutStgArg]-unariseConArg rho (StgVarArg x) =-  case lookupVarEnv rho x of-    Just (UnaryVal arg) -> [arg]-    Just (MultiVal as) -> as      -- 'as' can be empty-    Nothing-      | isVoidTy (idType x) -> [] -- e.g. C realWorld#-                                  -- Here realWorld# is not in the envt, but-                                  -- is a void, and so should be eliminated-      | otherwise -> [StgVarArg x]-unariseConArg _ arg@(StgLitArg lit) =-    ASSERT(not (isVoidTy (literalType lit)))  -- We have no void literals-    [arg]--unariseConArgs :: UnariseEnv -> [InStgArg] -> [OutStgArg]-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 = unariseArgBinder True------------------------------------------------------------------------------------mkIds :: FastString -> [UnaryType] -> UniqSM [Id]-mkIds fs tys = mapM (mkId fs) tys--mkId :: FastString -> UnaryType -> UniqSM Id-mkId = mkSysLocalOrCoVarM--isMultiValBndr :: Id -> Bool-isMultiValBndr id-  | [_] <- typePrimRep (idType id)-  = False-  | otherwise-  = True--isUnboxedSumBndr :: Id -> Bool-isUnboxedSumBndr = isUnboxedSumType . idType--isUnboxedTupleBndr :: Id -> Bool-isUnboxedTupleBndr = isUnboxedTupleType . idType--mkTuple :: [StgArg] -> StgExpr-mkTuple args = StgConApp (tupleDataCon Unboxed (length args)) args (map stgArgType args)--tagAltTy :: AltType-tagAltTy = PrimAlt IntRep--tagTy :: Type-tagTy = intPrimTy--voidArg :: StgArg-voidArg = StgVarArg voidPrimId--mkDefaultLitAlt :: [StgAlt] -> [StgAlt]--- We have an exhauseive list of literal alternatives---    1# -> e1---    2# -> e2--- Since they are exhaustive, we can replace one with DEFAULT, to avoid--- generating a final test. Remember, the DEFAULT comes first if it exists.-mkDefaultLitAlt [] = pprPanic "elimUbxSumExpr.mkDefaultAlt" (text "Empty alts")-mkDefaultLitAlt alts@((DEFAULT, _, _) : _) = alts-mkDefaultLitAlt ((LitAlt{}, [], rhs) : alts) = (DEFAULT, [], rhs) : alts-mkDefaultLitAlt alts = pprPanic "mkDefaultLitAlt" (text "Not a lit alt:" <+> ppr alts)
compiler/specialise/SpecConstr.hs view
@@ -699,7 +699,7 @@   = do       dflags <- getDynFlags       us     <- getUniqueSupplyM-      annos  <- getFirstAnnotations deserializeWithData guts+      (_, annos) <- getFirstAnnotations deserializeWithData guts       this_mod <- getModule       let binds' = reverse $ fst $ initUs us $ do                     -- Note [Top-level recursive groups]@@ -1720,8 +1720,8 @@                spec_join_arity | isJoinId fn = Just (length spec_lam_args)                               | otherwise   = Nothing-              spec_id    = mkLocalIdOrCoVar spec_name-                                            (mkLamTypes spec_lam_args body_ty)+              spec_id    = mkLocalId spec_name+                                     (mkLamTypes spec_lam_args body_ty)                              -- See Note [Transfer strictness]                              `setIdStrictness` spec_str                              `setIdArity` count isId spec_lam_args
compiler/specialise/Specialise.hs view
@@ -2378,7 +2378,7 @@     interesting :: InterestingVarFun     interesting v = isLocalVar v || (isId v && isDFunId v)         -- Very important: include DFunIds /even/ if it is imported-        -- Reason: See Note [Avoiding loops], the second exmaple+        -- Reason: See Note [Avoiding loops], the second example         --         involving an imported dfun.  We must know whether         --         a dictionary binding depends on an imported dfun,         --         in case we try to specialise that imported dfun@@ -2635,7 +2635,7 @@ newDictBndr env b = do { uniq <- getUniqueM                        ; let n   = idName b                              ty' = substTy env (idType b)-                       ; return (mkUserLocalOrCoVar (nameOccName n) uniq ty' (getSrcSpan n)) }+                       ; return (mkUserLocal (nameOccName n) uniq ty' (getSrcSpan n)) }  newSpecIdSM :: Id -> Type -> Maybe JoinArity -> SpecM Id     -- Give the new Id a similar occurrence name to the old one@@ -2643,7 +2643,7 @@   = do  { uniq <- getUniqueM         ; let name    = idName old_id               new_occ = mkSpecOcc (nameOccName name)-              new_id  = mkUserLocalOrCoVar new_occ uniq new_ty (getSrcSpan name)+              new_id  = mkUserLocal new_occ uniq new_ty (getSrcSpan name)                           `asJoinId_maybe` join_arity_maybe         ; return new_id } 
− compiler/stgSyn/CoreToStg.hs
@@ -1,939 +0,0 @@-{-# LANGUAGE CPP, DeriveFunctor #-}------- (c) The GRASP/AQUA Project, Glasgow University, 1993-1998---------------------------------------------------------------------- Converting Core to STG Syntax------------------------------------------------------------------- And, as we have the info in hand, we may convert some lets to--- let-no-escapes.--module CoreToStg ( coreToStg ) where--#include "HsVersions.h"--import GhcPrelude--import CoreSyn-import CoreUtils        ( exprType, findDefault, isJoinBind-                        , exprIsTickedString_maybe )-import CoreArity        ( manifestArity )-import StgSyn--import Type-import RepType-import TyCon-import MkId             ( coercionTokenId )-import Id-import IdInfo-import DataCon-import CostCentre-import VarEnv-import Module-import Name             ( isExternalName, nameOccName, nameModule_maybe )-import OccName          ( occNameFS )-import BasicTypes       ( Arity )-import TysWiredIn       ( unboxedUnitDataCon, unitDataConId )-import Literal-import Outputable-import MonadUtils-import FastString-import Util-import DynFlags-import ForeignCall-import Demand           ( isUsedOnce )-import PrimOp           ( PrimCall(..), primOpWrapperId )-import SrcLoc           ( mkGeneralSrcSpan )--import Data.List.NonEmpty (nonEmpty, toList)-import Data.Maybe    (fromMaybe)-import Control.Monad (ap)---- Note [Live vs free]--- ~~~~~~~~~~~~~~~~~~~------ The two are not the same. Liveness is an operational property rather--- than a semantic one. A variable is live at a particular execution--- point if it can be referred to directly again. In particular, a dead--- variable's stack slot (if it has one):------           - should be stubbed to avoid space leaks, and---           - may be reused for something else.------ There ought to be a better way to say this. Here are some examples:------         let v = [q] \[x] -> e---         in---         ...v...  (but no q's)------ Just after the `in', v is live, but q is dead. If the whole of that--- let expression was enclosed in a case expression, thus:------         case (let v = [q] \[x] -> e in ...v...) of---                 alts[...q...]------ (ie `alts' mention `q'), then `q' is live even after the `in'; because--- we'll return later to the `alts' and need it.------ Let-no-escapes make this a bit more interesting:------         let-no-escape v = [q] \ [x] -> e---         in---         ...v...------ Here, `q' is still live at the `in', because `v' is represented not by--- a closure but by the current stack state.  In other words, if `v' is--- live then so is `q'. Furthermore, if `e' mentions an enclosing--- let-no-escaped variable, then its free variables are also live if `v' is.---- Note [What are these SRTs all about?]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~------ Consider the Core program,------     fibs = go 1 1---       where go a b = let c = a + c---                      in c : go b c---     add x = map (\y -> x*y) fibs------ In this case we have a CAF, 'fibs', which is quite large after evaluation and--- has only one possible user, 'add'. Consequently, we want to ensure that when--- all references to 'add' die we can garbage collect any bit of 'fibs' that we--- have evaluated.------ However, how do we know whether there are any references to 'fibs' still--- around? Afterall, the only reference to it is buried in the code generated--- for 'add'. The answer is that we record the CAFs referred to by a definition--- in its info table, namely a part of it known as the Static Reference Table--- (SRT).------ Since SRTs are so common, we use a special compact encoding for them in: we--- produce one table containing a list of CAFs in a module and then include a--- bitmap in each info table describing which entries of this table the closure--- references.------ See also: commentary/rts/storage/gc/CAFs on the GHC Wiki.---- Note [What is a non-escaping let]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~------ NB: Nowadays this is recognized by the occurrence analyser by turning a--- "non-escaping let" into a join point. The following is then an operational--- account of join points.------ Consider:------     let x = fvs \ args -> e---     in---         if ... then x else---            if ... then x else ...------ `x' is used twice (so we probably can't unfold it), but when it is--- entered, the stack is deeper than it was when the definition of `x'--- happened.  Specifically, if instead of allocating a closure for `x',--- we saved all `x's fvs on the stack, and remembered the stack depth at--- that moment, then whenever we enter `x' we can simply set the stack--- pointer(s) to these remembered (compile-time-fixed) values, and jump--- to the code for `x'.------ All of this is provided x is:---   1. non-updatable;---   2. guaranteed to be entered before the stack retreats -- ie x is not---      buried in a heap-allocated closure, or passed as an argument to---      something;---   3. all the enters have exactly the right number of arguments,---      no more no less;---   4. all the enters are tail calls; that is, they return to the---      caller enclosing the definition of `x'.------ Under these circumstances we say that `x' is non-escaping.------ An example of when (4) does not hold:------     let x = ...---     in case x of ...alts...------ Here, `x' is certainly entered only when the stack is deeper than when--- `x' is defined, but here it must return to ...alts... So we can't just--- adjust the stack down to `x''s recalled points, because that would lost--- alts' context.------ Things can get a little more complicated.  Consider:------     let y = ...---     in let x = fvs \ args -> ...y...---     in ...x...------ Now, if `x' is used in a non-escaping way in ...x..., and `y' is used in a--- non-escaping way in ...y..., then `y' is non-escaping.------ `x' can even be recursive!  Eg:------     letrec x = [y] \ [v] -> if v then x True else ...---     in---         ...(x b)...---- Note [Cost-centre initialization plan]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~------ Previously `coreToStg` was initializing cost-centre stack fields as `noCCS`,--- and the fields were then fixed by a separate pass `stgMassageForProfiling`.--- We now initialize these correctly. The initialization works like this:------   - For non-top level bindings always use `currentCCS`.------   - For top-level bindings, check if the binding is a CAF------     - CAF:      If -fcaf-all is enabled, create a new CAF just for this CAF---                 and use it. Note that these new cost centres need to be---                 collected to be able to generate cost centre initialization---                 code, so `coreToTopStgRhs` now returns `CollectedCCs`.------                 If -fcaf-all is not enabled, use "all CAFs" cost centre.------     - Non-CAF:  Top-level (static) data is not counted in heap profiles; nor---                 do we set CCCS from it; so we just slam in---                 dontCareCostCentre.---- ----------------------------------------------------------------- Setting variable info: top-level, binds, RHSs--- ----------------------------------------------------------------coreToStg :: DynFlags -> Module -> CoreProgram-          -> ([StgTopBinding], CollectedCCs)-coreToStg dflags this_mod pgm-  = (pgm', final_ccs)-  where-    (_, (local_ccs, local_cc_stacks), pgm')-      = coreTopBindsToStg dflags this_mod emptyVarEnv emptyCollectedCCs pgm--    prof = WayProf `elem` ways dflags--    final_ccs-      | prof && gopt Opt_AutoSccsOnIndividualCafs dflags-      = (local_ccs,local_cc_stacks)  -- don't need "all CAFs" CC-      | prof-      = (all_cafs_cc:local_ccs, all_cafs_ccs:local_cc_stacks)-      | otherwise-      = emptyCollectedCCs--    (all_cafs_cc, all_cafs_ccs) = getAllCAFsCC this_mod--coreTopBindsToStg-    :: DynFlags-    -> Module-    -> IdEnv HowBound           -- environment for the bindings-    -> CollectedCCs-    -> CoreProgram-    -> (IdEnv HowBound, CollectedCCs, [StgTopBinding])--coreTopBindsToStg _      _        env ccs []-  = (env, ccs, [])-coreTopBindsToStg dflags this_mod env ccs (b:bs)-  = (env2, ccs2, b':bs')-  where-        (env1, ccs1, b' ) =-          coreTopBindToStg dflags this_mod env ccs b-        (env2, ccs2, bs') =-          coreTopBindsToStg dflags this_mod env1 ccs1 bs--coreTopBindToStg-        :: DynFlags-        -> Module-        -> IdEnv HowBound-        -> CollectedCCs-        -> CoreBind-        -> (IdEnv HowBound, CollectedCCs, StgTopBinding)--coreTopBindToStg _ _ env ccs (NonRec id e)-  | Just str <- exprIsTickedString_maybe e-  -- top-level string literal-  -- See Note [CoreSyn top-level string literals] in CoreSyn-  = let-        env' = extendVarEnv env id how_bound-        how_bound = LetBound TopLet 0-    in (env', ccs, StgTopStringLit id str)--coreTopBindToStg dflags this_mod env ccs (NonRec id rhs)-  = let-        env'      = extendVarEnv env id how_bound-        how_bound = LetBound TopLet $! manifestArity rhs--        (stg_rhs, ccs') =-            initCts dflags env $-              coreToTopStgRhs dflags ccs this_mod (id,rhs)--        bind = StgTopLifted $ StgNonRec id stg_rhs-    in-    assertConsistentCafInfo dflags id bind (ppr bind)-      -- NB: previously the assertion printed 'rhs' and 'bind'-      --     as well as 'id', but that led to a black hole-      --     where printing the assertion error tripped the-      --     assertion again!-    (env', ccs', bind)--coreTopBindToStg dflags this_mod env ccs (Rec pairs)-  = ASSERT( not (null pairs) )-    let-        binders = map fst pairs--        extra_env' = [ (b, LetBound TopLet $! manifestArity rhs)-                     | (b, rhs) <- pairs ]-        env' = extendVarEnvList env extra_env'--        -- generate StgTopBindings and CAF cost centres created for CAFs-        (ccs', stg_rhss)-          = initCts dflags env' $ do-               mapAccumLM (\ccs rhs -> do-                            (rhs', ccs') <--                              coreToTopStgRhs dflags ccs this_mod rhs-                            return (ccs', rhs'))-                          ccs-                          pairs--        bind = StgTopLifted $ StgRec (zip binders stg_rhss)-    in-    assertConsistentCafInfo dflags (head binders) bind (ppr binders)-    (env', ccs', bind)---- | CAF consistency issues will generally result in segfaults and are quite--- difficult to debug (see #16846). We enable checking of the--- 'consistentCafInfo' invariant with @-dstg-lint@ to increase the chance that--- we catch these issues.-assertConsistentCafInfo :: DynFlags -> Id -> StgTopBinding -> SDoc -> a -> a-assertConsistentCafInfo dflags id bind err_doc result-  | gopt Opt_DoStgLinting dflags || debugIsOn-  , not $ consistentCafInfo id bind = pprPanic "assertConsistentCafInfo" err_doc-  | otherwise = result---- Assertion helper: this checks that the CafInfo on the Id matches--- what CoreToStg has figured out about the binding's SRT.  The--- CafInfo will be exact in all cases except when CorePrep has--- floated out a binding, in which case it will be approximate.-consistentCafInfo :: Id -> StgTopBinding -> Bool-consistentCafInfo id bind-  = WARN( not (exact || is_sat_thing) , ppr id <+> ppr id_marked_caffy <+> ppr binding_is_caffy )-    safe-  where-    safe  = id_marked_caffy || not binding_is_caffy-    exact = id_marked_caffy == binding_is_caffy-    id_marked_caffy  = mayHaveCafRefs (idCafInfo id)-    binding_is_caffy = topStgBindHasCafRefs bind-    is_sat_thing = occNameFS (nameOccName (idName id)) == fsLit "sat"--coreToTopStgRhs-        :: DynFlags-        -> CollectedCCs-        -> Module-        -> (Id,CoreExpr)-        -> CtsM (StgRhs, CollectedCCs)--coreToTopStgRhs dflags ccs this_mod (bndr, rhs)-  = do { new_rhs <- coreToStgExpr rhs--       ; let (stg_rhs, ccs') =-               mkTopStgRhs dflags this_mod ccs bndr new_rhs-             stg_arity =-               stgRhsArity stg_rhs--       ; return (ASSERT2( arity_ok stg_arity, mk_arity_msg stg_arity) stg_rhs,-                 ccs') }-  where-        -- It's vital that the arity on a top-level Id matches-        -- the arity of the generated STG binding, else an importing-        -- module will use the wrong calling convention-        --      (#2844 was an example where this happened)-        -- NB1: we can't move the assertion further out without-        --      blocking the "knot" tied in coreTopBindsToStg-        -- NB2: the arity check is only needed for Ids with External-        --      Names, because they are externally visible.  The CorePrep-        --      pass introduces "sat" things with Local Names and does-        --      not bother to set their Arity info, so don't fail for those-    arity_ok stg_arity-       | isExternalName (idName bndr) = id_arity == stg_arity-       | otherwise                    = True-    id_arity  = idArity bndr-    mk_arity_msg stg_arity-        = vcat [ppr bndr,-                text "Id arity:" <+> ppr id_arity,-                text "STG arity:" <+> ppr stg_arity]---- ------------------------------------------------------------------------------ Expressions--- -----------------------------------------------------------------------------coreToStgExpr-        :: CoreExpr-        -> CtsM StgExpr---- The second and third components can be derived in a simple bottom up pass, not--- dependent on any decisions about which variables will be let-no-escaped or--- not.  The first component, that is, the decorated expression, may then depend--- on these components, but it in turn is not scrutinised as the basis for any--- decisions.  Hence no black holes.---- No LitInteger's or LitNatural's should be left by the time this is called.--- CorePrep should have converted them all to a real core representation.-coreToStgExpr (Lit (LitNumber LitNumInteger _ _)) = panic "coreToStgExpr: LitInteger"-coreToStgExpr (Lit (LitNumber LitNumNatural _ _)) = panic "coreToStgExpr: LitNatural"-coreToStgExpr (Lit l)      = return (StgLit l)-coreToStgExpr (App (Lit LitRubbish) _some_unlifted_type)-  -- We lower 'LitRubbish' to @()@ here, which is much easier than doing it in-  -- a STG to Cmm pass.-  = coreToStgExpr (Var unitDataConId)-coreToStgExpr (Var v)      = coreToStgApp v               [] []-coreToStgExpr (Coercion _) = coreToStgApp coercionTokenId [] []--coreToStgExpr expr@(App _ _)-  = coreToStgApp f args ticks-  where-    (f, args, ticks) = myCollectArgs expr--coreToStgExpr expr@(Lam _ _)-  = let-        (args, body) = myCollectBinders expr-        args'        = filterStgBinders args-    in-    extendVarEnvCts [ (a, LambdaBound) | a <- args' ] $ do-    body' <- coreToStgExpr body-    let-        result_expr = case nonEmpty args' of-          Nothing     -> body'-          Just args'' -> StgLam args'' body'--    return result_expr--coreToStgExpr (Tick tick expr)-  = do case tick of-         HpcTick{}    -> return ()-         ProfNote{}   -> return ()-         SourceNote{} -> return ()-         Breakpoint{} -> panic "coreToStgExpr: breakpoint should not happen"-       expr2 <- coreToStgExpr expr-       return (StgTick tick expr2)--coreToStgExpr (Cast expr _)-  = coreToStgExpr expr---- Cases require a little more real work.--coreToStgExpr (Case scrut _ _ [])-  = coreToStgExpr scrut-    -- See Note [Empty case alternatives] in CoreSyn If the case-    -- alternatives are empty, the scrutinee must diverge or raise an-    -- exception, so we can just dive into it.-    ---    -- Of course this may seg-fault if the scrutinee *does* return.  A-    -- belt-and-braces approach would be to move this case into the-    -- code generator, and put a return point anyway that calls a-    -- runtime system error function.---coreToStgExpr (Case scrut bndr _ alts) = do-    alts2 <- extendVarEnvCts [(bndr, LambdaBound)] (mapM vars_alt alts)-    scrut2 <- coreToStgExpr scrut-    return (StgCase scrut2 bndr (mkStgAltType bndr alts) alts2)-  where-    vars_alt (con, binders, rhs)-      | DataAlt c <- con, c == unboxedUnitDataCon-      = -- This case is a bit smelly.-        -- See Note [Nullary unboxed tuple] in Type.hs-        -- where a nullary tuple is mapped to (State# World#)-        ASSERT( null binders )-        do { rhs2 <- coreToStgExpr rhs-           ; return (DEFAULT, [], rhs2)  }-      | otherwise-      = let     -- Remove type variables-            binders' = filterStgBinders binders-        in-        extendVarEnvCts [(b, LambdaBound) | b <- binders'] $ do-        rhs2 <- coreToStgExpr rhs-        return (con, binders', rhs2)--coreToStgExpr (Let bind body) = do-    coreToStgLet bind body--coreToStgExpr e = pprPanic "coreToStgExpr" (ppr e)--mkStgAltType :: Id -> [CoreAlt] -> AltType-mkStgAltType bndr alts-  | isUnboxedTupleType bndr_ty || isUnboxedSumType bndr_ty-  = MultiValAlt (length prim_reps)  -- always use MultiValAlt for unboxed tuples--  | otherwise-  = case prim_reps of-      [LiftedRep] -> case tyConAppTyCon_maybe (unwrapType bndr_ty) of-        Just tc-          | isAbstractTyCon tc -> look_for_better_tycon-          | isAlgTyCon tc      -> AlgAlt tc-          | otherwise          -> ASSERT2( _is_poly_alt_tycon tc, ppr tc )-                                  PolyAlt-        Nothing                -> PolyAlt-      [unlifted] -> PrimAlt unlifted-      not_unary  -> MultiValAlt (length not_unary)-  where-   bndr_ty   = idType bndr-   prim_reps = typePrimRep bndr_ty--   _is_poly_alt_tycon tc-        =  isFunTyCon tc-        || isPrimTyCon tc   -- "Any" is lifted but primitive-        || isFamilyTyCon tc -- Type family; e.g. Any, or arising from strict-                            -- function application where argument has a-                            -- type-family type--   -- Sometimes, the TyCon is a AbstractTyCon which may not have any-   -- constructors inside it.  Then we may get a better TyCon by-   -- grabbing the one from a constructor alternative-   -- if one exists.-   look_for_better_tycon-        | ((DataAlt con, _, _) : _) <- data_alts =-                AlgAlt (dataConTyCon con)-        | otherwise =-                ASSERT(null data_alts)-                PolyAlt-        where-                (data_alts, _deflt) = findDefault alts---- ------------------------------------------------------------------------------ Applications--- -----------------------------------------------------------------------------coreToStgApp :: Id            -- Function-             -> [CoreArg]     -- Arguments-             -> [Tickish Id]  -- Debug ticks-             -> CtsM StgExpr-coreToStgApp f args ticks = do-    (args', ticks') <- coreToStgArgs args-    how_bound <- lookupVarCts f--    let-        n_val_args       = valArgCount args--        -- Mostly, the arity info of a function is in the fn's IdInfo-        -- But new bindings introduced by CoreSat may not have no-        -- arity info; it would do us no good anyway.  For example:-        --      let f = \ab -> e in f-        -- No point in having correct arity info for f!-        -- Hence the hasArity stuff below.-        -- NB: f_arity is only consulted for LetBound things-        f_arity   = stgArity f how_bound-        saturated = f_arity <= n_val_args--        res_ty = exprType (mkApps (Var f) args)-        app = case idDetails f of-                DataConWorkId dc-                  | saturated    -> StgConApp dc args'-                                      (dropRuntimeRepArgs (fromMaybe [] (tyConAppArgs_maybe res_ty)))--                -- Some primitive operator that might be implemented as a library call.-                -- As described in Note [Primop wrappers] in PrimOp.hs, here we-                -- turn unsaturated primop applications into applications of-                -- the primop's wrapper.-                PrimOpId op-                  | saturated    -> StgOpApp (StgPrimOp op) args' res_ty-                  | otherwise    -> StgApp (primOpWrapperId op) args'--                -- A call to some primitive Cmm function.-                FCallId (CCall (CCallSpec (StaticTarget _ lbl (Just pkgId) True)-                                          PrimCallConv _))-                                 -> ASSERT( saturated )-                                    StgOpApp (StgPrimCallOp (PrimCall lbl pkgId)) args' res_ty--                -- A regular foreign call.-                FCallId call     -> ASSERT( saturated )-                                    StgOpApp (StgFCallOp call (idType f)) args' res_ty--                TickBoxOpId {}   -> pprPanic "coreToStg TickBox" $ ppr (f,args')-                _other           -> StgApp f args'--        tapp = foldr StgTick app (ticks ++ ticks')--    -- Forcing these fixes a leak in the code generator, noticed while-    -- profiling for trac #4367-    app `seq` return tapp---- ------------------------------------------------------------------------------ Argument lists--- This is the guy that turns applications into A-normal form--- -----------------------------------------------------------------------------coreToStgArgs :: [CoreArg] -> CtsM ([StgArg], [Tickish Id])-coreToStgArgs []-  = return ([], [])--coreToStgArgs (Type _ : args) = do     -- Type argument-    (args', ts) <- coreToStgArgs args-    return (args', ts)--coreToStgArgs (Coercion _ : args)  -- Coercion argument; replace with place holder-  = do { (args', ts) <- coreToStgArgs args-       ; return (StgVarArg coercionTokenId : args', ts) }--coreToStgArgs (Tick t e : args)-  = ASSERT( not (tickishIsCode t) )-    do { (args', ts) <- coreToStgArgs (e : args)-       ; return (args', t:ts) }--coreToStgArgs (arg : args) = do         -- Non-type argument-    (stg_args, ticks) <- coreToStgArgs args-    arg' <- coreToStgExpr arg-    let-        (aticks, arg'') = stripStgTicksTop tickishFloatable arg'-        stg_arg = case arg'' of-                       StgApp v []        -> StgVarArg v-                       StgConApp con [] _ -> StgVarArg (dataConWorkId con)-                       StgLit lit         -> StgLitArg lit-                       _                  -> pprPanic "coreToStgArgs" (ppr arg)--        -- WARNING: what if we have an argument like (v `cast` co)-        --          where 'co' changes the representation type?-        --          (This really only happens if co is unsafe.)-        -- Then all the getArgAmode stuff in CgBindery will set the-        -- cg_rep of the CgIdInfo based on the type of v, rather-        -- than the type of 'co'.-        -- This matters particularly when the function is a primop-        -- or foreign call.-        -- Wanted: a better solution than this hacky warning--    dflags <- getDynFlags-    let-        arg_rep = typePrimRep (exprType arg)-        stg_arg_rep = typePrimRep (stgArgType stg_arg)-        bad_args = not (primRepsCompatible dflags arg_rep stg_arg_rep)--    WARN( bad_args, text "Dangerous-looking argument. Probable cause: bad unsafeCoerce#" $$ ppr arg )-     return (stg_arg : stg_args, ticks ++ aticks)----- ------------------------------------------------------------------------------ The magic for lets:--- -----------------------------------------------------------------------------coreToStgLet-         :: CoreBind     -- bindings-         -> CoreExpr     -- body-         -> CtsM StgExpr -- new let--coreToStgLet bind body = do-    (bind2, body2)-       <- do--          ( bind2, env_ext)-                <- vars_bind bind--          -- Do the body-          extendVarEnvCts env_ext $ do-             body2 <- coreToStgExpr body--             return (bind2, body2)--        -- Compute the new let-expression-    let-        new_let | isJoinBind bind = StgLetNoEscape noExtFieldSilent bind2 body2-                | otherwise       = StgLet noExtFieldSilent bind2 body2--    return new_let-  where-    mk_binding binder rhs-        = (binder, LetBound NestedLet (manifestArity rhs))--    vars_bind :: CoreBind-              -> CtsM (StgBinding,-                       [(Id, HowBound)])  -- extension to environment--    vars_bind (NonRec binder rhs) = do-        rhs2 <- coreToStgRhs (binder,rhs)-        let-            env_ext_item = mk_binding binder rhs--        return (StgNonRec binder rhs2, [env_ext_item])--    vars_bind (Rec pairs)-      =    let-                binders = map fst pairs-                env_ext = [ mk_binding b rhs-                          | (b,rhs) <- pairs ]-           in-           extendVarEnvCts env_ext $ do-              rhss2 <- mapM coreToStgRhs pairs-              return (StgRec (binders `zip` rhss2), env_ext)--coreToStgRhs :: (Id,CoreExpr)-             -> CtsM StgRhs--coreToStgRhs (bndr, rhs) = do-    new_rhs <- coreToStgExpr rhs-    return (mkStgRhs bndr new_rhs)---- Generate a top-level RHS. Any new cost centres generated for CAFs will be--- appended to `CollectedCCs` argument.-mkTopStgRhs :: DynFlags -> Module -> CollectedCCs-            -> Id -> StgExpr -> (StgRhs, CollectedCCs)--mkTopStgRhs dflags this_mod ccs bndr rhs-  | StgLam bndrs body <- rhs-  = -- StgLam can't have empty arguments, so not CAF-    ( StgRhsClosure noExtFieldSilent-                    dontCareCCS-                    ReEntrant-                    (toList bndrs) body-    , ccs )--  | StgConApp con args _ <- unticked_rhs-  , -- Dynamic StgConApps are updatable-    not (isDllConApp dflags this_mod con args)-  = -- CorePrep does this right, but just to make sure-    ASSERT2( not (isUnboxedTupleCon con || isUnboxedSumCon con)-           , ppr bndr $$ ppr con $$ ppr args)-    ( StgRhsCon dontCareCCS con args, ccs )--  -- Otherwise it's a CAF, see Note [Cost-centre initialization plan].-  | gopt Opt_AutoSccsOnIndividualCafs dflags-  = ( StgRhsClosure noExtFieldSilent-                    caf_ccs-                    upd_flag [] rhs-    , collectCC caf_cc caf_ccs ccs )--  | otherwise-  = ( StgRhsClosure noExtFieldSilent-                    all_cafs_ccs-                    upd_flag [] rhs-    , ccs )--  where-    unticked_rhs = stripStgTicksTopE (not . tickishIsCode) rhs--    upd_flag | isUsedOnce (idDemandInfo bndr) = SingleEntry-             | otherwise                      = Updatable--    -- CAF cost centres generated for -fcaf-all-    caf_cc = mkAutoCC bndr modl-    caf_ccs = mkSingletonCCS caf_cc-           -- careful: the binder might be :Main.main,-           -- which doesn't belong to module mod_name.-           -- bug #249, tests prof001, prof002-    modl | Just m <- nameModule_maybe (idName bndr) = m-         | otherwise = this_mod--    -- default CAF cost centre-    (_, all_cafs_ccs) = getAllCAFsCC this_mod---- Generate a non-top-level RHS. Cost-centre is always currentCCS,--- see Note [Cost-centre initialzation plan].-mkStgRhs :: Id -> StgExpr -> StgRhs-mkStgRhs bndr rhs-  | StgLam bndrs body <- rhs-  = StgRhsClosure noExtFieldSilent-                  currentCCS-                  ReEntrant-                  (toList bndrs) body--  | isJoinId bndr -- must be a nullary join point-  = ASSERT(idJoinArity bndr == 0)-    StgRhsClosure noExtFieldSilent-                  currentCCS-                  ReEntrant -- ignored for LNE-                  [] rhs--  | StgConApp con args _ <- unticked_rhs-  = StgRhsCon currentCCS con args--  | otherwise-  = StgRhsClosure noExtFieldSilent-                  currentCCS-                  upd_flag [] rhs-  where-    unticked_rhs = stripStgTicksTopE (not . tickishIsCode) rhs--    upd_flag | isUsedOnce (idDemandInfo bndr) = SingleEntry-             | otherwise                      = Updatable--  {--    SDM: disabled.  Eval/Apply can't handle functions with arity zero very-    well; and making these into simple non-updatable thunks breaks other-    assumptions (namely that they will be entered only once).--    upd_flag | isPAP env rhs  = ReEntrant-             | otherwise      = Updatable---- Detect thunks which will reduce immediately to PAPs, and make them--- non-updatable.  This has several advantages:------         - the non-updatable thunk behaves exactly like the PAP,------         - the thunk is more efficient to enter, because it is---           specialised to the task.------         - we save one update frame, one stg_update_PAP, one update---           and lots of PAP_enters.------         - in the case where the thunk is top-level, we save building---           a black hole and furthermore the thunk isn't considered to---           be a CAF any more, so it doesn't appear in any SRTs.------ We do it here, because the arity information is accurate, and we need--- to do it before the SRT pass to save the SRT entries associated with--- any top-level PAPs.--isPAP env (StgApp f args) = listLengthCmp args arity == LT -- idArity f > length args-                              where-                                 arity = stgArity f (lookupBinding env f)-isPAP env _               = False---}--{- ToDo:-          upd = if isOnceDem dem-                    then (if isNotTop toplev-                            then SingleEntry    -- HA!  Paydirt for "dem"-                            else-                     (if debugIsOn then trace "WARNING: SE CAFs unsupported, forcing UPD instead" else id) $-                     Updatable)-                else Updatable-        -- For now we forbid SingleEntry CAFs; they tickle the-        -- ASSERT in rts/Storage.c line 215 at newCAF() re mut_link,-        -- and I don't understand why.  There's only one SE_CAF (well,-        -- only one that tickled a great gaping bug in an earlier attempt-        -- at ClosureInfo.getEntryConvention) in the whole of nofib,-        -- specifically Main.lvl6 in spectral/cryptarithm2.-        -- So no great loss.  KSW 2000-07.--}---- ------------------------------------------------------------------------------ A monad for the core-to-STG pass--- ------------------------------------------------------------------------------- There's a lot of stuff to pass around, so we use this CtsM--- ("core-to-STG monad") monad to help.  All the stuff here is only passed--- *down*.--newtype CtsM a = CtsM-    { unCtsM :: DynFlags -- Needed for checking for bad coercions in coreToStgArgs-             -> IdEnv HowBound-             -> a-    }-    deriving (Functor)--data HowBound-  = ImportBound         -- Used only as a response to lookupBinding; never-                        -- exists in the range of the (IdEnv HowBound)--  | LetBound            -- A let(rec) in this module-        LetInfo         -- Whether top level or nested-        Arity           -- Its arity (local Ids don't have arity info at this point)--  | LambdaBound         -- Used for both lambda and case-  deriving (Eq)--data LetInfo-  = TopLet              -- top level things-  | NestedLet-  deriving (Eq)---- For a let(rec)-bound variable, x, we record LiveInfo, the set of--- variables that are live if x is live.  This LiveInfo comprises---         (a) dynamic live variables (ones with a non-top-level binding)---         (b) static live variabes (CAFs or things that refer to CAFs)------ For "normal" variables (a) is just x alone.  If x is a let-no-escaped--- variable then x is represented by a code pointer and a stack pointer--- (well, one for each stack).  So all of the variables needed in the--- execution of x are live if x is, and are therefore recorded in the--- LetBound constructor; x itself *is* included.------ The set of dynamic live variables is guaranteed ot have no further--- let-no-escaped variables in it.---- The std monad functions:--initCts :: DynFlags -> IdEnv HowBound -> CtsM a -> a-initCts dflags env m = unCtsM m dflags env----{-# INLINE thenCts #-}-{-# INLINE returnCts #-}--returnCts :: a -> CtsM a-returnCts e = CtsM $ \_ _ -> e--thenCts :: CtsM a -> (a -> CtsM b) -> CtsM b-thenCts m k = CtsM $ \dflags env-  -> unCtsM (k (unCtsM m dflags env)) dflags env--instance Applicative CtsM where-    pure = returnCts-    (<*>) = ap--instance Monad CtsM where-    (>>=)  = thenCts--instance HasDynFlags CtsM where-    getDynFlags = CtsM $ \dflags _ -> dflags---- Functions specific to this monad:--extendVarEnvCts :: [(Id, HowBound)] -> CtsM a -> CtsM a-extendVarEnvCts ids_w_howbound expr-   =    CtsM $   \dflags env-   -> unCtsM expr dflags (extendVarEnvList env ids_w_howbound)--lookupVarCts :: Id -> CtsM HowBound-lookupVarCts v = CtsM $ \_ env -> lookupBinding env v--lookupBinding :: IdEnv HowBound -> Id -> HowBound-lookupBinding env v = case lookupVarEnv env v of-                        Just xx -> xx-                        Nothing -> ASSERT2( isGlobalId v, ppr v ) ImportBound--getAllCAFsCC :: Module -> (CostCentre, CostCentreStack)-getAllCAFsCC this_mod =-    let-      span = mkGeneralSrcSpan (mkFastString "<entire-module>") -- XXX do better-      all_cafs_cc  = mkAllCafsCC this_mod span-      all_cafs_ccs = mkSingletonCCS all_cafs_cc-    in-      (all_cafs_cc, all_cafs_ccs)---- Misc.--filterStgBinders :: [Var] -> [Var]-filterStgBinders bndrs = filter isId bndrs--myCollectBinders :: Expr Var -> ([Var], Expr Var)-myCollectBinders expr-  = go [] expr-  where-    go bs (Lam b e)          = go (b:bs) e-    go bs (Cast e _)         = go bs e-    go bs e                  = (reverse bs, e)---- | Precondition: argument expression is an 'App', and there is a 'Var' at the--- head of the 'App' chain.-myCollectArgs :: CoreExpr -> (Id, [CoreArg], [Tickish Id])-myCollectArgs expr-  = go expr [] []-  where-    go (Var v)          as ts = (v, as, ts)-    go (App f a)        as ts = go f (a:as) ts-    go (Tick t e)       as ts = ASSERT( all isTypeArg as )-                                go e as (t:ts) -- ticks can appear in type apps-    go (Cast e _)       as ts = go e as ts-    go (Lam b e)        as ts-       | isTyVar b            = go e as ts -- Note [Collect args]-    go _                _  _  = pprPanic "CoreToStg.myCollectArgs" (ppr expr)---- Note [Collect args]--- ~~~~~~~~~~~~~~~~~~~------ This big-lambda case occurred following a rather obscure eta expansion.--- It all seems a bit yukky to me.--stgArity :: Id -> HowBound -> Arity-stgArity _ (LetBound _ arity) = arity-stgArity f ImportBound        = idArity f-stgArity _ LambdaBound        = 0
− compiler/stgSyn/StgFVs.hs
@@ -1,130 +0,0 @@--- | Free variable analysis on STG terms.-module StgFVs (-    annTopBindingsFreeVars,-    annBindingFreeVars-  ) where--import GhcPrelude--import StgSyn-import Id-import VarSet-import CoreSyn    ( Tickish(Breakpoint) )-import Outputable-import Util--import Data.Maybe ( mapMaybe )--newtype Env-  = Env-  { locals :: IdSet-  }--emptyEnv :: Env-emptyEnv = Env emptyVarSet--addLocals :: [Id] -> Env -> Env-addLocals bndrs env-  = env { locals = extendVarSetList (locals env) bndrs }---- | Annotates a top-level STG binding group with its free variables.-annTopBindingsFreeVars :: [StgTopBinding] -> [CgStgTopBinding]-annTopBindingsFreeVars = map go-  where-    go (StgTopStringLit id bs) = StgTopStringLit id bs-    go (StgTopLifted bind)-      = StgTopLifted (annBindingFreeVars bind)---- | Annotates an STG binding with its free variables.-annBindingFreeVars :: StgBinding -> CgStgBinding-annBindingFreeVars = fst . binding emptyEnv emptyDVarSet--boundIds :: StgBinding -> [Id]-boundIds (StgNonRec b _) = [b]-boundIds (StgRec pairs)  = map fst pairs---- Note [Tracking local binders]--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--- 'locals' contains non-toplevel, non-imported binders.--- We maintain the set in 'expr', 'alt' and 'rhs', which are the only--- places where new local binders are introduced.--- Why do it there rather than in 'binding'? Two reasons:------   1. We call 'binding' from 'annTopBindingsFreeVars', which would---      add top-level bindings to the 'locals' set.---   2. In the let(-no-escape) case, we need to extend the environment---      prior to analysing the body, but we also need the fvs from the---      body to analyse the RHSs. No way to do this without some---      knot-tying.---- | This makes sure that only local, non-global free vars make it into the set.-mkFreeVarSet :: Env -> [Id] -> DIdSet-mkFreeVarSet env = mkDVarSet . filter (`elemVarSet` locals env)--args :: Env -> [StgArg] -> DIdSet-args env = mkFreeVarSet env . mapMaybe f-  where-    f (StgVarArg occ) = Just occ-    f _               = Nothing--binding :: Env -> DIdSet -> StgBinding -> (CgStgBinding, DIdSet)-binding env body_fv (StgNonRec bndr r) = (StgNonRec bndr r', fvs)-  where-    -- See Note [Tracking local binders]-    (r', rhs_fvs) = rhs env r-    fvs = delDVarSet body_fv bndr `unionDVarSet` rhs_fvs-binding env body_fv (StgRec pairs) = (StgRec pairs', fvs)-  where-    -- See Note [Tracking local binders]-    bndrs = map fst pairs-    (rhss, rhs_fvss) = mapAndUnzip (rhs env . snd) pairs-    pairs' = zip bndrs rhss-    fvs = delDVarSetList (unionDVarSets (body_fv:rhs_fvss)) bndrs--expr :: Env -> StgExpr -> (CgStgExpr, DIdSet)-expr env = go-  where-    go (StgApp occ as)-      = (StgApp occ as, unionDVarSet (args env as) (mkFreeVarSet env [occ]))-    go (StgLit lit) = (StgLit lit, emptyDVarSet)-    go (StgConApp dc as tys) = (StgConApp dc as tys, args env as)-    go (StgOpApp op as ty) = (StgOpApp op as ty, args env as)-    go StgLam{} = pprPanic "StgFVs: StgLam" empty-    go (StgCase scrut bndr ty alts) = (StgCase scrut' bndr ty alts', fvs)-      where-        (scrut', scrut_fvs) = go scrut-        -- See Note [Tracking local binders]-        (alts', alt_fvss) = mapAndUnzip (alt (addLocals [bndr] env)) alts-        alt_fvs = unionDVarSets alt_fvss-        fvs = delDVarSet (unionDVarSet scrut_fvs alt_fvs) bndr-    go (StgLet ext bind body) = go_bind (StgLet ext) bind body-    go (StgLetNoEscape ext bind body) = go_bind (StgLetNoEscape ext) bind body-    go (StgTick tick e) = (StgTick tick e', fvs')-      where-        (e', fvs) = go e-        fvs' = unionDVarSet (tickish tick) fvs-        tickish (Breakpoint _ ids) = mkDVarSet ids-        tickish _                  = emptyDVarSet--    go_bind dc bind body = (dc bind' body', fvs)-      where-        -- See Note [Tracking local binders]-        env' = addLocals (boundIds bind) env-        (body', body_fvs) = expr env' body-        (bind', fvs) = binding env' body_fvs bind--rhs :: Env -> StgRhs -> (CgStgRhs, DIdSet)-rhs env (StgRhsClosure _ ccs uf bndrs body)-  = (StgRhsClosure fvs ccs uf bndrs body', fvs)-  where-    -- See Note [Tracking local binders]-    (body', body_fvs) = expr (addLocals bndrs env) body-    fvs = delDVarSetList body_fvs bndrs-rhs env (StgRhsCon ccs dc as) = (StgRhsCon ccs dc as, args env as)--alt :: Env -> StgAlt -> (CgStgAlt, DIdSet)-alt env (con, bndrs, e) = ((con, bndrs, e'), fvs)-  where-    -- See Note [Tracking local binders]-    (e', rhs_fvs) = expr (addLocals bndrs env) e-    fvs = delDVarSetList rhs_fvs bndrs
− compiler/stgSyn/StgLint.hs
@@ -1,396 +0,0 @@-{- |-(c) The GRASP/AQUA Project, Glasgow University, 1993-1998--A lint pass to check basic STG invariants:--- Variables should be defined before used.--- Let bindings should not have unboxed types (unboxed bindings should only-  appear in case), except when they're join points (see Note [CoreSyn let/app-  invariant] and #14117).--- If linting after unarisation, invariants listed in Note [Post-unarisation-  invariants].--Because we don't have types and coercions in STG we can't really check types-here.--Some history:--StgLint used to check types, but it never worked and so it was disabled in 2000-with this note:--    WARNING:-    ~~~~~~~~--    This module has suffered bit-rot; it is likely to yield lint errors-    for Stg code that is currently perfectly acceptable for code-    generation.  Solution: don't use it!  (KSW 2000-05).--Since then there were some attempts at enabling it again, as summarised in-#14787. It's finally decided that we remove all type checking and only look for-basic properties listed above.--}--{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, TypeFamilies,-  DeriveFunctor #-}--module StgLint ( lintStgTopBindings ) where--import GhcPrelude--import StgSyn--import DynFlags-import Bag              ( Bag, emptyBag, isEmptyBag, snocBag, bagToList )-import BasicTypes       ( TopLevelFlag(..), isTopLevel )-import CostCentre       ( isCurrentCCS )-import Id               ( Id, idType, isJoinId, idName )-import VarSet-import DataCon-import CoreSyn          ( AltCon(..) )-import Name             ( getSrcLoc, nameIsLocalOrFrom )-import ErrUtils         ( MsgDoc, Severity(..), mkLocMessage )-import Type-import RepType-import SrcLoc-import Outputable-import Module           ( Module )-import qualified ErrUtils as Err-import Control.Applicative ((<|>))-import Control.Monad--lintStgTopBindings :: forall a . (OutputablePass a, BinderP a ~ Id)-                   => DynFlags-                   -> Module -- ^ module being compiled-                   -> Bool   -- ^ have we run Unarise yet?-                   -> String -- ^ who produced the STG?-                   -> [GenStgTopBinding a]-                   -> IO ()--lintStgTopBindings dflags this_mod unarised whodunnit binds-  = {-# SCC "StgLint" #-}-    case initL this_mod unarised top_level_binds (lint_binds binds) of-      Nothing  ->-        return ()-      Just msg -> do-        putLogMsg dflags NoReason Err.SevDump noSrcSpan-          (defaultDumpStyle dflags)-          (vcat [ text "*** Stg Lint ErrMsgs: in" <+>-                        text whodunnit <+> text "***",-                  msg,-                  text "*** Offending Program ***",-                  pprGenStgTopBindings binds,-                  text "*** End of Offense ***"])-        Err.ghcExit dflags 1-  where-    -- Bring all top-level binds into scope because CoreToStg does not generate-    -- bindings in dependency order (so we may see a use before its definition).-    top_level_binds = mkVarSet (bindersOfTopBinds binds)--    lint_binds :: [GenStgTopBinding a] -> LintM ()--    lint_binds [] = return ()-    lint_binds (bind:binds) = do-        binders <- lint_bind bind-        addInScopeVars binders $-            lint_binds binds--    lint_bind (StgTopLifted bind) = lintStgBinds TopLevel bind-    lint_bind (StgTopStringLit v _) = return [v]--lintStgArg :: StgArg -> LintM ()-lintStgArg (StgLitArg _) = return ()-lintStgArg (StgVarArg v) = lintStgVar v--lintStgVar :: Id -> LintM ()-lintStgVar id = checkInScope id--lintStgBinds-    :: (OutputablePass a, BinderP a ~ Id)-    => TopLevelFlag -> GenStgBinding a -> LintM [Id] -- Returns the binders-lintStgBinds top_lvl (StgNonRec binder rhs) = do-    lint_binds_help top_lvl (binder,rhs)-    return [binder]--lintStgBinds top_lvl (StgRec pairs)-  = addInScopeVars binders $ do-        mapM_ (lint_binds_help top_lvl) pairs-        return binders-  where-    binders = [b | (b,_) <- pairs]--lint_binds_help-    :: (OutputablePass a, BinderP a ~ Id)-    => TopLevelFlag-    -> (Id, GenStgRhs a)-    -> LintM ()-lint_binds_help top_lvl (binder, rhs)-  = addLoc (RhsOf binder) $ do-        when (isTopLevel top_lvl) (checkNoCurrentCCS rhs)-        lintStgRhs rhs-        -- Check binder doesn't have unlifted type or it's a join point-        checkL (isJoinId binder || not (isUnliftedType (idType binder)))-               (mkUnliftedTyMsg binder rhs)---- | Top-level bindings can't inherit the cost centre stack from their--- (static) allocation site.-checkNoCurrentCCS-    :: (OutputablePass a, BinderP a ~ Id)-    => GenStgRhs a-    -> LintM ()-checkNoCurrentCCS rhs@(StgRhsClosure _ ccs _ _ _)-  | isCurrentCCS ccs-  = addErrL (text "Top-level StgRhsClosure with CurrentCCS" $$ ppr rhs)-checkNoCurrentCCS rhs@(StgRhsCon ccs _ _)-  | isCurrentCCS ccs-  = addErrL (text "Top-level StgRhsCon with CurrentCCS" $$ ppr rhs)-checkNoCurrentCCS _-  = return ()--lintStgRhs :: (OutputablePass a, BinderP a ~ Id) => GenStgRhs a -> LintM ()--lintStgRhs (StgRhsClosure _ _ _ [] expr)-  = lintStgExpr expr--lintStgRhs (StgRhsClosure _ _ _ binders expr)-  = addLoc (LambdaBodyOf binders) $-      addInScopeVars binders $-        lintStgExpr expr--lintStgRhs rhs@(StgRhsCon _ con args) = do-    when (isUnboxedTupleCon con || isUnboxedSumCon con) $-      addErrL (text "StgRhsCon is an unboxed tuple or sum application" $$-               ppr rhs)-    mapM_ lintStgArg args-    mapM_ checkPostUnariseConArg args--lintStgExpr :: (OutputablePass a, BinderP a ~ Id) => GenStgExpr a -> LintM ()--lintStgExpr (StgLit _) = return ()--lintStgExpr (StgApp fun args) = do-    lintStgVar fun-    mapM_ lintStgArg args--lintStgExpr app@(StgConApp con args _arg_tys) = do-    -- unboxed sums should vanish during unarise-    lf <- getLintFlags-    when (lf_unarised lf && isUnboxedSumCon con) $-      addErrL (text "Unboxed sum after unarise:" $$-               ppr app)-    mapM_ lintStgArg args-    mapM_ checkPostUnariseConArg args--lintStgExpr (StgOpApp _ args _) =-    mapM_ lintStgArg args--lintStgExpr lam@(StgLam _ _) =-    addErrL (text "Unexpected StgLam" <+> ppr lam)--lintStgExpr (StgLet _ binds body) = do-    binders <- lintStgBinds NotTopLevel binds-    addLoc (BodyOfLetRec binders) $-      addInScopeVars binders $-        lintStgExpr body--lintStgExpr (StgLetNoEscape _ binds body) = do-    binders <- lintStgBinds NotTopLevel binds-    addLoc (BodyOfLetRec binders) $-      addInScopeVars binders $-        lintStgExpr body--lintStgExpr (StgTick _ expr) = lintStgExpr expr--lintStgExpr (StgCase scrut bndr alts_type alts) = do-    lintStgExpr scrut--    lf <- getLintFlags-    let in_scope = stgCaseBndrInScope alts_type (lf_unarised lf)--    addInScopeVars [bndr | in_scope] (mapM_ lintAlt alts)--lintAlt-    :: (OutputablePass a, BinderP a ~ Id)-    => (AltCon, [Id], GenStgExpr a) -> LintM ()--lintAlt (DEFAULT, _, rhs) =-    lintStgExpr rhs--lintAlt (LitAlt _, _, rhs) =-    lintStgExpr rhs--lintAlt (DataAlt _, bndrs, rhs) = do-    mapM_ checkPostUnariseBndr bndrs-    addInScopeVars bndrs (lintStgExpr rhs)--{--************************************************************************-*                                                                      *-Utilities-*                                                                      *-************************************************************************--}--bindersOf :: BinderP a ~ Id => GenStgBinding a -> [Id]-bindersOf (StgNonRec binder _) = [binder]-bindersOf (StgRec pairs)       = [binder | (binder, _) <- pairs]--bindersOfTop :: BinderP a ~ Id => GenStgTopBinding a -> [Id]-bindersOfTop (StgTopLifted bind) = bindersOf bind-bindersOfTop (StgTopStringLit binder _) = [binder]--bindersOfTopBinds :: BinderP a ~ Id => [GenStgTopBinding a] -> [Id]-bindersOfTopBinds = foldr ((++) . bindersOfTop) []--{--************************************************************************-*                                                                      *-The Lint monad-*                                                                      *-************************************************************************--}--newtype LintM a = LintM-    { unLintM :: Module-              -> LintFlags-              -> [LintLocInfo]     -- Locations-              -> IdSet             -- Local vars in scope-              -> Bag MsgDoc        -- Error messages so far-              -> (a, Bag MsgDoc)   -- Result and error messages (if any)-    }-    deriving (Functor)--data LintFlags = LintFlags { lf_unarised :: !Bool-                             -- ^ have we run the unariser yet?-                           }--data LintLocInfo-  = RhsOf Id            -- The variable bound-  | LambdaBodyOf [Id]   -- The lambda-binder-  | BodyOfLetRec [Id]   -- One of the binders--dumpLoc :: LintLocInfo -> (SrcSpan, SDoc)-dumpLoc (RhsOf v) =-  (srcLocSpan (getSrcLoc v), text " [RHS of " <> pp_binders [v] <> char ']' )-dumpLoc (LambdaBodyOf bs) =-  (srcLocSpan (getSrcLoc (head bs)), text " [in body of lambda with binders " <> pp_binders bs <> char ']' )--dumpLoc (BodyOfLetRec bs) =-  (srcLocSpan (getSrcLoc (head bs)), text " [in body of letrec with binders " <> pp_binders bs <> char ']' )---pp_binders :: [Id] -> SDoc-pp_binders bs-  = sep (punctuate comma (map pp_binder bs))-  where-    pp_binder b-      = hsep [ppr b, dcolon, ppr (idType b)]--initL :: Module -> Bool -> IdSet -> LintM a -> Maybe MsgDoc-initL this_mod unarised locals (LintM m) = do-  let (_, errs) = m this_mod (LintFlags unarised) [] locals emptyBag-  if isEmptyBag errs then-      Nothing-  else-      Just (vcat (punctuate blankLine (bagToList errs)))--instance Applicative LintM where-      pure a = LintM $ \_mod _lf _loc _scope errs -> (a, errs)-      (<*>) = ap-      (*>)  = thenL_--instance Monad LintM where-    (>>=) = thenL-    (>>)  = (*>)--thenL :: LintM a -> (a -> LintM b) -> LintM b-thenL m k = LintM $ \mod lf loc scope errs-  -> case unLintM m mod lf loc scope errs of-      (r, errs') -> unLintM (k r) mod lf loc scope errs'--thenL_ :: LintM a -> LintM b -> LintM b-thenL_ m k = LintM $ \mod lf loc scope errs-  -> case unLintM m mod lf loc scope errs of-      (_, errs') -> unLintM k mod lf loc scope errs'--checkL :: Bool -> MsgDoc -> LintM ()-checkL True  _   = return ()-checkL False msg = addErrL msg---- Case alts shouldn't have unboxed sum, unboxed tuple, or void binders.-checkPostUnariseBndr :: Id -> LintM ()-checkPostUnariseBndr bndr = do-    lf <- getLintFlags-    when (lf_unarised lf) $-      forM_ (checkPostUnariseId bndr) $ \unexpected ->-        addErrL $-          text "After unarisation, binder " <>-          ppr bndr <> text " has " <> text unexpected <> text " type " <>-          ppr (idType bndr)---- Arguments shouldn't have sum, tuple, or void types.-checkPostUnariseConArg :: StgArg -> LintM ()-checkPostUnariseConArg arg = case arg of-    StgLitArg _ ->-      return ()-    StgVarArg id -> do-      lf <- getLintFlags-      when (lf_unarised lf) $-        forM_ (checkPostUnariseId id) $ \unexpected ->-          addErrL $-            text "After unarisation, arg " <>-            ppr id <> text " has " <> text unexpected <> text " type " <>-            ppr (idType id)---- Post-unarisation args and case alt binders should not have unboxed tuple,--- unboxed sum, or void types. Return what the binder is if it is one of these.-checkPostUnariseId :: Id -> Maybe String-checkPostUnariseId id =-    let-      id_ty = idType id-      is_sum, is_tuple, is_void :: Maybe String-      is_sum = guard (isUnboxedSumType id_ty) >> return "unboxed sum"-      is_tuple = guard (isUnboxedTupleType id_ty) >> return "unboxed tuple"-      is_void = guard (isVoidTy id_ty) >> return "void"-    in-      is_sum <|> is_tuple <|> is_void--addErrL :: MsgDoc -> LintM ()-addErrL msg = LintM $ \_mod _lf loc _scope errs -> ((), addErr errs msg loc)--addErr :: Bag MsgDoc -> MsgDoc -> [LintLocInfo] -> Bag MsgDoc-addErr errs_so_far msg locs-  = errs_so_far `snocBag` mk_msg locs-  where-    mk_msg (loc:_) = let (l,hdr) = dumpLoc loc-                     in  mkLocMessage SevWarning l (hdr $$ msg)-    mk_msg []      = msg--addLoc :: LintLocInfo -> LintM a -> LintM a-addLoc extra_loc m = LintM $ \mod lf loc scope errs-   -> unLintM m mod lf (extra_loc:loc) scope errs--addInScopeVars :: [Id] -> LintM a -> LintM a-addInScopeVars ids m = LintM $ \mod lf loc scope errs- -> let-        new_set = mkVarSet ids-    in unLintM m mod lf loc (scope `unionVarSet` new_set) errs--getLintFlags :: LintM LintFlags-getLintFlags = LintM $ \_mod lf _loc _scope errs -> (lf, errs)--checkInScope :: Id -> LintM ()-checkInScope id = LintM $ \mod _lf loc scope errs- -> if nameIsLocalOrFrom mod (idName id) && not (id `elemVarSet` scope) then-        ((), addErr errs (hsep [ppr id, dcolon, ppr (idType id),-                                text "is out of scope"]) loc)-    else-        ((), errs)--mkUnliftedTyMsg :: OutputablePass a => Id -> GenStgRhs a -> SDoc-mkUnliftedTyMsg binder rhs-  = (text "Let(rec) binder" <+> quotes (ppr binder) <+>-     text "has unlifted type" <+> quotes (ppr (idType binder)))-    $$-    (text "RHS:" <+> ppr rhs)
− compiler/stgSyn/StgSubst.hs
@@ -1,80 +0,0 @@-{-# LANGUAGE CPP #-}--module StgSubst where--#include "HsVersions.h"--import GhcPrelude--import Id-import VarEnv-import Control.Monad.Trans.State.Strict-import Outputable-import Util---- | A renaming substitution from 'Id's to 'Id's. Like 'RnEnv2', but not--- maintaining pairs of substitutions. Like @"CoreSubst".'CoreSubst.Subst'@, but--- with the domain being 'Id's instead of entire 'CoreExpr'.-data Subst = Subst InScopeSet IdSubstEnv--type IdSubstEnv = IdEnv Id---- | @emptySubst = 'mkEmptySubst' 'emptyInScopeSet'@-emptySubst :: Subst-emptySubst = mkEmptySubst emptyInScopeSet---- | Constructs a new 'Subst' assuming the variables in the given 'InScopeSet'--- are in scope.-mkEmptySubst :: InScopeSet -> Subst-mkEmptySubst in_scope = Subst in_scope emptyVarEnv---- | Substitutes an 'Id' for another one according to the 'Subst' given in a way--- that avoids shadowing the 'InScopeSet', returning the result and an updated--- 'Subst' that should be used by subsequent substitutions.-substBndr :: Id -> Subst -> (Id, Subst)-substBndr id (Subst in_scope env)-  = (new_id, Subst new_in_scope new_env)-  where-    new_id = uniqAway in_scope id-    no_change = new_id == id -- in case nothing shadowed-    new_in_scope = in_scope `extendInScopeSet` new_id-    new_env-      | no_change = delVarEnv env id-      | otherwise = extendVarEnv env id new_id---- | @substBndrs = runState . traverse (state . substBndr)@-substBndrs :: Traversable f => f Id -> Subst -> (f Id, Subst)-substBndrs = runState . traverse (state . substBndr)---- | Substitutes an occurrence of an identifier for its counterpart recorded--- in the 'Subst'.-lookupIdSubst :: HasCallStack => Id -> Subst -> Id-lookupIdSubst id (Subst in_scope env)-  | not (isLocalId id) = id-  | Just id' <- lookupVarEnv env id = id'-  | Just id' <- lookupInScope in_scope id = id'-  | otherwise = WARN( True, text "StgSubst.lookupIdSubst" <+> ppr id $$ ppr in_scope)-                id---- | Substitutes an occurrence of an identifier for its counterpart recorded--- in the 'Subst'. Does not generate a debug warning if the identifier to--- to substitute wasn't in scope.-noWarnLookupIdSubst :: HasCallStack => Id -> Subst -> Id-noWarnLookupIdSubst id (Subst in_scope env)-  | not (isLocalId id) = id-  | Just id' <- lookupVarEnv env id = id'-  | Just id' <- lookupInScope in_scope id = id'-  | otherwise = id---- | Add the 'Id' to the in-scope set and remove any existing substitutions for--- it.-extendInScope :: Id -> Subst -> Subst-extendInScope id (Subst in_scope env) = Subst (in_scope `extendInScopeSet` id) env---- | Add a substitution for an 'Id' to the 'Subst': you must ensure that the--- in-scope set is such that TyCoSubst Note [The substitution invariant]--- holds after extending the substitution like this.-extendSubst :: Id -> Id -> Subst -> Subst-extendSubst id new_id (Subst in_scope env)-  = ASSERT2( new_id `elemInScopeSet` in_scope, ppr id <+> ppr new_id $$ ppr in_scope )-    Subst in_scope (extendVarEnv env id new_id)
− compiler/stgSyn/StgSyn.hs
@@ -1,871 +0,0 @@-{--(c) The GRASP/AQUA Project, Glasgow University, 1992-1998--Shared term graph (STG) syntax for spineless-tagless code generation-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--This data type represents programs just before code generation (conversion to-@Cmm@): basically, what we have is a stylised form of @CoreSyntax@, the style-being one that happens to be ideally suited to spineless tagless code-generation.--}--{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ConstraintKinds #-}--module StgSyn (-        StgArg(..),--        GenStgTopBinding(..), GenStgBinding(..), GenStgExpr(..), GenStgRhs(..),-        GenStgAlt, AltType(..),--        StgPass(..), BinderP, XRhsClosure, XLet, XLetNoEscape,-        NoExtFieldSilent, noExtFieldSilent,-        OutputablePass,--        UpdateFlag(..), isUpdatable,--        -- a set of synonyms for the vanilla parameterisation-        StgTopBinding, StgBinding, StgExpr, StgRhs, StgAlt,--        -- a set of synonyms for the code gen parameterisation-        CgStgTopBinding, CgStgBinding, CgStgExpr, CgStgRhs, CgStgAlt,--        -- a set of synonyms for the lambda lifting parameterisation-        LlStgTopBinding, LlStgBinding, LlStgExpr, LlStgRhs, LlStgAlt,--        -- a set of synonyms to distinguish in- and out variants-        InStgArg,  InStgTopBinding,  InStgBinding,  InStgExpr,  InStgRhs,  InStgAlt,-        OutStgArg, OutStgTopBinding, OutStgBinding, OutStgExpr, OutStgRhs, OutStgAlt,--        -- StgOp-        StgOp(..),--        -- utils-        topStgBindHasCafRefs, stgArgHasCafRefs, stgRhsArity,-        isDllConApp,-        stgArgType,-        stripStgTicksTop, stripStgTicksTopE,-        stgCaseBndrInScope,--        pprStgBinding, pprGenStgTopBindings, pprStgTopBindings-    ) where--#include "HsVersions.h"--import GhcPrelude--import CoreSyn     ( AltCon, Tickish )-import CostCentre  ( CostCentreStack )-import Data.ByteString ( ByteString )-import Data.Data   ( Data )-import Data.List   ( intersperse )-import DataCon-import DynFlags-import ForeignCall ( ForeignCall )-import Id-import IdInfo      ( mayHaveCafRefs )-import VarSet-import Literal     ( Literal, literalType )-import Module      ( Module )-import Outputable-import Packages    ( isDllName )-import GHC.Platform-import PprCore     ( {- instances -} )-import PrimOp      ( PrimOp, PrimCall )-import TyCon       ( PrimRep(..), TyCon )-import Type        ( Type )-import RepType     ( typePrimRep1 )-import Util--import Data.List.NonEmpty ( NonEmpty, toList )--{--************************************************************************-*                                                                      *-GenStgBinding-*                                                                      *-************************************************************************--As usual, expressions are interesting; other things are boring. Here are the-boring things (except note the @GenStgRhs@), parameterised with respect to-binder and occurrence information (just as in @CoreSyn@):--}---- | A top-level binding.-data GenStgTopBinding pass--- See Note [CoreSyn top-level string literals]-  = StgTopLifted (GenStgBinding pass)-  | StgTopStringLit Id ByteString--data GenStgBinding pass-  = StgNonRec (BinderP pass) (GenStgRhs pass)-  | StgRec    [(BinderP pass, GenStgRhs pass)]--{--************************************************************************-*                                                                      *-StgArg-*                                                                      *-************************************************************************--}--data StgArg-  = StgVarArg  Id-  | StgLitArg  Literal---- | Does this constructor application refer to anything in a different--- *Windows* DLL?--- If so, we can't allocate it statically-isDllConApp :: DynFlags -> Module -> DataCon -> [StgArg] -> Bool-isDllConApp dflags this_mod con args- | platformOS (targetPlatform dflags) == OSMinGW32-    = isDllName dflags this_mod (dataConName con) || any is_dll_arg args- | otherwise = False-  where-    -- NB: typePrimRep1 is legit because any free variables won't have-    -- unlifted type (there are no unlifted things at top level)-    is_dll_arg :: StgArg -> Bool-    is_dll_arg (StgVarArg v) =  isAddrRep (typePrimRep1 (idType v))-                             && isDllName dflags this_mod (idName v)-    is_dll_arg _             = False---- True of machine addresses; these are the things that don't work across DLLs.--- The key point here is that VoidRep comes out False, so that a top level--- nullary GADT constructor is False for isDllConApp------    data T a where---      T1 :: T Int------ gives------    T1 :: forall a. (a~Int) -> T a------ and hence the top-level binding------    $WT1 :: T Int---    $WT1 = T1 Int (Coercion (Refl Int))------ The coercion argument here gets VoidRep-isAddrRep :: PrimRep -> Bool-isAddrRep AddrRep     = True-isAddrRep LiftedRep   = True-isAddrRep UnliftedRep = True-isAddrRep _           = False---- | Type of an @StgArg@------ Very half baked because we have lost the type arguments.-stgArgType :: StgArg -> Type-stgArgType (StgVarArg v)   = idType v-stgArgType (StgLitArg lit) = literalType lit----- | Strip ticks of a given type from an STG expression.-stripStgTicksTop :: (Tickish Id -> Bool) -> GenStgExpr p -> ([Tickish Id], GenStgExpr p)-stripStgTicksTop p = go []-   where go ts (StgTick t e) | p t = go (t:ts) e-         go ts other               = (reverse ts, other)---- | Strip ticks of a given type from an STG expression returning only the expression.-stripStgTicksTopE :: (Tickish Id -> Bool) -> GenStgExpr p -> GenStgExpr p-stripStgTicksTopE p = go-   where go (StgTick t e) | p t = go e-         go other               = other---- | Given an alt type and whether the program is unarised, return whether the--- case binder is in scope.------ Case binders of unboxed tuple or unboxed sum type always dead after the--- unariser has run. See Note [Post-unarisation invariants].-stgCaseBndrInScope :: AltType -> Bool {- ^ unarised? -} -> Bool-stgCaseBndrInScope alt_ty unarised =-    case alt_ty of-      AlgAlt _      -> True-      PrimAlt _     -> True-      MultiValAlt _ -> not unarised-      PolyAlt       -> True--{--************************************************************************-*                                                                      *-STG expressions-*                                                                      *-************************************************************************--The @GenStgExpr@ data type is parameterised on binder and occurrence info, as-before.--************************************************************************-*                                                                      *-GenStgExpr-*                                                                      *-************************************************************************--An application is of a function to a list of atoms (not expressions).-Operationally, we want to push the arguments on the stack and call the function.-(If the arguments were expressions, we would have to build their closures-first.)--There is no constructor for a lone variable; it would appear as @StgApp var []@.--}--data GenStgExpr pass-  = StgApp-        Id       -- function-        [StgArg] -- arguments; may be empty--{--************************************************************************-*                                                                      *-StgConApp and StgPrimApp --- saturated applications-*                                                                      *-************************************************************************--There are specialised forms of application, for constructors, primitives, and-literals.--}--  | StgLit      Literal--        -- StgConApp is vital for returning unboxed tuples or sums-        -- which can't be let-bound-  | StgConApp   DataCon-                [StgArg] -- Saturated-                [Type]   -- See Note [Types in StgConApp] in UnariseStg--  | StgOpApp    StgOp    -- Primitive op or foreign call-                [StgArg] -- Saturated.-                Type     -- Result type-                         -- We need to know this so that we can-                         -- assign result registers--{--************************************************************************-*                                                                      *-StgLam-*                                                                      *-************************************************************************--StgLam is used *only* during CoreToStg's work. Before CoreToStg has finished it-encodes (\x -> e) as (let f = \x -> e in f) TODO: Encode this via an extension-to GenStgExpr à la TTG.--}--  | StgLam-        (NonEmpty (BinderP pass))-        StgExpr    -- Body of lambda--{--************************************************************************-*                                                                      *-GenStgExpr: case-expressions-*                                                                      *-************************************************************************--This has the same boxed/unboxed business as Core case expressions.--}--  | StgCase-        (GenStgExpr pass) -- the thing to examine-        (BinderP pass) -- binds the result of evaluating the scrutinee-        AltType-        [GenStgAlt pass]-                    -- The DEFAULT case is always *first*-                    -- if it is there at all--{--************************************************************************-*                                                                      *-GenStgExpr: let(rec)-expressions-*                                                                      *-************************************************************************--The various forms of let(rec)-expression encode most of the interesting things-we want to do.---   let-closure x = [free-vars] [args] expr in e--  is equivalent to--    let x = (\free-vars -> \args -> expr) free-vars--  @args@ may be empty (and is for most closures). It isn't under circumstances-  like this:--    let x = (\y -> y+z)--  This gets mangled to--    let-closure x = [z] [y] (y+z)--  The idea is that we compile code for @(y+z)@ in an environment in which @z@ is-  bound to an offset from Node, and `y` is bound to an offset from the stack-  pointer.--  (A let-closure is an @StgLet@ with a @StgRhsClosure@ RHS.)---   let-constructor x = Constructor [args] in e--  (A let-constructor is an @StgLet@ with a @StgRhsCon@ RHS.)--- Letrec-expressions are essentially the same deal as let-closure/-  let-constructor, so we use a common structure and distinguish between them-  with an @is_recursive@ boolean flag.---   let-unboxed u = <an arbitrary arithmetic expression in unboxed values> in e--  All the stuff on the RHS must be fully evaluated. No function calls either!--  (We've backed away from this toward case-expressions with suitably-magical-  alts ...)--- Advanced stuff here! Not to start with, but makes pattern matching generate-  more efficient code.--    let-escapes-not fail = expr-    in e'--  Here the idea is that @e'@ guarantees not to put @fail@ in a data structure,-  or pass it to another function. All @e'@ will ever do is tail-call @fail@.-  Rather than build a closure for @fail@, all we need do is to record the stack-  level at the moment of the @let-escapes-not@; then entering @fail@ is just a-  matter of adjusting the stack pointer back down to that point and entering the-  code for it.--  Another example:--    f x y = let z = huge-expression in-            if y==1 then z else-            if y==2 then z else-            1--  (A let-escapes-not is an @StgLetNoEscape@.)--- We may eventually want:--    let-literal x = Literal in e--And so the code for let(rec)-things:--}--  | StgLet-        (XLet pass)-        (GenStgBinding pass)    -- right hand sides (see below)-        (GenStgExpr pass)       -- body--  | StgLetNoEscape-        (XLetNoEscape pass)-        (GenStgBinding pass)    -- right hand sides (see below)-        (GenStgExpr pass)       -- body--{--*************************************************************************-*                                                                      *-GenStgExpr: hpc, scc and other debug annotations-*                                                                      *-*************************************************************************--Finally for @hpc@ expressions we introduce a new STG construct.--}--  | StgTick-    (Tickish Id)-    (GenStgExpr pass)       -- sub expression---- END of GenStgExpr--{--************************************************************************-*                                                                      *-STG right-hand sides-*                                                                      *-************************************************************************--Here's the rest of the interesting stuff for @StgLet@s; the first flavour is for-closures:--}--data GenStgRhs pass-  = StgRhsClosure-        (XRhsClosure pass) -- ^ Extension point for non-global free var-                           --   list just before 'CodeGen'.-        CostCentreStack    -- ^ CCS to be attached (default is CurrentCCS)-        !UpdateFlag        -- ^ 'ReEntrant' | 'Updatable' | 'SingleEntry'-        [BinderP pass]     -- ^ arguments; if empty, then not a function;-                           --   as above, order is important.-        (GenStgExpr pass)  -- ^ body--{--An example may be in order.  Consider:--  let t = \x -> \y -> ... x ... y ... p ... q in e--Pulling out the free vars and stylising somewhat, we get the equivalent:--  let t = (\[p,q] -> \[x,y] -> ... x ... y ... p ...q) p q--Stg-operationally, the @[x,y]@ are on the stack, the @[p,q]@ are offsets from-@Node@ into the closure, and the code ptr for the closure will be exactly that-in parentheses above.--The second flavour of right-hand-side is for constructors (simple but-important):--}--  | StgRhsCon-        CostCentreStack -- CCS to be attached (default is CurrentCCS).-                        -- Top-level (static) ones will end up with-                        -- DontCareCCS, because we don't count static-                        -- data in heap profiles, and we don't set CCCS-                        -- from static closure.-        DataCon         -- Constructor. Never an unboxed tuple or sum, as those-                        -- are not allocated.-        [StgArg]        -- Args---- | Used as a data type index for the stgSyn AST-data StgPass-  = Vanilla-  | LiftLams-  | CodeGen---- | Like 'GHC.Hs.Extension.NoExtField', but with an 'Outputable' instance that--- returns 'empty'.-data NoExtFieldSilent = NoExtFieldSilent-  deriving (Data, Eq, Ord)--instance Outputable NoExtFieldSilent where-  ppr _ = empty---- | Used when constructing a term with an unused extension point that should--- not appear in pretty-printed output at all.-noExtFieldSilent :: NoExtFieldSilent-noExtFieldSilent = NoExtFieldSilent--- TODO: Maybe move this to GHC.Hs.Extension? I'm not sure about the--- implications on build time...---- TODO: Do we really want to the extension point type families to have a closed--- domain?-type family BinderP (pass :: StgPass)-type instance BinderP 'Vanilla = Id-type instance BinderP 'CodeGen = Id--type family XRhsClosure (pass :: StgPass)-type instance XRhsClosure 'Vanilla = NoExtFieldSilent--- | Code gen needs to track non-global free vars-type instance XRhsClosure 'CodeGen = DIdSet--type family XLet (pass :: StgPass)-type instance XLet 'Vanilla = NoExtFieldSilent-type instance XLet 'CodeGen = NoExtFieldSilent--type family XLetNoEscape (pass :: StgPass)-type instance XLetNoEscape 'Vanilla = NoExtFieldSilent-type instance XLetNoEscape 'CodeGen = NoExtFieldSilent--stgRhsArity :: StgRhs -> Int-stgRhsArity (StgRhsClosure _ _ _ bndrs _)-  = ASSERT( all isId bndrs ) length bndrs-  -- The arity never includes type parameters, but they should have gone by now-stgRhsArity (StgRhsCon _ _ _) = 0---- Note [CAF consistency]--- ~~~~~~~~~~~~~~~~~~~~~~------ `topStgBindHasCafRefs` is only used by an assert (`consistentCafInfo` in--- `CoreToStg`) to make sure CAF-ness predicted by `TidyPgm` is consistent with--- reality.------ Specifically, if the RHS mentions any Id that itself is marked--- `MayHaveCafRefs`; or if the binding is a top-level updateable thunk; then the--- `Id` for the binding should be marked `MayHaveCafRefs`. The potential trouble--- is that `TidyPgm` computed the CAF info on the `Id` but some transformations--- have taken place since then.--topStgBindHasCafRefs :: GenStgTopBinding pass -> Bool-topStgBindHasCafRefs (StgTopLifted (StgNonRec _ rhs))-  = topRhsHasCafRefs rhs-topStgBindHasCafRefs (StgTopLifted (StgRec binds))-  = any topRhsHasCafRefs (map snd binds)-topStgBindHasCafRefs StgTopStringLit{}-  = False--topRhsHasCafRefs :: GenStgRhs pass -> Bool-topRhsHasCafRefs (StgRhsClosure _ _ upd _ body)-  = -- See Note [CAF consistency]-    isUpdatable upd || exprHasCafRefs body-topRhsHasCafRefs (StgRhsCon _ _ args)-  = any stgArgHasCafRefs args--exprHasCafRefs :: GenStgExpr pass -> Bool-exprHasCafRefs (StgApp f args)-  = stgIdHasCafRefs f || any stgArgHasCafRefs args-exprHasCafRefs StgLit{}-  = False-exprHasCafRefs (StgConApp _ args _)-  = any stgArgHasCafRefs args-exprHasCafRefs (StgOpApp _ args _)-  = any stgArgHasCafRefs args-exprHasCafRefs (StgLam _ body)-  = exprHasCafRefs body-exprHasCafRefs (StgCase scrt _ _ alts)-  = exprHasCafRefs scrt || any altHasCafRefs alts-exprHasCafRefs (StgLet _ bind body)-  = bindHasCafRefs bind || exprHasCafRefs body-exprHasCafRefs (StgLetNoEscape _ bind body)-  = bindHasCafRefs bind || exprHasCafRefs body-exprHasCafRefs (StgTick _ expr)-  = exprHasCafRefs expr--bindHasCafRefs :: GenStgBinding pass -> Bool-bindHasCafRefs (StgNonRec _ rhs)-  = rhsHasCafRefs rhs-bindHasCafRefs (StgRec binds)-  = any rhsHasCafRefs (map snd binds)--rhsHasCafRefs :: GenStgRhs pass -> Bool-rhsHasCafRefs (StgRhsClosure _ _ _ _ body)-  = exprHasCafRefs body-rhsHasCafRefs (StgRhsCon _ _ args)-  = any stgArgHasCafRefs args--altHasCafRefs :: GenStgAlt pass -> Bool-altHasCafRefs (_, _, rhs) = exprHasCafRefs rhs--stgArgHasCafRefs :: StgArg -> Bool-stgArgHasCafRefs (StgVarArg id)-  = stgIdHasCafRefs id-stgArgHasCafRefs _-  = False--stgIdHasCafRefs :: Id -> Bool-stgIdHasCafRefs id =-  -- We are looking for occurrences of an Id that is bound at top level, and may-  -- have CAF refs. At this point (after TidyPgm) top-level Ids (whether-  -- imported or defined in this module) are GlobalIds, so the test is easy.-  isGlobalId id && mayHaveCafRefs (idCafInfo id)--{--************************************************************************-*                                                                      *-STG case alternatives-*                                                                      *-************************************************************************--Very like in @CoreSyntax@ (except no type-world stuff).--The type constructor is guaranteed not to be abstract; that is, we can see its-representation. This is important because the code generator uses it to-determine return conventions etc. But it's not trivial where there's a module-loop involved, because some versions of a type constructor might not have all-the constructors visible. So mkStgAlgAlts (in CoreToStg) ensures that it gets-the TyCon from the constructors or literals (which are guaranteed to have the-Real McCoy) rather than from the scrutinee type.--}--type GenStgAlt pass-  = (AltCon,          -- alts: data constructor,-     [BinderP pass],  -- constructor's parameters,-     GenStgExpr pass) -- ...right-hand side.--data AltType-  = PolyAlt             -- Polymorphic (a lifted type variable)-  | MultiValAlt Int     -- Multi value of this arity (unboxed tuple or sum)-                        -- the arity could indeed be 1 for unary unboxed tuple-                        -- or enum-like unboxed sums-  | AlgAlt      TyCon   -- Algebraic data type; the AltCons will be DataAlts-  | PrimAlt     PrimRep -- Primitive data type; the AltCons (if any) will be LitAlts--{--************************************************************************-*                                                                      *-The Plain STG parameterisation-*                                                                      *-************************************************************************--This happens to be the only one we use at the moment.--}--type StgTopBinding = GenStgTopBinding 'Vanilla-type StgBinding    = GenStgBinding    'Vanilla-type StgExpr       = GenStgExpr       'Vanilla-type StgRhs        = GenStgRhs        'Vanilla-type StgAlt        = GenStgAlt        'Vanilla--type LlStgTopBinding = GenStgTopBinding 'LiftLams-type LlStgBinding    = GenStgBinding    'LiftLams-type LlStgExpr       = GenStgExpr       'LiftLams-type LlStgRhs        = GenStgRhs        'LiftLams-type LlStgAlt        = GenStgAlt        'LiftLams--type CgStgTopBinding = GenStgTopBinding 'CodeGen-type CgStgBinding    = GenStgBinding    'CodeGen-type CgStgExpr       = GenStgExpr       'CodeGen-type CgStgRhs        = GenStgRhs        'CodeGen-type CgStgAlt        = GenStgAlt        'CodeGen--{- Many passes apply a substitution, and it's very handy to have type-   synonyms to remind us whether or not the substitution has been applied.-   See CoreSyn for precedence in Core land--}--type InStgTopBinding  = StgTopBinding-type InStgBinding     = StgBinding-type InStgArg         = StgArg-type InStgExpr        = StgExpr-type InStgRhs         = StgRhs-type InStgAlt         = StgAlt-type OutStgTopBinding = StgTopBinding-type OutStgBinding    = StgBinding-type OutStgArg        = StgArg-type OutStgExpr       = StgExpr-type OutStgRhs        = StgRhs-type OutStgAlt        = StgAlt--{---************************************************************************-*                                                                      *-UpdateFlag-*                                                                      *-************************************************************************--This is also used in @LambdaFormInfo@ in the @ClosureInfo@ module.--A @ReEntrant@ closure may be entered multiple times, but should not be updated-or blackholed. An @Updatable@ closure should be updated after evaluation (and-may be blackholed during evaluation). A @SingleEntry@ closure will only be-entered once, and so need not be updated but may safely be blackholed.--}--data UpdateFlag = ReEntrant | Updatable | SingleEntry--instance Outputable UpdateFlag where-    ppr u = char $ case u of-                       ReEntrant   -> 'r'-                       Updatable   -> 'u'-                       SingleEntry -> 's'--isUpdatable :: UpdateFlag -> Bool-isUpdatable ReEntrant   = False-isUpdatable SingleEntry = False-isUpdatable Updatable   = True--{--************************************************************************-*                                                                      *-StgOp-*                                                                      *-************************************************************************--An StgOp allows us to group together PrimOps and ForeignCalls. It's quite useful-to move these around together, notably in StgOpApp and COpStmt.--}--data StgOp-  = StgPrimOp  PrimOp--  | StgPrimCallOp PrimCall--  | StgFCallOp ForeignCall Type-        -- The Type, which is obtained from the foreign import declaration-        -- itself, is needed by the stg-to-cmm pass to determine the offset to-        -- apply to unlifted boxed arguments in GHC.StgToCmm.Foreign. See Note-        -- [Unlifted boxed arguments to foreign calls]--{--************************************************************************-*                                                                      *-Pretty-printing-*                                                                      *-************************************************************************--Robin Popplestone asked for semi-colon separators on STG binds; here's hoping he-likes terminators instead...  Ditto for case alternatives.--}--type OutputablePass pass =-  ( Outputable (XLet pass)-  , Outputable (XLetNoEscape pass)-  , Outputable (XRhsClosure pass)-  , OutputableBndr (BinderP pass)-  )--pprGenStgTopBinding-  :: OutputablePass pass => GenStgTopBinding pass -> SDoc-pprGenStgTopBinding (StgTopStringLit bndr str)-  = hang (hsep [pprBndr LetBind bndr, equals])-        4 (pprHsBytes str <> semi)-pprGenStgTopBinding (StgTopLifted bind)-  = pprGenStgBinding bind--pprGenStgBinding-  :: OutputablePass pass => GenStgBinding pass -> SDoc--pprGenStgBinding (StgNonRec bndr rhs)-  = hang (hsep [pprBndr LetBind bndr, equals])-        4 (ppr rhs <> semi)--pprGenStgBinding (StgRec pairs)-  = vcat [ text "Rec {"-         , vcat (intersperse blankLine (map ppr_bind pairs))-         , text "end Rec }" ]-  where-    ppr_bind (bndr, expr)-      = hang (hsep [pprBndr LetBind bndr, equals])-             4 (ppr expr <> semi)--pprGenStgTopBindings-  :: (OutputablePass pass) => [GenStgTopBinding pass] -> SDoc-pprGenStgTopBindings binds-  = vcat $ intersperse blankLine (map pprGenStgTopBinding binds)--pprStgBinding :: StgBinding -> SDoc-pprStgBinding = pprGenStgBinding--pprStgTopBindings :: [StgTopBinding] -> SDoc-pprStgTopBindings = pprGenStgTopBindings--instance Outputable StgArg where-    ppr = pprStgArg--instance OutputablePass pass => Outputable (GenStgTopBinding pass) where-    ppr = pprGenStgTopBinding--instance OutputablePass pass => Outputable (GenStgBinding pass) where-    ppr = pprGenStgBinding--instance OutputablePass pass => Outputable (GenStgExpr pass) where-    ppr = pprStgExpr--instance OutputablePass pass => Outputable (GenStgRhs pass) where-    ppr rhs = pprStgRhs rhs--pprStgArg :: StgArg -> SDoc-pprStgArg (StgVarArg var) = ppr var-pprStgArg (StgLitArg con) = ppr con--pprStgExpr :: OutputablePass pass => GenStgExpr pass -> SDoc--- special case-pprStgExpr (StgLit lit)     = ppr lit---- general case-pprStgExpr (StgApp func args)-  = hang (ppr func) 4 (sep (map (ppr) args))--pprStgExpr (StgConApp con args _)-  = hsep [ ppr con, brackets (interppSP args) ]--pprStgExpr (StgOpApp op args _)-  = hsep [ pprStgOp op, brackets (interppSP args)]--pprStgExpr (StgLam bndrs body)-  = sep [ char '\\' <+> ppr_list (map (pprBndr LambdaBind) (toList bndrs))-            <+> text "->",-         pprStgExpr body ]-  where ppr_list = brackets . fsep . punctuate comma---- special case: let v = <very specific thing>---               in---               let ...---               in---               ...------ Very special!  Suspicious! (SLPJ)--{--pprStgExpr (StgLet srt (StgNonRec bndr (StgRhsClosure cc bi free_vars upd_flag args rhs))-                        expr@(StgLet _ _))-  = ($$)-      (hang (hcat [text "let { ", ppr bndr, ptext (sLit " = "),-                          ppr cc,-                          pp_binder_info bi,-                          text " [", whenPprDebug (interppSP free_vars), ptext (sLit "] \\"),-                          ppr upd_flag, text " [",-                          interppSP args, char ']'])-            8 (sep [hsep [ppr rhs, text "} in"]]))-      (ppr expr)--}---- special case: let ... in let ...--pprStgExpr (StgLet ext bind expr@StgLet{})-  = ($$)-      (sep [hang (text "let" <+> ppr ext <+> text "{")-                2 (hsep [pprGenStgBinding bind, text "} in"])])-      (ppr expr)---- general case-pprStgExpr (StgLet ext bind expr)-  = sep [hang (text "let" <+> ppr ext <+> text "{") 2 (pprGenStgBinding bind),-           hang (text "} in ") 2 (ppr expr)]--pprStgExpr (StgLetNoEscape ext bind expr)-  = sep [hang (text "let-no-escape" <+> ppr ext <+> text "{")-                2 (pprGenStgBinding bind),-           hang (text "} in ")-                2 (ppr expr)]--pprStgExpr (StgTick tickish expr)-  = sdocWithDynFlags $ \dflags ->-    if gopt Opt_SuppressTicks dflags-    then pprStgExpr expr-    else sep [ ppr tickish, pprStgExpr expr ]----- Don't indent for a single case alternative.-pprStgExpr (StgCase expr bndr alt_type [alt])-  = sep [sep [text "case",-           nest 4 (hsep [pprStgExpr expr,-             whenPprDebug (dcolon <+> ppr alt_type)]),-           text "of", pprBndr CaseBind bndr, char '{'],-           pprStgAlt False alt,-           char '}']--pprStgExpr (StgCase expr bndr alt_type alts)-  = sep [sep [text "case",-           nest 4 (hsep [pprStgExpr expr,-             whenPprDebug (dcolon <+> ppr alt_type)]),-           text "of", pprBndr CaseBind bndr, char '{'],-           nest 2 (vcat (map (pprStgAlt True) alts)),-           char '}']---pprStgAlt :: OutputablePass pass => Bool -> GenStgAlt pass -> SDoc-pprStgAlt indent (con, params, expr)-  | indent    = hang altPattern 4 (ppr expr <> semi)-  | otherwise = sep [altPattern, ppr expr <> semi]-    where-      altPattern = (hsep [ppr con, sep (map (pprBndr CasePatBind) params), text "->"])---pprStgOp :: StgOp -> SDoc-pprStgOp (StgPrimOp  op)   = ppr op-pprStgOp (StgPrimCallOp op)= ppr op-pprStgOp (StgFCallOp op _) = ppr op--instance Outputable AltType where-  ppr PolyAlt         = text "Polymorphic"-  ppr (MultiValAlt n) = text "MultiAlt" <+> ppr n-  ppr (AlgAlt tc)     = text "Alg"    <+> ppr tc-  ppr (PrimAlt tc)    = text "Prim"   <+> ppr tc--pprStgRhs :: OutputablePass pass => GenStgRhs pass -> SDoc--pprStgRhs (StgRhsClosure ext cc upd_flag args body)-  = sdocWithDynFlags $ \dflags ->-    hang (hsep [if gopt Opt_SccProfilingOn dflags then ppr cc else empty,-                if not $ gopt Opt_SuppressStgExts dflags-                  then ppr ext else empty,-                char '\\' <> ppr upd_flag, brackets (interppSP args)])-         4 (ppr body)--pprStgRhs (StgRhsCon cc con args)-  = hcat [ ppr cc,-           space, ppr con, text "! ", brackets (interppSP args)]
compiler/stranal/DmdAnal.hs view
@@ -35,7 +35,7 @@ import Maybes           ( isJust ) import TysWiredIn import TysPrim          ( realWorldStatePrimTy )-import ErrUtils         ( dumpIfSet_dyn )+import ErrUtils         ( dumpIfSet_dyn, DumpFormat (..) ) import Name             ( getName, stableNameCmp ) import Data.Function    ( on ) import UniqSet@@ -53,8 +53,8 @@   = do {         let { binds_plus_dmds = do_prog binds } ;         dumpIfSet_dyn dflags Opt_D_dump_str_signatures-                      "Strictness signatures" $-            dumpStrSig binds_plus_dmds ;+            "Strictness signatures" FormatSTG+            (dumpStrSig binds_plus_dmds) ;         -- See Note [Stamp out space leaks in demand analysis]         seqBinds binds_plus_dmds `seq` return binds_plus_dmds     }
compiler/stranal/WwLib.hs view
@@ -31,7 +31,7 @@ import VarSet           ( VarSet ) import Type import Predicate        ( isClassPred )-import RepType          ( isVoidTy, typePrimRep )+import GHC.Types.RepType          ( isVoidTy, typePrimRep ) import Coercion import FamInstEnv import BasicTypes       ( Boxity(..) )
compiler/typecheck/TcBinds.hs view
@@ -919,7 +919,7 @@          -- do this check; otherwise (#14000) we may report an ambiguity          -- error for a rather bogus type. -       ; return (mkLocalIdOrCoVar poly_name inferred_poly_ty) }+       ; return (mkLocalId poly_name inferred_poly_ty) }   chooseInferredQuantifiers :: TcThetaType   -- inferred
compiler/typecheck/TcClassDcl.hs view
@@ -13,7 +13,7 @@                     findMethodBind, instantiateMethod,                     tcClassMinimalDef,                     HsSigFun, mkHsSigFun,-                    tcMkDeclCtxt, tcAddDeclCtxt, badMethodErr,+                    badMethodErr,                     instDeclCtxt1, instDeclCtxt2, instDeclCtxt3,                     tcATDefault                   ) where@@ -422,14 +422,6 @@ *                                                                      * ************************************************************************ -}--tcMkDeclCtxt :: TyClDecl GhcRn -> SDoc-tcMkDeclCtxt decl = hsep [text "In the", pprTyClDeclFlavour decl,-                      text "declaration for", quotes (ppr (tcdName decl))]--tcAddDeclCtxt :: TyClDecl GhcRn -> TcM a -> TcM a-tcAddDeclCtxt decl thing_inside-  = addErrCtxt (tcMkDeclCtxt decl) thing_inside  badMethodErr :: Outputable a => a -> Name -> SDoc badMethodErr clas op
compiler/typecheck/TcDeriv.hs view
@@ -235,6 +235,7 @@          ; unless (isEmptyBag inst_info) $              liftIO (dumpIfSet_dyn dflags Opt_D_dump_deriv "Derived instances"+                        FormatHaskell                         (ddump_deriving inst_info rn_binds famInsts))          ; gbl_env <- tcExtendLocalInstEnv (map iSpec (bagToList inst_info))@@ -1915,7 +1916,7 @@          rdr_env <- lift getGlobalRdrEnv         let data_con_names = map dataConName (tyConDataCons rep_tc)-            hidden_data_cons = not (isWiredInName (tyConName rep_tc)) &&+            hidden_data_cons = not (isWiredIn rep_tc) &&                                (isAbstractTyCon rep_tc ||                                 any not_in_scope data_con_names)             not_in_scope dc  = isNothing (lookupGRE_Name rdr_env dc)
compiler/typecheck/TcGenDeriv.hs view
@@ -2369,7 +2369,7 @@ {- Note [Auxiliary binders] ~~~~~~~~~~~~~~~~~~~~~~~~-We often want to make a top-level auxiliary binding.  E.g. for comparison we haev+We often want to make a top-level auxiliary binding.  E.g. for comparison we have    instance Ord T where     compare a b = $con2tag a `compare` $con2tag b
compiler/typecheck/TcHsType.hs view
@@ -947,30 +947,34 @@              -> [TcKind]    -- ^ of these kinds              -> TcKind      -- ^ expected kind of the whole tuple              -> TcM TcType-finish_tuple rn_ty tup_sort tau_tys tau_kinds exp_kind-  = do { traceTc "finish_tuple" (ppr res_kind $$ ppr tau_kinds $$ ppr exp_kind)-       ; let arg_tys  = case tup_sort of-                   -- See also Note [Unboxed tuple RuntimeRep vars] in TyCon-                 UnboxedTuple    -> tau_reps ++ tau_tys-                 BoxedTuple      -> tau_tys-                 ConstraintTuple -> tau_tys-       ; tycon <- case tup_sort of-           ConstraintTuple-             | arity > mAX_CTUPLE_SIZE-                         -> failWith (bigConstraintTuple arity)-             | otherwise -> tcLookupTyCon (cTupleTyConName arity)-           BoxedTuple    -> do { let tc = tupleTyCon Boxed arity-                               ; checkWiredInTyCon tc-                               ; return tc }-           UnboxedTuple  -> return (tupleTyCon Unboxed arity)-       ; checkExpectedKind rn_ty (mkTyConApp tycon arg_tys) res_kind exp_kind }+finish_tuple rn_ty tup_sort tau_tys tau_kinds exp_kind = do+  traceTc "finish_tuple" (ppr tup_sort $$ ppr tau_kinds $$ ppr exp_kind)+  case tup_sort of+    ConstraintTuple+      |  [tau_ty] <- tau_tys+         -- Drop any uses of 1-tuple constraints here.+         -- See Note [Ignore unary constraint tuples]+      -> check_expected_kind tau_ty constraintKind+      |  arity > mAX_CTUPLE_SIZE+      -> failWith (bigConstraintTuple arity)+      |  otherwise+      -> do tycon <- tcLookupTyCon (cTupleTyConName arity)+            check_expected_kind (mkTyConApp tycon tau_tys) constraintKind+    BoxedTuple -> do+      let tycon = tupleTyCon Boxed arity+      checkWiredInTyCon tycon+      check_expected_kind (mkTyConApp tycon tau_tys) liftedTypeKind+    UnboxedTuple ->+      let tycon    = tupleTyCon Unboxed arity+          tau_reps = map kindRep tau_kinds+          -- See also Note [Unboxed tuple RuntimeRep vars] in TyCon+          arg_tys  = tau_reps ++ tau_tys+          res_kind = unboxedTupleKind tau_reps in+      check_expected_kind (mkTyConApp tycon arg_tys) res_kind   where     arity = length tau_tys-    tau_reps = map kindRep tau_kinds-    res_kind = case tup_sort of-                 UnboxedTuple    -> unboxedTupleKind tau_reps-                 BoxedTuple      -> liftedTypeKind-                 ConstraintTuple -> constraintKind+    check_expected_kind ty act_kind =+      checkExpectedKind rn_ty ty act_kind exp_kind  bigConstraintTuple :: Arity -> MsgDoc bigConstraintTuple arity@@ -978,7 +982,47 @@           <+> parens (text "max arity =" <+> int mAX_CTUPLE_SIZE))        2 (text "Instead, use a nested tuple") +{-+Note [Ignore unary constraint tuples]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GHC provides unary tuples and unboxed tuples (see Note [One-tuples] in+TysWiredIn) but does *not* provide unary constraint tuples. Why? First,+recall the definition of a unary tuple data type: +  data Unit a = Unit a++Note that `Unit a` is *not* the same thing as `a`, since Unit is boxed and+lazy. Therefore, the presence of `Unit` matters semantically. On the other+hand, suppose we had a unary constraint tuple:++  class a => Unit% a++This compiles down a newtype (i.e., a cast) in Core, so `Unit% a` is+semantically equivalent to `a`. Therefore, a 1-tuple constraint would have+no user-visible impact, nor would it allow you to express anything that+you couldn't otherwise.++We could simply add Unit% for consistency with tuples (Unit) and unboxed+tuples (Unit#), but that would require even more magic to wire in another+magical class, so we opt not to do so. We must be careful, however, since+one can try to sneak in uses of unary constraint tuples through Template+Haskell, such as in this program (from #17511):++  f :: $(pure (ForallT [] [TupleT 1 `AppT` (ConT ''Show `AppT` ConT ''Int)]+                       (ConT ''String)))+  -- f :: Unit% (Show Int) => String+  f = "abc"++This use of `TupleT 1` will produce an HsBoxedOrConstraintTuple of arity 1,+and since it is used in a Constraint position, GHC will attempt to treat+it as thought it were a constraint tuple, which can potentially lead to+trouble if one attempts to look up the name of a constraint tuple of arity+1 (as it won't exist). To avoid this trouble, we simply take any unary+constraint tuples discovered when typechecking and drop them—i.e., treat+"Unit% a" as though the user had written "a". This is always safe to do+since the two constraints should be semantically equivalent.+-}+ {- ********************************************************************* *                                                                      *                 Type applications@@ -1941,7 +1985,8 @@                       , hsq_explicit = hs_tvs }) kc_res_ki   -- No standalane kind signature and no CUSK.   -- See note [Required, Specified, and Inferred for types] in TcTyClsDecls-  = do { (scoped_kvs, (tc_tvs, res_kind))+  = addTyConFlavCtxt name flav $+    do { (scoped_kvs, (tc_tvs, res_kind))            -- Why bindImplicitTKBndrs_Q_Tv which uses newTyVarTyVar?            -- See Note [Inferring kinds for type declarations] in TcTyClsDecls            <- bindImplicitTKBndrs_Q_Tv kv_ns            $
compiler/typecheck/TcInstDcls.hs view
@@ -1918,6 +1918,7 @@                              [mkSimpleMatch (mkPrefixFunRhs fn) [] rhs]          ; liftIO (dumpIfSet_dyn dflags Opt_D_dump_deriv "Filling in method body"+                   FormatHaskell                    (vcat [ppr clas <+> ppr inst_tys,                           nest 2 (ppr sel_id <+> equals <+> ppr rhs)])) 
compiler/typecheck/TcMatches.hs view
@@ -514,7 +514,7 @@              -- typically something like [(Int,Bool,Int)]              -- We don't know what tuple_ty is yet, so we use a variable        ; let mk_n_bndr :: Name -> TcId -> TcId-             mk_n_bndr n_bndr_name bndr_id = mkLocalIdOrCoVar n_bndr_name (n_app (idType bndr_id))+             mk_n_bndr n_bndr_name bndr_id = mkLocalId n_bndr_name (n_app (idType bndr_id))               -- Ensure that every old binder of type `b` is linked up with its              -- new binder which should have type `n b`@@ -693,7 +693,7 @@         --------------- Bulding the bindersMap ----------------        ; let mk_n_bndr :: Name -> TcId -> TcId-             mk_n_bndr n_bndr_name bndr_id = mkLocalIdOrCoVar n_bndr_name (n_app (idType bndr_id))+             mk_n_bndr n_bndr_name bndr_id = mkLocalId n_bndr_name (n_app (idType bndr_id))               -- Ensure that every old binder of type `b` is linked up with its              -- new binder which should have type `n b`
compiler/typecheck/TcPat.hs view
@@ -211,7 +211,8 @@ tcPatBndr _ bndr_name pat_ty   = do { pat_ty <- expTypeToType pat_ty        ; traceTc "tcPatBndr(not let)" (ppr bndr_name $$ ppr pat_ty)-       ; return (idHsWrapper, mkLocalId bndr_name pat_ty) }+       ; return (idHsWrapper, mkLocalIdOrCoVar bndr_name pat_ty) }+               -- We should not have "OrCoVar" here, this is a bug (#17545)                -- Whether or not there is a sig is irrelevant,                -- as this is local 
compiler/typecheck/TcRnDriver.hs view
@@ -2711,9 +2711,9 @@ ************************************************************************ -} +-- | Dump, with a banner, if -ddump-rn rnDump :: (Outputable a, Data a) => a -> TcRn ()--- Dump, with a banner, if -ddump-rn-rnDump rn = do { traceOptTcRn Opt_D_dump_rn (mkDumpDoc "Renamer" (ppr rn)) }+rnDump rn = dumpOptTcRn Opt_D_dump_rn "Renamer" FormatHaskell (ppr rn)  tcDump :: TcGblEnv -> TcRn () tcDump env@@ -2721,13 +2721,14 @@          -- Dump short output if -ddump-types or -ddump-tc         when (dopt Opt_D_dump_types dflags || dopt Opt_D_dump_tc dflags)-          (traceTcRnForUser Opt_D_dump_types short_dump) ;+          (dumpTcRn True (dumpOptionsFromFlag Opt_D_dump_types)+            "" FormatText short_dump) ;          -- Dump bindings if -ddump-tc-        traceOptTcRn Opt_D_dump_tc (mkDumpDoc "Typechecker" full_dump);+        dumpOptTcRn Opt_D_dump_tc "Typechecker" FormatHaskell full_dump;          -- Dump bindings as an hsSyn AST if -ddump-tc-ast-        traceOptTcRn Opt_D_dump_tc_ast (mkDumpDoc "Typechecker" ast_dump)+        dumpOptTcRn Opt_D_dump_tc_ast "Typechecker AST" FormatHaskell ast_dump    }   where     short_dump = pprTcGblEnv env
compiler/typecheck/TcRnMonad.hs view
@@ -42,8 +42,8 @@   newTcRef, readTcRef, writeTcRef, updTcRef,    -- * Debugging-  traceTc, traceRn, traceOptTcRn, traceTcRn, traceTcRnForUser,-  traceTcRnWithStyle,+  traceTc, traceRn, traceOptTcRn, dumpOptTcRn,+  dumpTcRn,   getPrintUnqualified,   printForUserTcRn,   traceIf, traceHiDiffs, traceOptIf,@@ -623,12 +623,12 @@ newSysLocalId :: FastString -> TcType -> TcRnIf gbl lcl TcId newSysLocalId fs ty   = do  { u <- newUnique-        ; return (mkSysLocalOrCoVar fs u ty) }+        ; return (mkSysLocal fs u ty) }  newSysLocalIds :: FastString -> [TcType] -> TcRnIf gbl lcl [TcId] newSysLocalIds fs tys   = do  { us <- newUniqueSupply-        ; return (zipWith (mkSysLocalOrCoVar fs) (uniqsFromSupply us) tys) }+        ; return (zipWith (mkSysLocal fs) (uniqsFromSupply us) tys) }  instance MonadUnique (IOEnv (Env gbl lcl)) where         getUniqueM = newUnique@@ -684,58 +684,48 @@ formatTraceMsg :: String -> SDoc -> SDoc formatTraceMsg herald doc = hang (text herald) 2 doc --- | Output a doc if the given 'DumpFlag' is set.------ By default this logs to stdout--- However, if the `-ddump-to-file` flag is set,--- then this will dump output to a file------ Just a wrapper for 'dumpSDoc'+-- | Trace if the given 'DumpFlag' is set. traceOptTcRn :: DumpFlag -> SDoc -> TcRn ()-traceOptTcRn flag doc-  = do { dflags <- getDynFlags-       ; when (dopt flag dflags)-              (traceTcRn flag doc)-       }+traceOptTcRn flag doc = do+  dflags <- getDynFlags+  when (dopt flag dflags) $+    dumpTcRn False (dumpOptionsFromFlag flag) "" FormatText doc +-- | Dump if the given 'DumpFlag' is set.+dumpOptTcRn :: DumpFlag -> String -> DumpFormat -> SDoc -> TcRn ()+dumpOptTcRn flag title fmt doc = do+  dflags <- getDynFlags+  when (dopt flag dflags) $+    dumpTcRn False (dumpOptionsFromFlag flag) title fmt doc++-- | Unconditionally dump some trace output+-- -- Certain tests (T3017, Roles3, T12763 etc.) expect part of the -- output generated by `-ddump-types` to be in 'PprUser' style. However, -- generally we want all other debugging output to use 'PprDump'--- style. 'traceTcRn' and 'traceTcRnForUser' help us accomplish this.---- | A wrapper around 'traceTcRnWithStyle' which uses 'PprDump' style.-traceTcRn :: DumpFlag -> SDoc -> TcRn ()-traceTcRn flag doc-  = do { dflags  <- getDynFlags-       ; printer <- getPrintUnqualified dflags-       ; let dump_style = mkDumpStyle dflags printer-       ; traceTcRnWithStyle dump_style dflags flag doc }---- | A wrapper around 'traceTcRnWithStyle' which uses 'PprUser' style.-traceTcRnForUser :: DumpFlag -> SDoc -> TcRn ()--- Used by 'TcRnDriver.tcDump'.-traceTcRnForUser flag doc-  = do { dflags  <- getDynFlags-       ; printer <- getPrintUnqualified dflags-       ; let user_style = mkUserStyle dflags printer AllTheWay-       ; traceTcRnWithStyle user_style dflags flag doc }--traceTcRnWithStyle :: PprStyle -> DynFlags -> DumpFlag -> SDoc -> TcRn ()--- ^ Unconditionally dump some trace output+-- style. We 'PprUser' style if 'useUserStyle' is True. ----- The DumpFlag is used only to set the output filename--- for --dump-to-file, not to decide whether or not to output--- That part is done by the caller-traceTcRnWithStyle sty dflags flag doc-  = do { real_doc <- prettyDoc dflags doc-       ; liftIO $ dumpSDocWithStyle sty dflags flag "" real_doc }-  where-    -- Add current location if -dppr-debug-    prettyDoc :: DynFlags -> SDoc -> TcRn SDoc-    prettyDoc dflags doc = if hasPprDebug dflags-       then do { loc  <- getSrcSpanM; return $ mkLocMessage SevOutput loc doc }-       else return doc -- The full location is usually way too much+dumpTcRn :: Bool -> DumpOptions -> String -> DumpFormat -> SDoc -> TcRn ()+dumpTcRn useUserStyle dumpOpt title fmt doc = do+  dflags <- getDynFlags+  printer <- getPrintUnqualified dflags+  real_doc <- wrapDocLoc doc+  let sty = if useUserStyle+              then mkUserStyle dflags printer AllTheWay+              else mkDumpStyle dflags printer+  liftIO $ dumpAction dflags sty dumpOpt title fmt real_doc +-- | Add current location if -dppr-debug+-- (otherwise the full location is usually way too much)+wrapDocLoc :: SDoc -> TcRn SDoc+wrapDocLoc doc = do+  dflags <- getDynFlags+  if hasPprDebug dflags+    then do+      loc <- getSrcSpanM+      return (mkLocMessage SevOutput loc doc)+    else+      return doc  getPrintUnqualified :: DynFlags -> TcRn PrintUnqualified getPrintUnqualified dflags
compiler/typecheck/TcRules.hs view
@@ -198,7 +198,7 @@ --   error for each out-of-scope type variable used   = do  { let ctxt = RuleSigCtxt name         ; (_ , tvs, id_ty) <- tcHsPatSigType ctxt rn_ty-        ; let id  = mkLocalIdOrCoVar name id_ty+        ; let id  = mkLocalId name id_ty                     -- See Note [Pattern signature binders] in TcHsType                -- The type variables scope over subsequent bindings; yuk
compiler/typecheck/TcSMonad.hs view
@@ -146,6 +146,7 @@ import Coercion import Unify +import ErrUtils import TcEvidence import Class import TyCon@@ -2733,7 +2734,10 @@        ; when (  dopt Opt_D_dump_cs_trace dflags                   || dopt Opt_D_dump_tc_trace dflags )               ( do { msg <- mk_doc-                   ; TcM.traceTcRn Opt_D_dump_cs_trace msg }) }+                   ; TcM.dumpTcRn False+                       (dumpOptionsFromFlag Opt_D_dump_cs_trace)+                       "" FormatText+                       msg }) }  runTcS :: TcS a                -- What to run        -> TcM (a, EvBindMap)
compiler/typecheck/TcTyClsDecls.hs view
@@ -316,8 +316,8 @@ you can always specify a CUSK directly to make this work out. See tc269 for an example. -Note [Skip decls with CUSKs in kcLTyClDecl]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note [CUSKs and PolyKinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider      data T (a :: *) = MkT (S a)   -- Has CUSK@@ -530,7 +530,8 @@           --    3. Generalise the inferred kinds           -- See Note [Kind checking for type and class decls] -        ; cusks_enabled <- xoptM LangExt.CUSKs+        ; cusks_enabled <- xoptM LangExt.CUSKs <&&> xoptM LangExt.PolyKinds+                    -- See Note [CUSKs and PolyKinds]         ; let (kindless_decls, kinded_decls) = partitionWith get_kind decls                get_kind d@@ -559,10 +560,8 @@                     -- NB: the environment extension overrides the tycon                     --     promotion-errors bindings                     --     See Note [Type environment evolution]-                  ; poly_kinds  <- xoptM LangExt.PolyKinds                   ; tcExtendKindEnvWithTyCons mono_tcs $-                    mapM_ kcLTyClDecl (if poly_kinds then kindless_decls else decls)-                    -- See Note [Skip decls with CUSKs in kcLTyClDecl]+                    mapM_ kcLTyClDecl kindless_decls                    ; return mono_tcs } @@ -974,8 +973,40 @@ final TyVars despite the fact that we unified kka:=kkb  zonkRecTyVarBndrs we need to do knot-tying because of the need to-apply this same substitution to the kind of each.  -}+apply this same substitution to the kind of each. +Note [Inferring visible dependent quantification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++  data T k :: k -> Type where+    MkT1 :: T Type Int+    MkT2 :: T (Type -> Type) Maybe++This looks like it should work. However, it is polymorphically recursive,+as the uses of T in the constructor types specialize the k in the kind+of T. This trips up our dear users (#17131, #17541), and so we add+a "landmark" context (which cannot be suppressed) whenever we+spot inferred visible dependent quantification (VDQ).++It's hard to know when we've actually been tripped up by polymorphic recursion+specifically, so we just include a note to users whenever we infer VDQ. The+testsuite did not show up a single spurious inclusion of this message.++The context is added in addVDQNote, which looks for a visible TyConBinder+that also appears in the TyCon's kind. (I first looked at the kind for+a visible, dependent quantifier, but Note [No polymorphic recursion] in+TcHsType defeats that approach.) addVDQNote is used in kcTyClDecl,+which is used only when inferring the kind of a tycon (never with a CUSK or+SAK).++Once upon a time, I (Richard E) thought that the tycon-kind could+not be a forall-type. But this is wrong: data T :: forall k. k -> Type+(with -XNoCUSKs) could end up here. And this is all OK.+++-}+ -------------- tcExtendKindEnvWithTyCons :: [TcTyCon] -> TcM a -> TcM a tcExtendKindEnvWithTyCons tcs@@ -1258,30 +1289,32 @@ ------------------------------------------------------------------------ kcLTyClDecl :: LTyClDecl GhcRn -> TcM ()   -- See Note [Kind checking for type and class decls]+  -- Called only for declarations without a signature (no CUSKs or SAKs here) kcLTyClDecl (L loc decl)   = setSrcSpan loc $-    tcAddDeclCtxt decl $-    do { traceTc "kcTyClDecl {" (ppr tc_name)-       ; kcTyClDecl decl+    do { tycon <- kcLookupTcTyCon tc_name+       ; traceTc "kcTyClDecl {" (ppr tc_name)+       ; addVDQNote tycon $   -- See Note [Inferring visible dependent quantification]+         addErrCtxt (tcMkDeclCtxt decl) $+         kcTyClDecl decl tycon        ; traceTc "kcTyClDecl done }" (ppr tc_name) }   where-    tc_name = tyClDeclLName decl+    tc_name = tcdName decl -kcTyClDecl :: TyClDecl GhcRn -> TcM ()+kcTyClDecl :: TyClDecl GhcRn -> TcTyCon -> TcM () -- This function is used solely for its side effect on kind variables -- NB kind signatures on the type variables and --    result kind signature have already been dealt with --    by inferInitialKind, so we can ignore them here.  kcTyClDecl (DataDecl { tcdLName    = (L _ name)-                     , tcdDataDefn = defn })+                     , tcdDataDefn = defn }) tyCon   | HsDataDefn { dd_cons = cons@((L _ (ConDeclGADT {})) : _)                , dd_ctxt = (L _ [])                , dd_ND = new_or_data } <- defn-  = do { tyCon <- kcLookupTcTyCon name-         -- See Note [Implementation of UnliftedNewtypes] STEP 2-       ; kcConDecls new_or_data (tyConResKind tyCon) cons-       }+  = -- See Note [Implementation of UnliftedNewtypes] STEP 2+    kcConDecls new_or_data (tyConResKind tyCon) cons+     -- hs_tvs and dd_kindSig already dealt with in inferInitialKind     -- This must be a GADT-style decl,     --        (see invariants of DataDefn declaration)@@ -1294,18 +1327,17 @@                , dd_ND = new_or_data } <- defn   = bindTyClTyVars name $ \ _ _ ->     do { _ <- tcHsContext ctxt-       ; tyCon <- kcLookupTcTyCon name        ; kcConDecls new_or_data (tyConResKind tyCon) cons        } -kcTyClDecl (SynDecl { tcdLName = L _ name, tcdRhs = rhs })+kcTyClDecl (SynDecl { tcdLName = L _ name, tcdRhs = rhs }) _tycon   = bindTyClTyVars name $ \ _ res_kind ->     discardResult $ tcCheckLHsType rhs res_kind         -- NB: check against the result kind that we allocated         -- in inferInitialKinds.  kcTyClDecl (ClassDecl { tcdLName = L _ name-                      , tcdCtxt = ctxt, tcdSigs = sigs })+                      , tcdCtxt = ctxt, tcdSigs = sigs }) _tycon   = bindTyClTyVars name $ \ _ _ ->     do  { _ <- tcHsContext ctxt         ; mapM_ (wrapLocM_ kc_sig) sigs }@@ -1315,18 +1347,15 @@      skol_info = TyConSkol ClassFlavour name -kcTyClDecl (FamDecl _ (FamilyDecl { fdLName  = L _ fam_tc_name-                                  , fdInfo   = fd_info }))+kcTyClDecl (FamDecl _ (FamilyDecl { fdInfo   = fd_info })) fam_tc -- closed type families look at their equations, but other families don't -- do anything here   = case fd_info of-      ClosedTypeFamily (Just eqns) ->-        do { fam_tc <- kcLookupTcTyCon fam_tc_name-           ; mapM_ (kcTyFamInstEqn fam_tc) eqns }+      ClosedTypeFamily (Just eqns) -> mapM_ (kcTyFamInstEqn fam_tc) eqns       _ -> return ()-kcTyClDecl (FamDecl _ (XFamilyDecl nec))        = noExtCon nec-kcTyClDecl (DataDecl _ _ _ _ (XHsDataDefn nec)) = noExtCon nec-kcTyClDecl (XTyClDecl nec)                      = noExtCon nec+kcTyClDecl (FamDecl _ (XFamilyDecl nec))        _ = noExtCon nec+kcTyClDecl (DataDecl _ _ _ _ (XHsDataDefn nec)) _ = noExtCon nec+kcTyClDecl (XTyClDecl nec)                      _ = noExtCon nec  ------------------- @@ -3365,6 +3394,12 @@   | isPrimTyCon tc   -- Happens when Haddock'ing GHC.Prim   = return () +  | isWiredIn tc     -- validity-checking wired-in tycons is a waste of+                     -- time. More importantly, a wired-in tycon might+                     -- violate assumptions. Example: (~) has a superclass+                     -- mentioning (~#), which is ill-kinded in source Haskell+  = traceTc "Skipping validity check for wired-in" (ppr tc)+   | otherwise   = do { traceTc "checkValidTyCon" (ppr tc $$ ppr (tyConClass_maybe tc))        ; if | Just cl <- tyConClass_maybe tc@@ -3438,7 +3473,7 @@                 -- NB: this check assumes that all the constructors of a given                 -- data type use the same type variables         where-        (_, _, _, res1) = dataConSig con1+        res1 = dataConOrigResTy con1         fty1 = dataConFieldType con1 lbl         lbl = flLabel label @@ -3446,7 +3481,7 @@             = do { checkFieldCompat lbl con1 con2 res1 res2 fty1 fty2                  ; checkFieldCompat lbl con2 con1 res2 res1 fty2 fty1 }             where-                (_, _, _, res2) = dataConSig con2+                res2 = dataConOrigResTy con2                 fty2 = dataConFieldType con2 lbl  checkPartialRecordField :: [DataCon] -> FieldLabel -> TcM ()@@ -3546,12 +3581,12 @@                    user_tvbs_invariant                      =    Set.fromList (filterEqSpec eq_spec univs ++ exs)                        == Set.fromList user_tvs-             ; WARN( not user_tvbs_invariant+             ; MASSERT2( user_tvbs_invariant                        , vcat ([ ppr con                                , ppr univs                                , ppr exs                                , ppr eq_spec-                               , ppr user_tvs ])) return () }+                               , ppr user_tvs ])) }          ; traceTc "Done validity of data con" $           vcat [ ppr con@@ -4156,6 +4191,46 @@ *                                                                      * ************************************************************************ -}++tcMkDeclCtxt :: TyClDecl GhcRn -> SDoc+tcMkDeclCtxt decl = hsep [text "In the", pprTyClDeclFlavour decl,+                      text "declaration for", quotes (ppr (tcdName decl))]++addVDQNote :: TcTyCon -> TcM a -> TcM a+-- See Note [Inferring visible dependent quantification]+-- Only types without a signature (CUSK or SAK) here+addVDQNote tycon thing_inside+  | ASSERT2( isTcTyCon tycon, ppr tycon )+    ASSERT2( not (tcTyConIsPoly tycon), ppr tycon $$ ppr tc_kind )+    has_vdq+  = addLandmarkErrCtxt vdq_warning thing_inside+  | otherwise+  = thing_inside+  where+      -- Check whether a tycon has visible dependent quantification.+      -- This will *always* be a TcTyCon. Furthermore, it will *always*+      -- be an ungeneralised TcTyCon, straight out of kcInferDeclHeader.+      -- Thus, all the TyConBinders will be anonymous. Thus, the+      -- free variables of the tycon's kind will be the same as the free+      -- variables from all the binders.+    has_vdq  = any is_vdq_tcb (tyConBinders tycon)+    tc_kind  = tyConKind tycon+    kind_fvs = tyCoVarsOfType tc_kind++    is_vdq_tcb tcb = (binderVar tcb `elemVarSet` kind_fvs) &&+                     isVisibleTyConBinder tcb++    vdq_warning = vcat+      [ text "NB: Type" <+> quotes (ppr tycon) <+>+        text "was inferred to use visible dependent quantification."+      , text "Most types with visible dependent quantification are"+      , text "polymorphically recursive and need a standalone kind"+      , text "signature. Perhaps supply one, with StandaloneKindSignatures."+      ]++tcAddDeclCtxt :: TyClDecl GhcRn -> TcM a -> TcM a+tcAddDeclCtxt decl thing_inside+  = addErrCtxt (tcMkDeclCtxt decl) thing_inside  tcAddTyFamInstCtxt :: TyFamInstDecl GhcRn -> TcM a -> TcM a tcAddTyFamInstCtxt decl
compiler/typecheck/TcValidity.hs view
@@ -1116,15 +1116,14 @@         | isCTupleClass cls   -> check_tuple_pred under_syn env dflags ctxt pred tys         | otherwise           -> check_class_pred env dflags ctxt pred cls tys -      EqPred NomEq _ _  -> -- a ~# b-                           check_eq_pred env dflags pred--      EqPred ReprEq _ _ -> -- Ugh!  When inferring types we may get-                           -- f :: (a ~R# b) => blha-                           -- And we want to treat that like (Coercible a b)-                           -- We should probably check argument shapes, but we-                           -- didn't do so before, so I'm leaving it for now-                           return ()+      EqPred _ _ _      -> pprPanic "check_pred_help" (ppr pred)+              -- EqPreds, such as (t1 ~ #t2) or (t1 ~R# t2), don't even have kind Constraint+              -- and should never appear before the '=>' of a type.  Thus+              --     f :: (a ~# b) => blah+              -- is wrong.  For user written signatures, it'll be rejected by kind-checking+              -- well before we get to validity checking.  For inferred types we are careful+              -- to box such constraints in TcType.pickQuantifiablePreds, as described+              -- in Note [Lift equality constraints when quantifying] in TcType        ForAllPred _ theta head -> check_quant_pred env dflags ctxt pred theta head       IrredPred {}            -> check_irred_pred under_syn env dflags ctxt pred@@ -1139,13 +1138,18 @@  check_quant_pred :: TidyEnv -> DynFlags -> UserTypeCtxt                  -> PredType -> ThetaType -> PredType -> TcM ()-check_quant_pred env dflags _ctxt pred theta head_pred+check_quant_pred env dflags ctxt pred theta head_pred   = addErrCtxt (text "In the quantified constraint" <+> quotes (ppr pred)) $     do { -- Check the instance head          case classifyPredType head_pred of-            ClassPred cls tys -> checkValidInstHead SigmaCtxt cls tys                                  -- SigmaCtxt tells checkValidInstHead that                                  -- this is the head of a quantified constraint+            ClassPred cls tys -> do { checkValidInstHead SigmaCtxt cls tys+                                    ; check_pred_help False env dflags ctxt head_pred }+                               -- need check_pred_help to do extra pred-only validity+                               -- checks, such as for (~). Otherwise, we get #17563+                               -- NB: checks for the context are covered by the check_type+                               -- in check_pred_ty             IrredPred {}      | hasTyVarHead head_pred                               -> return ()             _                 -> failWithTcM (badQuantHeadErr env pred)@@ -1216,10 +1220,9 @@ check_class_pred :: TidyEnv -> DynFlags -> UserTypeCtxt                  -> PredType -> Class -> [TcType] -> TcM () check_class_pred env dflags ctxt pred cls tys-  |  isEqPredClass cls    -- (~) and (~~) are classified as classes,-                          -- but here we want to treat them as equalities-  = -- pprTrace "check_class" (ppr cls) $-    check_eq_pred env dflags pred+  | isEqPredClass cls    -- (~) and (~~) are classified as classes,+                         -- but here we want to treat them as equalities+  = check_eq_pred env dflags pred    | isIPClass cls   = do { check_arity
ghc-lib.cabal view
@@ -1,7 +1,7 @@ cabal-version: >=1.22 build-type: Simple name: ghc-lib-version: 0.20191201+version: 0.20200102 license: BSD3 license-file: LICENSE category: Development@@ -54,6 +54,7 @@ library     default-language:   Haskell2010     default-extensions: NoImplicitPrelude+    exposed: False     include-dirs:         includes         ghc-lib/stage0/lib@@ -81,7 +82,7 @@         transformers == 0.5.*,         process >= 1 && < 1.7,         hpc == 0.6.*,-        ghc-lib-parser == 0.20191201+        ghc-lib-parser == 0.20200102     build-tools: alex >= 3.1, happy >= 1.19.4     other-extensions:         BangPatterns@@ -127,7 +128,6 @@         compiler/typecheck         libraries/ghc-boot         compiler/backpack-        compiler/simplStg         compiler/coreSyn         compiler/deSugar         compiler/hieFile@@ -135,7 +135,6 @@         compiler/prelude         compiler/stranal         compiler/rename-        compiler/stgSyn         compiler/iface         compiler/utils         libraries/ghci@@ -235,6 +234,7 @@         GHC.PackageDb,         GHC.Platform,         GHC.Serialized,+        GHC.Types.RepType,         GHC.UniqueSubdir,         GHC.Version,         GHCi.BreakArray,@@ -304,7 +304,6 @@         PrimOp,         RdrHsSyn,         RdrName,-        RepType,         Rules,         Settings,         SizedSeq,@@ -385,8 +384,6 @@         CmmUtils         CodeOutput         CoreLint-        CorePrep-        CoreToStg         Coverage         Debug         Debugger@@ -422,6 +419,8 @@         Format         FunDeps         GHC+        GHC.CoreToStg+        GHC.CoreToStg.Prep         GHC.HandleEncoding         GHC.Hs.Dump         GHC.HsToCore.PmCheck@@ -438,6 +437,17 @@         GHC.Platform.X86         GHC.Platform.X86_64         GHC.Settings+        GHC.Stg.CSE+        GHC.Stg.FVs+        GHC.Stg.Lift+        GHC.Stg.Lift.Analysis+        GHC.Stg.Lift.Monad+        GHC.Stg.Lint+        GHC.Stg.Pipeline+        GHC.Stg.Stats+        GHC.Stg.Subst+        GHC.Stg.Syntax+        GHC.Stg.Unarise         GHC.StgToCmm         GHC.StgToCmm.ArgRep         GHC.StgToCmm.Bind@@ -587,23 +597,12 @@         SimplCore         SimplEnv         SimplMonad-        SimplStg         SimplUtils         Simplify         SpecConstr         Specialise         State         StaticPtrTable-        StgCse-        StgFVs-        StgLiftLams-        StgLiftLams.Analysis-        StgLiftLams.LiftM-        StgLiftLams.Transformation-        StgLint-        StgStats-        StgSubst-        StgSyn         Stream         SysTools         SysTools.ExtraObj@@ -659,7 +658,6 @@         TcValidity         TidyPgm         UnVarGraph-        UnariseStg         UniqMap         WorkWrap         WwLib
ghc-lib/stage0/compiler/build/primop-can-fail.hs-incl view
@@ -1,6 +1,3 @@-primOpCanFail IntQuotOp = True-primOpCanFail IntRemOp = True-primOpCanFail IntQuotRemOp = True primOpCanFail Int8QuotOp = True primOpCanFail Int8RemOp = True primOpCanFail Int8QuotRemOp = True@@ -13,6 +10,9 @@ primOpCanFail Word16QuotOp = True primOpCanFail Word16RemOp = True primOpCanFail Word16QuotRemOp = True+primOpCanFail IntQuotOp = True+primOpCanFail IntRemOp = True+primOpCanFail IntQuotRemOp = True primOpCanFail WordQuotOp = True primOpCanFail WordRemOp = True primOpCanFail WordQuotRemOp = True
ghc-lib/stage0/compiler/build/primop-commutable.hs-incl view
@@ -1,5 +1,13 @@ commutableOp CharEqOp = True commutableOp CharNeOp = True+commutableOp Int8AddOp = True+commutableOp Int8MulOp = True+commutableOp Word8AddOp = True+commutableOp Word8MulOp = True+commutableOp Int16AddOp = True+commutableOp Int16MulOp = True+commutableOp Word16AddOp = True+commutableOp Word16MulOp = True commutableOp IntAddOp = True commutableOp IntMulOp = True commutableOp IntMulMayOfloOp = True@@ -9,14 +17,6 @@ commutableOp IntAddCOp = True commutableOp IntEqOp = True commutableOp IntNeOp = True-commutableOp Int8AddOp = True-commutableOp Int8MulOp = True-commutableOp Word8AddOp = True-commutableOp Word8MulOp = True-commutableOp Int16AddOp = True-commutableOp Int16MulOp = True-commutableOp Word16AddOp = True-commutableOp Word16MulOp = True commutableOp WordAddOp = True commutableOp WordAddCOp = True commutableOp WordAdd2Op = True
ghc-lib/stage0/compiler/build/primop-data-decl.hs-incl view
@@ -6,35 +6,6 @@    | CharLtOp    | CharLeOp    | OrdOp-   | IntAddOp-   | IntSubOp-   | IntMulOp-   | IntMulMayOfloOp-   | IntQuotOp-   | IntRemOp-   | IntQuotRemOp-   | AndIOp-   | OrIOp-   | XorIOp-   | NotIOp-   | IntNegOp-   | IntAddCOp-   | IntSubCOp-   | IntGtOp-   | IntGeOp-   | IntEqOp-   | IntNeOp-   | IntLtOp-   | IntLeOp-   | ChrOp-   | Int2WordOp-   | Int2FloatOp-   | Int2DoubleOp-   | Word2FloatOp-   | Word2DoubleOp-   | ISllOp-   | ISraOp-   | ISrlOp    | Int8Extend    | Int8Narrow    | Int8NegOp@@ -95,6 +66,36 @@    | Word16LeOp    | Word16LtOp    | Word16NeOp+   | IntAddOp+   | IntSubOp+   | IntMulOp+   | IntMul2Op+   | IntMulMayOfloOp+   | IntQuotOp+   | IntRemOp+   | IntQuotRemOp+   | AndIOp+   | OrIOp+   | XorIOp+   | NotIOp+   | IntNegOp+   | IntAddCOp+   | IntSubCOp+   | IntGtOp+   | IntGeOp+   | IntEqOp+   | IntNeOp+   | IntLtOp+   | IntLeOp+   | ChrOp+   | Int2WordOp+   | Int2FloatOp+   | Int2DoubleOp+   | Word2FloatOp+   | Word2DoubleOp+   | ISllOp+   | ISraOp+   | ISrlOp    | WordAddOp    | WordAddCOp    | WordSubCOp
ghc-lib/stage0/compiler/build/primop-list.hs-incl view
@@ -5,35 +5,6 @@    , CharLtOp    , CharLeOp    , OrdOp-   , IntAddOp-   , IntSubOp-   , IntMulOp-   , IntMulMayOfloOp-   , IntQuotOp-   , IntRemOp-   , IntQuotRemOp-   , AndIOp-   , OrIOp-   , XorIOp-   , NotIOp-   , IntNegOp-   , IntAddCOp-   , IntSubCOp-   , IntGtOp-   , IntGeOp-   , IntEqOp-   , IntNeOp-   , IntLtOp-   , IntLeOp-   , ChrOp-   , Int2WordOp-   , Int2FloatOp-   , Int2DoubleOp-   , Word2FloatOp-   , Word2DoubleOp-   , ISllOp-   , ISraOp-   , ISrlOp    , Int8Extend    , Int8Narrow    , Int8NegOp@@ -94,6 +65,36 @@    , Word16LeOp    , Word16LtOp    , Word16NeOp+   , IntAddOp+   , IntSubOp+   , IntMulOp+   , IntMul2Op+   , IntMulMayOfloOp+   , IntQuotOp+   , IntRemOp+   , IntQuotRemOp+   , AndIOp+   , OrIOp+   , XorIOp+   , NotIOp+   , IntNegOp+   , IntAddCOp+   , IntSubCOp+   , IntGtOp+   , IntGeOp+   , IntEqOp+   , IntNeOp+   , IntLtOp+   , IntLeOp+   , ChrOp+   , Int2WordOp+   , Int2FloatOp+   , Int2DoubleOp+   , Word2FloatOp+   , Word2DoubleOp+   , ISllOp+   , ISraOp+   , ISrlOp    , WordAddOp    , WordAddCOp    , WordSubCOp
ghc-lib/stage0/compiler/build/primop-primop-info.hs-incl view
@@ -5,35 +5,6 @@ primOpInfo CharLtOp = mkCompare (fsLit "ltChar#") charPrimTy primOpInfo CharLeOp = mkCompare (fsLit "leChar#") charPrimTy primOpInfo OrdOp = mkGenPrimOp (fsLit "ord#")  [] [charPrimTy] (intPrimTy)-primOpInfo IntAddOp = mkDyadic (fsLit "+#") intPrimTy-primOpInfo IntSubOp = mkDyadic (fsLit "-#") intPrimTy-primOpInfo IntMulOp = mkDyadic (fsLit "*#") intPrimTy-primOpInfo IntMulMayOfloOp = mkDyadic (fsLit "mulIntMayOflo#") intPrimTy-primOpInfo IntQuotOp = mkDyadic (fsLit "quotInt#") intPrimTy-primOpInfo IntRemOp = mkDyadic (fsLit "remInt#") intPrimTy-primOpInfo IntQuotRemOp = mkGenPrimOp (fsLit "quotRemInt#")  [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))-primOpInfo AndIOp = mkDyadic (fsLit "andI#") intPrimTy-primOpInfo OrIOp = mkDyadic (fsLit "orI#") intPrimTy-primOpInfo XorIOp = mkDyadic (fsLit "xorI#") intPrimTy-primOpInfo NotIOp = mkMonadic (fsLit "notI#") intPrimTy-primOpInfo IntNegOp = mkMonadic (fsLit "negateInt#") intPrimTy-primOpInfo IntAddCOp = mkGenPrimOp (fsLit "addIntC#")  [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))-primOpInfo IntSubCOp = mkGenPrimOp (fsLit "subIntC#")  [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))-primOpInfo IntGtOp = mkCompare (fsLit ">#") intPrimTy-primOpInfo IntGeOp = mkCompare (fsLit ">=#") intPrimTy-primOpInfo IntEqOp = mkCompare (fsLit "==#") intPrimTy-primOpInfo IntNeOp = mkCompare (fsLit "/=#") intPrimTy-primOpInfo IntLtOp = mkCompare (fsLit "<#") intPrimTy-primOpInfo IntLeOp = mkCompare (fsLit "<=#") intPrimTy-primOpInfo ChrOp = mkGenPrimOp (fsLit "chr#")  [] [intPrimTy] (charPrimTy)-primOpInfo Int2WordOp = mkGenPrimOp (fsLit "int2Word#")  [] [intPrimTy] (wordPrimTy)-primOpInfo Int2FloatOp = mkGenPrimOp (fsLit "int2Float#")  [] [intPrimTy] (floatPrimTy)-primOpInfo Int2DoubleOp = mkGenPrimOp (fsLit "int2Double#")  [] [intPrimTy] (doublePrimTy)-primOpInfo Word2FloatOp = mkGenPrimOp (fsLit "word2Float#")  [] [wordPrimTy] (floatPrimTy)-primOpInfo Word2DoubleOp = mkGenPrimOp (fsLit "word2Double#")  [] [wordPrimTy] (doublePrimTy)-primOpInfo ISllOp = mkGenPrimOp (fsLit "uncheckedIShiftL#")  [] [intPrimTy, intPrimTy] (intPrimTy)-primOpInfo ISraOp = mkGenPrimOp (fsLit "uncheckedIShiftRA#")  [] [intPrimTy, intPrimTy] (intPrimTy)-primOpInfo ISrlOp = mkGenPrimOp (fsLit "uncheckedIShiftRL#")  [] [intPrimTy, intPrimTy] (intPrimTy) primOpInfo Int8Extend = mkGenPrimOp (fsLit "extendInt8#")  [] [int8PrimTy] (intPrimTy) primOpInfo Int8Narrow = mkGenPrimOp (fsLit "narrowInt8#")  [] [intPrimTy] (int8PrimTy) primOpInfo Int8NegOp = mkMonadic (fsLit "negateInt8#") int8PrimTy@@ -94,6 +65,36 @@ primOpInfo Word16LeOp = mkCompare (fsLit "leWord16#") word16PrimTy primOpInfo Word16LtOp = mkCompare (fsLit "ltWord16#") word16PrimTy primOpInfo Word16NeOp = mkCompare (fsLit "neWord16#") word16PrimTy+primOpInfo IntAddOp = mkDyadic (fsLit "+#") intPrimTy+primOpInfo IntSubOp = mkDyadic (fsLit "-#") intPrimTy+primOpInfo IntMulOp = mkDyadic (fsLit "*#") intPrimTy+primOpInfo IntMul2Op = mkGenPrimOp (fsLit "timesInt2#")  [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy]))+primOpInfo IntMulMayOfloOp = mkDyadic (fsLit "mulIntMayOflo#") intPrimTy+primOpInfo IntQuotOp = mkDyadic (fsLit "quotInt#") intPrimTy+primOpInfo IntRemOp = mkDyadic (fsLit "remInt#") intPrimTy+primOpInfo IntQuotRemOp = mkGenPrimOp (fsLit "quotRemInt#")  [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo AndIOp = mkDyadic (fsLit "andI#") intPrimTy+primOpInfo OrIOp = mkDyadic (fsLit "orI#") intPrimTy+primOpInfo XorIOp = mkDyadic (fsLit "xorI#") intPrimTy+primOpInfo NotIOp = mkMonadic (fsLit "notI#") intPrimTy+primOpInfo IntNegOp = mkMonadic (fsLit "negateInt#") intPrimTy+primOpInfo IntAddCOp = mkGenPrimOp (fsLit "addIntC#")  [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo IntSubCOp = mkGenPrimOp (fsLit "subIntC#")  [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo IntGtOp = mkCompare (fsLit ">#") intPrimTy+primOpInfo IntGeOp = mkCompare (fsLit ">=#") intPrimTy+primOpInfo IntEqOp = mkCompare (fsLit "==#") intPrimTy+primOpInfo IntNeOp = mkCompare (fsLit "/=#") intPrimTy+primOpInfo IntLtOp = mkCompare (fsLit "<#") intPrimTy+primOpInfo IntLeOp = mkCompare (fsLit "<=#") intPrimTy+primOpInfo ChrOp = mkGenPrimOp (fsLit "chr#")  [] [intPrimTy] (charPrimTy)+primOpInfo Int2WordOp = mkGenPrimOp (fsLit "int2Word#")  [] [intPrimTy] (wordPrimTy)+primOpInfo Int2FloatOp = mkGenPrimOp (fsLit "int2Float#")  [] [intPrimTy] (floatPrimTy)+primOpInfo Int2DoubleOp = mkGenPrimOp (fsLit "int2Double#")  [] [intPrimTy] (doublePrimTy)+primOpInfo Word2FloatOp = mkGenPrimOp (fsLit "word2Float#")  [] [wordPrimTy] (floatPrimTy)+primOpInfo Word2DoubleOp = mkGenPrimOp (fsLit "word2Double#")  [] [wordPrimTy] (doublePrimTy)+primOpInfo ISllOp = mkGenPrimOp (fsLit "uncheckedIShiftL#")  [] [intPrimTy, intPrimTy] (intPrimTy)+primOpInfo ISraOp = mkGenPrimOp (fsLit "uncheckedIShiftRA#")  [] [intPrimTy, intPrimTy] (intPrimTy)+primOpInfo ISrlOp = mkGenPrimOp (fsLit "uncheckedIShiftRL#")  [] [intPrimTy, intPrimTy] (intPrimTy) primOpInfo WordAddOp = mkDyadic (fsLit "plusWord#") wordPrimTy primOpInfo WordAddCOp = mkGenPrimOp (fsLit "addWordC#")  [] [wordPrimTy, wordPrimTy] ((mkTupleTy Unboxed [wordPrimTy, intPrimTy])) primOpInfo WordSubCOp = mkGenPrimOp (fsLit "subWordC#")  [] [wordPrimTy, wordPrimTy] ((mkTupleTy Unboxed [wordPrimTy, intPrimTy]))
ghc-lib/stage0/compiler/build/primop-tag.hs-incl view
@@ -1,1206 +1,1207 @@ maxPrimOpTag :: Int-maxPrimOpTag = 1203-primOpTag :: PrimOp -> Int-primOpTag CharGtOp = 1-primOpTag CharGeOp = 2-primOpTag CharEqOp = 3-primOpTag CharNeOp = 4-primOpTag CharLtOp = 5-primOpTag CharLeOp = 6-primOpTag OrdOp = 7-primOpTag IntAddOp = 8-primOpTag IntSubOp = 9-primOpTag IntMulOp = 10-primOpTag IntMulMayOfloOp = 11-primOpTag IntQuotOp = 12-primOpTag IntRemOp = 13-primOpTag IntQuotRemOp = 14-primOpTag AndIOp = 15-primOpTag OrIOp = 16-primOpTag XorIOp = 17-primOpTag NotIOp = 18-primOpTag IntNegOp = 19-primOpTag IntAddCOp = 20-primOpTag IntSubCOp = 21-primOpTag IntGtOp = 22-primOpTag IntGeOp = 23-primOpTag IntEqOp = 24-primOpTag IntNeOp = 25-primOpTag IntLtOp = 26-primOpTag IntLeOp = 27-primOpTag ChrOp = 28-primOpTag Int2WordOp = 29-primOpTag Int2FloatOp = 30-primOpTag Int2DoubleOp = 31-primOpTag Word2FloatOp = 32-primOpTag Word2DoubleOp = 33-primOpTag ISllOp = 34-primOpTag ISraOp = 35-primOpTag ISrlOp = 36-primOpTag Int8Extend = 37-primOpTag Int8Narrow = 38-primOpTag Int8NegOp = 39-primOpTag Int8AddOp = 40-primOpTag Int8SubOp = 41-primOpTag Int8MulOp = 42-primOpTag Int8QuotOp = 43-primOpTag Int8RemOp = 44-primOpTag Int8QuotRemOp = 45-primOpTag Int8EqOp = 46-primOpTag Int8GeOp = 47-primOpTag Int8GtOp = 48-primOpTag Int8LeOp = 49-primOpTag Int8LtOp = 50-primOpTag Int8NeOp = 51-primOpTag Word8Extend = 52-primOpTag Word8Narrow = 53-primOpTag Word8NotOp = 54-primOpTag Word8AddOp = 55-primOpTag Word8SubOp = 56-primOpTag Word8MulOp = 57-primOpTag Word8QuotOp = 58-primOpTag Word8RemOp = 59-primOpTag Word8QuotRemOp = 60-primOpTag Word8EqOp = 61-primOpTag Word8GeOp = 62-primOpTag Word8GtOp = 63-primOpTag Word8LeOp = 64-primOpTag Word8LtOp = 65-primOpTag Word8NeOp = 66-primOpTag Int16Extend = 67-primOpTag Int16Narrow = 68-primOpTag Int16NegOp = 69-primOpTag Int16AddOp = 70-primOpTag Int16SubOp = 71-primOpTag Int16MulOp = 72-primOpTag Int16QuotOp = 73-primOpTag Int16RemOp = 74-primOpTag Int16QuotRemOp = 75-primOpTag Int16EqOp = 76-primOpTag Int16GeOp = 77-primOpTag Int16GtOp = 78-primOpTag Int16LeOp = 79-primOpTag Int16LtOp = 80-primOpTag Int16NeOp = 81-primOpTag Word16Extend = 82-primOpTag Word16Narrow = 83-primOpTag Word16NotOp = 84-primOpTag Word16AddOp = 85-primOpTag Word16SubOp = 86-primOpTag Word16MulOp = 87-primOpTag Word16QuotOp = 88-primOpTag Word16RemOp = 89-primOpTag Word16QuotRemOp = 90-primOpTag Word16EqOp = 91-primOpTag Word16GeOp = 92-primOpTag Word16GtOp = 93-primOpTag Word16LeOp = 94-primOpTag Word16LtOp = 95-primOpTag Word16NeOp = 96-primOpTag WordAddOp = 97-primOpTag WordAddCOp = 98-primOpTag WordSubCOp = 99-primOpTag WordAdd2Op = 100-primOpTag WordSubOp = 101-primOpTag WordMulOp = 102-primOpTag WordMul2Op = 103-primOpTag WordQuotOp = 104-primOpTag WordRemOp = 105-primOpTag WordQuotRemOp = 106-primOpTag WordQuotRem2Op = 107-primOpTag AndOp = 108-primOpTag OrOp = 109-primOpTag XorOp = 110-primOpTag NotOp = 111-primOpTag SllOp = 112-primOpTag SrlOp = 113-primOpTag Word2IntOp = 114-primOpTag WordGtOp = 115-primOpTag WordGeOp = 116-primOpTag WordEqOp = 117-primOpTag WordNeOp = 118-primOpTag WordLtOp = 119-primOpTag WordLeOp = 120-primOpTag PopCnt8Op = 121-primOpTag PopCnt16Op = 122-primOpTag PopCnt32Op = 123-primOpTag PopCnt64Op = 124-primOpTag PopCntOp = 125-primOpTag Pdep8Op = 126-primOpTag Pdep16Op = 127-primOpTag Pdep32Op = 128-primOpTag Pdep64Op = 129-primOpTag PdepOp = 130-primOpTag Pext8Op = 131-primOpTag Pext16Op = 132-primOpTag Pext32Op = 133-primOpTag Pext64Op = 134-primOpTag PextOp = 135-primOpTag Clz8Op = 136-primOpTag Clz16Op = 137-primOpTag Clz32Op = 138-primOpTag Clz64Op = 139-primOpTag ClzOp = 140-primOpTag Ctz8Op = 141-primOpTag Ctz16Op = 142-primOpTag Ctz32Op = 143-primOpTag Ctz64Op = 144-primOpTag CtzOp = 145-primOpTag BSwap16Op = 146-primOpTag BSwap32Op = 147-primOpTag BSwap64Op = 148-primOpTag BSwapOp = 149-primOpTag BRev8Op = 150-primOpTag BRev16Op = 151-primOpTag BRev32Op = 152-primOpTag BRev64Op = 153-primOpTag BRevOp = 154-primOpTag Narrow8IntOp = 155-primOpTag Narrow16IntOp = 156-primOpTag Narrow32IntOp = 157-primOpTag Narrow8WordOp = 158-primOpTag Narrow16WordOp = 159-primOpTag Narrow32WordOp = 160-primOpTag DoubleGtOp = 161-primOpTag DoubleGeOp = 162-primOpTag DoubleEqOp = 163-primOpTag DoubleNeOp = 164-primOpTag DoubleLtOp = 165-primOpTag DoubleLeOp = 166-primOpTag DoubleAddOp = 167-primOpTag DoubleSubOp = 168-primOpTag DoubleMulOp = 169-primOpTag DoubleDivOp = 170-primOpTag DoubleNegOp = 171-primOpTag DoubleFabsOp = 172-primOpTag Double2IntOp = 173-primOpTag Double2FloatOp = 174-primOpTag DoubleExpOp = 175-primOpTag DoubleExpM1Op = 176-primOpTag DoubleLogOp = 177-primOpTag DoubleLog1POp = 178-primOpTag DoubleSqrtOp = 179-primOpTag DoubleSinOp = 180-primOpTag DoubleCosOp = 181-primOpTag DoubleTanOp = 182-primOpTag DoubleAsinOp = 183-primOpTag DoubleAcosOp = 184-primOpTag DoubleAtanOp = 185-primOpTag DoubleSinhOp = 186-primOpTag DoubleCoshOp = 187-primOpTag DoubleTanhOp = 188-primOpTag DoubleAsinhOp = 189-primOpTag DoubleAcoshOp = 190-primOpTag DoubleAtanhOp = 191-primOpTag DoublePowerOp = 192-primOpTag DoubleDecode_2IntOp = 193-primOpTag DoubleDecode_Int64Op = 194-primOpTag FloatGtOp = 195-primOpTag FloatGeOp = 196-primOpTag FloatEqOp = 197-primOpTag FloatNeOp = 198-primOpTag FloatLtOp = 199-primOpTag FloatLeOp = 200-primOpTag FloatAddOp = 201-primOpTag FloatSubOp = 202-primOpTag FloatMulOp = 203-primOpTag FloatDivOp = 204-primOpTag FloatNegOp = 205-primOpTag FloatFabsOp = 206-primOpTag Float2IntOp = 207-primOpTag FloatExpOp = 208-primOpTag FloatExpM1Op = 209-primOpTag FloatLogOp = 210-primOpTag FloatLog1POp = 211-primOpTag FloatSqrtOp = 212-primOpTag FloatSinOp = 213-primOpTag FloatCosOp = 214-primOpTag FloatTanOp = 215-primOpTag FloatAsinOp = 216-primOpTag FloatAcosOp = 217-primOpTag FloatAtanOp = 218-primOpTag FloatSinhOp = 219-primOpTag FloatCoshOp = 220-primOpTag FloatTanhOp = 221-primOpTag FloatAsinhOp = 222-primOpTag FloatAcoshOp = 223-primOpTag FloatAtanhOp = 224-primOpTag FloatPowerOp = 225-primOpTag Float2DoubleOp = 226-primOpTag FloatDecode_IntOp = 227-primOpTag NewArrayOp = 228-primOpTag SameMutableArrayOp = 229-primOpTag ReadArrayOp = 230-primOpTag WriteArrayOp = 231-primOpTag SizeofArrayOp = 232-primOpTag SizeofMutableArrayOp = 233-primOpTag IndexArrayOp = 234-primOpTag UnsafeFreezeArrayOp = 235-primOpTag UnsafeThawArrayOp = 236-primOpTag CopyArrayOp = 237-primOpTag CopyMutableArrayOp = 238-primOpTag CloneArrayOp = 239-primOpTag CloneMutableArrayOp = 240-primOpTag FreezeArrayOp = 241-primOpTag ThawArrayOp = 242-primOpTag CasArrayOp = 243-primOpTag NewSmallArrayOp = 244-primOpTag SameSmallMutableArrayOp = 245-primOpTag ShrinkSmallMutableArrayOp_Char = 246-primOpTag ReadSmallArrayOp = 247-primOpTag WriteSmallArrayOp = 248-primOpTag SizeofSmallArrayOp = 249-primOpTag SizeofSmallMutableArrayOp = 250-primOpTag GetSizeofSmallMutableArrayOp = 251-primOpTag IndexSmallArrayOp = 252-primOpTag UnsafeFreezeSmallArrayOp = 253-primOpTag UnsafeThawSmallArrayOp = 254-primOpTag CopySmallArrayOp = 255-primOpTag CopySmallMutableArrayOp = 256-primOpTag CloneSmallArrayOp = 257-primOpTag CloneSmallMutableArrayOp = 258-primOpTag FreezeSmallArrayOp = 259-primOpTag ThawSmallArrayOp = 260-primOpTag CasSmallArrayOp = 261-primOpTag NewByteArrayOp_Char = 262-primOpTag NewPinnedByteArrayOp_Char = 263-primOpTag NewAlignedPinnedByteArrayOp_Char = 264-primOpTag MutableByteArrayIsPinnedOp = 265-primOpTag ByteArrayIsPinnedOp = 266-primOpTag ByteArrayContents_Char = 267-primOpTag SameMutableByteArrayOp = 268-primOpTag ShrinkMutableByteArrayOp_Char = 269-primOpTag ResizeMutableByteArrayOp_Char = 270-primOpTag UnsafeFreezeByteArrayOp = 271-primOpTag SizeofByteArrayOp = 272-primOpTag SizeofMutableByteArrayOp = 273-primOpTag GetSizeofMutableByteArrayOp = 274-primOpTag IndexByteArrayOp_Char = 275-primOpTag IndexByteArrayOp_WideChar = 276-primOpTag IndexByteArrayOp_Int = 277-primOpTag IndexByteArrayOp_Word = 278-primOpTag IndexByteArrayOp_Addr = 279-primOpTag IndexByteArrayOp_Float = 280-primOpTag IndexByteArrayOp_Double = 281-primOpTag IndexByteArrayOp_StablePtr = 282-primOpTag IndexByteArrayOp_Int8 = 283-primOpTag IndexByteArrayOp_Int16 = 284-primOpTag IndexByteArrayOp_Int32 = 285-primOpTag IndexByteArrayOp_Int64 = 286-primOpTag IndexByteArrayOp_Word8 = 287-primOpTag IndexByteArrayOp_Word16 = 288-primOpTag IndexByteArrayOp_Word32 = 289-primOpTag IndexByteArrayOp_Word64 = 290-primOpTag IndexByteArrayOp_Word8AsChar = 291-primOpTag IndexByteArrayOp_Word8AsWideChar = 292-primOpTag IndexByteArrayOp_Word8AsAddr = 293-primOpTag IndexByteArrayOp_Word8AsFloat = 294-primOpTag IndexByteArrayOp_Word8AsDouble = 295-primOpTag IndexByteArrayOp_Word8AsStablePtr = 296-primOpTag IndexByteArrayOp_Word8AsInt16 = 297-primOpTag IndexByteArrayOp_Word8AsInt32 = 298-primOpTag IndexByteArrayOp_Word8AsInt64 = 299-primOpTag IndexByteArrayOp_Word8AsInt = 300-primOpTag IndexByteArrayOp_Word8AsWord16 = 301-primOpTag IndexByteArrayOp_Word8AsWord32 = 302-primOpTag IndexByteArrayOp_Word8AsWord64 = 303-primOpTag IndexByteArrayOp_Word8AsWord = 304-primOpTag ReadByteArrayOp_Char = 305-primOpTag ReadByteArrayOp_WideChar = 306-primOpTag ReadByteArrayOp_Int = 307-primOpTag ReadByteArrayOp_Word = 308-primOpTag ReadByteArrayOp_Addr = 309-primOpTag ReadByteArrayOp_Float = 310-primOpTag ReadByteArrayOp_Double = 311-primOpTag ReadByteArrayOp_StablePtr = 312-primOpTag ReadByteArrayOp_Int8 = 313-primOpTag ReadByteArrayOp_Int16 = 314-primOpTag ReadByteArrayOp_Int32 = 315-primOpTag ReadByteArrayOp_Int64 = 316-primOpTag ReadByteArrayOp_Word8 = 317-primOpTag ReadByteArrayOp_Word16 = 318-primOpTag ReadByteArrayOp_Word32 = 319-primOpTag ReadByteArrayOp_Word64 = 320-primOpTag ReadByteArrayOp_Word8AsChar = 321-primOpTag ReadByteArrayOp_Word8AsWideChar = 322-primOpTag ReadByteArrayOp_Word8AsAddr = 323-primOpTag ReadByteArrayOp_Word8AsFloat = 324-primOpTag ReadByteArrayOp_Word8AsDouble = 325-primOpTag ReadByteArrayOp_Word8AsStablePtr = 326-primOpTag ReadByteArrayOp_Word8AsInt16 = 327-primOpTag ReadByteArrayOp_Word8AsInt32 = 328-primOpTag ReadByteArrayOp_Word8AsInt64 = 329-primOpTag ReadByteArrayOp_Word8AsInt = 330-primOpTag ReadByteArrayOp_Word8AsWord16 = 331-primOpTag ReadByteArrayOp_Word8AsWord32 = 332-primOpTag ReadByteArrayOp_Word8AsWord64 = 333-primOpTag ReadByteArrayOp_Word8AsWord = 334-primOpTag WriteByteArrayOp_Char = 335-primOpTag WriteByteArrayOp_WideChar = 336-primOpTag WriteByteArrayOp_Int = 337-primOpTag WriteByteArrayOp_Word = 338-primOpTag WriteByteArrayOp_Addr = 339-primOpTag WriteByteArrayOp_Float = 340-primOpTag WriteByteArrayOp_Double = 341-primOpTag WriteByteArrayOp_StablePtr = 342-primOpTag WriteByteArrayOp_Int8 = 343-primOpTag WriteByteArrayOp_Int16 = 344-primOpTag WriteByteArrayOp_Int32 = 345-primOpTag WriteByteArrayOp_Int64 = 346-primOpTag WriteByteArrayOp_Word8 = 347-primOpTag WriteByteArrayOp_Word16 = 348-primOpTag WriteByteArrayOp_Word32 = 349-primOpTag WriteByteArrayOp_Word64 = 350-primOpTag WriteByteArrayOp_Word8AsChar = 351-primOpTag WriteByteArrayOp_Word8AsWideChar = 352-primOpTag WriteByteArrayOp_Word8AsAddr = 353-primOpTag WriteByteArrayOp_Word8AsFloat = 354-primOpTag WriteByteArrayOp_Word8AsDouble = 355-primOpTag WriteByteArrayOp_Word8AsStablePtr = 356-primOpTag WriteByteArrayOp_Word8AsInt16 = 357-primOpTag WriteByteArrayOp_Word8AsInt32 = 358-primOpTag WriteByteArrayOp_Word8AsInt64 = 359-primOpTag WriteByteArrayOp_Word8AsInt = 360-primOpTag WriteByteArrayOp_Word8AsWord16 = 361-primOpTag WriteByteArrayOp_Word8AsWord32 = 362-primOpTag WriteByteArrayOp_Word8AsWord64 = 363-primOpTag WriteByteArrayOp_Word8AsWord = 364-primOpTag CompareByteArraysOp = 365-primOpTag CopyByteArrayOp = 366-primOpTag CopyMutableByteArrayOp = 367-primOpTag CopyByteArrayToAddrOp = 368-primOpTag CopyMutableByteArrayToAddrOp = 369-primOpTag CopyAddrToByteArrayOp = 370-primOpTag SetByteArrayOp = 371-primOpTag AtomicReadByteArrayOp_Int = 372-primOpTag AtomicWriteByteArrayOp_Int = 373-primOpTag CasByteArrayOp_Int = 374-primOpTag FetchAddByteArrayOp_Int = 375-primOpTag FetchSubByteArrayOp_Int = 376-primOpTag FetchAndByteArrayOp_Int = 377-primOpTag FetchNandByteArrayOp_Int = 378-primOpTag FetchOrByteArrayOp_Int = 379-primOpTag FetchXorByteArrayOp_Int = 380-primOpTag NewArrayArrayOp = 381-primOpTag SameMutableArrayArrayOp = 382-primOpTag UnsafeFreezeArrayArrayOp = 383-primOpTag SizeofArrayArrayOp = 384-primOpTag SizeofMutableArrayArrayOp = 385-primOpTag IndexArrayArrayOp_ByteArray = 386-primOpTag IndexArrayArrayOp_ArrayArray = 387-primOpTag ReadArrayArrayOp_ByteArray = 388-primOpTag ReadArrayArrayOp_MutableByteArray = 389-primOpTag ReadArrayArrayOp_ArrayArray = 390-primOpTag ReadArrayArrayOp_MutableArrayArray = 391-primOpTag WriteArrayArrayOp_ByteArray = 392-primOpTag WriteArrayArrayOp_MutableByteArray = 393-primOpTag WriteArrayArrayOp_ArrayArray = 394-primOpTag WriteArrayArrayOp_MutableArrayArray = 395-primOpTag CopyArrayArrayOp = 396-primOpTag CopyMutableArrayArrayOp = 397-primOpTag AddrAddOp = 398-primOpTag AddrSubOp = 399-primOpTag AddrRemOp = 400-primOpTag Addr2IntOp = 401-primOpTag Int2AddrOp = 402-primOpTag AddrGtOp = 403-primOpTag AddrGeOp = 404-primOpTag AddrEqOp = 405-primOpTag AddrNeOp = 406-primOpTag AddrLtOp = 407-primOpTag AddrLeOp = 408-primOpTag IndexOffAddrOp_Char = 409-primOpTag IndexOffAddrOp_WideChar = 410-primOpTag IndexOffAddrOp_Int = 411-primOpTag IndexOffAddrOp_Word = 412-primOpTag IndexOffAddrOp_Addr = 413-primOpTag IndexOffAddrOp_Float = 414-primOpTag IndexOffAddrOp_Double = 415-primOpTag IndexOffAddrOp_StablePtr = 416-primOpTag IndexOffAddrOp_Int8 = 417-primOpTag IndexOffAddrOp_Int16 = 418-primOpTag IndexOffAddrOp_Int32 = 419-primOpTag IndexOffAddrOp_Int64 = 420-primOpTag IndexOffAddrOp_Word8 = 421-primOpTag IndexOffAddrOp_Word16 = 422-primOpTag IndexOffAddrOp_Word32 = 423-primOpTag IndexOffAddrOp_Word64 = 424-primOpTag ReadOffAddrOp_Char = 425-primOpTag ReadOffAddrOp_WideChar = 426-primOpTag ReadOffAddrOp_Int = 427-primOpTag ReadOffAddrOp_Word = 428-primOpTag ReadOffAddrOp_Addr = 429-primOpTag ReadOffAddrOp_Float = 430-primOpTag ReadOffAddrOp_Double = 431-primOpTag ReadOffAddrOp_StablePtr = 432-primOpTag ReadOffAddrOp_Int8 = 433-primOpTag ReadOffAddrOp_Int16 = 434-primOpTag ReadOffAddrOp_Int32 = 435-primOpTag ReadOffAddrOp_Int64 = 436-primOpTag ReadOffAddrOp_Word8 = 437-primOpTag ReadOffAddrOp_Word16 = 438-primOpTag ReadOffAddrOp_Word32 = 439-primOpTag ReadOffAddrOp_Word64 = 440-primOpTag WriteOffAddrOp_Char = 441-primOpTag WriteOffAddrOp_WideChar = 442-primOpTag WriteOffAddrOp_Int = 443-primOpTag WriteOffAddrOp_Word = 444-primOpTag WriteOffAddrOp_Addr = 445-primOpTag WriteOffAddrOp_Float = 446-primOpTag WriteOffAddrOp_Double = 447-primOpTag WriteOffAddrOp_StablePtr = 448-primOpTag WriteOffAddrOp_Int8 = 449-primOpTag WriteOffAddrOp_Int16 = 450-primOpTag WriteOffAddrOp_Int32 = 451-primOpTag WriteOffAddrOp_Int64 = 452-primOpTag WriteOffAddrOp_Word8 = 453-primOpTag WriteOffAddrOp_Word16 = 454-primOpTag WriteOffAddrOp_Word32 = 455-primOpTag WriteOffAddrOp_Word64 = 456-primOpTag NewMutVarOp = 457-primOpTag ReadMutVarOp = 458-primOpTag WriteMutVarOp = 459-primOpTag SameMutVarOp = 460-primOpTag AtomicModifyMutVar2Op = 461-primOpTag AtomicModifyMutVar_Op = 462-primOpTag CasMutVarOp = 463-primOpTag CatchOp = 464-primOpTag RaiseOp = 465-primOpTag RaiseIOOp = 466-primOpTag MaskAsyncExceptionsOp = 467-primOpTag MaskUninterruptibleOp = 468-primOpTag UnmaskAsyncExceptionsOp = 469-primOpTag MaskStatus = 470-primOpTag AtomicallyOp = 471-primOpTag RetryOp = 472-primOpTag CatchRetryOp = 473-primOpTag CatchSTMOp = 474-primOpTag NewTVarOp = 475-primOpTag ReadTVarOp = 476-primOpTag ReadTVarIOOp = 477-primOpTag WriteTVarOp = 478-primOpTag SameTVarOp = 479-primOpTag NewMVarOp = 480-primOpTag TakeMVarOp = 481-primOpTag TryTakeMVarOp = 482-primOpTag PutMVarOp = 483-primOpTag TryPutMVarOp = 484-primOpTag ReadMVarOp = 485-primOpTag TryReadMVarOp = 486-primOpTag SameMVarOp = 487-primOpTag IsEmptyMVarOp = 488-primOpTag DelayOp = 489-primOpTag WaitReadOp = 490-primOpTag WaitWriteOp = 491-primOpTag ForkOp = 492-primOpTag ForkOnOp = 493-primOpTag KillThreadOp = 494-primOpTag YieldOp = 495-primOpTag MyThreadIdOp = 496-primOpTag LabelThreadOp = 497-primOpTag IsCurrentThreadBoundOp = 498-primOpTag NoDuplicateOp = 499-primOpTag ThreadStatusOp = 500-primOpTag MkWeakOp = 501-primOpTag MkWeakNoFinalizerOp = 502-primOpTag AddCFinalizerToWeakOp = 503-primOpTag DeRefWeakOp = 504-primOpTag FinalizeWeakOp = 505-primOpTag TouchOp = 506-primOpTag MakeStablePtrOp = 507-primOpTag DeRefStablePtrOp = 508-primOpTag EqStablePtrOp = 509-primOpTag MakeStableNameOp = 510-primOpTag EqStableNameOp = 511-primOpTag StableNameToIntOp = 512-primOpTag CompactNewOp = 513-primOpTag CompactResizeOp = 514-primOpTag CompactContainsOp = 515-primOpTag CompactContainsAnyOp = 516-primOpTag CompactGetFirstBlockOp = 517-primOpTag CompactGetNextBlockOp = 518-primOpTag CompactAllocateBlockOp = 519-primOpTag CompactFixupPointersOp = 520-primOpTag CompactAdd = 521-primOpTag CompactAddWithSharing = 522-primOpTag CompactSize = 523-primOpTag ReallyUnsafePtrEqualityOp = 524-primOpTag ParOp = 525-primOpTag SparkOp = 526-primOpTag SeqOp = 527-primOpTag GetSparkOp = 528-primOpTag NumSparks = 529-primOpTag DataToTagOp = 530-primOpTag TagToEnumOp = 531-primOpTag AddrToAnyOp = 532-primOpTag AnyToAddrOp = 533-primOpTag MkApUpd0_Op = 534-primOpTag NewBCOOp = 535-primOpTag UnpackClosureOp = 536-primOpTag ClosureSizeOp = 537-primOpTag GetApStackValOp = 538-primOpTag GetCCSOfOp = 539-primOpTag GetCurrentCCSOp = 540-primOpTag ClearCCSOp = 541-primOpTag TraceEventOp = 542-primOpTag TraceEventBinaryOp = 543-primOpTag TraceMarkerOp = 544-primOpTag SetThreadAllocationCounter = 545-primOpTag (VecBroadcastOp IntVec 16 W8) = 546-primOpTag (VecBroadcastOp IntVec 8 W16) = 547-primOpTag (VecBroadcastOp IntVec 4 W32) = 548-primOpTag (VecBroadcastOp IntVec 2 W64) = 549-primOpTag (VecBroadcastOp IntVec 32 W8) = 550-primOpTag (VecBroadcastOp IntVec 16 W16) = 551-primOpTag (VecBroadcastOp IntVec 8 W32) = 552-primOpTag (VecBroadcastOp IntVec 4 W64) = 553-primOpTag (VecBroadcastOp IntVec 64 W8) = 554-primOpTag (VecBroadcastOp IntVec 32 W16) = 555-primOpTag (VecBroadcastOp IntVec 16 W32) = 556-primOpTag (VecBroadcastOp IntVec 8 W64) = 557-primOpTag (VecBroadcastOp WordVec 16 W8) = 558-primOpTag (VecBroadcastOp WordVec 8 W16) = 559-primOpTag (VecBroadcastOp WordVec 4 W32) = 560-primOpTag (VecBroadcastOp WordVec 2 W64) = 561-primOpTag (VecBroadcastOp WordVec 32 W8) = 562-primOpTag (VecBroadcastOp WordVec 16 W16) = 563-primOpTag (VecBroadcastOp WordVec 8 W32) = 564-primOpTag (VecBroadcastOp WordVec 4 W64) = 565-primOpTag (VecBroadcastOp WordVec 64 W8) = 566-primOpTag (VecBroadcastOp WordVec 32 W16) = 567-primOpTag (VecBroadcastOp WordVec 16 W32) = 568-primOpTag (VecBroadcastOp WordVec 8 W64) = 569-primOpTag (VecBroadcastOp FloatVec 4 W32) = 570-primOpTag (VecBroadcastOp FloatVec 2 W64) = 571-primOpTag (VecBroadcastOp FloatVec 8 W32) = 572-primOpTag (VecBroadcastOp FloatVec 4 W64) = 573-primOpTag (VecBroadcastOp FloatVec 16 W32) = 574-primOpTag (VecBroadcastOp FloatVec 8 W64) = 575-primOpTag (VecPackOp IntVec 16 W8) = 576-primOpTag (VecPackOp IntVec 8 W16) = 577-primOpTag (VecPackOp IntVec 4 W32) = 578-primOpTag (VecPackOp IntVec 2 W64) = 579-primOpTag (VecPackOp IntVec 32 W8) = 580-primOpTag (VecPackOp IntVec 16 W16) = 581-primOpTag (VecPackOp IntVec 8 W32) = 582-primOpTag (VecPackOp IntVec 4 W64) = 583-primOpTag (VecPackOp IntVec 64 W8) = 584-primOpTag (VecPackOp IntVec 32 W16) = 585-primOpTag (VecPackOp IntVec 16 W32) = 586-primOpTag (VecPackOp IntVec 8 W64) = 587-primOpTag (VecPackOp WordVec 16 W8) = 588-primOpTag (VecPackOp WordVec 8 W16) = 589-primOpTag (VecPackOp WordVec 4 W32) = 590-primOpTag (VecPackOp WordVec 2 W64) = 591-primOpTag (VecPackOp WordVec 32 W8) = 592-primOpTag (VecPackOp WordVec 16 W16) = 593-primOpTag (VecPackOp WordVec 8 W32) = 594-primOpTag (VecPackOp WordVec 4 W64) = 595-primOpTag (VecPackOp WordVec 64 W8) = 596-primOpTag (VecPackOp WordVec 32 W16) = 597-primOpTag (VecPackOp WordVec 16 W32) = 598-primOpTag (VecPackOp WordVec 8 W64) = 599-primOpTag (VecPackOp FloatVec 4 W32) = 600-primOpTag (VecPackOp FloatVec 2 W64) = 601-primOpTag (VecPackOp FloatVec 8 W32) = 602-primOpTag (VecPackOp FloatVec 4 W64) = 603-primOpTag (VecPackOp FloatVec 16 W32) = 604-primOpTag (VecPackOp FloatVec 8 W64) = 605-primOpTag (VecUnpackOp IntVec 16 W8) = 606-primOpTag (VecUnpackOp IntVec 8 W16) = 607-primOpTag (VecUnpackOp IntVec 4 W32) = 608-primOpTag (VecUnpackOp IntVec 2 W64) = 609-primOpTag (VecUnpackOp IntVec 32 W8) = 610-primOpTag (VecUnpackOp IntVec 16 W16) = 611-primOpTag (VecUnpackOp IntVec 8 W32) = 612-primOpTag (VecUnpackOp IntVec 4 W64) = 613-primOpTag (VecUnpackOp IntVec 64 W8) = 614-primOpTag (VecUnpackOp IntVec 32 W16) = 615-primOpTag (VecUnpackOp IntVec 16 W32) = 616-primOpTag (VecUnpackOp IntVec 8 W64) = 617-primOpTag (VecUnpackOp WordVec 16 W8) = 618-primOpTag (VecUnpackOp WordVec 8 W16) = 619-primOpTag (VecUnpackOp WordVec 4 W32) = 620-primOpTag (VecUnpackOp WordVec 2 W64) = 621-primOpTag (VecUnpackOp WordVec 32 W8) = 622-primOpTag (VecUnpackOp WordVec 16 W16) = 623-primOpTag (VecUnpackOp WordVec 8 W32) = 624-primOpTag (VecUnpackOp WordVec 4 W64) = 625-primOpTag (VecUnpackOp WordVec 64 W8) = 626-primOpTag (VecUnpackOp WordVec 32 W16) = 627-primOpTag (VecUnpackOp WordVec 16 W32) = 628-primOpTag (VecUnpackOp WordVec 8 W64) = 629-primOpTag (VecUnpackOp FloatVec 4 W32) = 630-primOpTag (VecUnpackOp FloatVec 2 W64) = 631-primOpTag (VecUnpackOp FloatVec 8 W32) = 632-primOpTag (VecUnpackOp FloatVec 4 W64) = 633-primOpTag (VecUnpackOp FloatVec 16 W32) = 634-primOpTag (VecUnpackOp FloatVec 8 W64) = 635-primOpTag (VecInsertOp IntVec 16 W8) = 636-primOpTag (VecInsertOp IntVec 8 W16) = 637-primOpTag (VecInsertOp IntVec 4 W32) = 638-primOpTag (VecInsertOp IntVec 2 W64) = 639-primOpTag (VecInsertOp IntVec 32 W8) = 640-primOpTag (VecInsertOp IntVec 16 W16) = 641-primOpTag (VecInsertOp IntVec 8 W32) = 642-primOpTag (VecInsertOp IntVec 4 W64) = 643-primOpTag (VecInsertOp IntVec 64 W8) = 644-primOpTag (VecInsertOp IntVec 32 W16) = 645-primOpTag (VecInsertOp IntVec 16 W32) = 646-primOpTag (VecInsertOp IntVec 8 W64) = 647-primOpTag (VecInsertOp WordVec 16 W8) = 648-primOpTag (VecInsertOp WordVec 8 W16) = 649-primOpTag (VecInsertOp WordVec 4 W32) = 650-primOpTag (VecInsertOp WordVec 2 W64) = 651-primOpTag (VecInsertOp WordVec 32 W8) = 652-primOpTag (VecInsertOp WordVec 16 W16) = 653-primOpTag (VecInsertOp WordVec 8 W32) = 654-primOpTag (VecInsertOp WordVec 4 W64) = 655-primOpTag (VecInsertOp WordVec 64 W8) = 656-primOpTag (VecInsertOp WordVec 32 W16) = 657-primOpTag (VecInsertOp WordVec 16 W32) = 658-primOpTag (VecInsertOp WordVec 8 W64) = 659-primOpTag (VecInsertOp FloatVec 4 W32) = 660-primOpTag (VecInsertOp FloatVec 2 W64) = 661-primOpTag (VecInsertOp FloatVec 8 W32) = 662-primOpTag (VecInsertOp FloatVec 4 W64) = 663-primOpTag (VecInsertOp FloatVec 16 W32) = 664-primOpTag (VecInsertOp FloatVec 8 W64) = 665-primOpTag (VecAddOp IntVec 16 W8) = 666-primOpTag (VecAddOp IntVec 8 W16) = 667-primOpTag (VecAddOp IntVec 4 W32) = 668-primOpTag (VecAddOp IntVec 2 W64) = 669-primOpTag (VecAddOp IntVec 32 W8) = 670-primOpTag (VecAddOp IntVec 16 W16) = 671-primOpTag (VecAddOp IntVec 8 W32) = 672-primOpTag (VecAddOp IntVec 4 W64) = 673-primOpTag (VecAddOp IntVec 64 W8) = 674-primOpTag (VecAddOp IntVec 32 W16) = 675-primOpTag (VecAddOp IntVec 16 W32) = 676-primOpTag (VecAddOp IntVec 8 W64) = 677-primOpTag (VecAddOp WordVec 16 W8) = 678-primOpTag (VecAddOp WordVec 8 W16) = 679-primOpTag (VecAddOp WordVec 4 W32) = 680-primOpTag (VecAddOp WordVec 2 W64) = 681-primOpTag (VecAddOp WordVec 32 W8) = 682-primOpTag (VecAddOp WordVec 16 W16) = 683-primOpTag (VecAddOp WordVec 8 W32) = 684-primOpTag (VecAddOp WordVec 4 W64) = 685-primOpTag (VecAddOp WordVec 64 W8) = 686-primOpTag (VecAddOp WordVec 32 W16) = 687-primOpTag (VecAddOp WordVec 16 W32) = 688-primOpTag (VecAddOp WordVec 8 W64) = 689-primOpTag (VecAddOp FloatVec 4 W32) = 690-primOpTag (VecAddOp FloatVec 2 W64) = 691-primOpTag (VecAddOp FloatVec 8 W32) = 692-primOpTag (VecAddOp FloatVec 4 W64) = 693-primOpTag (VecAddOp FloatVec 16 W32) = 694-primOpTag (VecAddOp FloatVec 8 W64) = 695-primOpTag (VecSubOp IntVec 16 W8) = 696-primOpTag (VecSubOp IntVec 8 W16) = 697-primOpTag (VecSubOp IntVec 4 W32) = 698-primOpTag (VecSubOp IntVec 2 W64) = 699-primOpTag (VecSubOp IntVec 32 W8) = 700-primOpTag (VecSubOp IntVec 16 W16) = 701-primOpTag (VecSubOp IntVec 8 W32) = 702-primOpTag (VecSubOp IntVec 4 W64) = 703-primOpTag (VecSubOp IntVec 64 W8) = 704-primOpTag (VecSubOp IntVec 32 W16) = 705-primOpTag (VecSubOp IntVec 16 W32) = 706-primOpTag (VecSubOp IntVec 8 W64) = 707-primOpTag (VecSubOp WordVec 16 W8) = 708-primOpTag (VecSubOp WordVec 8 W16) = 709-primOpTag (VecSubOp WordVec 4 W32) = 710-primOpTag (VecSubOp WordVec 2 W64) = 711-primOpTag (VecSubOp WordVec 32 W8) = 712-primOpTag (VecSubOp WordVec 16 W16) = 713-primOpTag (VecSubOp WordVec 8 W32) = 714-primOpTag (VecSubOp WordVec 4 W64) = 715-primOpTag (VecSubOp WordVec 64 W8) = 716-primOpTag (VecSubOp WordVec 32 W16) = 717-primOpTag (VecSubOp WordVec 16 W32) = 718-primOpTag (VecSubOp WordVec 8 W64) = 719-primOpTag (VecSubOp FloatVec 4 W32) = 720-primOpTag (VecSubOp FloatVec 2 W64) = 721-primOpTag (VecSubOp FloatVec 8 W32) = 722-primOpTag (VecSubOp FloatVec 4 W64) = 723-primOpTag (VecSubOp FloatVec 16 W32) = 724-primOpTag (VecSubOp FloatVec 8 W64) = 725-primOpTag (VecMulOp IntVec 16 W8) = 726-primOpTag (VecMulOp IntVec 8 W16) = 727-primOpTag (VecMulOp IntVec 4 W32) = 728-primOpTag (VecMulOp IntVec 2 W64) = 729-primOpTag (VecMulOp IntVec 32 W8) = 730-primOpTag (VecMulOp IntVec 16 W16) = 731-primOpTag (VecMulOp IntVec 8 W32) = 732-primOpTag (VecMulOp IntVec 4 W64) = 733-primOpTag (VecMulOp IntVec 64 W8) = 734-primOpTag (VecMulOp IntVec 32 W16) = 735-primOpTag (VecMulOp IntVec 16 W32) = 736-primOpTag (VecMulOp IntVec 8 W64) = 737-primOpTag (VecMulOp WordVec 16 W8) = 738-primOpTag (VecMulOp WordVec 8 W16) = 739-primOpTag (VecMulOp WordVec 4 W32) = 740-primOpTag (VecMulOp WordVec 2 W64) = 741-primOpTag (VecMulOp WordVec 32 W8) = 742-primOpTag (VecMulOp WordVec 16 W16) = 743-primOpTag (VecMulOp WordVec 8 W32) = 744-primOpTag (VecMulOp WordVec 4 W64) = 745-primOpTag (VecMulOp WordVec 64 W8) = 746-primOpTag (VecMulOp WordVec 32 W16) = 747-primOpTag (VecMulOp WordVec 16 W32) = 748-primOpTag (VecMulOp WordVec 8 W64) = 749-primOpTag (VecMulOp FloatVec 4 W32) = 750-primOpTag (VecMulOp FloatVec 2 W64) = 751-primOpTag (VecMulOp FloatVec 8 W32) = 752-primOpTag (VecMulOp FloatVec 4 W64) = 753-primOpTag (VecMulOp FloatVec 16 W32) = 754-primOpTag (VecMulOp FloatVec 8 W64) = 755-primOpTag (VecDivOp FloatVec 4 W32) = 756-primOpTag (VecDivOp FloatVec 2 W64) = 757-primOpTag (VecDivOp FloatVec 8 W32) = 758-primOpTag (VecDivOp FloatVec 4 W64) = 759-primOpTag (VecDivOp FloatVec 16 W32) = 760-primOpTag (VecDivOp FloatVec 8 W64) = 761-primOpTag (VecQuotOp IntVec 16 W8) = 762-primOpTag (VecQuotOp IntVec 8 W16) = 763-primOpTag (VecQuotOp IntVec 4 W32) = 764-primOpTag (VecQuotOp IntVec 2 W64) = 765-primOpTag (VecQuotOp IntVec 32 W8) = 766-primOpTag (VecQuotOp IntVec 16 W16) = 767-primOpTag (VecQuotOp IntVec 8 W32) = 768-primOpTag (VecQuotOp IntVec 4 W64) = 769-primOpTag (VecQuotOp IntVec 64 W8) = 770-primOpTag (VecQuotOp IntVec 32 W16) = 771-primOpTag (VecQuotOp IntVec 16 W32) = 772-primOpTag (VecQuotOp IntVec 8 W64) = 773-primOpTag (VecQuotOp WordVec 16 W8) = 774-primOpTag (VecQuotOp WordVec 8 W16) = 775-primOpTag (VecQuotOp WordVec 4 W32) = 776-primOpTag (VecQuotOp WordVec 2 W64) = 777-primOpTag (VecQuotOp WordVec 32 W8) = 778-primOpTag (VecQuotOp WordVec 16 W16) = 779-primOpTag (VecQuotOp WordVec 8 W32) = 780-primOpTag (VecQuotOp WordVec 4 W64) = 781-primOpTag (VecQuotOp WordVec 64 W8) = 782-primOpTag (VecQuotOp WordVec 32 W16) = 783-primOpTag (VecQuotOp WordVec 16 W32) = 784-primOpTag (VecQuotOp WordVec 8 W64) = 785-primOpTag (VecRemOp IntVec 16 W8) = 786-primOpTag (VecRemOp IntVec 8 W16) = 787-primOpTag (VecRemOp IntVec 4 W32) = 788-primOpTag (VecRemOp IntVec 2 W64) = 789-primOpTag (VecRemOp IntVec 32 W8) = 790-primOpTag (VecRemOp IntVec 16 W16) = 791-primOpTag (VecRemOp IntVec 8 W32) = 792-primOpTag (VecRemOp IntVec 4 W64) = 793-primOpTag (VecRemOp IntVec 64 W8) = 794-primOpTag (VecRemOp IntVec 32 W16) = 795-primOpTag (VecRemOp IntVec 16 W32) = 796-primOpTag (VecRemOp IntVec 8 W64) = 797-primOpTag (VecRemOp WordVec 16 W8) = 798-primOpTag (VecRemOp WordVec 8 W16) = 799-primOpTag (VecRemOp WordVec 4 W32) = 800-primOpTag (VecRemOp WordVec 2 W64) = 801-primOpTag (VecRemOp WordVec 32 W8) = 802-primOpTag (VecRemOp WordVec 16 W16) = 803-primOpTag (VecRemOp WordVec 8 W32) = 804-primOpTag (VecRemOp WordVec 4 W64) = 805-primOpTag (VecRemOp WordVec 64 W8) = 806-primOpTag (VecRemOp WordVec 32 W16) = 807-primOpTag (VecRemOp WordVec 16 W32) = 808-primOpTag (VecRemOp WordVec 8 W64) = 809-primOpTag (VecNegOp IntVec 16 W8) = 810-primOpTag (VecNegOp IntVec 8 W16) = 811-primOpTag (VecNegOp IntVec 4 W32) = 812-primOpTag (VecNegOp IntVec 2 W64) = 813-primOpTag (VecNegOp IntVec 32 W8) = 814-primOpTag (VecNegOp IntVec 16 W16) = 815-primOpTag (VecNegOp IntVec 8 W32) = 816-primOpTag (VecNegOp IntVec 4 W64) = 817-primOpTag (VecNegOp IntVec 64 W8) = 818-primOpTag (VecNegOp IntVec 32 W16) = 819-primOpTag (VecNegOp IntVec 16 W32) = 820-primOpTag (VecNegOp IntVec 8 W64) = 821-primOpTag (VecNegOp FloatVec 4 W32) = 822-primOpTag (VecNegOp FloatVec 2 W64) = 823-primOpTag (VecNegOp FloatVec 8 W32) = 824-primOpTag (VecNegOp FloatVec 4 W64) = 825-primOpTag (VecNegOp FloatVec 16 W32) = 826-primOpTag (VecNegOp FloatVec 8 W64) = 827-primOpTag (VecIndexByteArrayOp IntVec 16 W8) = 828-primOpTag (VecIndexByteArrayOp IntVec 8 W16) = 829-primOpTag (VecIndexByteArrayOp IntVec 4 W32) = 830-primOpTag (VecIndexByteArrayOp IntVec 2 W64) = 831-primOpTag (VecIndexByteArrayOp IntVec 32 W8) = 832-primOpTag (VecIndexByteArrayOp IntVec 16 W16) = 833-primOpTag (VecIndexByteArrayOp IntVec 8 W32) = 834-primOpTag (VecIndexByteArrayOp IntVec 4 W64) = 835-primOpTag (VecIndexByteArrayOp IntVec 64 W8) = 836-primOpTag (VecIndexByteArrayOp IntVec 32 W16) = 837-primOpTag (VecIndexByteArrayOp IntVec 16 W32) = 838-primOpTag (VecIndexByteArrayOp IntVec 8 W64) = 839-primOpTag (VecIndexByteArrayOp WordVec 16 W8) = 840-primOpTag (VecIndexByteArrayOp WordVec 8 W16) = 841-primOpTag (VecIndexByteArrayOp WordVec 4 W32) = 842-primOpTag (VecIndexByteArrayOp WordVec 2 W64) = 843-primOpTag (VecIndexByteArrayOp WordVec 32 W8) = 844-primOpTag (VecIndexByteArrayOp WordVec 16 W16) = 845-primOpTag (VecIndexByteArrayOp WordVec 8 W32) = 846-primOpTag (VecIndexByteArrayOp WordVec 4 W64) = 847-primOpTag (VecIndexByteArrayOp WordVec 64 W8) = 848-primOpTag (VecIndexByteArrayOp WordVec 32 W16) = 849-primOpTag (VecIndexByteArrayOp WordVec 16 W32) = 850-primOpTag (VecIndexByteArrayOp WordVec 8 W64) = 851-primOpTag (VecIndexByteArrayOp FloatVec 4 W32) = 852-primOpTag (VecIndexByteArrayOp FloatVec 2 W64) = 853-primOpTag (VecIndexByteArrayOp FloatVec 8 W32) = 854-primOpTag (VecIndexByteArrayOp FloatVec 4 W64) = 855-primOpTag (VecIndexByteArrayOp FloatVec 16 W32) = 856-primOpTag (VecIndexByteArrayOp FloatVec 8 W64) = 857-primOpTag (VecReadByteArrayOp IntVec 16 W8) = 858-primOpTag (VecReadByteArrayOp IntVec 8 W16) = 859-primOpTag (VecReadByteArrayOp IntVec 4 W32) = 860-primOpTag (VecReadByteArrayOp IntVec 2 W64) = 861-primOpTag (VecReadByteArrayOp IntVec 32 W8) = 862-primOpTag (VecReadByteArrayOp IntVec 16 W16) = 863-primOpTag (VecReadByteArrayOp IntVec 8 W32) = 864-primOpTag (VecReadByteArrayOp IntVec 4 W64) = 865-primOpTag (VecReadByteArrayOp IntVec 64 W8) = 866-primOpTag (VecReadByteArrayOp IntVec 32 W16) = 867-primOpTag (VecReadByteArrayOp IntVec 16 W32) = 868-primOpTag (VecReadByteArrayOp IntVec 8 W64) = 869-primOpTag (VecReadByteArrayOp WordVec 16 W8) = 870-primOpTag (VecReadByteArrayOp WordVec 8 W16) = 871-primOpTag (VecReadByteArrayOp WordVec 4 W32) = 872-primOpTag (VecReadByteArrayOp WordVec 2 W64) = 873-primOpTag (VecReadByteArrayOp WordVec 32 W8) = 874-primOpTag (VecReadByteArrayOp WordVec 16 W16) = 875-primOpTag (VecReadByteArrayOp WordVec 8 W32) = 876-primOpTag (VecReadByteArrayOp WordVec 4 W64) = 877-primOpTag (VecReadByteArrayOp WordVec 64 W8) = 878-primOpTag (VecReadByteArrayOp WordVec 32 W16) = 879-primOpTag (VecReadByteArrayOp WordVec 16 W32) = 880-primOpTag (VecReadByteArrayOp WordVec 8 W64) = 881-primOpTag (VecReadByteArrayOp FloatVec 4 W32) = 882-primOpTag (VecReadByteArrayOp FloatVec 2 W64) = 883-primOpTag (VecReadByteArrayOp FloatVec 8 W32) = 884-primOpTag (VecReadByteArrayOp FloatVec 4 W64) = 885-primOpTag (VecReadByteArrayOp FloatVec 16 W32) = 886-primOpTag (VecReadByteArrayOp FloatVec 8 W64) = 887-primOpTag (VecWriteByteArrayOp IntVec 16 W8) = 888-primOpTag (VecWriteByteArrayOp IntVec 8 W16) = 889-primOpTag (VecWriteByteArrayOp IntVec 4 W32) = 890-primOpTag (VecWriteByteArrayOp IntVec 2 W64) = 891-primOpTag (VecWriteByteArrayOp IntVec 32 W8) = 892-primOpTag (VecWriteByteArrayOp IntVec 16 W16) = 893-primOpTag (VecWriteByteArrayOp IntVec 8 W32) = 894-primOpTag (VecWriteByteArrayOp IntVec 4 W64) = 895-primOpTag (VecWriteByteArrayOp IntVec 64 W8) = 896-primOpTag (VecWriteByteArrayOp IntVec 32 W16) = 897-primOpTag (VecWriteByteArrayOp IntVec 16 W32) = 898-primOpTag (VecWriteByteArrayOp IntVec 8 W64) = 899-primOpTag (VecWriteByteArrayOp WordVec 16 W8) = 900-primOpTag (VecWriteByteArrayOp WordVec 8 W16) = 901-primOpTag (VecWriteByteArrayOp WordVec 4 W32) = 902-primOpTag (VecWriteByteArrayOp WordVec 2 W64) = 903-primOpTag (VecWriteByteArrayOp WordVec 32 W8) = 904-primOpTag (VecWriteByteArrayOp WordVec 16 W16) = 905-primOpTag (VecWriteByteArrayOp WordVec 8 W32) = 906-primOpTag (VecWriteByteArrayOp WordVec 4 W64) = 907-primOpTag (VecWriteByteArrayOp WordVec 64 W8) = 908-primOpTag (VecWriteByteArrayOp WordVec 32 W16) = 909-primOpTag (VecWriteByteArrayOp WordVec 16 W32) = 910-primOpTag (VecWriteByteArrayOp WordVec 8 W64) = 911-primOpTag (VecWriteByteArrayOp FloatVec 4 W32) = 912-primOpTag (VecWriteByteArrayOp FloatVec 2 W64) = 913-primOpTag (VecWriteByteArrayOp FloatVec 8 W32) = 914-primOpTag (VecWriteByteArrayOp FloatVec 4 W64) = 915-primOpTag (VecWriteByteArrayOp FloatVec 16 W32) = 916-primOpTag (VecWriteByteArrayOp FloatVec 8 W64) = 917-primOpTag (VecIndexOffAddrOp IntVec 16 W8) = 918-primOpTag (VecIndexOffAddrOp IntVec 8 W16) = 919-primOpTag (VecIndexOffAddrOp IntVec 4 W32) = 920-primOpTag (VecIndexOffAddrOp IntVec 2 W64) = 921-primOpTag (VecIndexOffAddrOp IntVec 32 W8) = 922-primOpTag (VecIndexOffAddrOp IntVec 16 W16) = 923-primOpTag (VecIndexOffAddrOp IntVec 8 W32) = 924-primOpTag (VecIndexOffAddrOp IntVec 4 W64) = 925-primOpTag (VecIndexOffAddrOp IntVec 64 W8) = 926-primOpTag (VecIndexOffAddrOp IntVec 32 W16) = 927-primOpTag (VecIndexOffAddrOp IntVec 16 W32) = 928-primOpTag (VecIndexOffAddrOp IntVec 8 W64) = 929-primOpTag (VecIndexOffAddrOp WordVec 16 W8) = 930-primOpTag (VecIndexOffAddrOp WordVec 8 W16) = 931-primOpTag (VecIndexOffAddrOp WordVec 4 W32) = 932-primOpTag (VecIndexOffAddrOp WordVec 2 W64) = 933-primOpTag (VecIndexOffAddrOp WordVec 32 W8) = 934-primOpTag (VecIndexOffAddrOp WordVec 16 W16) = 935-primOpTag (VecIndexOffAddrOp WordVec 8 W32) = 936-primOpTag (VecIndexOffAddrOp WordVec 4 W64) = 937-primOpTag (VecIndexOffAddrOp WordVec 64 W8) = 938-primOpTag (VecIndexOffAddrOp WordVec 32 W16) = 939-primOpTag (VecIndexOffAddrOp WordVec 16 W32) = 940-primOpTag (VecIndexOffAddrOp WordVec 8 W64) = 941-primOpTag (VecIndexOffAddrOp FloatVec 4 W32) = 942-primOpTag (VecIndexOffAddrOp FloatVec 2 W64) = 943-primOpTag (VecIndexOffAddrOp FloatVec 8 W32) = 944-primOpTag (VecIndexOffAddrOp FloatVec 4 W64) = 945-primOpTag (VecIndexOffAddrOp FloatVec 16 W32) = 946-primOpTag (VecIndexOffAddrOp FloatVec 8 W64) = 947-primOpTag (VecReadOffAddrOp IntVec 16 W8) = 948-primOpTag (VecReadOffAddrOp IntVec 8 W16) = 949-primOpTag (VecReadOffAddrOp IntVec 4 W32) = 950-primOpTag (VecReadOffAddrOp IntVec 2 W64) = 951-primOpTag (VecReadOffAddrOp IntVec 32 W8) = 952-primOpTag (VecReadOffAddrOp IntVec 16 W16) = 953-primOpTag (VecReadOffAddrOp IntVec 8 W32) = 954-primOpTag (VecReadOffAddrOp IntVec 4 W64) = 955-primOpTag (VecReadOffAddrOp IntVec 64 W8) = 956-primOpTag (VecReadOffAddrOp IntVec 32 W16) = 957-primOpTag (VecReadOffAddrOp IntVec 16 W32) = 958-primOpTag (VecReadOffAddrOp IntVec 8 W64) = 959-primOpTag (VecReadOffAddrOp WordVec 16 W8) = 960-primOpTag (VecReadOffAddrOp WordVec 8 W16) = 961-primOpTag (VecReadOffAddrOp WordVec 4 W32) = 962-primOpTag (VecReadOffAddrOp WordVec 2 W64) = 963-primOpTag (VecReadOffAddrOp WordVec 32 W8) = 964-primOpTag (VecReadOffAddrOp WordVec 16 W16) = 965-primOpTag (VecReadOffAddrOp WordVec 8 W32) = 966-primOpTag (VecReadOffAddrOp WordVec 4 W64) = 967-primOpTag (VecReadOffAddrOp WordVec 64 W8) = 968-primOpTag (VecReadOffAddrOp WordVec 32 W16) = 969-primOpTag (VecReadOffAddrOp WordVec 16 W32) = 970-primOpTag (VecReadOffAddrOp WordVec 8 W64) = 971-primOpTag (VecReadOffAddrOp FloatVec 4 W32) = 972-primOpTag (VecReadOffAddrOp FloatVec 2 W64) = 973-primOpTag (VecReadOffAddrOp FloatVec 8 W32) = 974-primOpTag (VecReadOffAddrOp FloatVec 4 W64) = 975-primOpTag (VecReadOffAddrOp FloatVec 16 W32) = 976-primOpTag (VecReadOffAddrOp FloatVec 8 W64) = 977-primOpTag (VecWriteOffAddrOp IntVec 16 W8) = 978-primOpTag (VecWriteOffAddrOp IntVec 8 W16) = 979-primOpTag (VecWriteOffAddrOp IntVec 4 W32) = 980-primOpTag (VecWriteOffAddrOp IntVec 2 W64) = 981-primOpTag (VecWriteOffAddrOp IntVec 32 W8) = 982-primOpTag (VecWriteOffAddrOp IntVec 16 W16) = 983-primOpTag (VecWriteOffAddrOp IntVec 8 W32) = 984-primOpTag (VecWriteOffAddrOp IntVec 4 W64) = 985-primOpTag (VecWriteOffAddrOp IntVec 64 W8) = 986-primOpTag (VecWriteOffAddrOp IntVec 32 W16) = 987-primOpTag (VecWriteOffAddrOp IntVec 16 W32) = 988-primOpTag (VecWriteOffAddrOp IntVec 8 W64) = 989-primOpTag (VecWriteOffAddrOp WordVec 16 W8) = 990-primOpTag (VecWriteOffAddrOp WordVec 8 W16) = 991-primOpTag (VecWriteOffAddrOp WordVec 4 W32) = 992-primOpTag (VecWriteOffAddrOp WordVec 2 W64) = 993-primOpTag (VecWriteOffAddrOp WordVec 32 W8) = 994-primOpTag (VecWriteOffAddrOp WordVec 16 W16) = 995-primOpTag (VecWriteOffAddrOp WordVec 8 W32) = 996-primOpTag (VecWriteOffAddrOp WordVec 4 W64) = 997-primOpTag (VecWriteOffAddrOp WordVec 64 W8) = 998-primOpTag (VecWriteOffAddrOp WordVec 32 W16) = 999-primOpTag (VecWriteOffAddrOp WordVec 16 W32) = 1000-primOpTag (VecWriteOffAddrOp WordVec 8 W64) = 1001-primOpTag (VecWriteOffAddrOp FloatVec 4 W32) = 1002-primOpTag (VecWriteOffAddrOp FloatVec 2 W64) = 1003-primOpTag (VecWriteOffAddrOp FloatVec 8 W32) = 1004-primOpTag (VecWriteOffAddrOp FloatVec 4 W64) = 1005-primOpTag (VecWriteOffAddrOp FloatVec 16 W32) = 1006-primOpTag (VecWriteOffAddrOp FloatVec 8 W64) = 1007-primOpTag (VecIndexScalarByteArrayOp IntVec 16 W8) = 1008-primOpTag (VecIndexScalarByteArrayOp IntVec 8 W16) = 1009-primOpTag (VecIndexScalarByteArrayOp IntVec 4 W32) = 1010-primOpTag (VecIndexScalarByteArrayOp IntVec 2 W64) = 1011-primOpTag (VecIndexScalarByteArrayOp IntVec 32 W8) = 1012-primOpTag (VecIndexScalarByteArrayOp IntVec 16 W16) = 1013-primOpTag (VecIndexScalarByteArrayOp IntVec 8 W32) = 1014-primOpTag (VecIndexScalarByteArrayOp IntVec 4 W64) = 1015-primOpTag (VecIndexScalarByteArrayOp IntVec 64 W8) = 1016-primOpTag (VecIndexScalarByteArrayOp IntVec 32 W16) = 1017-primOpTag (VecIndexScalarByteArrayOp IntVec 16 W32) = 1018-primOpTag (VecIndexScalarByteArrayOp IntVec 8 W64) = 1019-primOpTag (VecIndexScalarByteArrayOp WordVec 16 W8) = 1020-primOpTag (VecIndexScalarByteArrayOp WordVec 8 W16) = 1021-primOpTag (VecIndexScalarByteArrayOp WordVec 4 W32) = 1022-primOpTag (VecIndexScalarByteArrayOp WordVec 2 W64) = 1023-primOpTag (VecIndexScalarByteArrayOp WordVec 32 W8) = 1024-primOpTag (VecIndexScalarByteArrayOp WordVec 16 W16) = 1025-primOpTag (VecIndexScalarByteArrayOp WordVec 8 W32) = 1026-primOpTag (VecIndexScalarByteArrayOp WordVec 4 W64) = 1027-primOpTag (VecIndexScalarByteArrayOp WordVec 64 W8) = 1028-primOpTag (VecIndexScalarByteArrayOp WordVec 32 W16) = 1029-primOpTag (VecIndexScalarByteArrayOp WordVec 16 W32) = 1030-primOpTag (VecIndexScalarByteArrayOp WordVec 8 W64) = 1031-primOpTag (VecIndexScalarByteArrayOp FloatVec 4 W32) = 1032-primOpTag (VecIndexScalarByteArrayOp FloatVec 2 W64) = 1033-primOpTag (VecIndexScalarByteArrayOp FloatVec 8 W32) = 1034-primOpTag (VecIndexScalarByteArrayOp FloatVec 4 W64) = 1035-primOpTag (VecIndexScalarByteArrayOp FloatVec 16 W32) = 1036-primOpTag (VecIndexScalarByteArrayOp FloatVec 8 W64) = 1037-primOpTag (VecReadScalarByteArrayOp IntVec 16 W8) = 1038-primOpTag (VecReadScalarByteArrayOp IntVec 8 W16) = 1039-primOpTag (VecReadScalarByteArrayOp IntVec 4 W32) = 1040-primOpTag (VecReadScalarByteArrayOp IntVec 2 W64) = 1041-primOpTag (VecReadScalarByteArrayOp IntVec 32 W8) = 1042-primOpTag (VecReadScalarByteArrayOp IntVec 16 W16) = 1043-primOpTag (VecReadScalarByteArrayOp IntVec 8 W32) = 1044-primOpTag (VecReadScalarByteArrayOp IntVec 4 W64) = 1045-primOpTag (VecReadScalarByteArrayOp IntVec 64 W8) = 1046-primOpTag (VecReadScalarByteArrayOp IntVec 32 W16) = 1047-primOpTag (VecReadScalarByteArrayOp IntVec 16 W32) = 1048-primOpTag (VecReadScalarByteArrayOp IntVec 8 W64) = 1049-primOpTag (VecReadScalarByteArrayOp WordVec 16 W8) = 1050-primOpTag (VecReadScalarByteArrayOp WordVec 8 W16) = 1051-primOpTag (VecReadScalarByteArrayOp WordVec 4 W32) = 1052-primOpTag (VecReadScalarByteArrayOp WordVec 2 W64) = 1053-primOpTag (VecReadScalarByteArrayOp WordVec 32 W8) = 1054-primOpTag (VecReadScalarByteArrayOp WordVec 16 W16) = 1055-primOpTag (VecReadScalarByteArrayOp WordVec 8 W32) = 1056-primOpTag (VecReadScalarByteArrayOp WordVec 4 W64) = 1057-primOpTag (VecReadScalarByteArrayOp WordVec 64 W8) = 1058-primOpTag (VecReadScalarByteArrayOp WordVec 32 W16) = 1059-primOpTag (VecReadScalarByteArrayOp WordVec 16 W32) = 1060-primOpTag (VecReadScalarByteArrayOp WordVec 8 W64) = 1061-primOpTag (VecReadScalarByteArrayOp FloatVec 4 W32) = 1062-primOpTag (VecReadScalarByteArrayOp FloatVec 2 W64) = 1063-primOpTag (VecReadScalarByteArrayOp FloatVec 8 W32) = 1064-primOpTag (VecReadScalarByteArrayOp FloatVec 4 W64) = 1065-primOpTag (VecReadScalarByteArrayOp FloatVec 16 W32) = 1066-primOpTag (VecReadScalarByteArrayOp FloatVec 8 W64) = 1067-primOpTag (VecWriteScalarByteArrayOp IntVec 16 W8) = 1068-primOpTag (VecWriteScalarByteArrayOp IntVec 8 W16) = 1069-primOpTag (VecWriteScalarByteArrayOp IntVec 4 W32) = 1070-primOpTag (VecWriteScalarByteArrayOp IntVec 2 W64) = 1071-primOpTag (VecWriteScalarByteArrayOp IntVec 32 W8) = 1072-primOpTag (VecWriteScalarByteArrayOp IntVec 16 W16) = 1073-primOpTag (VecWriteScalarByteArrayOp IntVec 8 W32) = 1074-primOpTag (VecWriteScalarByteArrayOp IntVec 4 W64) = 1075-primOpTag (VecWriteScalarByteArrayOp IntVec 64 W8) = 1076-primOpTag (VecWriteScalarByteArrayOp IntVec 32 W16) = 1077-primOpTag (VecWriteScalarByteArrayOp IntVec 16 W32) = 1078-primOpTag (VecWriteScalarByteArrayOp IntVec 8 W64) = 1079-primOpTag (VecWriteScalarByteArrayOp WordVec 16 W8) = 1080-primOpTag (VecWriteScalarByteArrayOp WordVec 8 W16) = 1081-primOpTag (VecWriteScalarByteArrayOp WordVec 4 W32) = 1082-primOpTag (VecWriteScalarByteArrayOp WordVec 2 W64) = 1083-primOpTag (VecWriteScalarByteArrayOp WordVec 32 W8) = 1084-primOpTag (VecWriteScalarByteArrayOp WordVec 16 W16) = 1085-primOpTag (VecWriteScalarByteArrayOp WordVec 8 W32) = 1086-primOpTag (VecWriteScalarByteArrayOp WordVec 4 W64) = 1087-primOpTag (VecWriteScalarByteArrayOp WordVec 64 W8) = 1088-primOpTag (VecWriteScalarByteArrayOp WordVec 32 W16) = 1089-primOpTag (VecWriteScalarByteArrayOp WordVec 16 W32) = 1090-primOpTag (VecWriteScalarByteArrayOp WordVec 8 W64) = 1091-primOpTag (VecWriteScalarByteArrayOp FloatVec 4 W32) = 1092-primOpTag (VecWriteScalarByteArrayOp FloatVec 2 W64) = 1093-primOpTag (VecWriteScalarByteArrayOp FloatVec 8 W32) = 1094-primOpTag (VecWriteScalarByteArrayOp FloatVec 4 W64) = 1095-primOpTag (VecWriteScalarByteArrayOp FloatVec 16 W32) = 1096-primOpTag (VecWriteScalarByteArrayOp FloatVec 8 W64) = 1097-primOpTag (VecIndexScalarOffAddrOp IntVec 16 W8) = 1098-primOpTag (VecIndexScalarOffAddrOp IntVec 8 W16) = 1099-primOpTag (VecIndexScalarOffAddrOp IntVec 4 W32) = 1100-primOpTag (VecIndexScalarOffAddrOp IntVec 2 W64) = 1101-primOpTag (VecIndexScalarOffAddrOp IntVec 32 W8) = 1102-primOpTag (VecIndexScalarOffAddrOp IntVec 16 W16) = 1103-primOpTag (VecIndexScalarOffAddrOp IntVec 8 W32) = 1104-primOpTag (VecIndexScalarOffAddrOp IntVec 4 W64) = 1105-primOpTag (VecIndexScalarOffAddrOp IntVec 64 W8) = 1106-primOpTag (VecIndexScalarOffAddrOp IntVec 32 W16) = 1107-primOpTag (VecIndexScalarOffAddrOp IntVec 16 W32) = 1108-primOpTag (VecIndexScalarOffAddrOp IntVec 8 W64) = 1109-primOpTag (VecIndexScalarOffAddrOp WordVec 16 W8) = 1110-primOpTag (VecIndexScalarOffAddrOp WordVec 8 W16) = 1111-primOpTag (VecIndexScalarOffAddrOp WordVec 4 W32) = 1112-primOpTag (VecIndexScalarOffAddrOp WordVec 2 W64) = 1113-primOpTag (VecIndexScalarOffAddrOp WordVec 32 W8) = 1114-primOpTag (VecIndexScalarOffAddrOp WordVec 16 W16) = 1115-primOpTag (VecIndexScalarOffAddrOp WordVec 8 W32) = 1116-primOpTag (VecIndexScalarOffAddrOp WordVec 4 W64) = 1117-primOpTag (VecIndexScalarOffAddrOp WordVec 64 W8) = 1118-primOpTag (VecIndexScalarOffAddrOp WordVec 32 W16) = 1119-primOpTag (VecIndexScalarOffAddrOp WordVec 16 W32) = 1120-primOpTag (VecIndexScalarOffAddrOp WordVec 8 W64) = 1121-primOpTag (VecIndexScalarOffAddrOp FloatVec 4 W32) = 1122-primOpTag (VecIndexScalarOffAddrOp FloatVec 2 W64) = 1123-primOpTag (VecIndexScalarOffAddrOp FloatVec 8 W32) = 1124-primOpTag (VecIndexScalarOffAddrOp FloatVec 4 W64) = 1125-primOpTag (VecIndexScalarOffAddrOp FloatVec 16 W32) = 1126-primOpTag (VecIndexScalarOffAddrOp FloatVec 8 W64) = 1127-primOpTag (VecReadScalarOffAddrOp IntVec 16 W8) = 1128-primOpTag (VecReadScalarOffAddrOp IntVec 8 W16) = 1129-primOpTag (VecReadScalarOffAddrOp IntVec 4 W32) = 1130-primOpTag (VecReadScalarOffAddrOp IntVec 2 W64) = 1131-primOpTag (VecReadScalarOffAddrOp IntVec 32 W8) = 1132-primOpTag (VecReadScalarOffAddrOp IntVec 16 W16) = 1133-primOpTag (VecReadScalarOffAddrOp IntVec 8 W32) = 1134-primOpTag (VecReadScalarOffAddrOp IntVec 4 W64) = 1135-primOpTag (VecReadScalarOffAddrOp IntVec 64 W8) = 1136-primOpTag (VecReadScalarOffAddrOp IntVec 32 W16) = 1137-primOpTag (VecReadScalarOffAddrOp IntVec 16 W32) = 1138-primOpTag (VecReadScalarOffAddrOp IntVec 8 W64) = 1139-primOpTag (VecReadScalarOffAddrOp WordVec 16 W8) = 1140-primOpTag (VecReadScalarOffAddrOp WordVec 8 W16) = 1141-primOpTag (VecReadScalarOffAddrOp WordVec 4 W32) = 1142-primOpTag (VecReadScalarOffAddrOp WordVec 2 W64) = 1143-primOpTag (VecReadScalarOffAddrOp WordVec 32 W8) = 1144-primOpTag (VecReadScalarOffAddrOp WordVec 16 W16) = 1145-primOpTag (VecReadScalarOffAddrOp WordVec 8 W32) = 1146-primOpTag (VecReadScalarOffAddrOp WordVec 4 W64) = 1147-primOpTag (VecReadScalarOffAddrOp WordVec 64 W8) = 1148-primOpTag (VecReadScalarOffAddrOp WordVec 32 W16) = 1149-primOpTag (VecReadScalarOffAddrOp WordVec 16 W32) = 1150-primOpTag (VecReadScalarOffAddrOp WordVec 8 W64) = 1151-primOpTag (VecReadScalarOffAddrOp FloatVec 4 W32) = 1152-primOpTag (VecReadScalarOffAddrOp FloatVec 2 W64) = 1153-primOpTag (VecReadScalarOffAddrOp FloatVec 8 W32) = 1154-primOpTag (VecReadScalarOffAddrOp FloatVec 4 W64) = 1155-primOpTag (VecReadScalarOffAddrOp FloatVec 16 W32) = 1156-primOpTag (VecReadScalarOffAddrOp FloatVec 8 W64) = 1157-primOpTag (VecWriteScalarOffAddrOp IntVec 16 W8) = 1158-primOpTag (VecWriteScalarOffAddrOp IntVec 8 W16) = 1159-primOpTag (VecWriteScalarOffAddrOp IntVec 4 W32) = 1160-primOpTag (VecWriteScalarOffAddrOp IntVec 2 W64) = 1161-primOpTag (VecWriteScalarOffAddrOp IntVec 32 W8) = 1162-primOpTag (VecWriteScalarOffAddrOp IntVec 16 W16) = 1163-primOpTag (VecWriteScalarOffAddrOp IntVec 8 W32) = 1164-primOpTag (VecWriteScalarOffAddrOp IntVec 4 W64) = 1165-primOpTag (VecWriteScalarOffAddrOp IntVec 64 W8) = 1166-primOpTag (VecWriteScalarOffAddrOp IntVec 32 W16) = 1167-primOpTag (VecWriteScalarOffAddrOp IntVec 16 W32) = 1168-primOpTag (VecWriteScalarOffAddrOp IntVec 8 W64) = 1169-primOpTag (VecWriteScalarOffAddrOp WordVec 16 W8) = 1170-primOpTag (VecWriteScalarOffAddrOp WordVec 8 W16) = 1171-primOpTag (VecWriteScalarOffAddrOp WordVec 4 W32) = 1172-primOpTag (VecWriteScalarOffAddrOp WordVec 2 W64) = 1173-primOpTag (VecWriteScalarOffAddrOp WordVec 32 W8) = 1174-primOpTag (VecWriteScalarOffAddrOp WordVec 16 W16) = 1175-primOpTag (VecWriteScalarOffAddrOp WordVec 8 W32) = 1176-primOpTag (VecWriteScalarOffAddrOp WordVec 4 W64) = 1177-primOpTag (VecWriteScalarOffAddrOp WordVec 64 W8) = 1178-primOpTag (VecWriteScalarOffAddrOp WordVec 32 W16) = 1179-primOpTag (VecWriteScalarOffAddrOp WordVec 16 W32) = 1180-primOpTag (VecWriteScalarOffAddrOp WordVec 8 W64) = 1181-primOpTag (VecWriteScalarOffAddrOp FloatVec 4 W32) = 1182-primOpTag (VecWriteScalarOffAddrOp FloatVec 2 W64) = 1183-primOpTag (VecWriteScalarOffAddrOp FloatVec 8 W32) = 1184-primOpTag (VecWriteScalarOffAddrOp FloatVec 4 W64) = 1185-primOpTag (VecWriteScalarOffAddrOp FloatVec 16 W32) = 1186-primOpTag (VecWriteScalarOffAddrOp FloatVec 8 W64) = 1187-primOpTag PrefetchByteArrayOp3 = 1188-primOpTag PrefetchMutableByteArrayOp3 = 1189-primOpTag PrefetchAddrOp3 = 1190-primOpTag PrefetchValueOp3 = 1191-primOpTag PrefetchByteArrayOp2 = 1192-primOpTag PrefetchMutableByteArrayOp2 = 1193-primOpTag PrefetchAddrOp2 = 1194-primOpTag PrefetchValueOp2 = 1195-primOpTag PrefetchByteArrayOp1 = 1196-primOpTag PrefetchMutableByteArrayOp1 = 1197-primOpTag PrefetchAddrOp1 = 1198-primOpTag PrefetchValueOp1 = 1199-primOpTag PrefetchByteArrayOp0 = 1200-primOpTag PrefetchMutableByteArrayOp0 = 1201-primOpTag PrefetchAddrOp0 = 1202-primOpTag PrefetchValueOp0 = 1203+maxPrimOpTag = 1204+primOpTag :: PrimOp -> Int+primOpTag CharGtOp = 1+primOpTag CharGeOp = 2+primOpTag CharEqOp = 3+primOpTag CharNeOp = 4+primOpTag CharLtOp = 5+primOpTag CharLeOp = 6+primOpTag OrdOp = 7+primOpTag Int8Extend = 8+primOpTag Int8Narrow = 9+primOpTag Int8NegOp = 10+primOpTag Int8AddOp = 11+primOpTag Int8SubOp = 12+primOpTag Int8MulOp = 13+primOpTag Int8QuotOp = 14+primOpTag Int8RemOp = 15+primOpTag Int8QuotRemOp = 16+primOpTag Int8EqOp = 17+primOpTag Int8GeOp = 18+primOpTag Int8GtOp = 19+primOpTag Int8LeOp = 20+primOpTag Int8LtOp = 21+primOpTag Int8NeOp = 22+primOpTag Word8Extend = 23+primOpTag Word8Narrow = 24+primOpTag Word8NotOp = 25+primOpTag Word8AddOp = 26+primOpTag Word8SubOp = 27+primOpTag Word8MulOp = 28+primOpTag Word8QuotOp = 29+primOpTag Word8RemOp = 30+primOpTag Word8QuotRemOp = 31+primOpTag Word8EqOp = 32+primOpTag Word8GeOp = 33+primOpTag Word8GtOp = 34+primOpTag Word8LeOp = 35+primOpTag Word8LtOp = 36+primOpTag Word8NeOp = 37+primOpTag Int16Extend = 38+primOpTag Int16Narrow = 39+primOpTag Int16NegOp = 40+primOpTag Int16AddOp = 41+primOpTag Int16SubOp = 42+primOpTag Int16MulOp = 43+primOpTag Int16QuotOp = 44+primOpTag Int16RemOp = 45+primOpTag Int16QuotRemOp = 46+primOpTag Int16EqOp = 47+primOpTag Int16GeOp = 48+primOpTag Int16GtOp = 49+primOpTag Int16LeOp = 50+primOpTag Int16LtOp = 51+primOpTag Int16NeOp = 52+primOpTag Word16Extend = 53+primOpTag Word16Narrow = 54+primOpTag Word16NotOp = 55+primOpTag Word16AddOp = 56+primOpTag Word16SubOp = 57+primOpTag Word16MulOp = 58+primOpTag Word16QuotOp = 59+primOpTag Word16RemOp = 60+primOpTag Word16QuotRemOp = 61+primOpTag Word16EqOp = 62+primOpTag Word16GeOp = 63+primOpTag Word16GtOp = 64+primOpTag Word16LeOp = 65+primOpTag Word16LtOp = 66+primOpTag Word16NeOp = 67+primOpTag IntAddOp = 68+primOpTag IntSubOp = 69+primOpTag IntMulOp = 70+primOpTag IntMul2Op = 71+primOpTag IntMulMayOfloOp = 72+primOpTag IntQuotOp = 73+primOpTag IntRemOp = 74+primOpTag IntQuotRemOp = 75+primOpTag AndIOp = 76+primOpTag OrIOp = 77+primOpTag XorIOp = 78+primOpTag NotIOp = 79+primOpTag IntNegOp = 80+primOpTag IntAddCOp = 81+primOpTag IntSubCOp = 82+primOpTag IntGtOp = 83+primOpTag IntGeOp = 84+primOpTag IntEqOp = 85+primOpTag IntNeOp = 86+primOpTag IntLtOp = 87+primOpTag IntLeOp = 88+primOpTag ChrOp = 89+primOpTag Int2WordOp = 90+primOpTag Int2FloatOp = 91+primOpTag Int2DoubleOp = 92+primOpTag Word2FloatOp = 93+primOpTag Word2DoubleOp = 94+primOpTag ISllOp = 95+primOpTag ISraOp = 96+primOpTag ISrlOp = 97+primOpTag WordAddOp = 98+primOpTag WordAddCOp = 99+primOpTag WordSubCOp = 100+primOpTag WordAdd2Op = 101+primOpTag WordSubOp = 102+primOpTag WordMulOp = 103+primOpTag WordMul2Op = 104+primOpTag WordQuotOp = 105+primOpTag WordRemOp = 106+primOpTag WordQuotRemOp = 107+primOpTag WordQuotRem2Op = 108+primOpTag AndOp = 109+primOpTag OrOp = 110+primOpTag XorOp = 111+primOpTag NotOp = 112+primOpTag SllOp = 113+primOpTag SrlOp = 114+primOpTag Word2IntOp = 115+primOpTag WordGtOp = 116+primOpTag WordGeOp = 117+primOpTag WordEqOp = 118+primOpTag WordNeOp = 119+primOpTag WordLtOp = 120+primOpTag WordLeOp = 121+primOpTag PopCnt8Op = 122+primOpTag PopCnt16Op = 123+primOpTag PopCnt32Op = 124+primOpTag PopCnt64Op = 125+primOpTag PopCntOp = 126+primOpTag Pdep8Op = 127+primOpTag Pdep16Op = 128+primOpTag Pdep32Op = 129+primOpTag Pdep64Op = 130+primOpTag PdepOp = 131+primOpTag Pext8Op = 132+primOpTag Pext16Op = 133+primOpTag Pext32Op = 134+primOpTag Pext64Op = 135+primOpTag PextOp = 136+primOpTag Clz8Op = 137+primOpTag Clz16Op = 138+primOpTag Clz32Op = 139+primOpTag Clz64Op = 140+primOpTag ClzOp = 141+primOpTag Ctz8Op = 142+primOpTag Ctz16Op = 143+primOpTag Ctz32Op = 144+primOpTag Ctz64Op = 145+primOpTag CtzOp = 146+primOpTag BSwap16Op = 147+primOpTag BSwap32Op = 148+primOpTag BSwap64Op = 149+primOpTag BSwapOp = 150+primOpTag BRev8Op = 151+primOpTag BRev16Op = 152+primOpTag BRev32Op = 153+primOpTag BRev64Op = 154+primOpTag BRevOp = 155+primOpTag Narrow8IntOp = 156+primOpTag Narrow16IntOp = 157+primOpTag Narrow32IntOp = 158+primOpTag Narrow8WordOp = 159+primOpTag Narrow16WordOp = 160+primOpTag Narrow32WordOp = 161+primOpTag DoubleGtOp = 162+primOpTag DoubleGeOp = 163+primOpTag DoubleEqOp = 164+primOpTag DoubleNeOp = 165+primOpTag DoubleLtOp = 166+primOpTag DoubleLeOp = 167+primOpTag DoubleAddOp = 168+primOpTag DoubleSubOp = 169+primOpTag DoubleMulOp = 170+primOpTag DoubleDivOp = 171+primOpTag DoubleNegOp = 172+primOpTag DoubleFabsOp = 173+primOpTag Double2IntOp = 174+primOpTag Double2FloatOp = 175+primOpTag DoubleExpOp = 176+primOpTag DoubleExpM1Op = 177+primOpTag DoubleLogOp = 178+primOpTag DoubleLog1POp = 179+primOpTag DoubleSqrtOp = 180+primOpTag DoubleSinOp = 181+primOpTag DoubleCosOp = 182+primOpTag DoubleTanOp = 183+primOpTag DoubleAsinOp = 184+primOpTag DoubleAcosOp = 185+primOpTag DoubleAtanOp = 186+primOpTag DoubleSinhOp = 187+primOpTag DoubleCoshOp = 188+primOpTag DoubleTanhOp = 189+primOpTag DoubleAsinhOp = 190+primOpTag DoubleAcoshOp = 191+primOpTag DoubleAtanhOp = 192+primOpTag DoublePowerOp = 193+primOpTag DoubleDecode_2IntOp = 194+primOpTag DoubleDecode_Int64Op = 195+primOpTag FloatGtOp = 196+primOpTag FloatGeOp = 197+primOpTag FloatEqOp = 198+primOpTag FloatNeOp = 199+primOpTag FloatLtOp = 200+primOpTag FloatLeOp = 201+primOpTag FloatAddOp = 202+primOpTag FloatSubOp = 203+primOpTag FloatMulOp = 204+primOpTag FloatDivOp = 205+primOpTag FloatNegOp = 206+primOpTag FloatFabsOp = 207+primOpTag Float2IntOp = 208+primOpTag FloatExpOp = 209+primOpTag FloatExpM1Op = 210+primOpTag FloatLogOp = 211+primOpTag FloatLog1POp = 212+primOpTag FloatSqrtOp = 213+primOpTag FloatSinOp = 214+primOpTag FloatCosOp = 215+primOpTag FloatTanOp = 216+primOpTag FloatAsinOp = 217+primOpTag FloatAcosOp = 218+primOpTag FloatAtanOp = 219+primOpTag FloatSinhOp = 220+primOpTag FloatCoshOp = 221+primOpTag FloatTanhOp = 222+primOpTag FloatAsinhOp = 223+primOpTag FloatAcoshOp = 224+primOpTag FloatAtanhOp = 225+primOpTag FloatPowerOp = 226+primOpTag Float2DoubleOp = 227+primOpTag FloatDecode_IntOp = 228+primOpTag NewArrayOp = 229+primOpTag SameMutableArrayOp = 230+primOpTag ReadArrayOp = 231+primOpTag WriteArrayOp = 232+primOpTag SizeofArrayOp = 233+primOpTag SizeofMutableArrayOp = 234+primOpTag IndexArrayOp = 235+primOpTag UnsafeFreezeArrayOp = 236+primOpTag UnsafeThawArrayOp = 237+primOpTag CopyArrayOp = 238+primOpTag CopyMutableArrayOp = 239+primOpTag CloneArrayOp = 240+primOpTag CloneMutableArrayOp = 241+primOpTag FreezeArrayOp = 242+primOpTag ThawArrayOp = 243+primOpTag CasArrayOp = 244+primOpTag NewSmallArrayOp = 245+primOpTag SameSmallMutableArrayOp = 246+primOpTag ShrinkSmallMutableArrayOp_Char = 247+primOpTag ReadSmallArrayOp = 248+primOpTag WriteSmallArrayOp = 249+primOpTag SizeofSmallArrayOp = 250+primOpTag SizeofSmallMutableArrayOp = 251+primOpTag GetSizeofSmallMutableArrayOp = 252+primOpTag IndexSmallArrayOp = 253+primOpTag UnsafeFreezeSmallArrayOp = 254+primOpTag UnsafeThawSmallArrayOp = 255+primOpTag CopySmallArrayOp = 256+primOpTag CopySmallMutableArrayOp = 257+primOpTag CloneSmallArrayOp = 258+primOpTag CloneSmallMutableArrayOp = 259+primOpTag FreezeSmallArrayOp = 260+primOpTag ThawSmallArrayOp = 261+primOpTag CasSmallArrayOp = 262+primOpTag NewByteArrayOp_Char = 263+primOpTag NewPinnedByteArrayOp_Char = 264+primOpTag NewAlignedPinnedByteArrayOp_Char = 265+primOpTag MutableByteArrayIsPinnedOp = 266+primOpTag ByteArrayIsPinnedOp = 267+primOpTag ByteArrayContents_Char = 268+primOpTag SameMutableByteArrayOp = 269+primOpTag ShrinkMutableByteArrayOp_Char = 270+primOpTag ResizeMutableByteArrayOp_Char = 271+primOpTag UnsafeFreezeByteArrayOp = 272+primOpTag SizeofByteArrayOp = 273+primOpTag SizeofMutableByteArrayOp = 274+primOpTag GetSizeofMutableByteArrayOp = 275+primOpTag IndexByteArrayOp_Char = 276+primOpTag IndexByteArrayOp_WideChar = 277+primOpTag IndexByteArrayOp_Int = 278+primOpTag IndexByteArrayOp_Word = 279+primOpTag IndexByteArrayOp_Addr = 280+primOpTag IndexByteArrayOp_Float = 281+primOpTag IndexByteArrayOp_Double = 282+primOpTag IndexByteArrayOp_StablePtr = 283+primOpTag IndexByteArrayOp_Int8 = 284+primOpTag IndexByteArrayOp_Int16 = 285+primOpTag IndexByteArrayOp_Int32 = 286+primOpTag IndexByteArrayOp_Int64 = 287+primOpTag IndexByteArrayOp_Word8 = 288+primOpTag IndexByteArrayOp_Word16 = 289+primOpTag IndexByteArrayOp_Word32 = 290+primOpTag IndexByteArrayOp_Word64 = 291+primOpTag IndexByteArrayOp_Word8AsChar = 292+primOpTag IndexByteArrayOp_Word8AsWideChar = 293+primOpTag IndexByteArrayOp_Word8AsAddr = 294+primOpTag IndexByteArrayOp_Word8AsFloat = 295+primOpTag IndexByteArrayOp_Word8AsDouble = 296+primOpTag IndexByteArrayOp_Word8AsStablePtr = 297+primOpTag IndexByteArrayOp_Word8AsInt16 = 298+primOpTag IndexByteArrayOp_Word8AsInt32 = 299+primOpTag IndexByteArrayOp_Word8AsInt64 = 300+primOpTag IndexByteArrayOp_Word8AsInt = 301+primOpTag IndexByteArrayOp_Word8AsWord16 = 302+primOpTag IndexByteArrayOp_Word8AsWord32 = 303+primOpTag IndexByteArrayOp_Word8AsWord64 = 304+primOpTag IndexByteArrayOp_Word8AsWord = 305+primOpTag ReadByteArrayOp_Char = 306+primOpTag ReadByteArrayOp_WideChar = 307+primOpTag ReadByteArrayOp_Int = 308+primOpTag ReadByteArrayOp_Word = 309+primOpTag ReadByteArrayOp_Addr = 310+primOpTag ReadByteArrayOp_Float = 311+primOpTag ReadByteArrayOp_Double = 312+primOpTag ReadByteArrayOp_StablePtr = 313+primOpTag ReadByteArrayOp_Int8 = 314+primOpTag ReadByteArrayOp_Int16 = 315+primOpTag ReadByteArrayOp_Int32 = 316+primOpTag ReadByteArrayOp_Int64 = 317+primOpTag ReadByteArrayOp_Word8 = 318+primOpTag ReadByteArrayOp_Word16 = 319+primOpTag ReadByteArrayOp_Word32 = 320+primOpTag ReadByteArrayOp_Word64 = 321+primOpTag ReadByteArrayOp_Word8AsChar = 322+primOpTag ReadByteArrayOp_Word8AsWideChar = 323+primOpTag ReadByteArrayOp_Word8AsAddr = 324+primOpTag ReadByteArrayOp_Word8AsFloat = 325+primOpTag ReadByteArrayOp_Word8AsDouble = 326+primOpTag ReadByteArrayOp_Word8AsStablePtr = 327+primOpTag ReadByteArrayOp_Word8AsInt16 = 328+primOpTag ReadByteArrayOp_Word8AsInt32 = 329+primOpTag ReadByteArrayOp_Word8AsInt64 = 330+primOpTag ReadByteArrayOp_Word8AsInt = 331+primOpTag ReadByteArrayOp_Word8AsWord16 = 332+primOpTag ReadByteArrayOp_Word8AsWord32 = 333+primOpTag ReadByteArrayOp_Word8AsWord64 = 334+primOpTag ReadByteArrayOp_Word8AsWord = 335+primOpTag WriteByteArrayOp_Char = 336+primOpTag WriteByteArrayOp_WideChar = 337+primOpTag WriteByteArrayOp_Int = 338+primOpTag WriteByteArrayOp_Word = 339+primOpTag WriteByteArrayOp_Addr = 340+primOpTag WriteByteArrayOp_Float = 341+primOpTag WriteByteArrayOp_Double = 342+primOpTag WriteByteArrayOp_StablePtr = 343+primOpTag WriteByteArrayOp_Int8 = 344+primOpTag WriteByteArrayOp_Int16 = 345+primOpTag WriteByteArrayOp_Int32 = 346+primOpTag WriteByteArrayOp_Int64 = 347+primOpTag WriteByteArrayOp_Word8 = 348+primOpTag WriteByteArrayOp_Word16 = 349+primOpTag WriteByteArrayOp_Word32 = 350+primOpTag WriteByteArrayOp_Word64 = 351+primOpTag WriteByteArrayOp_Word8AsChar = 352+primOpTag WriteByteArrayOp_Word8AsWideChar = 353+primOpTag WriteByteArrayOp_Word8AsAddr = 354+primOpTag WriteByteArrayOp_Word8AsFloat = 355+primOpTag WriteByteArrayOp_Word8AsDouble = 356+primOpTag WriteByteArrayOp_Word8AsStablePtr = 357+primOpTag WriteByteArrayOp_Word8AsInt16 = 358+primOpTag WriteByteArrayOp_Word8AsInt32 = 359+primOpTag WriteByteArrayOp_Word8AsInt64 = 360+primOpTag WriteByteArrayOp_Word8AsInt = 361+primOpTag WriteByteArrayOp_Word8AsWord16 = 362+primOpTag WriteByteArrayOp_Word8AsWord32 = 363+primOpTag WriteByteArrayOp_Word8AsWord64 = 364+primOpTag WriteByteArrayOp_Word8AsWord = 365+primOpTag CompareByteArraysOp = 366+primOpTag CopyByteArrayOp = 367+primOpTag CopyMutableByteArrayOp = 368+primOpTag CopyByteArrayToAddrOp = 369+primOpTag CopyMutableByteArrayToAddrOp = 370+primOpTag CopyAddrToByteArrayOp = 371+primOpTag SetByteArrayOp = 372+primOpTag AtomicReadByteArrayOp_Int = 373+primOpTag AtomicWriteByteArrayOp_Int = 374+primOpTag CasByteArrayOp_Int = 375+primOpTag FetchAddByteArrayOp_Int = 376+primOpTag FetchSubByteArrayOp_Int = 377+primOpTag FetchAndByteArrayOp_Int = 378+primOpTag FetchNandByteArrayOp_Int = 379+primOpTag FetchOrByteArrayOp_Int = 380+primOpTag FetchXorByteArrayOp_Int = 381+primOpTag NewArrayArrayOp = 382+primOpTag SameMutableArrayArrayOp = 383+primOpTag UnsafeFreezeArrayArrayOp = 384+primOpTag SizeofArrayArrayOp = 385+primOpTag SizeofMutableArrayArrayOp = 386+primOpTag IndexArrayArrayOp_ByteArray = 387+primOpTag IndexArrayArrayOp_ArrayArray = 388+primOpTag ReadArrayArrayOp_ByteArray = 389+primOpTag ReadArrayArrayOp_MutableByteArray = 390+primOpTag ReadArrayArrayOp_ArrayArray = 391+primOpTag ReadArrayArrayOp_MutableArrayArray = 392+primOpTag WriteArrayArrayOp_ByteArray = 393+primOpTag WriteArrayArrayOp_MutableByteArray = 394+primOpTag WriteArrayArrayOp_ArrayArray = 395+primOpTag WriteArrayArrayOp_MutableArrayArray = 396+primOpTag CopyArrayArrayOp = 397+primOpTag CopyMutableArrayArrayOp = 398+primOpTag AddrAddOp = 399+primOpTag AddrSubOp = 400+primOpTag AddrRemOp = 401+primOpTag Addr2IntOp = 402+primOpTag Int2AddrOp = 403+primOpTag AddrGtOp = 404+primOpTag AddrGeOp = 405+primOpTag AddrEqOp = 406+primOpTag AddrNeOp = 407+primOpTag AddrLtOp = 408+primOpTag AddrLeOp = 409+primOpTag IndexOffAddrOp_Char = 410+primOpTag IndexOffAddrOp_WideChar = 411+primOpTag IndexOffAddrOp_Int = 412+primOpTag IndexOffAddrOp_Word = 413+primOpTag IndexOffAddrOp_Addr = 414+primOpTag IndexOffAddrOp_Float = 415+primOpTag IndexOffAddrOp_Double = 416+primOpTag IndexOffAddrOp_StablePtr = 417+primOpTag IndexOffAddrOp_Int8 = 418+primOpTag IndexOffAddrOp_Int16 = 419+primOpTag IndexOffAddrOp_Int32 = 420+primOpTag IndexOffAddrOp_Int64 = 421+primOpTag IndexOffAddrOp_Word8 = 422+primOpTag IndexOffAddrOp_Word16 = 423+primOpTag IndexOffAddrOp_Word32 = 424+primOpTag IndexOffAddrOp_Word64 = 425+primOpTag ReadOffAddrOp_Char = 426+primOpTag ReadOffAddrOp_WideChar = 427+primOpTag ReadOffAddrOp_Int = 428+primOpTag ReadOffAddrOp_Word = 429+primOpTag ReadOffAddrOp_Addr = 430+primOpTag ReadOffAddrOp_Float = 431+primOpTag ReadOffAddrOp_Double = 432+primOpTag ReadOffAddrOp_StablePtr = 433+primOpTag ReadOffAddrOp_Int8 = 434+primOpTag ReadOffAddrOp_Int16 = 435+primOpTag ReadOffAddrOp_Int32 = 436+primOpTag ReadOffAddrOp_Int64 = 437+primOpTag ReadOffAddrOp_Word8 = 438+primOpTag ReadOffAddrOp_Word16 = 439+primOpTag ReadOffAddrOp_Word32 = 440+primOpTag ReadOffAddrOp_Word64 = 441+primOpTag WriteOffAddrOp_Char = 442+primOpTag WriteOffAddrOp_WideChar = 443+primOpTag WriteOffAddrOp_Int = 444+primOpTag WriteOffAddrOp_Word = 445+primOpTag WriteOffAddrOp_Addr = 446+primOpTag WriteOffAddrOp_Float = 447+primOpTag WriteOffAddrOp_Double = 448+primOpTag WriteOffAddrOp_StablePtr = 449+primOpTag WriteOffAddrOp_Int8 = 450+primOpTag WriteOffAddrOp_Int16 = 451+primOpTag WriteOffAddrOp_Int32 = 452+primOpTag WriteOffAddrOp_Int64 = 453+primOpTag WriteOffAddrOp_Word8 = 454+primOpTag WriteOffAddrOp_Word16 = 455+primOpTag WriteOffAddrOp_Word32 = 456+primOpTag WriteOffAddrOp_Word64 = 457+primOpTag NewMutVarOp = 458+primOpTag ReadMutVarOp = 459+primOpTag WriteMutVarOp = 460+primOpTag SameMutVarOp = 461+primOpTag AtomicModifyMutVar2Op = 462+primOpTag AtomicModifyMutVar_Op = 463+primOpTag CasMutVarOp = 464+primOpTag CatchOp = 465+primOpTag RaiseOp = 466+primOpTag RaiseIOOp = 467+primOpTag MaskAsyncExceptionsOp = 468+primOpTag MaskUninterruptibleOp = 469+primOpTag UnmaskAsyncExceptionsOp = 470+primOpTag MaskStatus = 471+primOpTag AtomicallyOp = 472+primOpTag RetryOp = 473+primOpTag CatchRetryOp = 474+primOpTag CatchSTMOp = 475+primOpTag NewTVarOp = 476+primOpTag ReadTVarOp = 477+primOpTag ReadTVarIOOp = 478+primOpTag WriteTVarOp = 479+primOpTag SameTVarOp = 480+primOpTag NewMVarOp = 481+primOpTag TakeMVarOp = 482+primOpTag TryTakeMVarOp = 483+primOpTag PutMVarOp = 484+primOpTag TryPutMVarOp = 485+primOpTag ReadMVarOp = 486+primOpTag TryReadMVarOp = 487+primOpTag SameMVarOp = 488+primOpTag IsEmptyMVarOp = 489+primOpTag DelayOp = 490+primOpTag WaitReadOp = 491+primOpTag WaitWriteOp = 492+primOpTag ForkOp = 493+primOpTag ForkOnOp = 494+primOpTag KillThreadOp = 495+primOpTag YieldOp = 496+primOpTag MyThreadIdOp = 497+primOpTag LabelThreadOp = 498+primOpTag IsCurrentThreadBoundOp = 499+primOpTag NoDuplicateOp = 500+primOpTag ThreadStatusOp = 501+primOpTag MkWeakOp = 502+primOpTag MkWeakNoFinalizerOp = 503+primOpTag AddCFinalizerToWeakOp = 504+primOpTag DeRefWeakOp = 505+primOpTag FinalizeWeakOp = 506+primOpTag TouchOp = 507+primOpTag MakeStablePtrOp = 508+primOpTag DeRefStablePtrOp = 509+primOpTag EqStablePtrOp = 510+primOpTag MakeStableNameOp = 511+primOpTag EqStableNameOp = 512+primOpTag StableNameToIntOp = 513+primOpTag CompactNewOp = 514+primOpTag CompactResizeOp = 515+primOpTag CompactContainsOp = 516+primOpTag CompactContainsAnyOp = 517+primOpTag CompactGetFirstBlockOp = 518+primOpTag CompactGetNextBlockOp = 519+primOpTag CompactAllocateBlockOp = 520+primOpTag CompactFixupPointersOp = 521+primOpTag CompactAdd = 522+primOpTag CompactAddWithSharing = 523+primOpTag CompactSize = 524+primOpTag ReallyUnsafePtrEqualityOp = 525+primOpTag ParOp = 526+primOpTag SparkOp = 527+primOpTag SeqOp = 528+primOpTag GetSparkOp = 529+primOpTag NumSparks = 530+primOpTag DataToTagOp = 531+primOpTag TagToEnumOp = 532+primOpTag AddrToAnyOp = 533+primOpTag AnyToAddrOp = 534+primOpTag MkApUpd0_Op = 535+primOpTag NewBCOOp = 536+primOpTag UnpackClosureOp = 537+primOpTag ClosureSizeOp = 538+primOpTag GetApStackValOp = 539+primOpTag GetCCSOfOp = 540+primOpTag GetCurrentCCSOp = 541+primOpTag ClearCCSOp = 542+primOpTag TraceEventOp = 543+primOpTag TraceEventBinaryOp = 544+primOpTag TraceMarkerOp = 545+primOpTag SetThreadAllocationCounter = 546+primOpTag (VecBroadcastOp IntVec 16 W8) = 547+primOpTag (VecBroadcastOp IntVec 8 W16) = 548+primOpTag (VecBroadcastOp IntVec 4 W32) = 549+primOpTag (VecBroadcastOp IntVec 2 W64) = 550+primOpTag (VecBroadcastOp IntVec 32 W8) = 551+primOpTag (VecBroadcastOp IntVec 16 W16) = 552+primOpTag (VecBroadcastOp IntVec 8 W32) = 553+primOpTag (VecBroadcastOp IntVec 4 W64) = 554+primOpTag (VecBroadcastOp IntVec 64 W8) = 555+primOpTag (VecBroadcastOp IntVec 32 W16) = 556+primOpTag (VecBroadcastOp IntVec 16 W32) = 557+primOpTag (VecBroadcastOp IntVec 8 W64) = 558+primOpTag (VecBroadcastOp WordVec 16 W8) = 559+primOpTag (VecBroadcastOp WordVec 8 W16) = 560+primOpTag (VecBroadcastOp WordVec 4 W32) = 561+primOpTag (VecBroadcastOp WordVec 2 W64) = 562+primOpTag (VecBroadcastOp WordVec 32 W8) = 563+primOpTag (VecBroadcastOp WordVec 16 W16) = 564+primOpTag (VecBroadcastOp WordVec 8 W32) = 565+primOpTag (VecBroadcastOp WordVec 4 W64) = 566+primOpTag (VecBroadcastOp WordVec 64 W8) = 567+primOpTag (VecBroadcastOp WordVec 32 W16) = 568+primOpTag (VecBroadcastOp WordVec 16 W32) = 569+primOpTag (VecBroadcastOp WordVec 8 W64) = 570+primOpTag (VecBroadcastOp FloatVec 4 W32) = 571+primOpTag (VecBroadcastOp FloatVec 2 W64) = 572+primOpTag (VecBroadcastOp FloatVec 8 W32) = 573+primOpTag (VecBroadcastOp FloatVec 4 W64) = 574+primOpTag (VecBroadcastOp FloatVec 16 W32) = 575+primOpTag (VecBroadcastOp FloatVec 8 W64) = 576+primOpTag (VecPackOp IntVec 16 W8) = 577+primOpTag (VecPackOp IntVec 8 W16) = 578+primOpTag (VecPackOp IntVec 4 W32) = 579+primOpTag (VecPackOp IntVec 2 W64) = 580+primOpTag (VecPackOp IntVec 32 W8) = 581+primOpTag (VecPackOp IntVec 16 W16) = 582+primOpTag (VecPackOp IntVec 8 W32) = 583+primOpTag (VecPackOp IntVec 4 W64) = 584+primOpTag (VecPackOp IntVec 64 W8) = 585+primOpTag (VecPackOp IntVec 32 W16) = 586+primOpTag (VecPackOp IntVec 16 W32) = 587+primOpTag (VecPackOp IntVec 8 W64) = 588+primOpTag (VecPackOp WordVec 16 W8) = 589+primOpTag (VecPackOp WordVec 8 W16) = 590+primOpTag (VecPackOp WordVec 4 W32) = 591+primOpTag (VecPackOp WordVec 2 W64) = 592+primOpTag (VecPackOp WordVec 32 W8) = 593+primOpTag (VecPackOp WordVec 16 W16) = 594+primOpTag (VecPackOp WordVec 8 W32) = 595+primOpTag (VecPackOp WordVec 4 W64) = 596+primOpTag (VecPackOp WordVec 64 W8) = 597+primOpTag (VecPackOp WordVec 32 W16) = 598+primOpTag (VecPackOp WordVec 16 W32) = 599+primOpTag (VecPackOp WordVec 8 W64) = 600+primOpTag (VecPackOp FloatVec 4 W32) = 601+primOpTag (VecPackOp FloatVec 2 W64) = 602+primOpTag (VecPackOp FloatVec 8 W32) = 603+primOpTag (VecPackOp FloatVec 4 W64) = 604+primOpTag (VecPackOp FloatVec 16 W32) = 605+primOpTag (VecPackOp FloatVec 8 W64) = 606+primOpTag (VecUnpackOp IntVec 16 W8) = 607+primOpTag (VecUnpackOp IntVec 8 W16) = 608+primOpTag (VecUnpackOp IntVec 4 W32) = 609+primOpTag (VecUnpackOp IntVec 2 W64) = 610+primOpTag (VecUnpackOp IntVec 32 W8) = 611+primOpTag (VecUnpackOp IntVec 16 W16) = 612+primOpTag (VecUnpackOp IntVec 8 W32) = 613+primOpTag (VecUnpackOp IntVec 4 W64) = 614+primOpTag (VecUnpackOp IntVec 64 W8) = 615+primOpTag (VecUnpackOp IntVec 32 W16) = 616+primOpTag (VecUnpackOp IntVec 16 W32) = 617+primOpTag (VecUnpackOp IntVec 8 W64) = 618+primOpTag (VecUnpackOp WordVec 16 W8) = 619+primOpTag (VecUnpackOp WordVec 8 W16) = 620+primOpTag (VecUnpackOp WordVec 4 W32) = 621+primOpTag (VecUnpackOp WordVec 2 W64) = 622+primOpTag (VecUnpackOp WordVec 32 W8) = 623+primOpTag (VecUnpackOp WordVec 16 W16) = 624+primOpTag (VecUnpackOp WordVec 8 W32) = 625+primOpTag (VecUnpackOp WordVec 4 W64) = 626+primOpTag (VecUnpackOp WordVec 64 W8) = 627+primOpTag (VecUnpackOp WordVec 32 W16) = 628+primOpTag (VecUnpackOp WordVec 16 W32) = 629+primOpTag (VecUnpackOp WordVec 8 W64) = 630+primOpTag (VecUnpackOp FloatVec 4 W32) = 631+primOpTag (VecUnpackOp FloatVec 2 W64) = 632+primOpTag (VecUnpackOp FloatVec 8 W32) = 633+primOpTag (VecUnpackOp FloatVec 4 W64) = 634+primOpTag (VecUnpackOp FloatVec 16 W32) = 635+primOpTag (VecUnpackOp FloatVec 8 W64) = 636+primOpTag (VecInsertOp IntVec 16 W8) = 637+primOpTag (VecInsertOp IntVec 8 W16) = 638+primOpTag (VecInsertOp IntVec 4 W32) = 639+primOpTag (VecInsertOp IntVec 2 W64) = 640+primOpTag (VecInsertOp IntVec 32 W8) = 641+primOpTag (VecInsertOp IntVec 16 W16) = 642+primOpTag (VecInsertOp IntVec 8 W32) = 643+primOpTag (VecInsertOp IntVec 4 W64) = 644+primOpTag (VecInsertOp IntVec 64 W8) = 645+primOpTag (VecInsertOp IntVec 32 W16) = 646+primOpTag (VecInsertOp IntVec 16 W32) = 647+primOpTag (VecInsertOp IntVec 8 W64) = 648+primOpTag (VecInsertOp WordVec 16 W8) = 649+primOpTag (VecInsertOp WordVec 8 W16) = 650+primOpTag (VecInsertOp WordVec 4 W32) = 651+primOpTag (VecInsertOp WordVec 2 W64) = 652+primOpTag (VecInsertOp WordVec 32 W8) = 653+primOpTag (VecInsertOp WordVec 16 W16) = 654+primOpTag (VecInsertOp WordVec 8 W32) = 655+primOpTag (VecInsertOp WordVec 4 W64) = 656+primOpTag (VecInsertOp WordVec 64 W8) = 657+primOpTag (VecInsertOp WordVec 32 W16) = 658+primOpTag (VecInsertOp WordVec 16 W32) = 659+primOpTag (VecInsertOp WordVec 8 W64) = 660+primOpTag (VecInsertOp FloatVec 4 W32) = 661+primOpTag (VecInsertOp FloatVec 2 W64) = 662+primOpTag (VecInsertOp FloatVec 8 W32) = 663+primOpTag (VecInsertOp FloatVec 4 W64) = 664+primOpTag (VecInsertOp FloatVec 16 W32) = 665+primOpTag (VecInsertOp FloatVec 8 W64) = 666+primOpTag (VecAddOp IntVec 16 W8) = 667+primOpTag (VecAddOp IntVec 8 W16) = 668+primOpTag (VecAddOp IntVec 4 W32) = 669+primOpTag (VecAddOp IntVec 2 W64) = 670+primOpTag (VecAddOp IntVec 32 W8) = 671+primOpTag (VecAddOp IntVec 16 W16) = 672+primOpTag (VecAddOp IntVec 8 W32) = 673+primOpTag (VecAddOp IntVec 4 W64) = 674+primOpTag (VecAddOp IntVec 64 W8) = 675+primOpTag (VecAddOp IntVec 32 W16) = 676+primOpTag (VecAddOp IntVec 16 W32) = 677+primOpTag (VecAddOp IntVec 8 W64) = 678+primOpTag (VecAddOp WordVec 16 W8) = 679+primOpTag (VecAddOp WordVec 8 W16) = 680+primOpTag (VecAddOp WordVec 4 W32) = 681+primOpTag (VecAddOp WordVec 2 W64) = 682+primOpTag (VecAddOp WordVec 32 W8) = 683+primOpTag (VecAddOp WordVec 16 W16) = 684+primOpTag (VecAddOp WordVec 8 W32) = 685+primOpTag (VecAddOp WordVec 4 W64) = 686+primOpTag (VecAddOp WordVec 64 W8) = 687+primOpTag (VecAddOp WordVec 32 W16) = 688+primOpTag (VecAddOp WordVec 16 W32) = 689+primOpTag (VecAddOp WordVec 8 W64) = 690+primOpTag (VecAddOp FloatVec 4 W32) = 691+primOpTag (VecAddOp FloatVec 2 W64) = 692+primOpTag (VecAddOp FloatVec 8 W32) = 693+primOpTag (VecAddOp FloatVec 4 W64) = 694+primOpTag (VecAddOp FloatVec 16 W32) = 695+primOpTag (VecAddOp FloatVec 8 W64) = 696+primOpTag (VecSubOp IntVec 16 W8) = 697+primOpTag (VecSubOp IntVec 8 W16) = 698+primOpTag (VecSubOp IntVec 4 W32) = 699+primOpTag (VecSubOp IntVec 2 W64) = 700+primOpTag (VecSubOp IntVec 32 W8) = 701+primOpTag (VecSubOp IntVec 16 W16) = 702+primOpTag (VecSubOp IntVec 8 W32) = 703+primOpTag (VecSubOp IntVec 4 W64) = 704+primOpTag (VecSubOp IntVec 64 W8) = 705+primOpTag (VecSubOp IntVec 32 W16) = 706+primOpTag (VecSubOp IntVec 16 W32) = 707+primOpTag (VecSubOp IntVec 8 W64) = 708+primOpTag (VecSubOp WordVec 16 W8) = 709+primOpTag (VecSubOp WordVec 8 W16) = 710+primOpTag (VecSubOp WordVec 4 W32) = 711+primOpTag (VecSubOp WordVec 2 W64) = 712+primOpTag (VecSubOp WordVec 32 W8) = 713+primOpTag (VecSubOp WordVec 16 W16) = 714+primOpTag (VecSubOp WordVec 8 W32) = 715+primOpTag (VecSubOp WordVec 4 W64) = 716+primOpTag (VecSubOp WordVec 64 W8) = 717+primOpTag (VecSubOp WordVec 32 W16) = 718+primOpTag (VecSubOp WordVec 16 W32) = 719+primOpTag (VecSubOp WordVec 8 W64) = 720+primOpTag (VecSubOp FloatVec 4 W32) = 721+primOpTag (VecSubOp FloatVec 2 W64) = 722+primOpTag (VecSubOp FloatVec 8 W32) = 723+primOpTag (VecSubOp FloatVec 4 W64) = 724+primOpTag (VecSubOp FloatVec 16 W32) = 725+primOpTag (VecSubOp FloatVec 8 W64) = 726+primOpTag (VecMulOp IntVec 16 W8) = 727+primOpTag (VecMulOp IntVec 8 W16) = 728+primOpTag (VecMulOp IntVec 4 W32) = 729+primOpTag (VecMulOp IntVec 2 W64) = 730+primOpTag (VecMulOp IntVec 32 W8) = 731+primOpTag (VecMulOp IntVec 16 W16) = 732+primOpTag (VecMulOp IntVec 8 W32) = 733+primOpTag (VecMulOp IntVec 4 W64) = 734+primOpTag (VecMulOp IntVec 64 W8) = 735+primOpTag (VecMulOp IntVec 32 W16) = 736+primOpTag (VecMulOp IntVec 16 W32) = 737+primOpTag (VecMulOp IntVec 8 W64) = 738+primOpTag (VecMulOp WordVec 16 W8) = 739+primOpTag (VecMulOp WordVec 8 W16) = 740+primOpTag (VecMulOp WordVec 4 W32) = 741+primOpTag (VecMulOp WordVec 2 W64) = 742+primOpTag (VecMulOp WordVec 32 W8) = 743+primOpTag (VecMulOp WordVec 16 W16) = 744+primOpTag (VecMulOp WordVec 8 W32) = 745+primOpTag (VecMulOp WordVec 4 W64) = 746+primOpTag (VecMulOp WordVec 64 W8) = 747+primOpTag (VecMulOp WordVec 32 W16) = 748+primOpTag (VecMulOp WordVec 16 W32) = 749+primOpTag (VecMulOp WordVec 8 W64) = 750+primOpTag (VecMulOp FloatVec 4 W32) = 751+primOpTag (VecMulOp FloatVec 2 W64) = 752+primOpTag (VecMulOp FloatVec 8 W32) = 753+primOpTag (VecMulOp FloatVec 4 W64) = 754+primOpTag (VecMulOp FloatVec 16 W32) = 755+primOpTag (VecMulOp FloatVec 8 W64) = 756+primOpTag (VecDivOp FloatVec 4 W32) = 757+primOpTag (VecDivOp FloatVec 2 W64) = 758+primOpTag (VecDivOp FloatVec 8 W32) = 759+primOpTag (VecDivOp FloatVec 4 W64) = 760+primOpTag (VecDivOp FloatVec 16 W32) = 761+primOpTag (VecDivOp FloatVec 8 W64) = 762+primOpTag (VecQuotOp IntVec 16 W8) = 763+primOpTag (VecQuotOp IntVec 8 W16) = 764+primOpTag (VecQuotOp IntVec 4 W32) = 765+primOpTag (VecQuotOp IntVec 2 W64) = 766+primOpTag (VecQuotOp IntVec 32 W8) = 767+primOpTag (VecQuotOp IntVec 16 W16) = 768+primOpTag (VecQuotOp IntVec 8 W32) = 769+primOpTag (VecQuotOp IntVec 4 W64) = 770+primOpTag (VecQuotOp IntVec 64 W8) = 771+primOpTag (VecQuotOp IntVec 32 W16) = 772+primOpTag (VecQuotOp IntVec 16 W32) = 773+primOpTag (VecQuotOp IntVec 8 W64) = 774+primOpTag (VecQuotOp WordVec 16 W8) = 775+primOpTag (VecQuotOp WordVec 8 W16) = 776+primOpTag (VecQuotOp WordVec 4 W32) = 777+primOpTag (VecQuotOp WordVec 2 W64) = 778+primOpTag (VecQuotOp WordVec 32 W8) = 779+primOpTag (VecQuotOp WordVec 16 W16) = 780+primOpTag (VecQuotOp WordVec 8 W32) = 781+primOpTag (VecQuotOp WordVec 4 W64) = 782+primOpTag (VecQuotOp WordVec 64 W8) = 783+primOpTag (VecQuotOp WordVec 32 W16) = 784+primOpTag (VecQuotOp WordVec 16 W32) = 785+primOpTag (VecQuotOp WordVec 8 W64) = 786+primOpTag (VecRemOp IntVec 16 W8) = 787+primOpTag (VecRemOp IntVec 8 W16) = 788+primOpTag (VecRemOp IntVec 4 W32) = 789+primOpTag (VecRemOp IntVec 2 W64) = 790+primOpTag (VecRemOp IntVec 32 W8) = 791+primOpTag (VecRemOp IntVec 16 W16) = 792+primOpTag (VecRemOp IntVec 8 W32) = 793+primOpTag (VecRemOp IntVec 4 W64) = 794+primOpTag (VecRemOp IntVec 64 W8) = 795+primOpTag (VecRemOp IntVec 32 W16) = 796+primOpTag (VecRemOp IntVec 16 W32) = 797+primOpTag (VecRemOp IntVec 8 W64) = 798+primOpTag (VecRemOp WordVec 16 W8) = 799+primOpTag (VecRemOp WordVec 8 W16) = 800+primOpTag (VecRemOp WordVec 4 W32) = 801+primOpTag (VecRemOp WordVec 2 W64) = 802+primOpTag (VecRemOp WordVec 32 W8) = 803+primOpTag (VecRemOp WordVec 16 W16) = 804+primOpTag (VecRemOp WordVec 8 W32) = 805+primOpTag (VecRemOp WordVec 4 W64) = 806+primOpTag (VecRemOp WordVec 64 W8) = 807+primOpTag (VecRemOp WordVec 32 W16) = 808+primOpTag (VecRemOp WordVec 16 W32) = 809+primOpTag (VecRemOp WordVec 8 W64) = 810+primOpTag (VecNegOp IntVec 16 W8) = 811+primOpTag (VecNegOp IntVec 8 W16) = 812+primOpTag (VecNegOp IntVec 4 W32) = 813+primOpTag (VecNegOp IntVec 2 W64) = 814+primOpTag (VecNegOp IntVec 32 W8) = 815+primOpTag (VecNegOp IntVec 16 W16) = 816+primOpTag (VecNegOp IntVec 8 W32) = 817+primOpTag (VecNegOp IntVec 4 W64) = 818+primOpTag (VecNegOp IntVec 64 W8) = 819+primOpTag (VecNegOp IntVec 32 W16) = 820+primOpTag (VecNegOp IntVec 16 W32) = 821+primOpTag (VecNegOp IntVec 8 W64) = 822+primOpTag (VecNegOp FloatVec 4 W32) = 823+primOpTag (VecNegOp FloatVec 2 W64) = 824+primOpTag (VecNegOp FloatVec 8 W32) = 825+primOpTag (VecNegOp FloatVec 4 W64) = 826+primOpTag (VecNegOp FloatVec 16 W32) = 827+primOpTag (VecNegOp FloatVec 8 W64) = 828+primOpTag (VecIndexByteArrayOp IntVec 16 W8) = 829+primOpTag (VecIndexByteArrayOp IntVec 8 W16) = 830+primOpTag (VecIndexByteArrayOp IntVec 4 W32) = 831+primOpTag (VecIndexByteArrayOp IntVec 2 W64) = 832+primOpTag (VecIndexByteArrayOp IntVec 32 W8) = 833+primOpTag (VecIndexByteArrayOp IntVec 16 W16) = 834+primOpTag (VecIndexByteArrayOp IntVec 8 W32) = 835+primOpTag (VecIndexByteArrayOp IntVec 4 W64) = 836+primOpTag (VecIndexByteArrayOp IntVec 64 W8) = 837+primOpTag (VecIndexByteArrayOp IntVec 32 W16) = 838+primOpTag (VecIndexByteArrayOp IntVec 16 W32) = 839+primOpTag (VecIndexByteArrayOp IntVec 8 W64) = 840+primOpTag (VecIndexByteArrayOp WordVec 16 W8) = 841+primOpTag (VecIndexByteArrayOp WordVec 8 W16) = 842+primOpTag (VecIndexByteArrayOp WordVec 4 W32) = 843+primOpTag (VecIndexByteArrayOp WordVec 2 W64) = 844+primOpTag (VecIndexByteArrayOp WordVec 32 W8) = 845+primOpTag (VecIndexByteArrayOp WordVec 16 W16) = 846+primOpTag (VecIndexByteArrayOp WordVec 8 W32) = 847+primOpTag (VecIndexByteArrayOp WordVec 4 W64) = 848+primOpTag (VecIndexByteArrayOp WordVec 64 W8) = 849+primOpTag (VecIndexByteArrayOp WordVec 32 W16) = 850+primOpTag (VecIndexByteArrayOp WordVec 16 W32) = 851+primOpTag (VecIndexByteArrayOp WordVec 8 W64) = 852+primOpTag (VecIndexByteArrayOp FloatVec 4 W32) = 853+primOpTag (VecIndexByteArrayOp FloatVec 2 W64) = 854+primOpTag (VecIndexByteArrayOp FloatVec 8 W32) = 855+primOpTag (VecIndexByteArrayOp FloatVec 4 W64) = 856+primOpTag (VecIndexByteArrayOp FloatVec 16 W32) = 857+primOpTag (VecIndexByteArrayOp FloatVec 8 W64) = 858+primOpTag (VecReadByteArrayOp IntVec 16 W8) = 859+primOpTag (VecReadByteArrayOp IntVec 8 W16) = 860+primOpTag (VecReadByteArrayOp IntVec 4 W32) = 861+primOpTag (VecReadByteArrayOp IntVec 2 W64) = 862+primOpTag (VecReadByteArrayOp IntVec 32 W8) = 863+primOpTag (VecReadByteArrayOp IntVec 16 W16) = 864+primOpTag (VecReadByteArrayOp IntVec 8 W32) = 865+primOpTag (VecReadByteArrayOp IntVec 4 W64) = 866+primOpTag (VecReadByteArrayOp IntVec 64 W8) = 867+primOpTag (VecReadByteArrayOp IntVec 32 W16) = 868+primOpTag (VecReadByteArrayOp IntVec 16 W32) = 869+primOpTag (VecReadByteArrayOp IntVec 8 W64) = 870+primOpTag (VecReadByteArrayOp WordVec 16 W8) = 871+primOpTag (VecReadByteArrayOp WordVec 8 W16) = 872+primOpTag (VecReadByteArrayOp WordVec 4 W32) = 873+primOpTag (VecReadByteArrayOp WordVec 2 W64) = 874+primOpTag (VecReadByteArrayOp WordVec 32 W8) = 875+primOpTag (VecReadByteArrayOp WordVec 16 W16) = 876+primOpTag (VecReadByteArrayOp WordVec 8 W32) = 877+primOpTag (VecReadByteArrayOp WordVec 4 W64) = 878+primOpTag (VecReadByteArrayOp WordVec 64 W8) = 879+primOpTag (VecReadByteArrayOp WordVec 32 W16) = 880+primOpTag (VecReadByteArrayOp WordVec 16 W32) = 881+primOpTag (VecReadByteArrayOp WordVec 8 W64) = 882+primOpTag (VecReadByteArrayOp FloatVec 4 W32) = 883+primOpTag (VecReadByteArrayOp FloatVec 2 W64) = 884+primOpTag (VecReadByteArrayOp FloatVec 8 W32) = 885+primOpTag (VecReadByteArrayOp FloatVec 4 W64) = 886+primOpTag (VecReadByteArrayOp FloatVec 16 W32) = 887+primOpTag (VecReadByteArrayOp FloatVec 8 W64) = 888+primOpTag (VecWriteByteArrayOp IntVec 16 W8) = 889+primOpTag (VecWriteByteArrayOp IntVec 8 W16) = 890+primOpTag (VecWriteByteArrayOp IntVec 4 W32) = 891+primOpTag (VecWriteByteArrayOp IntVec 2 W64) = 892+primOpTag (VecWriteByteArrayOp IntVec 32 W8) = 893+primOpTag (VecWriteByteArrayOp IntVec 16 W16) = 894+primOpTag (VecWriteByteArrayOp IntVec 8 W32) = 895+primOpTag (VecWriteByteArrayOp IntVec 4 W64) = 896+primOpTag (VecWriteByteArrayOp IntVec 64 W8) = 897+primOpTag (VecWriteByteArrayOp IntVec 32 W16) = 898+primOpTag (VecWriteByteArrayOp IntVec 16 W32) = 899+primOpTag (VecWriteByteArrayOp IntVec 8 W64) = 900+primOpTag (VecWriteByteArrayOp WordVec 16 W8) = 901+primOpTag (VecWriteByteArrayOp WordVec 8 W16) = 902+primOpTag (VecWriteByteArrayOp WordVec 4 W32) = 903+primOpTag (VecWriteByteArrayOp WordVec 2 W64) = 904+primOpTag (VecWriteByteArrayOp WordVec 32 W8) = 905+primOpTag (VecWriteByteArrayOp WordVec 16 W16) = 906+primOpTag (VecWriteByteArrayOp WordVec 8 W32) = 907+primOpTag (VecWriteByteArrayOp WordVec 4 W64) = 908+primOpTag (VecWriteByteArrayOp WordVec 64 W8) = 909+primOpTag (VecWriteByteArrayOp WordVec 32 W16) = 910+primOpTag (VecWriteByteArrayOp WordVec 16 W32) = 911+primOpTag (VecWriteByteArrayOp WordVec 8 W64) = 912+primOpTag (VecWriteByteArrayOp FloatVec 4 W32) = 913+primOpTag (VecWriteByteArrayOp FloatVec 2 W64) = 914+primOpTag (VecWriteByteArrayOp FloatVec 8 W32) = 915+primOpTag (VecWriteByteArrayOp FloatVec 4 W64) = 916+primOpTag (VecWriteByteArrayOp FloatVec 16 W32) = 917+primOpTag (VecWriteByteArrayOp FloatVec 8 W64) = 918+primOpTag (VecIndexOffAddrOp IntVec 16 W8) = 919+primOpTag (VecIndexOffAddrOp IntVec 8 W16) = 920+primOpTag (VecIndexOffAddrOp IntVec 4 W32) = 921+primOpTag (VecIndexOffAddrOp IntVec 2 W64) = 922+primOpTag (VecIndexOffAddrOp IntVec 32 W8) = 923+primOpTag (VecIndexOffAddrOp IntVec 16 W16) = 924+primOpTag (VecIndexOffAddrOp IntVec 8 W32) = 925+primOpTag (VecIndexOffAddrOp IntVec 4 W64) = 926+primOpTag (VecIndexOffAddrOp IntVec 64 W8) = 927+primOpTag (VecIndexOffAddrOp IntVec 32 W16) = 928+primOpTag (VecIndexOffAddrOp IntVec 16 W32) = 929+primOpTag (VecIndexOffAddrOp IntVec 8 W64) = 930+primOpTag (VecIndexOffAddrOp WordVec 16 W8) = 931+primOpTag (VecIndexOffAddrOp WordVec 8 W16) = 932+primOpTag (VecIndexOffAddrOp WordVec 4 W32) = 933+primOpTag (VecIndexOffAddrOp WordVec 2 W64) = 934+primOpTag (VecIndexOffAddrOp WordVec 32 W8) = 935+primOpTag (VecIndexOffAddrOp WordVec 16 W16) = 936+primOpTag (VecIndexOffAddrOp WordVec 8 W32) = 937+primOpTag (VecIndexOffAddrOp WordVec 4 W64) = 938+primOpTag (VecIndexOffAddrOp WordVec 64 W8) = 939+primOpTag (VecIndexOffAddrOp WordVec 32 W16) = 940+primOpTag (VecIndexOffAddrOp WordVec 16 W32) = 941+primOpTag (VecIndexOffAddrOp WordVec 8 W64) = 942+primOpTag (VecIndexOffAddrOp FloatVec 4 W32) = 943+primOpTag (VecIndexOffAddrOp FloatVec 2 W64) = 944+primOpTag (VecIndexOffAddrOp FloatVec 8 W32) = 945+primOpTag (VecIndexOffAddrOp FloatVec 4 W64) = 946+primOpTag (VecIndexOffAddrOp FloatVec 16 W32) = 947+primOpTag (VecIndexOffAddrOp FloatVec 8 W64) = 948+primOpTag (VecReadOffAddrOp IntVec 16 W8) = 949+primOpTag (VecReadOffAddrOp IntVec 8 W16) = 950+primOpTag (VecReadOffAddrOp IntVec 4 W32) = 951+primOpTag (VecReadOffAddrOp IntVec 2 W64) = 952+primOpTag (VecReadOffAddrOp IntVec 32 W8) = 953+primOpTag (VecReadOffAddrOp IntVec 16 W16) = 954+primOpTag (VecReadOffAddrOp IntVec 8 W32) = 955+primOpTag (VecReadOffAddrOp IntVec 4 W64) = 956+primOpTag (VecReadOffAddrOp IntVec 64 W8) = 957+primOpTag (VecReadOffAddrOp IntVec 32 W16) = 958+primOpTag (VecReadOffAddrOp IntVec 16 W32) = 959+primOpTag (VecReadOffAddrOp IntVec 8 W64) = 960+primOpTag (VecReadOffAddrOp WordVec 16 W8) = 961+primOpTag (VecReadOffAddrOp WordVec 8 W16) = 962+primOpTag (VecReadOffAddrOp WordVec 4 W32) = 963+primOpTag (VecReadOffAddrOp WordVec 2 W64) = 964+primOpTag (VecReadOffAddrOp WordVec 32 W8) = 965+primOpTag (VecReadOffAddrOp WordVec 16 W16) = 966+primOpTag (VecReadOffAddrOp WordVec 8 W32) = 967+primOpTag (VecReadOffAddrOp WordVec 4 W64) = 968+primOpTag (VecReadOffAddrOp WordVec 64 W8) = 969+primOpTag (VecReadOffAddrOp WordVec 32 W16) = 970+primOpTag (VecReadOffAddrOp WordVec 16 W32) = 971+primOpTag (VecReadOffAddrOp WordVec 8 W64) = 972+primOpTag (VecReadOffAddrOp FloatVec 4 W32) = 973+primOpTag (VecReadOffAddrOp FloatVec 2 W64) = 974+primOpTag (VecReadOffAddrOp FloatVec 8 W32) = 975+primOpTag (VecReadOffAddrOp FloatVec 4 W64) = 976+primOpTag (VecReadOffAddrOp FloatVec 16 W32) = 977+primOpTag (VecReadOffAddrOp FloatVec 8 W64) = 978+primOpTag (VecWriteOffAddrOp IntVec 16 W8) = 979+primOpTag (VecWriteOffAddrOp IntVec 8 W16) = 980+primOpTag (VecWriteOffAddrOp IntVec 4 W32) = 981+primOpTag (VecWriteOffAddrOp IntVec 2 W64) = 982+primOpTag (VecWriteOffAddrOp IntVec 32 W8) = 983+primOpTag (VecWriteOffAddrOp IntVec 16 W16) = 984+primOpTag (VecWriteOffAddrOp IntVec 8 W32) = 985+primOpTag (VecWriteOffAddrOp IntVec 4 W64) = 986+primOpTag (VecWriteOffAddrOp IntVec 64 W8) = 987+primOpTag (VecWriteOffAddrOp IntVec 32 W16) = 988+primOpTag (VecWriteOffAddrOp IntVec 16 W32) = 989+primOpTag (VecWriteOffAddrOp IntVec 8 W64) = 990+primOpTag (VecWriteOffAddrOp WordVec 16 W8) = 991+primOpTag (VecWriteOffAddrOp WordVec 8 W16) = 992+primOpTag (VecWriteOffAddrOp WordVec 4 W32) = 993+primOpTag (VecWriteOffAddrOp WordVec 2 W64) = 994+primOpTag (VecWriteOffAddrOp WordVec 32 W8) = 995+primOpTag (VecWriteOffAddrOp WordVec 16 W16) = 996+primOpTag (VecWriteOffAddrOp WordVec 8 W32) = 997+primOpTag (VecWriteOffAddrOp WordVec 4 W64) = 998+primOpTag (VecWriteOffAddrOp WordVec 64 W8) = 999+primOpTag (VecWriteOffAddrOp WordVec 32 W16) = 1000+primOpTag (VecWriteOffAddrOp WordVec 16 W32) = 1001+primOpTag (VecWriteOffAddrOp WordVec 8 W64) = 1002+primOpTag (VecWriteOffAddrOp FloatVec 4 W32) = 1003+primOpTag (VecWriteOffAddrOp FloatVec 2 W64) = 1004+primOpTag (VecWriteOffAddrOp FloatVec 8 W32) = 1005+primOpTag (VecWriteOffAddrOp FloatVec 4 W64) = 1006+primOpTag (VecWriteOffAddrOp FloatVec 16 W32) = 1007+primOpTag (VecWriteOffAddrOp FloatVec 8 W64) = 1008+primOpTag (VecIndexScalarByteArrayOp IntVec 16 W8) = 1009+primOpTag (VecIndexScalarByteArrayOp IntVec 8 W16) = 1010+primOpTag (VecIndexScalarByteArrayOp IntVec 4 W32) = 1011+primOpTag (VecIndexScalarByteArrayOp IntVec 2 W64) = 1012+primOpTag (VecIndexScalarByteArrayOp IntVec 32 W8) = 1013+primOpTag (VecIndexScalarByteArrayOp IntVec 16 W16) = 1014+primOpTag (VecIndexScalarByteArrayOp IntVec 8 W32) = 1015+primOpTag (VecIndexScalarByteArrayOp IntVec 4 W64) = 1016+primOpTag (VecIndexScalarByteArrayOp IntVec 64 W8) = 1017+primOpTag (VecIndexScalarByteArrayOp IntVec 32 W16) = 1018+primOpTag (VecIndexScalarByteArrayOp IntVec 16 W32) = 1019+primOpTag (VecIndexScalarByteArrayOp IntVec 8 W64) = 1020+primOpTag (VecIndexScalarByteArrayOp WordVec 16 W8) = 1021+primOpTag (VecIndexScalarByteArrayOp WordVec 8 W16) = 1022+primOpTag (VecIndexScalarByteArrayOp WordVec 4 W32) = 1023+primOpTag (VecIndexScalarByteArrayOp WordVec 2 W64) = 1024+primOpTag (VecIndexScalarByteArrayOp WordVec 32 W8) = 1025+primOpTag (VecIndexScalarByteArrayOp WordVec 16 W16) = 1026+primOpTag (VecIndexScalarByteArrayOp WordVec 8 W32) = 1027+primOpTag (VecIndexScalarByteArrayOp WordVec 4 W64) = 1028+primOpTag (VecIndexScalarByteArrayOp WordVec 64 W8) = 1029+primOpTag (VecIndexScalarByteArrayOp WordVec 32 W16) = 1030+primOpTag (VecIndexScalarByteArrayOp WordVec 16 W32) = 1031+primOpTag (VecIndexScalarByteArrayOp WordVec 8 W64) = 1032+primOpTag (VecIndexScalarByteArrayOp FloatVec 4 W32) = 1033+primOpTag (VecIndexScalarByteArrayOp FloatVec 2 W64) = 1034+primOpTag (VecIndexScalarByteArrayOp FloatVec 8 W32) = 1035+primOpTag (VecIndexScalarByteArrayOp FloatVec 4 W64) = 1036+primOpTag (VecIndexScalarByteArrayOp FloatVec 16 W32) = 1037+primOpTag (VecIndexScalarByteArrayOp FloatVec 8 W64) = 1038+primOpTag (VecReadScalarByteArrayOp IntVec 16 W8) = 1039+primOpTag (VecReadScalarByteArrayOp IntVec 8 W16) = 1040+primOpTag (VecReadScalarByteArrayOp IntVec 4 W32) = 1041+primOpTag (VecReadScalarByteArrayOp IntVec 2 W64) = 1042+primOpTag (VecReadScalarByteArrayOp IntVec 32 W8) = 1043+primOpTag (VecReadScalarByteArrayOp IntVec 16 W16) = 1044+primOpTag (VecReadScalarByteArrayOp IntVec 8 W32) = 1045+primOpTag (VecReadScalarByteArrayOp IntVec 4 W64) = 1046+primOpTag (VecReadScalarByteArrayOp IntVec 64 W8) = 1047+primOpTag (VecReadScalarByteArrayOp IntVec 32 W16) = 1048+primOpTag (VecReadScalarByteArrayOp IntVec 16 W32) = 1049+primOpTag (VecReadScalarByteArrayOp IntVec 8 W64) = 1050+primOpTag (VecReadScalarByteArrayOp WordVec 16 W8) = 1051+primOpTag (VecReadScalarByteArrayOp WordVec 8 W16) = 1052+primOpTag (VecReadScalarByteArrayOp WordVec 4 W32) = 1053+primOpTag (VecReadScalarByteArrayOp WordVec 2 W64) = 1054+primOpTag (VecReadScalarByteArrayOp WordVec 32 W8) = 1055+primOpTag (VecReadScalarByteArrayOp WordVec 16 W16) = 1056+primOpTag (VecReadScalarByteArrayOp WordVec 8 W32) = 1057+primOpTag (VecReadScalarByteArrayOp WordVec 4 W64) = 1058+primOpTag (VecReadScalarByteArrayOp WordVec 64 W8) = 1059+primOpTag (VecReadScalarByteArrayOp WordVec 32 W16) = 1060+primOpTag (VecReadScalarByteArrayOp WordVec 16 W32) = 1061+primOpTag (VecReadScalarByteArrayOp WordVec 8 W64) = 1062+primOpTag (VecReadScalarByteArrayOp FloatVec 4 W32) = 1063+primOpTag (VecReadScalarByteArrayOp FloatVec 2 W64) = 1064+primOpTag (VecReadScalarByteArrayOp FloatVec 8 W32) = 1065+primOpTag (VecReadScalarByteArrayOp FloatVec 4 W64) = 1066+primOpTag (VecReadScalarByteArrayOp FloatVec 16 W32) = 1067+primOpTag (VecReadScalarByteArrayOp FloatVec 8 W64) = 1068+primOpTag (VecWriteScalarByteArrayOp IntVec 16 W8) = 1069+primOpTag (VecWriteScalarByteArrayOp IntVec 8 W16) = 1070+primOpTag (VecWriteScalarByteArrayOp IntVec 4 W32) = 1071+primOpTag (VecWriteScalarByteArrayOp IntVec 2 W64) = 1072+primOpTag (VecWriteScalarByteArrayOp IntVec 32 W8) = 1073+primOpTag (VecWriteScalarByteArrayOp IntVec 16 W16) = 1074+primOpTag (VecWriteScalarByteArrayOp IntVec 8 W32) = 1075+primOpTag (VecWriteScalarByteArrayOp IntVec 4 W64) = 1076+primOpTag (VecWriteScalarByteArrayOp IntVec 64 W8) = 1077+primOpTag (VecWriteScalarByteArrayOp IntVec 32 W16) = 1078+primOpTag (VecWriteScalarByteArrayOp IntVec 16 W32) = 1079+primOpTag (VecWriteScalarByteArrayOp IntVec 8 W64) = 1080+primOpTag (VecWriteScalarByteArrayOp WordVec 16 W8) = 1081+primOpTag (VecWriteScalarByteArrayOp WordVec 8 W16) = 1082+primOpTag (VecWriteScalarByteArrayOp WordVec 4 W32) = 1083+primOpTag (VecWriteScalarByteArrayOp WordVec 2 W64) = 1084+primOpTag (VecWriteScalarByteArrayOp WordVec 32 W8) = 1085+primOpTag (VecWriteScalarByteArrayOp WordVec 16 W16) = 1086+primOpTag (VecWriteScalarByteArrayOp WordVec 8 W32) = 1087+primOpTag (VecWriteScalarByteArrayOp WordVec 4 W64) = 1088+primOpTag (VecWriteScalarByteArrayOp WordVec 64 W8) = 1089+primOpTag (VecWriteScalarByteArrayOp WordVec 32 W16) = 1090+primOpTag (VecWriteScalarByteArrayOp WordVec 16 W32) = 1091+primOpTag (VecWriteScalarByteArrayOp WordVec 8 W64) = 1092+primOpTag (VecWriteScalarByteArrayOp FloatVec 4 W32) = 1093+primOpTag (VecWriteScalarByteArrayOp FloatVec 2 W64) = 1094+primOpTag (VecWriteScalarByteArrayOp FloatVec 8 W32) = 1095+primOpTag (VecWriteScalarByteArrayOp FloatVec 4 W64) = 1096+primOpTag (VecWriteScalarByteArrayOp FloatVec 16 W32) = 1097+primOpTag (VecWriteScalarByteArrayOp FloatVec 8 W64) = 1098+primOpTag (VecIndexScalarOffAddrOp IntVec 16 W8) = 1099+primOpTag (VecIndexScalarOffAddrOp IntVec 8 W16) = 1100+primOpTag (VecIndexScalarOffAddrOp IntVec 4 W32) = 1101+primOpTag (VecIndexScalarOffAddrOp IntVec 2 W64) = 1102+primOpTag (VecIndexScalarOffAddrOp IntVec 32 W8) = 1103+primOpTag (VecIndexScalarOffAddrOp IntVec 16 W16) = 1104+primOpTag (VecIndexScalarOffAddrOp IntVec 8 W32) = 1105+primOpTag (VecIndexScalarOffAddrOp IntVec 4 W64) = 1106+primOpTag (VecIndexScalarOffAddrOp IntVec 64 W8) = 1107+primOpTag (VecIndexScalarOffAddrOp IntVec 32 W16) = 1108+primOpTag (VecIndexScalarOffAddrOp IntVec 16 W32) = 1109+primOpTag (VecIndexScalarOffAddrOp IntVec 8 W64) = 1110+primOpTag (VecIndexScalarOffAddrOp WordVec 16 W8) = 1111+primOpTag (VecIndexScalarOffAddrOp WordVec 8 W16) = 1112+primOpTag (VecIndexScalarOffAddrOp WordVec 4 W32) = 1113+primOpTag (VecIndexScalarOffAddrOp WordVec 2 W64) = 1114+primOpTag (VecIndexScalarOffAddrOp WordVec 32 W8) = 1115+primOpTag (VecIndexScalarOffAddrOp WordVec 16 W16) = 1116+primOpTag (VecIndexScalarOffAddrOp WordVec 8 W32) = 1117+primOpTag (VecIndexScalarOffAddrOp WordVec 4 W64) = 1118+primOpTag (VecIndexScalarOffAddrOp WordVec 64 W8) = 1119+primOpTag (VecIndexScalarOffAddrOp WordVec 32 W16) = 1120+primOpTag (VecIndexScalarOffAddrOp WordVec 16 W32) = 1121+primOpTag (VecIndexScalarOffAddrOp WordVec 8 W64) = 1122+primOpTag (VecIndexScalarOffAddrOp FloatVec 4 W32) = 1123+primOpTag (VecIndexScalarOffAddrOp FloatVec 2 W64) = 1124+primOpTag (VecIndexScalarOffAddrOp FloatVec 8 W32) = 1125+primOpTag (VecIndexScalarOffAddrOp FloatVec 4 W64) = 1126+primOpTag (VecIndexScalarOffAddrOp FloatVec 16 W32) = 1127+primOpTag (VecIndexScalarOffAddrOp FloatVec 8 W64) = 1128+primOpTag (VecReadScalarOffAddrOp IntVec 16 W8) = 1129+primOpTag (VecReadScalarOffAddrOp IntVec 8 W16) = 1130+primOpTag (VecReadScalarOffAddrOp IntVec 4 W32) = 1131+primOpTag (VecReadScalarOffAddrOp IntVec 2 W64) = 1132+primOpTag (VecReadScalarOffAddrOp IntVec 32 W8) = 1133+primOpTag (VecReadScalarOffAddrOp IntVec 16 W16) = 1134+primOpTag (VecReadScalarOffAddrOp IntVec 8 W32) = 1135+primOpTag (VecReadScalarOffAddrOp IntVec 4 W64) = 1136+primOpTag (VecReadScalarOffAddrOp IntVec 64 W8) = 1137+primOpTag (VecReadScalarOffAddrOp IntVec 32 W16) = 1138+primOpTag (VecReadScalarOffAddrOp IntVec 16 W32) = 1139+primOpTag (VecReadScalarOffAddrOp IntVec 8 W64) = 1140+primOpTag (VecReadScalarOffAddrOp WordVec 16 W8) = 1141+primOpTag (VecReadScalarOffAddrOp WordVec 8 W16) = 1142+primOpTag (VecReadScalarOffAddrOp WordVec 4 W32) = 1143+primOpTag (VecReadScalarOffAddrOp WordVec 2 W64) = 1144+primOpTag (VecReadScalarOffAddrOp WordVec 32 W8) = 1145+primOpTag (VecReadScalarOffAddrOp WordVec 16 W16) = 1146+primOpTag (VecReadScalarOffAddrOp WordVec 8 W32) = 1147+primOpTag (VecReadScalarOffAddrOp WordVec 4 W64) = 1148+primOpTag (VecReadScalarOffAddrOp WordVec 64 W8) = 1149+primOpTag (VecReadScalarOffAddrOp WordVec 32 W16) = 1150+primOpTag (VecReadScalarOffAddrOp WordVec 16 W32) = 1151+primOpTag (VecReadScalarOffAddrOp WordVec 8 W64) = 1152+primOpTag (VecReadScalarOffAddrOp FloatVec 4 W32) = 1153+primOpTag (VecReadScalarOffAddrOp FloatVec 2 W64) = 1154+primOpTag (VecReadScalarOffAddrOp FloatVec 8 W32) = 1155+primOpTag (VecReadScalarOffAddrOp FloatVec 4 W64) = 1156+primOpTag (VecReadScalarOffAddrOp FloatVec 16 W32) = 1157+primOpTag (VecReadScalarOffAddrOp FloatVec 8 W64) = 1158+primOpTag (VecWriteScalarOffAddrOp IntVec 16 W8) = 1159+primOpTag (VecWriteScalarOffAddrOp IntVec 8 W16) = 1160+primOpTag (VecWriteScalarOffAddrOp IntVec 4 W32) = 1161+primOpTag (VecWriteScalarOffAddrOp IntVec 2 W64) = 1162+primOpTag (VecWriteScalarOffAddrOp IntVec 32 W8) = 1163+primOpTag (VecWriteScalarOffAddrOp IntVec 16 W16) = 1164+primOpTag (VecWriteScalarOffAddrOp IntVec 8 W32) = 1165+primOpTag (VecWriteScalarOffAddrOp IntVec 4 W64) = 1166+primOpTag (VecWriteScalarOffAddrOp IntVec 64 W8) = 1167+primOpTag (VecWriteScalarOffAddrOp IntVec 32 W16) = 1168+primOpTag (VecWriteScalarOffAddrOp IntVec 16 W32) = 1169+primOpTag (VecWriteScalarOffAddrOp IntVec 8 W64) = 1170+primOpTag (VecWriteScalarOffAddrOp WordVec 16 W8) = 1171+primOpTag (VecWriteScalarOffAddrOp WordVec 8 W16) = 1172+primOpTag (VecWriteScalarOffAddrOp WordVec 4 W32) = 1173+primOpTag (VecWriteScalarOffAddrOp WordVec 2 W64) = 1174+primOpTag (VecWriteScalarOffAddrOp WordVec 32 W8) = 1175+primOpTag (VecWriteScalarOffAddrOp WordVec 16 W16) = 1176+primOpTag (VecWriteScalarOffAddrOp WordVec 8 W32) = 1177+primOpTag (VecWriteScalarOffAddrOp WordVec 4 W64) = 1178+primOpTag (VecWriteScalarOffAddrOp WordVec 64 W8) = 1179+primOpTag (VecWriteScalarOffAddrOp WordVec 32 W16) = 1180+primOpTag (VecWriteScalarOffAddrOp WordVec 16 W32) = 1181+primOpTag (VecWriteScalarOffAddrOp WordVec 8 W64) = 1182+primOpTag (VecWriteScalarOffAddrOp FloatVec 4 W32) = 1183+primOpTag (VecWriteScalarOffAddrOp FloatVec 2 W64) = 1184+primOpTag (VecWriteScalarOffAddrOp FloatVec 8 W32) = 1185+primOpTag (VecWriteScalarOffAddrOp FloatVec 4 W64) = 1186+primOpTag (VecWriteScalarOffAddrOp FloatVec 16 W32) = 1187+primOpTag (VecWriteScalarOffAddrOp FloatVec 8 W64) = 1188+primOpTag PrefetchByteArrayOp3 = 1189+primOpTag PrefetchMutableByteArrayOp3 = 1190+primOpTag PrefetchAddrOp3 = 1191+primOpTag PrefetchValueOp3 = 1192+primOpTag PrefetchByteArrayOp2 = 1193+primOpTag PrefetchMutableByteArrayOp2 = 1194+primOpTag PrefetchAddrOp2 = 1195+primOpTag PrefetchValueOp2 = 1196+primOpTag PrefetchByteArrayOp1 = 1197+primOpTag PrefetchMutableByteArrayOp1 = 1198+primOpTag PrefetchAddrOp1 = 1199+primOpTag PrefetchValueOp1 = 1200+primOpTag PrefetchByteArrayOp0 = 1201+primOpTag PrefetchMutableByteArrayOp0 = 1202+primOpTag PrefetchAddrOp0 = 1203+primOpTag PrefetchValueOp0 = 1204
ghc-lib/stage0/lib/DerivedConstants.h view
@@ -491,22 +491,22 @@ #define OFFSET_StgCompactNFDataBlock_next 16 #define REP_StgCompactNFDataBlock_next b64 #define StgCompactNFDataBlock_next(__ptr__) REP_StgCompactNFDataBlock_next[__ptr__+OFFSET_StgCompactNFDataBlock_next]-#define OFFSET_RtsFlags_ProfFlags_showCCSOnException 277+#define OFFSET_RtsFlags_ProfFlags_showCCSOnException 285 #define REP_RtsFlags_ProfFlags_showCCSOnException b8 #define RtsFlags_ProfFlags_showCCSOnException(__ptr__) REP_RtsFlags_ProfFlags_showCCSOnException[__ptr__+OFFSET_RtsFlags_ProfFlags_showCCSOnException]-#define OFFSET_RtsFlags_DebugFlags_apply 220+#define OFFSET_RtsFlags_DebugFlags_apply 228 #define REP_RtsFlags_DebugFlags_apply b8 #define RtsFlags_DebugFlags_apply(__ptr__) REP_RtsFlags_DebugFlags_apply[__ptr__+OFFSET_RtsFlags_DebugFlags_apply]-#define OFFSET_RtsFlags_DebugFlags_sanity 215+#define OFFSET_RtsFlags_DebugFlags_sanity 223 #define REP_RtsFlags_DebugFlags_sanity b8 #define RtsFlags_DebugFlags_sanity(__ptr__) REP_RtsFlags_DebugFlags_sanity[__ptr__+OFFSET_RtsFlags_DebugFlags_sanity]-#define OFFSET_RtsFlags_DebugFlags_weak 210+#define OFFSET_RtsFlags_DebugFlags_weak 218 #define REP_RtsFlags_DebugFlags_weak b8 #define RtsFlags_DebugFlags_weak(__ptr__) REP_RtsFlags_DebugFlags_weak[__ptr__+OFFSET_RtsFlags_DebugFlags_weak] #define OFFSET_RtsFlags_GcFlags_initialStkSize 16 #define REP_RtsFlags_GcFlags_initialStkSize b32 #define RtsFlags_GcFlags_initialStkSize(__ptr__) REP_RtsFlags_GcFlags_initialStkSize[__ptr__+OFFSET_RtsFlags_GcFlags_initialStkSize]-#define OFFSET_RtsFlags_MiscFlags_tickInterval 184+#define OFFSET_RtsFlags_MiscFlags_tickInterval 192 #define REP_RtsFlags_MiscFlags_tickInterval b64 #define RtsFlags_MiscFlags_tickInterval(__ptr__) REP_RtsFlags_MiscFlags_tickInterval[__ptr__+OFFSET_RtsFlags_MiscFlags_tickInterval] #define SIZEOF_StgFunInfoExtraFwd 32
ghc-lib/stage0/lib/ghcversion.h view
@@ -6,7 +6,7 @@ #endif  #define __GLASGOW_HASKELL_PATCHLEVEL1__ 0-#define __GLASGOW_HASKELL_PATCHLEVEL2__ 20191201+#define __GLASGOW_HASKELL_PATCHLEVEL2__ 20200101  #define MIN_VERSION_GLASGOW_HASKELL(ma,mi,pl1,pl2) (\    ((ma)*100+(mi)) <  __GLASGOW_HASKELL__ || \
libraries/ghci/GHCi/CreateBCO.hs view
@@ -23,6 +23,7 @@ import Control.Monad import Data.Array.Base import Foreign hiding (newArray)+import Unsafe.Coerce (unsafeCoerce) import GHC.Arr          ( Array(..) ) import GHC.Exts import GHC.IO@@ -45,6 +46,8 @@                 ]) createBCO arr bco    = do BCO bco# <- linkBCO' arr bco+        -- Note [Updatable CAF BCOs]+        -- ~~~~~~~~~~~~~~~~~~~~~~~~~         -- Why do we need mkApUpd0 here?  Otherwise top-level         -- interpreted CAFs don't get updated after evaluation.  A         -- top-level BCO will evaluate itself and return its value@@ -57,6 +60,7 @@         --   (c) An AP is always fully saturated, so we *can't* wrap         --       non-zero arity BCOs in an AP thunk.         --+        -- See #17424.         if (resolvedBCOArity bco > 0)            then return (HValue (unsafeCoerce# bco#))            else case mkApUpd0# bco# of { (# final_bco #) ->@@ -135,7 +139,6 @@   case (unsafeCoerce# writeArray#) arr i bco s of s' -> (# s', () #)  data BCO = BCO BCO#- writePtrsArrayMBA :: Int -> MutableByteArray# s -> PtrsArr -> IO () writePtrsArrayMBA (I# i) mba (PtrsArr arr) = IO $ \s ->   case (unsafeCoerce# writeArray#) arr i mba s of s' -> (# s', () #)@@ -146,7 +149,7 @@     (# s1, bco #) -> (# s1, BCO bco #)  {- Note [BCO empty array]-+   ~~~~~~~~~~~~~~~~~~~~~~ Lots of BCOs have empty ptrs or nptrs, but empty arrays are not free: they are 2-word heap objects.  So let's make a single empty array and share it between all BCOs.