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 argOccurrence, funOccurrence, dangerousArgOcc, noBinderInfo,
20 markMany, markDangerousToDup, markInsideSCC,
22 setBinderInfoArityToZero,
24 inlineUnconditionally, isFun, isDupDanger -- for Simon Marlow deforestation
31 #if __GLASGOW_HASKELL__ >= 202
37 The @BinderInfo@ describes how a variable is used in a given scope.
39 NOTE: With SCCs we have to be careful what we unfold! We don't want to
40 change the attribution of execution costs. If we decide to unfold
41 within an SCC we can tag the definition as @DontKeepBinder@.
42 Definitions tagged as @KeepBinder@ are discarded when we enter the
47 = DeadCode -- Dead code; discard the binding.
49 | ManyOcc -- Everything else besides DeadCode and OneOccs
51 Int -- number of arguments on stack when called; this is a minimum guarantee
54 | OneOcc -- Just one occurrence (or one each in
55 -- mutually-exclusive case alts).
57 FunOrArg -- How it occurs
63 Int -- Number of mutually-exclusive case alternatives
66 -- Note that we only worry about the case-alt counts
67 -- if the OneOcc is substitutable -- that's the only
68 -- time we *use* the info; we could be more clever for
69 -- other cases if we really had to. (WDP/PS)
71 Int -- number of arguments on stack when called; minimum guarantee
73 -- In general, we are feel free to substitute unless
74 -- (a) is in an argument position (ArgOcc)
75 -- (b) is inside a lambda [or type lambda?] (DupDanger)
76 -- (c) is inside an SCC expression (InsideSCC)
77 -- (d) is in the RHS of a binding for a variable with an INLINE pragma
78 -- (because the RHS will be inlined regardless of its size)
82 = FunOcc -- An occurrence in a function position
83 | ArgOcc -- Other arg occurrence
85 -- When combining branches of a case, only report FunOcc if
86 -- both branches are FunOccs
88 data DuplicationDanger
89 = DupDanger -- Inside a non-linear lambda (that is, a lambda which
90 -- is sure to be instantiated only once), or inside
91 -- the rhs of an INLINE-pragma'd thing. Either way,
92 -- substituting a redex for this occurrence is
93 -- dangerous because it might duplicate work.
95 | NoDupDanger -- It's ok; substitution won't duplicate work.
98 = InsideSCC -- Inside an SCC; so be careful when substituting.
99 | NotInsideSCC -- It's ok.
101 noBinderInfo = ManyOcc 0 -- A non-committal value
107 isFun :: FunOrArg -> Bool
111 isDupDanger :: DuplicationDanger -> Bool
112 isDupDanger DupDanger = True
113 isDupDanger _ = False
116 @inlineUnconditionally@ decides whether a let-bound thing can
117 definitely be inlined.
120 inlineUnconditionally :: Bool -> BinderInfo -> Bool
122 --inlineUnconditionally ok_to_dup DeadCode = True
123 inlineUnconditionally ok_to_dup (OneOcc FunOcc NoDupDanger NotInsideSCC n_alt_occs _)
124 = n_alt_occs <= 1 || ok_to_dup
125 -- We [i.e., Patrick] don't mind the code explosion,
126 -- though. We could have a flag to limit the
127 -- damage, e.g., limit to M alternatives.
129 inlineUnconditionally _ _ = False
136 argOccurrence, funOccurrence :: Int -> BinderInfo
138 funOccurrence = OneOcc FunOcc NoDupDanger NotInsideSCC 1
139 argOccurrence = OneOcc ArgOcc NoDupDanger NotInsideSCC 1
141 markMany, markDangerousToDup, markInsideSCC :: BinderInfo -> BinderInfo
143 markMany (OneOcc _ _ _ _ ar) = ManyOcc ar
144 markMany (ManyOcc ar) = ManyOcc ar
145 markMany DeadCode = panic "markMany"
147 markDangerousToDup (OneOcc posn _ in_scc n_alts ar)
148 = OneOcc posn DupDanger in_scc n_alts ar
149 markDangerousToDup other = other
151 dangerousArgOcc = OneOcc ArgOcc DupDanger NotInsideSCC 1 0
153 markInsideSCC (OneOcc posn dup_danger _ n_alts ar)
154 = OneOcc posn dup_danger InsideSCC n_alts ar
155 markInsideSCC other = other
157 addBinderInfo, orBinderInfo
158 :: BinderInfo -> BinderInfo -> BinderInfo
160 addBinderInfo DeadCode info2 = info2
161 addBinderInfo info1 DeadCode = info1
162 addBinderInfo info1 info2
163 = case (min (getBinderInfoArity info1) (getBinderInfoArity info2)) of
164 (I# i#) -> ManyOcc (I# i#)
165 -- ManyOcc min (getBinderInfoArity info1) (getBinderInfoArity info2))
167 -- (orBinderInfo orig new) is used when combining occurrence
168 -- info from branches of a case
170 orBinderInfo DeadCode info2 = info2
171 orBinderInfo info1 DeadCode = info1
172 orBinderInfo (OneOcc posn1 dup1 scc1 n_alts1 ar_1)
173 (OneOcc posn2 dup2 scc2 n_alts2 ar_2)
175 -- Seriously maligned in order to make it stricter,
176 -- let's hope it is worth it..
177 posn = combine_posns posn1 posn2
178 scc = combine_sccs scc1 scc2
179 dup = combine_dups dup1 dup2
180 alts = n_alts1 + n_alts2
184 cont1 = case scc of { InsideSCC -> cont2; _ -> cont2 }
185 cont2 = case dup of { DupDanger -> cont3; _ -> cont3 }
186 cont3 = case alts of { (I# 0#) -> cont4; _ -> cont4 }
187 cont4 = case ar of { (I# 0#) -> cont5; _ -> cont5 }
188 cont5 = OneOcc posn dup scc alts ar
190 case posn of { FunOcc -> cont1; _ -> cont1 }
191 orBinderInfo info1 info2
192 = case (min (getBinderInfoArity info1) (getBinderInfoArity info2)) of
193 (I# i#) -> ManyOcc (I# i#)
195 -- (andBinderInfo orig new) is used in two situations:
196 -- First, when a variable whose occurrence info
197 -- is currently "orig" is bound to a variable whose occurrence info is "new"
198 -- eg (\new -> e) orig
199 -- What we want to do is to *worsen* orig's info to take account of new's
201 -- second, when completing a let-binding
202 -- let new = ...orig...
203 -- we compute the way orig occurs in (...orig...), and then use orBinderInfo
204 -- to worsen this info by the way new occurs in the let body; then we use
205 -- that to worsen orig's currently recorded occurrence info.
207 andBinderInfo DeadCode info2 = DeadCode
208 andBinderInfo info1 DeadCode = DeadCode
209 andBinderInfo (OneOcc posn1 dup1 scc1 (I# n_alts1#) (I# ar_1#))
210 (OneOcc posn2 dup2 scc2 (I# n_alts2#) ar_2)
212 -- Perversly maligned in order to make it stricter.
213 posn = combine_posns posn1 posn2
214 scc = combine_sccs scc1 scc2
215 dup = combine_dups dup1 dup2
216 alts = I# (n_alts1# +# n_alts2#)
219 cont1 = case scc of { InsideSCC -> cont2; _ -> cont2 }
220 cont2 = case dup of { DupDanger -> cont3; _ -> cont3 }
221 cont3 = case alts of { (I# 0#) -> cont4; _ -> cont4 }
222 cont4 = OneOcc posn dup scc alts (I# ar_1#)
224 case posn of {FunOcc -> cont1; _ -> cont1}
226 andBinderInfo info1 info2 =
227 case getBinderInfoArity info1 of
228 (I# i#) -> ManyOcc (I# i#)
229 --ManyOcc (getBinderInfoArity info1)
232 combine_posns FunOcc FunOcc = FunOcc -- see comment at FunOrArg defn
233 combine_posns _ _ = ArgOcc
235 combine_dups DupDanger _ = DupDanger -- Too paranoid?? ToDo
236 combine_dups _ DupDanger = DupDanger
237 combine_dups _ _ = NoDupDanger
239 combine_sccs InsideSCC _ = InsideSCC -- Too paranoid?? ToDo
240 combine_sccs _ InsideSCC = InsideSCC
241 combine_sccs _ _ = NotInsideSCC
243 setBinderInfoArityToZero :: BinderInfo -> BinderInfo
244 setBinderInfoArityToZero DeadCode = DeadCode
245 setBinderInfoArityToZero (ManyOcc _) = ManyOcc 0
246 setBinderInfoArityToZero (OneOcc fa dd sc i _) = OneOcc fa dd sc i 0
250 getBinderInfoArity (DeadCode) = 0
251 getBinderInfoArity (ManyOcc i) = i
252 getBinderInfoArity (OneOcc _ _ _ _ i) = i
256 instance Outputable BinderInfo where
257 ppr sty DeadCode = ptext SLIT("Dead")
258 ppr sty (ManyOcc ar) = hcat [ ptext SLIT("Many-"), int ar ]
259 ppr sty (OneOcc posn dup_danger in_scc n_alts ar)
260 = hcat [ ptext SLIT("One-"), pp_posn posn, char '-', pp_danger dup_danger,
261 char '-', pp_scc in_scc, char '-', int n_alts,
264 pp_posn FunOcc = ptext SLIT("fun")
265 pp_posn ArgOcc = ptext SLIT("arg")
267 pp_danger DupDanger = ptext SLIT("*dup*")
268 pp_danger NoDupDanger = ptext SLIT("nodup")
270 pp_scc InsideSCC = ptext SLIT("*SCC*")
271 pp_scc NotInsideSCC = ptext SLIT("noscc")