2 * X86 instruction/operand internal representation and manipulation
3 * Author: Joshua Wise <jwise@andrew.cmu.edu>
4 * Author: Chris Lu <czl@andrew.cmu.edu>
11 EAX | EBX | ECX | EDX | ESI | EDI | EBP | RSP | R8D | R9D | R10D | R11D | R12D | R13D | R14D | R15D
12 (* operands to instructions *)
13 datatype size = Byte | Word | Long | Qword
14 datatype oper = REG of reg | TEMP of Temp.temp | CONST of Word32.word | REL of (oper * oper) | STACKARG of int | OSIZE of (size * oper)
15 datatype cc = E | NE | GE | LE | L | G
20 LABEL of Label.label |
25 IMUL3 of oper * oper * Word32.word |
39 Jcc of cc * Label.label |
40 CALL of Symbol.symbol * int |
41 MOVZB of oper * oper |
46 structure OperSet : ORD_SET
47 where type Key.ord_key = oper;
48 structure LiveMap : ORD_MAP
49 where type Key.ord_key = int;
52 val sizeoper : oper -> size * oper
53 val stripsize : oper -> oper
54 val osize : oper -> size
55 val cmpoper : oper * oper -> order
56 val opereq : oper * oper -> bool
57 val regname : size -> reg -> string
58 val regtonum : reg -> int
59 val numtoreg : int -> reg
60 val ccname : cc -> string
61 val opsused : insn list -> OperSet.set
62 val prettyprint_oper : size -> oper -> string
63 val prettyprint : insn -> string
66 structure x86 :> X86 =
71 EAX | EBX | ECX | EDX | ESI | EDI | EBP | RSP | R8D | R9D | R10D | R11D | R12D | R13D | R14D | R15D
72 datatype size = Byte | Word | Long | Qword
73 datatype oper = REG of reg | TEMP of Temp.temp | CONST of Word32.word | REL of (oper * oper) | STACKARG of int | OSIZE of (size * oper)
74 datatype cc = E | NE | GE | LE | L | G
78 LABEL of Label.label |
83 IMUL3 of oper * oper * Word32.word |
97 Jcc of cc * Label.label |
98 CALL of Symbol.symbol * int |
99 MOVZB of oper * oper |
104 type func = Ast.ident * insn list
106 (* gives name of reg *)
108 [ (EAX, ("al", "ax", "eax", "rax")),
109 (EBX, ("bl", "bx", "ebx", "rbx")),
110 (ECX, ("cl", "cx", "ecx", "rcx")),
111 (EDX, ("dl", "dx", "edx", "rdx")),
112 (ESI, ("sil", "si", "esi", "rsi")),
113 (EDI, ("dil", "di", "edi", "rdi")),
114 (EBP, ("bpl", "bp", "ebp", "rbp")),
115 (RSP, ("spl", "sp", "esp", "rsp")),
116 (R8D, ("r8b", "r8w", "r8d", "r8")),
117 (R9D, ("r9b", "r9w", "r9d", "r9")),
118 (R10D, ("r10b", "r10w", "r10d", "r10")),
119 (R11D, ("r11b", "r11w", "r11d", "r11")),
120 (R12D, ("r12b", "r12w", "r12d", "r12")),
121 (R13D, ("r13b", "r13w", "r13d", "r13")),
122 (R14D, ("r14b", "r14w", "r14d", "r14")),
123 (R15D, ("r15b", "r15w", "r15d", "r15")) ];
127 val (n, (b, w, l, q)) = valOf (List.find (fn (r, _) => r = reg) regnames)
143 (* gives number (color) associated with reg *)
158 | regtonum EBP = 14 (* Dummy numbers -- not permitted for allocation, but there so that we can compare *)
161 (* gives reg associated with number (color) *)
176 | numtoreg n = raise ErrorMsg.InternalError ("numtoreg: Unknown register "^(Int.toString n))
178 (* register compare *)
179 fun regcmp (r1, r2) = Int.compare (regtonum r1, regtonum r2)
181 (* operand compare; arbitrary order imposed to make
182 * various things easier (e.g. liveness, for sorting)
184 fun cmpoper (REG(reg1), REG(reg2)) = regcmp (reg1, reg2)
185 | cmpoper (TEMP(temp1), TEMP(temp2)) = Temp.compare (temp1,temp2)
186 | cmpoper (CONST(const1), CONST(const2)) = Word32.compare (const1, const2)
187 | cmpoper (REL (r1, i1), REL (r2, i2)) =
189 val order1 = cmpoper (r1, r2)
190 val order2 = cmpoper (i1, i2)
192 if (order1 = EQUAL) then order2
195 | cmpoper (CONST _, _) = LESS
196 | cmpoper (REG _, _) = LESS
197 | cmpoper (REL _, _) = LESS
198 | cmpoper (_, _) = GREATER
200 fun opereq (REG a, REG b) = a = b
201 | opereq (TEMP a, TEMP b) = Temp.eq (a, b)
202 | opereq (CONST a, CONST b) = a = b
203 | opereq (REL (a1, b1), REL (a2, b2)) = opereq (a1,a2) andalso opereq (b1,b2)
204 (* | opereq (OSIZE (s1, o1), OSIZE (s2, o2)) = (s1 = s2) andalso opereq (o1, o2)*) (* This breaks the peepholer, shit *)
205 | opereq (_, _) = false
207 structure OperSet = ListSetFn (
210 val compare = cmpoper
213 structure LiveMap = SplayMapFn(struct
215 val compare = Int.compare
218 fun opsused nil = OperSet.empty
219 | opsused ((DIRECTIVE _)::l) = opsused l
220 | opsused ((COMMENT _)::l) = opsused l
221 | opsused ((LABEL _)::l) = opsused l
222 | opsused ((MOV (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
223 | opsused ((LEA (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
224 | opsused ((SUB (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
225 | opsused ((IMUL (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
226 | opsused ((IMUL3 (dst, src, _))::l) = OperSet.addList (opsused l, [dst, src])
227 | opsused ((ADD (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
228 | opsused ((IDIV (src))::l) = OperSet.addList (opsused l, [src, REG EDX, REG EAX])
229 | opsused ((NEG (dst))::l) = OperSet.addList (opsused l, [dst])
230 | opsused ((NOT (dst))::l) = OperSet.addList (opsused l, [dst])
231 | opsused ((SAL (dst, shft))::l) = OperSet.addList (opsused l, [dst, shft])
232 | opsused ((SAR (dst, shft))::l) = OperSet.addList (opsused l, [dst, shft])
233 | opsused ((AND (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
234 | opsused ((OR (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
235 | opsused ((XOR (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
236 | opsused ((CMP (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
237 | opsused ((TEST (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
238 | opsused ((SETcc (c, dst))::l) = OperSet.addList (opsused l, [dst])
239 | opsused ((JMP _)::l) = opsused l
240 | opsused ((Jcc _)::l) = opsused l
241 | opsused ((CALL _)::l) = opsused l
242 | opsused ((MOVZB (dst, src))::l) = OperSet.addList (opsused l, [dst, src])
243 | opsused ((CLTD)::l) = opsused l
244 | opsused ((RET)::l) = opsused l
245 | opsused ((LIVEIGN i)::l) = opsused (i::l)
251 | sts _ = raise ErrorMsg.InternalError "invalid size"
253 (* pretty prints an operand *)
259 fun osize (OSIZE (s, _)) = s
262 fun stripsize (OSIZE (_, oo)) = stripsize oo
265 fun sizeoper (OSIZE (s, oo)) = (s, stripsize oo)
266 | sizeoper oo = (Long, oo)
268 fun prettyprint_oper s (REG r) = "%" ^ (regname s r)
269 | prettyprint_oper _ (TEMP t) = (Temp.name t) ^ (sfx (sts (Temp.size t)))
270 | prettyprint_oper _ (CONST c) = "$0x" ^ (Word32.toString c)
271 | prettyprint_oper _ (REL (r, CONST n)) = (Word32Signed.toString n) ^ "(" ^ (prettyprint_oper Qword r) ^ ")"
272 | prettyprint_oper s (REL (r1, r2)) = "(" ^ (prettyprint_oper Qword (stripsize r1)) ^ "," ^ (prettyprint_oper Qword (stripsize r2)) ^ ")"
273 | prettyprint_oper _ (STACKARG i) = "arg#"^Int.toString i
274 | prettyprint_oper _ (OSIZE (s, oo)) = prettyprint_oper s (stripsize oo)
276 (* pretty prints (no...) *)
277 fun prettyprint (DIRECTIVE(str)) = str ^ "\n"
278 | prettyprint (COMMENT(str)) = "// " ^ str ^ "\n"
279 | prettyprint (LABEL(l)) = Label.name l ^ ":\n"
280 | prettyprint (LEA(dst, src)) = "\tlea" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
281 | prettyprint (MOV(dst, src)) = "\tmov" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
282 | prettyprint (SUB(dst, src)) = "\tsub" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
283 | prettyprint (IMUL(dst, src)) = "\timul" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
284 | prettyprint (IMUL3(dst, tmp, const)) = "\timul" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (CONST const)) ^ ", " ^ (prettyprint_oper (osize dst) (stripsize tmp)) ^ ", " ^ (prettyprint_oper (osize dst) dst) ^ "\n"
285 | prettyprint (ADD(dst, src)) = "\tadd" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
286 | prettyprint (IDIV(src)) = "\tidiv" ^ (sfx (osize src)) ^ "\t" ^ (prettyprint_oper (osize src) src) ^ "\n"
287 | prettyprint (NEG (dst)) = "\tneg" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper Long dst) ^ "\n"
288 | prettyprint (NOT (dst)) = "\tnot" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper Long dst) ^ "\n"
289 | prettyprint (SAL (dst, shft)) = "\tsal" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper Byte shft) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
290 | prettyprint (SAR (dst, shft)) = "\tsar" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper Byte shft) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
291 | prettyprint (AND (dst, src)) = "\tand" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
292 | prettyprint (OR (dst, src)) = "\tor" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
293 | prettyprint (XOR (dst, src)) = "\txor" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
294 | prettyprint (CMP (dst, src)) = "\tcmp" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
295 | prettyprint (TEST (dst, src)) = "\ttest" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper (osize dst) (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
296 | prettyprint (SETcc (c, dst)) = "\tset" ^ (ccname c) ^ "\t" ^ (prettyprint_oper Byte (stripsize dst)) ^ "\n"
297 | prettyprint (JMP (label)) = "\tjmp\t" ^ (Label.name label) ^ "\n"
298 | prettyprint (Jcc (c,label)) = "\tj" ^ (ccname c) ^ "\t" ^ (Label.name label) ^ "\n"
299 | prettyprint (CALL (l,n)) = "\tcall\t" ^ Symbol.name l ^ "\t # (" ^ Int.toString n ^ "args)\n"
300 | prettyprint (MOVZB (dst, src)) = "\tmovzb" ^ (sfx (osize dst)) ^ "\t" ^ (prettyprint_oper Byte (stripsize src)) ^ ", " ^ (prettyprint_oper Long dst) ^ "\n"
301 | prettyprint (CLTD) = "\tcltd\n"
302 | prettyprint (RET) = "\tret\n"
303 | prettyprint (LIVEIGN i) = prettyprint i
304 (* | prettyprint _ = raise ErrorMsg.InternalError ("prettyprint: Type A? Hatchar de coneccion?")*)