structure IA32Frame : IA32FRAME = struct datatype access = InFrame of int | InReg of Temp.temp type frame = {name: Temp.label,formals: access list, noflocals: int ref} (* tentative *) datatype frag = PROC of {body: Tree.stm, frame: frame} | STRING of Temp.label * string type register = Temp.temp (* there should be better trick instead of just writing down like this... *) val EAX = Temp.newtemp() val EBX = Temp.newtemp() val ECX = Temp.newtemp() val EDX = Temp.newtemp() val ESI = Temp.newtemp() val EDI = Temp.newtemp() val EBP = Temp.newtemp() val RV = EAX val FP = EBP val wordSize = 4 val tempMap = foldl (fn ((tmp,str),tbl) => Temp.Table.enter(tbl,tmp,str)) Temp.Table.empty [(EAX,"%eax"), (EBX,"%ebx"), (ECX,"%ecx"), (EDX,"%edx"), (ESI,"%esi"), (EDI,"%edi"), (EBP,"%ebp")] val registers = [EAX,EBX,ECX,EDX,ESI,EDI,EBP] structure T = Tree structure A = Assem fun exp(InFrame(k))(e) = T.MEM(T.BINOP(T.PLUS,T.CONST(k),e)) | exp(InReg(t))(_) = T.TEMP(t) fun offsetVal(e,i) = T.MEM(T.BINOP(T.PLUS, T.MEM(e), T.BINOP(T.MUL,i,T.CONST(wordSize)))) fun convertFormals(nil,offset,formals) = formals | convertFormals(x::xs,offset,formals) = if x = true then convertFormals(xs,offset+wordSize, formals@[InFrame(offset)]) else convertFormals(xs,offset,formals@[InReg(Temp.newtemp())]) (* May need to give 8, instead of 0, to offset param of convertFormals. See IA32 CALL operation semantics for details. (Or if you put the static link address before CALLing, you don't have to be concerned about that?) *) fun newFrame({name,formals}) = {name=name, formals=convertFormals(formals,0,nil), noflocals = ref 0} fun name({name,...}:frame) = name fun formals({formals,...}:frame) = formals fun alloclocal({noflocals,...}:frame) = let fun setAccess(escape) = if escape = true then (noflocals := !noflocals + 1; InFrame(!noflocals * ~wordSize)) else InReg(Temp.newtemp()) in setAccess end fun externalCall(s,args) = T.CALL(T.NAME(Temp.namedlabel("_" ^ s)), args) (* XXX placeholder impl *) fun procEntryExit1(frame,body) = let val name = Symbol.name(name(frame)) in T.SEQ(T.LABEL(Temp.namedlabel("_proc_" ^ name)), body) end fun procEntryExit2(frame, body) = body @ [A.OPER{assem="",src=[],dst=[],jump=SOME[]}] fun procEntryExit3({name,params,locals}, body) = {prolog = "PROCEDURE " ^ Symbol.name name ^ "\n", body = body, epilog = "END " ^ Symbol.name name ^ "\n"} fun string(lab,s) = Symbol.name lab ^ ":\n" ^ "\t.ascii \"" ^ s ^ "\\0\"\n" exception IllegalState (* For each spillTemp, alloc a local variable to frame and inserts instructions - a store after each definition - a fetch before each use to body *) fun handleASpill frame (spillTemp,body) = let fun getOffset(InFrame(k)) = "-" ^ Int.toString(Int.abs(k)) | getOffset(_) = raise IllegalState val lVal = alloclocal(frame) true fun insertStore0(dst) = if List.exists (fn x => x = spillTemp) dst then [A.OPER{assem="movl\t`s1, " ^ getOffset(lVal) ^ "(`s0)", src=[FP,spillTemp],dst=[],jump=NONE}] else nil fun insertStore(nil) = nil | insertStore((x as A.OPER{dst,...})::xs) = x::insertStore0(dst) @ insertStore(xs) | insertStore((x as A.MOVE{dst,...})::xs) = x::insertStore0([dst]) @ insertStore(xs) | insertStore(x::xs) = x::insertStore(xs) fun insertFetch0(src) = if List.exists (fn x => x = spillTemp) src then [A.OPER{assem="leal\t" ^ getOffset(lVal) ^ "(`s0), `d0", src=[FP],dst=[spillTemp],jump=NONE}] else nil fun insertFetch(nil) = nil | insertFetch((x as A.OPER{src,...})::xs) = insertFetch0(src) @ x::insertFetch(xs) | insertFetch((x as A.MOVE{src,...})::xs) = insertFetch0([src]) @ x::insertFetch(xs) | insertFetch(x::xs) = x::insertFetch(xs) in insertFetch(insertStore(body)) end fun rewriteProgram(frame,body,spillList) = foldl (handleASpill frame) body spillList end