X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2FbasicTypes%2FBasicTypes.lhs;h=f14ab4d98ceeb84a4cf4d25cccdaad78db1860a2;hb=011680bdbd73c93f6fd8363aaef93f995ba8f5b1;hp=0182139b761b26e827ddd03dc463274425bed7f0;hpb=2476249a77bde34ea2052910f111a3424c366db6;p=ghc-hetmet.git diff --git a/compiler/basicTypes/BasicTypes.lhs b/compiler/basicTypes/BasicTypes.lhs index 0182139..f14ab4d 100644 --- a/compiler/basicTypes/BasicTypes.lhs +++ b/compiler/basicTypes/BasicTypes.lhs @@ -42,8 +42,9 @@ module BasicTypes( TupCon(..), tupleParens, - OccInfo(..), seqOccInfo, isFragileOcc, isOneOcc, + OccInfo(..), seqOccInfo, zapFragileOcc, isOneOcc, isDeadOcc, isLoopBreaker, isNonRuleLoopBreaker, isNoOcc, + nonRuleLoopBreaker, InsideLam, insideLam, notInsideLam, OneBranch, oneBranch, notOneBranch, @@ -54,12 +55,12 @@ module BasicTypes( StrictnessMark(..), isMarkedUnboxed, isMarkedStrict, CompilerPhase, - Activation(..), isActive, isNeverActive, isAlwaysActive, - RuleMatchInfo(..), isConLike, isFunLike, - InlinePragma(..), defaultInlinePragma, isDefaultInlinePragma, + Activation(..), isActive, isNeverActive, isAlwaysActive, isEarlyActive, + RuleMatchInfo(..), isConLike, isFunLike, + InlinePragma(..), defaultInlinePragma, alwaysInlinePragma, neverInlinePragma, dfunInlinePragma, + isDefaultInlinePragma, isInlinePragma, inlinePragmaSat, inlinePragmaActivation, inlinePragmaRuleMatchInfo, setInlinePragmaActivation, setInlinePragmaRuleMatchInfo, - InlineSpec(..), defaultInlineSpec, alwaysInlineSpec, neverInlineSpec, SuccessFlag(..), succeeded, failed, successIf ) where @@ -476,17 +477,20 @@ isNonRuleLoopBreaker :: OccInfo -> Bool isNonRuleLoopBreaker (IAmALoopBreaker False) = True -- Loop-breaker that breaks a non-rule cycle isNonRuleLoopBreaker _ = False +nonRuleLoopBreaker :: OccInfo +nonRuleLoopBreaker = IAmALoopBreaker False + isDeadOcc :: OccInfo -> Bool isDeadOcc IAmDead = True isDeadOcc _ = False isOneOcc :: OccInfo -> Bool -isOneOcc (OneOcc _ _ _) = True -isOneOcc _ = False +isOneOcc (OneOcc {}) = True +isOneOcc _ = False -isFragileOcc :: OccInfo -> Bool -isFragileOcc (OneOcc _ _ _) = True -isFragileOcc _ = False +zapFragileOcc :: OccInfo -> OccInfo +zapFragileOcc (OneOcc {}) = NoOccInfo +zapFragileOcc occ = occ \end{code} \begin{code} @@ -585,10 +589,73 @@ data Activation = NeverActive | ActiveAfter CompilerPhase -- Active in this phase and later deriving( Eq ) -- Eq used in comparing rules in HsDecls -data RuleMatchInfo = ConLike +data RuleMatchInfo = ConLike -- See Note [CONLIKE pragma] | FunLike deriving( Eq ) +data InlinePragma -- Note [InlinePragma] + = InlinePragma + { inl_inline :: Bool -- True <=> INLINE, + -- False <=> no pragma at all, or NOINLINE + , inl_sat :: Maybe Arity -- Just n <=> Inline only when applied to n + -- explicit (non-type, non-dictionary) args + , inl_act :: Activation -- Says during which phases inlining is allowed + , inl_rule :: RuleMatchInfo -- Should the function be treated like a constructor? + } deriving( Eq ) +\end{code} + +Note [InlinePragma] +~~~~~~~~~~~~~~~~~~~ +This data type mirrors what you can write in an INLINE or NOINLINE pragma in +the source program. + +If you write nothing at all, you get defaultInlinePragma: + inl_inline = False + inl_act = AlwaysActive + inl_rule = FunLike + +It's not possible to get that combination by *writing* something, so +if an Id has defaultInlinePragma it means the user didn't specify anything. + +If inl_inline = True, then the Id should have an InlineRule unfolding. + +Note [CONLIKE pragma] +~~~~~~~~~~~~~~~~~~~~~ +The ConLike constructor of a RuleMatchInfo is aimed at the following. +Consider first + {-# RULE "r/cons" forall a as. r (a:as) = f (a+1) #-} + g b bs = let x = b:bs in ..x...x...(r x)... +Now, the rule applies to the (r x) term, because GHC "looks through" +the definition of 'x' to see that it is (b:bs). + +Now consider + {-# RULE "r/f" forall v. r (f v) = f (v+1) #-} + g v = let x = f v in ..x...x...(r x)... +Normally the (r x) would *not* match the rule, because GHC would be +scared about duplicating the redex (f v), so it does not "look +through" the bindings. + +However the CONLIKE modifier says to treat 'f' like a constructor in +this situation, and "look through" the unfolding for x. So (r x) +fires, yielding (f (v+1)). + +This is all controlled with a user-visible pragma: + {-# NOINLINE CONLIKE [1] f #-} + +The main effects of CONLIKE are: + + - The occurrence analyser (OccAnal) and simplifier (Simplify) treat + CONLIKE thing like constructors, by ANF-ing them + + - New function coreUtils.exprIsExpandable is like exprIsCheap, but + additionally spots applications of CONLIKE functions + + - A CoreUnfolding has a field that caches exprIsExpandable + + - The rule matcher consults this field. See + Note [Expanding variables] in Rules.lhs. + +\begin{code} isConLike :: RuleMatchInfo -> Bool isConLike ConLike = True isConLike _ = False @@ -597,55 +664,50 @@ isFunLike :: RuleMatchInfo -> Bool isFunLike FunLike = True isFunLike _ = False -data InlinePragma - = InlinePragma - Activation -- Says during which phases inlining is allowed - RuleMatchInfo -- Should the function be treated like a constructor? - deriving( Eq ) +defaultInlinePragma, alwaysInlinePragma, neverInlinePragma, dfunInlinePragma + :: InlinePragma +defaultInlinePragma = InlinePragma { inl_act = AlwaysActive + , inl_rule = FunLike + , inl_inline = False + , inl_sat = Nothing } + +alwaysInlinePragma = defaultInlinePragma { inl_inline = True } +neverInlinePragma = defaultInlinePragma { inl_act = NeverActive } -defaultInlinePragma :: InlinePragma -defaultInlinePragma = InlinePragma AlwaysActive FunLike +-- A DFun has an always-active inline activation so that +-- exprIsConApp_maybe can "see" its unfolding +-- (However, its actual Unfolding is a DFunUnfolding, which is +-- never inlined other than via exprIsConApp_maybe.) +dfunInlinePragma = defaultInlinePragma { inl_act = AlwaysActive + , inl_rule = ConLike } isDefaultInlinePragma :: InlinePragma -> Bool -isDefaultInlinePragma (InlinePragma activation match_info) - = isAlwaysActive activation && isFunLike match_info +isDefaultInlinePragma (InlinePragma { inl_act = activation + , inl_rule = match_info + , inl_inline = inline }) + = not inline && isAlwaysActive activation && isFunLike match_info + +isInlinePragma :: InlinePragma -> Bool +isInlinePragma prag = inl_inline prag + +inlinePragmaSat :: InlinePragma -> Maybe Arity +inlinePragmaSat = inl_sat inlinePragmaActivation :: InlinePragma -> Activation -inlinePragmaActivation (InlinePragma activation _) = activation +inlinePragmaActivation (InlinePragma { inl_act = activation }) = activation inlinePragmaRuleMatchInfo :: InlinePragma -> RuleMatchInfo -inlinePragmaRuleMatchInfo (InlinePragma _ info) = info +inlinePragmaRuleMatchInfo (InlinePragma { inl_rule = info }) = info setInlinePragmaActivation :: InlinePragma -> Activation -> InlinePragma -setInlinePragmaActivation (InlinePragma _ info) activation - = InlinePragma activation info +setInlinePragmaActivation prag activation = prag { inl_act = activation } setInlinePragmaRuleMatchInfo :: InlinePragma -> RuleMatchInfo -> InlinePragma -setInlinePragmaRuleMatchInfo (InlinePragma activation _) info - = InlinePragma activation info - -data InlineSpec - = Inline - InlinePragma - Bool -- True <=> INLINE - -- False <=> NOINLINE - deriving( Eq ) - -defaultInlineSpec :: InlineSpec -alwaysInlineSpec, neverInlineSpec :: RuleMatchInfo -> InlineSpec - -defaultInlineSpec = Inline defaultInlinePragma False - -- Inlining is OK, but not forced -alwaysInlineSpec match_info - = Inline (InlinePragma AlwaysActive match_info) True - -- INLINE always -neverInlineSpec match_info - = Inline (InlinePragma NeverActive match_info) False - -- NOINLINE +setInlinePragmaRuleMatchInfo prag info = prag { inl_rule = info } instance Outputable Activation where - ppr NeverActive = ptext (sLit "NEVER") - ppr AlwaysActive = ptext (sLit "ALWAYS") + ppr AlwaysActive = brackets (ptext (sLit "ALWAYS")) + ppr NeverActive = brackets (ptext (sLit "NEVER")) ppr (ActiveBefore n) = brackets (char '~' <> int n) ppr (ActiveAfter n) = brackets (int n) @@ -654,25 +716,20 @@ instance Outputable RuleMatchInfo where ppr FunLike = ptext (sLit "FUNLIKE") instance Outputable InlinePragma where - ppr (InlinePragma activation FunLike) - = ppr activation - ppr (InlinePragma activation match_info) - = ppr match_info <+> ppr activation - -instance Outputable InlineSpec where - ppr (Inline (InlinePragma act match_info) is_inline) - | is_inline = ptext (sLit "INLINE") - <+> ppr_match_info - <+> case act of - AlwaysActive -> empty - _ -> ppr act - | otherwise = ptext (sLit "NOINLINE") - <+> ppr_match_info - <+> case act of - NeverActive -> empty - _ -> ppr act - where - ppr_match_info = if isFunLike match_info then empty else ppr match_info + ppr (InlinePragma { inl_inline = inline, inl_act = activation + , inl_rule = info, inl_sat = mb_arity }) + = pp_inl_act (inline, activation) <+> pp_sat <+> pp_info + where + pp_inl_act (False, AlwaysActive) = empty -- defaultInlinePragma + pp_inl_act (False, NeverActive) = ptext (sLit "NOINLINE") + pp_inl_act (False, act) = ptext (sLit "NOINLINE") <> ppr act + pp_inl_act (True, AlwaysActive) = ptext (sLit "INLINE") + pp_inl_act (True, act) = ptext (sLit "INLINE") <> ppr act + + pp_sat | Just ar <- mb_arity = parens (ptext (sLit "sat-args=") <> int ar) + | otherwise = empty + pp_info | isFunLike info = empty + | otherwise = ppr info isActive :: CompilerPhase -> Activation -> Bool isActive _ NeverActive = False @@ -680,11 +737,15 @@ isActive _ AlwaysActive = True isActive p (ActiveAfter n) = p <= n isActive p (ActiveBefore n) = p > n -isNeverActive, isAlwaysActive :: Activation -> Bool +isNeverActive, isAlwaysActive, isEarlyActive :: Activation -> Bool isNeverActive NeverActive = True isNeverActive _ = False isAlwaysActive AlwaysActive = True isAlwaysActive _ = False + +isEarlyActive AlwaysActive = True +isEarlyActive (ActiveBefore {}) = True +isEarlyActive _ = False \end{code}