2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
4 %************************************************************************
6 \section[BinderInfo]{Information attached to binders by SubstAnal}
8 %************************************************************************
11 #include "HsVersions.h"
15 FunOrArg, DuplicationDanger, InsideSCC, -- NB: all abstract (yay!)
17 addBinderInfo, orBinderInfo, andBinderInfo,
19 deadOccurrence, argOccurrence, funOccurrence, dangerousArgOcc, noBinderInfo,
21 markMany, markDangerousToDup, markInsideSCC,
23 setBinderInfoArityToZero,
25 okToInline, isOneOcc, isOneFunOcc, isOneSafeFunOcc, isDeadOcc,
27 isFun, isDupDanger -- for Simon Marlow deforestation
34 #if __GLASGOW_HASKELL__ >= 202
40 The @BinderInfo@ describes how a variable is used in a given scope.
42 NOTE: With SCCs we have to be careful what we unfold! We don't want to
43 change the attribution of execution costs. If we decide to unfold
44 within an SCC we can tag the definition as @DontKeepBinder@.
45 Definitions tagged as @KeepBinder@ are discarded when we enter the
50 = DeadCode -- Dead code; discard the binding.
52 | ManyOcc -- Everything else besides DeadCode and OneOccs
54 Int -- number of arguments on stack when called; this is a minimum guarantee
57 | OneOcc -- Just one occurrence (or one each in
58 -- mutually-exclusive case alts).
60 FunOrArg -- How it occurs
66 Int -- Number of mutually-exclusive case alternatives
69 -- Note that we only worry about the case-alt counts
70 -- if the OneOcc is substitutable -- that's the only
71 -- time we *use* the info; we could be more clever for
72 -- other cases if we really had to. (WDP/PS)
74 Int -- number of arguments on stack when called; minimum guarantee
76 -- In general, we are feel free to substitute unless
77 -- (a) is in an argument position (ArgOcc)
78 -- (b) is inside a lambda [or type lambda?] (DupDanger)
79 -- (c) is inside an SCC expression (InsideSCC)
80 -- (d) is in the RHS of a binding for a variable with an INLINE pragma
81 -- (because the RHS will be inlined regardless of its size)
85 = FunOcc -- An occurrence in a function position
86 | ArgOcc -- Other arg occurrence
88 -- When combining branches of a case, only report FunOcc if
89 -- both branches are FunOccs
91 data DuplicationDanger
92 = DupDanger -- Inside a non-linear lambda (that is, a lambda which
93 -- is sure to be instantiated only once), or inside
94 -- the rhs of an INLINE-pragma'd thing. Either way,
95 -- substituting a redex for this occurrence is
96 -- dangerous because it might duplicate work.
98 | NoDupDanger -- It's ok; substitution won't duplicate work.
101 = InsideSCC -- Inside an SCC; so be careful when substituting.
102 | NotInsideSCC -- It's ok.
104 noBinderInfo = ManyOcc 0 -- A non-committal value
110 isOneOcc :: BinderInfo -> Bool
111 isOneOcc (OneOcc _ _ _ _ _) = True
112 isOneOcc other_bind = False
114 isOneFunOcc :: BinderInfo -> Bool
115 isOneFunOcc (OneOcc FunOcc _ _ _ _) = True
116 isOneFunOcc other_bind = False
118 isOneSafeFunOcc :: Bool -> BinderInfo -> Bool
119 isOneSafeFunOcc ok_to_dup (OneOcc FunOcc NoDupDanger NotInsideSCC n_alts _)
120 = ok_to_dup || n_alts <= 1
121 isOneSafeFunOcc ok_to_dup other_bind = False
123 isDeadOcc :: BinderInfo -> Bool
124 isDeadOcc DeadCode = True
125 isDeadOcc other = False
127 isFun :: FunOrArg -> Bool
131 isDupDanger :: DuplicationDanger -> Bool
132 isDupDanger DupDanger = True
133 isDupDanger _ = False
138 okToInline :: Bool -- The thing is WHNF or bottom;
139 -> Bool -- It's small enough to duplicate the code
141 -> Bool -- True <=> inline it
143 -- A non-WHNF can be inlined if it doesn't occur inside a lambda,
144 -- and occurs exactly once or
145 -- occurs once in each branch of a case and is small
146 okToInline False small_enough (OneOcc _ NoDupDanger _ n_alts _)
147 = n_alts <= 1 || small_enough
149 -- If the thing isn't a redex, there's no danger of duplicating work,
150 -- so we can inline if it occurs once, or is small
151 okToInline True small_enough occ_info
152 = small_enough || one_occ
154 one_occ = case occ_info of
155 OneOcc _ _ _ n_alts _ -> n_alts <= 1
158 okToInline whnf_or_bot small_enough any_occ = False
165 deadOccurrence :: BinderInfo
166 deadOccurrence = DeadCode
168 argOccurrence, funOccurrence :: Int -> BinderInfo
170 funOccurrence = OneOcc FunOcc NoDupDanger NotInsideSCC 1
171 argOccurrence = OneOcc ArgOcc NoDupDanger NotInsideSCC 1
173 markMany, markDangerousToDup, markInsideSCC :: BinderInfo -> BinderInfo
175 markMany (OneOcc _ _ _ _ ar) = ManyOcc ar
176 markMany (ManyOcc ar) = ManyOcc ar
177 markMany DeadCode = panic "markMany"
179 markDangerousToDup (OneOcc posn _ in_scc n_alts ar)
180 = OneOcc posn DupDanger in_scc n_alts ar
181 markDangerousToDup other = other
183 dangerousArgOcc = OneOcc ArgOcc DupDanger NotInsideSCC 1 0
185 markInsideSCC (OneOcc posn dup_danger _ n_alts ar)
186 = OneOcc posn dup_danger InsideSCC n_alts ar
187 markInsideSCC other = other
189 addBinderInfo, orBinderInfo
190 :: BinderInfo -> BinderInfo -> BinderInfo
192 addBinderInfo DeadCode info2 = info2
193 addBinderInfo info1 DeadCode = info1
194 addBinderInfo info1 info2
195 = case (min (getBinderInfoArity info1) (getBinderInfoArity info2)) of
196 (I# i#) -> ManyOcc (I# i#)
197 -- ManyOcc min (getBinderInfoArity info1) (getBinderInfoArity info2))
199 -- (orBinderInfo orig new) is used when combining occurrence
200 -- info from branches of a case
202 orBinderInfo DeadCode info2 = info2
203 orBinderInfo info1 DeadCode = info1
204 orBinderInfo (OneOcc posn1 dup1 scc1 n_alts1 ar_1)
205 (OneOcc posn2 dup2 scc2 n_alts2 ar_2)
207 -- Seriously maligned in order to make it stricter,
208 -- let's hope it is worth it..
209 posn = combine_posns posn1 posn2
210 scc = combine_sccs scc1 scc2
211 dup = combine_dups dup1 dup2
212 alts = n_alts1 + n_alts2
216 cont1 = case scc of { InsideSCC -> cont2; _ -> cont2 }
217 cont2 = case dup of { DupDanger -> cont3; _ -> cont3 }
218 cont3 = case alts of { (I# 0#) -> cont4; _ -> cont4 }
219 cont4 = case ar of { (I# 0#) -> cont5; _ -> cont5 }
220 cont5 = OneOcc posn dup scc alts ar
222 case posn of { FunOcc -> cont1; _ -> cont1 }
223 orBinderInfo info1 info2
224 = case (min (getBinderInfoArity info1) (getBinderInfoArity info2)) of
225 (I# i#) -> ManyOcc (I# i#)
227 -- (andBinderInfo orig new) is used in two situations:
228 -- First, when a variable whose occurrence info
229 -- is currently "orig" is bound to a variable whose occurrence info is "new"
230 -- eg (\new -> e) orig
231 -- What we want to do is to *worsen* orig's info to take account of new's
233 -- second, when completing a let-binding
234 -- let new = ...orig...
235 -- we compute the way orig occurs in (...orig...), and then use orBinderInfo
236 -- to worsen this info by the way new occurs in the let body; then we use
237 -- that to worsen orig's currently recorded occurrence info.
239 andBinderInfo DeadCode info2 = DeadCode
240 andBinderInfo info1 DeadCode = DeadCode
241 andBinderInfo (OneOcc posn1 dup1 scc1 (I# n_alts1#) (I# ar_1#))
242 (OneOcc posn2 dup2 scc2 (I# n_alts2#) ar_2)
244 -- Perversly maligned in order to make it stricter.
245 posn = combine_posns posn1 posn2
246 scc = combine_sccs scc1 scc2
247 dup = combine_dups dup1 dup2
248 alts = I# (n_alts1# +# n_alts2#)
251 cont1 = case scc of { InsideSCC -> cont2; _ -> cont2 }
252 cont2 = case dup of { DupDanger -> cont3; _ -> cont3 }
253 cont3 = case alts of { (I# 0#) -> cont4; _ -> cont4 }
254 cont4 = OneOcc posn dup scc alts (I# ar_1#)
256 case posn of {FunOcc -> cont1; _ -> cont1}
258 andBinderInfo info1 info2 =
259 case getBinderInfoArity info1 of
260 (I# i#) -> ManyOcc (I# i#)
261 --ManyOcc (getBinderInfoArity info1)
264 combine_posns FunOcc FunOcc = FunOcc -- see comment at FunOrArg defn
265 combine_posns _ _ = ArgOcc
267 combine_dups DupDanger _ = DupDanger -- Too paranoid?? ToDo
268 combine_dups _ DupDanger = DupDanger
269 combine_dups _ _ = NoDupDanger
271 combine_sccs InsideSCC _ = InsideSCC -- Too paranoid?? ToDo
272 combine_sccs _ InsideSCC = InsideSCC
273 combine_sccs _ _ = NotInsideSCC
275 setBinderInfoArityToZero :: BinderInfo -> BinderInfo
276 setBinderInfoArityToZero DeadCode = DeadCode
277 setBinderInfoArityToZero (ManyOcc _) = ManyOcc 0
278 setBinderInfoArityToZero (OneOcc fa dd sc i _) = OneOcc fa dd sc i 0
282 getBinderInfoArity (DeadCode) = 0
283 getBinderInfoArity (ManyOcc i) = i
284 getBinderInfoArity (OneOcc _ _ _ _ i) = i
288 instance Outputable BinderInfo where
289 ppr sty DeadCode = ptext SLIT("Dead")
290 ppr sty (ManyOcc ar) = hcat [ ptext SLIT("Many-"), int ar ]
291 ppr sty (OneOcc posn dup_danger in_scc n_alts ar)
292 = hcat [ ptext SLIT("One-"), pp_posn posn, char '-', pp_danger dup_danger,
293 char '-', pp_scc in_scc, char '-', int n_alts,
296 pp_posn FunOcc = ptext SLIT("fun")
297 pp_posn ArgOcc = ptext SLIT("arg")
299 pp_danger DupDanger = ptext SLIT("*dup*")
300 pp_danger NoDupDanger = ptext SLIT("nodup")
302 pp_scc InsideSCC = ptext SLIT("*SCC*")
303 pp_scc NotInsideSCC = ptext SLIT("noscc")