diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2018-07-30 13:43:56 +0100 |
---|---|---|
committer | Simon Peyton Jones <simonpj@microsoft.com> | 2018-07-31 13:19:43 +0100 |
commit | 2110738b280543698407924a16ac92b6d804dc36 (patch) | |
tree | f5a5bbb377b4554e99eae18a146894908d88f9d5 /compiler/specialise | |
parent | 56590db07a776ce81eb89d4a4d86bd0f953fb44e (diff) | |
download | haskell-2110738b280543698407924a16ac92b6d804dc36.tar.gz |
Don't inline functions with RULES too early
Trac #15445 showed that a function with an automatically
generated specialisation RULE coudl be inlined before the
RULE had a chance to fire.
This patch attaches a NOINLINE[2] activation to the Id, to
stop this happening.
Diffstat (limited to 'compiler/specialise')
-rw-r--r-- | compiler/specialise/Rules.hs | 49 |
1 files changed, 42 insertions, 7 deletions
diff --git a/compiler/specialise/Rules.hs b/compiler/specialise/Rules.hs index 3380d02f99..850dba64cd 100644 --- a/compiler/specialise/Rules.hs +++ b/compiler/specialise/Rules.hs @@ -46,7 +46,8 @@ import TysWiredIn ( anyTypeOfKind ) import Coercion import CoreTidy ( tidyRules ) import Id -import IdInfo ( RuleInfo( RuleInfo ) ) +import IdInfo ( IdInfo( ruleInfo, inlinePragInfo ) + , RuleInfo( RuleInfo ), setRuleInfo, setInlinePragInfo ) import Var import VarEnv import VarSet @@ -55,7 +56,7 @@ import NameSet import NameEnv import UniqFM import Unify ( ruleMatchTyKiX ) -import BasicTypes ( Activation, CompilerPhase, isActive, pprRuleName ) +import BasicTypes import DynFlags ( DynFlags ) import Outputable import FastString @@ -290,11 +291,23 @@ addRuleInfo (RuleInfo rs1 fvs1) (RuleInfo rs2 fvs2) = RuleInfo (rs1 ++ rs2) (fvs1 `unionDVarSet` fvs2) addIdSpecialisations :: Id -> [CoreRule] -> Id -addIdSpecialisations id [] - = id +-- See Note [Adding specialisations to an Id] addIdSpecialisations id rules - = setIdSpecialisation id $ - extendRuleInfo (idSpecialisation id) rules + | null rules + = id + | otherwise + = modifyIdInfo (add_rules . add_activation) id + where + add_rules, add_activation :: IdInfo -> IdInfo + add_rules info = info `setRuleInfo` extendRuleInfo (ruleInfo info) rules + add_activation info + | AlwaysActive <- inlinePragmaActivation inl_prag + = info `setInlinePragInfo` inl_prag' + | otherwise + = info + where + inl_prag = inlinePragInfo info + inl_prag' = inl_prag `setInlinePragmaActivation` activeAfterInitial -- | Gather all the rules for locally bound identifiers from the supplied bindings rulesOfBinds :: [CoreBind] -> [CoreRule] @@ -312,7 +325,29 @@ ruleIsVisible _ BuiltinRule{} = True ruleIsVisible vis_orphs Rule { ru_orphan = orph, ru_origin = origin } = notOrphan orph || origin `elemModuleSet` vis_orphs -{- +{- Note [Adding specialisations to an Id] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Suppose (Trac #15445) we have + f,g :: Num a => a -> a + f x = ...f (x-1)..... + g y = ...g (y-1) .... +and we make some specialisations of 'g', either automatically, or via +a SPECIALISE pragma. Then CSE kicks in and notices that the RHSs of +'f' and 'g' are identical, so we get + f x = ...f (x-1)... + g = f + {-# RULES g @Int _ = $sg #-} + +Now there is terrible danger that, in an importing module, we'll inline +'g' before we have a chance to run its specialisation! + +This is admittedly a bit of an exotic case; but in general with RULES +we want to delay inlining to give the rule a chance to fire. So we +attach a NOINLINE[2] activation to it, to ensure it's not inlined +right away. c.f. other uses of activeAfterInitial in the compiler +e.g. Note [Wrapper activation] in WorkWrap, and + Note [Activation for data constructor wrappers] in MkId + Note [Where rules are found] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The rules for an Id come from two places: |