230 likes | 366 Views
Languages and Compiler Design II Project 5 Hints. Material provided by Prof. Jingke Li Stolen with pride and modified by Herb Mayer PSU Spring 2010 rev.: 4/16/2010. Agenda. SPARC Assembly Code Generation CodeGen Class Register Representation Simple Register Allocation Freeing Registers
E N D
Languages and Compiler Design IIProject 5 Hints Material provided by Prof. Jingke Li Stolen with pride and modified by Herb Mayer PSU Spring 2010 rev.: 4/16/2010 CS322
Agenda • SPARC Assembly Code Generation • CodeGen Class • Register Representation • Simple Register Allocation • Freeing Registers • Low-Level Code Emission • Sample: hello world • Statements • Operands • Expressions • Sample: MEM • Sample: CALL CS322
SPARC Assembly Code Generation • Input: IR Tree program • Strategy: Traverse IR tree top-down; generate code bottom-up — for each node, generate code for its children first, then generate code for itself • Register Management: When needed, allocate the next available register; if mo registers available, issue an error and die with suitable message CS322
The CodeGen Class public class Codegen{ static final int wordSize = 4, // word size minArgSize=24, // minumum arg-build area reservedSize=68; // space for reg window dump private PROG program; // input IR program private Hashtable<Integer, Reg> tempTable; // temp-reg table private Hashtable<String, String> strTable; // string table private int tempCnt, strCnt, // sizes of the two tables regUseCnt, maxRegCnt; // reg-use statistics public Codegen( PROG p ) { program = p; tempTable = new Hashtable<Integer, Reg>(); strTable = new Hashtable<String, String>(); tempCnt = 0; strCnt = 2; // The first two slots are reserved for ’printf’ regUseCnt = 0; maxRegCnt = 0; } //end Codegen CS322
Register Representation public class Reg extends Operand { static final int RESERVED = -1, FREE = 0, USE = 1, TEM P=2; String name; int status; public Reg(String s) { name=s; status=FREE; } public Reg(String s, int st) { name=s; status=st; } public void emit() { System.out.print(name); } } //end Reg // SPARC special registers static final Reg regSP = new Reg("%sp", Reg.RESERVED), // stack ptr regFP = new Reg("%fp", Reg.RESERVED), // frame ptr regG0 = new Reg("%g0", Reg.RESERVED), // always zero regY = new Reg("%y", Reg.RESERVED), // for div op regO0 = new Reg("%o0"), // first arg regO1 = new Reg("%o1"), // second arg regRV = new Reg("%i0"); // return value // general SPARC registers static final int maxRegs = 26; static final Reg[] reg = { new Reg("%l0"), new Reg("%l1"), new Reg("%l2"), new Reg("%l3"), new Reg("%l4"), new Reg("%l5"), new Reg("%l6"), new Reg("%l7"), new Reg("%i1"), new Reg("%i2"), new Reg("%i3"), new Reg("%i4"), new Reg("%i5"), new Reg("%i7"), new Reg("%g1"), new Reg("%g2"), new Reg("%g3"), new Reg("%g4"), new Reg("%g5"), new Reg("%g6"), new Reg("%g7"), new Reg("%o2"), new Reg("%o3"), new Reg("%o4"), new Reg("%o5"), new Reg("%o7") }; CS322
Simple Register Allocation Upon a request, allocate next register numerically. None available? Exception! private Reg getReg() throws CodegenException { for( int i = 0; i < maxRegs; i++ ) { if( reg[i].status == Reg.FREE ) { Reg[i].status = Reg.USE; if( ++regUseCnt > maxRegCnt ) maxRegCnt = regUseCnt; return reg[i]; } //end if } //end for throw new CodegenException( "Out of registers“ ); } //end getReg private void useReg( Reg r ) throws CodegenException { if( r.status != Reg.FREE ) { throw new CodegenException( "Trying to use an occupied reg: " ...); } //end if r.status = Reg.USE; if( ++regUseCnt > maxRegCnt ) maxRegCnt = regUseCnt; } //end useReg When temp is assigned a register, status set to Reg.TEMP, so not to be freed CS322
Freeing Registers // freeing a used reg, skip if it holds a temp void freeReg( Reg r ) { if( r.status == Reg.USE ) { r.status = Reg.FREE; regUseCnt--; } //end if } //end freeReg // freeing all used regs, including those holding temps void freeAllRegs() { for( int i = 0; i < maxRegs; i++ ) { if( ( reg[i].status == Reg.USE ) || ( reg[i].status == Reg.TEMP) ) { //Then reg[i].status = Reg.FREE; } //end if regUseCnt = 0; } //end for } //end freeAllRegs CS322
Low-Level Code Emission void emit ( String s ) { System.out.print(s); } void emit0( String op) { emit("\t" + op + "\n"); } void emit2( String op, Operand rand1, Operand rand2 ) { emit("\t" + op + " "); rand1.emit(); emit(","); rand2.emit(); emit("\n"); } //end emit2 void emit3( String op, Operand rand1, Operand rand2, Operand rand3) { emit( "\t" + op + " "); rand1.emit(); emit(","); rand2.emit(); emit(","); rand3.emit(); emit("\n"); } //end emit3 void emitStore( Operand rand1, Operand rand2 ) { emit("\tst "); rand1.emit(); emit(",["); rand2.emit(); emit("]\n"); } //end emitStore void emitLoad( Operand rand1, Operand rand2 ) { emit( "\tld [“ ); rand1.emit(); emit("],"); rand2.emit(); emit("\n"); } //end emitLoad CS322
Top-Level Code Emission public void go() throws CodegenException { for( int i = 0; i < program.funcs.size(); i++ ) { FUNC f = (FUNC) program.funcs.elementAt(i); int framesize = frameSize(f.varCnt * wordSize, f.argCnt * wordSize); if( f.label.equals("main") ) emit0(".global main"); emit0(".align 4"); emit(f.label + ":\n"); emit("!locals=" + f.varCnt + ", max_args=" + f.argCnt + "\n"); emit0("save %sp,-" + framesize + ",%sp"); genStmts(f.stmts); freeAllRegs(); emit0("ret"); emit0("restore"); emit("\n"); } //end for printStrConsts(); printRegStatus(); } //end go private int roundup( int x, int p) { return ((x+p-1)/p) * p; } private int frameSize( int localSize, int argSize) { if( argSize < minArgSize ) argSize = minArgSize; return roundup( reservedSize + localSize + argSize, 8 ); } //end frameSize CS322
Sample: hello world class hello { public static void main(String[] a) { System.out.println("Hello World!"); } } IR_PROGRAM main( locals = 0, max_args = 0 ) { [CALLST (NAME prString) ( (STRING "Hello World!"))] } //end main ------------------maps into------------------------------------ .global main .align 4 main: !locals=0, max_args=0 save %sp,-96,%sp ![CALLST( NAME prString ) ( ( STRING "Hello World!“ ))] sethi %hi(L$2),%o0 call printf or %o0, %lo(L$2),%o0 ret restore L$2: .ascii "Hello World!\12\0" !Total regs: 1 !Total insts: 8 CS322
Statements void genStmts( STMTlist sl ) throws CodegenException{ for( int i = 0; i < sl.size(); i++ ) { STMT s = (STMT) sl.elementAt(i); emit("!"); s.dump(); if( s instanceof MOVE) genMove((MOVE) s); else if( s instanceof JUMP) genJump((JUMP) s ); else if( s instanceof CJUMP) genCjump((CJUMP) s ); else if( s instanceof LABEL) genLabel((LABEL) s ); else if( s instanceof CALLST) genCallSt((CALLST) s); else if( s instanceof RETURN) genReturn((RETURN) s); else throw new CodegenException("Illegal STMT: "+s); } //end for } //end genStmts CS322
Statements: Move, Jump MOVE — Generate code for src and bring result to a reg; if dst is temp, then gen a mov instruction, else generate code for dst; then gen a store instruction: void genMove( MOVE s ) throws CodegenException { if( s.dst instanceof TEMP ) { Reg r = toReg(genExp(s.src)); Operand dst = genTemp((TEMP) s.dst); emit2("mov", r, dst); freeReg( r ); }else{ ... } //end if } //end genMove JUMP — Gen a ba instruction followed by a nop: void genJump( JUMP s ) throws CodegenException { if( s.target instanceof NAME ) emit0("ba " + ((NAME) s.target).id); emit0("nop"); else throw new CodegenException("JUMP target not a NAME"); } //end genJump CS322
Statements: Return etc. CJUMP: First gen a cmp instruction; then gen a conditional jump LABEL: Void genLabel(LABEL s) { emit0(s.lab + ":"); } RETURN: void genReturn( RETURN s ) throws CodegenException { if( s.exp != null) // gen code for s.exp and bring result to RegRV emit0("ret"); emit0("restore"); } //end genReturn CS322
Statements: Call and Print void genCallSt( CALLST s ) throws CodegenException { String fname = s.func.id; if( fname.equals( "prInt“ )) genPrintInt(s.args); else if( fname.equals( "prString“ ) ) genPrintString( s.args ); else if( fname.equals( "error“ ) ) genPrintError(); else handleCall( fname, s.args ); } //end genCall void genPrintInt( EXPlist args ) throws CodegenException { if( args.size() != 1) throw new CodegenException("wrong number of args to prInt"); useReg( regO0 ); useReg( regO1 ); toReg( regO1, genExp((EXP) args.elementAt(0))); emit0( "sethi %hi(L$0),%o0"); emit0( "call printf"); emit0( "or %o0, %lo(L$0),%o0“ ); freeReg( regO0 ); freeReg( regO1 ); } //end genPrint CS322
Operands Intermediate results are stored in different operands: registers, stack locations, 13-bit and 32-bit immediate values, or globals abstract class Operand {} public class Reg extends Operand { static final int RESERVED=-1, FREE=0, USE=1, TEMP=2; String name; int status; } //end Operand public class RegOffset extends Operand{ Reg r; int o; } public class Imm13 extends Operand { int i; } public class Imm32 extends Operand { int i; } public class AddrName extends Operand { String s; } CS322
Expressions Gen code and return Operand that is holding the expression’s value. Operand genExp( EXP e ) throws CodegenException { if( e instanceof MEM ) return genMem((MEM) e); else if( e instanceof CALL ) return genCall((CALL) e); else if( e instanceof BINOP ) return genBinop((BINOP) e); else if( e instanceof TEMP ) return genTemp((TEMP) e); ... } //end genExp MEM: exp component is translated into Operand node, which should represent an address. If the MEM appears on the left-hand-side of a MOVE statement, it should be translated into a store instruction; otherwise it should be translated into a load instruction. Can default the genMem routine to translate a MEM into a load, and have the genMOVE routine handle the store case directly. CS322
MEM Example class tt3 { public static void main( String[] a ){ int[] a = new int[4]; int len = a.length(); System.out.println(len); } } //end main main: save %sp,-104,% sp st %l2,[%l1] mov 5,%l0 sub %l1,4,%l2 smul %l0,4,%l0 mov %l2,%l1 mov %l0,%o0 cmp %l1,%l0 call malloc bg L0 nop nop mov %o0,%l0 st %l0,[%fp-4] mov 4,%l1 ld [%fp-4],%l2 st %l1,[%l0] st %l2,[%fp-8] mov 4,%l1 ld [%fp-8],%o1 smul %l1,4,%l1 sethi %hi(L$0),%o0 add %l0,%l1,%l2 call printf mov %l2,%l1 or %o0, %lo(L$0),%o0 L0: ret mov 0,%l2 restore CS322
Handling Expressions, Cont’d BINOP • The first operand must be a register. • Only a 13-bit immediate value can directly participate in an operation as an operand. A large immediate value must be load to a register (with a set instruction) first. • DIV operation is implemented with the instruction sdiv, which require the use of a special register %y. The content of %y needs to be cleared before the execution of udiv CALL • Distinguish system routines (i.e. prInt(), prString(), error(), and malloc() ) from user-defined routines. For system routines, pass parameters through the registers %o0 and %o1 • For user-defined routines, pass parameters on the stack CS322
MEM Example, Cont’d class tt1 { public static void main( String[] a ) { int a = 12; int b = 3; System.out.println(a+4096-b*4095/15); } //end main } //end tt1 .global main .align 4 main: !locals=2, max_args=0 wr %g0,%g0,%y save %sp,-104,%sp sdiv %l1,15,%l1 ! [MOVE (VAR 1) (CONST 12)] sub %l0,%l1,%l0 mov 12,%l0 mov %l0,%o1 st %l0,[%fp-4] sethi %hi(L$0),%o0 ! [MOVE (VAR 2) (CONST 3)] call printf mov 3,%l0 or %o0, %lo(L$0),%o0 st %l0,[%fp-8] ret ! [CALLST (NAME prInt) ...] restore ld [%fp-4],%l0 set 4096,%l1 L$0: . ascii "%d\12\0" add %l0,%l1,%l0 ld [%fp-8],%l1 !Total regs: 3 smul %l1,4095,%l1 !Total insts: 21 CS322
CALL Example class tt2 { public int f( int a, int b, int c, int d ) { return a+b+c+d; } public static void main( String[] a ) { System.out.println( f( 1,2,3,4 ) ); } } //end tt2 tt2_f: main: save %sp,-96,%sp save %sp,-96,%sp ld [%fp+72],%l0 ld [%fp+68],%l0 ld [%fp+76],%l1 st %l0,[%sp+68] add %l0,%l1,%l0 mov 1,%l0 ld [%fp+80],%l1 st %l0,[%sp+72] add %l0,%l1,%l0 mov 2,%l0 ld [%fp+84],%l1 st %l0,[%sp+76] add %l0,%l1,%l0 mov 3,%l0 mov %l0,%i0 st %l0,[%sp+80] ret mov 4,%l0 restore st %l0,[%sp+84] call tt2_f nop mov %o0,%l0 ... !Total regs: 3 !Total insts: 36 CS322
genBinop and genMem // A primitive version, both operands are brought into registers Operand genBinop( BINOP e ) throws CodegenException { Reg r1 = toReg( genExp( e.left ) ); Reg r2 = toReg( genExp( e.right ) ); Reg r3 = getReg(); if( e.op == BINOP.DIV ) emit3( "wr", regG0, regG0, regY ); emit3( binopCode(e.op), r1, r2, r3 ); freeReg( r1 ); freeReg( r2 ); return r3; } //end genBinop // Generate a load instruction Operand genMem( MEM e ) throws CodegenException { Operand t = genAddr( e.exp ); if( t instanceof Reg ) { emitLoad(t, t ); return t; }else if( t instanceof RegOffset ) { ... }else if( t instanceof AddrName ) { ... } //end if throw new CodegenException( "wrong address form: " + t ); } //end genMem CS322
Other Expressions TEMP: Check tempTable to see if the temp has been assigned a register already; if so, return that register; otherwise, get a new register and save the info in the table: Operand genTemp(TEMP t) throws CodegenException { Reg r = (Reg) tempTable.get( t.num ); if( r == null ) { ... } return r; } //end genTemp VAR: Generate a RegOffset operand; using %fp as the base register: Operand genVar( VAR e ) { return new RegOffset(regFP, - e.idx * wordSize); } //end genVar PARAM: Similar to VAR; but offset needs to be adjusted by the reserved space (i.e. 68 bytes) CS322
Other Expressions, Cont’d MEMBER: Bring the base address (i.e. the obj component) into a register and then generate a RegOffset operand NAME wSZ: Gen a word-size constant: Operand genName( NAME e ) throws CodegenException { if( e.id.equals("wSZ") ) return new Imm13( wordSize ); throw new CodegenException( "Illegal NAME node“ ); } //end genName CONST: Gen either a 13-bit or 32-bit const value: Operand genConst( CONST e ) throws CodegenException { if( (e.val >= -4096) && (e.val < 4096) ) return new Imm13( e.val ); return new Imm32( e.val ); } //end genConst CS322