CVS: sml-dist/src/MLRISC/amd64/omit-frameptr amd64omit-frameptr.sml, NONE, 1.1
Matthias Blume <[email protected]> Thu, 05 Oct 2006 08:09:18 -0700
| Newsgroups | gmane.comp.lang.sml.smlnj.commits |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/smlnj/sml-dist/src/MLRISC/amd64/omit-frameptr
In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv621/amd64/omit-frameptr
Added Files:
amd64omit-frameptr.sml
Log Message:
added AMD64 stuff to MLRISC tree
--- NEW FILE: amd64omit-frameptr.sml ---
(* replaces uses and definitions of a virtual frame pointer (vfp) with the appropriate
* operation on the stack pointer.
*
* Invariant: fp = sp + delta && stack grows from high to low && fp >= sp
*
* Assumptions: At the entry node fp = sp + idelta
*
* The tricky business is to recognize that things that look like register may
* really be memory registers.
*)
functor AMD64OmitFramePointer (
structure I : AMD64INSTR
structure CFG : CONTROL_FLOW_GRAPH where I = I
structure MemRegs : MEMORY_REGISTERS where I=I
val memRegBase : CellsBasis.cell option): OMIT_FRAME_POINTER =
struct
structure CFG = CFG
structure I = I
structure C = I.C
structure CB = CellsBasis
structure HT = IntHashTable
val sp = C.esp
val dumpCfg = MLRiscControl.mkFlag ("dump-cfg-after-omit-frame-pointer",
"whether CFG is shown after omit-framepointer phase")
fun error msg = MLRiscErrorMsg.error("AMD64OmitFramePointer", msg)
fun omitframeptr{vfp:CB.cell, idelta:Int32.int option, cfg as Graph.GRAPH graph} = let
(* rewrite a list of instructions where the gap between fp and sp is delta *)
fun rewrite(instrs, idelta) = let
(* What kind of register? *)
datatype which = SP | FP | OTHER
fun isSp cell = CB.sameColor(cell, sp)
fun isVfp cell = CB.sameColor(cell, vfp)
fun which(cell) = if isSp(cell) then SP else if isVfp(cell) then FP else OTHER
fun either(cell) = isSp(cell) orelse isVfp(cell)
(* Has the instruction been rewritten? *)
val changedFlag = ref false
(*
* rewrite a single instruction assuming gap (fp=sp+delta)
* returns NONE is instruction is deleted and SOME(instruction) otherwise.
*)
fun doInstr(instr, delta:Int32.int option) = let
(* if a delta exists then add to it,
* otherwise maintain that there is no delta
*)
fun addToDelta i =
(case delta
of SOME d => SOME(i+d)
| NONE => NONE
(*esac*))
fun incOffset(i) =
(case delta
of NONE => error "incOffset"
| SOME k => k+i
(*esac*))
fun incDisp(I.Immed i) = I.Immed(incOffset(i))
| incDisp _ = error "incDisp" (* CONSTANTS? *)
fun operand(opnd as I.Displace{base, disp, mem}) =
if isVfp base then
(changedFlag := true;
I.Displace{base=sp, mem=mem, disp=incDisp(disp)})
else opnd
| operand(opnd as I.Indexed{base, index, scale, disp, mem}) =
if isVfp index then
error "operand: frame pointer used in index"
else (case base
of NONE => opnd
| SOME b =>
if isVfp b then
(changedFlag := true;
I.Indexed{base=SOME(sp), index=index, scale=scale, mem=mem,
disp=incDisp(disp)})
else opnd
(*esac*))
| operand(opnd as I.FDirect _) =
operand(MemRegs.memReg{reg=opnd, base=Option.valOf memRegBase})
| operand(opnd) = opnd
fun annotate(i, k:Int32.int option) = let
val instr =
if !changedFlag then
(changedFlag := false;
case k
of NONE => i
| SOME d =>
if d <> 0 then let
val cmt = "offset adjusted to " ^ Int32.toString d
val ann = #create MLRiscAnnotations.COMMENT cmt
in I.ANNOTATION{i=i, a=ann}
end
else i
(*esac*))
else i
in (SOME(instr),k)
end
fun unchanged(i:I.instr) = annotate(I.INSTR i, delta)
fun changedto(i, k) = annotate(I.INSTR i, k)
fun compare(test, lsrc, rsrc) = unchanged(test{lsrc=operand(lsrc), rsrc=operand(rsrc)})
fun float(oper, opnd) = unchanged(oper(operand(opnd)))
fun doAMD64Instr (instr: I.instr) =
(case instr
of I.JMP(opnd,labs) => unchanged(I.JMP(operand opnd, labs))
| I.JCC{cond:I.cond, opnd:I.operand} =>
unchanged(I.JCC{cond=cond, opnd=operand(opnd)})
| I.CALL{opnd, defs, uses, cutsTo, mem, return, pops=0} =>
unchanged(I.CALL{opnd=operand(opnd), defs=defs, uses=uses,
cutsTo=cutsTo, mem=mem, pops=0,
return=return})
| I.CALL{opnd, defs, uses, cutsTo, mem, return, pops} =>
changedto(I.CALL{opnd=operand(opnd), defs=defs, uses=uses,
cutsTo=cutsTo, mem=mem, pops=pops,
return=return},
addToDelta(~pops))
| I.ENTER{src1=I.Immed i1, src2=I.Immed i2} => changedto(instr, addToDelta(i1 + i2*4))
| I.LEAVE => (SOME(I.INSTR instr), NONE)
| I.RET opnd => (SOME(I.INSTR instr), NONE)
| I.MOVE{mvOp:I.move, src=I.Direct s, dst=I.Direct d} =>
(case (which d, which s)
of (FP, SP) => (NONE, SOME 0)
| (SP, FP) => (case delta
of NONE => error "MOVE: (SP, FP)"
| SOME 0 => (NONE, SOME 0)
| SOME n => let
val addr = I.Displace{base=sp, disp=I.Immed(n), mem=I.Region.stack}
in
(SOME(I.lea{r32=sp, addr=addr}), SOME 0)
end
(*esac*))
| (OTHER, OTHER) => unchanged(instr)
| (FP, FP) => (NONE, delta)
| (SP, SP) => (NONE, delta)
| (FP, _) => error "MOVE: to FP"
| (SP, _) => error "MOVE: to SP"
| (OTHER, SP) => unchanged(instr)
| (OTHER, FP) => error "MOVE: FP to OTHER" (* d:=sp+delta; lazy!*)
(*esac*))
| I.MOVE{mvOp, src, dst as I.Direct d} =>
if either(d) then error "MOVE: assignment to FP/SP"
else unchanged(I.MOVE{mvOp=mvOp, src=operand(src), dst=dst})
| I.MOVE{mvOp, src, dst} =>
unchanged(I.MOVE{mvOp=mvOp, src=operand(src), dst=operand(dst)})
| I.LEA{r32:CB.cell, addr as I.Displace{base, disp=I.Immed d, mem}} =>
(case (which r32, which base)
of (SP, SP) =>
(* assumes stack grows from high to low.
* if sp is incremented by a positive delta, then the gap is
* reduced by delta-d;
* if sp is decremented, the the gap is increased and d is negative.
*)
changedto(instr, addToDelta(~d))
| (SP, FP) =>
(* sp = fp + d
* or sp = sp + delta + d
*)
changedto(I.LEA{r32=r32, addr=operand(addr)}, SOME(incOffset(d)))
| (FP, FP) =>
(* fp = fp + d
* if d is positive, then the gap is increased to delta+d,
* if d is negative, then the gap is reduced.
*)
(NONE, SOME(incOffset(d)))
| (FP, SP) => (NONE, addToDelta(d))
| (SP, OTHER) => error "LEA: sp changed by non-immed"
| (FP, OTHER) => error "LEA: fp changed by non-immed"
| _ => unchanged(instr)
(*esac*))
| I.LEA{r32, addr} =>
if either(r32) then error "LEA: SP/FP changed by non-immed"
else unchanged(I.LEA{r32=r32, addr=operand(addr)})
| I.CMPL{lsrc: I.operand, rsrc: I.operand} => compare(I.CMPL, lsrc, rsrc)
| I.CMPW{lsrc: I.operand, rsrc: I.operand} => compare(I.CMPW, lsrc, rsrc)
| I.CMPB{lsrc: I.operand, rsrc: I.operand} => compare(I.CMPB, lsrc, rsrc)
| I.TESTL{lsrc: I.operand, rsrc: I.operand} => compare(I.TESTL, lsrc, rsrc)
| I.TESTW{lsrc: I.operand, rsrc: I.operand} => compare(I.TESTW, lsrc, rsrc)
| I.TESTB{lsrc: I.operand, rsrc: I.operand} => compare(I.TESTB, lsrc, rsrc)
| I.BITOP{bitOp:I.bitOp, lsrc: I.operand, rsrc: I.operand} =>
unchanged(I.BITOP{bitOp=bitOp, lsrc=operand(lsrc), rsrc=operand(rsrc)})
| I.BINARY{binOp=I.ADDL, src=I.Immed(k), dst=I.Direct(d)} =>
(case which d
of SP => changedto(instr, addToDelta(~k))
| FP => (NONE, SOME(incOffset(k)))
| OTHER => unchanged(instr)
(*esac*))
| I.BINARY{binOp=I.SUBL, src=I.Immed(k), dst=I.Direct(d)} =>
(case which d
of SP => changedto(instr, addToDelta(k))
| FP => (NONE, SOME(incOffset(~k)))
| OTHER => unchanged(instr)
(*esac*))
| I.BINARY{binOp, dst as I.Direct(d), src} =>
if either(d) then error "binary: assignment to SP | FP"
else unchanged(I.BINARY{binOp=binOp, src=operand(src), dst=dst})
| I.BINARY{binOp, src, dst} =>
unchanged(I.BINARY{binOp=binOp, src=operand(src), dst=operand(dst)})
| I.CMPXCHG{lock:bool, sz:I.isize, src:I.operand, dst:I.operand} =>
unchanged(I.CMPXCHG{lock=lock, sz=sz, src=operand(src), dst=operand(dst)})
| I.MULTDIV{multDivOp:I.multDivOp, src:I.operand} =>
unchanged(I.MULTDIV{multDivOp=multDivOp, src=operand(src)})
| I.MUL3{dst:CB.cell, src2:Int32.int, src1:I.operand} =>
if either(dst) then error "MUL3: assignment to FP/SP"
else unchanged(I.MUL3{dst=dst, src2=src2, src1=operand(src1)})
| I.UNARY{unOp=I.INCL, opnd as I.Direct(r)} =>
(case (which r)
of SP => changedto(instr, addToDelta(~1))
| FP => (NONE, SOME(incOffset(1)))
| OTHER => unchanged(I.UNARY{unOp=I.INCL, opnd=opnd})
(*esac*))
| I.UNARY{unOp=I.DECL, opnd as I.Direct(r)} =>
(case (which r)
of SP => changedto(instr, addToDelta(1))
| FP => (NONE, SOME(incOffset(~1)))
| OTHER => unchanged(I.UNARY{unOp=I.DECL, opnd=opnd})
(*esac*))
| I.UNARY{unOp, opnd} => unchanged(I.UNARY{unOp=unOp, opnd=operand(opnd)})
| I.SET{cond:I.cond, opnd:I.operand} =>
unchanged(I.SET{cond=cond, opnd=operand(opnd)})
| I.CMOV{cond:I.cond, src as I.Direct(s), dst:CB.cell} =>
if either(s) orelse either(dst) then
error "CMOV: FP/SP in conditional move"
else unchanged(I.CMOV{cond=cond, src=operand(src), dst=dst})
| I.PUSHL opnd => changedto(I.PUSHL(operand(opnd)), addToDelta(4))
| I.PUSHW opnd => changedto(I.PUSHW(operand(opnd)), addToDelta(2))
| I.PUSHB opnd => changedto(I.PUSHB(operand(opnd)), addToDelta(1))
| I.POP opnd => changedto(I.POP(operand(opnd)), addToDelta(~4))
| I.FBINARY{binOp:I.fbinOp, src:I.operand, dst:I.operand} =>
unchanged(I.FBINARY{binOp=binOp, src=operand(src), dst=operand(dst)})
| I.FIBINARY{binOp:I.fibinOp, src:I.operand} =>
unchanged(I.FIBINARY{binOp=binOp, src=operand(src)})
| I.FUCOM opnd => unchanged(I.FUCOM(operand opnd))
| I.FUCOMP opnd => unchanged(I.FUCOMP(operand (opnd)))
| I.FCOMI opnd => unchanged(I.FCOMI(operand opnd))
| I.FCOMIP opnd => unchanged(I.FCOMIP(operand (opnd)))
| I.FUCOMI opnd => unchanged(I.FUCOMI(operand opnd))
| I.FUCOMIP opnd => unchanged(I.FUCOMIP(operand (opnd)))
| I.FSTPL opnd => float(I.FSTPL, opnd)
| I.FSTPS opnd => float(I.FSTPS, opnd)
| I.FSTPT opnd => float(I.FSTPT, opnd)
| I.FSTL opnd => float(I.FSTL, opnd)
| I.FSTS opnd => float(I.FSTS, opnd)
| I.FLDL opnd => float(I.FLDL, opnd)
| I.FLDS opnd => float(I.FLDS, opnd)
| I.FLDT opnd => float(I.FLDT, opnd)
| I.FILD opnd => float(I.FILD, opnd)
| I.FILDL opnd => float(I.FILDLL, opnd)
| I.FILDLL opnd => float(I.FILDLL, opnd)
| I.FENV{fenvOp:I.fenvOp, opnd:I.operand} =>
unchanged(I.FENV{fenvOp=fenvOp, opnd=operand(opnd)})
| I.FMOVE{fsize:I.fsize, src:I.operand, dst:I.operand} =>
unchanged(I.FMOVE{fsize=fsize, src=operand(src), dst=operand(dst)})
| I.FILOAD{isize:I.isize, ea:I.operand, dst:I.operand} =>
unchanged(I.FILOAD{isize=isize, ea=operand(ea), dst=operand(dst)})
| I.FBINOP{fsize, binOp, lsrc, rsrc, dst} =>
unchanged(I.FBINOP{fsize=fsize, binOp=binOp, lsrc=operand(lsrc),
rsrc=operand(rsrc), dst=operand(dst)})
| I.FIBINOP{isize, binOp, lsrc, rsrc, dst} =>
unchanged(I.FIBINOP{isize=isize, binOp=binOp, lsrc=operand(lsrc),
rsrc=operand(rsrc), dst=operand(dst)})
| I.FUNOP{fsize:I.fsize, unOp:I.funOp, src:I.operand, dst:I.operand} =>
unchanged(I.FUNOP{fsize=fsize, unOp=unOp, src=operand(src),
dst=operand(dst)})
| I.FCMP{i,fsize:I.fsize, lsrc:I.operand, rsrc:I.operand} =>
unchanged(I.FCMP{i=i,fsize=fsize, lsrc=operand(lsrc), rsrc=operand(rsrc)})
| _ => unchanged(instr)
(*esac*))
in
case instr
of I.ANNOTATION{i,a} => let
val (instr, delta) = doInstr(i, delta)
in
case instr
of NONE => (NONE, delta)
| SOME(i) => annotate(I.ANNOTATION{i=i, a=a}, delta)
end
| I.COPY{k=CB.GP, dst, src, ...} => let
(* the situation where SP <- FP is somewhat complicated.
* The copy must be extracted, and a lea generated.
* Should it be before or after the parallel copy? Depends on if SP is used.
* However, will such a thing ever exist in a parallel copy!?
*)
fun okay(s, d, acc) =
(case (which s, which d)
of (FP, SP) => true
| (SP, FP) => error "COPY:SP<-FP; lazy!"
| (SP, OTHER) => error "COPY:SP<-OTHER"
| (FP, OTHER) => error "COPY:FP<-OTHER"
| (OTHER, SP) => error "COPY:OTHER<-SP"
| (OTHER, FP) => error "COPY:OTHER<-FP"
| _ => acc
(*esac*))
in annotate(instr, if ListPair.foldl okay false (dst, src) then SOME 0 else delta)
end
| I.INSTR instr => doAMD64Instr instr
| _ => annotate(instr, delta) (* unchanged *)
end (*doInstr*)
(* rewrite instructions *)
fun doInstrs([], instrs, delta) = (instrs, delta)
| doInstrs(instr::rest, acc, delta) = let
val (instr, delta2) = doInstr(instr, delta)
in
case instr
of NONE => doInstrs(rest, acc, delta2)
| SOME(i) => doInstrs(rest, i::acc, delta2)
end
in doInstrs(instrs, [], idelta)
end (* rewrite *)
(* rewrite blocks using a depth first traversal of the blocks *)
val info : {visited:bool, delta: Int32.int option} HT.hash_table =
HT.mkTable(32, General.Fail "AMD64OmitFramePtr: Not Found")
val noInfo = {visited=false, delta=NONE}
fun dfs (nid, delta) = let
fun doSucc(delta) =
app (fn snid => dfs(snid, delta)) (#succ graph nid)
val CFG.BLOCK{insns, kind, ...} = #node_info graph nid
in
case kind
of CFG.STOP => ()
| CFG.START => doSucc(delta)
| CFG.NORMAL => let
val {visited, delta=d} = Option.getOpt(HT.find info nid, noInfo)
fun sameDelta(NONE, NONE) = true
| sameDelta(SOME i1: Int32.int option, SOME i2) = i1 = i2
| sameDelta _ = false
in
if visited then (if sameDelta(d, delta) then () else error "dfs")
else let
val (instrs, delta2) = rewrite(rev(!insns), delta)
in
insns := instrs;
HT.insert info (nid, {visited=true, delta=delta});
doSucc(delta2)
end
end
(*esac*)
end
val CB.CELL{col, ...} = vfp
in
(*
* check that virtual frame pointer is a pseudo register or
* aliased to the stack pointer.
*)
case !col
of CB.PSEUDO => app (fn nid => dfs(nid, idelta)) (#entries graph ())
| _ => error "virtual frame pointer not a pseudo register"
(*esac*)
(* output cluster *)
(* if !dumpCfg then
PC.printCluster TextIO.stdOut "after omit frame pointer" cl
else () *)
end
end
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV