mkConApp, mkTyBind,
varToCoreExpr, varsToCoreExprs,
- isTyVar, isIdVar, cmpAltCon, cmpAlt, ltAlt,
+ isTyVar, isId, cmpAltCon, cmpAlt, ltAlt,
-- ** Simple 'Expr' access functions and predicates
bindersOf, bindersOfBinds, rhssOfBind, rhssOfAlts,
noUnfolding, evaldUnfolding, mkOtherCon,
-- ** Predicates and deconstruction on 'Unfolding'
- unfoldingTemplate, setUnfoldingTemplate,
- maybeUnfoldingTemplate, otherCons,
- isValueUnfolding, isEvaldUnfolding, isCheapUnfolding, isCompulsoryUnfolding,
- isInlineRule, isClosedUnfolding, hasSomeUnfolding, canUnfold, neverUnfoldGuidance,
+ unfoldingTemplate, maybeUnfoldingTemplate, otherCons,
+ isValueUnfolding, isEvaldUnfolding, isCheapUnfolding,
+ isExpandableUnfolding, isCompulsoryUnfolding,
+ hasUnfolding, hasSomeUnfolding, neverUnfold,
-- * Strictness
seqExpr, seqExprs, seqUnfolding,
-- | Allows attaching extra information to points in expressions rather than e.g. identifiers.
data Note
= SCC CostCentre -- ^ A cost centre annotation for profiling
+
+ | InlineMe -- ^ Instructs the core simplifer to treat the enclosed expression
+ -- as very small, and inline it at its call sites
+
| CoreNote String -- ^ A generic core annotation, propagated but not used by GHC
+
+-- NOTE: we also treat expressions wrapped in InlineMe as
+-- 'cheap' and 'dupable' (in the sense of exprIsCheap, exprIsDupable)
+-- What this means is that we obediently inline even things that don't
+-- look like valuse. This is sometimes important:
+-- {-# INLINE f #-}
+-- f = g . h
+-- Here, f looks like a redex, and we aren't going to inline (.) because it's
+-- inside an INLINE, so it'll stay looking like a redex. Nevertheless, we
+-- should inline f even inside lambdas. In effect, we should trust the programmer.
\end{code}
--
-- Here, @f@ gets an @OtherCon []@ unfolding.
- | CompulsoryUnfolding { -- There is /no original definition/, so you'd better unfold.
- uf_tmpl :: CoreExpr -- The unfolding is guaranteed to have no free variables
- } -- so no need to think about it during dependency analysis
-
- | InlineRule { -- The function has an INLINE pragma, with the specified (original) RHS
- -- (The inline phase, if any, is in the InlinePragInfo for this Id.)
- -- Inline when (a) applied to at least this number of args
- -- (b) if there is something interesting about args or context
- uf_tmpl :: CoreExpr, -- The *original* RHS; occurrence info is correct
- -- (The actual RHS of the function may be different by now,
- -- but what we inline is still the original RHS (kept in the InlineRule).)
- uf_is_top :: Bool,
-
- uf_arity :: Arity, -- Don't inline unless applied to this number of *value* args
- uf_is_value :: Bool, -- True <=> exprIsHNF is true; save to discard a `seq`
- uf_worker :: Maybe Id -- Just wrk_id <=> this unfolding is a the wrapper in a worker/wrapper
- -- split from the strictness analyser
- -- Used to abbreviate the uf_tmpl in interface files
- -- In the Just case, interface files don't actually
- -- need to contain the RHS; it can be derived from
- -- the strictness info
- -- Also used in CoreUnfold to guide inlining decisions
- }
+ | CompulsoryUnfolding CoreExpr -- ^ There is /no original definition/,
+ -- so you'd better unfold.
- | CoreUnfolding { -- An unfolding for an Id with no pragma, or perhaps a NOINLINE pragma
- -- (For NOINLINE, the phase, if any, is in the InlinePragInfo for this Id.)
- uf_tmpl :: CoreExpr, -- Template; binder-info is correct
- uf_is_top :: Bool, -- True <=> top level binding
- uf_is_value :: Bool, -- exprIsHNF template (cached); it is ok to discard a `seq` on
- -- this variable
- uf_is_cheap :: Bool, -- True <=> doesn't waste (much) work to expand inside an inlining
- -- Basically it's exprIsCheap
- uf_guidance :: UnfoldingGuidance -- Tells about the *size* of the template.
- }
+ | CoreUnfolding
+ CoreExpr
+ Bool
+ Bool
+ Bool
+ Bool
+ UnfoldingGuidance
-- ^ An unfolding with redundant cached information. Parameters:
--
- -- uf_tmpl: Template used to perform unfolding; binder-info is correct
+ -- 1) Template used to perform unfolding; binder-info is correct
--
- -- uf_is_top: Is this a top level binding?
+ -- 2) Is this a top level binding?
--
- -- uf_is_valiue: 'exprIsHNF' template (cached); it is ok to discard a 'seq' on
+ -- 3) 'exprIsHNF' template (cached); it is ok to discard a 'seq' on
-- this variable
--
- -- uf_is_cheap: Does this waste only a little work if we expand it inside an inlining?
+ -- 4) Does this waste only a little work if we expand it inside an inlining?
-- Basically this is a cached version of 'exprIsCheap'
--
- -- uf_guidance: Tells us about the /size/ of the unfolding template
+ -- 5) Tells us about the /size/ of the unfolding template
-------------------------------------------------
--- | 'UnfoldingGuidance' says when unfolding should take place
+-- | When unfolding should take place
data UnfoldingGuidance
= UnfoldNever
- | UnfoldIfGoodArgs {
- ug_arity :: Arity, -- "n" value args
+ | UnfoldIfGoodArgs Int -- and "n" value args
- ug_args :: [Int], -- Discount if the argument is evaluated.
- -- (i.e., a simplification will definitely
- -- be possible). One elt of the list per *value* arg.
+ [Int] -- Discount if the argument is evaluated.
+ -- (i.e., a simplification will definitely
+ -- be possible). One elt of the list per *value* arg.
- ug_size :: Int, -- The "size" of the unfolding; to be elaborated
- -- later. ToDo
+ Int -- The "size" of the unfolding; to be elaborated
+ -- later. ToDo
- ug_res :: Int -- Scrutinee discount: the discount to substract if the thing is in
- } -- a context (case (thing args) of ...),
- -- (where there are the right number of arguments.)
+ Int -- Scrutinee discount: the discount to substract if the thing is in
+ -- a context (case (thing args) of ...),
+ -- (where there are the right number of arguments.)
-------------------------------------------------
noUnfolding :: Unfolding
-- ^ There is no known 'Unfolding'
evaldUnfolding :: Unfolding
mkOtherCon = OtherCon
seqUnfolding :: Unfolding -> ()
-seqUnfolding (CoreUnfolding { uf_tmpl = e, uf_is_top = top,
- uf_is_value = b1, uf_is_cheap = b2, uf_guidance = g})
- = seqExpr e `seq` top `seq` b1 `seq` b2 `seq` seqGuidance g
+seqUnfolding (CoreUnfolding e top b1 b2 b3 g)
+ = seqExpr e `seq` top `seq` b1 `seq` b2 `seq` b3 `seq` seqGuidance g
seqUnfolding _ = ()
seqGuidance :: UnfoldingGuidance -> ()
\begin{code}
-- | Retrieves the template of an unfolding: panics if none is known
unfoldingTemplate :: Unfolding -> CoreExpr
-unfoldingTemplate = uf_tmpl
-
-setUnfoldingTemplate :: Unfolding -> CoreExpr -> Unfolding
-setUnfoldingTemplate unf rhs = unf { uf_tmpl = rhs }
+unfoldingTemplate (CoreUnfolding expr _ _ _ _ _) = expr
+unfoldingTemplate (CompulsoryUnfolding expr) = expr
+unfoldingTemplate _ = panic "getUnfoldingTemplate"
-- | Retrieves the template of an unfolding if possible
maybeUnfoldingTemplate :: Unfolding -> Maybe CoreExpr
-maybeUnfoldingTemplate (CoreUnfolding { uf_tmpl = expr }) = Just expr
-maybeUnfoldingTemplate (CompulsoryUnfolding { uf_tmpl = expr }) = Just expr
-maybeUnfoldingTemplate (InlineRule { uf_tmpl = expr }) = Just expr
-maybeUnfoldingTemplate _ = Nothing
+maybeUnfoldingTemplate (CoreUnfolding expr _ _ _ _ _) = Just expr
+maybeUnfoldingTemplate (CompulsoryUnfolding expr) = Just expr
+maybeUnfoldingTemplate _ = Nothing
-- | The constructors that the unfolding could never be:
-- returns @[]@ if no information is available
-- | Determines if it is certainly the case that the unfolding will
-- yield a value (something in HNF): returns @False@ if unsure
isValueUnfolding :: Unfolding -> Bool
- -- Returns False for OtherCon
-isValueUnfolding (CoreUnfolding { uf_is_value = is_evald }) = is_evald
-isValueUnfolding (InlineRule { uf_is_value = is_evald }) = is_evald
-isValueUnfolding _ = False
+isValueUnfolding (CoreUnfolding _ _ is_evald _ _ _) = is_evald
+isValueUnfolding _ = False
-- | Determines if it possibly the case that the unfolding will
-- yield a value. Unlike 'isValueUnfolding' it returns @True@
-- for 'OtherCon'
isEvaldUnfolding :: Unfolding -> Bool
- -- Returns True for OtherCon
-isEvaldUnfolding (OtherCon _) = True
-isEvaldUnfolding (CoreUnfolding { uf_is_value = is_evald }) = is_evald
-isEvaldUnfolding (InlineRule { uf_is_value = is_evald }) = is_evald
-isEvaldUnfolding _ = False
+isEvaldUnfolding (OtherCon _) = True
+isEvaldUnfolding (CoreUnfolding _ _ is_evald _ _ _) = is_evald
+isEvaldUnfolding _ = False
-- | Is the thing we will unfold into certainly cheap?
isCheapUnfolding :: Unfolding -> Bool
-isCheapUnfolding (CoreUnfolding { uf_is_cheap = is_cheap }) = is_cheap
-isCheapUnfolding _ = False
+isCheapUnfolding (CoreUnfolding _ _ _ is_cheap _ _) = is_cheap
+isCheapUnfolding _ = False
-isInlineRule :: Unfolding -> Bool
-isInlineRule (InlineRule {}) = True
-isInlineRule _ = False
+isExpandableUnfolding :: Unfolding -> Bool
+isExpandableUnfolding (CoreUnfolding _ _ _ _ is_expable _) = is_expable
+isExpandableUnfolding _ = False
-- | Must this unfolding happen for the code to be executable?
isCompulsoryUnfolding :: Unfolding -> Bool
-isCompulsoryUnfolding (CompulsoryUnfolding {}) = True
+isCompulsoryUnfolding (CompulsoryUnfolding _) = True
isCompulsoryUnfolding _ = False
-isClosedUnfolding :: Unfolding -> Bool -- No free variables
-isClosedUnfolding (CoreUnfolding {}) = False
-isClosedUnfolding (InlineRule {}) = False
-isClosedUnfolding _ = True
+-- | Do we have an available or compulsory unfolding?
+hasUnfolding :: Unfolding -> Bool
+hasUnfolding (CoreUnfolding _ _ _ _ _ _) = True
+hasUnfolding (CompulsoryUnfolding _) = True
+hasUnfolding _ = False
-- | Only returns False if there is no unfolding information available at all
hasSomeUnfolding :: Unfolding -> Bool
hasSomeUnfolding NoUnfolding = False
hasSomeUnfolding _ = True
-neverUnfoldGuidance :: UnfoldingGuidance -> Bool
-neverUnfoldGuidance UnfoldNever = True
-neverUnfoldGuidance _ = False
-
-canUnfold :: Unfolding -> Bool
-canUnfold (InlineRule {}) = True
-canUnfold (CoreUnfolding { uf_guidance = g }) = not (neverUnfoldGuidance g)
-canUnfold _ = False
+-- | Similar to @not . hasUnfolding@, but also returns @True@
+-- if it has an unfolding that says it should never occur
+neverUnfold :: Unfolding -> Bool
+neverUnfold NoUnfolding = True
+neverUnfold (OtherCon _) = True
+neverUnfold (CoreUnfolding _ _ _ _ _ UnfoldNever) = True
+neverUnfold _ = False
\end{code}
-- | Convert a binder into either a 'Var' or 'Type' 'Expr' appropriately
varToCoreExpr :: CoreBndr -> Expr b
-varToCoreExpr v | isIdVar v = Var v
+varToCoreExpr v | isId v = Var v
| otherwise = Type (mkTyVarTy v)
varsToCoreExprs :: [CoreBndr] -> [Expr b]
collectValBinders expr
= go [] expr
where
- go ids (Lam b e) | isIdVar b = go (b:ids) e
- go ids body = (reverse ids, body)
+ go ids (Lam b e) | isId b = go (b:ids) e
+ go ids body = (reverse ids, body)
\end{code}
\begin{code}
\begin{code}
-- | Will this variable exist at runtime?
isRuntimeVar :: Var -> Bool
-isRuntimeVar = isIdVar
+isRuntimeVar = isId
-- | Will this argument expression exist at runtime?
isRuntimeArg :: CoreExpr -> Bool
-- | The number of binders that bind values rather than types
valBndrCount :: [CoreBndr] -> Int
-valBndrCount = count isIdVar
+valBndrCount = count isId
-- | The number of argument expressions that are values rather than types at their top level
valArgCount :: [Arg b] -> Int