blob: ecfaa14744e156e8cee8ebd3f95d0203b84f00bd [file] [log] [blame]
sewardjc97096c2004-06-30 09:28:04 +00001
2/*---------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00003/*--- begin host_x86_defs.c ---*/
sewardjc97096c2004-06-30 09:28:04 +00004/*---------------------------------------------------------------*/
5
sewardjf8ed9d82004-11-12 17:40:23 +00006/*
sewardj752f9062010-05-03 21:38:49 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjf8ed9d82004-11-12 17:40:23 +00009
sewardj25e54732012-08-05 15:36:51 +000010 Copyright (C) 2004-2012 OpenWorks LLP
sewardj752f9062010-05-03 21:38:49 +000011 info@open-works.net
sewardjf8ed9d82004-11-12 17:40:23 +000012
sewardj752f9062010-05-03 21:38:49 +000013 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
sewardjf8ed9d82004-11-12 17:40:23 +000017
sewardj752f9062010-05-03 21:38:49 +000018 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000026 02110-1301, USA.
27
sewardj752f9062010-05-03 21:38:49 +000028 The GNU General Public License is contained in the file COPYING.
sewardjf8ed9d82004-11-12 17:40:23 +000029
30 Neither the names of the U.S. Department of Energy nor the
31 University of California nor the names of its contributors may be
32 used to endorse or promote products derived from this software
33 without prior written permission.
sewardjf8ed9d82004-11-12 17:40:23 +000034*/
35
sewardj887a11a2004-07-05 17:26:47 +000036#include "libvex_basictypes.h"
37#include "libvex.h"
sewardjc4278f42004-11-26 13:18:19 +000038#include "libvex_trc_values.h"
sewardj35421a32004-07-05 13:12:34 +000039
sewardjcef7d3e2009-07-02 12:21:59 +000040#include "main_util.h"
41#include "host_generic_regs.h"
42#include "host_x86_defs.h"
sewardjc97096c2004-06-30 09:28:04 +000043
44
45/* --------- Registers. --------- */
46
sewardj35421a32004-07-05 13:12:34 +000047void ppHRegX86 ( HReg reg )
sewardjc97096c2004-06-30 09:28:04 +000048{
49 Int r;
florian55085f82012-11-21 00:36:55 +000050 static const HChar* ireg32_names[8]
sewardjc97096c2004-06-30 09:28:04 +000051 = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi" };
52 /* Be generic for all virtual regs. */
53 if (hregIsVirtual(reg)) {
sewardj35421a32004-07-05 13:12:34 +000054 ppHReg(reg);
sewardjc97096c2004-06-30 09:28:04 +000055 return;
56 }
57 /* But specific for real regs. */
58 switch (hregClass(reg)) {
sewardj4a31b262004-12-01 02:24:44 +000059 case HRcInt32:
sewardjc97096c2004-06-30 09:28:04 +000060 r = hregNumber(reg);
sewardj35421a32004-07-05 13:12:34 +000061 vassert(r >= 0 && r < 8);
62 vex_printf("%s", ireg32_names[r]);
sewardjc97096c2004-06-30 09:28:04 +000063 return;
sewardj4a31b262004-12-01 02:24:44 +000064 case HRcFlt64:
sewardjc97096c2004-06-30 09:28:04 +000065 r = hregNumber(reg);
sewardjd7bd8ac2004-10-09 10:06:12 +000066 vassert(r >= 0 && r < 6);
sewardj35421a32004-07-05 13:12:34 +000067 vex_printf("%%fake%d", r);
sewardjc97096c2004-06-30 09:28:04 +000068 return;
sewardj4a31b262004-12-01 02:24:44 +000069 case HRcVec128:
sewardjd08f2d72004-12-01 23:19:36 +000070 r = hregNumber(reg);
71 vassert(r >= 0 && r < 8);
72 vex_printf("%%xmm%d", r);
73 return;
74 default:
sewardj35421a32004-07-05 13:12:34 +000075 vpanic("ppHRegX86");
sewardjc97096c2004-06-30 09:28:04 +000076 }
77}
78
sewardj4a31b262004-12-01 02:24:44 +000079HReg hregX86_EAX ( void ) { return mkHReg(0, HRcInt32, False); }
80HReg hregX86_ECX ( void ) { return mkHReg(1, HRcInt32, False); }
81HReg hregX86_EDX ( void ) { return mkHReg(2, HRcInt32, False); }
82HReg hregX86_EBX ( void ) { return mkHReg(3, HRcInt32, False); }
83HReg hregX86_ESP ( void ) { return mkHReg(4, HRcInt32, False); }
84HReg hregX86_EBP ( void ) { return mkHReg(5, HRcInt32, False); }
85HReg hregX86_ESI ( void ) { return mkHReg(6, HRcInt32, False); }
86HReg hregX86_EDI ( void ) { return mkHReg(7, HRcInt32, False); }
sewardjf13a16a2004-07-05 17:10:14 +000087
sewardj4a31b262004-12-01 02:24:44 +000088HReg hregX86_FAKE0 ( void ) { return mkHReg(0, HRcFlt64, False); }
89HReg hregX86_FAKE1 ( void ) { return mkHReg(1, HRcFlt64, False); }
90HReg hregX86_FAKE2 ( void ) { return mkHReg(2, HRcFlt64, False); }
91HReg hregX86_FAKE3 ( void ) { return mkHReg(3, HRcFlt64, False); }
92HReg hregX86_FAKE4 ( void ) { return mkHReg(4, HRcFlt64, False); }
93HReg hregX86_FAKE5 ( void ) { return mkHReg(5, HRcFlt64, False); }
sewardjd1725d12004-08-12 20:46:53 +000094
sewardjd08f2d72004-12-01 23:19:36 +000095HReg hregX86_XMM0 ( void ) { return mkHReg(0, HRcVec128, False); }
96HReg hregX86_XMM1 ( void ) { return mkHReg(1, HRcVec128, False); }
97HReg hregX86_XMM2 ( void ) { return mkHReg(2, HRcVec128, False); }
98HReg hregX86_XMM3 ( void ) { return mkHReg(3, HRcVec128, False); }
99HReg hregX86_XMM4 ( void ) { return mkHReg(4, HRcVec128, False); }
100HReg hregX86_XMM5 ( void ) { return mkHReg(5, HRcVec128, False); }
101HReg hregX86_XMM6 ( void ) { return mkHReg(6, HRcVec128, False); }
102HReg hregX86_XMM7 ( void ) { return mkHReg(7, HRcVec128, False); }
103
104
sewardjf13a16a2004-07-05 17:10:14 +0000105void getAllocableRegs_X86 ( Int* nregs, HReg** arr )
106{
sewardjd08f2d72004-12-01 23:19:36 +0000107 *nregs = 20;
sewardjf13a16a2004-07-05 17:10:14 +0000108 *arr = LibVEX_Alloc(*nregs * sizeof(HReg));
sewardj0a5f5c82004-07-07 11:56:35 +0000109 (*arr)[0] = hregX86_EAX();
110 (*arr)[1] = hregX86_EBX();
111 (*arr)[2] = hregX86_ECX();
112 (*arr)[3] = hregX86_EDX();
113 (*arr)[4] = hregX86_ESI();
114 (*arr)[5] = hregX86_EDI();
sewardjd1725d12004-08-12 20:46:53 +0000115 (*arr)[6] = hregX86_FAKE0();
116 (*arr)[7] = hregX86_FAKE1();
117 (*arr)[8] = hregX86_FAKE2();
118 (*arr)[9] = hregX86_FAKE3();
sewardjeafde5a2004-10-09 01:36:57 +0000119 (*arr)[10] = hregX86_FAKE4();
120 (*arr)[11] = hregX86_FAKE5();
sewardjd08f2d72004-12-01 23:19:36 +0000121 (*arr)[12] = hregX86_XMM0();
122 (*arr)[13] = hregX86_XMM1();
123 (*arr)[14] = hregX86_XMM2();
124 (*arr)[15] = hregX86_XMM3();
125 (*arr)[16] = hregX86_XMM4();
126 (*arr)[17] = hregX86_XMM5();
127 (*arr)[18] = hregX86_XMM6();
128 (*arr)[19] = hregX86_XMM7();
sewardjf13a16a2004-07-05 17:10:14 +0000129}
sewardj53f85a92004-07-02 13:45:17 +0000130
sewardjc97096c2004-06-30 09:28:04 +0000131
sewardj443cd9d2004-07-18 23:06:45 +0000132/* --------- Condition codes, Intel encoding. --------- */
133
florian55085f82012-11-21 00:36:55 +0000134const HChar* showX86CondCode ( X86CondCode cond )
sewardj443cd9d2004-07-18 23:06:45 +0000135{
136 switch (cond) {
sewardj60f4e3c2004-07-19 01:56:50 +0000137 case Xcc_O: return "o";
138 case Xcc_NO: return "no";
139 case Xcc_B: return "b";
140 case Xcc_NB: return "nb";
141 case Xcc_Z: return "z";
142 case Xcc_NZ: return "nz";
143 case Xcc_BE: return "be";
144 case Xcc_NBE: return "nbe";
145 case Xcc_S: return "s";
146 case Xcc_NS: return "ns";
147 case Xcc_P: return "p";
148 case Xcc_NP: return "np";
149 case Xcc_L: return "l";
150 case Xcc_NL: return "nl";
151 case Xcc_LE: return "le";
152 case Xcc_NLE: return "nle";
153 case Xcc_ALWAYS: return "ALWAYS";
sewardj443cd9d2004-07-18 23:06:45 +0000154 default: vpanic("ppX86CondCode");
155 }
156}
157
158
sewardjc97096c2004-06-30 09:28:04 +0000159/* --------- X86AMode: memory address expressions. --------- */
160
161X86AMode* X86AMode_IR ( UInt imm32, HReg reg ) {
sewardj35421a32004-07-05 13:12:34 +0000162 X86AMode* am = LibVEX_Alloc(sizeof(X86AMode));
sewardjc97096c2004-06-30 09:28:04 +0000163 am->tag = Xam_IR;
164 am->Xam.IR.imm = imm32;
165 am->Xam.IR.reg = reg;
166 return am;
167}
sewardj0e63b522004-08-25 13:24:44 +0000168X86AMode* X86AMode_IRRS ( UInt imm32, HReg base, HReg indEx, Int shift ) {
sewardj35421a32004-07-05 13:12:34 +0000169 X86AMode* am = LibVEX_Alloc(sizeof(X86AMode));
sewardjc97096c2004-06-30 09:28:04 +0000170 am->tag = Xam_IRRS;
171 am->Xam.IRRS.imm = imm32;
172 am->Xam.IRRS.base = base;
sewardj0e63b522004-08-25 13:24:44 +0000173 am->Xam.IRRS.index = indEx;
sewardjc97096c2004-06-30 09:28:04 +0000174 am->Xam.IRRS.shift = shift;
sewardj35421a32004-07-05 13:12:34 +0000175 vassert(shift >= 0 && shift <= 3);
sewardjc97096c2004-06-30 09:28:04 +0000176 return am;
177}
178
sewardj218e29f2004-11-07 18:45:15 +0000179X86AMode* dopyX86AMode ( X86AMode* am ) {
180 switch (am->tag) {
181 case Xam_IR:
182 return X86AMode_IR( am->Xam.IR.imm, am->Xam.IR.reg );
183 case Xam_IRRS:
184 return X86AMode_IRRS( am->Xam.IRRS.imm, am->Xam.IRRS.base,
185 am->Xam.IRRS.index, am->Xam.IRRS.shift );
186 default:
187 vpanic("dopyX86AMode");
188 }
189}
190
sewardj35421a32004-07-05 13:12:34 +0000191void ppX86AMode ( X86AMode* am ) {
sewardjc97096c2004-06-30 09:28:04 +0000192 switch (am->tag) {
193 case Xam_IR:
sewardjea64e142004-07-22 16:47:21 +0000194 if (am->Xam.IR.imm == 0)
195 vex_printf("(");
196 else
197 vex_printf("0x%x(", am->Xam.IR.imm);
sewardj35421a32004-07-05 13:12:34 +0000198 ppHRegX86(am->Xam.IR.reg);
199 vex_printf(")");
sewardjc97096c2004-06-30 09:28:04 +0000200 return;
201 case Xam_IRRS:
sewardj35421a32004-07-05 13:12:34 +0000202 vex_printf("0x%x(", am->Xam.IRRS.imm);
203 ppHRegX86(am->Xam.IRRS.base);
204 vex_printf(",");
205 ppHRegX86(am->Xam.IRRS.index);
sewardjea64e142004-07-22 16:47:21 +0000206 vex_printf(",%d)", 1 << am->Xam.IRRS.shift);
sewardjc97096c2004-06-30 09:28:04 +0000207 return;
208 default:
sewardj35421a32004-07-05 13:12:34 +0000209 vpanic("ppX86AMode");
sewardjc97096c2004-06-30 09:28:04 +0000210 }
211}
212
sewardj53f85a92004-07-02 13:45:17 +0000213static void addRegUsage_X86AMode ( HRegUsage* u, X86AMode* am ) {
214 switch (am->tag) {
215 case Xam_IR:
216 addHRegUse(u, HRmRead, am->Xam.IR.reg);
217 return;
218 case Xam_IRRS:
219 addHRegUse(u, HRmRead, am->Xam.IRRS.base);
220 addHRegUse(u, HRmRead, am->Xam.IRRS.index);
221 return;
222 default:
sewardj35421a32004-07-05 13:12:34 +0000223 vpanic("addRegUsage_X86AMode");
sewardj53f85a92004-07-02 13:45:17 +0000224 }
225}
226
227static void mapRegs_X86AMode ( HRegRemap* m, X86AMode* am ) {
228 switch (am->tag) {
229 case Xam_IR:
230 am->Xam.IR.reg = lookupHRegRemap(m, am->Xam.IR.reg);
231 return;
232 case Xam_IRRS:
233 am->Xam.IRRS.base = lookupHRegRemap(m, am->Xam.IRRS.base);
234 am->Xam.IRRS.index = lookupHRegRemap(m, am->Xam.IRRS.index);
235 return;
236 default:
sewardj35421a32004-07-05 13:12:34 +0000237 vpanic("mapRegs_X86AMode");
sewardj53f85a92004-07-02 13:45:17 +0000238 }
239}
sewardjc97096c2004-06-30 09:28:04 +0000240
sewardj66f2f792004-06-30 16:37:16 +0000241/* --------- Operand, which can be reg, immediate or memory. --------- */
sewardjc97096c2004-06-30 09:28:04 +0000242
sewardj66f2f792004-06-30 16:37:16 +0000243X86RMI* X86RMI_Imm ( UInt imm32 ) {
sewardj35421a32004-07-05 13:12:34 +0000244 X86RMI* op = LibVEX_Alloc(sizeof(X86RMI));
sewardj66f2f792004-06-30 16:37:16 +0000245 op->tag = Xrmi_Imm;
246 op->Xrmi.Imm.imm32 = imm32;
sewardjc97096c2004-06-30 09:28:04 +0000247 return op;
248}
sewardj66f2f792004-06-30 16:37:16 +0000249X86RMI* X86RMI_Reg ( HReg reg ) {
sewardj35421a32004-07-05 13:12:34 +0000250 X86RMI* op = LibVEX_Alloc(sizeof(X86RMI));
sewardj66f2f792004-06-30 16:37:16 +0000251 op->tag = Xrmi_Reg;
252 op->Xrmi.Reg.reg = reg;
sewardjc97096c2004-06-30 09:28:04 +0000253 return op;
254}
sewardj66f2f792004-06-30 16:37:16 +0000255X86RMI* X86RMI_Mem ( X86AMode* am ) {
sewardj35421a32004-07-05 13:12:34 +0000256 X86RMI* op = LibVEX_Alloc(sizeof(X86RMI));
sewardj66f2f792004-06-30 16:37:16 +0000257 op->tag = Xrmi_Mem;
258 op->Xrmi.Mem.am = am;
sewardjc97096c2004-06-30 09:28:04 +0000259 return op;
260}
261
sewardj35421a32004-07-05 13:12:34 +0000262void ppX86RMI ( X86RMI* op ) {
sewardjc97096c2004-06-30 09:28:04 +0000263 switch (op->tag) {
sewardj66f2f792004-06-30 16:37:16 +0000264 case Xrmi_Imm:
sewardj35421a32004-07-05 13:12:34 +0000265 vex_printf("$0x%x", op->Xrmi.Imm.imm32);
sewardjc97096c2004-06-30 09:28:04 +0000266 return;
sewardj66f2f792004-06-30 16:37:16 +0000267 case Xrmi_Reg:
sewardj35421a32004-07-05 13:12:34 +0000268 ppHRegX86(op->Xrmi.Reg.reg);
sewardjc97096c2004-06-30 09:28:04 +0000269 return;
sewardj66f2f792004-06-30 16:37:16 +0000270 case Xrmi_Mem:
sewardj35421a32004-07-05 13:12:34 +0000271 ppX86AMode(op->Xrmi.Mem.am);
sewardjc97096c2004-06-30 09:28:04 +0000272 return;
273 default:
sewardj35421a32004-07-05 13:12:34 +0000274 vpanic("ppX86RMI");
sewardj66f2f792004-06-30 16:37:16 +0000275 }
276}
277
sewardj53f85a92004-07-02 13:45:17 +0000278/* An X86RMI can only be used in a "read" context (what would it mean
279 to write or modify a literal?) and so we enumerate its registers
280 accordingly. */
281static void addRegUsage_X86RMI ( HRegUsage* u, X86RMI* op ) {
282 switch (op->tag) {
283 case Xrmi_Imm:
284 return;
285 case Xrmi_Reg:
286 addHRegUse(u, HRmRead, op->Xrmi.Reg.reg);
287 return;
288 case Xrmi_Mem:
289 addRegUsage_X86AMode(u, op->Xrmi.Mem.am);
290 return;
291 default:
sewardj35421a32004-07-05 13:12:34 +0000292 vpanic("addRegUsage_X86RMI");
sewardj53f85a92004-07-02 13:45:17 +0000293 }
294}
295
296static void mapRegs_X86RMI ( HRegRemap* m, X86RMI* op ) {
297 switch (op->tag) {
298 case Xrmi_Imm:
299 return;
300 case Xrmi_Reg:
301 op->Xrmi.Reg.reg = lookupHRegRemap(m, op->Xrmi.Reg.reg);
302 return;
303 case Xrmi_Mem:
304 mapRegs_X86AMode(m, op->Xrmi.Mem.am);
305 return;
306 default:
sewardj35421a32004-07-05 13:12:34 +0000307 vpanic("mapRegs_X86RMI");
sewardj53f85a92004-07-02 13:45:17 +0000308 }
309}
310
sewardj66f2f792004-06-30 16:37:16 +0000311
312/* --------- Operand, which can be reg or immediate only. --------- */
313
314X86RI* X86RI_Imm ( UInt imm32 ) {
sewardj35421a32004-07-05 13:12:34 +0000315 X86RI* op = LibVEX_Alloc(sizeof(X86RI));
sewardj66f2f792004-06-30 16:37:16 +0000316 op->tag = Xri_Imm;
317 op->Xri.Imm.imm32 = imm32;
318 return op;
319}
sewardj66f2f792004-06-30 16:37:16 +0000320X86RI* X86RI_Reg ( HReg reg ) {
sewardj35421a32004-07-05 13:12:34 +0000321 X86RI* op = LibVEX_Alloc(sizeof(X86RI));
sewardj66f2f792004-06-30 16:37:16 +0000322 op->tag = Xri_Reg;
323 op->Xri.Reg.reg = reg;
324 return op;
325}
326
sewardj35421a32004-07-05 13:12:34 +0000327void ppX86RI ( X86RI* op ) {
sewardj66f2f792004-06-30 16:37:16 +0000328 switch (op->tag) {
329 case Xri_Imm:
sewardj35421a32004-07-05 13:12:34 +0000330 vex_printf("$0x%x", op->Xri.Imm.imm32);
sewardj66f2f792004-06-30 16:37:16 +0000331 return;
332 case Xri_Reg:
sewardj35421a32004-07-05 13:12:34 +0000333 ppHRegX86(op->Xri.Reg.reg);
sewardj66f2f792004-06-30 16:37:16 +0000334 return;
335 default:
sewardj35421a32004-07-05 13:12:34 +0000336 vpanic("ppX86RI");
sewardj66f2f792004-06-30 16:37:16 +0000337 }
338}
339
sewardj53f85a92004-07-02 13:45:17 +0000340/* An X86RI can only be used in a "read" context (what would it mean
341 to write or modify a literal?) and so we enumerate its registers
342 accordingly. */
343static void addRegUsage_X86RI ( HRegUsage* u, X86RI* op ) {
344 switch (op->tag) {
345 case Xri_Imm:
346 return;
347 case Xri_Reg:
348 addHRegUse(u, HRmRead, op->Xri.Reg.reg);
349 return;
350 default:
sewardj35421a32004-07-05 13:12:34 +0000351 vpanic("addRegUsage_X86RI");
sewardj53f85a92004-07-02 13:45:17 +0000352 }
353}
354
355static void mapRegs_X86RI ( HRegRemap* m, X86RI* op ) {
356 switch (op->tag) {
357 case Xri_Imm:
358 return;
359 case Xri_Reg:
360 op->Xri.Reg.reg = lookupHRegRemap(m, op->Xri.Reg.reg);
361 return;
362 default:
sewardj35421a32004-07-05 13:12:34 +0000363 vpanic("mapRegs_X86RI");
sewardj53f85a92004-07-02 13:45:17 +0000364 }
365}
366
sewardj66f2f792004-06-30 16:37:16 +0000367
368/* --------- Operand, which can be reg or memory only. --------- */
369
370X86RM* X86RM_Reg ( HReg reg ) {
sewardj35421a32004-07-05 13:12:34 +0000371 X86RM* op = LibVEX_Alloc(sizeof(X86RM));
sewardj66f2f792004-06-30 16:37:16 +0000372 op->tag = Xrm_Reg;
373 op->Xrm.Reg.reg = reg;
374 return op;
375}
sewardj66f2f792004-06-30 16:37:16 +0000376X86RM* X86RM_Mem ( X86AMode* am ) {
sewardj35421a32004-07-05 13:12:34 +0000377 X86RM* op = LibVEX_Alloc(sizeof(X86RM));
sewardj66f2f792004-06-30 16:37:16 +0000378 op->tag = Xrm_Mem;
379 op->Xrm.Mem.am = am;
380 return op;
381}
382
sewardj35421a32004-07-05 13:12:34 +0000383void ppX86RM ( X86RM* op ) {
sewardj66f2f792004-06-30 16:37:16 +0000384 switch (op->tag) {
385 case Xrm_Mem:
sewardj35421a32004-07-05 13:12:34 +0000386 ppX86AMode(op->Xrm.Mem.am);
sewardj66f2f792004-06-30 16:37:16 +0000387 return;
388 case Xrm_Reg:
sewardj35421a32004-07-05 13:12:34 +0000389 ppHRegX86(op->Xrm.Reg.reg);
sewardj66f2f792004-06-30 16:37:16 +0000390 return;
391 default:
sewardj35421a32004-07-05 13:12:34 +0000392 vpanic("ppX86RM");
sewardjc97096c2004-06-30 09:28:04 +0000393 }
394}
395
sewardj53f85a92004-07-02 13:45:17 +0000396/* Because an X86RM can be both a source or destination operand, we
397 have to supply a mode -- pertaining to the operand as a whole --
398 indicating how it's being used. */
399static void addRegUsage_X86RM ( HRegUsage* u, X86RM* op, HRegMode mode ) {
400 switch (op->tag) {
401 case Xrm_Mem:
402 /* Memory is read, written or modified. So we just want to
403 know the regs read by the amode. */
404 addRegUsage_X86AMode(u, op->Xrm.Mem.am);
405 return;
406 case Xrm_Reg:
407 /* reg is read, written or modified. Add it in the
408 appropriate way. */
409 addHRegUse(u, mode, op->Xrm.Reg.reg);
410 return;
411 default:
sewardj35421a32004-07-05 13:12:34 +0000412 vpanic("addRegUsage_X86RM");
sewardj53f85a92004-07-02 13:45:17 +0000413 }
414}
415
416static void mapRegs_X86RM ( HRegRemap* m, X86RM* op )
417{
418 switch (op->tag) {
419 case Xrm_Mem:
420 mapRegs_X86AMode(m, op->Xrm.Mem.am);
421 return;
422 case Xrm_Reg:
423 op->Xrm.Reg.reg = lookupHRegRemap(m, op->Xrm.Reg.reg);
424 return;
425 default:
sewardj35421a32004-07-05 13:12:34 +0000426 vpanic("mapRegs_X86RM");
sewardj53f85a92004-07-02 13:45:17 +0000427 }
428}
429
sewardjc97096c2004-06-30 09:28:04 +0000430
431/* --------- Instructions. --------- */
432
florian55085f82012-11-21 00:36:55 +0000433const HChar* showX86UnaryOp ( X86UnaryOp op ) {
sewardj66f2f792004-06-30 16:37:16 +0000434 switch (op) {
sewardj358b7d42004-11-08 18:54:50 +0000435 case Xun_NOT: return "not";
436 case Xun_NEG: return "neg";
sewardjcfded9a2004-09-09 11:44:16 +0000437 default: vpanic("showX86UnaryOp");
sewardj60f4e3c2004-07-19 01:56:50 +0000438 }
439}
440
florian55085f82012-11-21 00:36:55 +0000441const HChar* showX86AluOp ( X86AluOp op ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000442 switch (op) {
443 case Xalu_MOV: return "mov";
444 case Xalu_CMP: return "cmp";
sewardj60f4e3c2004-07-19 01:56:50 +0000445 case Xalu_ADD: return "add";
446 case Xalu_SUB: return "sub";
447 case Xalu_ADC: return "adc";
448 case Xalu_SBB: return "sbb";
449 case Xalu_AND: return "and";
450 case Xalu_OR: return "or";
451 case Xalu_XOR: return "xor";
452 case Xalu_MUL: return "mul";
sewardjcfded9a2004-09-09 11:44:16 +0000453 default: vpanic("showX86AluOp");
sewardj60f4e3c2004-07-19 01:56:50 +0000454 }
455}
456
florian55085f82012-11-21 00:36:55 +0000457const HChar* showX86ShiftOp ( X86ShiftOp op ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000458 switch (op) {
459 case Xsh_SHL: return "shl";
460 case Xsh_SHR: return "shr";
461 case Xsh_SAR: return "sar";
sewardjcfded9a2004-09-09 11:44:16 +0000462 default: vpanic("showX86ShiftOp");
sewardj66f2f792004-06-30 16:37:16 +0000463 }
sewardj66f2f792004-06-30 16:37:16 +0000464}
465
florian55085f82012-11-21 00:36:55 +0000466const HChar* showX86FpOp ( X86FpOp op ) {
sewardjd1725d12004-08-12 20:46:53 +0000467 switch (op) {
sewardjbb53f8c2004-08-14 11:50:01 +0000468 case Xfp_ADD: return "add";
469 case Xfp_SUB: return "sub";
470 case Xfp_MUL: return "mul";
471 case Xfp_DIV: return "div";
sewardj8d387782004-11-11 02:15:15 +0000472 case Xfp_SCALE: return "scale";
473 case Xfp_ATAN: return "atan";
474 case Xfp_YL2X: return "yl2x";
475 case Xfp_YL2XP1: return "yl2xp1";
476 case Xfp_PREM: return "prem";
477 case Xfp_PREM1: return "prem1";
sewardjbb53f8c2004-08-14 11:50:01 +0000478 case Xfp_SQRT: return "sqrt";
sewardj883b00b2004-09-11 09:30:24 +0000479 case Xfp_ABS: return "abs";
sewardj8d387782004-11-11 02:15:15 +0000480 case Xfp_NEG: return "chs";
sewardjbb53f8c2004-08-14 11:50:01 +0000481 case Xfp_MOV: return "mov";
sewardjcfded9a2004-09-09 11:44:16 +0000482 case Xfp_SIN: return "sin";
483 case Xfp_COS: return "cos";
sewardj99016a72004-10-15 22:09:17 +0000484 case Xfp_TAN: return "tan";
sewardj8d387782004-11-11 02:15:15 +0000485 case Xfp_ROUND: return "round";
sewardj06c32a02004-09-12 12:07:34 +0000486 case Xfp_2XM1: return "2xm1";
sewardjcfded9a2004-09-09 11:44:16 +0000487 default: vpanic("showX86FpOp");
sewardjd1725d12004-08-12 20:46:53 +0000488 }
489}
490
florian55085f82012-11-21 00:36:55 +0000491const HChar* showX86SseOp ( X86SseOp op ) {
sewardjd08f2d72004-12-01 23:19:36 +0000492 switch (op) {
sewardj164f9272004-12-09 00:39:32 +0000493 case Xsse_MOV: return "mov(?!)";
494 case Xsse_ADDF: return "add";
495 case Xsse_SUBF: return "sub";
496 case Xsse_MULF: return "mul";
497 case Xsse_DIVF: return "div";
498 case Xsse_MAXF: return "max";
499 case Xsse_MINF: return "min";
500 case Xsse_CMPEQF: return "cmpFeq";
501 case Xsse_CMPLTF: return "cmpFlt";
502 case Xsse_CMPLEF: return "cmpFle";
503 case Xsse_CMPUNF: return "cmpFun";
504 case Xsse_RCPF: return "rcp";
505 case Xsse_RSQRTF: return "rsqrt";
506 case Xsse_SQRTF: return "sqrt";
507 case Xsse_AND: return "and";
508 case Xsse_OR: return "or";
509 case Xsse_XOR: return "xor";
510 case Xsse_ANDN: return "andn";
511 case Xsse_ADD8: return "paddb";
512 case Xsse_ADD16: return "paddw";
513 case Xsse_ADD32: return "paddd";
514 case Xsse_ADD64: return "paddq";
515 case Xsse_QADD8U: return "paddusb";
516 case Xsse_QADD16U: return "paddusw";
517 case Xsse_QADD8S: return "paddsb";
518 case Xsse_QADD16S: return "paddsw";
519 case Xsse_SUB8: return "psubb";
520 case Xsse_SUB16: return "psubw";
521 case Xsse_SUB32: return "psubd";
522 case Xsse_SUB64: return "psubq";
523 case Xsse_QSUB8U: return "psubusb";
524 case Xsse_QSUB16U: return "psubusw";
525 case Xsse_QSUB8S: return "psubsb";
526 case Xsse_QSUB16S: return "psubsw";
527 case Xsse_MUL16: return "pmullw";
528 case Xsse_MULHI16U: return "pmulhuw";
529 case Xsse_MULHI16S: return "pmulhw";
530 case Xsse_AVG8U: return "pavgb";
531 case Xsse_AVG16U: return "pavgw";
532 case Xsse_MAX16S: return "pmaxw";
533 case Xsse_MAX8U: return "pmaxub";
534 case Xsse_MIN16S: return "pminw";
535 case Xsse_MIN8U: return "pminub";
536 case Xsse_CMPEQ8: return "pcmpeqb";
537 case Xsse_CMPEQ16: return "pcmpeqw";
538 case Xsse_CMPEQ32: return "pcmpeqd";
539 case Xsse_CMPGT8S: return "pcmpgtb";
540 case Xsse_CMPGT16S: return "pcmpgtw";
541 case Xsse_CMPGT32S: return "pcmpgtd";
542 case Xsse_SHL16: return "psllw";
543 case Xsse_SHL32: return "pslld";
544 case Xsse_SHL64: return "psllq";
545 case Xsse_SHR16: return "psrlw";
546 case Xsse_SHR32: return "psrld";
547 case Xsse_SHR64: return "psrlq";
548 case Xsse_SAR16: return "psraw";
549 case Xsse_SAR32: return "psrad";
550 case Xsse_PACKSSD: return "packssdw";
551 case Xsse_PACKSSW: return "packsswb";
552 case Xsse_PACKUSW: return "packuswb";
sewardj9e203592004-12-10 01:48:18 +0000553 case Xsse_UNPCKHB: return "punpckhb";
554 case Xsse_UNPCKHW: return "punpckhw";
555 case Xsse_UNPCKHD: return "punpckhd";
556 case Xsse_UNPCKHQ: return "punpckhq";
557 case Xsse_UNPCKLB: return "punpcklb";
558 case Xsse_UNPCKLW: return "punpcklw";
559 case Xsse_UNPCKLD: return "punpckld";
560 case Xsse_UNPCKLQ: return "punpcklq";
sewardjd08f2d72004-12-01 23:19:36 +0000561 default: vpanic("showX86SseOp");
562 }
563}
564
sewardj66f2f792004-06-30 16:37:16 +0000565X86Instr* X86Instr_Alu32R ( X86AluOp op, X86RMI* src, HReg dst ) {
sewardj35421a32004-07-05 13:12:34 +0000566 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardj66f2f792004-06-30 16:37:16 +0000567 i->tag = Xin_Alu32R;
568 i->Xin.Alu32R.op = op;
569 i->Xin.Alu32R.src = src;
570 i->Xin.Alu32R.dst = dst;
571 return i;
572}
sewardj66f2f792004-06-30 16:37:16 +0000573X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) {
sewardj35421a32004-07-05 13:12:34 +0000574 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardj66f2f792004-06-30 16:37:16 +0000575 i->tag = Xin_Alu32M;
576 i->Xin.Alu32M.op = op;
577 i->Xin.Alu32M.src = src;
578 i->Xin.Alu32M.dst = dst;
sewardje8c922f2004-07-23 01:34:11 +0000579 vassert(op != Xalu_MUL);
580 return i;
581}
sewardjeba63f82005-02-23 13:31:25 +0000582X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, HReg dst ) {
sewardje8c922f2004-07-23 01:34:11 +0000583 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
584 i->tag = Xin_Sh32;
585 i->Xin.Sh32.op = op;
586 i->Xin.Sh32.src = src;
587 i->Xin.Sh32.dst = dst;
588 return i;
589}
sewardjfb7373a2007-08-25 21:29:03 +0000590X86Instr* X86Instr_Test32 ( UInt imm32, X86RM* dst ) {
sewardjeba63f82005-02-23 13:31:25 +0000591 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
592 i->tag = Xin_Test32;
593 i->Xin.Test32.imm32 = imm32;
594 i->Xin.Test32.dst = dst;
sewardj66f2f792004-06-30 16:37:16 +0000595 return i;
596}
sewardjeba63f82005-02-23 13:31:25 +0000597X86Instr* X86Instr_Unary32 ( X86UnaryOp op, HReg dst ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000598 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
599 i->tag = Xin_Unary32;
600 i->Xin.Unary32.op = op;
601 i->Xin.Unary32.dst = dst;
sewardj443cd9d2004-07-18 23:06:45 +0000602 return i;
603}
sewardj79e04f82007-03-31 14:30:12 +0000604X86Instr* X86Instr_Lea32 ( X86AMode* am, HReg dst ) {
605 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
606 i->tag = Xin_Lea32;
607 i->Xin.Lea32.am = am;
608 i->Xin.Lea32.dst = dst;
609 return i;
610}
sewardjeba63f82005-02-23 13:31:25 +0000611X86Instr* X86Instr_MulL ( Bool syned, X86RM* src ) {
sewardj597b71b2004-07-19 02:51:12 +0000612 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
613 i->tag = Xin_MulL;
614 i->Xin.MulL.syned = syned;
sewardj597b71b2004-07-19 02:51:12 +0000615 i->Xin.MulL.src = src;
616 return i;
617}
sewardjeba63f82005-02-23 13:31:25 +0000618X86Instr* X86Instr_Div ( Bool syned, X86RM* src ) {
619 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
620 i->tag = Xin_Div;
621 i->Xin.Div.syned = syned;
622 i->Xin.Div.src = src;
sewardj5c34dc92004-07-19 12:48:11 +0000623 return i;
624}
sewardje5f384c2004-07-30 16:17:28 +0000625X86Instr* X86Instr_Sh3232 ( X86ShiftOp op, UInt amt, HReg src, HReg dst ) {
sewardj5c34dc92004-07-19 12:48:11 +0000626 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
627 i->tag = Xin_Sh3232;
628 i->Xin.Sh3232.op = op;
629 i->Xin.Sh3232.amt = amt;
sewardje5f384c2004-07-30 16:17:28 +0000630 i->Xin.Sh3232.src = src;
631 i->Xin.Sh3232.dst = dst;
sewardj5c34dc92004-07-19 12:48:11 +0000632 vassert(op == Xsh_SHL || op == Xsh_SHR);
633 return i;
634}
sewardje8e9d732004-07-16 21:03:45 +0000635X86Instr* X86Instr_Push( X86RMI* src ) {
sewardj35421a32004-07-05 13:12:34 +0000636 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardje8e9d732004-07-16 21:03:45 +0000637 i->tag = Xin_Push;
638 i->Xin.Push.src = src;
639 return i;
640}
sewardjcfe046e2013-01-17 14:23:53 +0000641X86Instr* X86Instr_Call ( X86CondCode cond, Addr32 target, Int regparms,
642 RetLoc rloc ) {
sewardj77352542004-10-30 20:39:01 +0000643 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
644 i->tag = Xin_Call;
sewardj4b861de2004-11-03 15:24:42 +0000645 i->Xin.Call.cond = cond;
sewardj77352542004-10-30 20:39:01 +0000646 i->Xin.Call.target = target;
647 i->Xin.Call.regparms = regparms;
sewardjcfe046e2013-01-17 14:23:53 +0000648 i->Xin.Call.rloc = rloc;
sewardj77352542004-10-30 20:39:01 +0000649 vassert(regparms >= 0 && regparms <= 3);
sewardjcfe046e2013-01-17 14:23:53 +0000650 vassert(rloc != RetLocINVALID);
sewardje8e9d732004-07-16 21:03:45 +0000651 return i;
652}
sewardjc6f970f2012-04-02 21:54:49 +0000653X86Instr* X86Instr_XDirect ( Addr32 dstGA, X86AMode* amEIP,
654 X86CondCode cond, Bool toFastEP ) {
655 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
656 i->tag = Xin_XDirect;
657 i->Xin.XDirect.dstGA = dstGA;
658 i->Xin.XDirect.amEIP = amEIP;
659 i->Xin.XDirect.cond = cond;
660 i->Xin.XDirect.toFastEP = toFastEP;
661 return i;
662}
663X86Instr* X86Instr_XIndir ( HReg dstGA, X86AMode* amEIP,
664 X86CondCode cond ) {
665 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
666 i->tag = Xin_XIndir;
667 i->Xin.XIndir.dstGA = dstGA;
668 i->Xin.XIndir.amEIP = amEIP;
669 i->Xin.XIndir.cond = cond;
670 return i;
671}
672X86Instr* X86Instr_XAssisted ( HReg dstGA, X86AMode* amEIP,
673 X86CondCode cond, IRJumpKind jk ) {
674 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
675 i->tag = Xin_XAssisted;
676 i->Xin.XAssisted.dstGA = dstGA;
677 i->Xin.XAssisted.amEIP = amEIP;
678 i->Xin.XAssisted.cond = cond;
679 i->Xin.XAssisted.jk = jk;
sewardjc97096c2004-06-30 09:28:04 +0000680 return i;
681}
sewardj5c34dc92004-07-19 12:48:11 +0000682X86Instr* X86Instr_CMov32 ( X86CondCode cond, X86RM* src, HReg dst ) {
683 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
684 i->tag = Xin_CMov32;
685 i->Xin.CMov32.cond = cond;
686 i->Xin.CMov32.src = src;
687 i->Xin.CMov32.dst = dst;
688 vassert(cond != Xcc_ALWAYS);
sewardj4042c7e2004-07-18 01:28:30 +0000689 return i;
690}
sewardj4042c7e2004-07-18 01:28:30 +0000691X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
692 X86AMode* src, HReg dst ) {
693 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
694 i->tag = Xin_LoadEX;
695 i->Xin.LoadEX.szSmall = szSmall;
696 i->Xin.LoadEX.syned = syned;
697 i->Xin.LoadEX.src = src;
698 i->Xin.LoadEX.dst = dst;
699 vassert(szSmall == 1 || szSmall == 2);
700 return i;
701}
sewardjd1725d12004-08-12 20:46:53 +0000702X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ) {
sewardj443cd9d2004-07-18 23:06:45 +0000703 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
704 i->tag = Xin_Store;
705 i->Xin.Store.sz = sz;
706 i->Xin.Store.src = src;
707 i->Xin.Store.dst = dst;
708 vassert(sz == 1 || sz == 2);
709 return i;
710}
sewardjd7cb8532004-08-17 23:59:23 +0000711X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ) {
712 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
713 i->tag = Xin_Set32;
714 i->Xin.Set32.cond = cond;
715 i->Xin.Set32.dst = dst;
716 return i;
717}
sewardjd08f2d72004-12-01 23:19:36 +0000718X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst ) {
sewardjce646f22004-08-31 23:55:54 +0000719 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
720 i->tag = Xin_Bsfr32;
721 i->Xin.Bsfr32.isFwds = isFwds;
722 i->Xin.Bsfr32.src = src;
723 i->Xin.Bsfr32.dst = dst;
724 return i;
725}
sewardje9d8a262009-07-01 08:06:34 +0000726X86Instr* X86Instr_MFence ( UInt hwcaps ) {
sewardj5117ce12006-01-27 21:20:15 +0000727 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
728 i->tag = Xin_MFence;
729 i->Xin.MFence.hwcaps = hwcaps;
sewardj536fbab2010-07-29 15:39:05 +0000730 vassert(0 == (hwcaps & ~(VEX_HWCAPS_X86_SSE1
731 |VEX_HWCAPS_X86_SSE2
732 |VEX_HWCAPS_X86_SSE3
733 |VEX_HWCAPS_X86_LZCNT)));
sewardj3e838932005-01-07 12:09:15 +0000734 return i;
735}
sewardje9d8a262009-07-01 08:06:34 +0000736X86Instr* X86Instr_ACAS ( X86AMode* addr, UChar sz ) {
737 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
738 i->tag = Xin_ACAS;
739 i->Xin.ACAS.addr = addr;
740 i->Xin.ACAS.sz = sz;
741 vassert(sz == 4 || sz == 2 || sz == 1);
742 return i;
743}
744X86Instr* X86Instr_DACAS ( X86AMode* addr ) {
745 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
746 i->tag = Xin_DACAS;
747 i->Xin.DACAS.addr = addr;
748 return i;
749}
sewardj3e838932005-01-07 12:09:15 +0000750
sewardjd1725d12004-08-12 20:46:53 +0000751X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) {
752 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
753 i->tag = Xin_FpUnary;
754 i->Xin.FpUnary.op = op;
755 i->Xin.FpUnary.src = src;
756 i->Xin.FpUnary.dst = dst;
757 return i;
758}
759X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst ) {
760 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
761 i->tag = Xin_FpBinary;
762 i->Xin.FpBinary.op = op;
763 i->Xin.FpBinary.srcL = srcL;
764 i->Xin.FpBinary.srcR = srcR;
765 i->Xin.FpBinary.dst = dst;
766 return i;
767}
768X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* addr ) {
769 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
770 i->tag = Xin_FpLdSt;
771 i->Xin.FpLdSt.isLoad = isLoad;
772 i->Xin.FpLdSt.sz = sz;
773 i->Xin.FpLdSt.reg = reg;
774 i->Xin.FpLdSt.addr = addr;
sewardj7fb65eb2007-03-25 04:14:58 +0000775 vassert(sz == 4 || sz == 8 || sz == 10);
sewardjd1725d12004-08-12 20:46:53 +0000776 return i;
777}
sewardjd08f2d72004-12-01 23:19:36 +0000778X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz,
779 HReg reg, X86AMode* addr ) {
sewardj89cd0932004-09-08 18:23:25 +0000780 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
781 i->tag = Xin_FpLdStI;
782 i->Xin.FpLdStI.isLoad = isLoad;
783 i->Xin.FpLdStI.sz = sz;
784 i->Xin.FpLdStI.reg = reg;
785 i->Xin.FpLdStI.addr = addr;
786 vassert(sz == 2 || sz == 4 || sz == 8);
sewardjd1725d12004-08-12 20:46:53 +0000787 return i;
788}
sewardj3bca9062004-12-04 14:36:09 +0000789X86Instr* X86Instr_Fp64to32 ( HReg src, HReg dst ) {
790 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
791 i->tag = Xin_Fp64to32;
792 i->Xin.Fp64to32.src = src;
793 i->Xin.Fp64to32.dst = dst;
794 return i;
795}
sewardj33124f62004-08-30 17:54:18 +0000796X86Instr* X86Instr_FpCMov ( X86CondCode cond, HReg src, HReg dst ) {
797 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
798 i->tag = Xin_FpCMov;
799 i->Xin.FpCMov.cond = cond;
800 i->Xin.FpCMov.src = src;
801 i->Xin.FpCMov.dst = dst;
802 vassert(cond != Xcc_ALWAYS);
803 return i;
804}
sewardjeba63f82005-02-23 13:31:25 +0000805X86Instr* X86Instr_FpLdCW ( X86AMode* addr ) {
806 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
807 i->tag = Xin_FpLdCW;
808 i->Xin.FpLdCW.addr = addr;
sewardj8f3debf2004-09-08 23:42:23 +0000809 return i;
810}
sewardjd08f2d72004-12-01 23:19:36 +0000811X86Instr* X86Instr_FpStSW_AX ( void ) {
sewardj46de4072004-09-11 19:23:24 +0000812 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
813 i->tag = Xin_FpStSW_AX;
814 return i;
815}
sewardjd08f2d72004-12-01 23:19:36 +0000816X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ) {
sewardjbdc7d212004-09-09 02:46:40 +0000817 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
818 i->tag = Xin_FpCmp;
819 i->Xin.FpCmp.srcL = srcL;
820 i->Xin.FpCmp.srcR = srcR;
821 i->Xin.FpCmp.dst = dst;
822 return i;
823}
sewardj1e6ad742004-12-02 16:16:11 +0000824X86Instr* X86Instr_SseConst ( UShort con, HReg dst ) {
825 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
826 i->tag = Xin_SseConst;
827 i->Xin.SseConst.con = con;
828 i->Xin.SseConst.dst = dst;
829 vassert(hregClass(dst) == HRcVec128);
830 return i;
831}
sewardjd08f2d72004-12-01 23:19:36 +0000832X86Instr* X86Instr_SseLdSt ( Bool isLoad, HReg reg, X86AMode* addr ) {
833 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
834 i->tag = Xin_SseLdSt;
835 i->Xin.SseLdSt.isLoad = isLoad;
836 i->Xin.SseLdSt.reg = reg;
837 i->Xin.SseLdSt.addr = addr;
838 return i;
839}
sewardj129b3d92004-12-05 15:42:05 +0000840X86Instr* X86Instr_SseLdzLO ( Int sz, HReg reg, X86AMode* addr )
841{
842 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
843 i->tag = Xin_SseLdzLO;
sewardj8ee8c882005-02-25 17:40:26 +0000844 i->Xin.SseLdzLO.sz = toUChar(sz);
sewardj129b3d92004-12-05 15:42:05 +0000845 i->Xin.SseLdzLO.reg = reg;
846 i->Xin.SseLdzLO.addr = addr;
847 vassert(sz == 4 || sz == 8);
848 return i;
849}
sewardj636ad762004-12-07 11:16:04 +0000850X86Instr* X86Instr_Sse32Fx4 ( X86SseOp op, HReg src, HReg dst ) {
sewardjd08f2d72004-12-01 23:19:36 +0000851 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
852 i->tag = Xin_Sse32Fx4;
853 i->Xin.Sse32Fx4.op = op;
854 i->Xin.Sse32Fx4.src = src;
855 i->Xin.Sse32Fx4.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000856 vassert(op != Xsse_MOV);
sewardjd08f2d72004-12-01 23:19:36 +0000857 return i;
858}
sewardj636ad762004-12-07 11:16:04 +0000859X86Instr* X86Instr_Sse32FLo ( X86SseOp op, HReg src, HReg dst ) {
sewardjd08f2d72004-12-01 23:19:36 +0000860 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
861 i->tag = Xin_Sse32FLo;
862 i->Xin.Sse32FLo.op = op;
863 i->Xin.Sse32FLo.src = src;
864 i->Xin.Sse32FLo.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000865 vassert(op != Xsse_MOV);
sewardjd08f2d72004-12-01 23:19:36 +0000866 return i;
867}
sewardj636ad762004-12-07 11:16:04 +0000868X86Instr* X86Instr_Sse64Fx2 ( X86SseOp op, HReg src, HReg dst ) {
869 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
870 i->tag = Xin_Sse64Fx2;
871 i->Xin.Sse64Fx2.op = op;
872 i->Xin.Sse64Fx2.src = src;
873 i->Xin.Sse64Fx2.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000874 vassert(op != Xsse_MOV);
sewardj636ad762004-12-07 11:16:04 +0000875 return i;
876}
877X86Instr* X86Instr_Sse64FLo ( X86SseOp op, HReg src, HReg dst ) {
878 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
879 i->tag = Xin_Sse64FLo;
880 i->Xin.Sse64FLo.op = op;
881 i->Xin.Sse64FLo.src = src;
882 i->Xin.Sse64FLo.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000883 vassert(op != Xsse_MOV);
884 return i;
885}
886X86Instr* X86Instr_SseReRg ( X86SseOp op, HReg re, HReg rg ) {
887 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
888 i->tag = Xin_SseReRg;
889 i->Xin.SseReRg.op = op;
890 i->Xin.SseReRg.src = re;
891 i->Xin.SseReRg.dst = rg;
sewardj636ad762004-12-07 11:16:04 +0000892 return i;
893}
sewardjb9fa69b2004-12-09 23:25:14 +0000894X86Instr* X86Instr_SseCMov ( X86CondCode cond, HReg src, HReg dst ) {
895 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
896 i->tag = Xin_SseCMov;
897 i->Xin.SseCMov.cond = cond;
898 i->Xin.SseCMov.src = src;
899 i->Xin.SseCMov.dst = dst;
900 vassert(cond != Xcc_ALWAYS);
901 return i;
902}
sewardj109ffdb2004-12-10 21:45:38 +0000903X86Instr* X86Instr_SseShuf ( Int order, HReg src, HReg dst ) {
904 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
905 i->tag = Xin_SseShuf;
906 i->Xin.SseShuf.order = order;
907 i->Xin.SseShuf.src = src;
908 i->Xin.SseShuf.dst = dst;
909 vassert(order >= 0 && order <= 0xFF);
910 return i;
911}
sewardjc6f970f2012-04-02 21:54:49 +0000912X86Instr* X86Instr_EvCheck ( X86AMode* amCounter,
913 X86AMode* amFailAddr ) {
914 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
915 i->tag = Xin_EvCheck;
916 i->Xin.EvCheck.amCounter = amCounter;
917 i->Xin.EvCheck.amFailAddr = amFailAddr;
918 return i;
919}
920X86Instr* X86Instr_ProfInc ( void ) {
921 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
922 i->tag = Xin_ProfInc;
923 return i;
924}
sewardj4042c7e2004-07-18 01:28:30 +0000925
cerion92b64362005-12-13 12:02:26 +0000926void ppX86Instr ( X86Instr* i, Bool mode64 ) {
927 vassert(mode64 == False);
sewardjc97096c2004-06-30 09:28:04 +0000928 switch (i->tag) {
sewardj66f2f792004-06-30 16:37:16 +0000929 case Xin_Alu32R:
sewardj60f4e3c2004-07-19 01:56:50 +0000930 vex_printf("%sl ", showX86AluOp(i->Xin.Alu32R.op));
sewardj35421a32004-07-05 13:12:34 +0000931 ppX86RMI(i->Xin.Alu32R.src);
932 vex_printf(",");
933 ppHRegX86(i->Xin.Alu32R.dst);
sewardjc97096c2004-06-30 09:28:04 +0000934 return;
sewardj66f2f792004-06-30 16:37:16 +0000935 case Xin_Alu32M:
sewardj60f4e3c2004-07-19 01:56:50 +0000936 vex_printf("%sl ", showX86AluOp(i->Xin.Alu32M.op));
sewardj35421a32004-07-05 13:12:34 +0000937 ppX86RI(i->Xin.Alu32M.src);
938 vex_printf(",");
939 ppX86AMode(i->Xin.Alu32M.dst);
sewardjc97096c2004-06-30 09:28:04 +0000940 return;
sewardje8c922f2004-07-23 01:34:11 +0000941 case Xin_Sh32:
942 vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op));
943 if (i->Xin.Sh32.src == 0)
sewardjbb53f8c2004-08-14 11:50:01 +0000944 vex_printf("%%cl,");
sewardje8c922f2004-07-23 01:34:11 +0000945 else
sewardj8ee8c882005-02-25 17:40:26 +0000946 vex_printf("$%d,", (Int)i->Xin.Sh32.src);
sewardjeba63f82005-02-23 13:31:25 +0000947 ppHRegX86(i->Xin.Sh32.dst);
sewardje8c922f2004-07-23 01:34:11 +0000948 return;
949 case Xin_Test32:
sewardj8ee8c882005-02-25 17:40:26 +0000950 vex_printf("testl $%d,", (Int)i->Xin.Test32.imm32);
sewardjfb7373a2007-08-25 21:29:03 +0000951 ppX86RM(i->Xin.Test32.dst);
sewardje8c922f2004-07-23 01:34:11 +0000952 return;
sewardj60f4e3c2004-07-19 01:56:50 +0000953 case Xin_Unary32:
954 vex_printf("%sl ", showX86UnaryOp(i->Xin.Unary32.op));
sewardjeba63f82005-02-23 13:31:25 +0000955 ppHRegX86(i->Xin.Unary32.dst);
sewardj443cd9d2004-07-18 23:06:45 +0000956 return;
sewardj79e04f82007-03-31 14:30:12 +0000957 case Xin_Lea32:
958 vex_printf("leal ");
959 ppX86AMode(i->Xin.Lea32.am);
960 vex_printf(",");
961 ppHRegX86(i->Xin.Lea32.dst);
962 return;
sewardj597b71b2004-07-19 02:51:12 +0000963 case Xin_MulL:
sewardjeba63f82005-02-23 13:31:25 +0000964 vex_printf("%cmull ", i->Xin.MulL.syned ? 's' : 'u');
sewardj597b71b2004-07-19 02:51:12 +0000965 ppX86RM(i->Xin.MulL.src);
966 return;
sewardj5c34dc92004-07-19 12:48:11 +0000967 case Xin_Div:
sewardjeba63f82005-02-23 13:31:25 +0000968 vex_printf("%cdivl ", i->Xin.Div.syned ? 's' : 'u');
sewardj5c34dc92004-07-19 12:48:11 +0000969 ppX86RM(i->Xin.Div.src);
970 return;
sewardj5c34dc92004-07-19 12:48:11 +0000971 case Xin_Sh3232:
972 vex_printf("%sdl ", showX86ShiftOp(i->Xin.Sh3232.op));
973 if (i->Xin.Sh3232.amt == 0)
sewardjea64e142004-07-22 16:47:21 +0000974 vex_printf(" %%cl,");
sewardj5c34dc92004-07-19 12:48:11 +0000975 else
sewardj8ee8c882005-02-25 17:40:26 +0000976 vex_printf(" $%d,", (Int)i->Xin.Sh3232.amt);
sewardje5f384c2004-07-30 16:17:28 +0000977 ppHRegX86(i->Xin.Sh3232.src);
sewardj5c34dc92004-07-19 12:48:11 +0000978 vex_printf(",");
sewardje5f384c2004-07-30 16:17:28 +0000979 ppHRegX86(i->Xin.Sh3232.dst);
sewardj5c34dc92004-07-19 12:48:11 +0000980 return;
sewardje8e9d732004-07-16 21:03:45 +0000981 case Xin_Push:
982 vex_printf("pushl ");
983 ppX86RMI(i->Xin.Push.src);
984 return;
985 case Xin_Call:
sewardjcfe046e2013-01-17 14:23:53 +0000986 vex_printf("call%s[%d,",
sewardj4b861de2004-11-03 15:24:42 +0000987 i->Xin.Call.cond==Xcc_ALWAYS
988 ? "" : showX86CondCode(i->Xin.Call.cond),
989 i->Xin.Call.regparms);
sewardjcfe046e2013-01-17 14:23:53 +0000990 ppRetLoc(i->Xin.Call.rloc);
991 vex_printf("] 0x%x", i->Xin.Call.target);
sewardje8e9d732004-07-16 21:03:45 +0000992 break;
sewardjc6f970f2012-04-02 21:54:49 +0000993 case Xin_XDirect:
994 vex_printf("(xDirect) ");
995 vex_printf("if (%%eflags.%s) { ",
996 showX86CondCode(i->Xin.XDirect.cond));
997 vex_printf("movl $0x%x,", i->Xin.XDirect.dstGA);
998 ppX86AMode(i->Xin.XDirect.amEIP);
999 vex_printf("; ");
1000 vex_printf("movl $disp_cp_chain_me_to_%sEP,%%edx; call *%%edx }",
1001 i->Xin.XDirect.toFastEP ? "fast" : "slow");
1002 return;
1003 case Xin_XIndir:
1004 vex_printf("(xIndir) ");
1005 vex_printf("if (%%eflags.%s) { movl ",
1006 showX86CondCode(i->Xin.XIndir.cond));
1007 ppHRegX86(i->Xin.XIndir.dstGA);
1008 vex_printf(",");
1009 ppX86AMode(i->Xin.XIndir.amEIP);
1010 vex_printf("; movl $disp_indir,%%edx; jmp *%%edx }");
1011 return;
1012 case Xin_XAssisted:
1013 vex_printf("(xAssisted) ");
1014 vex_printf("if (%%eflags.%s) { ",
1015 showX86CondCode(i->Xin.XAssisted.cond));
sewardj893aada2004-11-29 19:57:54 +00001016 vex_printf("movl ");
sewardjc6f970f2012-04-02 21:54:49 +00001017 ppHRegX86(i->Xin.XAssisted.dstGA);
1018 vex_printf(",");
1019 ppX86AMode(i->Xin.XAssisted.amEIP);
1020 vex_printf("; movl $IRJumpKind_to_TRCVAL(%d),%%ebp",
1021 (Int)i->Xin.XAssisted.jk);
1022 vex_printf("; movl $disp_assisted,%%edx; jmp *%%edx }");
sewardjc97096c2004-06-30 09:28:04 +00001023 return;
sewardj5c34dc92004-07-19 12:48:11 +00001024 case Xin_CMov32:
sewardja2dad5c2004-07-23 11:43:43 +00001025 vex_printf("cmov%s ", showX86CondCode(i->Xin.CMov32.cond));
sewardj5c34dc92004-07-19 12:48:11 +00001026 ppX86RM(i->Xin.CMov32.src);
sewardj4042c7e2004-07-18 01:28:30 +00001027 vex_printf(",");
sewardj5c34dc92004-07-19 12:48:11 +00001028 ppHRegX86(i->Xin.CMov32.dst);
sewardj4042c7e2004-07-18 01:28:30 +00001029 return;
1030 case Xin_LoadEX:
1031 vex_printf("mov%c%cl ",
1032 i->Xin.LoadEX.syned ? 's' : 'z',
1033 i->Xin.LoadEX.szSmall==1 ? 'b' : 'w');
1034 ppX86AMode(i->Xin.LoadEX.src);
1035 vex_printf(",");
1036 ppHRegX86(i->Xin.LoadEX.dst);
1037 return;
sewardj443cd9d2004-07-18 23:06:45 +00001038 case Xin_Store:
1039 vex_printf("mov%c ", i->Xin.Store.sz==1 ? 'b' : 'w');
1040 ppHRegX86(i->Xin.Store.src);
1041 vex_printf(",");
1042 ppX86AMode(i->Xin.Store.dst);
1043 return;
sewardjd7cb8532004-08-17 23:59:23 +00001044 case Xin_Set32:
1045 vex_printf("setl%s ", showX86CondCode(i->Xin.Set32.cond));
1046 ppHRegX86(i->Xin.Set32.dst);
1047 return;
sewardjce646f22004-08-31 23:55:54 +00001048 case Xin_Bsfr32:
1049 vex_printf("bs%cl ", i->Xin.Bsfr32.isFwds ? 'f' : 'r');
1050 ppHRegX86(i->Xin.Bsfr32.src);
1051 vex_printf(",");
1052 ppHRegX86(i->Xin.Bsfr32.dst);
1053 return;
sewardj3e838932005-01-07 12:09:15 +00001054 case Xin_MFence:
1055 vex_printf("mfence(%s)",
sewardj5117ce12006-01-27 21:20:15 +00001056 LibVEX_ppVexHwCaps(VexArchX86,i->Xin.MFence.hwcaps));
sewardj3e838932005-01-07 12:09:15 +00001057 return;
sewardje9d8a262009-07-01 08:06:34 +00001058 case Xin_ACAS:
1059 vex_printf("lock cmpxchg%c ",
1060 i->Xin.ACAS.sz==1 ? 'b'
1061 : i->Xin.ACAS.sz==2 ? 'w' : 'l');
1062 vex_printf("{%%eax->%%ebx},");
1063 ppX86AMode(i->Xin.ACAS.addr);
1064 return;
1065 case Xin_DACAS:
1066 vex_printf("lock cmpxchg8b {%%edx:%%eax->%%ecx:%%ebx},");
1067 ppX86AMode(i->Xin.DACAS.addr);
1068 return;
sewardjbb53f8c2004-08-14 11:50:01 +00001069 case Xin_FpUnary:
1070 vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op));
1071 ppHRegX86(i->Xin.FpUnary.src);
1072 vex_printf(",");
1073 ppHRegX86(i->Xin.FpUnary.dst);
1074 break;
1075 case Xin_FpBinary:
1076 vex_printf("g%sD ", showX86FpOp(i->Xin.FpBinary.op));
1077 ppHRegX86(i->Xin.FpBinary.srcL);
1078 vex_printf(",");
1079 ppHRegX86(i->Xin.FpBinary.srcR);
1080 vex_printf(",");
1081 ppHRegX86(i->Xin.FpBinary.dst);
1082 break;
sewardjd1725d12004-08-12 20:46:53 +00001083 case Xin_FpLdSt:
1084 if (i->Xin.FpLdSt.isLoad) {
sewardj7fb65eb2007-03-25 04:14:58 +00001085 vex_printf("gld%c " , i->Xin.FpLdSt.sz==10 ? 'T'
1086 : (i->Xin.FpLdSt.sz==8 ? 'D' : 'F'));
sewardjd1725d12004-08-12 20:46:53 +00001087 ppX86AMode(i->Xin.FpLdSt.addr);
1088 vex_printf(", ");
1089 ppHRegX86(i->Xin.FpLdSt.reg);
1090 } else {
sewardj7fb65eb2007-03-25 04:14:58 +00001091 vex_printf("gst%c " , i->Xin.FpLdSt.sz==10 ? 'T'
1092 : (i->Xin.FpLdSt.sz==8 ? 'D' : 'F'));
sewardjd1725d12004-08-12 20:46:53 +00001093 ppHRegX86(i->Xin.FpLdSt.reg);
1094 vex_printf(", ");
1095 ppX86AMode(i->Xin.FpLdSt.addr);
1096 }
1097 return;
sewardj89cd0932004-09-08 18:23:25 +00001098 case Xin_FpLdStI:
1099 if (i->Xin.FpLdStI.isLoad) {
1100 vex_printf("gild%s ", i->Xin.FpLdStI.sz==8 ? "ll" :
1101 i->Xin.FpLdStI.sz==4 ? "l" : "w");
1102 ppX86AMode(i->Xin.FpLdStI.addr);
sewardjbb53f8c2004-08-14 11:50:01 +00001103 vex_printf(", ");
sewardj89cd0932004-09-08 18:23:25 +00001104 ppHRegX86(i->Xin.FpLdStI.reg);
1105 } else {
1106 vex_printf("gist%s ", i->Xin.FpLdStI.sz==8 ? "ll" :
1107 i->Xin.FpLdStI.sz==4 ? "l" : "w");
1108 ppHRegX86(i->Xin.FpLdStI.reg);
1109 vex_printf(", ");
1110 ppX86AMode(i->Xin.FpLdStI.addr);
sewardjbb53f8c2004-08-14 11:50:01 +00001111 }
1112 return;
sewardj3bca9062004-12-04 14:36:09 +00001113 case Xin_Fp64to32:
1114 vex_printf("gdtof ");
1115 ppHRegX86(i->Xin.Fp64to32.src);
1116 vex_printf(",");
1117 ppHRegX86(i->Xin.Fp64to32.dst);
1118 return;
sewardj33124f62004-08-30 17:54:18 +00001119 case Xin_FpCMov:
1120 vex_printf("gcmov%s ", showX86CondCode(i->Xin.FpCMov.cond));
1121 ppHRegX86(i->Xin.FpCMov.src);
1122 vex_printf(",");
1123 ppHRegX86(i->Xin.FpCMov.dst);
1124 return;
sewardjeba63f82005-02-23 13:31:25 +00001125 case Xin_FpLdCW:
1126 vex_printf("fldcw ");
1127 ppX86AMode(i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00001128 return;
sewardj46de4072004-09-11 19:23:24 +00001129 case Xin_FpStSW_AX:
1130 vex_printf("fstsw %%ax");
1131 return;
sewardjbdc7d212004-09-09 02:46:40 +00001132 case Xin_FpCmp:
1133 vex_printf("gcmp ");
1134 ppHRegX86(i->Xin.FpCmp.srcL);
1135 vex_printf(",");
1136 ppHRegX86(i->Xin.FpCmp.srcR);
1137 vex_printf(",");
1138 ppHRegX86(i->Xin.FpCmp.dst);
1139 break;
sewardj1e6ad742004-12-02 16:16:11 +00001140 case Xin_SseConst:
1141 vex_printf("const $0x%04x,", (Int)i->Xin.SseConst.con);
1142 ppHRegX86(i->Xin.SseConst.dst);
1143 break;
sewardjd08f2d72004-12-01 23:19:36 +00001144 case Xin_SseLdSt:
1145 vex_printf("movups ");
1146 if (i->Xin.SseLdSt.isLoad) {
1147 ppX86AMode(i->Xin.SseLdSt.addr);
1148 vex_printf(",");
1149 ppHRegX86(i->Xin.SseLdSt.reg);
1150 } else {
1151 ppHRegX86(i->Xin.SseLdSt.reg);
1152 vex_printf(",");
1153 ppX86AMode(i->Xin.SseLdSt.addr);
1154 }
1155 return;
sewardj129b3d92004-12-05 15:42:05 +00001156 case Xin_SseLdzLO:
1157 vex_printf("movs%s ", i->Xin.SseLdzLO.sz==4 ? "s" : "d");
1158 ppX86AMode(i->Xin.SseLdzLO.addr);
1159 vex_printf(",");
1160 ppHRegX86(i->Xin.SseLdzLO.reg);
1161 return;
sewardjd08f2d72004-12-01 23:19:36 +00001162 case Xin_Sse32Fx4:
1163 vex_printf("%sps ", showX86SseOp(i->Xin.Sse32Fx4.op));
1164 ppHRegX86(i->Xin.Sse32Fx4.src);
1165 vex_printf(",");
1166 ppHRegX86(i->Xin.Sse32Fx4.dst);
1167 return;
1168 case Xin_Sse32FLo:
1169 vex_printf("%sss ", showX86SseOp(i->Xin.Sse32FLo.op));
1170 ppHRegX86(i->Xin.Sse32FLo.src);
1171 vex_printf(",");
1172 ppHRegX86(i->Xin.Sse32FLo.dst);
1173 return;
sewardj636ad762004-12-07 11:16:04 +00001174 case Xin_Sse64Fx2:
1175 vex_printf("%spd ", showX86SseOp(i->Xin.Sse64Fx2.op));
1176 ppHRegX86(i->Xin.Sse64Fx2.src);
1177 vex_printf(",");
1178 ppHRegX86(i->Xin.Sse64Fx2.dst);
1179 return;
1180 case Xin_Sse64FLo:
1181 vex_printf("%ssd ", showX86SseOp(i->Xin.Sse64FLo.op));
1182 ppHRegX86(i->Xin.Sse64FLo.src);
1183 vex_printf(",");
1184 ppHRegX86(i->Xin.Sse64FLo.dst);
1185 return;
sewardj164f9272004-12-09 00:39:32 +00001186 case Xin_SseReRg:
1187 vex_printf("%s ", showX86SseOp(i->Xin.SseReRg.op));
1188 ppHRegX86(i->Xin.SseReRg.src);
1189 vex_printf(",");
1190 ppHRegX86(i->Xin.SseReRg.dst);
1191 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001192 case Xin_SseCMov:
1193 vex_printf("cmov%s ", showX86CondCode(i->Xin.SseCMov.cond));
1194 ppHRegX86(i->Xin.SseCMov.src);
1195 vex_printf(",");
1196 ppHRegX86(i->Xin.SseCMov.dst);
1197 return;
sewardj109ffdb2004-12-10 21:45:38 +00001198 case Xin_SseShuf:
1199 vex_printf("pshufd $0x%x,", i->Xin.SseShuf.order);
1200 ppHRegX86(i->Xin.SseShuf.src);
1201 vex_printf(",");
1202 ppHRegX86(i->Xin.SseShuf.dst);
1203 return;
sewardjc6f970f2012-04-02 21:54:49 +00001204 case Xin_EvCheck:
1205 vex_printf("(evCheck) decl ");
1206 ppX86AMode(i->Xin.EvCheck.amCounter);
1207 vex_printf("; jns nofail; jmp *");
1208 ppX86AMode(i->Xin.EvCheck.amFailAddr);
1209 vex_printf("; nofail:");
1210 return;
1211 case Xin_ProfInc:
1212 vex_printf("(profInc) addl $1,NotKnownYet; "
1213 "adcl $0,NotKnownYet+4");
1214 return;
sewardjc97096c2004-06-30 09:28:04 +00001215 default:
sewardj35421a32004-07-05 13:12:34 +00001216 vpanic("ppX86Instr");
sewardjc97096c2004-06-30 09:28:04 +00001217 }
1218}
sewardj53f85a92004-07-02 13:45:17 +00001219
sewardj194d54a2004-07-03 19:08:18 +00001220/* --------- Helpers for register allocation. --------- */
1221
cerion92b64362005-12-13 12:02:26 +00001222void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i, Bool mode64)
sewardj53f85a92004-07-02 13:45:17 +00001223{
sewardj0bd7ce62004-12-05 02:47:40 +00001224 Bool unary;
cerion92b64362005-12-13 12:02:26 +00001225 vassert(mode64 == False);
sewardj53f85a92004-07-02 13:45:17 +00001226 initHRegUsage(u);
1227 switch (i->tag) {
1228 case Xin_Alu32R:
1229 addRegUsage_X86RMI(u, i->Xin.Alu32R.src);
sewardj4042c7e2004-07-18 01:28:30 +00001230 if (i->Xin.Alu32R.op == Xalu_MOV) {
sewardjeba63f82005-02-23 13:31:25 +00001231 addHRegUse(u, HRmWrite, i->Xin.Alu32R.dst);
sewardj4042c7e2004-07-18 01:28:30 +00001232 return;
1233 }
sewardje8c922f2004-07-23 01:34:11 +00001234 if (i->Xin.Alu32R.op == Xalu_CMP) {
sewardjeba63f82005-02-23 13:31:25 +00001235 addHRegUse(u, HRmRead, i->Xin.Alu32R.dst);
sewardj4042c7e2004-07-18 01:28:30 +00001236 return;
1237 }
1238 addHRegUse(u, HRmModify, i->Xin.Alu32R.dst);
sewardj53f85a92004-07-02 13:45:17 +00001239 return;
1240 case Xin_Alu32M:
1241 addRegUsage_X86RI(u, i->Xin.Alu32M.src);
1242 addRegUsage_X86AMode(u, i->Xin.Alu32M.dst);
1243 return;
sewardje8c922f2004-07-23 01:34:11 +00001244 case Xin_Sh32:
sewardjeba63f82005-02-23 13:31:25 +00001245 addHRegUse(u, HRmModify, i->Xin.Sh32.dst);
sewardje8c922f2004-07-23 01:34:11 +00001246 if (i->Xin.Sh32.src == 0)
1247 addHRegUse(u, HRmRead, hregX86_ECX());
1248 return;
1249 case Xin_Test32:
sewardjfb7373a2007-08-25 21:29:03 +00001250 addRegUsage_X86RM(u, i->Xin.Test32.dst, HRmRead);
sewardje8c922f2004-07-23 01:34:11 +00001251 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001252 case Xin_Unary32:
sewardjeba63f82005-02-23 13:31:25 +00001253 addHRegUse(u, HRmModify, i->Xin.Unary32.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001254 return;
sewardj79e04f82007-03-31 14:30:12 +00001255 case Xin_Lea32:
1256 addRegUsage_X86AMode(u, i->Xin.Lea32.am);
1257 addHRegUse(u, HRmWrite, i->Xin.Lea32.dst);
1258 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001259 case Xin_MulL:
1260 addRegUsage_X86RM(u, i->Xin.MulL.src, HRmRead);
1261 addHRegUse(u, HRmModify, hregX86_EAX());
1262 addHRegUse(u, HRmWrite, hregX86_EDX());
1263 return;
1264 case Xin_Div:
sewardjea64e142004-07-22 16:47:21 +00001265 addRegUsage_X86RM(u, i->Xin.Div.src, HRmRead);
sewardj1f40a0a2004-07-21 12:28:07 +00001266 addHRegUse(u, HRmModify, hregX86_EAX());
1267 addHRegUse(u, HRmModify, hregX86_EDX());
1268 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001269 case Xin_Sh3232:
sewardje5f384c2004-07-30 16:17:28 +00001270 addHRegUse(u, HRmRead, i->Xin.Sh3232.src);
1271 addHRegUse(u, HRmModify, i->Xin.Sh3232.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001272 if (i->Xin.Sh3232.amt == 0)
1273 addHRegUse(u, HRmRead, hregX86_ECX());
1274 return;
sewardje8e9d732004-07-16 21:03:45 +00001275 case Xin_Push:
1276 addRegUsage_X86RMI(u, i->Xin.Push.src);
1277 addHRegUse(u, HRmModify, hregX86_ESP());
1278 return;
1279 case Xin_Call:
sewardj4b861de2004-11-03 15:24:42 +00001280 /* This is a bit subtle. */
sewardjcdcf00b2005-02-04 01:40:03 +00001281 /* First off, claim it trashes all the caller-saved regs
1282 which fall within the register allocator's jurisdiction.
sewardj9e341ca2009-07-22 11:06:17 +00001283 These I believe to be %eax %ecx %edx and all the xmm
1284 registers. */
sewardje8e9d732004-07-16 21:03:45 +00001285 addHRegUse(u, HRmWrite, hregX86_EAX());
1286 addHRegUse(u, HRmWrite, hregX86_ECX());
1287 addHRegUse(u, HRmWrite, hregX86_EDX());
sewardj9e341ca2009-07-22 11:06:17 +00001288 addHRegUse(u, HRmWrite, hregX86_XMM0());
1289 addHRegUse(u, HRmWrite, hregX86_XMM1());
1290 addHRegUse(u, HRmWrite, hregX86_XMM2());
1291 addHRegUse(u, HRmWrite, hregX86_XMM3());
1292 addHRegUse(u, HRmWrite, hregX86_XMM4());
1293 addHRegUse(u, HRmWrite, hregX86_XMM5());
1294 addHRegUse(u, HRmWrite, hregX86_XMM6());
1295 addHRegUse(u, HRmWrite, hregX86_XMM7());
sewardj4b861de2004-11-03 15:24:42 +00001296 /* Now we have to state any parameter-carrying registers
1297 which might be read. This depends on the regparmness. */
sewardj77352542004-10-30 20:39:01 +00001298 switch (i->Xin.Call.regparms) {
1299 case 3: addHRegUse(u, HRmRead, hregX86_ECX()); /*fallthru*/
1300 case 2: addHRegUse(u, HRmRead, hregX86_EDX()); /*fallthru*/
1301 case 1: addHRegUse(u, HRmRead, hregX86_EAX()); break;
1302 case 0: break;
1303 default: vpanic("getRegUsage_X86Instr:Call:regparms");
1304 }
sewardj4b861de2004-11-03 15:24:42 +00001305 /* Finally, there is the issue that the insn trashes a
1306 register because the literal target address has to be
1307 loaded into a register. Fortunately, for the 0/1/2
sewardj45c50eb2004-11-04 18:25:33 +00001308 regparm case, we can use EAX, EDX and ECX respectively, so
sewardj4b861de2004-11-03 15:24:42 +00001309 this does not cause any further damage. For the 3-regparm
1310 case, we'll have to choose another register arbitrarily --
sewardj45c50eb2004-11-04 18:25:33 +00001311 since A, D and C are used for parameters -- and so we might
sewardj4b861de2004-11-03 15:24:42 +00001312 as well choose EDI. */
1313 if (i->Xin.Call.regparms == 3)
1314 addHRegUse(u, HRmWrite, hregX86_EDI());
1315 /* Upshot of this is that the assembler really must observe
1316 the here-stated convention of which register to use as an
1317 address temporary, depending on the regparmness: 0==EAX,
sewardj45c50eb2004-11-04 18:25:33 +00001318 1==EDX, 2==ECX, 3==EDI. */
sewardje8e9d732004-07-16 21:03:45 +00001319 return;
sewardjc6f970f2012-04-02 21:54:49 +00001320 /* XDirect/XIndir/XAssisted are also a bit subtle. They
1321 conditionally exit the block. Hence we only need to list (1)
1322 the registers that they read, and (2) the registers that they
1323 write in the case where the block is not exited. (2) is
1324 empty, hence only (1) is relevant here. */
1325 case Xin_XDirect:
1326 addRegUsage_X86AMode(u, i->Xin.XDirect.amEIP);
1327 return;
1328 case Xin_XIndir:
1329 addHRegUse(u, HRmRead, i->Xin.XIndir.dstGA);
1330 addRegUsage_X86AMode(u, i->Xin.XIndir.amEIP);
1331 return;
1332 case Xin_XAssisted:
1333 addHRegUse(u, HRmRead, i->Xin.XAssisted.dstGA);
1334 addRegUsage_X86AMode(u, i->Xin.XAssisted.amEIP);
sewardj0ec33252004-07-03 13:30:00 +00001335 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001336 case Xin_CMov32:
1337 addRegUsage_X86RM(u, i->Xin.CMov32.src, HRmRead);
1338 addHRegUse(u, HRmModify, i->Xin.CMov32.dst);
1339 return;
1340 case Xin_LoadEX:
1341 addRegUsage_X86AMode(u, i->Xin.LoadEX.src);
1342 addHRegUse(u, HRmWrite, i->Xin.LoadEX.dst);
1343 return;
1344 case Xin_Store:
1345 addHRegUse(u, HRmRead, i->Xin.Store.src);
1346 addRegUsage_X86AMode(u, i->Xin.Store.dst);
1347 return;
sewardjd7cb8532004-08-17 23:59:23 +00001348 case Xin_Set32:
1349 addHRegUse(u, HRmWrite, i->Xin.Set32.dst);
1350 return;
sewardjce646f22004-08-31 23:55:54 +00001351 case Xin_Bsfr32:
1352 addHRegUse(u, HRmRead, i->Xin.Bsfr32.src);
1353 addHRegUse(u, HRmWrite, i->Xin.Bsfr32.dst);
1354 return;
sewardj3e838932005-01-07 12:09:15 +00001355 case Xin_MFence:
1356 return;
sewardje9d8a262009-07-01 08:06:34 +00001357 case Xin_ACAS:
1358 addRegUsage_X86AMode(u, i->Xin.ACAS.addr);
1359 addHRegUse(u, HRmRead, hregX86_EBX());
1360 addHRegUse(u, HRmModify, hregX86_EAX());
1361 return;
1362 case Xin_DACAS:
1363 addRegUsage_X86AMode(u, i->Xin.DACAS.addr);
1364 addHRegUse(u, HRmRead, hregX86_ECX());
1365 addHRegUse(u, HRmRead, hregX86_EBX());
1366 addHRegUse(u, HRmModify, hregX86_EDX());
1367 addHRegUse(u, HRmModify, hregX86_EAX());
1368 return;
sewardjbb53f8c2004-08-14 11:50:01 +00001369 case Xin_FpUnary:
1370 addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
1371 addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
1372 return;
1373 case Xin_FpBinary:
1374 addHRegUse(u, HRmRead, i->Xin.FpBinary.srcL);
1375 addHRegUse(u, HRmRead, i->Xin.FpBinary.srcR);
1376 addHRegUse(u, HRmWrite, i->Xin.FpBinary.dst);
1377 return;
sewardj3196daf2004-08-13 00:18:58 +00001378 case Xin_FpLdSt:
1379 addRegUsage_X86AMode(u, i->Xin.FpLdSt.addr);
1380 addHRegUse(u, i->Xin.FpLdSt.isLoad ? HRmWrite : HRmRead,
1381 i->Xin.FpLdSt.reg);
1382 return;
sewardj89cd0932004-09-08 18:23:25 +00001383 case Xin_FpLdStI:
1384 addRegUsage_X86AMode(u, i->Xin.FpLdStI.addr);
1385 addHRegUse(u, i->Xin.FpLdStI.isLoad ? HRmWrite : HRmRead,
1386 i->Xin.FpLdStI.reg);
sewardjbb53f8c2004-08-14 11:50:01 +00001387 return;
sewardj3bca9062004-12-04 14:36:09 +00001388 case Xin_Fp64to32:
1389 addHRegUse(u, HRmRead, i->Xin.Fp64to32.src);
1390 addHRegUse(u, HRmWrite, i->Xin.Fp64to32.dst);
1391 return;
sewardj3fc76d22004-08-31 11:47:54 +00001392 case Xin_FpCMov:
sewardjb9fa69b2004-12-09 23:25:14 +00001393 addHRegUse(u, HRmRead, i->Xin.FpCMov.src);
sewardj3fc76d22004-08-31 11:47:54 +00001394 addHRegUse(u, HRmModify, i->Xin.FpCMov.dst);
1395 return;
sewardjeba63f82005-02-23 13:31:25 +00001396 case Xin_FpLdCW:
1397 addRegUsage_X86AMode(u, i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00001398 return;
sewardj46de4072004-09-11 19:23:24 +00001399 case Xin_FpStSW_AX:
1400 addHRegUse(u, HRmWrite, hregX86_EAX());
1401 return;
sewardjbdc7d212004-09-09 02:46:40 +00001402 case Xin_FpCmp:
1403 addHRegUse(u, HRmRead, i->Xin.FpCmp.srcL);
1404 addHRegUse(u, HRmRead, i->Xin.FpCmp.srcR);
1405 addHRegUse(u, HRmWrite, i->Xin.FpCmp.dst);
1406 addHRegUse(u, HRmWrite, hregX86_EAX());
1407 return;
sewardjd08f2d72004-12-01 23:19:36 +00001408 case Xin_SseLdSt:
1409 addRegUsage_X86AMode(u, i->Xin.SseLdSt.addr);
1410 addHRegUse(u, i->Xin.SseLdSt.isLoad ? HRmWrite : HRmRead,
1411 i->Xin.SseLdSt.reg);
1412 return;
sewardj129b3d92004-12-05 15:42:05 +00001413 case Xin_SseLdzLO:
1414 addRegUsage_X86AMode(u, i->Xin.SseLdzLO.addr);
1415 addHRegUse(u, HRmWrite, i->Xin.SseLdzLO.reg);
1416 return;
sewardj1e6ad742004-12-02 16:16:11 +00001417 case Xin_SseConst:
1418 addHRegUse(u, HRmWrite, i->Xin.SseConst.dst);
1419 return;
sewardjd08f2d72004-12-01 23:19:36 +00001420 case Xin_Sse32Fx4:
1421 vassert(i->Xin.Sse32Fx4.op != Xsse_MOV);
sewardj8ee8c882005-02-25 17:40:26 +00001422 unary = toBool( i->Xin.Sse32Fx4.op == Xsse_RCPF
1423 || i->Xin.Sse32Fx4.op == Xsse_RSQRTF
1424 || i->Xin.Sse32Fx4.op == Xsse_SQRTF );
sewardj0bd7ce62004-12-05 02:47:40 +00001425 addHRegUse(u, HRmRead, i->Xin.Sse32Fx4.src);
1426 addHRegUse(u, unary ? HRmWrite : HRmModify,
1427 i->Xin.Sse32Fx4.dst);
sewardjd08f2d72004-12-01 23:19:36 +00001428 return;
sewardj1e6ad742004-12-02 16:16:11 +00001429 case Xin_Sse32FLo:
1430 vassert(i->Xin.Sse32FLo.op != Xsse_MOV);
sewardj8ee8c882005-02-25 17:40:26 +00001431 unary = toBool( i->Xin.Sse32FLo.op == Xsse_RCPF
1432 || i->Xin.Sse32FLo.op == Xsse_RSQRTF
1433 || i->Xin.Sse32FLo.op == Xsse_SQRTF );
sewardj0bd7ce62004-12-05 02:47:40 +00001434 addHRegUse(u, HRmRead, i->Xin.Sse32FLo.src);
1435 addHRegUse(u, unary ? HRmWrite : HRmModify,
1436 i->Xin.Sse32FLo.dst);
sewardj1e6ad742004-12-02 16:16:11 +00001437 return;
sewardj636ad762004-12-07 11:16:04 +00001438 case Xin_Sse64Fx2:
1439 vassert(i->Xin.Sse64Fx2.op != Xsse_MOV);
sewardj8ee8c882005-02-25 17:40:26 +00001440 unary = toBool( i->Xin.Sse64Fx2.op == Xsse_RCPF
1441 || i->Xin.Sse64Fx2.op == Xsse_RSQRTF
1442 || i->Xin.Sse64Fx2.op == Xsse_SQRTF );
sewardj636ad762004-12-07 11:16:04 +00001443 addHRegUse(u, HRmRead, i->Xin.Sse64Fx2.src);
1444 addHRegUse(u, unary ? HRmWrite : HRmModify,
1445 i->Xin.Sse64Fx2.dst);
1446 return;
1447 case Xin_Sse64FLo:
1448 vassert(i->Xin.Sse64FLo.op != Xsse_MOV);
sewardj8ee8c882005-02-25 17:40:26 +00001449 unary = toBool( i->Xin.Sse64FLo.op == Xsse_RCPF
1450 || i->Xin.Sse64FLo.op == Xsse_RSQRTF
1451 || i->Xin.Sse64FLo.op == Xsse_SQRTF );
sewardj636ad762004-12-07 11:16:04 +00001452 addHRegUse(u, HRmRead, i->Xin.Sse64FLo.src);
1453 addHRegUse(u, unary ? HRmWrite : HRmModify,
1454 i->Xin.Sse64FLo.dst);
1455 return;
sewardj164f9272004-12-09 00:39:32 +00001456 case Xin_SseReRg:
sewardj109ffdb2004-12-10 21:45:38 +00001457 if (i->Xin.SseReRg.op == Xsse_XOR
1458 && i->Xin.SseReRg.src == i->Xin.SseReRg.dst) {
1459 /* reg-alloc needs to understand 'xor r,r' as a write of r */
1460 /* (as opposed to a rite of passage :-) */
1461 addHRegUse(u, HRmWrite, i->Xin.SseReRg.dst);
1462 } else {
1463 addHRegUse(u, HRmRead, i->Xin.SseReRg.src);
1464 addHRegUse(u, i->Xin.SseReRg.op == Xsse_MOV
1465 ? HRmWrite : HRmModify,
1466 i->Xin.SseReRg.dst);
1467 }
sewardj164f9272004-12-09 00:39:32 +00001468 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001469 case Xin_SseCMov:
1470 addHRegUse(u, HRmRead, i->Xin.SseCMov.src);
1471 addHRegUse(u, HRmModify, i->Xin.SseCMov.dst);
1472 return;
sewardj109ffdb2004-12-10 21:45:38 +00001473 case Xin_SseShuf:
1474 addHRegUse(u, HRmRead, i->Xin.SseShuf.src);
1475 addHRegUse(u, HRmWrite, i->Xin.SseShuf.dst);
1476 return;
sewardjc6f970f2012-04-02 21:54:49 +00001477 case Xin_EvCheck:
1478 /* We expect both amodes only to mention %ebp, so this is in
1479 fact pointless, since %ebp isn't allocatable, but anyway.. */
1480 addRegUsage_X86AMode(u, i->Xin.EvCheck.amCounter);
1481 addRegUsage_X86AMode(u, i->Xin.EvCheck.amFailAddr);
1482 return;
1483 case Xin_ProfInc:
1484 /* does not use any registers. */
1485 return;
sewardj53f85a92004-07-02 13:45:17 +00001486 default:
cerion92b64362005-12-13 12:02:26 +00001487 ppX86Instr(i, False);
sewardj35421a32004-07-05 13:12:34 +00001488 vpanic("getRegUsage_X86Instr");
sewardj53f85a92004-07-02 13:45:17 +00001489 }
1490}
1491
sewardj1f40a0a2004-07-21 12:28:07 +00001492/* local helper */
cerion92b64362005-12-13 12:02:26 +00001493static void mapReg( HRegRemap* m, HReg* r )
sewardj1f40a0a2004-07-21 12:28:07 +00001494{
1495 *r = lookupHRegRemap(m, *r);
1496}
1497
cerion92b64362005-12-13 12:02:26 +00001498void mapRegs_X86Instr ( HRegRemap* m, X86Instr* i, Bool mode64 )
sewardj53f85a92004-07-02 13:45:17 +00001499{
cerion92b64362005-12-13 12:02:26 +00001500 vassert(mode64 == False);
sewardj53f85a92004-07-02 13:45:17 +00001501 switch (i->tag) {
1502 case Xin_Alu32R:
1503 mapRegs_X86RMI(m, i->Xin.Alu32R.src);
sewardj1f40a0a2004-07-21 12:28:07 +00001504 mapReg(m, &i->Xin.Alu32R.dst);
sewardj53f85a92004-07-02 13:45:17 +00001505 return;
1506 case Xin_Alu32M:
1507 mapRegs_X86RI(m, i->Xin.Alu32M.src);
1508 mapRegs_X86AMode(m, i->Xin.Alu32M.dst);
1509 return;
sewardje8c922f2004-07-23 01:34:11 +00001510 case Xin_Sh32:
sewardjeba63f82005-02-23 13:31:25 +00001511 mapReg(m, &i->Xin.Sh32.dst);
sewardje8c922f2004-07-23 01:34:11 +00001512 return;
1513 case Xin_Test32:
sewardjfb7373a2007-08-25 21:29:03 +00001514 mapRegs_X86RM(m, i->Xin.Test32.dst);
sewardje8c922f2004-07-23 01:34:11 +00001515 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001516 case Xin_Unary32:
sewardjeba63f82005-02-23 13:31:25 +00001517 mapReg(m, &i->Xin.Unary32.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001518 return;
sewardj79e04f82007-03-31 14:30:12 +00001519 case Xin_Lea32:
1520 mapRegs_X86AMode(m, i->Xin.Lea32.am);
1521 mapReg(m, &i->Xin.Lea32.dst);
1522 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001523 case Xin_MulL:
1524 mapRegs_X86RM(m, i->Xin.MulL.src);
1525 return;
1526 case Xin_Div:
sewardjea64e142004-07-22 16:47:21 +00001527 mapRegs_X86RM(m, i->Xin.Div.src);
sewardj1f40a0a2004-07-21 12:28:07 +00001528 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001529 case Xin_Sh3232:
sewardje5f384c2004-07-30 16:17:28 +00001530 mapReg(m, &i->Xin.Sh3232.src);
1531 mapReg(m, &i->Xin.Sh3232.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001532 return;
1533 case Xin_Push:
1534 mapRegs_X86RMI(m, i->Xin.Push.src);
1535 return;
1536 case Xin_Call:
sewardj1f40a0a2004-07-21 12:28:07 +00001537 return;
sewardjc6f970f2012-04-02 21:54:49 +00001538 case Xin_XDirect:
1539 mapRegs_X86AMode(m, i->Xin.XDirect.amEIP);
1540 return;
1541 case Xin_XIndir:
1542 mapReg(m, &i->Xin.XIndir.dstGA);
1543 mapRegs_X86AMode(m, i->Xin.XIndir.amEIP);
1544 return;
1545 case Xin_XAssisted:
1546 mapReg(m, &i->Xin.XAssisted.dstGA);
1547 mapRegs_X86AMode(m, i->Xin.XAssisted.amEIP);
sewardj0ec33252004-07-03 13:30:00 +00001548 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001549 case Xin_CMov32:
1550 mapRegs_X86RM(m, i->Xin.CMov32.src);
1551 mapReg(m, &i->Xin.CMov32.dst);
1552 return;
1553 case Xin_LoadEX:
1554 mapRegs_X86AMode(m, i->Xin.LoadEX.src);
1555 mapReg(m, &i->Xin.LoadEX.dst);
1556 return;
1557 case Xin_Store:
1558 mapReg(m, &i->Xin.Store.src);
1559 mapRegs_X86AMode(m, i->Xin.Store.dst);
1560 return;
sewardjd7cb8532004-08-17 23:59:23 +00001561 case Xin_Set32:
1562 mapReg(m, &i->Xin.Set32.dst);
1563 return;
sewardjce646f22004-08-31 23:55:54 +00001564 case Xin_Bsfr32:
1565 mapReg(m, &i->Xin.Bsfr32.src);
1566 mapReg(m, &i->Xin.Bsfr32.dst);
1567 return;
sewardj3e838932005-01-07 12:09:15 +00001568 case Xin_MFence:
1569 return;
sewardje9d8a262009-07-01 08:06:34 +00001570 case Xin_ACAS:
1571 mapRegs_X86AMode(m, i->Xin.ACAS.addr);
1572 return;
1573 case Xin_DACAS:
1574 mapRegs_X86AMode(m, i->Xin.DACAS.addr);
1575 return;
sewardjcfded9a2004-09-09 11:44:16 +00001576 case Xin_FpUnary:
1577 mapReg(m, &i->Xin.FpUnary.src);
1578 mapReg(m, &i->Xin.FpUnary.dst);
1579 return;
sewardjbb53f8c2004-08-14 11:50:01 +00001580 case Xin_FpBinary:
1581 mapReg(m, &i->Xin.FpBinary.srcL);
1582 mapReg(m, &i->Xin.FpBinary.srcR);
1583 mapReg(m, &i->Xin.FpBinary.dst);
1584 return;
sewardj3196daf2004-08-13 00:18:58 +00001585 case Xin_FpLdSt:
1586 mapRegs_X86AMode(m, i->Xin.FpLdSt.addr);
1587 mapReg(m, &i->Xin.FpLdSt.reg);
1588 return;
sewardj89cd0932004-09-08 18:23:25 +00001589 case Xin_FpLdStI:
1590 mapRegs_X86AMode(m, i->Xin.FpLdStI.addr);
1591 mapReg(m, &i->Xin.FpLdStI.reg);
sewardjbb53f8c2004-08-14 11:50:01 +00001592 return;
sewardj3bca9062004-12-04 14:36:09 +00001593 case Xin_Fp64to32:
1594 mapReg(m, &i->Xin.Fp64to32.src);
1595 mapReg(m, &i->Xin.Fp64to32.dst);
1596 return;
sewardj3fc76d22004-08-31 11:47:54 +00001597 case Xin_FpCMov:
1598 mapReg(m, &i->Xin.FpCMov.src);
1599 mapReg(m, &i->Xin.FpCMov.dst);
1600 return;
sewardjeba63f82005-02-23 13:31:25 +00001601 case Xin_FpLdCW:
1602 mapRegs_X86AMode(m, i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00001603 return;
sewardj46de4072004-09-11 19:23:24 +00001604 case Xin_FpStSW_AX:
1605 return;
sewardjbdc7d212004-09-09 02:46:40 +00001606 case Xin_FpCmp:
1607 mapReg(m, &i->Xin.FpCmp.srcL);
1608 mapReg(m, &i->Xin.FpCmp.srcR);
1609 mapReg(m, &i->Xin.FpCmp.dst);
1610 return;
sewardj1e6ad742004-12-02 16:16:11 +00001611 case Xin_SseConst:
1612 mapReg(m, &i->Xin.SseConst.dst);
1613 return;
sewardjd08f2d72004-12-01 23:19:36 +00001614 case Xin_SseLdSt:
1615 mapReg(m, &i->Xin.SseLdSt.reg);
1616 mapRegs_X86AMode(m, i->Xin.SseLdSt.addr);
1617 break;
sewardj129b3d92004-12-05 15:42:05 +00001618 case Xin_SseLdzLO:
1619 mapReg(m, &i->Xin.SseLdzLO.reg);
1620 mapRegs_X86AMode(m, i->Xin.SseLdzLO.addr);
1621 break;
sewardjd08f2d72004-12-01 23:19:36 +00001622 case Xin_Sse32Fx4:
1623 mapReg(m, &i->Xin.Sse32Fx4.src);
1624 mapReg(m, &i->Xin.Sse32Fx4.dst);
1625 return;
sewardj1e6ad742004-12-02 16:16:11 +00001626 case Xin_Sse32FLo:
1627 mapReg(m, &i->Xin.Sse32FLo.src);
1628 mapReg(m, &i->Xin.Sse32FLo.dst);
1629 return;
sewardj636ad762004-12-07 11:16:04 +00001630 case Xin_Sse64Fx2:
1631 mapReg(m, &i->Xin.Sse64Fx2.src);
1632 mapReg(m, &i->Xin.Sse64Fx2.dst);
1633 return;
1634 case Xin_Sse64FLo:
1635 mapReg(m, &i->Xin.Sse64FLo.src);
1636 mapReg(m, &i->Xin.Sse64FLo.dst);
1637 return;
sewardj164f9272004-12-09 00:39:32 +00001638 case Xin_SseReRg:
1639 mapReg(m, &i->Xin.SseReRg.src);
1640 mapReg(m, &i->Xin.SseReRg.dst);
1641 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001642 case Xin_SseCMov:
1643 mapReg(m, &i->Xin.SseCMov.src);
1644 mapReg(m, &i->Xin.SseCMov.dst);
1645 return;
sewardj109ffdb2004-12-10 21:45:38 +00001646 case Xin_SseShuf:
1647 mapReg(m, &i->Xin.SseShuf.src);
1648 mapReg(m, &i->Xin.SseShuf.dst);
1649 return;
sewardjc6f970f2012-04-02 21:54:49 +00001650 case Xin_EvCheck:
1651 /* We expect both amodes only to mention %ebp, so this is in
1652 fact pointless, since %ebp isn't allocatable, but anyway.. */
1653 mapRegs_X86AMode(m, i->Xin.EvCheck.amCounter);
1654 mapRegs_X86AMode(m, i->Xin.EvCheck.amFailAddr);
1655 return;
1656 case Xin_ProfInc:
1657 /* does not use any registers. */
1658 return;
1659
sewardj53f85a92004-07-02 13:45:17 +00001660 default:
cerion92b64362005-12-13 12:02:26 +00001661 ppX86Instr(i, mode64);
sewardj35421a32004-07-05 13:12:34 +00001662 vpanic("mapRegs_X86Instr");
sewardj53f85a92004-07-02 13:45:17 +00001663 }
1664}
1665
sewardjbb53f8c2004-08-14 11:50:01 +00001666/* Figure out if i represents a reg-reg move, and if so assign the
1667 source and destination to *src and *dst. If in doubt say No. Used
1668 by the register allocator to do move coalescing.
1669*/
sewardja9a0cd22004-07-03 14:49:41 +00001670Bool isMove_X86Instr ( X86Instr* i, HReg* src, HReg* dst )
1671{
sewardjbb53f8c2004-08-14 11:50:01 +00001672 /* Moves between integer regs */
1673 if (i->tag == Xin_Alu32R) {
1674 if (i->Xin.Alu32R.op != Xalu_MOV)
1675 return False;
1676 if (i->Xin.Alu32R.src->tag != Xrmi_Reg)
1677 return False;
1678 *src = i->Xin.Alu32R.src->Xrmi.Reg.reg;
1679 *dst = i->Xin.Alu32R.dst;
1680 return True;
1681 }
1682 /* Moves between FP regs */
1683 if (i->tag == Xin_FpUnary) {
1684 if (i->Xin.FpUnary.op != Xfp_MOV)
1685 return False;
1686 *src = i->Xin.FpUnary.src;
1687 *dst = i->Xin.FpUnary.dst;
1688 return True;
1689 }
sewardj9e203592004-12-10 01:48:18 +00001690 if (i->tag == Xin_SseReRg) {
1691 if (i->Xin.SseReRg.op != Xsse_MOV)
sewardjd08f2d72004-12-01 23:19:36 +00001692 return False;
sewardj9e203592004-12-10 01:48:18 +00001693 *src = i->Xin.SseReRg.src;
1694 *dst = i->Xin.SseReRg.dst;
sewardjd08f2d72004-12-01 23:19:36 +00001695 return True;
1696 }
sewardjbb53f8c2004-08-14 11:50:01 +00001697 return False;
sewardja9a0cd22004-07-03 14:49:41 +00001698}
sewardj194d54a2004-07-03 19:08:18 +00001699
sewardjbb53f8c2004-08-14 11:50:01 +00001700
sewardj81ec4182004-10-25 23:15:52 +00001701/* Generate x86 spill/reload instructions under the direction of the
sewardj4b861de2004-11-03 15:24:42 +00001702 register allocator. Note it's critical these don't write the
1703 condition codes. */
sewardj14731f22004-07-25 01:24:28 +00001704
sewardj2a1ed8e2009-12-31 19:26:03 +00001705void genSpill_X86 ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
1706 HReg rreg, Int offsetB, Bool mode64 )
sewardj194d54a2004-07-03 19:08:18 +00001707{
sewardj3f57c2d2004-10-04 09:14:05 +00001708 X86AMode* am;
sewardj81ec4182004-10-25 23:15:52 +00001709 vassert(offsetB >= 0);
sewardj35421a32004-07-05 13:12:34 +00001710 vassert(!hregIsVirtual(rreg));
cerion92b64362005-12-13 12:02:26 +00001711 vassert(mode64 == False);
sewardj2a1ed8e2009-12-31 19:26:03 +00001712 *i1 = *i2 = NULL;
sewardj81ec4182004-10-25 23:15:52 +00001713 am = X86AMode_IR(offsetB, hregX86_EBP());
sewardj194d54a2004-07-03 19:08:18 +00001714 switch (hregClass(rreg)) {
sewardj4a31b262004-12-01 02:24:44 +00001715 case HRcInt32:
sewardj2a1ed8e2009-12-31 19:26:03 +00001716 *i1 = X86Instr_Alu32M ( Xalu_MOV, X86RI_Reg(rreg), am );
1717 return;
sewardj4a31b262004-12-01 02:24:44 +00001718 case HRcFlt64:
sewardj2a1ed8e2009-12-31 19:26:03 +00001719 *i1 = X86Instr_FpLdSt ( False/*store*/, 10, rreg, am );
1720 return;
sewardj9ee82862004-12-14 01:16:59 +00001721 case HRcVec128:
sewardj2a1ed8e2009-12-31 19:26:03 +00001722 *i1 = X86Instr_SseLdSt ( False/*store*/, rreg, am );
1723 return;
sewardj194d54a2004-07-03 19:08:18 +00001724 default:
sewardj35421a32004-07-05 13:12:34 +00001725 ppHRegClass(hregClass(rreg));
1726 vpanic("genSpill_X86: unimplemented regclass");
sewardj194d54a2004-07-03 19:08:18 +00001727 }
1728}
1729
sewardj2a1ed8e2009-12-31 19:26:03 +00001730void genReload_X86 ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
1731 HReg rreg, Int offsetB, Bool mode64 )
sewardj194d54a2004-07-03 19:08:18 +00001732{
sewardj3f57c2d2004-10-04 09:14:05 +00001733 X86AMode* am;
sewardj81ec4182004-10-25 23:15:52 +00001734 vassert(offsetB >= 0);
sewardj35421a32004-07-05 13:12:34 +00001735 vassert(!hregIsVirtual(rreg));
cerion92b64362005-12-13 12:02:26 +00001736 vassert(mode64 == False);
sewardj2a1ed8e2009-12-31 19:26:03 +00001737 *i1 = *i2 = NULL;
sewardj81ec4182004-10-25 23:15:52 +00001738 am = X86AMode_IR(offsetB, hregX86_EBP());
sewardj194d54a2004-07-03 19:08:18 +00001739 switch (hregClass(rreg)) {
sewardj4a31b262004-12-01 02:24:44 +00001740 case HRcInt32:
sewardj2a1ed8e2009-12-31 19:26:03 +00001741 *i1 = X86Instr_Alu32R ( Xalu_MOV, X86RMI_Mem(am), rreg );
1742 return;
sewardj4a31b262004-12-01 02:24:44 +00001743 case HRcFlt64:
sewardj2a1ed8e2009-12-31 19:26:03 +00001744 *i1 = X86Instr_FpLdSt ( True/*load*/, 10, rreg, am );
1745 return;
sewardj9ee82862004-12-14 01:16:59 +00001746 case HRcVec128:
sewardj2a1ed8e2009-12-31 19:26:03 +00001747 *i1 = X86Instr_SseLdSt ( True/*load*/, rreg, am );
1748 return;
sewardj194d54a2004-07-03 19:08:18 +00001749 default:
sewardj35421a32004-07-05 13:12:34 +00001750 ppHRegClass(hregClass(rreg));
1751 vpanic("genReload_X86: unimplemented regclass");
sewardj194d54a2004-07-03 19:08:18 +00001752 }
1753}
sewardj35421a32004-07-05 13:12:34 +00001754
sewardjfb7373a2007-08-25 21:29:03 +00001755/* The given instruction reads the specified vreg exactly once, and
1756 that vreg is currently located at the given spill offset. If
sewardjeb17e492007-08-25 23:07:44 +00001757 possible, return a variant of the instruction to one which instead
sewardjfb7373a2007-08-25 21:29:03 +00001758 references the spill slot directly. */
1759
1760X86Instr* directReload_X86( X86Instr* i, HReg vreg, Short spill_off )
1761{
1762 vassert(spill_off >= 0 && spill_off < 10000); /* let's say */
1763
1764 /* Deal with form: src=RMI_Reg, dst=Reg where src == vreg
1765 Convert to: src=RMI_Mem, dst=Reg
1766 */
1767 if (i->tag == Xin_Alu32R
1768 && (i->Xin.Alu32R.op == Xalu_MOV || i->Xin.Alu32R.op == Xalu_OR
1769 || i->Xin.Alu32R.op == Xalu_XOR)
1770 && i->Xin.Alu32R.src->tag == Xrmi_Reg
1771 && i->Xin.Alu32R.src->Xrmi.Reg.reg == vreg) {
1772 vassert(i->Xin.Alu32R.dst != vreg);
1773 return X86Instr_Alu32R(
1774 i->Xin.Alu32R.op,
1775 X86RMI_Mem( X86AMode_IR( spill_off, hregX86_EBP())),
1776 i->Xin.Alu32R.dst
1777 );
1778 }
1779
1780 /* Deal with form: src=RMI_Imm, dst=Reg where dst == vreg
1781 Convert to: src=RI_Imm, dst=Mem
1782 */
1783 if (i->tag == Xin_Alu32R
1784 && (i->Xin.Alu32R.op == Xalu_CMP)
1785 && i->Xin.Alu32R.src->tag == Xrmi_Imm
1786 && i->Xin.Alu32R.dst == vreg) {
1787 return X86Instr_Alu32M(
1788 i->Xin.Alu32R.op,
1789 X86RI_Imm( i->Xin.Alu32R.src->Xrmi.Imm.imm32 ),
1790 X86AMode_IR( spill_off, hregX86_EBP())
1791 );
1792 }
1793
1794 /* Deal with form: Push(RMI_Reg)
1795 Convert to: Push(RMI_Mem)
1796 */
1797 if (i->tag == Xin_Push
1798 && i->Xin.Push.src->tag == Xrmi_Reg
1799 && i->Xin.Push.src->Xrmi.Reg.reg == vreg) {
1800 return X86Instr_Push(
1801 X86RMI_Mem( X86AMode_IR( spill_off, hregX86_EBP()))
1802 );
1803 }
1804
1805 /* Deal with form: CMov32(src=RM_Reg, dst) where vreg == src
1806 Convert to CMov32(RM_Mem, dst) */
1807 if (i->tag == Xin_CMov32
1808 && i->Xin.CMov32.src->tag == Xrm_Reg
1809 && i->Xin.CMov32.src->Xrm.Reg.reg == vreg) {
1810 vassert(i->Xin.CMov32.dst != vreg);
1811 return X86Instr_CMov32(
1812 i->Xin.CMov32.cond,
1813 X86RM_Mem( X86AMode_IR( spill_off, hregX86_EBP() )),
1814 i->Xin.CMov32.dst
1815 );
1816 }
1817
1818 /* Deal with form: Test32(imm,RM_Reg vreg) -> Test32(imm,amode) */
1819 if (i->tag == Xin_Test32
1820 && i->Xin.Test32.dst->tag == Xrm_Reg
1821 && i->Xin.Test32.dst->Xrm.Reg.reg == vreg) {
1822 return X86Instr_Test32(
1823 i->Xin.Test32.imm32,
1824 X86RM_Mem( X86AMode_IR( spill_off, hregX86_EBP() ) )
1825 );
1826 }
1827
1828 return NULL;
1829}
1830
sewardj81bd5502004-07-21 18:49:27 +00001831
1832/* --------- The x86 assembler (bleh.) --------- */
1833
sewardj8ee8c882005-02-25 17:40:26 +00001834static UChar iregNo ( HReg r )
sewardjbad34a92004-07-22 01:14:11 +00001835{
1836 UInt n;
sewardj4a31b262004-12-01 02:24:44 +00001837 vassert(hregClass(r) == HRcInt32);
sewardjbad34a92004-07-22 01:14:11 +00001838 vassert(!hregIsVirtual(r));
1839 n = hregNumber(r);
1840 vassert(n <= 7);
sewardj8ee8c882005-02-25 17:40:26 +00001841 return toUChar(n);
sewardjbad34a92004-07-22 01:14:11 +00001842}
1843
sewardj140656d2004-08-22 02:37:25 +00001844static UInt fregNo ( HReg r )
1845{
1846 UInt n;
sewardj4a31b262004-12-01 02:24:44 +00001847 vassert(hregClass(r) == HRcFlt64);
sewardj140656d2004-08-22 02:37:25 +00001848 vassert(!hregIsVirtual(r));
1849 n = hregNumber(r);
sewardjeafde5a2004-10-09 01:36:57 +00001850 vassert(n <= 5);
sewardj140656d2004-08-22 02:37:25 +00001851 return n;
1852}
1853
sewardjd08f2d72004-12-01 23:19:36 +00001854static UInt vregNo ( HReg r )
1855{
1856 UInt n;
1857 vassert(hregClass(r) == HRcVec128);
1858 vassert(!hregIsVirtual(r));
1859 n = hregNumber(r);
1860 vassert(n <= 7);
1861 return n;
1862}
1863
sewardjbad34a92004-07-22 01:14:11 +00001864static UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
1865{
sewardj8ee8c882005-02-25 17:40:26 +00001866 return toUChar( ((mod & 3) << 6)
1867 | ((reg & 7) << 3)
1868 | (regmem & 7) );
sewardjbad34a92004-07-22 01:14:11 +00001869}
1870
1871static UChar mkSIB ( Int shift, Int regindex, Int regbase )
1872{
sewardj8ee8c882005-02-25 17:40:26 +00001873 return toUChar( ((shift & 3) << 6)
1874 | ((regindex & 7) << 3)
1875 | (regbase & 7) );
sewardjbad34a92004-07-22 01:14:11 +00001876}
1877
1878static UChar* emit32 ( UChar* p, UInt w32 )
1879{
sewardj8ee8c882005-02-25 17:40:26 +00001880 *p++ = toUChar( w32 & 0x000000FF);
1881 *p++ = toUChar((w32 >> 8) & 0x000000FF);
1882 *p++ = toUChar((w32 >> 16) & 0x000000FF);
1883 *p++ = toUChar((w32 >> 24) & 0x000000FF);
sewardjbad34a92004-07-22 01:14:11 +00001884 return p;
1885}
1886
sewardjea64e142004-07-22 16:47:21 +00001887/* Does a sign-extend of the lowest 8 bits give
1888 the original number? */
sewardjbad34a92004-07-22 01:14:11 +00001889static Bool fits8bits ( UInt w32 )
1890{
sewardjea64e142004-07-22 16:47:21 +00001891 Int i32 = (Int)w32;
sewardj8ee8c882005-02-25 17:40:26 +00001892 return toBool(i32 == ((i32 << 24) >> 24));
sewardjbad34a92004-07-22 01:14:11 +00001893}
1894
1895
1896/* Forming mod-reg-rm bytes and scale-index-base bytes.
1897
1898 greg, 0(ereg) | ereg != ESP && ereg != EBP
1899 = 00 greg ereg
1900
1901 greg, d8(ereg) | ereg != ESP
1902 = 01 greg ereg, d8
1903
1904 greg, d32(ereg) | ereg != ESP
1905 = 10 greg ereg, d32
1906
sewardja58ea662004-08-15 03:12:41 +00001907 greg, d8(%esp) = 01 greg 100, 0x24, d8
1908
sewardjbad34a92004-07-22 01:14:11 +00001909 -----------------------------------------------
1910
1911 greg, d8(base,index,scale)
1912 | index != ESP
1913 = 01 greg 100, scale index base, d8
1914
1915 greg, d32(base,index,scale)
1916 | index != ESP
1917 = 10 greg 100, scale index base, d32
1918*/
1919static UChar* doAMode_M ( UChar* p, HReg greg, X86AMode* am )
1920{
1921 if (am->tag == Xam_IR) {
1922 if (am->Xam.IR.imm == 0
1923 && am->Xam.IR.reg != hregX86_ESP()
1924 && am->Xam.IR.reg != hregX86_EBP() ) {
1925 *p++ = mkModRegRM(0, iregNo(greg), iregNo(am->Xam.IR.reg));
1926 return p;
1927 }
1928 if (fits8bits(am->Xam.IR.imm)
1929 && am->Xam.IR.reg != hregX86_ESP()) {
1930 *p++ = mkModRegRM(1, iregNo(greg), iregNo(am->Xam.IR.reg));
sewardj8ee8c882005-02-25 17:40:26 +00001931 *p++ = toUChar(am->Xam.IR.imm & 0xFF);
sewardjbad34a92004-07-22 01:14:11 +00001932 return p;
1933 }
1934 if (am->Xam.IR.reg != hregX86_ESP()) {
1935 *p++ = mkModRegRM(2, iregNo(greg), iregNo(am->Xam.IR.reg));
1936 p = emit32(p, am->Xam.IR.imm);
1937 return p;
1938 }
sewardja58ea662004-08-15 03:12:41 +00001939 if (am->Xam.IR.reg == hregX86_ESP()
1940 && fits8bits(am->Xam.IR.imm)) {
1941 *p++ = mkModRegRM(1, iregNo(greg), 4);
1942 *p++ = 0x24;
sewardj8ee8c882005-02-25 17:40:26 +00001943 *p++ = toUChar(am->Xam.IR.imm & 0xFF);
sewardja58ea662004-08-15 03:12:41 +00001944 return p;
1945 }
sewardjbad34a92004-07-22 01:14:11 +00001946 ppX86AMode(am);
1947 vpanic("doAMode_M: can't emit amode IR");
1948 /*NOTREACHED*/
1949 }
1950 if (am->tag == Xam_IRRS) {
1951 if (fits8bits(am->Xam.IRRS.imm)
1952 && am->Xam.IRRS.index != hregX86_ESP()) {
1953 *p++ = mkModRegRM(1, iregNo(greg), 4);
1954 *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index,
1955 am->Xam.IRRS.base);
sewardj8ee8c882005-02-25 17:40:26 +00001956 *p++ = toUChar(am->Xam.IRRS.imm & 0xFF);
sewardjbad34a92004-07-22 01:14:11 +00001957 return p;
1958 }
1959 if (am->Xam.IRRS.index != hregX86_ESP()) {
1960 *p++ = mkModRegRM(2, iregNo(greg), 4);
1961 *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index,
1962 am->Xam.IRRS.base);
1963 p = emit32(p, am->Xam.IRRS.imm);
1964 return p;
1965 }
1966 ppX86AMode(am);
1967 vpanic("doAMode_M: can't emit amode IRRS");
1968 /*NOTREACHED*/
1969 }
1970 vpanic("doAMode_M: unknown amode");
1971 /*NOTREACHED*/
1972}
1973
1974
1975/* Emit a mod-reg-rm byte when the rm bit denotes a reg. */
1976static UChar* doAMode_R ( UChar* p, HReg greg, HReg ereg )
1977{
1978 *p++ = mkModRegRM(3, iregNo(greg), iregNo(ereg));
1979 return p;
1980}
1981
1982
sewardj3196daf2004-08-13 00:18:58 +00001983/* Emit ffree %st(7) */
1984static UChar* do_ffree_st7 ( UChar* p )
1985{
1986 *p++ = 0xDD;
1987 *p++ = 0xC7;
1988 return p;
1989}
1990
sewardjeafde5a2004-10-09 01:36:57 +00001991/* Emit fstp %st(i), 1 <= i <= 7 */
sewardj3196daf2004-08-13 00:18:58 +00001992static UChar* do_fstp_st ( UChar* p, Int i )
1993{
sewardjeafde5a2004-10-09 01:36:57 +00001994 vassert(1 <= i && i <= 7);
sewardj3196daf2004-08-13 00:18:58 +00001995 *p++ = 0xDD;
sewardj8ee8c882005-02-25 17:40:26 +00001996 *p++ = toUChar(0xD8+i);
sewardj3196daf2004-08-13 00:18:58 +00001997 return p;
1998}
1999
sewardjb3944c22004-10-15 22:22:09 +00002000/* Emit fld %st(i), 0 <= i <= 6 */
sewardj3196daf2004-08-13 00:18:58 +00002001static UChar* do_fld_st ( UChar* p, Int i )
2002{
sewardjb3944c22004-10-15 22:22:09 +00002003 vassert(0 <= i && i <= 6);
sewardj3196daf2004-08-13 00:18:58 +00002004 *p++ = 0xD9;
sewardj8ee8c882005-02-25 17:40:26 +00002005 *p++ = toUChar(0xC0+i);
sewardj3196daf2004-08-13 00:18:58 +00002006 return p;
2007}
2008
sewardjcfded9a2004-09-09 11:44:16 +00002009/* Emit f<op> %st(0) */
2010static UChar* do_fop1_st ( UChar* p, X86FpOp op )
2011{
2012 switch (op) {
sewardj883b00b2004-09-11 09:30:24 +00002013 case Xfp_NEG: *p++ = 0xD9; *p++ = 0xE0; break;
2014 case Xfp_ABS: *p++ = 0xD9; *p++ = 0xE1; break;
sewardjc4be80c2004-09-10 16:17:45 +00002015 case Xfp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break;
sewardje6709112004-09-10 18:37:18 +00002016 case Xfp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break;
sewardjcfded9a2004-09-09 11:44:16 +00002017 case Xfp_SIN: *p++ = 0xD9; *p++ = 0xFE; break;
2018 case Xfp_COS: *p++ = 0xD9; *p++ = 0xFF; break;
sewardj06c32a02004-09-12 12:07:34 +00002019 case Xfp_2XM1: *p++ = 0xD9; *p++ = 0xF0; break;
sewardjbec10842004-10-12 13:44:45 +00002020 case Xfp_MOV: break;
sewardj99016a72004-10-15 22:09:17 +00002021 case Xfp_TAN: p = do_ffree_st7(p); /* since fptan pushes 1.0 */
2022 *p++ = 0xD9; *p++ = 0xF2; /* fptan */
2023 *p++ = 0xD9; *p++ = 0xF7; /* fincstp */
2024 break;
sewardjcfded9a2004-09-09 11:44:16 +00002025 default: vpanic("do_fop1_st: unknown op");
2026 }
2027 return p;
2028}
2029
sewardjbb53f8c2004-08-14 11:50:01 +00002030/* Emit f<op> %st(i), 1 <= i <= 5 */
sewardjcfded9a2004-09-09 11:44:16 +00002031static UChar* do_fop2_st ( UChar* p, X86FpOp op, Int i )
sewardjbb53f8c2004-08-14 11:50:01 +00002032{
sewardj4a31b262004-12-01 02:24:44 +00002033# define fake(_n) mkHReg((_n), HRcInt32, False)
sewardjbb53f8c2004-08-14 11:50:01 +00002034 Int subopc;
2035 switch (op) {
sewardja58ea662004-08-15 03:12:41 +00002036 case Xfp_ADD: subopc = 0; break;
sewardjce646f22004-08-31 23:55:54 +00002037 case Xfp_SUB: subopc = 4; break;
sewardjbb53f8c2004-08-14 11:50:01 +00002038 case Xfp_MUL: subopc = 1; break;
sewardjce646f22004-08-31 23:55:54 +00002039 case Xfp_DIV: subopc = 6; break;
sewardjcfded9a2004-09-09 11:44:16 +00002040 default: vpanic("do_fop2_st: unknown op");
sewardjbb53f8c2004-08-14 11:50:01 +00002041 }
2042 *p++ = 0xD8;
2043 p = doAMode_R(p, fake(subopc), fake(i));
2044 return p;
2045# undef fake
2046}
sewardjbad34a92004-07-22 01:14:11 +00002047
sewardj1e6ad742004-12-02 16:16:11 +00002048/* Push a 32-bit word on the stack. The word depends on tags[3:0];
2049each byte is either 0x00 or 0xFF depending on the corresponding bit in tags[].
2050*/
2051static UChar* push_word_from_tags ( UChar* p, UShort tags )
2052{
2053 UInt w;
2054 vassert(0 == (tags & ~0xF));
2055 if (tags == 0) {
2056 /* pushl $0x00000000 */
2057 *p++ = 0x6A;
2058 *p++ = 0x00;
2059 }
2060 else
2061 /* pushl $0xFFFFFFFF */
2062 if (tags == 0xF) {
2063 *p++ = 0x6A;
2064 *p++ = 0xFF;
2065 } else {
2066 vassert(0); /* awaiting test case */
2067 w = 0;
2068 if (tags & 1) w |= 0x000000FF;
2069 if (tags & 2) w |= 0x0000FF00;
2070 if (tags & 4) w |= 0x00FF0000;
2071 if (tags & 8) w |= 0xFF000000;
2072 *p++ = 0x68;
2073 p = emit32(p, w);
2074 }
2075 return p;
2076}
2077
sewardj81bd5502004-07-21 18:49:27 +00002078/* Emit an instruction into buf and return the number of bytes used.
2079 Note that buf is not the insn's final place, and therefore it is
sewardjc6f970f2012-04-02 21:54:49 +00002080 imperative to emit position-independent code. If the emitted
2081 instruction was a profiler inc, set *is_profInc to True, else
2082 leave it unchanged. */
sewardj81bd5502004-07-21 18:49:27 +00002083
sewardjc6f970f2012-04-02 21:54:49 +00002084Int emit_X86Instr ( /*MB_MOD*/Bool* is_profInc,
2085 UChar* buf, Int nbuf, X86Instr* i,
sewardj010ac542011-05-29 09:29:18 +00002086 Bool mode64,
sewardjc6f970f2012-04-02 21:54:49 +00002087 void* disp_cp_chain_me_to_slowEP,
2088 void* disp_cp_chain_me_to_fastEP,
2089 void* disp_cp_xindir,
2090 void* disp_cp_xassisted )
sewardj81bd5502004-07-21 18:49:27 +00002091{
sewardj4b861de2004-11-03 15:24:42 +00002092 UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
sewardjea64e142004-07-22 16:47:21 +00002093
sewardj1e6ad742004-12-02 16:16:11 +00002094 UInt xtra;
sewardjbad34a92004-07-22 01:14:11 +00002095 UChar* p = &buf[0];
sewardj750f4072004-07-26 22:39:11 +00002096 UChar* ptmp;
sewardjbad34a92004-07-22 01:14:11 +00002097 vassert(nbuf >= 32);
cerion92b64362005-12-13 12:02:26 +00002098 vassert(mode64 == False);
sewardjbad34a92004-07-22 01:14:11 +00002099
sewardjea64e142004-07-22 16:47:21 +00002100 /* Wrap an integer as a int register, for use assembling
2101 GrpN insns, in which the greg field is used as a sub-opcode
2102 and does not really contain a register. */
sewardj4a31b262004-12-01 02:24:44 +00002103# define fake(_n) mkHReg((_n), HRcInt32, False)
sewardjea64e142004-07-22 16:47:21 +00002104
cerion92b64362005-12-13 12:02:26 +00002105 /* vex_printf("asm ");ppX86Instr(i, mode64); vex_printf("\n"); */
sewardjbec10842004-10-12 13:44:45 +00002106
sewardj81bd5502004-07-21 18:49:27 +00002107 switch (i->tag) {
sewardjbad34a92004-07-22 01:14:11 +00002108
2109 case Xin_Alu32R:
sewardjea64e142004-07-22 16:47:21 +00002110 /* Deal specially with MOV */
sewardjbad34a92004-07-22 01:14:11 +00002111 if (i->Xin.Alu32R.op == Xalu_MOV) {
2112 switch (i->Xin.Alu32R.src->tag) {
sewardjea64e142004-07-22 16:47:21 +00002113 case Xrmi_Imm:
sewardj8ee8c882005-02-25 17:40:26 +00002114 *p++ = toUChar(0xB8 + iregNo(i->Xin.Alu32R.dst));
sewardjea64e142004-07-22 16:47:21 +00002115 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
2116 goto done;
2117 case Xrmi_Reg:
sewardj750f4072004-07-26 22:39:11 +00002118 *p++ = 0x89;
2119 p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg,
2120 i->Xin.Alu32R.dst);
2121 goto done;
sewardjea64e142004-07-22 16:47:21 +00002122 case Xrmi_Mem:
2123 *p++ = 0x8B;
2124 p = doAMode_M(p, i->Xin.Alu32R.dst,
2125 i->Xin.Alu32R.src->Xrmi.Mem.am);
2126 goto done;
2127 default:
2128 goto bad;
2129 }
2130 }
sewardje8c922f2004-07-23 01:34:11 +00002131 /* MUL */
2132 if (i->Xin.Alu32R.op == Xalu_MUL) {
sewardjd75fe5a2004-07-23 12:57:47 +00002133 switch (i->Xin.Alu32R.src->tag) {
2134 case Xrmi_Reg:
2135 *p++ = 0x0F;
2136 *p++ = 0xAF;
2137 p = doAMode_R(p, i->Xin.Alu32R.dst,
2138 i->Xin.Alu32R.src->Xrmi.Reg.reg);
2139 goto done;
sewardj140656d2004-08-22 02:37:25 +00002140 case Xrmi_Mem:
2141 *p++ = 0x0F;
2142 *p++ = 0xAF;
2143 p = doAMode_M(p, i->Xin.Alu32R.dst,
2144 i->Xin.Alu32R.src->Xrmi.Mem.am);
2145 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002146 case Xrmi_Imm:
2147 if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
2148 *p++ = 0x6B;
2149 p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
sewardj8ee8c882005-02-25 17:40:26 +00002150 *p++ = toUChar(0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjd75fe5a2004-07-23 12:57:47 +00002151 } else {
sewardj278c44c2004-08-20 00:28:13 +00002152 *p++ = 0x69;
2153 p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
2154 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjd75fe5a2004-07-23 12:57:47 +00002155 }
sewardj278c44c2004-08-20 00:28:13 +00002156 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002157 default:
2158 goto bad;
2159 }
sewardje8c922f2004-07-23 01:34:11 +00002160 }
2161 /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP */
sewardjea64e142004-07-22 16:47:21 +00002162 opc = opc_rr = subopc_imm = opc_imma = 0;
2163 switch (i->Xin.Alu32R.op) {
sewardjd3f9de72005-01-15 20:43:10 +00002164 case Xalu_ADC: opc = 0x13; opc_rr = 0x11;
2165 subopc_imm = 2; opc_imma = 0x15; break;
sewardjea64e142004-07-22 16:47:21 +00002166 case Xalu_ADD: opc = 0x03; opc_rr = 0x01;
2167 subopc_imm = 0; opc_imma = 0x05; break;
2168 case Xalu_SUB: opc = 0x2B; opc_rr = 0x29;
2169 subopc_imm = 5; opc_imma = 0x2D; break;
sewardj70f676d2004-12-10 14:59:57 +00002170 case Xalu_SBB: opc = 0x1B; opc_rr = 0x19;
2171 subopc_imm = 3; opc_imma = 0x1D; break;
sewardj86898e82004-07-22 17:26:12 +00002172 case Xalu_AND: opc = 0x23; opc_rr = 0x21;
2173 subopc_imm = 4; opc_imma = 0x25; break;
sewardje8c922f2004-07-23 01:34:11 +00002174 case Xalu_XOR: opc = 0x33; opc_rr = 0x31;
2175 subopc_imm = 6; opc_imma = 0x35; break;
2176 case Xalu_OR: opc = 0x0B; opc_rr = 0x09;
2177 subopc_imm = 1; opc_imma = 0x0D; break;
2178 case Xalu_CMP: opc = 0x3B; opc_rr = 0x39;
2179 subopc_imm = 7; opc_imma = 0x3D; break;
sewardjea64e142004-07-22 16:47:21 +00002180 default: goto bad;
2181 }
2182 switch (i->Xin.Alu32R.src->tag) {
2183 case Xrmi_Imm:
2184 if (i->Xin.Alu32R.dst == hregX86_EAX()
2185 && !fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
sewardj8ee8c882005-02-25 17:40:26 +00002186 *p++ = toUChar(opc_imma);
sewardjea64e142004-07-22 16:47:21 +00002187 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
2188 } else
sewardjd3f9de72005-01-15 20:43:10 +00002189 if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
sewardjea64e142004-07-22 16:47:21 +00002190 *p++ = 0x83;
2191 p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst);
sewardj8ee8c882005-02-25 17:40:26 +00002192 *p++ = toUChar(0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjea64e142004-07-22 16:47:21 +00002193 } else {
2194 *p++ = 0x81;
2195 p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst);
2196 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
2197 }
2198 goto done;
2199 case Xrmi_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00002200 *p++ = toUChar(opc_rr);
sewardjea64e142004-07-22 16:47:21 +00002201 p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg,
2202 i->Xin.Alu32R.dst);
2203 goto done;
sewardjbad34a92004-07-22 01:14:11 +00002204 case Xrmi_Mem:
sewardj8ee8c882005-02-25 17:40:26 +00002205 *p++ = toUChar(opc);
sewardjea64e142004-07-22 16:47:21 +00002206 p = doAMode_M(p, i->Xin.Alu32R.dst,
sewardjbad34a92004-07-22 01:14:11 +00002207 i->Xin.Alu32R.src->Xrmi.Mem.am);
2208 goto done;
sewardjea64e142004-07-22 16:47:21 +00002209 default:
sewardjbad34a92004-07-22 01:14:11 +00002210 goto bad;
sewardjbad34a92004-07-22 01:14:11 +00002211 }
2212 break;
2213
2214 case Xin_Alu32M:
sewardjea64e142004-07-22 16:47:21 +00002215 /* Deal specially with MOV */
sewardjbad34a92004-07-22 01:14:11 +00002216 if (i->Xin.Alu32M.op == Xalu_MOV) {
sewardjea64e142004-07-22 16:47:21 +00002217 switch (i->Xin.Alu32M.src->tag) {
2218 case Xri_Reg:
2219 *p++ = 0x89;
2220 p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg,
2221 i->Xin.Alu32M.dst);
2222 goto done;
2223 case Xri_Imm:
2224 *p++ = 0xC7;
2225 p = doAMode_M(p, fake(0), i->Xin.Alu32M.dst);
2226 p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32);
2227 goto done;
2228 default:
2229 goto bad;
2230 }
2231 }
sewardje8c922f2004-07-23 01:34:11 +00002232 /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP. MUL is not
2233 allowed here. */
sewardjea64e142004-07-22 16:47:21 +00002234 opc = subopc_imm = opc_imma = 0;
2235 switch (i->Xin.Alu32M.op) {
2236 case Xalu_ADD: opc = 0x01; subopc_imm = 0; break;
sewardj86898e82004-07-22 17:26:12 +00002237 case Xalu_SUB: opc = 0x29; subopc_imm = 5; break;
sewardjfb7373a2007-08-25 21:29:03 +00002238 case Xalu_CMP: opc = 0x39; subopc_imm = 7; break;
sewardjea64e142004-07-22 16:47:21 +00002239 default: goto bad;
2240 }
2241 switch (i->Xin.Alu32M.src->tag) {
2242 case Xri_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00002243 *p++ = toUChar(opc);
sewardjea64e142004-07-22 16:47:21 +00002244 p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg,
2245 i->Xin.Alu32M.dst);
2246 goto done;
2247 case Xri_Imm:
2248 if (fits8bits(i->Xin.Alu32M.src->Xri.Imm.imm32)) {
2249 *p++ = 0x83;
2250 p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst);
sewardj8ee8c882005-02-25 17:40:26 +00002251 *p++ = toUChar(0xFF & i->Xin.Alu32M.src->Xri.Imm.imm32);
sewardjea64e142004-07-22 16:47:21 +00002252 goto done;
2253 } else {
2254 *p++ = 0x81;
2255 p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst);
2256 p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32);
2257 goto done;
2258 }
2259 default:
2260 goto bad;
sewardjbad34a92004-07-22 01:14:11 +00002261 }
2262 break;
2263
sewardje8c922f2004-07-23 01:34:11 +00002264 case Xin_Sh32:
sewardjd75fe5a2004-07-23 12:57:47 +00002265 opc_cl = opc_imm = subopc = 0;
2266 switch (i->Xin.Sh32.op) {
2267 case Xsh_SHR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 5; break;
sewardj07134a42004-07-26 02:04:54 +00002268 case Xsh_SAR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 7; break;
2269 case Xsh_SHL: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 4; break;
sewardjd75fe5a2004-07-23 12:57:47 +00002270 default: goto bad;
2271 }
2272 if (i->Xin.Sh32.src == 0) {
sewardj8ee8c882005-02-25 17:40:26 +00002273 *p++ = toUChar(opc_cl);
sewardjeba63f82005-02-23 13:31:25 +00002274 p = doAMode_R(p, fake(subopc), i->Xin.Sh32.dst);
sewardjd75fe5a2004-07-23 12:57:47 +00002275 } else {
sewardj8ee8c882005-02-25 17:40:26 +00002276 *p++ = toUChar(opc_imm);
sewardjeba63f82005-02-23 13:31:25 +00002277 p = doAMode_R(p, fake(subopc), i->Xin.Sh32.dst);
2278 *p++ = (UChar)(i->Xin.Sh32.src);
sewardjd75fe5a2004-07-23 12:57:47 +00002279 }
sewardjeba63f82005-02-23 13:31:25 +00002280 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002281
2282 case Xin_Test32:
sewardjfb7373a2007-08-25 21:29:03 +00002283 if (i->Xin.Test32.dst->tag == Xrm_Reg) {
2284 /* testl $imm32, %reg */
2285 *p++ = 0xF7;
2286 p = doAMode_R(p, fake(0), i->Xin.Test32.dst->Xrm.Reg.reg);
2287 p = emit32(p, i->Xin.Test32.imm32);
2288 goto done;
2289 } else {
2290 /* testl $imm32, amode */
2291 *p++ = 0xF7;
2292 p = doAMode_M(p, fake(0), i->Xin.Test32.dst->Xrm.Mem.am);
2293 p = emit32(p, i->Xin.Test32.imm32);
2294 goto done;
2295 }
sewardje8c922f2004-07-23 01:34:11 +00002296
2297 case Xin_Unary32:
sewardj358b7d42004-11-08 18:54:50 +00002298 if (i->Xin.Unary32.op == Xun_NOT) {
sewardjd75fe5a2004-07-23 12:57:47 +00002299 *p++ = 0xF7;
sewardjeba63f82005-02-23 13:31:25 +00002300 p = doAMode_R(p, fake(2), i->Xin.Unary32.dst);
2301 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002302 }
sewardj358b7d42004-11-08 18:54:50 +00002303 if (i->Xin.Unary32.op == Xun_NEG) {
2304 *p++ = 0xF7;
sewardjeba63f82005-02-23 13:31:25 +00002305 p = doAMode_R(p, fake(3), i->Xin.Unary32.dst);
2306 goto done;
sewardj358b7d42004-11-08 18:54:50 +00002307 }
sewardjd75fe5a2004-07-23 12:57:47 +00002308 break;
sewardje8c922f2004-07-23 01:34:11 +00002309
sewardj79e04f82007-03-31 14:30:12 +00002310 case Xin_Lea32:
2311 *p++ = 0x8D;
2312 p = doAMode_M(p, i->Xin.Lea32.dst, i->Xin.Lea32.am);
2313 goto done;
2314
sewardja2dad5c2004-07-23 11:43:43 +00002315 case Xin_MulL:
sewardjd75fe5a2004-07-23 12:57:47 +00002316 subopc = i->Xin.MulL.syned ? 5 : 4;
sewardjeba63f82005-02-23 13:31:25 +00002317 *p++ = 0xF7;
2318 switch (i->Xin.MulL.src->tag) {
2319 case Xrm_Mem:
2320 p = doAMode_M(p, fake(subopc),
2321 i->Xin.MulL.src->Xrm.Mem.am);
2322 goto done;
2323 case Xrm_Reg:
2324 p = doAMode_R(p, fake(subopc),
2325 i->Xin.MulL.src->Xrm.Reg.reg);
2326 goto done;
2327 default:
2328 goto bad;
sewardjd75fe5a2004-07-23 12:57:47 +00002329 }
2330 break;
sewardja2dad5c2004-07-23 11:43:43 +00002331
2332 case Xin_Div:
sewardjd75fe5a2004-07-23 12:57:47 +00002333 subopc = i->Xin.Div.syned ? 7 : 6;
sewardjeba63f82005-02-23 13:31:25 +00002334 *p++ = 0xF7;
2335 switch (i->Xin.Div.src->tag) {
2336 case Xrm_Mem:
2337 p = doAMode_M(p, fake(subopc),
2338 i->Xin.Div.src->Xrm.Mem.am);
2339 goto done;
2340 case Xrm_Reg:
2341 p = doAMode_R(p, fake(subopc),
2342 i->Xin.Div.src->Xrm.Reg.reg);
2343 goto done;
2344 default:
2345 goto bad;
sewardjd75fe5a2004-07-23 12:57:47 +00002346 }
2347 break;
sewardja2dad5c2004-07-23 11:43:43 +00002348
2349 case Xin_Sh3232:
sewardjd75fe5a2004-07-23 12:57:47 +00002350 vassert(i->Xin.Sh3232.op == Xsh_SHL || i->Xin.Sh3232.op == Xsh_SHR);
2351 if (i->Xin.Sh3232.amt == 0) {
2352 /* shldl/shrdl by %cl */
2353 *p++ = 0x0F;
sewardj68511542004-07-28 00:15:44 +00002354 if (i->Xin.Sh3232.op == Xsh_SHL) {
2355 *p++ = 0xA5;
sewardj68511542004-07-28 00:15:44 +00002356 } else {
2357 *p++ = 0xAD;
sewardj68511542004-07-28 00:15:44 +00002358 }
sewardje5f384c2004-07-30 16:17:28 +00002359 p = doAMode_R(p, i->Xin.Sh3232.src, i->Xin.Sh3232.dst);
sewardjd75fe5a2004-07-23 12:57:47 +00002360 goto done;
2361 }
2362 break;
sewardja2dad5c2004-07-23 11:43:43 +00002363
sewardje8c922f2004-07-23 01:34:11 +00002364 case Xin_Push:
sewardjd75fe5a2004-07-23 12:57:47 +00002365 switch (i->Xin.Push.src->tag) {
2366 case Xrmi_Mem:
2367 *p++ = 0xFF;
2368 p = doAMode_M(p, fake(6), i->Xin.Push.src->Xrmi.Mem.am);
2369 goto done;
sewardja58ea662004-08-15 03:12:41 +00002370 case Xrmi_Imm:
2371 *p++ = 0x68;
2372 p = emit32(p, i->Xin.Push.src->Xrmi.Imm.imm32);
2373 goto done;
sewardjd7cb8532004-08-17 23:59:23 +00002374 case Xrmi_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00002375 *p++ = toUChar(0x50 + iregNo(i->Xin.Push.src->Xrmi.Reg.reg));
sewardjd7cb8532004-08-17 23:59:23 +00002376 goto done;
sewardja58ea662004-08-15 03:12:41 +00002377 default:
sewardjd75fe5a2004-07-23 12:57:47 +00002378 goto bad;
2379 }
sewardje8c922f2004-07-23 01:34:11 +00002380
2381 case Xin_Call:
sewardjcfe046e2013-01-17 14:23:53 +00002382 if (i->Xin.Call.cond != Xcc_ALWAYS && i->Xin.Call.rloc != RetLocNone) {
2383 /* The call might not happen (it isn't unconditional) and it
2384 returns a result. In this case we will need to generate a
2385 control flow diamond to put 0x555..555 in the return
2386 register(s) in the case where the call doesn't happen. If
2387 this ever becomes necessary, maybe copy code from the ARM
2388 equivalent. Until that day, just give up. */
2389 goto bad;
2390 }
sewardj4b861de2004-11-03 15:24:42 +00002391 /* See detailed comment for Xin_Call in getRegUsage_X86Instr above
2392 for explanation of this. */
2393 switch (i->Xin.Call.regparms) {
2394 case 0: irno = iregNo(hregX86_EAX()); break;
sewardj45c50eb2004-11-04 18:25:33 +00002395 case 1: irno = iregNo(hregX86_EDX()); break;
2396 case 2: irno = iregNo(hregX86_ECX()); break;
sewardj4b861de2004-11-03 15:24:42 +00002397 case 3: irno = iregNo(hregX86_EDI()); break;
2398 default: vpanic(" emit_X86Instr:call:regparms");
2399 }
2400 /* jump over the following two insns if the condition does not
2401 hold */
2402 if (i->Xin.Call.cond != Xcc_ALWAYS) {
sewardj8ee8c882005-02-25 17:40:26 +00002403 *p++ = toUChar(0x70 + (0xF & (i->Xin.Call.cond ^ 1)));
sewardj4b861de2004-11-03 15:24:42 +00002404 *p++ = 0x07; /* 7 bytes in the next two insns */
2405 }
2406 /* movl $target, %tmp */
sewardj8ee8c882005-02-25 17:40:26 +00002407 *p++ = toUChar(0xB8 + irno);
sewardj4b861de2004-11-03 15:24:42 +00002408 p = emit32(p, i->Xin.Call.target);
2409 /* call *%tmp */
sewardjd75fe5a2004-07-23 12:57:47 +00002410 *p++ = 0xFF;
sewardj8ee8c882005-02-25 17:40:26 +00002411 *p++ = toUChar(0xD0 + irno);
sewardjd75fe5a2004-07-23 12:57:47 +00002412 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002413
sewardjc6f970f2012-04-02 21:54:49 +00002414 case Xin_XDirect: {
2415 /* NB: what goes on here has to be very closely coordinated with the
2416 chainXDirect_X86 and unchainXDirect_X86 below. */
2417 /* We're generating chain-me requests here, so we need to be
2418 sure this is actually allowed -- no-redir translations can't
2419 use chain-me's. Hence: */
2420 vassert(disp_cp_chain_me_to_slowEP != NULL);
2421 vassert(disp_cp_chain_me_to_fastEP != NULL);
sewardj010ac542011-05-29 09:29:18 +00002422
sewardj893aada2004-11-29 19:57:54 +00002423 /* Use ptmp for backpatching conditional jumps. */
2424 ptmp = NULL;
2425
2426 /* First off, if this is conditional, create a conditional
sewardjc6f970f2012-04-02 21:54:49 +00002427 jump over the rest of it. */
2428 if (i->Xin.XDirect.cond != Xcc_ALWAYS) {
sewardj893aada2004-11-29 19:57:54 +00002429 /* jmp fwds if !condition */
sewardjc6f970f2012-04-02 21:54:49 +00002430 *p++ = toUChar(0x70 + (0xF & (i->Xin.XDirect.cond ^ 1)));
sewardj893aada2004-11-29 19:57:54 +00002431 ptmp = p; /* fill in this bit later */
2432 *p++ = 0; /* # of bytes to jump over; don't know how many yet. */
sewardj750f4072004-07-26 22:39:11 +00002433 }
sewardj893aada2004-11-29 19:57:54 +00002434
sewardjc6f970f2012-04-02 21:54:49 +00002435 /* Update the guest EIP. */
2436 /* movl $dstGA, amEIP */
2437 *p++ = 0xC7;
2438 p = doAMode_M(p, fake(0), i->Xin.XDirect.amEIP);
2439 p = emit32(p, i->Xin.XDirect.dstGA);
sewardj010ac542011-05-29 09:29:18 +00002440
sewardjc6f970f2012-04-02 21:54:49 +00002441 /* --- FIRST PATCHABLE BYTE follows --- */
2442 /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're calling
2443 to) backs up the return address, so as to find the address of
2444 the first patchable byte. So: don't change the length of the
2445 two instructions below. */
2446 /* movl $disp_cp_chain_me_to_{slow,fast}EP,%edx; */
sewardj17c7f952005-12-15 14:02:34 +00002447 *p++ = 0xBA;
sewardjc6f970f2012-04-02 21:54:49 +00002448 void* disp_cp_chain_me
2449 = i->Xin.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP
2450 : disp_cp_chain_me_to_slowEP;
2451 p = emit32(p, (UInt)Ptr_to_ULong(disp_cp_chain_me));
2452 /* call *%edx */
2453 *p++ = 0xFF;
2454 *p++ = 0xD2;
2455 /* --- END of PATCHABLE BYTES --- */
sewardj17c7f952005-12-15 14:02:34 +00002456
sewardjc6f970f2012-04-02 21:54:49 +00002457 /* Fix up the conditional jump, if there was one. */
2458 if (i->Xin.XDirect.cond != Xcc_ALWAYS) {
2459 Int delta = p - ptmp;
2460 vassert(delta > 0 && delta < 40);
2461 *ptmp = toUChar(delta-1);
2462 }
2463 goto done;
2464 }
2465
2466 case Xin_XIndir: {
2467 /* We're generating transfers that could lead indirectly to a
2468 chain-me, so we need to be sure this is actually allowed --
2469 no-redir translations are not allowed to reach normal
2470 translations without going through the scheduler. That means
2471 no XDirects or XIndirs out from no-redir translations.
2472 Hence: */
2473 vassert(disp_cp_xindir != NULL);
2474
2475 /* Use ptmp for backpatching conditional jumps. */
2476 ptmp = NULL;
2477
2478 /* First off, if this is conditional, create a conditional
2479 jump over the rest of it. */
2480 if (i->Xin.XIndir.cond != Xcc_ALWAYS) {
2481 /* jmp fwds if !condition */
2482 *p++ = toUChar(0x70 + (0xF & (i->Xin.XIndir.cond ^ 1)));
2483 ptmp = p; /* fill in this bit later */
2484 *p++ = 0; /* # of bytes to jump over; don't know how many yet. */
2485 }
2486
2487 /* movl dstGA(a reg), amEIP -- copied from Alu32M MOV case */
2488 *p++ = 0x89;
2489 p = doAMode_M(p, i->Xin.XIndir.dstGA, i->Xin.XIndir.amEIP);
2490
2491 /* movl $disp_indir, %edx */
2492 *p++ = 0xBA;
2493 p = emit32(p, (UInt)Ptr_to_ULong(disp_cp_xindir));
sewardj17c7f952005-12-15 14:02:34 +00002494 /* jmp *%edx */
2495 *p++ = 0xFF;
2496 *p++ = 0xE2;
sewardj893aada2004-11-29 19:57:54 +00002497
2498 /* Fix up the conditional jump, if there was one. */
sewardjc6f970f2012-04-02 21:54:49 +00002499 if (i->Xin.XIndir.cond != Xcc_ALWAYS) {
sewardj893aada2004-11-29 19:57:54 +00002500 Int delta = p - ptmp;
sewardjc6f970f2012-04-02 21:54:49 +00002501 vassert(delta > 0 && delta < 40);
2502 *ptmp = toUChar(delta-1);
2503 }
2504 goto done;
2505 }
2506
2507 case Xin_XAssisted: {
2508 /* Use ptmp for backpatching conditional jumps. */
2509 ptmp = NULL;
2510
2511 /* First off, if this is conditional, create a conditional
2512 jump over the rest of it. */
2513 if (i->Xin.XAssisted.cond != Xcc_ALWAYS) {
2514 /* jmp fwds if !condition */
2515 *p++ = toUChar(0x70 + (0xF & (i->Xin.XAssisted.cond ^ 1)));
2516 ptmp = p; /* fill in this bit later */
2517 *p++ = 0; /* # of bytes to jump over; don't know how many yet. */
2518 }
2519
2520 /* movl dstGA(a reg), amEIP -- copied from Alu32M MOV case */
2521 *p++ = 0x89;
2522 p = doAMode_M(p, i->Xin.XIndir.dstGA, i->Xin.XIndir.amEIP);
2523 /* movl $magic_number, %ebp. */
2524 UInt trcval = 0;
2525 switch (i->Xin.XAssisted.jk) {
sewardj39aacda2012-04-21 15:34:25 +00002526 case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
2527 case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
2528 case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break;
2529 case Ijk_Sys_int129: trcval = VEX_TRC_JMP_SYS_INT129; break;
2530 case Ijk_Sys_int130: trcval = VEX_TRC_JMP_SYS_INT130; break;
2531 case Ijk_Sys_sysenter: trcval = VEX_TRC_JMP_SYS_SYSENTER; break;
2532 case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
2533 case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
2534 case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break;
2535 case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
2536 case Ijk_TInval: trcval = VEX_TRC_JMP_TINVAL; break;
2537 case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
2538 case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
2539 case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break;
2540 case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
sewardjc6f970f2012-04-02 21:54:49 +00002541 /* We don't expect to see the following being assisted. */
2542 case Ijk_Ret:
2543 case Ijk_Call:
2544 /* fallthrough */
2545 default:
2546 ppIRJumpKind(i->Xin.XAssisted.jk);
2547 vpanic("emit_X86Instr.Xin_XAssisted: unexpected jump kind");
2548 }
2549 vassert(trcval != 0);
2550 *p++ = 0xBD;
2551 p = emit32(p, trcval);
2552
2553 /* movl $disp_indir, %edx */
2554 *p++ = 0xBA;
2555 p = emit32(p, (UInt)Ptr_to_ULong(disp_cp_xassisted));
2556 /* jmp *%edx */
2557 *p++ = 0xFF;
2558 *p++ = 0xE2;
2559
2560 /* Fix up the conditional jump, if there was one. */
2561 if (i->Xin.XAssisted.cond != Xcc_ALWAYS) {
2562 Int delta = p - ptmp;
2563 vassert(delta > 0 && delta < 40);
sewardj8ee8c882005-02-25 17:40:26 +00002564 *ptmp = toUChar(delta-1);
sewardje8c922f2004-07-23 01:34:11 +00002565 }
sewardj893aada2004-11-29 19:57:54 +00002566 goto done;
sewardj010ac542011-05-29 09:29:18 +00002567 }
sewardj86898e82004-07-22 17:26:12 +00002568
sewardje8c922f2004-07-23 01:34:11 +00002569 case Xin_CMov32:
sewardjd75fe5a2004-07-23 12:57:47 +00002570 vassert(i->Xin.CMov32.cond != Xcc_ALWAYS);
sewardjc4904af2005-08-08 00:33:37 +00002571
sewardj893aada2004-11-29 19:57:54 +00002572 /* This generates cmov, which is illegal on P54/P55. */
sewardjc4904af2005-08-08 00:33:37 +00002573 /*
sewardjd75fe5a2004-07-23 12:57:47 +00002574 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002575 *p++ = toUChar(0x40 + (0xF & i->Xin.CMov32.cond));
sewardjd75fe5a2004-07-23 12:57:47 +00002576 if (i->Xin.CMov32.src->tag == Xrm_Reg) {
2577 p = doAMode_R(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Reg.reg);
2578 goto done;
2579 }
2580 if (i->Xin.CMov32.src->tag == Xrm_Mem) {
2581 p = doAMode_M(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Mem.am);
2582 goto done;
2583 }
sewardjc4904af2005-08-08 00:33:37 +00002584 */
2585
2586 /* Alternative version which works on any x86 variant. */
2587 /* jmp fwds if !condition */
sewardjc7cd2142005-09-09 22:31:49 +00002588 *p++ = toUChar(0x70 + (i->Xin.CMov32.cond ^ 1));
sewardjc4904af2005-08-08 00:33:37 +00002589 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2590 ptmp = p;
2591
2592 switch (i->Xin.CMov32.src->tag) {
2593 case Xrm_Reg:
2594 /* Big sigh. This is movl E -> G ... */
2595 *p++ = 0x89;
2596 p = doAMode_R(p, i->Xin.CMov32.src->Xrm.Reg.reg,
2597 i->Xin.CMov32.dst);
2598
2599 break;
2600 case Xrm_Mem:
2601 /* ... whereas this is movl G -> E. That's why the args
2602 to doAMode_R appear to be the wrong way round in the
2603 Xrm_Reg case. */
2604 *p++ = 0x8B;
2605 p = doAMode_M(p, i->Xin.CMov32.dst,
2606 i->Xin.CMov32.src->Xrm.Mem.am);
2607 break;
2608 default:
2609 goto bad;
2610 }
2611 /* Fill in the jump offset. */
sewardjc7cd2142005-09-09 22:31:49 +00002612 *(ptmp-1) = toUChar(p - ptmp);
sewardjc4904af2005-08-08 00:33:37 +00002613 goto done;
2614
sewardjd75fe5a2004-07-23 12:57:47 +00002615 break;
sewardje8c922f2004-07-23 01:34:11 +00002616
2617 case Xin_LoadEX:
sewardjd75fe5a2004-07-23 12:57:47 +00002618 if (i->Xin.LoadEX.szSmall == 1 && !i->Xin.LoadEX.syned) {
2619 /* movzbl */
2620 *p++ = 0x0F;
2621 *p++ = 0xB6;
2622 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2623 goto done;
2624 }
2625 if (i->Xin.LoadEX.szSmall == 2 && !i->Xin.LoadEX.syned) {
2626 /* movzwl */
2627 *p++ = 0x0F;
2628 *p++ = 0xB7;
2629 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2630 goto done;
2631 }
sewardjeb17e492007-08-25 23:07:44 +00002632 if (i->Xin.LoadEX.szSmall == 1 && i->Xin.LoadEX.syned) {
2633 /* movsbl */
2634 *p++ = 0x0F;
2635 *p++ = 0xBE;
2636 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2637 goto done;
2638 }
sewardjd75fe5a2004-07-23 12:57:47 +00002639 break;
sewardje8c922f2004-07-23 01:34:11 +00002640
sewardjd7cb8532004-08-17 23:59:23 +00002641 case Xin_Set32:
2642 /* Make the destination register be 1 or 0, depending on whether
2643 the relevant condition holds. We have to dodge and weave
2644 when the destination is %esi or %edi as we cannot directly
2645 emit the native 'setb %reg' for those. Further complication:
2646 the top 24 bits of the destination should be forced to zero,
2647 but doing 'xor %r,%r' kills the flag(s) we are about to read.
sewardj3503ad82004-08-24 00:24:56 +00002648 Sigh. So start off my moving $0 into the dest. */
sewardjd7cb8532004-08-17 23:59:23 +00002649
sewardj3503ad82004-08-24 00:24:56 +00002650 /* Do we need to swap in %eax? */
sewardjd7cb8532004-08-17 23:59:23 +00002651 if (iregNo(i->Xin.Set32.dst) >= 4) {
2652 /* xchg %eax, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002653 *p++ = toUChar(0x90 + iregNo(i->Xin.Set32.dst));
sewardj3503ad82004-08-24 00:24:56 +00002654 /* movl $0, %eax */
sewardj8ee8c882005-02-25 17:40:26 +00002655 *p++ =toUChar(0xB8 + iregNo(hregX86_EAX()));
sewardj3503ad82004-08-24 00:24:56 +00002656 p = emit32(p, 0);
2657 /* setb lo8(%eax) */
sewardjd7cb8532004-08-17 23:59:23 +00002658 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002659 *p++ = toUChar(0x90 + (0xF & i->Xin.Set32.cond));
sewardjd7cb8532004-08-17 23:59:23 +00002660 p = doAMode_R(p, fake(0), hregX86_EAX());
2661 /* xchg %eax, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002662 *p++ = toUChar(0x90 + iregNo(i->Xin.Set32.dst));
sewardjd7cb8532004-08-17 23:59:23 +00002663 } else {
sewardj3503ad82004-08-24 00:24:56 +00002664 /* movl $0, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002665 *p++ = toUChar(0xB8 + iregNo(i->Xin.Set32.dst));
sewardj3503ad82004-08-24 00:24:56 +00002666 p = emit32(p, 0);
2667 /* setb lo8(%dst) */
sewardjd7cb8532004-08-17 23:59:23 +00002668 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002669 *p++ = toUChar(0x90 + (0xF & i->Xin.Set32.cond));
sewardjd7cb8532004-08-17 23:59:23 +00002670 p = doAMode_R(p, fake(0), i->Xin.Set32.dst);
2671 }
2672 goto done;
2673
sewardjce646f22004-08-31 23:55:54 +00002674 case Xin_Bsfr32:
2675 *p++ = 0x0F;
2676 if (i->Xin.Bsfr32.isFwds) {
2677 *p++ = 0xBC;
2678 } else {
2679 *p++ = 0xBD;
2680 }
2681 p = doAMode_R(p, i->Xin.Bsfr32.dst, i->Xin.Bsfr32.src);
2682 goto done;
2683
sewardj3e838932005-01-07 12:09:15 +00002684 case Xin_MFence:
2685 /* see comment in hdefs.h re this insn */
sewardjbb3f52d2005-01-07 14:14:50 +00002686 if (0) vex_printf("EMIT FENCE\n");
sewardj5117ce12006-01-27 21:20:15 +00002687 if (i->Xin.MFence.hwcaps & (VEX_HWCAPS_X86_SSE3
2688 |VEX_HWCAPS_X86_SSE2)) {
2689 /* mfence */
2690 *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF0;
2691 goto done;
sewardj3e838932005-01-07 12:09:15 +00002692 }
sewardj5117ce12006-01-27 21:20:15 +00002693 if (i->Xin.MFence.hwcaps & VEX_HWCAPS_X86_SSE1) {
2694 /* sfence */
2695 *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF8;
2696 /* lock addl $0,0(%esp) */
2697 *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44;
2698 *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
2699 goto done;
2700 }
2701 if (i->Xin.MFence.hwcaps == 0/*baseline, no SSE*/) {
2702 /* lock addl $0,0(%esp) */
2703 *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44;
2704 *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
2705 goto done;
2706 }
2707 vpanic("emit_X86Instr:mfence:hwcaps");
2708 /*NOTREACHED*/
sewardj3e838932005-01-07 12:09:15 +00002709 break;
2710
sewardje9d8a262009-07-01 08:06:34 +00002711 case Xin_ACAS:
2712 /* lock */
2713 *p++ = 0xF0;
2714 /* cmpxchg{b,w,l} %ebx,mem. Expected-value in %eax, new value
2715 in %ebx. The new-value register is hardwired to be %ebx
2716 since letting it be any integer register gives the problem
2717 that %sil and %dil are unaddressible on x86 and hence we
2718 would have to resort to the same kind of trickery as with
2719 byte-sized Xin.Store, just below. Given that this isn't
2720 performance critical, it is simpler just to force the
2721 register operand to %ebx (could equally be %ecx or %edx).
2722 (Although %ebx is more consistent with cmpxchg8b.) */
2723 if (i->Xin.ACAS.sz == 2) *p++ = 0x66;
2724 *p++ = 0x0F;
2725 if (i->Xin.ACAS.sz == 1) *p++ = 0xB0; else *p++ = 0xB1;
2726 p = doAMode_M(p, hregX86_EBX(), i->Xin.ACAS.addr);
2727 goto done;
2728
2729 case Xin_DACAS:
2730 /* lock */
2731 *p++ = 0xF0;
2732 /* cmpxchg8b m64. Expected-value in %edx:%eax, new value
2733 in %ecx:%ebx. All 4 regs are hardwired in the ISA, so
2734 aren't encoded in the insn. */
2735 *p++ = 0x0F;
2736 *p++ = 0xC7;
2737 p = doAMode_M(p, fake(1), i->Xin.DACAS.addr);
2738 goto done;
2739
sewardje8c922f2004-07-23 01:34:11 +00002740 case Xin_Store:
sewardjd75fe5a2004-07-23 12:57:47 +00002741 if (i->Xin.Store.sz == 2) {
2742 /* This case, at least, is simple, given that we can
2743 reference the low 16 bits of any integer register. */
2744 *p++ = 0x66;
2745 *p++ = 0x89;
2746 p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
2747 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002748 }
sewardjd75fe5a2004-07-23 12:57:47 +00002749
2750 if (i->Xin.Store.sz == 1) {
2751 /* We have to do complex dodging and weaving if src is not
2752 the low 8 bits of %eax/%ebx/%ecx/%edx. */
2753 if (iregNo(i->Xin.Store.src) < 4) {
2754 /* we're OK, can do it directly */
2755 *p++ = 0x88;
2756 p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
2757 goto done;
2758 } else {
2759 /* Bleh. This means the source is %edi or %esi. Since
2760 the address mode can only mention three registers, at
2761 least one of %eax/%ebx/%ecx/%edx must be available to
2762 temporarily swap the source into, so the store can
2763 happen. So we have to look at the regs mentioned
2764 in the amode. */
sewardj2e56f9f2004-07-24 01:24:38 +00002765 HReg swap = INVALID_HREG;
2766 HReg eax = hregX86_EAX(), ebx = hregX86_EBX(),
2767 ecx = hregX86_ECX(), edx = hregX86_EDX();
sewardjd75fe5a2004-07-23 12:57:47 +00002768 Bool a_ok = True, b_ok = True, c_ok = True, d_ok = True;
2769 HRegUsage u;
2770 Int j;
2771 initHRegUsage(&u);
2772 addRegUsage_X86AMode(&u, i->Xin.Store.dst);
2773 for (j = 0; j < u.n_used; j++) {
2774 HReg r = u.hreg[j];
2775 if (r == eax) a_ok = False;
2776 if (r == ebx) b_ok = False;
2777 if (r == ecx) c_ok = False;
2778 if (r == edx) d_ok = False;
2779 }
sewardjd75fe5a2004-07-23 12:57:47 +00002780 if (a_ok) swap = eax;
2781 if (b_ok) swap = ebx;
2782 if (c_ok) swap = ecx;
2783 if (d_ok) swap = edx;
2784 vassert(swap != INVALID_HREG);
2785 /* xchgl %source, %swap. Could do better if swap is %eax. */
2786 *p++ = 0x87;
2787 p = doAMode_R(p, i->Xin.Store.src, swap);
2788 /* movb lo8{%swap}, (dst) */
2789 *p++ = 0x88;
2790 p = doAMode_M(p, swap, i->Xin.Store.dst);
2791 /* xchgl %source, %swap. Could do better if swap is %eax. */
2792 *p++ = 0x87;
2793 p = doAMode_R(p, i->Xin.Store.src, swap);
2794 goto done;
2795 }
2796 } /* if (i->Xin.Store.sz == 1) */
2797 break;
sewardj86898e82004-07-22 17:26:12 +00002798
sewardjcfded9a2004-09-09 11:44:16 +00002799 case Xin_FpUnary:
2800 /* gop %src, %dst
2801 --> ffree %st7 ; fld %st(src) ; fop %st(0) ; fstp %st(1+dst)
2802 */
2803 p = do_ffree_st7(p);
2804 p = do_fld_st(p, 0+hregNumber(i->Xin.FpUnary.src));
2805 p = do_fop1_st(p, i->Xin.FpUnary.op);
2806 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpUnary.dst));
2807 goto done;
2808
sewardjbb53f8c2004-08-14 11:50:01 +00002809 case Xin_FpBinary:
sewardj06c32a02004-09-12 12:07:34 +00002810 if (i->Xin.FpBinary.op == Xfp_YL2X
2811 || i->Xin.FpBinary.op == Xfp_YL2XP1) {
sewardj8308aad2004-09-12 11:09:54 +00002812 /* Have to do this specially. */
2813 /* ffree %st7 ; fld %st(srcL) ;
sewardj06c32a02004-09-12 12:07:34 +00002814 ffree %st7 ; fld %st(srcR+1) ; fyl2x{p1} ; fstp(1+dst) */
sewardj8308aad2004-09-12 11:09:54 +00002815 p = do_ffree_st7(p);
2816 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
2817 p = do_ffree_st7(p);
2818 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
sewardj06c32a02004-09-12 12:07:34 +00002819 *p++ = 0xD9;
sewardj8ee8c882005-02-25 17:40:26 +00002820 *p++ = toUChar(i->Xin.FpBinary.op==Xfp_YL2X ? 0xF1 : 0xF9);
sewardj8308aad2004-09-12 11:09:54 +00002821 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2822 goto done;
2823 }
sewardj52ace3e2004-09-11 17:10:08 +00002824 if (i->Xin.FpBinary.op == Xfp_ATAN) {
sewardjcfded9a2004-09-09 11:44:16 +00002825 /* Have to do this specially. */
sewardj46de4072004-09-11 19:23:24 +00002826 /* ffree %st7 ; fld %st(srcL) ;
2827 ffree %st7 ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */
sewardjcfded9a2004-09-09 11:44:16 +00002828 p = do_ffree_st7(p);
2829 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
sewardj46de4072004-09-11 19:23:24 +00002830 p = do_ffree_st7(p);
sewardjcfded9a2004-09-09 11:44:16 +00002831 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
2832 *p++ = 0xD9; *p++ = 0xF3;
2833 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2834 goto done;
2835 }
sewardj06c32a02004-09-12 12:07:34 +00002836 if (i->Xin.FpBinary.op == Xfp_PREM
sewardj442d0be2004-10-15 22:57:13 +00002837 || i->Xin.FpBinary.op == Xfp_PREM1
sewardj06c32a02004-09-12 12:07:34 +00002838 || i->Xin.FpBinary.op == Xfp_SCALE) {
sewardj46de4072004-09-11 19:23:24 +00002839 /* Have to do this specially. */
2840 /* ffree %st7 ; fld %st(srcR) ;
sewardj442d0be2004-10-15 22:57:13 +00002841 ffree %st7 ; fld %st(srcL+1) ; fprem/fprem1/fscale ; fstp(2+dst) ;
sewardj46de4072004-09-11 19:23:24 +00002842 fincstp ; ffree %st7 */
2843 p = do_ffree_st7(p);
2844 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR));
2845 p = do_ffree_st7(p);
2846 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL));
sewardj442d0be2004-10-15 22:57:13 +00002847 *p++ = 0xD9;
2848 switch (i->Xin.FpBinary.op) {
2849 case Xfp_PREM: *p++ = 0xF8; break;
2850 case Xfp_PREM1: *p++ = 0xF5; break;
2851 case Xfp_SCALE: *p++ = 0xFD; break;
2852 default: vpanic("emitX86Instr(FpBinary,PREM/PREM1/SCALE)");
2853 }
sewardj46de4072004-09-11 19:23:24 +00002854 p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst));
2855 *p++ = 0xD9; *p++ = 0xF7;
2856 p = do_ffree_st7(p);
2857 goto done;
2858 }
sewardjcfded9a2004-09-09 11:44:16 +00002859 /* General case */
sewardjbb53f8c2004-08-14 11:50:01 +00002860 /* gop %srcL, %srcR, %dst
2861 --> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst)
2862 */
2863 p = do_ffree_st7(p);
2864 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
sewardj3bca9062004-12-04 14:36:09 +00002865 p = do_fop2_st(p, i->Xin.FpBinary.op,
2866 1+hregNumber(i->Xin.FpBinary.srcR));
sewardjbb53f8c2004-08-14 11:50:01 +00002867 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2868 goto done;
2869
sewardj3196daf2004-08-13 00:18:58 +00002870 case Xin_FpLdSt:
2871 if (i->Xin.FpLdSt.isLoad) {
2872 /* Load from memory into %fakeN.
sewardj7fb65eb2007-03-25 04:14:58 +00002873 --> ffree %st(7) ; fld{s/l/t} amode ; fstp st(N+1)
sewardj3196daf2004-08-13 00:18:58 +00002874 */
2875 p = do_ffree_st7(p);
sewardj7fb65eb2007-03-25 04:14:58 +00002876 switch (i->Xin.FpLdSt.sz) {
2877 case 4:
2878 *p++ = 0xD9;
2879 p = doAMode_M(p, fake(0)/*subopcode*/, i->Xin.FpLdSt.addr);
2880 break;
2881 case 8:
2882 *p++ = 0xDD;
2883 p = doAMode_M(p, fake(0)/*subopcode*/, i->Xin.FpLdSt.addr);
2884 break;
2885 case 10:
2886 *p++ = 0xDB;
2887 p = doAMode_M(p, fake(5)/*subopcode*/, i->Xin.FpLdSt.addr);
2888 break;
2889 default:
2890 vpanic("emitX86Instr(FpLdSt,load)");
2891 }
sewardj3196daf2004-08-13 00:18:58 +00002892 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdSt.reg));
2893 goto done;
2894 } else {
2895 /* Store from %fakeN into memory.
sewardjbb53f8c2004-08-14 11:50:01 +00002896 --> ffree %st(7) ; fld st(N) ; fstp{l|s} amode
sewardj3196daf2004-08-13 00:18:58 +00002897 */
2898 p = do_ffree_st7(p);
2899 p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdSt.reg));
sewardj7fb65eb2007-03-25 04:14:58 +00002900 switch (i->Xin.FpLdSt.sz) {
2901 case 4:
2902 *p++ = 0xD9;
2903 p = doAMode_M(p, fake(3)/*subopcode*/, i->Xin.FpLdSt.addr);
2904 break;
2905 case 8:
2906 *p++ = 0xDD;
2907 p = doAMode_M(p, fake(3)/*subopcode*/, i->Xin.FpLdSt.addr);
2908 break;
2909 case 10:
2910 *p++ = 0xDB;
2911 p = doAMode_M(p, fake(7)/*subopcode*/, i->Xin.FpLdSt.addr);
2912 break;
2913 default:
2914 vpanic("emitX86Instr(FpLdSt,store)");
2915 }
sewardj3196daf2004-08-13 00:18:58 +00002916 goto done;
2917 }
2918 break;
2919
sewardj89cd0932004-09-08 18:23:25 +00002920 case Xin_FpLdStI:
2921 if (i->Xin.FpLdStI.isLoad) {
2922 /* Load from memory into %fakeN, converting from an int.
2923 --> ffree %st(7) ; fild{w/l/ll} amode ; fstp st(N+1)
2924 */
2925 switch (i->Xin.FpLdStI.sz) {
sewardjbdc7d212004-09-09 02:46:40 +00002926 case 8: opc = 0xDF; subopc_imm = 5; break;
sewardj89cd0932004-09-08 18:23:25 +00002927 case 4: opc = 0xDB; subopc_imm = 0; break;
2928 case 2: vassert(0); opc = 0xDF; subopc_imm = 0; break;
2929 default: vpanic("emitX86Instr(Xin_FpLdStI-load)");
2930 }
2931 p = do_ffree_st7(p);
sewardj8ee8c882005-02-25 17:40:26 +00002932 *p++ = toUChar(opc);
sewardj89cd0932004-09-08 18:23:25 +00002933 p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr);
2934 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdStI.reg));
2935 goto done;
2936 } else {
2937 /* Store from %fakeN into memory, converting to an int.
2938 --> ffree %st(7) ; fld st(N) ; fistp{w/l/ll} amode
2939 */
2940 switch (i->Xin.FpLdStI.sz) {
sewardjcfded9a2004-09-09 11:44:16 +00002941 case 8: opc = 0xDF; subopc_imm = 7; break;
sewardj89cd0932004-09-08 18:23:25 +00002942 case 4: opc = 0xDB; subopc_imm = 3; break;
2943 case 2: opc = 0xDF; subopc_imm = 3; break;
2944 default: vpanic("emitX86Instr(Xin_FpLdStI-store)");
2945 }
2946 p = do_ffree_st7(p);
2947 p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdStI.reg));
sewardj8ee8c882005-02-25 17:40:26 +00002948 *p++ = toUChar(opc);
sewardj89cd0932004-09-08 18:23:25 +00002949 p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr);
2950 goto done;
2951 }
2952 break;
2953
sewardj3bca9062004-12-04 14:36:09 +00002954 case Xin_Fp64to32:
2955 /* ffree %st7 ; fld %st(src) */
2956 p = do_ffree_st7(p);
2957 p = do_fld_st(p, 0+fregNo(i->Xin.Fp64to32.src));
2958 /* subl $4, %esp */
2959 *p++ = 0x83; *p++ = 0xEC; *p++ = 0x04;
2960 /* fstps (%esp) */
2961 *p++ = 0xD9; *p++ = 0x1C; *p++ = 0x24;
2962 /* flds (%esp) */
2963 *p++ = 0xD9; *p++ = 0x04; *p++ = 0x24;
2964 /* addl $4, %esp */
2965 *p++ = 0x83; *p++ = 0xC4; *p++ = 0x04;
2966 /* fstp %st(1+dst) */
2967 p = do_fstp_st(p, 1+fregNo(i->Xin.Fp64to32.dst));
2968 goto done;
2969
sewardj3fc76d22004-08-31 11:47:54 +00002970 case Xin_FpCMov:
2971 /* jmp fwds if !condition */
sewardj8ee8c882005-02-25 17:40:26 +00002972 *p++ = toUChar(0x70 + (i->Xin.FpCMov.cond ^ 1));
sewardj3fc76d22004-08-31 11:47:54 +00002973 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2974 ptmp = p;
2975
2976 /* ffree %st7 ; fld %st(src) ; fstp %st(1+dst) */
2977 p = do_ffree_st7(p);
sewardjbdc7d212004-09-09 02:46:40 +00002978 p = do_fld_st(p, 0+fregNo(i->Xin.FpCMov.src));
2979 p = do_fstp_st(p, 1+fregNo(i->Xin.FpCMov.dst));
sewardj3fc76d22004-08-31 11:47:54 +00002980
2981 /* Fill in the jump offset. */
sewardj8ee8c882005-02-25 17:40:26 +00002982 *(ptmp-1) = toUChar(p - ptmp);
sewardj3fc76d22004-08-31 11:47:54 +00002983 goto done;
2984
sewardjeba63f82005-02-23 13:31:25 +00002985 case Xin_FpLdCW:
2986 *p++ = 0xD9;
2987 p = doAMode_M(p, fake(5)/*subopcode*/, i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00002988 goto done;
2989
sewardj46de4072004-09-11 19:23:24 +00002990 case Xin_FpStSW_AX:
2991 /* note, this emits fnstsw %ax, not fstsw %ax */
2992 *p++ = 0xDF;
2993 *p++ = 0xE0;
2994 goto done;
sewardjbdc7d212004-09-09 02:46:40 +00002995
2996 case Xin_FpCmp:
2997 /* gcmp %fL, %fR, %dst
2998 -> ffree %st7; fpush %fL ; fucomp %(fR+1) ;
2999 fnstsw %ax ; movl %eax, %dst
3000 */
3001 /* ffree %st7 */
3002 p = do_ffree_st7(p);
3003 /* fpush %fL */
3004 p = do_fld_st(p, 0+fregNo(i->Xin.FpCmp.srcL));
3005 /* fucomp %(fR+1) */
3006 *p++ = 0xDD;
sewardj8ee8c882005-02-25 17:40:26 +00003007 *p++ = toUChar(0xE8 + (7 & (1+fregNo(i->Xin.FpCmp.srcR))));
sewardjbdc7d212004-09-09 02:46:40 +00003008 /* fnstsw %ax */
3009 *p++ = 0xDF;
3010 *p++ = 0xE0;
3011 /* movl %eax, %dst */
3012 *p++ = 0x89;
3013 p = doAMode_R(p, hregX86_EAX(), i->Xin.FpCmp.dst);
3014 goto done;
3015
sewardj1e6ad742004-12-02 16:16:11 +00003016 case Xin_SseConst: {
3017 UShort con = i->Xin.SseConst.con;
sewardj8ee8c882005-02-25 17:40:26 +00003018 p = push_word_from_tags(p, toUShort((con >> 12) & 0xF));
3019 p = push_word_from_tags(p, toUShort((con >> 8) & 0xF));
3020 p = push_word_from_tags(p, toUShort((con >> 4) & 0xF));
3021 p = push_word_from_tags(p, toUShort(con & 0xF));
sewardj1e6ad742004-12-02 16:16:11 +00003022 /* movl (%esp), %xmm-dst */
3023 *p++ = 0x0F;
3024 *p++ = 0x10;
sewardj8ee8c882005-02-25 17:40:26 +00003025 *p++ = toUChar(0x04 + 8 * (7 & vregNo(i->Xin.SseConst.dst)));
sewardj1e6ad742004-12-02 16:16:11 +00003026 *p++ = 0x24;
3027 /* addl $16, %esp */
3028 *p++ = 0x83;
3029 *p++ = 0xC4;
3030 *p++ = 0x10;
3031 goto done;
3032 }
sewardj129b3d92004-12-05 15:42:05 +00003033
sewardjd08f2d72004-12-01 23:19:36 +00003034 case Xin_SseLdSt:
3035 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00003036 *p++ = toUChar(i->Xin.SseLdSt.isLoad ? 0x10 : 0x11);
sewardjd08f2d72004-12-01 23:19:36 +00003037 p = doAMode_M(p, fake(vregNo(i->Xin.SseLdSt.reg)), i->Xin.SseLdSt.addr);
3038 goto done;
3039
sewardj129b3d92004-12-05 15:42:05 +00003040 case Xin_SseLdzLO:
sewardj636ad762004-12-07 11:16:04 +00003041 vassert(i->Xin.SseLdzLO.sz == 4 || i->Xin.SseLdzLO.sz == 8);
3042 /* movs[sd] amode, %xmm-dst */
sewardj8ee8c882005-02-25 17:40:26 +00003043 *p++ = toUChar(i->Xin.SseLdzLO.sz==4 ? 0xF3 : 0xF2);
sewardj636ad762004-12-07 11:16:04 +00003044 *p++ = 0x0F;
3045 *p++ = 0x10;
3046 p = doAMode_M(p, fake(vregNo(i->Xin.SseLdzLO.reg)),
3047 i->Xin.SseLdzLO.addr);
3048 goto done;
sewardj129b3d92004-12-05 15:42:05 +00003049
sewardj1e6ad742004-12-02 16:16:11 +00003050 case Xin_Sse32Fx4:
3051 xtra = 0;
3052 *p++ = 0x0F;
3053 switch (i->Xin.Sse32Fx4.op) {
3054 case Xsse_ADDF: *p++ = 0x58; break;
sewardj176a59c2004-12-03 20:08:31 +00003055 case Xsse_DIVF: *p++ = 0x5E; break;
3056 case Xsse_MAXF: *p++ = 0x5F; break;
3057 case Xsse_MINF: *p++ = 0x5D; break;
sewardj9636b442004-12-04 01:38:37 +00003058 case Xsse_MULF: *p++ = 0x59; break;
sewardj0bd7ce62004-12-05 02:47:40 +00003059 case Xsse_RCPF: *p++ = 0x53; break;
sewardjc1e7dfc2004-12-05 19:29:45 +00003060 case Xsse_RSQRTF: *p++ = 0x52; break;
3061 case Xsse_SQRTF: *p++ = 0x51; break;
3062 case Xsse_SUBF: *p++ = 0x5C; break;
sewardj1e6ad742004-12-02 16:16:11 +00003063 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
3064 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
3065 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00003066 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj1e6ad742004-12-02 16:16:11 +00003067 default: goto bad;
3068 }
sewardjd08f2d72004-12-01 23:19:36 +00003069 p = doAMode_R(p, fake(vregNo(i->Xin.Sse32Fx4.dst)),
3070 fake(vregNo(i->Xin.Sse32Fx4.src)) );
sewardj1e6ad742004-12-02 16:16:11 +00003071 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00003072 *p++ = toUChar(xtra & 0xFF);
sewardj1e6ad742004-12-02 16:16:11 +00003073 goto done;
3074
sewardj636ad762004-12-07 11:16:04 +00003075 case Xin_Sse64Fx2:
3076 xtra = 0;
3077 *p++ = 0x66;
3078 *p++ = 0x0F;
3079 switch (i->Xin.Sse64Fx2.op) {
3080 case Xsse_ADDF: *p++ = 0x58; break;
3081 case Xsse_DIVF: *p++ = 0x5E; break;
3082 case Xsse_MAXF: *p++ = 0x5F; break;
3083 case Xsse_MINF: *p++ = 0x5D; break;
3084 case Xsse_MULF: *p++ = 0x59; break;
3085 case Xsse_RCPF: *p++ = 0x53; break;
3086 case Xsse_RSQRTF: *p++ = 0x52; break;
3087 case Xsse_SQRTF: *p++ = 0x51; break;
3088 case Xsse_SUBF: *p++ = 0x5C; break;
3089 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
3090 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
3091 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00003092 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj636ad762004-12-07 11:16:04 +00003093 default: goto bad;
3094 }
3095 p = doAMode_R(p, fake(vregNo(i->Xin.Sse64Fx2.dst)),
3096 fake(vregNo(i->Xin.Sse64Fx2.src)) );
3097 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00003098 *p++ = toUChar(xtra & 0xFF);
sewardj636ad762004-12-07 11:16:04 +00003099 goto done;
3100
sewardj1e6ad742004-12-02 16:16:11 +00003101 case Xin_Sse32FLo:
3102 xtra = 0;
3103 *p++ = 0xF3;
3104 *p++ = 0x0F;
3105 switch (i->Xin.Sse32FLo.op) {
3106 case Xsse_ADDF: *p++ = 0x58; break;
sewardj176a59c2004-12-03 20:08:31 +00003107 case Xsse_DIVF: *p++ = 0x5E; break;
3108 case Xsse_MAXF: *p++ = 0x5F; break;
3109 case Xsse_MINF: *p++ = 0x5D; break;
sewardj9636b442004-12-04 01:38:37 +00003110 case Xsse_MULF: *p++ = 0x59; break;
sewardj0bd7ce62004-12-05 02:47:40 +00003111 case Xsse_RCPF: *p++ = 0x53; break;
sewardjc1e7dfc2004-12-05 19:29:45 +00003112 case Xsse_RSQRTF: *p++ = 0x52; break;
3113 case Xsse_SQRTF: *p++ = 0x51; break;
3114 case Xsse_SUBF: *p++ = 0x5C; break;
sewardj1e6ad742004-12-02 16:16:11 +00003115 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
3116 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
3117 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00003118 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj1e6ad742004-12-02 16:16:11 +00003119 default: goto bad;
3120 }
3121 p = doAMode_R(p, fake(vregNo(i->Xin.Sse32FLo.dst)),
3122 fake(vregNo(i->Xin.Sse32FLo.src)) );
3123 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00003124 *p++ = toUChar(xtra & 0xFF);
sewardjd08f2d72004-12-01 23:19:36 +00003125 goto done;
3126
sewardj636ad762004-12-07 11:16:04 +00003127 case Xin_Sse64FLo:
3128 xtra = 0;
3129 *p++ = 0xF2;
3130 *p++ = 0x0F;
3131 switch (i->Xin.Sse64FLo.op) {
3132 case Xsse_ADDF: *p++ = 0x58; break;
3133 case Xsse_DIVF: *p++ = 0x5E; break;
3134 case Xsse_MAXF: *p++ = 0x5F; break;
3135 case Xsse_MINF: *p++ = 0x5D; break;
3136 case Xsse_MULF: *p++ = 0x59; break;
3137 case Xsse_RCPF: *p++ = 0x53; break;
3138 case Xsse_RSQRTF: *p++ = 0x52; break;
3139 case Xsse_SQRTF: *p++ = 0x51; break;
3140 case Xsse_SUBF: *p++ = 0x5C; break;
3141 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
3142 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
3143 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00003144 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj636ad762004-12-07 11:16:04 +00003145 default: goto bad;
3146 }
3147 p = doAMode_R(p, fake(vregNo(i->Xin.Sse64FLo.dst)),
3148 fake(vregNo(i->Xin.Sse64FLo.src)) );
3149 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00003150 *p++ = toUChar(xtra & 0xFF);
sewardj636ad762004-12-07 11:16:04 +00003151 goto done;
3152
sewardj164f9272004-12-09 00:39:32 +00003153 case Xin_SseReRg:
3154# define XX(_n) *p++ = (_n)
3155 switch (i->Xin.SseReRg.op) {
sewardj9e203592004-12-10 01:48:18 +00003156 case Xsse_MOV: /*movups*/ XX(0x0F); XX(0x10); break;
3157 case Xsse_OR: XX(0x0F); XX(0x56); break;
3158 case Xsse_XOR: XX(0x0F); XX(0x57); break;
3159 case Xsse_AND: XX(0x0F); XX(0x54); break;
sewardje5854d62004-12-09 03:44:34 +00003160 case Xsse_PACKSSD: XX(0x66); XX(0x0F); XX(0x6B); break;
3161 case Xsse_PACKSSW: XX(0x66); XX(0x0F); XX(0x63); break;
3162 case Xsse_PACKUSW: XX(0x66); XX(0x0F); XX(0x67); break;
3163 case Xsse_ADD8: XX(0x66); XX(0x0F); XX(0xFC); break;
3164 case Xsse_ADD16: XX(0x66); XX(0x0F); XX(0xFD); break;
3165 case Xsse_ADD32: XX(0x66); XX(0x0F); XX(0xFE); break;
3166 case Xsse_ADD64: XX(0x66); XX(0x0F); XX(0xD4); break;
3167 case Xsse_QADD8S: XX(0x66); XX(0x0F); XX(0xEC); break;
3168 case Xsse_QADD16S: XX(0x66); XX(0x0F); XX(0xED); break;
3169 case Xsse_QADD8U: XX(0x66); XX(0x0F); XX(0xDC); break;
3170 case Xsse_QADD16U: XX(0x66); XX(0x0F); XX(0xDD); break;
3171 case Xsse_AVG8U: XX(0x66); XX(0x0F); XX(0xE0); break;
3172 case Xsse_AVG16U: XX(0x66); XX(0x0F); XX(0xE3); break;
3173 case Xsse_CMPEQ8: XX(0x66); XX(0x0F); XX(0x74); break;
3174 case Xsse_CMPEQ16: XX(0x66); XX(0x0F); XX(0x75); break;
3175 case Xsse_CMPEQ32: XX(0x66); XX(0x0F); XX(0x76); break;
3176 case Xsse_CMPGT8S: XX(0x66); XX(0x0F); XX(0x64); break;
3177 case Xsse_CMPGT16S: XX(0x66); XX(0x0F); XX(0x65); break;
3178 case Xsse_CMPGT32S: XX(0x66); XX(0x0F); XX(0x66); break;
3179 case Xsse_MAX16S: XX(0x66); XX(0x0F); XX(0xEE); break;
3180 case Xsse_MAX8U: XX(0x66); XX(0x0F); XX(0xDE); break;
3181 case Xsse_MIN16S: XX(0x66); XX(0x0F); XX(0xEA); break;
3182 case Xsse_MIN8U: XX(0x66); XX(0x0F); XX(0xDA); break;
3183 case Xsse_MULHI16U: XX(0x66); XX(0x0F); XX(0xE4); break;
3184 case Xsse_MULHI16S: XX(0x66); XX(0x0F); XX(0xE5); break;
3185 case Xsse_MUL16: XX(0x66); XX(0x0F); XX(0xD5); break;
sewardjb9fa69b2004-12-09 23:25:14 +00003186 case Xsse_SHL16: XX(0x66); XX(0x0F); XX(0xF1); break;
3187 case Xsse_SHL32: XX(0x66); XX(0x0F); XX(0xF2); break;
3188 case Xsse_SHL64: XX(0x66); XX(0x0F); XX(0xF3); break;
3189 case Xsse_SAR16: XX(0x66); XX(0x0F); XX(0xE1); break;
3190 case Xsse_SAR32: XX(0x66); XX(0x0F); XX(0xE2); break;
3191 case Xsse_SHR16: XX(0x66); XX(0x0F); XX(0xD1); break;
3192 case Xsse_SHR32: XX(0x66); XX(0x0F); XX(0xD2); break;
3193 case Xsse_SHR64: XX(0x66); XX(0x0F); XX(0xD3); break;
3194 case Xsse_SUB8: XX(0x66); XX(0x0F); XX(0xF8); break;
3195 case Xsse_SUB16: XX(0x66); XX(0x0F); XX(0xF9); break;
3196 case Xsse_SUB32: XX(0x66); XX(0x0F); XX(0xFA); break;
3197 case Xsse_SUB64: XX(0x66); XX(0x0F); XX(0xFB); break;
3198 case Xsse_QSUB8S: XX(0x66); XX(0x0F); XX(0xE8); break;
3199 case Xsse_QSUB16S: XX(0x66); XX(0x0F); XX(0xE9); break;
3200 case Xsse_QSUB8U: XX(0x66); XX(0x0F); XX(0xD8); break;
3201 case Xsse_QSUB16U: XX(0x66); XX(0x0F); XX(0xD9); break;
sewardj9e203592004-12-10 01:48:18 +00003202 case Xsse_UNPCKHB: XX(0x66); XX(0x0F); XX(0x68); break;
3203 case Xsse_UNPCKHW: XX(0x66); XX(0x0F); XX(0x69); break;
3204 case Xsse_UNPCKHD: XX(0x66); XX(0x0F); XX(0x6A); break;
3205 case Xsse_UNPCKHQ: XX(0x66); XX(0x0F); XX(0x6D); break;
3206 case Xsse_UNPCKLB: XX(0x66); XX(0x0F); XX(0x60); break;
3207 case Xsse_UNPCKLW: XX(0x66); XX(0x0F); XX(0x61); break;
3208 case Xsse_UNPCKLD: XX(0x66); XX(0x0F); XX(0x62); break;
3209 case Xsse_UNPCKLQ: XX(0x66); XX(0x0F); XX(0x6C); break;
sewardj164f9272004-12-09 00:39:32 +00003210 default: goto bad;
3211 }
3212 p = doAMode_R(p, fake(vregNo(i->Xin.SseReRg.dst)),
3213 fake(vregNo(i->Xin.SseReRg.src)) );
3214# undef XX
3215 goto done;
3216
sewardjb9fa69b2004-12-09 23:25:14 +00003217 case Xin_SseCMov:
3218 /* jmp fwds if !condition */
sewardj8ee8c882005-02-25 17:40:26 +00003219 *p++ = toUChar(0x70 + (i->Xin.SseCMov.cond ^ 1));
sewardjb9fa69b2004-12-09 23:25:14 +00003220 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
3221 ptmp = p;
3222
3223 /* movaps %src, %dst */
3224 *p++ = 0x0F;
3225 *p++ = 0x28;
3226 p = doAMode_R(p, fake(vregNo(i->Xin.SseCMov.dst)),
3227 fake(vregNo(i->Xin.SseCMov.src)) );
3228
3229 /* Fill in the jump offset. */
sewardj8ee8c882005-02-25 17:40:26 +00003230 *(ptmp-1) = toUChar(p - ptmp);
sewardjb9fa69b2004-12-09 23:25:14 +00003231 goto done;
3232
sewardj109ffdb2004-12-10 21:45:38 +00003233 case Xin_SseShuf:
3234 *p++ = 0x66;
3235 *p++ = 0x0F;
3236 *p++ = 0x70;
3237 p = doAMode_R(p, fake(vregNo(i->Xin.SseShuf.dst)),
3238 fake(vregNo(i->Xin.SseShuf.src)) );
3239 *p++ = (UChar)(i->Xin.SseShuf.order);
3240 goto done;
3241
sewardjc6f970f2012-04-02 21:54:49 +00003242 case Xin_EvCheck: {
3243 /* We generate:
3244 (3 bytes) decl 4(%ebp) 4 == offsetof(host_EvC_COUNTER)
3245 (2 bytes) jns nofail expected taken
3246 (3 bytes) jmp* 0(%ebp) 0 == offsetof(host_EvC_FAILADDR)
3247 nofail:
3248 */
3249 /* This is heavily asserted re instruction lengths. It needs to
3250 be. If we get given unexpected forms of .amCounter or
3251 .amFailAddr -- basically, anything that's not of the form
3252 uimm7(%ebp) -- they are likely to fail. */
3253 /* Note also that after the decl we must be very careful not to
3254 read the carry flag, else we get a partial flags stall.
3255 js/jns avoids that, though. */
3256 UChar* p0 = p;
3257 /* --- decl 8(%ebp) --- */
3258 /* "fake(1)" because + there's no register in this encoding;
3259 instead the register + field is used as a sub opcode. The
3260 encoding for "decl r/m32" + is FF /1, hence the fake(1). */
3261 *p++ = 0xFF;
3262 p = doAMode_M(p, fake(1), i->Xin.EvCheck.amCounter);
3263 vassert(p - p0 == 3);
3264 /* --- jns nofail --- */
3265 *p++ = 0x79;
3266 *p++ = 0x03; /* need to check this 0x03 after the next insn */
3267 vassert(p - p0 == 5);
3268 /* --- jmp* 0(%ebp) --- */
3269 /* The encoding is FF /4. */
3270 *p++ = 0xFF;
3271 p = doAMode_M(p, fake(4), i->Xin.EvCheck.amFailAddr);
3272 vassert(p - p0 == 8); /* also ensures that 0x03 offset above is ok */
3273 /* And crosscheck .. */
3274 vassert(evCheckSzB_X86() == 8);
3275 goto done;
3276 }
3277
3278 case Xin_ProfInc: {
3279 /* We generate addl $1,NotKnownYet
3280 adcl $0,NotKnownYet+4
3281 in the expectation that a later call to LibVEX_patchProfCtr
3282 will be used to fill in the immediate fields once the right
3283 value is known.
3284 83 05 00 00 00 00 01
3285 83 15 00 00 00 00 00
3286 */
3287 *p++ = 0x83; *p++ = 0x05;
3288 *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
3289 *p++ = 0x01;
3290 *p++ = 0x83; *p++ = 0x15;
3291 *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
3292 *p++ = 0x00;
3293 /* Tell the caller .. */
3294 vassert(!(*is_profInc));
3295 *is_profInc = True;
3296 goto done;
3297 }
3298
sewardjea64e142004-07-22 16:47:21 +00003299 default:
3300 goto bad;
sewardj81bd5502004-07-21 18:49:27 +00003301 }
sewardjea64e142004-07-22 16:47:21 +00003302
3303 bad:
cerion92b64362005-12-13 12:02:26 +00003304 ppX86Instr(i, mode64);
sewardjea64e142004-07-22 16:47:21 +00003305 vpanic("emit_X86Instr");
3306 /*NOTREACHED*/
3307
sewardjbad34a92004-07-22 01:14:11 +00003308 done:
3309 vassert(p - &buf[0] <= 32);
3310 return p - &buf[0];
sewardjea64e142004-07-22 16:47:21 +00003311
sewardjd75fe5a2004-07-23 12:57:47 +00003312# undef fake
sewardj81bd5502004-07-21 18:49:27 +00003313}
3314
sewardjc6f970f2012-04-02 21:54:49 +00003315
3316/* How big is an event check? See case for Xin_EvCheck in
3317 emit_X86Instr just above. That crosschecks what this returns, so
3318 we can tell if we're inconsistent. */
3319Int evCheckSzB_X86 ( void )
3320{
3321 return 8;
3322}
3323
3324
3325/* NB: what goes on here has to be very closely coordinated with the
3326 emitInstr case for XDirect, above. */
3327VexInvalRange chainXDirect_X86 ( void* place_to_chain,
3328 void* disp_cp_chain_me_EXPECTED,
3329 void* place_to_jump_to )
3330{
3331 /* What we're expecting to see is:
3332 movl $disp_cp_chain_me_EXPECTED, %edx
3333 call *%edx
3334 viz
3335 BA <4 bytes value == disp_cp_chain_me_EXPECTED>
3336 FF D2
3337 */
3338 UChar* p = (UChar*)place_to_chain;
3339 vassert(p[0] == 0xBA);
3340 vassert(*(UInt*)(&p[1]) == (UInt)Ptr_to_ULong(disp_cp_chain_me_EXPECTED));
3341 vassert(p[5] == 0xFF);
3342 vassert(p[6] == 0xD2);
3343 /* And what we want to change it to is:
3344 jmp disp32 where disp32 is relative to the next insn
3345 ud2;
3346 viz
3347 E9 <4 bytes == disp32>
3348 0F 0B
3349 The replacement has the same length as the original.
3350 */
3351 /* This is the delta we need to put into a JMP d32 insn. It's
3352 relative to the start of the next insn, hence the -5. */
3353 Long delta = (Long)((UChar*)place_to_jump_to - (UChar*)p) - (Long)5;
3354
3355 /* And make the modifications. */
3356 p[0] = 0xE9;
3357 p[1] = (delta >> 0) & 0xFF;
3358 p[2] = (delta >> 8) & 0xFF;
3359 p[3] = (delta >> 16) & 0xFF;
3360 p[4] = (delta >> 24) & 0xFF;
3361 p[5] = 0x0F; p[6] = 0x0B;
3362 /* sanity check on the delta -- top 32 are all 0 or all 1 */
3363 delta >>= 32;
3364 vassert(delta == 0LL || delta == -1LL);
florian5ea257b2012-09-29 17:05:46 +00003365 VexInvalRange vir = { (HWord)place_to_chain, 7 };
sewardjc6f970f2012-04-02 21:54:49 +00003366 return vir;
3367}
3368
3369
3370/* NB: what goes on here has to be very closely coordinated with the
3371 emitInstr case for XDirect, above. */
3372VexInvalRange unchainXDirect_X86 ( void* place_to_unchain,
3373 void* place_to_jump_to_EXPECTED,
3374 void* disp_cp_chain_me )
3375{
3376 /* What we're expecting to see is:
3377 jmp d32
3378 ud2;
3379 viz
3380 E9 <4 bytes == disp32>
3381 0F 0B
3382 */
3383 UChar* p = (UChar*)place_to_unchain;
3384 Bool valid = False;
3385 if (p[0] == 0xE9
3386 && p[5] == 0x0F && p[6] == 0x0B) {
3387 /* Check the offset is right. */
3388 Int s32 = *(Int*)(&p[1]);
3389 if ((UChar*)p + 5 + s32 == (UChar*)place_to_jump_to_EXPECTED) {
3390 valid = True;
3391 if (0)
3392 vex_printf("QQQ unchainXDirect_X86: found valid\n");
3393 }
3394 }
3395 vassert(valid);
3396 /* And what we want to change it to is:
3397 movl $disp_cp_chain_me, %edx
3398 call *%edx
3399 viz
3400 BA <4 bytes value == disp_cp_chain_me_EXPECTED>
3401 FF D2
3402 So it's the same length (convenient, huh).
3403 */
3404 p[0] = 0xBA;
3405 *(UInt*)(&p[1]) = (UInt)Ptr_to_ULong(disp_cp_chain_me);
3406 p[5] = 0xFF;
3407 p[6] = 0xD2;
florian5ea257b2012-09-29 17:05:46 +00003408 VexInvalRange vir = { (HWord)place_to_unchain, 7 };
sewardjc6f970f2012-04-02 21:54:49 +00003409 return vir;
3410}
3411
3412
3413/* Patch the counter address into a profile inc point, as previously
3414 created by the Xin_ProfInc case for emit_X86Instr. */
3415VexInvalRange patchProfInc_X86 ( void* place_to_patch,
3416 ULong* location_of_counter )
3417{
3418 vassert(sizeof(ULong*) == 4);
3419 UChar* p = (UChar*)place_to_patch;
3420 vassert(p[0] == 0x83);
3421 vassert(p[1] == 0x05);
3422 vassert(p[2] == 0x00);
3423 vassert(p[3] == 0x00);
3424 vassert(p[4] == 0x00);
3425 vassert(p[5] == 0x00);
3426 vassert(p[6] == 0x01);
3427 vassert(p[7] == 0x83);
3428 vassert(p[8] == 0x15);
3429 vassert(p[9] == 0x00);
3430 vassert(p[10] == 0x00);
3431 vassert(p[11] == 0x00);
3432 vassert(p[12] == 0x00);
3433 vassert(p[13] == 0x00);
3434 UInt imm32 = (UInt)Ptr_to_ULong(location_of_counter);
3435 p[2] = imm32 & 0xFF; imm32 >>= 8;
3436 p[3] = imm32 & 0xFF; imm32 >>= 8;
3437 p[4] = imm32 & 0xFF; imm32 >>= 8;
3438 p[5] = imm32 & 0xFF; imm32 >>= 8;
3439 imm32 = 4 + (UInt)Ptr_to_ULong(location_of_counter);
3440 p[9] = imm32 & 0xFF; imm32 >>= 8;
3441 p[10] = imm32 & 0xFF; imm32 >>= 8;
3442 p[11] = imm32 & 0xFF; imm32 >>= 8;
3443 p[12] = imm32 & 0xFF; imm32 >>= 8;
florian5ea257b2012-09-29 17:05:46 +00003444 VexInvalRange vir = { (HWord)place_to_patch, 14 };
sewardjc6f970f2012-04-02 21:54:49 +00003445 return vir;
3446}
3447
3448
sewardj35421a32004-07-05 13:12:34 +00003449/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00003450/*--- end host_x86_defs.c ---*/
sewardj35421a32004-07-05 13:12:34 +00003451/*---------------------------------------------------------------*/