1   // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.io.PrintWriter;
6   import java.util.ArrayList;
7   
8   import static jminusminus.CLConstants.*;
9   import static jminusminus.NPhysicalRegister.*;
10  
11  /**
12   * This abstract base class provides a low-level intermediate representation (LIR) of a JVM
13   * instruction.
14   */
15  abstract class NLIRInstruction {
16      /**
17       * Maps JVM opcode to a string mnemonic for LIR instructions. For example, imul is mapped to
18       * the "MUL".
19       */
20      protected static String[] lirMnemonic;
21  
22      static {
23          lirMnemonic = new String[256];
24          lirMnemonic[IADD] = "ADD";
25          lirMnemonic[IMUL] = "MUL";
26          lirMnemonic[ISUB] = "SUB";
27          lirMnemonic[MULTIANEWARRAY] = "MULTIANEWARRAY";
28          lirMnemonic[AALOAD] = "AALOAD";
29          lirMnemonic[IALOAD] = "IALOAD";
30          lirMnemonic[IASTORE] = "IASTORE";
31          lirMnemonic[IF_ICMPNE] = "NE";
32          lirMnemonic[IF_ICMPGT] = "GT";
33          lirMnemonic[IF_ICMPLE] = "LE";
34          lirMnemonic[GETSTATIC] = "GETSTATIC";
35          lirMnemonic[PUTSTATIC] = "PUTSTATIC";
36          lirMnemonic[INVOKESPECIAL] = "INVOKESPECIAL";
37          lirMnemonic[INVOKESTATIC] = "INVOKESTATIC";
38      }
39  
40      /**
41       * The block containing this instruction.
42       */
43      public NBasicBlock block;
44  
45      /**
46       * Unique identifier of this instruction.
47       */
48      public int id;
49  
50      /**
51       * Registers that store the inputs (if any) of this instruction.
52       */
53      public ArrayList<NRegister> reads;
54  
55      /**
56       * Register that stores the result (if any) of this instruction.
57       */
58      public NRegister write;
59  
60      /**
61       * Constructs an NLIRInstruction object.
62       *
63       * @param block enclosing block.
64       * @param id    identifier of the instruction.
65       */
66      protected NLIRInstruction(NBasicBlock block, int id) {
67          this.block = block;
68          this.id = id;
69          reads = new ArrayList<NRegister>();
70      }
71  
72      /**
73       * Replace references to virtual registers in this LIR instruction with references to
74       * physical registers.
75       */
76      public void allocatePhysicalRegisters() {
77          // Nothing here.
78      }
79  
80      /**
81       * Translates this LIR instruction into SPIM and writes it out to the specified output stream.
82       *
83       * @param out output stream for SPIM code.
84       */
85      public void toSpim(PrintWriter out) {
86          // Nothing here.
87      }
88  
89      /**
90       * Returns a string representation of this instruction.
91       *
92       * @return a string representation of this instruction.
93       */
94      public String toString() {
95          return "" + id;
96      }
97  }
98  
99  /**
100  * LIR instruction corresponding to the JVM arithmetic instructions.
101  */
102 class NLIRArithmetic extends NLIRInstruction {
103     // Opcode for the arithmetic operator.
104     private int opcode;
105 
106     /**
107      * Constructs an NLIRArithmetic object.
108      *
109      * @param block  enclosing block.
110      * @param id     identifier of the instruction.
111      * @param opcode opcode for the arithmetic operator.
112      * @param lhs    LIR for lhs.
113      * @param rhs    LIR for rhs.
114      */
115     public NLIRArithmetic(NBasicBlock block, int id, int opcode, NLIRInstruction lhs,
116                           NLIRInstruction rhs) {
117         super(block, id);
118         this.opcode = opcode;
119         reads.add(lhs.write);
120         reads.add(rhs.write);
121         write = new NVirtualRegister(NControlFlowGraph.regId++, "I", "I");
122         block.cfg.registers.add((NVirtualRegister) write);
123     }
124 
125     /**
126      * {@inheritDoc}
127      */
128     public void allocatePhysicalRegisters() {
129         NInterval input1 = block.cfg.intervals.get(reads.get(0).number()).childAt(id);
130         NInterval input2 = block.cfg.intervals.get(reads.get(1).number()).childAt(id);
131         NInterval output = block.cfg.intervals.get(write.number()).childAt(id);
132         reads.set(0, input1.pRegister);
133         reads.set(1, input2.pRegister);
134         write = output.pRegister;
135     }
136 
137     /**
138      * {@inheritDoc}
139      */
140     public void toSpim(PrintWriter out) {
141         switch (opcode) {
142             case IADD:
143                 out.printf("    add %s,%s,%s\n", write, reads.get(0), reads.get(1));
144                 break;
145             case ISUB:
146                 out.printf("    sub %s,%s,%s\n", write, reads.get(0), reads.get(1));
147                 break;
148             case IMUL:
149                 out.printf("    mul %s,%s,%s\n", write, reads.get(0), reads.get(1));
150                 break;
151         }
152     }
153 
154     /**
155      * {@inheritDoc}
156      */
157     public String toString() {
158         return id + ": " + lirMnemonic[opcode] + " " + reads.get(0) + " " + reads.get(1) +
159                 " " + write;
160     }
161 }
162 
163 /**
164  * LIR instruction corresponding to the JVM instructions representing integer constants.
165  */
166 class NLIRIntConstant extends NLIRInstruction {
167     // The constant int value.
168     private int value;
169 
170     /**
171      * Constructs an NLIRIntConstant object.
172      *
173      * @param block enclosing block.
174      * @param id    identifier of the instruction.
175      * @param value the constant int value.
176      */
177     public NLIRIntConstant(NBasicBlock block, int id, int value) {
178         super(block, id);
179         this.value = value;
180         write = new NVirtualRegister(NControlFlowGraph.regId++, "I", "I");
181         block.cfg.registers.add((NVirtualRegister) write);
182     }
183 
184     /**
185      * {@inheritDoc}
186      */
187     public void allocatePhysicalRegisters() {
188         NInterval output = block.cfg.intervals.get(write.number()).childAt(id);
189         write = output.pRegister;
190     }
191 
192     /**
193      * {@inheritDoc}
194      */
195     public void toSpim(PrintWriter out) {
196         out.printf("    li %s,%d\n", write, value);
197     }
198 
199     /**
200      * {@inheritDoc}
201      */
202     public String toString() {
203         return id + ": LDC [" + value + "] " + write;
204     }
205 }
206 
207 /**
208  * LIR instruction corresponding to the JVM instructions representing string constants.
209  */
210 class NLIRStringConstant extends NLIRInstruction {
211     // The constant string value.
212     private String value;
213 
214     // For generating unique label for the string in the data segment.
215     private static int labelSuffix;
216 
217     /**
218      * Constructs an NHIRStringConstant object.
219      *
220      * @param block enclosing block.
221      * @param id    identifier for the instruction.
222      * @param value the constant string value.
223      */
224     public NLIRStringConstant(NBasicBlock block, int id, String value) {
225         super(block, id);
226         this.value = value;
227         write = new NVirtualRegister(NControlFlowGraph.regId++, "L", "Ljava/lang/String;");
228         block.cfg.registers.add((NVirtualRegister) write);
229         labelSuffix = 0;
230     }
231 
232     /**
233      * Creates and returns a label for LIR code.
234      *
235      * @return the label for LIR code.
236      */
237     private String createLabel() {
238         return "Constant..String" + labelSuffix++;
239     }
240 
241     /**
242      * {@inheritDoc}
243      */
244     public void allocatePhysicalRegisters() {
245         NInterval output = block.cfg.intervals.get(write.number()).childAt(id);
246         write = output.pRegister;
247     }
248 
249     /**
250      * {@inheritDoc}
251      */
252     public void toSpim(PrintWriter out) {
253         String label = createLabel();
254         String s = label + ":\n";
255         int size = 12 + value.length() + 1;
256         int align = (size % 4 == 0) ? 0 : (size + 4) / 4 * 4 - size;
257         s += "    .word 2 # Tag 2 indicates a string\n";
258         s += "    .word " + (size + align) + " # Size of object in bytes\n";
259         s += "    .word " + value.length() + " # String length (not including null terminator)\n";
260         s += "    .asciiz \"" + value + "\" # String terminated by null character 0\n";
261         s += "    .align " + align + " # Next object is on a word boundary\n";
262         block.cfg.data.add(s);
263         out.printf("    la %s,%s+12\n", write, label);
264     }
265 
266     /**
267      * {@inheritDoc}
268      */
269     public String toString() {
270         return id + ": LDC [\"" + value + "\"] " + write;
271     }
272 }
273 
274 /**
275  * LIR instruction representing an conditional jump instructions in JVM.
276  */
277 class NLIRConditionalJump extends NLIRInstruction {
278     // Test expression opcode.
279     private int opcode;
280 
281     // Block to jump to on true.
282     private NBasicBlock onTrueDestination;
283 
284     // Block to jump to on false.
285     private NBasicBlock onFalseDestination;
286 
287     /**
288      * Constructs an NLIRConditionalJump object.
289      *
290      * @param block              enclosing block.
291      * @param id                 identifier of the instruction.
292      * @param lhs                lhs LIR.
293      * @param rhs                rhs LIR.
294      * @param opcode             opcode in the test.
295      * @param onTrueDestination  block to jump to on true.
296      * @param onFalseDestination block to jump to on false.
297      */
298     public NLIRConditionalJump(NBasicBlock block, int id, NLIRInstruction lhs,
299                                NLIRInstruction rhs, int opcode, NBasicBlock onTrueDestination,
300                                NBasicBlock onFalseDestination) {
301         super(block, id);
302         this.opcode = opcode;
303         reads.add(lhs.write);
304         reads.add(rhs.write);
305         this.onTrueDestination = onTrueDestination;
306         this.onFalseDestination = onFalseDestination;
307     }
308 
309     /**
310      * {@inheritDoc}
311      */
312     public void allocatePhysicalRegisters() {
313         NInterval input1 = block.cfg.intervals.get(reads.get(0).number()).childAt(id);
314         NInterval input2 = block.cfg.intervals.get(reads.get(1).number()).childAt(id);
315         reads.set(0, input1.pRegister);
316         reads.set(1, input2.pRegister);
317     }
318 
319     /**
320      * {@inheritDoc}
321      */
322     public void toSpim(PrintWriter out) {
323         switch (opcode) {
324             case IF_ICMPNE:
325                 out.printf("    bne %s,%s,%s\n", reads.get(0), reads.get(1),
326                         block.cfg.labelPrefix + "." + onTrueDestination.id);
327                 break;
328             case IF_ICMPGT:
329                 out.printf("    bgt %s,%s,%s\n", reads.get(0), reads.get(1),
330                         block.cfg.labelPrefix + "." + onTrueDestination.id);
331                 break;
332             case IF_ICMPLE:
333                 out.printf("    ble %s,%s,%s\n", reads.get(0), reads.get(1),
334                         block.cfg.labelPrefix + "." + onTrueDestination.id);
335                 break;
336         }
337         out.printf("    j %s\n", block.cfg.labelPrefix + "." + onFalseDestination.id);
338     }
339 
340     /**
341      * {@inheritDoc}
342      */
343     public String toString() {
344         return id + ": BRANCH [" + lirMnemonic[opcode] + "] " + reads.get(0)
345                 + " " + reads.get(1) + " " + onTrueDestination.id();
346     }
347 }
348 
349 /**
350  * LIR instruction representing an unconditional jump instruction in JVM.
351  */
352 class NLIRGoto extends NLIRInstruction {
353     // The destination block to unconditionally jump to.
354     private NBasicBlock destination;
355 
356     /**
357      * Constructs an NLIRGoto object.
358      *
359      * @param block       enclosing block.
360      * @param id          identifier of the instruction.
361      * @param destination the block to jump to.
362      */
363     public NLIRGoto(NBasicBlock block, int id, NBasicBlock destination) {
364         super(block, id);
365         this.destination = destination;
366     }
367 
368     /**
369      * {@inheritDoc}
370      */
371     public void toSpim(PrintWriter out) {
372         String label = block.cfg.labelPrefix + "." + destination.id;
373         out.printf("    j %s\n", label);
374     }
375 
376     /**
377      * {@inheritDoc}
378      */
379     public String toString() {
380         return id + ": BRANCH " + destination.id();
381     }
382 }
383 
384 /**
385  * LIR instruction representing method invocation instructions in JVM.
386  */
387 class NLIRInvoke extends NLIRInstruction {
388     // Opcode of the JVM instruction.
389     private int opcode;
390 
391     // Target for the method.
392     private String target;
393 
394     // Name of the method being invoked.
395     private String name;
396 
397     /**
398      * Constructs an NHIRInvoke object.
399      *
400      * @param block     enclosing block.
401      * @param id        identifier of the instruction.
402      * @param opcode    opcode of the JVM instruction.
403      * @param target    target of the method.
404      * @param name      name of the method.
405      * @param arguments list of register storing the of arguments for the method.
406      * @param sType     return type (short name) of the method.
407      * @param lType     return type (long name) of the method.
408      */
409     public NLIRInvoke(NBasicBlock block, int id, int opcode, String target, String name,
410                       ArrayList<NRegister> arguments, String sType, String lType) {
411         super(block, id);
412         this.opcode = opcode;
413         this.target = target;
414         this.name = name;
415         for (NRegister arg : arguments) {
416             reads.add(arg);
417         }
418         if (!sType.equals("V")) {
419             write = NPhysicalRegister.regInfo[V0];
420             block.cfg.registers.set(V0, write);
421         }
422     }
423 
424     /**
425      * {@inheritDoc}
426      */
427     public void allocatePhysicalRegisters() {
428         for (int i = 0; i < reads.size(); i++) {
429             NInterval input = block.cfg.intervals.get(reads.get(i).number()).childAt(id);
430             reads.set(i, input.pRegister);
431         }
432     }
433 
434     /**
435      * {@inheritDoc}
436      */
437     public void toSpim(PrintWriter out) {
438         out.printf("    jal %s.%s\n", target.replace("/", "."),
439                 name.equals("<init>") ? "__init__" : name);
440     }
441 
442     /**
443      * {@inheritDoc}
444      */
445     public String toString() {
446         String s = id + ": " + lirMnemonic[opcode] + " " +
447                 (write != null ? write + " = " : "") + target + "." + name + "( ";
448         for (NRegister input : reads) {
449             s += input + " ";
450         }
451         s += ")";
452         return s;
453     }
454 }
455 
456 /**
457  * HIR instruction representing a JVM return instruction.
458  */
459 class NLIRReturn extends NLIRInstruction {
460     // JVM opcode for the return instruction.
461     private int opcode;
462 
463     /**
464      * Constructs an NLIRReturn object.
465      *
466      * @param block  enclosing block.
467      * @param id     identifier of the instruction.
468      * @param opcode JVM opcode for the return instruction.
469      * @param result physical register storing return value, or null.
470      */
471     public NLIRReturn(NBasicBlock block, int id, int opcode, NPhysicalRegister result) {
472         super(block, id);
473         this.opcode = opcode;
474         if (result != null) {
475             reads.add(result);
476         }
477     }
478 
479     /**
480      * {@inheritDoc}
481      */
482     public void toSpim(PrintWriter out) {
483         out.printf("    j %s\n", block.cfg.labelPrefix + ".restore");
484     }
485 
486     /**
487      * {@inheritDoc}
488      */
489     public String toString() {
490         if (reads.size() == 0) {
491             return id + ": RETURN";
492         }
493         return id + ": RETURN " + reads.get(0);
494     }
495 }
496 
497 /**
498  * LIR instruction representing JVM (put) field instructions.
499  */
500 class NLIRPutField extends NLIRInstruction {
501     // Opcode of the JVM instruction.
502     private int opcode;
503 
504     // Target for the field.
505     private String target;
506 
507     // Name of the field being accessed.
508     private String name;
509 
510     /**
511      * Constructs an NLIRPutField object.
512      *
513      * @param block  enclosing block.
514      * @param id     identifier of the instruction.
515      * @param opcode JVM opcode for the return instruction.
516      * @param target target for the field.
517      * @param name   name of the field.
518      * @param sType  type (short name) of the field.
519      * @param lType  type (long name) of the field.
520      * @param value  LIR of the value of the field.
521      */
522     public NLIRPutField(NBasicBlock block, int id, int opcode, String target, String name,
523                         String sType, String lType, NLIRInstruction value) {
524         super(block, id);
525         this.opcode = opcode;
526         this.target = target;
527         this.name = name;
528         reads.add(value.write);
529     }
530 
531     /**
532      * {@inheritDoc}
533      */
534     public void toSpim(PrintWriter out) {
535         out.printf("    NLIRPutField.toSpim() not yet implemented!\n");
536     }
537 
538     /**
539      * {@inheritDoc}
540      */
541     public String toString() {
542         return id + ": " + lirMnemonic[opcode] + " " + target + "." + name + " = " + reads.get(0);
543     }
544 }
545 
546 /**
547  * LIR instruction representing JVM (get) field instructions.
548  */
549 class NLIRGetField extends NLIRInstruction {
550     // Opcode of the JVM instruction.
551     private int opcode;
552 
553     // Target for the field.
554     private String target;
555 
556     // Name of the field being accessed.
557     private String name;
558 
559     /**
560      * Constructs an NLIRGetField object.
561      *
562      * @param block  enclosing block.
563      * @param id     identifier of the instruction.
564      * @param opcode JVM opcode for the return instruction.
565      * @param target target for the field.
566      * @param name   name of the field.
567      * @param sType  type (short name) of the field.
568      * @param lType  type (long name) of the field.
569      */
570     public NLIRGetField(NBasicBlock block, int id, int opcode, String target, String name,
571                         String sType, String lType) {
572         super(block, id);
573         this.opcode = opcode;
574         this.target = target;
575         this.name = name;
576         write = new NVirtualRegister(NControlFlowGraph.regId++, sType, lType);
577         block.cfg.registers.add((NVirtualRegister) write);
578     }
579 
580     /**
581      * {@inheritDoc}
582      */
583     public void toSpim(PrintWriter out) {
584         out.printf("    NLIRGetField.toSpim() not yet implemented!\n");
585     }
586 
587     /**
588      * {@inheritDoc}
589      */
590     public String toString() {
591         return id + ": " + lirMnemonic[opcode] + " " + write + " = " + target + "." + name;
592     }
593 }
594 
595 /**
596  * LIR instruction representing JVM array creation instructions.
597  */
598 class NLIRNewArray extends NLIRInstruction {
599     // Opcode of the JVM instruction.
600     private int opcode;
601 
602     // Dimension of the array.
603     private int dim;
604 
605     /**
606      * Constructs an NLIRNewArray object.
607      *
608      * @param block  enclosing block.
609      * @param id     identifier of the instruction.
610      * @param opcode JVM opcode for the instruction.
611      * @param dim    dimension of the array.
612      * @param sType  type (short name) of the array.
613      * @param lType  type (long name) of the array.
614      */
615     public NLIRNewArray(NBasicBlock block, int id, int opcode, int dim, String sType,
616                         String lType) {
617         super(block, id);
618         this.opcode = opcode;
619         this.dim = dim;
620         write = new NVirtualRegister(NControlFlowGraph.regId++, sType, lType);
621         block.cfg.registers.add((NVirtualRegister) write);
622     }
623 
624     /**
625      * {@inheritDoc}
626      */
627     public void toSpim(PrintWriter out) {
628         out.printf("    NLIRNewArray.toSpim() not yet implemented!\n");
629     }
630 
631     /**
632      * {@inheritDoc}
633      */
634     public String toString() {
635         return id + ": " + lirMnemonic[opcode] + " [" + dim + "]" + " " + write;
636     }
637 }
638 
639 /**
640  * LIR instruction representing JVM array load instructions.
641  */
642 class NLIRALoad extends NLIRInstruction {
643     // Opcode of the JVM instruction.
644     private int opcode;
645 
646     /**
647      * Constructs an NLIRALoad object.
648      *
649      * @param block    enclosing block.
650      * @param id       identifier of the instruction.
651      * @param opcode   JVM opcode for the instruction.
652      * @param arrayRef LIR of the array reference.
653      * @param index    LIR of the array index.
654      * @param sType    type (short name) of the array.
655      * @param lType    type (long name) of the array.
656      */
657     public NLIRALoad(NBasicBlock block, int id, int opcode,
658                      NLIRInstruction arrayRef, NLIRInstruction index, String sType,
659                      String lType) {
660         super(block, id);
661         this.opcode = opcode;
662         reads.add(arrayRef.write);
663         reads.add(index.write);
664         write = new NVirtualRegister(NControlFlowGraph.regId++, sType, lType);
665         block.cfg.registers.add((NVirtualRegister) write);
666     }
667 
668     /**
669      * {@inheritDoc}
670      */
671 
672     public void toSpim(PrintWriter out) {
673         out.printf("    NLIRALoad.toSpim() not yet implemented!\n");
674     }
675 
676     /**
677      * {@inheritDoc}
678      */
679 
680     public String toString() {
681         return id + ": " + lirMnemonic[opcode] + " " + write + "= " + reads.get(0) + "[" +
682                 reads.get(1) + "]";
683     }
684 }
685 
686 /**
687  * LIR instruction representing JVM array store instructions.
688  */
689 class NLIRAStore extends NLIRInstruction {
690     // Opcode of the JVM instruction.
691     private int opcode;
692 
693     /**
694      * Constructs an NLIRAStore object.
695      *
696      * @param block    enclosing block.
697      * @param id       identifier of the instruction.
698      * @param opcode   JVM opcode for the instruction.
699      * @param arrayRef LIR of the array reference.
700      * @param index    LIR of the array index.
701      * @param value    LIR of the value to store.
702      * @param sType    type (short name) of the array.
703      * @param lType    type (long name) of the array.
704      */
705     public NLIRAStore(NBasicBlock block, int id, int opcode, NLIRInstruction arrayRef,
706                       NLIRInstruction index, NLIRInstruction value, String sType, String lType) {
707         super(block, id);
708         this.opcode = opcode;
709         reads.add(arrayRef.write);
710         reads.add(index.write);
711         reads.add(value.write);
712     }
713 
714     /**
715      * {@inheritDoc}
716      */
717     public void toSpim(PrintWriter out) {
718         out.printf("    NLIRAStore.toSpim() not yet implemented!\n");
719     }
720 
721     /**
722      * {@inheritDoc}
723      */
724     public String toString() {
725         return id + ": " + lirMnemonic[opcode] + " " + reads.get(0) + "[" + reads.get(1) + "] = " +
726                 reads.get(2);
727     }
728 }
729 
730 /**
731  * LIR instruction representing phi functions.
732  */
733 class NLIRPhiFunction extends NLIRInstruction {
734     /**
735      * Constructs an NLIRPhiFunction object.
736      *
737      * @param block enclosing block.
738      * @param id    identifier of the instruction.
739      * @param sType type (short name) of the phi function.
740      * @param lType type (long name) of the phi function.
741      */
742     public NLIRPhiFunction(NBasicBlock block, int id, String sType, String lType) {
743         super(block, id);
744         write = new NVirtualRegister(NControlFlowGraph.regId++, sType, lType);
745         block.cfg.registers.add((NVirtualRegister) write);
746     }
747 
748     /**
749      * {@inheritDoc}
750      */
751     public String toString() {
752         return id + ": phi " + write;
753     }
754 }
755 
756 /**
757  * LIR move instruction.
758  */
759 class NLIRMove extends NLIRInstruction {
760     /**
761      * Constructs an NLIRMove object.
762      *
763      * @param block enclosing block.
764      * @param id    identifier of the instruction.
765      * @param from  LIR to move from.
766      * @param to    LIR to move to.
767      */
768     public NLIRMove(NBasicBlock block, int id, NLIRInstruction from, NLIRInstruction to) {
769         super(block, id);
770         reads.add(from.write);
771         write = to.write;
772     }
773 
774     /**
775      * Constructs an NLIRMove object.
776      *
777      * @param block enclosing block.
778      * @param id    identifier of the instruction.
779      * @param from  register (virtual or physical) to move from.
780      * @param to    register (virtual or physical) to move to.
781      */
782     public NLIRMove(NBasicBlock block, int id, NRegister from, NRegister to) {
783         super(block, id);
784         reads.add(from);
785         write = to;
786     }
787 
788     /**
789      * {@inheritDoc}
790      */
791     public void allocatePhysicalRegisters() {
792         NInterval input = block.cfg.intervals.get(reads.get(0).number()).childAt(id);
793         NInterval output = block.cfg.intervals.get(write.number()).childAt(id);
794         reads.set(0, input.pRegister);
795         write = output.pRegister;
796     }
797 
798     /**
799      * {@inheritDoc}
800      */
801     public void toSpim(PrintWriter out) {
802         out.printf("    move %s,%s\n", write, reads.get(0));
803     }
804 
805     /**
806      * {@inheritDoc}
807      */
808     public String toString() {
809         return id + ": MOVE " + reads.get(0) + " " + write;
810     }
811 }
812 
813 /**
814  * LIR instruction representing a formal parameter.
815  */
816 class NLIRLoadLocal extends NLIRInstruction {
817     // Local variable index.
818     private int local;
819 
820     /**
821      * Constructs an NLIRLoadLocal object.
822      *
823      * @param block enclosing block.
824      * @param id    identifier of the instruction.
825      * @param local local variable index.
826      * @param sType short type name of the instruction.
827      * @param lType long type name of the instruction.
828      */
829     public NLIRLoadLocal(NBasicBlock block, int id, int local, String sType, String lType) {
830         super(block, id);
831         this.local = local;
832         if (local < 4) {
833             write = NPhysicalRegister.regInfo[A0 + local];
834             block.cfg.registers.set(A0 + local, NPhysicalRegister.regInfo[A0 + local]);
835         } else {
836             write = new NVirtualRegister(NControlFlowGraph.regId++, sType, lType);
837             block.cfg.registers.add((NVirtualRegister) write);
838         }
839     }
840 
841     /**
842      * Returns the local variable index for this instruction.
843      *
844      * @return the local variable index for this instruction.
845      */
846     public int getLocal() {
847         return local;
848     }
849 
850     /**
851      * {@inheritDoc}
852      */
853     public String toString() {
854         return id + ": LDLOC " + local + " " + write;
855     }
856 }
857 
858 /**
859  * LIR instruction representing a load from memory to register.
860  */
861 class NLIRLoad extends NLIRInstruction {
862     // Stack offset to load from.
863     private int offset;
864 
865     // Whether offset is relative to stack pointer (sp) or frame pointer (fp).
866     private OffsetFrom offsetFrom;
867 
868     // Register to load to.
869     private NRegister register;
870 
871     /**
872      * Constructs an NLIRLoad object.
873      *
874      * @param block      enclosing block.
875      * @param id         identifier of the instruction.
876      * @param offset     stack offset to load from.
877      * @param offsetFrom whether offset relative to stack pointer (sp) or frame pointer (fp).
878      * @param register   register to load to.
879      */
880     public NLIRLoad(NBasicBlock block, int id, int offset, OffsetFrom offsetFrom,
881                     NRegister register) {
882         super(block, id);
883         this.offset = offset;
884         this.offsetFrom = offsetFrom;
885         this.register = register;
886     }
887 
888     /**
889      * {@inheritDoc}
890      */
891     public void toSpim(PrintWriter out) {
892         if (offsetFrom == OffsetFrom.FP) {
893             out.printf("    lw %s,%d($fp)\n", register, offset * 4);
894         } else {
895             out.printf("    lw %s,%d($sp)\n", register, offset * 4);
896         }
897     }
898 
899     /**
900      * {@inheritDoc}
901      */
902     public String toString() {
903         return id + ": LOAD " + (offsetFrom == OffsetFrom.FP ? "[frame:" : "[stack:") +
904                 offset + "] " + register;
905     }
906 }
907 
908 /**
909  * LIR instruction representing a store from a register to memory.
910  */
911 class NLIRStore extends NLIRInstruction {
912     // Stack offset to store to.
913     private int offset;
914 
915     // Whether offset is relative to stack pointer (sp) or frame pointer (fp).
916     private OffsetFrom offsetFrom;
917 
918     // Register to store from.
919     private NRegister register;
920 
921     /**
922      * Constructs an NLIRStore object.
923      *
924      * @param block      enclosing block.
925      * @param id         identifier of the instruction.
926      * @param offset     stack offset to store to.
927      * @param offsetFrom whether offset relative to stack pointer (sp) or frame pointer (fp).
928      * @param register   register to store from.
929      */
930     public NLIRStore(NBasicBlock block, int id, int offset, OffsetFrom offsetFrom,
931                      NRegister register) {
932         super(block, id);
933         this.offset = offset;
934         this.offsetFrom = offsetFrom;
935         this.register = register;
936         reads.add(register);
937     }
938 
939     /**
940      * {@inheritDoc}
941      */
942     public void allocatePhysicalRegisters() {
943         NInterval input = block.cfg.intervals.get(reads.get(0).number()).childAt(id);
944         if (input.vRegId >= 32) {
945             reads.set(0, input.pRegister);
946         }
947     }
948 
949     /**
950      * {@inheritDoc}
951      */
952     public void toSpim(PrintWriter out) {
953         if (offsetFrom == OffsetFrom.FP) {
954             out.printf("    sw %s,%d($fp)\n", reads.get(0), offset * 4);
955         } else {
956             out.printf("    sw %s,%d($sp)\n", reads.get(0), offset * 4);
957         }
958     }
959 
960     /**
961      * {@inheritDoc}
962      */
963     public String toString() {
964         return id + ": STORE " + reads.get(0) + " " + (offsetFrom == OffsetFrom.FP ? "[frame:" :
965                 "[stack:") + offset + "]";
966     }
967 }
968