blob: ca946054f9557319c2c474a0de7092ccf0eacfdc [file] [log] [blame]
sewardjc97096c2004-06-30 09:28:04 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (host-x86/hdefs.c) is ---*/
sewardjdbcfae72005-08-02 11:14:04 +00005/*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/
sewardjc97096c2004-06-30 09:28:04 +00006/*--- ---*/
7/*---------------------------------------------------------------*/
8
sewardjf8ed9d82004-11-12 17:40:23 +00009/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
sewardj7bd6ffe2005-08-03 16:07:36 +000013 Copyright (C) 2004-2005 OpenWorks LLP. All rights reserved.
sewardjf8ed9d82004-11-12 17:40:23 +000014
sewardj7bd6ffe2005-08-03 16:07:36 +000015 This library is made available under a dual licensing scheme.
sewardjf8ed9d82004-11-12 17:40:23 +000016
sewardj7bd6ffe2005-08-03 16:07:36 +000017 If you link LibVEX against other code all of which is itself
18 licensed under the GNU General Public License, version 2 dated June
19 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL
20 v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL
21 is missing, you can obtain a copy of the GPL v2 from the Free
22 Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 02110-1301, USA.
24
25 For any other uses of LibVEX, you must first obtain a commercial
26 license from OpenWorks LLP. Please contact info@open-works.co.uk
27 for information about commercial licensing.
28
29 This software is provided by OpenWorks LLP "as is" and any express
30 or implied warranties, including, but not limited to, the implied
31 warranties of merchantability and fitness for a particular purpose
32 are disclaimed. In no event shall OpenWorks LLP be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability,
37 whether in contract, strict liability, or tort (including
38 negligence or otherwise) arising in any way out of the use of this
39 software, even if advised of the possibility of such damage.
sewardjf8ed9d82004-11-12 17:40:23 +000040
41 Neither the names of the U.S. Department of Energy nor the
42 University of California nor the names of its contributors may be
43 used to endorse or promote products derived from this software
44 without prior written permission.
sewardjf8ed9d82004-11-12 17:40:23 +000045*/
46
sewardj887a11a2004-07-05 17:26:47 +000047#include "libvex_basictypes.h"
48#include "libvex.h"
sewardjc4278f42004-11-26 13:18:19 +000049#include "libvex_trc_values.h"
sewardj35421a32004-07-05 13:12:34 +000050
sewardjc0ee2ed2004-07-27 10:29:41 +000051#include "main/vex_util.h"
52#include "host-generic/h_generic_regs.h"
53#include "host-x86/hdefs.h"
sewardjc97096c2004-06-30 09:28:04 +000054
55
56/* --------- Registers. --------- */
57
sewardj35421a32004-07-05 13:12:34 +000058void ppHRegX86 ( HReg reg )
sewardjc97096c2004-06-30 09:28:04 +000059{
60 Int r;
sewardjd08f2d72004-12-01 23:19:36 +000061 static HChar* ireg32_names[8]
sewardjc97096c2004-06-30 09:28:04 +000062 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" };
63 /* Be generic for all virtual regs. */
64 if (hregIsVirtual(reg)) {
sewardj35421a32004-07-05 13:12:34 +000065 ppHReg(reg);
sewardjc97096c2004-06-30 09:28:04 +000066 return;
67 }
68 /* But specific for real regs. */
69 switch (hregClass(reg)) {
sewardj4a31b262004-12-01 02:24:44 +000070 case HRcInt32:
sewardjc97096c2004-06-30 09:28:04 +000071 r = hregNumber(reg);
sewardj35421a32004-07-05 13:12:34 +000072 vassert(r >= 0 && r < 8);
73 vex_printf("%s", ireg32_names[r]);
sewardjc97096c2004-06-30 09:28:04 +000074 return;
sewardj4a31b262004-12-01 02:24:44 +000075 case HRcFlt64:
sewardjc97096c2004-06-30 09:28:04 +000076 r = hregNumber(reg);
sewardjd7bd8ac2004-10-09 10:06:12 +000077 vassert(r >= 0 && r < 6);
sewardj35421a32004-07-05 13:12:34 +000078 vex_printf("%%fake%d", r);
sewardjc97096c2004-06-30 09:28:04 +000079 return;
sewardj4a31b262004-12-01 02:24:44 +000080 case HRcVec128:
sewardjd08f2d72004-12-01 23:19:36 +000081 r = hregNumber(reg);
82 vassert(r >= 0 && r < 8);
83 vex_printf("%%xmm%d", r);
84 return;
85 default:
sewardj35421a32004-07-05 13:12:34 +000086 vpanic("ppHRegX86");
sewardjc97096c2004-06-30 09:28:04 +000087 }
88}
89
sewardj4a31b262004-12-01 02:24:44 +000090HReg hregX86_EAX ( void ) { return mkHReg(0, HRcInt32, False); }
91HReg hregX86_ECX ( void ) { return mkHReg(1, HRcInt32, False); }
92HReg hregX86_EDX ( void ) { return mkHReg(2, HRcInt32, False); }
93HReg hregX86_EBX ( void ) { return mkHReg(3, HRcInt32, False); }
94HReg hregX86_ESP ( void ) { return mkHReg(4, HRcInt32, False); }
95HReg hregX86_EBP ( void ) { return mkHReg(5, HRcInt32, False); }
96HReg hregX86_ESI ( void ) { return mkHReg(6, HRcInt32, False); }
97HReg hregX86_EDI ( void ) { return mkHReg(7, HRcInt32, False); }
sewardjf13a16a2004-07-05 17:10:14 +000098
sewardj4a31b262004-12-01 02:24:44 +000099HReg hregX86_FAKE0 ( void ) { return mkHReg(0, HRcFlt64, False); }
100HReg hregX86_FAKE1 ( void ) { return mkHReg(1, HRcFlt64, False); }
101HReg hregX86_FAKE2 ( void ) { return mkHReg(2, HRcFlt64, False); }
102HReg hregX86_FAKE3 ( void ) { return mkHReg(3, HRcFlt64, False); }
103HReg hregX86_FAKE4 ( void ) { return mkHReg(4, HRcFlt64, False); }
104HReg hregX86_FAKE5 ( void ) { return mkHReg(5, HRcFlt64, False); }
sewardjd1725d12004-08-12 20:46:53 +0000105
sewardjd08f2d72004-12-01 23:19:36 +0000106HReg hregX86_XMM0 ( void ) { return mkHReg(0, HRcVec128, False); }
107HReg hregX86_XMM1 ( void ) { return mkHReg(1, HRcVec128, False); }
108HReg hregX86_XMM2 ( void ) { return mkHReg(2, HRcVec128, False); }
109HReg hregX86_XMM3 ( void ) { return mkHReg(3, HRcVec128, False); }
110HReg hregX86_XMM4 ( void ) { return mkHReg(4, HRcVec128, False); }
111HReg hregX86_XMM5 ( void ) { return mkHReg(5, HRcVec128, False); }
112HReg hregX86_XMM6 ( void ) { return mkHReg(6, HRcVec128, False); }
113HReg hregX86_XMM7 ( void ) { return mkHReg(7, HRcVec128, False); }
114
115
sewardjf13a16a2004-07-05 17:10:14 +0000116void getAllocableRegs_X86 ( Int* nregs, HReg** arr )
117{
sewardjd08f2d72004-12-01 23:19:36 +0000118 *nregs = 20;
sewardjf13a16a2004-07-05 17:10:14 +0000119 *arr = LibVEX_Alloc(*nregs * sizeof(HReg));
sewardj0a5f5c82004-07-07 11:56:35 +0000120 (*arr)[0] = hregX86_EAX();
121 (*arr)[1] = hregX86_EBX();
122 (*arr)[2] = hregX86_ECX();
123 (*arr)[3] = hregX86_EDX();
124 (*arr)[4] = hregX86_ESI();
125 (*arr)[5] = hregX86_EDI();
sewardjd1725d12004-08-12 20:46:53 +0000126 (*arr)[6] = hregX86_FAKE0();
127 (*arr)[7] = hregX86_FAKE1();
128 (*arr)[8] = hregX86_FAKE2();
129 (*arr)[9] = hregX86_FAKE3();
sewardjeafde5a2004-10-09 01:36:57 +0000130 (*arr)[10] = hregX86_FAKE4();
131 (*arr)[11] = hregX86_FAKE5();
sewardjd08f2d72004-12-01 23:19:36 +0000132 (*arr)[12] = hregX86_XMM0();
133 (*arr)[13] = hregX86_XMM1();
134 (*arr)[14] = hregX86_XMM2();
135 (*arr)[15] = hregX86_XMM3();
136 (*arr)[16] = hregX86_XMM4();
137 (*arr)[17] = hregX86_XMM5();
138 (*arr)[18] = hregX86_XMM6();
139 (*arr)[19] = hregX86_XMM7();
sewardjf13a16a2004-07-05 17:10:14 +0000140}
sewardj53f85a92004-07-02 13:45:17 +0000141
sewardjc97096c2004-06-30 09:28:04 +0000142
sewardj443cd9d2004-07-18 23:06:45 +0000143/* --------- Condition codes, Intel encoding. --------- */
144
sewardj810dcf02004-11-22 12:55:45 +0000145HChar* showX86CondCode ( X86CondCode cond )
sewardj443cd9d2004-07-18 23:06:45 +0000146{
147 switch (cond) {
sewardj60f4e3c2004-07-19 01:56:50 +0000148 case Xcc_O: return "o";
149 case Xcc_NO: return "no";
150 case Xcc_B: return "b";
151 case Xcc_NB: return "nb";
152 case Xcc_Z: return "z";
153 case Xcc_NZ: return "nz";
154 case Xcc_BE: return "be";
155 case Xcc_NBE: return "nbe";
156 case Xcc_S: return "s";
157 case Xcc_NS: return "ns";
158 case Xcc_P: return "p";
159 case Xcc_NP: return "np";
160 case Xcc_L: return "l";
161 case Xcc_NL: return "nl";
162 case Xcc_LE: return "le";
163 case Xcc_NLE: return "nle";
164 case Xcc_ALWAYS: return "ALWAYS";
sewardj443cd9d2004-07-18 23:06:45 +0000165 default: vpanic("ppX86CondCode");
166 }
167}
168
169
sewardjc97096c2004-06-30 09:28:04 +0000170/* --------- X86AMode: memory address expressions. --------- */
171
172X86AMode* X86AMode_IR ( UInt imm32, HReg reg ) {
sewardj35421a32004-07-05 13:12:34 +0000173 X86AMode* am = LibVEX_Alloc(sizeof(X86AMode));
sewardjc97096c2004-06-30 09:28:04 +0000174 am->tag = Xam_IR;
175 am->Xam.IR.imm = imm32;
176 am->Xam.IR.reg = reg;
177 return am;
178}
sewardj0e63b522004-08-25 13:24:44 +0000179X86AMode* X86AMode_IRRS ( UInt imm32, HReg base, HReg indEx, Int shift ) {
sewardj35421a32004-07-05 13:12:34 +0000180 X86AMode* am = LibVEX_Alloc(sizeof(X86AMode));
sewardjc97096c2004-06-30 09:28:04 +0000181 am->tag = Xam_IRRS;
182 am->Xam.IRRS.imm = imm32;
183 am->Xam.IRRS.base = base;
sewardj0e63b522004-08-25 13:24:44 +0000184 am->Xam.IRRS.index = indEx;
sewardjc97096c2004-06-30 09:28:04 +0000185 am->Xam.IRRS.shift = shift;
sewardj35421a32004-07-05 13:12:34 +0000186 vassert(shift >= 0 && shift <= 3);
sewardjc97096c2004-06-30 09:28:04 +0000187 return am;
188}
189
sewardj218e29f2004-11-07 18:45:15 +0000190X86AMode* dopyX86AMode ( X86AMode* am ) {
191 switch (am->tag) {
192 case Xam_IR:
193 return X86AMode_IR( am->Xam.IR.imm, am->Xam.IR.reg );
194 case Xam_IRRS:
195 return X86AMode_IRRS( am->Xam.IRRS.imm, am->Xam.IRRS.base,
196 am->Xam.IRRS.index, am->Xam.IRRS.shift );
197 default:
198 vpanic("dopyX86AMode");
199 }
200}
201
sewardj35421a32004-07-05 13:12:34 +0000202void ppX86AMode ( X86AMode* am ) {
sewardjc97096c2004-06-30 09:28:04 +0000203 switch (am->tag) {
204 case Xam_IR:
sewardjea64e142004-07-22 16:47:21 +0000205 if (am->Xam.IR.imm == 0)
206 vex_printf("(");
207 else
208 vex_printf("0x%x(", am->Xam.IR.imm);
sewardj35421a32004-07-05 13:12:34 +0000209 ppHRegX86(am->Xam.IR.reg);
210 vex_printf(")");
sewardjc97096c2004-06-30 09:28:04 +0000211 return;
212 case Xam_IRRS:
sewardj35421a32004-07-05 13:12:34 +0000213 vex_printf("0x%x(", am->Xam.IRRS.imm);
214 ppHRegX86(am->Xam.IRRS.base);
215 vex_printf(",");
216 ppHRegX86(am->Xam.IRRS.index);
sewardjea64e142004-07-22 16:47:21 +0000217 vex_printf(",%d)", 1 << am->Xam.IRRS.shift);
sewardjc97096c2004-06-30 09:28:04 +0000218 return;
219 default:
sewardj35421a32004-07-05 13:12:34 +0000220 vpanic("ppX86AMode");
sewardjc97096c2004-06-30 09:28:04 +0000221 }
222}
223
sewardj53f85a92004-07-02 13:45:17 +0000224static void addRegUsage_X86AMode ( HRegUsage* u, X86AMode* am ) {
225 switch (am->tag) {
226 case Xam_IR:
227 addHRegUse(u, HRmRead, am->Xam.IR.reg);
228 return;
229 case Xam_IRRS:
230 addHRegUse(u, HRmRead, am->Xam.IRRS.base);
231 addHRegUse(u, HRmRead, am->Xam.IRRS.index);
232 return;
233 default:
sewardj35421a32004-07-05 13:12:34 +0000234 vpanic("addRegUsage_X86AMode");
sewardj53f85a92004-07-02 13:45:17 +0000235 }
236}
237
238static void mapRegs_X86AMode ( HRegRemap* m, X86AMode* am ) {
239 switch (am->tag) {
240 case Xam_IR:
241 am->Xam.IR.reg = lookupHRegRemap(m, am->Xam.IR.reg);
242 return;
243 case Xam_IRRS:
244 am->Xam.IRRS.base = lookupHRegRemap(m, am->Xam.IRRS.base);
245 am->Xam.IRRS.index = lookupHRegRemap(m, am->Xam.IRRS.index);
246 return;
247 default:
sewardj35421a32004-07-05 13:12:34 +0000248 vpanic("mapRegs_X86AMode");
sewardj53f85a92004-07-02 13:45:17 +0000249 }
250}
sewardjc97096c2004-06-30 09:28:04 +0000251
sewardj66f2f792004-06-30 16:37:16 +0000252/* --------- Operand, which can be reg, immediate or memory. --------- */
sewardjc97096c2004-06-30 09:28:04 +0000253
sewardj66f2f792004-06-30 16:37:16 +0000254X86RMI* X86RMI_Imm ( UInt imm32 ) {
sewardj35421a32004-07-05 13:12:34 +0000255 X86RMI* op = LibVEX_Alloc(sizeof(X86RMI));
sewardj66f2f792004-06-30 16:37:16 +0000256 op->tag = Xrmi_Imm;
257 op->Xrmi.Imm.imm32 = imm32;
sewardjc97096c2004-06-30 09:28:04 +0000258 return op;
259}
sewardj66f2f792004-06-30 16:37:16 +0000260X86RMI* X86RMI_Reg ( HReg reg ) {
sewardj35421a32004-07-05 13:12:34 +0000261 X86RMI* op = LibVEX_Alloc(sizeof(X86RMI));
sewardj66f2f792004-06-30 16:37:16 +0000262 op->tag = Xrmi_Reg;
263 op->Xrmi.Reg.reg = reg;
sewardjc97096c2004-06-30 09:28:04 +0000264 return op;
265}
sewardj66f2f792004-06-30 16:37:16 +0000266X86RMI* X86RMI_Mem ( X86AMode* am ) {
sewardj35421a32004-07-05 13:12:34 +0000267 X86RMI* op = LibVEX_Alloc(sizeof(X86RMI));
sewardj66f2f792004-06-30 16:37:16 +0000268 op->tag = Xrmi_Mem;
269 op->Xrmi.Mem.am = am;
sewardjc97096c2004-06-30 09:28:04 +0000270 return op;
271}
272
sewardj35421a32004-07-05 13:12:34 +0000273void ppX86RMI ( X86RMI* op ) {
sewardjc97096c2004-06-30 09:28:04 +0000274 switch (op->tag) {
sewardj66f2f792004-06-30 16:37:16 +0000275 case Xrmi_Imm:
sewardj35421a32004-07-05 13:12:34 +0000276 vex_printf("$0x%x", op->Xrmi.Imm.imm32);
sewardjc97096c2004-06-30 09:28:04 +0000277 return;
sewardj66f2f792004-06-30 16:37:16 +0000278 case Xrmi_Reg:
sewardj35421a32004-07-05 13:12:34 +0000279 ppHRegX86(op->Xrmi.Reg.reg);
sewardjc97096c2004-06-30 09:28:04 +0000280 return;
sewardj66f2f792004-06-30 16:37:16 +0000281 case Xrmi_Mem:
sewardj35421a32004-07-05 13:12:34 +0000282 ppX86AMode(op->Xrmi.Mem.am);
sewardjc97096c2004-06-30 09:28:04 +0000283 return;
284 default:
sewardj35421a32004-07-05 13:12:34 +0000285 vpanic("ppX86RMI");
sewardj66f2f792004-06-30 16:37:16 +0000286 }
287}
288
sewardj53f85a92004-07-02 13:45:17 +0000289/* An X86RMI can only be used in a "read" context (what would it mean
290 to write or modify a literal?) and so we enumerate its registers
291 accordingly. */
292static void addRegUsage_X86RMI ( HRegUsage* u, X86RMI* op ) {
293 switch (op->tag) {
294 case Xrmi_Imm:
295 return;
296 case Xrmi_Reg:
297 addHRegUse(u, HRmRead, op->Xrmi.Reg.reg);
298 return;
299 case Xrmi_Mem:
300 addRegUsage_X86AMode(u, op->Xrmi.Mem.am);
301 return;
302 default:
sewardj35421a32004-07-05 13:12:34 +0000303 vpanic("addRegUsage_X86RMI");
sewardj53f85a92004-07-02 13:45:17 +0000304 }
305}
306
307static void mapRegs_X86RMI ( HRegRemap* m, X86RMI* op ) {
308 switch (op->tag) {
309 case Xrmi_Imm:
310 return;
311 case Xrmi_Reg:
312 op->Xrmi.Reg.reg = lookupHRegRemap(m, op->Xrmi.Reg.reg);
313 return;
314 case Xrmi_Mem:
315 mapRegs_X86AMode(m, op->Xrmi.Mem.am);
316 return;
317 default:
sewardj35421a32004-07-05 13:12:34 +0000318 vpanic("mapRegs_X86RMI");
sewardj53f85a92004-07-02 13:45:17 +0000319 }
320}
321
sewardj66f2f792004-06-30 16:37:16 +0000322
323/* --------- Operand, which can be reg or immediate only. --------- */
324
325X86RI* X86RI_Imm ( UInt imm32 ) {
sewardj35421a32004-07-05 13:12:34 +0000326 X86RI* op = LibVEX_Alloc(sizeof(X86RI));
sewardj66f2f792004-06-30 16:37:16 +0000327 op->tag = Xri_Imm;
328 op->Xri.Imm.imm32 = imm32;
329 return op;
330}
sewardj66f2f792004-06-30 16:37:16 +0000331X86RI* X86RI_Reg ( HReg reg ) {
sewardj35421a32004-07-05 13:12:34 +0000332 X86RI* op = LibVEX_Alloc(sizeof(X86RI));
sewardj66f2f792004-06-30 16:37:16 +0000333 op->tag = Xri_Reg;
334 op->Xri.Reg.reg = reg;
335 return op;
336}
337
sewardj35421a32004-07-05 13:12:34 +0000338void ppX86RI ( X86RI* op ) {
sewardj66f2f792004-06-30 16:37:16 +0000339 switch (op->tag) {
340 case Xri_Imm:
sewardj35421a32004-07-05 13:12:34 +0000341 vex_printf("$0x%x", op->Xri.Imm.imm32);
sewardj66f2f792004-06-30 16:37:16 +0000342 return;
343 case Xri_Reg:
sewardj35421a32004-07-05 13:12:34 +0000344 ppHRegX86(op->Xri.Reg.reg);
sewardj66f2f792004-06-30 16:37:16 +0000345 return;
346 default:
sewardj35421a32004-07-05 13:12:34 +0000347 vpanic("ppX86RI");
sewardj66f2f792004-06-30 16:37:16 +0000348 }
349}
350
sewardj53f85a92004-07-02 13:45:17 +0000351/* An X86RI can only be used in a "read" context (what would it mean
352 to write or modify a literal?) and so we enumerate its registers
353 accordingly. */
354static void addRegUsage_X86RI ( HRegUsage* u, X86RI* op ) {
355 switch (op->tag) {
356 case Xri_Imm:
357 return;
358 case Xri_Reg:
359 addHRegUse(u, HRmRead, op->Xri.Reg.reg);
360 return;
361 default:
sewardj35421a32004-07-05 13:12:34 +0000362 vpanic("addRegUsage_X86RI");
sewardj53f85a92004-07-02 13:45:17 +0000363 }
364}
365
366static void mapRegs_X86RI ( HRegRemap* m, X86RI* op ) {
367 switch (op->tag) {
368 case Xri_Imm:
369 return;
370 case Xri_Reg:
371 op->Xri.Reg.reg = lookupHRegRemap(m, op->Xri.Reg.reg);
372 return;
373 default:
sewardj35421a32004-07-05 13:12:34 +0000374 vpanic("mapRegs_X86RI");
sewardj53f85a92004-07-02 13:45:17 +0000375 }
376}
377
sewardj66f2f792004-06-30 16:37:16 +0000378
379/* --------- Operand, which can be reg or memory only. --------- */
380
381X86RM* X86RM_Reg ( HReg reg ) {
sewardj35421a32004-07-05 13:12:34 +0000382 X86RM* op = LibVEX_Alloc(sizeof(X86RM));
sewardj66f2f792004-06-30 16:37:16 +0000383 op->tag = Xrm_Reg;
384 op->Xrm.Reg.reg = reg;
385 return op;
386}
sewardj66f2f792004-06-30 16:37:16 +0000387X86RM* X86RM_Mem ( X86AMode* am ) {
sewardj35421a32004-07-05 13:12:34 +0000388 X86RM* op = LibVEX_Alloc(sizeof(X86RM));
sewardj66f2f792004-06-30 16:37:16 +0000389 op->tag = Xrm_Mem;
390 op->Xrm.Mem.am = am;
391 return op;
392}
393
sewardj35421a32004-07-05 13:12:34 +0000394void ppX86RM ( X86RM* op ) {
sewardj66f2f792004-06-30 16:37:16 +0000395 switch (op->tag) {
396 case Xrm_Mem:
sewardj35421a32004-07-05 13:12:34 +0000397 ppX86AMode(op->Xrm.Mem.am);
sewardj66f2f792004-06-30 16:37:16 +0000398 return;
399 case Xrm_Reg:
sewardj35421a32004-07-05 13:12:34 +0000400 ppHRegX86(op->Xrm.Reg.reg);
sewardj66f2f792004-06-30 16:37:16 +0000401 return;
402 default:
sewardj35421a32004-07-05 13:12:34 +0000403 vpanic("ppX86RM");
sewardjc97096c2004-06-30 09:28:04 +0000404 }
405}
406
sewardj53f85a92004-07-02 13:45:17 +0000407/* Because an X86RM can be both a source or destination operand, we
408 have to supply a mode -- pertaining to the operand as a whole --
409 indicating how it's being used. */
410static void addRegUsage_X86RM ( HRegUsage* u, X86RM* op, HRegMode mode ) {
411 switch (op->tag) {
412 case Xrm_Mem:
413 /* Memory is read, written or modified. So we just want to
414 know the regs read by the amode. */
415 addRegUsage_X86AMode(u, op->Xrm.Mem.am);
416 return;
417 case Xrm_Reg:
418 /* reg is read, written or modified. Add it in the
419 appropriate way. */
420 addHRegUse(u, mode, op->Xrm.Reg.reg);
421 return;
422 default:
sewardj35421a32004-07-05 13:12:34 +0000423 vpanic("addRegUsage_X86RM");
sewardj53f85a92004-07-02 13:45:17 +0000424 }
425}
426
427static void mapRegs_X86RM ( HRegRemap* m, X86RM* op )
428{
429 switch (op->tag) {
430 case Xrm_Mem:
431 mapRegs_X86AMode(m, op->Xrm.Mem.am);
432 return;
433 case Xrm_Reg:
434 op->Xrm.Reg.reg = lookupHRegRemap(m, op->Xrm.Reg.reg);
435 return;
436 default:
sewardj35421a32004-07-05 13:12:34 +0000437 vpanic("mapRegs_X86RM");
sewardj53f85a92004-07-02 13:45:17 +0000438 }
439}
440
sewardjc97096c2004-06-30 09:28:04 +0000441
442/* --------- Instructions. --------- */
443
sewardjd08f2d72004-12-01 23:19:36 +0000444HChar* showX86UnaryOp ( X86UnaryOp op ) {
sewardj66f2f792004-06-30 16:37:16 +0000445 switch (op) {
sewardj358b7d42004-11-08 18:54:50 +0000446 case Xun_NOT: return "not";
447 case Xun_NEG: return "neg";
sewardjcfded9a2004-09-09 11:44:16 +0000448 default: vpanic("showX86UnaryOp");
sewardj60f4e3c2004-07-19 01:56:50 +0000449 }
450}
451
sewardjd08f2d72004-12-01 23:19:36 +0000452HChar* showX86AluOp ( X86AluOp op ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000453 switch (op) {
454 case Xalu_MOV: return "mov";
455 case Xalu_CMP: return "cmp";
sewardj60f4e3c2004-07-19 01:56:50 +0000456 case Xalu_ADD: return "add";
457 case Xalu_SUB: return "sub";
458 case Xalu_ADC: return "adc";
459 case Xalu_SBB: return "sbb";
460 case Xalu_AND: return "and";
461 case Xalu_OR: return "or";
462 case Xalu_XOR: return "xor";
463 case Xalu_MUL: return "mul";
sewardjcfded9a2004-09-09 11:44:16 +0000464 default: vpanic("showX86AluOp");
sewardj60f4e3c2004-07-19 01:56:50 +0000465 }
466}
467
sewardjd08f2d72004-12-01 23:19:36 +0000468HChar* showX86ShiftOp ( X86ShiftOp op ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000469 switch (op) {
470 case Xsh_SHL: return "shl";
471 case Xsh_SHR: return "shr";
472 case Xsh_SAR: return "sar";
sewardjcfded9a2004-09-09 11:44:16 +0000473 default: vpanic("showX86ShiftOp");
sewardj66f2f792004-06-30 16:37:16 +0000474 }
sewardj66f2f792004-06-30 16:37:16 +0000475}
476
sewardjd08f2d72004-12-01 23:19:36 +0000477HChar* showX86FpOp ( X86FpOp op ) {
sewardjd1725d12004-08-12 20:46:53 +0000478 switch (op) {
sewardjbb53f8c2004-08-14 11:50:01 +0000479 case Xfp_ADD: return "add";
480 case Xfp_SUB: return "sub";
481 case Xfp_MUL: return "mul";
482 case Xfp_DIV: return "div";
sewardj8d387782004-11-11 02:15:15 +0000483 case Xfp_SCALE: return "scale";
484 case Xfp_ATAN: return "atan";
485 case Xfp_YL2X: return "yl2x";
486 case Xfp_YL2XP1: return "yl2xp1";
487 case Xfp_PREM: return "prem";
488 case Xfp_PREM1: return "prem1";
sewardjbb53f8c2004-08-14 11:50:01 +0000489 case Xfp_SQRT: return "sqrt";
sewardj883b00b2004-09-11 09:30:24 +0000490 case Xfp_ABS: return "abs";
sewardj8d387782004-11-11 02:15:15 +0000491 case Xfp_NEG: return "chs";
sewardjbb53f8c2004-08-14 11:50:01 +0000492 case Xfp_MOV: return "mov";
sewardjcfded9a2004-09-09 11:44:16 +0000493 case Xfp_SIN: return "sin";
494 case Xfp_COS: return "cos";
sewardj99016a72004-10-15 22:09:17 +0000495 case Xfp_TAN: return "tan";
sewardj8d387782004-11-11 02:15:15 +0000496 case Xfp_ROUND: return "round";
sewardj06c32a02004-09-12 12:07:34 +0000497 case Xfp_2XM1: return "2xm1";
sewardjcfded9a2004-09-09 11:44:16 +0000498 default: vpanic("showX86FpOp");
sewardjd1725d12004-08-12 20:46:53 +0000499 }
500}
501
sewardjd08f2d72004-12-01 23:19:36 +0000502HChar* showX86SseOp ( X86SseOp op ) {
503 switch (op) {
sewardj164f9272004-12-09 00:39:32 +0000504 case Xsse_MOV: return "mov(?!)";
505 case Xsse_ADDF: return "add";
506 case Xsse_SUBF: return "sub";
507 case Xsse_MULF: return "mul";
508 case Xsse_DIVF: return "div";
509 case Xsse_MAXF: return "max";
510 case Xsse_MINF: return "min";
511 case Xsse_CMPEQF: return "cmpFeq";
512 case Xsse_CMPLTF: return "cmpFlt";
513 case Xsse_CMPLEF: return "cmpFle";
514 case Xsse_CMPUNF: return "cmpFun";
515 case Xsse_RCPF: return "rcp";
516 case Xsse_RSQRTF: return "rsqrt";
517 case Xsse_SQRTF: return "sqrt";
518 case Xsse_AND: return "and";
519 case Xsse_OR: return "or";
520 case Xsse_XOR: return "xor";
521 case Xsse_ANDN: return "andn";
522 case Xsse_ADD8: return "paddb";
523 case Xsse_ADD16: return "paddw";
524 case Xsse_ADD32: return "paddd";
525 case Xsse_ADD64: return "paddq";
526 case Xsse_QADD8U: return "paddusb";
527 case Xsse_QADD16U: return "paddusw";
528 case Xsse_QADD8S: return "paddsb";
529 case Xsse_QADD16S: return "paddsw";
530 case Xsse_SUB8: return "psubb";
531 case Xsse_SUB16: return "psubw";
532 case Xsse_SUB32: return "psubd";
533 case Xsse_SUB64: return "psubq";
534 case Xsse_QSUB8U: return "psubusb";
535 case Xsse_QSUB16U: return "psubusw";
536 case Xsse_QSUB8S: return "psubsb";
537 case Xsse_QSUB16S: return "psubsw";
538 case Xsse_MUL16: return "pmullw";
539 case Xsse_MULHI16U: return "pmulhuw";
540 case Xsse_MULHI16S: return "pmulhw";
541 case Xsse_AVG8U: return "pavgb";
542 case Xsse_AVG16U: return "pavgw";
543 case Xsse_MAX16S: return "pmaxw";
544 case Xsse_MAX8U: return "pmaxub";
545 case Xsse_MIN16S: return "pminw";
546 case Xsse_MIN8U: return "pminub";
547 case Xsse_CMPEQ8: return "pcmpeqb";
548 case Xsse_CMPEQ16: return "pcmpeqw";
549 case Xsse_CMPEQ32: return "pcmpeqd";
550 case Xsse_CMPGT8S: return "pcmpgtb";
551 case Xsse_CMPGT16S: return "pcmpgtw";
552 case Xsse_CMPGT32S: return "pcmpgtd";
553 case Xsse_SHL16: return "psllw";
554 case Xsse_SHL32: return "pslld";
555 case Xsse_SHL64: return "psllq";
556 case Xsse_SHR16: return "psrlw";
557 case Xsse_SHR32: return "psrld";
558 case Xsse_SHR64: return "psrlq";
559 case Xsse_SAR16: return "psraw";
560 case Xsse_SAR32: return "psrad";
561 case Xsse_PACKSSD: return "packssdw";
562 case Xsse_PACKSSW: return "packsswb";
563 case Xsse_PACKUSW: return "packuswb";
sewardj9e203592004-12-10 01:48:18 +0000564 case Xsse_UNPCKHB: return "punpckhb";
565 case Xsse_UNPCKHW: return "punpckhw";
566 case Xsse_UNPCKHD: return "punpckhd";
567 case Xsse_UNPCKHQ: return "punpckhq";
568 case Xsse_UNPCKLB: return "punpcklb";
569 case Xsse_UNPCKLW: return "punpcklw";
570 case Xsse_UNPCKLD: return "punpckld";
571 case Xsse_UNPCKLQ: return "punpcklq";
sewardjd08f2d72004-12-01 23:19:36 +0000572 default: vpanic("showX86SseOp");
573 }
574}
575
sewardj66f2f792004-06-30 16:37:16 +0000576X86Instr* X86Instr_Alu32R ( X86AluOp op, X86RMI* src, HReg dst ) {
sewardj35421a32004-07-05 13:12:34 +0000577 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardj66f2f792004-06-30 16:37:16 +0000578 i->tag = Xin_Alu32R;
579 i->Xin.Alu32R.op = op;
580 i->Xin.Alu32R.src = src;
581 i->Xin.Alu32R.dst = dst;
582 return i;
583}
sewardj66f2f792004-06-30 16:37:16 +0000584X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) {
sewardj35421a32004-07-05 13:12:34 +0000585 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardj66f2f792004-06-30 16:37:16 +0000586 i->tag = Xin_Alu32M;
587 i->Xin.Alu32M.op = op;
588 i->Xin.Alu32M.src = src;
589 i->Xin.Alu32M.dst = dst;
sewardje8c922f2004-07-23 01:34:11 +0000590 vassert(op != Xalu_MUL);
591 return i;
592}
sewardjeba63f82005-02-23 13:31:25 +0000593X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, HReg dst ) {
sewardje8c922f2004-07-23 01:34:11 +0000594 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
595 i->tag = Xin_Sh32;
596 i->Xin.Sh32.op = op;
597 i->Xin.Sh32.src = src;
598 i->Xin.Sh32.dst = dst;
599 return i;
600}
sewardjeba63f82005-02-23 13:31:25 +0000601X86Instr* X86Instr_Test32 ( UInt imm32, HReg dst ) {
602 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
603 i->tag = Xin_Test32;
604 i->Xin.Test32.imm32 = imm32;
605 i->Xin.Test32.dst = dst;
sewardj66f2f792004-06-30 16:37:16 +0000606 return i;
607}
sewardjeba63f82005-02-23 13:31:25 +0000608X86Instr* X86Instr_Unary32 ( X86UnaryOp op, HReg dst ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000609 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
610 i->tag = Xin_Unary32;
611 i->Xin.Unary32.op = op;
612 i->Xin.Unary32.dst = dst;
sewardj443cd9d2004-07-18 23:06:45 +0000613 return i;
614}
sewardjeba63f82005-02-23 13:31:25 +0000615X86Instr* X86Instr_MulL ( Bool syned, X86RM* src ) {
sewardj597b71b2004-07-19 02:51:12 +0000616 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
617 i->tag = Xin_MulL;
618 i->Xin.MulL.syned = syned;
sewardj597b71b2004-07-19 02:51:12 +0000619 i->Xin.MulL.src = src;
620 return i;
621}
sewardjeba63f82005-02-23 13:31:25 +0000622X86Instr* X86Instr_Div ( Bool syned, X86RM* src ) {
623 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
624 i->tag = Xin_Div;
625 i->Xin.Div.syned = syned;
626 i->Xin.Div.src = src;
sewardj5c34dc92004-07-19 12:48:11 +0000627 return i;
628}
sewardje5f384c2004-07-30 16:17:28 +0000629X86Instr* X86Instr_Sh3232 ( X86ShiftOp op, UInt amt, HReg src, HReg dst ) {
sewardj5c34dc92004-07-19 12:48:11 +0000630 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
631 i->tag = Xin_Sh3232;
632 i->Xin.Sh3232.op = op;
633 i->Xin.Sh3232.amt = amt;
sewardje5f384c2004-07-30 16:17:28 +0000634 i->Xin.Sh3232.src = src;
635 i->Xin.Sh3232.dst = dst;
sewardj5c34dc92004-07-19 12:48:11 +0000636 vassert(op == Xsh_SHL || op == Xsh_SHR);
637 return i;
638}
sewardje8e9d732004-07-16 21:03:45 +0000639X86Instr* X86Instr_Push( X86RMI* src ) {
sewardj35421a32004-07-05 13:12:34 +0000640 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardje8e9d732004-07-16 21:03:45 +0000641 i->tag = Xin_Push;
642 i->Xin.Push.src = src;
643 return i;
644}
sewardj4b861de2004-11-03 15:24:42 +0000645X86Instr* X86Instr_Call ( X86CondCode cond, Addr32 target, Int regparms ) {
sewardj77352542004-10-30 20:39:01 +0000646 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
647 i->tag = Xin_Call;
sewardj4b861de2004-11-03 15:24:42 +0000648 i->Xin.Call.cond = cond;
sewardj77352542004-10-30 20:39:01 +0000649 i->Xin.Call.target = target;
650 i->Xin.Call.regparms = regparms;
651 vassert(regparms >= 0 && regparms <= 3);
sewardje8e9d732004-07-16 21:03:45 +0000652 return i;
653}
sewardj750f4072004-07-26 22:39:11 +0000654X86Instr* X86Instr_Goto ( IRJumpKind jk, X86CondCode cond, X86RI* dst ) {
sewardj443cd9d2004-07-18 23:06:45 +0000655 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
656 i->tag = Xin_Goto;
657 i->Xin.Goto.cond = cond;
658 i->Xin.Goto.dst = dst;
sewardj750f4072004-07-26 22:39:11 +0000659 i->Xin.Goto.jk = jk;
sewardjc97096c2004-06-30 09:28:04 +0000660 return i;
661}
sewardj5c34dc92004-07-19 12:48:11 +0000662X86Instr* X86Instr_CMov32 ( X86CondCode cond, X86RM* src, HReg dst ) {
663 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
664 i->tag = Xin_CMov32;
665 i->Xin.CMov32.cond = cond;
666 i->Xin.CMov32.src = src;
667 i->Xin.CMov32.dst = dst;
668 vassert(cond != Xcc_ALWAYS);
sewardj4042c7e2004-07-18 01:28:30 +0000669 return i;
670}
sewardj4042c7e2004-07-18 01:28:30 +0000671X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
672 X86AMode* src, HReg dst ) {
673 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
674 i->tag = Xin_LoadEX;
675 i->Xin.LoadEX.szSmall = szSmall;
676 i->Xin.LoadEX.syned = syned;
677 i->Xin.LoadEX.src = src;
678 i->Xin.LoadEX.dst = dst;
679 vassert(szSmall == 1 || szSmall == 2);
680 return i;
681}
sewardjd1725d12004-08-12 20:46:53 +0000682X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ) {
sewardj443cd9d2004-07-18 23:06:45 +0000683 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
684 i->tag = Xin_Store;
685 i->Xin.Store.sz = sz;
686 i->Xin.Store.src = src;
687 i->Xin.Store.dst = dst;
688 vassert(sz == 1 || sz == 2);
689 return i;
690}
sewardjd7cb8532004-08-17 23:59:23 +0000691X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ) {
692 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
693 i->tag = Xin_Set32;
694 i->Xin.Set32.cond = cond;
695 i->Xin.Set32.dst = dst;
696 return i;
697}
sewardjd08f2d72004-12-01 23:19:36 +0000698X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst ) {
sewardjce646f22004-08-31 23:55:54 +0000699 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
700 i->tag = Xin_Bsfr32;
701 i->Xin.Bsfr32.isFwds = isFwds;
702 i->Xin.Bsfr32.src = src;
703 i->Xin.Bsfr32.dst = dst;
704 return i;
705}
sewardj3e838932005-01-07 12:09:15 +0000706X86Instr* X86Instr_MFence ( VexSubArch subarch )
707{
708 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
709 i->tag = Xin_MFence;
710 i->Xin.MFence.subarch = subarch;
711 vassert(subarch == VexSubArchX86_sse0
712 || subarch == VexSubArchX86_sse1
713 || subarch == VexSubArchX86_sse2);
714 return i;
715}
716
sewardjd1725d12004-08-12 20:46:53 +0000717X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) {
718 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
719 i->tag = Xin_FpUnary;
720 i->Xin.FpUnary.op = op;
721 i->Xin.FpUnary.src = src;
722 i->Xin.FpUnary.dst = dst;
723 return i;
724}
725X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst ) {
726 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
727 i->tag = Xin_FpBinary;
728 i->Xin.FpBinary.op = op;
729 i->Xin.FpBinary.srcL = srcL;
730 i->Xin.FpBinary.srcR = srcR;
731 i->Xin.FpBinary.dst = dst;
732 return i;
733}
734X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* addr ) {
735 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
736 i->tag = Xin_FpLdSt;
737 i->Xin.FpLdSt.isLoad = isLoad;
738 i->Xin.FpLdSt.sz = sz;
739 i->Xin.FpLdSt.reg = reg;
740 i->Xin.FpLdSt.addr = addr;
741 vassert(sz == 4 || sz == 8);
742 return i;
743}
sewardjd08f2d72004-12-01 23:19:36 +0000744X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz,
745 HReg reg, X86AMode* addr ) {
sewardj89cd0932004-09-08 18:23:25 +0000746 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
747 i->tag = Xin_FpLdStI;
748 i->Xin.FpLdStI.isLoad = isLoad;
749 i->Xin.FpLdStI.sz = sz;
750 i->Xin.FpLdStI.reg = reg;
751 i->Xin.FpLdStI.addr = addr;
752 vassert(sz == 2 || sz == 4 || sz == 8);
sewardjd1725d12004-08-12 20:46:53 +0000753 return i;
754}
sewardj3bca9062004-12-04 14:36:09 +0000755X86Instr* X86Instr_Fp64to32 ( HReg src, HReg dst ) {
756 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
757 i->tag = Xin_Fp64to32;
758 i->Xin.Fp64to32.src = src;
759 i->Xin.Fp64to32.dst = dst;
760 return i;
761}
sewardj33124f62004-08-30 17:54:18 +0000762X86Instr* X86Instr_FpCMov ( X86CondCode cond, HReg src, HReg dst ) {
763 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
764 i->tag = Xin_FpCMov;
765 i->Xin.FpCMov.cond = cond;
766 i->Xin.FpCMov.src = src;
767 i->Xin.FpCMov.dst = dst;
768 vassert(cond != Xcc_ALWAYS);
769 return i;
770}
sewardjeba63f82005-02-23 13:31:25 +0000771X86Instr* X86Instr_FpLdCW ( X86AMode* addr ) {
772 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
773 i->tag = Xin_FpLdCW;
774 i->Xin.FpLdCW.addr = addr;
sewardj8f3debf2004-09-08 23:42:23 +0000775 return i;
776}
sewardjd08f2d72004-12-01 23:19:36 +0000777X86Instr* X86Instr_FpStSW_AX ( void ) {
sewardj46de4072004-09-11 19:23:24 +0000778 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
779 i->tag = Xin_FpStSW_AX;
780 return i;
781}
sewardjd08f2d72004-12-01 23:19:36 +0000782X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ) {
sewardjbdc7d212004-09-09 02:46:40 +0000783 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
784 i->tag = Xin_FpCmp;
785 i->Xin.FpCmp.srcL = srcL;
786 i->Xin.FpCmp.srcR = srcR;
787 i->Xin.FpCmp.dst = dst;
788 return i;
789}
sewardj4042c7e2004-07-18 01:28:30 +0000790
sewardj1e6ad742004-12-02 16:16:11 +0000791X86Instr* X86Instr_SseConst ( UShort con, HReg dst ) {
792 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
793 i->tag = Xin_SseConst;
794 i->Xin.SseConst.con = con;
795 i->Xin.SseConst.dst = dst;
796 vassert(hregClass(dst) == HRcVec128);
797 return i;
798}
sewardjd08f2d72004-12-01 23:19:36 +0000799X86Instr* X86Instr_SseLdSt ( Bool isLoad, HReg reg, X86AMode* addr ) {
800 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
801 i->tag = Xin_SseLdSt;
802 i->Xin.SseLdSt.isLoad = isLoad;
803 i->Xin.SseLdSt.reg = reg;
804 i->Xin.SseLdSt.addr = addr;
805 return i;
806}
sewardj129b3d92004-12-05 15:42:05 +0000807X86Instr* X86Instr_SseLdzLO ( Int sz, HReg reg, X86AMode* addr )
808{
809 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
810 i->tag = Xin_SseLdzLO;
sewardj8ee8c882005-02-25 17:40:26 +0000811 i->Xin.SseLdzLO.sz = toUChar(sz);
sewardj129b3d92004-12-05 15:42:05 +0000812 i->Xin.SseLdzLO.reg = reg;
813 i->Xin.SseLdzLO.addr = addr;
814 vassert(sz == 4 || sz == 8);
815 return i;
816}
sewardj636ad762004-12-07 11:16:04 +0000817X86Instr* X86Instr_Sse32Fx4 ( X86SseOp op, HReg src, HReg dst ) {
sewardjd08f2d72004-12-01 23:19:36 +0000818 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
819 i->tag = Xin_Sse32Fx4;
820 i->Xin.Sse32Fx4.op = op;
821 i->Xin.Sse32Fx4.src = src;
822 i->Xin.Sse32Fx4.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000823 vassert(op != Xsse_MOV);
sewardjd08f2d72004-12-01 23:19:36 +0000824 return i;
825}
sewardj636ad762004-12-07 11:16:04 +0000826X86Instr* X86Instr_Sse32FLo ( X86SseOp op, HReg src, HReg dst ) {
sewardjd08f2d72004-12-01 23:19:36 +0000827 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
828 i->tag = Xin_Sse32FLo;
829 i->Xin.Sse32FLo.op = op;
830 i->Xin.Sse32FLo.src = src;
831 i->Xin.Sse32FLo.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000832 vassert(op != Xsse_MOV);
sewardjd08f2d72004-12-01 23:19:36 +0000833 return i;
834}
sewardj636ad762004-12-07 11:16:04 +0000835X86Instr* X86Instr_Sse64Fx2 ( X86SseOp op, HReg src, HReg dst ) {
836 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
837 i->tag = Xin_Sse64Fx2;
838 i->Xin.Sse64Fx2.op = op;
839 i->Xin.Sse64Fx2.src = src;
840 i->Xin.Sse64Fx2.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000841 vassert(op != Xsse_MOV);
sewardj636ad762004-12-07 11:16:04 +0000842 return i;
843}
844X86Instr* X86Instr_Sse64FLo ( X86SseOp op, HReg src, HReg dst ) {
845 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
846 i->tag = Xin_Sse64FLo;
847 i->Xin.Sse64FLo.op = op;
848 i->Xin.Sse64FLo.src = src;
849 i->Xin.Sse64FLo.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000850 vassert(op != Xsse_MOV);
851 return i;
852}
853X86Instr* X86Instr_SseReRg ( X86SseOp op, HReg re, HReg rg ) {
854 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
855 i->tag = Xin_SseReRg;
856 i->Xin.SseReRg.op = op;
857 i->Xin.SseReRg.src = re;
858 i->Xin.SseReRg.dst = rg;
sewardj636ad762004-12-07 11:16:04 +0000859 return i;
860}
sewardjb9fa69b2004-12-09 23:25:14 +0000861X86Instr* X86Instr_SseCMov ( X86CondCode cond, HReg src, HReg dst ) {
862 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
863 i->tag = Xin_SseCMov;
864 i->Xin.SseCMov.cond = cond;
865 i->Xin.SseCMov.src = src;
866 i->Xin.SseCMov.dst = dst;
867 vassert(cond != Xcc_ALWAYS);
868 return i;
869}
sewardj109ffdb2004-12-10 21:45:38 +0000870X86Instr* X86Instr_SseShuf ( Int order, HReg src, HReg dst ) {
871 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
872 i->tag = Xin_SseShuf;
873 i->Xin.SseShuf.order = order;
874 i->Xin.SseShuf.src = src;
875 i->Xin.SseShuf.dst = dst;
876 vassert(order >= 0 && order <= 0xFF);
877 return i;
878}
sewardj4042c7e2004-07-18 01:28:30 +0000879
cerion92b64362005-12-13 12:02:26 +0000880void ppX86Instr ( X86Instr* i, Bool mode64 ) {
881 vassert(mode64 == False);
sewardjc97096c2004-06-30 09:28:04 +0000882 switch (i->tag) {
sewardj66f2f792004-06-30 16:37:16 +0000883 case Xin_Alu32R:
sewardj60f4e3c2004-07-19 01:56:50 +0000884 vex_printf("%sl ", showX86AluOp(i->Xin.Alu32R.op));
sewardj35421a32004-07-05 13:12:34 +0000885 ppX86RMI(i->Xin.Alu32R.src);
886 vex_printf(",");
887 ppHRegX86(i->Xin.Alu32R.dst);
sewardjc97096c2004-06-30 09:28:04 +0000888 return;
sewardj66f2f792004-06-30 16:37:16 +0000889 case Xin_Alu32M:
sewardj60f4e3c2004-07-19 01:56:50 +0000890 vex_printf("%sl ", showX86AluOp(i->Xin.Alu32M.op));
sewardj35421a32004-07-05 13:12:34 +0000891 ppX86RI(i->Xin.Alu32M.src);
892 vex_printf(",");
893 ppX86AMode(i->Xin.Alu32M.dst);
sewardjc97096c2004-06-30 09:28:04 +0000894 return;
sewardje8c922f2004-07-23 01:34:11 +0000895 case Xin_Sh32:
896 vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op));
897 if (i->Xin.Sh32.src == 0)
sewardjbb53f8c2004-08-14 11:50:01 +0000898 vex_printf("%%cl,");
sewardje8c922f2004-07-23 01:34:11 +0000899 else
sewardj8ee8c882005-02-25 17:40:26 +0000900 vex_printf("$%d,", (Int)i->Xin.Sh32.src);
sewardjeba63f82005-02-23 13:31:25 +0000901 ppHRegX86(i->Xin.Sh32.dst);
sewardje8c922f2004-07-23 01:34:11 +0000902 return;
903 case Xin_Test32:
sewardj8ee8c882005-02-25 17:40:26 +0000904 vex_printf("testl $%d,", (Int)i->Xin.Test32.imm32);
sewardjeba63f82005-02-23 13:31:25 +0000905 ppHRegX86(i->Xin.Test32.dst);
sewardje8c922f2004-07-23 01:34:11 +0000906 return;
sewardj60f4e3c2004-07-19 01:56:50 +0000907 case Xin_Unary32:
908 vex_printf("%sl ", showX86UnaryOp(i->Xin.Unary32.op));
sewardjeba63f82005-02-23 13:31:25 +0000909 ppHRegX86(i->Xin.Unary32.dst);
sewardj443cd9d2004-07-18 23:06:45 +0000910 return;
sewardj597b71b2004-07-19 02:51:12 +0000911 case Xin_MulL:
sewardjeba63f82005-02-23 13:31:25 +0000912 vex_printf("%cmull ", i->Xin.MulL.syned ? 's' : 'u');
sewardj597b71b2004-07-19 02:51:12 +0000913 ppX86RM(i->Xin.MulL.src);
914 return;
sewardj5c34dc92004-07-19 12:48:11 +0000915 case Xin_Div:
sewardjeba63f82005-02-23 13:31:25 +0000916 vex_printf("%cdivl ", i->Xin.Div.syned ? 's' : 'u');
sewardj5c34dc92004-07-19 12:48:11 +0000917 ppX86RM(i->Xin.Div.src);
918 return;
sewardj5c34dc92004-07-19 12:48:11 +0000919 case Xin_Sh3232:
920 vex_printf("%sdl ", showX86ShiftOp(i->Xin.Sh3232.op));
921 if (i->Xin.Sh3232.amt == 0)
sewardjea64e142004-07-22 16:47:21 +0000922 vex_printf(" %%cl,");
sewardj5c34dc92004-07-19 12:48:11 +0000923 else
sewardj8ee8c882005-02-25 17:40:26 +0000924 vex_printf(" $%d,", (Int)i->Xin.Sh3232.amt);
sewardje5f384c2004-07-30 16:17:28 +0000925 ppHRegX86(i->Xin.Sh3232.src);
sewardj5c34dc92004-07-19 12:48:11 +0000926 vex_printf(",");
sewardje5f384c2004-07-30 16:17:28 +0000927 ppHRegX86(i->Xin.Sh3232.dst);
sewardj5c34dc92004-07-19 12:48:11 +0000928 return;
sewardje8e9d732004-07-16 21:03:45 +0000929 case Xin_Push:
930 vex_printf("pushl ");
931 ppX86RMI(i->Xin.Push.src);
932 return;
933 case Xin_Call:
sewardj4b861de2004-11-03 15:24:42 +0000934 vex_printf("call%s[%d] ",
935 i->Xin.Call.cond==Xcc_ALWAYS
936 ? "" : showX86CondCode(i->Xin.Call.cond),
937 i->Xin.Call.regparms);
938 vex_printf("0x%x", i->Xin.Call.target);
sewardje8e9d732004-07-16 21:03:45 +0000939 break;
sewardj443cd9d2004-07-18 23:06:45 +0000940 case Xin_Goto:
sewardj893aada2004-11-29 19:57:54 +0000941 if (i->Xin.Goto.cond != Xcc_ALWAYS) {
942 vex_printf("if (%%eflags.%s) { ",
943 showX86CondCode(i->Xin.Goto.cond));
944 }
sewardj17c7f952005-12-15 14:02:34 +0000945 if (i->Xin.Goto.jk != Ijk_Boring
946 && i->Xin.Goto.jk != Ijk_Call
947 && i->Xin.Goto.jk != Ijk_Ret) {
sewardj750f4072004-07-26 22:39:11 +0000948 vex_printf("movl $");
949 ppIRJumpKind(i->Xin.Goto.jk);
sewardj893aada2004-11-29 19:57:54 +0000950 vex_printf(",%%ebp ; ");
sewardj750f4072004-07-26 22:39:11 +0000951 }
sewardj893aada2004-11-29 19:57:54 +0000952 vex_printf("movl ");
953 ppX86RI(i->Xin.Goto.dst);
sewardj17c7f952005-12-15 14:02:34 +0000954 vex_printf(",%%eax ; movl $dispatcher_addr,%%edx ; jmp *%%edx");
sewardj893aada2004-11-29 19:57:54 +0000955 if (i->Xin.Goto.cond != Xcc_ALWAYS) {
956 vex_printf(" }");
957 }
sewardjc97096c2004-06-30 09:28:04 +0000958 return;
sewardj5c34dc92004-07-19 12:48:11 +0000959 case Xin_CMov32:
sewardja2dad5c2004-07-23 11:43:43 +0000960 vex_printf("cmov%s ", showX86CondCode(i->Xin.CMov32.cond));
sewardj5c34dc92004-07-19 12:48:11 +0000961 ppX86RM(i->Xin.CMov32.src);
sewardj4042c7e2004-07-18 01:28:30 +0000962 vex_printf(",");
sewardj5c34dc92004-07-19 12:48:11 +0000963 ppHRegX86(i->Xin.CMov32.dst);
sewardj4042c7e2004-07-18 01:28:30 +0000964 return;
965 case Xin_LoadEX:
966 vex_printf("mov%c%cl ",
967 i->Xin.LoadEX.syned ? 's' : 'z',
968 i->Xin.LoadEX.szSmall==1 ? 'b' : 'w');
969 ppX86AMode(i->Xin.LoadEX.src);
970 vex_printf(",");
971 ppHRegX86(i->Xin.LoadEX.dst);
972 return;
sewardj443cd9d2004-07-18 23:06:45 +0000973 case Xin_Store:
974 vex_printf("mov%c ", i->Xin.Store.sz==1 ? 'b' : 'w');
975 ppHRegX86(i->Xin.Store.src);
976 vex_printf(",");
977 ppX86AMode(i->Xin.Store.dst);
978 return;
sewardjd7cb8532004-08-17 23:59:23 +0000979 case Xin_Set32:
980 vex_printf("setl%s ", showX86CondCode(i->Xin.Set32.cond));
981 ppHRegX86(i->Xin.Set32.dst);
982 return;
sewardjce646f22004-08-31 23:55:54 +0000983 case Xin_Bsfr32:
984 vex_printf("bs%cl ", i->Xin.Bsfr32.isFwds ? 'f' : 'r');
985 ppHRegX86(i->Xin.Bsfr32.src);
986 vex_printf(",");
987 ppHRegX86(i->Xin.Bsfr32.dst);
988 return;
sewardj3e838932005-01-07 12:09:15 +0000989 case Xin_MFence:
990 vex_printf("mfence(%s)",
991 LibVEX_ppVexSubArch(i->Xin.MFence.subarch));
992 return;
sewardjbb53f8c2004-08-14 11:50:01 +0000993 case Xin_FpUnary:
994 vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op));
995 ppHRegX86(i->Xin.FpUnary.src);
996 vex_printf(",");
997 ppHRegX86(i->Xin.FpUnary.dst);
998 break;
999 case Xin_FpBinary:
1000 vex_printf("g%sD ", showX86FpOp(i->Xin.FpBinary.op));
1001 ppHRegX86(i->Xin.FpBinary.srcL);
1002 vex_printf(",");
1003 ppHRegX86(i->Xin.FpBinary.srcR);
1004 vex_printf(",");
1005 ppHRegX86(i->Xin.FpBinary.dst);
1006 break;
sewardjd1725d12004-08-12 20:46:53 +00001007 case Xin_FpLdSt:
1008 if (i->Xin.FpLdSt.isLoad) {
sewardj3196daf2004-08-13 00:18:58 +00001009 vex_printf("gld%c " , i->Xin.FpLdSt.sz==8 ? 'D' : 'F');
sewardjd1725d12004-08-12 20:46:53 +00001010 ppX86AMode(i->Xin.FpLdSt.addr);
1011 vex_printf(", ");
1012 ppHRegX86(i->Xin.FpLdSt.reg);
1013 } else {
sewardj3196daf2004-08-13 00:18:58 +00001014 vex_printf("gst%c " , i->Xin.FpLdSt.sz==8 ? 'D' : 'F');
sewardjd1725d12004-08-12 20:46:53 +00001015 ppHRegX86(i->Xin.FpLdSt.reg);
1016 vex_printf(", ");
1017 ppX86AMode(i->Xin.FpLdSt.addr);
1018 }
1019 return;
sewardj89cd0932004-09-08 18:23:25 +00001020 case Xin_FpLdStI:
1021 if (i->Xin.FpLdStI.isLoad) {
1022 vex_printf("gild%s ", i->Xin.FpLdStI.sz==8 ? "ll" :
1023 i->Xin.FpLdStI.sz==4 ? "l" : "w");
1024 ppX86AMode(i->Xin.FpLdStI.addr);
sewardjbb53f8c2004-08-14 11:50:01 +00001025 vex_printf(", ");
sewardj89cd0932004-09-08 18:23:25 +00001026 ppHRegX86(i->Xin.FpLdStI.reg);
1027 } else {
1028 vex_printf("gist%s ", i->Xin.FpLdStI.sz==8 ? "ll" :
1029 i->Xin.FpLdStI.sz==4 ? "l" : "w");
1030 ppHRegX86(i->Xin.FpLdStI.reg);
1031 vex_printf(", ");
1032 ppX86AMode(i->Xin.FpLdStI.addr);
sewardjbb53f8c2004-08-14 11:50:01 +00001033 }
1034 return;
sewardj3bca9062004-12-04 14:36:09 +00001035 case Xin_Fp64to32:
1036 vex_printf("gdtof ");
1037 ppHRegX86(i->Xin.Fp64to32.src);
1038 vex_printf(",");
1039 ppHRegX86(i->Xin.Fp64to32.dst);
1040 return;
sewardj33124f62004-08-30 17:54:18 +00001041 case Xin_FpCMov:
1042 vex_printf("gcmov%s ", showX86CondCode(i->Xin.FpCMov.cond));
1043 ppHRegX86(i->Xin.FpCMov.src);
1044 vex_printf(",");
1045 ppHRegX86(i->Xin.FpCMov.dst);
1046 return;
sewardjeba63f82005-02-23 13:31:25 +00001047 case Xin_FpLdCW:
1048 vex_printf("fldcw ");
1049 ppX86AMode(i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00001050 return;
sewardj46de4072004-09-11 19:23:24 +00001051 case Xin_FpStSW_AX:
1052 vex_printf("fstsw %%ax");
1053 return;
sewardjbdc7d212004-09-09 02:46:40 +00001054 case Xin_FpCmp:
1055 vex_printf("gcmp ");
1056 ppHRegX86(i->Xin.FpCmp.srcL);
1057 vex_printf(",");
1058 ppHRegX86(i->Xin.FpCmp.srcR);
1059 vex_printf(",");
1060 ppHRegX86(i->Xin.FpCmp.dst);
1061 break;
sewardj1e6ad742004-12-02 16:16:11 +00001062 case Xin_SseConst:
1063 vex_printf("const $0x%04x,", (Int)i->Xin.SseConst.con);
1064 ppHRegX86(i->Xin.SseConst.dst);
1065 break;
sewardjd08f2d72004-12-01 23:19:36 +00001066 case Xin_SseLdSt:
1067 vex_printf("movups ");
1068 if (i->Xin.SseLdSt.isLoad) {
1069 ppX86AMode(i->Xin.SseLdSt.addr);
1070 vex_printf(",");
1071 ppHRegX86(i->Xin.SseLdSt.reg);
1072 } else {
1073 ppHRegX86(i->Xin.SseLdSt.reg);
1074 vex_printf(",");
1075 ppX86AMode(i->Xin.SseLdSt.addr);
1076 }
1077 return;
sewardj129b3d92004-12-05 15:42:05 +00001078 case Xin_SseLdzLO:
1079 vex_printf("movs%s ", i->Xin.SseLdzLO.sz==4 ? "s" : "d");
1080 ppX86AMode(i->Xin.SseLdzLO.addr);
1081 vex_printf(",");
1082 ppHRegX86(i->Xin.SseLdzLO.reg);
1083 return;
sewardjd08f2d72004-12-01 23:19:36 +00001084 case Xin_Sse32Fx4:
1085 vex_printf("%sps ", showX86SseOp(i->Xin.Sse32Fx4.op));
1086 ppHRegX86(i->Xin.Sse32Fx4.src);
1087 vex_printf(",");
1088 ppHRegX86(i->Xin.Sse32Fx4.dst);
1089 return;
1090 case Xin_Sse32FLo:
1091 vex_printf("%sss ", showX86SseOp(i->Xin.Sse32FLo.op));
1092 ppHRegX86(i->Xin.Sse32FLo.src);
1093 vex_printf(",");
1094 ppHRegX86(i->Xin.Sse32FLo.dst);
1095 return;
sewardj636ad762004-12-07 11:16:04 +00001096 case Xin_Sse64Fx2:
1097 vex_printf("%spd ", showX86SseOp(i->Xin.Sse64Fx2.op));
1098 ppHRegX86(i->Xin.Sse64Fx2.src);
1099 vex_printf(",");
1100 ppHRegX86(i->Xin.Sse64Fx2.dst);
1101 return;
1102 case Xin_Sse64FLo:
1103 vex_printf("%ssd ", showX86SseOp(i->Xin.Sse64FLo.op));
1104 ppHRegX86(i->Xin.Sse64FLo.src);
1105 vex_printf(",");
1106 ppHRegX86(i->Xin.Sse64FLo.dst);
1107 return;
sewardj164f9272004-12-09 00:39:32 +00001108 case Xin_SseReRg:
1109 vex_printf("%s ", showX86SseOp(i->Xin.SseReRg.op));
1110 ppHRegX86(i->Xin.SseReRg.src);
1111 vex_printf(",");
1112 ppHRegX86(i->Xin.SseReRg.dst);
1113 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001114 case Xin_SseCMov:
1115 vex_printf("cmov%s ", showX86CondCode(i->Xin.SseCMov.cond));
1116 ppHRegX86(i->Xin.SseCMov.src);
1117 vex_printf(",");
1118 ppHRegX86(i->Xin.SseCMov.dst);
1119 return;
sewardj109ffdb2004-12-10 21:45:38 +00001120 case Xin_SseShuf:
1121 vex_printf("pshufd $0x%x,", i->Xin.SseShuf.order);
1122 ppHRegX86(i->Xin.SseShuf.src);
1123 vex_printf(",");
1124 ppHRegX86(i->Xin.SseShuf.dst);
1125 return;
sewardjd08f2d72004-12-01 23:19:36 +00001126
sewardjc97096c2004-06-30 09:28:04 +00001127 default:
sewardj35421a32004-07-05 13:12:34 +00001128 vpanic("ppX86Instr");
sewardjc97096c2004-06-30 09:28:04 +00001129 }
1130}
sewardj53f85a92004-07-02 13:45:17 +00001131
sewardj194d54a2004-07-03 19:08:18 +00001132/* --------- Helpers for register allocation. --------- */
1133
cerion92b64362005-12-13 12:02:26 +00001134void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i, Bool mode64)
sewardj53f85a92004-07-02 13:45:17 +00001135{
sewardj0bd7ce62004-12-05 02:47:40 +00001136 Bool unary;
cerion92b64362005-12-13 12:02:26 +00001137 vassert(mode64 == False);
sewardj53f85a92004-07-02 13:45:17 +00001138 initHRegUsage(u);
1139 switch (i->tag) {
1140 case Xin_Alu32R:
1141 addRegUsage_X86RMI(u, i->Xin.Alu32R.src);
sewardj4042c7e2004-07-18 01:28:30 +00001142 if (i->Xin.Alu32R.op == Xalu_MOV) {
sewardjeba63f82005-02-23 13:31:25 +00001143 addHRegUse(u, HRmWrite, i->Xin.Alu32R.dst);
sewardj4042c7e2004-07-18 01:28:30 +00001144 return;
1145 }
sewardje8c922f2004-07-23 01:34:11 +00001146 if (i->Xin.Alu32R.op == Xalu_CMP) {
sewardjeba63f82005-02-23 13:31:25 +00001147 addHRegUse(u, HRmRead, i->Xin.Alu32R.dst);
sewardj4042c7e2004-07-18 01:28:30 +00001148 return;
1149 }
1150 addHRegUse(u, HRmModify, i->Xin.Alu32R.dst);
sewardj53f85a92004-07-02 13:45:17 +00001151 return;
1152 case Xin_Alu32M:
1153 addRegUsage_X86RI(u, i->Xin.Alu32M.src);
1154 addRegUsage_X86AMode(u, i->Xin.Alu32M.dst);
1155 return;
sewardje8c922f2004-07-23 01:34:11 +00001156 case Xin_Sh32:
sewardjeba63f82005-02-23 13:31:25 +00001157 addHRegUse(u, HRmModify, i->Xin.Sh32.dst);
sewardje8c922f2004-07-23 01:34:11 +00001158 if (i->Xin.Sh32.src == 0)
1159 addHRegUse(u, HRmRead, hregX86_ECX());
1160 return;
1161 case Xin_Test32:
sewardjeba63f82005-02-23 13:31:25 +00001162 addHRegUse(u, HRmRead, i->Xin.Test32.dst);
sewardje8c922f2004-07-23 01:34:11 +00001163 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001164 case Xin_Unary32:
sewardjeba63f82005-02-23 13:31:25 +00001165 addHRegUse(u, HRmModify, i->Xin.Unary32.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001166 return;
1167 case Xin_MulL:
1168 addRegUsage_X86RM(u, i->Xin.MulL.src, HRmRead);
1169 addHRegUse(u, HRmModify, hregX86_EAX());
1170 addHRegUse(u, HRmWrite, hregX86_EDX());
1171 return;
1172 case Xin_Div:
sewardjea64e142004-07-22 16:47:21 +00001173 addRegUsage_X86RM(u, i->Xin.Div.src, HRmRead);
sewardj1f40a0a2004-07-21 12:28:07 +00001174 addHRegUse(u, HRmModify, hregX86_EAX());
1175 addHRegUse(u, HRmModify, hregX86_EDX());
1176 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001177 case Xin_Sh3232:
sewardje5f384c2004-07-30 16:17:28 +00001178 addHRegUse(u, HRmRead, i->Xin.Sh3232.src);
1179 addHRegUse(u, HRmModify, i->Xin.Sh3232.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001180 if (i->Xin.Sh3232.amt == 0)
1181 addHRegUse(u, HRmRead, hregX86_ECX());
1182 return;
sewardje8e9d732004-07-16 21:03:45 +00001183 case Xin_Push:
1184 addRegUsage_X86RMI(u, i->Xin.Push.src);
1185 addHRegUse(u, HRmModify, hregX86_ESP());
1186 return;
1187 case Xin_Call:
sewardj4b861de2004-11-03 15:24:42 +00001188 /* This is a bit subtle. */
sewardjcdcf00b2005-02-04 01:40:03 +00001189 /* First off, claim it trashes all the caller-saved regs
1190 which fall within the register allocator's jurisdiction.
1191 These I believe to be %eax,%ecx,%edx. */
sewardje8e9d732004-07-16 21:03:45 +00001192 addHRegUse(u, HRmWrite, hregX86_EAX());
1193 addHRegUse(u, HRmWrite, hregX86_ECX());
1194 addHRegUse(u, HRmWrite, hregX86_EDX());
sewardj4b861de2004-11-03 15:24:42 +00001195 /* Now we have to state any parameter-carrying registers
1196 which might be read. This depends on the regparmness. */
sewardj77352542004-10-30 20:39:01 +00001197 switch (i->Xin.Call.regparms) {
1198 case 3: addHRegUse(u, HRmRead, hregX86_ECX()); /*fallthru*/
1199 case 2: addHRegUse(u, HRmRead, hregX86_EDX()); /*fallthru*/
1200 case 1: addHRegUse(u, HRmRead, hregX86_EAX()); break;
1201 case 0: break;
1202 default: vpanic("getRegUsage_X86Instr:Call:regparms");
1203 }
sewardj4b861de2004-11-03 15:24:42 +00001204 /* Finally, there is the issue that the insn trashes a
1205 register because the literal target address has to be
1206 loaded into a register. Fortunately, for the 0/1/2
sewardj45c50eb2004-11-04 18:25:33 +00001207 regparm case, we can use EAX, EDX and ECX respectively, so
sewardj4b861de2004-11-03 15:24:42 +00001208 this does not cause any further damage. For the 3-regparm
1209 case, we'll have to choose another register arbitrarily --
sewardj45c50eb2004-11-04 18:25:33 +00001210 since A, D and C are used for parameters -- and so we might
sewardj4b861de2004-11-03 15:24:42 +00001211 as well choose EDI. */
1212 if (i->Xin.Call.regparms == 3)
1213 addHRegUse(u, HRmWrite, hregX86_EDI());
1214 /* Upshot of this is that the assembler really must observe
1215 the here-stated convention of which register to use as an
1216 address temporary, depending on the regparmness: 0==EAX,
sewardj45c50eb2004-11-04 18:25:33 +00001217 1==EDX, 2==ECX, 3==EDI. */
sewardje8e9d732004-07-16 21:03:45 +00001218 return;
sewardj443cd9d2004-07-18 23:06:45 +00001219 case Xin_Goto:
1220 addRegUsage_X86RI(u, i->Xin.Goto.dst);
sewardj17c7f952005-12-15 14:02:34 +00001221 addHRegUse(u, HRmWrite, hregX86_EAX()); /* used for next guest addr */
1222 addHRegUse(u, HRmWrite, hregX86_EDX()); /* used for dispatcher addr */
1223 if (i->Xin.Goto.jk != Ijk_Boring
1224 && i->Xin.Goto.jk != Ijk_Call
1225 && i->Xin.Goto.jk != Ijk_Ret)
1226 /* note, this is irrelevant since ebp is not actually
1227 available to the allocator. But still .. */
sewardj750f4072004-07-26 22:39:11 +00001228 addHRegUse(u, HRmWrite, hregX86_EBP());
sewardj0ec33252004-07-03 13:30:00 +00001229 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001230 case Xin_CMov32:
1231 addRegUsage_X86RM(u, i->Xin.CMov32.src, HRmRead);
1232 addHRegUse(u, HRmModify, i->Xin.CMov32.dst);
1233 return;
1234 case Xin_LoadEX:
1235 addRegUsage_X86AMode(u, i->Xin.LoadEX.src);
1236 addHRegUse(u, HRmWrite, i->Xin.LoadEX.dst);
1237 return;
1238 case Xin_Store:
1239 addHRegUse(u, HRmRead, i->Xin.Store.src);
1240 addRegUsage_X86AMode(u, i->Xin.Store.dst);
1241 return;
sewardjd7cb8532004-08-17 23:59:23 +00001242 case Xin_Set32:
1243 addHRegUse(u, HRmWrite, i->Xin.Set32.dst);
1244 return;
sewardjce646f22004-08-31 23:55:54 +00001245 case Xin_Bsfr32:
1246 addHRegUse(u, HRmRead, i->Xin.Bsfr32.src);
1247 addHRegUse(u, HRmWrite, i->Xin.Bsfr32.dst);
1248 return;
sewardj3e838932005-01-07 12:09:15 +00001249 case Xin_MFence:
1250 return;
sewardjbb53f8c2004-08-14 11:50:01 +00001251 case Xin_FpUnary:
1252 addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
1253 addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
1254 return;
1255 case Xin_FpBinary:
1256 addHRegUse(u, HRmRead, i->Xin.FpBinary.srcL);
1257 addHRegUse(u, HRmRead, i->Xin.FpBinary.srcR);
1258 addHRegUse(u, HRmWrite, i->Xin.FpBinary.dst);
1259 return;
sewardj3196daf2004-08-13 00:18:58 +00001260 case Xin_FpLdSt:
1261 addRegUsage_X86AMode(u, i->Xin.FpLdSt.addr);
1262 addHRegUse(u, i->Xin.FpLdSt.isLoad ? HRmWrite : HRmRead,
1263 i->Xin.FpLdSt.reg);
1264 return;
sewardj89cd0932004-09-08 18:23:25 +00001265 case Xin_FpLdStI:
1266 addRegUsage_X86AMode(u, i->Xin.FpLdStI.addr);
1267 addHRegUse(u, i->Xin.FpLdStI.isLoad ? HRmWrite : HRmRead,
1268 i->Xin.FpLdStI.reg);
sewardjbb53f8c2004-08-14 11:50:01 +00001269 return;
sewardj3bca9062004-12-04 14:36:09 +00001270 case Xin_Fp64to32:
1271 addHRegUse(u, HRmRead, i->Xin.Fp64to32.src);
1272 addHRegUse(u, HRmWrite, i->Xin.Fp64to32.dst);
1273 return;
sewardj3fc76d22004-08-31 11:47:54 +00001274 case Xin_FpCMov:
sewardjb9fa69b2004-12-09 23:25:14 +00001275 addHRegUse(u, HRmRead, i->Xin.FpCMov.src);
sewardj3fc76d22004-08-31 11:47:54 +00001276 addHRegUse(u, HRmModify, i->Xin.FpCMov.dst);
1277 return;
sewardjeba63f82005-02-23 13:31:25 +00001278 case Xin_FpLdCW:
1279 addRegUsage_X86AMode(u, i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00001280 return;
sewardj46de4072004-09-11 19:23:24 +00001281 case Xin_FpStSW_AX:
1282 addHRegUse(u, HRmWrite, hregX86_EAX());
1283 return;
sewardjbdc7d212004-09-09 02:46:40 +00001284 case Xin_FpCmp:
1285 addHRegUse(u, HRmRead, i->Xin.FpCmp.srcL);
1286 addHRegUse(u, HRmRead, i->Xin.FpCmp.srcR);
1287 addHRegUse(u, HRmWrite, i->Xin.FpCmp.dst);
1288 addHRegUse(u, HRmWrite, hregX86_EAX());
1289 return;
sewardjd08f2d72004-12-01 23:19:36 +00001290 case Xin_SseLdSt:
1291 addRegUsage_X86AMode(u, i->Xin.SseLdSt.addr);
1292 addHRegUse(u, i->Xin.SseLdSt.isLoad ? HRmWrite : HRmRead,
1293 i->Xin.SseLdSt.reg);
1294 return;
sewardj129b3d92004-12-05 15:42:05 +00001295 case Xin_SseLdzLO:
1296 addRegUsage_X86AMode(u, i->Xin.SseLdzLO.addr);
1297 addHRegUse(u, HRmWrite, i->Xin.SseLdzLO.reg);
1298 return;
sewardj1e6ad742004-12-02 16:16:11 +00001299 case Xin_SseConst:
1300 addHRegUse(u, HRmWrite, i->Xin.SseConst.dst);
1301 return;
sewardjd08f2d72004-12-01 23:19:36 +00001302 case Xin_Sse32Fx4:
1303 vassert(i->Xin.Sse32Fx4.op != Xsse_MOV);
sewardj8ee8c882005-02-25 17:40:26 +00001304 unary = toBool( i->Xin.Sse32Fx4.op == Xsse_RCPF
1305 || i->Xin.Sse32Fx4.op == Xsse_RSQRTF
1306 || i->Xin.Sse32Fx4.op == Xsse_SQRTF );
sewardj0bd7ce62004-12-05 02:47:40 +00001307 addHRegUse(u, HRmRead, i->Xin.Sse32Fx4.src);
1308 addHRegUse(u, unary ? HRmWrite : HRmModify,
1309 i->Xin.Sse32Fx4.dst);
sewardjd08f2d72004-12-01 23:19:36 +00001310 return;
sewardj1e6ad742004-12-02 16:16:11 +00001311 case Xin_Sse32FLo:
1312 vassert(i->Xin.Sse32FLo.op != Xsse_MOV);
sewardj8ee8c882005-02-25 17:40:26 +00001313 unary = toBool( i->Xin.Sse32FLo.op == Xsse_RCPF
1314 || i->Xin.Sse32FLo.op == Xsse_RSQRTF
1315 || i->Xin.Sse32FLo.op == Xsse_SQRTF );
sewardj0bd7ce62004-12-05 02:47:40 +00001316 addHRegUse(u, HRmRead, i->Xin.Sse32FLo.src);
1317 addHRegUse(u, unary ? HRmWrite : HRmModify,
1318 i->Xin.Sse32FLo.dst);
sewardj1e6ad742004-12-02 16:16:11 +00001319 return;
sewardj636ad762004-12-07 11:16:04 +00001320 case Xin_Sse64Fx2:
1321 vassert(i->Xin.Sse64Fx2.op != Xsse_MOV);
sewardj8ee8c882005-02-25 17:40:26 +00001322 unary = toBool( i->Xin.Sse64Fx2.op == Xsse_RCPF
1323 || i->Xin.Sse64Fx2.op == Xsse_RSQRTF
1324 || i->Xin.Sse64Fx2.op == Xsse_SQRTF );
sewardj636ad762004-12-07 11:16:04 +00001325 addHRegUse(u, HRmRead, i->Xin.Sse64Fx2.src);
1326 addHRegUse(u, unary ? HRmWrite : HRmModify,
1327 i->Xin.Sse64Fx2.dst);
1328 return;
1329 case Xin_Sse64FLo:
1330 vassert(i->Xin.Sse64FLo.op != Xsse_MOV);
sewardj8ee8c882005-02-25 17:40:26 +00001331 unary = toBool( i->Xin.Sse64FLo.op == Xsse_RCPF
1332 || i->Xin.Sse64FLo.op == Xsse_RSQRTF
1333 || i->Xin.Sse64FLo.op == Xsse_SQRTF );
sewardj636ad762004-12-07 11:16:04 +00001334 addHRegUse(u, HRmRead, i->Xin.Sse64FLo.src);
1335 addHRegUse(u, unary ? HRmWrite : HRmModify,
1336 i->Xin.Sse64FLo.dst);
1337 return;
sewardj164f9272004-12-09 00:39:32 +00001338 case Xin_SseReRg:
sewardj109ffdb2004-12-10 21:45:38 +00001339 if (i->Xin.SseReRg.op == Xsse_XOR
1340 && i->Xin.SseReRg.src == i->Xin.SseReRg.dst) {
1341 /* reg-alloc needs to understand 'xor r,r' as a write of r */
1342 /* (as opposed to a rite of passage :-) */
1343 addHRegUse(u, HRmWrite, i->Xin.SseReRg.dst);
1344 } else {
1345 addHRegUse(u, HRmRead, i->Xin.SseReRg.src);
1346 addHRegUse(u, i->Xin.SseReRg.op == Xsse_MOV
1347 ? HRmWrite : HRmModify,
1348 i->Xin.SseReRg.dst);
1349 }
sewardj164f9272004-12-09 00:39:32 +00001350 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001351 case Xin_SseCMov:
1352 addHRegUse(u, HRmRead, i->Xin.SseCMov.src);
1353 addHRegUse(u, HRmModify, i->Xin.SseCMov.dst);
1354 return;
sewardj109ffdb2004-12-10 21:45:38 +00001355 case Xin_SseShuf:
1356 addHRegUse(u, HRmRead, i->Xin.SseShuf.src);
1357 addHRegUse(u, HRmWrite, i->Xin.SseShuf.dst);
1358 return;
sewardj53f85a92004-07-02 13:45:17 +00001359 default:
cerion92b64362005-12-13 12:02:26 +00001360 ppX86Instr(i, False);
sewardj35421a32004-07-05 13:12:34 +00001361 vpanic("getRegUsage_X86Instr");
sewardj53f85a92004-07-02 13:45:17 +00001362 }
1363}
1364
sewardj1f40a0a2004-07-21 12:28:07 +00001365/* local helper */
cerion92b64362005-12-13 12:02:26 +00001366static void mapReg( HRegRemap* m, HReg* r )
sewardj1f40a0a2004-07-21 12:28:07 +00001367{
1368 *r = lookupHRegRemap(m, *r);
1369}
1370
cerion92b64362005-12-13 12:02:26 +00001371void mapRegs_X86Instr ( HRegRemap* m, X86Instr* i, Bool mode64 )
sewardj53f85a92004-07-02 13:45:17 +00001372{
cerion92b64362005-12-13 12:02:26 +00001373 vassert(mode64 == False);
sewardj53f85a92004-07-02 13:45:17 +00001374 switch (i->tag) {
1375 case Xin_Alu32R:
1376 mapRegs_X86RMI(m, i->Xin.Alu32R.src);
sewardj1f40a0a2004-07-21 12:28:07 +00001377 mapReg(m, &i->Xin.Alu32R.dst);
sewardj53f85a92004-07-02 13:45:17 +00001378 return;
1379 case Xin_Alu32M:
1380 mapRegs_X86RI(m, i->Xin.Alu32M.src);
1381 mapRegs_X86AMode(m, i->Xin.Alu32M.dst);
1382 return;
sewardje8c922f2004-07-23 01:34:11 +00001383 case Xin_Sh32:
sewardjeba63f82005-02-23 13:31:25 +00001384 mapReg(m, &i->Xin.Sh32.dst);
sewardje8c922f2004-07-23 01:34:11 +00001385 return;
1386 case Xin_Test32:
sewardjeba63f82005-02-23 13:31:25 +00001387 mapReg(m, &i->Xin.Test32.dst);
sewardje8c922f2004-07-23 01:34:11 +00001388 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001389 case Xin_Unary32:
sewardjeba63f82005-02-23 13:31:25 +00001390 mapReg(m, &i->Xin.Unary32.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001391 return;
1392 case Xin_MulL:
1393 mapRegs_X86RM(m, i->Xin.MulL.src);
1394 return;
1395 case Xin_Div:
sewardjea64e142004-07-22 16:47:21 +00001396 mapRegs_X86RM(m, i->Xin.Div.src);
sewardj1f40a0a2004-07-21 12:28:07 +00001397 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001398 case Xin_Sh3232:
sewardje5f384c2004-07-30 16:17:28 +00001399 mapReg(m, &i->Xin.Sh3232.src);
1400 mapReg(m, &i->Xin.Sh3232.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001401 return;
1402 case Xin_Push:
1403 mapRegs_X86RMI(m, i->Xin.Push.src);
1404 return;
1405 case Xin_Call:
sewardj1f40a0a2004-07-21 12:28:07 +00001406 return;
sewardj443cd9d2004-07-18 23:06:45 +00001407 case Xin_Goto:
1408 mapRegs_X86RI(m, i->Xin.Goto.dst);
sewardj0ec33252004-07-03 13:30:00 +00001409 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001410 case Xin_CMov32:
1411 mapRegs_X86RM(m, i->Xin.CMov32.src);
1412 mapReg(m, &i->Xin.CMov32.dst);
1413 return;
1414 case Xin_LoadEX:
1415 mapRegs_X86AMode(m, i->Xin.LoadEX.src);
1416 mapReg(m, &i->Xin.LoadEX.dst);
1417 return;
1418 case Xin_Store:
1419 mapReg(m, &i->Xin.Store.src);
1420 mapRegs_X86AMode(m, i->Xin.Store.dst);
1421 return;
sewardjd7cb8532004-08-17 23:59:23 +00001422 case Xin_Set32:
1423 mapReg(m, &i->Xin.Set32.dst);
1424 return;
sewardjce646f22004-08-31 23:55:54 +00001425 case Xin_Bsfr32:
1426 mapReg(m, &i->Xin.Bsfr32.src);
1427 mapReg(m, &i->Xin.Bsfr32.dst);
1428 return;
sewardj3e838932005-01-07 12:09:15 +00001429 case Xin_MFence:
1430 return;
sewardjcfded9a2004-09-09 11:44:16 +00001431 case Xin_FpUnary:
1432 mapReg(m, &i->Xin.FpUnary.src);
1433 mapReg(m, &i->Xin.FpUnary.dst);
1434 return;
sewardjbb53f8c2004-08-14 11:50:01 +00001435 case Xin_FpBinary:
1436 mapReg(m, &i->Xin.FpBinary.srcL);
1437 mapReg(m, &i->Xin.FpBinary.srcR);
1438 mapReg(m, &i->Xin.FpBinary.dst);
1439 return;
sewardj3196daf2004-08-13 00:18:58 +00001440 case Xin_FpLdSt:
1441 mapRegs_X86AMode(m, i->Xin.FpLdSt.addr);
1442 mapReg(m, &i->Xin.FpLdSt.reg);
1443 return;
sewardj89cd0932004-09-08 18:23:25 +00001444 case Xin_FpLdStI:
1445 mapRegs_X86AMode(m, i->Xin.FpLdStI.addr);
1446 mapReg(m, &i->Xin.FpLdStI.reg);
sewardjbb53f8c2004-08-14 11:50:01 +00001447 return;
sewardj3bca9062004-12-04 14:36:09 +00001448 case Xin_Fp64to32:
1449 mapReg(m, &i->Xin.Fp64to32.src);
1450 mapReg(m, &i->Xin.Fp64to32.dst);
1451 return;
sewardj3fc76d22004-08-31 11:47:54 +00001452 case Xin_FpCMov:
1453 mapReg(m, &i->Xin.FpCMov.src);
1454 mapReg(m, &i->Xin.FpCMov.dst);
1455 return;
sewardjeba63f82005-02-23 13:31:25 +00001456 case Xin_FpLdCW:
1457 mapRegs_X86AMode(m, i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00001458 return;
sewardj46de4072004-09-11 19:23:24 +00001459 case Xin_FpStSW_AX:
1460 return;
sewardjbdc7d212004-09-09 02:46:40 +00001461 case Xin_FpCmp:
1462 mapReg(m, &i->Xin.FpCmp.srcL);
1463 mapReg(m, &i->Xin.FpCmp.srcR);
1464 mapReg(m, &i->Xin.FpCmp.dst);
1465 return;
sewardj1e6ad742004-12-02 16:16:11 +00001466 case Xin_SseConst:
1467 mapReg(m, &i->Xin.SseConst.dst);
1468 return;
sewardjd08f2d72004-12-01 23:19:36 +00001469 case Xin_SseLdSt:
1470 mapReg(m, &i->Xin.SseLdSt.reg);
1471 mapRegs_X86AMode(m, i->Xin.SseLdSt.addr);
1472 break;
sewardj129b3d92004-12-05 15:42:05 +00001473 case Xin_SseLdzLO:
1474 mapReg(m, &i->Xin.SseLdzLO.reg);
1475 mapRegs_X86AMode(m, i->Xin.SseLdzLO.addr);
1476 break;
sewardjd08f2d72004-12-01 23:19:36 +00001477 case Xin_Sse32Fx4:
1478 mapReg(m, &i->Xin.Sse32Fx4.src);
1479 mapReg(m, &i->Xin.Sse32Fx4.dst);
1480 return;
sewardj1e6ad742004-12-02 16:16:11 +00001481 case Xin_Sse32FLo:
1482 mapReg(m, &i->Xin.Sse32FLo.src);
1483 mapReg(m, &i->Xin.Sse32FLo.dst);
1484 return;
sewardj636ad762004-12-07 11:16:04 +00001485 case Xin_Sse64Fx2:
1486 mapReg(m, &i->Xin.Sse64Fx2.src);
1487 mapReg(m, &i->Xin.Sse64Fx2.dst);
1488 return;
1489 case Xin_Sse64FLo:
1490 mapReg(m, &i->Xin.Sse64FLo.src);
1491 mapReg(m, &i->Xin.Sse64FLo.dst);
1492 return;
sewardj164f9272004-12-09 00:39:32 +00001493 case Xin_SseReRg:
1494 mapReg(m, &i->Xin.SseReRg.src);
1495 mapReg(m, &i->Xin.SseReRg.dst);
1496 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001497 case Xin_SseCMov:
1498 mapReg(m, &i->Xin.SseCMov.src);
1499 mapReg(m, &i->Xin.SseCMov.dst);
1500 return;
sewardj109ffdb2004-12-10 21:45:38 +00001501 case Xin_SseShuf:
1502 mapReg(m, &i->Xin.SseShuf.src);
1503 mapReg(m, &i->Xin.SseShuf.dst);
1504 return;
sewardj53f85a92004-07-02 13:45:17 +00001505 default:
cerion92b64362005-12-13 12:02:26 +00001506 ppX86Instr(i, mode64);
sewardj35421a32004-07-05 13:12:34 +00001507 vpanic("mapRegs_X86Instr");
sewardj53f85a92004-07-02 13:45:17 +00001508 }
1509}
1510
sewardjbb53f8c2004-08-14 11:50:01 +00001511/* Figure out if i represents a reg-reg move, and if so assign the
1512 source and destination to *src and *dst. If in doubt say No. Used
1513 by the register allocator to do move coalescing.
1514*/
sewardja9a0cd22004-07-03 14:49:41 +00001515Bool isMove_X86Instr ( X86Instr* i, HReg* src, HReg* dst )
1516{
sewardjbb53f8c2004-08-14 11:50:01 +00001517 /* Moves between integer regs */
1518 if (i->tag == Xin_Alu32R) {
1519 if (i->Xin.Alu32R.op != Xalu_MOV)
1520 return False;
1521 if (i->Xin.Alu32R.src->tag != Xrmi_Reg)
1522 return False;
1523 *src = i->Xin.Alu32R.src->Xrmi.Reg.reg;
1524 *dst = i->Xin.Alu32R.dst;
1525 return True;
1526 }
1527 /* Moves between FP regs */
1528 if (i->tag == Xin_FpUnary) {
1529 if (i->Xin.FpUnary.op != Xfp_MOV)
1530 return False;
1531 *src = i->Xin.FpUnary.src;
1532 *dst = i->Xin.FpUnary.dst;
1533 return True;
1534 }
sewardj9e203592004-12-10 01:48:18 +00001535 if (i->tag == Xin_SseReRg) {
1536 if (i->Xin.SseReRg.op != Xsse_MOV)
sewardjd08f2d72004-12-01 23:19:36 +00001537 return False;
sewardj9e203592004-12-10 01:48:18 +00001538 *src = i->Xin.SseReRg.src;
1539 *dst = i->Xin.SseReRg.dst;
sewardjd08f2d72004-12-01 23:19:36 +00001540 return True;
1541 }
sewardjbb53f8c2004-08-14 11:50:01 +00001542 return False;
sewardja9a0cd22004-07-03 14:49:41 +00001543}
sewardj194d54a2004-07-03 19:08:18 +00001544
sewardjbb53f8c2004-08-14 11:50:01 +00001545
sewardj81ec4182004-10-25 23:15:52 +00001546/* Generate x86 spill/reload instructions under the direction of the
sewardj4b861de2004-11-03 15:24:42 +00001547 register allocator. Note it's critical these don't write the
1548 condition codes. */
sewardj14731f22004-07-25 01:24:28 +00001549
cerion92b64362005-12-13 12:02:26 +00001550X86Instr* genSpill_X86 ( HReg rreg, Int offsetB, Bool mode64 )
sewardj194d54a2004-07-03 19:08:18 +00001551{
sewardj3f57c2d2004-10-04 09:14:05 +00001552 X86AMode* am;
sewardj81ec4182004-10-25 23:15:52 +00001553 vassert(offsetB >= 0);
sewardj35421a32004-07-05 13:12:34 +00001554 vassert(!hregIsVirtual(rreg));
cerion92b64362005-12-13 12:02:26 +00001555 vassert(mode64 == False);
sewardj81ec4182004-10-25 23:15:52 +00001556 am = X86AMode_IR(offsetB, hregX86_EBP());
sewardj3f57c2d2004-10-04 09:14:05 +00001557
sewardj194d54a2004-07-03 19:08:18 +00001558 switch (hregClass(rreg)) {
sewardj4a31b262004-12-01 02:24:44 +00001559 case HRcInt32:
sewardj3f57c2d2004-10-04 09:14:05 +00001560 return X86Instr_Alu32M ( Xalu_MOV, X86RI_Reg(rreg), am );
sewardj4a31b262004-12-01 02:24:44 +00001561 case HRcFlt64:
sewardj3f57c2d2004-10-04 09:14:05 +00001562 return X86Instr_FpLdSt ( False/*store*/, 8, rreg, am );
sewardj9ee82862004-12-14 01:16:59 +00001563 case HRcVec128:
1564 return X86Instr_SseLdSt ( False/*store*/, rreg, am );
sewardj194d54a2004-07-03 19:08:18 +00001565 default:
sewardj35421a32004-07-05 13:12:34 +00001566 ppHRegClass(hregClass(rreg));
1567 vpanic("genSpill_X86: unimplemented regclass");
sewardj194d54a2004-07-03 19:08:18 +00001568 }
1569}
1570
cerion92b64362005-12-13 12:02:26 +00001571X86Instr* genReload_X86 ( HReg rreg, Int offsetB, Bool mode64 )
sewardj194d54a2004-07-03 19:08:18 +00001572{
sewardj3f57c2d2004-10-04 09:14:05 +00001573 X86AMode* am;
sewardj81ec4182004-10-25 23:15:52 +00001574 vassert(offsetB >= 0);
sewardj35421a32004-07-05 13:12:34 +00001575 vassert(!hregIsVirtual(rreg));
cerion92b64362005-12-13 12:02:26 +00001576 vassert(mode64 == False);
sewardj81ec4182004-10-25 23:15:52 +00001577 am = X86AMode_IR(offsetB, hregX86_EBP());
sewardj194d54a2004-07-03 19:08:18 +00001578 switch (hregClass(rreg)) {
sewardj4a31b262004-12-01 02:24:44 +00001579 case HRcInt32:
sewardj3f57c2d2004-10-04 09:14:05 +00001580 return X86Instr_Alu32R ( Xalu_MOV, X86RMI_Mem(am), rreg );
sewardj4a31b262004-12-01 02:24:44 +00001581 case HRcFlt64:
sewardj3f57c2d2004-10-04 09:14:05 +00001582 return X86Instr_FpLdSt ( True/*load*/, 8, rreg, am );
sewardj9ee82862004-12-14 01:16:59 +00001583 case HRcVec128:
1584 return X86Instr_SseLdSt ( True/*load*/, rreg, am );
sewardj194d54a2004-07-03 19:08:18 +00001585 default:
sewardj35421a32004-07-05 13:12:34 +00001586 ppHRegClass(hregClass(rreg));
1587 vpanic("genReload_X86: unimplemented regclass");
sewardj194d54a2004-07-03 19:08:18 +00001588 }
1589}
sewardj35421a32004-07-05 13:12:34 +00001590
sewardj81bd5502004-07-21 18:49:27 +00001591
1592/* --------- The x86 assembler (bleh.) --------- */
1593
sewardj8ee8c882005-02-25 17:40:26 +00001594static UChar iregNo ( HReg r )
sewardjbad34a92004-07-22 01:14:11 +00001595{
1596 UInt n;
sewardj4a31b262004-12-01 02:24:44 +00001597 vassert(hregClass(r) == HRcInt32);
sewardjbad34a92004-07-22 01:14:11 +00001598 vassert(!hregIsVirtual(r));
1599 n = hregNumber(r);
1600 vassert(n <= 7);
sewardj8ee8c882005-02-25 17:40:26 +00001601 return toUChar(n);
sewardjbad34a92004-07-22 01:14:11 +00001602}
1603
sewardj140656d2004-08-22 02:37:25 +00001604static UInt fregNo ( HReg r )
1605{
1606 UInt n;
sewardj4a31b262004-12-01 02:24:44 +00001607 vassert(hregClass(r) == HRcFlt64);
sewardj140656d2004-08-22 02:37:25 +00001608 vassert(!hregIsVirtual(r));
1609 n = hregNumber(r);
sewardjeafde5a2004-10-09 01:36:57 +00001610 vassert(n <= 5);
sewardj140656d2004-08-22 02:37:25 +00001611 return n;
1612}
1613
sewardjd08f2d72004-12-01 23:19:36 +00001614static UInt vregNo ( HReg r )
1615{
1616 UInt n;
1617 vassert(hregClass(r) == HRcVec128);
1618 vassert(!hregIsVirtual(r));
1619 n = hregNumber(r);
1620 vassert(n <= 7);
1621 return n;
1622}
1623
sewardjbad34a92004-07-22 01:14:11 +00001624static UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
1625{
sewardj8ee8c882005-02-25 17:40:26 +00001626 return toUChar( ((mod & 3) << 6)
1627 | ((reg & 7) << 3)
1628 | (regmem & 7) );
sewardjbad34a92004-07-22 01:14:11 +00001629}
1630
1631static UChar mkSIB ( Int shift, Int regindex, Int regbase )
1632{
sewardj8ee8c882005-02-25 17:40:26 +00001633 return toUChar( ((shift & 3) << 6)
1634 | ((regindex & 7) << 3)
1635 | (regbase & 7) );
sewardjbad34a92004-07-22 01:14:11 +00001636}
1637
1638static UChar* emit32 ( UChar* p, UInt w32 )
1639{
sewardj8ee8c882005-02-25 17:40:26 +00001640 *p++ = toUChar( w32 & 0x000000FF);
1641 *p++ = toUChar((w32 >> 8) & 0x000000FF);
1642 *p++ = toUChar((w32 >> 16) & 0x000000FF);
1643 *p++ = toUChar((w32 >> 24) & 0x000000FF);
sewardjbad34a92004-07-22 01:14:11 +00001644 return p;
1645}
1646
sewardjea64e142004-07-22 16:47:21 +00001647/* Does a sign-extend of the lowest 8 bits give
1648 the original number? */
sewardjbad34a92004-07-22 01:14:11 +00001649static Bool fits8bits ( UInt w32 )
1650{
sewardjea64e142004-07-22 16:47:21 +00001651 Int i32 = (Int)w32;
sewardj8ee8c882005-02-25 17:40:26 +00001652 return toBool(i32 == ((i32 << 24) >> 24));
sewardjbad34a92004-07-22 01:14:11 +00001653}
1654
1655
1656/* Forming mod-reg-rm bytes and scale-index-base bytes.
1657
1658 greg, 0(ereg) | ereg != ESP && ereg != EBP
1659 = 00 greg ereg
1660
1661 greg, d8(ereg) | ereg != ESP
1662 = 01 greg ereg, d8
1663
1664 greg, d32(ereg) | ereg != ESP
1665 = 10 greg ereg, d32
1666
sewardja58ea662004-08-15 03:12:41 +00001667 greg, d8(%esp) = 01 greg 100, 0x24, d8
1668
sewardjbad34a92004-07-22 01:14:11 +00001669 -----------------------------------------------
1670
1671 greg, d8(base,index,scale)
1672 | index != ESP
1673 = 01 greg 100, scale index base, d8
1674
1675 greg, d32(base,index,scale)
1676 | index != ESP
1677 = 10 greg 100, scale index base, d32
1678*/
1679static UChar* doAMode_M ( UChar* p, HReg greg, X86AMode* am )
1680{
1681 if (am->tag == Xam_IR) {
1682 if (am->Xam.IR.imm == 0
1683 && am->Xam.IR.reg != hregX86_ESP()
1684 && am->Xam.IR.reg != hregX86_EBP() ) {
1685 *p++ = mkModRegRM(0, iregNo(greg), iregNo(am->Xam.IR.reg));
1686 return p;
1687 }
1688 if (fits8bits(am->Xam.IR.imm)
1689 && am->Xam.IR.reg != hregX86_ESP()) {
1690 *p++ = mkModRegRM(1, iregNo(greg), iregNo(am->Xam.IR.reg));
sewardj8ee8c882005-02-25 17:40:26 +00001691 *p++ = toUChar(am->Xam.IR.imm & 0xFF);
sewardjbad34a92004-07-22 01:14:11 +00001692 return p;
1693 }
1694 if (am->Xam.IR.reg != hregX86_ESP()) {
1695 *p++ = mkModRegRM(2, iregNo(greg), iregNo(am->Xam.IR.reg));
1696 p = emit32(p, am->Xam.IR.imm);
1697 return p;
1698 }
sewardja58ea662004-08-15 03:12:41 +00001699 if (am->Xam.IR.reg == hregX86_ESP()
1700 && fits8bits(am->Xam.IR.imm)) {
1701 *p++ = mkModRegRM(1, iregNo(greg), 4);
1702 *p++ = 0x24;
sewardj8ee8c882005-02-25 17:40:26 +00001703 *p++ = toUChar(am->Xam.IR.imm & 0xFF);
sewardja58ea662004-08-15 03:12:41 +00001704 return p;
1705 }
sewardjbad34a92004-07-22 01:14:11 +00001706 ppX86AMode(am);
1707 vpanic("doAMode_M: can't emit amode IR");
1708 /*NOTREACHED*/
1709 }
1710 if (am->tag == Xam_IRRS) {
1711 if (fits8bits(am->Xam.IRRS.imm)
1712 && am->Xam.IRRS.index != hregX86_ESP()) {
1713 *p++ = mkModRegRM(1, iregNo(greg), 4);
1714 *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index,
1715 am->Xam.IRRS.base);
sewardj8ee8c882005-02-25 17:40:26 +00001716 *p++ = toUChar(am->Xam.IRRS.imm & 0xFF);
sewardjbad34a92004-07-22 01:14:11 +00001717 return p;
1718 }
1719 if (am->Xam.IRRS.index != hregX86_ESP()) {
1720 *p++ = mkModRegRM(2, iregNo(greg), 4);
1721 *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index,
1722 am->Xam.IRRS.base);
1723 p = emit32(p, am->Xam.IRRS.imm);
1724 return p;
1725 }
1726 ppX86AMode(am);
1727 vpanic("doAMode_M: can't emit amode IRRS");
1728 /*NOTREACHED*/
1729 }
1730 vpanic("doAMode_M: unknown amode");
1731 /*NOTREACHED*/
1732}
1733
1734
1735/* Emit a mod-reg-rm byte when the rm bit denotes a reg. */
1736static UChar* doAMode_R ( UChar* p, HReg greg, HReg ereg )
1737{
1738 *p++ = mkModRegRM(3, iregNo(greg), iregNo(ereg));
1739 return p;
1740}
1741
1742
sewardj3196daf2004-08-13 00:18:58 +00001743/* Emit ffree %st(7) */
1744static UChar* do_ffree_st7 ( UChar* p )
1745{
1746 *p++ = 0xDD;
1747 *p++ = 0xC7;
1748 return p;
1749}
1750
sewardjeafde5a2004-10-09 01:36:57 +00001751/* Emit fstp %st(i), 1 <= i <= 7 */
sewardj3196daf2004-08-13 00:18:58 +00001752static UChar* do_fstp_st ( UChar* p, Int i )
1753{
sewardjeafde5a2004-10-09 01:36:57 +00001754 vassert(1 <= i && i <= 7);
sewardj3196daf2004-08-13 00:18:58 +00001755 *p++ = 0xDD;
sewardj8ee8c882005-02-25 17:40:26 +00001756 *p++ = toUChar(0xD8+i);
sewardj3196daf2004-08-13 00:18:58 +00001757 return p;
1758}
1759
sewardjb3944c22004-10-15 22:22:09 +00001760/* Emit fld %st(i), 0 <= i <= 6 */
sewardj3196daf2004-08-13 00:18:58 +00001761static UChar* do_fld_st ( UChar* p, Int i )
1762{
sewardjb3944c22004-10-15 22:22:09 +00001763 vassert(0 <= i && i <= 6);
sewardj3196daf2004-08-13 00:18:58 +00001764 *p++ = 0xD9;
sewardj8ee8c882005-02-25 17:40:26 +00001765 *p++ = toUChar(0xC0+i);
sewardj3196daf2004-08-13 00:18:58 +00001766 return p;
1767}
1768
sewardjcfded9a2004-09-09 11:44:16 +00001769/* Emit f<op> %st(0) */
1770static UChar* do_fop1_st ( UChar* p, X86FpOp op )
1771{
1772 switch (op) {
sewardj883b00b2004-09-11 09:30:24 +00001773 case Xfp_NEG: *p++ = 0xD9; *p++ = 0xE0; break;
1774 case Xfp_ABS: *p++ = 0xD9; *p++ = 0xE1; break;
sewardjc4be80c2004-09-10 16:17:45 +00001775 case Xfp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break;
sewardje6709112004-09-10 18:37:18 +00001776 case Xfp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break;
sewardjcfded9a2004-09-09 11:44:16 +00001777 case Xfp_SIN: *p++ = 0xD9; *p++ = 0xFE; break;
1778 case Xfp_COS: *p++ = 0xD9; *p++ = 0xFF; break;
sewardj06c32a02004-09-12 12:07:34 +00001779 case Xfp_2XM1: *p++ = 0xD9; *p++ = 0xF0; break;
sewardjbec10842004-10-12 13:44:45 +00001780 case Xfp_MOV: break;
sewardj99016a72004-10-15 22:09:17 +00001781 case Xfp_TAN: p = do_ffree_st7(p); /* since fptan pushes 1.0 */
1782 *p++ = 0xD9; *p++ = 0xF2; /* fptan */
1783 *p++ = 0xD9; *p++ = 0xF7; /* fincstp */
1784 break;
sewardjcfded9a2004-09-09 11:44:16 +00001785 default: vpanic("do_fop1_st: unknown op");
1786 }
1787 return p;
1788}
1789
sewardjbb53f8c2004-08-14 11:50:01 +00001790/* Emit f<op> %st(i), 1 <= i <= 5 */
sewardjcfded9a2004-09-09 11:44:16 +00001791static UChar* do_fop2_st ( UChar* p, X86FpOp op, Int i )
sewardjbb53f8c2004-08-14 11:50:01 +00001792{
sewardj4a31b262004-12-01 02:24:44 +00001793# define fake(_n) mkHReg((_n), HRcInt32, False)
sewardjbb53f8c2004-08-14 11:50:01 +00001794 Int subopc;
1795 switch (op) {
sewardja58ea662004-08-15 03:12:41 +00001796 case Xfp_ADD: subopc = 0; break;
sewardjce646f22004-08-31 23:55:54 +00001797 case Xfp_SUB: subopc = 4; break;
sewardjbb53f8c2004-08-14 11:50:01 +00001798 case Xfp_MUL: subopc = 1; break;
sewardjce646f22004-08-31 23:55:54 +00001799 case Xfp_DIV: subopc = 6; break;
sewardjcfded9a2004-09-09 11:44:16 +00001800 default: vpanic("do_fop2_st: unknown op");
sewardjbb53f8c2004-08-14 11:50:01 +00001801 }
1802 *p++ = 0xD8;
1803 p = doAMode_R(p, fake(subopc), fake(i));
1804 return p;
1805# undef fake
1806}
sewardjbad34a92004-07-22 01:14:11 +00001807
sewardj1e6ad742004-12-02 16:16:11 +00001808/* Push a 32-bit word on the stack. The word depends on tags[3:0];
1809each byte is either 0x00 or 0xFF depending on the corresponding bit in tags[].
1810*/
1811static UChar* push_word_from_tags ( UChar* p, UShort tags )
1812{
1813 UInt w;
1814 vassert(0 == (tags & ~0xF));
1815 if (tags == 0) {
1816 /* pushl $0x00000000 */
1817 *p++ = 0x6A;
1818 *p++ = 0x00;
1819 }
1820 else
1821 /* pushl $0xFFFFFFFF */
1822 if (tags == 0xF) {
1823 *p++ = 0x6A;
1824 *p++ = 0xFF;
1825 } else {
1826 vassert(0); /* awaiting test case */
1827 w = 0;
1828 if (tags & 1) w |= 0x000000FF;
1829 if (tags & 2) w |= 0x0000FF00;
1830 if (tags & 4) w |= 0x00FF0000;
1831 if (tags & 8) w |= 0xFF000000;
1832 *p++ = 0x68;
1833 p = emit32(p, w);
1834 }
1835 return p;
1836}
1837
sewardj81bd5502004-07-21 18:49:27 +00001838/* Emit an instruction into buf and return the number of bytes used.
1839 Note that buf is not the insn's final place, and therefore it is
1840 imperative to emit position-independent code. */
1841
sewardj17c7f952005-12-15 14:02:34 +00001842Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i,
1843 Bool mode64, void* dispatch )
sewardj81bd5502004-07-21 18:49:27 +00001844{
sewardj4b861de2004-11-03 15:24:42 +00001845 UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
sewardjea64e142004-07-22 16:47:21 +00001846
sewardj1e6ad742004-12-02 16:16:11 +00001847 UInt xtra;
sewardjbad34a92004-07-22 01:14:11 +00001848 UChar* p = &buf[0];
sewardj750f4072004-07-26 22:39:11 +00001849 UChar* ptmp;
sewardjbad34a92004-07-22 01:14:11 +00001850 vassert(nbuf >= 32);
cerion92b64362005-12-13 12:02:26 +00001851 vassert(mode64 == False);
sewardjbad34a92004-07-22 01:14:11 +00001852
sewardjea64e142004-07-22 16:47:21 +00001853 /* Wrap an integer as a int register, for use assembling
1854 GrpN insns, in which the greg field is used as a sub-opcode
1855 and does not really contain a register. */
sewardj4a31b262004-12-01 02:24:44 +00001856# define fake(_n) mkHReg((_n), HRcInt32, False)
sewardjea64e142004-07-22 16:47:21 +00001857
cerion92b64362005-12-13 12:02:26 +00001858 /* vex_printf("asm ");ppX86Instr(i, mode64); vex_printf("\n"); */
sewardjbec10842004-10-12 13:44:45 +00001859
sewardj81bd5502004-07-21 18:49:27 +00001860 switch (i->tag) {
sewardjbad34a92004-07-22 01:14:11 +00001861
1862 case Xin_Alu32R:
sewardjea64e142004-07-22 16:47:21 +00001863 /* Deal specially with MOV */
sewardjbad34a92004-07-22 01:14:11 +00001864 if (i->Xin.Alu32R.op == Xalu_MOV) {
1865 switch (i->Xin.Alu32R.src->tag) {
sewardjea64e142004-07-22 16:47:21 +00001866 case Xrmi_Imm:
sewardj8ee8c882005-02-25 17:40:26 +00001867 *p++ = toUChar(0xB8 + iregNo(i->Xin.Alu32R.dst));
sewardjea64e142004-07-22 16:47:21 +00001868 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
1869 goto done;
1870 case Xrmi_Reg:
sewardj750f4072004-07-26 22:39:11 +00001871 *p++ = 0x89;
1872 p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg,
1873 i->Xin.Alu32R.dst);
1874 goto done;
sewardjea64e142004-07-22 16:47:21 +00001875 case Xrmi_Mem:
1876 *p++ = 0x8B;
1877 p = doAMode_M(p, i->Xin.Alu32R.dst,
1878 i->Xin.Alu32R.src->Xrmi.Mem.am);
1879 goto done;
1880 default:
1881 goto bad;
1882 }
1883 }
sewardje8c922f2004-07-23 01:34:11 +00001884 /* MUL */
1885 if (i->Xin.Alu32R.op == Xalu_MUL) {
sewardjd75fe5a2004-07-23 12:57:47 +00001886 switch (i->Xin.Alu32R.src->tag) {
1887 case Xrmi_Reg:
1888 *p++ = 0x0F;
1889 *p++ = 0xAF;
1890 p = doAMode_R(p, i->Xin.Alu32R.dst,
1891 i->Xin.Alu32R.src->Xrmi.Reg.reg);
1892 goto done;
sewardj140656d2004-08-22 02:37:25 +00001893 case Xrmi_Mem:
1894 *p++ = 0x0F;
1895 *p++ = 0xAF;
1896 p = doAMode_M(p, i->Xin.Alu32R.dst,
1897 i->Xin.Alu32R.src->Xrmi.Mem.am);
1898 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00001899 case Xrmi_Imm:
1900 if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
1901 *p++ = 0x6B;
1902 p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
sewardj8ee8c882005-02-25 17:40:26 +00001903 *p++ = toUChar(0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjd75fe5a2004-07-23 12:57:47 +00001904 } else {
sewardj278c44c2004-08-20 00:28:13 +00001905 *p++ = 0x69;
1906 p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
1907 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjd75fe5a2004-07-23 12:57:47 +00001908 }
sewardj278c44c2004-08-20 00:28:13 +00001909 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00001910 default:
1911 goto bad;
1912 }
sewardje8c922f2004-07-23 01:34:11 +00001913 }
1914 /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP */
sewardjea64e142004-07-22 16:47:21 +00001915 opc = opc_rr = subopc_imm = opc_imma = 0;
1916 switch (i->Xin.Alu32R.op) {
sewardjd3f9de72005-01-15 20:43:10 +00001917 case Xalu_ADC: opc = 0x13; opc_rr = 0x11;
1918 subopc_imm = 2; opc_imma = 0x15; break;
sewardjea64e142004-07-22 16:47:21 +00001919 case Xalu_ADD: opc = 0x03; opc_rr = 0x01;
1920 subopc_imm = 0; opc_imma = 0x05; break;
1921 case Xalu_SUB: opc = 0x2B; opc_rr = 0x29;
1922 subopc_imm = 5; opc_imma = 0x2D; break;
sewardj70f676d2004-12-10 14:59:57 +00001923 case Xalu_SBB: opc = 0x1B; opc_rr = 0x19;
1924 subopc_imm = 3; opc_imma = 0x1D; break;
sewardj86898e82004-07-22 17:26:12 +00001925 case Xalu_AND: opc = 0x23; opc_rr = 0x21;
1926 subopc_imm = 4; opc_imma = 0x25; break;
sewardje8c922f2004-07-23 01:34:11 +00001927 case Xalu_XOR: opc = 0x33; opc_rr = 0x31;
1928 subopc_imm = 6; opc_imma = 0x35; break;
1929 case Xalu_OR: opc = 0x0B; opc_rr = 0x09;
1930 subopc_imm = 1; opc_imma = 0x0D; break;
1931 case Xalu_CMP: opc = 0x3B; opc_rr = 0x39;
1932 subopc_imm = 7; opc_imma = 0x3D; break;
sewardjea64e142004-07-22 16:47:21 +00001933 default: goto bad;
1934 }
1935 switch (i->Xin.Alu32R.src->tag) {
1936 case Xrmi_Imm:
1937 if (i->Xin.Alu32R.dst == hregX86_EAX()
1938 && !fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
sewardj8ee8c882005-02-25 17:40:26 +00001939 *p++ = toUChar(opc_imma);
sewardjea64e142004-07-22 16:47:21 +00001940 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
1941 } else
sewardjd3f9de72005-01-15 20:43:10 +00001942 if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
sewardjea64e142004-07-22 16:47:21 +00001943 *p++ = 0x83;
1944 p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst);
sewardj8ee8c882005-02-25 17:40:26 +00001945 *p++ = toUChar(0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjea64e142004-07-22 16:47:21 +00001946 } else {
1947 *p++ = 0x81;
1948 p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst);
1949 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
1950 }
1951 goto done;
1952 case Xrmi_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00001953 *p++ = toUChar(opc_rr);
sewardjea64e142004-07-22 16:47:21 +00001954 p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg,
1955 i->Xin.Alu32R.dst);
1956 goto done;
sewardjbad34a92004-07-22 01:14:11 +00001957 case Xrmi_Mem:
sewardj8ee8c882005-02-25 17:40:26 +00001958 *p++ = toUChar(opc);
sewardjea64e142004-07-22 16:47:21 +00001959 p = doAMode_M(p, i->Xin.Alu32R.dst,
sewardjbad34a92004-07-22 01:14:11 +00001960 i->Xin.Alu32R.src->Xrmi.Mem.am);
1961 goto done;
sewardjea64e142004-07-22 16:47:21 +00001962 default:
sewardjbad34a92004-07-22 01:14:11 +00001963 goto bad;
sewardjbad34a92004-07-22 01:14:11 +00001964 }
1965 break;
1966
1967 case Xin_Alu32M:
sewardjea64e142004-07-22 16:47:21 +00001968 /* Deal specially with MOV */
sewardjbad34a92004-07-22 01:14:11 +00001969 if (i->Xin.Alu32M.op == Xalu_MOV) {
sewardjea64e142004-07-22 16:47:21 +00001970 switch (i->Xin.Alu32M.src->tag) {
1971 case Xri_Reg:
1972 *p++ = 0x89;
1973 p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg,
1974 i->Xin.Alu32M.dst);
1975 goto done;
1976 case Xri_Imm:
1977 *p++ = 0xC7;
1978 p = doAMode_M(p, fake(0), i->Xin.Alu32M.dst);
1979 p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32);
1980 goto done;
1981 default:
1982 goto bad;
1983 }
1984 }
sewardje8c922f2004-07-23 01:34:11 +00001985 /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP. MUL is not
1986 allowed here. */
sewardjea64e142004-07-22 16:47:21 +00001987 opc = subopc_imm = opc_imma = 0;
1988 switch (i->Xin.Alu32M.op) {
1989 case Xalu_ADD: opc = 0x01; subopc_imm = 0; break;
sewardj86898e82004-07-22 17:26:12 +00001990 case Xalu_SUB: opc = 0x29; subopc_imm = 5; break;
sewardjea64e142004-07-22 16:47:21 +00001991 default: goto bad;
1992 }
1993 switch (i->Xin.Alu32M.src->tag) {
1994 case Xri_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00001995 *p++ = toUChar(opc);
sewardjea64e142004-07-22 16:47:21 +00001996 p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg,
1997 i->Xin.Alu32M.dst);
1998 goto done;
1999 case Xri_Imm:
2000 if (fits8bits(i->Xin.Alu32M.src->Xri.Imm.imm32)) {
2001 *p++ = 0x83;
2002 p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst);
sewardj8ee8c882005-02-25 17:40:26 +00002003 *p++ = toUChar(0xFF & i->Xin.Alu32M.src->Xri.Imm.imm32);
sewardjea64e142004-07-22 16:47:21 +00002004 goto done;
2005 } else {
2006 *p++ = 0x81;
2007 p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst);
2008 p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32);
2009 goto done;
2010 }
2011 default:
2012 goto bad;
sewardjbad34a92004-07-22 01:14:11 +00002013 }
2014 break;
2015
sewardje8c922f2004-07-23 01:34:11 +00002016 case Xin_Sh32:
sewardjd75fe5a2004-07-23 12:57:47 +00002017 opc_cl = opc_imm = subopc = 0;
2018 switch (i->Xin.Sh32.op) {
2019 case Xsh_SHR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 5; break;
sewardj07134a42004-07-26 02:04:54 +00002020 case Xsh_SAR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 7; break;
2021 case Xsh_SHL: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 4; break;
sewardjd75fe5a2004-07-23 12:57:47 +00002022 default: goto bad;
2023 }
2024 if (i->Xin.Sh32.src == 0) {
sewardj8ee8c882005-02-25 17:40:26 +00002025 *p++ = toUChar(opc_cl);
sewardjeba63f82005-02-23 13:31:25 +00002026 p = doAMode_R(p, fake(subopc), i->Xin.Sh32.dst);
sewardjd75fe5a2004-07-23 12:57:47 +00002027 } else {
sewardj8ee8c882005-02-25 17:40:26 +00002028 *p++ = toUChar(opc_imm);
sewardjeba63f82005-02-23 13:31:25 +00002029 p = doAMode_R(p, fake(subopc), i->Xin.Sh32.dst);
2030 *p++ = (UChar)(i->Xin.Sh32.src);
sewardjd75fe5a2004-07-23 12:57:47 +00002031 }
sewardjeba63f82005-02-23 13:31:25 +00002032 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002033
2034 case Xin_Test32:
sewardjeba63f82005-02-23 13:31:25 +00002035 /* testl $imm32, %reg */
2036 *p++ = 0xF7;
2037 p = doAMode_R(p, fake(0), i->Xin.Test32.dst);
2038 p = emit32(p, i->Xin.Test32.imm32);
2039 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002040
2041 case Xin_Unary32:
sewardj358b7d42004-11-08 18:54:50 +00002042 if (i->Xin.Unary32.op == Xun_NOT) {
sewardjd75fe5a2004-07-23 12:57:47 +00002043 *p++ = 0xF7;
sewardjeba63f82005-02-23 13:31:25 +00002044 p = doAMode_R(p, fake(2), i->Xin.Unary32.dst);
2045 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002046 }
sewardj358b7d42004-11-08 18:54:50 +00002047 if (i->Xin.Unary32.op == Xun_NEG) {
2048 *p++ = 0xF7;
sewardjeba63f82005-02-23 13:31:25 +00002049 p = doAMode_R(p, fake(3), i->Xin.Unary32.dst);
2050 goto done;
sewardj358b7d42004-11-08 18:54:50 +00002051 }
sewardjd75fe5a2004-07-23 12:57:47 +00002052 break;
sewardje8c922f2004-07-23 01:34:11 +00002053
sewardja2dad5c2004-07-23 11:43:43 +00002054 case Xin_MulL:
sewardjd75fe5a2004-07-23 12:57:47 +00002055 subopc = i->Xin.MulL.syned ? 5 : 4;
sewardjeba63f82005-02-23 13:31:25 +00002056 *p++ = 0xF7;
2057 switch (i->Xin.MulL.src->tag) {
2058 case Xrm_Mem:
2059 p = doAMode_M(p, fake(subopc),
2060 i->Xin.MulL.src->Xrm.Mem.am);
2061 goto done;
2062 case Xrm_Reg:
2063 p = doAMode_R(p, fake(subopc),
2064 i->Xin.MulL.src->Xrm.Reg.reg);
2065 goto done;
2066 default:
2067 goto bad;
sewardjd75fe5a2004-07-23 12:57:47 +00002068 }
2069 break;
sewardja2dad5c2004-07-23 11:43:43 +00002070
2071 case Xin_Div:
sewardjd75fe5a2004-07-23 12:57:47 +00002072 subopc = i->Xin.Div.syned ? 7 : 6;
sewardjeba63f82005-02-23 13:31:25 +00002073 *p++ = 0xF7;
2074 switch (i->Xin.Div.src->tag) {
2075 case Xrm_Mem:
2076 p = doAMode_M(p, fake(subopc),
2077 i->Xin.Div.src->Xrm.Mem.am);
2078 goto done;
2079 case Xrm_Reg:
2080 p = doAMode_R(p, fake(subopc),
2081 i->Xin.Div.src->Xrm.Reg.reg);
2082 goto done;
2083 default:
2084 goto bad;
sewardjd75fe5a2004-07-23 12:57:47 +00002085 }
2086 break;
sewardja2dad5c2004-07-23 11:43:43 +00002087
2088 case Xin_Sh3232:
sewardjd75fe5a2004-07-23 12:57:47 +00002089 vassert(i->Xin.Sh3232.op == Xsh_SHL || i->Xin.Sh3232.op == Xsh_SHR);
2090 if (i->Xin.Sh3232.amt == 0) {
2091 /* shldl/shrdl by %cl */
2092 *p++ = 0x0F;
sewardj68511542004-07-28 00:15:44 +00002093 if (i->Xin.Sh3232.op == Xsh_SHL) {
2094 *p++ = 0xA5;
sewardj68511542004-07-28 00:15:44 +00002095 } else {
2096 *p++ = 0xAD;
sewardj68511542004-07-28 00:15:44 +00002097 }
sewardje5f384c2004-07-30 16:17:28 +00002098 p = doAMode_R(p, i->Xin.Sh3232.src, i->Xin.Sh3232.dst);
sewardjd75fe5a2004-07-23 12:57:47 +00002099 goto done;
2100 }
2101 break;
sewardja2dad5c2004-07-23 11:43:43 +00002102
sewardje8c922f2004-07-23 01:34:11 +00002103 case Xin_Push:
sewardjd75fe5a2004-07-23 12:57:47 +00002104 switch (i->Xin.Push.src->tag) {
2105 case Xrmi_Mem:
2106 *p++ = 0xFF;
2107 p = doAMode_M(p, fake(6), i->Xin.Push.src->Xrmi.Mem.am);
2108 goto done;
sewardja58ea662004-08-15 03:12:41 +00002109 case Xrmi_Imm:
2110 *p++ = 0x68;
2111 p = emit32(p, i->Xin.Push.src->Xrmi.Imm.imm32);
2112 goto done;
sewardjd7cb8532004-08-17 23:59:23 +00002113 case Xrmi_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00002114 *p++ = toUChar(0x50 + iregNo(i->Xin.Push.src->Xrmi.Reg.reg));
sewardjd7cb8532004-08-17 23:59:23 +00002115 goto done;
sewardja58ea662004-08-15 03:12:41 +00002116 default:
sewardjd75fe5a2004-07-23 12:57:47 +00002117 goto bad;
2118 }
sewardje8c922f2004-07-23 01:34:11 +00002119
2120 case Xin_Call:
sewardj4b861de2004-11-03 15:24:42 +00002121 /* See detailed comment for Xin_Call in getRegUsage_X86Instr above
2122 for explanation of this. */
2123 switch (i->Xin.Call.regparms) {
2124 case 0: irno = iregNo(hregX86_EAX()); break;
sewardj45c50eb2004-11-04 18:25:33 +00002125 case 1: irno = iregNo(hregX86_EDX()); break;
2126 case 2: irno = iregNo(hregX86_ECX()); break;
sewardj4b861de2004-11-03 15:24:42 +00002127 case 3: irno = iregNo(hregX86_EDI()); break;
2128 default: vpanic(" emit_X86Instr:call:regparms");
2129 }
2130 /* jump over the following two insns if the condition does not
2131 hold */
2132 if (i->Xin.Call.cond != Xcc_ALWAYS) {
sewardj8ee8c882005-02-25 17:40:26 +00002133 *p++ = toUChar(0x70 + (0xF & (i->Xin.Call.cond ^ 1)));
sewardj4b861de2004-11-03 15:24:42 +00002134 *p++ = 0x07; /* 7 bytes in the next two insns */
2135 }
2136 /* movl $target, %tmp */
sewardj8ee8c882005-02-25 17:40:26 +00002137 *p++ = toUChar(0xB8 + irno);
sewardj4b861de2004-11-03 15:24:42 +00002138 p = emit32(p, i->Xin.Call.target);
2139 /* call *%tmp */
sewardjd75fe5a2004-07-23 12:57:47 +00002140 *p++ = 0xFF;
sewardj8ee8c882005-02-25 17:40:26 +00002141 *p++ = toUChar(0xD0 + irno);
sewardjd75fe5a2004-07-23 12:57:47 +00002142 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002143
sewardj86898e82004-07-22 17:26:12 +00002144 case Xin_Goto:
sewardj893aada2004-11-29 19:57:54 +00002145 /* Use ptmp for backpatching conditional jumps. */
2146 ptmp = NULL;
2147
2148 /* First off, if this is conditional, create a conditional
2149 jump over the rest of it. */
2150 if (i->Xin.Goto.cond != Xcc_ALWAYS) {
2151 /* jmp fwds if !condition */
sewardj8ee8c882005-02-25 17:40:26 +00002152 *p++ = toUChar(0x70 + (0xF & (i->Xin.Goto.cond ^ 1)));
sewardj893aada2004-11-29 19:57:54 +00002153 ptmp = p; /* fill in this bit later */
2154 *p++ = 0; /* # of bytes to jump over; don't know how many yet. */
sewardj750f4072004-07-26 22:39:11 +00002155 }
sewardj893aada2004-11-29 19:57:54 +00002156
2157 /* If a non-boring, set %ebp (the guest state pointer)
2158 appropriately. */
2159 /* movl $magic_number, %ebp */
2160 switch (i->Xin.Goto.jk) {
2161 case Ijk_ClientReq:
2162 *p++ = 0xBD;
2163 p = emit32(p, VEX_TRC_JMP_CLIENTREQ); break;
sewardj4fa325a2005-11-03 13:27:24 +00002164 case Ijk_Sys_int128:
sewardj893aada2004-11-29 19:57:54 +00002165 *p++ = 0xBD;
sewardj4fa325a2005-11-03 13:27:24 +00002166 p = emit32(p, VEX_TRC_JMP_SYS_INT128); break;
sewardj893aada2004-11-29 19:57:54 +00002167 case Ijk_Yield:
2168 *p++ = 0xBD;
2169 p = emit32(p, VEX_TRC_JMP_YIELD); break;
2170 case Ijk_EmWarn:
2171 *p++ = 0xBD;
2172 p = emit32(p, VEX_TRC_JMP_EMWARN); break;
sewardj52444cb2004-12-13 14:09:01 +00002173 case Ijk_MapFail:
2174 *p++ = 0xBD;
2175 p = emit32(p, VEX_TRC_JMP_MAPFAIL); break;
2176 case Ijk_NoDecode:
2177 *p++ = 0xBD;
2178 p = emit32(p, VEX_TRC_JMP_NODECODE); break;
sewardjdb4738a2005-07-07 01:32:16 +00002179 case Ijk_TInval:
2180 *p++ = 0xBD;
2181 p = emit32(p, VEX_TRC_JMP_TINVAL); break;
sewardj4fa325a2005-11-03 13:27:24 +00002182 case Ijk_Sys_sysenter:
sewardjf07ed032005-08-07 14:48:03 +00002183 *p++ = 0xBD;
sewardj4fa325a2005-11-03 13:27:24 +00002184 p = emit32(p, VEX_TRC_JMP_SYS_SYSENTER); break;
sewardj893aada2004-11-29 19:57:54 +00002185 case Ijk_Ret:
2186 case Ijk_Call:
2187 case Ijk_Boring:
2188 break;
2189 default:
2190 ppIRJumpKind(i->Xin.Goto.jk);
2191 vpanic("emit_X86Instr.Xin_Goto: unknown jump kind");
2192 }
2193
2194 /* Get the destination address into %eax */
2195 if (i->Xin.Goto.dst->tag == Xri_Imm) {
sewardj17c7f952005-12-15 14:02:34 +00002196 /* movl $immediate, %eax */
sewardj86898e82004-07-22 17:26:12 +00002197 *p++ = 0xB8;
2198 p = emit32(p, i->Xin.Goto.dst->Xri.Imm.imm32);
sewardj893aada2004-11-29 19:57:54 +00002199 } else {
2200 vassert(i->Xin.Goto.dst->tag == Xri_Reg);
sewardj17c7f952005-12-15 14:02:34 +00002201 /* movl %reg, %eax */
sewardje8c922f2004-07-23 01:34:11 +00002202 if (i->Xin.Goto.dst->Xri.Reg.reg != hregX86_EAX()) {
2203 *p++ = 0x89;
2204 p = doAMode_R(p, i->Xin.Goto.dst->Xri.Reg.reg, hregX86_EAX());
sewardjd75fe5a2004-07-23 12:57:47 +00002205 }
sewardjd75fe5a2004-07-23 12:57:47 +00002206 }
sewardj893aada2004-11-29 19:57:54 +00002207
sewardj17c7f952005-12-15 14:02:34 +00002208 /* Get the dispatcher address into %edx. This has to happen
2209 after the load of %eax since %edx might be carrying the value
2210 destined for %eax immediately prior to this Xin_Goto. */
2211 vassert(sizeof(UInt) == sizeof(void*));
2212 vassert(dispatch != NULL);
2213 /* movl $imm32, %edx */
2214 *p++ = 0xBA;
2215 p = emit32(p, (UInt)dispatch);
2216
2217 /* jmp *%edx */
2218 *p++ = 0xFF;
2219 *p++ = 0xE2;
sewardj893aada2004-11-29 19:57:54 +00002220
2221 /* Fix up the conditional jump, if there was one. */
2222 if (i->Xin.Goto.cond != Xcc_ALWAYS) {
2223 Int delta = p - ptmp;
2224 vassert(delta > 0 && delta < 20);
sewardj8ee8c882005-02-25 17:40:26 +00002225 *ptmp = toUChar(delta-1);
sewardje8c922f2004-07-23 01:34:11 +00002226 }
sewardj893aada2004-11-29 19:57:54 +00002227 goto done;
sewardj86898e82004-07-22 17:26:12 +00002228
sewardje8c922f2004-07-23 01:34:11 +00002229 case Xin_CMov32:
sewardjd75fe5a2004-07-23 12:57:47 +00002230 vassert(i->Xin.CMov32.cond != Xcc_ALWAYS);
sewardjc4904af2005-08-08 00:33:37 +00002231
sewardj893aada2004-11-29 19:57:54 +00002232 /* This generates cmov, which is illegal on P54/P55. */
sewardjc4904af2005-08-08 00:33:37 +00002233 /*
sewardjd75fe5a2004-07-23 12:57:47 +00002234 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002235 *p++ = toUChar(0x40 + (0xF & i->Xin.CMov32.cond));
sewardjd75fe5a2004-07-23 12:57:47 +00002236 if (i->Xin.CMov32.src->tag == Xrm_Reg) {
2237 p = doAMode_R(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Reg.reg);
2238 goto done;
2239 }
2240 if (i->Xin.CMov32.src->tag == Xrm_Mem) {
2241 p = doAMode_M(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Mem.am);
2242 goto done;
2243 }
sewardjc4904af2005-08-08 00:33:37 +00002244 */
2245
2246 /* Alternative version which works on any x86 variant. */
2247 /* jmp fwds if !condition */
sewardjc7cd2142005-09-09 22:31:49 +00002248 *p++ = toUChar(0x70 + (i->Xin.CMov32.cond ^ 1));
sewardjc4904af2005-08-08 00:33:37 +00002249 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2250 ptmp = p;
2251
2252 switch (i->Xin.CMov32.src->tag) {
2253 case Xrm_Reg:
2254 /* Big sigh. This is movl E -> G ... */
2255 *p++ = 0x89;
2256 p = doAMode_R(p, i->Xin.CMov32.src->Xrm.Reg.reg,
2257 i->Xin.CMov32.dst);
2258
2259 break;
2260 case Xrm_Mem:
2261 /* ... whereas this is movl G -> E. That's why the args
2262 to doAMode_R appear to be the wrong way round in the
2263 Xrm_Reg case. */
2264 *p++ = 0x8B;
2265 p = doAMode_M(p, i->Xin.CMov32.dst,
2266 i->Xin.CMov32.src->Xrm.Mem.am);
2267 break;
2268 default:
2269 goto bad;
2270 }
2271 /* Fill in the jump offset. */
sewardjc7cd2142005-09-09 22:31:49 +00002272 *(ptmp-1) = toUChar(p - ptmp);
sewardjc4904af2005-08-08 00:33:37 +00002273 goto done;
2274
sewardjd75fe5a2004-07-23 12:57:47 +00002275 break;
sewardje8c922f2004-07-23 01:34:11 +00002276
2277 case Xin_LoadEX:
sewardjd75fe5a2004-07-23 12:57:47 +00002278 if (i->Xin.LoadEX.szSmall == 1 && !i->Xin.LoadEX.syned) {
2279 /* movzbl */
2280 *p++ = 0x0F;
2281 *p++ = 0xB6;
2282 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2283 goto done;
2284 }
2285 if (i->Xin.LoadEX.szSmall == 2 && !i->Xin.LoadEX.syned) {
2286 /* movzwl */
2287 *p++ = 0x0F;
2288 *p++ = 0xB7;
2289 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2290 goto done;
2291 }
2292 break;
sewardje8c922f2004-07-23 01:34:11 +00002293
sewardjd7cb8532004-08-17 23:59:23 +00002294 case Xin_Set32:
2295 /* Make the destination register be 1 or 0, depending on whether
2296 the relevant condition holds. We have to dodge and weave
2297 when the destination is %esi or %edi as we cannot directly
2298 emit the native 'setb %reg' for those. Further complication:
2299 the top 24 bits of the destination should be forced to zero,
2300 but doing 'xor %r,%r' kills the flag(s) we are about to read.
sewardj3503ad82004-08-24 00:24:56 +00002301 Sigh. So start off my moving $0 into the dest. */
sewardjd7cb8532004-08-17 23:59:23 +00002302
sewardj3503ad82004-08-24 00:24:56 +00002303 /* Do we need to swap in %eax? */
sewardjd7cb8532004-08-17 23:59:23 +00002304 if (iregNo(i->Xin.Set32.dst) >= 4) {
2305 /* xchg %eax, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002306 *p++ = toUChar(0x90 + iregNo(i->Xin.Set32.dst));
sewardj3503ad82004-08-24 00:24:56 +00002307 /* movl $0, %eax */
sewardj8ee8c882005-02-25 17:40:26 +00002308 *p++ =toUChar(0xB8 + iregNo(hregX86_EAX()));
sewardj3503ad82004-08-24 00:24:56 +00002309 p = emit32(p, 0);
2310 /* setb lo8(%eax) */
sewardjd7cb8532004-08-17 23:59:23 +00002311 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002312 *p++ = toUChar(0x90 + (0xF & i->Xin.Set32.cond));
sewardjd7cb8532004-08-17 23:59:23 +00002313 p = doAMode_R(p, fake(0), hregX86_EAX());
2314 /* xchg %eax, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002315 *p++ = toUChar(0x90 + iregNo(i->Xin.Set32.dst));
sewardjd7cb8532004-08-17 23:59:23 +00002316 } else {
sewardj3503ad82004-08-24 00:24:56 +00002317 /* movl $0, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002318 *p++ = toUChar(0xB8 + iregNo(i->Xin.Set32.dst));
sewardj3503ad82004-08-24 00:24:56 +00002319 p = emit32(p, 0);
2320 /* setb lo8(%dst) */
sewardjd7cb8532004-08-17 23:59:23 +00002321 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002322 *p++ = toUChar(0x90 + (0xF & i->Xin.Set32.cond));
sewardjd7cb8532004-08-17 23:59:23 +00002323 p = doAMode_R(p, fake(0), i->Xin.Set32.dst);
2324 }
2325 goto done;
2326
sewardjce646f22004-08-31 23:55:54 +00002327 case Xin_Bsfr32:
2328 *p++ = 0x0F;
2329 if (i->Xin.Bsfr32.isFwds) {
2330 *p++ = 0xBC;
2331 } else {
2332 *p++ = 0xBD;
2333 }
2334 p = doAMode_R(p, i->Xin.Bsfr32.dst, i->Xin.Bsfr32.src);
2335 goto done;
2336
sewardj3e838932005-01-07 12:09:15 +00002337 case Xin_MFence:
2338 /* see comment in hdefs.h re this insn */
sewardjbb3f52d2005-01-07 14:14:50 +00002339 if (0) vex_printf("EMIT FENCE\n");
sewardj3e838932005-01-07 12:09:15 +00002340 switch (i->Xin.MFence.subarch) {
2341 case VexSubArchX86_sse0:
sewardj3e838932005-01-07 12:09:15 +00002342 /* lock addl $0,0(%esp) */
2343 *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44;
2344 *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
2345 goto done;
2346 case VexSubArchX86_sse1:
2347 /* sfence */
2348 *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF8;
2349 /* lock addl $0,0(%esp) */
2350 *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44;
2351 *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
2352 goto done;
2353 case VexSubArchX86_sse2:
sewardj3e838932005-01-07 12:09:15 +00002354 /* mfence */
2355 *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF0;
2356 goto done;
2357 default:
2358 vpanic("emit_X86Instr:mfence:subarch");
2359 }
2360 break;
2361
sewardje8c922f2004-07-23 01:34:11 +00002362 case Xin_Store:
sewardjd75fe5a2004-07-23 12:57:47 +00002363 if (i->Xin.Store.sz == 2) {
2364 /* This case, at least, is simple, given that we can
2365 reference the low 16 bits of any integer register. */
2366 *p++ = 0x66;
2367 *p++ = 0x89;
2368 p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
2369 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002370 }
sewardjd75fe5a2004-07-23 12:57:47 +00002371
2372 if (i->Xin.Store.sz == 1) {
2373 /* We have to do complex dodging and weaving if src is not
2374 the low 8 bits of %eax/%ebx/%ecx/%edx. */
2375 if (iregNo(i->Xin.Store.src) < 4) {
2376 /* we're OK, can do it directly */
2377 *p++ = 0x88;
2378 p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
2379 goto done;
2380 } else {
2381 /* Bleh. This means the source is %edi or %esi. Since
2382 the address mode can only mention three registers, at
2383 least one of %eax/%ebx/%ecx/%edx must be available to
2384 temporarily swap the source into, so the store can
2385 happen. So we have to look at the regs mentioned
2386 in the amode. */
sewardj2e56f9f2004-07-24 01:24:38 +00002387 HReg swap = INVALID_HREG;
2388 HReg eax = hregX86_EAX(), ebx = hregX86_EBX(),
2389 ecx = hregX86_ECX(), edx = hregX86_EDX();
sewardjd75fe5a2004-07-23 12:57:47 +00002390 Bool a_ok = True, b_ok = True, c_ok = True, d_ok = True;
2391 HRegUsage u;
2392 Int j;
2393 initHRegUsage(&u);
2394 addRegUsage_X86AMode(&u, i->Xin.Store.dst);
2395 for (j = 0; j < u.n_used; j++) {
2396 HReg r = u.hreg[j];
2397 if (r == eax) a_ok = False;
2398 if (r == ebx) b_ok = False;
2399 if (r == ecx) c_ok = False;
2400 if (r == edx) d_ok = False;
2401 }
sewardjd75fe5a2004-07-23 12:57:47 +00002402 if (a_ok) swap = eax;
2403 if (b_ok) swap = ebx;
2404 if (c_ok) swap = ecx;
2405 if (d_ok) swap = edx;
2406 vassert(swap != INVALID_HREG);
2407 /* xchgl %source, %swap. Could do better if swap is %eax. */
2408 *p++ = 0x87;
2409 p = doAMode_R(p, i->Xin.Store.src, swap);
2410 /* movb lo8{%swap}, (dst) */
2411 *p++ = 0x88;
2412 p = doAMode_M(p, swap, i->Xin.Store.dst);
2413 /* xchgl %source, %swap. Could do better if swap is %eax. */
2414 *p++ = 0x87;
2415 p = doAMode_R(p, i->Xin.Store.src, swap);
2416 goto done;
2417 }
2418 } /* if (i->Xin.Store.sz == 1) */
2419 break;
sewardj86898e82004-07-22 17:26:12 +00002420
sewardjcfded9a2004-09-09 11:44:16 +00002421 case Xin_FpUnary:
2422 /* gop %src, %dst
2423 --> ffree %st7 ; fld %st(src) ; fop %st(0) ; fstp %st(1+dst)
2424 */
2425 p = do_ffree_st7(p);
2426 p = do_fld_st(p, 0+hregNumber(i->Xin.FpUnary.src));
2427 p = do_fop1_st(p, i->Xin.FpUnary.op);
2428 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpUnary.dst));
2429 goto done;
2430
sewardjbb53f8c2004-08-14 11:50:01 +00002431 case Xin_FpBinary:
sewardj06c32a02004-09-12 12:07:34 +00002432 if (i->Xin.FpBinary.op == Xfp_YL2X
2433 || i->Xin.FpBinary.op == Xfp_YL2XP1) {
sewardj8308aad2004-09-12 11:09:54 +00002434 /* Have to do this specially. */
2435 /* ffree %st7 ; fld %st(srcL) ;
sewardj06c32a02004-09-12 12:07:34 +00002436 ffree %st7 ; fld %st(srcR+1) ; fyl2x{p1} ; fstp(1+dst) */
sewardj8308aad2004-09-12 11:09:54 +00002437 p = do_ffree_st7(p);
2438 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
2439 p = do_ffree_st7(p);
2440 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
sewardj06c32a02004-09-12 12:07:34 +00002441 *p++ = 0xD9;
sewardj8ee8c882005-02-25 17:40:26 +00002442 *p++ = toUChar(i->Xin.FpBinary.op==Xfp_YL2X ? 0xF1 : 0xF9);
sewardj8308aad2004-09-12 11:09:54 +00002443 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2444 goto done;
2445 }
sewardj52ace3e2004-09-11 17:10:08 +00002446 if (i->Xin.FpBinary.op == Xfp_ATAN) {
sewardjcfded9a2004-09-09 11:44:16 +00002447 /* Have to do this specially. */
sewardj46de4072004-09-11 19:23:24 +00002448 /* ffree %st7 ; fld %st(srcL) ;
2449 ffree %st7 ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */
sewardjcfded9a2004-09-09 11:44:16 +00002450 p = do_ffree_st7(p);
2451 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
sewardj46de4072004-09-11 19:23:24 +00002452 p = do_ffree_st7(p);
sewardjcfded9a2004-09-09 11:44:16 +00002453 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
2454 *p++ = 0xD9; *p++ = 0xF3;
2455 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2456 goto done;
2457 }
sewardj06c32a02004-09-12 12:07:34 +00002458 if (i->Xin.FpBinary.op == Xfp_PREM
sewardj442d0be2004-10-15 22:57:13 +00002459 || i->Xin.FpBinary.op == Xfp_PREM1
sewardj06c32a02004-09-12 12:07:34 +00002460 || i->Xin.FpBinary.op == Xfp_SCALE) {
sewardj46de4072004-09-11 19:23:24 +00002461 /* Have to do this specially. */
2462 /* ffree %st7 ; fld %st(srcR) ;
sewardj442d0be2004-10-15 22:57:13 +00002463 ffree %st7 ; fld %st(srcL+1) ; fprem/fprem1/fscale ; fstp(2+dst) ;
sewardj46de4072004-09-11 19:23:24 +00002464 fincstp ; ffree %st7 */
2465 p = do_ffree_st7(p);
2466 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR));
2467 p = do_ffree_st7(p);
2468 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL));
sewardj442d0be2004-10-15 22:57:13 +00002469 *p++ = 0xD9;
2470 switch (i->Xin.FpBinary.op) {
2471 case Xfp_PREM: *p++ = 0xF8; break;
2472 case Xfp_PREM1: *p++ = 0xF5; break;
2473 case Xfp_SCALE: *p++ = 0xFD; break;
2474 default: vpanic("emitX86Instr(FpBinary,PREM/PREM1/SCALE)");
2475 }
sewardj46de4072004-09-11 19:23:24 +00002476 p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst));
2477 *p++ = 0xD9; *p++ = 0xF7;
2478 p = do_ffree_st7(p);
2479 goto done;
2480 }
sewardjcfded9a2004-09-09 11:44:16 +00002481 /* General case */
sewardjbb53f8c2004-08-14 11:50:01 +00002482 /* gop %srcL, %srcR, %dst
2483 --> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst)
2484 */
2485 p = do_ffree_st7(p);
2486 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
sewardj3bca9062004-12-04 14:36:09 +00002487 p = do_fop2_st(p, i->Xin.FpBinary.op,
2488 1+hregNumber(i->Xin.FpBinary.srcR));
sewardjbb53f8c2004-08-14 11:50:01 +00002489 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2490 goto done;
2491
sewardj3196daf2004-08-13 00:18:58 +00002492 case Xin_FpLdSt:
sewardj3bca9062004-12-04 14:36:09 +00002493 vassert(i->Xin.FpLdSt.sz == 4 || i->Xin.FpLdSt.sz == 8);
sewardj3196daf2004-08-13 00:18:58 +00002494 if (i->Xin.FpLdSt.isLoad) {
2495 /* Load from memory into %fakeN.
sewardjbb53f8c2004-08-14 11:50:01 +00002496 --> ffree %st(7) ; fld{s/l} amode ; fstp st(N+1)
sewardj3196daf2004-08-13 00:18:58 +00002497 */
2498 p = do_ffree_st7(p);
sewardj8ee8c882005-02-25 17:40:26 +00002499 *p++ = toUChar(i->Xin.FpLdSt.sz==4 ? 0xD9 : 0xDD);
sewardj3196daf2004-08-13 00:18:58 +00002500 p = doAMode_M(p, fake(0)/*subopcode*/, i->Xin.FpLdSt.addr);
2501 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdSt.reg));
2502 goto done;
2503 } else {
2504 /* Store from %fakeN into memory.
sewardjbb53f8c2004-08-14 11:50:01 +00002505 --> ffree %st(7) ; fld st(N) ; fstp{l|s} amode
sewardj3196daf2004-08-13 00:18:58 +00002506 */
2507 p = do_ffree_st7(p);
2508 p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdSt.reg));
sewardj8ee8c882005-02-25 17:40:26 +00002509 *p++ = toUChar(i->Xin.FpLdSt.sz==4 ? 0xD9 : 0xDD);
sewardj3196daf2004-08-13 00:18:58 +00002510 p = doAMode_M(p, fake(3)/*subopcode*/, i->Xin.FpLdSt.addr);
2511 goto done;
2512 }
2513 break;
2514
sewardj89cd0932004-09-08 18:23:25 +00002515 case Xin_FpLdStI:
2516 if (i->Xin.FpLdStI.isLoad) {
2517 /* Load from memory into %fakeN, converting from an int.
2518 --> ffree %st(7) ; fild{w/l/ll} amode ; fstp st(N+1)
2519 */
2520 switch (i->Xin.FpLdStI.sz) {
sewardjbdc7d212004-09-09 02:46:40 +00002521 case 8: opc = 0xDF; subopc_imm = 5; break;
sewardj89cd0932004-09-08 18:23:25 +00002522 case 4: opc = 0xDB; subopc_imm = 0; break;
2523 case 2: vassert(0); opc = 0xDF; subopc_imm = 0; break;
2524 default: vpanic("emitX86Instr(Xin_FpLdStI-load)");
2525 }
2526 p = do_ffree_st7(p);
sewardj8ee8c882005-02-25 17:40:26 +00002527 *p++ = toUChar(opc);
sewardj89cd0932004-09-08 18:23:25 +00002528 p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr);
2529 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdStI.reg));
2530 goto done;
2531 } else {
2532 /* Store from %fakeN into memory, converting to an int.
2533 --> ffree %st(7) ; fld st(N) ; fistp{w/l/ll} amode
2534 */
2535 switch (i->Xin.FpLdStI.sz) {
sewardjcfded9a2004-09-09 11:44:16 +00002536 case 8: opc = 0xDF; subopc_imm = 7; break;
sewardj89cd0932004-09-08 18:23:25 +00002537 case 4: opc = 0xDB; subopc_imm = 3; break;
2538 case 2: opc = 0xDF; subopc_imm = 3; break;
2539 default: vpanic("emitX86Instr(Xin_FpLdStI-store)");
2540 }
2541 p = do_ffree_st7(p);
2542 p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdStI.reg));
sewardj8ee8c882005-02-25 17:40:26 +00002543 *p++ = toUChar(opc);
sewardj89cd0932004-09-08 18:23:25 +00002544 p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr);
2545 goto done;
2546 }
2547 break;
2548
sewardj3bca9062004-12-04 14:36:09 +00002549 case Xin_Fp64to32:
2550 /* ffree %st7 ; fld %st(src) */
2551 p = do_ffree_st7(p);
2552 p = do_fld_st(p, 0+fregNo(i->Xin.Fp64to32.src));
2553 /* subl $4, %esp */
2554 *p++ = 0x83; *p++ = 0xEC; *p++ = 0x04;
2555 /* fstps (%esp) */
2556 *p++ = 0xD9; *p++ = 0x1C; *p++ = 0x24;
2557 /* flds (%esp) */
2558 *p++ = 0xD9; *p++ = 0x04; *p++ = 0x24;
2559 /* addl $4, %esp */
2560 *p++ = 0x83; *p++ = 0xC4; *p++ = 0x04;
2561 /* fstp %st(1+dst) */
2562 p = do_fstp_st(p, 1+fregNo(i->Xin.Fp64to32.dst));
2563 goto done;
2564
sewardj3fc76d22004-08-31 11:47:54 +00002565 case Xin_FpCMov:
2566 /* jmp fwds if !condition */
sewardj8ee8c882005-02-25 17:40:26 +00002567 *p++ = toUChar(0x70 + (i->Xin.FpCMov.cond ^ 1));
sewardj3fc76d22004-08-31 11:47:54 +00002568 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2569 ptmp = p;
2570
2571 /* ffree %st7 ; fld %st(src) ; fstp %st(1+dst) */
2572 p = do_ffree_st7(p);
sewardjbdc7d212004-09-09 02:46:40 +00002573 p = do_fld_st(p, 0+fregNo(i->Xin.FpCMov.src));
2574 p = do_fstp_st(p, 1+fregNo(i->Xin.FpCMov.dst));
sewardj3fc76d22004-08-31 11:47:54 +00002575
2576 /* Fill in the jump offset. */
sewardj8ee8c882005-02-25 17:40:26 +00002577 *(ptmp-1) = toUChar(p - ptmp);
sewardj3fc76d22004-08-31 11:47:54 +00002578 goto done;
2579
sewardjeba63f82005-02-23 13:31:25 +00002580 case Xin_FpLdCW:
2581 *p++ = 0xD9;
2582 p = doAMode_M(p, fake(5)/*subopcode*/, i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00002583 goto done;
2584
sewardj46de4072004-09-11 19:23:24 +00002585 case Xin_FpStSW_AX:
2586 /* note, this emits fnstsw %ax, not fstsw %ax */
2587 *p++ = 0xDF;
2588 *p++ = 0xE0;
2589 goto done;
sewardjbdc7d212004-09-09 02:46:40 +00002590
2591 case Xin_FpCmp:
2592 /* gcmp %fL, %fR, %dst
2593 -> ffree %st7; fpush %fL ; fucomp %(fR+1) ;
2594 fnstsw %ax ; movl %eax, %dst
2595 */
2596 /* ffree %st7 */
2597 p = do_ffree_st7(p);
2598 /* fpush %fL */
2599 p = do_fld_st(p, 0+fregNo(i->Xin.FpCmp.srcL));
2600 /* fucomp %(fR+1) */
2601 *p++ = 0xDD;
sewardj8ee8c882005-02-25 17:40:26 +00002602 *p++ = toUChar(0xE8 + (7 & (1+fregNo(i->Xin.FpCmp.srcR))));
sewardjbdc7d212004-09-09 02:46:40 +00002603 /* fnstsw %ax */
2604 *p++ = 0xDF;
2605 *p++ = 0xE0;
2606 /* movl %eax, %dst */
2607 *p++ = 0x89;
2608 p = doAMode_R(p, hregX86_EAX(), i->Xin.FpCmp.dst);
2609 goto done;
2610
sewardj1e6ad742004-12-02 16:16:11 +00002611 case Xin_SseConst: {
2612 UShort con = i->Xin.SseConst.con;
sewardj8ee8c882005-02-25 17:40:26 +00002613 p = push_word_from_tags(p, toUShort((con >> 12) & 0xF));
2614 p = push_word_from_tags(p, toUShort((con >> 8) & 0xF));
2615 p = push_word_from_tags(p, toUShort((con >> 4) & 0xF));
2616 p = push_word_from_tags(p, toUShort(con & 0xF));
sewardj1e6ad742004-12-02 16:16:11 +00002617 /* movl (%esp), %xmm-dst */
2618 *p++ = 0x0F;
2619 *p++ = 0x10;
sewardj8ee8c882005-02-25 17:40:26 +00002620 *p++ = toUChar(0x04 + 8 * (7 & vregNo(i->Xin.SseConst.dst)));
sewardj1e6ad742004-12-02 16:16:11 +00002621 *p++ = 0x24;
2622 /* addl $16, %esp */
2623 *p++ = 0x83;
2624 *p++ = 0xC4;
2625 *p++ = 0x10;
2626 goto done;
2627 }
sewardj129b3d92004-12-05 15:42:05 +00002628
sewardjd08f2d72004-12-01 23:19:36 +00002629 case Xin_SseLdSt:
2630 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002631 *p++ = toUChar(i->Xin.SseLdSt.isLoad ? 0x10 : 0x11);
sewardjd08f2d72004-12-01 23:19:36 +00002632 p = doAMode_M(p, fake(vregNo(i->Xin.SseLdSt.reg)), i->Xin.SseLdSt.addr);
2633 goto done;
2634
sewardj129b3d92004-12-05 15:42:05 +00002635 case Xin_SseLdzLO:
sewardj636ad762004-12-07 11:16:04 +00002636 vassert(i->Xin.SseLdzLO.sz == 4 || i->Xin.SseLdzLO.sz == 8);
2637 /* movs[sd] amode, %xmm-dst */
sewardj8ee8c882005-02-25 17:40:26 +00002638 *p++ = toUChar(i->Xin.SseLdzLO.sz==4 ? 0xF3 : 0xF2);
sewardj636ad762004-12-07 11:16:04 +00002639 *p++ = 0x0F;
2640 *p++ = 0x10;
2641 p = doAMode_M(p, fake(vregNo(i->Xin.SseLdzLO.reg)),
2642 i->Xin.SseLdzLO.addr);
2643 goto done;
sewardj129b3d92004-12-05 15:42:05 +00002644
sewardj1e6ad742004-12-02 16:16:11 +00002645 case Xin_Sse32Fx4:
2646 xtra = 0;
2647 *p++ = 0x0F;
2648 switch (i->Xin.Sse32Fx4.op) {
2649 case Xsse_ADDF: *p++ = 0x58; break;
sewardj176a59c2004-12-03 20:08:31 +00002650 case Xsse_DIVF: *p++ = 0x5E; break;
2651 case Xsse_MAXF: *p++ = 0x5F; break;
2652 case Xsse_MINF: *p++ = 0x5D; break;
sewardj9636b442004-12-04 01:38:37 +00002653 case Xsse_MULF: *p++ = 0x59; break;
sewardj0bd7ce62004-12-05 02:47:40 +00002654 case Xsse_RCPF: *p++ = 0x53; break;
sewardjc1e7dfc2004-12-05 19:29:45 +00002655 case Xsse_RSQRTF: *p++ = 0x52; break;
2656 case Xsse_SQRTF: *p++ = 0x51; break;
2657 case Xsse_SUBF: *p++ = 0x5C; break;
sewardj1e6ad742004-12-02 16:16:11 +00002658 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
2659 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
2660 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00002661 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj1e6ad742004-12-02 16:16:11 +00002662 default: goto bad;
2663 }
sewardjd08f2d72004-12-01 23:19:36 +00002664 p = doAMode_R(p, fake(vregNo(i->Xin.Sse32Fx4.dst)),
2665 fake(vregNo(i->Xin.Sse32Fx4.src)) );
sewardj1e6ad742004-12-02 16:16:11 +00002666 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00002667 *p++ = toUChar(xtra & 0xFF);
sewardj1e6ad742004-12-02 16:16:11 +00002668 goto done;
2669
sewardj636ad762004-12-07 11:16:04 +00002670 case Xin_Sse64Fx2:
2671 xtra = 0;
2672 *p++ = 0x66;
2673 *p++ = 0x0F;
2674 switch (i->Xin.Sse64Fx2.op) {
2675 case Xsse_ADDF: *p++ = 0x58; break;
2676 case Xsse_DIVF: *p++ = 0x5E; break;
2677 case Xsse_MAXF: *p++ = 0x5F; break;
2678 case Xsse_MINF: *p++ = 0x5D; break;
2679 case Xsse_MULF: *p++ = 0x59; break;
2680 case Xsse_RCPF: *p++ = 0x53; break;
2681 case Xsse_RSQRTF: *p++ = 0x52; break;
2682 case Xsse_SQRTF: *p++ = 0x51; break;
2683 case Xsse_SUBF: *p++ = 0x5C; break;
2684 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
2685 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
2686 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00002687 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj636ad762004-12-07 11:16:04 +00002688 default: goto bad;
2689 }
2690 p = doAMode_R(p, fake(vregNo(i->Xin.Sse64Fx2.dst)),
2691 fake(vregNo(i->Xin.Sse64Fx2.src)) );
2692 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00002693 *p++ = toUChar(xtra & 0xFF);
sewardj636ad762004-12-07 11:16:04 +00002694 goto done;
2695
sewardj1e6ad742004-12-02 16:16:11 +00002696 case Xin_Sse32FLo:
2697 xtra = 0;
2698 *p++ = 0xF3;
2699 *p++ = 0x0F;
2700 switch (i->Xin.Sse32FLo.op) {
2701 case Xsse_ADDF: *p++ = 0x58; break;
sewardj176a59c2004-12-03 20:08:31 +00002702 case Xsse_DIVF: *p++ = 0x5E; break;
2703 case Xsse_MAXF: *p++ = 0x5F; break;
2704 case Xsse_MINF: *p++ = 0x5D; break;
sewardj9636b442004-12-04 01:38:37 +00002705 case Xsse_MULF: *p++ = 0x59; break;
sewardj0bd7ce62004-12-05 02:47:40 +00002706 case Xsse_RCPF: *p++ = 0x53; break;
sewardjc1e7dfc2004-12-05 19:29:45 +00002707 case Xsse_RSQRTF: *p++ = 0x52; break;
2708 case Xsse_SQRTF: *p++ = 0x51; break;
2709 case Xsse_SUBF: *p++ = 0x5C; break;
sewardj1e6ad742004-12-02 16:16:11 +00002710 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
2711 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
2712 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00002713 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj1e6ad742004-12-02 16:16:11 +00002714 default: goto bad;
2715 }
2716 p = doAMode_R(p, fake(vregNo(i->Xin.Sse32FLo.dst)),
2717 fake(vregNo(i->Xin.Sse32FLo.src)) );
2718 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00002719 *p++ = toUChar(xtra & 0xFF);
sewardjd08f2d72004-12-01 23:19:36 +00002720 goto done;
2721
sewardj636ad762004-12-07 11:16:04 +00002722 case Xin_Sse64FLo:
2723 xtra = 0;
2724 *p++ = 0xF2;
2725 *p++ = 0x0F;
2726 switch (i->Xin.Sse64FLo.op) {
2727 case Xsse_ADDF: *p++ = 0x58; break;
2728 case Xsse_DIVF: *p++ = 0x5E; break;
2729 case Xsse_MAXF: *p++ = 0x5F; break;
2730 case Xsse_MINF: *p++ = 0x5D; break;
2731 case Xsse_MULF: *p++ = 0x59; break;
2732 case Xsse_RCPF: *p++ = 0x53; break;
2733 case Xsse_RSQRTF: *p++ = 0x52; break;
2734 case Xsse_SQRTF: *p++ = 0x51; break;
2735 case Xsse_SUBF: *p++ = 0x5C; break;
2736 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
2737 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
2738 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00002739 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj636ad762004-12-07 11:16:04 +00002740 default: goto bad;
2741 }
2742 p = doAMode_R(p, fake(vregNo(i->Xin.Sse64FLo.dst)),
2743 fake(vregNo(i->Xin.Sse64FLo.src)) );
2744 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00002745 *p++ = toUChar(xtra & 0xFF);
sewardj636ad762004-12-07 11:16:04 +00002746 goto done;
2747
sewardj164f9272004-12-09 00:39:32 +00002748 case Xin_SseReRg:
2749# define XX(_n) *p++ = (_n)
2750 switch (i->Xin.SseReRg.op) {
sewardj9e203592004-12-10 01:48:18 +00002751 case Xsse_MOV: /*movups*/ XX(0x0F); XX(0x10); break;
2752 case Xsse_OR: XX(0x0F); XX(0x56); break;
2753 case Xsse_XOR: XX(0x0F); XX(0x57); break;
2754 case Xsse_AND: XX(0x0F); XX(0x54); break;
sewardje5854d62004-12-09 03:44:34 +00002755 case Xsse_PACKSSD: XX(0x66); XX(0x0F); XX(0x6B); break;
2756 case Xsse_PACKSSW: XX(0x66); XX(0x0F); XX(0x63); break;
2757 case Xsse_PACKUSW: XX(0x66); XX(0x0F); XX(0x67); break;
2758 case Xsse_ADD8: XX(0x66); XX(0x0F); XX(0xFC); break;
2759 case Xsse_ADD16: XX(0x66); XX(0x0F); XX(0xFD); break;
2760 case Xsse_ADD32: XX(0x66); XX(0x0F); XX(0xFE); break;
2761 case Xsse_ADD64: XX(0x66); XX(0x0F); XX(0xD4); break;
2762 case Xsse_QADD8S: XX(0x66); XX(0x0F); XX(0xEC); break;
2763 case Xsse_QADD16S: XX(0x66); XX(0x0F); XX(0xED); break;
2764 case Xsse_QADD8U: XX(0x66); XX(0x0F); XX(0xDC); break;
2765 case Xsse_QADD16U: XX(0x66); XX(0x0F); XX(0xDD); break;
2766 case Xsse_AVG8U: XX(0x66); XX(0x0F); XX(0xE0); break;
2767 case Xsse_AVG16U: XX(0x66); XX(0x0F); XX(0xE3); break;
2768 case Xsse_CMPEQ8: XX(0x66); XX(0x0F); XX(0x74); break;
2769 case Xsse_CMPEQ16: XX(0x66); XX(0x0F); XX(0x75); break;
2770 case Xsse_CMPEQ32: XX(0x66); XX(0x0F); XX(0x76); break;
2771 case Xsse_CMPGT8S: XX(0x66); XX(0x0F); XX(0x64); break;
2772 case Xsse_CMPGT16S: XX(0x66); XX(0x0F); XX(0x65); break;
2773 case Xsse_CMPGT32S: XX(0x66); XX(0x0F); XX(0x66); break;
2774 case Xsse_MAX16S: XX(0x66); XX(0x0F); XX(0xEE); break;
2775 case Xsse_MAX8U: XX(0x66); XX(0x0F); XX(0xDE); break;
2776 case Xsse_MIN16S: XX(0x66); XX(0x0F); XX(0xEA); break;
2777 case Xsse_MIN8U: XX(0x66); XX(0x0F); XX(0xDA); break;
2778 case Xsse_MULHI16U: XX(0x66); XX(0x0F); XX(0xE4); break;
2779 case Xsse_MULHI16S: XX(0x66); XX(0x0F); XX(0xE5); break;
2780 case Xsse_MUL16: XX(0x66); XX(0x0F); XX(0xD5); break;
sewardjb9fa69b2004-12-09 23:25:14 +00002781 case Xsse_SHL16: XX(0x66); XX(0x0F); XX(0xF1); break;
2782 case Xsse_SHL32: XX(0x66); XX(0x0F); XX(0xF2); break;
2783 case Xsse_SHL64: XX(0x66); XX(0x0F); XX(0xF3); break;
2784 case Xsse_SAR16: XX(0x66); XX(0x0F); XX(0xE1); break;
2785 case Xsse_SAR32: XX(0x66); XX(0x0F); XX(0xE2); break;
2786 case Xsse_SHR16: XX(0x66); XX(0x0F); XX(0xD1); break;
2787 case Xsse_SHR32: XX(0x66); XX(0x0F); XX(0xD2); break;
2788 case Xsse_SHR64: XX(0x66); XX(0x0F); XX(0xD3); break;
2789 case Xsse_SUB8: XX(0x66); XX(0x0F); XX(0xF8); break;
2790 case Xsse_SUB16: XX(0x66); XX(0x0F); XX(0xF9); break;
2791 case Xsse_SUB32: XX(0x66); XX(0x0F); XX(0xFA); break;
2792 case Xsse_SUB64: XX(0x66); XX(0x0F); XX(0xFB); break;
2793 case Xsse_QSUB8S: XX(0x66); XX(0x0F); XX(0xE8); break;
2794 case Xsse_QSUB16S: XX(0x66); XX(0x0F); XX(0xE9); break;
2795 case Xsse_QSUB8U: XX(0x66); XX(0x0F); XX(0xD8); break;
2796 case Xsse_QSUB16U: XX(0x66); XX(0x0F); XX(0xD9); break;
sewardj9e203592004-12-10 01:48:18 +00002797 case Xsse_UNPCKHB: XX(0x66); XX(0x0F); XX(0x68); break;
2798 case Xsse_UNPCKHW: XX(0x66); XX(0x0F); XX(0x69); break;
2799 case Xsse_UNPCKHD: XX(0x66); XX(0x0F); XX(0x6A); break;
2800 case Xsse_UNPCKHQ: XX(0x66); XX(0x0F); XX(0x6D); break;
2801 case Xsse_UNPCKLB: XX(0x66); XX(0x0F); XX(0x60); break;
2802 case Xsse_UNPCKLW: XX(0x66); XX(0x0F); XX(0x61); break;
2803 case Xsse_UNPCKLD: XX(0x66); XX(0x0F); XX(0x62); break;
2804 case Xsse_UNPCKLQ: XX(0x66); XX(0x0F); XX(0x6C); break;
sewardj164f9272004-12-09 00:39:32 +00002805 default: goto bad;
2806 }
2807 p = doAMode_R(p, fake(vregNo(i->Xin.SseReRg.dst)),
2808 fake(vregNo(i->Xin.SseReRg.src)) );
2809# undef XX
2810 goto done;
2811
sewardjb9fa69b2004-12-09 23:25:14 +00002812 case Xin_SseCMov:
2813 /* jmp fwds if !condition */
sewardj8ee8c882005-02-25 17:40:26 +00002814 *p++ = toUChar(0x70 + (i->Xin.SseCMov.cond ^ 1));
sewardjb9fa69b2004-12-09 23:25:14 +00002815 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2816 ptmp = p;
2817
2818 /* movaps %src, %dst */
2819 *p++ = 0x0F;
2820 *p++ = 0x28;
2821 p = doAMode_R(p, fake(vregNo(i->Xin.SseCMov.dst)),
2822 fake(vregNo(i->Xin.SseCMov.src)) );
2823
2824 /* Fill in the jump offset. */
sewardj8ee8c882005-02-25 17:40:26 +00002825 *(ptmp-1) = toUChar(p - ptmp);
sewardjb9fa69b2004-12-09 23:25:14 +00002826 goto done;
2827
sewardj109ffdb2004-12-10 21:45:38 +00002828 case Xin_SseShuf:
2829 *p++ = 0x66;
2830 *p++ = 0x0F;
2831 *p++ = 0x70;
2832 p = doAMode_R(p, fake(vregNo(i->Xin.SseShuf.dst)),
2833 fake(vregNo(i->Xin.SseShuf.src)) );
2834 *p++ = (UChar)(i->Xin.SseShuf.order);
2835 goto done;
2836
sewardjea64e142004-07-22 16:47:21 +00002837 default:
2838 goto bad;
sewardj81bd5502004-07-21 18:49:27 +00002839 }
sewardjea64e142004-07-22 16:47:21 +00002840
2841 bad:
cerion92b64362005-12-13 12:02:26 +00002842 ppX86Instr(i, mode64);
sewardjea64e142004-07-22 16:47:21 +00002843 vpanic("emit_X86Instr");
2844 /*NOTREACHED*/
2845
sewardjbad34a92004-07-22 01:14:11 +00002846 done:
2847 vassert(p - &buf[0] <= 32);
2848 return p - &buf[0];
sewardjea64e142004-07-22 16:47:21 +00002849
sewardjd75fe5a2004-07-23 12:57:47 +00002850# undef fake
sewardj81bd5502004-07-21 18:49:27 +00002851}
2852
sewardj35421a32004-07-05 13:12:34 +00002853/*---------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00002854/*--- end host-x86/hdefs.c ---*/
sewardj35421a32004-07-05 13:12:34 +00002855/*---------------------------------------------------------------*/