blob: a01a3deb704ef30447b2c142fcb7465b916bdf2b [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
sewardjb5e7ced2013-01-24 08:55:25 +00001864static UChar mkModRegRM ( UInt mod, UInt reg, UInt regmem )
sewardjbad34a92004-07-22 01:14:11 +00001865{
sewardjb5e7ced2013-01-24 08:55:25 +00001866 vassert(mod < 4);
1867 vassert((reg|regmem) < 8);
sewardj8ee8c882005-02-25 17:40:26 +00001868 return toUChar( ((mod & 3) << 6)
1869 | ((reg & 7) << 3)
1870 | (regmem & 7) );
sewardjbad34a92004-07-22 01:14:11 +00001871}
1872
sewardjb5e7ced2013-01-24 08:55:25 +00001873static UChar mkSIB ( UInt shift, UInt regindex, UInt regbase )
sewardjbad34a92004-07-22 01:14:11 +00001874{
sewardjb5e7ced2013-01-24 08:55:25 +00001875 vassert(shift < 4);
1876 vassert((regindex|regbase) < 8);
sewardj8ee8c882005-02-25 17:40:26 +00001877 return toUChar( ((shift & 3) << 6)
1878 | ((regindex & 7) << 3)
1879 | (regbase & 7) );
sewardjbad34a92004-07-22 01:14:11 +00001880}
1881
1882static UChar* emit32 ( UChar* p, UInt w32 )
1883{
sewardj8ee8c882005-02-25 17:40:26 +00001884 *p++ = toUChar( w32 & 0x000000FF);
1885 *p++ = toUChar((w32 >> 8) & 0x000000FF);
1886 *p++ = toUChar((w32 >> 16) & 0x000000FF);
1887 *p++ = toUChar((w32 >> 24) & 0x000000FF);
sewardjbad34a92004-07-22 01:14:11 +00001888 return p;
1889}
1890
sewardjea64e142004-07-22 16:47:21 +00001891/* Does a sign-extend of the lowest 8 bits give
1892 the original number? */
sewardjbad34a92004-07-22 01:14:11 +00001893static Bool fits8bits ( UInt w32 )
1894{
sewardjea64e142004-07-22 16:47:21 +00001895 Int i32 = (Int)w32;
sewardj8ee8c882005-02-25 17:40:26 +00001896 return toBool(i32 == ((i32 << 24) >> 24));
sewardjbad34a92004-07-22 01:14:11 +00001897}
1898
1899
1900/* Forming mod-reg-rm bytes and scale-index-base bytes.
1901
1902 greg, 0(ereg) | ereg != ESP && ereg != EBP
1903 = 00 greg ereg
1904
1905 greg, d8(ereg) | ereg != ESP
1906 = 01 greg ereg, d8
1907
1908 greg, d32(ereg) | ereg != ESP
1909 = 10 greg ereg, d32
1910
sewardja58ea662004-08-15 03:12:41 +00001911 greg, d8(%esp) = 01 greg 100, 0x24, d8
1912
sewardjbad34a92004-07-22 01:14:11 +00001913 -----------------------------------------------
1914
1915 greg, d8(base,index,scale)
1916 | index != ESP
1917 = 01 greg 100, scale index base, d8
1918
1919 greg, d32(base,index,scale)
1920 | index != ESP
1921 = 10 greg 100, scale index base, d32
1922*/
1923static UChar* doAMode_M ( UChar* p, HReg greg, X86AMode* am )
1924{
1925 if (am->tag == Xam_IR) {
1926 if (am->Xam.IR.imm == 0
1927 && am->Xam.IR.reg != hregX86_ESP()
1928 && am->Xam.IR.reg != hregX86_EBP() ) {
1929 *p++ = mkModRegRM(0, iregNo(greg), iregNo(am->Xam.IR.reg));
1930 return p;
1931 }
1932 if (fits8bits(am->Xam.IR.imm)
1933 && am->Xam.IR.reg != hregX86_ESP()) {
1934 *p++ = mkModRegRM(1, iregNo(greg), iregNo(am->Xam.IR.reg));
sewardj8ee8c882005-02-25 17:40:26 +00001935 *p++ = toUChar(am->Xam.IR.imm & 0xFF);
sewardjbad34a92004-07-22 01:14:11 +00001936 return p;
1937 }
1938 if (am->Xam.IR.reg != hregX86_ESP()) {
1939 *p++ = mkModRegRM(2, iregNo(greg), iregNo(am->Xam.IR.reg));
1940 p = emit32(p, am->Xam.IR.imm);
1941 return p;
1942 }
sewardja58ea662004-08-15 03:12:41 +00001943 if (am->Xam.IR.reg == hregX86_ESP()
1944 && fits8bits(am->Xam.IR.imm)) {
1945 *p++ = mkModRegRM(1, iregNo(greg), 4);
1946 *p++ = 0x24;
sewardj8ee8c882005-02-25 17:40:26 +00001947 *p++ = toUChar(am->Xam.IR.imm & 0xFF);
sewardja58ea662004-08-15 03:12:41 +00001948 return p;
1949 }
sewardjbad34a92004-07-22 01:14:11 +00001950 ppX86AMode(am);
1951 vpanic("doAMode_M: can't emit amode IR");
1952 /*NOTREACHED*/
1953 }
1954 if (am->tag == Xam_IRRS) {
1955 if (fits8bits(am->Xam.IRRS.imm)
1956 && am->Xam.IRRS.index != hregX86_ESP()) {
1957 *p++ = mkModRegRM(1, iregNo(greg), 4);
sewardjb5e7ced2013-01-24 08:55:25 +00001958 *p++ = mkSIB(am->Xam.IRRS.shift, iregNo(am->Xam.IRRS.index),
1959 iregNo(am->Xam.IRRS.base));
sewardj8ee8c882005-02-25 17:40:26 +00001960 *p++ = toUChar(am->Xam.IRRS.imm & 0xFF);
sewardjbad34a92004-07-22 01:14:11 +00001961 return p;
1962 }
1963 if (am->Xam.IRRS.index != hregX86_ESP()) {
1964 *p++ = mkModRegRM(2, iregNo(greg), 4);
sewardjb5e7ced2013-01-24 08:55:25 +00001965 *p++ = mkSIB(am->Xam.IRRS.shift, iregNo(am->Xam.IRRS.index),
1966 iregNo(am->Xam.IRRS.base));
sewardjbad34a92004-07-22 01:14:11 +00001967 p = emit32(p, am->Xam.IRRS.imm);
1968 return p;
1969 }
1970 ppX86AMode(am);
1971 vpanic("doAMode_M: can't emit amode IRRS");
1972 /*NOTREACHED*/
1973 }
1974 vpanic("doAMode_M: unknown amode");
1975 /*NOTREACHED*/
1976}
1977
1978
1979/* Emit a mod-reg-rm byte when the rm bit denotes a reg. */
1980static UChar* doAMode_R ( UChar* p, HReg greg, HReg ereg )
1981{
1982 *p++ = mkModRegRM(3, iregNo(greg), iregNo(ereg));
1983 return p;
1984}
1985
1986
sewardj3196daf2004-08-13 00:18:58 +00001987/* Emit ffree %st(7) */
1988static UChar* do_ffree_st7 ( UChar* p )
1989{
1990 *p++ = 0xDD;
1991 *p++ = 0xC7;
1992 return p;
1993}
1994
sewardjeafde5a2004-10-09 01:36:57 +00001995/* Emit fstp %st(i), 1 <= i <= 7 */
sewardj3196daf2004-08-13 00:18:58 +00001996static UChar* do_fstp_st ( UChar* p, Int i )
1997{
sewardjeafde5a2004-10-09 01:36:57 +00001998 vassert(1 <= i && i <= 7);
sewardj3196daf2004-08-13 00:18:58 +00001999 *p++ = 0xDD;
sewardj8ee8c882005-02-25 17:40:26 +00002000 *p++ = toUChar(0xD8+i);
sewardj3196daf2004-08-13 00:18:58 +00002001 return p;
2002}
2003
sewardjb3944c22004-10-15 22:22:09 +00002004/* Emit fld %st(i), 0 <= i <= 6 */
sewardj3196daf2004-08-13 00:18:58 +00002005static UChar* do_fld_st ( UChar* p, Int i )
2006{
sewardjb3944c22004-10-15 22:22:09 +00002007 vassert(0 <= i && i <= 6);
sewardj3196daf2004-08-13 00:18:58 +00002008 *p++ = 0xD9;
sewardj8ee8c882005-02-25 17:40:26 +00002009 *p++ = toUChar(0xC0+i);
sewardj3196daf2004-08-13 00:18:58 +00002010 return p;
2011}
2012
sewardjcfded9a2004-09-09 11:44:16 +00002013/* Emit f<op> %st(0) */
2014static UChar* do_fop1_st ( UChar* p, X86FpOp op )
2015{
2016 switch (op) {
sewardj883b00b2004-09-11 09:30:24 +00002017 case Xfp_NEG: *p++ = 0xD9; *p++ = 0xE0; break;
2018 case Xfp_ABS: *p++ = 0xD9; *p++ = 0xE1; break;
sewardjc4be80c2004-09-10 16:17:45 +00002019 case Xfp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break;
sewardje6709112004-09-10 18:37:18 +00002020 case Xfp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break;
sewardjcfded9a2004-09-09 11:44:16 +00002021 case Xfp_SIN: *p++ = 0xD9; *p++ = 0xFE; break;
2022 case Xfp_COS: *p++ = 0xD9; *p++ = 0xFF; break;
sewardj06c32a02004-09-12 12:07:34 +00002023 case Xfp_2XM1: *p++ = 0xD9; *p++ = 0xF0; break;
sewardjbec10842004-10-12 13:44:45 +00002024 case Xfp_MOV: break;
sewardj99016a72004-10-15 22:09:17 +00002025 case Xfp_TAN: p = do_ffree_st7(p); /* since fptan pushes 1.0 */
2026 *p++ = 0xD9; *p++ = 0xF2; /* fptan */
2027 *p++ = 0xD9; *p++ = 0xF7; /* fincstp */
2028 break;
sewardjcfded9a2004-09-09 11:44:16 +00002029 default: vpanic("do_fop1_st: unknown op");
2030 }
2031 return p;
2032}
2033
sewardjbb53f8c2004-08-14 11:50:01 +00002034/* Emit f<op> %st(i), 1 <= i <= 5 */
sewardjcfded9a2004-09-09 11:44:16 +00002035static UChar* do_fop2_st ( UChar* p, X86FpOp op, Int i )
sewardjbb53f8c2004-08-14 11:50:01 +00002036{
sewardj4a31b262004-12-01 02:24:44 +00002037# define fake(_n) mkHReg((_n), HRcInt32, False)
sewardjbb53f8c2004-08-14 11:50:01 +00002038 Int subopc;
2039 switch (op) {
sewardja58ea662004-08-15 03:12:41 +00002040 case Xfp_ADD: subopc = 0; break;
sewardjce646f22004-08-31 23:55:54 +00002041 case Xfp_SUB: subopc = 4; break;
sewardjbb53f8c2004-08-14 11:50:01 +00002042 case Xfp_MUL: subopc = 1; break;
sewardjce646f22004-08-31 23:55:54 +00002043 case Xfp_DIV: subopc = 6; break;
sewardjcfded9a2004-09-09 11:44:16 +00002044 default: vpanic("do_fop2_st: unknown op");
sewardjbb53f8c2004-08-14 11:50:01 +00002045 }
2046 *p++ = 0xD8;
2047 p = doAMode_R(p, fake(subopc), fake(i));
2048 return p;
2049# undef fake
2050}
sewardjbad34a92004-07-22 01:14:11 +00002051
sewardj1e6ad742004-12-02 16:16:11 +00002052/* Push a 32-bit word on the stack. The word depends on tags[3:0];
2053each byte is either 0x00 or 0xFF depending on the corresponding bit in tags[].
2054*/
2055static UChar* push_word_from_tags ( UChar* p, UShort tags )
2056{
2057 UInt w;
2058 vassert(0 == (tags & ~0xF));
2059 if (tags == 0) {
2060 /* pushl $0x00000000 */
2061 *p++ = 0x6A;
2062 *p++ = 0x00;
2063 }
2064 else
2065 /* pushl $0xFFFFFFFF */
2066 if (tags == 0xF) {
2067 *p++ = 0x6A;
2068 *p++ = 0xFF;
2069 } else {
2070 vassert(0); /* awaiting test case */
2071 w = 0;
2072 if (tags & 1) w |= 0x000000FF;
2073 if (tags & 2) w |= 0x0000FF00;
2074 if (tags & 4) w |= 0x00FF0000;
2075 if (tags & 8) w |= 0xFF000000;
2076 *p++ = 0x68;
2077 p = emit32(p, w);
2078 }
2079 return p;
2080}
2081
sewardj81bd5502004-07-21 18:49:27 +00002082/* Emit an instruction into buf and return the number of bytes used.
2083 Note that buf is not the insn's final place, and therefore it is
sewardjc6f970f2012-04-02 21:54:49 +00002084 imperative to emit position-independent code. If the emitted
2085 instruction was a profiler inc, set *is_profInc to True, else
2086 leave it unchanged. */
sewardj81bd5502004-07-21 18:49:27 +00002087
sewardjc6f970f2012-04-02 21:54:49 +00002088Int emit_X86Instr ( /*MB_MOD*/Bool* is_profInc,
2089 UChar* buf, Int nbuf, X86Instr* i,
sewardj010ac542011-05-29 09:29:18 +00002090 Bool mode64,
sewardjc6f970f2012-04-02 21:54:49 +00002091 void* disp_cp_chain_me_to_slowEP,
2092 void* disp_cp_chain_me_to_fastEP,
2093 void* disp_cp_xindir,
2094 void* disp_cp_xassisted )
sewardj81bd5502004-07-21 18:49:27 +00002095{
sewardj4b861de2004-11-03 15:24:42 +00002096 UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
sewardjea64e142004-07-22 16:47:21 +00002097
sewardj1e6ad742004-12-02 16:16:11 +00002098 UInt xtra;
sewardjbad34a92004-07-22 01:14:11 +00002099 UChar* p = &buf[0];
sewardj750f4072004-07-26 22:39:11 +00002100 UChar* ptmp;
sewardjbad34a92004-07-22 01:14:11 +00002101 vassert(nbuf >= 32);
cerion92b64362005-12-13 12:02:26 +00002102 vassert(mode64 == False);
sewardjbad34a92004-07-22 01:14:11 +00002103
sewardjea64e142004-07-22 16:47:21 +00002104 /* Wrap an integer as a int register, for use assembling
2105 GrpN insns, in which the greg field is used as a sub-opcode
2106 and does not really contain a register. */
sewardj4a31b262004-12-01 02:24:44 +00002107# define fake(_n) mkHReg((_n), HRcInt32, False)
sewardjea64e142004-07-22 16:47:21 +00002108
cerion92b64362005-12-13 12:02:26 +00002109 /* vex_printf("asm ");ppX86Instr(i, mode64); vex_printf("\n"); */
sewardjbec10842004-10-12 13:44:45 +00002110
sewardj81bd5502004-07-21 18:49:27 +00002111 switch (i->tag) {
sewardjbad34a92004-07-22 01:14:11 +00002112
2113 case Xin_Alu32R:
sewardjea64e142004-07-22 16:47:21 +00002114 /* Deal specially with MOV */
sewardjbad34a92004-07-22 01:14:11 +00002115 if (i->Xin.Alu32R.op == Xalu_MOV) {
2116 switch (i->Xin.Alu32R.src->tag) {
sewardjea64e142004-07-22 16:47:21 +00002117 case Xrmi_Imm:
sewardj8ee8c882005-02-25 17:40:26 +00002118 *p++ = toUChar(0xB8 + iregNo(i->Xin.Alu32R.dst));
sewardjea64e142004-07-22 16:47:21 +00002119 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
2120 goto done;
2121 case Xrmi_Reg:
sewardj750f4072004-07-26 22:39:11 +00002122 *p++ = 0x89;
2123 p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg,
2124 i->Xin.Alu32R.dst);
2125 goto done;
sewardjea64e142004-07-22 16:47:21 +00002126 case Xrmi_Mem:
2127 *p++ = 0x8B;
2128 p = doAMode_M(p, i->Xin.Alu32R.dst,
2129 i->Xin.Alu32R.src->Xrmi.Mem.am);
2130 goto done;
2131 default:
2132 goto bad;
2133 }
2134 }
sewardje8c922f2004-07-23 01:34:11 +00002135 /* MUL */
2136 if (i->Xin.Alu32R.op == Xalu_MUL) {
sewardjd75fe5a2004-07-23 12:57:47 +00002137 switch (i->Xin.Alu32R.src->tag) {
2138 case Xrmi_Reg:
2139 *p++ = 0x0F;
2140 *p++ = 0xAF;
2141 p = doAMode_R(p, i->Xin.Alu32R.dst,
2142 i->Xin.Alu32R.src->Xrmi.Reg.reg);
2143 goto done;
sewardj140656d2004-08-22 02:37:25 +00002144 case Xrmi_Mem:
2145 *p++ = 0x0F;
2146 *p++ = 0xAF;
2147 p = doAMode_M(p, i->Xin.Alu32R.dst,
2148 i->Xin.Alu32R.src->Xrmi.Mem.am);
2149 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002150 case Xrmi_Imm:
2151 if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
2152 *p++ = 0x6B;
2153 p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
sewardj8ee8c882005-02-25 17:40:26 +00002154 *p++ = toUChar(0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjd75fe5a2004-07-23 12:57:47 +00002155 } else {
sewardj278c44c2004-08-20 00:28:13 +00002156 *p++ = 0x69;
2157 p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
2158 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjd75fe5a2004-07-23 12:57:47 +00002159 }
sewardj278c44c2004-08-20 00:28:13 +00002160 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002161 default:
2162 goto bad;
2163 }
sewardje8c922f2004-07-23 01:34:11 +00002164 }
2165 /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP */
sewardjea64e142004-07-22 16:47:21 +00002166 opc = opc_rr = subopc_imm = opc_imma = 0;
2167 switch (i->Xin.Alu32R.op) {
sewardjd3f9de72005-01-15 20:43:10 +00002168 case Xalu_ADC: opc = 0x13; opc_rr = 0x11;
2169 subopc_imm = 2; opc_imma = 0x15; break;
sewardjea64e142004-07-22 16:47:21 +00002170 case Xalu_ADD: opc = 0x03; opc_rr = 0x01;
2171 subopc_imm = 0; opc_imma = 0x05; break;
2172 case Xalu_SUB: opc = 0x2B; opc_rr = 0x29;
2173 subopc_imm = 5; opc_imma = 0x2D; break;
sewardj70f676d2004-12-10 14:59:57 +00002174 case Xalu_SBB: opc = 0x1B; opc_rr = 0x19;
2175 subopc_imm = 3; opc_imma = 0x1D; break;
sewardj86898e82004-07-22 17:26:12 +00002176 case Xalu_AND: opc = 0x23; opc_rr = 0x21;
2177 subopc_imm = 4; opc_imma = 0x25; break;
sewardje8c922f2004-07-23 01:34:11 +00002178 case Xalu_XOR: opc = 0x33; opc_rr = 0x31;
2179 subopc_imm = 6; opc_imma = 0x35; break;
2180 case Xalu_OR: opc = 0x0B; opc_rr = 0x09;
2181 subopc_imm = 1; opc_imma = 0x0D; break;
2182 case Xalu_CMP: opc = 0x3B; opc_rr = 0x39;
2183 subopc_imm = 7; opc_imma = 0x3D; break;
sewardjea64e142004-07-22 16:47:21 +00002184 default: goto bad;
2185 }
2186 switch (i->Xin.Alu32R.src->tag) {
2187 case Xrmi_Imm:
2188 if (i->Xin.Alu32R.dst == hregX86_EAX()
2189 && !fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
sewardj8ee8c882005-02-25 17:40:26 +00002190 *p++ = toUChar(opc_imma);
sewardjea64e142004-07-22 16:47:21 +00002191 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
2192 } else
sewardjd3f9de72005-01-15 20:43:10 +00002193 if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
sewardjea64e142004-07-22 16:47:21 +00002194 *p++ = 0x83;
2195 p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst);
sewardj8ee8c882005-02-25 17:40:26 +00002196 *p++ = toUChar(0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjea64e142004-07-22 16:47:21 +00002197 } else {
2198 *p++ = 0x81;
2199 p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst);
2200 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
2201 }
2202 goto done;
2203 case Xrmi_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00002204 *p++ = toUChar(opc_rr);
sewardjea64e142004-07-22 16:47:21 +00002205 p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg,
2206 i->Xin.Alu32R.dst);
2207 goto done;
sewardjbad34a92004-07-22 01:14:11 +00002208 case Xrmi_Mem:
sewardj8ee8c882005-02-25 17:40:26 +00002209 *p++ = toUChar(opc);
sewardjea64e142004-07-22 16:47:21 +00002210 p = doAMode_M(p, i->Xin.Alu32R.dst,
sewardjbad34a92004-07-22 01:14:11 +00002211 i->Xin.Alu32R.src->Xrmi.Mem.am);
2212 goto done;
sewardjea64e142004-07-22 16:47:21 +00002213 default:
sewardjbad34a92004-07-22 01:14:11 +00002214 goto bad;
sewardjbad34a92004-07-22 01:14:11 +00002215 }
2216 break;
2217
2218 case Xin_Alu32M:
sewardjea64e142004-07-22 16:47:21 +00002219 /* Deal specially with MOV */
sewardjbad34a92004-07-22 01:14:11 +00002220 if (i->Xin.Alu32M.op == Xalu_MOV) {
sewardjea64e142004-07-22 16:47:21 +00002221 switch (i->Xin.Alu32M.src->tag) {
2222 case Xri_Reg:
2223 *p++ = 0x89;
2224 p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg,
2225 i->Xin.Alu32M.dst);
2226 goto done;
2227 case Xri_Imm:
2228 *p++ = 0xC7;
2229 p = doAMode_M(p, fake(0), i->Xin.Alu32M.dst);
2230 p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32);
2231 goto done;
2232 default:
2233 goto bad;
2234 }
2235 }
sewardje8c922f2004-07-23 01:34:11 +00002236 /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP. MUL is not
2237 allowed here. */
sewardjea64e142004-07-22 16:47:21 +00002238 opc = subopc_imm = opc_imma = 0;
2239 switch (i->Xin.Alu32M.op) {
2240 case Xalu_ADD: opc = 0x01; subopc_imm = 0; break;
sewardj86898e82004-07-22 17:26:12 +00002241 case Xalu_SUB: opc = 0x29; subopc_imm = 5; break;
sewardjfb7373a2007-08-25 21:29:03 +00002242 case Xalu_CMP: opc = 0x39; subopc_imm = 7; break;
sewardjea64e142004-07-22 16:47:21 +00002243 default: goto bad;
2244 }
2245 switch (i->Xin.Alu32M.src->tag) {
2246 case Xri_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00002247 *p++ = toUChar(opc);
sewardjea64e142004-07-22 16:47:21 +00002248 p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg,
2249 i->Xin.Alu32M.dst);
2250 goto done;
2251 case Xri_Imm:
2252 if (fits8bits(i->Xin.Alu32M.src->Xri.Imm.imm32)) {
2253 *p++ = 0x83;
2254 p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst);
sewardj8ee8c882005-02-25 17:40:26 +00002255 *p++ = toUChar(0xFF & i->Xin.Alu32M.src->Xri.Imm.imm32);
sewardjea64e142004-07-22 16:47:21 +00002256 goto done;
2257 } else {
2258 *p++ = 0x81;
2259 p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst);
2260 p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32);
2261 goto done;
2262 }
2263 default:
2264 goto bad;
sewardjbad34a92004-07-22 01:14:11 +00002265 }
2266 break;
2267
sewardje8c922f2004-07-23 01:34:11 +00002268 case Xin_Sh32:
sewardjd75fe5a2004-07-23 12:57:47 +00002269 opc_cl = opc_imm = subopc = 0;
2270 switch (i->Xin.Sh32.op) {
2271 case Xsh_SHR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 5; break;
sewardj07134a42004-07-26 02:04:54 +00002272 case Xsh_SAR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 7; break;
2273 case Xsh_SHL: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 4; break;
sewardjd75fe5a2004-07-23 12:57:47 +00002274 default: goto bad;
2275 }
2276 if (i->Xin.Sh32.src == 0) {
sewardj8ee8c882005-02-25 17:40:26 +00002277 *p++ = toUChar(opc_cl);
sewardjeba63f82005-02-23 13:31:25 +00002278 p = doAMode_R(p, fake(subopc), i->Xin.Sh32.dst);
sewardjd75fe5a2004-07-23 12:57:47 +00002279 } else {
sewardj8ee8c882005-02-25 17:40:26 +00002280 *p++ = toUChar(opc_imm);
sewardjeba63f82005-02-23 13:31:25 +00002281 p = doAMode_R(p, fake(subopc), i->Xin.Sh32.dst);
2282 *p++ = (UChar)(i->Xin.Sh32.src);
sewardjd75fe5a2004-07-23 12:57:47 +00002283 }
sewardjeba63f82005-02-23 13:31:25 +00002284 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002285
2286 case Xin_Test32:
sewardjfb7373a2007-08-25 21:29:03 +00002287 if (i->Xin.Test32.dst->tag == Xrm_Reg) {
2288 /* testl $imm32, %reg */
2289 *p++ = 0xF7;
2290 p = doAMode_R(p, fake(0), i->Xin.Test32.dst->Xrm.Reg.reg);
2291 p = emit32(p, i->Xin.Test32.imm32);
2292 goto done;
2293 } else {
2294 /* testl $imm32, amode */
2295 *p++ = 0xF7;
2296 p = doAMode_M(p, fake(0), i->Xin.Test32.dst->Xrm.Mem.am);
2297 p = emit32(p, i->Xin.Test32.imm32);
2298 goto done;
2299 }
sewardje8c922f2004-07-23 01:34:11 +00002300
2301 case Xin_Unary32:
sewardj358b7d42004-11-08 18:54:50 +00002302 if (i->Xin.Unary32.op == Xun_NOT) {
sewardjd75fe5a2004-07-23 12:57:47 +00002303 *p++ = 0xF7;
sewardjeba63f82005-02-23 13:31:25 +00002304 p = doAMode_R(p, fake(2), i->Xin.Unary32.dst);
2305 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002306 }
sewardj358b7d42004-11-08 18:54:50 +00002307 if (i->Xin.Unary32.op == Xun_NEG) {
2308 *p++ = 0xF7;
sewardjeba63f82005-02-23 13:31:25 +00002309 p = doAMode_R(p, fake(3), i->Xin.Unary32.dst);
2310 goto done;
sewardj358b7d42004-11-08 18:54:50 +00002311 }
sewardjd75fe5a2004-07-23 12:57:47 +00002312 break;
sewardje8c922f2004-07-23 01:34:11 +00002313
sewardj79e04f82007-03-31 14:30:12 +00002314 case Xin_Lea32:
2315 *p++ = 0x8D;
2316 p = doAMode_M(p, i->Xin.Lea32.dst, i->Xin.Lea32.am);
2317 goto done;
2318
sewardja2dad5c2004-07-23 11:43:43 +00002319 case Xin_MulL:
sewardjd75fe5a2004-07-23 12:57:47 +00002320 subopc = i->Xin.MulL.syned ? 5 : 4;
sewardjeba63f82005-02-23 13:31:25 +00002321 *p++ = 0xF7;
2322 switch (i->Xin.MulL.src->tag) {
2323 case Xrm_Mem:
2324 p = doAMode_M(p, fake(subopc),
2325 i->Xin.MulL.src->Xrm.Mem.am);
2326 goto done;
2327 case Xrm_Reg:
2328 p = doAMode_R(p, fake(subopc),
2329 i->Xin.MulL.src->Xrm.Reg.reg);
2330 goto done;
2331 default:
2332 goto bad;
sewardjd75fe5a2004-07-23 12:57:47 +00002333 }
2334 break;
sewardja2dad5c2004-07-23 11:43:43 +00002335
2336 case Xin_Div:
sewardjd75fe5a2004-07-23 12:57:47 +00002337 subopc = i->Xin.Div.syned ? 7 : 6;
sewardjeba63f82005-02-23 13:31:25 +00002338 *p++ = 0xF7;
2339 switch (i->Xin.Div.src->tag) {
2340 case Xrm_Mem:
2341 p = doAMode_M(p, fake(subopc),
2342 i->Xin.Div.src->Xrm.Mem.am);
2343 goto done;
2344 case Xrm_Reg:
2345 p = doAMode_R(p, fake(subopc),
2346 i->Xin.Div.src->Xrm.Reg.reg);
2347 goto done;
2348 default:
2349 goto bad;
sewardjd75fe5a2004-07-23 12:57:47 +00002350 }
2351 break;
sewardja2dad5c2004-07-23 11:43:43 +00002352
2353 case Xin_Sh3232:
sewardjd75fe5a2004-07-23 12:57:47 +00002354 vassert(i->Xin.Sh3232.op == Xsh_SHL || i->Xin.Sh3232.op == Xsh_SHR);
2355 if (i->Xin.Sh3232.amt == 0) {
2356 /* shldl/shrdl by %cl */
2357 *p++ = 0x0F;
sewardj68511542004-07-28 00:15:44 +00002358 if (i->Xin.Sh3232.op == Xsh_SHL) {
2359 *p++ = 0xA5;
sewardj68511542004-07-28 00:15:44 +00002360 } else {
2361 *p++ = 0xAD;
sewardj68511542004-07-28 00:15:44 +00002362 }
sewardje5f384c2004-07-30 16:17:28 +00002363 p = doAMode_R(p, i->Xin.Sh3232.src, i->Xin.Sh3232.dst);
sewardjd75fe5a2004-07-23 12:57:47 +00002364 goto done;
2365 }
2366 break;
sewardja2dad5c2004-07-23 11:43:43 +00002367
sewardje8c922f2004-07-23 01:34:11 +00002368 case Xin_Push:
sewardjd75fe5a2004-07-23 12:57:47 +00002369 switch (i->Xin.Push.src->tag) {
2370 case Xrmi_Mem:
2371 *p++ = 0xFF;
2372 p = doAMode_M(p, fake(6), i->Xin.Push.src->Xrmi.Mem.am);
2373 goto done;
sewardja58ea662004-08-15 03:12:41 +00002374 case Xrmi_Imm:
2375 *p++ = 0x68;
2376 p = emit32(p, i->Xin.Push.src->Xrmi.Imm.imm32);
2377 goto done;
sewardjd7cb8532004-08-17 23:59:23 +00002378 case Xrmi_Reg:
sewardj8ee8c882005-02-25 17:40:26 +00002379 *p++ = toUChar(0x50 + iregNo(i->Xin.Push.src->Xrmi.Reg.reg));
sewardjd7cb8532004-08-17 23:59:23 +00002380 goto done;
sewardja58ea662004-08-15 03:12:41 +00002381 default:
sewardjd75fe5a2004-07-23 12:57:47 +00002382 goto bad;
2383 }
sewardje8c922f2004-07-23 01:34:11 +00002384
2385 case Xin_Call:
sewardjcfe046e2013-01-17 14:23:53 +00002386 if (i->Xin.Call.cond != Xcc_ALWAYS && i->Xin.Call.rloc != RetLocNone) {
2387 /* The call might not happen (it isn't unconditional) and it
2388 returns a result. In this case we will need to generate a
2389 control flow diamond to put 0x555..555 in the return
2390 register(s) in the case where the call doesn't happen. If
2391 this ever becomes necessary, maybe copy code from the ARM
2392 equivalent. Until that day, just give up. */
2393 goto bad;
2394 }
sewardj4b861de2004-11-03 15:24:42 +00002395 /* See detailed comment for Xin_Call in getRegUsage_X86Instr above
2396 for explanation of this. */
2397 switch (i->Xin.Call.regparms) {
2398 case 0: irno = iregNo(hregX86_EAX()); break;
sewardj45c50eb2004-11-04 18:25:33 +00002399 case 1: irno = iregNo(hregX86_EDX()); break;
2400 case 2: irno = iregNo(hregX86_ECX()); break;
sewardj4b861de2004-11-03 15:24:42 +00002401 case 3: irno = iregNo(hregX86_EDI()); break;
2402 default: vpanic(" emit_X86Instr:call:regparms");
2403 }
2404 /* jump over the following two insns if the condition does not
2405 hold */
2406 if (i->Xin.Call.cond != Xcc_ALWAYS) {
sewardj8ee8c882005-02-25 17:40:26 +00002407 *p++ = toUChar(0x70 + (0xF & (i->Xin.Call.cond ^ 1)));
sewardj4b861de2004-11-03 15:24:42 +00002408 *p++ = 0x07; /* 7 bytes in the next two insns */
2409 }
2410 /* movl $target, %tmp */
sewardj8ee8c882005-02-25 17:40:26 +00002411 *p++ = toUChar(0xB8 + irno);
sewardj4b861de2004-11-03 15:24:42 +00002412 p = emit32(p, i->Xin.Call.target);
2413 /* call *%tmp */
sewardjd75fe5a2004-07-23 12:57:47 +00002414 *p++ = 0xFF;
sewardj8ee8c882005-02-25 17:40:26 +00002415 *p++ = toUChar(0xD0 + irno);
sewardjd75fe5a2004-07-23 12:57:47 +00002416 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002417
sewardjc6f970f2012-04-02 21:54:49 +00002418 case Xin_XDirect: {
2419 /* NB: what goes on here has to be very closely coordinated with the
2420 chainXDirect_X86 and unchainXDirect_X86 below. */
2421 /* We're generating chain-me requests here, so we need to be
2422 sure this is actually allowed -- no-redir translations can't
2423 use chain-me's. Hence: */
2424 vassert(disp_cp_chain_me_to_slowEP != NULL);
2425 vassert(disp_cp_chain_me_to_fastEP != NULL);
sewardj010ac542011-05-29 09:29:18 +00002426
sewardj893aada2004-11-29 19:57:54 +00002427 /* Use ptmp for backpatching conditional jumps. */
2428 ptmp = NULL;
2429
2430 /* First off, if this is conditional, create a conditional
sewardjc6f970f2012-04-02 21:54:49 +00002431 jump over the rest of it. */
2432 if (i->Xin.XDirect.cond != Xcc_ALWAYS) {
sewardj893aada2004-11-29 19:57:54 +00002433 /* jmp fwds if !condition */
sewardjc6f970f2012-04-02 21:54:49 +00002434 *p++ = toUChar(0x70 + (0xF & (i->Xin.XDirect.cond ^ 1)));
sewardj893aada2004-11-29 19:57:54 +00002435 ptmp = p; /* fill in this bit later */
2436 *p++ = 0; /* # of bytes to jump over; don't know how many yet. */
sewardj750f4072004-07-26 22:39:11 +00002437 }
sewardj893aada2004-11-29 19:57:54 +00002438
sewardjc6f970f2012-04-02 21:54:49 +00002439 /* Update the guest EIP. */
2440 /* movl $dstGA, amEIP */
2441 *p++ = 0xC7;
2442 p = doAMode_M(p, fake(0), i->Xin.XDirect.amEIP);
2443 p = emit32(p, i->Xin.XDirect.dstGA);
sewardj010ac542011-05-29 09:29:18 +00002444
sewardjc6f970f2012-04-02 21:54:49 +00002445 /* --- FIRST PATCHABLE BYTE follows --- */
2446 /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're calling
2447 to) backs up the return address, so as to find the address of
2448 the first patchable byte. So: don't change the length of the
2449 two instructions below. */
2450 /* movl $disp_cp_chain_me_to_{slow,fast}EP,%edx; */
sewardj17c7f952005-12-15 14:02:34 +00002451 *p++ = 0xBA;
sewardjc6f970f2012-04-02 21:54:49 +00002452 void* disp_cp_chain_me
2453 = i->Xin.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP
2454 : disp_cp_chain_me_to_slowEP;
2455 p = emit32(p, (UInt)Ptr_to_ULong(disp_cp_chain_me));
2456 /* call *%edx */
2457 *p++ = 0xFF;
2458 *p++ = 0xD2;
2459 /* --- END of PATCHABLE BYTES --- */
sewardj17c7f952005-12-15 14:02:34 +00002460
sewardjc6f970f2012-04-02 21:54:49 +00002461 /* Fix up the conditional jump, if there was one. */
2462 if (i->Xin.XDirect.cond != Xcc_ALWAYS) {
2463 Int delta = p - ptmp;
2464 vassert(delta > 0 && delta < 40);
2465 *ptmp = toUChar(delta-1);
2466 }
2467 goto done;
2468 }
2469
2470 case Xin_XIndir: {
2471 /* We're generating transfers that could lead indirectly to a
2472 chain-me, so we need to be sure this is actually allowed --
2473 no-redir translations are not allowed to reach normal
2474 translations without going through the scheduler. That means
2475 no XDirects or XIndirs out from no-redir translations.
2476 Hence: */
2477 vassert(disp_cp_xindir != NULL);
2478
2479 /* Use ptmp for backpatching conditional jumps. */
2480 ptmp = NULL;
2481
2482 /* First off, if this is conditional, create a conditional
2483 jump over the rest of it. */
2484 if (i->Xin.XIndir.cond != Xcc_ALWAYS) {
2485 /* jmp fwds if !condition */
2486 *p++ = toUChar(0x70 + (0xF & (i->Xin.XIndir.cond ^ 1)));
2487 ptmp = p; /* fill in this bit later */
2488 *p++ = 0; /* # of bytes to jump over; don't know how many yet. */
2489 }
2490
2491 /* movl dstGA(a reg), amEIP -- copied from Alu32M MOV case */
2492 *p++ = 0x89;
2493 p = doAMode_M(p, i->Xin.XIndir.dstGA, i->Xin.XIndir.amEIP);
2494
2495 /* movl $disp_indir, %edx */
2496 *p++ = 0xBA;
2497 p = emit32(p, (UInt)Ptr_to_ULong(disp_cp_xindir));
sewardj17c7f952005-12-15 14:02:34 +00002498 /* jmp *%edx */
2499 *p++ = 0xFF;
2500 *p++ = 0xE2;
sewardj893aada2004-11-29 19:57:54 +00002501
2502 /* Fix up the conditional jump, if there was one. */
sewardjc6f970f2012-04-02 21:54:49 +00002503 if (i->Xin.XIndir.cond != Xcc_ALWAYS) {
sewardj893aada2004-11-29 19:57:54 +00002504 Int delta = p - ptmp;
sewardjc6f970f2012-04-02 21:54:49 +00002505 vassert(delta > 0 && delta < 40);
2506 *ptmp = toUChar(delta-1);
2507 }
2508 goto done;
2509 }
2510
2511 case Xin_XAssisted: {
2512 /* Use ptmp for backpatching conditional jumps. */
2513 ptmp = NULL;
2514
2515 /* First off, if this is conditional, create a conditional
2516 jump over the rest of it. */
2517 if (i->Xin.XAssisted.cond != Xcc_ALWAYS) {
2518 /* jmp fwds if !condition */
2519 *p++ = toUChar(0x70 + (0xF & (i->Xin.XAssisted.cond ^ 1)));
2520 ptmp = p; /* fill in this bit later */
2521 *p++ = 0; /* # of bytes to jump over; don't know how many yet. */
2522 }
2523
2524 /* movl dstGA(a reg), amEIP -- copied from Alu32M MOV case */
2525 *p++ = 0x89;
2526 p = doAMode_M(p, i->Xin.XIndir.dstGA, i->Xin.XIndir.amEIP);
2527 /* movl $magic_number, %ebp. */
2528 UInt trcval = 0;
2529 switch (i->Xin.XAssisted.jk) {
sewardj39aacda2012-04-21 15:34:25 +00002530 case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
2531 case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
2532 case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break;
2533 case Ijk_Sys_int129: trcval = VEX_TRC_JMP_SYS_INT129; break;
2534 case Ijk_Sys_int130: trcval = VEX_TRC_JMP_SYS_INT130; break;
2535 case Ijk_Sys_sysenter: trcval = VEX_TRC_JMP_SYS_SYSENTER; break;
2536 case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
2537 case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
2538 case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break;
2539 case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
2540 case Ijk_TInval: trcval = VEX_TRC_JMP_TINVAL; break;
2541 case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
2542 case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
2543 case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break;
2544 case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
sewardjc6f970f2012-04-02 21:54:49 +00002545 /* We don't expect to see the following being assisted. */
2546 case Ijk_Ret:
2547 case Ijk_Call:
2548 /* fallthrough */
2549 default:
2550 ppIRJumpKind(i->Xin.XAssisted.jk);
2551 vpanic("emit_X86Instr.Xin_XAssisted: unexpected jump kind");
2552 }
2553 vassert(trcval != 0);
2554 *p++ = 0xBD;
2555 p = emit32(p, trcval);
2556
2557 /* movl $disp_indir, %edx */
2558 *p++ = 0xBA;
2559 p = emit32(p, (UInt)Ptr_to_ULong(disp_cp_xassisted));
2560 /* jmp *%edx */
2561 *p++ = 0xFF;
2562 *p++ = 0xE2;
2563
2564 /* Fix up the conditional jump, if there was one. */
2565 if (i->Xin.XAssisted.cond != Xcc_ALWAYS) {
2566 Int delta = p - ptmp;
2567 vassert(delta > 0 && delta < 40);
sewardj8ee8c882005-02-25 17:40:26 +00002568 *ptmp = toUChar(delta-1);
sewardje8c922f2004-07-23 01:34:11 +00002569 }
sewardj893aada2004-11-29 19:57:54 +00002570 goto done;
sewardj010ac542011-05-29 09:29:18 +00002571 }
sewardj86898e82004-07-22 17:26:12 +00002572
sewardje8c922f2004-07-23 01:34:11 +00002573 case Xin_CMov32:
sewardjd75fe5a2004-07-23 12:57:47 +00002574 vassert(i->Xin.CMov32.cond != Xcc_ALWAYS);
sewardjc4904af2005-08-08 00:33:37 +00002575
sewardj893aada2004-11-29 19:57:54 +00002576 /* This generates cmov, which is illegal on P54/P55. */
sewardjc4904af2005-08-08 00:33:37 +00002577 /*
sewardjd75fe5a2004-07-23 12:57:47 +00002578 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002579 *p++ = toUChar(0x40 + (0xF & i->Xin.CMov32.cond));
sewardjd75fe5a2004-07-23 12:57:47 +00002580 if (i->Xin.CMov32.src->tag == Xrm_Reg) {
2581 p = doAMode_R(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Reg.reg);
2582 goto done;
2583 }
2584 if (i->Xin.CMov32.src->tag == Xrm_Mem) {
2585 p = doAMode_M(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Mem.am);
2586 goto done;
2587 }
sewardjc4904af2005-08-08 00:33:37 +00002588 */
2589
2590 /* Alternative version which works on any x86 variant. */
2591 /* jmp fwds if !condition */
sewardjc7cd2142005-09-09 22:31:49 +00002592 *p++ = toUChar(0x70 + (i->Xin.CMov32.cond ^ 1));
sewardjc4904af2005-08-08 00:33:37 +00002593 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2594 ptmp = p;
2595
2596 switch (i->Xin.CMov32.src->tag) {
2597 case Xrm_Reg:
2598 /* Big sigh. This is movl E -> G ... */
2599 *p++ = 0x89;
2600 p = doAMode_R(p, i->Xin.CMov32.src->Xrm.Reg.reg,
2601 i->Xin.CMov32.dst);
2602
2603 break;
2604 case Xrm_Mem:
2605 /* ... whereas this is movl G -> E. That's why the args
2606 to doAMode_R appear to be the wrong way round in the
2607 Xrm_Reg case. */
2608 *p++ = 0x8B;
2609 p = doAMode_M(p, i->Xin.CMov32.dst,
2610 i->Xin.CMov32.src->Xrm.Mem.am);
2611 break;
2612 default:
2613 goto bad;
2614 }
2615 /* Fill in the jump offset. */
sewardjc7cd2142005-09-09 22:31:49 +00002616 *(ptmp-1) = toUChar(p - ptmp);
sewardjc4904af2005-08-08 00:33:37 +00002617 goto done;
2618
sewardjd75fe5a2004-07-23 12:57:47 +00002619 break;
sewardje8c922f2004-07-23 01:34:11 +00002620
2621 case Xin_LoadEX:
sewardjd75fe5a2004-07-23 12:57:47 +00002622 if (i->Xin.LoadEX.szSmall == 1 && !i->Xin.LoadEX.syned) {
2623 /* movzbl */
2624 *p++ = 0x0F;
2625 *p++ = 0xB6;
2626 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2627 goto done;
2628 }
2629 if (i->Xin.LoadEX.szSmall == 2 && !i->Xin.LoadEX.syned) {
2630 /* movzwl */
2631 *p++ = 0x0F;
2632 *p++ = 0xB7;
2633 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2634 goto done;
2635 }
sewardjeb17e492007-08-25 23:07:44 +00002636 if (i->Xin.LoadEX.szSmall == 1 && i->Xin.LoadEX.syned) {
2637 /* movsbl */
2638 *p++ = 0x0F;
2639 *p++ = 0xBE;
2640 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2641 goto done;
2642 }
sewardjd75fe5a2004-07-23 12:57:47 +00002643 break;
sewardje8c922f2004-07-23 01:34:11 +00002644
sewardjd7cb8532004-08-17 23:59:23 +00002645 case Xin_Set32:
2646 /* Make the destination register be 1 or 0, depending on whether
2647 the relevant condition holds. We have to dodge and weave
2648 when the destination is %esi or %edi as we cannot directly
2649 emit the native 'setb %reg' for those. Further complication:
2650 the top 24 bits of the destination should be forced to zero,
2651 but doing 'xor %r,%r' kills the flag(s) we are about to read.
sewardj3503ad82004-08-24 00:24:56 +00002652 Sigh. So start off my moving $0 into the dest. */
sewardjd7cb8532004-08-17 23:59:23 +00002653
sewardj3503ad82004-08-24 00:24:56 +00002654 /* Do we need to swap in %eax? */
sewardjd7cb8532004-08-17 23:59:23 +00002655 if (iregNo(i->Xin.Set32.dst) >= 4) {
2656 /* xchg %eax, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002657 *p++ = toUChar(0x90 + iregNo(i->Xin.Set32.dst));
sewardj3503ad82004-08-24 00:24:56 +00002658 /* movl $0, %eax */
sewardj8ee8c882005-02-25 17:40:26 +00002659 *p++ =toUChar(0xB8 + iregNo(hregX86_EAX()));
sewardj3503ad82004-08-24 00:24:56 +00002660 p = emit32(p, 0);
2661 /* setb lo8(%eax) */
sewardjd7cb8532004-08-17 23:59:23 +00002662 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002663 *p++ = toUChar(0x90 + (0xF & i->Xin.Set32.cond));
sewardjd7cb8532004-08-17 23:59:23 +00002664 p = doAMode_R(p, fake(0), hregX86_EAX());
2665 /* xchg %eax, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002666 *p++ = toUChar(0x90 + iregNo(i->Xin.Set32.dst));
sewardjd7cb8532004-08-17 23:59:23 +00002667 } else {
sewardj3503ad82004-08-24 00:24:56 +00002668 /* movl $0, %dst */
sewardj8ee8c882005-02-25 17:40:26 +00002669 *p++ = toUChar(0xB8 + iregNo(i->Xin.Set32.dst));
sewardj3503ad82004-08-24 00:24:56 +00002670 p = emit32(p, 0);
2671 /* setb lo8(%dst) */
sewardjd7cb8532004-08-17 23:59:23 +00002672 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00002673 *p++ = toUChar(0x90 + (0xF & i->Xin.Set32.cond));
sewardjd7cb8532004-08-17 23:59:23 +00002674 p = doAMode_R(p, fake(0), i->Xin.Set32.dst);
2675 }
2676 goto done;
2677
sewardjce646f22004-08-31 23:55:54 +00002678 case Xin_Bsfr32:
2679 *p++ = 0x0F;
2680 if (i->Xin.Bsfr32.isFwds) {
2681 *p++ = 0xBC;
2682 } else {
2683 *p++ = 0xBD;
2684 }
2685 p = doAMode_R(p, i->Xin.Bsfr32.dst, i->Xin.Bsfr32.src);
2686 goto done;
2687
sewardj3e838932005-01-07 12:09:15 +00002688 case Xin_MFence:
2689 /* see comment in hdefs.h re this insn */
sewardjbb3f52d2005-01-07 14:14:50 +00002690 if (0) vex_printf("EMIT FENCE\n");
sewardj5117ce12006-01-27 21:20:15 +00002691 if (i->Xin.MFence.hwcaps & (VEX_HWCAPS_X86_SSE3
2692 |VEX_HWCAPS_X86_SSE2)) {
2693 /* mfence */
2694 *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF0;
2695 goto done;
sewardj3e838932005-01-07 12:09:15 +00002696 }
sewardj5117ce12006-01-27 21:20:15 +00002697 if (i->Xin.MFence.hwcaps & VEX_HWCAPS_X86_SSE1) {
2698 /* sfence */
2699 *p++ = 0x0F; *p++ = 0xAE; *p++ = 0xF8;
2700 /* lock addl $0,0(%esp) */
2701 *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44;
2702 *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
2703 goto done;
2704 }
2705 if (i->Xin.MFence.hwcaps == 0/*baseline, no SSE*/) {
2706 /* lock addl $0,0(%esp) */
2707 *p++ = 0xF0; *p++ = 0x83; *p++ = 0x44;
2708 *p++ = 0x24; *p++ = 0x00; *p++ = 0x00;
2709 goto done;
2710 }
2711 vpanic("emit_X86Instr:mfence:hwcaps");
2712 /*NOTREACHED*/
sewardj3e838932005-01-07 12:09:15 +00002713 break;
2714
sewardje9d8a262009-07-01 08:06:34 +00002715 case Xin_ACAS:
2716 /* lock */
2717 *p++ = 0xF0;
2718 /* cmpxchg{b,w,l} %ebx,mem. Expected-value in %eax, new value
2719 in %ebx. The new-value register is hardwired to be %ebx
2720 since letting it be any integer register gives the problem
2721 that %sil and %dil are unaddressible on x86 and hence we
2722 would have to resort to the same kind of trickery as with
2723 byte-sized Xin.Store, just below. Given that this isn't
2724 performance critical, it is simpler just to force the
2725 register operand to %ebx (could equally be %ecx or %edx).
2726 (Although %ebx is more consistent with cmpxchg8b.) */
2727 if (i->Xin.ACAS.sz == 2) *p++ = 0x66;
2728 *p++ = 0x0F;
2729 if (i->Xin.ACAS.sz == 1) *p++ = 0xB0; else *p++ = 0xB1;
2730 p = doAMode_M(p, hregX86_EBX(), i->Xin.ACAS.addr);
2731 goto done;
2732
2733 case Xin_DACAS:
2734 /* lock */
2735 *p++ = 0xF0;
2736 /* cmpxchg8b m64. Expected-value in %edx:%eax, new value
2737 in %ecx:%ebx. All 4 regs are hardwired in the ISA, so
2738 aren't encoded in the insn. */
2739 *p++ = 0x0F;
2740 *p++ = 0xC7;
2741 p = doAMode_M(p, fake(1), i->Xin.DACAS.addr);
2742 goto done;
2743
sewardje8c922f2004-07-23 01:34:11 +00002744 case Xin_Store:
sewardjd75fe5a2004-07-23 12:57:47 +00002745 if (i->Xin.Store.sz == 2) {
2746 /* This case, at least, is simple, given that we can
2747 reference the low 16 bits of any integer register. */
2748 *p++ = 0x66;
2749 *p++ = 0x89;
2750 p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
2751 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002752 }
sewardjd75fe5a2004-07-23 12:57:47 +00002753
2754 if (i->Xin.Store.sz == 1) {
2755 /* We have to do complex dodging and weaving if src is not
2756 the low 8 bits of %eax/%ebx/%ecx/%edx. */
2757 if (iregNo(i->Xin.Store.src) < 4) {
2758 /* we're OK, can do it directly */
2759 *p++ = 0x88;
2760 p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
2761 goto done;
2762 } else {
2763 /* Bleh. This means the source is %edi or %esi. Since
2764 the address mode can only mention three registers, at
2765 least one of %eax/%ebx/%ecx/%edx must be available to
2766 temporarily swap the source into, so the store can
2767 happen. So we have to look at the regs mentioned
2768 in the amode. */
sewardj2e56f9f2004-07-24 01:24:38 +00002769 HReg swap = INVALID_HREG;
2770 HReg eax = hregX86_EAX(), ebx = hregX86_EBX(),
2771 ecx = hregX86_ECX(), edx = hregX86_EDX();
sewardjd75fe5a2004-07-23 12:57:47 +00002772 Bool a_ok = True, b_ok = True, c_ok = True, d_ok = True;
2773 HRegUsage u;
2774 Int j;
2775 initHRegUsage(&u);
2776 addRegUsage_X86AMode(&u, i->Xin.Store.dst);
2777 for (j = 0; j < u.n_used; j++) {
2778 HReg r = u.hreg[j];
2779 if (r == eax) a_ok = False;
2780 if (r == ebx) b_ok = False;
2781 if (r == ecx) c_ok = False;
2782 if (r == edx) d_ok = False;
2783 }
sewardjd75fe5a2004-07-23 12:57:47 +00002784 if (a_ok) swap = eax;
2785 if (b_ok) swap = ebx;
2786 if (c_ok) swap = ecx;
2787 if (d_ok) swap = edx;
2788 vassert(swap != INVALID_HREG);
2789 /* xchgl %source, %swap. Could do better if swap is %eax. */
2790 *p++ = 0x87;
2791 p = doAMode_R(p, i->Xin.Store.src, swap);
2792 /* movb lo8{%swap}, (dst) */
2793 *p++ = 0x88;
2794 p = doAMode_M(p, swap, i->Xin.Store.dst);
2795 /* xchgl %source, %swap. Could do better if swap is %eax. */
2796 *p++ = 0x87;
2797 p = doAMode_R(p, i->Xin.Store.src, swap);
2798 goto done;
2799 }
2800 } /* if (i->Xin.Store.sz == 1) */
2801 break;
sewardj86898e82004-07-22 17:26:12 +00002802
sewardjcfded9a2004-09-09 11:44:16 +00002803 case Xin_FpUnary:
2804 /* gop %src, %dst
2805 --> ffree %st7 ; fld %st(src) ; fop %st(0) ; fstp %st(1+dst)
2806 */
2807 p = do_ffree_st7(p);
2808 p = do_fld_st(p, 0+hregNumber(i->Xin.FpUnary.src));
2809 p = do_fop1_st(p, i->Xin.FpUnary.op);
2810 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpUnary.dst));
2811 goto done;
2812
sewardjbb53f8c2004-08-14 11:50:01 +00002813 case Xin_FpBinary:
sewardj06c32a02004-09-12 12:07:34 +00002814 if (i->Xin.FpBinary.op == Xfp_YL2X
2815 || i->Xin.FpBinary.op == Xfp_YL2XP1) {
sewardj8308aad2004-09-12 11:09:54 +00002816 /* Have to do this specially. */
2817 /* ffree %st7 ; fld %st(srcL) ;
sewardj06c32a02004-09-12 12:07:34 +00002818 ffree %st7 ; fld %st(srcR+1) ; fyl2x{p1} ; fstp(1+dst) */
sewardj8308aad2004-09-12 11:09:54 +00002819 p = do_ffree_st7(p);
2820 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
2821 p = do_ffree_st7(p);
2822 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
sewardj06c32a02004-09-12 12:07:34 +00002823 *p++ = 0xD9;
sewardj8ee8c882005-02-25 17:40:26 +00002824 *p++ = toUChar(i->Xin.FpBinary.op==Xfp_YL2X ? 0xF1 : 0xF9);
sewardj8308aad2004-09-12 11:09:54 +00002825 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2826 goto done;
2827 }
sewardj52ace3e2004-09-11 17:10:08 +00002828 if (i->Xin.FpBinary.op == Xfp_ATAN) {
sewardjcfded9a2004-09-09 11:44:16 +00002829 /* Have to do this specially. */
sewardj46de4072004-09-11 19:23:24 +00002830 /* ffree %st7 ; fld %st(srcL) ;
2831 ffree %st7 ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */
sewardjcfded9a2004-09-09 11:44:16 +00002832 p = do_ffree_st7(p);
2833 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
sewardj46de4072004-09-11 19:23:24 +00002834 p = do_ffree_st7(p);
sewardjcfded9a2004-09-09 11:44:16 +00002835 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
2836 *p++ = 0xD9; *p++ = 0xF3;
2837 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2838 goto done;
2839 }
sewardj06c32a02004-09-12 12:07:34 +00002840 if (i->Xin.FpBinary.op == Xfp_PREM
sewardj442d0be2004-10-15 22:57:13 +00002841 || i->Xin.FpBinary.op == Xfp_PREM1
sewardj06c32a02004-09-12 12:07:34 +00002842 || i->Xin.FpBinary.op == Xfp_SCALE) {
sewardj46de4072004-09-11 19:23:24 +00002843 /* Have to do this specially. */
2844 /* ffree %st7 ; fld %st(srcR) ;
sewardj442d0be2004-10-15 22:57:13 +00002845 ffree %st7 ; fld %st(srcL+1) ; fprem/fprem1/fscale ; fstp(2+dst) ;
sewardj46de4072004-09-11 19:23:24 +00002846 fincstp ; ffree %st7 */
2847 p = do_ffree_st7(p);
2848 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR));
2849 p = do_ffree_st7(p);
2850 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL));
sewardj442d0be2004-10-15 22:57:13 +00002851 *p++ = 0xD9;
2852 switch (i->Xin.FpBinary.op) {
2853 case Xfp_PREM: *p++ = 0xF8; break;
2854 case Xfp_PREM1: *p++ = 0xF5; break;
2855 case Xfp_SCALE: *p++ = 0xFD; break;
2856 default: vpanic("emitX86Instr(FpBinary,PREM/PREM1/SCALE)");
2857 }
sewardj46de4072004-09-11 19:23:24 +00002858 p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst));
2859 *p++ = 0xD9; *p++ = 0xF7;
2860 p = do_ffree_st7(p);
2861 goto done;
2862 }
sewardjcfded9a2004-09-09 11:44:16 +00002863 /* General case */
sewardjbb53f8c2004-08-14 11:50:01 +00002864 /* gop %srcL, %srcR, %dst
2865 --> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst)
2866 */
2867 p = do_ffree_st7(p);
2868 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
sewardj3bca9062004-12-04 14:36:09 +00002869 p = do_fop2_st(p, i->Xin.FpBinary.op,
2870 1+hregNumber(i->Xin.FpBinary.srcR));
sewardjbb53f8c2004-08-14 11:50:01 +00002871 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2872 goto done;
2873
sewardj3196daf2004-08-13 00:18:58 +00002874 case Xin_FpLdSt:
2875 if (i->Xin.FpLdSt.isLoad) {
2876 /* Load from memory into %fakeN.
sewardj7fb65eb2007-03-25 04:14:58 +00002877 --> ffree %st(7) ; fld{s/l/t} amode ; fstp st(N+1)
sewardj3196daf2004-08-13 00:18:58 +00002878 */
2879 p = do_ffree_st7(p);
sewardj7fb65eb2007-03-25 04:14:58 +00002880 switch (i->Xin.FpLdSt.sz) {
2881 case 4:
2882 *p++ = 0xD9;
2883 p = doAMode_M(p, fake(0)/*subopcode*/, i->Xin.FpLdSt.addr);
2884 break;
2885 case 8:
2886 *p++ = 0xDD;
2887 p = doAMode_M(p, fake(0)/*subopcode*/, i->Xin.FpLdSt.addr);
2888 break;
2889 case 10:
2890 *p++ = 0xDB;
2891 p = doAMode_M(p, fake(5)/*subopcode*/, i->Xin.FpLdSt.addr);
2892 break;
2893 default:
2894 vpanic("emitX86Instr(FpLdSt,load)");
2895 }
sewardj3196daf2004-08-13 00:18:58 +00002896 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdSt.reg));
2897 goto done;
2898 } else {
2899 /* Store from %fakeN into memory.
sewardjbb53f8c2004-08-14 11:50:01 +00002900 --> ffree %st(7) ; fld st(N) ; fstp{l|s} amode
sewardj3196daf2004-08-13 00:18:58 +00002901 */
2902 p = do_ffree_st7(p);
2903 p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdSt.reg));
sewardj7fb65eb2007-03-25 04:14:58 +00002904 switch (i->Xin.FpLdSt.sz) {
2905 case 4:
2906 *p++ = 0xD9;
2907 p = doAMode_M(p, fake(3)/*subopcode*/, i->Xin.FpLdSt.addr);
2908 break;
2909 case 8:
2910 *p++ = 0xDD;
2911 p = doAMode_M(p, fake(3)/*subopcode*/, i->Xin.FpLdSt.addr);
2912 break;
2913 case 10:
2914 *p++ = 0xDB;
2915 p = doAMode_M(p, fake(7)/*subopcode*/, i->Xin.FpLdSt.addr);
2916 break;
2917 default:
2918 vpanic("emitX86Instr(FpLdSt,store)");
2919 }
sewardj3196daf2004-08-13 00:18:58 +00002920 goto done;
2921 }
2922 break;
2923
sewardj89cd0932004-09-08 18:23:25 +00002924 case Xin_FpLdStI:
2925 if (i->Xin.FpLdStI.isLoad) {
2926 /* Load from memory into %fakeN, converting from an int.
2927 --> ffree %st(7) ; fild{w/l/ll} amode ; fstp st(N+1)
2928 */
2929 switch (i->Xin.FpLdStI.sz) {
sewardjbdc7d212004-09-09 02:46:40 +00002930 case 8: opc = 0xDF; subopc_imm = 5; break;
sewardj89cd0932004-09-08 18:23:25 +00002931 case 4: opc = 0xDB; subopc_imm = 0; break;
2932 case 2: vassert(0); opc = 0xDF; subopc_imm = 0; break;
2933 default: vpanic("emitX86Instr(Xin_FpLdStI-load)");
2934 }
2935 p = do_ffree_st7(p);
sewardj8ee8c882005-02-25 17:40:26 +00002936 *p++ = toUChar(opc);
sewardj89cd0932004-09-08 18:23:25 +00002937 p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr);
2938 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdStI.reg));
2939 goto done;
2940 } else {
2941 /* Store from %fakeN into memory, converting to an int.
2942 --> ffree %st(7) ; fld st(N) ; fistp{w/l/ll} amode
2943 */
2944 switch (i->Xin.FpLdStI.sz) {
sewardjcfded9a2004-09-09 11:44:16 +00002945 case 8: opc = 0xDF; subopc_imm = 7; break;
sewardj89cd0932004-09-08 18:23:25 +00002946 case 4: opc = 0xDB; subopc_imm = 3; break;
2947 case 2: opc = 0xDF; subopc_imm = 3; break;
2948 default: vpanic("emitX86Instr(Xin_FpLdStI-store)");
2949 }
2950 p = do_ffree_st7(p);
2951 p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdStI.reg));
sewardj8ee8c882005-02-25 17:40:26 +00002952 *p++ = toUChar(opc);
sewardj89cd0932004-09-08 18:23:25 +00002953 p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr);
2954 goto done;
2955 }
2956 break;
2957
sewardj3bca9062004-12-04 14:36:09 +00002958 case Xin_Fp64to32:
2959 /* ffree %st7 ; fld %st(src) */
2960 p = do_ffree_st7(p);
2961 p = do_fld_st(p, 0+fregNo(i->Xin.Fp64to32.src));
2962 /* subl $4, %esp */
2963 *p++ = 0x83; *p++ = 0xEC; *p++ = 0x04;
2964 /* fstps (%esp) */
2965 *p++ = 0xD9; *p++ = 0x1C; *p++ = 0x24;
2966 /* flds (%esp) */
2967 *p++ = 0xD9; *p++ = 0x04; *p++ = 0x24;
2968 /* addl $4, %esp */
2969 *p++ = 0x83; *p++ = 0xC4; *p++ = 0x04;
2970 /* fstp %st(1+dst) */
2971 p = do_fstp_st(p, 1+fregNo(i->Xin.Fp64to32.dst));
2972 goto done;
2973
sewardj3fc76d22004-08-31 11:47:54 +00002974 case Xin_FpCMov:
2975 /* jmp fwds if !condition */
sewardj8ee8c882005-02-25 17:40:26 +00002976 *p++ = toUChar(0x70 + (i->Xin.FpCMov.cond ^ 1));
sewardj3fc76d22004-08-31 11:47:54 +00002977 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2978 ptmp = p;
2979
2980 /* ffree %st7 ; fld %st(src) ; fstp %st(1+dst) */
2981 p = do_ffree_st7(p);
sewardjbdc7d212004-09-09 02:46:40 +00002982 p = do_fld_st(p, 0+fregNo(i->Xin.FpCMov.src));
2983 p = do_fstp_st(p, 1+fregNo(i->Xin.FpCMov.dst));
sewardj3fc76d22004-08-31 11:47:54 +00002984
2985 /* Fill in the jump offset. */
sewardj8ee8c882005-02-25 17:40:26 +00002986 *(ptmp-1) = toUChar(p - ptmp);
sewardj3fc76d22004-08-31 11:47:54 +00002987 goto done;
2988
sewardjeba63f82005-02-23 13:31:25 +00002989 case Xin_FpLdCW:
2990 *p++ = 0xD9;
2991 p = doAMode_M(p, fake(5)/*subopcode*/, i->Xin.FpLdCW.addr);
sewardj8f3debf2004-09-08 23:42:23 +00002992 goto done;
2993
sewardj46de4072004-09-11 19:23:24 +00002994 case Xin_FpStSW_AX:
2995 /* note, this emits fnstsw %ax, not fstsw %ax */
2996 *p++ = 0xDF;
2997 *p++ = 0xE0;
2998 goto done;
sewardjbdc7d212004-09-09 02:46:40 +00002999
3000 case Xin_FpCmp:
3001 /* gcmp %fL, %fR, %dst
3002 -> ffree %st7; fpush %fL ; fucomp %(fR+1) ;
3003 fnstsw %ax ; movl %eax, %dst
3004 */
3005 /* ffree %st7 */
3006 p = do_ffree_st7(p);
3007 /* fpush %fL */
3008 p = do_fld_st(p, 0+fregNo(i->Xin.FpCmp.srcL));
3009 /* fucomp %(fR+1) */
3010 *p++ = 0xDD;
sewardj8ee8c882005-02-25 17:40:26 +00003011 *p++ = toUChar(0xE8 + (7 & (1+fregNo(i->Xin.FpCmp.srcR))));
sewardjbdc7d212004-09-09 02:46:40 +00003012 /* fnstsw %ax */
3013 *p++ = 0xDF;
3014 *p++ = 0xE0;
3015 /* movl %eax, %dst */
3016 *p++ = 0x89;
3017 p = doAMode_R(p, hregX86_EAX(), i->Xin.FpCmp.dst);
3018 goto done;
3019
sewardj1e6ad742004-12-02 16:16:11 +00003020 case Xin_SseConst: {
3021 UShort con = i->Xin.SseConst.con;
sewardj8ee8c882005-02-25 17:40:26 +00003022 p = push_word_from_tags(p, toUShort((con >> 12) & 0xF));
3023 p = push_word_from_tags(p, toUShort((con >> 8) & 0xF));
3024 p = push_word_from_tags(p, toUShort((con >> 4) & 0xF));
3025 p = push_word_from_tags(p, toUShort(con & 0xF));
sewardj1e6ad742004-12-02 16:16:11 +00003026 /* movl (%esp), %xmm-dst */
3027 *p++ = 0x0F;
3028 *p++ = 0x10;
sewardj8ee8c882005-02-25 17:40:26 +00003029 *p++ = toUChar(0x04 + 8 * (7 & vregNo(i->Xin.SseConst.dst)));
sewardj1e6ad742004-12-02 16:16:11 +00003030 *p++ = 0x24;
3031 /* addl $16, %esp */
3032 *p++ = 0x83;
3033 *p++ = 0xC4;
3034 *p++ = 0x10;
3035 goto done;
3036 }
sewardj129b3d92004-12-05 15:42:05 +00003037
sewardjd08f2d72004-12-01 23:19:36 +00003038 case Xin_SseLdSt:
3039 *p++ = 0x0F;
sewardj8ee8c882005-02-25 17:40:26 +00003040 *p++ = toUChar(i->Xin.SseLdSt.isLoad ? 0x10 : 0x11);
sewardjd08f2d72004-12-01 23:19:36 +00003041 p = doAMode_M(p, fake(vregNo(i->Xin.SseLdSt.reg)), i->Xin.SseLdSt.addr);
3042 goto done;
3043
sewardj129b3d92004-12-05 15:42:05 +00003044 case Xin_SseLdzLO:
sewardj636ad762004-12-07 11:16:04 +00003045 vassert(i->Xin.SseLdzLO.sz == 4 || i->Xin.SseLdzLO.sz == 8);
3046 /* movs[sd] amode, %xmm-dst */
sewardj8ee8c882005-02-25 17:40:26 +00003047 *p++ = toUChar(i->Xin.SseLdzLO.sz==4 ? 0xF3 : 0xF2);
sewardj636ad762004-12-07 11:16:04 +00003048 *p++ = 0x0F;
3049 *p++ = 0x10;
3050 p = doAMode_M(p, fake(vregNo(i->Xin.SseLdzLO.reg)),
3051 i->Xin.SseLdzLO.addr);
3052 goto done;
sewardj129b3d92004-12-05 15:42:05 +00003053
sewardj1e6ad742004-12-02 16:16:11 +00003054 case Xin_Sse32Fx4:
3055 xtra = 0;
3056 *p++ = 0x0F;
3057 switch (i->Xin.Sse32Fx4.op) {
3058 case Xsse_ADDF: *p++ = 0x58; break;
sewardj176a59c2004-12-03 20:08:31 +00003059 case Xsse_DIVF: *p++ = 0x5E; break;
3060 case Xsse_MAXF: *p++ = 0x5F; break;
3061 case Xsse_MINF: *p++ = 0x5D; break;
sewardj9636b442004-12-04 01:38:37 +00003062 case Xsse_MULF: *p++ = 0x59; break;
sewardj0bd7ce62004-12-05 02:47:40 +00003063 case Xsse_RCPF: *p++ = 0x53; break;
sewardjc1e7dfc2004-12-05 19:29:45 +00003064 case Xsse_RSQRTF: *p++ = 0x52; break;
3065 case Xsse_SQRTF: *p++ = 0x51; break;
3066 case Xsse_SUBF: *p++ = 0x5C; break;
sewardj1e6ad742004-12-02 16:16:11 +00003067 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
3068 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
3069 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00003070 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj1e6ad742004-12-02 16:16:11 +00003071 default: goto bad;
3072 }
sewardjd08f2d72004-12-01 23:19:36 +00003073 p = doAMode_R(p, fake(vregNo(i->Xin.Sse32Fx4.dst)),
3074 fake(vregNo(i->Xin.Sse32Fx4.src)) );
sewardj1e6ad742004-12-02 16:16:11 +00003075 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00003076 *p++ = toUChar(xtra & 0xFF);
sewardj1e6ad742004-12-02 16:16:11 +00003077 goto done;
3078
sewardj636ad762004-12-07 11:16:04 +00003079 case Xin_Sse64Fx2:
3080 xtra = 0;
3081 *p++ = 0x66;
3082 *p++ = 0x0F;
3083 switch (i->Xin.Sse64Fx2.op) {
3084 case Xsse_ADDF: *p++ = 0x58; break;
3085 case Xsse_DIVF: *p++ = 0x5E; break;
3086 case Xsse_MAXF: *p++ = 0x5F; break;
3087 case Xsse_MINF: *p++ = 0x5D; break;
3088 case Xsse_MULF: *p++ = 0x59; break;
3089 case Xsse_RCPF: *p++ = 0x53; break;
3090 case Xsse_RSQRTF: *p++ = 0x52; break;
3091 case Xsse_SQRTF: *p++ = 0x51; break;
3092 case Xsse_SUBF: *p++ = 0x5C; break;
3093 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
3094 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
3095 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00003096 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj636ad762004-12-07 11:16:04 +00003097 default: goto bad;
3098 }
3099 p = doAMode_R(p, fake(vregNo(i->Xin.Sse64Fx2.dst)),
3100 fake(vregNo(i->Xin.Sse64Fx2.src)) );
3101 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00003102 *p++ = toUChar(xtra & 0xFF);
sewardj636ad762004-12-07 11:16:04 +00003103 goto done;
3104
sewardj1e6ad742004-12-02 16:16:11 +00003105 case Xin_Sse32FLo:
3106 xtra = 0;
3107 *p++ = 0xF3;
3108 *p++ = 0x0F;
3109 switch (i->Xin.Sse32FLo.op) {
3110 case Xsse_ADDF: *p++ = 0x58; break;
sewardj176a59c2004-12-03 20:08:31 +00003111 case Xsse_DIVF: *p++ = 0x5E; break;
3112 case Xsse_MAXF: *p++ = 0x5F; break;
3113 case Xsse_MINF: *p++ = 0x5D; break;
sewardj9636b442004-12-04 01:38:37 +00003114 case Xsse_MULF: *p++ = 0x59; break;
sewardj0bd7ce62004-12-05 02:47:40 +00003115 case Xsse_RCPF: *p++ = 0x53; break;
sewardjc1e7dfc2004-12-05 19:29:45 +00003116 case Xsse_RSQRTF: *p++ = 0x52; break;
3117 case Xsse_SQRTF: *p++ = 0x51; break;
3118 case Xsse_SUBF: *p++ = 0x5C; break;
sewardj1e6ad742004-12-02 16:16:11 +00003119 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
3120 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
3121 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00003122 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj1e6ad742004-12-02 16:16:11 +00003123 default: goto bad;
3124 }
3125 p = doAMode_R(p, fake(vregNo(i->Xin.Sse32FLo.dst)),
3126 fake(vregNo(i->Xin.Sse32FLo.src)) );
3127 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00003128 *p++ = toUChar(xtra & 0xFF);
sewardjd08f2d72004-12-01 23:19:36 +00003129 goto done;
3130
sewardj636ad762004-12-07 11:16:04 +00003131 case Xin_Sse64FLo:
3132 xtra = 0;
3133 *p++ = 0xF2;
3134 *p++ = 0x0F;
3135 switch (i->Xin.Sse64FLo.op) {
3136 case Xsse_ADDF: *p++ = 0x58; break;
3137 case Xsse_DIVF: *p++ = 0x5E; break;
3138 case Xsse_MAXF: *p++ = 0x5F; break;
3139 case Xsse_MINF: *p++ = 0x5D; break;
3140 case Xsse_MULF: *p++ = 0x59; break;
3141 case Xsse_RCPF: *p++ = 0x53; break;
3142 case Xsse_RSQRTF: *p++ = 0x52; break;
3143 case Xsse_SQRTF: *p++ = 0x51; break;
3144 case Xsse_SUBF: *p++ = 0x5C; break;
3145 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
3146 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
3147 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
sewardja26f6612005-11-05 01:54:07 +00003148 case Xsse_CMPUNF: *p++ = 0xC2; xtra = 0x103; break;
sewardj636ad762004-12-07 11:16:04 +00003149 default: goto bad;
3150 }
3151 p = doAMode_R(p, fake(vregNo(i->Xin.Sse64FLo.dst)),
3152 fake(vregNo(i->Xin.Sse64FLo.src)) );
3153 if (xtra & 0x100)
sewardj8ee8c882005-02-25 17:40:26 +00003154 *p++ = toUChar(xtra & 0xFF);
sewardj636ad762004-12-07 11:16:04 +00003155 goto done;
3156
sewardj164f9272004-12-09 00:39:32 +00003157 case Xin_SseReRg:
3158# define XX(_n) *p++ = (_n)
3159 switch (i->Xin.SseReRg.op) {
sewardj9e203592004-12-10 01:48:18 +00003160 case Xsse_MOV: /*movups*/ XX(0x0F); XX(0x10); break;
3161 case Xsse_OR: XX(0x0F); XX(0x56); break;
3162 case Xsse_XOR: XX(0x0F); XX(0x57); break;
3163 case Xsse_AND: XX(0x0F); XX(0x54); break;
sewardje5854d62004-12-09 03:44:34 +00003164 case Xsse_PACKSSD: XX(0x66); XX(0x0F); XX(0x6B); break;
3165 case Xsse_PACKSSW: XX(0x66); XX(0x0F); XX(0x63); break;
3166 case Xsse_PACKUSW: XX(0x66); XX(0x0F); XX(0x67); break;
3167 case Xsse_ADD8: XX(0x66); XX(0x0F); XX(0xFC); break;
3168 case Xsse_ADD16: XX(0x66); XX(0x0F); XX(0xFD); break;
3169 case Xsse_ADD32: XX(0x66); XX(0x0F); XX(0xFE); break;
3170 case Xsse_ADD64: XX(0x66); XX(0x0F); XX(0xD4); break;
3171 case Xsse_QADD8S: XX(0x66); XX(0x0F); XX(0xEC); break;
3172 case Xsse_QADD16S: XX(0x66); XX(0x0F); XX(0xED); break;
3173 case Xsse_QADD8U: XX(0x66); XX(0x0F); XX(0xDC); break;
3174 case Xsse_QADD16U: XX(0x66); XX(0x0F); XX(0xDD); break;
3175 case Xsse_AVG8U: XX(0x66); XX(0x0F); XX(0xE0); break;
3176 case Xsse_AVG16U: XX(0x66); XX(0x0F); XX(0xE3); break;
3177 case Xsse_CMPEQ8: XX(0x66); XX(0x0F); XX(0x74); break;
3178 case Xsse_CMPEQ16: XX(0x66); XX(0x0F); XX(0x75); break;
3179 case Xsse_CMPEQ32: XX(0x66); XX(0x0F); XX(0x76); break;
3180 case Xsse_CMPGT8S: XX(0x66); XX(0x0F); XX(0x64); break;
3181 case Xsse_CMPGT16S: XX(0x66); XX(0x0F); XX(0x65); break;
3182 case Xsse_CMPGT32S: XX(0x66); XX(0x0F); XX(0x66); break;
3183 case Xsse_MAX16S: XX(0x66); XX(0x0F); XX(0xEE); break;
3184 case Xsse_MAX8U: XX(0x66); XX(0x0F); XX(0xDE); break;
3185 case Xsse_MIN16S: XX(0x66); XX(0x0F); XX(0xEA); break;
3186 case Xsse_MIN8U: XX(0x66); XX(0x0F); XX(0xDA); break;
3187 case Xsse_MULHI16U: XX(0x66); XX(0x0F); XX(0xE4); break;
3188 case Xsse_MULHI16S: XX(0x66); XX(0x0F); XX(0xE5); break;
3189 case Xsse_MUL16: XX(0x66); XX(0x0F); XX(0xD5); break;
sewardjb9fa69b2004-12-09 23:25:14 +00003190 case Xsse_SHL16: XX(0x66); XX(0x0F); XX(0xF1); break;
3191 case Xsse_SHL32: XX(0x66); XX(0x0F); XX(0xF2); break;
3192 case Xsse_SHL64: XX(0x66); XX(0x0F); XX(0xF3); break;
3193 case Xsse_SAR16: XX(0x66); XX(0x0F); XX(0xE1); break;
3194 case Xsse_SAR32: XX(0x66); XX(0x0F); XX(0xE2); break;
3195 case Xsse_SHR16: XX(0x66); XX(0x0F); XX(0xD1); break;
3196 case Xsse_SHR32: XX(0x66); XX(0x0F); XX(0xD2); break;
3197 case Xsse_SHR64: XX(0x66); XX(0x0F); XX(0xD3); break;
3198 case Xsse_SUB8: XX(0x66); XX(0x0F); XX(0xF8); break;
3199 case Xsse_SUB16: XX(0x66); XX(0x0F); XX(0xF9); break;
3200 case Xsse_SUB32: XX(0x66); XX(0x0F); XX(0xFA); break;
3201 case Xsse_SUB64: XX(0x66); XX(0x0F); XX(0xFB); break;
3202 case Xsse_QSUB8S: XX(0x66); XX(0x0F); XX(0xE8); break;
3203 case Xsse_QSUB16S: XX(0x66); XX(0x0F); XX(0xE9); break;
3204 case Xsse_QSUB8U: XX(0x66); XX(0x0F); XX(0xD8); break;
3205 case Xsse_QSUB16U: XX(0x66); XX(0x0F); XX(0xD9); break;
sewardj9e203592004-12-10 01:48:18 +00003206 case Xsse_UNPCKHB: XX(0x66); XX(0x0F); XX(0x68); break;
3207 case Xsse_UNPCKHW: XX(0x66); XX(0x0F); XX(0x69); break;
3208 case Xsse_UNPCKHD: XX(0x66); XX(0x0F); XX(0x6A); break;
3209 case Xsse_UNPCKHQ: XX(0x66); XX(0x0F); XX(0x6D); break;
3210 case Xsse_UNPCKLB: XX(0x66); XX(0x0F); XX(0x60); break;
3211 case Xsse_UNPCKLW: XX(0x66); XX(0x0F); XX(0x61); break;
3212 case Xsse_UNPCKLD: XX(0x66); XX(0x0F); XX(0x62); break;
3213 case Xsse_UNPCKLQ: XX(0x66); XX(0x0F); XX(0x6C); break;
sewardj164f9272004-12-09 00:39:32 +00003214 default: goto bad;
3215 }
3216 p = doAMode_R(p, fake(vregNo(i->Xin.SseReRg.dst)),
3217 fake(vregNo(i->Xin.SseReRg.src)) );
3218# undef XX
3219 goto done;
3220
sewardjb9fa69b2004-12-09 23:25:14 +00003221 case Xin_SseCMov:
3222 /* jmp fwds if !condition */
sewardj8ee8c882005-02-25 17:40:26 +00003223 *p++ = toUChar(0x70 + (i->Xin.SseCMov.cond ^ 1));
sewardjb9fa69b2004-12-09 23:25:14 +00003224 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
3225 ptmp = p;
3226
3227 /* movaps %src, %dst */
3228 *p++ = 0x0F;
3229 *p++ = 0x28;
3230 p = doAMode_R(p, fake(vregNo(i->Xin.SseCMov.dst)),
3231 fake(vregNo(i->Xin.SseCMov.src)) );
3232
3233 /* Fill in the jump offset. */
sewardj8ee8c882005-02-25 17:40:26 +00003234 *(ptmp-1) = toUChar(p - ptmp);
sewardjb9fa69b2004-12-09 23:25:14 +00003235 goto done;
3236
sewardj109ffdb2004-12-10 21:45:38 +00003237 case Xin_SseShuf:
3238 *p++ = 0x66;
3239 *p++ = 0x0F;
3240 *p++ = 0x70;
3241 p = doAMode_R(p, fake(vregNo(i->Xin.SseShuf.dst)),
3242 fake(vregNo(i->Xin.SseShuf.src)) );
3243 *p++ = (UChar)(i->Xin.SseShuf.order);
3244 goto done;
3245
sewardjc6f970f2012-04-02 21:54:49 +00003246 case Xin_EvCheck: {
3247 /* We generate:
3248 (3 bytes) decl 4(%ebp) 4 == offsetof(host_EvC_COUNTER)
3249 (2 bytes) jns nofail expected taken
3250 (3 bytes) jmp* 0(%ebp) 0 == offsetof(host_EvC_FAILADDR)
3251 nofail:
3252 */
3253 /* This is heavily asserted re instruction lengths. It needs to
3254 be. If we get given unexpected forms of .amCounter or
3255 .amFailAddr -- basically, anything that's not of the form
3256 uimm7(%ebp) -- they are likely to fail. */
3257 /* Note also that after the decl we must be very careful not to
3258 read the carry flag, else we get a partial flags stall.
3259 js/jns avoids that, though. */
3260 UChar* p0 = p;
3261 /* --- decl 8(%ebp) --- */
3262 /* "fake(1)" because + there's no register in this encoding;
3263 instead the register + field is used as a sub opcode. The
3264 encoding for "decl r/m32" + is FF /1, hence the fake(1). */
3265 *p++ = 0xFF;
3266 p = doAMode_M(p, fake(1), i->Xin.EvCheck.amCounter);
3267 vassert(p - p0 == 3);
3268 /* --- jns nofail --- */
3269 *p++ = 0x79;
3270 *p++ = 0x03; /* need to check this 0x03 after the next insn */
3271 vassert(p - p0 == 5);
3272 /* --- jmp* 0(%ebp) --- */
3273 /* The encoding is FF /4. */
3274 *p++ = 0xFF;
3275 p = doAMode_M(p, fake(4), i->Xin.EvCheck.amFailAddr);
3276 vassert(p - p0 == 8); /* also ensures that 0x03 offset above is ok */
3277 /* And crosscheck .. */
3278 vassert(evCheckSzB_X86() == 8);
3279 goto done;
3280 }
3281
3282 case Xin_ProfInc: {
3283 /* We generate addl $1,NotKnownYet
3284 adcl $0,NotKnownYet+4
3285 in the expectation that a later call to LibVEX_patchProfCtr
3286 will be used to fill in the immediate fields once the right
3287 value is known.
3288 83 05 00 00 00 00 01
3289 83 15 00 00 00 00 00
3290 */
3291 *p++ = 0x83; *p++ = 0x05;
3292 *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
3293 *p++ = 0x01;
3294 *p++ = 0x83; *p++ = 0x15;
3295 *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
3296 *p++ = 0x00;
3297 /* Tell the caller .. */
3298 vassert(!(*is_profInc));
3299 *is_profInc = True;
3300 goto done;
3301 }
3302
sewardjea64e142004-07-22 16:47:21 +00003303 default:
3304 goto bad;
sewardj81bd5502004-07-21 18:49:27 +00003305 }
sewardjea64e142004-07-22 16:47:21 +00003306
3307 bad:
cerion92b64362005-12-13 12:02:26 +00003308 ppX86Instr(i, mode64);
sewardjea64e142004-07-22 16:47:21 +00003309 vpanic("emit_X86Instr");
3310 /*NOTREACHED*/
3311
sewardjbad34a92004-07-22 01:14:11 +00003312 done:
3313 vassert(p - &buf[0] <= 32);
3314 return p - &buf[0];
sewardjea64e142004-07-22 16:47:21 +00003315
sewardjd75fe5a2004-07-23 12:57:47 +00003316# undef fake
sewardj81bd5502004-07-21 18:49:27 +00003317}
3318
sewardjc6f970f2012-04-02 21:54:49 +00003319
3320/* How big is an event check? See case for Xin_EvCheck in
3321 emit_X86Instr just above. That crosschecks what this returns, so
3322 we can tell if we're inconsistent. */
3323Int evCheckSzB_X86 ( void )
3324{
3325 return 8;
3326}
3327
3328
3329/* NB: what goes on here has to be very closely coordinated with the
3330 emitInstr case for XDirect, above. */
3331VexInvalRange chainXDirect_X86 ( void* place_to_chain,
3332 void* disp_cp_chain_me_EXPECTED,
3333 void* place_to_jump_to )
3334{
3335 /* What we're expecting to see is:
3336 movl $disp_cp_chain_me_EXPECTED, %edx
3337 call *%edx
3338 viz
3339 BA <4 bytes value == disp_cp_chain_me_EXPECTED>
3340 FF D2
3341 */
3342 UChar* p = (UChar*)place_to_chain;
3343 vassert(p[0] == 0xBA);
3344 vassert(*(UInt*)(&p[1]) == (UInt)Ptr_to_ULong(disp_cp_chain_me_EXPECTED));
3345 vassert(p[5] == 0xFF);
3346 vassert(p[6] == 0xD2);
3347 /* And what we want to change it to is:
3348 jmp disp32 where disp32 is relative to the next insn
3349 ud2;
3350 viz
3351 E9 <4 bytes == disp32>
3352 0F 0B
3353 The replacement has the same length as the original.
3354 */
3355 /* This is the delta we need to put into a JMP d32 insn. It's
3356 relative to the start of the next insn, hence the -5. */
3357 Long delta = (Long)((UChar*)place_to_jump_to - (UChar*)p) - (Long)5;
3358
3359 /* And make the modifications. */
3360 p[0] = 0xE9;
3361 p[1] = (delta >> 0) & 0xFF;
3362 p[2] = (delta >> 8) & 0xFF;
3363 p[3] = (delta >> 16) & 0xFF;
3364 p[4] = (delta >> 24) & 0xFF;
3365 p[5] = 0x0F; p[6] = 0x0B;
3366 /* sanity check on the delta -- top 32 are all 0 or all 1 */
3367 delta >>= 32;
3368 vassert(delta == 0LL || delta == -1LL);
florian5ea257b2012-09-29 17:05:46 +00003369 VexInvalRange vir = { (HWord)place_to_chain, 7 };
sewardjc6f970f2012-04-02 21:54:49 +00003370 return vir;
3371}
3372
3373
3374/* NB: what goes on here has to be very closely coordinated with the
3375 emitInstr case for XDirect, above. */
3376VexInvalRange unchainXDirect_X86 ( void* place_to_unchain,
3377 void* place_to_jump_to_EXPECTED,
3378 void* disp_cp_chain_me )
3379{
3380 /* What we're expecting to see is:
3381 jmp d32
3382 ud2;
3383 viz
3384 E9 <4 bytes == disp32>
3385 0F 0B
3386 */
3387 UChar* p = (UChar*)place_to_unchain;
3388 Bool valid = False;
3389 if (p[0] == 0xE9
3390 && p[5] == 0x0F && p[6] == 0x0B) {
3391 /* Check the offset is right. */
3392 Int s32 = *(Int*)(&p[1]);
3393 if ((UChar*)p + 5 + s32 == (UChar*)place_to_jump_to_EXPECTED) {
3394 valid = True;
3395 if (0)
3396 vex_printf("QQQ unchainXDirect_X86: found valid\n");
3397 }
3398 }
3399 vassert(valid);
3400 /* And what we want to change it to is:
3401 movl $disp_cp_chain_me, %edx
3402 call *%edx
3403 viz
3404 BA <4 bytes value == disp_cp_chain_me_EXPECTED>
3405 FF D2
3406 So it's the same length (convenient, huh).
3407 */
3408 p[0] = 0xBA;
3409 *(UInt*)(&p[1]) = (UInt)Ptr_to_ULong(disp_cp_chain_me);
3410 p[5] = 0xFF;
3411 p[6] = 0xD2;
florian5ea257b2012-09-29 17:05:46 +00003412 VexInvalRange vir = { (HWord)place_to_unchain, 7 };
sewardjc6f970f2012-04-02 21:54:49 +00003413 return vir;
3414}
3415
3416
3417/* Patch the counter address into a profile inc point, as previously
3418 created by the Xin_ProfInc case for emit_X86Instr. */
3419VexInvalRange patchProfInc_X86 ( void* place_to_patch,
3420 ULong* location_of_counter )
3421{
3422 vassert(sizeof(ULong*) == 4);
3423 UChar* p = (UChar*)place_to_patch;
3424 vassert(p[0] == 0x83);
3425 vassert(p[1] == 0x05);
3426 vassert(p[2] == 0x00);
3427 vassert(p[3] == 0x00);
3428 vassert(p[4] == 0x00);
3429 vassert(p[5] == 0x00);
3430 vassert(p[6] == 0x01);
3431 vassert(p[7] == 0x83);
3432 vassert(p[8] == 0x15);
3433 vassert(p[9] == 0x00);
3434 vassert(p[10] == 0x00);
3435 vassert(p[11] == 0x00);
3436 vassert(p[12] == 0x00);
3437 vassert(p[13] == 0x00);
3438 UInt imm32 = (UInt)Ptr_to_ULong(location_of_counter);
3439 p[2] = imm32 & 0xFF; imm32 >>= 8;
3440 p[3] = imm32 & 0xFF; imm32 >>= 8;
3441 p[4] = imm32 & 0xFF; imm32 >>= 8;
3442 p[5] = imm32 & 0xFF; imm32 >>= 8;
3443 imm32 = 4 + (UInt)Ptr_to_ULong(location_of_counter);
3444 p[9] = imm32 & 0xFF; imm32 >>= 8;
3445 p[10] = imm32 & 0xFF; imm32 >>= 8;
3446 p[11] = imm32 & 0xFF; imm32 >>= 8;
3447 p[12] = imm32 & 0xFF; imm32 >>= 8;
florian5ea257b2012-09-29 17:05:46 +00003448 VexInvalRange vir = { (HWord)place_to_patch, 14 };
sewardjc6f970f2012-04-02 21:54:49 +00003449 return vir;
3450}
3451
3452
sewardj35421a32004-07-05 13:12:34 +00003453/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00003454/*--- end host_x86_defs.c ---*/
sewardj35421a32004-07-05 13:12:34 +00003455/*---------------------------------------------------------------*/