/* zweic -- a compiler for zwei * * Stephane Micheloud & LAMP * * $Id$ */ package zweic; class Generator(analyzer: Analyzer) { import RISC._; import scala.collection.mutable.{Map, HashMap}; val code = new Code(); private def genTmp(gen: Int => Unit) = { val tmpReg = code.getRegister(); gen(tmpReg); code.freeRegister(tmpReg); } def emitLoadConstant(r: Int, value: Int) = { val highBits = value >> 16; val lowBits = value & 0xFFFF; if (highBits != 0) { code.emit(ORIU, r, ZERO, highBits, value.toString()+"<<"); code.emit(LSHI, r, r, 16, "<< 16"); code.emit(ORIU, r, ZERO, lowBits, value.toString()); } else { code.emit(ORIU, r, ZERO, lowBits, value.toString()); } } def gen(tree: Tree): Unit = tree match { case Program(classes, main) => val init = code.getLabel(); code.emit(BEQ,ZERO,init); // go initialize the VMTs // ... à compléter ... // generate class and function definitions // ... à compléter ... // generate main expression val start = code.getLabel(); code.anchorLabel(start); genTmp { tmpReg => genLoad(main, tmpReg) } // exit code.emit(RET, ZERO); // the following code is placed here because the space that // it occupies can be used after initialization. code.anchorLabel(init); // initialise stack pointer code.emit(SYSCALL, SP, 0, SYS_GET_TOTAL_MEM_SIZE); // initialise garbage collector: // the heap starts at init and // its size is 2/3 * (total_mem_size - init) words val r1 = code.getRegister(); val r2 = code.getRegister(); val r3 = code.getRegister(); emitLoadConstant(r1,init.getAnchor()); code.emit(SUB,r2,SP,r1); code.emit(DIVIU,r2,r2,3*WORD_SIZE); code.emit(LSHI,r2,r2,1); // r2 now contains the size of the heap emitLoadConstant(r3,SP << 27); code.emit(ADD, r2, r2, r3); code.emit(SYSCALL, r1, r2, SYS_GC_INIT); code.freeRegister(r3); code.freeRegister(r2); code.freeRegister(r1); // populate VMTs // ... à compléter ... // jump to main expression code.emit(BEQ, ZERO, start); case ClassDef(_, _, members) => //TODO: case FieldDecl(_, _) => ; case FieldDecl(_) => ; case method @ MethodDef(name, params, _, body) => // ... à compléter ... case While(cond, stats) => genTmp { tmpReg => val valentin = code.getLabel(); val valerie = code.getLabel(); code.anchorLabel(valentin); genCond(cond, valerie, false); stats.foreach(gen); code.emit(BEQ, ZERO, valentin); code.anchorLabel(valerie); } // ... à compléter ... case Var(varname, _, init) => genTmp { tmpReg => genLoad(init, tmpReg); code.incFrameSize(4); varname.sym.offset = code.getFrameSize(); code.emit(PSH, tmpReg, SP, 4); } case Set(name, expr) => genTmp { tmpReg => genLoad(expr, tmpReg); code.emit(STW, tmpReg, SP, code.getFrameSize()-name.sym.offset); } case Do(expr) => genTmp { tmpReg => genLoad(expr, tmpReg); } case PrintInt(expr) => genTmp { tmpReg => genLoad(expr, tmpReg); code.emit(SYSCALL, tmpReg, ZERO, SYS_IO_WR_INT, "printInt"); code.emit(SYSCALL, ZERO, ZERO, SYS_IO_FLUSH, "flush"); } case PrintChar(expr) => genTmp { tempReg => genLoad(expr, tempReg); code.emit(SYSCALL, tempReg, ZERO, SYS_IO_WR_CHR, "printChar"); // TODO: do we flush all day long? code.emit(SYSCALL, ZERO, ZERO, SYS_IO_FLUSH, "flush"); } case _ => Console.println("gen __________________________________"); } // def gen(Tree): Unit def genLoad(tree: Expr, targetReg: Int): Unit = { def caseDefault(tree: Expr): Unit = genLoad( new If(tree, new IntLit(1), new IntLit(0)), targetReg); assert(code.usedRegisters()(targetReg), "invariant violated: target register R" + targetReg + " not allocated"); tree match { case NullLit() => // ... à compléter ... case IntLit(value) => emitLoadConstant(targetReg, value) case ReadInt() => code.emit(SYSCALL, targetReg, ZERO, SYS_IO_RD_INT, "readInt") case ReadChar() => code.emit(SYSCALL, targetReg, ZERO, SYS_IO_RD_CHR, "readChar") case Unop(op, expr) => op match { case Operators.NOT => val store1 = code.getLabel(); val end = code.getLabel(); genCond(expr, store1, false); emitLoadConstant(targetReg, 0); code.emit(BEQ, ZERO, end); code.anchorLabel(store1); emitLoadConstant(targetReg, 1); code.anchorLabel(end); case Operators.NEG => genLoad(expr, targetReg); code.emit(SUB, targetReg, ZERO, targetReg, "-"); } case Binop(op, left, right) => genTmp { tmpLeft => genLoad(left, tmpLeft); genLoad(right, targetReg); op match { case Operators.ADD => code.emit(ADD, targetReg, tmpLeft, targetReg, "+"); case Operators.SUB => code.emit(SUB, targetReg, tmpLeft, targetReg, "-"); case Operators.MUL => code.emit(MUL, targetReg, tmpLeft, targetReg, "*"); case Operators.DIV => code.emit(DIV, targetReg, tmpLeft, targetReg, "/"); case Operators.MOD => code.emit(MOD, targetReg, tmpLeft, targetReg, "%"); case _ => val store0 = code.getLabel(); val end = code.getLabel(); genCond(tree, store0, false); emitLoadConstant(targetReg, 1); code.emit(BEQ, ZERO, end); code.anchorLabel(store0); emitLoadConstant(targetReg, 0); code.anchorLabel(end); } } case Block(stats, main) => //TODO: what about VarScope? code.freeRegister(targetReg); stats.foreach(gen); code.getRegister(targetReg); genLoad(main, targetReg); code.emit(SUBI, SP, SP, code.getFrameSize()); code.decFrameSize(code.getFrameSize()); case Ident(name) => code.emit(LDW, targetReg, SP, code.getFrameSize()-name.sym.offset); case New(name, args) => val af = name.sym.asInstanceOf[ClassSymbol].allFields; genTmp { tmpReg => emitLoadConstant(tmpReg, 4+af.length*4); code.emit(SYSCALL, targetReg, tmpReg, SYS_GC_ALLOC, " allocate memory for class '"+name+"'"); } genTmp { tmpVal => for ( val x <- args.zip(af) ) { genLoad(x._1, tmpVal); code.emit(STW, tmpVal, targetReg, x._2.offset+4); } } case Select(prefix, selector) => genTmp { tmpReg => genLoad(prefix, tmpReg); code.emit(LDW, targetReg, tmpReg, selector.sym.offset+4); } case Call(receiver, method, args) => // ... à compléter ... case If(cond, thenp, elsep) => val elseLabel = code.getLabel(); val afterLabel = code.getLabel(); genCond(cond, elseLabel, false); genLoad(thenp, targetReg); code.emit(BEQ, ZERO, afterLabel); code.anchorLabel(elseLabel); genLoad(elsep, targetReg); code.anchorLabel(afterLabel); case _ => Console.println("LoadGen________________"); // ... à compléter ... } } // genLoad /** * Generates code for conditions, that is constructs * which jump somewhere on the result of a test. */ private def genCond(tree: Expr, targetLabel: code.Label, when: Boolean): Unit = { tree match { case Binop(op, left, right) => { genTmp { tmpLeft => genTmp { tmpRight => genLoad(left, tmpLeft); genLoad(right, tmpRight); op match { case Operators.EQ => code.emit(CMP, tmpLeft, tmpLeft, tmpRight, ""); if ( when ) { code.emit(BNE, tmpLeft, targetLabel); } else { code.emit(BEQ, tmpLeft, targetLabel); } case Operators.NE => code.emit(CMP, tmpLeft, tmpLeft, tmpRight, ""); if ( when ) { code.emit(BEQ, tmpLeft, targetLabel); } else { code.emit(BNE, tmpLeft, targetLabel); } case Operators.ADD => code.emit(ADD, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BNE, tmpLeft, targetLabel); } else { code.emit(BEQ, tmpLeft, targetLabel); } case Operators.SUB => code.emit(SUB, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BNE, tmpLeft, targetLabel); } else { code.emit(BEQ, tmpLeft, targetLabel); } case Operators.MUL => code.emit(MUL, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BNE, tmpLeft, targetLabel); } else { code.emit(BEQ, tmpLeft, targetLabel); } case Operators.DIV => code.emit(DIV, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BNE, tmpLeft, targetLabel); } else { code.emit(BEQ, tmpLeft, targetLabel); } case Operators.MOD => code.emit(MOD, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BNE, tmpLeft, targetLabel); } else { code.emit(BEQ, tmpLeft, targetLabel); } case Operators.LT => code.emit(SUB, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BLT, tmpLeft, targetLabel); } else { code.emit(BGE, tmpLeft, targetLabel); } case Operators.LE => code.emit(SUB, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BLE, tmpLeft, targetLabel); } else { code.emit(BGT, tmpLeft, targetLabel); } case Operators.GT => code.emit(SUB, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BGT, tmpLeft, targetLabel); } else { code.emit(BLE, tmpLeft, targetLabel); } case Operators.GE => code.emit(SUB, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BGE, tmpLeft, targetLabel); } else { code.emit(BLT, tmpLeft, targetLabel); } case Operators.AND => code.emit(AND, tmpLeft, tmpLeft, tmpRight); if ( when ) { code.emit(BNE, tmpLeft, targetLabel); } else { code.emit(BEQ, tmpLeft, targetLabel); } case _ => genLoad(tree, tmpLeft); if ( when ) { code.emit(BNE, tmpLeft, targetLabel); } else { code.emit(BEQ, tmpLeft, targetLabel); } } } } () } case Unop(op, expr) => { op match { case Operators.NOT => genCond(expr, targetLabel, !when); case Operators.NEG => genCond(expr, targetLabel, when); } () } case _ => genTmp { tmpReg => genLoad(tree, tmpReg); if ( when ) { code.emit(BNE, tmpReg, targetLabel); } else { code.emit(BEQ, tmpReg, targetLabel); } } () } } // genCond }