sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 1 | |
| 2 | /*---------------------------------------------------------------*/ |
| 3 | /*--- ---*/ |
| 4 | /*--- This file (x86h_defs.c) is ---*/ |
| 5 | /*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ |
| 6 | /*--- ---*/ |
| 7 | /*---------------------------------------------------------------*/ |
| 8 | |
sewardj | 887a11a | 2004-07-05 17:26:47 +0000 | [diff] [blame] | 9 | #include "libvex_basictypes.h" |
| 10 | #include "libvex.h" |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 11 | |
| 12 | #include "vex_util.h" |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 13 | #include "host_regs.h" |
sewardj | 8af36f1 | 2004-07-21 18:53:20 +0000 | [diff] [blame] | 14 | #include "x86host_defs.h" |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 15 | |
| 16 | |
| 17 | /* --------- Registers. --------- */ |
| 18 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 19 | void ppHRegX86 ( HReg reg ) |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 20 | { |
| 21 | Int r; |
| 22 | static Char* ireg32_names[8] |
| 23 | = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" }; |
| 24 | /* Be generic for all virtual regs. */ |
| 25 | if (hregIsVirtual(reg)) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 26 | ppHReg(reg); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 27 | return; |
| 28 | } |
| 29 | /* But specific for real regs. */ |
| 30 | switch (hregClass(reg)) { |
| 31 | case HRcInt: |
| 32 | r = hregNumber(reg); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 33 | vassert(r >= 0 && r < 8); |
| 34 | vex_printf("%s", ireg32_names[r]); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 35 | return; |
| 36 | case HRcFloat: |
| 37 | r = hregNumber(reg); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 38 | vassert(r >= 0 && r < 6); |
| 39 | vex_printf("%%fake%d", r); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 40 | return; |
| 41 | case HRcVector: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 42 | vpanic("ppHRegX86: real vector reg"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 43 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 44 | vpanic("ppHRegX86"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 45 | } |
| 46 | } |
| 47 | |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 48 | HReg hregX86_EAX ( void ) { return mkHReg(0, HRcInt, False); } |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 49 | HReg hregX86_EBX ( void ) { return mkHReg(3, HRcInt, False); } |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 50 | HReg hregX86_ECX ( void ) { return mkHReg(1, HRcInt, False); } |
sewardj | 2cd80dc | 2004-07-02 15:20:40 +0000 | [diff] [blame] | 51 | HReg hregX86_EDX ( void ) { return mkHReg(2, HRcInt, False); } |
sewardj | f13a16a | 2004-07-05 17:10:14 +0000 | [diff] [blame] | 52 | HReg hregX86_ESP ( void ) { return mkHReg(4, HRcInt, False); } |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 53 | HReg hregX86_EBP ( void ) { return mkHReg(5, HRcInt, False); } |
sewardj | f13a16a | 2004-07-05 17:10:14 +0000 | [diff] [blame] | 54 | HReg hregX86_ESI ( void ) { return mkHReg(6, HRcInt, False); } |
| 55 | HReg hregX86_EDI ( void ) { return mkHReg(7, HRcInt, False); } |
| 56 | |
| 57 | void getAllocableRegs_X86 ( Int* nregs, HReg** arr ) |
| 58 | { |
| 59 | *nregs = 6; |
| 60 | *arr = LibVEX_Alloc(*nregs * sizeof(HReg)); |
sewardj | 0a5f5c8 | 2004-07-07 11:56:35 +0000 | [diff] [blame] | 61 | (*arr)[0] = hregX86_EAX(); |
| 62 | (*arr)[1] = hregX86_EBX(); |
| 63 | (*arr)[2] = hregX86_ECX(); |
| 64 | (*arr)[3] = hregX86_EDX(); |
| 65 | (*arr)[4] = hregX86_ESI(); |
| 66 | (*arr)[5] = hregX86_EDI(); |
sewardj | f13a16a | 2004-07-05 17:10:14 +0000 | [diff] [blame] | 67 | } |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 68 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 69 | |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 70 | /* --------- Condition codes, Intel encoding. --------- */ |
| 71 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 72 | Char* showX86CondCode ( X86CondCode cond ) |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 73 | { |
| 74 | switch (cond) { |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 75 | case Xcc_O: return "o"; |
| 76 | case Xcc_NO: return "no"; |
| 77 | case Xcc_B: return "b"; |
| 78 | case Xcc_NB: return "nb"; |
| 79 | case Xcc_Z: return "z"; |
| 80 | case Xcc_NZ: return "nz"; |
| 81 | case Xcc_BE: return "be"; |
| 82 | case Xcc_NBE: return "nbe"; |
| 83 | case Xcc_S: return "s"; |
| 84 | case Xcc_NS: return "ns"; |
| 85 | case Xcc_P: return "p"; |
| 86 | case Xcc_NP: return "np"; |
| 87 | case Xcc_L: return "l"; |
| 88 | case Xcc_NL: return "nl"; |
| 89 | case Xcc_LE: return "le"; |
| 90 | case Xcc_NLE: return "nle"; |
| 91 | case Xcc_ALWAYS: return "ALWAYS"; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 92 | default: vpanic("ppX86CondCode"); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 97 | /* --------- X86AMode: memory address expressions. --------- */ |
| 98 | |
| 99 | X86AMode* X86AMode_IR ( UInt imm32, HReg reg ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 100 | X86AMode* am = LibVEX_Alloc(sizeof(X86AMode)); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 101 | am->tag = Xam_IR; |
| 102 | am->Xam.IR.imm = imm32; |
| 103 | am->Xam.IR.reg = reg; |
| 104 | return am; |
| 105 | } |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 106 | X86AMode* X86AMode_IRRS ( UInt imm32, HReg base, HReg index, Int shift ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 107 | X86AMode* am = LibVEX_Alloc(sizeof(X86AMode)); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 108 | am->tag = Xam_IRRS; |
| 109 | am->Xam.IRRS.imm = imm32; |
| 110 | am->Xam.IRRS.base = base; |
| 111 | am->Xam.IRRS.index = index; |
| 112 | am->Xam.IRRS.shift = shift; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 113 | vassert(shift >= 0 && shift <= 3); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 114 | return am; |
| 115 | } |
| 116 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 117 | void ppX86AMode ( X86AMode* am ) { |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 118 | switch (am->tag) { |
| 119 | case Xam_IR: |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 120 | if (am->Xam.IR.imm == 0) |
| 121 | vex_printf("("); |
| 122 | else |
| 123 | vex_printf("0x%x(", am->Xam.IR.imm); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 124 | ppHRegX86(am->Xam.IR.reg); |
| 125 | vex_printf(")"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 126 | return; |
| 127 | case Xam_IRRS: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 128 | vex_printf("0x%x(", am->Xam.IRRS.imm); |
| 129 | ppHRegX86(am->Xam.IRRS.base); |
| 130 | vex_printf(","); |
| 131 | ppHRegX86(am->Xam.IRRS.index); |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 132 | vex_printf(",%d)", 1 << am->Xam.IRRS.shift); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 133 | return; |
| 134 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 135 | vpanic("ppX86AMode"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 136 | } |
| 137 | } |
| 138 | |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 139 | static void addRegUsage_X86AMode ( HRegUsage* u, X86AMode* am ) { |
| 140 | switch (am->tag) { |
| 141 | case Xam_IR: |
| 142 | addHRegUse(u, HRmRead, am->Xam.IR.reg); |
| 143 | return; |
| 144 | case Xam_IRRS: |
| 145 | addHRegUse(u, HRmRead, am->Xam.IRRS.base); |
| 146 | addHRegUse(u, HRmRead, am->Xam.IRRS.index); |
| 147 | return; |
| 148 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 149 | vpanic("addRegUsage_X86AMode"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 150 | } |
| 151 | } |
| 152 | |
| 153 | static void mapRegs_X86AMode ( HRegRemap* m, X86AMode* am ) { |
| 154 | switch (am->tag) { |
| 155 | case Xam_IR: |
| 156 | am->Xam.IR.reg = lookupHRegRemap(m, am->Xam.IR.reg); |
| 157 | return; |
| 158 | case Xam_IRRS: |
| 159 | am->Xam.IRRS.base = lookupHRegRemap(m, am->Xam.IRRS.base); |
| 160 | am->Xam.IRRS.index = lookupHRegRemap(m, am->Xam.IRRS.index); |
| 161 | return; |
| 162 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 163 | vpanic("mapRegs_X86AMode"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 164 | } |
| 165 | } |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 166 | |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 167 | /* --------- Operand, which can be reg, immediate or memory. --------- */ |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 168 | |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 169 | X86RMI* X86RMI_Imm ( UInt imm32 ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 170 | X86RMI* op = LibVEX_Alloc(sizeof(X86RMI)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 171 | op->tag = Xrmi_Imm; |
| 172 | op->Xrmi.Imm.imm32 = imm32; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 173 | return op; |
| 174 | } |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 175 | X86RMI* X86RMI_Reg ( HReg reg ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 176 | X86RMI* op = LibVEX_Alloc(sizeof(X86RMI)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 177 | op->tag = Xrmi_Reg; |
| 178 | op->Xrmi.Reg.reg = reg; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 179 | return op; |
| 180 | } |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 181 | X86RMI* X86RMI_Mem ( X86AMode* am ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 182 | X86RMI* op = LibVEX_Alloc(sizeof(X86RMI)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 183 | op->tag = Xrmi_Mem; |
| 184 | op->Xrmi.Mem.am = am; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 185 | return op; |
| 186 | } |
| 187 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 188 | void ppX86RMI ( X86RMI* op ) { |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 189 | switch (op->tag) { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 190 | case Xrmi_Imm: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 191 | vex_printf("$0x%x", op->Xrmi.Imm.imm32); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 192 | return; |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 193 | case Xrmi_Reg: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 194 | ppHRegX86(op->Xrmi.Reg.reg); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 195 | return; |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 196 | case Xrmi_Mem: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 197 | ppX86AMode(op->Xrmi.Mem.am); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 198 | return; |
| 199 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 200 | vpanic("ppX86RMI"); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 201 | } |
| 202 | } |
| 203 | |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 204 | /* An X86RMI can only be used in a "read" context (what would it mean |
| 205 | to write or modify a literal?) and so we enumerate its registers |
| 206 | accordingly. */ |
| 207 | static void addRegUsage_X86RMI ( HRegUsage* u, X86RMI* op ) { |
| 208 | switch (op->tag) { |
| 209 | case Xrmi_Imm: |
| 210 | return; |
| 211 | case Xrmi_Reg: |
| 212 | addHRegUse(u, HRmRead, op->Xrmi.Reg.reg); |
| 213 | return; |
| 214 | case Xrmi_Mem: |
| 215 | addRegUsage_X86AMode(u, op->Xrmi.Mem.am); |
| 216 | return; |
| 217 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 218 | vpanic("addRegUsage_X86RMI"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 219 | } |
| 220 | } |
| 221 | |
| 222 | static void mapRegs_X86RMI ( HRegRemap* m, X86RMI* op ) { |
| 223 | switch (op->tag) { |
| 224 | case Xrmi_Imm: |
| 225 | return; |
| 226 | case Xrmi_Reg: |
| 227 | op->Xrmi.Reg.reg = lookupHRegRemap(m, op->Xrmi.Reg.reg); |
| 228 | return; |
| 229 | case Xrmi_Mem: |
| 230 | mapRegs_X86AMode(m, op->Xrmi.Mem.am); |
| 231 | return; |
| 232 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 233 | vpanic("mapRegs_X86RMI"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 234 | } |
| 235 | } |
| 236 | |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 237 | |
| 238 | /* --------- Operand, which can be reg or immediate only. --------- */ |
| 239 | |
| 240 | X86RI* X86RI_Imm ( UInt imm32 ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 241 | X86RI* op = LibVEX_Alloc(sizeof(X86RI)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 242 | op->tag = Xri_Imm; |
| 243 | op->Xri.Imm.imm32 = imm32; |
| 244 | return op; |
| 245 | } |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 246 | X86RI* X86RI_Reg ( HReg reg ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 247 | X86RI* op = LibVEX_Alloc(sizeof(X86RI)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 248 | op->tag = Xri_Reg; |
| 249 | op->Xri.Reg.reg = reg; |
| 250 | return op; |
| 251 | } |
| 252 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 253 | void ppX86RI ( X86RI* op ) { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 254 | switch (op->tag) { |
| 255 | case Xri_Imm: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 256 | vex_printf("$0x%x", op->Xri.Imm.imm32); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 257 | return; |
| 258 | case Xri_Reg: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 259 | ppHRegX86(op->Xri.Reg.reg); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 260 | return; |
| 261 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 262 | vpanic("ppX86RI"); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 263 | } |
| 264 | } |
| 265 | |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 266 | /* An X86RI can only be used in a "read" context (what would it mean |
| 267 | to write or modify a literal?) and so we enumerate its registers |
| 268 | accordingly. */ |
| 269 | static void addRegUsage_X86RI ( HRegUsage* u, X86RI* op ) { |
| 270 | switch (op->tag) { |
| 271 | case Xri_Imm: |
| 272 | return; |
| 273 | case Xri_Reg: |
| 274 | addHRegUse(u, HRmRead, op->Xri.Reg.reg); |
| 275 | return; |
| 276 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 277 | vpanic("addRegUsage_X86RI"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 278 | } |
| 279 | } |
| 280 | |
| 281 | static void mapRegs_X86RI ( HRegRemap* m, X86RI* op ) { |
| 282 | switch (op->tag) { |
| 283 | case Xri_Imm: |
| 284 | return; |
| 285 | case Xri_Reg: |
| 286 | op->Xri.Reg.reg = lookupHRegRemap(m, op->Xri.Reg.reg); |
| 287 | return; |
| 288 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 289 | vpanic("mapRegs_X86RI"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 290 | } |
| 291 | } |
| 292 | |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 293 | |
| 294 | /* --------- Operand, which can be reg or memory only. --------- */ |
| 295 | |
| 296 | X86RM* X86RM_Reg ( HReg reg ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 297 | X86RM* op = LibVEX_Alloc(sizeof(X86RM)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 298 | op->tag = Xrm_Reg; |
| 299 | op->Xrm.Reg.reg = reg; |
| 300 | return op; |
| 301 | } |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 302 | X86RM* X86RM_Mem ( X86AMode* am ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 303 | X86RM* op = LibVEX_Alloc(sizeof(X86RM)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 304 | op->tag = Xrm_Mem; |
| 305 | op->Xrm.Mem.am = am; |
| 306 | return op; |
| 307 | } |
| 308 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 309 | void ppX86RM ( X86RM* op ) { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 310 | switch (op->tag) { |
| 311 | case Xrm_Mem: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 312 | ppX86AMode(op->Xrm.Mem.am); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 313 | return; |
| 314 | case Xrm_Reg: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 315 | ppHRegX86(op->Xrm.Reg.reg); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 316 | return; |
| 317 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 318 | vpanic("ppX86RM"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 319 | } |
| 320 | } |
| 321 | |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 322 | /* Because an X86RM can be both a source or destination operand, we |
| 323 | have to supply a mode -- pertaining to the operand as a whole -- |
| 324 | indicating how it's being used. */ |
| 325 | static void addRegUsage_X86RM ( HRegUsage* u, X86RM* op, HRegMode mode ) { |
| 326 | switch (op->tag) { |
| 327 | case Xrm_Mem: |
| 328 | /* Memory is read, written or modified. So we just want to |
| 329 | know the regs read by the amode. */ |
| 330 | addRegUsage_X86AMode(u, op->Xrm.Mem.am); |
| 331 | return; |
| 332 | case Xrm_Reg: |
| 333 | /* reg is read, written or modified. Add it in the |
| 334 | appropriate way. */ |
| 335 | addHRegUse(u, mode, op->Xrm.Reg.reg); |
| 336 | return; |
| 337 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 338 | vpanic("addRegUsage_X86RM"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 339 | } |
| 340 | } |
| 341 | |
| 342 | static void mapRegs_X86RM ( HRegRemap* m, X86RM* op ) |
| 343 | { |
| 344 | switch (op->tag) { |
| 345 | case Xrm_Mem: |
| 346 | mapRegs_X86AMode(m, op->Xrm.Mem.am); |
| 347 | return; |
| 348 | case Xrm_Reg: |
| 349 | op->Xrm.Reg.reg = lookupHRegRemap(m, op->Xrm.Reg.reg); |
| 350 | return; |
| 351 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 352 | vpanic("mapRegs_X86RM"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 353 | } |
| 354 | } |
| 355 | |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 356 | |
| 357 | /* --------- Instructions. --------- */ |
| 358 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 359 | Char* showX86ScalarSz ( X86ScalarSz sz ) { |
| 360 | switch (sz) { |
| 361 | case Xss_16: return "w"; |
| 362 | case Xss_32: return "l"; |
| 363 | default: vpanic("ppX86ScalarSz"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 364 | } |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 365 | } |
| 366 | |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 367 | Char* showX86UnaryOp ( X86UnaryOp op ) { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 368 | switch (op) { |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 369 | case Xun_Not: return "not"; |
| 370 | case Xun_Neg: return "neg"; |
| 371 | default: vpanic("ppX86UnaryOp"); |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | Char* showX86AluOp ( X86AluOp op ) { |
| 376 | switch (op) { |
| 377 | case Xalu_MOV: return "mov"; |
| 378 | case Xalu_CMP: return "cmp"; |
| 379 | case Xalu_TEST: return "test"; |
| 380 | case Xalu_ADD: return "add"; |
| 381 | case Xalu_SUB: return "sub"; |
| 382 | case Xalu_ADC: return "adc"; |
| 383 | case Xalu_SBB: return "sbb"; |
| 384 | case Xalu_AND: return "and"; |
| 385 | case Xalu_OR: return "or"; |
| 386 | case Xalu_XOR: return "xor"; |
| 387 | case Xalu_MUL: return "mul"; |
| 388 | default: vpanic("ppX86AluOp"); |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | Char* showX86ShiftOp ( X86ShiftOp op ) { |
| 393 | switch (op) { |
| 394 | case Xsh_SHL: return "shl"; |
| 395 | case Xsh_SHR: return "shr"; |
| 396 | case Xsh_SAR: return "sar"; |
| 397 | case Xsh_ROL: return "rol"; |
| 398 | case Xsh_ROR: return "ror"; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 399 | default: vpanic("ppX86ShiftOp"); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 400 | } |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 401 | } |
| 402 | |
| 403 | X86Instr* X86Instr_Alu32R ( X86AluOp op, X86RMI* src, HReg dst ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 404 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 405 | i->tag = Xin_Alu32R; |
| 406 | i->Xin.Alu32R.op = op; |
| 407 | i->Xin.Alu32R.src = src; |
| 408 | i->Xin.Alu32R.dst = dst; |
| 409 | return i; |
| 410 | } |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 411 | X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 412 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 413 | i->tag = Xin_Alu32M; |
| 414 | i->Xin.Alu32M.op = op; |
| 415 | i->Xin.Alu32M.src = src; |
| 416 | i->Xin.Alu32M.dst = dst; |
| 417 | return i; |
| 418 | } |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 419 | X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ) { |
| 420 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 421 | i->tag = Xin_Unary32; |
| 422 | i->Xin.Unary32.op = op; |
| 423 | i->Xin.Unary32.dst = dst; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 424 | return i; |
| 425 | } |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 426 | X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz ssz , X86RM* src ) { |
| 427 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 428 | i->tag = Xin_MulL; |
| 429 | i->Xin.MulL.syned = syned; |
| 430 | i->Xin.MulL.ssz = ssz; |
| 431 | i->Xin.MulL.src = src; |
| 432 | return i; |
| 433 | } |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 434 | X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz ssz, X86RM* src ) { |
| 435 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 436 | i->tag = Xin_Div; |
| 437 | i->Xin.Div.syned = syned; |
| 438 | i->Xin.Div.ssz = ssz; |
| 439 | i->Xin.Div.src = src; |
| 440 | return i; |
| 441 | } |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 442 | X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 443 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 444 | i->tag = Xin_Sh32; |
| 445 | i->Xin.Sh32.op = op; |
| 446 | i->Xin.Sh32.src = src; |
| 447 | i->Xin.Sh32.dst = dst; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 448 | return i; |
| 449 | } |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 450 | X86Instr* X86Instr_Sh3232 ( X86ShiftOp op, UInt amt, HReg rHi, HReg rLo ) { |
| 451 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 452 | i->tag = Xin_Sh3232; |
| 453 | i->Xin.Sh3232.op = op; |
| 454 | i->Xin.Sh3232.amt = amt; |
| 455 | i->Xin.Sh3232.rHi = rHi; |
| 456 | i->Xin.Sh3232.rLo = rLo; |
| 457 | vassert(op == Xsh_SHL || op == Xsh_SHR); |
| 458 | return i; |
| 459 | } |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 460 | X86Instr* X86Instr_Push( X86RMI* src ) { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 461 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 462 | i->tag = Xin_Push; |
| 463 | i->Xin.Push.src = src; |
| 464 | return i; |
| 465 | } |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 466 | X86Instr* X86Instr_Call ( HReg target ) { |
| 467 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 468 | i->tag = Xin_Call; |
| 469 | i->Xin.Call.target = target; |
| 470 | return i; |
| 471 | } |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 472 | X86Instr* X86Instr_Goto ( X86CondCode cond, X86RI* dst ) { |
| 473 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 474 | i->tag = Xin_Goto; |
| 475 | i->Xin.Goto.cond = cond; |
| 476 | i->Xin.Goto.dst = dst; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 477 | return i; |
| 478 | } |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 479 | X86Instr* X86Instr_CMov32 ( X86CondCode cond, X86RM* src, HReg dst ) { |
| 480 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 481 | i->tag = Xin_CMov32; |
| 482 | i->Xin.CMov32.cond = cond; |
| 483 | i->Xin.CMov32.src = src; |
| 484 | i->Xin.CMov32.dst = dst; |
| 485 | vassert(cond != Xcc_ALWAYS); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 486 | return i; |
| 487 | } |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 488 | X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned, |
| 489 | X86AMode* src, HReg dst ) { |
| 490 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 491 | i->tag = Xin_LoadEX; |
| 492 | i->Xin.LoadEX.szSmall = szSmall; |
| 493 | i->Xin.LoadEX.syned = syned; |
| 494 | i->Xin.LoadEX.src = src; |
| 495 | i->Xin.LoadEX.dst = dst; |
| 496 | vassert(szSmall == 1 || szSmall == 2); |
| 497 | return i; |
| 498 | } |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 499 | X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ) { |
| 500 | X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); |
| 501 | i->tag = Xin_Store; |
| 502 | i->Xin.Store.sz = sz; |
| 503 | i->Xin.Store.src = src; |
| 504 | i->Xin.Store.dst = dst; |
| 505 | vassert(sz == 1 || sz == 2); |
| 506 | return i; |
| 507 | } |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 508 | |
| 509 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 510 | void ppX86Instr ( X86Instr* i ) { |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 511 | switch (i->tag) { |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 512 | case Xin_Alu32R: |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 513 | vex_printf("%sl ", showX86AluOp(i->Xin.Alu32R.op)); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 514 | ppX86RMI(i->Xin.Alu32R.src); |
| 515 | vex_printf(","); |
| 516 | ppHRegX86(i->Xin.Alu32R.dst); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 517 | return; |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 518 | case Xin_Alu32M: |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 519 | vex_printf("%sl ", showX86AluOp(i->Xin.Alu32M.op)); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 520 | ppX86RI(i->Xin.Alu32M.src); |
| 521 | vex_printf(","); |
| 522 | ppX86AMode(i->Xin.Alu32M.dst); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 523 | return; |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 524 | case Xin_Unary32: |
| 525 | vex_printf("%sl ", showX86UnaryOp(i->Xin.Unary32.op)); |
| 526 | ppX86RM(i->Xin.Unary32.dst); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 527 | return; |
sewardj | 597b71b | 2004-07-19 02:51:12 +0000 | [diff] [blame] | 528 | case Xin_MulL: |
| 529 | vex_printf("%cmul%s ", |
| 530 | i->Xin.MulL.syned ? 's' : 'u', |
| 531 | showX86ScalarSz(i->Xin.MulL.ssz)); |
| 532 | ppX86RM(i->Xin.MulL.src); |
| 533 | return; |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 534 | case Xin_Div: |
| 535 | vex_printf("%cdiv%s ", |
| 536 | i->Xin.Div.syned ? 's' : 'u', |
| 537 | showX86ScalarSz(i->Xin.Div.ssz)); |
| 538 | ppX86RM(i->Xin.Div.src); |
| 539 | return; |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 540 | case Xin_Sh32: |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 541 | vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op)); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 542 | if (i->Xin.Sh32.src == 0) |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 543 | vex_printf(" %%cl,"); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 544 | else |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 545 | vex_printf(" $%d,", i->Xin.Sh32.src); |
| 546 | ppX86RM(i->Xin.Sh32.dst); |
sewardj | 66f2f79 | 2004-06-30 16:37:16 +0000 | [diff] [blame] | 547 | return; |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 548 | case Xin_Sh3232: |
| 549 | vex_printf("%sdl ", showX86ShiftOp(i->Xin.Sh3232.op)); |
| 550 | if (i->Xin.Sh3232.amt == 0) |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 551 | vex_printf(" %%cl,"); |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 552 | else |
| 553 | vex_printf(" $%d,", i->Xin.Sh3232.amt); |
| 554 | ppHRegX86(i->Xin.Sh3232.rLo); |
| 555 | vex_printf(","); |
| 556 | ppHRegX86(i->Xin.Sh3232.rHi); |
| 557 | return; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 558 | case Xin_Push: |
| 559 | vex_printf("pushl "); |
| 560 | ppX86RMI(i->Xin.Push.src); |
| 561 | return; |
| 562 | case Xin_Call: |
| 563 | vex_printf("call *"); |
| 564 | ppHRegX86(i->Xin.Call.target); |
| 565 | break; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 566 | case Xin_Goto: |
| 567 | if (i->Xin.Goto.cond == Xcc_ALWAYS) { |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 568 | vex_printf("movl "); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 569 | ppX86RI(i->Xin.Goto.dst); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 570 | vex_printf(",%%eax ; ret"); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 571 | } else { |
sewardj | 60f4e3c | 2004-07-19 01:56:50 +0000 | [diff] [blame] | 572 | vex_printf("if (%%eflags.%s) { movl ", |
| 573 | showX86CondCode(i->Xin.Goto.cond)); |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 574 | ppX86RI(i->Xin.Goto.dst); |
| 575 | vex_printf(",%%eax ; ret }"); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 576 | } |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 577 | return; |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 578 | case Xin_CMov32: |
| 579 | vex_printf("cmovl%s ", showX86CondCode(i->Xin.CMov32.cond)); |
| 580 | ppX86RM(i->Xin.CMov32.src); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 581 | vex_printf(","); |
sewardj | 5c34dc9 | 2004-07-19 12:48:11 +0000 | [diff] [blame] | 582 | ppHRegX86(i->Xin.CMov32.dst); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 583 | return; |
| 584 | case Xin_LoadEX: |
| 585 | vex_printf("mov%c%cl ", |
| 586 | i->Xin.LoadEX.syned ? 's' : 'z', |
| 587 | i->Xin.LoadEX.szSmall==1 ? 'b' : 'w'); |
| 588 | ppX86AMode(i->Xin.LoadEX.src); |
| 589 | vex_printf(","); |
| 590 | ppHRegX86(i->Xin.LoadEX.dst); |
| 591 | return; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 592 | case Xin_Store: |
| 593 | vex_printf("mov%c ", i->Xin.Store.sz==1 ? 'b' : 'w'); |
| 594 | ppHRegX86(i->Xin.Store.src); |
| 595 | vex_printf(","); |
| 596 | ppX86AMode(i->Xin.Store.dst); |
| 597 | return; |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 598 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 599 | vpanic("ppX86Instr"); |
sewardj | c97096c | 2004-06-30 09:28:04 +0000 | [diff] [blame] | 600 | } |
| 601 | } |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 602 | |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 603 | /* --------- Helpers for register allocation. --------- */ |
| 604 | |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 605 | void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) |
| 606 | { |
| 607 | initHRegUsage(u); |
| 608 | switch (i->tag) { |
| 609 | case Xin_Alu32R: |
| 610 | addRegUsage_X86RMI(u, i->Xin.Alu32R.src); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 611 | if (i->Xin.Alu32R.op == Xalu_MOV) { |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 612 | addHRegUse(u, HRmWrite, i->Xin.Alu32R.dst); |
sewardj | 4042c7e | 2004-07-18 01:28:30 +0000 | [diff] [blame] | 613 | return; |
| 614 | } |
| 615 | if (i->Xin.Alu32R.op == Xalu_CMP |
| 616 | || i->Xin.Alu32R.op == Xalu_TEST) { |
| 617 | addHRegUse(u, HRmRead, i->Xin.Alu32R.dst); |
| 618 | return; |
| 619 | } |
| 620 | addHRegUse(u, HRmModify, i->Xin.Alu32R.dst); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 621 | return; |
| 622 | case Xin_Alu32M: |
| 623 | addRegUsage_X86RI(u, i->Xin.Alu32M.src); |
| 624 | addRegUsage_X86AMode(u, i->Xin.Alu32M.dst); |
| 625 | return; |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 626 | case Xin_Unary32: |
| 627 | addRegUsage_X86RM(u, i->Xin.Unary32.dst, HRmModify); |
| 628 | return; |
| 629 | case Xin_MulL: |
| 630 | addRegUsage_X86RM(u, i->Xin.MulL.src, HRmRead); |
| 631 | addHRegUse(u, HRmModify, hregX86_EAX()); |
| 632 | addHRegUse(u, HRmWrite, hregX86_EDX()); |
| 633 | return; |
| 634 | case Xin_Div: |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 635 | addRegUsage_X86RM(u, i->Xin.Div.src, HRmRead); |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 636 | addHRegUse(u, HRmModify, hregX86_EAX()); |
| 637 | addHRegUse(u, HRmModify, hregX86_EDX()); |
| 638 | return; |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 639 | case Xin_Sh32: |
| 640 | addRegUsage_X86RM(u, i->Xin.Sh32.dst, HRmModify); |
| 641 | if (i->Xin.Sh32.src == 0) |
| 642 | addHRegUse(u, HRmRead, hregX86_ECX()); |
| 643 | return; |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 644 | case Xin_Sh3232: |
| 645 | addHRegUse(u, HRmRead, i->Xin.Sh3232.rLo); |
| 646 | addHRegUse(u, HRmModify, i->Xin.Sh3232.rHi); |
| 647 | if (i->Xin.Sh3232.amt == 0) |
| 648 | addHRegUse(u, HRmRead, hregX86_ECX()); |
| 649 | return; |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 650 | case Xin_Push: |
| 651 | addRegUsage_X86RMI(u, i->Xin.Push.src); |
| 652 | addHRegUse(u, HRmModify, hregX86_ESP()); |
| 653 | return; |
| 654 | case Xin_Call: |
| 655 | addHRegUse(u, HRmRead, i->Xin.Call.target); |
| 656 | /* claim it trashes all the callee-saved regs */ |
| 657 | /* except I have no idea what they are */ |
| 658 | addHRegUse(u, HRmWrite, hregX86_EAX()); |
| 659 | addHRegUse(u, HRmWrite, hregX86_ECX()); |
| 660 | addHRegUse(u, HRmWrite, hregX86_EDX()); |
| 661 | return; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 662 | case Xin_Goto: |
| 663 | addRegUsage_X86RI(u, i->Xin.Goto.dst); |
sewardj | e8e9d73 | 2004-07-16 21:03:45 +0000 | [diff] [blame] | 664 | addHRegUse(u, HRmWrite, hregX86_EAX()); |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 665 | return; |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 666 | case Xin_CMov32: |
| 667 | addRegUsage_X86RM(u, i->Xin.CMov32.src, HRmRead); |
| 668 | addHRegUse(u, HRmModify, i->Xin.CMov32.dst); |
| 669 | return; |
| 670 | case Xin_LoadEX: |
| 671 | addRegUsage_X86AMode(u, i->Xin.LoadEX.src); |
| 672 | addHRegUse(u, HRmWrite, i->Xin.LoadEX.dst); |
| 673 | return; |
| 674 | case Xin_Store: |
| 675 | addHRegUse(u, HRmRead, i->Xin.Store.src); |
| 676 | addRegUsage_X86AMode(u, i->Xin.Store.dst); |
| 677 | return; |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 678 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 679 | ppX86Instr(i); |
| 680 | vpanic("getRegUsage_X86Instr"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 681 | } |
| 682 | } |
| 683 | |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 684 | /* local helper */ |
| 685 | static void mapReg(HRegRemap* m, HReg* r) |
| 686 | { |
| 687 | *r = lookupHRegRemap(m, *r); |
| 688 | } |
| 689 | |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 690 | void mapRegs_X86Instr (HRegRemap* m, X86Instr* i) |
| 691 | { |
| 692 | switch (i->tag) { |
| 693 | case Xin_Alu32R: |
| 694 | mapRegs_X86RMI(m, i->Xin.Alu32R.src); |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 695 | mapReg(m, &i->Xin.Alu32R.dst); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 696 | return; |
| 697 | case Xin_Alu32M: |
| 698 | mapRegs_X86RI(m, i->Xin.Alu32M.src); |
| 699 | mapRegs_X86AMode(m, i->Xin.Alu32M.dst); |
| 700 | return; |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 701 | case Xin_Unary32: |
| 702 | mapRegs_X86RM(m, i->Xin.Unary32.dst); |
| 703 | return; |
| 704 | case Xin_MulL: |
| 705 | mapRegs_X86RM(m, i->Xin.MulL.src); |
| 706 | return; |
| 707 | case Xin_Div: |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 708 | mapRegs_X86RM(m, i->Xin.Div.src); |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 709 | return; |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 710 | case Xin_Sh32: |
| 711 | mapRegs_X86RM(m, i->Xin.Sh32.dst); |
| 712 | return; |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 713 | case Xin_Sh3232: |
| 714 | mapReg(m, &i->Xin.Sh3232.rLo); |
| 715 | mapReg(m, &i->Xin.Sh3232.rHi); |
| 716 | return; |
| 717 | case Xin_Push: |
| 718 | mapRegs_X86RMI(m, i->Xin.Push.src); |
| 719 | return; |
| 720 | case Xin_Call: |
| 721 | mapReg(m, &i->Xin.Call.target); |
| 722 | return; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 723 | case Xin_Goto: |
| 724 | mapRegs_X86RI(m, i->Xin.Goto.dst); |
sewardj | 0ec3325 | 2004-07-03 13:30:00 +0000 | [diff] [blame] | 725 | return; |
sewardj | 1f40a0a | 2004-07-21 12:28:07 +0000 | [diff] [blame] | 726 | case Xin_CMov32: |
| 727 | mapRegs_X86RM(m, i->Xin.CMov32.src); |
| 728 | mapReg(m, &i->Xin.CMov32.dst); |
| 729 | return; |
| 730 | case Xin_LoadEX: |
| 731 | mapRegs_X86AMode(m, i->Xin.LoadEX.src); |
| 732 | mapReg(m, &i->Xin.LoadEX.dst); |
| 733 | return; |
| 734 | case Xin_Store: |
| 735 | mapReg(m, &i->Xin.Store.src); |
| 736 | mapRegs_X86AMode(m, i->Xin.Store.dst); |
| 737 | return; |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 738 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 739 | ppX86Instr(i); |
| 740 | vpanic("mapRegs_X86Instr"); |
sewardj | 53f85a9 | 2004-07-02 13:45:17 +0000 | [diff] [blame] | 741 | } |
| 742 | } |
| 743 | |
sewardj | a9a0cd2 | 2004-07-03 14:49:41 +0000 | [diff] [blame] | 744 | Bool isMove_X86Instr ( X86Instr* i, HReg* src, HReg* dst ) |
| 745 | { |
| 746 | if (i->tag != Xin_Alu32R) |
| 747 | return False; |
| 748 | if (i->Xin.Alu32R.op != Xalu_MOV) |
| 749 | return False; |
| 750 | if (i->Xin.Alu32R.src->tag != Xrmi_Reg) |
| 751 | return False; |
| 752 | *src = i->Xin.Alu32R.src->Xrmi.Reg.reg; |
| 753 | *dst = i->Xin.Alu32R.dst; |
| 754 | return True; |
| 755 | } |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 756 | |
| 757 | X86Instr* genSpill_X86 ( HReg rreg, Int offset ) |
| 758 | { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 759 | vassert(!hregIsVirtual(rreg)); |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 760 | switch (hregClass(rreg)) { |
| 761 | case HRcInt: |
| 762 | return |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 763 | X86Instr_Alu32M ( Xalu_MOV, X86RI_Reg(rreg), |
| 764 | X86AMode_IR(offset + 0x1000, |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 765 | hregX86_EBP())); |
| 766 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 767 | ppHRegClass(hregClass(rreg)); |
| 768 | vpanic("genSpill_X86: unimplemented regclass"); |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 769 | } |
| 770 | } |
| 771 | |
| 772 | X86Instr* genReload_X86 ( HReg rreg, Int offset ) |
| 773 | { |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 774 | vassert(!hregIsVirtual(rreg)); |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 775 | switch (hregClass(rreg)) { |
| 776 | case HRcInt: |
| 777 | return |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 778 | X86Instr_Alu32R ( Xalu_MOV, |
| 779 | X86RMI_Mem(X86AMode_IR(offset + 0x1000, |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 780 | hregX86_EBP())), |
| 781 | rreg ); |
| 782 | default: |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 783 | ppHRegClass(hregClass(rreg)); |
| 784 | vpanic("genReload_X86: unimplemented regclass"); |
sewardj | 194d54a | 2004-07-03 19:08:18 +0000 | [diff] [blame] | 785 | } |
| 786 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 787 | |
sewardj | 81bd550 | 2004-07-21 18:49:27 +0000 | [diff] [blame] | 788 | |
| 789 | /* --------- The x86 assembler (bleh.) --------- */ |
| 790 | |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 791 | static UInt iregNo ( HReg r ) |
| 792 | { |
| 793 | UInt n; |
| 794 | vassert(hregClass(r) == HRcInt); |
| 795 | vassert(!hregIsVirtual(r)); |
| 796 | n = hregNumber(r); |
| 797 | vassert(n <= 7); |
| 798 | return n; |
| 799 | } |
| 800 | |
| 801 | static UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem ) |
| 802 | { |
| 803 | return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7); |
| 804 | } |
| 805 | |
| 806 | static UChar mkSIB ( Int shift, Int regindex, Int regbase ) |
| 807 | { |
| 808 | return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7); |
| 809 | } |
| 810 | |
| 811 | static UChar* emit32 ( UChar* p, UInt w32 ) |
| 812 | { |
| 813 | *p++ = (w32) & 0x000000FF; |
| 814 | *p++ = (w32 >> 8) & 0x000000FF; |
| 815 | *p++ = (w32 >> 16) & 0x000000FF; |
| 816 | *p++ = (w32 >> 24) & 0x000000FF; |
| 817 | return p; |
| 818 | } |
| 819 | |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 820 | /* Does a sign-extend of the lowest 8 bits give |
| 821 | the original number? */ |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 822 | static Bool fits8bits ( UInt w32 ) |
| 823 | { |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 824 | Int i32 = (Int)w32; |
| 825 | return i32 == ((i32 << 24) >> 24); |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 826 | } |
| 827 | |
| 828 | |
| 829 | /* Forming mod-reg-rm bytes and scale-index-base bytes. |
| 830 | |
| 831 | greg, 0(ereg) | ereg != ESP && ereg != EBP |
| 832 | = 00 greg ereg |
| 833 | |
| 834 | greg, d8(ereg) | ereg != ESP |
| 835 | = 01 greg ereg, d8 |
| 836 | |
| 837 | greg, d32(ereg) | ereg != ESP |
| 838 | = 10 greg ereg, d32 |
| 839 | |
| 840 | ----------------------------------------------- |
| 841 | |
| 842 | greg, d8(base,index,scale) |
| 843 | | index != ESP |
| 844 | = 01 greg 100, scale index base, d8 |
| 845 | |
| 846 | greg, d32(base,index,scale) |
| 847 | | index != ESP |
| 848 | = 10 greg 100, scale index base, d32 |
| 849 | */ |
| 850 | static UChar* doAMode_M ( UChar* p, HReg greg, X86AMode* am ) |
| 851 | { |
| 852 | if (am->tag == Xam_IR) { |
| 853 | if (am->Xam.IR.imm == 0 |
| 854 | && am->Xam.IR.reg != hregX86_ESP() |
| 855 | && am->Xam.IR.reg != hregX86_EBP() ) { |
| 856 | *p++ = mkModRegRM(0, iregNo(greg), iregNo(am->Xam.IR.reg)); |
| 857 | return p; |
| 858 | } |
| 859 | if (fits8bits(am->Xam.IR.imm) |
| 860 | && am->Xam.IR.reg != hregX86_ESP()) { |
| 861 | *p++ = mkModRegRM(1, iregNo(greg), iregNo(am->Xam.IR.reg)); |
| 862 | *p++ = am->Xam.IR.imm & 0xFF; |
| 863 | return p; |
| 864 | } |
| 865 | if (am->Xam.IR.reg != hregX86_ESP()) { |
| 866 | *p++ = mkModRegRM(2, iregNo(greg), iregNo(am->Xam.IR.reg)); |
| 867 | p = emit32(p, am->Xam.IR.imm); |
| 868 | return p; |
| 869 | } |
| 870 | ppX86AMode(am); |
| 871 | vpanic("doAMode_M: can't emit amode IR"); |
| 872 | /*NOTREACHED*/ |
| 873 | } |
| 874 | if (am->tag == Xam_IRRS) { |
| 875 | if (fits8bits(am->Xam.IRRS.imm) |
| 876 | && am->Xam.IRRS.index != hregX86_ESP()) { |
| 877 | *p++ = mkModRegRM(1, iregNo(greg), 4); |
| 878 | *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index, |
| 879 | am->Xam.IRRS.base); |
| 880 | *p++ = am->Xam.IRRS.imm & 0xFF; |
| 881 | return p; |
| 882 | } |
| 883 | if (am->Xam.IRRS.index != hregX86_ESP()) { |
| 884 | *p++ = mkModRegRM(2, iregNo(greg), 4); |
| 885 | *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index, |
| 886 | am->Xam.IRRS.base); |
| 887 | p = emit32(p, am->Xam.IRRS.imm); |
| 888 | return p; |
| 889 | } |
| 890 | ppX86AMode(am); |
| 891 | vpanic("doAMode_M: can't emit amode IRRS"); |
| 892 | /*NOTREACHED*/ |
| 893 | } |
| 894 | vpanic("doAMode_M: unknown amode"); |
| 895 | /*NOTREACHED*/ |
| 896 | } |
| 897 | |
| 898 | |
| 899 | /* Emit a mod-reg-rm byte when the rm bit denotes a reg. */ |
| 900 | static UChar* doAMode_R ( UChar* p, HReg greg, HReg ereg ) |
| 901 | { |
| 902 | *p++ = mkModRegRM(3, iregNo(greg), iregNo(ereg)); |
| 903 | return p; |
| 904 | } |
| 905 | |
| 906 | |
| 907 | |
sewardj | 81bd550 | 2004-07-21 18:49:27 +0000 | [diff] [blame] | 908 | /* Emit an instruction into buf and return the number of bytes used. |
| 909 | Note that buf is not the insn's final place, and therefore it is |
| 910 | imperative to emit position-independent code. */ |
| 911 | |
| 912 | Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) |
| 913 | { |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 914 | UInt opc, opc_rr, subopc_imm, opc_imma; |
| 915 | |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 916 | UChar* p = &buf[0]; |
| 917 | vassert(nbuf >= 32); |
| 918 | |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 919 | /* Wrap an integer as a int register, for use assembling |
| 920 | GrpN insns, in which the greg field is used as a sub-opcode |
| 921 | and does not really contain a register. */ |
| 922 | # define fake(_n) mkHReg((_n), HRcInt, False) |
| 923 | |
sewardj | 81bd550 | 2004-07-21 18:49:27 +0000 | [diff] [blame] | 924 | switch (i->tag) { |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 925 | |
| 926 | case Xin_Alu32R: |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 927 | /* Deal specially with MOV */ |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 928 | if (i->Xin.Alu32R.op == Xalu_MOV) { |
| 929 | switch (i->Xin.Alu32R.src->tag) { |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 930 | case Xrmi_Imm: |
| 931 | *p++ = 0xB8 + iregNo(i->Xin.Alu32R.dst); |
| 932 | p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32); |
| 933 | goto done; |
| 934 | case Xrmi_Reg: |
| 935 | *p++ = 0x89; |
| 936 | p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg, |
| 937 | i->Xin.Alu32R.dst); |
| 938 | goto done; |
| 939 | case Xrmi_Mem: |
| 940 | *p++ = 0x8B; |
| 941 | p = doAMode_M(p, i->Xin.Alu32R.dst, |
| 942 | i->Xin.Alu32R.src->Xrmi.Mem.am); |
| 943 | goto done; |
| 944 | default: |
| 945 | goto bad; |
| 946 | } |
| 947 | } |
| 948 | /* ADD/SUB/ADC/SBB/AND/OR/XOR/TEST/CMP */ |
| 949 | opc = opc_rr = subopc_imm = opc_imma = 0; |
| 950 | switch (i->Xin.Alu32R.op) { |
| 951 | case Xalu_ADD: opc = 0x03; opc_rr = 0x01; |
| 952 | subopc_imm = 0; opc_imma = 0x05; break; |
| 953 | case Xalu_SUB: opc = 0x2B; opc_rr = 0x29; |
| 954 | subopc_imm = 5; opc_imma = 0x2D; break; |
| 955 | default: goto bad; |
| 956 | } |
| 957 | switch (i->Xin.Alu32R.src->tag) { |
| 958 | case Xrmi_Imm: |
| 959 | if (i->Xin.Alu32R.dst == hregX86_EAX() |
| 960 | && !fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) { |
| 961 | *p++ = opc_imma; |
| 962 | p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32); |
| 963 | } else |
| 964 | if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) { |
| 965 | *p++ = 0x83; |
| 966 | p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst); |
| 967 | *p++ = 0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32; |
| 968 | } else { |
| 969 | *p++ = 0x81; |
| 970 | p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst); |
| 971 | p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32); |
| 972 | } |
| 973 | goto done; |
| 974 | case Xrmi_Reg: |
| 975 | *p++ = opc_rr; |
| 976 | p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg, |
| 977 | i->Xin.Alu32R.dst); |
| 978 | goto done; |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 979 | case Xrmi_Mem: |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 980 | *p++ = opc; |
| 981 | p = doAMode_M(p, i->Xin.Alu32R.dst, |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 982 | i->Xin.Alu32R.src->Xrmi.Mem.am); |
| 983 | goto done; |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 984 | default: |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 985 | goto bad; |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 986 | } |
| 987 | break; |
| 988 | |
| 989 | case Xin_Alu32M: |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 990 | /* Deal specially with MOV */ |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 991 | if (i->Xin.Alu32M.op == Xalu_MOV) { |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 992 | switch (i->Xin.Alu32M.src->tag) { |
| 993 | case Xri_Reg: |
| 994 | *p++ = 0x89; |
| 995 | p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg, |
| 996 | i->Xin.Alu32M.dst); |
| 997 | goto done; |
| 998 | case Xri_Imm: |
| 999 | *p++ = 0xC7; |
| 1000 | p = doAMode_M(p, fake(0), i->Xin.Alu32M.dst); |
| 1001 | p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32); |
| 1002 | goto done; |
| 1003 | default: |
| 1004 | goto bad; |
| 1005 | } |
| 1006 | } |
| 1007 | /* ADD/SUB/ADC/SBB/AND/OR/XOR/TEST/CMP */ |
| 1008 | opc = subopc_imm = opc_imma = 0; |
| 1009 | switch (i->Xin.Alu32M.op) { |
| 1010 | case Xalu_ADD: opc = 0x01; subopc_imm = 0; break; |
| 1011 | default: goto bad; |
| 1012 | } |
| 1013 | switch (i->Xin.Alu32M.src->tag) { |
| 1014 | case Xri_Reg: |
| 1015 | *p++ = opc; |
| 1016 | p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg, |
| 1017 | i->Xin.Alu32M.dst); |
| 1018 | goto done; |
| 1019 | case Xri_Imm: |
| 1020 | if (fits8bits(i->Xin.Alu32M.src->Xri.Imm.imm32)) { |
| 1021 | *p++ = 0x83; |
| 1022 | p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst); |
| 1023 | *p++ = 0xFF & i->Xin.Alu32M.src->Xri.Imm.imm32; |
| 1024 | goto done; |
| 1025 | } else { |
| 1026 | *p++ = 0x81; |
| 1027 | p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst); |
| 1028 | p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32); |
| 1029 | goto done; |
| 1030 | } |
| 1031 | default: |
| 1032 | goto bad; |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 1033 | } |
| 1034 | break; |
| 1035 | |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 1036 | default: |
| 1037 | goto bad; |
sewardj | 81bd550 | 2004-07-21 18:49:27 +0000 | [diff] [blame] | 1038 | } |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 1039 | |
| 1040 | bad: |
| 1041 | ppX86Instr(i); |
| 1042 | vpanic("emit_X86Instr"); |
| 1043 | /*NOTREACHED*/ |
| 1044 | |
sewardj | bad34a9 | 2004-07-22 01:14:11 +0000 | [diff] [blame] | 1045 | done: |
| 1046 | vassert(p - &buf[0] <= 32); |
| 1047 | return p - &buf[0]; |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 1048 | |
| 1049 | # undef fake |
sewardj | 81bd550 | 2004-07-21 18:49:27 +0000 | [diff] [blame] | 1050 | } |
| 1051 | |
| 1052 | |
sewardj | ea64e14 | 2004-07-22 16:47:21 +0000 | [diff] [blame^] | 1053 | /* Self-contained test; can be called directly from |
| 1054 | main. */ |
| 1055 | void test_asm86 ( void ) |
| 1056 | { |
| 1057 | UChar buf[32]; |
| 1058 | Int i, n; |
| 1059 | HReg edi = hregX86_EDI(); |
| 1060 | HReg esi = hregX86_ESI(); |
| 1061 | HReg ecx = hregX86_ECX(); |
| 1062 | HReg ebp = hregX86_EBP(); |
| 1063 | HReg eax = hregX86_EAX(); |
| 1064 | HReg esp = hregX86_ESP(); |
| 1065 | |
| 1066 | #define T(_iii) \ |
| 1067 | do { X86Instr* iii = _iii; \ |
| 1068 | vex_printf("\n "); \ |
| 1069 | ppX86Instr(iii); \ |
| 1070 | vex_printf("\n "); \ |
| 1071 | n = emit_X86Instr( buf, 32, iii ); \ |
| 1072 | for (i = 0; i < n; i++) { \ |
| 1073 | if (buf[i] < 0x10) \ |
| 1074 | vex_printf("0%x ", (Int)buf[i]); \ |
| 1075 | else \ |
| 1076 | vex_printf("%x ", (Int)buf[i]); \ |
| 1077 | } \ |
| 1078 | vex_printf("\n"); \ |
| 1079 | } while (0) |
| 1080 | |
| 1081 | #if 0 |
| 1082 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(esi), edi) ); |
| 1083 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0x12345678), edi) ); |
| 1084 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(0,esi)), edi) ); |
| 1085 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(0,ebp)), edi) ); |
| 1086 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(1,esi)), edi) ); |
| 1087 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(1,ebp)), edi) ); |
| 1088 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(127,esi)), edi) ); |
| 1089 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(256,esi)), edi) ); |
| 1090 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IRRS(1,esi,ecx,0)), edi) ); |
| 1091 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IRRS(1,esi,ecx,3)), edi) ); |
| 1092 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IRRS(127,esi,ecx,3)), edi) ); |
| 1093 | T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IRRS(256,esi,ecx,3)), edi) ); |
| 1094 | #endif |
| 1095 | |
| 1096 | #if 0 |
| 1097 | T( X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(9), X86AMode_IR(0,esi)) ); |
| 1098 | T( X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(edi), X86AMode_IR(0,esi)) ); |
| 1099 | T( X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(999), X86AMode_IRRS(256,esi,ecx,3)) ); |
| 1100 | T( X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(ebp), X86AMode_IRRS(256,esi,ecx,3)) ); |
| 1101 | #endif |
| 1102 | |
| 1103 | #if 0 |
| 1104 | T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(0x42), eax) ); |
| 1105 | T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(0x41424344), eax) ); |
| 1106 | T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(0x42), esp) ); |
| 1107 | T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(0x41424344), esp) ); |
| 1108 | T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Reg(esi), edi) ); |
| 1109 | T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Mem(X86AMode_IR(1,esi)), edi) ); |
| 1110 | #endif |
| 1111 | |
| 1112 | #if 0 |
| 1113 | T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(0x42), eax) ); |
| 1114 | T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(0x41424344), eax) ); |
| 1115 | T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(0x42), esp) ); |
| 1116 | T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(0x41424344), esp) ); |
| 1117 | T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Reg(esi), edi) ); |
| 1118 | T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Mem(X86AMode_IR(1,esi)), edi) ); |
| 1119 | #endif |
| 1120 | |
| 1121 | #if 0 |
| 1122 | T( X86Instr_Alu32M(Xalu_ADD, X86RI_Imm(0x42), X86AMode_IR(0x99,esi)) ); |
| 1123 | T( X86Instr_Alu32M(Xalu_ADD, X86RI_Imm(0x4243), X86AMode_IR(0x99,esi)) ); |
| 1124 | T( X86Instr_Alu32M(Xalu_ADD, X86RI_Reg(ecx), X86AMode_IR(0x99,ebp)) ); |
| 1125 | T( X86Instr_Alu32M(Xalu_ADD, X86RI_Reg(ecx), X86AMode_IR(0x80,ebp)) ); |
| 1126 | T( X86Instr_Alu32M(Xalu_ADD, X86RI_Reg(ecx), X86AMode_IR(0x7F,ebp)) ); |
| 1127 | #endif |
| 1128 | |
| 1129 | #undef T |
| 1130 | } |
| 1131 | |
| 1132 | |
| 1133 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 1134 | /*---------------------------------------------------------------*/ |
| 1135 | /*--- end x86h_defs.c ---*/ |
| 1136 | /*---------------------------------------------------------------*/ |