summaryrefslogtreecommitdiff
path: root/compiler/coreSyn/CoreUtils.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/coreSyn/CoreUtils.hs')
-rw-r--r--compiler/coreSyn/CoreUtils.hs609
1 files changed, 440 insertions, 169 deletions
diff --git a/compiler/coreSyn/CoreUtils.hs b/compiler/coreSyn/CoreUtils.hs
index 540a36e0a1..453d984ec4 100644
--- a/compiler/coreSyn/CoreUtils.hs
+++ b/compiler/coreSyn/CoreUtils.hs
@@ -29,7 +29,8 @@ module CoreUtils (
exprIsHNF, exprOkForSpeculation, exprOkForSideEffects, exprIsWorkFree,
exprIsBig, exprIsConLike,
rhsIsStatic, isCheapApp, isExpandableApp,
- exprIsLiteralString, exprIsTopLevelBindable,
+ exprIsTickedString, exprIsTickedString_maybe,
+ exprIsTopLevelBindable,
altsAreExhaustive,
-- * Equality
@@ -58,6 +59,8 @@ module CoreUtils (
#include "HsVersions.h"
+import GhcPrelude
+
import CoreSyn
import PrelNames ( makeStaticName )
import PprCore
@@ -72,8 +75,9 @@ import DataCon
import PrimOp
import Id
import IdInfo
+import PrelNames( absentErrorIdKey )
import Type
-import TyCoRep( TyBinder(..) )
+import TyCoRep( TyCoBinder(..), TyBinder )
import Coercion
import TyCon
import Unique
@@ -83,14 +87,17 @@ import DynFlags
import FastString
import Maybes
import ListSetOps ( minusList )
-import BasicTypes ( Arity )
+import BasicTypes ( Arity, isConLike )
import Platform
import Util
import Pair
+import Data.ByteString ( ByteString )
import Data.Function ( on )
import Data.List
import Data.Ord ( comparing )
import OrdList
+import qualified Data.Set as Set
+import UniqSet
{-
************************************************************************
@@ -123,13 +130,13 @@ exprType other = pprTrace "exprType" (pprCoreExpr other) alphaTy
coreAltType :: CoreAlt -> Type
-- ^ Returns the type of the alternatives right hand side
-coreAltType (_,bs,rhs)
- | any bad_binder bs = expandTypeSynonyms ty
- | otherwise = ty -- Note [Existential variables and silly type synonyms]
+coreAltType alt@(_,bs,rhs)
+ = case occCheckExpand bs rhs_ty of
+ -- Note [Existential variables and silly type synonyms]
+ Just ty -> ty
+ Nothing -> pprPanic "coreAltType" (pprCoreAlt alt $$ ppr rhs_ty)
where
- ty = exprType rhs
- free_tvs = tyCoVarsOfType ty
- bad_binder b = b `elemVarSet` free_tvs
+ rhs_ty = exprType rhs
coreAltsType :: [CoreAlt] -> Type
-- ^ Returns the type of the first alternative, which should be the same as for all alternatives
@@ -179,7 +186,7 @@ isExprLevPoly = go
Note [Type bindings]
~~~~~~~~~~~~~~~~~~~~
Core does allow type bindings, although such bindings are
-not much used, except in the output of the desuguarer.
+not much used, except in the output of the desugarer.
Example:
let a = Int in (\x:a. x)
Given this, exprType must be careful to substitute 'a' in the
@@ -250,7 +257,7 @@ applyTypeToArgs e op_ty args
-- | Wrap the given expression in the coercion safely, dropping
-- identity coercions and coalescing nested coercions
-mkCast :: CoreExpr -> Coercion -> CoreExpr
+mkCast :: CoreExpr -> CoercionR -> CoreExpr
mkCast e co
| ASSERT2( coercionRole co == Representational
, text "coercion" <+> ppr co <+> ptext (sLit "passed to mkCast")
@@ -474,8 +481,15 @@ bindNonRec :: Id -> CoreExpr -> CoreExpr -> CoreExpr
-- the simplifier deals with them perfectly well. See
-- also 'MkCore.mkCoreLet'
bindNonRec bndr rhs body
- | needsCaseBinding (idType bndr) rhs = Case rhs bndr (exprType body) [(DEFAULT, [], body)]
- | otherwise = Let (NonRec bndr rhs) body
+ | isTyVar bndr = let_bind
+ | isCoVar bndr = if isCoArg rhs then let_bind
+ {- See Note [Binding coercions] -} else case_bind
+ | isJoinId bndr = let_bind
+ | needsCaseBinding (idType bndr) rhs = case_bind
+ | otherwise = let_bind
+ where
+ case_bind = Case rhs bndr (exprType body) [(DEFAULT, [], body)]
+ let_bind = Let (NonRec bndr rhs) body
-- | Tests whether we have to use a @case@ rather than @let@ binding for this expression
-- as per the invariants of 'CoreExpr': see "CoreSyn#let_app_invariant"
@@ -498,7 +512,12 @@ mkAltExpr (LitAlt lit) [] []
mkAltExpr (LitAlt _) _ _ = panic "mkAltExpr LitAlt"
mkAltExpr DEFAULT _ _ = panic "mkAltExpr DEFAULT"
-{-
+{- Note [Binding coercions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider binding a CoVar, c = e. Then, we must atisfy
+Note [CoreSyn type and coercion invariant] in CoreSyn,
+which allows only (Coercion co) on the RHS.
+
************************************************************************
* *
Operations oer case alternatives
@@ -525,7 +544,7 @@ isDefaultAlt _ = False
-- | Find the case alternative corresponding to a particular
-- constructor: panics if no such constructor exists
findAlt :: AltCon -> [(AltCon, a, b)] -> Maybe (AltCon, a, b)
- -- A "Nothing" result *is* legitmiate
+ -- A "Nothing" result *is* legitimate
-- See Note [Unreachable code]
findAlt con alts
= case alts of
@@ -607,8 +626,6 @@ filterAlts :: TyCon -- ^ Type constructor of scrutinee's type (us
-- 2. The new alternatives, trimmed by
-- a) remove imposs_cons
-- b) remove constructors which can't match because of GADTs
- -- and with the DEFAULT expanded to a DataAlt if there is exactly
- -- remaining constructor that can match
--
-- NB: the final list of alternatives may be empty:
-- This is a tricky corner case. If the data type has no constructors,
@@ -626,22 +643,26 @@ filterAlts _tycon inst_tys imposs_cons alts
trimmed_alts = filterOut (impossible_alt inst_tys) alts_wo_default
- imposs_deflt_cons = nub (imposs_cons ++ alt_cons)
+ imposs_cons_set = Set.fromList imposs_cons
+ imposs_deflt_cons =
+ imposs_cons ++ filterOut (`Set.member` imposs_cons_set) alt_cons
-- "imposs_deflt_cons" are handled
-- EITHER by the context,
-- OR by a non-DEFAULT branch in this case expression.
impossible_alt :: [Type] -> (AltCon, a, b) -> Bool
- impossible_alt _ (con, _, _) | con `elem` imposs_cons = True
+ impossible_alt _ (con, _, _) | con `Set.member` imposs_cons_set = True
impossible_alt inst_tys (DataAlt con, _, _) = dataConCannotMatch inst_tys con
impossible_alt _ _ = False
-refineDefaultAlt :: [Unique] -> TyCon -> [Type]
- -> [AltCon] -- Constructors that cannot match the DEFAULT (if any)
+-- | Refine the default alternative to a 'DataAlt', if there is a unique way to do so.
+-- See Note [Refine Default Alts]
+refineDefaultAlt :: [Unique] -- ^ Uniques for constructing new binders
+ -> TyCon -- ^ Type constructor of scrutinee's type
+ -> [Type] -- ^ Type arguments of scrutinee's type
+ -> [AltCon] -- ^ Constructors that cannot match the DEFAULT (if any)
-> [CoreAlt]
- -> (Bool, [CoreAlt])
--- Refine the default alternative to a DataAlt,
--- if there is a unique way to do so
+ -> (Bool, [CoreAlt]) -- ^ 'True', if a default alt was replaced with a 'DataAlt'
refineDefaultAlt us tycon tys imposs_deflt_cons all_alts
| (DEFAULT,_,rhs) : rest_alts <- all_alts
, isAlgTyCon tycon -- It's a data type, tuple, or unboxed tuples.
@@ -649,8 +670,11 @@ refineDefaultAlt us tycon tys imposs_deflt_cons all_alts
-- case x of { DEFAULT -> e }
-- and we don't want to fill in a default for them!
, Just all_cons <- tyConDataCons_maybe tycon
- , let imposs_data_cons = [con | DataAlt con <- imposs_deflt_cons] -- We now know it's a data type
- impossible con = con `elem` imposs_data_cons || dataConCannotMatch tys con
+ , let imposs_data_cons = mkUniqSet [con | DataAlt con <- imposs_deflt_cons]
+ -- We now know it's a data type, so we can use
+ -- UniqSet rather than Set (more efficient)
+ impossible con = con `elementOfUniqSet` imposs_data_cons
+ || dataConCannotMatch tys con
= case filterOut impossible all_cons of
-- Eliminate the default alternative
-- altogether if it can't match:
@@ -675,6 +699,93 @@ refineDefaultAlt us tycon tys imposs_deflt_cons all_alts
| otherwise -- The common case
= (False, all_alts)
+{- Note [Refine Default Alts]
+
+refineDefaultAlt replaces the DEFAULT alt with a constructor if there is one
+possible value it could be.
+
+The simplest example being
+
+foo :: () -> ()
+foo x = case x of !_ -> ()
+
+rewrites to
+
+foo :: () -> ()
+foo x = case x of () -> ()
+
+There are two reasons in general why this is desirable.
+
+1. We can simplify inner expressions
+
+In this example we can eliminate the inner case by refining the outer case.
+If we don't refine it, we are left with both case expressions.
+
+```
+{-# LANGUAGE BangPatterns #-}
+module Test where
+
+mid x = x
+{-# NOINLINE mid #-}
+
+data Foo = Foo1 ()
+
+test :: Foo -> ()
+test x =
+ case x of
+ !_ -> mid (case x of
+ Foo1 x1 -> x1)
+
+```
+
+refineDefaultAlt fills in the DEFAULT here with `Foo ip1` and then x
+becomes bound to `Foo ip1` so is inlined into the other case which
+causes the KnownBranch optimisation to kick in.
+
+
+2. combineIdenticalAlts does a better job
+
+Simon Jakobi also points out that that combineIdenticalAlts will do a better job
+if we refine the DEFAULT first.
+
+```
+data D = C0 | C1 | C2
+
+case e of
+ DEFAULT -> e0
+ C0 -> e1
+ C1 -> e1
+```
+
+When we apply combineIdenticalAlts to this expression, it can't
+combine the alts for C0 and C1, as we already have a default case.
+
+If we apply refineDefaultAlt first, we get
+
+```
+case e of
+ C0 -> e1
+ C1 -> e1
+ C2 -> e0
+```
+
+and combineIdenticalAlts can turn that into
+
+```
+case e of
+ DEFAULT -> e1
+ C2 -> e0
+```
+
+It isn't obvious that refineDefaultAlt does this but if you look at its one
+call site in SimplUtils then the `imposs_deflt_cons` argument is populated with
+constructors which are matched elsewhere.
+
+-}
+
+
+
+
{- Note [Combine identical alternatives]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If several alternatives are identical, merge them into a single
@@ -844,6 +955,8 @@ it off at source.
-}
exprIsTrivial :: CoreExpr -> Bool
+-- If you modify this function, you may also
+-- need to modify getIdFromTrivialExpr
exprIsTrivial (Var _) = True -- See Note [Variables are trivial]
exprIsTrivial (Type _) = True
exprIsTrivial (Coercion _) = True
@@ -873,20 +986,24 @@ if the variable actually refers to a literal; thus we use
T12076lit for an example where this matters.
-}
-getIdFromTrivialExpr :: CoreExpr -> Id
+getIdFromTrivialExpr :: HasDebugCallStack => CoreExpr -> Id
getIdFromTrivialExpr e
= fromMaybe (pprPanic "getIdFromTrivialExpr" (ppr e))
(getIdFromTrivialExpr_maybe e)
getIdFromTrivialExpr_maybe :: CoreExpr -> Maybe Id
-- See Note [getIdFromTrivialExpr]
-getIdFromTrivialExpr_maybe e = go e
- where go (Var v) = Just v
- go (App f t) | not (isRuntimeArg t) = go f
- go (Tick t e) | not (tickishIsCode t) = go e
- go (Cast e _) = go e
- go (Lam b e) | not (isRuntimeVar b) = go e
- go _ = Nothing
+-- Th equations for this should line up with those for exprIsTrivial
+getIdFromTrivialExpr_maybe e
+ = go e
+ where
+ go (App f t) | not (isRuntimeArg t) = go f
+ go (Tick t e) | not (tickishIsCode t) = go e
+ go (Cast e _) = go e
+ go (Lam b e) | not (isRuntimeVar b) = go e
+ go (Case e _ _ []) = go e
+ go (Var v) = Just v
+ go _ = Nothing
{-
exprIsBottom is a very cheap and cheerful function; it may return
@@ -1073,29 +1190,6 @@ Note that exprIsHNF does not imply exprIsCheap. Eg
This responds True to exprIsHNF (you can discard a seq), but
False to exprIsCheap.
-Note [exprIsExpandable]
-~~~~~~~~~~~~~~~~~~~~~~~
-An expression is "expandable" if we are willing to dupicate it, if doing
-so might make a RULE or case-of-constructor fire. Mainly this means
-data-constructor applications, but it's a bit more generous than exprIsCheap
-because it is true of "CONLIKE" Ids: see Note [CONLIKE pragma] in BasicTypes.
-
-It is used to set the uf_expandable field of an Unfolding, and that
-in turn is used
- * In RULE matching
- * In exprIsConApp_maybe, exprIsLiteral_maybe, exprIsLambda_maybe
-
-But take care: exprIsExpandable should /not/ be true of primops. I
-found this in test T5623a:
- let q = /\a. Ptr a (a +# b)
- in case q @ Float of Ptr v -> ...q...
-
-q's inlining should not be expandable, else exprIsConApp_maybe will
-say that (q @ Float) expands to (Ptr a (a +# b)), and that will
-duplicate the (a +# b) primop, which we should not do lightly.
-(It's quite hard to trigger this bug, but T13155 does so for GHC 8.0.)
-
-
Note [Arguments and let-bindings exprIsCheapX]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
What predicate should we apply to the argument of an application, or the
@@ -1121,16 +1215,12 @@ in this (which it previously was):
-}
--------------------
-exprIsCheap :: CoreExpr -> Bool
-exprIsCheap = exprIsCheapX isCheapApp
-
-exprIsExpandable :: CoreExpr -> Bool -- See Note [exprIsExpandable]
-exprIsExpandable = exprIsCheapX isExpandableApp
-
exprIsWorkFree :: CoreExpr -> Bool -- See Note [exprIsWorkFree]
exprIsWorkFree = exprIsCheapX isWorkFreeApp
---------------------
+exprIsCheap :: CoreExpr -> Bool
+exprIsCheap = exprIsCheapX isCheapApp
+
exprIsCheapX :: CheapAppFun -> CoreExpr -> Bool
exprIsCheapX ok_app e
= ok e
@@ -1158,6 +1248,75 @@ exprIsCheapX ok_app e
-- App, Let: see Note [Arguments and let-bindings exprIsCheapX]
+{- Note [exprIsExpandable]
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+An expression is "expandable" if we are willing to duplicate it, if doing
+so might make a RULE or case-of-constructor fire. Consider
+ let x = (a,b)
+ y = build g
+ in ....(case x of (p,q) -> rhs)....(foldr k z y)....
+
+We don't inline 'x' or 'y' (see Note [Lone variables] in CoreUnfold),
+but we do want
+
+ * the case-expression to simplify
+ (via exprIsConApp_maybe, exprIsLiteral_maybe)
+
+ * the foldr/build RULE to fire
+ (by expanding the unfolding during rule matching)
+
+So we classify the unfolding of a let-binding as "expandable" (via the
+uf_expandable field) if we want to do this kind of on-the-fly
+expansion. Specifically:
+
+* True of constructor applications (K a b)
+
+* True of applications of a "CONLIKE" Id; see Note [CONLIKE pragma] in BasicTypes.
+ (NB: exprIsCheap might not be true of this)
+
+* False of case-expressions. If we have
+ let x = case ... in ...(case x of ...)...
+ we won't simplify. We have to inline x. See Trac #14688.
+
+* False of let-expressions (same reason); and in any case we
+ float lets out of an RHS if doing so will reveal an expandable
+ application (see SimplEnv.doFloatFromRhs).
+
+* Take care: exprIsExpandable should /not/ be true of primops. I
+ found this in test T5623a:
+ let q = /\a. Ptr a (a +# b)
+ in case q @ Float of Ptr v -> ...q...
+
+ q's inlining should not be expandable, else exprIsConApp_maybe will
+ say that (q @ Float) expands to (Ptr a (a +# b)), and that will
+ duplicate the (a +# b) primop, which we should not do lightly.
+ (It's quite hard to trigger this bug, but T13155 does so for GHC 8.0.)
+-}
+
+-------------------------------------
+exprIsExpandable :: CoreExpr -> Bool
+-- See Note [exprIsExpandable]
+exprIsExpandable e
+ = ok e
+ where
+ ok e = go 0 e
+
+ -- n is the number of value arguments
+ go n (Var v) = isExpandableApp v n
+ go _ (Lit {}) = True
+ go _ (Type {}) = True
+ go _ (Coercion {}) = True
+ go n (Cast e _) = go n e
+ go n (Tick t e) | tickishCounts t = False
+ | otherwise = go n e
+ go n (Lam x e) | isRuntimeVar x = n==0 || go (n-1) e
+ | otherwise = go n e
+ go n (App f e) | isRuntimeArg e = go (n+1) f && ok e
+ | otherwise = go n f
+ go _ (Case {}) = False
+ go _ (Let {}) = False
+
+
-------------------------------------
type CheapAppFun = Id -> Arity -> Bool
-- Is an application of this function to n *value* args
@@ -1168,22 +1327,11 @@ type CheapAppFun = Id -> Arity -> Bool
-- isCheapApp
-- isExpandableApp
- -- NB: isCheapApp and isExpandableApp are called from outside
- -- this module, so don't be tempted to move the notRedex
- -- stuff into the call site in exprIsCheapX, and remove it
- -- from the CheapAppFun implementations
-
-
-notRedex :: CheapAppFun
-notRedex fn n_val_args
- = n_val_args == 0 -- No value args
- || n_val_args < idArity fn -- Partial application
- || isBottomingId fn -- OK to duplicate calls to bottom;
- -- it certainly doesn't need to be shared!
-
isWorkFreeApp :: CheapAppFun
isWorkFreeApp fn n_val_args
- | notRedex fn n_val_args
+ | n_val_args == 0 -- No value args
+ = True
+ | n_val_args < idArity fn -- Partial application
= True
| otherwise
= case idDetails fn of
@@ -1192,11 +1340,11 @@ isWorkFreeApp fn n_val_args
isCheapApp :: CheapAppFun
isCheapApp fn n_val_args
- | notRedex fn n_val_args
- = True
+ | isWorkFreeApp fn n_val_args = True
+ | isBottomingId fn = True -- See Note [isCheapApp: bottoming functions]
| otherwise
= case idDetails fn of
- DataConWorkId {} -> True
+ DataConWorkId {} -> True -- Actually handled by isWorkFreeApp
RecSelId {} -> n_val_args == 1 -- See Note [Record selection]
ClassOpId {} -> n_val_args == 1
PrimOpId op -> primOpIsCheap op
@@ -1208,21 +1356,24 @@ isCheapApp fn n_val_args
isExpandableApp :: CheapAppFun
isExpandableApp fn n_val_args
- | notRedex fn n_val_args
- = True
- | isConLikeId fn
- = True
+ | isWorkFreeApp fn n_val_args = True
| otherwise
= case idDetails fn of
- DataConWorkId {} -> True
+ DataConWorkId {} -> True -- Actually handled by isWorkFreeApp
RecSelId {} -> n_val_args == 1 -- See Note [Record selection]
ClassOpId {} -> n_val_args == 1
PrimOpId {} -> False
- _ -> all_pred_args n_val_args (idType fn)
+ _ | isBottomingId fn -> False
+ -- See Note [isExpandableApp: bottoming functions]
+ | isConLike (idRuleMatchInfo fn) -> True
+ | all_args_are_preds -> True
+ | otherwise -> False
where
- -- See if all the arguments are PredTys (implicit params or classes)
- -- If so we'll regard it as expandable; see Note [Expandable overloadings]
+ -- See if all the arguments are PredTys (implicit params or classes)
+ -- If so we'll regard it as expandable; see Note [Expandable overloadings]
+ all_args_are_preds = all_pred_args n_val_args (idType fn)
+
all_pred_args n_val_args ty
| n_val_args == 0
= True
@@ -1235,7 +1386,35 @@ isExpandableApp fn n_val_args
| otherwise
= False
-{- Note [Record selection]
+{- Note [isCheapApp: bottoming functions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+I'm not sure why we have a special case for bottoming
+functions in isCheapApp. Maybe we don't need it.
+
+Note [isExpandableApp: bottoming functions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+It's important that isExpandableApp does not respond True to bottoming
+functions. Recall undefined :: HasCallStack => a
+Suppose isExpandableApp responded True to (undefined d), and we had:
+
+ x = undefined <dict-expr>
+
+Then Simplify.prepareRhs would ANF the RHS:
+
+ d = <dict-expr>
+ x = undefined d
+
+This is already bad: we gain nothing from having x bound to (undefined
+var), unlike the case for data constructors. Worse, we get the
+simplifier loop described in OccurAnal Note [Cascading inlines].
+Suppose x occurs just once; OccurAnal.occAnalNonRecRhs decides x will
+certainly_inline; so we end up inlining d right back into x; but in
+the end x doesn't inline because it is bottom (preInlineUnconditionally);
+so the process repeats.. We could elaborate the certainly_inline logic
+some more, but it's better just to treat bottoming bindings as
+non-expandable, because ANFing them is a bad idea in the first place.
+
+Note [Record selection]
~~~~~~~~~~~~~~~~~~~~~~~~~~
I'm experimenting with making record selection
look cheap, so we will substitute it inside a
@@ -1308,18 +1487,22 @@ it's applied only to dictionaries.
--
-- 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.
-exprOkForSpeculation, exprOkForSideEffects :: Expr b -> Bool
+
+exprOkForSpeculation, exprOkForSideEffects :: CoreExpr -> Bool
exprOkForSpeculation = expr_ok primOpOkForSpeculation
exprOkForSideEffects = expr_ok primOpOkForSideEffects
- -- Polymorphic in binder type
- -- There is one call at a non-Id binder type, in SetLevels
-expr_ok :: (PrimOp -> Bool) -> Expr b -> Bool
+expr_ok :: (PrimOp -> Bool) -> CoreExpr -> Bool
expr_ok _ (Lit _) = True
expr_ok _ (Type _) = True
expr_ok _ (Coercion _) = True
-expr_ok primop_ok (Var v) = app_ok primop_ok v []
-expr_ok primop_ok (Cast e _) = expr_ok primop_ok e
+
+expr_ok primop_ok (Var v) = app_ok primop_ok v []
+expr_ok primop_ok (Cast e _) = expr_ok primop_ok e
+expr_ok primop_ok (Lam b e)
+ | isTyVar b = expr_ok primop_ok e
+ | otherwise = True
+
-- Tick annotations that *tick* cannot be speculated, because these
-- are meant to identify whether or not (and how often) the particular
@@ -1328,10 +1511,18 @@ expr_ok primop_ok (Tick tickish e)
| tickishCounts tickish = False
| otherwise = expr_ok primop_ok e
-expr_ok primop_ok (Case e _ _ alts)
- = expr_ok primop_ok e -- Note [exprOkForSpeculation: case expressions]
+expr_ok _ (Let {}) = False
+ -- Lets can be stacked deeply, so just give up.
+ -- In any case, the argument of exprOkForSpeculation is
+ -- usually in a strict context, so any lets will have been
+ -- floated away.
+
+expr_ok primop_ok (Case scrut bndr _ alts)
+ = -- See Note [exprOkForSpeculation: case expressions]
+ expr_ok primop_ok scrut
+ && isUnliftedType (idType bndr)
&& all (\(_,_,rhs) -> expr_ok primop_ok rhs) alts
- && altsAreExhaustive alts -- Note [Exhaustive alts]
+ && altsAreExhaustive alts
expr_ok primop_ok other_expr
= case collectArgs other_expr of
@@ -1340,7 +1531,7 @@ expr_ok primop_ok other_expr
_ -> False
-----------------------------
-app_ok :: (PrimOp -> Bool) -> Id -> [Expr b] -> Bool
+app_ok :: (PrimOp -> Bool) -> Id -> [CoreExpr] -> Bool
app_ok primop_ok fun args
= case idDetails fun of
DFunId new_type -> not new_type
@@ -1363,8 +1554,11 @@ app_ok primop_ok fun args
-- Often there is a literal divisor, and this
-- can get rid of a thunk in an inner loop
+ | SeqOp <- op -- See Note [seq# and expr_ok]
+ -> all (expr_ok primop_ok) args
+
| otherwise
- -> primop_ok op -- Check the primop itself
+ -> primop_ok op -- Check the primop itself
&& and (zipWith arg_ok arg_tys args) -- Check the arguments
_other -> isUnliftedType (idType fun) -- c.f. the Var case of exprIsHNF
@@ -1376,7 +1570,7 @@ app_ok primop_ok fun args
where
(arg_tys, _) = splitPiTys (idType fun)
- arg_ok :: TyBinder -> Expr b -> Bool
+ arg_ok :: TyBinder -> CoreExpr -> Bool
arg_ok (Named _) _ = True -- A type argument
arg_ok (Anon ty) arg -- A term argument
| isUnliftedType ty = expr_ok primop_ok arg
@@ -1411,22 +1605,72 @@ isDivOp FloatDivOp = True
isDivOp DoubleDivOp = True
isDivOp _ = False
-{-
-Note [exprOkForSpeculation: case expressions]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-It's always sound for exprOkForSpeculation to return False, and we
-don't want it to take too long, so it bales out on complicated-looking
-terms. Notably lets, which can be stacked very deeply; and in any
-case the argument of exprOkForSpeculation is usually in a strict context,
-so any lets will have been floated away.
-
-However, we keep going on case-expressions. An example like this one
-showed up in DPH code (Trac #3717):
+{- Note [exprOkForSpeculation: case expressions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+exprOkForSpeculation accepts very special case expressions.
+Reason: (a ==# b) is ok-for-speculation, but the litEq rules
+in PrelRules convert it (a ==# 3#) to
+ case a of { DEAFULT -> 0#; 3# -> 1# }
+for excellent reasons described in
+ PrelRules Note [The litEq rule: converting equality to case].
+So, annoyingly, we want that case expression to be
+ok-for-speculation too. Bother.
+
+But we restrict it sharply:
+
+* We restrict it to unlifted scrutinees. Consider this:
+ case x of y {
+ DEFAULT -> ... (let v::Int# = case y of { True -> e1
+ ; False -> e2 }
+ in ...) ...
+
+ Does the RHS of v satisfy the let/app invariant? Previously we said
+ yes, on the grounds that y is evaluated. But the binder-swap done
+ by SetLevels would transform the inner alternative to
+ DEFAULT -> ... (let v::Int# = case x of { ... }
+ in ...) ....
+ which does /not/ satisfy the let/app invariant, because x is
+ not evaluated. See Note [Binder-swap during float-out]
+ in SetLevels. To avoid this awkwardness it seems simpler
+ to stick to unlifted scrutinees where the issue does not
+ arise.
+
+* We restrict it to exhaustive alternatives. A non-exhaustive
+ case manifestly isn't ok-for-speculation. Consider
+ case e of x { DEAFULT ->
+ ...(case x of y
+ A -> ...
+ _ -> ...(case (case x of { B -> p; C -> p }) of
+ I# r -> blah)...
+ If SetLevesls considers the inner nested case as ok-for-speculation
+ it can do case-floating (see Note [Floating cases] in SetLevels).
+ So we'd float to:
+ case e of x { DEAFULT ->
+ case (case x of { B -> p; C -> p }) of I# r ->
+ ...(case x of y
+ A -> ...
+ _ -> ...blah...)...
+ which is utterly bogus (seg fault); see Trac #5453.
+
+ Similarly, this is a valid program (albeit a slightly dodgy one)
+ let v = case x of { B -> ...; C -> ... }
+ in case x of
+ A -> ...
+ _ -> ...v...v....
+ Should v be considered ok-for-speculation? Its scrutinee may be
+ evaluated, but the alternatives are incomplete so we should not
+ evaluate it strictly.
+
+ Now, all this is for lifted types, but it'd be the same for any
+ finite unlifted type. We don't have many of them, but we might
+ add unlifted algebraic types in due course.
+
+----- Historical note: Trac #3717: --------
foo :: Int -> Int
foo 0 = 0
foo n = (if n < 5 then 1 else 2) `seq` foo (n-1)
-If exprOkForSpeculation doesn't look through case expressions, you get this:
+In earlier GHCs, we got this:
T.$wfoo =
\ (ww :: GHC.Prim.Int#) ->
case ww of ds {
@@ -1435,31 +1679,13 @@ If exprOkForSpeculation doesn't look through case expressions, you get this:
GHC.Types.True -> lvl})
of _ { __DEFAULT ->
T.$wfoo (GHC.Prim.-# ds_XkE 1) };
- 0 -> 0
- }
-
-The inner case is redundant, and should be nuked.
-
-Note [Exhaustive alts]
-~~~~~~~~~~~~~~~~~~~~~~
-We might have something like
- case x of {
- A -> ...
- _ -> ...(case x of { B -> ...; C -> ... })...
-Here, the inner case is fine, because the A alternative
-can't happen, but it's not ok to float the inner case outside
-the outer one (even if we know x is evaluated outside), because
-then it would be non-exhaustive. See Trac #5453.
-
-Similarly, this is a valid program (albeit a slightly dodgy one)
- let v = case x of { B -> ...; C -> ... }
- in case x of
- A -> ...
- _ -> ...v...v....
-But we don't want to speculate the v binding.
+ 0 -> 0 }
-One could try to be clever, but the easy fix is simpy to regard
-a non-exhaustive case as *not* okForSpeculation.
+Before join-points etc we could only get rid of two cases (which are
+redundant) by recognising that th e(case <# ds 5 of { ... }) is
+ok-for-speculation, even though it has /lifted/ type. But now join
+points do the job nicely.
+------- End of historical note ------------
Note [Primops with lifted arguments]
@@ -1471,8 +1697,8 @@ evaluate them. Indeed, in general primops are, well, primitive
and do not perform evaluation.
There is one primop, dataToTag#, which does /require/ a lifted
-argument to be evaluted. To ensure this, CorePrep adds an
-eval if it can't see the the argument is definitely evaluated
+argument to be evaluated. To ensure this, CorePrep adds an
+eval if it can't see the argument is definitely evaluated
(see [dataToTag magic] in CorePrep).
We make no attempt to guarantee that dataToTag#'s argument is
@@ -1489,6 +1715,25 @@ See also Note [dataToTag#] in primops.txt.pp.
Bottom line:
* in exprOkForSpeculation we simply ignore all lifted arguments.
+ * except see Note [seq# and expr_ok] for an exception
+
+
+Note [seq# and expr_ok]
+~~~~~~~~~~~~~~~~~~~~~~~
+Recall that
+ seq# :: forall a s . a -> State# s -> (# State# s, a #)
+must always evaluate its first argument. So it's really a
+counter-example to Note [Primops with lifted arguments]. In
+the case of seq# we must check the argument to seq#. Remember
+item (d) of the specification of exprOkForSpeculation:
+
+ -- Precisely, it returns @True@ iff:
+ -- a) The expression guarantees to terminate,
+ ...
+ -- d) without throwing a Haskell exception
+
+The lack of this special case caused Trac #5129 to go bad again.
+See comment:24 and following
************************************************************************
@@ -1546,9 +1791,9 @@ exprIsHNFlike :: (Var -> Bool) -> (Unfolding -> Bool) -> CoreExpr -> Bool
exprIsHNFlike is_con is_con_unf = is_hnf_like
where
is_hnf_like (Var v) -- NB: There are no value args at this point
- = is_con v -- Catches nullary constructors,
- -- so that [] and () are values, for example
- || idArity v > 0 -- Catches (e.g.) primops that don't have unfoldings
+ = id_app_is_value v 0 -- Catches nullary constructors,
+ -- so that [] and () are values, for example
+ -- and (e.g.) primops that don't have unfoldings
|| is_con_unf (idUnfolding v)
-- Check the thing's unfolding; it might be bound to a value
-- We don't look through loop breakers here, which is a bit conservative
@@ -1561,7 +1806,7 @@ exprIsHNFlike is_con is_con_unf = is_hnf_like
is_hnf_like (Coercion _) = True -- Same for coercions
is_hnf_like (Lam b e) = isRuntimeVar b || is_hnf_like e
is_hnf_like (Tick tickish e) = not (tickishCounts tickish)
- && is_hnf_like e
+ && is_hnf_like e
-- See Note [exprIsHNF Tick]
is_hnf_like (Cast e _) = is_hnf_like e
is_hnf_like (App e a)
@@ -1573,9 +1818,7 @@ exprIsHNFlike is_con is_con_unf = is_hnf_like
-- There is at least one value argument
-- 'n' is number of value args to which the expression is applied
app_is_value :: CoreExpr -> Int -> Bool
- app_is_value (Var fun) n_val_args
- = idArity fun > n_val_args -- Under-applied function
- || is_con fun -- or constructor-like
+ app_is_value (Var f) nva = id_app_is_value f nva
app_is_value (Tick _ f) nva = app_is_value f nva
app_is_value (Cast f _) nva = app_is_value f nva
app_is_value (App f a) nva
@@ -1583,6 +1826,13 @@ exprIsHNFlike is_con is_con_unf = is_hnf_like
| otherwise = app_is_value f nva
app_is_value _ _ = False
+ id_app_is_value id n_val_args
+ = is_con id
+ || idArity id > n_val_args
+ || id `hasKey` absentErrorIdKey -- See Note [aBSENT_ERROR_ID] in MkCore
+ -- absentError behaves like an honorary data constructor
+
+
{-
Note [exprIsHNF Tick]
@@ -1602,13 +1852,28 @@ don't want to discard a seq on it.
exprIsTopLevelBindable :: CoreExpr -> Type -> Bool
-- See Note [CoreSyn top-level string literals]
-- Precondition: exprType expr = ty
+-- Top-level literal strings can't even be wrapped in ticks
+-- see Note [CoreSyn top-level string literals] in CoreSyn
exprIsTopLevelBindable expr ty
- = exprIsLiteralString expr
- || not (isUnliftedType ty)
-
-exprIsLiteralString :: CoreExpr -> Bool
-exprIsLiteralString (Lit (MachStr _)) = True
-exprIsLiteralString _ = False
+ = not (isUnliftedType ty)
+ || exprIsTickedString expr
+
+-- | Check if the expression is zero or more Ticks wrapped around a literal
+-- string.
+exprIsTickedString :: CoreExpr -> Bool
+exprIsTickedString = isJust . exprIsTickedString_maybe
+
+-- | Extract a literal string from an expression that is zero or more Ticks
+-- wrapped around a literal string. Returns Nothing if the expression has a
+-- different shape.
+-- Used to "look through" Ticks in places that need to handle literal strings.
+exprIsTickedString_maybe :: CoreExpr -> Maybe ByteString
+exprIsTickedString_maybe (Lit (MachStr bs)) = Just bs
+exprIsTickedString_maybe (Tick t e)
+ -- we don't tick literals with CostCentre ticks, compare to mkTick
+ | tickishPlace t == PlaceCostCentre = Nothing
+ | otherwise = exprIsTickedString_maybe e
+exprIsTickedString_maybe _ = Nothing
{-
************************************************************************
@@ -1620,8 +1885,8 @@ exprIsLiteralString _ = False
These InstPat functions go here to avoid circularity between DataCon and Id
-}
-dataConRepInstPat :: [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])
-dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])
+dataConRepInstPat :: [Unique] -> DataCon -> [Type] -> ([TyCoVar], [Id])
+dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyCoVar], [Id])
dataConRepInstPat = dataConInstPat (repeat ((fsLit "ipv")))
dataConRepFSInstPat = dataConInstPat
@@ -1630,7 +1895,7 @@ dataConInstPat :: [FastString] -- A long enough list of FSs to use for
-> [Unique] -- An equally long list of uniques, at least one for each binder
-> DataCon
-> [Type] -- Types to instantiate the universally quantified tyvars
- -> ([TyVar], [Id]) -- Return instantiated variables
+ -> ([TyCoVar], [Id]) -- Return instantiated variables
-- dataConInstPat arg_fun fss us con inst_tys returns a tuple
-- (ex_tvs, arg_ids),
--
@@ -1663,7 +1928,7 @@ dataConInstPat fss uniqs con inst_tys
(ex_bndrs, arg_ids)
where
univ_tvs = dataConUnivTyVars con
- ex_tvs = dataConExTyVars con
+ ex_tvs = dataConExTyCoVars con
arg_tys = dataConRepArgTys con
arg_strs = dataConRepStrictness con -- 1-1 with arg_tys
n_ex = length ex_tvs
@@ -1679,13 +1944,16 @@ dataConInstPat fss uniqs con inst_tys
(full_subst, ex_bndrs) = mapAccumL mk_ex_var univ_subst
(zip3 ex_tvs ex_fss ex_uniqs)
- mk_ex_var :: TCvSubst -> (TyVar, FastString, Unique) -> (TCvSubst, TyVar)
- mk_ex_var subst (tv, fs, uniq) = (Type.extendTvSubstWithClone subst tv
+ mk_ex_var :: TCvSubst -> (TyCoVar, FastString, Unique) -> (TCvSubst, TyCoVar)
+ mk_ex_var subst (tv, fs, uniq) = (Type.extendTCvSubstWithClone subst tv
new_tv
, new_tv)
where
- new_tv = mkTyVar (mkSysTvName uniq fs) kind
- kind = Type.substTyUnchecked subst (tyVarKind tv)
+ new_tv | isTyVar tv
+ = mkTyVar (mkSysTvName uniq fs) kind
+ | otherwise
+ = mkCoVar (mkSystemVarName uniq fs) kind
+ kind = Type.substTyUnchecked subst (varType tv)
-- Make value vars, instantiating types
arg_ids = zipWith4 mk_id_var id_uniqs id_fss arg_tys arg_strs
@@ -2162,12 +2430,13 @@ and 'execute' it rather than allocating it statically.
-- | 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.
-rhsIsStatic :: Platform
- -> (Name -> Bool) -- Which names are dynamic
- -> (Integer -> CoreExpr) -- Desugaring for integer literals (disgusting)
- -- C.f. Note [Disgusting computation of CafRefs]
- -- in TidyPgm
- -> CoreExpr -> Bool
+rhsIsStatic
+ :: Platform
+ -> (Name -> Bool) -- Which names are dynamic
+ -> (LitNumType -> Integer -> Maybe CoreExpr)
+ -- Desugaring for some literals (disgusting)
+ -- C.f. Note [Disgusting computation of CafRefs] in TidyPgm
+ -> CoreExpr -> Bool
-- It's called (i) in TidyPgm.hasCafRefs to decide if the rhs is, or
-- refers to, CAFs; (ii) in CoreToStg to decide whether to put an
-- update flag on it and (iii) in DsExpr to decide how to expand
@@ -2222,7 +2491,7 @@ rhsIsStatic :: Platform
--
-- c) don't look through unfolding of f in (f x).
-rhsIsStatic platform is_dynamic_name cvt_integer rhs = is_static False rhs
+rhsIsStatic platform is_dynamic_name cvt_literal rhs = is_static False rhs
where
is_static :: Bool -- True <=> in a constructor argument; must be atomic
-> CoreExpr -> Bool
@@ -2232,7 +2501,9 @@ rhsIsStatic platform is_dynamic_name cvt_integer rhs = is_static False rhs
&& is_static in_arg e
is_static in_arg (Cast e _) = is_static in_arg e
is_static _ (Coercion {}) = True -- Behaves just like a literal
- is_static in_arg (Lit (LitInteger i _)) = is_static in_arg (cvt_integer i)
+ is_static in_arg (Lit (LitNumber nt i _)) = case cvt_literal nt i of
+ Just e -> is_static in_arg e
+ Nothing -> True
is_static _ (Lit (MachLabel {})) = False
is_static _ (Lit _) = True
-- A MachLabel (foreign import "&foo") in an argument