1 |
structure X86CG = struct |
(* |
2 |
structure I = X86Instr |
* X86 specific backend |
3 |
structure C = X86Cells |
*) |
4 |
structure R = X86CpsRegs |
structure X86CG = |
5 |
|
MachineGen |
6 |
|
( structure I = X86Instr |
7 |
structure F = X86FlowGraph |
structure F = X86FlowGraph |
8 |
structure Asm = X86AsmEmitter |
structure R = X86CpsRegs |
|
structure MLTree = X86MLTree |
|
|
structure B = MLTree.BNames |
|
|
structure MachSpec = X86Spec |
|
|
structure Ctrl = Control.MLRISC |
|
9 |
structure CG = Control.CG |
structure CG = Control.CG |
10 |
|
|
11 |
structure P = X86Props(X86Instr) |
structure MachSpec = X86Spec |
12 |
|
structure PseudoOps = X86PseudoOps |
13 |
|
structure CpsRegs = X86CpsRegs |
14 |
|
structure InsnProps = X86Props(X86Instr) |
15 |
|
structure Asm = X86AsmEmitter |
16 |
|
|
17 |
structure FreqProps = FreqProps(P) |
val stack = I.Region.stack |
18 |
|
val esp = I.C.esp |
19 |
|
|
20 |
structure X86Spill = X86Spill(structure Instr=I structure Asm=X86AsmEmitter) |
fun error msg = MLRiscErrorMsg.error("X86CG",msg) |
21 |
|
|
22 |
structure PrintFlowGraph= |
structure MLTreeComp= |
23 |
PrintClusterFn(structure Flowgraph=X86FlowGraph |
X86(structure X86Instr=X86Instr |
24 |
structure Asm = X86AsmEmitter) |
structure X86MLTree=X86MLTree |
25 |
|
val tempMem=I.Displace{base=esp, disp=I.Immed 304, mem=stack} |
26 |
|
) |
27 |
|
|
28 |
structure X86Jumps = |
structure X86Jumps = |
29 |
X86Jumps(structure Instr=X86Instr |
X86Jumps(structure Instr=X86Instr |
34 |
structure BackPatch = |
structure BackPatch = |
35 |
BackPatch(structure Jumps=X86Jumps |
BackPatch(structure Jumps=X86Jumps |
36 |
structure Emitter=X86MCEmitter |
structure Emitter=X86MCEmitter |
37 |
structure Props=P |
structure Props=InsnProps |
38 |
structure Flowgraph=X86FlowGraph |
structure Flowgraph=X86FlowGraph |
39 |
structure Asm=X86AsmEmitter |
structure Asm=X86AsmEmitter |
40 |
structure CodeString=CodeString) |
structure CodeString=CodeString) |
41 |
|
|
42 |
fun error msg = ErrorMsg.impossible ("X86CG." ^ msg) |
structure PrintFlowGraph= |
43 |
|
PrintClusterFn(structure Flowgraph=X86FlowGraph |
44 |
|
structure Asm = X86AsmEmitter) |
45 |
|
|
46 |
|
structure X86Spill = X86Spill(structure Instr=I structure Asm=Asm) |
47 |
|
|
48 |
val toInt32 = Int32.fromInt |
val toInt32 = Int32.fromInt |
49 |
fun cacheOffset r = I.Immed(toInt32(X86Runtime.vregStart + (r-8)*4)) |
fun cacheOffset r = I.Immed(toInt32(X86Runtime.vregStart + (r-8)*4)) |
50 |
|
|
|
val stack = X86Instr.Region.stack |
|
|
val MLTree.REG(_,stackptr) = X86CpsRegs.stackptr |
|
|
|
|
51 |
structure X86RewritePseudo= |
structure X86RewritePseudo= |
52 |
X86RewritePseudo(structure Instr=X86Instr |
X86RewritePseudo(structure Instr=X86Instr |
53 |
structure Flowgraph=X86FlowGraph |
structure Flowgraph=X86FlowGraph |
54 |
structure Shuffle=X86Shuffle |
structure Shuffle=X86Shuffle |
55 |
fun ea r = I.Displace{base=C.esp, disp=cacheOffset r, |
fun ea r = I.Displace{base=esp, disp=cacheOffset r, |
56 |
mem=I.Region.stack}) |
mem=stack} |
57 |
|
) |
58 |
|
|
59 |
|
|
60 |
val intSpillCnt = Ctrl.getInt "ra-int-spills" |
val intSpillCnt = MLRiscControl.getCounter "ra-int-spills" |
61 |
val floatSpillCnt = Ctrl.getInt "ra-float-spills" |
val floatSpillCnt = MLRiscControl.getCounter "ra-float-spills" |
62 |
val intReloadCnt = Ctrl.getInt "ra-int-reloads" |
val intReloadCnt = MLRiscControl.getCounter "ra-int-reloads" |
63 |
val floatReloadCnt = Ctrl.getInt "ra-float-reloads" |
val floatReloadCnt = MLRiscControl.getCounter "ra-float-reloads" |
64 |
val x86CfgDebugFlg = Ctrl.getFlag "x86-cfg-debug" |
val x86CfgDebugFlg = MLRiscControl.getFlag "x86-cfg-debug" |
65 |
|
|
66 |
structure RegAllocation : sig |
structure RA = |
|
val ra : X86FlowGraph.cluster -> X86FlowGraph.cluster |
|
|
end = |
|
67 |
struct |
struct |
68 |
|
structure F = F |
69 |
|
|
70 |
(* create integer and floating point register allocators *) |
(* create integer and floating point register allocators *) |
71 |
structure X86Ra = |
structure X86Ra = |
72 |
X86RegAlloc(structure P = P |
X86RegAlloc(structure P = InsnProps |
73 |
structure I = X86Instr |
structure I = X86Instr |
74 |
structure F = X86FlowGraph |
structure F = X86FlowGraph |
75 |
structure Asm = X86AsmEmitter) |
structure Asm = X86AsmEmitter) |
79 |
val first=32) |
val first=32) |
80 |
|
|
81 |
structure FloatRaUser : RA_USER_PARAMS = struct |
structure FloatRaUser : RA_USER_PARAMS = struct |
82 |
structure I = X86Instr |
structure I = I |
83 |
structure B = B |
structure B = F.B |
84 |
|
|
85 |
val nFreeRegs = length R.availF |
val nFreeRegs = length R.availF |
86 |
val dedicated = R.dedicatedF |
val dedicated = R.dedicatedF |
87 |
fun copyInstr((rds, rss), I.FCOPY{tmp, ...}) = |
fun copyInstr((rds as [_], rss as [_]), _) = |
88 |
|
I.FCOPY{dst=rds, src=rss, tmp=NONE} |
89 |
|
| copyInstr((rds, rss), I.FCOPY{tmp, ...}) = |
90 |
I.FCOPY{dst=rds, src=rss, tmp=tmp} |
I.FCOPY{dst=rds, src=rss, tmp=tmp} |
91 |
|
|
92 |
val getreg = FR.getreg |
val getreg = FR.getreg |
94 |
|
|
95 |
(* register allocation for floating point registers *) |
(* register allocation for floating point registers *) |
96 |
fun spill{instr, reg, regmap, id} = let |
fun spill{instr, reg, regmap, id} = let |
97 |
val slot = I.Displace{base=stackptr, disp=getFregLoc reg, |
(* val _ = floatSpillCnt := !floatSpillCnt + 1 *) |
98 |
mem=I.Region.stack} |
val slot = I.Displace{base=esp, disp=getFregLoc reg, mem=stack} |
99 |
fun spillInstr(r) = [I.FLD(I.FDirect(r)), I.FSTP(slot)] |
fun spillInstr(r) = [I.FLD(I.FDirect(r)), I.FSTP(slot)] |
100 |
in |
in |
101 |
case instr |
case instr |
104 |
in |
in |
105 |
case tmp |
case tmp |
106 |
of SOME(I.Direct r) => |
of SOME(I.Direct r) => |
107 |
if r=reg then let |
if regmap r=reg then let |
108 |
val slot = I.Displace{base=stackptr, disp=getFregLoc reg, |
val slot = I.Displace{base=esp, disp=getFregLoc reg, |
109 |
mem=I.Region.stack} |
mem=stack} |
110 |
val fcopy = I.FCOPY{dst=dst, src=src, tmp=SOME slot} |
val fcopy = I.FCOPY{dst=dst, src=src, tmp=SOME slot} |
111 |
in {code=[], proh=[], instr= SOME fcopy} |
in {code=[], proh=[], instr= SOME fcopy} |
112 |
end |
end |
119 |
end |
end |
120 |
|
|
121 |
fun reload{instr, reg, regmap, id} = let |
fun reload{instr, reg, regmap, id} = let |
122 |
val slot = I.Displace{base=stackptr, disp=getFregLoc reg, |
(* val _ = floatReloadCnt := !floatReloadCnt + 1 *) |
123 |
mem=I.Region.stack} |
val slot = I.Displace{base=esp, disp=getFregLoc reg, mem=stack} |
124 |
fun reloadInstr(r, rest) = I.FLD(slot) :: I.FSTP(I.FDirect r) :: rest |
fun reloadInstr(r, rest) = I.FLD(slot) :: I.FSTP(I.FDirect r) :: rest |
125 |
in |
in |
126 |
case instr |
case instr |
146 |
val first=0) |
val first=0) |
147 |
|
|
148 |
structure IntRa32User : RA_USER_PARAMS = struct |
structure IntRa32User : RA_USER_PARAMS = struct |
149 |
structure I = X86Instr |
structure I = I |
150 |
structure B = B |
structure B = F.B |
151 |
|
|
152 |
val nFreeRegs = length (availR32) |
val nFreeRegs = length (availR32) |
153 |
val dedicated = X86CpsRegs.dedicatedR |
val dedicated = X86CpsRegs.dedicatedR |
154 |
fun copyInstr((rds, rss), I.COPY{tmp, ...}) = |
fun copyInstr((rds as [_], rss as [_]), _) = |
155 |
|
I.COPY{dst=rds, src=rss, tmp=NONE} |
156 |
|
| copyInstr((rds, rss), I.COPY{tmp, ...}) = |
157 |
I.COPY{dst=rds, src=rss, tmp=tmp} |
I.COPY{dst=rds, src=rss, tmp=tmp} |
158 |
|
|
159 |
(* avoid the physical registers when possible. *) |
(* avoid the physical registers when possible. *) |
178 |
val getRegLoc = X86StackSpills.getRegLoc |
val getRegLoc = X86StackSpills.getRegLoc |
179 |
|
|
180 |
fun spill{instr, reg, regmap, id} = let |
fun spill{instr, reg, regmap, id} = let |
181 |
val slot = I.Displace{base=stackptr, disp=getRegLoc reg, |
(* val _ = intSpillCnt := !intSpillCnt + 1 *) |
182 |
mem=I.Region.stack} |
val slot = I.Displace{base=esp, disp=getRegLoc reg, mem=stack} |
183 |
fun spillInstr(r) = |
fun spillInstr(r) = |
184 |
[I.MOVE{mvOp=I.MOVL, src=I.Direct r, dst=slot}] |
[I.MOVE{mvOp=I.MOVL, src=I.Direct r, dst=slot}] |
185 |
in |
in |
189 |
in |
in |
190 |
case tmp |
case tmp |
191 |
of SOME(I.Direct r) => |
of SOME(I.Direct r) => |
192 |
if r=reg then |
if regmap r=reg then |
193 |
{code=[], proh=[], |
{code=[], proh=[], |
194 |
instr= |
instr= |
195 |
SOME(I.COPY |
SOME(I.COPY |
196 |
{dst=dst, src=src, |
{dst=dst, src=src, |
197 |
tmp=SOME(I.Displace{base=stackptr, disp=getRegLoc r, |
tmp=SOME(I.Displace{base=esp, disp=getRegLoc r, |
198 |
mem=I.Region.stack})})} |
mem=stack})})} |
199 |
else |
else |
200 |
spillCpy(dst, src) |
spillCpy(dst, src) |
201 |
| _ => spillCpy(dst, src) |
| _ => spillCpy(dst, src) |
204 |
end |
end |
205 |
|
|
206 |
fun reload{instr, reg, regmap, id} = let |
fun reload{instr, reg, regmap, id} = let |
207 |
val slot = I.Displace{base=stackptr, disp=getRegLoc reg, |
(* val _ = intReloadCnt := !intReloadCnt + 1 *) |
208 |
mem=I.Region.stack} |
val slot = I.Displace{base=esp, disp=getRegLoc reg, mem=stack} |
209 |
fun reloadInstr(r, rest) = |
fun reloadInstr(r, rest) = |
210 |
I.MOVE{mvOp=I.MOVL, src=slot, dst=I.Direct r}::rest |
I.MOVE{mvOp=I.MOVL, src=slot, dst=I.Direct r}::rest |
211 |
in |
in |
219 |
|
|
220 |
structure IntRA32 = X86Ra.IntRa(structure RaUser= IntRa32User) |
structure IntRA32 = X86Ra.IntRa(structure RaUser= IntRa32User) |
221 |
|
|
222 |
val spillSlotTbl : int Intmap.intmap option ref = ref NONE |
fun noSpillSlotTbl _ = error "No spillSlotTbl" |
223 |
|
|
224 |
|
val spillSlotTbl : (int -> int) ref = ref noSpillSlotTbl |
225 |
|
|
226 |
structure GR8 = GetReg(val nRegs=8 val available=X86CpsRegs.availR |
structure GR8 = GetReg(val nRegs=8 val available=X86CpsRegs.availR |
227 |
val first=0) |
val first=0) |
228 |
|
|
229 |
structure IntRa8User : RA_USER_PARAMS = struct |
structure IntRa8User : RA_USER_PARAMS = struct |
230 |
structure I = X86Instr |
structure I = I |
231 |
structure B = B |
structure B = F.B |
232 |
|
|
233 |
val nFreeRegs = length X86CpsRegs.availR |
val nFreeRegs = length X86CpsRegs.availR |
234 |
val dedicated = R.dedicatedR |
val dedicated = R.dedicatedR |
235 |
fun copyInstr((rds, rss), I.COPY{tmp, ...}) = |
fun copyInstr((rds as [_], rss as [_]), _) = |
236 |
|
I.COPY{dst=rds, src=rss, tmp=NONE} |
237 |
|
| copyInstr((rds, rss), I.COPY{tmp, ...}) = |
238 |
I.COPY{dst=rds, src=rss, tmp=tmp} |
I.COPY{dst=rds, src=rss, tmp=tmp} |
|
| copyInstr((rds, rss), instr) = |
|
|
let val Asm.S.STREAM{emit,...} = Asm.makeStream() |
|
|
in emit (fn r => r) instr; |
|
|
error "copyInstr" |
|
|
end |
|
239 |
|
|
240 |
val getreg = GR8.getreg |
val getreg = GR8.getreg |
241 |
|
|
242 |
fun getRegLoc reg = let |
fun getRegLoc reg = let |
243 |
val recommended = Intmap.map (Option.valOf (!spillSlotTbl)) reg |
val recommended = ! spillSlotTbl reg |
244 |
in |
in |
245 |
if recommended < 32 then cacheOffset recommended |
if recommended < 32 then cacheOffset recommended |
246 |
else error ("getRegLoc:RA8 " ^ Int.toString recommended ^ "\n") |
else error ("getRegLoc:RA8 " ^ Int.toString recommended ^ "\n") |
248 |
|
|
249 |
(* register allocation for general purpose registers *) |
(* register allocation for general purpose registers *) |
250 |
fun spill{instr, reg, regmap, id} = let |
fun spill{instr, reg, regmap, id} = let |
251 |
val slot = I.Displace{base=stackptr, disp=getRegLoc reg, |
(* val _ = intSpillCnt := !intSpillCnt + 1 *) |
252 |
mem=I.Region.stack} |
val slot = I.Displace{base=esp, disp=getRegLoc reg, mem=stack} |
253 |
fun spillInstr(r) = |
fun spillInstr(r) = |
254 |
[I.MOVE{mvOp=I.MOVL, src=I.Direct r, dst=slot}] |
[I.MOVE{mvOp=I.MOVL, src=I.Direct r, dst=slot}] |
255 |
in |
in |
256 |
case instr |
case instr |
257 |
of I.COPY{tmp, dst, src, ...} => let |
of I.COPY{tmp, dst, src, ...} => let |
258 |
fun spillCpy([rd], [rs]) = {code=spillInstr(rs), proh=[], instr=NONE} |
fun spillCpy([rd], [rs]) = {code=spillInstr(rs), proh=[], |
259 |
|
instr=NONE} |
260 |
in |
in |
261 |
case tmp |
case tmp |
262 |
of SOME(I.Direct r) => |
of SOME(I.Direct r) => |
263 |
if r=reg then |
if regmap r=reg then |
264 |
{code=[], proh=[], |
{code=[], proh=[], |
265 |
instr= |
instr= |
266 |
SOME(I.COPY |
SOME(I.COPY |
267 |
{dst=dst, src=src, |
{dst=dst, src=src, |
268 |
tmp=SOME(I.Displace{base=stackptr, disp=getRegLoc r, |
tmp=SOME(I.Displace{base=esp, disp=getRegLoc r, |
269 |
mem=I.Region.stack})})} |
mem=stack})})} |
270 |
else |
else |
271 |
spillCpy(dst, src) |
spillCpy(dst, src) |
272 |
| _ => spillCpy(dst, src) |
| _ => spillCpy(dst, src) |
277 |
{code=[instr], proh=[reg], instr=NONE}) |
{code=[instr], proh=[reg], instr=NONE}) |
278 |
|
|
279 |
fun reload{instr, reg, regmap, id} = let |
fun reload{instr, reg, regmap, id} = let |
280 |
val slot = I.Displace{base=stackptr, disp=getRegLoc reg, |
(* val _ = intReloadCnt := !intReloadCnt + 1 *) |
281 |
mem=I.Region.stack} |
val slot = I.Displace{base=esp, disp=getRegLoc reg, mem=stack} |
282 |
fun reloadInstr(r, rest) = |
fun reloadInstr(r, rest) = |
283 |
I.MOVE{mvOp=I.MOVL, src=slot, dst=I.Direct r}::rest |
I.MOVE{mvOp=I.MOVL, src=slot, dst=I.Direct r}::rest |
284 |
in |
in |
298 |
(* X86StackSpills is esential; |
(* X86StackSpills is esential; |
299 |
* the rest is just to ensure repeatability between compilation runs. |
* the rest is just to ensure repeatability between compilation runs. |
300 |
*) |
*) |
301 |
(X86StackSpills.init(); GR32.reset(); FR.reset(); GR8.reset()) |
(spillSlotTbl := noSpillSlotTbl; |
302 |
|
X86StackSpills.init(); GR32.reset(); FR.reset(); GR8.reset()) |
303 |
|
|
304 |
fun ra(cluster as F.CLUSTER{regmap, ...}) = let |
fun ra(cluster as F.CLUSTER{regmap, ...}) = let |
305 |
fun rmPseudoPhysical(rmap, 32) = () (* Cells parameter *) |
fun rmPseudoPhysical(rmap, n) = |
306 |
| rmPseudoPhysical(rmap, n) = |
let val rmv = Intmap.rmv rmap |
307 |
(Intmap.rmv rmap n; rmPseudoPhysical(rmap, n+1)) |
fun loop 32 = () |
308 |
|
| loop n = (rmv n; loop(n+1)) |
309 |
fun cloneRegmap regmap = let |
in loop n end |
310 |
val new = Intmap.new(32, X86Cells.Cells) |
|
311 |
in app (Intmap.add new) (Intmap.intMapToList regmap); new |
fun cloneRegmap regmap = Intmap.copy regmap |
|
end |
|
312 |
|
|
313 |
fun setRegMap rmap |
fun setRegMap rmap |
314 |
(F.CLUSTER{blocks, entry, exit, blkCounter, annotations, ...}) = |
(F.CLUSTER{blocks, entry, exit, blkCounter, annotations, ...}) = |
322 |
fun intra32 cluster = let |
fun intra32 cluster = let |
323 |
val ra = IntRA32.ra IntRA32.REGISTER_ALLOCATION [] |
val ra = IntRA32.ra IntRA32.REGISTER_ALLOCATION [] |
324 |
val cluster' as F.CLUSTER{regmap, ...} = ra cluster |
val cluster' as F.CLUSTER{regmap, ...} = ra cluster |
325 |
in spillSlotTbl := SOME regmap; cluster' |
in spillSlotTbl := I.C.lookup regmap; cluster' |
326 |
end |
end |
327 |
|
|
328 |
fun insertPseudoPhysical(F.CLUSTER{regmap, ...}) = let |
fun insertPseudoPhysical(F.CLUSTER{regmap, ...}) = let |
329 |
|
val addIt = Intmap.add regmap |
330 |
fun add(32) = () |
fun add(32) = () |
331 |
| add(n) = (Intmap.add regmap (n, n); add(n+1)) |
| add(n) = (addIt (n, n); add(n+1)) |
332 |
in add(8) |
in add(8) |
333 |
end |
end |
334 |
|
|
335 |
fun preference r = let |
fun preference r = let |
336 |
val pref = Intmap.map (Option.valOf (!spillSlotTbl)) r |
val pref = ! spillSlotTbl r |
337 |
in if pref >= 0 andalso pref < 8 then SOME pref else NONE |
in if pref >= 0 andalso pref < 8 then SOME pref else NONE |
338 |
end handle _ => NONE |
end handle _ => NONE |
339 |
|
|
354 |
val cluster = intra32 cluster |
val cluster = intra32 cluster |
355 |
val _ = printGraph "\t---After register allocation K=32---\n" cluster |
val _ = printGraph "\t---After register allocation K=32---\n" cluster |
356 |
|
|
357 |
val (n,m) = X86RewritePseudo.rewrite 32 cluster |
val (n,m) = X86RewritePseudo.rewrite 32 (I.C.lookup regmap) cluster |
358 |
|
|
359 |
val cluster = setRegMap regmap cluster |
val cluster = setRegMap regmap cluster |
360 |
val _ = rmPseudoPhysical(regmap, 8) |
val _ = rmPseudoPhysical(regmap, 8) |
361 |
fun fromto(n,m) = if n>m then [] else n::fromto(n+1,m) |
val cluster = intra8 [(n,m)] (* preference *) cluster |
|
val cluster = intra8 (fromto(n,m)) (* preference *) cluster |
|
362 |
val _ = printGraph "\t---After register allocation K=8---\n" cluster |
val _ = printGraph "\t---After register allocation K=8---\n" cluster |
363 |
|
|
364 |
val _ = insertPseudoPhysical cluster |
val _ = insertPseudoPhysical cluster |
365 |
val cluster = floatRa cluster |
val cluster = floatRa cluster |
366 |
val _ = printGraph "\t---After floating register allocation---\n" cluster |
val _ = printGraph "\t---After floating register allocation---\n" |
367 |
|
cluster |
368 |
in |
in |
369 |
(* |
(* |
370 |
spillInit(); |
spillInit(); |
372 |
*) |
*) |
373 |
cluster |
cluster |
374 |
end |
end |
|
end (* RegAllocation *) |
|
375 |
|
|
376 |
val optimizerHook : (F.cluster -> F.cluster) option ref = ref NONE |
fun cp _ = error "copy propagation" |
377 |
|
end (* RegAllocation *) |
378 |
|
|
379 |
(* primitives for generation of X86 instruction flowgraphs *) |
) |
|
structure FlowGraphGen = |
|
|
ClusterGen(structure Flowgraph = X86FlowGraph |
|
|
structure InsnProps = P |
|
|
structure MLTree = X86MLTree |
|
|
structure Stream = X86Stream |
|
|
val optimize = optimizerHook |
|
|
val output = BackPatch.bbsched o RegAllocation.ra) |
|
|
|
|
|
(* compilation of CPS to MLRISC *) |
|
|
structure MLTreeGen = |
|
|
MLRiscGen(structure MachineSpec=MachSpec |
|
|
structure MLTreeComp= |
|
|
X86(structure Stream =X86Stream |
|
|
structure X86Instr=I |
|
|
structure X86MLTree=X86MLTree |
|
|
val tempMem=I.Displace{base=stackptr, disp=I.Immed 304, |
|
|
mem=I.Region.stack}) |
|
|
structure Cells=X86Cells |
|
|
structure C=X86CpsRegs |
|
|
structure PseudoOp=X86PseudoOps |
|
|
structure CpsTreeify=CpsTreeify |
|
|
structure Flowgen=FlowGraphGen) |
|
|
|
|
|
fun copyProp _ = error "copyProp: not defined" |
|
|
val codegen = MLTreeGen.codegen |
|
|
val finish = BackPatch.finish |
|
|
end |
|
380 |
|
|