1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
(* Stolen from John Reppy's Moby compiler:
*
* x86-leaf-opt.sml
*
* COPYRIGHT (c) 2001 Bell Labs, Lucent Technologies
*
* Optimization of leaf procedures for the IA32. We define a leaf procedure
* to be one that does not make calls and does not allocate any extra stack
* space (other than the usual linkage). We optimize by removing the saved
* frame-pointer and rewriting instructions that use the frame-pointer to
* ones that use the stack pointer.
*
* Eventually, we may support tail calls from leaf procedures.
*
*)
functor X86LeafOpt
(structure X86Instr : X86INSTR
structure FlowGraph : FLOWGRAPH where I = X86Instr
val isLeaf : FlowGraph.cluster -> bool
) : CLUSTER_OPTIMIZATION =
struct
structure F = FlowGraph
structure I = X86Instr
structure C = I.C
type flowgraph = F.cluster
val name = "X86LeafOpt"
(* is a register the frame pointer? *)
fun isFP reg = C.sameColor(reg, C.ebp)
(* is a register the stack pointer? *)
fun isSP reg = C.sameColor(reg, C.esp)
fun error msg = MLRiscErrorMsg.error("X86LeafOpt",msg)
fun err (blknum, msg) = error(concat[
"BLOCK ", Int.toString blknum, ": ", msg
])
fun optimize (F.CLUSTER cluster) = let
fun rewriteOpnd (opnd as I.Displace{base, disp, mem}) =
if (isFP base)
then (case disp
of I.Immed n =>
I.Displace{base = C.esp, disp = I.Immed(n-4), mem = mem}
| _ => error "unable to rewrite displacement operand"
(* end case *))
else opnd
| rewriteOpnd (opnd as I.Indexed{base=SOME r, index, scale, disp, mem}) =
if (isFP r)
then (case disp
of I.Immed n => I.Indexed{
base = SOME C.esp, index = index, scale = scale,
disp = I.Immed(n-4), mem = mem
}
| _ => error "unable to rewrite indexed operand"
(* end case *))
else opnd
| rewriteOpnd opnd = opnd
fun rewriteInsn insn = (case insn
of I.JMP(opnd, labs) => I.JMP(rewriteOpnd opnd, labs)
| I.JCC{cond, opnd} => I.JCC{cond = cond, opnd = rewriteOpnd opnd}
| I.CALL _ => error "unexpected call"
| I.MOVE{mvOp, src, dst} => I.MOVE{
mvOp = mvOp,
src = rewriteOpnd src,
dst = rewriteOpnd dst
}
| I.LEA{r32, addr} => I.LEA{r32 = r32, addr = rewriteOpnd addr}
| I.CMPL{lsrc, rsrc} =>
I.CMPL{lsrc = rewriteOpnd lsrc, rsrc = rewriteOpnd rsrc}
| I.CMPW{lsrc, rsrc} =>
I.CMPW{lsrc = rewriteOpnd lsrc, rsrc = rewriteOpnd rsrc}
| I.CMPB{lsrc, rsrc} =>
I.CMPB{lsrc = rewriteOpnd lsrc, rsrc = rewriteOpnd rsrc}
| I.TESTL{lsrc, rsrc} =>
I.TESTL{lsrc = rewriteOpnd lsrc, rsrc = rewriteOpnd rsrc}
| I.TESTW{lsrc, rsrc} =>
I.TESTW{lsrc = rewriteOpnd lsrc, rsrc = rewriteOpnd rsrc}
| I.TESTB{lsrc, rsrc} =>
I.TESTB{lsrc = rewriteOpnd lsrc, rsrc = rewriteOpnd rsrc}
| I.BITOP{bitOp, lsrc, rsrc} => I.BITOP{
bitOp = bitOp,
lsrc = rewriteOpnd lsrc,
rsrc = rewriteOpnd rsrc
}
| I.BINARY{binOp, src, dst} => I.BINARY{
binOp = binOp,
src = rewriteOpnd src,
dst = rewriteOpnd dst
}
| I.MULTDIV{multDivOp, src} => I.MULTDIV{
multDivOp = multDivOp, src = rewriteOpnd src
}
| I.MUL3{dst, src2, src1} => I.MUL3{
dst = dst, src2 = src2, src1 = rewriteOpnd src1
}
| I.UNARY{unOp, opnd} =>
I.UNARY{unOp = unOp, opnd = rewriteOpnd opnd}
| I.SET{cond, opnd} => I.SET{cond = cond, opnd = rewriteOpnd opnd}
| I.CMOV{cond, src, dst} => I.CMOV{
cond = cond, src = rewriteOpnd src, dst = dst
}
| I.PUSHL _ => error "unexpected pushl"
| I.PUSHW _ => error "unexpected pushw"
| I.PUSHB _ => error "unexpected pushb"
| I.POP _ => error "unexpected popl"
| I.COPY _ => error "unexpected copy"
| I.FCOPY _ => error "unexpected fcopy"
| I.FBINARY{binOp, src, dst} => I.FBINARY{
binOp = binOp, src = rewriteOpnd src, dst = rewriteOpnd dst
}
| I.FIBINARY{binOp, src} => I.FIBINARY{
binOp = binOp, src = rewriteOpnd src
}
| I.FUCOM opnd => I.FUCOM(rewriteOpnd opnd)
| I.FUCOMP opnd => I.FUCOMP(rewriteOpnd opnd)
| I.FSTPL opnd => I.FSTPL(rewriteOpnd opnd)
| I.FSTPS opnd => I.FSTPS(rewriteOpnd opnd)
| I.FSTPT opnd => I.FSTPT(rewriteOpnd opnd)
| I.FSTL opnd => I.FSTL(rewriteOpnd opnd)
| I.FSTS opnd => I.FSTS(rewriteOpnd opnd)
| I.FLDL opnd => I.FLDL(rewriteOpnd opnd)
| I.FLDS opnd => I.FLDS(rewriteOpnd opnd)
| I.FLDT opnd => I.FLDT(rewriteOpnd opnd)
| I.FILD opnd => I.FILD(rewriteOpnd opnd)
| I.FILDL opnd => I.FILDL(rewriteOpnd opnd)
| I.FILDLL opnd => I.FILDLL(rewriteOpnd opnd)
| I.FENV{fenvOp, opnd} =>
I.FENV{fenvOp = fenvOp, opnd = rewriteOpnd opnd}
| I.ANNOTATION{i, a} => I.ANNOTATION{i = rewriteInsn i, a = a}
| _ => insn
(* end case *))
(* rewrite the instructions of a block *)
fun rewriteBlock (F.BBLOCK{insns, ...}) =
insns := List.map rewriteInsn (!insns)
| rewriteBlock _ = ()
(* rewrite the exit protocol of an exit block *)
fun rewriteExit (F.BBLOCK{blknum, insns, ...}, _) = (
case !insns
of (ret as I.RET _)::I.LEAVE::rest =>
insns := ret :: rest
| (I.JMP _ :: _) => () (* non-local control flow *)
| _ => err(blknum,"unable to rewrite exit protocol")
(* end case *))
(* rewrite the entry protocol of an entry block *)
fun rewriteEntry (F.BBLOCK{blknum, insns, ...}, _) = let
fun rewrite [
I.BINARY{binOp=I.SUBL, src=I.ImmedLabel _, dst=I.Direct a},
I.MOVE{mvOp=I.MOVL, src=I.Direct b, dst=I.Direct c},
I.PUSHL(I.Direct d)
] = if ((isSP a) andalso (isSP b)
andalso (isFP c) andalso (isFP d))
then []
else err(blknum, "unable to rewrite entry protocol")
| rewrite (insn::rest) = insn :: rewrite rest
| rewrite [] = err(blknum, "unable to rewrite entry protocol")
in
insns := rewrite(!insns)
end
in
(* first, we rewrite the exit and entry blocks *)
case #exit cluster
of F.EXIT{pred, ...} => List.app rewriteExit (!pred)
(* end case *);
case #entry cluster
of F.ENTRY{succ, ...} => List.app rewriteEntry (!succ)
(* end case *);
(* then rewrite the instructions to use the %esp instead of %ebp *)
List.app rewriteBlock (#blocks cluster)
end
fun run cluster =
(if isLeaf cluster then optimize cluster else (); cluster)
end
|