44import java .util .stream .IntStream ;
55
66/**
7- * Implement the original graph coloring algorithm described by Chaitin.
7+ * Implements the original graph coloring algorithm described by Chaitin.
8+ * Since we are targeting an abstract machine where there are no limits on
9+ * number of registers except how we set them, our goal here is to get to
10+ * the minimum number of registers required to execute the function.
11+ * <p>
12+ * We do want to implement spilling even though we do not need it for the
13+ * abstract machine, but it is not yet implemented. We would spill to a
14+ * stack attached to the abstract machine.
815 *
916 * TODO spilling
1017 */
1118public class ChaitinGraphColoringRegisterAllocator {
1219
13- public ChaitinGraphColoringRegisterAllocator () {
14- }
15-
1620 public Map <Integer , Integer > assignRegisters (CompiledFunction function , int numRegisters ) {
1721 if (function .isSSA ) throw new IllegalStateException ("Register allocation should be done after exiting SSA" );
18- var g = coalesce (function );
19- var registers = registersInIR (function );
20- var colors = IntStream .range (0 , numRegisters ).boxed ().toList ();
21- // TODO pre-assign regs to args
22+ // Remove useless copy operations
23+ InterferenceGraph g = coalesce (function );
24+ // Get used registers
25+ Set <Integer > registers = registersInIR (function );
26+ // Create color set
27+ List <Integer > colors = new ArrayList <>(IntStream .range (0 , numRegisters ).boxed ().toList ());
28+ // Function args are pre-assigned colors
29+ // and we remove them from the register set
30+ Map <Integer , Integer > assignments = preAssignArgsToColors (function , registers , colors );
2231 // TODO spilling
23- var assignments = colorGraph (g , registers , new HashSet <>(colors ));
32+ // execute graph coloring on remaining registers
33+ assignments = colorGraph (g , registers , new HashSet <>(colors ), assignments );
34+ // update all instructions
35+ // We simply set the slot on each register - rather than actually trying to replace them
36+ updateInstructions (function , assignments );
37+ // Compute and set the new framesize
38+ function .setFrameSize (computeFrameSize (assignments ));
2439 return assignments ;
2540 }
2641
42+ /**
43+ * Frame size = max number of registers needed to execute the function
44+ */
45+ private int computeFrameSize (Map <Integer , Integer > assignments ) {
46+ return assignments .values ().stream ().mapToInt (k ->k ).max ().orElse (0 );
47+ }
48+
49+ /**
50+ * Due to the way function args are received by the abstract machine, we need
51+ * to assign them register slots starting from 0. After assigning colors/slots
52+ * we remove these from the set so that the graph coloring algo does
53+ */
54+ private Map <Integer , Integer > preAssignArgsToColors (CompiledFunction function , Set <Integer > registers , List <Integer > colors ) {
55+ int count = 0 ;
56+ Map <Integer , Integer > assignments = new HashMap <>();
57+ for (Instruction instruction : function .entry .instructions ) {
58+ if (instruction instanceof Instruction .ArgInstruction argInstruction ) {
59+ Integer color = colors .get (count );
60+ Register reg = argInstruction .arg ().reg ;
61+ registers .remove (reg .nonSSAId ()); // Remove register from set before changing slot
62+ assignments .put (reg .nonSSAId (), color );
63+ count ++;
64+ }
65+ else break ;
66+ }
67+ return assignments ;
68+ }
69+
70+ private void updateInstructions (CompiledFunction function , Map <Integer , Integer > assignments ) {
71+ var regPool = function .registerPool ;
72+ for (var entry : assignments .entrySet ()) {
73+ int reg = entry .getKey ();
74+ int slot = entry .getValue ();
75+ regPool .getReg (reg ).updateSlot (slot );
76+ }
77+ }
78+
2779 /**
2880 * Chaitin: coalesce_nodes - coalesce away copy operations
2981 */
@@ -85,9 +137,7 @@ private void rewriteInstructions(CompiledFunction function, Instruction deadInst
85137 private Set <Integer > registersInIR (CompiledFunction function ) {
86138 Set <Integer > registers = new HashSet <>();
87139 for (var block : function .getBlocks ()) {
88- Iterator <Instruction > iter = block .instructions .iterator ();
89- while (iter .hasNext ()) {
90- Instruction instruction = iter .next ();
140+ for (Instruction instruction : block .instructions ) {
91141 if (instruction .definesVar ())
92142 registers .add (instruction .def ().id );
93143 for (Register use : instruction .uses ())
@@ -112,7 +162,7 @@ private Integer findNodeWithNeighborCountLessThan(InterferenceGraph g, Set<Integ
112162 private Set <Integer > getNeighborColors (InterferenceGraph g , Integer node , Map <Integer ,Integer > assignedColors ) {
113163 Set <Integer > colors = new HashSet <>();
114164 for (var neighbour : g .neighbors (node )) {
115- var c = assignedColors .get (neighbour );
165+ Integer c = assignedColors .get (neighbour );
116166 if (c != null ) {
117167 colors .add (c );
118168 }
@@ -137,18 +187,18 @@ private static HashSet<Integer> subtract(Set<Integer> originalSet, Integer node)
137187 /**
138188 * Chaitin: color_graph
139189 */
140- private Map <Integer , Integer > colorGraph (InterferenceGraph g , Set <Integer > nodes , Set <Integer > colors ) {
190+ private Map <Integer , Integer > colorGraph (InterferenceGraph g , Set <Integer > nodes , Set <Integer > colors , Map < Integer , Integer > preAssignedColors ) {
141191 if (nodes .size () == 0 )
142- return new HashMap <>() ;
143- var numColors = colors .size ();
144- var node = findNodeWithNeighborCountLessThan (g , nodes , numColors );
192+ return preAssignedColors ;
193+ int numColors = colors .size ();
194+ Integer node = findNodeWithNeighborCountLessThan (g , nodes , numColors );
145195 if (node == null )
146196 return null ;
147- var coloring = colorGraph (g .dup ().subtract (node ), subtract (nodes , node ), colors );
197+ Map < Integer , Integer > coloring = colorGraph (g .dup ().subtract (node ), subtract (nodes , node ), colors , preAssignedColors );
148198 if (coloring == null )
149199 return null ;
150- var neighbourColors = getNeighborColors (g , node , coloring );
151- var color = chooseSomeColorNotAssignedToNeighbors (colors , neighbourColors );
200+ Set < Integer > neighbourColors = getNeighborColors (g , node , coloring );
201+ Integer color = chooseSomeColorNotAssignedToNeighbors (colors , neighbourColors );
152202 coloring .put (node , color );
153203 return coloring ;
154204 }
0 commit comments