structure Mips = struct structure A = Assem structure T = Tree fun codegen (frame) (stm: Tree.stm) : Assem.instr list = let val ilist = ref (nil: A.instr list) fun emit x = ilist := x :: !ilist fun result (gen) = let val t = Temp.newtemp() in gen t; t end fun munchArgs (i, []):Assem.temp list = [] | munchArgs (i, h::t) = let val reg = munchExp h val sp = munchExp (T.TEMP (MipsFrame.SP)) in if i < 4 (* and escapes? *) then (* move the sucker into the register and return that register *) (munchStm(T.MOVE(T.TEMP(List.nth (MipsFrame.argregisters, i)),h)); (List.nth (MipsFrame.argregisters, i))::munchArgs (i+1,t)) else (* advance to the next clean spot for the sp *) (munchStm ( T.MOVE (T.BINOP(T.PLUS, T.CONST MipsFrame.wordSize, T.TEMP (MipsFrame.SP)), T.TEMP MipsFrame.SP)); (* move the sucker into the register *) munchStm(T.MOVE (T.TEMP (List.nth (MipsFrame.argregisters, i)), T.MEM (T.TEMP (MipsFrame.SP)))); (List.nth (MipsFrame.argregisters, i))::munchArgs (i+1,t)) end (* do we still have to do somthing about let expressoins or so...? *) and munchStm (T.SEQ(a,b)):unit = (munchStm a; munchStm b) | munchStm (T.MOVE(T.MEM(T.BINOP(T.PLUS, e1, T.CONST i)), e2)) = (* sw Rsrc, address = sw e2, i(e1) *) emit (A.OPER{assem="sw `s0, " ^ (Int.toString i) ^ "(`s1)\n", src=[munchExp e1, munchExp e2], dst=[], jump=NONE}) | munchStm (T.MOVE(T.MEM(T.BINOP(T.PLUS, T.CONST i, e1)), e2)) = (* sw Rsrc, address = sw e2, i(e1) *) emit (A.OPER{assem="sw `s0, " ^ (Int.toString i) ^ "(`s1)\n", src=[munchExp e1, munchExp e2], dst=[], jump=NONE}) | munchStm (T.MOVE(T.MEM(e1),T.MEM(e2))) = emit (A.OPER {assem="sw `s0, `d0\n", src=[munchExp (T.MEM(e1))], dst=[munchExp (T.MEM(e2))], jump=NONE}) | munchStm (T.MOVE(T.MEM(T.CONST i), e2)) = emit (A.OPER {assem="sw `s0, " ^ (Int.toString i) ^ "\n", src=[munchExp(e2)], dst=[],jump=NONE}) | munchStm (T.MOVE(T.MEM(e1), e2)) = (* M[e1] <- e2 *) emit (A.OPER {assem="sw `s0, `d0\n", src=[munchExp(e1)], dst=[munchExp(e2)], jump=NONE}) | munchStm (T.MOVE(T.TEMP i, T.NAME n)) = emit (A.OPER {assem="sw `d0, " ^ (Temp.labelname n) ^ "\n", src=[], dst=[i], jump=NONE}) | munchStm (T.MOVE(T.NAME n, T.TEMP i)) = emit (A.OPER {assem="sw `s0, " ^ (Temp.labelname n) ^ "\n", src=[i], dst=[], jump=NONE}) | munchStm (T.MOVE(T.TEMP i, e2)) = (* i <- e2 *) emit (A.OPER {assem="move `d0, (`s0)\n", src=[munchExp(e2)], dst=[i], jump=NONE}) | munchStm (T.MOVE(T.NAME n, e)) = let val reg = munchExp(e) in emit (A.OPER {assem="lw `d0, " ^ (Temp.labelname n) ^ "\n", src=[], dst=[reg], jump=NONE}) end | munchStm (T.MOVE(e,T.NAME n)) = let val reg = munchExp(e) in emit (A.OPER {assem="sw `d0, " ^ (Temp.labelname n) ^ "\n", src=[], dst=[reg], jump=NONE}) end | munchStm (T.LABEL lab) = (* LAB: I didn't double check the syntax of this one? *) emit (A.LABEL{assem=Temp.labelname(lab) ^ ":\n", lab=lab}) | munchStm (T.EXP e) = (munchExp e ; ()) (* Jumps *) | munchStm (T.JUMP (T.NAME n, labels)) = emit (A.OPER {assem="b " ^ (Temp.labelname n) ^ "\n", src=[], dst=[], jump=SOME labels}) (* Greater & Less *) | munchStm (T.CJUMP (T.GT, e1, e2, l1, l2)) = (emit (A.OPER {assem="bgt `s0 `s1 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) | munchStm (T.CJUMP (T.GE, e1, e2, l1, l2)) = (emit (A.OPER {assem="bge `s0 `s1 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) | munchStm (T.CJUMP (T.LT, e1, e2, l1, l2)) = (emit (A.OPER {assem="bge `s1 `s0 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) | munchStm (T.CJUMP (T.LE, e1, e2, l1, l2)) = (emit (A.OPER {assem="bgt `s1 `s0 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) (* Unsigned Greater & Less *) | munchStm (T.CJUMP (T.UGT, e1, e2, l1, l2)) = (emit (A.OPER {assem="bgtu `s0 `s1 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) | munchStm (T.CJUMP (T.UGE, e1, e2, l1, l2)) = (emit (A.OPER {assem="bgeu `s0 `s1 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) | munchStm (T.CJUMP (T.ULT, e1, e2, l1, l2)) = (emit (A.OPER {assem="bgeu `s1 `s0 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) | munchStm (T.CJUMP (T.ULE, e1, e2, l1, l2)) = (emit (A.OPER {assem="bgtu `s1 `s0 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) (* Eq, NE *) | munchStm (T.CJUMP (T.EQ, e1, e2, l1, l2)) = (emit (A.OPER {assem="beq `s0, `s1, `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) | munchStm (T.CJUMP (T.NE, e1, e2, l1, l2)) = (emit (A.OPER {assem="bne `s0 `s1 `j0\n", src=[munchExp e1, munchExp e2], dst=[], jump=SOME [l1]}); munchStm (T.JUMP (T.NAME l2, [l2]))) and munchExp (T.MEM(T.BINOP(T.PLUS, e1,T.CONST i))):Assem.temp = (* lw `d0 M[i + e1] *) result (fn r:Temp.temp => emit (A.OPER {assem="ld `d0, " ^ (Int.toString i) ^ "(`s0)\n", src=[munchExp(e1)], dst=[r], jump=NONE})) | munchExp (T.MEM(T.BINOP(T.PLUS,T.CONST i, e1))) = (* lw `d0 M[i + e1] *) result (fn r => emit (A.OPER {assem="ld `d0, " ^ (Int.toString i) ^ "(`s0)\n", src=[munchExp(e1)], dst=[r], jump=NONE})) | munchExp (T.MEM(T.CONST i)) = result (fn r => emit (A.OPER {assem="ld `d0, " ^ (Int.toString i) ^ "\n", src=[], dst=[r], jump=NONE})) | munchExp (T.MEM(T.NAME n)) = result (fn r => emit (A.OPER {assem="ld `d0, " ^ (Temp.labelname n) ^ "\n", src=[], dst=[r], jump=NONE})) | munchExp (T.MEM (T.TEMP t)) = result (fn r => emit (A.OPER {assem="ld `d0, (`s0)\n", src=[t], dst=[r], jump=NONE})) | munchExp (T.MEM (e1)) = result (fn r => emit (A.OPER {assem="ld `d0, (`s0)\n", src=[munchExp(e1)], dst=[r], jump=NONE})) (* adding : *) | munchExp (T.BINOP(T.PLUS, e1, T.CONST i)) = result (fn r => emit (A.OPER {assem="addi `d0, (`s0), " ^ (Int.toString i) ^ "\n", src=[munchExp(e1)], dst=[r], jump=NONE})) | munchExp (T.BINOP (T.PLUS, T.CONST i, e1)) = result (fn r => emit (A.OPER {assem="addi `d0, (`s0), " ^ (Int.toString i) ^ "\n", src=[munchExp(e1)], dst=[r], jump=NONE})) | munchExp (T.BINOP (T.PLUS, e1, e2)) = result (fn r => emit (A.OPER {assem="add `d0, (`s0), (`s1)\n", src=[munchExp(e1), munchExp(e2)], dst=[r], jump=NONE})) (* subtracting: *) (* not sure if this one will work, can we have negitive immediate? *) | munchExp (T.BINOP(T.MINUS, e1, T.CONST i)) = result (fn r => emit (A.OPER {assem="addi `d0, (`s0), -" ^ (Int.toString i) ^ "\n", src=[munchExp(e1)], dst=[r], jump=NONE})) | munchExp (T.BINOP (T.MINUS, T.CONST i, e1)) = result (fn r => (emit (A.OPER {assem="neg `s0, `s0\n", src=[munchExp(e1)], dst=[], jump=NONE}); emit (A.OPER {assem="addi `d0, (`s0), " ^ (Int.toString i) ^ "\n", src=[munchExp(e1)], dst=[r], jump=NONE}))) | munchExp (T.BINOP (T.MINUS, e1, e2)) = result (fn r => emit (A.OPER {assem="sub `d0, (`s0), (`s1)\n", src=[munchExp(e1), munchExp(e2)], dst=[r], jump=NONE})) (* MUL DIV: *) (* maybe we can fix powers-of-two mult to be shift *) | munchExp (T.BINOP(T.MUL, e1, T.CONST i)) = result (fn r => let val t = Temp.newtemp() in emit (A.OPER {assem="ld `s0, " ^ (Int.toString i) ^ "\n", src=[t], dst=[r], jump=NONE}); emit (A.OPER {assem="mul `d0, (`s0), (`s1)\n", src=[munchExp(e1), t], dst=[r], jump=NONE}) end) | munchExp (T.BINOP (T.MUL, T.CONST i, e1)) = result (fn r => let val t = Temp.newtemp() in emit (A.OPER {assem="ld `s0, " ^ (Int.toString i) ^ "\n", src=[t], dst=[r], jump=NONE}); emit (A.OPER {assem="mul `d0, (`s0), (`s1)\n", src=[munchExp(e1), t], dst=[r], jump=NONE}) end) | munchExp (T.BINOP (T.MUL, e1, e2)) = result (fn r => emit (A.OPER {assem="mul `d0, (`s0), (`s1)\n", src=[munchExp(e1), munchExp(e2)], dst=[r], jump=NONE})) (*div*) | munchExp (T.BINOP(T.DIV, e1, T.CONST i)) = result (fn r => let val t = Temp.newtemp() in emit (A.OPER {assem="ld `s0, " ^ (Int.toString i) ^ "\n", src=[t], dst=[r], jump=NONE}); emit (A.OPER {assem="div `d0, (`s0), (`s1)\n", src=[munchExp(e1), t], dst=[r], jump=NONE}) end) | munchExp (T.BINOP (T.DIV, T.CONST i, e1)) = result (fn r => let val t = Temp.newtemp() in emit (A.OPER {assem="ld `s0, " ^ (Int.toString i) ^ "\n", src=[t], dst=[r], jump=NONE}); emit (A.OPER {assem="div `d0, (`s0), (`s1)\n", src=[munchExp(e1), t], dst=[r], jump=NONE}) end) | munchExp (T.BINOP (T.DIV, e1, e2)) = result (fn r => emit (A.OPER {assem="div `d0, (`s0), (`s1)\n", src=[munchExp(e1), munchExp(e2)], dst=[r], jump=NONE})) | munchExp (T.CONST i) = result (fn r => emit (A.OPER {assem="lw `d0, " ^ (Int.toString i) ^ "\n", src=[], dst=[r], jump=NONE})) | munchExp (T.TEMP t) = t (*idono, this is how it was in the book? *) | munchExp (T.CALL(T.NAME n,args)) = result (fn r => emit (A.OPER {assem="jalr `j0 \n", src=munchArgs(0, args), dst=[MipsFrame.RETURN], jump=SOME [n]})) (* | munchStm (T.EXP(T.CALL(e, args))) = *) (* emit (A.OPER *) (* {assem="jalr `s0\n", *) (* src=munchExp(e)::munchArgs(0, args), *) (* dst=[MipsFrame.RETURN], jump=NONE}) *) | munchExp (e) = (print "MunchExp NonExt Match Error: \n"; Printtree.printtree (TextIO.stdErr, T.EXP (e)); print "EndError\n"; result (fn r => emit (A.OPER {assem="typecheck\n", src=[], dst=[r], jump=NONE}))) in munchStm stm; rev (!ilist) end end