Rollback INLINE patches
[ghc-hetmet.git] / compiler / coreSyn / CoreSyn.lhs
index 25d2cdb..79e25a2 100644 (file)
@@ -41,10 +41,9 @@ module CoreSyn (
        noUnfolding, evaldUnfolding, mkOtherCon,
        
        -- ** Predicates and deconstruction on 'Unfolding'
-       unfoldingTemplate, setUnfoldingTemplate,
-       maybeUnfoldingTemplate, otherCons, 
+       unfoldingTemplate, maybeUnfoldingTemplate, otherCons, 
        isValueUnfolding, isEvaldUnfolding, isCheapUnfolding, isCompulsoryUnfolding,
-       isInlineRule, isClosedUnfolding, hasSomeUnfolding, canUnfold, neverUnfoldGuidance,
+       hasUnfolding, hasSomeUnfolding, neverUnfold,
 
        -- * Strictness
        seqExpr, seqExprs, seqUnfolding, 
@@ -272,7 +271,21 @@ See #type_let#
 -- | Allows attaching extra information to points in expressions rather than e.g. identifiers.
 data Note
   = SCC CostCentre      -- ^ A cost centre annotation for profiling
+
+  | InlineMe           -- ^ Instructs the core simplifer to treat the enclosed expression
+                       -- as very small, and inline it at its call sites
+
   | CoreNote String     -- ^ A generic core annotation, propagated but not used by GHC
+
+-- NOTE: we also treat expressions wrapped in InlineMe as
+-- 'cheap' and 'dupable' (in the sense of exprIsCheap, exprIsDupable)
+-- What this means is that we obediently inline even things that don't
+-- look like valuse.  This is sometimes important:
+--     {-# INLINE f #-}
+--     f = g . h
+-- Here, f looks like a redex, and we aren't going to inline (.) because it's
+-- inside an INLINE, so it'll stay looking like a redex.  Nevertheless, we 
+-- should inline f even inside lambdas.  In effect, we should trust the programmer.
 \end{code}
 
 
@@ -391,73 +404,45 @@ data Unfolding
                                --
                                -- Here, @f@ gets an @OtherCon []@ unfolding.
 
-  | CompulsoryUnfolding {      -- There is /no original definition/, so you'd better unfold.
-       uf_tmpl :: CoreExpr     -- The unfolding is guaranteed to have no free variables
-    }                          -- so no need to think about it during dependency analysis
-                               
-  | InlineRule {               -- The function has an INLINE pragma, with the specified (original) RHS
-                               -- (The inline phase, if any, is in the InlinePragInfo for this Id.)
-                               -- Inline when (a) applied to at least this number of args                              
-                               --             (b) if there is something interesting about args or context
-       uf_tmpl  :: CoreExpr,           -- The *original* RHS; occurrence info is correct
-                                       -- (The actual RHS of the function may be different by now,
-                                       -- but what we inline is still the original RHS (kept in the InlineRule).)
-       uf_is_top :: Bool,
-
-       uf_arity    :: Arity,           -- Don't inline unless applied to this number of *value* args
-       uf_is_value :: Bool,            -- True <=> exprIsHNF is true; save to discard a `seq`                  
-       uf_worker   :: Maybe Id         -- Just wrk_id <=> this unfolding is a the wrapper in a worker/wrapper
-                                       --                 split from the strictness analyser
-                                       --      Used to abbreviate the uf_tmpl in interface files
-                                       --        In the Just case, interface files don't actually 
-                                       --        need to contain the RHS; it can be derived from
-                                       --        the strictness info
-                                       --      Also used in CoreUnfold to guide inlining decisions
-    }
+  | CompulsoryUnfolding CoreExpr       -- ^ There is /no original definition/,
+                                       -- so you'd better unfold.
 
-  | CoreUnfolding {            -- An unfolding for an Id with no pragma, or perhaps a NOINLINE pragma
-                               -- (For NOINLINE, the phase, if any, is in the InlinePragInfo for this Id.)
-       uf_tmpl     :: CoreExpr,        -- Template; binder-info is correct
-       uf_is_top   :: Bool,            -- True <=> top level binding
-       uf_is_value :: Bool,            -- exprIsHNF template (cached); it is ok to discard a `seq` on
-                                       --      this variable
-       uf_is_cheap :: Bool,            -- True <=> doesn't waste (much) work to expand inside an inlining
-                                       --      Basically it's exprIsCheap
-       uf_guidance :: UnfoldingGuidance        -- Tells about the *size* of the template.
-    }
+  | CoreUnfolding
+               CoreExpr
+               Bool
+               Bool
+               Bool
+               UnfoldingGuidance
   -- ^ An unfolding with redundant cached information. Parameters:
   --
-  --  uf_tmpl: Template used to perform unfolding; binder-info is correct
+  --  1) Template used to perform unfolding; binder-info is correct
   --
-  --  uf_is_top: Is this a top level binding?
+  --  2) Is this a top level binding?
   --
-  --  uf_is_valiue: 'exprIsHNF' template (cached); it is ok to discard a 'seq' on
+  --  3) 'exprIsHNF' template (cached); it is ok to discard a 'seq' on
   --     this variable
   --
-  --  uf_is_cheap:  Does this waste only a little work if we expand it inside an inlining?
+  --  4) Does this waste only a little work if we expand it inside an inlining?
   --     Basically this is a cached version of 'exprIsCheap'
   --
-  --  uf_guidance:  Tells us about the /size/ of the unfolding template
+  --  5) Tells us about the /size/ of the unfolding template
 
-------------------------------------------------
--- | 'UnfoldingGuidance' says when unfolding should take place
+-- | When unfolding should take place
 data UnfoldingGuidance
   = UnfoldNever
-  | UnfoldIfGoodArgs {
-      ug_arity :: Arity,  -- "n" value args
+  | UnfoldIfGoodArgs   Int     -- and "n" value args
 
-      ug_args ::  [Int],  -- Discount if the argument is evaluated.
-                         -- (i.e., a simplification will definitely
-                         -- be possible).  One elt of the list per *value* arg.
+                       [Int]   -- Discount if the argument is evaluated.
+                               -- (i.e., a simplification will definitely
+                               -- be possible).  One elt of the list per *value* arg.
 
-      ug_size :: Int,    -- The "size" of the unfolding; to be elaborated
-                         -- later. ToDo
+                       Int     -- The "size" of the unfolding; to be elaborated
+                               -- later. ToDo
 
-      ug_res :: Int      -- Scrutinee discount: the discount to substract if the thing is in
-    }                    -- a context (case (thing args) of ...),
-                         -- (where there are the right number of arguments.)
+                       Int     -- Scrutinee discount: the discount to substract if the thing is in
+                               -- a context (case (thing args) of ...),
+                               -- (where there are the right number of arguments.)
 
-------------------------------------------------
 noUnfolding :: Unfolding
 -- ^ There is no known 'Unfolding'
 evaldUnfolding :: Unfolding
@@ -470,8 +455,7 @@ mkOtherCon :: [AltCon] -> Unfolding
 mkOtherCon = OtherCon
 
 seqUnfolding :: Unfolding -> ()
-seqUnfolding (CoreUnfolding { uf_tmpl = e, uf_is_top = top, 
-               uf_is_value = b1, uf_is_cheap = b2, uf_guidance = g})
+seqUnfolding (CoreUnfolding e top b1 b2 g)
   = seqExpr e `seq` top `seq` b1 `seq` b2 `seq` seqGuidance g
 seqUnfolding _ = ()
 
@@ -483,17 +467,15 @@ seqGuidance _                           = ()
 \begin{code}
 -- | Retrieves the template of an unfolding: panics if none is known
 unfoldingTemplate :: Unfolding -> CoreExpr
-unfoldingTemplate = uf_tmpl
-
-setUnfoldingTemplate :: Unfolding -> CoreExpr -> Unfolding
-setUnfoldingTemplate unf rhs = unf { uf_tmpl = rhs }
+unfoldingTemplate (CoreUnfolding expr _ _ _ _) = expr
+unfoldingTemplate (CompulsoryUnfolding expr)   = expr
+unfoldingTemplate _ = panic "getUnfoldingTemplate"
 
 -- | Retrieves the template of an unfolding if possible
 maybeUnfoldingTemplate :: Unfolding -> Maybe CoreExpr
-maybeUnfoldingTemplate (CoreUnfolding { uf_tmpl = expr })       = Just expr
-maybeUnfoldingTemplate (CompulsoryUnfolding { uf_tmpl = expr }) = Just expr
-maybeUnfoldingTemplate (InlineRule { uf_tmpl = expr })          = Just expr
-maybeUnfoldingTemplate _                                       = Nothing
+maybeUnfoldingTemplate (CoreUnfolding expr _ _ _ _) = Just expr
+maybeUnfoldingTemplate (CompulsoryUnfolding expr)   = Just expr
+maybeUnfoldingTemplate _                            = Nothing
 
 -- | The constructors that the unfolding could never be: 
 -- returns @[]@ if no information is available
@@ -504,53 +486,45 @@ otherCons _               = []
 -- | Determines if it is certainly the case that the unfolding will
 -- yield a value (something in HNF): returns @False@ if unsure
 isValueUnfolding :: Unfolding -> Bool
-       -- Returns False for OtherCon
-isValueUnfolding (CoreUnfolding   { uf_is_value = is_evald }) = is_evald
-isValueUnfolding (InlineRule { uf_is_value = is_evald })      = is_evald
-isValueUnfolding _                                           = False
+isValueUnfolding (CoreUnfolding _ _ is_evald _ _) = is_evald
+isValueUnfolding _                                = False
 
 -- | Determines if it possibly the case that the unfolding will
 -- yield a value. Unlike 'isValueUnfolding' it returns @True@
 -- for 'OtherCon'
 isEvaldUnfolding :: Unfolding -> Bool
-       -- Returns True for OtherCon
-isEvaldUnfolding (OtherCon _)                                = True
-isEvaldUnfolding (CoreUnfolding   { uf_is_value = is_evald }) = is_evald
-isEvaldUnfolding (InlineRule { uf_is_value = is_evald })      = is_evald
-isEvaldUnfolding _                                            = False
+isEvaldUnfolding (OtherCon _)                    = True
+isEvaldUnfolding (CoreUnfolding _ _ is_evald _ _) = is_evald
+isEvaldUnfolding _                                = False
 
 -- | Is the thing we will unfold into certainly cheap?
 isCheapUnfolding :: Unfolding -> Bool
-isCheapUnfolding (CoreUnfolding { uf_is_cheap = is_cheap }) = is_cheap
-isCheapUnfolding _                                          = False
-
-isInlineRule :: Unfolding -> Bool
-isInlineRule (InlineRule {}) = True
-isInlineRule _              = False
+isCheapUnfolding (CoreUnfolding _ _ _ is_cheap _) = is_cheap
+isCheapUnfolding _                                = False
 
 -- | Must this unfolding happen for the code to be executable?
 isCompulsoryUnfolding :: Unfolding -> Bool
-isCompulsoryUnfolding (CompulsoryUnfolding {}) = True
+isCompulsoryUnfolding (CompulsoryUnfolding _) = True
 isCompulsoryUnfolding _                       = False
 
-isClosedUnfolding :: Unfolding -> Bool         -- No free variables
-isClosedUnfolding (CoreUnfolding {})   = False
-isClosedUnfolding (InlineRule {}) = False
-isClosedUnfolding _               = True
+-- | Do we have an available or compulsory unfolding?
+hasUnfolding :: Unfolding -> Bool
+hasUnfolding (CoreUnfolding _ _ _ _ _) = True
+hasUnfolding (CompulsoryUnfolding _)   = True
+hasUnfolding _                         = False
 
 -- | Only returns False if there is no unfolding information available at all
 hasSomeUnfolding :: Unfolding -> Bool
 hasSomeUnfolding NoUnfolding = False
 hasSomeUnfolding _           = True
 
-neverUnfoldGuidance :: UnfoldingGuidance -> Bool
-neverUnfoldGuidance UnfoldNever = True
-neverUnfoldGuidance _           = False
-
-canUnfold :: Unfolding -> Bool
-canUnfold (InlineRule {})                    = True
-canUnfold (CoreUnfolding { uf_guidance = g }) = not (neverUnfoldGuidance g)
-canUnfold _                                  = False
+-- | Similar to @not . hasUnfolding@, but also returns @True@
+-- if it has an unfolding that says it should never occur
+neverUnfold :: Unfolding -> Bool
+neverUnfold NoUnfolding                                = True
+neverUnfold (OtherCon _)                       = True
+neverUnfold (CoreUnfolding _ _ _ _ UnfoldNever) = True
+neverUnfold _                                   = False
 \end{code}