]>
Commit | Line | Data |
---|---|---|
12aa4087 JW |
1 | (* L1 Compiler |
2 | * Gathers tiberium, fires rockets | |
3 | * Takes a list of mappings of temporaries to colors and a pseudoasm listing, | |
4 | * then produces x86 code. | |
5 | * Author: Joshua Wise <jwise@andrew.cmu.edu> | |
6 | *) | |
7 | ||
8 | signature SOLIDIFY = | |
9 | sig | |
10 | type colorings = (Temp.temp * int) list | |
11 | type asm = x86.insn list | |
12 | ||
13 | val solidify : colorings -> asm -> asm | |
14 | end | |
15 | ||
16 | structure Solidify :> SOLIDIFY = | |
17 | struct | |
18 | structure X = x86 | |
19 | structure T = Temp | |
20 | ||
21 | type colorings = (Temp.temp * int) list | |
22 | type asm = x86.insn list | |
23 | ||
24 | exception Spilled | |
25 | ||
26 | fun solidify (regmap : colorings) (instrs : asm) : asm = | |
27 | let | |
28 | (* r14d and r15d is reserved for spilling *) | |
29 | val maxreg = X.regtonum X.R13D | |
30 | fun numtoreg n = | |
31 | if (n > maxreg) | |
32 | then raise Spilled | |
33 | else X.numtoreg n | |
34 | ||
35 | fun temptonum (t: T.temp) : int = | |
36 | (List.hd | |
37 | (List.map (fn (_, n) => n) | |
38 | (List.filter (fn (a, _) => (Temp.compare (a, t) = EQUAL)) regmap))) | |
39 | ||
40 | fun temptoreg (t: T.temp) : x86.reg = | |
41 | numtoreg (temptonum t) | |
42 | handle Empty => | |
43 | (let | |
44 | val () = print (" Uncolored temp "^(Temp.name t)^" -- dead code?\n") | |
45 | in | |
46 | X.R15D (*If we don't care about the output, then it is cool to explode this; R15D is guaranteed not to be used across builtin blocks.*) | |
47 | end) | |
48 | ||
49 | val spillreg1 = X.R14D | |
50 | val spillreg2 = X.R15D | |
51 | ||
52 | val prologue = [X.DIRECTIVE "\tpush %rbx\n\tpush %r12\n\tpush %r13\n\tpush %r14\n\tpush %r15"] (* Could be done better. *) | |
53 | val epilogue = [X.DIRECTIVE "\tpop %r15\n\tpop %r14\n\tpop %r13\n\tpop %r12\n\tpop %rbx"] | |
54 | ||
55 | val numreg = foldr (Int.max) 0 (map (fn (_, n) => n) regmap) (* Number of registers used. *) | |
56 | val nspilled = Int.max (numreg - maxreg, 0) (* Number of spilled registers. *) | |
57 | fun isspilled (X.TEMP temp) = (((temptonum temp) > maxreg) handle Empty => false) (* Whether a register is spilled *) | |
58 | | isspilled _ = false | |
59 | fun stackpos (reg: int) = (reg - maxreg) * ~4 (* Stack position of some register number *) | |
60 | ||
61 | fun spill (X.TEMP temp, xreg: x86.reg) = (* Spill a register if need be. *) | |
62 | if (isspilled (X.TEMP temp)) | |
63 | then [X.MOVL (X.REL (X.RSP, stackpos (temptonum temp)), X.REG xreg)] | |
64 | else nil | |
65 | | spill _ = nil (* Nothing else can be spilled. *) | |
66 | fun unspill (X.TEMP temp, xreg: x86.reg) = (* Unspill a register if need be. *) | |
67 | if (isspilled (X.TEMP temp)) | |
68 | then [X.MOVL (X.REG xreg, X.REL (X.RSP, stackpos (temptonum temp)))] | |
69 | else nil | |
70 | | unspill _ = nil | |
71 | ||
72 | fun realoper (X.TEMP temp) = X.REG (temptoreg temp) (* Makes a operand 'real'. *) | |
73 | | realoper r = r | |
74 | fun stackoper (X.TEMP temp) = | |
75 | if not (isspilled (X.TEMP temp)) then raise ErrorMsg.InternalError "stackoper on unspilled temp?" | |
76 | else X.REL (X.RSP, stackpos (temptonum temp)) | |
77 | | stackoper _ = raise ErrorMsg.InternalError "stackoper on not temp?" | |
78 | ||
79 | fun transform (X.DIRECTIVE s) = [X.DIRECTIVE s] | |
80 | | transform (X.COMMENT s) = [X.COMMENT s] | |
81 | | transform (X.MOVL (dest, src)) = | |
82 | if (isspilled dest) | |
83 | then | |
84 | unspill (src, spillreg1) @ | |
85 | [ X.MOVL( | |
86 | realoper dest handle Spilled => stackoper dest, | |
87 | realoper src handle Spilled => X.REG spillreg1)] | |
88 | else | |
89 | [ X.MOVL( | |
90 | realoper dest handle Spilled => raise ErrorMsg.InternalError "But we said that wasn't spilled?", | |
91 | realoper src handle Spilled => stackoper src)] | |
92 | | transform (X.SUBL (dest, src)) = | |
93 | unspill (src, spillreg1) @ | |
94 | unspill (dest, spillreg2) @ | |
95 | [ X.SUBL( | |
96 | realoper dest handle Spilled => X.REG spillreg2, | |
97 | realoper src handle Spilled => X.REG spillreg1)] @ | |
98 | spill (dest, spillreg2) | |
99 | | transform (X.IMUL (dest, src)) = | |
100 | unspill (dest, spillreg1) @ | |
101 | [ X.IMUL( | |
102 | realoper dest handle Spilled => X.REG spillreg1, | |
103 | realoper src handle Spilled => stackoper src)] @ | |
104 | spill (dest, spillreg1) | |
105 | | transform (X.IMUL3 (dest, src, const)) = | |
106 | [ X.IMUL3( | |
107 | realoper dest handle Spilled => X.REG spillreg1, | |
108 | realoper src handle Spilled => stackoper src, | |
109 | const)] @ | |
110 | spill (dest, spillreg1) | |
111 | | transform (X.ADDL (dest, src)) = (* You can have either operand spilled, but not both. Pick one. *) | |
112 | if (isspilled dest) | |
113 | then | |
114 | unspill (src, spillreg1) @ | |
115 | [ X.ADDL( | |
116 | realoper dest handle Spilled => stackoper dest, | |
117 | realoper src handle Spilled => X.REG spillreg1)] | |
118 | else | |
119 | [ X.ADDL( | |
120 | realoper dest handle Spilled => raise ErrorMsg.InternalError "But we said that wasn't spilled?", | |
121 | realoper src handle Spilled => stackoper src)] | |
122 | | transform (X.LEAL (dest, src1, src2)) = | |
123 | unspill (src1, spillreg1) @ | |
124 | unspill (src2, spillreg2) @ | |
125 | [ X.LEAL( | |
126 | realoper dest handle Spilled => X.REG spillreg1, | |
127 | realoper src1 handle Spilled => X.REG spillreg1, | |
128 | realoper src2 handle Spilled => X.REG spillreg2)] @ | |
129 | spill (dest, spillreg1) | |
130 | | transform (X.IDIVL (src)) = [ X.IDIVL(realoper src handle Spilled => stackoper src)] | |
131 | | transform (X.NEG (src)) = [ X.NEG(realoper src handle Spilled => stackoper src)] | |
132 | | transform (X.CLTD) = [ X.CLTD ] | |
133 | | transform (X.RET) = epilogue @ [X.RET] | |
134 | (* | transform _ = raise ErrorMsg.InternalError ("Unimplemented transform")*) | |
135 | in | |
136 | List.concat (prologue :: (map transform instrs)) | |
137 | ||
138 | end | |
139 | end |