eb3110e0afa12736937f2bcb8dfd1339bad3a8fd
[ghc-hetmet.git] / ghc / compiler / simplCore / BinderInfo.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
3 %
4 %************************************************************************
5 %*                                                                      *
6 \section[BinderInfo]{Information attached to binders by SubstAnal}
7 %*                                                                      *
8 %************************************************************************
9
10 \begin{code}
11 module BinderInfo (
12         BinderInfo(..),
13         FunOrArg, DuplicationDanger, InsideSCC,  -- NB: all abstract (yay!)
14
15         addBinderInfo, orBinderInfo, andBinderInfo,
16
17         deadOccurrence, argOccurrence, funOccurrence, dangerousArgOcc, noBinderInfo,
18
19         markMany, markDangerousToDup, markInsideSCC,
20         getBinderInfoArity,
21         setBinderInfoArityToZero,
22
23         okToInline, isOneOcc, isOneFunOcc, isOneSafeFunOcc, isDeadOcc,
24
25         isFun, isDupDanger -- for Simon Marlow deforestation
26     ) where
27
28 #include "HsVersions.h"
29
30 import Util             ( panic )
31 import GlaExts          ( Int(..), (+#) )
32 import Outputable
33
34 \end{code}
35
36 The @BinderInfo@ describes how a variable is used in a given scope.
37
38 NOTE: With SCCs we have to be careful what we unfold! We don't want to
39 change the attribution of execution costs. If we decide to unfold
40 within an SCC we can tag the definition as @DontKeepBinder@.
41 Definitions tagged as @KeepBinder@ are discarded when we enter the
42 scope of an SCC.
43
44 \begin{code}
45 data BinderInfo
46   = DeadCode    -- Dead code; discard the binding.
47
48   | ManyOcc     -- Everything else besides DeadCode and OneOccs
49
50         !Int    -- number of arguments on stack when called; this is a minimum guarantee
51
52
53   | OneOcc      -- Just one occurrence (or one each in
54                 -- mutually-exclusive case alts).
55
56       !FunOrArg -- How it occurs
57
58       !DuplicationDanger
59
60       !InsideSCC
61
62       !Int      -- Number of mutually-exclusive case alternatives
63                 -- in which it occurs
64
65                 -- Note that we only worry about the case-alt counts
66                 -- if the OneOcc is substitutable -- that's the only
67                 -- time we *use* the info; we could be more clever for
68                 -- other cases if we really had to. (WDP/PS)
69
70       !Int      -- number of arguments on stack when called; minimum guarantee
71
72 -- In general, we are feel free to substitute unless
73 -- (a) is in an argument position (ArgOcc)
74 -- (b) is inside a lambda [or type lambda?] (DupDanger)
75 -- (c) is inside an SCC expression (InsideSCC)
76 -- (d) is in the RHS of a binding for a variable with an INLINE pragma
77 --      (because the RHS will be inlined regardless of its size)
78 --      [again, DupDanger]
79
80 data FunOrArg
81   = FunOcc      -- An occurrence in a function position
82   | ArgOcc      -- Other arg occurrence
83
84     -- When combining branches of a case, only report FunOcc if
85     -- both branches are FunOccs
86
87 data DuplicationDanger
88   = DupDanger   -- Inside a non-linear lambda (that is, a lambda which
89                 -- is sure to be instantiated only once), or inside
90                 -- the rhs of an INLINE-pragma'd thing.  Either way,
91                 -- substituting a redex for this occurrence is
92                 -- dangerous because it might duplicate work.
93
94   | NoDupDanger -- It's ok; substitution won't duplicate work.
95
96 data InsideSCC
97   = InsideSCC       -- Inside an SCC; so be careful when substituting.
98   | NotInsideSCC    -- It's ok.
99
100 noBinderInfo = ManyOcc 0        -- A non-committal value
101 \end{code}
102
103
104
105 \begin{code}
106 isOneOcc :: BinderInfo -> Bool
107 isOneOcc (OneOcc _ _ _ _ _) = True
108 isOneOcc other_bind         = False
109
110 isOneFunOcc :: BinderInfo -> Bool
111 isOneFunOcc (OneOcc FunOcc _ _ _ _) = True
112 isOneFunOcc other_bind              = False
113
114 isOneSafeFunOcc :: Bool -> BinderInfo -> Bool
115 isOneSafeFunOcc ok_to_dup (OneOcc FunOcc NoDupDanger NotInsideSCC n_alts _)
116   = ok_to_dup || n_alts <= 1
117 isOneSafeFunOcc ok_to_dup other_bind        = False
118
119 isDeadOcc :: BinderInfo -> Bool
120 isDeadOcc DeadCode = True
121 isDeadOcc other    = False
122
123 isFun :: FunOrArg -> Bool
124 isFun FunOcc = True
125 isFun _ = False
126
127 isDupDanger :: DuplicationDanger -> Bool
128 isDupDanger DupDanger = True
129 isDupDanger _ = False
130 \end{code}
131
132
133 \begin{code}
134 okToInline :: Bool              -- The thing is WHNF or bottom; 
135            -> Bool              -- It's small enough to duplicate the code
136            -> BinderInfo
137            -> Bool              -- True <=> inline it
138
139 -- A non-WHNF can be inlined if it doesn't occur inside a lambda,
140 -- and occurs exactly once or 
141 --     occurs once in each branch of a case and is small
142 okToInline False small_enough (OneOcc _ NoDupDanger _ n_alts _)
143   = n_alts <= 1 || small_enough
144
145 -- If the thing isn't a redex, there's no danger of duplicating work, 
146 -- so we can inline if it occurs once, or is small
147 okToInline True small_enough occ_info 
148  = one_occ || small_enough
149  where
150    one_occ = case occ_info of
151                 OneOcc _ _ _ n_alts _ -> n_alts <= 1
152                 other                 -> False
153
154 okToInline whnf_or_bot small_enough any_occ = False
155 \end{code}
156
157
158 Construction
159 ~~~~~~~~~~~~~
160 \begin{code}
161 deadOccurrence :: BinderInfo
162 deadOccurrence = DeadCode
163
164 argOccurrence, funOccurrence :: Int -> BinderInfo
165
166 funOccurrence = OneOcc FunOcc NoDupDanger NotInsideSCC 1
167 argOccurrence = OneOcc ArgOcc NoDupDanger NotInsideSCC 1
168
169 markMany, markDangerousToDup, markInsideSCC :: BinderInfo -> BinderInfo
170
171 markMany (OneOcc _ _ _ _ ar) = ManyOcc ar
172 markMany (ManyOcc ar)        = ManyOcc ar
173 markMany DeadCode            = panic "markMany"
174
175 markDangerousToDup (OneOcc posn _ in_scc n_alts ar)
176   = OneOcc posn DupDanger in_scc n_alts ar
177 markDangerousToDup other = other
178
179 dangerousArgOcc = OneOcc ArgOcc DupDanger NotInsideSCC 1 0
180
181 markInsideSCC (OneOcc posn dup_danger _ n_alts ar)
182   = OneOcc posn dup_danger InsideSCC n_alts ar
183 markInsideSCC other = other
184
185 addBinderInfo, orBinderInfo
186         :: BinderInfo -> BinderInfo -> BinderInfo
187
188 addBinderInfo DeadCode info2 = info2
189 addBinderInfo info1 DeadCode = info1
190 addBinderInfo info1 info2
191  = ManyOcc (min (getBinderInfoArity info1) (getBinderInfoArity info2))
192
193 -- (orBinderInfo orig new) is used in two situations:
194 -- First, when a variable whose occurrence info
195 --   is currently "orig" is bound to a variable whose occurrence info is "new"
196 --      eg  (\new -> e) orig
197 --   What we want to do is to *worsen* orig's info to take account of new's
198 --
199 -- Second, when combining occurrence info from branches of a case
200
201 orBinderInfo DeadCode info2 = info2
202 orBinderInfo info1 DeadCode = info1
203 orBinderInfo (OneOcc posn1 dup1 scc1 n_alts1 ar_1)
204              (OneOcc posn2 dup2 scc2 n_alts2 ar_2)
205   = let
206      posn = combine_posns posn1 posn2
207      scc  = combine_sccs  scc1  scc2
208      dup  = combine_dups  dup1  dup2
209      alts = n_alts1 + n_alts2
210      ar   = min ar_1 ar_2
211    in
212    OneOcc posn dup scc alts ar
213
214 orBinderInfo info1 info2
215  = ManyOcc (min (getBinderInfoArity info1) (getBinderInfoArity info2))
216
217 -- (andBinderInfo orig new) is used 
218 -- when completing a let-binding
219 --      let new = ...orig...
220 -- we compute the way orig occurs in (...orig...), and then use andBinderInfo
221 -- to worsen this info by the way new occurs in the let body; then we use
222 -- that to worsen orig's currently recorded occurrence info.
223
224 andBinderInfo DeadCode info2 = DeadCode
225 andBinderInfo info1 DeadCode = DeadCode
226 andBinderInfo (OneOcc posn1 dup1 scc1 n_alts1 ar_1)
227               (OneOcc posn2 dup2 scc2 n_alts2 ar_2)
228   = let
229        posn = combine_posns posn1 posn2
230        scc  = combine_sccs  scc1  scc2
231        dup  = combine_dups  dup1  dup2
232        alts = n_alts1 + n_alts2
233     in
234     OneOcc posn dup scc alts ar_1
235
236 andBinderInfo info1 info2 = ManyOcc (getBinderInfoArity info1)
237
238
239 combine_posns FunOcc FunOcc = FunOcc -- see comment at FunOrArg defn
240 combine_posns _          _  = ArgOcc
241
242 combine_dups DupDanger _ = DupDanger    -- Too paranoid?? ToDo
243 combine_dups _ DupDanger = DupDanger
244 combine_dups _ _         = NoDupDanger
245
246 combine_sccs InsideSCC _ = InsideSCC    -- Too paranoid?? ToDo
247 combine_sccs _ InsideSCC = InsideSCC
248 combine_sccs _ _             = NotInsideSCC
249
250 setBinderInfoArityToZero :: BinderInfo -> BinderInfo
251 setBinderInfoArityToZero DeadCode    = DeadCode
252 setBinderInfoArityToZero (ManyOcc _) = ManyOcc 0
253 setBinderInfoArityToZero (OneOcc fa dd sc i _) = OneOcc fa dd sc i 0
254 \end{code}
255
256 \begin{code}
257 getBinderInfoArity (DeadCode) = 0
258 getBinderInfoArity (ManyOcc i) = i
259 getBinderInfoArity (OneOcc _ _ _ _ i) = i
260 \end{code}
261
262 \begin{code}
263 instance Outputable BinderInfo where
264   ppr DeadCode     = ptext SLIT("Dead")
265   ppr (ManyOcc ar) = hcat [ ptext SLIT("Many-"), int ar ]
266   ppr (OneOcc posn dup_danger in_scc n_alts ar)
267     = hcat [ ptext SLIT("One-"), pp_posn posn, char '-', pp_danger dup_danger,
268                   char '-', pp_scc in_scc,  char '-', int n_alts,
269                   char '-', int ar ]
270     where
271       pp_posn FunOcc = ptext SLIT("fun")
272       pp_posn ArgOcc = ptext SLIT("arg")
273
274       pp_danger DupDanger   = ptext SLIT("*dup*")
275       pp_danger NoDupDanger = ptext SLIT("nodup")
276
277       pp_scc InsideSCC    = ptext SLIT("*SCC*")
278       pp_scc NotInsideSCC = ptext SLIT("noscc")
279 \end{code}
280