Safe Haskell | None |
---|---|
Language | Haskell2010 |
Commonly useful utilites for manipulating the Core language
- mkCast :: CoreExpr -> Coercion -> CoreExpr
- mkTick :: Tickish Id -> CoreExpr -> CoreExpr
- mkTicks :: [Tickish Id] -> CoreExpr -> CoreExpr
- mkTickNoHNF :: Tickish Id -> CoreExpr -> CoreExpr
- tickHNFArgs :: Tickish Id -> CoreExpr -> CoreExpr
- bindNonRec :: Id -> CoreExpr -> CoreExpr -> CoreExpr
- needsCaseBinding :: Type -> CoreExpr -> Bool
- mkAltExpr :: AltCon -> [CoreBndr] -> [Type] -> CoreExpr
- findDefault :: [(AltCon, [a], b)] -> ([(AltCon, [a], b)], Maybe b)
- findAlt :: AltCon -> [(AltCon, a, b)] -> Maybe (AltCon, a, b)
- isDefaultAlt :: (AltCon, a, b) -> Bool
- mergeAlts :: [(AltCon, a, b)] -> [(AltCon, a, b)] -> [(AltCon, a, b)]
- trimConArgs :: AltCon -> [CoreArg] -> [CoreArg]
- filterAlts :: [Unique] -> Type -> [AltCon] -> [(AltCon, [Var], a)] -> ([AltCon], Bool, [(AltCon, [Var], a)])
- exprType :: CoreExpr -> Type
- coreAltType :: CoreAlt -> Type
- coreAltsType :: [CoreAlt] -> Type
- exprIsDupable :: DynFlags -> CoreExpr -> Bool
- exprIsTrivial :: CoreExpr -> Bool
- getIdFromTrivialExpr :: CoreExpr -> Id
- exprIsBottom :: CoreExpr -> Bool
- exprIsCheap :: CoreExpr -> Bool
- exprIsExpandable :: CoreExpr -> Bool
- exprIsCheap' :: CheapAppFun -> CoreExpr -> Bool
- type CheapAppFun = Id -> Int -> Bool
- exprIsHNF :: CoreExpr -> Bool
- exprOkForSpeculation :: Expr b -> Bool
- exprOkForSideEffects :: Expr b -> Bool
- exprIsWorkFree :: CoreExpr -> Bool
- exprIsBig :: Expr b -> Bool
- exprIsConLike :: CoreExpr -> Bool
- rhsIsStatic :: Platform -> (Name -> Bool) -> (Integer -> CoreExpr) -> CoreExpr -> Bool
- isCheapApp :: CheapAppFun
- isExpandableApp :: CheapAppFun
- coreBindsSize :: [CoreBind] -> Int
- exprSize :: CoreExpr -> Int
- data CoreStats = CS {}
- coreBindsStats :: [CoreBind] -> CoreStats
- cheapEqExpr :: Expr b -> Expr b -> Bool
- cheapEqExpr' :: (Tickish Id -> Bool) -> Expr b -> Expr b -> Bool
- eqExpr :: InScopeSet -> CoreExpr -> CoreExpr -> Bool
- diffExpr :: Bool -> RnEnv2 -> CoreExpr -> CoreExpr -> [SDoc]
- diffBinds :: Bool -> RnEnv2 -> [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> ([SDoc], RnEnv2)
- tryEtaReduce :: [Var] -> CoreExpr -> Maybe CoreExpr
- applyTypeToArgs :: CoreExpr -> Type -> [CoreExpr] -> Type
- applyTypeToArg :: Type -> CoreExpr -> Type
- dataConRepInstPat :: [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])
- dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])
- stripTicksTop :: (Tickish Id -> Bool) -> Expr b -> ([Tickish Id], Expr b)
- stripTicksTopE :: (Tickish Id -> Bool) -> Expr b -> Expr b
- stripTicksTopT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id]
- stripTicksE :: (Tickish Id -> Bool) -> Expr b -> Expr b
- stripTicksT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id]
Constructing expressions
mkCast :: CoreExpr -> Coercion -> CoreExpr Source
Wrap the given expression in the coercion safely, dropping identity coercions and coalescing nested coercions
mkTick :: Tickish Id -> CoreExpr -> CoreExpr Source
Wraps the given expression in the source annotation, dropping the annotation if possible.
bindNonRec :: Id -> CoreExpr -> CoreExpr -> CoreExpr Source
bindNonRec x r b
produces either:
let x = r in b
or:
case r of x { _DEFAULT_ -> b }
depending on whether we have to use a case
or let
binding for the expression (see needsCaseBinding
).
It's used by the desugarer to avoid building bindings
that give Core Lint a heart attack, although actually
the simplifier deals with them perfectly well. See
also mkCoreLet
needsCaseBinding :: Type -> CoreExpr -> Bool Source
:: AltCon | Case alternative constructor |
-> [CoreBndr] | Things bound by the pattern match |
-> [Type] | The type arguments to the case alternative |
-> CoreExpr |
This guy constructs the value that the scrutinee must have given that you are in one particular branch of a case
Taking expressions apart
findDefault :: [(AltCon, [a], b)] -> ([(AltCon, [a], b)], Maybe b) Source
Extract the default case alternative
findAlt :: AltCon -> [(AltCon, a, b)] -> Maybe (AltCon, a, b) Source
Find the case alternative corresponding to a particular constructor: panics if no such constructor exists
isDefaultAlt :: (AltCon, a, b) -> Bool Source
mergeAlts :: [(AltCon, a, b)] -> [(AltCon, a, b)] -> [(AltCon, a, b)] Source
Merge alternatives preserving order; alternatives in the first argument shadow ones in the second
trimConArgs :: AltCon -> [CoreArg] -> [CoreArg] Source
Given:
case (C a b x y) of C b x y -> ...
We want to drop the leading type argument of the scrutinee leaving the arguments to match agains the pattern
Properties of expressions
exprType :: CoreExpr -> Type Source
Recover the type of a well-typed Core expression. Fails when
applied to the actual Type
expression as it cannot
really be said to have a type
coreAltType :: CoreAlt -> Type Source
Returns the type of the alternatives right hand side
coreAltsType :: [CoreAlt] -> Type Source
Returns the type of the first alternative, which should be the same as for all alternatives
exprIsDupable :: DynFlags -> CoreExpr -> Bool Source
exprIsTrivial :: CoreExpr -> Bool Source
getIdFromTrivialExpr :: CoreExpr -> Id Source
exprIsBottom :: CoreExpr -> Bool Source
exprIsCheap :: CoreExpr -> Bool Source
exprIsExpandable :: CoreExpr -> Bool Source
exprIsCheap' :: CheapAppFun -> CoreExpr -> Bool Source
type CheapAppFun = Id -> Int -> Bool Source
exprIsHNF :: CoreExpr -> Bool Source
exprIsHNF returns true for expressions that are certainly already evaluated to head normal form. This is used to decide whether it's ok to change:
case x of _ -> e
into:
e
and to decide whether it's safe to discard a seq
.
So, it does not treat variables as evaluated, unless they say they are. However, it does treat partial applications and constructor applications as values, even if their arguments are non-trivial, provided the argument type is lifted. For example, both of these are values:
(:) (f x) (map f xs) map (...redex...)
because seq
on such things completes immediately.
For unlifted argument types, we have to be careful:
C (f x :: Int#)
Suppose f x
diverges; then C (f x)
is not a value. However this can't
happen: see CoreSyn. This invariant states that arguments of
unboxed type must be ok-for-speculation (or trivial).
exprOkForSpeculation :: Expr b -> Bool Source
exprOkForSpeculation
returns True of an expression that is:
- Safe to evaluate even if normal order eval might not evaluate the expression at all, or
- Safe not to evaluate even if normal order would do so
It is usually called on arguments of unlifted type, but not always
In particular, Simplify.rebuildCase calls it on lifted types
when a 'case' is a plain seq
. See the example in
Note [exprOkForSpeculation: case expressions] below
Precisely, it returns True
iff:
a) The expression guarantees to terminate,
b) soon,
c) without causing a write side effect (e.g. writing a mutable variable)
d) without throwing a Haskell exception
e) without risking an unchecked runtime exception (array out of bounds,
divide by zero)
For exprOkForSideEffects
the list is the same, but omitting (e).
Note that exprIsHNF implies exprOkForSpeculation exprOkForSpeculation implies exprOkForSideEffects
See Note [PrimOp can_fail and has_side_effects] in PrimOp and Note [Implementation: how can_fail/has_side_effects affect transformations]
As an example of the considerations in this test, consider:
let x = case y# +# 1# of { r# -> I# r# } in E
being translated to:
case y# +# 1# of { r# -> let x = I# r# in E }
We can only do this if the y + 1
is ok for speculation: it has no
side effects, and can't diverge or raise an exception.
exprOkForSideEffects :: Expr b -> Bool Source
exprOkForSpeculation
returns True of an expression that is:
- Safe to evaluate even if normal order eval might not evaluate the expression at all, or
- Safe not to evaluate even if normal order would do so
It is usually called on arguments of unlifted type, but not always
In particular, Simplify.rebuildCase calls it on lifted types
when a 'case' is a plain seq
. See the example in
Note [exprOkForSpeculation: case expressions] below
Precisely, it returns True
iff:
a) The expression guarantees to terminate,
b) soon,
c) without causing a write side effect (e.g. writing a mutable variable)
d) without throwing a Haskell exception
e) without risking an unchecked runtime exception (array out of bounds,
divide by zero)
For exprOkForSideEffects
the list is the same, but omitting (e).
Note that exprIsHNF implies exprOkForSpeculation exprOkForSpeculation implies exprOkForSideEffects
See Note [PrimOp can_fail and has_side_effects] in PrimOp and Note [Implementation: how can_fail/has_side_effects affect transformations]
As an example of the considerations in this test, consider:
let x = case y# +# 1# of { r# -> I# r# } in E
being translated to:
case y# +# 1# of { r# -> let x = I# r# in E }
We can only do this if the y + 1
is ok for speculation: it has no
side effects, and can't diverge or raise an exception.
exprIsWorkFree :: CoreExpr -> Bool Source
exprIsBig :: Expr b -> Bool Source
Returns True
of expressions that are too big to be compared by cheapEqExpr
exprIsConLike :: CoreExpr -> Bool Source
Similar to exprIsHNF
but includes CONLIKE functions as well as
data constructors. Conlike arguments are considered interesting by the
inliner.
rhsIsStatic :: Platform -> (Name -> Bool) -> (Integer -> CoreExpr) -> CoreExpr -> Bool Source
This function is called only on *top-level* right-hand sides.
Returns True
if the RHS can be allocated statically in the output,
with no thunks involved at all.
Expression and bindings size
coreBindsSize :: [CoreBind] -> Int Source
exprSize :: CoreExpr -> Int Source
A measure of the size of the expressions, strictly greater than 0 It also forces the expression pretty drastically as a side effect Counts *leaves*, not internal nodes. Types and coercions are not counted.
coreBindsStats :: [CoreBind] -> CoreStats Source
Equality
cheapEqExpr :: Expr b -> Expr b -> Bool Source
A cheap equality test which bales out fast!
If it returns True
the arguments are definitely equal,
otherwise, they may or may not be equal.
See also exprIsBig
cheapEqExpr' :: (Tickish Id -> Bool) -> Expr b -> Expr b -> Bool Source
Cheap expression equality test, can ignore ticks by type.
diffExpr :: Bool -> RnEnv2 -> CoreExpr -> CoreExpr -> [SDoc] Source
Finds differences between core expressions, modulo alpha and
renaming. Setting top
means that the IdInfo
of bindings will be
checked for differences as well.
diffBinds :: Bool -> RnEnv2 -> [(Var, CoreExpr)] -> [(Var, CoreExpr)] -> ([SDoc], RnEnv2) Source
Finds differences between core bindings, see diffExpr
.
The main problem here is that while we expect the binds to have the same order in both lists, this is not guaranteed. To do this properly we'd either have to do some sort of unification or check all possible mappings, which would be seriously expensive. So instead we simply match single bindings as far as we can. This leaves us just with mutually recursive and/or mismatching bindings, which we then specuatively match by ordering them. It's by no means perfect, but gets the job done well enough.
Eta reduction
Manipulating data constructors and types
applyTypeToArgs :: CoreExpr -> Type -> [CoreExpr] -> Type Source
A more efficient version of applyTypeToArg
when we have several arguments.
The first argument is just for debugging, and gives some context
applyTypeToArg :: Type -> CoreExpr -> Type Source
Determines the type resulting from applying an expression with given type to a given argument expression
dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [Id]) Source
Working with ticks
stripTicksTop :: (Tickish Id -> Bool) -> Expr b -> ([Tickish Id], Expr b) Source
Strip ticks satisfying a predicate from top of an expression
stripTicksTopE :: (Tickish Id -> Bool) -> Expr b -> Expr b Source
Strip ticks satisfying a predicate from top of an expression, returning the remaining expresion
stripTicksTopT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id] Source
Strip ticks satisfying a predicate from top of an expression, returning the ticks