bindNonRec, mkIfThenElse, mkAltExpr,
mkPiType,
+ -- Taking expressions apart
+ findDefault, findAlt,
+
-- Properties of expressions
exprType, coreAltsType,
exprIsBottom, exprIsDupable, exprIsTrivial, exprIsCheap,
exprIsValue,exprOkForSpeculation, exprIsBig,
- exprIsConApp_maybe,
+ exprIsConApp_maybe, exprIsAtom,
idAppIsBottom, idAppIsCheap,
exprArity,
primOpIsDupable )
import Id ( Id, idType, idFlavour, idStrictness, idLBVarInfo,
mkWildId, idArity, idName, idUnfolding, idInfo,
- isDataConId_maybe, isPrimOpId_maybe, mkSysLocal
+ isDataConId_maybe, isPrimOpId_maybe, mkSysLocal, hasNoBinding
)
import IdInfo ( LBVarInfo(..),
IdFlavour(..),
that looks like (Note InlineMe (Var v)), the InlineMe doesn't go away because it may
not be *applied* to anything.
+We don't use exprIsTrivial here, though, because we sometimes generate worker/wrapper
+bindings like
+ fw = ...
+ f = inline_me (coerce t fw)
+As usual, the inline_me prevents the worker from getting inlined back into the wrapper.
+We want the split, so that the coerces can cancel at the call site.
+
+However, we can get left with tiresome type applications. Notably, consider
+ f = /\ a -> let t = e in (t, w)
+Then lifting the let out of the big lambda gives
+ t' = /\a -> e
+ f = /\ a -> let t = inline_me (t' a) in (t, w)
+The inline_me is to stop the simplifier inlining t' right back
+into t's RHS. In the next phase we'll substitute for t (since
+its rhs is trivial) and *then* we could get rid of the inline_me.
+But it hardly seems worth it, so I don't bother.
+
\begin{code}
-mkInlineMe e | exprIsTrivial e = e
- | otherwise = Note InlineMe e
+mkInlineMe (Var v) = Var v
+mkInlineMe e = Note InlineMe e
\end{code}
(DataAlt falseDataCon, [], else_expr) ]
\end{code}
+
+%************************************************************************
+%* *
+\subsection{Taking expressions apart}
+%* *
+%************************************************************************
+
+
+\begin{code}
+findDefault :: [CoreAlt] -> ([CoreAlt], Maybe CoreExpr)
+findDefault [] = ([], Nothing)
+findDefault ((DEFAULT,args,rhs) : alts) = ASSERT( null alts && null args )
+ ([], Just rhs)
+findDefault (alt : alts) = case findDefault alts of
+ (alts', deflt) -> (alt : alts', deflt)
+
+findAlt :: AltCon -> [CoreAlt] -> CoreAlt
+findAlt con alts
+ = go alts
+ where
+ go [] = pprPanic "Missing alternative" (ppr con $$ vcat (map ppr alts))
+ go (alt : alts) | matches alt = alt
+ | otherwise = go alts
+
+ matches (DEFAULT, _, _) = True
+ matches (con1, _, _) = con == con1
+\end{code}
+
+
%************************************************************************
%* *
\subsection{Figuring out things about expressions}
\begin{code}
exprIsTrivial (Var v)
- | Just op <- isPrimOpId_maybe v = primOpIsDupable op
+ | hasNoBinding v = idArity v == 0
+ -- WAS: | Just op <- isPrimOpId_maybe v = primOpIsDupable op
+ -- The idea here is that a constructor worker, like $wJust, is
+ -- really short for (\x -> $wJust x), becuase $wJust has no binding.
+ -- So it should be treated like a lambda.
+ -- Ditto unsaturated primops.
+ -- This came up when dealing with eta expansion/reduction for
+ -- x = $wJust
+ -- Here we want to eta-expand. This looks like an optimisation,
+ -- but it's important (albeit tiresome) that CoreSat doesn't increase
+ -- anything's arity
| otherwise = True
exprIsTrivial (Type _) = True
exprIsTrivial (Lit lit) = True
exprIsTrivial (Note _ e) = exprIsTrivial e
exprIsTrivial (Lam b body) | isTyVar b = exprIsTrivial body
exprIsTrivial other = False
+
+exprIsAtom :: CoreExpr -> Bool
+-- Used to decide whether to let-binding an STG argument
+-- when compiling to ILX => type applications are not allowed
+exprIsAtom (Var v) = True -- primOpIsDupable?
+exprIsAtom (Lit lit) = True
+exprIsAtom (Type ty) = True
+exprIsAtom (Note _ e) = exprIsAtom e
+exprIsAtom other = False
\end{code}
and to decide whether it's safe to discard a `seq`
-So, it does *not* treat variables as evaluated, unless they say they are
+So, it does *not* treat variables as evaluated, unless they say they are.
+
+But it *does* treat partial applications and constructor applications
+as values, even if their arguments are non-trivial;
+ e.g. (:) (f x) (map f xs) is a value
+ map (...redex...) is a value
+Because `seq` on such things completes immediately
+
+A worry: constructors with unboxed args:
+ C (f x :: Int#)
+Suppose (f x) diverges; then C (f x) is not a value.
\begin{code}
exprIsValue :: CoreExpr -> Bool -- True => Value-lambda, constructor, PAP
= analyse (collectArgs expr)
where
analyse (Var fun, args)
- | maybeToBool maybe_con_app = maybe_con_app
- where
- maybe_con_app = case isDataConId_maybe fun of
- Just con | length args >= dataConRepArity con
- -- Might be > because the arity excludes type args
- -> Just (con, args)
- other -> Nothing
+ | Just con <- isDataConId_maybe fun,
+ length args >= dataConRepArity con
+ -- Might be > because the arity excludes type args
+ = Just (con,args)
+ -- Look through unfoldings, but only cheap ones, because
+ -- we are effectively duplicating the unfolding
analyse (Var fun, [])
- = case maybeUnfoldingTemplate (idUnfolding fun) of
- Nothing -> Nothing
- Just unf -> exprIsConApp_maybe unf
+ | let unf = idUnfolding fun,
+ isCheapUnfolding unf
+ = exprIsConApp_maybe (unfoldingTemplate unf)
analyse other = Nothing
\end{code}