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 basicop = REG of reg |
 
  15                      CONST of Word32.word |
 
  16                      REL of ((basicop * Temp.size) * (basicop * Temp.size) * Word32.word) |
 
  18   type oper = basicop * Temp.size
 
  19   datatype cc = E | NE | GE | LE | L | G | B | BE | A | AE
 
  24     LABEL of Label.label |
 
  26     MOVSC of oper * oper |
 
  30     IMUL3 of oper * oper * Word32.word |
 
  43     CMOVcc of cc * oper * oper |
 
  45     Jcc of cc * Label.label |
 
  46     CALL of Symbol.symbol * int |
 
  47     MOVZB of oper * oper |
 
  52   structure OperSet : ORD_SET
 
  53     where type Key.ord_key = basicop;
 
  54   structure LiveMap : ORD_MAP
 
  55     where type Key.ord_key = int;
 
  57   val resize : Temp.size -> oper -> oper
 
  58   val regcmp : reg * reg -> order
 
  59   val getop : oper -> basicop
 
  60   val osize : oper -> Temp.size
 
  61   val cmpoper : oper * oper -> order
 
  62   val cmpbasic : basicop * basicop -> order
 
  63   val opereq : oper * oper -> bool
 
  64   val basiceq : basicop * basicop -> bool
 
  65   val regname : Temp.size -> reg -> string
 
  66   val regtonum : reg -> int
 
  67   val numtoreg : int -> reg
 
  68   val ccname : cc -> string
 
  69   val opsused : insn list -> OperSet.set
 
  70   val pp_oper : oper -> string
 
  71   val print : insn -> string
 
  74 structure x86 :> X86 =
 
  78     EAX | EBX | ECX | EDX | ESI | EDI | EBP | RSP | R8D | R9D | R10D | R11D | R12D | R13D | R14D | R15D
 
  79   (* operands to instructions *)
 
  80   datatype basicop = REG of reg |
 
  82                      CONST of Word32.word |
 
  83                      REL of ((basicop * Temp.size) * (basicop * Temp.size) * Word32.word) |
 
  85   datatype cc = E | NE | GE | LE | L | G | B | BE | A | AE
 
  86   type oper = basicop * Temp.size
 
  90     LABEL of Label.label |
 
  92     MOVSC of oper * oper |
 
  96     IMUL3 of oper * oper * Word32.word |
 
 107     TEST of oper * oper |
 
 109     CMOVcc of cc * oper * oper |
 
 111     Jcc of cc * Label.label |
 
 112     CALL of Symbol.symbol * int |
 
 113     MOVZB of oper * oper |
 
 118   type func = Ast.ident * insn list
 
 120   (* gives name of reg *)
 
 122     [ (EAX, ("al", "ax", "eax", "rax")),
 
 123       (EBX, ("bl", "bx", "ebx", "rbx")),
 
 124       (ECX, ("cl", "cx", "ecx", "rcx")),
 
 125       (EDX, ("dl", "dx", "edx", "rdx")),
 
 126       (ESI, ("sil", "si", "esi", "rsi")),
 
 127       (EDI, ("dil", "di", "edi", "rdi")),
 
 128       (EBP, ("bpl", "bp", "ebp", "rbp")),
 
 129       (RSP, ("spl", "sp", "esp", "rsp")),
 
 130       (R8D, ("r8b", "r8w", "r8d", "r8")),
 
 131       (R9D, ("r9b", "r9w", "r9d", "r9")),
 
 132       (R10D, ("r10b", "r10w", "r10d", "r10")),
 
 133       (R11D, ("r11b", "r11w", "r11d", "r11")),
 
 134       (R12D, ("r12b", "r12w", "r12d", "r12")),
 
 135       (R13D, ("r13b", "r13w", "r13d", "r13")),
 
 136       (R14D, ("r14b", "r14w", "r14d", "r14")),
 
 137       (R15D, ("r15b", "r15w", "r15d", "r15")) ];
 
 141       val (n, (b, w, l, q)) = valOf (List.find (fn (r, _) => r = reg) regnames)
 
 161   (* gives number (color) associated with reg *)
 
 179   (* gives reg associated with number (color) *)
 
 195     | numtoreg n = raise ErrorMsg.InternalError ("numtoreg: Invalid register "^(Int.toString n))
 
 197   (* register compare *)
 
 198   fun regcmp (r1, r2) = Int.compare (regtonum r1, regtonum r2)
 
 200   fun resize ss (a,_) = (a,ss)
 
 203   (* operand compare; arbitrary order imposed to make
 
 204    * various things easier (e.g. liveness, for sorting)
 
 206   fun cmpbasic (REG reg1, REG reg2) = regcmp (reg1, reg2)
 
 207     | cmpbasic (TEMP temp1, TEMP temp2) = Temp.compare (temp1,temp2)
 
 208     | cmpbasic (CONST(const1), CONST(const2)) = Word32.compare (const1, const2)
 
 209     | cmpbasic (REL (r1, i1, m1), REL (r2, i2, m2)) =
 
 211           val orderm = Word32.compare (m1,m2)
 
 212           val order1 = cmpbasic (getop r1, getop r2)
 
 213           val order2 = cmpbasic (getop i1, getop i2)
 
 214           val o1 = if(order1 = EQUAL) then order2 else order1
 
 216           if (o1 = EQUAL) then orderm
 
 219     | cmpbasic (CONST _, _) = LESS
 
 220     | cmpbasic (REG _, _) = LESS
 
 221     | cmpbasic (REL _, _) = LESS
 
 222     | cmpbasic (_, _) = GREATER
 
 224   fun cmpoper ((o1,s1),(o2,s2)) = (case (cmpbasic (o1,o2)) of EQUAL => Temp.cmpsize (s1,s2) | a => a)
 
 226   fun basiceq (REG a, REG b) = a = b
 
 227     | basiceq (TEMP a, TEMP b) = Temp.eq (a, b)
 
 228     | basiceq (CONST a, CONST b) = a = b
 
 229     | basiceq (REL (a1, b1, m1), REL (a2, b2, m2)) = m1 = m2 andalso basiceq (getop a1, getop a2) andalso basiceq (getop b1, getop b2)
 
 230     | basiceq (_, _) = false
 
 232   fun opereq ((o1,s1),(o2,s2)) = basiceq (o1,o2) andalso s1 = s2
 
 234   structure OperSet = ListSetFn (
 
 236       type ord_key = basicop
 
 237       val compare = cmpbasic
 
 240   structure LiveMap = SplayMapFn(struct
 
 242                                    val compare = Int.compare
 
 245   fun opsused nil = OperSet.empty
 
 246     | opsused ((DIRECTIVE _)::l) = opsused l
 
 247     | opsused ((COMMENT _)::l) = opsused l
 
 248     | opsused ((LABEL _)::l) = opsused l
 
 249     | opsused ((MOV ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 250     | opsused ((MOVSC((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 251     | opsused ((LEA ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 252     | opsused ((SUB ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 253     | opsused ((IMUL ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 254     | opsused ((IMUL3 ((dst,_), (src,_), _))::l) = OperSet.addList (opsused l, [dst, src])
 
 255     | opsused ((ADD ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 256     | opsused ((IDIV (src,_))::l) = OperSet.addList (opsused l, [src, REG EDX, REG EAX])
 
 257     | opsused ((NEG (dst,_))::l) = OperSet.addList (opsused l, [dst])
 
 258     | opsused ((NOT (dst,_))::l) = OperSet.addList (opsused l, [dst])
 
 259     | opsused ((SAL ((dst,_), (shft,_)))::l) = OperSet.addList (opsused l, [dst, shft])
 
 260     | opsused ((SAR ((dst,_), (shft,_)))::l) = OperSet.addList (opsused l, [dst, shft])
 
 261     | opsused ((AND ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 262     | opsused ((OR ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 263     | opsused ((XOR ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 264     | opsused ((CMP ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 265     | opsused ((TEST ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 266     | opsused ((SETcc (c, (dst,_)))::l) = OperSet.addList (opsused l, [dst])
 
 267     | opsused ((CMOVcc (c, (dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 268     | opsused ((JMP _)::l) = opsused l
 
 269     | opsused ((Jcc _)::l) = opsused l
 
 270     | opsused ((CALL _)::l) = opsused l
 
 271     | opsused ((MOVZB ((dst,_), (src,_)))::l) = OperSet.addList (opsused l, [dst, src])
 
 272     | opsused ((CLTD)::l) = opsused l
 
 273     | opsused ((RET)::l) = opsused l
 
 274     | opsused ((LIVEIGN i)::l) = opsused (i::l)
 
 277   fun pp_oper (REG r, s) = "%" ^ (regname s r)
 
 278     | pp_oper (TEMP t, _) = (Temp.name t) ^ (Temp.sfx (Temp.size t))
 
 279     | pp_oper (CONST c, _) = "$" ^ Word32Signed.toString c
 
 280     | pp_oper (REL ((CONST n, _), _, _), _) = Word32Signed.toString n
 
 281     | pp_oper (REL (r, (CONST n, _), _), _) = (Word32Signed.toString n) ^ "(" ^ (pp_oper r) ^ ")"
 
 282     | pp_oper (REL (r1, r2, m), _) = "(" ^ (pp_oper r1) ^ "," ^ (pp_oper r2) ^ "," ^
 
 283                                            (Word32.toString m) ^ ")"
 
 284     | pp_oper (STACKARG i, _) = "arg#"^Int.toString i
 
 286   (* pretty prints the asm *)
 
 287   fun print (DIRECTIVE(str)) = str ^ "\n"
 
 288     | print (COMMENT(str)) = "// " ^ str ^ "\n"
 
 289     | print (LABEL(l)) = Label.name l ^ ":\n"
 
 290     | print (LEA(dst, src)) = "\tlea" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 291     | print (MOV(dst, src)) = "\tmov" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 292     | print (MOVSC((d,Temp.Long), (s,Temp.Quad))) = "\tmov" ^ (Temp.sfx Temp.Long) ^ "\t" ^ (pp_oper (s,Temp.Long)) ^ ", " ^ (pp_oper (d,Temp.Long)) ^ " // sex change\n"
 
 293     | print (MOVSC((d,Temp.Quad), (s,Temp.Long))) = "\tmov" ^ (Temp.sfx Temp.Long) ^ "\t" ^ (pp_oper (s,Temp.Long)) ^ ", " ^ (pp_oper (d,Temp.Long)) ^ " // sex change\n"
 
 294     | print (MOVSC(_,_)) = raise ErrorMsg.InternalError "invalid size change"
 
 295     | print (SUB(dst, src)) = "\tsub" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 296     | print (IMUL(dst, src)) = "\timul" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 297     | print (IMUL3(dst, tmp, const)) = "\timul" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper (CONST const, Temp.Long)) ^ ", " ^ (pp_oper tmp) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 298     | print (ADD(dst, src)) = "\tadd" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 299     | print (IDIV(src)) = "\tidiv" ^ (Temp.sfx (osize src)) ^ "\t" ^ (pp_oper src) ^ "\n"
 
 300     | print (NEG (dst)) = "\tneg" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper dst) ^ "\n"
 
 301     | print (NOT (dst)) = "\tnot" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper dst) ^ "\n"
 
 302     | print (SAL (dst, shft)) = "\tsal" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper shft) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 303     | print (SAR (dst, shft)) = "\tsar" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper shft) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 304     | print (AND (dst, src)) = "\tand" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 305     | print (OR (dst, src)) = "\tor" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 306     | print (XOR (dst, src)) = "\txor" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 307     | print (CMP (dst, src)) = "\tcmp" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 308     | print (TEST (dst, src)) = "\ttest" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 309     | print (SETcc (c, dst)) = "\tset" ^ (ccname c) ^ "\t" ^ (pp_oper dst) ^ "\n"
 
 310     | print (CMOVcc (c, dst, src)) = "\tcmov" ^ (ccname c) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 311     | print (JMP (label)) = "\tjmp\t" ^ (Label.name label) ^ "\n"
 
 312     | print (Jcc (c,label)) = "\tj" ^ (ccname c) ^ "\t" ^ (Label.name label) ^ "\n"
 
 313     | print (CALL (l,n)) = "\tcall\t" ^ Symbol.name l ^ "\t # (" ^ Int.toString n ^ "args)\n"
 
 314     | print (MOVZB (dst, src)) = "\tmovzb" ^ (Temp.sfx (osize dst)) ^ "\t" ^ (pp_oper src) ^ ", " ^ (pp_oper dst) ^ "\n"
 
 315     | print (CLTD) = "\tcltd\n"
 
 316     | print (RET) = "\tret\n"
 
 317     | print (LIVEIGN i) = print i