Newer
Older
zweic / sources / zweic / Generator.scala
@glproj03 glproj03 on 31 Jan 2006 10 KB confilct solved
/*  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


}