1 (* Pasted from Pottier's PP compiler *)
3 open Untrusted_interference
7 (* ------------------------------------------------------------------------- *)
10 (* This module performs graph coloring with an unlimited number of
11 colors and aggressive coalescing. It is used for assigning stack
12 slots to the pseudo-registers that have been spilled by register
15 (* A coloring is a partial function of graph vertices to stack
16 slots. Vertices that are not in the domain of the coloring are
17 waiting for a decision to be made. *)
25 (* ------------------------------------------------------------------------- *)
26 (* Here is the coloring algorithm. *)
36 Set.Make(struct type t = int let compare = Pervasives.compare end)
38 (* [forbidden_slots graph coloring v] is the set of stack slots that
39 cannot be assigned to [v] considering the (partial) coloring
40 [coloring]. This takes into account [v]'s possible interferences
41 with other spilled vertices. *)
43 let add_slot coloring r slots =
44 SlotSet.add (Vertex.Map.find r coloring) slots
46 let forbidden_slots graph coloring v =
47 Vertex.Set.fold (add_slot coloring) (ipp graph v) SlotSet.empty
49 (* [allocate_slot forbidden] returns a stack slot that is not a
50 member of the set [forbidden]. Unlike hardware registers, stack
51 slots are infinitely many, so it is always possible to allocate a
52 new one. The reference [locals] holds the space that must be
53 reserved on the stack for locals. *)
58 let allocate_slot forbidden =
60 if SlotSet.mem slot forbidden then
61 loop (slot + Glue.int_of_bitvector I8051.int_size)
66 locals := max (slot + Glue.int_of_bitvector I8051.int_size) !locals;
69 (* Allocation is in two phases, implemented by [coalescing] and
70 [simplification]. Each of these functions produces a coloring of its
73 (* [simplification] expects a graph that does not contain any preference
74 edges. It picks a vertex [v], removes it, colors the remaining graph,
75 then colors [v] using a color that is still available. Such a color must
76 exist, since there is an unlimited number of colors. *)
78 (* Following Appel, [v] is chosen with lowest degree: this will make this
79 vertex easier to color and might (?) help use fewer colors. *)
81 let rec simplification graph : coloring =
83 match lowest graph with
88 printf "SPILL: Picking vertex: %s.\n" (print_vertex graph v);
91 (* Remove [v] from the graph and color what remains. *)
93 let coloring = simplification (Untrusted_interference.remove graph v) in
95 (* Choose a color for [v]. *)
98 allocate_slot (forbidden_slots graph coloring v)
103 printf "SPILL: Decision concerning %s: offset %d.\n" (print_vertex graph v) decision;
106 (* Record our decision and return. *)
108 Vertex.Map.add v decision coloring
112 (* The graph is empty. Return an empty coloring. *)
116 (* [coalescing] looks for a preference edge, that is, for two vertices
117 [x] and [y] such that [x] and [y] are move-related. In that case,
118 [x] and [y] cannot interfere, because the [Interference] module
119 does not allow two vertices to be related by both an interference
120 edge and a preference edge. If [coalescing] finds such an edge, it
121 coalesces [x] and [y] and continues coalescing. Otherwise, it
122 invokes the next phase, [simplification].
124 This is aggressive coalescing: we coalesce all preference edges,
125 without fear of creating high-degree nodes. This is good because
126 a move between two pseudo-registers that have been spilled in
127 distinct stack slots is very expensive: one load followed by one
130 let rec coalescing graph : coloring =
132 match pppick graph (fun _ -> true) with
137 printf "SPILL: Coalescing %s and %s.\n" (print_vertex graph x) (print_vertex graph y);
140 let graph = Untrusted_interference.coalesce graph x y in
141 let coloring = coalescing graph in
142 Vertex.Map.add x (Vertex.Map.find y coloring) coloring
148 (* Run the algorithm. [coalescing] runs first and calls [simplification]
154 (* Report how much stack space was used. *)