ghc-7.6.3: The GHC API

Safe Haskell | None

CoreUtils

Contents

- Constructing expressions
- Taking expressions apart
- Properties of expressions
- Expression and bindings size
- Hashing
- Equality
- Eta reduction
- Manipulating data constructors and types

Description

Commonly useful utilites for manipulating the Core language

Synopsis

- mkCast :: CoreExpr -> Coercion -> CoreExpr
- mkTick :: Tickish Id -> CoreExpr -> CoreExpr
- mkTickNoHNF :: 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 :: 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 :: (Name -> Bool) -> CoreExpr -> Bool
- isCheapApp :: CheapAppFun
- isExpandableApp :: CheapAppFun
- coreBindsSize :: [CoreBind] -> Int
- exprSize :: CoreExpr -> Int
- data CoreStats = CS {
  - cs_tm :: Int
  - cs_ty :: Int
  - cs_co :: Int
  }
- coreBindsStats :: [CoreBind] -> CoreStats
- hashExpr :: CoreExpr -> Int
- cheapEqExpr :: Expr b -> Expr b -> Bool
- eqExpr :: InScopeSet -> CoreExpr -> CoreExpr -> Bool
- eqExprX :: IdUnfoldingFun -> RnEnv2 -> CoreExpr -> CoreExpr -> Bool
- 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])

# Constructing expressions

mkCast :: CoreExpr -> Coercion -> CoreExpr

Wrap the given expression in the coercion safely, dropping identity coercions and coalescing nested coercions

mkTick :: Tickish Id -> CoreExpr -> CoreExpr

Wraps the given expression in the source annotation, dropping the annotation if possible.

mkTickNoHNF :: Tickish Id -> CoreExpr -> CoreExpr

bindNonRec :: Id -> CoreExpr -> CoreExpr -> CoreExpr

`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

Tests whether we have to use a `case` rather than `let` binding for this expression as per the invariants of `CoreExpr`: see CoreSyn

mkAltExpr

Arguments

:: 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)

Extract the default case alternative

findAlt :: AltCon -> [(AltCon, a, b)] -> Maybe (AltCon, a, b)

Find the case alternative corresponding to a particular constructor: panics if no such constructor exists

isDefaultAlt :: (AltCon, a, b) -> Bool

mergeAlts :: [(AltCon, a, b)] -> [(AltCon, a, b)] -> [(AltCon, a, b)]

Merge alternatives preserving order; alternatives in the first argument shadow ones in the second

trimConArgs :: AltCon -> [CoreArg] -> [CoreArg]

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

filterAlts

Arguments

:: [Unique] | Supply of uniques used in case we have to manufacture a new AltCon
-> Type | Type of scrutinee (used to prune possibilities)
-> [AltCon] | `imposs_cons`: constructors known to be impossible due to the form of the scrutinee
-> [(AltCon, [Var], a)] | Alternatives
-> ([AltCon], Bool, [(AltCon, [Var], a)]) |

# Properties of expressions

exprType :: CoreExpr -> Type

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

Returns the type of the alternatives right hand side

coreAltsType :: [CoreAlt] -> Type

Returns the type of the first alternative, which should be the same as for all alternatives

exprIsDupable :: 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

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

`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:

- The expression guarantees to terminate, * soon, * without raising an exception, * without causing a side effect (e.g. writing a mutable variable)

Note that if `exprIsHNF e`, then `exprOkForSpecuation e`. 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

`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:

- The expression guarantees to terminate, * soon, * without raising an exception, * without causing a side effect (e.g. writing a mutable variable)

Note that if `exprIsHNF e`, then `exprOkForSpecuation e`. 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

exprIsBig :: Expr b -> Bool

Returns `True` of expressions that are too big to be compared by `cheapEqExpr`

exprIsConLike :: CoreExpr -> Bool

Similar to `exprIsHNF` but includes CONLIKE functions as well as data constructors. Conlike arguments are considered interesting by the inliner.

rhsIsStatic :: (Name -> Bool) -> CoreExpr -> Bool

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.

isCheapApp :: CheapAppFun

isExpandableApp :: CheapAppFun

# Expression and bindings size

coreBindsSize :: [CoreBind] -> Int

exprSize :: CoreExpr -> Int

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.

data CoreStats

Constructors

CS |

Fields

cs_tm :: Int
cs_ty :: Int
cs_co :: Int

Instances

Outputable CoreStats |

coreBindsStats :: [CoreBind] -> CoreStats

# Hashing

hashExpr :: CoreExpr -> Int

Two expressions that hash to the same `Int` may be equal (but may not be) Two expressions that hash to the different Ints are definitely unequal.

The emphasis is on a crude, fast hash, rather than on high precision.

But unequal here means "not identical"; two alpha-equivalent expressions may hash to the different Ints.

We must be careful that `\x.x` and `\y.y` map to the same hash code, (at least if we want the above invariant to be true).

# Equality

cheapEqExpr :: Expr b -> Expr b -> Bool

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`

eqExpr :: InScopeSet -> CoreExpr -> CoreExpr -> Bool

eqExprX :: IdUnfoldingFun -> RnEnv2 -> CoreExpr -> CoreExpr -> Bool

Compares expressions for equality, modulo alpha. Does not look through newtypes or predicate types Used in rule matching, and also CSE

# Eta reduction

tryEtaReduce :: [Var] -> CoreExpr -> Maybe CoreExpr

# Manipulating data constructors and types

applyTypeToArgs :: CoreExpr -> Type -> [CoreExpr] -> Type

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

Determines the type resulting from applying an expression to a function with the given type

dataConRepInstPat :: [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])

dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])