CS 453 Programming Assignment #6 — Code Generation

Due Wednesday, May 7th (by 11:59pm) early and late policy

Introduction

You will now make your MiniJava compiler generate MIPS code that is wrapped in the Assem interface. Using the Assem interface makes it possible to generate MIPS code where the temporaries have not yet been mapped to registers. We will be providing you with a pass that handles register allocation. You can generate the list of Assem instructions for the MiniJava program anyway you want. The test will be whether the generated MIPS code generates the same result as the java virtual machine run on the same MiniJava input file.

CodeGenDriver

The CodeGenDriver creates a MipsCodeGen visitor that visits all of the nodes in the AST and generates MIPS code wrapped in the Assem interface, which is then returned via a call to getInstrs(). These instructions are then printed to a MIPS assembly file along with the MIPS instructions for the MiniJava runtime library (frame.programTail()). Your compiler can generate the list of Assem.Instr in any way. You can even modify the driver.

Getting Started

Download the MJCodeGenStart.tar to get all the files that we are providing for this project. We recommend the following steps for starting the code generation phase of the MiniJava compiler:
  1. Implement the run-time library routines in MIPS and test them. Some of them should look familiar. After they have been implemented and tested, have the programTail() routine in the MipsFrame class return a string with their implementations so they can be easily appended to the end of any MIPS file. Here are the comments for the runtime library routines.
    #####################     
    # _initArray              
    # pass a ptr to array on stack at 0($fp)
    # pass the size of the array in terms of elements on stack at -4($fp)
    # This routine puts the number of elements in the first word of the array
    # and then initializes all of the elements in the array to zero.
    #####################  
    #####################     
    # _printint               
    # pass number to print on stack to be found at 0($fp)
    #####################     
    #####################     
    # _halloc                 
    # pass number of bytes to allocate on stack at 0($fp)
    #####################     
    
  2. Start with a MiniJava input program that only has a main and that main prints a constant.
    class PrintConst {
        public static void main(String[] args) {
            System.out.println(42);
        }
    }
        
    Figure out how to automatically generate the epilogue and prologue for main and then generalize that to any function. The prologue and epilogue should be added to the front and end of the list of statements for each function/method (i.e., in the outMethod() routine). Here is the MIPS epilogue and prologue from the reference compiler for the above example:
    
            # prologue start
            .text
    main:
    main_framesize=16
    main_paramsNregsaves=8
            sw $ra, 0($sp)
            subu $sp, $sp, 4
            sw $fp, 0($sp)
            subu $sp, $sp, 4
            addu $fp, $sp, main_paramsNregsaves
            subu $sp, $fp, main_framesize
            # prologue end
            
            
            # ...
    
            
            
            # epilogue start
    done1:
            lw $ra, 0($fp)
            move $t0, $fp
            lw $fp, -4($fp)
            move $sp, $t0
            jr $ra
            # epilogue end
    
    
    The above code runs in spim just fine.
  3. Implement the generation of Assem.Instr for integer expressions and the print statement. Here are some examples of how to generate Assem.Instrs.
       /**
        * @param val Immediate value that should be loaded.
        * @param comment Inline comment to put in the generated code.
        * @param ilist List of instructions that the load instruction(s) are added to.
        * @return The Temp where the loaded value will be put.
        */
       private Temp genLoadImm(int val, String comment, List ilist) {
           Temp retval = new Temp();
           ArrayList destlist = new ArrayList();
           destlist.add(retval);
           ilist.add(new Assem.OPER("\tli `d0, " + val + "\t# " + comment + "\n", 
                                 destlist, null));
           return retval;
       }
    
  4. Next add some debugging output that prints the instructions before register allocation. For the above, the reference compiler generates the following debug output:
    -------------------
    main
            li t32, 42      # IntegerExp
            # PrintStatement
            # push parameter onto stack
            sw t32, 0($sp)
            subu $sp, $sp, 4
            jal _printint
            move t33, $v0   # store return value to Temp
    
    Notice the temporaries t32 and t33. Also notice that comments in the generated MIPS code could be quite helpful for debugging.
  5. Finally call the spill all register allocator on the instructions for the body of the function/method BEFORE adding the prologue and epilogue. In spill all, the temporaries will be replaced with registers and everything spilled to memory.
           // perform spillAll on body of the function
           // need the method's frame
           MethodSTE methodInfo = (MethodSTE)this.mCurrentST.lookup(node.getName().getText());
           Set noSpillSet = new HashSet();
           noSpillSet.add(mFrame.FP());
           noSpillSet.add(mFrame.SP());
           noSpillSet.add(mFrame.RV());
           noSpillSet.add(mFrame.RA());
           List instrs 
             = (new Mips.SpillAllRegAlloc((Mips.MipsFrame)methodInfo.getFrame())).spillAll(
                   noSpillSet, mFrame.tempRegSet(),this.mNoregInstrList);
    
        # Body of main after spill all
            li $t0, 42      # IntegerExp
            sw $t0, -8($fp)
            # PrintStatement
            lw $t0, -8($fp)
            # push parameter onto stack
            sw $t0, 0($sp)
            subu $sp, $sp, 4
            jal _printint
            move $t1, $v0   # store return value to Temp
            sw $t1, -12($fp)
    
    At this point, you should be able to add code generation for one ast node at a time and test the MIPS output with spim as you go. We will also be covering various aspects of the code generation in class.
Here are the other MIPS instructions you will need.
    .text
L1:

    beq $t0, $t1, L1
    bne $t0, $t1, L1
    blt $t0, $t1, L1
    j L1
    jal L1
    jr $ra
    
    
    sw $t0, 4($t1)
    lw $t0, -8($sp)
    li $t0, 42
    
    move $t0, $t1
    
    subu $t0, $t1, 8
    
    and $t0, $t1, $t2
    sub, mul, xor, add

Extra Credit Possibilities

The MIPS code generated after spilling most of the temporaries to memory will be very inefficient. Here are two possible things you can do to reduce the number of instructions executed. Any extra points earned from implementing one of these optimizations will be added to your final exam. You need to indicate that you have implemented extra credit in your README file and show how the optimization has reduced the number of static and dynamic instructions. You can do a dynamic instruction count by using "spim -keepstats".

Removing Unnecessary Jumps

This optimization is worth 2 points. It could be done by doing a pass over the list of Assem instructions before the code that prints the instructions to a file. Any jump directly followed by the label it is jumping to can be removed.

Register Allocation for Expression Trees

This optimization is worth 5 points. Chapter 8.10.3 in the book describes how to do register allocation for expression trees.

Other Optimizations

Propose an optimization in an email, and I will gladly assign a point value.

Implement Inherited Fields

This is worth 3 points. You need to include a test case that shows this works.

Implement Polymorphism

This is worth 5 points. You need to include a test case that shows this works.

Taking advantage of Early Policy and Extra Credit

If you do write a version of the code generator that removes unnecessary jumps and/or does register allocation for expression trees, you should turn in a generic version of the code generator as early as possible and name it "PA6_username.tar", then later turn in a "PA6_username_extra.tar". Make sure to indicate in your README file what optimizations you did and where Alan should look in your code to see how the optimization is implemented.

The Assignment

Write a code generator that can generate MIPS Assem instructions given the AST and a SymTable. Use spillAll to generate MIPS code with register assignments. The resulting MIPS code should be in the file inputfile.s. The output of "spim inputfile.s" should match the output of compiling and running the inputfile with the normal JVM.

All the features in the MiniJava grammar should be implemented with the exception of inheritance: accesses to inherited member variables, assignment of a subclass reference to a parent class reference, and virtual method calls. The semantics of each statement in MiniJava is the same as Java except that System.out.println() can only be applied to integers and the parameter to main should be ignored.

Submitting the Assignment

  • Submit assignment using checkin utility
    ~cs453/bin/checkin PA6 MJCompiler-groupname.jar
  • Sanity Check (procedure TA will use to run your assignment):
      % java -classpath java-cup-11a-runtime.jar -jar MJCompiler-groupname.jar filename.java
      % mkdir MJCompiler-groupname/src/
      % cd MJCompiler-groupname/src/
      % cp ../../MJCompiler-groupname.jar .
      % jar xf MJCompiler-groupname.jar
      
    Note that you need to have a copy of the java-cup-11a-runtime.jar file in the same directory as the MJCompiler-groupname.jar file. We will provide our own copy of the runtime jar file for testing. We will be running your compiler on multiple test files. Also, the TA will be looking at the source files.
  • Early and Late Policy

    For PA6, each day the assignment is turned in early, you will earn an extra 2% on the assignment.

    Late assignments will be accepted up to 24 hours past the due date for a deduction of 20% and will not accepted past this period.


    mstrout@cs.colostate.edu .... April 16, 2008