/* 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) = { if (value > (Math.pow(2,16) - 1)) { code.emit(ADDI, r, ZERO, value >> 16, value.toString()); //TODO: SHIFT code.emit(ADDI, r, r, value << 16 >> 16); } else { code.emit(ADDI, r, ZERO, value, 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) => // ... à compléter ... //TODO: case FieldDecl(_, _) => ; case FieldDecl(_) => ; case method @ MethodDef(name, params, _, body) => // ... à compléter ... case While(cond, stats) => // ... à compléter ... case Var(varname, _, init) => // ... à compléter ... case Set(name, expr) => // ... à compléter ... case Do(expr) => 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) => genTmp { tmpReg => op match { case Operators.NOT => genTmp { allOnes => code.emit(XOR, allOnes, ZERO, ZERO); genLoad(expr, tmpReg); code.emit(BIC, targetReg, allOnes, tmpReg); } case Operators.NEG => genLoad(expr, tmpReg); code.emit(SUB, targetReg, ZERO, tmpReg, "-"); } } case Binop(op, left, right) => genTmp { tmpLeft => genLoad(left, tmpLeft); genTmp { tmpRight => genLoad(right, tmpRight); op match { case Operators.ADD => code.emit(ADD, targetReg, tmpLeft, tmpRight, "+"); case Operators.SUB => code.emit(SUB, targetReg, tmpLeft, tmpRight, "-"); case Operators.MUL => code.emit(MUL, targetReg, tmpLeft, tmpRight, "*"); case Operators.DIV => code.emit(DIV, targetReg, tmpLeft, tmpRight, "/"); case Operators.MOD => code.emit(MOD, targetReg, tmpLeft, tmpRight, "%"); case _ => Console.println("unsupported BinOp: "+op); //TODO: does AND fit in here? what about other logic operations? } } } case Block(stats, main) => // ... à compléter ... case Ident(name) => // ... à compléter ... case New(name, args) => // ... à compléter ... case Select(prefix, selector) => // ... à compléter ... case Call(receiver, method, args) => // ... à compléter ... case If(cond, thenp, elsep) => //TODO: this is absolutely wrong val thenpos = code.getLabel(); val elsepos = code.getLabel(); genCond(cond, thenpos, true); genTmp { leftret => genTmp { rightret => genLoad(thenp, leftret); genLoad(elsep, rightret); } } 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 = { // ... à compléter ... //genTmp { tmpLeft => tree match { case Binop(op, left, right) => //op match { // ... à compléter ... case Unop(op, expr) => () // ... à compléter ... case _ => () //TODO: caseDefault(tree) /* case Operators.EQ => code.emit(CMP, targetReg, tmpLeft, tmpRight, "*"); case Operators.LT => //TODO case Operators.LE => //TODO case Operators.GT => //TODO case Operators.GE => //TODO case Operators.AND => code.emit(AND, targetReg, tmpLeft, tmpRight, "*"); */ } } // genCond }