blob: c6d472fdc56d15c2d341fee603b3fe3c8cefad70 [file] [log] [blame]
sewardjc97096c2004-06-30 09:28:04 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (host-x86/hdefs.c) is ---*/
sewardjc97096c2004-06-30 09:28:04 +00005/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
sewardjf8ed9d82004-11-12 17:40:23 +00009/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
13 Copyright (C) 2004 OpenWorks, LLP.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; Version 2 dated June 1991 of the
18 license.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
23 for damages. See the GNU General Public License for more details.
24
25 Neither the names of the U.S. Department of Energy nor the
26 University of California nor the names of its contributors may be
27 used to endorse or promote products derived from this software
28 without prior written permission.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 USA.
34*/
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
sewardjc0ee2ed2004-07-27 10:29:41 +000040#include "main/vex_util.h"
41#include "host-generic/h_generic_regs.h"
42#include "host-x86/hdefs.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;
sewardjd08f2d72004-12-01 23:19:36 +000050 static 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
sewardj810dcf02004-11-22 12:55:45 +0000134HChar* 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
sewardjd08f2d72004-12-01 23:19:36 +0000433HChar* showX86ScalarSz ( X86ScalarSz sz ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000434 switch (sz) {
435 case Xss_16: return "w";
436 case Xss_32: return "l";
sewardjcfded9a2004-09-09 11:44:16 +0000437 default: vpanic("showX86ScalarSz");
sewardjc97096c2004-06-30 09:28:04 +0000438 }
sewardjc97096c2004-06-30 09:28:04 +0000439}
440
sewardjd08f2d72004-12-01 23:19:36 +0000441HChar* showX86UnaryOp ( X86UnaryOp op ) {
sewardj66f2f792004-06-30 16:37:16 +0000442 switch (op) {
sewardj358b7d42004-11-08 18:54:50 +0000443 case Xun_NOT: return "not";
444 case Xun_NEG: return "neg";
sewardjcfded9a2004-09-09 11:44:16 +0000445 default: vpanic("showX86UnaryOp");
sewardj60f4e3c2004-07-19 01:56:50 +0000446 }
447}
448
sewardjd08f2d72004-12-01 23:19:36 +0000449HChar* showX86AluOp ( X86AluOp op ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000450 switch (op) {
451 case Xalu_MOV: return "mov";
452 case Xalu_CMP: return "cmp";
sewardj60f4e3c2004-07-19 01:56:50 +0000453 case Xalu_ADD: return "add";
454 case Xalu_SUB: return "sub";
455 case Xalu_ADC: return "adc";
456 case Xalu_SBB: return "sbb";
457 case Xalu_AND: return "and";
458 case Xalu_OR: return "or";
459 case Xalu_XOR: return "xor";
460 case Xalu_MUL: return "mul";
sewardjcfded9a2004-09-09 11:44:16 +0000461 default: vpanic("showX86AluOp");
sewardj60f4e3c2004-07-19 01:56:50 +0000462 }
463}
464
sewardjd08f2d72004-12-01 23:19:36 +0000465HChar* showX86ShiftOp ( X86ShiftOp op ) {
sewardj60f4e3c2004-07-19 01:56:50 +0000466 switch (op) {
467 case Xsh_SHL: return "shl";
468 case Xsh_SHR: return "shr";
469 case Xsh_SAR: return "sar";
470 case Xsh_ROL: return "rol";
471 case Xsh_ROR: return "ror";
sewardjcfded9a2004-09-09 11:44:16 +0000472 default: vpanic("showX86ShiftOp");
sewardj66f2f792004-06-30 16:37:16 +0000473 }
sewardj66f2f792004-06-30 16:37:16 +0000474}
475
sewardjd08f2d72004-12-01 23:19:36 +0000476HChar* showX86FpOp ( X86FpOp op ) {
sewardjd1725d12004-08-12 20:46:53 +0000477 switch (op) {
sewardjbb53f8c2004-08-14 11:50:01 +0000478 case Xfp_ADD: return "add";
479 case Xfp_SUB: return "sub";
480 case Xfp_MUL: return "mul";
481 case Xfp_DIV: return "div";
sewardj8d387782004-11-11 02:15:15 +0000482 case Xfp_SCALE: return "scale";
483 case Xfp_ATAN: return "atan";
484 case Xfp_YL2X: return "yl2x";
485 case Xfp_YL2XP1: return "yl2xp1";
486 case Xfp_PREM: return "prem";
487 case Xfp_PREM1: return "prem1";
sewardjbb53f8c2004-08-14 11:50:01 +0000488 case Xfp_SQRT: return "sqrt";
sewardj883b00b2004-09-11 09:30:24 +0000489 case Xfp_ABS: return "abs";
sewardj8d387782004-11-11 02:15:15 +0000490 case Xfp_NEG: return "chs";
sewardjbb53f8c2004-08-14 11:50:01 +0000491 case Xfp_MOV: return "mov";
sewardjcfded9a2004-09-09 11:44:16 +0000492 case Xfp_SIN: return "sin";
493 case Xfp_COS: return "cos";
sewardj99016a72004-10-15 22:09:17 +0000494 case Xfp_TAN: return "tan";
sewardj8d387782004-11-11 02:15:15 +0000495 case Xfp_ROUND: return "round";
sewardj06c32a02004-09-12 12:07:34 +0000496 case Xfp_2XM1: return "2xm1";
sewardjcfded9a2004-09-09 11:44:16 +0000497 default: vpanic("showX86FpOp");
sewardjd1725d12004-08-12 20:46:53 +0000498 }
499}
500
sewardjd08f2d72004-12-01 23:19:36 +0000501HChar* showX86SseOp ( X86SseOp op ) {
502 switch (op) {
sewardj164f9272004-12-09 00:39:32 +0000503 case Xsse_MOV: return "mov(?!)";
504 case Xsse_ADDF: return "add";
505 case Xsse_SUBF: return "sub";
506 case Xsse_MULF: return "mul";
507 case Xsse_DIVF: return "div";
508 case Xsse_MAXF: return "max";
509 case Xsse_MINF: return "min";
510 case Xsse_CMPEQF: return "cmpFeq";
511 case Xsse_CMPLTF: return "cmpFlt";
512 case Xsse_CMPLEF: return "cmpFle";
513 case Xsse_CMPUNF: return "cmpFun";
514 case Xsse_RCPF: return "rcp";
515 case Xsse_RSQRTF: return "rsqrt";
516 case Xsse_SQRTF: return "sqrt";
517 case Xsse_AND: return "and";
518 case Xsse_OR: return "or";
519 case Xsse_XOR: return "xor";
520 case Xsse_ANDN: return "andn";
521 case Xsse_ADD8: return "paddb";
522 case Xsse_ADD16: return "paddw";
523 case Xsse_ADD32: return "paddd";
524 case Xsse_ADD64: return "paddq";
525 case Xsse_QADD8U: return "paddusb";
526 case Xsse_QADD16U: return "paddusw";
527 case Xsse_QADD8S: return "paddsb";
528 case Xsse_QADD16S: return "paddsw";
529 case Xsse_SUB8: return "psubb";
530 case Xsse_SUB16: return "psubw";
531 case Xsse_SUB32: return "psubd";
532 case Xsse_SUB64: return "psubq";
533 case Xsse_QSUB8U: return "psubusb";
534 case Xsse_QSUB16U: return "psubusw";
535 case Xsse_QSUB8S: return "psubsb";
536 case Xsse_QSUB16S: return "psubsw";
537 case Xsse_MUL16: return "pmullw";
538 case Xsse_MULHI16U: return "pmulhuw";
539 case Xsse_MULHI16S: return "pmulhw";
540 case Xsse_AVG8U: return "pavgb";
541 case Xsse_AVG16U: return "pavgw";
542 case Xsse_MAX16S: return "pmaxw";
543 case Xsse_MAX8U: return "pmaxub";
544 case Xsse_MIN16S: return "pminw";
545 case Xsse_MIN8U: return "pminub";
546 case Xsse_CMPEQ8: return "pcmpeqb";
547 case Xsse_CMPEQ16: return "pcmpeqw";
548 case Xsse_CMPEQ32: return "pcmpeqd";
549 case Xsse_CMPGT8S: return "pcmpgtb";
550 case Xsse_CMPGT16S: return "pcmpgtw";
551 case Xsse_CMPGT32S: return "pcmpgtd";
552 case Xsse_SHL16: return "psllw";
553 case Xsse_SHL32: return "pslld";
554 case Xsse_SHL64: return "psllq";
555 case Xsse_SHR16: return "psrlw";
556 case Xsse_SHR32: return "psrld";
557 case Xsse_SHR64: return "psrlq";
558 case Xsse_SAR16: return "psraw";
559 case Xsse_SAR32: return "psrad";
560 case Xsse_PACKSSD: return "packssdw";
561 case Xsse_PACKSSW: return "packsswb";
562 case Xsse_PACKUSW: return "packuswb";
sewardj9e203592004-12-10 01:48:18 +0000563 case Xsse_UNPCKHB: return "punpckhb";
564 case Xsse_UNPCKHW: return "punpckhw";
565 case Xsse_UNPCKHD: return "punpckhd";
566 case Xsse_UNPCKHQ: return "punpckhq";
567 case Xsse_UNPCKLB: return "punpcklb";
568 case Xsse_UNPCKLW: return "punpcklw";
569 case Xsse_UNPCKLD: return "punpckld";
570 case Xsse_UNPCKLQ: return "punpcklq";
sewardjd08f2d72004-12-01 23:19:36 +0000571 default: vpanic("showX86SseOp");
572 }
573}
574
sewardj66f2f792004-06-30 16:37:16 +0000575X86Instr* X86Instr_Alu32R ( X86AluOp op, X86RMI* src, HReg dst ) {
sewardj35421a32004-07-05 13:12:34 +0000576 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardj66f2f792004-06-30 16:37:16 +0000577 i->tag = Xin_Alu32R;
578 i->Xin.Alu32R.op = op;
579 i->Xin.Alu32R.src = src;
580 i->Xin.Alu32R.dst = dst;
581 return i;
582}
sewardj66f2f792004-06-30 16:37:16 +0000583X86Instr* X86Instr_Alu32M ( X86AluOp op, X86RI* src, X86AMode* dst ) {
sewardj35421a32004-07-05 13:12:34 +0000584 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardj66f2f792004-06-30 16:37:16 +0000585 i->tag = Xin_Alu32M;
586 i->Xin.Alu32M.op = op;
587 i->Xin.Alu32M.src = src;
588 i->Xin.Alu32M.dst = dst;
sewardje8c922f2004-07-23 01:34:11 +0000589 vassert(op != Xalu_MUL);
590 return i;
591}
592X86Instr* X86Instr_Sh32 ( X86ShiftOp op, UInt src, X86RM* dst ) {
593 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
594 i->tag = Xin_Sh32;
595 i->Xin.Sh32.op = op;
596 i->Xin.Sh32.src = src;
597 i->Xin.Sh32.dst = dst;
598 return i;
599}
600X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst ) {
601 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
602 i->tag = Xin_Test32;
603 i->Xin.Test32.src = src;
604 i->Xin.Test32.dst = dst;
sewardj66f2f792004-06-30 16:37:16 +0000605 return i;
606}
sewardj60f4e3c2004-07-19 01:56:50 +0000607X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ) {
608 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
609 i->tag = Xin_Unary32;
610 i->Xin.Unary32.op = op;
611 i->Xin.Unary32.dst = dst;
sewardj443cd9d2004-07-18 23:06:45 +0000612 return i;
613}
sewardj597b71b2004-07-19 02:51:12 +0000614X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz ssz , X86RM* src ) {
615 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
616 i->tag = Xin_MulL;
617 i->Xin.MulL.syned = syned;
618 i->Xin.MulL.ssz = ssz;
619 i->Xin.MulL.src = src;
620 return i;
621}
sewardj5c34dc92004-07-19 12:48:11 +0000622X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz ssz, X86RM* src ) {
623 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
624 i->tag = Xin_Div;
625 i->Xin.Div.syned = syned;
626 i->Xin.Div.ssz = ssz;
627 i->Xin.Div.src = src;
628 return i;
629}
sewardje5f384c2004-07-30 16:17:28 +0000630X86Instr* X86Instr_Sh3232 ( X86ShiftOp op, UInt amt, HReg src, HReg dst ) {
sewardj5c34dc92004-07-19 12:48:11 +0000631 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
632 i->tag = Xin_Sh3232;
633 i->Xin.Sh3232.op = op;
634 i->Xin.Sh3232.amt = amt;
sewardje5f384c2004-07-30 16:17:28 +0000635 i->Xin.Sh3232.src = src;
636 i->Xin.Sh3232.dst = dst;
sewardj5c34dc92004-07-19 12:48:11 +0000637 vassert(op == Xsh_SHL || op == Xsh_SHR);
638 return i;
639}
sewardje8e9d732004-07-16 21:03:45 +0000640X86Instr* X86Instr_Push( X86RMI* src ) {
sewardj35421a32004-07-05 13:12:34 +0000641 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
sewardje8e9d732004-07-16 21:03:45 +0000642 i->tag = Xin_Push;
643 i->Xin.Push.src = src;
644 return i;
645}
sewardj4b861de2004-11-03 15:24:42 +0000646X86Instr* X86Instr_Call ( X86CondCode cond, Addr32 target, Int regparms ) {
sewardj77352542004-10-30 20:39:01 +0000647 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
648 i->tag = Xin_Call;
sewardj4b861de2004-11-03 15:24:42 +0000649 i->Xin.Call.cond = cond;
sewardj77352542004-10-30 20:39:01 +0000650 i->Xin.Call.target = target;
651 i->Xin.Call.regparms = regparms;
652 vassert(regparms >= 0 && regparms <= 3);
sewardje8e9d732004-07-16 21:03:45 +0000653 return i;
654}
sewardj750f4072004-07-26 22:39:11 +0000655X86Instr* X86Instr_Goto ( IRJumpKind jk, X86CondCode cond, X86RI* dst ) {
sewardj443cd9d2004-07-18 23:06:45 +0000656 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
657 i->tag = Xin_Goto;
658 i->Xin.Goto.cond = cond;
659 i->Xin.Goto.dst = dst;
sewardj750f4072004-07-26 22:39:11 +0000660 i->Xin.Goto.jk = jk;
sewardjc97096c2004-06-30 09:28:04 +0000661 return i;
662}
sewardj5c34dc92004-07-19 12:48:11 +0000663X86Instr* X86Instr_CMov32 ( X86CondCode cond, X86RM* src, HReg dst ) {
664 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
665 i->tag = Xin_CMov32;
666 i->Xin.CMov32.cond = cond;
667 i->Xin.CMov32.src = src;
668 i->Xin.CMov32.dst = dst;
669 vassert(cond != Xcc_ALWAYS);
sewardj4042c7e2004-07-18 01:28:30 +0000670 return i;
671}
sewardj4042c7e2004-07-18 01:28:30 +0000672X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
673 X86AMode* src, HReg dst ) {
674 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
675 i->tag = Xin_LoadEX;
676 i->Xin.LoadEX.szSmall = szSmall;
677 i->Xin.LoadEX.syned = syned;
678 i->Xin.LoadEX.src = src;
679 i->Xin.LoadEX.dst = dst;
680 vassert(szSmall == 1 || szSmall == 2);
681 return i;
682}
sewardjd1725d12004-08-12 20:46:53 +0000683X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ) {
sewardj443cd9d2004-07-18 23:06:45 +0000684 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
685 i->tag = Xin_Store;
686 i->Xin.Store.sz = sz;
687 i->Xin.Store.src = src;
688 i->Xin.Store.dst = dst;
689 vassert(sz == 1 || sz == 2);
690 return i;
691}
sewardjd7cb8532004-08-17 23:59:23 +0000692X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ) {
693 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
694 i->tag = Xin_Set32;
695 i->Xin.Set32.cond = cond;
696 i->Xin.Set32.dst = dst;
697 return i;
698}
sewardjd08f2d72004-12-01 23:19:36 +0000699X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst ) {
sewardjce646f22004-08-31 23:55:54 +0000700 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
701 i->tag = Xin_Bsfr32;
702 i->Xin.Bsfr32.isFwds = isFwds;
703 i->Xin.Bsfr32.src = src;
704 i->Xin.Bsfr32.dst = dst;
705 return i;
706}
sewardjd1725d12004-08-12 20:46:53 +0000707X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ) {
708 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
709 i->tag = Xin_FpUnary;
710 i->Xin.FpUnary.op = op;
711 i->Xin.FpUnary.src = src;
712 i->Xin.FpUnary.dst = dst;
713 return i;
714}
715X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst ) {
716 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
717 i->tag = Xin_FpBinary;
718 i->Xin.FpBinary.op = op;
719 i->Xin.FpBinary.srcL = srcL;
720 i->Xin.FpBinary.srcR = srcR;
721 i->Xin.FpBinary.dst = dst;
722 return i;
723}
724X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* addr ) {
725 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
726 i->tag = Xin_FpLdSt;
727 i->Xin.FpLdSt.isLoad = isLoad;
728 i->Xin.FpLdSt.sz = sz;
729 i->Xin.FpLdSt.reg = reg;
730 i->Xin.FpLdSt.addr = addr;
731 vassert(sz == 4 || sz == 8);
732 return i;
733}
sewardjd08f2d72004-12-01 23:19:36 +0000734X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz,
735 HReg reg, X86AMode* addr ) {
sewardj89cd0932004-09-08 18:23:25 +0000736 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
737 i->tag = Xin_FpLdStI;
738 i->Xin.FpLdStI.isLoad = isLoad;
739 i->Xin.FpLdStI.sz = sz;
740 i->Xin.FpLdStI.reg = reg;
741 i->Xin.FpLdStI.addr = addr;
742 vassert(sz == 2 || sz == 4 || sz == 8);
sewardjd1725d12004-08-12 20:46:53 +0000743 return i;
744}
sewardj3bca9062004-12-04 14:36:09 +0000745X86Instr* X86Instr_Fp64to32 ( HReg src, HReg dst ) {
746 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
747 i->tag = Xin_Fp64to32;
748 i->Xin.Fp64to32.src = src;
749 i->Xin.Fp64to32.dst = dst;
750 return i;
751}
sewardj33124f62004-08-30 17:54:18 +0000752X86Instr* X86Instr_FpCMov ( X86CondCode cond, HReg src, HReg dst ) {
753 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
754 i->tag = Xin_FpCMov;
755 i->Xin.FpCMov.cond = cond;
756 i->Xin.FpCMov.src = src;
757 i->Xin.FpCMov.dst = dst;
758 vassert(cond != Xcc_ALWAYS);
759 return i;
760}
sewardjd08f2d72004-12-01 23:19:36 +0000761X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* addr ) {
sewardj8f3debf2004-09-08 23:42:23 +0000762 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
763 i->tag = Xin_FpLdStCW;
764 i->Xin.FpLdStCW.isLoad = isLoad;
765 i->Xin.FpLdStCW.addr = addr;
766 return i;
767}
sewardjd08f2d72004-12-01 23:19:36 +0000768X86Instr* X86Instr_FpStSW_AX ( void ) {
sewardj46de4072004-09-11 19:23:24 +0000769 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
770 i->tag = Xin_FpStSW_AX;
771 return i;
772}
sewardjd08f2d72004-12-01 23:19:36 +0000773X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ) {
sewardjbdc7d212004-09-09 02:46:40 +0000774 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
775 i->tag = Xin_FpCmp;
776 i->Xin.FpCmp.srcL = srcL;
777 i->Xin.FpCmp.srcR = srcR;
778 i->Xin.FpCmp.dst = dst;
779 return i;
780}
sewardj4042c7e2004-07-18 01:28:30 +0000781
sewardj1e6ad742004-12-02 16:16:11 +0000782X86Instr* X86Instr_SseConst ( UShort con, HReg dst ) {
783 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
784 i->tag = Xin_SseConst;
785 i->Xin.SseConst.con = con;
786 i->Xin.SseConst.dst = dst;
787 vassert(hregClass(dst) == HRcVec128);
788 return i;
789}
sewardjd08f2d72004-12-01 23:19:36 +0000790X86Instr* X86Instr_SseLdSt ( Bool isLoad, HReg reg, X86AMode* addr ) {
791 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
792 i->tag = Xin_SseLdSt;
793 i->Xin.SseLdSt.isLoad = isLoad;
794 i->Xin.SseLdSt.reg = reg;
795 i->Xin.SseLdSt.addr = addr;
796 return i;
797}
sewardj129b3d92004-12-05 15:42:05 +0000798X86Instr* X86Instr_SseLdzLO ( Int sz, HReg reg, X86AMode* addr )
799{
800 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
801 i->tag = Xin_SseLdzLO;
802 i->Xin.SseLdzLO.sz = sz;
803 i->Xin.SseLdzLO.reg = reg;
804 i->Xin.SseLdzLO.addr = addr;
805 vassert(sz == 4 || sz == 8);
806 return i;
807}
sewardj636ad762004-12-07 11:16:04 +0000808X86Instr* X86Instr_Sse32Fx4 ( X86SseOp op, HReg src, HReg dst ) {
sewardjd08f2d72004-12-01 23:19:36 +0000809 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
810 i->tag = Xin_Sse32Fx4;
811 i->Xin.Sse32Fx4.op = op;
812 i->Xin.Sse32Fx4.src = src;
813 i->Xin.Sse32Fx4.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000814 vassert(op != Xsse_MOV);
sewardjd08f2d72004-12-01 23:19:36 +0000815 return i;
816}
sewardj636ad762004-12-07 11:16:04 +0000817X86Instr* X86Instr_Sse32FLo ( X86SseOp op, HReg src, HReg dst ) {
sewardjd08f2d72004-12-01 23:19:36 +0000818 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
819 i->tag = Xin_Sse32FLo;
820 i->Xin.Sse32FLo.op = op;
821 i->Xin.Sse32FLo.src = src;
822 i->Xin.Sse32FLo.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000823 vassert(op != Xsse_MOV);
sewardjd08f2d72004-12-01 23:19:36 +0000824 return i;
825}
sewardj636ad762004-12-07 11:16:04 +0000826X86Instr* X86Instr_Sse64Fx2 ( X86SseOp op, HReg src, HReg dst ) {
827 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
828 i->tag = Xin_Sse64Fx2;
829 i->Xin.Sse64Fx2.op = op;
830 i->Xin.Sse64Fx2.src = src;
831 i->Xin.Sse64Fx2.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000832 vassert(op != Xsse_MOV);
sewardj636ad762004-12-07 11:16:04 +0000833 return i;
834}
835X86Instr* X86Instr_Sse64FLo ( X86SseOp op, HReg src, HReg dst ) {
836 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
837 i->tag = Xin_Sse64FLo;
838 i->Xin.Sse64FLo.op = op;
839 i->Xin.Sse64FLo.src = src;
840 i->Xin.Sse64FLo.dst = dst;
sewardj164f9272004-12-09 00:39:32 +0000841 vassert(op != Xsse_MOV);
842 return i;
843}
844X86Instr* X86Instr_SseReRg ( X86SseOp op, HReg re, HReg rg ) {
845 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
846 i->tag = Xin_SseReRg;
847 i->Xin.SseReRg.op = op;
848 i->Xin.SseReRg.src = re;
849 i->Xin.SseReRg.dst = rg;
sewardj636ad762004-12-07 11:16:04 +0000850 return i;
851}
sewardjb9fa69b2004-12-09 23:25:14 +0000852X86Instr* X86Instr_SseCMov ( X86CondCode cond, HReg src, HReg dst ) {
853 X86Instr* i = LibVEX_Alloc(sizeof(X86Instr));
854 i->tag = Xin_SseCMov;
855 i->Xin.SseCMov.cond = cond;
856 i->Xin.SseCMov.src = src;
857 i->Xin.SseCMov.dst = dst;
858 vassert(cond != Xcc_ALWAYS);
859 return i;
860}
sewardj4042c7e2004-07-18 01:28:30 +0000861
sewardj35421a32004-07-05 13:12:34 +0000862void ppX86Instr ( X86Instr* i ) {
sewardjc97096c2004-06-30 09:28:04 +0000863 switch (i->tag) {
sewardj66f2f792004-06-30 16:37:16 +0000864 case Xin_Alu32R:
sewardj60f4e3c2004-07-19 01:56:50 +0000865 vex_printf("%sl ", showX86AluOp(i->Xin.Alu32R.op));
sewardj35421a32004-07-05 13:12:34 +0000866 ppX86RMI(i->Xin.Alu32R.src);
867 vex_printf(",");
868 ppHRegX86(i->Xin.Alu32R.dst);
sewardjc97096c2004-06-30 09:28:04 +0000869 return;
sewardj66f2f792004-06-30 16:37:16 +0000870 case Xin_Alu32M:
sewardj60f4e3c2004-07-19 01:56:50 +0000871 vex_printf("%sl ", showX86AluOp(i->Xin.Alu32M.op));
sewardj35421a32004-07-05 13:12:34 +0000872 ppX86RI(i->Xin.Alu32M.src);
873 vex_printf(",");
874 ppX86AMode(i->Xin.Alu32M.dst);
sewardjc97096c2004-06-30 09:28:04 +0000875 return;
sewardje8c922f2004-07-23 01:34:11 +0000876 case Xin_Sh32:
877 vex_printf("%sl ", showX86ShiftOp(i->Xin.Sh32.op));
878 if (i->Xin.Sh32.src == 0)
sewardjbb53f8c2004-08-14 11:50:01 +0000879 vex_printf("%%cl,");
sewardje8c922f2004-07-23 01:34:11 +0000880 else
sewardjbb53f8c2004-08-14 11:50:01 +0000881 vex_printf("$%d,", i->Xin.Sh32.src);
sewardje8c922f2004-07-23 01:34:11 +0000882 ppX86RM(i->Xin.Sh32.dst);
883 return;
884 case Xin_Test32:
885 vex_printf("testl ");
886 ppX86RI(i->Xin.Test32.src);
887 vex_printf(",");
888 ppX86RM(i->Xin.Test32.dst);
889 return;
sewardj60f4e3c2004-07-19 01:56:50 +0000890 case Xin_Unary32:
891 vex_printf("%sl ", showX86UnaryOp(i->Xin.Unary32.op));
892 ppX86RM(i->Xin.Unary32.dst);
sewardj443cd9d2004-07-18 23:06:45 +0000893 return;
sewardj597b71b2004-07-19 02:51:12 +0000894 case Xin_MulL:
895 vex_printf("%cmul%s ",
896 i->Xin.MulL.syned ? 's' : 'u',
897 showX86ScalarSz(i->Xin.MulL.ssz));
898 ppX86RM(i->Xin.MulL.src);
899 return;
sewardj5c34dc92004-07-19 12:48:11 +0000900 case Xin_Div:
901 vex_printf("%cdiv%s ",
902 i->Xin.Div.syned ? 's' : 'u',
903 showX86ScalarSz(i->Xin.Div.ssz));
904 ppX86RM(i->Xin.Div.src);
905 return;
sewardj5c34dc92004-07-19 12:48:11 +0000906 case Xin_Sh3232:
907 vex_printf("%sdl ", showX86ShiftOp(i->Xin.Sh3232.op));
908 if (i->Xin.Sh3232.amt == 0)
sewardjea64e142004-07-22 16:47:21 +0000909 vex_printf(" %%cl,");
sewardj5c34dc92004-07-19 12:48:11 +0000910 else
911 vex_printf(" $%d,", i->Xin.Sh3232.amt);
sewardje5f384c2004-07-30 16:17:28 +0000912 ppHRegX86(i->Xin.Sh3232.src);
sewardj5c34dc92004-07-19 12:48:11 +0000913 vex_printf(",");
sewardje5f384c2004-07-30 16:17:28 +0000914 ppHRegX86(i->Xin.Sh3232.dst);
sewardj5c34dc92004-07-19 12:48:11 +0000915 return;
sewardje8e9d732004-07-16 21:03:45 +0000916 case Xin_Push:
917 vex_printf("pushl ");
918 ppX86RMI(i->Xin.Push.src);
919 return;
920 case Xin_Call:
sewardj4b861de2004-11-03 15:24:42 +0000921 vex_printf("call%s[%d] ",
922 i->Xin.Call.cond==Xcc_ALWAYS
923 ? "" : showX86CondCode(i->Xin.Call.cond),
924 i->Xin.Call.regparms);
925 vex_printf("0x%x", i->Xin.Call.target);
sewardje8e9d732004-07-16 21:03:45 +0000926 break;
sewardj443cd9d2004-07-18 23:06:45 +0000927 case Xin_Goto:
sewardj893aada2004-11-29 19:57:54 +0000928 if (i->Xin.Goto.cond != Xcc_ALWAYS) {
929 vex_printf("if (%%eflags.%s) { ",
930 showX86CondCode(i->Xin.Goto.cond));
931 }
932 if (i->Xin.Goto.jk != Ijk_Boring) {
sewardj750f4072004-07-26 22:39:11 +0000933 vex_printf("movl $");
934 ppIRJumpKind(i->Xin.Goto.jk);
sewardj893aada2004-11-29 19:57:54 +0000935 vex_printf(",%%ebp ; ");
sewardj750f4072004-07-26 22:39:11 +0000936 }
sewardj893aada2004-11-29 19:57:54 +0000937 vex_printf("movl ");
938 ppX86RI(i->Xin.Goto.dst);
939 vex_printf(",%%eax ; ret");
940 if (i->Xin.Goto.cond != Xcc_ALWAYS) {
941 vex_printf(" }");
942 }
sewardjc97096c2004-06-30 09:28:04 +0000943 return;
sewardj5c34dc92004-07-19 12:48:11 +0000944 case Xin_CMov32:
sewardja2dad5c2004-07-23 11:43:43 +0000945 vex_printf("cmov%s ", showX86CondCode(i->Xin.CMov32.cond));
sewardj5c34dc92004-07-19 12:48:11 +0000946 ppX86RM(i->Xin.CMov32.src);
sewardj4042c7e2004-07-18 01:28:30 +0000947 vex_printf(",");
sewardj5c34dc92004-07-19 12:48:11 +0000948 ppHRegX86(i->Xin.CMov32.dst);
sewardj4042c7e2004-07-18 01:28:30 +0000949 return;
950 case Xin_LoadEX:
951 vex_printf("mov%c%cl ",
952 i->Xin.LoadEX.syned ? 's' : 'z',
953 i->Xin.LoadEX.szSmall==1 ? 'b' : 'w');
954 ppX86AMode(i->Xin.LoadEX.src);
955 vex_printf(",");
956 ppHRegX86(i->Xin.LoadEX.dst);
957 return;
sewardj443cd9d2004-07-18 23:06:45 +0000958 case Xin_Store:
959 vex_printf("mov%c ", i->Xin.Store.sz==1 ? 'b' : 'w');
960 ppHRegX86(i->Xin.Store.src);
961 vex_printf(",");
962 ppX86AMode(i->Xin.Store.dst);
963 return;
sewardjd7cb8532004-08-17 23:59:23 +0000964 case Xin_Set32:
965 vex_printf("setl%s ", showX86CondCode(i->Xin.Set32.cond));
966 ppHRegX86(i->Xin.Set32.dst);
967 return;
sewardjce646f22004-08-31 23:55:54 +0000968 case Xin_Bsfr32:
969 vex_printf("bs%cl ", i->Xin.Bsfr32.isFwds ? 'f' : 'r');
970 ppHRegX86(i->Xin.Bsfr32.src);
971 vex_printf(",");
972 ppHRegX86(i->Xin.Bsfr32.dst);
973 return;
sewardjbb53f8c2004-08-14 11:50:01 +0000974 case Xin_FpUnary:
975 vex_printf("g%sD ", showX86FpOp(i->Xin.FpUnary.op));
976 ppHRegX86(i->Xin.FpUnary.src);
977 vex_printf(",");
978 ppHRegX86(i->Xin.FpUnary.dst);
979 break;
980 case Xin_FpBinary:
981 vex_printf("g%sD ", showX86FpOp(i->Xin.FpBinary.op));
982 ppHRegX86(i->Xin.FpBinary.srcL);
983 vex_printf(",");
984 ppHRegX86(i->Xin.FpBinary.srcR);
985 vex_printf(",");
986 ppHRegX86(i->Xin.FpBinary.dst);
987 break;
sewardjd1725d12004-08-12 20:46:53 +0000988 case Xin_FpLdSt:
989 if (i->Xin.FpLdSt.isLoad) {
sewardj3196daf2004-08-13 00:18:58 +0000990 vex_printf("gld%c " , i->Xin.FpLdSt.sz==8 ? 'D' : 'F');
sewardjd1725d12004-08-12 20:46:53 +0000991 ppX86AMode(i->Xin.FpLdSt.addr);
992 vex_printf(", ");
993 ppHRegX86(i->Xin.FpLdSt.reg);
994 } else {
sewardj3196daf2004-08-13 00:18:58 +0000995 vex_printf("gst%c " , i->Xin.FpLdSt.sz==8 ? 'D' : 'F');
sewardjd1725d12004-08-12 20:46:53 +0000996 ppHRegX86(i->Xin.FpLdSt.reg);
997 vex_printf(", ");
998 ppX86AMode(i->Xin.FpLdSt.addr);
999 }
1000 return;
sewardj89cd0932004-09-08 18:23:25 +00001001 case Xin_FpLdStI:
1002 if (i->Xin.FpLdStI.isLoad) {
1003 vex_printf("gild%s ", i->Xin.FpLdStI.sz==8 ? "ll" :
1004 i->Xin.FpLdStI.sz==4 ? "l" : "w");
1005 ppX86AMode(i->Xin.FpLdStI.addr);
sewardjbb53f8c2004-08-14 11:50:01 +00001006 vex_printf(", ");
sewardj89cd0932004-09-08 18:23:25 +00001007 ppHRegX86(i->Xin.FpLdStI.reg);
1008 } else {
1009 vex_printf("gist%s ", i->Xin.FpLdStI.sz==8 ? "ll" :
1010 i->Xin.FpLdStI.sz==4 ? "l" : "w");
1011 ppHRegX86(i->Xin.FpLdStI.reg);
1012 vex_printf(", ");
1013 ppX86AMode(i->Xin.FpLdStI.addr);
sewardjbb53f8c2004-08-14 11:50:01 +00001014 }
1015 return;
sewardj3bca9062004-12-04 14:36:09 +00001016 case Xin_Fp64to32:
1017 vex_printf("gdtof ");
1018 ppHRegX86(i->Xin.Fp64to32.src);
1019 vex_printf(",");
1020 ppHRegX86(i->Xin.Fp64to32.dst);
1021 return;
sewardj33124f62004-08-30 17:54:18 +00001022 case Xin_FpCMov:
1023 vex_printf("gcmov%s ", showX86CondCode(i->Xin.FpCMov.cond));
1024 ppHRegX86(i->Xin.FpCMov.src);
1025 vex_printf(",");
1026 ppHRegX86(i->Xin.FpCMov.dst);
1027 return;
sewardj8f3debf2004-09-08 23:42:23 +00001028 case Xin_FpLdStCW:
1029 vex_printf(i->Xin.FpLdStCW.isLoad ? "fldcw " : "fstcw ");
1030 ppX86AMode(i->Xin.FpLdStCW.addr);
1031 return;
sewardj46de4072004-09-11 19:23:24 +00001032 case Xin_FpStSW_AX:
1033 vex_printf("fstsw %%ax");
1034 return;
sewardjbdc7d212004-09-09 02:46:40 +00001035 case Xin_FpCmp:
1036 vex_printf("gcmp ");
1037 ppHRegX86(i->Xin.FpCmp.srcL);
1038 vex_printf(",");
1039 ppHRegX86(i->Xin.FpCmp.srcR);
1040 vex_printf(",");
1041 ppHRegX86(i->Xin.FpCmp.dst);
1042 break;
sewardj1e6ad742004-12-02 16:16:11 +00001043 case Xin_SseConst:
1044 vex_printf("const $0x%04x,", (Int)i->Xin.SseConst.con);
1045 ppHRegX86(i->Xin.SseConst.dst);
1046 break;
sewardjd08f2d72004-12-01 23:19:36 +00001047 case Xin_SseLdSt:
1048 vex_printf("movups ");
1049 if (i->Xin.SseLdSt.isLoad) {
1050 ppX86AMode(i->Xin.SseLdSt.addr);
1051 vex_printf(",");
1052 ppHRegX86(i->Xin.SseLdSt.reg);
1053 } else {
1054 ppHRegX86(i->Xin.SseLdSt.reg);
1055 vex_printf(",");
1056 ppX86AMode(i->Xin.SseLdSt.addr);
1057 }
1058 return;
sewardj129b3d92004-12-05 15:42:05 +00001059 case Xin_SseLdzLO:
1060 vex_printf("movs%s ", i->Xin.SseLdzLO.sz==4 ? "s" : "d");
1061 ppX86AMode(i->Xin.SseLdzLO.addr);
1062 vex_printf(",");
1063 ppHRegX86(i->Xin.SseLdzLO.reg);
1064 return;
sewardjd08f2d72004-12-01 23:19:36 +00001065 case Xin_Sse32Fx4:
1066 vex_printf("%sps ", showX86SseOp(i->Xin.Sse32Fx4.op));
1067 ppHRegX86(i->Xin.Sse32Fx4.src);
1068 vex_printf(",");
1069 ppHRegX86(i->Xin.Sse32Fx4.dst);
1070 return;
1071 case Xin_Sse32FLo:
1072 vex_printf("%sss ", showX86SseOp(i->Xin.Sse32FLo.op));
1073 ppHRegX86(i->Xin.Sse32FLo.src);
1074 vex_printf(",");
1075 ppHRegX86(i->Xin.Sse32FLo.dst);
1076 return;
sewardj636ad762004-12-07 11:16:04 +00001077 case Xin_Sse64Fx2:
1078 vex_printf("%spd ", showX86SseOp(i->Xin.Sse64Fx2.op));
1079 ppHRegX86(i->Xin.Sse64Fx2.src);
1080 vex_printf(",");
1081 ppHRegX86(i->Xin.Sse64Fx2.dst);
1082 return;
1083 case Xin_Sse64FLo:
1084 vex_printf("%ssd ", showX86SseOp(i->Xin.Sse64FLo.op));
1085 ppHRegX86(i->Xin.Sse64FLo.src);
1086 vex_printf(",");
1087 ppHRegX86(i->Xin.Sse64FLo.dst);
1088 return;
sewardj164f9272004-12-09 00:39:32 +00001089 case Xin_SseReRg:
1090 vex_printf("%s ", showX86SseOp(i->Xin.SseReRg.op));
1091 ppHRegX86(i->Xin.SseReRg.src);
1092 vex_printf(",");
1093 ppHRegX86(i->Xin.SseReRg.dst);
1094 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001095 case Xin_SseCMov:
1096 vex_printf("cmov%s ", showX86CondCode(i->Xin.SseCMov.cond));
1097 ppHRegX86(i->Xin.SseCMov.src);
1098 vex_printf(",");
1099 ppHRegX86(i->Xin.SseCMov.dst);
1100 return;
sewardjd08f2d72004-12-01 23:19:36 +00001101
sewardjc97096c2004-06-30 09:28:04 +00001102 default:
sewardj35421a32004-07-05 13:12:34 +00001103 vpanic("ppX86Instr");
sewardjc97096c2004-06-30 09:28:04 +00001104 }
1105}
sewardj53f85a92004-07-02 13:45:17 +00001106
sewardj194d54a2004-07-03 19:08:18 +00001107/* --------- Helpers for register allocation. --------- */
1108
sewardj53f85a92004-07-02 13:45:17 +00001109void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
1110{
sewardj0bd7ce62004-12-05 02:47:40 +00001111 Bool unary;
sewardj53f85a92004-07-02 13:45:17 +00001112 initHRegUsage(u);
1113 switch (i->tag) {
1114 case Xin_Alu32R:
1115 addRegUsage_X86RMI(u, i->Xin.Alu32R.src);
sewardj4042c7e2004-07-18 01:28:30 +00001116 if (i->Xin.Alu32R.op == Xalu_MOV) {
sewardj53f85a92004-07-02 13:45:17 +00001117 addHRegUse(u, HRmWrite, i->Xin.Alu32R.dst);
sewardj4042c7e2004-07-18 01:28:30 +00001118 return;
1119 }
sewardje8c922f2004-07-23 01:34:11 +00001120 if (i->Xin.Alu32R.op == Xalu_CMP) {
sewardj4042c7e2004-07-18 01:28:30 +00001121 addHRegUse(u, HRmRead, i->Xin.Alu32R.dst);
1122 return;
1123 }
1124 addHRegUse(u, HRmModify, i->Xin.Alu32R.dst);
sewardj53f85a92004-07-02 13:45:17 +00001125 return;
1126 case Xin_Alu32M:
1127 addRegUsage_X86RI(u, i->Xin.Alu32M.src);
1128 addRegUsage_X86AMode(u, i->Xin.Alu32M.dst);
1129 return;
sewardje8c922f2004-07-23 01:34:11 +00001130 case Xin_Sh32:
1131 addRegUsage_X86RM(u, i->Xin.Sh32.dst, HRmModify);
1132 if (i->Xin.Sh32.src == 0)
1133 addHRegUse(u, HRmRead, hregX86_ECX());
1134 return;
1135 case Xin_Test32:
1136 addRegUsage_X86RI(u, i->Xin.Test32.src);
1137 addRegUsage_X86RM(u, i->Xin.Test32.dst, HRmRead);
1138 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001139 case Xin_Unary32:
1140 addRegUsage_X86RM(u, i->Xin.Unary32.dst, HRmModify);
1141 return;
1142 case Xin_MulL:
1143 addRegUsage_X86RM(u, i->Xin.MulL.src, HRmRead);
1144 addHRegUse(u, HRmModify, hregX86_EAX());
1145 addHRegUse(u, HRmWrite, hregX86_EDX());
1146 return;
1147 case Xin_Div:
sewardjea64e142004-07-22 16:47:21 +00001148 addRegUsage_X86RM(u, i->Xin.Div.src, HRmRead);
sewardj1f40a0a2004-07-21 12:28:07 +00001149 addHRegUse(u, HRmModify, hregX86_EAX());
1150 addHRegUse(u, HRmModify, hregX86_EDX());
1151 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001152 case Xin_Sh3232:
sewardje5f384c2004-07-30 16:17:28 +00001153 addHRegUse(u, HRmRead, i->Xin.Sh3232.src);
1154 addHRegUse(u, HRmModify, i->Xin.Sh3232.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001155 if (i->Xin.Sh3232.amt == 0)
1156 addHRegUse(u, HRmRead, hregX86_ECX());
1157 return;
sewardje8e9d732004-07-16 21:03:45 +00001158 case Xin_Push:
1159 addRegUsage_X86RMI(u, i->Xin.Push.src);
1160 addHRegUse(u, HRmModify, hregX86_ESP());
1161 return;
1162 case Xin_Call:
sewardj4b861de2004-11-03 15:24:42 +00001163 /* This is a bit subtle. */
1164 /* First off, claim it trashes all the callee-saved regs */
sewardj36ca5132004-07-24 13:12:23 +00001165 /* which I believe to be %eax,%ecx,%edx. */
sewardje8e9d732004-07-16 21:03:45 +00001166 addHRegUse(u, HRmWrite, hregX86_EAX());
1167 addHRegUse(u, HRmWrite, hregX86_ECX());
1168 addHRegUse(u, HRmWrite, hregX86_EDX());
sewardj4b861de2004-11-03 15:24:42 +00001169 /* Now we have to state any parameter-carrying registers
1170 which might be read. This depends on the regparmness. */
sewardj77352542004-10-30 20:39:01 +00001171 switch (i->Xin.Call.regparms) {
1172 case 3: addHRegUse(u, HRmRead, hregX86_ECX()); /*fallthru*/
1173 case 2: addHRegUse(u, HRmRead, hregX86_EDX()); /*fallthru*/
1174 case 1: addHRegUse(u, HRmRead, hregX86_EAX()); break;
1175 case 0: break;
1176 default: vpanic("getRegUsage_X86Instr:Call:regparms");
1177 }
sewardj4b861de2004-11-03 15:24:42 +00001178 /* Finally, there is the issue that the insn trashes a
1179 register because the literal target address has to be
1180 loaded into a register. Fortunately, for the 0/1/2
sewardj45c50eb2004-11-04 18:25:33 +00001181 regparm case, we can use EAX, EDX and ECX respectively, so
sewardj4b861de2004-11-03 15:24:42 +00001182 this does not cause any further damage. For the 3-regparm
1183 case, we'll have to choose another register arbitrarily --
sewardj45c50eb2004-11-04 18:25:33 +00001184 since A, D and C are used for parameters -- and so we might
sewardj4b861de2004-11-03 15:24:42 +00001185 as well choose EDI. */
1186 if (i->Xin.Call.regparms == 3)
1187 addHRegUse(u, HRmWrite, hregX86_EDI());
1188 /* Upshot of this is that the assembler really must observe
1189 the here-stated convention of which register to use as an
1190 address temporary, depending on the regparmness: 0==EAX,
sewardj45c50eb2004-11-04 18:25:33 +00001191 1==EDX, 2==ECX, 3==EDI. */
sewardje8e9d732004-07-16 21:03:45 +00001192 return;
sewardj443cd9d2004-07-18 23:06:45 +00001193 case Xin_Goto:
1194 addRegUsage_X86RI(u, i->Xin.Goto.dst);
sewardje8e9d732004-07-16 21:03:45 +00001195 addHRegUse(u, HRmWrite, hregX86_EAX());
sewardj893aada2004-11-29 19:57:54 +00001196 if (i->Xin.Goto.jk != Ijk_Boring)
sewardj750f4072004-07-26 22:39:11 +00001197 addHRegUse(u, HRmWrite, hregX86_EBP());
sewardj0ec33252004-07-03 13:30:00 +00001198 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001199 case Xin_CMov32:
1200 addRegUsage_X86RM(u, i->Xin.CMov32.src, HRmRead);
1201 addHRegUse(u, HRmModify, i->Xin.CMov32.dst);
1202 return;
1203 case Xin_LoadEX:
1204 addRegUsage_X86AMode(u, i->Xin.LoadEX.src);
1205 addHRegUse(u, HRmWrite, i->Xin.LoadEX.dst);
1206 return;
1207 case Xin_Store:
1208 addHRegUse(u, HRmRead, i->Xin.Store.src);
1209 addRegUsage_X86AMode(u, i->Xin.Store.dst);
1210 return;
sewardjd7cb8532004-08-17 23:59:23 +00001211 case Xin_Set32:
1212 addHRegUse(u, HRmWrite, i->Xin.Set32.dst);
1213 return;
sewardjce646f22004-08-31 23:55:54 +00001214 case Xin_Bsfr32:
1215 addHRegUse(u, HRmRead, i->Xin.Bsfr32.src);
1216 addHRegUse(u, HRmWrite, i->Xin.Bsfr32.dst);
1217 return;
sewardjbb53f8c2004-08-14 11:50:01 +00001218 case Xin_FpUnary:
1219 addHRegUse(u, HRmRead, i->Xin.FpUnary.src);
1220 addHRegUse(u, HRmWrite, i->Xin.FpUnary.dst);
1221 return;
1222 case Xin_FpBinary:
1223 addHRegUse(u, HRmRead, i->Xin.FpBinary.srcL);
1224 addHRegUse(u, HRmRead, i->Xin.FpBinary.srcR);
1225 addHRegUse(u, HRmWrite, i->Xin.FpBinary.dst);
1226 return;
sewardj3196daf2004-08-13 00:18:58 +00001227 case Xin_FpLdSt:
1228 addRegUsage_X86AMode(u, i->Xin.FpLdSt.addr);
1229 addHRegUse(u, i->Xin.FpLdSt.isLoad ? HRmWrite : HRmRead,
1230 i->Xin.FpLdSt.reg);
1231 return;
sewardj89cd0932004-09-08 18:23:25 +00001232 case Xin_FpLdStI:
1233 addRegUsage_X86AMode(u, i->Xin.FpLdStI.addr);
1234 addHRegUse(u, i->Xin.FpLdStI.isLoad ? HRmWrite : HRmRead,
1235 i->Xin.FpLdStI.reg);
sewardjbb53f8c2004-08-14 11:50:01 +00001236 return;
sewardj3bca9062004-12-04 14:36:09 +00001237 case Xin_Fp64to32:
1238 addHRegUse(u, HRmRead, i->Xin.Fp64to32.src);
1239 addHRegUse(u, HRmWrite, i->Xin.Fp64to32.dst);
1240 return;
sewardj3fc76d22004-08-31 11:47:54 +00001241 case Xin_FpCMov:
sewardjb9fa69b2004-12-09 23:25:14 +00001242 addHRegUse(u, HRmRead, i->Xin.FpCMov.src);
sewardj3fc76d22004-08-31 11:47:54 +00001243 addHRegUse(u, HRmModify, i->Xin.FpCMov.dst);
1244 return;
sewardj8f3debf2004-09-08 23:42:23 +00001245 case Xin_FpLdStCW:
1246 addRegUsage_X86AMode(u, i->Xin.FpLdStCW.addr);
1247 return;
sewardj46de4072004-09-11 19:23:24 +00001248 case Xin_FpStSW_AX:
1249 addHRegUse(u, HRmWrite, hregX86_EAX());
1250 return;
sewardjbdc7d212004-09-09 02:46:40 +00001251 case Xin_FpCmp:
1252 addHRegUse(u, HRmRead, i->Xin.FpCmp.srcL);
1253 addHRegUse(u, HRmRead, i->Xin.FpCmp.srcR);
1254 addHRegUse(u, HRmWrite, i->Xin.FpCmp.dst);
1255 addHRegUse(u, HRmWrite, hregX86_EAX());
1256 return;
sewardjd08f2d72004-12-01 23:19:36 +00001257 case Xin_SseLdSt:
1258 addRegUsage_X86AMode(u, i->Xin.SseLdSt.addr);
1259 addHRegUse(u, i->Xin.SseLdSt.isLoad ? HRmWrite : HRmRead,
1260 i->Xin.SseLdSt.reg);
1261 return;
sewardj129b3d92004-12-05 15:42:05 +00001262 case Xin_SseLdzLO:
1263 addRegUsage_X86AMode(u, i->Xin.SseLdzLO.addr);
1264 addHRegUse(u, HRmWrite, i->Xin.SseLdzLO.reg);
1265 return;
sewardj1e6ad742004-12-02 16:16:11 +00001266 case Xin_SseConst:
1267 addHRegUse(u, HRmWrite, i->Xin.SseConst.dst);
1268 return;
sewardjd08f2d72004-12-01 23:19:36 +00001269 case Xin_Sse32Fx4:
1270 vassert(i->Xin.Sse32Fx4.op != Xsse_MOV);
sewardjc1e7dfc2004-12-05 19:29:45 +00001271 unary = i->Xin.Sse32Fx4.op == Xsse_RCPF
1272 || i->Xin.Sse32Fx4.op == Xsse_RSQRTF
1273 || i->Xin.Sse32Fx4.op == Xsse_SQRTF;
sewardj0bd7ce62004-12-05 02:47:40 +00001274 addHRegUse(u, HRmRead, i->Xin.Sse32Fx4.src);
1275 addHRegUse(u, unary ? HRmWrite : HRmModify,
1276 i->Xin.Sse32Fx4.dst);
sewardjd08f2d72004-12-01 23:19:36 +00001277 return;
sewardj1e6ad742004-12-02 16:16:11 +00001278 case Xin_Sse32FLo:
1279 vassert(i->Xin.Sse32FLo.op != Xsse_MOV);
sewardjc1e7dfc2004-12-05 19:29:45 +00001280 unary = i->Xin.Sse32FLo.op == Xsse_RCPF
1281 || i->Xin.Sse32FLo.op == Xsse_RSQRTF
1282 || i->Xin.Sse32FLo.op == Xsse_SQRTF;
sewardj0bd7ce62004-12-05 02:47:40 +00001283 addHRegUse(u, HRmRead, i->Xin.Sse32FLo.src);
1284 addHRegUse(u, unary ? HRmWrite : HRmModify,
1285 i->Xin.Sse32FLo.dst);
sewardj1e6ad742004-12-02 16:16:11 +00001286 return;
sewardj636ad762004-12-07 11:16:04 +00001287 case Xin_Sse64Fx2:
1288 vassert(i->Xin.Sse64Fx2.op != Xsse_MOV);
1289 unary = i->Xin.Sse64Fx2.op == Xsse_RCPF
1290 || i->Xin.Sse64Fx2.op == Xsse_RSQRTF
1291 || i->Xin.Sse64Fx2.op == Xsse_SQRTF;
1292 addHRegUse(u, HRmRead, i->Xin.Sse64Fx2.src);
1293 addHRegUse(u, unary ? HRmWrite : HRmModify,
1294 i->Xin.Sse64Fx2.dst);
1295 return;
1296 case Xin_Sse64FLo:
1297 vassert(i->Xin.Sse64FLo.op != Xsse_MOV);
1298 unary = i->Xin.Sse64FLo.op == Xsse_RCPF
1299 || i->Xin.Sse64FLo.op == Xsse_RSQRTF
1300 || i->Xin.Sse64FLo.op == Xsse_SQRTF;
1301 addHRegUse(u, HRmRead, i->Xin.Sse64FLo.src);
1302 addHRegUse(u, unary ? HRmWrite : HRmModify,
1303 i->Xin.Sse64FLo.dst);
1304 return;
sewardj164f9272004-12-09 00:39:32 +00001305 case Xin_SseReRg:
sewardj9e203592004-12-10 01:48:18 +00001306 addHRegUse(u, HRmRead, i->Xin.SseReRg.src);
1307 addHRegUse(u, i->Xin.SseReRg.op == Xsse_MOV ? HRmWrite : HRmModify,
1308 i->Xin.SseReRg.dst);
sewardj164f9272004-12-09 00:39:32 +00001309 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001310 case Xin_SseCMov:
1311 addHRegUse(u, HRmRead, i->Xin.SseCMov.src);
1312 addHRegUse(u, HRmModify, i->Xin.SseCMov.dst);
1313 return;
sewardj53f85a92004-07-02 13:45:17 +00001314 default:
sewardj35421a32004-07-05 13:12:34 +00001315 ppX86Instr(i);
1316 vpanic("getRegUsage_X86Instr");
sewardj53f85a92004-07-02 13:45:17 +00001317 }
1318}
1319
sewardj1f40a0a2004-07-21 12:28:07 +00001320/* local helper */
1321static void mapReg(HRegRemap* m, HReg* r)
1322{
1323 *r = lookupHRegRemap(m, *r);
1324}
1325
sewardj53f85a92004-07-02 13:45:17 +00001326void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
1327{
1328 switch (i->tag) {
1329 case Xin_Alu32R:
1330 mapRegs_X86RMI(m, i->Xin.Alu32R.src);
sewardj1f40a0a2004-07-21 12:28:07 +00001331 mapReg(m, &i->Xin.Alu32R.dst);
sewardj53f85a92004-07-02 13:45:17 +00001332 return;
1333 case Xin_Alu32M:
1334 mapRegs_X86RI(m, i->Xin.Alu32M.src);
1335 mapRegs_X86AMode(m, i->Xin.Alu32M.dst);
1336 return;
sewardje8c922f2004-07-23 01:34:11 +00001337 case Xin_Sh32:
1338 mapRegs_X86RM(m, i->Xin.Sh32.dst);
1339 return;
1340 case Xin_Test32:
1341 mapRegs_X86RI(m, i->Xin.Test32.src);
1342 mapRegs_X86RM(m, i->Xin.Test32.dst);
1343 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001344 case Xin_Unary32:
1345 mapRegs_X86RM(m, i->Xin.Unary32.dst);
1346 return;
1347 case Xin_MulL:
1348 mapRegs_X86RM(m, i->Xin.MulL.src);
1349 return;
1350 case Xin_Div:
sewardjea64e142004-07-22 16:47:21 +00001351 mapRegs_X86RM(m, i->Xin.Div.src);
sewardj1f40a0a2004-07-21 12:28:07 +00001352 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001353 case Xin_Sh3232:
sewardje5f384c2004-07-30 16:17:28 +00001354 mapReg(m, &i->Xin.Sh3232.src);
1355 mapReg(m, &i->Xin.Sh3232.dst);
sewardj1f40a0a2004-07-21 12:28:07 +00001356 return;
1357 case Xin_Push:
1358 mapRegs_X86RMI(m, i->Xin.Push.src);
1359 return;
1360 case Xin_Call:
sewardj1f40a0a2004-07-21 12:28:07 +00001361 return;
sewardj443cd9d2004-07-18 23:06:45 +00001362 case Xin_Goto:
1363 mapRegs_X86RI(m, i->Xin.Goto.dst);
sewardj0ec33252004-07-03 13:30:00 +00001364 return;
sewardj1f40a0a2004-07-21 12:28:07 +00001365 case Xin_CMov32:
1366 mapRegs_X86RM(m, i->Xin.CMov32.src);
1367 mapReg(m, &i->Xin.CMov32.dst);
1368 return;
1369 case Xin_LoadEX:
1370 mapRegs_X86AMode(m, i->Xin.LoadEX.src);
1371 mapReg(m, &i->Xin.LoadEX.dst);
1372 return;
1373 case Xin_Store:
1374 mapReg(m, &i->Xin.Store.src);
1375 mapRegs_X86AMode(m, i->Xin.Store.dst);
1376 return;
sewardjd7cb8532004-08-17 23:59:23 +00001377 case Xin_Set32:
1378 mapReg(m, &i->Xin.Set32.dst);
1379 return;
sewardjce646f22004-08-31 23:55:54 +00001380 case Xin_Bsfr32:
1381 mapReg(m, &i->Xin.Bsfr32.src);
1382 mapReg(m, &i->Xin.Bsfr32.dst);
1383 return;
sewardjcfded9a2004-09-09 11:44:16 +00001384 case Xin_FpUnary:
1385 mapReg(m, &i->Xin.FpUnary.src);
1386 mapReg(m, &i->Xin.FpUnary.dst);
1387 return;
sewardjbb53f8c2004-08-14 11:50:01 +00001388 case Xin_FpBinary:
1389 mapReg(m, &i->Xin.FpBinary.srcL);
1390 mapReg(m, &i->Xin.FpBinary.srcR);
1391 mapReg(m, &i->Xin.FpBinary.dst);
1392 return;
sewardj3196daf2004-08-13 00:18:58 +00001393 case Xin_FpLdSt:
1394 mapRegs_X86AMode(m, i->Xin.FpLdSt.addr);
1395 mapReg(m, &i->Xin.FpLdSt.reg);
1396 return;
sewardj89cd0932004-09-08 18:23:25 +00001397 case Xin_FpLdStI:
1398 mapRegs_X86AMode(m, i->Xin.FpLdStI.addr);
1399 mapReg(m, &i->Xin.FpLdStI.reg);
sewardjbb53f8c2004-08-14 11:50:01 +00001400 return;
sewardj3bca9062004-12-04 14:36:09 +00001401 case Xin_Fp64to32:
1402 mapReg(m, &i->Xin.Fp64to32.src);
1403 mapReg(m, &i->Xin.Fp64to32.dst);
1404 return;
sewardj3fc76d22004-08-31 11:47:54 +00001405 case Xin_FpCMov:
1406 mapReg(m, &i->Xin.FpCMov.src);
1407 mapReg(m, &i->Xin.FpCMov.dst);
1408 return;
sewardj8f3debf2004-09-08 23:42:23 +00001409 case Xin_FpLdStCW:
1410 mapRegs_X86AMode(m, i->Xin.FpLdStCW.addr);
1411 return;
sewardj46de4072004-09-11 19:23:24 +00001412 case Xin_FpStSW_AX:
1413 return;
sewardjbdc7d212004-09-09 02:46:40 +00001414 case Xin_FpCmp:
1415 mapReg(m, &i->Xin.FpCmp.srcL);
1416 mapReg(m, &i->Xin.FpCmp.srcR);
1417 mapReg(m, &i->Xin.FpCmp.dst);
1418 return;
sewardj1e6ad742004-12-02 16:16:11 +00001419 case Xin_SseConst:
1420 mapReg(m, &i->Xin.SseConst.dst);
1421 return;
sewardjd08f2d72004-12-01 23:19:36 +00001422 case Xin_SseLdSt:
1423 mapReg(m, &i->Xin.SseLdSt.reg);
1424 mapRegs_X86AMode(m, i->Xin.SseLdSt.addr);
1425 break;
sewardj129b3d92004-12-05 15:42:05 +00001426 case Xin_SseLdzLO:
1427 mapReg(m, &i->Xin.SseLdzLO.reg);
1428 mapRegs_X86AMode(m, i->Xin.SseLdzLO.addr);
1429 break;
sewardjd08f2d72004-12-01 23:19:36 +00001430 case Xin_Sse32Fx4:
1431 mapReg(m, &i->Xin.Sse32Fx4.src);
1432 mapReg(m, &i->Xin.Sse32Fx4.dst);
1433 return;
sewardj1e6ad742004-12-02 16:16:11 +00001434 case Xin_Sse32FLo:
1435 mapReg(m, &i->Xin.Sse32FLo.src);
1436 mapReg(m, &i->Xin.Sse32FLo.dst);
1437 return;
sewardj636ad762004-12-07 11:16:04 +00001438 case Xin_Sse64Fx2:
1439 mapReg(m, &i->Xin.Sse64Fx2.src);
1440 mapReg(m, &i->Xin.Sse64Fx2.dst);
1441 return;
1442 case Xin_Sse64FLo:
1443 mapReg(m, &i->Xin.Sse64FLo.src);
1444 mapReg(m, &i->Xin.Sse64FLo.dst);
1445 return;
sewardj164f9272004-12-09 00:39:32 +00001446 case Xin_SseReRg:
1447 mapReg(m, &i->Xin.SseReRg.src);
1448 mapReg(m, &i->Xin.SseReRg.dst);
1449 return;
sewardjb9fa69b2004-12-09 23:25:14 +00001450 case Xin_SseCMov:
1451 mapReg(m, &i->Xin.SseCMov.src);
1452 mapReg(m, &i->Xin.SseCMov.dst);
1453 return;
sewardj53f85a92004-07-02 13:45:17 +00001454 default:
sewardj35421a32004-07-05 13:12:34 +00001455 ppX86Instr(i);
1456 vpanic("mapRegs_X86Instr");
sewardj53f85a92004-07-02 13:45:17 +00001457 }
1458}
1459
sewardjbb53f8c2004-08-14 11:50:01 +00001460/* Figure out if i represents a reg-reg move, and if so assign the
1461 source and destination to *src and *dst. If in doubt say No. Used
1462 by the register allocator to do move coalescing.
1463*/
sewardja9a0cd22004-07-03 14:49:41 +00001464Bool isMove_X86Instr ( X86Instr* i, HReg* src, HReg* dst )
1465{
sewardjbb53f8c2004-08-14 11:50:01 +00001466 /* Moves between integer regs */
1467 if (i->tag == Xin_Alu32R) {
1468 if (i->Xin.Alu32R.op != Xalu_MOV)
1469 return False;
1470 if (i->Xin.Alu32R.src->tag != Xrmi_Reg)
1471 return False;
1472 *src = i->Xin.Alu32R.src->Xrmi.Reg.reg;
1473 *dst = i->Xin.Alu32R.dst;
1474 return True;
1475 }
1476 /* Moves between FP regs */
1477 if (i->tag == Xin_FpUnary) {
1478 if (i->Xin.FpUnary.op != Xfp_MOV)
1479 return False;
1480 *src = i->Xin.FpUnary.src;
1481 *dst = i->Xin.FpUnary.dst;
1482 return True;
1483 }
sewardj9e203592004-12-10 01:48:18 +00001484 if (i->tag == Xin_SseReRg) {
1485 if (i->Xin.SseReRg.op != Xsse_MOV)
sewardjd08f2d72004-12-01 23:19:36 +00001486 return False;
sewardj9e203592004-12-10 01:48:18 +00001487 *src = i->Xin.SseReRg.src;
1488 *dst = i->Xin.SseReRg.dst;
sewardjd08f2d72004-12-01 23:19:36 +00001489 return True;
1490 }
sewardjbb53f8c2004-08-14 11:50:01 +00001491 return False;
sewardja9a0cd22004-07-03 14:49:41 +00001492}
sewardj194d54a2004-07-03 19:08:18 +00001493
sewardjbb53f8c2004-08-14 11:50:01 +00001494
sewardj81ec4182004-10-25 23:15:52 +00001495/* Generate x86 spill/reload instructions under the direction of the
sewardj4b861de2004-11-03 15:24:42 +00001496 register allocator. Note it's critical these don't write the
1497 condition codes. */
sewardj14731f22004-07-25 01:24:28 +00001498
sewardj81ec4182004-10-25 23:15:52 +00001499X86Instr* genSpill_X86 ( HReg rreg, Int offsetB )
sewardj194d54a2004-07-03 19:08:18 +00001500{
sewardj3f57c2d2004-10-04 09:14:05 +00001501 X86AMode* am;
sewardj81ec4182004-10-25 23:15:52 +00001502 vassert(offsetB >= 0);
sewardj35421a32004-07-05 13:12:34 +00001503 vassert(!hregIsVirtual(rreg));
sewardj81ec4182004-10-25 23:15:52 +00001504 am = X86AMode_IR(offsetB, hregX86_EBP());
sewardj3f57c2d2004-10-04 09:14:05 +00001505
sewardj194d54a2004-07-03 19:08:18 +00001506 switch (hregClass(rreg)) {
sewardj4a31b262004-12-01 02:24:44 +00001507 case HRcInt32:
sewardj3f57c2d2004-10-04 09:14:05 +00001508 return X86Instr_Alu32M ( Xalu_MOV, X86RI_Reg(rreg), am );
sewardj4a31b262004-12-01 02:24:44 +00001509 case HRcFlt64:
sewardj3f57c2d2004-10-04 09:14:05 +00001510 return X86Instr_FpLdSt ( False/*store*/, 8, rreg, am );
sewardj194d54a2004-07-03 19:08:18 +00001511 default:
sewardj35421a32004-07-05 13:12:34 +00001512 ppHRegClass(hregClass(rreg));
1513 vpanic("genSpill_X86: unimplemented regclass");
sewardj194d54a2004-07-03 19:08:18 +00001514 }
1515}
1516
sewardj81ec4182004-10-25 23:15:52 +00001517X86Instr* genReload_X86 ( HReg rreg, Int offsetB )
sewardj194d54a2004-07-03 19:08:18 +00001518{
sewardj3f57c2d2004-10-04 09:14:05 +00001519 X86AMode* am;
sewardj81ec4182004-10-25 23:15:52 +00001520 vassert(offsetB >= 0);
sewardj35421a32004-07-05 13:12:34 +00001521 vassert(!hregIsVirtual(rreg));
sewardj81ec4182004-10-25 23:15:52 +00001522 am = X86AMode_IR(offsetB, hregX86_EBP());
sewardj194d54a2004-07-03 19:08:18 +00001523 switch (hregClass(rreg)) {
sewardj4a31b262004-12-01 02:24:44 +00001524 case HRcInt32:
sewardj3f57c2d2004-10-04 09:14:05 +00001525 return X86Instr_Alu32R ( Xalu_MOV, X86RMI_Mem(am), rreg );
sewardj4a31b262004-12-01 02:24:44 +00001526 case HRcFlt64:
sewardj3f57c2d2004-10-04 09:14:05 +00001527 return X86Instr_FpLdSt ( True/*load*/, 8, rreg, am );
sewardj194d54a2004-07-03 19:08:18 +00001528 default:
sewardj35421a32004-07-05 13:12:34 +00001529 ppHRegClass(hregClass(rreg));
1530 vpanic("genReload_X86: unimplemented regclass");
sewardj194d54a2004-07-03 19:08:18 +00001531 }
1532}
sewardj35421a32004-07-05 13:12:34 +00001533
sewardj81bd5502004-07-21 18:49:27 +00001534
1535/* --------- The x86 assembler (bleh.) --------- */
1536
sewardjbad34a92004-07-22 01:14:11 +00001537static UInt iregNo ( HReg r )
1538{
1539 UInt n;
sewardj4a31b262004-12-01 02:24:44 +00001540 vassert(hregClass(r) == HRcInt32);
sewardjbad34a92004-07-22 01:14:11 +00001541 vassert(!hregIsVirtual(r));
1542 n = hregNumber(r);
1543 vassert(n <= 7);
1544 return n;
1545}
1546
sewardj140656d2004-08-22 02:37:25 +00001547static UInt fregNo ( HReg r )
1548{
1549 UInt n;
sewardj4a31b262004-12-01 02:24:44 +00001550 vassert(hregClass(r) == HRcFlt64);
sewardj140656d2004-08-22 02:37:25 +00001551 vassert(!hregIsVirtual(r));
1552 n = hregNumber(r);
sewardjeafde5a2004-10-09 01:36:57 +00001553 vassert(n <= 5);
sewardj140656d2004-08-22 02:37:25 +00001554 return n;
1555}
1556
sewardjd08f2d72004-12-01 23:19:36 +00001557static UInt vregNo ( HReg r )
1558{
1559 UInt n;
1560 vassert(hregClass(r) == HRcVec128);
1561 vassert(!hregIsVirtual(r));
1562 n = hregNumber(r);
1563 vassert(n <= 7);
1564 return n;
1565}
1566
sewardjbad34a92004-07-22 01:14:11 +00001567static UChar mkModRegRM ( UChar mod, UChar reg, UChar regmem )
1568{
1569 return ((mod & 3) << 6) | ((reg & 7) << 3) | (regmem & 7);
1570}
1571
1572static UChar mkSIB ( Int shift, Int regindex, Int regbase )
1573{
1574 return ((shift & 3) << 6) | ((regindex & 7) << 3) | (regbase & 7);
1575}
1576
1577static UChar* emit32 ( UChar* p, UInt w32 )
1578{
1579 *p++ = (w32) & 0x000000FF;
1580 *p++ = (w32 >> 8) & 0x000000FF;
1581 *p++ = (w32 >> 16) & 0x000000FF;
1582 *p++ = (w32 >> 24) & 0x000000FF;
1583 return p;
1584}
1585
sewardjea64e142004-07-22 16:47:21 +00001586/* Does a sign-extend of the lowest 8 bits give
1587 the original number? */
sewardjbad34a92004-07-22 01:14:11 +00001588static Bool fits8bits ( UInt w32 )
1589{
sewardjea64e142004-07-22 16:47:21 +00001590 Int i32 = (Int)w32;
1591 return i32 == ((i32 << 24) >> 24);
sewardjbad34a92004-07-22 01:14:11 +00001592}
1593
1594
1595/* Forming mod-reg-rm bytes and scale-index-base bytes.
1596
1597 greg, 0(ereg) | ereg != ESP && ereg != EBP
1598 = 00 greg ereg
1599
1600 greg, d8(ereg) | ereg != ESP
1601 = 01 greg ereg, d8
1602
1603 greg, d32(ereg) | ereg != ESP
1604 = 10 greg ereg, d32
1605
sewardja58ea662004-08-15 03:12:41 +00001606 greg, d8(%esp) = 01 greg 100, 0x24, d8
1607
sewardjbad34a92004-07-22 01:14:11 +00001608 -----------------------------------------------
1609
1610 greg, d8(base,index,scale)
1611 | index != ESP
1612 = 01 greg 100, scale index base, d8
1613
1614 greg, d32(base,index,scale)
1615 | index != ESP
1616 = 10 greg 100, scale index base, d32
1617*/
1618static UChar* doAMode_M ( UChar* p, HReg greg, X86AMode* am )
1619{
1620 if (am->tag == Xam_IR) {
1621 if (am->Xam.IR.imm == 0
1622 && am->Xam.IR.reg != hregX86_ESP()
1623 && am->Xam.IR.reg != hregX86_EBP() ) {
1624 *p++ = mkModRegRM(0, iregNo(greg), iregNo(am->Xam.IR.reg));
1625 return p;
1626 }
1627 if (fits8bits(am->Xam.IR.imm)
1628 && am->Xam.IR.reg != hregX86_ESP()) {
1629 *p++ = mkModRegRM(1, iregNo(greg), iregNo(am->Xam.IR.reg));
1630 *p++ = am->Xam.IR.imm & 0xFF;
1631 return p;
1632 }
1633 if (am->Xam.IR.reg != hregX86_ESP()) {
1634 *p++ = mkModRegRM(2, iregNo(greg), iregNo(am->Xam.IR.reg));
1635 p = emit32(p, am->Xam.IR.imm);
1636 return p;
1637 }
sewardja58ea662004-08-15 03:12:41 +00001638 if (am->Xam.IR.reg == hregX86_ESP()
1639 && fits8bits(am->Xam.IR.imm)) {
1640 *p++ = mkModRegRM(1, iregNo(greg), 4);
1641 *p++ = 0x24;
1642 *p++ = am->Xam.IR.imm & 0xFF;
1643 return p;
1644 }
sewardjbad34a92004-07-22 01:14:11 +00001645 ppX86AMode(am);
1646 vpanic("doAMode_M: can't emit amode IR");
1647 /*NOTREACHED*/
1648 }
1649 if (am->tag == Xam_IRRS) {
1650 if (fits8bits(am->Xam.IRRS.imm)
1651 && am->Xam.IRRS.index != hregX86_ESP()) {
1652 *p++ = mkModRegRM(1, iregNo(greg), 4);
1653 *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index,
1654 am->Xam.IRRS.base);
1655 *p++ = am->Xam.IRRS.imm & 0xFF;
1656 return p;
1657 }
1658 if (am->Xam.IRRS.index != hregX86_ESP()) {
1659 *p++ = mkModRegRM(2, iregNo(greg), 4);
1660 *p++ = mkSIB(am->Xam.IRRS.shift, am->Xam.IRRS.index,
1661 am->Xam.IRRS.base);
1662 p = emit32(p, am->Xam.IRRS.imm);
1663 return p;
1664 }
1665 ppX86AMode(am);
1666 vpanic("doAMode_M: can't emit amode IRRS");
1667 /*NOTREACHED*/
1668 }
1669 vpanic("doAMode_M: unknown amode");
1670 /*NOTREACHED*/
1671}
1672
1673
1674/* Emit a mod-reg-rm byte when the rm bit denotes a reg. */
1675static UChar* doAMode_R ( UChar* p, HReg greg, HReg ereg )
1676{
1677 *p++ = mkModRegRM(3, iregNo(greg), iregNo(ereg));
1678 return p;
1679}
1680
1681
sewardj3196daf2004-08-13 00:18:58 +00001682/* Emit ffree %st(7) */
1683static UChar* do_ffree_st7 ( UChar* p )
1684{
1685 *p++ = 0xDD;
1686 *p++ = 0xC7;
1687 return p;
1688}
1689
sewardjeafde5a2004-10-09 01:36:57 +00001690/* Emit fstp %st(i), 1 <= i <= 7 */
sewardj3196daf2004-08-13 00:18:58 +00001691static UChar* do_fstp_st ( UChar* p, Int i )
1692{
sewardjeafde5a2004-10-09 01:36:57 +00001693 vassert(1 <= i && i <= 7);
sewardj3196daf2004-08-13 00:18:58 +00001694 *p++ = 0xDD;
1695 *p++ = 0xD8+i;
1696 return p;
1697}
1698
sewardjb3944c22004-10-15 22:22:09 +00001699/* Emit fld %st(i), 0 <= i <= 6 */
sewardj3196daf2004-08-13 00:18:58 +00001700static UChar* do_fld_st ( UChar* p, Int i )
1701{
sewardjb3944c22004-10-15 22:22:09 +00001702 vassert(0 <= i && i <= 6);
sewardj3196daf2004-08-13 00:18:58 +00001703 *p++ = 0xD9;
1704 *p++ = 0xC0+i;
1705 return p;
1706}
1707
sewardjcfded9a2004-09-09 11:44:16 +00001708/* Emit f<op> %st(0) */
1709static UChar* do_fop1_st ( UChar* p, X86FpOp op )
1710{
1711 switch (op) {
sewardj883b00b2004-09-11 09:30:24 +00001712 case Xfp_NEG: *p++ = 0xD9; *p++ = 0xE0; break;
1713 case Xfp_ABS: *p++ = 0xD9; *p++ = 0xE1; break;
sewardjc4be80c2004-09-10 16:17:45 +00001714 case Xfp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break;
sewardje6709112004-09-10 18:37:18 +00001715 case Xfp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break;
sewardjcfded9a2004-09-09 11:44:16 +00001716 case Xfp_SIN: *p++ = 0xD9; *p++ = 0xFE; break;
1717 case Xfp_COS: *p++ = 0xD9; *p++ = 0xFF; break;
sewardj06c32a02004-09-12 12:07:34 +00001718 case Xfp_2XM1: *p++ = 0xD9; *p++ = 0xF0; break;
sewardjbec10842004-10-12 13:44:45 +00001719 case Xfp_MOV: break;
sewardj99016a72004-10-15 22:09:17 +00001720 case Xfp_TAN: p = do_ffree_st7(p); /* since fptan pushes 1.0 */
1721 *p++ = 0xD9; *p++ = 0xF2; /* fptan */
1722 *p++ = 0xD9; *p++ = 0xF7; /* fincstp */
1723 break;
sewardjcfded9a2004-09-09 11:44:16 +00001724 default: vpanic("do_fop1_st: unknown op");
1725 }
1726 return p;
1727}
1728
sewardjbb53f8c2004-08-14 11:50:01 +00001729/* Emit f<op> %st(i), 1 <= i <= 5 */
sewardjcfded9a2004-09-09 11:44:16 +00001730static UChar* do_fop2_st ( UChar* p, X86FpOp op, Int i )
sewardjbb53f8c2004-08-14 11:50:01 +00001731{
sewardj4a31b262004-12-01 02:24:44 +00001732# define fake(_n) mkHReg((_n), HRcInt32, False)
sewardjbb53f8c2004-08-14 11:50:01 +00001733 Int subopc;
1734 switch (op) {
sewardja58ea662004-08-15 03:12:41 +00001735 case Xfp_ADD: subopc = 0; break;
sewardjce646f22004-08-31 23:55:54 +00001736 case Xfp_SUB: subopc = 4; break;
sewardjbb53f8c2004-08-14 11:50:01 +00001737 case Xfp_MUL: subopc = 1; break;
sewardjce646f22004-08-31 23:55:54 +00001738 case Xfp_DIV: subopc = 6; break;
sewardjcfded9a2004-09-09 11:44:16 +00001739 default: vpanic("do_fop2_st: unknown op");
sewardjbb53f8c2004-08-14 11:50:01 +00001740 }
1741 *p++ = 0xD8;
1742 p = doAMode_R(p, fake(subopc), fake(i));
1743 return p;
1744# undef fake
1745}
sewardjbad34a92004-07-22 01:14:11 +00001746
sewardj1e6ad742004-12-02 16:16:11 +00001747/* Push a 32-bit word on the stack. The word depends on tags[3:0];
1748each byte is either 0x00 or 0xFF depending on the corresponding bit in tags[].
1749*/
1750static UChar* push_word_from_tags ( UChar* p, UShort tags )
1751{
1752 UInt w;
1753 vassert(0 == (tags & ~0xF));
1754 if (tags == 0) {
1755 /* pushl $0x00000000 */
1756 *p++ = 0x6A;
1757 *p++ = 0x00;
1758 }
1759 else
1760 /* pushl $0xFFFFFFFF */
1761 if (tags == 0xF) {
1762 *p++ = 0x6A;
1763 *p++ = 0xFF;
1764 } else {
1765 vassert(0); /* awaiting test case */
1766 w = 0;
1767 if (tags & 1) w |= 0x000000FF;
1768 if (tags & 2) w |= 0x0000FF00;
1769 if (tags & 4) w |= 0x00FF0000;
1770 if (tags & 8) w |= 0xFF000000;
1771 *p++ = 0x68;
1772 p = emit32(p, w);
1773 }
1774 return p;
1775}
1776
sewardj81bd5502004-07-21 18:49:27 +00001777/* Emit an instruction into buf and return the number of bytes used.
1778 Note that buf is not the insn's final place, and therefore it is
1779 imperative to emit position-independent code. */
1780
1781Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
1782{
sewardj4b861de2004-11-03 15:24:42 +00001783 UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
sewardjea64e142004-07-22 16:47:21 +00001784
sewardj1e6ad742004-12-02 16:16:11 +00001785 UInt xtra;
sewardjbad34a92004-07-22 01:14:11 +00001786 UChar* p = &buf[0];
sewardj750f4072004-07-26 22:39:11 +00001787 UChar* ptmp;
sewardjbad34a92004-07-22 01:14:11 +00001788 vassert(nbuf >= 32);
1789
sewardjea64e142004-07-22 16:47:21 +00001790 /* Wrap an integer as a int register, for use assembling
1791 GrpN insns, in which the greg field is used as a sub-opcode
1792 and does not really contain a register. */
sewardj4a31b262004-12-01 02:24:44 +00001793# define fake(_n) mkHReg((_n), HRcInt32, False)
sewardjea64e142004-07-22 16:47:21 +00001794
sewardjbec10842004-10-12 13:44:45 +00001795 /* vex_printf("asm ");ppX86Instr(i); vex_printf("\n"); */
1796
sewardj81bd5502004-07-21 18:49:27 +00001797 switch (i->tag) {
sewardjbad34a92004-07-22 01:14:11 +00001798
1799 case Xin_Alu32R:
sewardjea64e142004-07-22 16:47:21 +00001800 /* Deal specially with MOV */
sewardjbad34a92004-07-22 01:14:11 +00001801 if (i->Xin.Alu32R.op == Xalu_MOV) {
1802 switch (i->Xin.Alu32R.src->tag) {
sewardjea64e142004-07-22 16:47:21 +00001803 case Xrmi_Imm:
1804 *p++ = 0xB8 + iregNo(i->Xin.Alu32R.dst);
1805 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
1806 goto done;
1807 case Xrmi_Reg:
sewardj750f4072004-07-26 22:39:11 +00001808 *p++ = 0x89;
1809 p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg,
1810 i->Xin.Alu32R.dst);
1811 goto done;
sewardjea64e142004-07-22 16:47:21 +00001812 case Xrmi_Mem:
1813 *p++ = 0x8B;
1814 p = doAMode_M(p, i->Xin.Alu32R.dst,
1815 i->Xin.Alu32R.src->Xrmi.Mem.am);
1816 goto done;
1817 default:
1818 goto bad;
1819 }
1820 }
sewardje8c922f2004-07-23 01:34:11 +00001821 /* MUL */
1822 if (i->Xin.Alu32R.op == Xalu_MUL) {
sewardjd75fe5a2004-07-23 12:57:47 +00001823 switch (i->Xin.Alu32R.src->tag) {
1824 case Xrmi_Reg:
1825 *p++ = 0x0F;
1826 *p++ = 0xAF;
1827 p = doAMode_R(p, i->Xin.Alu32R.dst,
1828 i->Xin.Alu32R.src->Xrmi.Reg.reg);
1829 goto done;
sewardj140656d2004-08-22 02:37:25 +00001830 case Xrmi_Mem:
1831 *p++ = 0x0F;
1832 *p++ = 0xAF;
1833 p = doAMode_M(p, i->Xin.Alu32R.dst,
1834 i->Xin.Alu32R.src->Xrmi.Mem.am);
1835 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00001836 case Xrmi_Imm:
1837 if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
1838 *p++ = 0x6B;
1839 p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
1840 *p++ = 0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32;
sewardjd75fe5a2004-07-23 12:57:47 +00001841 } else {
sewardj278c44c2004-08-20 00:28:13 +00001842 *p++ = 0x69;
1843 p = doAMode_R(p, i->Xin.Alu32R.dst, i->Xin.Alu32R.dst);
1844 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
sewardjd75fe5a2004-07-23 12:57:47 +00001845 }
sewardj278c44c2004-08-20 00:28:13 +00001846 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00001847 default:
1848 goto bad;
1849 }
sewardje8c922f2004-07-23 01:34:11 +00001850 }
1851 /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP */
sewardjea64e142004-07-22 16:47:21 +00001852 opc = opc_rr = subopc_imm = opc_imma = 0;
1853 switch (i->Xin.Alu32R.op) {
1854 case Xalu_ADD: opc = 0x03; opc_rr = 0x01;
1855 subopc_imm = 0; opc_imma = 0x05; break;
1856 case Xalu_SUB: opc = 0x2B; opc_rr = 0x29;
1857 subopc_imm = 5; opc_imma = 0x2D; break;
sewardj70f676d2004-12-10 14:59:57 +00001858 case Xalu_SBB: opc = 0x1B; opc_rr = 0x19;
1859 subopc_imm = 3; opc_imma = 0x1D; break;
sewardj86898e82004-07-22 17:26:12 +00001860 case Xalu_AND: opc = 0x23; opc_rr = 0x21;
1861 subopc_imm = 4; opc_imma = 0x25; break;
sewardje8c922f2004-07-23 01:34:11 +00001862 case Xalu_XOR: opc = 0x33; opc_rr = 0x31;
1863 subopc_imm = 6; opc_imma = 0x35; break;
1864 case Xalu_OR: opc = 0x0B; opc_rr = 0x09;
1865 subopc_imm = 1; opc_imma = 0x0D; break;
1866 case Xalu_CMP: opc = 0x3B; opc_rr = 0x39;
1867 subopc_imm = 7; opc_imma = 0x3D; break;
sewardjea64e142004-07-22 16:47:21 +00001868 default: goto bad;
1869 }
1870 switch (i->Xin.Alu32R.src->tag) {
1871 case Xrmi_Imm:
1872 if (i->Xin.Alu32R.dst == hregX86_EAX()
1873 && !fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
1874 *p++ = opc_imma;
1875 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
1876 } else
1877 if (fits8bits(i->Xin.Alu32R.src->Xrmi.Imm.imm32)) {
1878 *p++ = 0x83;
1879 p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst);
1880 *p++ = 0xFF & i->Xin.Alu32R.src->Xrmi.Imm.imm32;
1881 } else {
1882 *p++ = 0x81;
1883 p = doAMode_R(p, fake(subopc_imm), i->Xin.Alu32R.dst);
1884 p = emit32(p, i->Xin.Alu32R.src->Xrmi.Imm.imm32);
1885 }
1886 goto done;
1887 case Xrmi_Reg:
1888 *p++ = opc_rr;
1889 p = doAMode_R(p, i->Xin.Alu32R.src->Xrmi.Reg.reg,
1890 i->Xin.Alu32R.dst);
1891 goto done;
sewardjbad34a92004-07-22 01:14:11 +00001892 case Xrmi_Mem:
sewardjea64e142004-07-22 16:47:21 +00001893 *p++ = opc;
1894 p = doAMode_M(p, i->Xin.Alu32R.dst,
sewardjbad34a92004-07-22 01:14:11 +00001895 i->Xin.Alu32R.src->Xrmi.Mem.am);
1896 goto done;
sewardjea64e142004-07-22 16:47:21 +00001897 default:
sewardjbad34a92004-07-22 01:14:11 +00001898 goto bad;
sewardjbad34a92004-07-22 01:14:11 +00001899 }
1900 break;
1901
1902 case Xin_Alu32M:
sewardjea64e142004-07-22 16:47:21 +00001903 /* Deal specially with MOV */
sewardjbad34a92004-07-22 01:14:11 +00001904 if (i->Xin.Alu32M.op == Xalu_MOV) {
sewardjea64e142004-07-22 16:47:21 +00001905 switch (i->Xin.Alu32M.src->tag) {
1906 case Xri_Reg:
1907 *p++ = 0x89;
1908 p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg,
1909 i->Xin.Alu32M.dst);
1910 goto done;
1911 case Xri_Imm:
1912 *p++ = 0xC7;
1913 p = doAMode_M(p, fake(0), i->Xin.Alu32M.dst);
1914 p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32);
1915 goto done;
1916 default:
1917 goto bad;
1918 }
1919 }
sewardje8c922f2004-07-23 01:34:11 +00001920 /* ADD/SUB/ADC/SBB/AND/OR/XOR/CMP. MUL is not
1921 allowed here. */
sewardjea64e142004-07-22 16:47:21 +00001922 opc = subopc_imm = opc_imma = 0;
1923 switch (i->Xin.Alu32M.op) {
1924 case Xalu_ADD: opc = 0x01; subopc_imm = 0; break;
sewardj86898e82004-07-22 17:26:12 +00001925 case Xalu_SUB: opc = 0x29; subopc_imm = 5; break;
sewardjea64e142004-07-22 16:47:21 +00001926 default: goto bad;
1927 }
1928 switch (i->Xin.Alu32M.src->tag) {
1929 case Xri_Reg:
1930 *p++ = opc;
1931 p = doAMode_M(p, i->Xin.Alu32M.src->Xri.Reg.reg,
1932 i->Xin.Alu32M.dst);
1933 goto done;
1934 case Xri_Imm:
1935 if (fits8bits(i->Xin.Alu32M.src->Xri.Imm.imm32)) {
1936 *p++ = 0x83;
1937 p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst);
1938 *p++ = 0xFF & i->Xin.Alu32M.src->Xri.Imm.imm32;
1939 goto done;
1940 } else {
1941 *p++ = 0x81;
1942 p = doAMode_M(p, fake(subopc_imm), i->Xin.Alu32M.dst);
1943 p = emit32(p, i->Xin.Alu32M.src->Xri.Imm.imm32);
1944 goto done;
1945 }
1946 default:
1947 goto bad;
sewardjbad34a92004-07-22 01:14:11 +00001948 }
1949 break;
1950
sewardje8c922f2004-07-23 01:34:11 +00001951 case Xin_Sh32:
sewardjd75fe5a2004-07-23 12:57:47 +00001952 opc_cl = opc_imm = subopc = 0;
1953 switch (i->Xin.Sh32.op) {
1954 case Xsh_SHR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 5; break;
sewardj07134a42004-07-26 02:04:54 +00001955 case Xsh_SAR: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 7; break;
1956 case Xsh_SHL: opc_cl = 0xD3; opc_imm = 0xC1; subopc = 4; break;
sewardjd75fe5a2004-07-23 12:57:47 +00001957 default: goto bad;
1958 }
1959 if (i->Xin.Sh32.src == 0) {
1960 *p++ = opc_cl;
1961 switch (i->Xin.Sh32.dst->tag) {
1962 case Xrm_Reg:
1963 p = doAMode_R(p, fake(subopc),
1964 i->Xin.Sh32.dst->Xrm.Reg.reg);
1965 goto done;
1966 default:
1967 goto bad;
1968 }
1969 } else {
sewardj38ff3d82004-07-26 23:27:08 +00001970 *p++ = opc_imm;
1971 switch (i->Xin.Sh32.dst->tag) {
1972 case Xrm_Reg:
1973 p = doAMode_R(p, fake(subopc),
1974 i->Xin.Sh32.dst->Xrm.Reg.reg);
1975 *p++ = (UChar)(i->Xin.Sh32.src);
1976 goto done;
1977 default:
1978 goto bad;
1979 }
sewardjd75fe5a2004-07-23 12:57:47 +00001980 }
1981 break;
sewardje8c922f2004-07-23 01:34:11 +00001982
1983 case Xin_Test32:
sewardjd75fe5a2004-07-23 12:57:47 +00001984 if (i->Xin.Test32.src->tag == Xri_Imm
1985 && i->Xin.Test32.dst->tag == Xrm_Reg) {
1986 /* testl $imm32, %reg */
1987 *p++ = 0xF7;
1988 p = doAMode_R(p, fake(0), i->Xin.Test32.dst->Xrm.Reg.reg);
1989 p = emit32(p, i->Xin.Test32.src->Xri.Imm.imm32);
1990 goto done;
1991 }
1992 break;
sewardje8c922f2004-07-23 01:34:11 +00001993
1994 case Xin_Unary32:
sewardj358b7d42004-11-08 18:54:50 +00001995 if (i->Xin.Unary32.op == Xun_NOT) {
sewardjd75fe5a2004-07-23 12:57:47 +00001996 *p++ = 0xF7;
1997 if (i->Xin.Unary32.dst->tag == Xrm_Reg) {
1998 p = doAMode_R(p, fake(2), i->Xin.Unary32.dst->Xrm.Reg.reg);
1999 goto done;
2000 } else {
2001 goto bad;
2002 }
2003 }
sewardj358b7d42004-11-08 18:54:50 +00002004 if (i->Xin.Unary32.op == Xun_NEG) {
2005 *p++ = 0xF7;
2006 if (i->Xin.Unary32.dst->tag == Xrm_Reg) {
2007 p = doAMode_R(p, fake(3), i->Xin.Unary32.dst->Xrm.Reg.reg);
2008 goto done;
2009 } else {
2010 goto bad;
2011 }
2012 }
sewardjd75fe5a2004-07-23 12:57:47 +00002013 break;
sewardje8c922f2004-07-23 01:34:11 +00002014
sewardja2dad5c2004-07-23 11:43:43 +00002015 case Xin_MulL:
sewardjd75fe5a2004-07-23 12:57:47 +00002016 subopc = i->Xin.MulL.syned ? 5 : 4;
2017 if (i->Xin.MulL.ssz == Xss_32) {
sewardjd75fe5a2004-07-23 12:57:47 +00002018 *p++ = 0xF7;
2019 switch (i->Xin.MulL.src->tag) {
2020 case Xrm_Mem:
2021 p = doAMode_M(p, fake(subopc),
2022 i->Xin.MulL.src->Xrm.Mem.am);
sewardj140656d2004-08-22 02:37:25 +00002023 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002024 case Xrm_Reg:
2025 p = doAMode_R(p, fake(subopc),
2026 i->Xin.MulL.src->Xrm.Reg.reg);
2027 goto done;
2028 default:
2029 goto bad;
2030 }
2031 }
2032 break;
sewardja2dad5c2004-07-23 11:43:43 +00002033
2034 case Xin_Div:
sewardjd75fe5a2004-07-23 12:57:47 +00002035 subopc = i->Xin.Div.syned ? 7 : 6;
2036 if (i->Xin.Div.ssz == Xss_32) {
sewardjd75fe5a2004-07-23 12:57:47 +00002037 *p++ = 0xF7;
2038 switch (i->Xin.Div.src->tag) {
2039 case Xrm_Mem:
2040 p = doAMode_M(p, fake(subopc),
2041 i->Xin.Div.src->Xrm.Mem.am);
sewardj140656d2004-08-22 02:37:25 +00002042 goto done;
sewardjd75fe5a2004-07-23 12:57:47 +00002043 case Xrm_Reg:
2044 p = doAMode_R(p, fake(subopc),
2045 i->Xin.Div.src->Xrm.Reg.reg);
2046 goto done;
2047 default:
2048 goto bad;
2049 }
2050 }
2051 break;
sewardja2dad5c2004-07-23 11:43:43 +00002052
2053 case Xin_Sh3232:
sewardjd75fe5a2004-07-23 12:57:47 +00002054 vassert(i->Xin.Sh3232.op == Xsh_SHL || i->Xin.Sh3232.op == Xsh_SHR);
2055 if (i->Xin.Sh3232.amt == 0) {
2056 /* shldl/shrdl by %cl */
2057 *p++ = 0x0F;
sewardj68511542004-07-28 00:15:44 +00002058 if (i->Xin.Sh3232.op == Xsh_SHL) {
2059 *p++ = 0xA5;
sewardj68511542004-07-28 00:15:44 +00002060 } else {
2061 *p++ = 0xAD;
sewardj68511542004-07-28 00:15:44 +00002062 }
sewardje5f384c2004-07-30 16:17:28 +00002063 p = doAMode_R(p, i->Xin.Sh3232.src, i->Xin.Sh3232.dst);
sewardjd75fe5a2004-07-23 12:57:47 +00002064 goto done;
2065 }
2066 break;
sewardja2dad5c2004-07-23 11:43:43 +00002067
sewardje8c922f2004-07-23 01:34:11 +00002068 case Xin_Push:
sewardjd75fe5a2004-07-23 12:57:47 +00002069 switch (i->Xin.Push.src->tag) {
2070 case Xrmi_Mem:
2071 *p++ = 0xFF;
2072 p = doAMode_M(p, fake(6), i->Xin.Push.src->Xrmi.Mem.am);
2073 goto done;
sewardja58ea662004-08-15 03:12:41 +00002074 case Xrmi_Imm:
2075 *p++ = 0x68;
2076 p = emit32(p, i->Xin.Push.src->Xrmi.Imm.imm32);
2077 goto done;
sewardjd7cb8532004-08-17 23:59:23 +00002078 case Xrmi_Reg:
2079 *p++ = 0x50 + iregNo(i->Xin.Push.src->Xrmi.Reg.reg);
2080 goto done;
sewardja58ea662004-08-15 03:12:41 +00002081 default:
sewardjd75fe5a2004-07-23 12:57:47 +00002082 goto bad;
2083 }
sewardje8c922f2004-07-23 01:34:11 +00002084
2085 case Xin_Call:
sewardj4b861de2004-11-03 15:24:42 +00002086 /* See detailed comment for Xin_Call in getRegUsage_X86Instr above
2087 for explanation of this. */
2088 switch (i->Xin.Call.regparms) {
2089 case 0: irno = iregNo(hregX86_EAX()); break;
sewardj45c50eb2004-11-04 18:25:33 +00002090 case 1: irno = iregNo(hregX86_EDX()); break;
2091 case 2: irno = iregNo(hregX86_ECX()); break;
sewardj4b861de2004-11-03 15:24:42 +00002092 case 3: irno = iregNo(hregX86_EDI()); break;
2093 default: vpanic(" emit_X86Instr:call:regparms");
2094 }
2095 /* jump over the following two insns if the condition does not
2096 hold */
2097 if (i->Xin.Call.cond != Xcc_ALWAYS) {
2098 *p++ = 0x70 + (0xF & (i->Xin.Call.cond ^ 1));
2099 *p++ = 0x07; /* 7 bytes in the next two insns */
2100 }
2101 /* movl $target, %tmp */
2102 *p++ = 0xB8 + irno;
2103 p = emit32(p, i->Xin.Call.target);
2104 /* call *%tmp */
sewardjd75fe5a2004-07-23 12:57:47 +00002105 *p++ = 0xFF;
sewardj4b861de2004-11-03 15:24:42 +00002106 *p++ = 0xD0 + irno;
sewardjd75fe5a2004-07-23 12:57:47 +00002107 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002108
sewardj86898e82004-07-22 17:26:12 +00002109 case Xin_Goto:
sewardj893aada2004-11-29 19:57:54 +00002110 /* Use ptmp for backpatching conditional jumps. */
2111 ptmp = NULL;
2112
2113 /* First off, if this is conditional, create a conditional
2114 jump over the rest of it. */
2115 if (i->Xin.Goto.cond != Xcc_ALWAYS) {
2116 /* jmp fwds if !condition */
2117 *p++ = 0x70 + (i->Xin.Goto.cond ^ 1);
2118 ptmp = p; /* fill in this bit later */
2119 *p++ = 0; /* # of bytes to jump over; don't know how many yet. */
sewardj750f4072004-07-26 22:39:11 +00002120 }
sewardj893aada2004-11-29 19:57:54 +00002121
2122 /* If a non-boring, set %ebp (the guest state pointer)
2123 appropriately. */
2124 /* movl $magic_number, %ebp */
2125 switch (i->Xin.Goto.jk) {
2126 case Ijk_ClientReq:
2127 *p++ = 0xBD;
2128 p = emit32(p, VEX_TRC_JMP_CLIENTREQ); break;
2129 case Ijk_Syscall:
2130 *p++ = 0xBD;
2131 p = emit32(p, VEX_TRC_JMP_SYSCALL); break;
2132 case Ijk_Yield:
2133 *p++ = 0xBD;
2134 p = emit32(p, VEX_TRC_JMP_YIELD); break;
2135 case Ijk_EmWarn:
2136 *p++ = 0xBD;
2137 p = emit32(p, VEX_TRC_JMP_EMWARN); break;
2138 case Ijk_Ret:
2139 case Ijk_Call:
2140 case Ijk_Boring:
2141 break;
2142 default:
2143 ppIRJumpKind(i->Xin.Goto.jk);
2144 vpanic("emit_X86Instr.Xin_Goto: unknown jump kind");
2145 }
2146
2147 /* Get the destination address into %eax */
2148 if (i->Xin.Goto.dst->tag == Xri_Imm) {
sewardj86898e82004-07-22 17:26:12 +00002149 /* movl $immediate, %eax ; ret */
2150 *p++ = 0xB8;
2151 p = emit32(p, i->Xin.Goto.dst->Xri.Imm.imm32);
sewardj893aada2004-11-29 19:57:54 +00002152 } else {
2153 vassert(i->Xin.Goto.dst->tag == Xri_Reg);
sewardj86898e82004-07-22 17:26:12 +00002154 /* movl %reg, %eax ; ret */
sewardje8c922f2004-07-23 01:34:11 +00002155 if (i->Xin.Goto.dst->Xri.Reg.reg != hregX86_EAX()) {
2156 *p++ = 0x89;
2157 p = doAMode_R(p, i->Xin.Goto.dst->Xri.Reg.reg, hregX86_EAX());
sewardjd75fe5a2004-07-23 12:57:47 +00002158 }
sewardjd75fe5a2004-07-23 12:57:47 +00002159 }
sewardj893aada2004-11-29 19:57:54 +00002160
2161 /* ret */
2162 *p++ = 0xC3;
2163
2164 /* Fix up the conditional jump, if there was one. */
2165 if (i->Xin.Goto.cond != Xcc_ALWAYS) {
2166 Int delta = p - ptmp;
2167 vassert(delta > 0 && delta < 20);
2168 *ptmp = (UChar)(delta-1);
sewardje8c922f2004-07-23 01:34:11 +00002169 }
sewardj893aada2004-11-29 19:57:54 +00002170 goto done;
sewardj86898e82004-07-22 17:26:12 +00002171
sewardje8c922f2004-07-23 01:34:11 +00002172 case Xin_CMov32:
sewardjd75fe5a2004-07-23 12:57:47 +00002173 vassert(i->Xin.CMov32.cond != Xcc_ALWAYS);
sewardj750f4072004-07-26 22:39:11 +00002174#if 0
sewardj893aada2004-11-29 19:57:54 +00002175 /* This generates cmov, which is illegal on P54/P55. */
sewardjd75fe5a2004-07-23 12:57:47 +00002176 *p++ = 0x0F;
2177 *p++ = 0x40 + i->Xin.CMov32.cond;
2178 if (i->Xin.CMov32.src->tag == Xrm_Reg) {
2179 p = doAMode_R(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Reg.reg);
2180 goto done;
2181 }
2182 if (i->Xin.CMov32.src->tag == Xrm_Mem) {
2183 p = doAMode_M(p, i->Xin.CMov32.dst, i->Xin.CMov32.src->Xrm.Mem.am);
2184 goto done;
2185 }
sewardj750f4072004-07-26 22:39:11 +00002186#else
2187 /* P5 friendly version: conditional jump over an unconditional
2188 move. */
2189 /* jmp fwds if !condition */
2190 *p++ = 0x70 + (i->Xin.CMov32.cond ^ 1);
2191 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2192 ptmp = p;
2193
2194 switch (i->Xin.CMov32.src->tag) {
2195 case Xrm_Reg:
sewardj7d5b66e2004-08-24 23:34:39 +00002196 /* Big sigh. This is movl E -> G ... */
sewardj750f4072004-07-26 22:39:11 +00002197 *p++ = 0x89;
sewardj7d5b66e2004-08-24 23:34:39 +00002198 p = doAMode_R(p, i->Xin.CMov32.src->Xrm.Reg.reg,
2199 i->Xin.CMov32.dst);
sewardj68511542004-07-28 00:15:44 +00002200
sewardj750f4072004-07-26 22:39:11 +00002201 break;
2202 case Xrm_Mem:
sewardj7d5b66e2004-08-24 23:34:39 +00002203 /* ... whereas this is movl G -> E. That's why the args
2204 to doAMode_R appear to be the wrong way round in the
2205 Xrm_Reg case. */
sewardj750f4072004-07-26 22:39:11 +00002206 *p++ = 0x8B;
2207 p = doAMode_M(p, i->Xin.CMov32.dst,
2208 i->Xin.CMov32.src->Xrm.Mem.am);
2209 break;
2210 default:
2211 goto bad;
2212 }
2213 /* Fill in the jump offset. */
2214 *(ptmp-1) = p - ptmp;
2215 goto done;
2216#endif
sewardjd75fe5a2004-07-23 12:57:47 +00002217 break;
sewardje8c922f2004-07-23 01:34:11 +00002218
2219 case Xin_LoadEX:
sewardjd75fe5a2004-07-23 12:57:47 +00002220 if (i->Xin.LoadEX.szSmall == 1 && !i->Xin.LoadEX.syned) {
2221 /* movzbl */
2222 *p++ = 0x0F;
2223 *p++ = 0xB6;
2224 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2225 goto done;
2226 }
2227 if (i->Xin.LoadEX.szSmall == 2 && !i->Xin.LoadEX.syned) {
2228 /* movzwl */
2229 *p++ = 0x0F;
2230 *p++ = 0xB7;
2231 p = doAMode_M(p, i->Xin.LoadEX.dst, i->Xin.LoadEX.src);
2232 goto done;
2233 }
2234 break;
sewardje8c922f2004-07-23 01:34:11 +00002235
sewardjd7cb8532004-08-17 23:59:23 +00002236 case Xin_Set32:
2237 /* Make the destination register be 1 or 0, depending on whether
2238 the relevant condition holds. We have to dodge and weave
2239 when the destination is %esi or %edi as we cannot directly
2240 emit the native 'setb %reg' for those. Further complication:
2241 the top 24 bits of the destination should be forced to zero,
2242 but doing 'xor %r,%r' kills the flag(s) we are about to read.
sewardj3503ad82004-08-24 00:24:56 +00002243 Sigh. So start off my moving $0 into the dest. */
sewardjd7cb8532004-08-17 23:59:23 +00002244
sewardj3503ad82004-08-24 00:24:56 +00002245 /* Do we need to swap in %eax? */
sewardjd7cb8532004-08-17 23:59:23 +00002246 if (iregNo(i->Xin.Set32.dst) >= 4) {
2247 /* xchg %eax, %dst */
2248 *p++ = 0x90 + iregNo(i->Xin.Set32.dst);
sewardj3503ad82004-08-24 00:24:56 +00002249 /* movl $0, %eax */
2250 *p++ = 0xB8 + iregNo(hregX86_EAX());
2251 p = emit32(p, 0);
2252 /* setb lo8(%eax) */
sewardjd7cb8532004-08-17 23:59:23 +00002253 *p++ = 0x0F;
2254 *p++ = 0x90 + (UChar)(i->Xin.Set32.cond);
2255 p = doAMode_R(p, fake(0), hregX86_EAX());
2256 /* xchg %eax, %dst */
2257 *p++ = 0x90 + iregNo(i->Xin.Set32.dst);
2258 } else {
sewardj3503ad82004-08-24 00:24:56 +00002259 /* movl $0, %dst */
2260 *p++ = 0xB8 + iregNo(i->Xin.Set32.dst);
2261 p = emit32(p, 0);
2262 /* setb lo8(%dst) */
sewardjd7cb8532004-08-17 23:59:23 +00002263 *p++ = 0x0F;
2264 *p++ = 0x90 + (UChar)(i->Xin.Set32.cond);
2265 p = doAMode_R(p, fake(0), i->Xin.Set32.dst);
2266 }
2267 goto done;
2268
sewardjce646f22004-08-31 23:55:54 +00002269 case Xin_Bsfr32:
2270 *p++ = 0x0F;
2271 if (i->Xin.Bsfr32.isFwds) {
2272 *p++ = 0xBC;
2273 } else {
2274 *p++ = 0xBD;
2275 }
2276 p = doAMode_R(p, i->Xin.Bsfr32.dst, i->Xin.Bsfr32.src);
2277 goto done;
2278
sewardje8c922f2004-07-23 01:34:11 +00002279 case Xin_Store:
sewardjd75fe5a2004-07-23 12:57:47 +00002280 if (i->Xin.Store.sz == 2) {
2281 /* This case, at least, is simple, given that we can
2282 reference the low 16 bits of any integer register. */
2283 *p++ = 0x66;
2284 *p++ = 0x89;
2285 p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
2286 goto done;
sewardje8c922f2004-07-23 01:34:11 +00002287 }
sewardjd75fe5a2004-07-23 12:57:47 +00002288
2289 if (i->Xin.Store.sz == 1) {
2290 /* We have to do complex dodging and weaving if src is not
2291 the low 8 bits of %eax/%ebx/%ecx/%edx. */
2292 if (iregNo(i->Xin.Store.src) < 4) {
2293 /* we're OK, can do it directly */
2294 *p++ = 0x88;
2295 p = doAMode_M(p, i->Xin.Store.src, i->Xin.Store.dst);
2296 goto done;
2297 } else {
2298 /* Bleh. This means the source is %edi or %esi. Since
2299 the address mode can only mention three registers, at
2300 least one of %eax/%ebx/%ecx/%edx must be available to
2301 temporarily swap the source into, so the store can
2302 happen. So we have to look at the regs mentioned
2303 in the amode. */
sewardj2e56f9f2004-07-24 01:24:38 +00002304 HReg swap = INVALID_HREG;
2305 HReg eax = hregX86_EAX(), ebx = hregX86_EBX(),
2306 ecx = hregX86_ECX(), edx = hregX86_EDX();
sewardjd75fe5a2004-07-23 12:57:47 +00002307 Bool a_ok = True, b_ok = True, c_ok = True, d_ok = True;
2308 HRegUsage u;
2309 Int j;
2310 initHRegUsage(&u);
2311 addRegUsage_X86AMode(&u, i->Xin.Store.dst);
2312 for (j = 0; j < u.n_used; j++) {
2313 HReg r = u.hreg[j];
2314 if (r == eax) a_ok = False;
2315 if (r == ebx) b_ok = False;
2316 if (r == ecx) c_ok = False;
2317 if (r == edx) d_ok = False;
2318 }
sewardjd75fe5a2004-07-23 12:57:47 +00002319 if (a_ok) swap = eax;
2320 if (b_ok) swap = ebx;
2321 if (c_ok) swap = ecx;
2322 if (d_ok) swap = edx;
2323 vassert(swap != INVALID_HREG);
2324 /* xchgl %source, %swap. Could do better if swap is %eax. */
2325 *p++ = 0x87;
2326 p = doAMode_R(p, i->Xin.Store.src, swap);
2327 /* movb lo8{%swap}, (dst) */
2328 *p++ = 0x88;
2329 p = doAMode_M(p, swap, i->Xin.Store.dst);
2330 /* xchgl %source, %swap. Could do better if swap is %eax. */
2331 *p++ = 0x87;
2332 p = doAMode_R(p, i->Xin.Store.src, swap);
2333 goto done;
2334 }
2335 } /* if (i->Xin.Store.sz == 1) */
2336 break;
sewardj86898e82004-07-22 17:26:12 +00002337
sewardjcfded9a2004-09-09 11:44:16 +00002338 case Xin_FpUnary:
2339 /* gop %src, %dst
2340 --> ffree %st7 ; fld %st(src) ; fop %st(0) ; fstp %st(1+dst)
2341 */
2342 p = do_ffree_st7(p);
2343 p = do_fld_st(p, 0+hregNumber(i->Xin.FpUnary.src));
2344 p = do_fop1_st(p, i->Xin.FpUnary.op);
2345 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpUnary.dst));
2346 goto done;
2347
sewardjbb53f8c2004-08-14 11:50:01 +00002348 case Xin_FpBinary:
sewardj06c32a02004-09-12 12:07:34 +00002349 if (i->Xin.FpBinary.op == Xfp_YL2X
2350 || i->Xin.FpBinary.op == Xfp_YL2XP1) {
sewardj8308aad2004-09-12 11:09:54 +00002351 /* Have to do this specially. */
2352 /* ffree %st7 ; fld %st(srcL) ;
sewardj06c32a02004-09-12 12:07:34 +00002353 ffree %st7 ; fld %st(srcR+1) ; fyl2x{p1} ; fstp(1+dst) */
sewardj8308aad2004-09-12 11:09:54 +00002354 p = do_ffree_st7(p);
2355 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
2356 p = do_ffree_st7(p);
2357 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
sewardj06c32a02004-09-12 12:07:34 +00002358 *p++ = 0xD9;
2359 *p++ = i->Xin.FpBinary.op==Xfp_YL2X ? 0xF1 : 0xF9;
sewardj8308aad2004-09-12 11:09:54 +00002360 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2361 goto done;
2362 }
sewardj52ace3e2004-09-11 17:10:08 +00002363 if (i->Xin.FpBinary.op == Xfp_ATAN) {
sewardjcfded9a2004-09-09 11:44:16 +00002364 /* Have to do this specially. */
sewardj46de4072004-09-11 19:23:24 +00002365 /* ffree %st7 ; fld %st(srcL) ;
2366 ffree %st7 ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */
sewardjcfded9a2004-09-09 11:44:16 +00002367 p = do_ffree_st7(p);
2368 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
sewardj46de4072004-09-11 19:23:24 +00002369 p = do_ffree_st7(p);
sewardjcfded9a2004-09-09 11:44:16 +00002370 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR));
2371 *p++ = 0xD9; *p++ = 0xF3;
2372 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2373 goto done;
2374 }
sewardj06c32a02004-09-12 12:07:34 +00002375 if (i->Xin.FpBinary.op == Xfp_PREM
sewardj442d0be2004-10-15 22:57:13 +00002376 || i->Xin.FpBinary.op == Xfp_PREM1
sewardj06c32a02004-09-12 12:07:34 +00002377 || i->Xin.FpBinary.op == Xfp_SCALE) {
sewardj46de4072004-09-11 19:23:24 +00002378 /* Have to do this specially. */
2379 /* ffree %st7 ; fld %st(srcR) ;
sewardj442d0be2004-10-15 22:57:13 +00002380 ffree %st7 ; fld %st(srcL+1) ; fprem/fprem1/fscale ; fstp(2+dst) ;
sewardj46de4072004-09-11 19:23:24 +00002381 fincstp ; ffree %st7 */
2382 p = do_ffree_st7(p);
2383 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR));
2384 p = do_ffree_st7(p);
2385 p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL));
sewardj442d0be2004-10-15 22:57:13 +00002386 *p++ = 0xD9;
2387 switch (i->Xin.FpBinary.op) {
2388 case Xfp_PREM: *p++ = 0xF8; break;
2389 case Xfp_PREM1: *p++ = 0xF5; break;
2390 case Xfp_SCALE: *p++ = 0xFD; break;
2391 default: vpanic("emitX86Instr(FpBinary,PREM/PREM1/SCALE)");
2392 }
sewardj46de4072004-09-11 19:23:24 +00002393 p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst));
2394 *p++ = 0xD9; *p++ = 0xF7;
2395 p = do_ffree_st7(p);
2396 goto done;
2397 }
sewardjcfded9a2004-09-09 11:44:16 +00002398 /* General case */
sewardjbb53f8c2004-08-14 11:50:01 +00002399 /* gop %srcL, %srcR, %dst
2400 --> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst)
2401 */
2402 p = do_ffree_st7(p);
2403 p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL));
sewardj3bca9062004-12-04 14:36:09 +00002404 p = do_fop2_st(p, i->Xin.FpBinary.op,
2405 1+hregNumber(i->Xin.FpBinary.srcR));
sewardjbb53f8c2004-08-14 11:50:01 +00002406 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst));
2407 goto done;
2408
sewardj3196daf2004-08-13 00:18:58 +00002409 case Xin_FpLdSt:
sewardj3bca9062004-12-04 14:36:09 +00002410 vassert(i->Xin.FpLdSt.sz == 4 || i->Xin.FpLdSt.sz == 8);
sewardj3196daf2004-08-13 00:18:58 +00002411 if (i->Xin.FpLdSt.isLoad) {
2412 /* Load from memory into %fakeN.
sewardjbb53f8c2004-08-14 11:50:01 +00002413 --> ffree %st(7) ; fld{s/l} amode ; fstp st(N+1)
sewardj3196daf2004-08-13 00:18:58 +00002414 */
2415 p = do_ffree_st7(p);
2416 *p++ = i->Xin.FpLdSt.sz==4 ? 0xD9 : 0xDD;
2417 p = doAMode_M(p, fake(0)/*subopcode*/, i->Xin.FpLdSt.addr);
2418 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdSt.reg));
2419 goto done;
2420 } else {
2421 /* Store from %fakeN into memory.
sewardjbb53f8c2004-08-14 11:50:01 +00002422 --> ffree %st(7) ; fld st(N) ; fstp{l|s} amode
sewardj3196daf2004-08-13 00:18:58 +00002423 */
2424 p = do_ffree_st7(p);
2425 p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdSt.reg));
2426 *p++ = i->Xin.FpLdSt.sz==4 ? 0xD9 : 0xDD;
2427 p = doAMode_M(p, fake(3)/*subopcode*/, i->Xin.FpLdSt.addr);
2428 goto done;
2429 }
2430 break;
2431
sewardj89cd0932004-09-08 18:23:25 +00002432 case Xin_FpLdStI:
2433 if (i->Xin.FpLdStI.isLoad) {
2434 /* Load from memory into %fakeN, converting from an int.
2435 --> ffree %st(7) ; fild{w/l/ll} amode ; fstp st(N+1)
2436 */
2437 switch (i->Xin.FpLdStI.sz) {
sewardjbdc7d212004-09-09 02:46:40 +00002438 case 8: opc = 0xDF; subopc_imm = 5; break;
sewardj89cd0932004-09-08 18:23:25 +00002439 case 4: opc = 0xDB; subopc_imm = 0; break;
2440 case 2: vassert(0); opc = 0xDF; subopc_imm = 0; break;
2441 default: vpanic("emitX86Instr(Xin_FpLdStI-load)");
2442 }
2443 p = do_ffree_st7(p);
2444 *p++ = opc;
2445 p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr);
2446 p = do_fstp_st(p, 1+hregNumber(i->Xin.FpLdStI.reg));
2447 goto done;
2448 } else {
2449 /* Store from %fakeN into memory, converting to an int.
2450 --> ffree %st(7) ; fld st(N) ; fistp{w/l/ll} amode
2451 */
2452 switch (i->Xin.FpLdStI.sz) {
sewardjcfded9a2004-09-09 11:44:16 +00002453 case 8: opc = 0xDF; subopc_imm = 7; break;
sewardj89cd0932004-09-08 18:23:25 +00002454 case 4: opc = 0xDB; subopc_imm = 3; break;
2455 case 2: opc = 0xDF; subopc_imm = 3; break;
2456 default: vpanic("emitX86Instr(Xin_FpLdStI-store)");
2457 }
2458 p = do_ffree_st7(p);
2459 p = do_fld_st(p, 0+hregNumber(i->Xin.FpLdStI.reg));
2460 *p++ = opc;
2461 p = doAMode_M(p, fake(subopc_imm)/*subopcode*/, i->Xin.FpLdStI.addr);
2462 goto done;
2463 }
2464 break;
2465
sewardj3bca9062004-12-04 14:36:09 +00002466 case Xin_Fp64to32:
2467 /* ffree %st7 ; fld %st(src) */
2468 p = do_ffree_st7(p);
2469 p = do_fld_st(p, 0+fregNo(i->Xin.Fp64to32.src));
2470 /* subl $4, %esp */
2471 *p++ = 0x83; *p++ = 0xEC; *p++ = 0x04;
2472 /* fstps (%esp) */
2473 *p++ = 0xD9; *p++ = 0x1C; *p++ = 0x24;
2474 /* flds (%esp) */
2475 *p++ = 0xD9; *p++ = 0x04; *p++ = 0x24;
2476 /* addl $4, %esp */
2477 *p++ = 0x83; *p++ = 0xC4; *p++ = 0x04;
2478 /* fstp %st(1+dst) */
2479 p = do_fstp_st(p, 1+fregNo(i->Xin.Fp64to32.dst));
2480 goto done;
2481
sewardj3fc76d22004-08-31 11:47:54 +00002482 case Xin_FpCMov:
2483 /* jmp fwds if !condition */
2484 *p++ = 0x70 + (i->Xin.FpCMov.cond ^ 1);
2485 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2486 ptmp = p;
2487
2488 /* ffree %st7 ; fld %st(src) ; fstp %st(1+dst) */
2489 p = do_ffree_st7(p);
sewardjbdc7d212004-09-09 02:46:40 +00002490 p = do_fld_st(p, 0+fregNo(i->Xin.FpCMov.src));
2491 p = do_fstp_st(p, 1+fregNo(i->Xin.FpCMov.dst));
sewardj3fc76d22004-08-31 11:47:54 +00002492
2493 /* Fill in the jump offset. */
2494 *(ptmp-1) = p - ptmp;
2495 goto done;
2496
sewardj8f3debf2004-09-08 23:42:23 +00002497 case Xin_FpLdStCW:
2498 if (i->Xin.FpLdStCW.isLoad) {
2499 *p++ = 0xD9;
2500 p = doAMode_M(p, fake(5)/*subopcode*/, i->Xin.FpLdStCW.addr);
2501 } else {
2502 vassert(0);
2503 }
2504 goto done;
2505
sewardj46de4072004-09-11 19:23:24 +00002506 case Xin_FpStSW_AX:
2507 /* note, this emits fnstsw %ax, not fstsw %ax */
2508 *p++ = 0xDF;
2509 *p++ = 0xE0;
2510 goto done;
sewardjbdc7d212004-09-09 02:46:40 +00002511
2512 case Xin_FpCmp:
2513 /* gcmp %fL, %fR, %dst
2514 -> ffree %st7; fpush %fL ; fucomp %(fR+1) ;
2515 fnstsw %ax ; movl %eax, %dst
2516 */
2517 /* ffree %st7 */
2518 p = do_ffree_st7(p);
2519 /* fpush %fL */
2520 p = do_fld_st(p, 0+fregNo(i->Xin.FpCmp.srcL));
2521 /* fucomp %(fR+1) */
2522 *p++ = 0xDD;
2523 *p++ = 0xE8 + (7 & (1+fregNo(i->Xin.FpCmp.srcR)));
2524 /* fnstsw %ax */
2525 *p++ = 0xDF;
2526 *p++ = 0xE0;
2527 /* movl %eax, %dst */
2528 *p++ = 0x89;
2529 p = doAMode_R(p, hregX86_EAX(), i->Xin.FpCmp.dst);
2530 goto done;
2531
sewardj1e6ad742004-12-02 16:16:11 +00002532 case Xin_SseConst: {
2533 UShort con = i->Xin.SseConst.con;
2534 p = push_word_from_tags(p, (con >> 12) & 0xF);
2535 p = push_word_from_tags(p, (con >> 8) & 0xF);
2536 p = push_word_from_tags(p, (con >> 4) & 0xF);
2537 p = push_word_from_tags(p, con & 0xF);
2538 /* movl (%esp), %xmm-dst */
2539 *p++ = 0x0F;
2540 *p++ = 0x10;
2541 *p++ = 0x04 + 8 * (7 & vregNo(i->Xin.SseConst.dst));
2542 *p++ = 0x24;
2543 /* addl $16, %esp */
2544 *p++ = 0x83;
2545 *p++ = 0xC4;
2546 *p++ = 0x10;
2547 goto done;
2548 }
sewardj129b3d92004-12-05 15:42:05 +00002549
sewardjd08f2d72004-12-01 23:19:36 +00002550 case Xin_SseLdSt:
2551 *p++ = 0x0F;
2552 *p++ = i->Xin.SseLdSt.isLoad ? 0x10 : 0x11;
2553 p = doAMode_M(p, fake(vregNo(i->Xin.SseLdSt.reg)), i->Xin.SseLdSt.addr);
2554 goto done;
2555
sewardj129b3d92004-12-05 15:42:05 +00002556 case Xin_SseLdzLO:
sewardj636ad762004-12-07 11:16:04 +00002557 vassert(i->Xin.SseLdzLO.sz == 4 || i->Xin.SseLdzLO.sz == 8);
2558 /* movs[sd] amode, %xmm-dst */
2559 *p++ = i->Xin.SseLdzLO.sz==4 ? 0xF3 : 0xF2;
2560 *p++ = 0x0F;
2561 *p++ = 0x10;
2562 p = doAMode_M(p, fake(vregNo(i->Xin.SseLdzLO.reg)),
2563 i->Xin.SseLdzLO.addr);
2564 goto done;
sewardj129b3d92004-12-05 15:42:05 +00002565
sewardj1e6ad742004-12-02 16:16:11 +00002566 case Xin_Sse32Fx4:
2567 xtra = 0;
2568 *p++ = 0x0F;
2569 switch (i->Xin.Sse32Fx4.op) {
2570 case Xsse_ADDF: *p++ = 0x58; break;
sewardj176a59c2004-12-03 20:08:31 +00002571 case Xsse_DIVF: *p++ = 0x5E; break;
2572 case Xsse_MAXF: *p++ = 0x5F; break;
2573 case Xsse_MINF: *p++ = 0x5D; break;
sewardj9636b442004-12-04 01:38:37 +00002574 case Xsse_MULF: *p++ = 0x59; break;
sewardj0bd7ce62004-12-05 02:47:40 +00002575 case Xsse_RCPF: *p++ = 0x53; break;
sewardjc1e7dfc2004-12-05 19:29:45 +00002576 case Xsse_RSQRTF: *p++ = 0x52; break;
2577 case Xsse_SQRTF: *p++ = 0x51; break;
2578 case Xsse_SUBF: *p++ = 0x5C; break;
sewardj1e6ad742004-12-02 16:16:11 +00002579 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
2580 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
2581 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
2582 default: goto bad;
2583 }
sewardjd08f2d72004-12-01 23:19:36 +00002584 p = doAMode_R(p, fake(vregNo(i->Xin.Sse32Fx4.dst)),
2585 fake(vregNo(i->Xin.Sse32Fx4.src)) );
sewardj1e6ad742004-12-02 16:16:11 +00002586 if (xtra & 0x100)
2587 *p++ = (UChar)(xtra & 0xFF);
2588 goto done;
2589
sewardj636ad762004-12-07 11:16:04 +00002590 case Xin_Sse64Fx2:
2591 xtra = 0;
2592 *p++ = 0x66;
2593 *p++ = 0x0F;
2594 switch (i->Xin.Sse64Fx2.op) {
2595 case Xsse_ADDF: *p++ = 0x58; break;
2596 case Xsse_DIVF: *p++ = 0x5E; break;
2597 case Xsse_MAXF: *p++ = 0x5F; break;
2598 case Xsse_MINF: *p++ = 0x5D; break;
2599 case Xsse_MULF: *p++ = 0x59; break;
2600 case Xsse_RCPF: *p++ = 0x53; break;
2601 case Xsse_RSQRTF: *p++ = 0x52; break;
2602 case Xsse_SQRTF: *p++ = 0x51; break;
2603 case Xsse_SUBF: *p++ = 0x5C; break;
2604 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
2605 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
2606 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
2607 default: goto bad;
2608 }
2609 p = doAMode_R(p, fake(vregNo(i->Xin.Sse64Fx2.dst)),
2610 fake(vregNo(i->Xin.Sse64Fx2.src)) );
2611 if (xtra & 0x100)
2612 *p++ = (UChar)(xtra & 0xFF);
2613 goto done;
2614
sewardj1e6ad742004-12-02 16:16:11 +00002615 case Xin_Sse32FLo:
2616 xtra = 0;
2617 *p++ = 0xF3;
2618 *p++ = 0x0F;
2619 switch (i->Xin.Sse32FLo.op) {
2620 case Xsse_ADDF: *p++ = 0x58; break;
sewardj176a59c2004-12-03 20:08:31 +00002621 case Xsse_DIVF: *p++ = 0x5E; break;
2622 case Xsse_MAXF: *p++ = 0x5F; break;
2623 case Xsse_MINF: *p++ = 0x5D; break;
sewardj9636b442004-12-04 01:38:37 +00002624 case Xsse_MULF: *p++ = 0x59; break;
sewardj0bd7ce62004-12-05 02:47:40 +00002625 case Xsse_RCPF: *p++ = 0x53; break;
sewardjc1e7dfc2004-12-05 19:29:45 +00002626 case Xsse_RSQRTF: *p++ = 0x52; break;
2627 case Xsse_SQRTF: *p++ = 0x51; break;
2628 case Xsse_SUBF: *p++ = 0x5C; break;
sewardj1e6ad742004-12-02 16:16:11 +00002629 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
2630 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
2631 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
2632 default: goto bad;
2633 }
2634 p = doAMode_R(p, fake(vregNo(i->Xin.Sse32FLo.dst)),
2635 fake(vregNo(i->Xin.Sse32FLo.src)) );
2636 if (xtra & 0x100)
2637 *p++ = (UChar)(xtra & 0xFF);
sewardjd08f2d72004-12-01 23:19:36 +00002638 goto done;
2639
sewardj636ad762004-12-07 11:16:04 +00002640 case Xin_Sse64FLo:
2641 xtra = 0;
2642 *p++ = 0xF2;
2643 *p++ = 0x0F;
2644 switch (i->Xin.Sse64FLo.op) {
2645 case Xsse_ADDF: *p++ = 0x58; break;
2646 case Xsse_DIVF: *p++ = 0x5E; break;
2647 case Xsse_MAXF: *p++ = 0x5F; break;
2648 case Xsse_MINF: *p++ = 0x5D; break;
2649 case Xsse_MULF: *p++ = 0x59; break;
2650 case Xsse_RCPF: *p++ = 0x53; break;
2651 case Xsse_RSQRTF: *p++ = 0x52; break;
2652 case Xsse_SQRTF: *p++ = 0x51; break;
2653 case Xsse_SUBF: *p++ = 0x5C; break;
2654 case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
2655 case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
2656 case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
2657 default: goto bad;
2658 }
2659 p = doAMode_R(p, fake(vregNo(i->Xin.Sse64FLo.dst)),
2660 fake(vregNo(i->Xin.Sse64FLo.src)) );
2661 if (xtra & 0x100)
2662 *p++ = (UChar)(xtra & 0xFF);
2663 goto done;
2664
sewardj164f9272004-12-09 00:39:32 +00002665 case Xin_SseReRg:
2666# define XX(_n) *p++ = (_n)
2667 switch (i->Xin.SseReRg.op) {
sewardj9e203592004-12-10 01:48:18 +00002668 case Xsse_MOV: /*movups*/ XX(0x0F); XX(0x10); break;
2669 case Xsse_OR: XX(0x0F); XX(0x56); break;
2670 case Xsse_XOR: XX(0x0F); XX(0x57); break;
2671 case Xsse_AND: XX(0x0F); XX(0x54); break;
sewardje5854d62004-12-09 03:44:34 +00002672 case Xsse_PACKSSD: XX(0x66); XX(0x0F); XX(0x6B); break;
2673 case Xsse_PACKSSW: XX(0x66); XX(0x0F); XX(0x63); break;
2674 case Xsse_PACKUSW: XX(0x66); XX(0x0F); XX(0x67); break;
2675 case Xsse_ADD8: XX(0x66); XX(0x0F); XX(0xFC); break;
2676 case Xsse_ADD16: XX(0x66); XX(0x0F); XX(0xFD); break;
2677 case Xsse_ADD32: XX(0x66); XX(0x0F); XX(0xFE); break;
2678 case Xsse_ADD64: XX(0x66); XX(0x0F); XX(0xD4); break;
2679 case Xsse_QADD8S: XX(0x66); XX(0x0F); XX(0xEC); break;
2680 case Xsse_QADD16S: XX(0x66); XX(0x0F); XX(0xED); break;
2681 case Xsse_QADD8U: XX(0x66); XX(0x0F); XX(0xDC); break;
2682 case Xsse_QADD16U: XX(0x66); XX(0x0F); XX(0xDD); break;
2683 case Xsse_AVG8U: XX(0x66); XX(0x0F); XX(0xE0); break;
2684 case Xsse_AVG16U: XX(0x66); XX(0x0F); XX(0xE3); break;
2685 case Xsse_CMPEQ8: XX(0x66); XX(0x0F); XX(0x74); break;
2686 case Xsse_CMPEQ16: XX(0x66); XX(0x0F); XX(0x75); break;
2687 case Xsse_CMPEQ32: XX(0x66); XX(0x0F); XX(0x76); break;
2688 case Xsse_CMPGT8S: XX(0x66); XX(0x0F); XX(0x64); break;
2689 case Xsse_CMPGT16S: XX(0x66); XX(0x0F); XX(0x65); break;
2690 case Xsse_CMPGT32S: XX(0x66); XX(0x0F); XX(0x66); break;
2691 case Xsse_MAX16S: XX(0x66); XX(0x0F); XX(0xEE); break;
2692 case Xsse_MAX8U: XX(0x66); XX(0x0F); XX(0xDE); break;
2693 case Xsse_MIN16S: XX(0x66); XX(0x0F); XX(0xEA); break;
2694 case Xsse_MIN8U: XX(0x66); XX(0x0F); XX(0xDA); break;
2695 case Xsse_MULHI16U: XX(0x66); XX(0x0F); XX(0xE4); break;
2696 case Xsse_MULHI16S: XX(0x66); XX(0x0F); XX(0xE5); break;
2697 case Xsse_MUL16: XX(0x66); XX(0x0F); XX(0xD5); break;
sewardjb9fa69b2004-12-09 23:25:14 +00002698 case Xsse_SHL16: XX(0x66); XX(0x0F); XX(0xF1); break;
2699 case Xsse_SHL32: XX(0x66); XX(0x0F); XX(0xF2); break;
2700 case Xsse_SHL64: XX(0x66); XX(0x0F); XX(0xF3); break;
2701 case Xsse_SAR16: XX(0x66); XX(0x0F); XX(0xE1); break;
2702 case Xsse_SAR32: XX(0x66); XX(0x0F); XX(0xE2); break;
2703 case Xsse_SHR16: XX(0x66); XX(0x0F); XX(0xD1); break;
2704 case Xsse_SHR32: XX(0x66); XX(0x0F); XX(0xD2); break;
2705 case Xsse_SHR64: XX(0x66); XX(0x0F); XX(0xD3); break;
2706 case Xsse_SUB8: XX(0x66); XX(0x0F); XX(0xF8); break;
2707 case Xsse_SUB16: XX(0x66); XX(0x0F); XX(0xF9); break;
2708 case Xsse_SUB32: XX(0x66); XX(0x0F); XX(0xFA); break;
2709 case Xsse_SUB64: XX(0x66); XX(0x0F); XX(0xFB); break;
2710 case Xsse_QSUB8S: XX(0x66); XX(0x0F); XX(0xE8); break;
2711 case Xsse_QSUB16S: XX(0x66); XX(0x0F); XX(0xE9); break;
2712 case Xsse_QSUB8U: XX(0x66); XX(0x0F); XX(0xD8); break;
2713 case Xsse_QSUB16U: XX(0x66); XX(0x0F); XX(0xD9); break;
sewardj9e203592004-12-10 01:48:18 +00002714 case Xsse_UNPCKHB: XX(0x66); XX(0x0F); XX(0x68); break;
2715 case Xsse_UNPCKHW: XX(0x66); XX(0x0F); XX(0x69); break;
2716 case Xsse_UNPCKHD: XX(0x66); XX(0x0F); XX(0x6A); break;
2717 case Xsse_UNPCKHQ: XX(0x66); XX(0x0F); XX(0x6D); break;
2718 case Xsse_UNPCKLB: XX(0x66); XX(0x0F); XX(0x60); break;
2719 case Xsse_UNPCKLW: XX(0x66); XX(0x0F); XX(0x61); break;
2720 case Xsse_UNPCKLD: XX(0x66); XX(0x0F); XX(0x62); break;
2721 case Xsse_UNPCKLQ: XX(0x66); XX(0x0F); XX(0x6C); break;
sewardj164f9272004-12-09 00:39:32 +00002722 default: goto bad;
2723 }
2724 p = doAMode_R(p, fake(vregNo(i->Xin.SseReRg.dst)),
2725 fake(vregNo(i->Xin.SseReRg.src)) );
2726# undef XX
2727 goto done;
2728
sewardjb9fa69b2004-12-09 23:25:14 +00002729 case Xin_SseCMov:
2730 /* jmp fwds if !condition */
2731 *p++ = 0x70 + (i->Xin.SseCMov.cond ^ 1);
2732 *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
2733 ptmp = p;
2734
2735 /* movaps %src, %dst */
2736 *p++ = 0x0F;
2737 *p++ = 0x28;
2738 p = doAMode_R(p, fake(vregNo(i->Xin.SseCMov.dst)),
2739 fake(vregNo(i->Xin.SseCMov.src)) );
2740
2741 /* Fill in the jump offset. */
2742 *(ptmp-1) = p - ptmp;
2743 goto done;
2744
sewardjea64e142004-07-22 16:47:21 +00002745 default:
2746 goto bad;
sewardj81bd5502004-07-21 18:49:27 +00002747 }
sewardjea64e142004-07-22 16:47:21 +00002748
2749 bad:
2750 ppX86Instr(i);
2751 vpanic("emit_X86Instr");
2752 /*NOTREACHED*/
2753
sewardjbad34a92004-07-22 01:14:11 +00002754 done:
2755 vassert(p - &buf[0] <= 32);
2756 return p - &buf[0];
sewardjea64e142004-07-22 16:47:21 +00002757
sewardjd75fe5a2004-07-23 12:57:47 +00002758# undef fake
sewardj81bd5502004-07-21 18:49:27 +00002759}
2760
sewardj35421a32004-07-05 13:12:34 +00002761/*---------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00002762/*--- end host-x86/hdefs.c ---*/
sewardj35421a32004-07-05 13:12:34 +00002763/*---------------------------------------------------------------*/