1 (* Pasted from Pottier's PP compiler *)
5 (* In the following, a ``variable'' means a pseudo-register or an
6 allocatable hardware register. *)
8 (* These functions allow turning an [ERTL] control flow graph into an
9 explicit graph, that is, making successor edges explicit. This is
10 useful in itself and facilitates the computation of predecessor
13 let statement_successors (stmt : statement) =
20 | St_set_hdw (_, _, l)
21 | St_get_hdw (_, _, l)
22 | St_hdw_to_hdw (_, _, l)
32 | St_opaccsA (_, _, _, _, l)
33 | St_opaccsB (_, _, _, _, l)
35 | St_op2 (_, _, _, _, l)
38 | St_load (_, _, _, l)
39 | St_store (_, _, _, l)
40 | St_call_id (_, _, l)
41 | St_call_ptr (_, _, _, l) ->
43 | St_cond (_, l1, l2) ->
44 Label.Set.add l1 (Label.Set.singleton l2)
46 (* The analysis uses the lattice of sets of variables. The lattice's
47 join operation is pointwise set union, which reflects the fact that
48 a variable is deemed live at a program point if and only if it is
49 live at any of the successors of that program point. *)
53 (* A set of variable is represented as a pair of a set of
54 pseudo-registers and a set of hardware registers. *)
57 Register.Set.t * I8051.RegisterSet.t
63 Register.Set.empty, I8051.RegisterSet.empty
66 Register.Set.singleton r, I8051.RegisterSet.empty
69 Register.Set.empty, I8051.RegisterSet.singleton hwr
71 let join (rset1, hwrset1) (rset2, hwrset2) =
72 (Register.Set.union rset1 rset2, I8051.RegisterSet.union hwrset1 hwrset2)
74 let diff (rset1, hwrset1) (rset2, hwrset2) =
75 (Register.Set.diff rset1 rset2, I8051.RegisterSet.diff hwrset1 hwrset2)
77 let equal (rset1, hwrset1) (rset2, hwrset2) =
78 Register.Set.equal rset1 rset2 && I8051.RegisterSet.equal hwrset1 hwrset2
85 module Label_ImperativeMap = struct
100 t := Label.Map.add k d !t
110 module F = Fix.Make (Label_ImperativeMap) (L)
112 (* These are the sets of variables defined at (written by) a statement. *)
114 let defined (stmt : statement) : L.t =
126 Register.Set.empty, I8051.RegisterSet.singleton I8051.carry
127 | St_op2 (I8051.Add, r, _, _, _)
128 | St_op2 (I8051.Addc, r, _, _, _)
129 | St_op2 (I8051.Sub, r, _, _, _) ->
130 L.join (L.hsingleton I8051.carry) (L.psingleton r)
131 | St_op1 (I8051.Inc, r, _, _)
132 | St_get_hdw (r, _, _)
133 | St_framesize (r, _)
139 | St_opaccsA (_, r, _, _, _)
140 | St_opaccsB (_, r, _, _, _)
141 | St_op1 (_, r, _, _)
142 | St_op2 (_, r, _, _, _)
143 | St_load (r, _, _, _) ->
145 | St_set_hdw (r, _, _)
146 | St_hdw_to_hdw (r, _, _) ->
148 | St_call_id _ | St_call_ptr _ ->
149 (* Potentially destroys all caller-save hardware registers. *)
150 Register.Set.empty, I8051.caller_saved
153 L.join (L.hsingleton I8051.spl) (L.hsingleton I8051.sph)
156 List.fold_right I8051.RegisterSet.add rl I8051.RegisterSet.empty
158 (* This is the set of variables used at (read by) a statement. *)
161 let f set r = I8051.RegisterSet.add r set in
162 List.fold_left f I8051.RegisterSet.empty
164 let ret_regs = set_of_list I8051.rets
166 let used (stmt : statement) : L.t =
179 | St_call_id (_, nparams, _) ->
180 (* Reads the hardware registers that are used to pass parameters. *)
182 set_of_list (MiscPottier.prefix nparams I8051.parameters)
183 | St_call_ptr (r1, r2, nparams, _) ->
184 (* Reads the hardware registers that are used to pass parameters. *)
185 Register.Set.of_list [r1 ; r2],
186 set_of_list (MiscPottier.prefix nparams I8051.parameters)
187 | St_get_hdw (_, r, _)
188 | St_hdw_to_hdw (_, r, _) ->
190 | St_set_hdw (_, r, _)
193 | St_op1 (_, _, r, _)
194 | St_cond (r, _, _) ->
196 | St_op2 (I8051.Addc, _, r1, r2, _) ->
197 L.join (L.join (L.psingleton r1) (L.psingleton r2))
198 (L.hsingleton I8051.carry)
199 | St_opaccsA (_, _, r1, r2, _)
200 | St_opaccsB (_, _, r1, r2, _)
201 | St_op2 (_, _, r1, r2, _)
202 | St_load (_, r1, r2, _) ->
203 L.join (L.psingleton r1) (L.psingleton r2)
204 | St_store (r1, r2, r3, _) ->
205 L.join (L.join (L.psingleton r1) (L.psingleton r2)) (L.psingleton r3)
208 L.join (L.hsingleton I8051.spl) (L.hsingleton I8051.sph)
210 Register.Set.empty, I8051.RegisterSet.union I8051.callee_saved ret_regs
212 (* A statement is considered pure if it has no side effect, that is, if
213 its only effect is to write a value to its destination variable.
215 A pure statement whose destination is dead after the statement will
216 be eliminated during the translation of [ERTL] to [LTL]. This is done by
217 replacing the statement with an [St_skip] statement.
219 [eliminable liveafter stmt] returns [Some l], where [l] is [stmt]'s single
220 successor, if statement [stmt] is eliminable. Otherwise, it returns
221 [None]. The parameter [liveafter] is the set of variables that are live
222 after the statement. *)
224 let eliminable ((pliveafter, hliveafter) : L.t) (stmt : statement) =
241 | St_get_hdw (r, _, l)
242 | St_framesize (r, l)
247 | St_opaccsA (_, r, _, _, l)
248 | St_opaccsB (_, r, _, _, l)
249 | St_op1 (_, r, _, l)
250 | St_op2 (_, r, _, _, l)
251 | St_load (r, _, _, l) ->
252 if (Register.Set.mem r pliveafter) ||
253 (I8051.RegisterSet.mem I8051.carry hliveafter) then None else Some l
254 | St_set_hdw (r, _, l)
255 | St_hdw_to_hdw (r, _, l) ->
256 if I8051.RegisterSet.mem r hliveafter then None else Some l
258 (* This is the abstract semantics of instructions. It defines the
259 variables that are live before the instruction in terms of
260 those that are live after the instruction. *)
262 (* The standard definition is: a variable is considered live
263 before the instruction if either (1) it is used by the instruction,
264 or (2) it is live after the instruction and not defined by the
267 As an exception to this rule, if the instruction is eliminable,
268 then a variable is considered live before the instruction
269 if and only if it is live after the instruction. This anticipates
270 on the instruction's elimination.
272 This exception means that the source variables of a pure
273 instruction need not be considered live if the instruction's result
274 is unused. This allows a sequence of pure instructions whose end
275 result is dead to be considered entirely dead.
277 It is a simple, but not entirely trivial, exercise to check that
278 this transfer function is monotone. *)
280 let statement_semantics (stmt : statement) (liveafter : L.t) : L.t =
281 match eliminable liveafter stmt with
283 L.join (L.diff liveafter (defined stmt)) (used stmt)
287 (* A valuation is a function that maps a program point (a control flow
288 graph label) to the set of variables that are live after that
294 (* This is how we turn an [ERTL] procedure into a liveness analysis
295 problem and solve it. *)
297 let analyze (int_fun : internal_function) : valuation =
299 (* Formulate the problem. Construct a system (recursive) equations
300 that describe the live variables before and after each
303 (* The following two functions, [livebefore] and [liveafter],
304 define these equations. Both use an oracle, a valuation --
305 also called [liveafter] -- which is supposed to tell us
306 which variables are live after each label. *)
308 (* The live variables before an instruction are computed, using the
309 instruction's semantics, in terms of the live variables after the
310 instruction -- which are given by the oracle. *)
312 let livebefore label (liveafter : valuation) : L.t =
313 let stmt : statement = Label.Map.find label int_fun.f_graph in
314 statement_semantics stmt (liveafter label)
317 (* The live variables after an instruction are the union of the live
318 variables before each of the instruction's successors. *)
320 let liveafter label (liveafter : valuation) : L.t =
321 let stmt : statement = Label.Map.find label int_fun.f_graph in
322 Label.Set.fold (fun successor accu ->
323 L.join (livebefore successor liveafter) accu
324 ) (statement_successors stmt) L.bottom
327 (* Compute the least fixed point of these recursive equations. *)