blob: 97576df2992c84338f03d2b6c7688392461e48d3 [file] [log] [blame]
sewardjc97096c2004-06-30 09:28:04 +00001
2/*---------------------------------------------------------------*/
sewardj752f9062010-05-03 21:38:49 +00003/*--- begin host_x86_isel.c ---*/
sewardjc97096c2004-06-30 09:28:04 +00004/*---------------------------------------------------------------*/
5
sewardjf8ed9d82004-11-12 17:40:23 +00006/*
sewardj752f9062010-05-03 21:38:49 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjf8ed9d82004-11-12 17:40:23 +00009
sewardj89ae8472013-10-18 14:12:58 +000010 Copyright (C) 2004-2013 OpenWorks LLP
sewardj752f9062010-05-03 21:38:49 +000011 info@open-works.net
sewardjf8ed9d82004-11-12 17:40:23 +000012
sewardj752f9062010-05-03 21:38:49 +000013 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
sewardjf8ed9d82004-11-12 17:40:23 +000017
sewardj752f9062010-05-03 21:38:49 +000018 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
sewardj7bd6ffe2005-08-03 16:07:36 +000026 02110-1301, USA.
27
sewardj752f9062010-05-03 21:38:49 +000028 The GNU General Public License is contained in the file COPYING.
sewardjf8ed9d82004-11-12 17:40:23 +000029
30 Neither the names of the U.S. Department of Energy nor the
31 University of California nor the names of its contributors may be
32 used to endorse or promote products derived from this software
33 without prior written permission.
sewardjf8ed9d82004-11-12 17:40:23 +000034*/
35
sewardj887a11a2004-07-05 17:26:47 +000036#include "libvex_basictypes.h"
37#include "libvex_ir.h"
38#include "libvex.h"
sewardj35421a32004-07-05 13:12:34 +000039
sewardjcef7d3e2009-07-02 12:21:59 +000040#include "ir_match.h"
41#include "main_util.h"
42#include "main_globals.h"
43#include "host_generic_regs.h"
44#include "host_generic_simd64.h"
sewardjad2c9ea2011-10-22 09:32:16 +000045#include "host_generic_simd128.h"
sewardjcef7d3e2009-07-02 12:21:59 +000046#include "host_x86_defs.h"
sewardjc97096c2004-06-30 09:28:04 +000047
sewardj79d8a4b2005-04-22 21:20:47 +000048/* TODO 21 Apr 2005:
sewardj78830182005-02-04 01:40:54 +000049
sewardj79d8a4b2005-04-22 21:20:47 +000050 -- (Really an assembler issue) don't emit CMov32 as a cmov
51 insn, since that's expensive on P4 and conditional branch
52 is cheaper if (as we expect) the condition is highly predictable
sewardj3f5d7fa2005-02-21 08:22:44 +000053
sewardj78830182005-02-04 01:40:54 +000054 -- preserve xmm registers across function calls (by declaring them
55 as trashed by call insns)
56
57 -- preserve x87 ST stack discipline across function calls. Sigh.
58
59 -- Check doHelperCall: if a call is conditional, we cannot safely
60 compute any regparm args directly to registers. Hence, the
61 fast-regparm marshalling should be restricted to unconditional
62 calls only.
63*/
sewardjc97096c2004-06-30 09:28:04 +000064
65/*---------------------------------------------------------*/
sewardj9c323762005-01-10 16:49:19 +000066/*--- x87 control word stuff ---*/
67/*---------------------------------------------------------*/
68
69/* Vex-generated code expects to run with the FPU set as follows: all
70 exceptions masked, round-to-nearest, precision = 53 bits. This
71 corresponds to a FPU control word value of 0x027F.
72
73 Similarly the SSE control word (%mxcsr) should be 0x1F80.
74
75 %fpucw and %mxcsr should have these values on entry to
76 Vex-generated code, and should those values should be
77 unchanged at exit.
78*/
79
80#define DEFAULT_FPUCW 0x027F
81
82/* debugging only, do not use */
83/* define DEFAULT_FPUCW 0x037F */
84
85
86/*---------------------------------------------------------*/
sewardj69933ac2004-12-20 04:12:14 +000087/*--- misc helpers ---*/
sewardj443cd9d2004-07-18 23:06:45 +000088/*---------------------------------------------------------*/
89
sewardj69933ac2004-12-20 04:12:14 +000090/* These are duplicated in guest-x86/toIR.c */
sewardj443cd9d2004-07-18 23:06:45 +000091static IRExpr* unop ( IROp op, IRExpr* a )
92{
93 return IRExpr_Unop(op, a);
94}
95
96static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
97{
98 return IRExpr_Binop(op, a1, a2);
99}
sewardj08790542004-09-14 23:18:06 +0000100
sewardj443cd9d2004-07-18 23:06:45 +0000101static IRExpr* bind ( Int binder )
102{
103 return IRExpr_Binder(binder);
104}
105
sewardjfb7373a2007-08-25 21:29:03 +0000106static Bool isZeroU8 ( IRExpr* e )
107{
108 return e->tag == Iex_Const
109 && e->Iex.Const.con->tag == Ico_U8
110 && e->Iex.Const.con->Ico.U8 == 0;
111}
sewardj443cd9d2004-07-18 23:06:45 +0000112
sewardjeb17e492007-08-25 23:07:44 +0000113static Bool isZeroU32 ( IRExpr* e )
114{
115 return e->tag == Iex_Const
116 && e->Iex.Const.con->tag == Ico_U32
117 && e->Iex.Const.con->Ico.U32 == 0;
118}
119
sewardj009230b2013-01-26 11:47:55 +0000120//static Bool isZeroU64 ( IRExpr* e )
121//{
122// return e->tag == Iex_Const
123// && e->Iex.Const.con->tag == Ico_U64
124// && e->Iex.Const.con->Ico.U64 == 0ULL;
125//}
sewardjeb17e492007-08-25 23:07:44 +0000126
sewardj443cd9d2004-07-18 23:06:45 +0000127
sewardj443cd9d2004-07-18 23:06:45 +0000128/*---------------------------------------------------------*/
sewardjc97096c2004-06-30 09:28:04 +0000129/*--- ISelEnv ---*/
130/*---------------------------------------------------------*/
131
132/* This carries around:
133
134 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
135 might encounter. This is computed before insn selection starts,
136 and does not change.
137
138 - A mapping from IRTemp to HReg. This tells the insn selector
sewardje8e9d732004-07-16 21:03:45 +0000139 which virtual register(s) are associated with each IRTemp
140 temporary. This is computed before insn selection starts, and
141 does not change. We expect this mapping to map precisely the
142 same set of IRTemps as the type mapping does.
143
144 - vregmap holds the primary register for the IRTemp.
145 - vregmapHI is only used for 64-bit integer-typed
146 IRTemps. It holds the identity of a second
147 32-bit virtual HReg, which holds the high half
148 of the value.
sewardjc97096c2004-06-30 09:28:04 +0000149
150 - The code array, that is, the insns selected so far.
151
152 - A counter, for generating new virtual registers.
153
sewardj9df271d2004-12-31 22:37:42 +0000154 - The host subarchitecture we are selecting insns for.
155 This is set at the start and does not change.
156
sewardjc6f970f2012-04-02 21:54:49 +0000157 - A Bool for indicating whether we may generate chain-me
158 instructions for control flow transfers, or whether we must use
159 XAssisted.
160
161 - The maximum guest address of any guest insn in this block.
162 Actually, the address of the highest-addressed byte from any insn
163 in this block. Is set at the start and does not change. This is
164 used for detecting jumps which are definitely forward-edges from
165 this block, and therefore can be made (chained) to the fast entry
166 point of the destination, thereby avoiding the destination's
167 event check.
168
169 Note, this is all (well, mostly) host-independent.
170*/
sewardjc97096c2004-06-30 09:28:04 +0000171
172typedef
173 struct {
sewardjc6f970f2012-04-02 21:54:49 +0000174 /* Constant -- are set at the start and do not change. */
sewardj194d54a2004-07-03 19:08:18 +0000175 IRTypeEnv* type_env;
sewardjc97096c2004-06-30 09:28:04 +0000176
sewardje539a402004-07-14 18:24:17 +0000177 HReg* vregmap;
sewardje8e9d732004-07-16 21:03:45 +0000178 HReg* vregmapHI;
sewardj194d54a2004-07-03 19:08:18 +0000179 Int n_vregmap;
sewardjc97096c2004-06-30 09:28:04 +0000180
sewardj5117ce12006-01-27 21:20:15 +0000181 UInt hwcaps;
sewardjc6f970f2012-04-02 21:54:49 +0000182
183 Bool chainingAllowed;
184 Addr64 max_ga;
185
186 /* These are modified as we go along. */
187 HInstrArray* code;
188 Int vreg_ctr;
sewardjc97096c2004-06-30 09:28:04 +0000189 }
190 ISelEnv;
191
192
193static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
194{
sewardje539a402004-07-14 18:24:17 +0000195 vassert(tmp >= 0);
196 vassert(tmp < env->n_vregmap);
197 return env->vregmap[tmp];
sewardjc97096c2004-06-30 09:28:04 +0000198}
199
sewardj597b71b2004-07-19 02:51:12 +0000200static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp )
sewardje8e9d732004-07-16 21:03:45 +0000201{
202 vassert(tmp >= 0);
203 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000204 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardje8e9d732004-07-16 21:03:45 +0000205 *vrLO = env->vregmap[tmp];
206 *vrHI = env->vregmapHI[tmp];
207}
208
sewardj2cd80dc2004-07-02 15:20:40 +0000209static void addInstr ( ISelEnv* env, X86Instr* instr )
sewardjc97096c2004-06-30 09:28:04 +0000210{
sewardj2cd80dc2004-07-02 15:20:40 +0000211 addHInstr(env->code, instr);
sewardjf48ac192004-10-29 00:41:29 +0000212 if (vex_traceflags & VEX_TRACE_VCODE) {
cerion92b64362005-12-13 12:02:26 +0000213 ppX86Instr(instr, False);
sewardj1f40a0a2004-07-21 12:28:07 +0000214 vex_printf("\n");
215 }
sewardjc97096c2004-06-30 09:28:04 +0000216}
217
218static HReg newVRegI ( ISelEnv* env )
219{
sewardj4a31b262004-12-01 02:24:44 +0000220 HReg reg = mkHReg(env->vreg_ctr, HRcInt32, True/*virtual reg*/);
sewardj194d54a2004-07-03 19:08:18 +0000221 env->vreg_ctr++;
sewardjc97096c2004-06-30 09:28:04 +0000222 return reg;
223}
224
sewardj3196daf2004-08-13 00:18:58 +0000225static HReg newVRegF ( ISelEnv* env )
226{
sewardj4a31b262004-12-01 02:24:44 +0000227 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/);
sewardj3196daf2004-08-13 00:18:58 +0000228 env->vreg_ctr++;
229 return reg;
230}
231
sewardjd08f2d72004-12-01 23:19:36 +0000232static HReg newVRegV ( ISelEnv* env )
233{
234 HReg reg = mkHReg(env->vreg_ctr, HRcVec128, True/*virtual reg*/);
235 env->vreg_ctr++;
236 return reg;
237}
238
sewardj66f2f792004-06-30 16:37:16 +0000239
sewardjd18d1bf2004-08-25 12:49:22 +0000240/*---------------------------------------------------------*/
241/*--- ISEL: Forward declarations ---*/
242/*---------------------------------------------------------*/
243
244/* These are organised as iselXXX and iselXXX_wrk pairs. The
245 iselXXX_wrk do the real work, but are not to be called directly.
246 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
sewardjd08f2d72004-12-01 23:19:36 +0000247 checks that all returned registers are virtual. You should not
248 call the _wrk version directly.
sewardjd18d1bf2004-08-25 12:49:22 +0000249*/
sewardjd08f2d72004-12-01 23:19:36 +0000250static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e );
251static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e );
sewardjd18d1bf2004-08-25 12:49:22 +0000252
sewardjd08f2d72004-12-01 23:19:36 +0000253static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e );
254static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e );
sewardjd18d1bf2004-08-25 12:49:22 +0000255
sewardjd08f2d72004-12-01 23:19:36 +0000256static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e );
257static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e );
sewardjd18d1bf2004-08-25 12:49:22 +0000258
sewardjd08f2d72004-12-01 23:19:36 +0000259static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e );
260static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e );
sewardjd18d1bf2004-08-25 12:49:22 +0000261
sewardjd08f2d72004-12-01 23:19:36 +0000262static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e );
263static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e );
sewardjd18d1bf2004-08-25 12:49:22 +0000264
sewardjd08f2d72004-12-01 23:19:36 +0000265static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
266 ISelEnv* env, IRExpr* e );
267static void iselInt64Expr ( HReg* rHi, HReg* rLo,
268 ISelEnv* env, IRExpr* e );
sewardjd18d1bf2004-08-25 12:49:22 +0000269
270static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
271static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e );
272
sewardjd08f2d72004-12-01 23:19:36 +0000273static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e );
274static HReg iselDblExpr ( ISelEnv* env, IRExpr* e );
275
276static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e );
277static HReg iselFltExpr ( ISelEnv* env, IRExpr* e );
278
279static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e );
280static HReg iselVecExpr ( ISelEnv* env, IRExpr* e );
sewardj89cd0932004-09-08 18:23:25 +0000281
sewardjd18d1bf2004-08-25 12:49:22 +0000282
283/*---------------------------------------------------------*/
sewardj17442fe2004-09-20 14:54:28 +0000284/*--- ISEL: Misc helpers ---*/
285/*---------------------------------------------------------*/
286
287/* Make a int reg-reg move. */
288
sewardjd08f2d72004-12-01 23:19:36 +0000289static X86Instr* mk_iMOVsd_RR ( HReg src, HReg dst )
sewardj17442fe2004-09-20 14:54:28 +0000290{
sewardj4a31b262004-12-01 02:24:44 +0000291 vassert(hregClass(src) == HRcInt32);
292 vassert(hregClass(dst) == HRcInt32);
sewardj17442fe2004-09-20 14:54:28 +0000293 return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst);
294}
295
sewardj77352542004-10-30 20:39:01 +0000296
sewardjd08f2d72004-12-01 23:19:36 +0000297/* Make a vector reg-reg move. */
298
299static X86Instr* mk_vMOVsd_RR ( HReg src, HReg dst )
300{
301 vassert(hregClass(src) == HRcVec128);
302 vassert(hregClass(dst) == HRcVec128);
sewardj9e203592004-12-10 01:48:18 +0000303 return X86Instr_SseReRg(Xsse_MOV, src, dst);
sewardjd08f2d72004-12-01 23:19:36 +0000304}
305
sewardj129b3d92004-12-05 15:42:05 +0000306/* Advance/retreat %esp by n. */
307
sewardj855f32d2004-12-05 21:22:38 +0000308static void add_to_esp ( ISelEnv* env, Int n )
sewardj129b3d92004-12-05 15:42:05 +0000309{
310 vassert(n > 0 && n < 256 && (n%4) == 0);
311 addInstr(env,
312 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(n), hregX86_ESP()));
313}
314
sewardj855f32d2004-12-05 21:22:38 +0000315static void sub_from_esp ( ISelEnv* env, Int n )
sewardj129b3d92004-12-05 15:42:05 +0000316{
317 vassert(n > 0 && n < 256 && (n%4) == 0);
318 addInstr(env,
319 X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(n), hregX86_ESP()));
320}
321
sewardjd08f2d72004-12-01 23:19:36 +0000322
sewardj218e29f2004-11-07 18:45:15 +0000323/* Given an amode, return one which references 4 bytes further
324 along. */
325
326static X86AMode* advance4 ( X86AMode* am )
327{
328 X86AMode* am4 = dopyX86AMode(am);
sewardj464efa42004-11-19 22:17:29 +0000329 switch (am4->tag) {
330 case Xam_IRRS:
331 am4->Xam.IRRS.imm += 4; break;
332 case Xam_IR:
333 am4->Xam.IR.imm += 4; break;
334 default:
335 vpanic("advance4(x86,host)");
336 }
sewardj218e29f2004-11-07 18:45:15 +0000337 return am4;
338}
339
340
sewardj17442fe2004-09-20 14:54:28 +0000341/* Push an arg onto the host stack, in preparation for a call to a
342 helper function of some kind. Returns the number of 32-bit words
florian90419562013-08-15 20:54:52 +0000343 pushed. If we encounter an IRExpr_VECRET() then we expect that
sewardj74142b82013-08-08 10:28:59 +0000344 r_vecRetAddr will be a valid register, that holds the relevant
345 address.
346*/
347static Int pushArg ( ISelEnv* env, IRExpr* arg, HReg r_vecRetAddr )
sewardj17442fe2004-09-20 14:54:28 +0000348{
florian90419562013-08-15 20:54:52 +0000349 if (UNLIKELY(arg->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000350 vassert(0); //ATC
351 vassert(!hregIsInvalid(r_vecRetAddr));
352 addInstr(env, X86Instr_Push(X86RMI_Reg(r_vecRetAddr)));
353 return 1;
354 }
florian90419562013-08-15 20:54:52 +0000355 if (UNLIKELY(arg->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000356 addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
357 return 1;
358 }
359 /* Else it's a "normal" expression. */
sewardj17442fe2004-09-20 14:54:28 +0000360 IRType arg_ty = typeOfIRExpr(env->type_env, arg);
361 if (arg_ty == Ity_I32) {
362 addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg)));
363 return 1;
364 } else
365 if (arg_ty == Ity_I64) {
366 HReg rHi, rLo;
sewardjd08f2d72004-12-01 23:19:36 +0000367 iselInt64Expr(&rHi, &rLo, env, arg);
sewardj17442fe2004-09-20 14:54:28 +0000368 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
369 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
370 return 2;
371 }
372 ppIRExpr(arg);
373 vpanic("pushArg(x86): can't handle arg of this type");
374}
375
sewardjc5fc7aa2004-10-27 23:00:55 +0000376
sewardj17442fe2004-09-20 14:54:28 +0000377/* Complete the call to a helper function, by calling the
378 helper and clearing the args off the stack. */
379
380static
sewardj4b861de2004-11-03 15:24:42 +0000381void callHelperAndClearArgs ( ISelEnv* env, X86CondCode cc,
sewardjcfe046e2013-01-17 14:23:53 +0000382 IRCallee* cee, Int n_arg_ws,
383 RetLoc rloc )
sewardj17442fe2004-09-20 14:54:28 +0000384{
sewardj77352542004-10-30 20:39:01 +0000385 /* Complication. Need to decide which reg to use as the fn address
386 pointer, in a way that doesn't trash regparm-passed
387 parameters. */
sewardjf9655262004-10-31 20:02:16 +0000388 vassert(sizeof(void*) == 4);
sewardj77352542004-10-30 20:39:01 +0000389
sewardj428fabd2005-03-21 03:11:17 +0000390 addInstr(env, X86Instr_Call( cc, toUInt(Ptr_to_ULong(cee->addr)),
sewardjcfe046e2013-01-17 14:23:53 +0000391 cee->regparms, rloc));
sewardj17442fe2004-09-20 14:54:28 +0000392 if (n_arg_ws > 0)
sewardj855f32d2004-12-05 21:22:38 +0000393 add_to_esp(env, 4*n_arg_ws);
sewardj17442fe2004-09-20 14:54:28 +0000394}
395
sewardj77352542004-10-30 20:39:01 +0000396
sewardj108b3012004-11-17 13:06:21 +0000397/* Used only in doHelperCall. See big comment in doHelperCall re
398 handling of regparm args. This function figures out whether
399 evaluation of an expression might require use of a fixed register.
400 If in doubt return True (safe but suboptimal).
401*/
402static
403Bool mightRequireFixedRegs ( IRExpr* e )
404{
florian90419562013-08-15 20:54:52 +0000405 if (UNLIKELY(is_IRExpr_VECRET_or_BBPTR(e))) {
sewardj74142b82013-08-08 10:28:59 +0000406 // These are always "safe" -- either a copy of %esp in some
407 // arbitrary vreg, or a copy of %ebp, respectively.
408 return False;
409 }
410 /* Else it's a "normal" expression. */
sewardj108b3012004-11-17 13:06:21 +0000411 switch (e->tag) {
sewardjdd40fdf2006-12-24 02:20:24 +0000412 case Iex_RdTmp: case Iex_Const: case Iex_Get:
sewardj108b3012004-11-17 13:06:21 +0000413 return False;
414 default:
415 return True;
416 }
417}
418
419
sewardj74142b82013-08-08 10:28:59 +0000420/* Do a complete function call. |guard| is a Ity_Bit expression
sewardj4b861de2004-11-03 15:24:42 +0000421 indicating whether or not the call happens. If guard==NULL, the
sewardj74142b82013-08-08 10:28:59 +0000422 call is unconditional. |retloc| is set to indicate where the
423 return value is after the call. The caller (of this fn) must
424 generate code to add |stackAdjustAfterCall| to the stack pointer
425 after the call is done. */
sewardj77352542004-10-30 20:39:01 +0000426
427static
sewardj74142b82013-08-08 10:28:59 +0000428void doHelperCall ( /*OUT*/UInt* stackAdjustAfterCall,
429 /*OUT*/RetLoc* retloc,
430 ISelEnv* env,
431 IRExpr* guard,
432 IRCallee* cee, IRType retTy, IRExpr** args )
sewardj77352542004-10-30 20:39:01 +0000433{
sewardj4b861de2004-11-03 15:24:42 +0000434 X86CondCode cc;
sewardj108b3012004-11-17 13:06:21 +0000435 HReg argregs[3];
436 HReg tmpregs[3];
437 Bool danger;
438 Int not_done_yet, n_args, n_arg_ws, stack_limit,
439 i, argreg, argregX;
sewardj77352542004-10-30 20:39:01 +0000440
sewardj74142b82013-08-08 10:28:59 +0000441 /* Set default returns. We'll update them later if needed. */
442 *stackAdjustAfterCall = 0;
443 *retloc = mk_RetLoc_INVALID();
444
445 /* These are used for cross-checking that IR-level constraints on
florian90419562013-08-15 20:54:52 +0000446 the use of Iex_VECRET and Iex_BBPTR are observed. */
sewardj74142b82013-08-08 10:28:59 +0000447 UInt nVECRETs = 0;
448 UInt nBBPTRs = 0;
449
sewardj77352542004-10-30 20:39:01 +0000450 /* Marshal args for a call, do the call, and clear the stack.
451 Complexities to consider:
452
sewardj74142b82013-08-08 10:28:59 +0000453 * The return type can be I{64,32,16,8} or V128. In the V128
454 case, it is expected that |args| will contain the special
florian90419562013-08-15 20:54:52 +0000455 node IRExpr_VECRET(), in which case this routine generates
sewardj74142b82013-08-08 10:28:59 +0000456 code to allocate space on the stack for the vector return
457 value. Since we are not passing any scalars on the stack, it
458 is enough to preallocate the return space before marshalling
459 any arguments, in this case.
460
florian90419562013-08-15 20:54:52 +0000461 |args| may also contain IRExpr_BBPTR(), in which case the
sewardj74142b82013-08-08 10:28:59 +0000462 value in %ebp is passed as the corresponding argument.
sewardj77352542004-10-30 20:39:01 +0000463
464 * If the callee claims regparmness of 1, 2 or 3, we must pass the
465 first 1, 2 or 3 args in registers (EAX, EDX, and ECX
466 respectively). To keep things relatively simple, only args of
467 type I32 may be passed as regparms -- just bomb out if anything
468 else turns up. Clearly this depends on the front ends not
469 trying to pass any other types as regparms.
470 */
471
sewardj108b3012004-11-17 13:06:21 +0000472 /* 16 Nov 2004: the regparm handling is complicated by the
473 following problem.
474
475 Consider a call two a function with two regparm parameters:
476 f(e1,e2). We need to compute e1 into %eax and e2 into %edx.
477 Suppose code is first generated to compute e1 into %eax. Then,
478 code is generated to compute e2 into %edx. Unfortunately, if
479 the latter code sequence uses %eax, it will trash the value of
480 e1 computed by the former sequence. This could happen if (for
481 example) e2 itself involved a function call. In the code below,
482 args are evaluated right-to-left, not left-to-right, but the
483 principle and the problem are the same.
484
485 One solution is to compute all regparm-bound args into vregs
486 first, and once they are all done, move them to the relevant
487 real regs. This always gives correct code, but it also gives
488 a bunch of vreg-to-rreg moves which are usually redundant but
489 are hard for the register allocator to get rid of.
490
491 A compromise is to first examine all regparm'd argument
492 expressions. If they are all so simple that it is clear
493 they will be evaluated without use of any fixed registers,
494 use the old compute-directly-to-fixed-target scheme. If not,
495 be safe and use the via-vregs scheme.
496
497 Note this requires being able to examine an expression and
498 determine whether or not evaluation of it might use a fixed
499 register. That requires knowledge of how the rest of this
500 insn selector works. Currently just the following 3 are
501 regarded as safe -- hopefully they cover the majority of
502 arguments in practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
503 */
sewardj77352542004-10-30 20:39:01 +0000504 vassert(cee->regparms >= 0 && cee->regparms <= 3);
505
sewardj74142b82013-08-08 10:28:59 +0000506 /* Count the number of args and also the VECRETs */
sewardj77352542004-10-30 20:39:01 +0000507 n_args = n_arg_ws = 0;
sewardj74142b82013-08-08 10:28:59 +0000508 while (args[n_args]) {
509 IRExpr* arg = args[n_args];
510 n_args++;
florian90419562013-08-15 20:54:52 +0000511 if (UNLIKELY(arg->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000512 nVECRETs++;
florian90419562013-08-15 20:54:52 +0000513 } else if (UNLIKELY(arg->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000514 nBBPTRs++;
515 }
516 }
517
518 /* If this fails, the IR is ill-formed */
519 vassert(nBBPTRs == 0 || nBBPTRs == 1);
520
521 /* If we have a VECRET, allocate space on the stack for the return
522 value, and record the stack pointer after that. */
523 HReg r_vecRetAddr = INVALID_HREG;
524 if (nVECRETs == 1) {
525 vassert(retTy == Ity_V128 || retTy == Ity_V256);
526 vassert(retTy != Ity_V256); // we don't handle that yet (if ever)
527 r_vecRetAddr = newVRegI(env);
528 sub_from_esp(env, 16);
529 addInstr(env, mk_iMOVsd_RR( hregX86_ESP(), r_vecRetAddr ));
530 } else {
531 // If either of these fail, the IR is ill-formed
532 vassert(retTy != Ity_V128 && retTy != Ity_V256);
533 vassert(nVECRETs == 0);
534 }
sewardj77352542004-10-30 20:39:01 +0000535
sewardj11eebbe2004-10-30 22:20:02 +0000536 not_done_yet = n_args;
sewardj11eebbe2004-10-30 22:20:02 +0000537
sewardj77352542004-10-30 20:39:01 +0000538 stack_limit = cee->regparms;
sewardj77352542004-10-30 20:39:01 +0000539
sewardj108b3012004-11-17 13:06:21 +0000540 /* ------ BEGIN marshall all arguments ------ */
541
sewardj11eebbe2004-10-30 22:20:02 +0000542 /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */
543 for (i = n_args-1; i >= stack_limit; i--) {
sewardj74142b82013-08-08 10:28:59 +0000544 n_arg_ws += pushArg(env, args[i], r_vecRetAddr);
sewardj11eebbe2004-10-30 22:20:02 +0000545 not_done_yet--;
546 }
sewardj77352542004-10-30 20:39:01 +0000547
548 /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in
549 registers. */
sewardj77352542004-10-30 20:39:01 +0000550
551 if (cee->regparms > 0) {
sewardj108b3012004-11-17 13:06:21 +0000552
553 /* ------ BEGIN deal with regparms ------ */
554
sewardj77352542004-10-30 20:39:01 +0000555 /* deal with regparms, not forgetting %ebp if needed. */
556 argregs[0] = hregX86_EAX();
557 argregs[1] = hregX86_EDX();
558 argregs[2] = hregX86_ECX();
sewardj108b3012004-11-17 13:06:21 +0000559 tmpregs[0] = tmpregs[1] = tmpregs[2] = INVALID_HREG;
560
sewardj77352542004-10-30 20:39:01 +0000561 argreg = cee->regparms;
562
sewardj108b3012004-11-17 13:06:21 +0000563 /* In keeping with big comment above, detect potential danger
564 and use the via-vregs scheme if needed. */
565 danger = False;
sewardj77352542004-10-30 20:39:01 +0000566 for (i = stack_limit-1; i >= 0; i--) {
sewardj108b3012004-11-17 13:06:21 +0000567 if (mightRequireFixedRegs(args[i])) {
568 danger = True;
569 break;
570 }
sewardj77352542004-10-30 20:39:01 +0000571 }
sewardj108b3012004-11-17 13:06:21 +0000572
573 if (danger) {
574
575 /* Move via temporaries */
576 argregX = argreg;
577 for (i = stack_limit-1; i >= 0; i--) {
578
579 if (0) {
580 vex_printf("x86 host: register param is complex: ");
581 ppIRExpr(args[i]);
582 vex_printf("\n");
583 }
584
sewardj74142b82013-08-08 10:28:59 +0000585 IRExpr* arg = args[i];
sewardj108b3012004-11-17 13:06:21 +0000586 argreg--;
587 vassert(argreg >= 0);
florian90419562013-08-15 20:54:52 +0000588 if (UNLIKELY(arg->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000589 vassert(0); //ATC
590 }
florian90419562013-08-15 20:54:52 +0000591 else if (UNLIKELY(arg->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000592 vassert(0); //ATC
593 } else {
594 vassert(typeOfIRExpr(env->type_env, arg) == Ity_I32);
595 tmpregs[argreg] = iselIntExpr_R(env, arg);
596 }
sewardj108b3012004-11-17 13:06:21 +0000597 not_done_yet--;
598 }
599 for (i = stack_limit-1; i >= 0; i--) {
600 argregX--;
601 vassert(argregX >= 0);
sewardjd08f2d72004-12-01 23:19:36 +0000602 addInstr( env, mk_iMOVsd_RR( tmpregs[argregX], argregs[argregX] ) );
sewardj108b3012004-11-17 13:06:21 +0000603 }
604
605 } else {
606 /* It's safe to compute all regparm args directly into their
607 target registers. */
608 for (i = stack_limit-1; i >= 0; i--) {
sewardj74142b82013-08-08 10:28:59 +0000609 IRExpr* arg = args[i];
sewardj108b3012004-11-17 13:06:21 +0000610 argreg--;
611 vassert(argreg >= 0);
florian90419562013-08-15 20:54:52 +0000612 if (UNLIKELY(arg->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000613 vassert(!hregIsInvalid(r_vecRetAddr));
614 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
615 X86RMI_Reg(r_vecRetAddr),
616 argregs[argreg]));
617 }
florian90419562013-08-15 20:54:52 +0000618 else if (UNLIKELY(arg->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000619 vassert(0); //ATC
620 } else {
621 vassert(typeOfIRExpr(env->type_env, arg) == Ity_I32);
622 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
623 iselIntExpr_RMI(env, arg),
624 argregs[argreg]));
625 }
sewardj108b3012004-11-17 13:06:21 +0000626 not_done_yet--;
627 }
628
629 }
630
sewardj108b3012004-11-17 13:06:21 +0000631 /* ------ END deal with regparms ------ */
632
sewardj77352542004-10-30 20:39:01 +0000633 }
634
sewardj11eebbe2004-10-30 22:20:02 +0000635 vassert(not_done_yet == 0);
636
sewardj108b3012004-11-17 13:06:21 +0000637 /* ------ END marshall all arguments ------ */
638
sewardj4b861de2004-11-03 15:24:42 +0000639 /* Now we can compute the condition. We can't do it earlier
640 because the argument computations could trash the condition
641 codes. Be a bit clever to handle the common case where the
642 guard is 1:Bit. */
643 cc = Xcc_ALWAYS;
644 if (guard) {
645 if (guard->tag == Iex_Const
sewardjba999312004-11-15 15:21:17 +0000646 && guard->Iex.Const.con->tag == Ico_U1
647 && guard->Iex.Const.con->Ico.U1 == True) {
sewardj4b861de2004-11-03 15:24:42 +0000648 /* unconditional -- do nothing */
649 } else {
650 cc = iselCondCode( env, guard );
651 }
652 }
653
sewardj74142b82013-08-08 10:28:59 +0000654 /* Do final checks, set the return values, and generate the call
655 instruction proper. */
656 vassert(*stackAdjustAfterCall == 0);
657 vassert(is_RetLoc_INVALID(*retloc));
658 switch (retTy) {
659 case Ity_INVALID:
660 /* Function doesn't return a value. */
661 *retloc = mk_RetLoc_simple(RLPri_None);
662 break;
663 case Ity_I64:
664 *retloc = mk_RetLoc_simple(RLPri_2Int);
665 break;
666 case Ity_I32: case Ity_I16: case Ity_I8:
667 *retloc = mk_RetLoc_simple(RLPri_Int);
668 break;
669 case Ity_V128:
670 *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
671 *stackAdjustAfterCall = 16;
672 break;
673 case Ity_V256:
674 vassert(0); // ATC
675 *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
676 *stackAdjustAfterCall = 32;
677 break;
678 default:
679 /* IR can denote other possible return types, but we don't
680 handle those here. */
681 vassert(0);
682 }
683
684 /* Finally, generate the call itself. This needs the *retloc value
685 set in the switch above, which is why it's at the end. */
686 callHelperAndClearArgs( env, cc, cee, n_arg_ws, *retloc );
sewardj77352542004-10-30 20:39:01 +0000687}
688
689
sewardj2d3f77c2004-09-22 23:49:09 +0000690/* Given a guest-state array descriptor, an index expression and a
691 bias, generate an X86AMode holding the relevant guest state
692 offset. */
693
694static
sewardjdd40fdf2006-12-24 02:20:24 +0000695X86AMode* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr,
sewardj2d3f77c2004-09-22 23:49:09 +0000696 IRExpr* off, Int bias )
697{
sewardj8fc93742004-11-22 11:29:33 +0000698 HReg tmp, roff;
699 Int elemSz = sizeofIRType(descr->elemTy);
700 Int nElems = descr->nElems;
sewardje12d6442005-05-09 12:16:33 +0000701 Int shift = 0;
sewardj2d3f77c2004-09-22 23:49:09 +0000702
703 /* throw out any cases not generated by an x86 front end. In
704 theory there might be a day where we need to handle them -- if
705 we ever run non-x86-guest on x86 host. */
706
sewardje12d6442005-05-09 12:16:33 +0000707 if (nElems != 8)
708 vpanic("genGuestArrayOffset(x86 host)(1)");
709
710 switch (elemSz) {
711 case 1: shift = 0; break;
sewardje5f740c2005-05-11 10:05:04 +0000712 case 4: shift = 2; break;
sewardje12d6442005-05-09 12:16:33 +0000713 case 8: shift = 3; break;
714 default: vpanic("genGuestArrayOffset(x86 host)(2)");
715 }
sewardj2d3f77c2004-09-22 23:49:09 +0000716
717 /* Compute off into a reg, %off. Then return:
718
719 movl %off, %tmp
720 addl $bias, %tmp (if bias != 0)
721 andl %tmp, 7
722 ... base(%ebp, %tmp, shift) ...
723 */
sewardj8fc93742004-11-22 11:29:33 +0000724 tmp = newVRegI(env);
725 roff = iselIntExpr_R(env, off);
sewardjd08f2d72004-12-01 23:19:36 +0000726 addInstr(env, mk_iMOVsd_RR(roff, tmp));
sewardj2d3f77c2004-09-22 23:49:09 +0000727 if (bias != 0) {
728 addInstr(env,
729 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(bias), tmp));
730 }
731 addInstr(env,
732 X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(7), tmp));
sewardj2d3f77c2004-09-22 23:49:09 +0000733 return
sewardje12d6442005-05-09 12:16:33 +0000734 X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, shift );
sewardj2d3f77c2004-09-22 23:49:09 +0000735}
736
sewardj17442fe2004-09-20 14:54:28 +0000737
sewardj4cb918d2004-12-03 19:43:31 +0000738/* Mess with the FPU's rounding mode: set to the default rounding mode
sewardj9c323762005-01-10 16:49:19 +0000739 (DEFAULT_FPUCW). */
sewardj4cb918d2004-12-03 19:43:31 +0000740static
741void set_FPU_rounding_default ( ISelEnv* env )
742{
sewardj9c323762005-01-10 16:49:19 +0000743 /* pushl $DEFAULT_FPUCW
sewardj4cb918d2004-12-03 19:43:31 +0000744 fldcw 0(%esp)
745 addl $4, %esp
746 */
747 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
sewardj9c323762005-01-10 16:49:19 +0000748 addInstr(env, X86Instr_Push(X86RMI_Imm(DEFAULT_FPUCW)));
sewardjeba63f82005-02-23 13:31:25 +0000749 addInstr(env, X86Instr_FpLdCW(zero_esp));
sewardj855f32d2004-12-05 21:22:38 +0000750 add_to_esp(env, 4);
sewardj4cb918d2004-12-03 19:43:31 +0000751}
752
753
754/* Mess with the FPU's rounding mode: 'mode' is an I32-typed
755 expression denoting a value in the range 0 .. 3, indicating a round
756 mode encoded as per type IRRoundingMode. Set the x87 FPU to have
757 the same rounding.
758*/
759static
760void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
761{
762 HReg rrm = iselIntExpr_R(env, mode);
763 HReg rrm2 = newVRegI(env);
764 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
765
766 /* movl %rrm, %rrm2
767 andl $3, %rrm2 -- shouldn't be needed; paranoia
768 shll $10, %rrm2
sewardj9c323762005-01-10 16:49:19 +0000769 orl $DEFAULT_FPUCW, %rrm2
sewardj4cb918d2004-12-03 19:43:31 +0000770 pushl %rrm2
771 fldcw 0(%esp)
772 addl $4, %esp
773 */
774 addInstr(env, mk_iMOVsd_RR(rrm, rrm2));
775 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
sewardjeba63f82005-02-23 13:31:25 +0000776 addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, rrm2));
sewardj9c323762005-01-10 16:49:19 +0000777 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(DEFAULT_FPUCW), rrm2));
sewardj4cb918d2004-12-03 19:43:31 +0000778 addInstr(env, X86Instr_Push(X86RMI_Reg(rrm2)));
sewardjeba63f82005-02-23 13:31:25 +0000779 addInstr(env, X86Instr_FpLdCW(zero_esp));
sewardj855f32d2004-12-05 21:22:38 +0000780 add_to_esp(env, 4);
sewardj4cb918d2004-12-03 19:43:31 +0000781}
782
783
sewardj2e383862004-12-12 16:46:47 +0000784/* Generate !src into a new vector register, and be sure that the code
785 is SSE1 compatible. Amazing that Intel doesn't offer a less crappy
786 way to do this.
787*/
788static HReg do_sse_Not128 ( ISelEnv* env, HReg src )
789{
790 HReg dst = newVRegV(env);
sewardjf1b5b1a2006-02-03 22:54:17 +0000791 /* Set dst to zero. If dst contains a NaN then all hell might
792 break loose after the comparison. So, first zero it. */
sewardj2e383862004-12-12 16:46:47 +0000793 addInstr(env, X86Instr_SseReRg(Xsse_XOR, dst, dst));
794 /* And now make it all 1s ... */
795 addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, dst, dst));
796 /* Finally, xor 'src' into it. */
797 addInstr(env, X86Instr_SseReRg(Xsse_XOR, src, dst));
sewardjf1b5b1a2006-02-03 22:54:17 +0000798 /* Doesn't that just totally suck? */
sewardj2e383862004-12-12 16:46:47 +0000799 return dst;
800}
801
802
sewardj9c323762005-01-10 16:49:19 +0000803/* Round an x87 FPU value to 53-bit-mantissa precision, to be used
804 after most non-simple FPU operations (simple = +, -, *, / and
805 sqrt).
806
807 This could be done a lot more efficiently if needed, by loading
808 zero and adding it to the value to be rounded (fldz ; faddp?).
809*/
810static void roundToF64 ( ISelEnv* env, HReg reg )
811{
812 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
813 sub_from_esp(env, 8);
814 addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, reg, zero_esp));
815 addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, reg, zero_esp));
816 add_to_esp(env, 8);
817}
818
819
sewardj17442fe2004-09-20 14:54:28 +0000820/*---------------------------------------------------------*/
sewardjd18d1bf2004-08-25 12:49:22 +0000821/*--- ISEL: Integer expressions (32/16/8 bit) ---*/
822/*---------------------------------------------------------*/
823
sewardjc97096c2004-06-30 09:28:04 +0000824/* Select insns for an integer-typed expression, and add them to the
sewardjd18d1bf2004-08-25 12:49:22 +0000825 code list. Return a reg holding the result. This reg will be a
826 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
827 want to modify it, ask for a new vreg, copy it in there, and modify
828 the copy. The register allocator will do its best to map both
829 vregs to the same real register, so the copies will often disappear
830 later in the game.
sewardj4042c7e2004-07-18 01:28:30 +0000831
832 This should handle expressions of 32, 16 and 8-bit type. All
833 results are returned in a 32-bit register. For 16- and 8-bit
sewardjd18d1bf2004-08-25 12:49:22 +0000834 expressions, the upper 16/24 bits are arbitrary, so you should mask
835 or sign extend partial values if necessary.
sewardjc97096c2004-06-30 09:28:04 +0000836*/
sewardjd18d1bf2004-08-25 12:49:22 +0000837
sewardj66f2f792004-06-30 16:37:16 +0000838static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
sewardjc97096c2004-06-30 09:28:04 +0000839{
sewardjd18d1bf2004-08-25 12:49:22 +0000840 HReg r = iselIntExpr_R_wrk(env, e);
841 /* sanity checks ... */
842# if 0
843 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
844# endif
sewardj4a31b262004-12-01 02:24:44 +0000845 vassert(hregClass(r) == HRcInt32);
sewardjd18d1bf2004-08-25 12:49:22 +0000846 vassert(hregIsVirtual(r));
847 return r;
848}
849
850/* DO NOT CALL THIS DIRECTLY ! */
851static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
852{
sewardj443cd9d2004-07-18 23:06:45 +0000853 MatchInfo mi;
sewardj443cd9d2004-07-18 23:06:45 +0000854
sewardje8e9d732004-07-16 21:03:45 +0000855 IRType ty = typeOfIRExpr(env->type_env,e);
sewardjf73b94a2005-02-04 21:14:52 +0000856 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardjc97096c2004-06-30 09:28:04 +0000857
858 switch (e->tag) {
859
sewardj60f4e3c2004-07-19 01:56:50 +0000860 /* --------- TEMP --------- */
sewardjdd40fdf2006-12-24 02:20:24 +0000861 case Iex_RdTmp: {
862 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
sewardje8e9d732004-07-16 21:03:45 +0000863 }
sewardjc97096c2004-06-30 09:28:04 +0000864
sewardj60f4e3c2004-07-19 01:56:50 +0000865 /* --------- LOAD --------- */
sewardjaf1ceca2005-06-30 23:31:27 +0000866 case Iex_Load: {
sewardje8e9d732004-07-16 21:03:45 +0000867 HReg dst = newVRegI(env);
sewardjaf1ceca2005-06-30 23:31:27 +0000868 X86AMode* amode = iselIntExpr_AMode ( env, e->Iex.Load.addr );
869
sewardje9d8a262009-07-01 08:06:34 +0000870 /* We can't handle big-endian loads, nor load-linked. */
sewardjaf1ceca2005-06-30 23:31:27 +0000871 if (e->Iex.Load.end != Iend_LE)
872 goto irreducible;
873
sewardj4042c7e2004-07-18 01:28:30 +0000874 if (ty == Ity_I32) {
875 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
876 X86RMI_Mem(amode), dst) );
877 return dst;
878 }
879 if (ty == Ity_I16) {
880 addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
881 return dst;
882 }
sewardj443cd9d2004-07-18 23:06:45 +0000883 if (ty == Ity_I8) {
884 addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
885 return dst;
886 }
sewardj4042c7e2004-07-18 01:28:30 +0000887 break;
sewardje8e9d732004-07-16 21:03:45 +0000888 }
889
sewardjf47286e2006-02-04 15:20:13 +0000890 /* --------- TERNARY OP --------- */
891 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +0000892 IRTriop *triop = e->Iex.Triop.details;
sewardjf47286e2006-02-04 15:20:13 +0000893 /* C3210 flags following FPU partial remainder (fprem), both
894 IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
florian420bfa92012-06-02 20:29:22 +0000895 if (triop->op == Iop_PRemC3210F64
896 || triop->op == Iop_PRem1C3210F64) {
sewardjf47286e2006-02-04 15:20:13 +0000897 HReg junk = newVRegF(env);
898 HReg dst = newVRegI(env);
florian420bfa92012-06-02 20:29:22 +0000899 HReg srcL = iselDblExpr(env, triop->arg2);
900 HReg srcR = iselDblExpr(env, triop->arg3);
sewardjf47286e2006-02-04 15:20:13 +0000901 /* XXXROUNDINGFIXME */
902 /* set roundingmode here */
903 addInstr(env, X86Instr_FpBinary(
904 e->Iex.Binop.op==Iop_PRemC3210F64
905 ? Xfp_PREM : Xfp_PREM1,
906 srcL,srcR,junk
907 ));
908 /* The previous pseudo-insn will have left the FPU's C3210
909 flags set correctly. So bag them. */
910 addInstr(env, X86Instr_FpStSW_AX());
911 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
912 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
913 return dst;
914 }
915
916 break;
917 }
918
sewardj60f4e3c2004-07-19 01:56:50 +0000919 /* --------- BINARY OP --------- */
sewardje8e9d732004-07-16 21:03:45 +0000920 case Iex_Binop: {
921 X86AluOp aluOp;
922 X86ShiftOp shOp;
sewardj8c7f1ab2004-07-29 20:31:09 +0000923
sewardjeb17e492007-08-25 23:07:44 +0000924 /* Pattern: Sub32(0,x) */
925 if (e->Iex.Binop.op == Iop_Sub32 && isZeroU32(e->Iex.Binop.arg1)) {
926 HReg dst = newVRegI(env);
927 HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg2);
928 addInstr(env, mk_iMOVsd_RR(reg,dst));
929 addInstr(env, X86Instr_Unary32(Xun_NEG,dst));
930 return dst;
931 }
932
sewardj4042c7e2004-07-18 01:28:30 +0000933 /* Is it an addition or logical style op? */
sewardje8e9d732004-07-16 21:03:45 +0000934 switch (e->Iex.Binop.op) {
sewardja2384712004-07-29 14:36:40 +0000935 case Iop_Add8: case Iop_Add16: case Iop_Add32:
sewardj1813dbe2004-07-28 17:09:04 +0000936 aluOp = Xalu_ADD; break;
sewardj60f4e3c2004-07-19 01:56:50 +0000937 case Iop_Sub8: case Iop_Sub16: case Iop_Sub32:
938 aluOp = Xalu_SUB; break;
sewardj5c34dc92004-07-19 12:48:11 +0000939 case Iop_And8: case Iop_And16: case Iop_And32:
940 aluOp = Xalu_AND; break;
sewardj750f4072004-07-26 22:39:11 +0000941 case Iop_Or8: case Iop_Or16: case Iop_Or32:
sewardj597b71b2004-07-19 02:51:12 +0000942 aluOp = Xalu_OR; break;
sewardja2384712004-07-29 14:36:40 +0000943 case Iop_Xor8: case Iop_Xor16: case Iop_Xor32:
sewardj597b71b2004-07-19 02:51:12 +0000944 aluOp = Xalu_XOR; break;
sewardjb81f8b32004-07-30 10:17:50 +0000945 case Iop_Mul16: case Iop_Mul32:
946 aluOp = Xalu_MUL; break;
947 default:
948 aluOp = Xalu_INVALID; break;
sewardje8e9d732004-07-16 21:03:45 +0000949 }
950 /* For commutative ops we assume any literal
sewardj66f2f792004-06-30 16:37:16 +0000951 values are on the second operand. */
sewardje8e9d732004-07-16 21:03:45 +0000952 if (aluOp != Xalu_INVALID) {
sewardj66f2f792004-06-30 16:37:16 +0000953 HReg dst = newVRegI(env);
954 HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
955 X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
sewardjd08f2d72004-12-01 23:19:36 +0000956 addInstr(env, mk_iMOVsd_RR(reg,dst));
sewardje8e9d732004-07-16 21:03:45 +0000957 addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst));
sewardj66f2f792004-06-30 16:37:16 +0000958 return dst;
sewardjc97096c2004-06-30 09:28:04 +0000959 }
sewardj4f391492004-08-24 22:45:30 +0000960 /* Could do better here; forcing the first arg into a reg
961 isn't always clever.
962 -- t70 = Xor32(And32(Xor32(LDle:I32(Add32(t41,0xFFFFFFA0:I32)),
963 LDle:I32(Add32(t41,0xFFFFFFA4:I32))),LDle:I32(Add32(
964 t41,0xFFFFFFA8:I32))),LDle:I32(Add32(t41,0xFFFFFFA0:I32)))
965 movl 0xFFFFFFA0(%vr41),%vr107
966 movl 0xFFFFFFA4(%vr41),%vr108
967 movl %vr107,%vr106
968 xorl %vr108,%vr106
969 movl 0xFFFFFFA8(%vr41),%vr109
970 movl %vr106,%vr105
971 andl %vr109,%vr105
972 movl 0xFFFFFFA0(%vr41),%vr110
973 movl %vr105,%vr104
974 xorl %vr110,%vr104
975 movl %vr104,%vr70
976 */
sewardj8c7f1ab2004-07-29 20:31:09 +0000977
sewardj4042c7e2004-07-18 01:28:30 +0000978 /* Perhaps a shift op? */
sewardje8e9d732004-07-16 21:03:45 +0000979 switch (e->Iex.Binop.op) {
sewardj1813dbe2004-07-28 17:09:04 +0000980 case Iop_Shl32: case Iop_Shl16: case Iop_Shl8:
981 shOp = Xsh_SHL; break;
982 case Iop_Shr32: case Iop_Shr16: case Iop_Shr8:
sewardj5c34dc92004-07-19 12:48:11 +0000983 shOp = Xsh_SHR; break;
sewardj8c7f1ab2004-07-29 20:31:09 +0000984 case Iop_Sar32: case Iop_Sar16: case Iop_Sar8:
sewardj1813dbe2004-07-28 17:09:04 +0000985 shOp = Xsh_SAR; break;
986 default:
987 shOp = Xsh_INVALID; break;
sewardje8e9d732004-07-16 21:03:45 +0000988 }
989 if (shOp != Xsh_INVALID) {
sewardj8c7f1ab2004-07-29 20:31:09 +0000990 HReg dst = newVRegI(env);
sewardj38ff3d82004-07-26 23:27:08 +0000991
992 /* regL = the value to be shifted */
sewardj96efe572004-07-03 14:48:24 +0000993 HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardjd08f2d72004-12-01 23:19:36 +0000994 addInstr(env, mk_iMOVsd_RR(regL,dst));
sewardj38ff3d82004-07-26 23:27:08 +0000995
sewardj5c34dc92004-07-19 12:48:11 +0000996 /* Do any necessary widening for 16/8 bit operands */
997 switch (e->Iex.Binop.op) {
998 case Iop_Shr8:
999 addInstr(env, X86Instr_Alu32R(
1000 Xalu_AND, X86RMI_Imm(0xFF), dst));
1001 break;
1002 case Iop_Shr16:
1003 addInstr(env, X86Instr_Alu32R(
1004 Xalu_AND, X86RMI_Imm(0xFFFF), dst));
1005 break;
sewardj8c7f1ab2004-07-29 20:31:09 +00001006 case Iop_Sar8:
sewardjeba63f82005-02-23 13:31:25 +00001007 addInstr(env, X86Instr_Sh32(Xsh_SHL, 24, dst));
1008 addInstr(env, X86Instr_Sh32(Xsh_SAR, 24, dst));
sewardj8c7f1ab2004-07-29 20:31:09 +00001009 break;
1010 case Iop_Sar16:
sewardjeba63f82005-02-23 13:31:25 +00001011 addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, dst));
1012 addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, dst));
sewardj8c7f1ab2004-07-29 20:31:09 +00001013 break;
sewardj5c34dc92004-07-19 12:48:11 +00001014 default: break;
1015 }
sewardj38ff3d82004-07-26 23:27:08 +00001016
1017 /* Now consider the shift amount. If it's a literal, we
1018 can do a much better job than the general case. */
1019 if (e->Iex.Binop.arg2->tag == Iex_Const) {
1020 /* assert that the IR is well-typed */
1021 Int nshift;
1022 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj38ff3d82004-07-26 23:27:08 +00001023 nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
sewardj3bd676c2004-07-27 10:50:38 +00001024 vassert(nshift >= 0);
sewardj38ff3d82004-07-26 23:27:08 +00001025 if (nshift > 0)
sewardjb81f8b32004-07-30 10:17:50 +00001026 /* Can't allow nshift==0 since that means %cl */
sewardjeba63f82005-02-23 13:31:25 +00001027 addInstr(env, X86Instr_Sh32( shOp, nshift, dst ));
sewardj38ff3d82004-07-26 23:27:08 +00001028 } else {
1029 /* General case; we have to force the amount into %cl. */
1030 HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2);
sewardjd08f2d72004-12-01 23:19:36 +00001031 addInstr(env, mk_iMOVsd_RR(regR,hregX86_ECX()));
sewardjeba63f82005-02-23 13:31:25 +00001032 addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, dst));
sewardj38ff3d82004-07-26 23:27:08 +00001033 }
sewardjd9c2b792004-07-08 01:44:38 +00001034 return dst;
1035 }
sewardj8c7f1ab2004-07-29 20:31:09 +00001036
1037 /* Handle misc other ops. */
sewardj478646f2008-05-01 20:13:04 +00001038
1039 if (e->Iex.Binop.op == Iop_Max32U) {
1040 HReg src1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1041 HReg dst = newVRegI(env);
1042 HReg src2 = iselIntExpr_R(env, e->Iex.Binop.arg2);
1043 addInstr(env, mk_iMOVsd_RR(src1,dst));
1044 addInstr(env, X86Instr_Alu32R(Xalu_CMP, X86RMI_Reg(src2), dst));
1045 addInstr(env, X86Instr_CMov32(Xcc_B, X86RM_Reg(src2), dst));
1046 return dst;
1047 }
1048
sewardjfd332772004-11-09 16:01:40 +00001049 if (e->Iex.Binop.op == Iop_8HLto16) {
1050 HReg hi8 = newVRegI(env);
1051 HReg lo8 = newVRegI(env);
1052 HReg hi8s = iselIntExpr_R(env, e->Iex.Binop.arg1);
1053 HReg lo8s = iselIntExpr_R(env, e->Iex.Binop.arg2);
sewardjd08f2d72004-12-01 23:19:36 +00001054 addInstr(env, mk_iMOVsd_RR(hi8s, hi8));
1055 addInstr(env, mk_iMOVsd_RR(lo8s, lo8));
sewardjeba63f82005-02-23 13:31:25 +00001056 addInstr(env, X86Instr_Sh32(Xsh_SHL, 8, hi8));
sewardjfd332772004-11-09 16:01:40 +00001057 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFF), lo8));
1058 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo8), hi8));
1059 return hi8;
1060 }
1061
sewardj8c7f1ab2004-07-29 20:31:09 +00001062 if (e->Iex.Binop.op == Iop_16HLto32) {
1063 HReg hi16 = newVRegI(env);
1064 HReg lo16 = newVRegI(env);
1065 HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
1066 HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
sewardjd08f2d72004-12-01 23:19:36 +00001067 addInstr(env, mk_iMOVsd_RR(hi16s, hi16));
1068 addInstr(env, mk_iMOVsd_RR(lo16s, lo16));
sewardjeba63f82005-02-23 13:31:25 +00001069 addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, hi16));
sewardj8c7f1ab2004-07-29 20:31:09 +00001070 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFFFF), lo16));
1071 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo16), hi16));
1072 return hi16;
1073 }
1074
sewardjb81f8b32004-07-30 10:17:50 +00001075 if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8
1076 || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) {
1077 HReg a16 = newVRegI(env);
1078 HReg b16 = newVRegI(env);
1079 HReg a16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
1080 HReg b16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
1081 Int shift = (e->Iex.Binop.op == Iop_MullS8
1082 || e->Iex.Binop.op == Iop_MullU8)
1083 ? 24 : 16;
1084 X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8
1085 || e->Iex.Binop.op == Iop_MullS16)
1086 ? Xsh_SAR : Xsh_SHR;
1087
sewardjd08f2d72004-12-01 23:19:36 +00001088 addInstr(env, mk_iMOVsd_RR(a16s, a16));
1089 addInstr(env, mk_iMOVsd_RR(b16s, b16));
sewardjeba63f82005-02-23 13:31:25 +00001090 addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, a16));
1091 addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, b16));
1092 addInstr(env, X86Instr_Sh32(shr_op, shift, a16));
1093 addInstr(env, X86Instr_Sh32(shr_op, shift, b16));
sewardjb81f8b32004-07-30 10:17:50 +00001094 addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16));
1095 return b16;
1096 }
1097
sewardjbdc7d212004-09-09 02:46:40 +00001098 if (e->Iex.Binop.op == Iop_CmpF64) {
1099 HReg fL = iselDblExpr(env, e->Iex.Binop.arg1);
1100 HReg fR = iselDblExpr(env, e->Iex.Binop.arg2);
1101 HReg dst = newVRegI(env);
1102 addInstr(env, X86Instr_FpCmp(fL,fR,dst));
1103 /* shift this right 8 bits so as to conform to CmpF64
1104 definition. */
sewardjeba63f82005-02-23 13:31:25 +00001105 addInstr(env, X86Instr_Sh32(Xsh_SHR, 8, dst));
sewardjbdc7d212004-09-09 02:46:40 +00001106 return dst;
1107 }
1108
sewardj6c299f32009-12-31 18:00:12 +00001109 if (e->Iex.Binop.op == Iop_F64toI32S
1110 || e->Iex.Binop.op == Iop_F64toI16S) {
1111 Int sz = e->Iex.Binop.op == Iop_F64toI16S ? 2 : 4;
sewardj4cb918d2004-12-03 19:43:31 +00001112 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
1113 HReg dst = newVRegI(env);
sewardj8f3debf2004-09-08 23:42:23 +00001114
1115 /* Used several times ... */
1116 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
1117
1118 /* rf now holds the value to be converted, and rrm holds the
1119 rounding mode value, encoded as per the IRRoundingMode
1120 enum. The first thing to do is set the FPU's rounding
1121 mode accordingly. */
1122
sewardj4cb918d2004-12-03 19:43:31 +00001123 /* Create a space for the format conversion. */
sewardj8f3debf2004-09-08 23:42:23 +00001124 /* subl $4, %esp */
sewardj855f32d2004-12-05 21:22:38 +00001125 sub_from_esp(env, 4);
sewardj4cb918d2004-12-03 19:43:31 +00001126
1127 /* Set host rounding mode */
1128 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
sewardj8f3debf2004-09-08 23:42:23 +00001129
1130 /* gistw/l %rf, 0(%esp) */
sewardj428fabd2005-03-21 03:11:17 +00001131 addInstr(env, X86Instr_FpLdStI(False/*store*/,
1132 toUChar(sz), rf, zero_esp));
sewardj8f3debf2004-09-08 23:42:23 +00001133
1134 if (sz == 2) {
1135 /* movzwl 0(%esp), %dst */
1136 addInstr(env, X86Instr_LoadEX(2,False,zero_esp,dst));
sewardj3bca9062004-12-04 14:36:09 +00001137 } else {
sewardj8f3debf2004-09-08 23:42:23 +00001138 /* movl 0(%esp), %dst */
1139 vassert(sz == 4);
1140 addInstr(env, X86Instr_Alu32R(
1141 Xalu_MOV, X86RMI_Mem(zero_esp), dst));
1142 }
1143
sewardj4cb918d2004-12-03 19:43:31 +00001144 /* Restore default FPU rounding. */
1145 set_FPU_rounding_default( env );
sewardj8f3debf2004-09-08 23:42:23 +00001146
1147 /* addl $4, %esp */
sewardj855f32d2004-12-05 21:22:38 +00001148 add_to_esp(env, 4);
sewardj8f3debf2004-09-08 23:42:23 +00001149 return dst;
1150 }
1151
sewardje8e9d732004-07-16 21:03:45 +00001152 break;
sewardjd9c2b792004-07-08 01:44:38 +00001153 }
1154
sewardj60f4e3c2004-07-19 01:56:50 +00001155 /* --------- UNARY OP --------- */
sewardj4042c7e2004-07-18 01:28:30 +00001156 case Iex_Unop: {
sewardjeb17e492007-08-25 23:07:44 +00001157
sewardj443cd9d2004-07-18 23:06:45 +00001158 /* 1Uto8(32to1(expr32)) */
sewardjeb17e492007-08-25 23:07:44 +00001159 if (e->Iex.Unop.op == Iop_1Uto8) {
1160 DECLARE_PATTERN(p_32to1_then_1Uto8);
1161 DEFINE_PATTERN(p_32to1_then_1Uto8,
1162 unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
1163 if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
1164 IRExpr* expr32 = mi.bindee[0];
1165 HReg dst = newVRegI(env);
1166 HReg src = iselIntExpr_R(env, expr32);
1167 addInstr(env, mk_iMOVsd_RR(src,dst) );
1168 addInstr(env, X86Instr_Alu32R(Xalu_AND,
1169 X86RMI_Imm(1), dst));
1170 return dst;
1171 }
1172 }
1173
1174 /* 8Uto32(LDle(expr32)) */
1175 if (e->Iex.Unop.op == Iop_8Uto32) {
1176 DECLARE_PATTERN(p_LDle8_then_8Uto32);
1177 DEFINE_PATTERN(p_LDle8_then_8Uto32,
1178 unop(Iop_8Uto32,
sewardje768e922009-11-26 17:17:37 +00001179 IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
sewardjeb17e492007-08-25 23:07:44 +00001180 if (matchIRExpr(&mi,p_LDle8_then_8Uto32,e)) {
1181 HReg dst = newVRegI(env);
1182 X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1183 addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
1184 return dst;
1185 }
1186 }
1187
1188 /* 8Sto32(LDle(expr32)) */
1189 if (e->Iex.Unop.op == Iop_8Sto32) {
1190 DECLARE_PATTERN(p_LDle8_then_8Sto32);
1191 DEFINE_PATTERN(p_LDle8_then_8Sto32,
1192 unop(Iop_8Sto32,
sewardje768e922009-11-26 17:17:37 +00001193 IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
sewardjeb17e492007-08-25 23:07:44 +00001194 if (matchIRExpr(&mi,p_LDle8_then_8Sto32,e)) {
1195 HReg dst = newVRegI(env);
1196 X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1197 addInstr(env, X86Instr_LoadEX(1,True,amode,dst));
1198 return dst;
1199 }
sewardj443cd9d2004-07-18 23:06:45 +00001200 }
1201
sewardjd18d1bf2004-08-25 12:49:22 +00001202 /* 16Uto32(LDle(expr32)) */
sewardjeb17e492007-08-25 23:07:44 +00001203 if (e->Iex.Unop.op == Iop_16Uto32) {
sewardjd18d1bf2004-08-25 12:49:22 +00001204 DECLARE_PATTERN(p_LDle16_then_16Uto32);
1205 DEFINE_PATTERN(p_LDle16_then_16Uto32,
sewardjaf1ceca2005-06-30 23:31:27 +00001206 unop(Iop_16Uto32,
sewardje768e922009-11-26 17:17:37 +00001207 IRExpr_Load(Iend_LE,Ity_I16,bind(0))) );
sewardjd18d1bf2004-08-25 12:49:22 +00001208 if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) {
1209 HReg dst = newVRegI(env);
1210 X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1211 addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1212 return dst;
1213 }
1214 }
1215
sewardjeb17e492007-08-25 23:07:44 +00001216 /* 8Uto32(GET:I8) */
1217 if (e->Iex.Unop.op == Iop_8Uto32) {
1218 if (e->Iex.Unop.arg->tag == Iex_Get) {
1219 HReg dst;
1220 X86AMode* amode;
1221 vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I8);
1222 dst = newVRegI(env);
1223 amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
1224 hregX86_EBP());
1225 addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
1226 return dst;
1227 }
1228 }
1229
1230 /* 16to32(GET:I16) */
1231 if (e->Iex.Unop.op == Iop_16Uto32) {
1232 if (e->Iex.Unop.arg->tag == Iex_Get) {
1233 HReg dst;
1234 X86AMode* amode;
1235 vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I16);
1236 dst = newVRegI(env);
1237 amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
1238 hregX86_EBP());
1239 addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1240 return dst;
1241 }
1242 }
1243
sewardj4042c7e2004-07-18 01:28:30 +00001244 switch (e->Iex.Unop.op) {
sewardj47341042004-09-19 11:55:46 +00001245 case Iop_8Uto16:
sewardj443cd9d2004-07-18 23:06:45 +00001246 case Iop_8Uto32:
1247 case Iop_16Uto32: {
sewardj4042c7e2004-07-18 01:28:30 +00001248 HReg dst = newVRegI(env);
1249 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
sewardj47341042004-09-19 11:55:46 +00001250 UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF;
sewardjd08f2d72004-12-01 23:19:36 +00001251 addInstr(env, mk_iMOVsd_RR(src,dst) );
sewardj4042c7e2004-07-18 01:28:30 +00001252 addInstr(env, X86Instr_Alu32R(Xalu_AND,
sewardj443cd9d2004-07-18 23:06:45 +00001253 X86RMI_Imm(mask), dst));
1254 return dst;
1255 }
sewardj47341042004-09-19 11:55:46 +00001256 case Iop_8Sto16:
sewardjc22a6fd2004-07-29 23:41:47 +00001257 case Iop_8Sto32:
1258 case Iop_16Sto32: {
1259 HReg dst = newVRegI(env);
1260 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
sewardj47341042004-09-19 11:55:46 +00001261 UInt amt = e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24;
sewardjd08f2d72004-12-01 23:19:36 +00001262 addInstr(env, mk_iMOVsd_RR(src,dst) );
sewardjeba63f82005-02-23 13:31:25 +00001263 addInstr(env, X86Instr_Sh32(Xsh_SHL, amt, dst));
1264 addInstr(env, X86Instr_Sh32(Xsh_SAR, amt, dst));
sewardjc22a6fd2004-07-29 23:41:47 +00001265 return dst;
1266 }
sewardja2384712004-07-29 14:36:40 +00001267 case Iop_Not8:
1268 case Iop_Not16:
sewardj443cd9d2004-07-18 23:06:45 +00001269 case Iop_Not32: {
1270 HReg dst = newVRegI(env);
1271 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
sewardjd08f2d72004-12-01 23:19:36 +00001272 addInstr(env, mk_iMOVsd_RR(src,dst) );
sewardjeba63f82005-02-23 13:31:25 +00001273 addInstr(env, X86Instr_Unary32(Xun_NOT,dst));
sewardj4042c7e2004-07-18 01:28:30 +00001274 return dst;
1275 }
sewardj597b71b2004-07-19 02:51:12 +00001276 case Iop_64HIto32: {
1277 HReg rHi, rLo;
sewardjd08f2d72004-12-01 23:19:36 +00001278 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
sewardj597b71b2004-07-19 02:51:12 +00001279 return rHi; /* and abandon rLo .. poor wee thing :-) */
1280 }
sewardj8c7f1ab2004-07-29 20:31:09 +00001281 case Iop_64to32: {
sewardj597b71b2004-07-19 02:51:12 +00001282 HReg rHi, rLo;
sewardjd08f2d72004-12-01 23:19:36 +00001283 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
sewardj597b71b2004-07-19 02:51:12 +00001284 return rLo; /* similar stupid comment to the above ... */
1285 }
sewardjb81f8b32004-07-30 10:17:50 +00001286 case Iop_16HIto8:
sewardj8c7f1ab2004-07-29 20:31:09 +00001287 case Iop_32HIto16: {
sewardjb81f8b32004-07-30 10:17:50 +00001288 HReg dst = newVRegI(env);
1289 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1290 Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
sewardjd08f2d72004-12-01 23:19:36 +00001291 addInstr(env, mk_iMOVsd_RR(src,dst) );
sewardjeba63f82005-02-23 13:31:25 +00001292 addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, dst));
sewardj8c7f1ab2004-07-29 20:31:09 +00001293 return dst;
1294 }
sewardj84ff0652004-08-23 16:16:08 +00001295 case Iop_1Uto32:
sewardjd7cb8532004-08-17 23:59:23 +00001296 case Iop_1Uto8: {
1297 HReg dst = newVRegI(env);
1298 X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1299 addInstr(env, X86Instr_Set32(cond,dst));
1300 return dst;
1301 }
sewardjfd332772004-11-09 16:01:40 +00001302 case Iop_1Sto8:
sewardj218e29f2004-11-07 18:45:15 +00001303 case Iop_1Sto16:
sewardj415d9352004-11-04 15:20:15 +00001304 case Iop_1Sto32: {
1305 /* could do better than this, but for now ... */
1306 HReg dst = newVRegI(env);
1307 X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1308 addInstr(env, X86Instr_Set32(cond,dst));
sewardjeba63f82005-02-23 13:31:25 +00001309 addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, dst));
1310 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, dst));
sewardj415d9352004-11-04 15:20:15 +00001311 return dst;
1312 }
sewardjce646f22004-08-31 23:55:54 +00001313 case Iop_Ctz32: {
1314 /* Count trailing zeroes, implemented by x86 'bsfl' */
1315 HReg dst = newVRegI(env);
1316 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1317 addInstr(env, X86Instr_Bsfr32(True,src,dst));
1318 return dst;
1319 }
1320 case Iop_Clz32: {
1321 /* Count leading zeroes. Do 'bsrl' to establish the index
1322 of the highest set bit, and subtract that value from
1323 31. */
1324 HReg tmp = newVRegI(env);
1325 HReg dst = newVRegI(env);
1326 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1327 addInstr(env, X86Instr_Bsfr32(False,src,tmp));
1328 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
1329 X86RMI_Imm(31), dst));
1330 addInstr(env, X86Instr_Alu32R(Xalu_SUB,
1331 X86RMI_Reg(tmp), dst));
1332 return dst;
1333 }
sewardjeb17e492007-08-25 23:07:44 +00001334
1335 case Iop_CmpwNEZ32: {
sewardj0f1a4882005-04-26 23:39:45 +00001336 HReg dst = newVRegI(env);
sewardjeb17e492007-08-25 23:07:44 +00001337 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1338 addInstr(env, mk_iMOVsd_RR(src,dst));
sewardj0f1a4882005-04-26 23:39:45 +00001339 addInstr(env, X86Instr_Unary32(Xun_NEG,dst));
sewardjeb17e492007-08-25 23:07:44 +00001340 addInstr(env, X86Instr_Alu32R(Xalu_OR,
1341 X86RMI_Reg(src), dst));
1342 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, dst));
1343 return dst;
1344 }
1345 case Iop_Left8:
1346 case Iop_Left16:
1347 case Iop_Left32: {
1348 HReg dst = newVRegI(env);
1349 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1350 addInstr(env, mk_iMOVsd_RR(src, dst));
1351 addInstr(env, X86Instr_Unary32(Xun_NEG, dst));
1352 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(src), dst));
sewardj0f1a4882005-04-26 23:39:45 +00001353 return dst;
1354 }
sewardj89cd0932004-09-08 18:23:25 +00001355
sewardjf0c1c582005-02-07 23:47:38 +00001356 case Iop_V128to32: {
sewardja0037df2004-12-10 18:56:29 +00001357 HReg dst = newVRegI(env);
1358 HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
1359 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
1360 sub_from_esp(env, 16);
1361 addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
1362 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(esp0), dst ));
1363 add_to_esp(env, 16);
1364 return dst;
1365 }
1366
sewardjfc1b5412007-01-09 15:20:07 +00001367 /* ReinterpF32asI32(e) */
1368 /* Given an IEEE754 single, produce an I32 with the same bit
1369 pattern. Keep stack 8-aligned even though only using 4
1370 bytes. */
1371 case Iop_ReinterpF32asI32: {
1372 HReg rf = iselFltExpr(env, e->Iex.Unop.arg);
1373 HReg dst = newVRegI(env);
1374 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
1375 /* paranoia */
1376 set_FPU_rounding_default(env);
1377 /* subl $8, %esp */
1378 sub_from_esp(env, 8);
1379 /* gstF %rf, 0(%esp) */
1380 addInstr(env,
1381 X86Instr_FpLdSt(False/*store*/, 4, rf, zero_esp));
1382 /* movl 0(%esp), %dst */
1383 addInstr(env,
1384 X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(zero_esp), dst));
1385 /* addl $8, %esp */
1386 add_to_esp(env, 8);
1387 return dst;
1388 }
1389
sewardjb81f8b32004-07-30 10:17:50 +00001390 case Iop_16to8:
sewardja2384712004-07-29 14:36:40 +00001391 case Iop_32to8:
1392 case Iop_32to16:
sewardjb81f8b32004-07-30 10:17:50 +00001393 /* These are no-ops. */
sewardja2384712004-07-29 14:36:40 +00001394 return iselIntExpr_R(env, e->Iex.Unop.arg);
1395
sewardje13074c2012-11-08 10:57:08 +00001396 case Iop_GetMSBs8x8: {
1397 /* Note: the following assumes the helper is of
1398 signature
1399 UInt fn ( ULong ), and is not a regparm fn.
1400 */
1401 HReg xLo, xHi;
1402 HReg dst = newVRegI(env);
1403 HWord fn = (HWord)h_generic_calc_GetMSBs8x8;
1404 iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg);
1405 addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
1406 addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
sewardjcfe046e2013-01-17 14:23:53 +00001407 addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn,
sewardj74142b82013-08-08 10:28:59 +00001408 0, mk_RetLoc_simple(RLPri_Int) ));
sewardje13074c2012-11-08 10:57:08 +00001409 add_to_esp(env, 2*4);
1410 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
1411 return dst;
1412 }
1413
sewardj4042c7e2004-07-18 01:28:30 +00001414 default:
1415 break;
1416 }
1417 break;
1418 }
1419
sewardj60f4e3c2004-07-19 01:56:50 +00001420 /* --------- GET --------- */
sewardje8e9d732004-07-16 21:03:45 +00001421 case Iex_Get: {
1422 if (ty == Ity_I32) {
1423 HReg dst = newVRegI(env);
1424 addInstr(env, X86Instr_Alu32R(
1425 Xalu_MOV,
1426 X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset,
1427 hregX86_EBP())),
1428 dst));
1429 return dst;
sewardjc97096c2004-06-30 09:28:04 +00001430 }
sewardj60f4e3c2004-07-19 01:56:50 +00001431 if (ty == Ity_I8 || ty == Ity_I16) {
sewardj4042c7e2004-07-18 01:28:30 +00001432 HReg dst = newVRegI(env);
1433 addInstr(env, X86Instr_LoadEX(
sewardj428fabd2005-03-21 03:11:17 +00001434 toUChar(ty==Ity_I8 ? 1 : 2),
sewardj60f4e3c2004-07-19 01:56:50 +00001435 False,
sewardj4042c7e2004-07-18 01:28:30 +00001436 X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()),
1437 dst));
1438 return dst;
1439 }
sewardje8e9d732004-07-16 21:03:45 +00001440 break;
sewardjc97096c2004-06-30 09:28:04 +00001441 }
sewardje8e9d732004-07-16 21:03:45 +00001442
sewardj33124f62004-08-30 17:54:18 +00001443 case Iex_GetI: {
sewardj2d3f77c2004-09-22 23:49:09 +00001444 X86AMode* am
1445 = genGuestArrayOffset(
1446 env, e->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00001447 e->Iex.GetI.ix, e->Iex.GetI.bias );
sewardj33124f62004-08-30 17:54:18 +00001448 HReg dst = newVRegI(env);
1449 if (ty == Ity_I8) {
sewardj2d3f77c2004-09-22 23:49:09 +00001450 addInstr(env, X86Instr_LoadEX( 1, False, am, dst ));
sewardj33124f62004-08-30 17:54:18 +00001451 return dst;
1452 }
sewardje12d6442005-05-09 12:16:33 +00001453 if (ty == Ity_I32) {
sewardje12d6442005-05-09 12:16:33 +00001454 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(am), dst));
1455 return dst;
1456 }
sewardj2d3f77c2004-09-22 23:49:09 +00001457 break;
sewardj33124f62004-08-30 17:54:18 +00001458 }
1459
sewardj60f4e3c2004-07-19 01:56:50 +00001460 /* --------- CCALL --------- */
sewardje8e9d732004-07-16 21:03:45 +00001461 case Iex_CCall: {
sewardjd18d1bf2004-08-25 12:49:22 +00001462 HReg dst = newVRegI(env);
sewardjf73b94a2005-02-04 21:14:52 +00001463 vassert(ty == e->Iex.CCall.retty);
sewardjc4be80c2004-09-10 16:17:45 +00001464
sewardjcfe046e2013-01-17 14:23:53 +00001465 /* be very restrictive for now. Only 32/64-bit ints allowed for
1466 args, and 32 bits for return type. Don't forget to change
1467 the RetLoc if more return types are allowed in future. */
sewardj4042c7e2004-07-18 01:28:30 +00001468 if (e->Iex.CCall.retty != Ity_I32)
sewardjd18d1bf2004-08-25 12:49:22 +00001469 goto irreducible;
sewardjc4be80c2004-09-10 16:17:45 +00001470
sewardj77352542004-10-30 20:39:01 +00001471 /* Marshal args, do the call, clear stack. */
sewardj74142b82013-08-08 10:28:59 +00001472 UInt addToSp = 0;
1473 RetLoc rloc = mk_RetLoc_INVALID();
1474 doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
1475 e->Iex.CCall.cee, e->Iex.CCall.retty, e->Iex.CCall.args );
1476 vassert(is_sane_RetLoc(rloc));
1477 vassert(rloc.pri == RLPri_Int);
1478 vassert(addToSp == 0);
sewardj17442fe2004-09-20 14:54:28 +00001479
sewardjd08f2d72004-12-01 23:19:36 +00001480 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
sewardjd18d1bf2004-08-25 12:49:22 +00001481 return dst;
sewardje8e9d732004-07-16 21:03:45 +00001482 }
1483
sewardj60f4e3c2004-07-19 01:56:50 +00001484 /* --------- LITERAL --------- */
sewardje8e9d732004-07-16 21:03:45 +00001485 /* 32/16/8-bit literals */
1486 case Iex_Const: {
sewardj4042c7e2004-07-18 01:28:30 +00001487 X86RMI* rmi = iselIntExpr_RMI ( env, e );
1488 HReg r = newVRegI(env);
1489 addInstr(env, X86Instr_Alu32R(Xalu_MOV, rmi, r));
sewardje8e9d732004-07-16 21:03:45 +00001490 return r;
1491 }
sewardjc97096c2004-06-30 09:28:04 +00001492
sewardj60f4e3c2004-07-19 01:56:50 +00001493 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00001494 case Iex_ITE: { // VFD
sewardjc744e872004-08-26 11:24:39 +00001495 if ((ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8)
florian99dd03e2013-01-29 03:56:06 +00001496 && typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
1497 HReg r1 = iselIntExpr_R(env, e->Iex.ITE.iftrue);
1498 X86RM* r0 = iselIntExpr_RM(env, e->Iex.ITE.iffalse);
sewardjfb7373a2007-08-25 21:29:03 +00001499 HReg dst = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00001500 addInstr(env, mk_iMOVsd_RR(r1,dst));
1501 X86CondCode cc = iselCondCode(env, e->Iex.ITE.cond);
sewardj009230b2013-01-26 11:47:55 +00001502 addInstr(env, X86Instr_CMov32(cc ^ 1, r0, dst));
sewardj38ff3d82004-07-26 23:27:08 +00001503 return dst;
sewardj4042c7e2004-07-18 01:28:30 +00001504 }
1505 break;
1506 }
1507
sewardjc97096c2004-06-30 09:28:04 +00001508 default:
1509 break;
1510 } /* switch (e->tag) */
1511
1512 /* We get here if no pattern matched. */
sewardje8e9d732004-07-16 21:03:45 +00001513 irreducible:
sewardj35421a32004-07-05 13:12:34 +00001514 ppIRExpr(e);
sewardjd9c2b792004-07-08 01:44:38 +00001515 vpanic("iselIntExpr_R: cannot reduce tree");
sewardjc97096c2004-06-30 09:28:04 +00001516}
1517
1518
sewardj66f2f792004-06-30 16:37:16 +00001519/*---------------------------------------------------------*/
1520/*--- ISEL: Integer expression auxiliaries ---*/
1521/*---------------------------------------------------------*/
1522
sewardjd18d1bf2004-08-25 12:49:22 +00001523/* --------------------- AMODEs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001524
sewardj66f2f792004-06-30 16:37:16 +00001525/* Return an AMode which computes the value of the specified
1526 expression, possibly also adding insns to the code list as a
sewardj4042c7e2004-07-18 01:28:30 +00001527 result. The expression may only be a 32-bit one.
sewardjc97096c2004-06-30 09:28:04 +00001528*/
sewardjd18d1bf2004-08-25 12:49:22 +00001529
1530static Bool sane_AMode ( X86AMode* am )
1531{
1532 switch (am->tag) {
1533 case Xam_IR:
sewardj428fabd2005-03-21 03:11:17 +00001534 return
1535 toBool( hregClass(am->Xam.IR.reg) == HRcInt32
1536 && (hregIsVirtual(am->Xam.IR.reg)
florian79efdc62013-02-11 00:47:35 +00001537 || sameHReg(am->Xam.IR.reg, hregX86_EBP())) );
sewardjd18d1bf2004-08-25 12:49:22 +00001538 case Xam_IRRS:
sewardj428fabd2005-03-21 03:11:17 +00001539 return
1540 toBool( hregClass(am->Xam.IRRS.base) == HRcInt32
1541 && hregIsVirtual(am->Xam.IRRS.base)
1542 && hregClass(am->Xam.IRRS.index) == HRcInt32
1543 && hregIsVirtual(am->Xam.IRRS.index) );
sewardjd18d1bf2004-08-25 12:49:22 +00001544 default:
1545 vpanic("sane_AMode: unknown x86 amode tag");
1546 }
1547}
1548
sewardj66f2f792004-06-30 16:37:16 +00001549static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e )
sewardjc97096c2004-06-30 09:28:04 +00001550{
sewardjd18d1bf2004-08-25 12:49:22 +00001551 X86AMode* am = iselIntExpr_AMode_wrk(env, e);
1552 vassert(sane_AMode(am));
1553 return am;
1554}
1555
1556/* DO NOT CALL THIS DIRECTLY ! */
1557static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e )
1558{
sewardj4042c7e2004-07-18 01:28:30 +00001559 IRType ty = typeOfIRExpr(env->type_env,e);
1560 vassert(ty == Ity_I32);
sewardjc97096c2004-06-30 09:28:04 +00001561
sewardj79e04f82007-03-31 14:30:12 +00001562 /* Add32( Add32(expr1, Shl32(expr2, simm)), imm32 ) */
1563 if (e->tag == Iex_Binop
1564 && e->Iex.Binop.op == Iop_Add32
1565 && e->Iex.Binop.arg2->tag == Iex_Const
1566 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
1567 && e->Iex.Binop.arg1->tag == Iex_Binop
1568 && e->Iex.Binop.arg1->Iex.Binop.op == Iop_Add32
1569 && e->Iex.Binop.arg1->Iex.Binop.arg2->tag == Iex_Binop
1570 && e->Iex.Binop.arg1->Iex.Binop.arg2->Iex.Binop.op == Iop_Shl32
1571 && e->Iex.Binop.arg1
1572 ->Iex.Binop.arg2->Iex.Binop.arg2->tag == Iex_Const
1573 && e->Iex.Binop.arg1
1574 ->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8) {
1575 UInt shift = e->Iex.Binop.arg1
1576 ->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
1577 UInt imm32 = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
1578 if (shift == 1 || shift == 2 || shift == 3) {
1579 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1->Iex.Binop.arg1);
1580 HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg1
1581 ->Iex.Binop.arg2->Iex.Binop.arg1 );
1582 return X86AMode_IRRS(imm32, r1, r2, shift);
1583 }
1584 }
1585
sewardjc97096c2004-06-30 09:28:04 +00001586 /* Add32(expr1, Shl32(expr2, imm)) */
1587 if (e->tag == Iex_Binop
1588 && e->Iex.Binop.op == Iop_Add32
1589 && e->Iex.Binop.arg2->tag == Iex_Binop
1590 && e->Iex.Binop.arg2->Iex.Binop.op == Iop_Shl32
1591 && e->Iex.Binop.arg2->Iex.Binop.arg2->tag == Iex_Const
sewardjd18d1bf2004-08-25 12:49:22 +00001592 && e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8) {
1593 UInt shift = e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
1594 if (shift == 1 || shift == 2 || shift == 3) {
sewardj66f2f792004-06-30 16:37:16 +00001595 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1596 HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg2->Iex.Binop.arg1 );
sewardjc97096c2004-06-30 09:28:04 +00001597 return X86AMode_IRRS(0, r1, r2, shift);
1598 }
1599 }
1600
1601 /* Add32(expr,i) */
1602 if (e->tag == Iex_Binop
1603 && e->Iex.Binop.op == Iop_Add32
1604 && e->Iex.Binop.arg2->tag == Iex_Const
1605 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
sewardj66f2f792004-06-30 16:37:16 +00001606 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardjd9c2b792004-07-08 01:44:38 +00001607 return X86AMode_IR(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, r1);
sewardjc97096c2004-06-30 09:28:04 +00001608 }
1609
1610 /* Doesn't match anything in particular. Generate it into
1611 a register and use that. */
1612 {
sewardj66f2f792004-06-30 16:37:16 +00001613 HReg r1 = iselIntExpr_R(env, e);
sewardjd9c2b792004-07-08 01:44:38 +00001614 return X86AMode_IR(0, r1);
sewardjc97096c2004-06-30 09:28:04 +00001615 }
1616}
1617
1618
sewardjd18d1bf2004-08-25 12:49:22 +00001619/* --------------------- RMIs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001620
sewardj4042c7e2004-07-18 01:28:30 +00001621/* Similarly, calculate an expression into an X86RMI operand. As with
1622 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
sewardj66f2f792004-06-30 16:37:16 +00001623
1624static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e )
1625{
sewardjd18d1bf2004-08-25 12:49:22 +00001626 X86RMI* rmi = iselIntExpr_RMI_wrk(env, e);
1627 /* sanity checks ... */
1628 switch (rmi->tag) {
1629 case Xrmi_Imm:
1630 return rmi;
1631 case Xrmi_Reg:
sewardj4a31b262004-12-01 02:24:44 +00001632 vassert(hregClass(rmi->Xrmi.Reg.reg) == HRcInt32);
sewardjd18d1bf2004-08-25 12:49:22 +00001633 vassert(hregIsVirtual(rmi->Xrmi.Reg.reg));
1634 return rmi;
1635 case Xrmi_Mem:
1636 vassert(sane_AMode(rmi->Xrmi.Mem.am));
1637 return rmi;
1638 default:
1639 vpanic("iselIntExpr_RMI: unknown x86 RMI tag");
1640 }
1641}
1642
1643/* DO NOT CALL THIS DIRECTLY ! */
1644static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e )
1645{
sewardj4042c7e2004-07-18 01:28:30 +00001646 IRType ty = typeOfIRExpr(env->type_env,e);
1647 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardj66f2f792004-06-30 16:37:16 +00001648
1649 /* special case: immediate */
sewardj4042c7e2004-07-18 01:28:30 +00001650 if (e->tag == Iex_Const) {
1651 UInt u;
1652 switch (e->Iex.Const.con->tag) {
1653 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
1654 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
1655 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
1656 default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)");
1657 }
1658 return X86RMI_Imm(u);
sewardj66f2f792004-06-30 16:37:16 +00001659 }
1660
sewardje8e9d732004-07-16 21:03:45 +00001661 /* special case: 32-bit GET */
sewardj4042c7e2004-07-18 01:28:30 +00001662 if (e->tag == Iex_Get && ty == Ity_I32) {
sewardje8e9d732004-07-16 21:03:45 +00001663 return X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset,
1664 hregX86_EBP()));
1665 }
1666
sewardjeba63f82005-02-23 13:31:25 +00001667 /* special case: 32-bit load from memory */
sewardje9d8a262009-07-01 08:06:34 +00001668 if (e->tag == Iex_Load && ty == Ity_I32
sewardje768e922009-11-26 17:17:37 +00001669 && e->Iex.Load.end == Iend_LE) {
sewardjaf1ceca2005-06-30 23:31:27 +00001670 X86AMode* am = iselIntExpr_AMode(env, e->Iex.Load.addr);
sewardjeba63f82005-02-23 13:31:25 +00001671 return X86RMI_Mem(am);
1672 }
sewardj66f2f792004-06-30 16:37:16 +00001673
1674 /* default case: calculate into a register and return that */
1675 {
1676 HReg r = iselIntExpr_R ( env, e );
1677 return X86RMI_Reg(r);
1678 }
1679}
1680
1681
sewardjd18d1bf2004-08-25 12:49:22 +00001682/* --------------------- RIs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001683
sewardj4042c7e2004-07-18 01:28:30 +00001684/* Calculate an expression into an X86RI operand. As with
1685 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
sewardj66f2f792004-06-30 16:37:16 +00001686
1687static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e )
1688{
sewardjd18d1bf2004-08-25 12:49:22 +00001689 X86RI* ri = iselIntExpr_RI_wrk(env, e);
1690 /* sanity checks ... */
1691 switch (ri->tag) {
1692 case Xri_Imm:
1693 return ri;
sewardj80d6e6d2008-05-28 09:40:29 +00001694 case Xri_Reg:
sewardj4a31b262004-12-01 02:24:44 +00001695 vassert(hregClass(ri->Xri.Reg.reg) == HRcInt32);
sewardjd18d1bf2004-08-25 12:49:22 +00001696 vassert(hregIsVirtual(ri->Xri.Reg.reg));
1697 return ri;
1698 default:
1699 vpanic("iselIntExpr_RI: unknown x86 RI tag");
1700 }
1701}
1702
1703/* DO NOT CALL THIS DIRECTLY ! */
1704static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
1705{
sewardj4042c7e2004-07-18 01:28:30 +00001706 IRType ty = typeOfIRExpr(env->type_env,e);
1707 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardj66f2f792004-06-30 16:37:16 +00001708
1709 /* special case: immediate */
sewardj4042c7e2004-07-18 01:28:30 +00001710 if (e->tag == Iex_Const) {
1711 UInt u;
1712 switch (e->Iex.Const.con->tag) {
1713 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
1714 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
1715 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
1716 default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)");
1717 }
1718 return X86RI_Imm(u);
sewardj66f2f792004-06-30 16:37:16 +00001719 }
1720
1721 /* default case: calculate into a register and return that */
1722 {
1723 HReg r = iselIntExpr_R ( env, e );
1724 return X86RI_Reg(r);
1725 }
1726}
1727
1728
sewardjd18d1bf2004-08-25 12:49:22 +00001729/* --------------------- RMs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001730
sewardj4042c7e2004-07-18 01:28:30 +00001731/* Similarly, calculate an expression into an X86RM operand. As with
1732 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
1733
1734static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e )
1735{
sewardjd18d1bf2004-08-25 12:49:22 +00001736 X86RM* rm = iselIntExpr_RM_wrk(env, e);
1737 /* sanity checks ... */
1738 switch (rm->tag) {
1739 case Xrm_Reg:
sewardj4a31b262004-12-01 02:24:44 +00001740 vassert(hregClass(rm->Xrm.Reg.reg) == HRcInt32);
sewardjd18d1bf2004-08-25 12:49:22 +00001741 vassert(hregIsVirtual(rm->Xrm.Reg.reg));
1742 return rm;
1743 case Xrm_Mem:
1744 vassert(sane_AMode(rm->Xrm.Mem.am));
1745 return rm;
1746 default:
1747 vpanic("iselIntExpr_RM: unknown x86 RM tag");
1748 }
1749}
1750
1751/* DO NOT CALL THIS DIRECTLY ! */
1752static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e )
1753{
sewardj4042c7e2004-07-18 01:28:30 +00001754 IRType ty = typeOfIRExpr(env->type_env,e);
1755 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
1756
1757 /* special case: 32-bit GET */
1758 if (e->tag == Iex_Get && ty == Ity_I32) {
1759 return X86RM_Mem(X86AMode_IR(e->Iex.Get.offset,
1760 hregX86_EBP()));
1761 }
1762
1763 /* special case: load from memory */
1764
1765 /* default case: calculate into a register and return that */
1766 {
1767 HReg r = iselIntExpr_R ( env, e );
1768 return X86RM_Reg(r);
1769 }
1770}
1771
1772
sewardjd18d1bf2004-08-25 12:49:22 +00001773/* --------------------- CONDCODE --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001774
sewardj443cd9d2004-07-18 23:06:45 +00001775/* Generate code to evaluated a bit-typed expression, returning the
1776 condition code which would correspond when the expression would
1777 notionally have returned 1. */
1778
1779static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
1780{
sewardjd18d1bf2004-08-25 12:49:22 +00001781 /* Uh, there's nothing we can sanity check here, unfortunately. */
1782 return iselCondCode_wrk(env,e);
1783}
1784
1785/* DO NOT CALL THIS DIRECTLY ! */
1786static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
1787{
sewardj443cd9d2004-07-18 23:06:45 +00001788 MatchInfo mi;
sewardj443cd9d2004-07-18 23:06:45 +00001789
1790 vassert(e);
sewardjba999312004-11-15 15:21:17 +00001791 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
sewardj443cd9d2004-07-18 23:06:45 +00001792
sewardj0f1a4882005-04-26 23:39:45 +00001793 /* var */
sewardjdd40fdf2006-12-24 02:20:24 +00001794 if (e->tag == Iex_RdTmp) {
1795 HReg r32 = lookupIRTemp(env, e->Iex.RdTmp.tmp);
sewardj8ac39e42005-05-02 16:16:15 +00001796 /* Test32 doesn't modify r32; so this is OK. */
sewardjfb7373a2007-08-25 21:29:03 +00001797 addInstr(env, X86Instr_Test32(1,X86RM_Reg(r32)));
sewardj0f1a4882005-04-26 23:39:45 +00001798 return Xcc_NZ;
1799 }
1800
sewardj0dc3ff92004-10-16 11:31:31 +00001801 /* Constant 1:Bit */
sewardjd45b4462005-07-18 13:54:49 +00001802 if (e->tag == Iex_Const) {
sewardj8fc93742004-11-22 11:29:33 +00001803 HReg r;
sewardjba999312004-11-15 15:21:17 +00001804 vassert(e->Iex.Const.con->tag == Ico_U1);
sewardjd45b4462005-07-18 13:54:49 +00001805 vassert(e->Iex.Const.con->Ico.U1 == True
1806 || e->Iex.Const.con->Ico.U1 == False);
sewardj8fc93742004-11-22 11:29:33 +00001807 r = newVRegI(env);
sewardj0dc3ff92004-10-16 11:31:31 +00001808 addInstr(env, X86Instr_Alu32R(Xalu_MOV,X86RMI_Imm(0),r));
1809 addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(r),r));
sewardjd45b4462005-07-18 13:54:49 +00001810 return e->Iex.Const.con->Ico.U1 ? Xcc_Z : Xcc_NZ;
sewardj0dc3ff92004-10-16 11:31:31 +00001811 }
1812
sewardj0f1a4882005-04-26 23:39:45 +00001813 /* Not1(e) */
sewardj6e797c52004-10-13 15:20:17 +00001814 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
1815 /* Generate code for the arg, and negate the test condition */
1816 return 1 ^ iselCondCode(env, e->Iex.Unop.arg);
1817 }
1818
sewardj0f1a4882005-04-26 23:39:45 +00001819 /* --- patterns rooted at: 32to1 --- */
1820
sewardjeb17e492007-08-25 23:07:44 +00001821 if (e->tag == Iex_Unop
1822 && e->Iex.Unop.op == Iop_32to1) {
1823 X86RM* rm = iselIntExpr_RM(env, e->Iex.Unop.arg);
sewardjfb7373a2007-08-25 21:29:03 +00001824 addInstr(env, X86Instr_Test32(1,rm));
sewardj443cd9d2004-07-18 23:06:45 +00001825 return Xcc_NZ;
1826 }
1827
sewardj0f1a4882005-04-26 23:39:45 +00001828 /* --- patterns rooted at: CmpNEZ8 --- */
1829
1830 /* CmpNEZ8(x) */
1831 if (e->tag == Iex_Unop
1832 && e->Iex.Unop.op == Iop_CmpNEZ8) {
sewardjfb7373a2007-08-25 21:29:03 +00001833 X86RM* rm = iselIntExpr_RM(env, e->Iex.Unop.arg);
1834 addInstr(env, X86Instr_Test32(0xFF,rm));
sewardj0f1a4882005-04-26 23:39:45 +00001835 return Xcc_NZ;
1836 }
1837
1838 /* --- patterns rooted at: CmpNEZ16 --- */
1839
1840 /* CmpNEZ16(x) */
1841 if (e->tag == Iex_Unop
1842 && e->Iex.Unop.op == Iop_CmpNEZ16) {
sewardjfb7373a2007-08-25 21:29:03 +00001843 X86RM* rm = iselIntExpr_RM(env, e->Iex.Unop.arg);
1844 addInstr(env, X86Instr_Test32(0xFFFF,rm));
sewardj0f1a4882005-04-26 23:39:45 +00001845 return Xcc_NZ;
1846 }
1847
1848 /* --- patterns rooted at: CmpNEZ32 --- */
1849
sewardj0f1a4882005-04-26 23:39:45 +00001850 /* CmpNEZ32(And32(x,y)) */
1851 {
1852 DECLARE_PATTERN(p_CmpNEZ32_And32);
1853 DEFINE_PATTERN(p_CmpNEZ32_And32,
1854 unop(Iop_CmpNEZ32, binop(Iop_And32, bind(0), bind(1))));
1855 if (matchIRExpr(&mi, p_CmpNEZ32_And32, e)) {
1856 HReg r0 = iselIntExpr_R(env, mi.bindee[0]);
1857 X86RMI* rmi1 = iselIntExpr_RMI(env, mi.bindee[1]);
sewardj4a64fee2005-05-03 09:09:27 +00001858 HReg tmp = newVRegI(env);
sewardj0f1a4882005-04-26 23:39:45 +00001859 addInstr(env, mk_iMOVsd_RR(r0, tmp));
1860 addInstr(env, X86Instr_Alu32R(Xalu_AND,rmi1,tmp));
1861 return Xcc_NZ;
1862 }
1863 }
1864
1865 /* CmpNEZ32(Or32(x,y)) */
1866 {
1867 DECLARE_PATTERN(p_CmpNEZ32_Or32);
1868 DEFINE_PATTERN(p_CmpNEZ32_Or32,
1869 unop(Iop_CmpNEZ32, binop(Iop_Or32, bind(0), bind(1))));
1870 if (matchIRExpr(&mi, p_CmpNEZ32_Or32, e)) {
1871 HReg r0 = iselIntExpr_R(env, mi.bindee[0]);
1872 X86RMI* rmi1 = iselIntExpr_RMI(env, mi.bindee[1]);
sewardj4a64fee2005-05-03 09:09:27 +00001873 HReg tmp = newVRegI(env);
sewardj0f1a4882005-04-26 23:39:45 +00001874 addInstr(env, mk_iMOVsd_RR(r0, tmp));
1875 addInstr(env, X86Instr_Alu32R(Xalu_OR,rmi1,tmp));
1876 return Xcc_NZ;
1877 }
1878 }
sewardj4a64fee2005-05-03 09:09:27 +00001879
sewardjeb17e492007-08-25 23:07:44 +00001880 /* CmpNEZ32(GET(..):I32) */
1881 if (e->tag == Iex_Unop
1882 && e->Iex.Unop.op == Iop_CmpNEZ32
1883 && e->Iex.Unop.arg->tag == Iex_Get) {
1884 X86AMode* am = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
1885 hregX86_EBP());
1886 addInstr(env, X86Instr_Alu32M(Xalu_CMP, X86RI_Imm(0), am));
1887 return Xcc_NZ;
1888 }
1889
sewardj0f1a4882005-04-26 23:39:45 +00001890 /* CmpNEZ32(x) */
1891 if (e->tag == Iex_Unop
1892 && e->Iex.Unop.op == Iop_CmpNEZ32) {
1893 HReg r1 = iselIntExpr_R(env, e->Iex.Unop.arg);
1894 X86RMI* rmi2 = X86RMI_Imm(0);
1895 addInstr(env, X86Instr_Alu32R(Xalu_CMP,rmi2,r1));
1896 return Xcc_NZ;
1897 }
1898
1899 /* --- patterns rooted at: CmpNEZ64 --- */
1900
sewardj4a64fee2005-05-03 09:09:27 +00001901 /* CmpNEZ64(Or64(x,y)) */
1902 {
1903 DECLARE_PATTERN(p_CmpNEZ64_Or64);
1904 DEFINE_PATTERN(p_CmpNEZ64_Or64,
1905 unop(Iop_CmpNEZ64, binop(Iop_Or64, bind(0), bind(1))));
1906 if (matchIRExpr(&mi, p_CmpNEZ64_Or64, e)) {
1907 HReg hi1, lo1, hi2, lo2;
1908 HReg tmp = newVRegI(env);
1909 iselInt64Expr( &hi1, &lo1, env, mi.bindee[0] );
1910 addInstr(env, mk_iMOVsd_RR(hi1, tmp));
1911 addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(lo1),tmp));
1912 iselInt64Expr( &hi2, &lo2, env, mi.bindee[1] );
1913 addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(hi2),tmp));
1914 addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(lo2),tmp));
1915 return Xcc_NZ;
1916 }
1917 }
1918
sewardj0f1a4882005-04-26 23:39:45 +00001919 /* CmpNEZ64(x) */
1920 if (e->tag == Iex_Unop
1921 && e->Iex.Unop.op == Iop_CmpNEZ64) {
1922 HReg hi, lo;
1923 HReg tmp = newVRegI(env);
1924 iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg );
1925 addInstr(env, mk_iMOVsd_RR(hi, tmp));
1926 addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(lo), tmp));
1927 return Xcc_NZ;
1928 }
1929
1930 /* --- patterns rooted at: Cmp{EQ,NE}{8,16} --- */
1931
sewardjb9c5cf62004-08-24 15:10:38 +00001932 /* CmpEQ8 / CmpNE8 */
sewardj84ff0652004-08-23 16:16:08 +00001933 if (e->tag == Iex_Binop
sewardjb9c5cf62004-08-24 15:10:38 +00001934 && (e->Iex.Binop.op == Iop_CmpEQ8
sewardj1fb8c922009-07-12 12:56:53 +00001935 || e->Iex.Binop.op == Iop_CmpNE8
1936 || e->Iex.Binop.op == Iop_CasCmpEQ8
1937 || e->Iex.Binop.op == Iop_CasCmpNE8)) {
sewardjfb7373a2007-08-25 21:29:03 +00001938 if (isZeroU8(e->Iex.Binop.arg2)) {
1939 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1940 addInstr(env, X86Instr_Test32(0xFF,X86RM_Reg(r1)));
1941 switch (e->Iex.Binop.op) {
sewardj1fb8c922009-07-12 12:56:53 +00001942 case Iop_CmpEQ8: case Iop_CasCmpEQ8: return Xcc_Z;
1943 case Iop_CmpNE8: case Iop_CasCmpNE8: return Xcc_NZ;
sewardjfb7373a2007-08-25 21:29:03 +00001944 default: vpanic("iselCondCode(x86): CmpXX8(expr,0:I8)");
1945 }
1946 } else {
1947 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1948 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1949 HReg r = newVRegI(env);
1950 addInstr(env, mk_iMOVsd_RR(r1,r));
1951 addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r));
1952 addInstr(env, X86Instr_Test32(0xFF,X86RM_Reg(r)));
1953 switch (e->Iex.Binop.op) {
sewardj1fb8c922009-07-12 12:56:53 +00001954 case Iop_CmpEQ8: case Iop_CasCmpEQ8: return Xcc_Z;
1955 case Iop_CmpNE8: case Iop_CasCmpNE8: return Xcc_NZ;
sewardjfb7373a2007-08-25 21:29:03 +00001956 default: vpanic("iselCondCode(x86): CmpXX8(expr,expr)");
1957 }
sewardjb9c5cf62004-08-24 15:10:38 +00001958 }
1959 }
1960
1961 /* CmpEQ16 / CmpNE16 */
1962 if (e->tag == Iex_Binop
1963 && (e->Iex.Binop.op == Iop_CmpEQ16
sewardj1fb8c922009-07-12 12:56:53 +00001964 || e->Iex.Binop.op == Iop_CmpNE16
1965 || e->Iex.Binop.op == Iop_CasCmpEQ16
sewardje13074c2012-11-08 10:57:08 +00001966 || e->Iex.Binop.op == Iop_CasCmpNE16
1967 || e->Iex.Binop.op == Iop_ExpCmpNE16)) {
sewardjb9c5cf62004-08-24 15:10:38 +00001968 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1969 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1970 HReg r = newVRegI(env);
sewardjd08f2d72004-12-01 23:19:36 +00001971 addInstr(env, mk_iMOVsd_RR(r1,r));
sewardjb9c5cf62004-08-24 15:10:38 +00001972 addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r));
sewardjfb7373a2007-08-25 21:29:03 +00001973 addInstr(env, X86Instr_Test32(0xFFFF,X86RM_Reg(r)));
sewardjb9c5cf62004-08-24 15:10:38 +00001974 switch (e->Iex.Binop.op) {
sewardje13074c2012-11-08 10:57:08 +00001975 case Iop_CmpEQ16: case Iop_CasCmpEQ16:
1976 return Xcc_Z;
1977 case Iop_CmpNE16: case Iop_CasCmpNE16: case Iop_ExpCmpNE16:
1978 return Xcc_NZ;
1979 default:
1980 vpanic("iselCondCode(x86): CmpXX16");
sewardjb9c5cf62004-08-24 15:10:38 +00001981 }
1982 }
1983
sewardj50d89bf2011-01-10 15:10:48 +00001984 /* CmpNE32(ccall, 32-bit constant) (--smc-check=all optimisation).
1985 Saves a "movl %eax, %tmp" compared to the default route. */
1986 if (e->tag == Iex_Binop
1987 && e->Iex.Binop.op == Iop_CmpNE32
1988 && e->Iex.Binop.arg1->tag == Iex_CCall
1989 && e->Iex.Binop.arg2->tag == Iex_Const) {
1990 IRExpr* cal = e->Iex.Binop.arg1;
1991 IRExpr* con = e->Iex.Binop.arg2;
1992 /* clone & partial-eval of generic Iex_CCall and Iex_Const cases */
1993 vassert(cal->Iex.CCall.retty == Ity_I32); /* else ill-typed IR */
1994 vassert(con->Iex.Const.con->tag == Ico_U32);
1995 /* Marshal args, do the call. */
sewardj74142b82013-08-08 10:28:59 +00001996 UInt addToSp = 0;
1997 RetLoc rloc = mk_RetLoc_INVALID();
1998 doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
1999 cal->Iex.CCall.cee,
2000 cal->Iex.CCall.retty, cal->Iex.CCall.args );
2001 vassert(is_sane_RetLoc(rloc));
2002 vassert(rloc.pri == RLPri_Int);
2003 vassert(addToSp == 0);
2004 /* */
sewardj50d89bf2011-01-10 15:10:48 +00002005 addInstr(env, X86Instr_Alu32R(Xalu_CMP,
2006 X86RMI_Imm(con->Iex.Const.con->Ico.U32),
2007 hregX86_EAX()));
2008 return Xcc_NZ;
2009 }
2010
sewardjb9c5cf62004-08-24 15:10:38 +00002011 /* Cmp*32*(x,y) */
2012 if (e->tag == Iex_Binop
2013 && (e->Iex.Binop.op == Iop_CmpEQ32
2014 || e->Iex.Binop.op == Iop_CmpNE32
2015 || e->Iex.Binop.op == Iop_CmpLT32S
sewardj84ff0652004-08-23 16:16:08 +00002016 || e->Iex.Binop.op == Iop_CmpLT32U
2017 || e->Iex.Binop.op == Iop_CmpLE32S
sewardj1fb8c922009-07-12 12:56:53 +00002018 || e->Iex.Binop.op == Iop_CmpLE32U
2019 || e->Iex.Binop.op == Iop_CasCmpEQ32
sewardje13074c2012-11-08 10:57:08 +00002020 || e->Iex.Binop.op == Iop_CasCmpNE32
2021 || e->Iex.Binop.op == Iop_ExpCmpNE32)) {
sewardjb9c5cf62004-08-24 15:10:38 +00002022 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardj84ff0652004-08-23 16:16:08 +00002023 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
2024 addInstr(env, X86Instr_Alu32R(Xalu_CMP,rmi2,r1));
2025 switch (e->Iex.Binop.op) {
sewardj1fb8c922009-07-12 12:56:53 +00002026 case Iop_CmpEQ32: case Iop_CasCmpEQ32: return Xcc_Z;
sewardje13074c2012-11-08 10:57:08 +00002027 case Iop_CmpNE32:
2028 case Iop_CasCmpNE32: case Iop_ExpCmpNE32: return Xcc_NZ;
sewardj84ff0652004-08-23 16:16:08 +00002029 case Iop_CmpLT32S: return Xcc_L;
2030 case Iop_CmpLT32U: return Xcc_B;
2031 case Iop_CmpLE32S: return Xcc_LE;
2032 case Iop_CmpLE32U: return Xcc_BE;
sewardjb9c5cf62004-08-24 15:10:38 +00002033 default: vpanic("iselCondCode(x86): CmpXX32");
sewardj84ff0652004-08-23 16:16:08 +00002034 }
2035 }
2036
sewardjb5874aa2004-11-04 16:57:50 +00002037 /* CmpNE64 */
2038 if (e->tag == Iex_Binop
sewardj300bb872005-08-12 23:04:48 +00002039 && (e->Iex.Binop.op == Iop_CmpNE64
2040 || e->Iex.Binop.op == Iop_CmpEQ64)) {
sewardjb5874aa2004-11-04 16:57:50 +00002041 HReg hi1, hi2, lo1, lo2;
2042 HReg tHi = newVRegI(env);
2043 HReg tLo = newVRegI(env);
sewardjd08f2d72004-12-01 23:19:36 +00002044 iselInt64Expr( &hi1, &lo1, env, e->Iex.Binop.arg1 );
2045 iselInt64Expr( &hi2, &lo2, env, e->Iex.Binop.arg2 );
2046 addInstr(env, mk_iMOVsd_RR(hi1, tHi));
sewardjb5874aa2004-11-04 16:57:50 +00002047 addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(hi2), tHi));
sewardjd08f2d72004-12-01 23:19:36 +00002048 addInstr(env, mk_iMOVsd_RR(lo1, tLo));
sewardjb5874aa2004-11-04 16:57:50 +00002049 addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(lo2), tLo));
2050 addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(tHi), tLo));
2051 switch (e->Iex.Binop.op) {
sewardj1fb8c922009-07-12 12:56:53 +00002052 case Iop_CmpNE64: return Xcc_NZ;
2053 case Iop_CmpEQ64: return Xcc_Z;
sewardjb5874aa2004-11-04 16:57:50 +00002054 default: vpanic("iselCondCode(x86): CmpXX64");
2055 }
2056 }
2057
sewardj443cd9d2004-07-18 23:06:45 +00002058 ppIRExpr(e);
2059 vpanic("iselCondCode");
2060}
2061
2062
sewardj597b71b2004-07-19 02:51:12 +00002063/*---------------------------------------------------------*/
2064/*--- ISEL: Integer expressions (64 bit) ---*/
2065/*---------------------------------------------------------*/
2066
2067/* Compute a 64-bit value into a register pair, which is returned as
2068 the first two parameters. As with iselIntExpr_R, these may be
2069 either real or virtual regs; in any case they must not be changed
2070 by subsequent code emitted by the caller. */
2071
sewardjd08f2d72004-12-01 23:19:36 +00002072static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
sewardj597b71b2004-07-19 02:51:12 +00002073{
sewardjd08f2d72004-12-01 23:19:36 +00002074 iselInt64Expr_wrk(rHi, rLo, env, e);
sewardjd18d1bf2004-08-25 12:49:22 +00002075# if 0
2076 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2077# endif
sewardj4a31b262004-12-01 02:24:44 +00002078 vassert(hregClass(*rHi) == HRcInt32);
sewardjd18d1bf2004-08-25 12:49:22 +00002079 vassert(hregIsVirtual(*rHi));
sewardj4a31b262004-12-01 02:24:44 +00002080 vassert(hregClass(*rLo) == HRcInt32);
sewardjd18d1bf2004-08-25 12:49:22 +00002081 vassert(hregIsVirtual(*rLo));
2082}
2083
2084/* DO NOT CALL THIS DIRECTLY ! */
sewardjd08f2d72004-12-01 23:19:36 +00002085static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
sewardjd18d1bf2004-08-25 12:49:22 +00002086{
sewardjeb17e492007-08-25 23:07:44 +00002087 MatchInfo mi;
sewardj38a3f862005-01-13 15:06:51 +00002088 HWord fn = 0; /* helper fn for most SIMD64 stuff */
sewardj597b71b2004-07-19 02:51:12 +00002089 vassert(e);
2090 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
2091
sewardj38a3f862005-01-13 15:06:51 +00002092 /* 64-bit literal */
sewardjc09278c2004-08-19 17:15:49 +00002093 if (e->tag == Iex_Const) {
2094 ULong w64 = e->Iex.Const.con->Ico.U64;
sewardj428fabd2005-03-21 03:11:17 +00002095 UInt wHi = toUInt(w64 >> 32);
2096 UInt wLo = toUInt(w64);
sewardjc09278c2004-08-19 17:15:49 +00002097 HReg tLo = newVRegI(env);
2098 HReg tHi = newVRegI(env);
2099 vassert(e->Iex.Const.con->tag == Ico_U64);
sewardj85619c42005-04-06 01:11:53 +00002100 if (wLo == wHi) {
2101 /* Save a precious Int register in this special case. */
2102 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wLo), tLo));
2103 *rHi = tLo;
2104 *rLo = tLo;
2105 } else {
2106 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wHi), tHi));
2107 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wLo), tLo));
2108 *rHi = tHi;
2109 *rLo = tLo;
2110 }
sewardjc09278c2004-08-19 17:15:49 +00002111 return;
2112 }
2113
sewardj597b71b2004-07-19 02:51:12 +00002114 /* read 64-bit IRTemp */
sewardjdd40fdf2006-12-24 02:20:24 +00002115 if (e->tag == Iex_RdTmp) {
2116 lookupIRTemp64( rHi, rLo, env, e->Iex.RdTmp.tmp);
sewardj597b71b2004-07-19 02:51:12 +00002117 return;
2118 }
2119
sewardjbdc7d212004-09-09 02:46:40 +00002120 /* 64-bit load */
sewardje768e922009-11-26 17:17:37 +00002121 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
sewardjd08f2d72004-12-01 23:19:36 +00002122 HReg tLo, tHi;
2123 X86AMode *am0, *am4;
sewardjaf1ceca2005-06-30 23:31:27 +00002124 vassert(e->Iex.Load.ty == Ity_I64);
sewardj8fc93742004-11-22 11:29:33 +00002125 tLo = newVRegI(env);
2126 tHi = newVRegI(env);
sewardjaf1ceca2005-06-30 23:31:27 +00002127 am0 = iselIntExpr_AMode(env, e->Iex.Load.addr);
sewardjd08f2d72004-12-01 23:19:36 +00002128 am4 = advance4(am0);
2129 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am0), tLo ));
2130 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi ));
sewardjbdc7d212004-09-09 02:46:40 +00002131 *rHi = tHi;
2132 *rLo = tLo;
2133 return;
2134 }
2135
sewardj464efa42004-11-19 22:17:29 +00002136 /* 64-bit GET */
2137 if (e->tag == Iex_Get) {
2138 X86AMode* am = X86AMode_IR(e->Iex.Get.offset, hregX86_EBP());
2139 X86AMode* am4 = advance4(am);
2140 HReg tLo = newVRegI(env);
2141 HReg tHi = newVRegI(env);
2142 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am), tLo ));
2143 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi ));
2144 *rHi = tHi;
2145 *rLo = tLo;
2146 return;
2147 }
2148
sewardj218e29f2004-11-07 18:45:15 +00002149 /* 64-bit GETI */
2150 if (e->tag == Iex_GetI) {
2151 X86AMode* am
2152 = genGuestArrayOffset( env, e->Iex.GetI.descr,
2153 e->Iex.GetI.ix, e->Iex.GetI.bias );
2154 X86AMode* am4 = advance4(am);
2155 HReg tLo = newVRegI(env);
2156 HReg tHi = newVRegI(env);
2157 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am), tLo ));
2158 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi ));
2159 *rHi = tHi;
2160 *rLo = tLo;
2161 return;
2162 }
2163
florian99dd03e2013-01-29 03:56:06 +00002164 /* 64-bit ITE: ITE(g, expr, expr) */ // VFD
2165 if (e->tag == Iex_ITE) {
2166 HReg e0Lo, e0Hi, e1Lo, e1Hi;
sewardjeb17e492007-08-25 23:07:44 +00002167 HReg tLo = newVRegI(env);
2168 HReg tHi = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00002169 iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.ITE.iffalse);
2170 iselInt64Expr(&e1Hi, &e1Lo, env, e->Iex.ITE.iftrue);
2171 addInstr(env, mk_iMOVsd_RR(e1Hi, tHi));
2172 addInstr(env, mk_iMOVsd_RR(e1Lo, tLo));
2173 X86CondCode cc = iselCondCode(env, e->Iex.ITE.cond);
sewardj218e29f2004-11-07 18:45:15 +00002174 /* This assumes the first cmov32 doesn't trash the condition
2175 codes, so they are still available for the second cmov32 */
sewardj009230b2013-01-26 11:47:55 +00002176 addInstr(env, X86Instr_CMov32(cc ^ 1, X86RM_Reg(e0Hi), tHi));
2177 addInstr(env, X86Instr_CMov32(cc ^ 1, X86RM_Reg(e0Lo), tLo));
sewardj218e29f2004-11-07 18:45:15 +00002178 *rHi = tHi;
2179 *rLo = tLo;
2180 return;
2181 }
2182
sewardj38a3f862005-01-13 15:06:51 +00002183 /* --------- BINARY ops --------- */
2184 if (e->tag == Iex_Binop) {
2185 switch (e->Iex.Binop.op) {
2186 /* 32 x 32 -> 64 multiply */
2187 case Iop_MullU32:
2188 case Iop_MullS32: {
2189 /* get one operand into %eax, and the other into a R/M.
2190 Need to make an educated guess about which is better in
2191 which. */
2192 HReg tLo = newVRegI(env);
2193 HReg tHi = newVRegI(env);
sewardj428fabd2005-03-21 03:11:17 +00002194 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32);
sewardj38a3f862005-01-13 15:06:51 +00002195 X86RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1);
2196 HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2);
2197 addInstr(env, mk_iMOVsd_RR(rRight, hregX86_EAX()));
sewardjeba63f82005-02-23 13:31:25 +00002198 addInstr(env, X86Instr_MulL(syned, rmLeft));
sewardj38a3f862005-01-13 15:06:51 +00002199 /* Result is now in EDX:EAX. Tell the caller. */
2200 addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2201 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2202 *rHi = tHi;
2203 *rLo = tLo;
2204 return;
2205 }
sewardj597b71b2004-07-19 02:51:12 +00002206
sewardj38a3f862005-01-13 15:06:51 +00002207 /* 64 x 32 -> (32(rem),32(div)) division */
2208 case Iop_DivModU64to32:
2209 case Iop_DivModS64to32: {
2210 /* Get the 64-bit operand into edx:eax, and the other into
2211 any old R/M. */
2212 HReg sHi, sLo;
2213 HReg tLo = newVRegI(env);
2214 HReg tHi = newVRegI(env);
sewardj428fabd2005-03-21 03:11:17 +00002215 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to32);
sewardj38a3f862005-01-13 15:06:51 +00002216 X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
2217 iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
2218 addInstr(env, mk_iMOVsd_RR(sHi, hregX86_EDX()));
2219 addInstr(env, mk_iMOVsd_RR(sLo, hregX86_EAX()));
sewardjeba63f82005-02-23 13:31:25 +00002220 addInstr(env, X86Instr_Div(syned, rmRight));
sewardj38a3f862005-01-13 15:06:51 +00002221 addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2222 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2223 *rHi = tHi;
2224 *rLo = tLo;
2225 return;
2226 }
sewardj5c34dc92004-07-19 12:48:11 +00002227
sewardjd3f9de72005-01-15 20:43:10 +00002228 /* Or64/And64/Xor64 */
sewardj38a3f862005-01-13 15:06:51 +00002229 case Iop_Or64:
2230 case Iop_And64:
2231 case Iop_Xor64: {
2232 HReg xLo, xHi, yLo, yHi;
2233 HReg tLo = newVRegI(env);
2234 HReg tHi = newVRegI(env);
2235 X86AluOp op = e->Iex.Binop.op==Iop_Or64 ? Xalu_OR
2236 : e->Iex.Binop.op==Iop_And64 ? Xalu_AND
2237 : Xalu_XOR;
2238 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
sewardj38a3f862005-01-13 15:06:51 +00002239 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
sewardjeb17e492007-08-25 23:07:44 +00002240 addInstr(env, mk_iMOVsd_RR(xHi, tHi));
sewardj38a3f862005-01-13 15:06:51 +00002241 addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yHi), tHi));
sewardjeb17e492007-08-25 23:07:44 +00002242 addInstr(env, mk_iMOVsd_RR(xLo, tLo));
sewardj38a3f862005-01-13 15:06:51 +00002243 addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yLo), tLo));
2244 *rHi = tHi;
2245 *rLo = tLo;
2246 return;
2247 }
sewardj218e29f2004-11-07 18:45:15 +00002248
sewardjd3f9de72005-01-15 20:43:10 +00002249 /* Add64/Sub64 */
2250 case Iop_Add64:
sewardj3252c072007-11-27 00:11:13 +00002251 if (e->Iex.Binop.arg2->tag == Iex_Const) {
2252 /* special case Add64(e, const) */
2253 ULong w64 = e->Iex.Binop.arg2->Iex.Const.con->Ico.U64;
2254 UInt wHi = toUInt(w64 >> 32);
2255 UInt wLo = toUInt(w64);
2256 HReg tLo = newVRegI(env);
2257 HReg tHi = newVRegI(env);
2258 HReg xLo, xHi;
2259 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64);
2260 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2261 addInstr(env, mk_iMOVsd_RR(xHi, tHi));
2262 addInstr(env, mk_iMOVsd_RR(xLo, tLo));
2263 addInstr(env, X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(wLo), tLo));
2264 addInstr(env, X86Instr_Alu32R(Xalu_ADC, X86RMI_Imm(wHi), tHi));
2265 *rHi = tHi;
2266 *rLo = tLo;
2267 return;
2268 }
2269 /* else fall through to the generic case */
sewardjd3f9de72005-01-15 20:43:10 +00002270 case Iop_Sub64: {
2271 HReg xLo, xHi, yLo, yHi;
2272 HReg tLo = newVRegI(env);
2273 HReg tHi = newVRegI(env);
2274 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2275 addInstr(env, mk_iMOVsd_RR(xHi, tHi));
2276 addInstr(env, mk_iMOVsd_RR(xLo, tLo));
2277 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2278 if (e->Iex.Binop.op==Iop_Add64) {
2279 addInstr(env, X86Instr_Alu32R(Xalu_ADD, X86RMI_Reg(yLo), tLo));
2280 addInstr(env, X86Instr_Alu32R(Xalu_ADC, X86RMI_Reg(yHi), tHi));
2281 } else {
2282 addInstr(env, X86Instr_Alu32R(Xalu_SUB, X86RMI_Reg(yLo), tLo));
2283 addInstr(env, X86Instr_Alu32R(Xalu_SBB, X86RMI_Reg(yHi), tHi));
2284 }
2285 *rHi = tHi;
2286 *rLo = tLo;
2287 return;
2288 }
2289
sewardj38a3f862005-01-13 15:06:51 +00002290 /* 32HLto64(e1,e2) */
2291 case Iop_32HLto64:
2292 *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
2293 *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
2294 return;
sewardj5c34dc92004-07-19 12:48:11 +00002295
sewardj38a3f862005-01-13 15:06:51 +00002296 /* 64-bit shifts */
2297 case Iop_Shl64: {
2298 /* We use the same ingenious scheme as gcc. Put the value
2299 to be shifted into %hi:%lo, and the shift amount into
2300 %cl. Then (dsts on right, a la ATT syntax):
sewardj5c34dc92004-07-19 12:48:11 +00002301
sewardj38a3f862005-01-13 15:06:51 +00002302 shldl %cl, %lo, %hi -- make %hi be right for the
2303 -- shift amt %cl % 32
2304 shll %cl, %lo -- make %lo be right for the
2305 -- shift amt %cl % 32
sewardj5c34dc92004-07-19 12:48:11 +00002306
sewardj38a3f862005-01-13 15:06:51 +00002307 Now, if (shift amount % 64) is in the range 32 .. 63,
2308 we have to do a fixup, which puts the result low half
2309 into the result high half, and zeroes the low half:
sewardj5c34dc92004-07-19 12:48:11 +00002310
sewardj38a3f862005-01-13 15:06:51 +00002311 testl $32, %ecx
sewardj5c34dc92004-07-19 12:48:11 +00002312
sewardj38a3f862005-01-13 15:06:51 +00002313 cmovnz %lo, %hi
2314 movl $0, %tmp -- sigh; need yet another reg
2315 cmovnz %tmp, %lo
2316 */
2317 HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
2318 tLo = newVRegI(env);
2319 tHi = newVRegI(env);
2320 tTemp = newVRegI(env);
2321 rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
2322 iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
2323 addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX()));
2324 addInstr(env, mk_iMOVsd_RR(sHi, tHi));
2325 addInstr(env, mk_iMOVsd_RR(sLo, tLo));
2326 /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo
2327 and those regs are legitimately modifiable. */
2328 addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tLo, tHi));
sewardjeba63f82005-02-23 13:31:25 +00002329 addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, tLo));
sewardjfb7373a2007-08-25 21:29:03 +00002330 addInstr(env, X86Instr_Test32(32, X86RM_Reg(hregX86_ECX())));
sewardj38a3f862005-01-13 15:06:51 +00002331 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi));
2332 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
2333 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo));
2334 *rHi = tHi;
2335 *rLo = tLo;
2336 return;
2337 }
sewardj5c34dc92004-07-19 12:48:11 +00002338
sewardj38a3f862005-01-13 15:06:51 +00002339 case Iop_Shr64: {
2340 /* We use the same ingenious scheme as gcc. Put the value
2341 to be shifted into %hi:%lo, and the shift amount into
2342 %cl. Then:
sewardj68511542004-07-28 00:15:44 +00002343
sewardj38a3f862005-01-13 15:06:51 +00002344 shrdl %cl, %hi, %lo -- make %lo be right for the
2345 -- shift amt %cl % 32
2346 shrl %cl, %hi -- make %hi be right for the
2347 -- shift amt %cl % 32
sewardj68511542004-07-28 00:15:44 +00002348
sewardj38a3f862005-01-13 15:06:51 +00002349 Now, if (shift amount % 64) is in the range 32 .. 63,
2350 we have to do a fixup, which puts the result high half
2351 into the result low half, and zeroes the high half:
sewardj68511542004-07-28 00:15:44 +00002352
sewardj38a3f862005-01-13 15:06:51 +00002353 testl $32, %ecx
sewardj68511542004-07-28 00:15:44 +00002354
sewardj38a3f862005-01-13 15:06:51 +00002355 cmovnz %hi, %lo
2356 movl $0, %tmp -- sigh; need yet another reg
2357 cmovnz %tmp, %hi
2358 */
2359 HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
2360 tLo = newVRegI(env);
2361 tHi = newVRegI(env);
2362 tTemp = newVRegI(env);
2363 rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
2364 iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
2365 addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX()));
2366 addInstr(env, mk_iMOVsd_RR(sHi, tHi));
2367 addInstr(env, mk_iMOVsd_RR(sLo, tLo));
2368 /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo
2369 and those regs are legitimately modifiable. */
2370 addInstr(env, X86Instr_Sh3232(Xsh_SHR, 0/*%cl*/, tHi, tLo));
sewardjeba63f82005-02-23 13:31:25 +00002371 addInstr(env, X86Instr_Sh32(Xsh_SHR, 0/*%cl*/, tHi));
sewardjfb7373a2007-08-25 21:29:03 +00002372 addInstr(env, X86Instr_Test32(32, X86RM_Reg(hregX86_ECX())));
sewardj38a3f862005-01-13 15:06:51 +00002373 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tHi), tLo));
2374 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
2375 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tHi));
2376 *rHi = tHi;
2377 *rLo = tLo;
2378 return;
2379 }
sewardj68511542004-07-28 00:15:44 +00002380
sewardj38a3f862005-01-13 15:06:51 +00002381 /* F64 -> I64 */
2382 /* Sigh, this is an almost exact copy of the F64 -> I32/I16
2383 case. Unfortunately I see no easy way to avoid the
2384 duplication. */
sewardj6c299f32009-12-31 18:00:12 +00002385 case Iop_F64toI64S: {
sewardj38a3f862005-01-13 15:06:51 +00002386 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
2387 HReg tLo = newVRegI(env);
2388 HReg tHi = newVRegI(env);
sewardjcfded9a2004-09-09 11:44:16 +00002389
sewardj38a3f862005-01-13 15:06:51 +00002390 /* Used several times ... */
2391 /* Careful ... this sharing is only safe because
2392 zero_esp/four_esp do not hold any registers which the
2393 register allocator could attempt to swizzle later. */
2394 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
2395 X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
sewardjcfded9a2004-09-09 11:44:16 +00002396
sewardj38a3f862005-01-13 15:06:51 +00002397 /* rf now holds the value to be converted, and rrm holds
2398 the rounding mode value, encoded as per the
2399 IRRoundingMode enum. The first thing to do is set the
2400 FPU's rounding mode accordingly. */
sewardjcfded9a2004-09-09 11:44:16 +00002401
sewardj38a3f862005-01-13 15:06:51 +00002402 /* Create a space for the format conversion. */
2403 /* subl $8, %esp */
2404 sub_from_esp(env, 8);
sewardj4cb918d2004-12-03 19:43:31 +00002405
sewardj38a3f862005-01-13 15:06:51 +00002406 /* Set host rounding mode */
2407 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
sewardjcfded9a2004-09-09 11:44:16 +00002408
sewardj38a3f862005-01-13 15:06:51 +00002409 /* gistll %rf, 0(%esp) */
2410 addInstr(env, X86Instr_FpLdStI(False/*store*/, 8, rf, zero_esp));
sewardjcfded9a2004-09-09 11:44:16 +00002411
sewardj38a3f862005-01-13 15:06:51 +00002412 /* movl 0(%esp), %dstLo */
2413 /* movl 4(%esp), %dstHi */
2414 addInstr(env, X86Instr_Alu32R(
2415 Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
2416 addInstr(env, X86Instr_Alu32R(
2417 Xalu_MOV, X86RMI_Mem(four_esp), tHi));
sewardjcfded9a2004-09-09 11:44:16 +00002418
sewardj38a3f862005-01-13 15:06:51 +00002419 /* Restore default FPU rounding. */
2420 set_FPU_rounding_default( env );
sewardjcfded9a2004-09-09 11:44:16 +00002421
sewardj38a3f862005-01-13 15:06:51 +00002422 /* addl $8, %esp */
2423 add_to_esp(env, 8);
sewardjcfded9a2004-09-09 11:44:16 +00002424
sewardj38a3f862005-01-13 15:06:51 +00002425 *rHi = tHi;
2426 *rLo = tLo;
2427 return;
2428 }
2429
2430 case Iop_Add8x8:
2431 fn = (HWord)h_generic_calc_Add8x8; goto binnish;
2432 case Iop_Add16x4:
2433 fn = (HWord)h_generic_calc_Add16x4; goto binnish;
2434 case Iop_Add32x2:
2435 fn = (HWord)h_generic_calc_Add32x2; goto binnish;
2436
2437 case Iop_Avg8Ux8:
2438 fn = (HWord)h_generic_calc_Avg8Ux8; goto binnish;
2439 case Iop_Avg16Ux4:
2440 fn = (HWord)h_generic_calc_Avg16Ux4; goto binnish;
2441
2442 case Iop_CmpEQ8x8:
2443 fn = (HWord)h_generic_calc_CmpEQ8x8; goto binnish;
2444 case Iop_CmpEQ16x4:
2445 fn = (HWord)h_generic_calc_CmpEQ16x4; goto binnish;
2446 case Iop_CmpEQ32x2:
2447 fn = (HWord)h_generic_calc_CmpEQ32x2; goto binnish;
2448
2449 case Iop_CmpGT8Sx8:
2450 fn = (HWord)h_generic_calc_CmpGT8Sx8; goto binnish;
2451 case Iop_CmpGT16Sx4:
2452 fn = (HWord)h_generic_calc_CmpGT16Sx4; goto binnish;
2453 case Iop_CmpGT32Sx2:
2454 fn = (HWord)h_generic_calc_CmpGT32Sx2; goto binnish;
2455
2456 case Iop_InterleaveHI8x8:
2457 fn = (HWord)h_generic_calc_InterleaveHI8x8; goto binnish;
2458 case Iop_InterleaveLO8x8:
2459 fn = (HWord)h_generic_calc_InterleaveLO8x8; goto binnish;
2460 case Iop_InterleaveHI16x4:
2461 fn = (HWord)h_generic_calc_InterleaveHI16x4; goto binnish;
2462 case Iop_InterleaveLO16x4:
2463 fn = (HWord)h_generic_calc_InterleaveLO16x4; goto binnish;
2464 case Iop_InterleaveHI32x2:
2465 fn = (HWord)h_generic_calc_InterleaveHI32x2; goto binnish;
2466 case Iop_InterleaveLO32x2:
2467 fn = (HWord)h_generic_calc_InterleaveLO32x2; goto binnish;
sewardj150c9cd2008-02-09 01:16:02 +00002468 case Iop_CatOddLanes16x4:
2469 fn = (HWord)h_generic_calc_CatOddLanes16x4; goto binnish;
2470 case Iop_CatEvenLanes16x4:
2471 fn = (HWord)h_generic_calc_CatEvenLanes16x4; goto binnish;
2472 case Iop_Perm8x8:
2473 fn = (HWord)h_generic_calc_Perm8x8; goto binnish;
sewardj38a3f862005-01-13 15:06:51 +00002474
2475 case Iop_Max8Ux8:
2476 fn = (HWord)h_generic_calc_Max8Ux8; goto binnish;
2477 case Iop_Max16Sx4:
2478 fn = (HWord)h_generic_calc_Max16Sx4; goto binnish;
2479 case Iop_Min8Ux8:
2480 fn = (HWord)h_generic_calc_Min8Ux8; goto binnish;
2481 case Iop_Min16Sx4:
2482 fn = (HWord)h_generic_calc_Min16Sx4; goto binnish;
2483
2484 case Iop_Mul16x4:
2485 fn = (HWord)h_generic_calc_Mul16x4; goto binnish;
sewardj150c9cd2008-02-09 01:16:02 +00002486 case Iop_Mul32x2:
2487 fn = (HWord)h_generic_calc_Mul32x2; goto binnish;
sewardj38a3f862005-01-13 15:06:51 +00002488 case Iop_MulHi16Sx4:
2489 fn = (HWord)h_generic_calc_MulHi16Sx4; goto binnish;
2490 case Iop_MulHi16Ux4:
2491 fn = (HWord)h_generic_calc_MulHi16Ux4; goto binnish;
2492
2493 case Iop_QAdd8Sx8:
2494 fn = (HWord)h_generic_calc_QAdd8Sx8; goto binnish;
2495 case Iop_QAdd16Sx4:
2496 fn = (HWord)h_generic_calc_QAdd16Sx4; goto binnish;
2497 case Iop_QAdd8Ux8:
2498 fn = (HWord)h_generic_calc_QAdd8Ux8; goto binnish;
2499 case Iop_QAdd16Ux4:
2500 fn = (HWord)h_generic_calc_QAdd16Ux4; goto binnish;
2501
sewardj5f438dd2011-06-16 11:36:23 +00002502 case Iop_QNarrowBin32Sto16Sx4:
2503 fn = (HWord)h_generic_calc_QNarrowBin32Sto16Sx4; goto binnish;
2504 case Iop_QNarrowBin16Sto8Sx8:
2505 fn = (HWord)h_generic_calc_QNarrowBin16Sto8Sx8; goto binnish;
2506 case Iop_QNarrowBin16Sto8Ux8:
2507 fn = (HWord)h_generic_calc_QNarrowBin16Sto8Ux8; goto binnish;
sewardjad2c9ea2011-10-22 09:32:16 +00002508 case Iop_NarrowBin16to8x8:
2509 fn = (HWord)h_generic_calc_NarrowBin16to8x8; goto binnish;
2510 case Iop_NarrowBin32to16x4:
2511 fn = (HWord)h_generic_calc_NarrowBin32to16x4; goto binnish;
sewardj38a3f862005-01-13 15:06:51 +00002512
2513 case Iop_QSub8Sx8:
2514 fn = (HWord)h_generic_calc_QSub8Sx8; goto binnish;
2515 case Iop_QSub16Sx4:
2516 fn = (HWord)h_generic_calc_QSub16Sx4; goto binnish;
2517 case Iop_QSub8Ux8:
2518 fn = (HWord)h_generic_calc_QSub8Ux8; goto binnish;
2519 case Iop_QSub16Ux4:
2520 fn = (HWord)h_generic_calc_QSub16Ux4; goto binnish;
2521
2522 case Iop_Sub8x8:
2523 fn = (HWord)h_generic_calc_Sub8x8; goto binnish;
2524 case Iop_Sub16x4:
2525 fn = (HWord)h_generic_calc_Sub16x4; goto binnish;
2526 case Iop_Sub32x2:
2527 fn = (HWord)h_generic_calc_Sub32x2; goto binnish;
2528
2529 binnish: {
2530 /* Note: the following assumes all helpers are of
2531 signature
2532 ULong fn ( ULong, ULong ), and they are
2533 not marked as regparm functions.
2534 */
2535 HReg xLo, xHi, yLo, yHi;
2536 HReg tLo = newVRegI(env);
2537 HReg tHi = newVRegI(env);
2538 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2539 addInstr(env, X86Instr_Push(X86RMI_Reg(yHi)));
2540 addInstr(env, X86Instr_Push(X86RMI_Reg(yLo)));
2541 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2542 addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
2543 addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
sewardjcfe046e2013-01-17 14:23:53 +00002544 addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn,
sewardj74142b82013-08-08 10:28:59 +00002545 0, mk_RetLoc_simple(RLPri_2Int) ));
sewardj38a3f862005-01-13 15:06:51 +00002546 add_to_esp(env, 4*4);
2547 addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2548 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2549 *rHi = tHi;
2550 *rLo = tLo;
2551 return;
2552 }
2553
2554 case Iop_ShlN32x2:
2555 fn = (HWord)h_generic_calc_ShlN32x2; goto shifty;
2556 case Iop_ShlN16x4:
2557 fn = (HWord)h_generic_calc_ShlN16x4; goto shifty;
sewardj150c9cd2008-02-09 01:16:02 +00002558 case Iop_ShlN8x8:
2559 fn = (HWord)h_generic_calc_ShlN8x8; goto shifty;
sewardj38a3f862005-01-13 15:06:51 +00002560 case Iop_ShrN32x2:
2561 fn = (HWord)h_generic_calc_ShrN32x2; goto shifty;
2562 case Iop_ShrN16x4:
2563 fn = (HWord)h_generic_calc_ShrN16x4; goto shifty;
2564 case Iop_SarN32x2:
2565 fn = (HWord)h_generic_calc_SarN32x2; goto shifty;
2566 case Iop_SarN16x4:
2567 fn = (HWord)h_generic_calc_SarN16x4; goto shifty;
sewardjd71ba832006-12-27 01:15:29 +00002568 case Iop_SarN8x8:
2569 fn = (HWord)h_generic_calc_SarN8x8; goto shifty;
sewardj38a3f862005-01-13 15:06:51 +00002570 shifty: {
2571 /* Note: the following assumes all helpers are of
2572 signature
2573 ULong fn ( ULong, UInt ), and they are
2574 not marked as regparm functions.
2575 */
2576 HReg xLo, xHi;
2577 HReg tLo = newVRegI(env);
2578 HReg tHi = newVRegI(env);
2579 X86RMI* y = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
2580 addInstr(env, X86Instr_Push(y));
2581 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2582 addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
2583 addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
sewardjcfe046e2013-01-17 14:23:53 +00002584 addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn,
sewardj74142b82013-08-08 10:28:59 +00002585 0, mk_RetLoc_simple(RLPri_2Int) ));
sewardj38a3f862005-01-13 15:06:51 +00002586 add_to_esp(env, 3*4);
2587 addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2588 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2589 *rHi = tHi;
2590 *rLo = tLo;
2591 return;
2592 }
2593
2594 default:
2595 break;
2596 }
2597 } /* if (e->tag == Iex_Binop) */
2598
2599
2600 /* --------- UNARY ops --------- */
2601 if (e->tag == Iex_Unop) {
2602 switch (e->Iex.Unop.op) {
2603
2604 /* 32Sto64(e) */
2605 case Iop_32Sto64: {
2606 HReg tLo = newVRegI(env);
2607 HReg tHi = newVRegI(env);
2608 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
2609 addInstr(env, mk_iMOVsd_RR(src,tHi));
2610 addInstr(env, mk_iMOVsd_RR(src,tLo));
sewardjeba63f82005-02-23 13:31:25 +00002611 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, tHi));
sewardj38a3f862005-01-13 15:06:51 +00002612 *rHi = tHi;
2613 *rLo = tLo;
2614 return;
2615 }
2616
2617 /* 32Uto64(e) */
2618 case Iop_32Uto64: {
2619 HReg tLo = newVRegI(env);
2620 HReg tHi = newVRegI(env);
2621 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
2622 addInstr(env, mk_iMOVsd_RR(src,tLo));
2623 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi));
2624 *rHi = tHi;
2625 *rLo = tLo;
2626 return;
2627 }
2628
sewardjcc855582010-09-09 07:14:31 +00002629 /* 16Uto64(e) */
2630 case Iop_16Uto64: {
2631 HReg tLo = newVRegI(env);
2632 HReg tHi = newVRegI(env);
2633 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
2634 addInstr(env, mk_iMOVsd_RR(src,tLo));
2635 addInstr(env, X86Instr_Alu32R(Xalu_AND,
2636 X86RMI_Imm(0xFFFF), tLo));
2637 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi));
2638 *rHi = tHi;
2639 *rLo = tLo;
2640 return;
2641 }
2642
sewardjf0c1c582005-02-07 23:47:38 +00002643 /* V128{HI}to64 */
2644 case Iop_V128HIto64:
2645 case Iop_V128to64: {
2646 Int off = e->Iex.Unop.op==Iop_V128HIto64 ? 8 : 0;
sewardj38a3f862005-01-13 15:06:51 +00002647 HReg tLo = newVRegI(env);
2648 HReg tHi = newVRegI(env);
2649 HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
2650 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
2651 X86AMode* espLO = X86AMode_IR(off, hregX86_ESP());
2652 X86AMode* espHI = X86AMode_IR(off+4, hregX86_ESP());
2653 sub_from_esp(env, 16);
2654 addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
2655 addInstr(env, X86Instr_Alu32R( Xalu_MOV,
2656 X86RMI_Mem(espLO), tLo ));
2657 addInstr(env, X86Instr_Alu32R( Xalu_MOV,
2658 X86RMI_Mem(espHI), tHi ));
2659 add_to_esp(env, 16);
2660 *rHi = tHi;
2661 *rLo = tLo;
2662 return;
2663 }
2664
2665 /* could do better than this, but for now ... */
2666 case Iop_1Sto64: {
2667 HReg tLo = newVRegI(env);
2668 HReg tHi = newVRegI(env);
2669 X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
2670 addInstr(env, X86Instr_Set32(cond,tLo));
sewardjeba63f82005-02-23 13:31:25 +00002671 addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, tLo));
2672 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, tLo));
sewardj38a3f862005-01-13 15:06:51 +00002673 addInstr(env, mk_iMOVsd_RR(tLo, tHi));
2674 *rHi = tHi;
2675 *rLo = tLo;
2676 return;
2677 }
2678
2679 /* Not64(e) */
2680 case Iop_Not64: {
2681 HReg tLo = newVRegI(env);
2682 HReg tHi = newVRegI(env);
2683 HReg sHi, sLo;
2684 iselInt64Expr(&sHi, &sLo, env, e->Iex.Unop.arg);
2685 addInstr(env, mk_iMOVsd_RR(sHi, tHi));
2686 addInstr(env, mk_iMOVsd_RR(sLo, tLo));
sewardjeba63f82005-02-23 13:31:25 +00002687 addInstr(env, X86Instr_Unary32(Xun_NOT,tHi));
2688 addInstr(env, X86Instr_Unary32(Xun_NOT,tLo));
sewardj38a3f862005-01-13 15:06:51 +00002689 *rHi = tHi;
2690 *rLo = tLo;
2691 return;
2692 }
2693
sewardjeb17e492007-08-25 23:07:44 +00002694 /* Left64(e) */
2695 case Iop_Left64: {
sewardj7f64c4c2005-05-14 02:02:50 +00002696 HReg yLo, yHi;
2697 HReg tLo = newVRegI(env);
2698 HReg tHi = newVRegI(env);
2699 /* yHi:yLo = arg */
2700 iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg);
2701 /* tLo = 0 - yLo, and set carry */
2702 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tLo));
2703 addInstr(env, X86Instr_Alu32R(Xalu_SUB, X86RMI_Reg(yLo), tLo));
2704 /* tHi = 0 - yHi - carry */
2705 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi));
2706 addInstr(env, X86Instr_Alu32R(Xalu_SBB, X86RMI_Reg(yHi), tHi));
sewardjeb17e492007-08-25 23:07:44 +00002707 /* So now we have tHi:tLo = -arg. To finish off, or 'arg'
2708 back in, so as to give the final result
2709 tHi:tLo = arg | -arg. */
2710 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(yLo), tLo));
2711 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(yHi), tHi));
sewardj7f64c4c2005-05-14 02:02:50 +00002712 *rHi = tHi;
2713 *rLo = tLo;
2714 return;
2715 }
2716
sewardjeb17e492007-08-25 23:07:44 +00002717 /* --- patterns rooted at: CmpwNEZ64 --- */
2718
2719 /* CmpwNEZ64(e) */
2720 case Iop_CmpwNEZ64: {
2721
2722 DECLARE_PATTERN(p_CmpwNEZ64_Or64);
2723 DEFINE_PATTERN(p_CmpwNEZ64_Or64,
2724 unop(Iop_CmpwNEZ64,binop(Iop_Or64,bind(0),bind(1))));
2725 if (matchIRExpr(&mi, p_CmpwNEZ64_Or64, e)) {
2726 /* CmpwNEZ64(Or64(x,y)) */
2727 HReg xHi,xLo,yHi,yLo;
2728 HReg xBoth = newVRegI(env);
2729 HReg merged = newVRegI(env);
2730 HReg tmp2 = newVRegI(env);
2731
2732 iselInt64Expr(&xHi,&xLo, env, mi.bindee[0]);
2733 addInstr(env, mk_iMOVsd_RR(xHi,xBoth));
2734 addInstr(env, X86Instr_Alu32R(Xalu_OR,
2735 X86RMI_Reg(xLo),xBoth));
2736
2737 iselInt64Expr(&yHi,&yLo, env, mi.bindee[1]);
2738 addInstr(env, mk_iMOVsd_RR(yHi,merged));
2739 addInstr(env, X86Instr_Alu32R(Xalu_OR,
2740 X86RMI_Reg(yLo),merged));
2741 addInstr(env, X86Instr_Alu32R(Xalu_OR,
2742 X86RMI_Reg(xBoth),merged));
2743
2744 /* tmp2 = (merged | -merged) >>s 31 */
2745 addInstr(env, mk_iMOVsd_RR(merged,tmp2));
2746 addInstr(env, X86Instr_Unary32(Xun_NEG,tmp2));
2747 addInstr(env, X86Instr_Alu32R(Xalu_OR,
2748 X86RMI_Reg(merged), tmp2));
2749 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, tmp2));
2750 *rHi = tmp2;
2751 *rLo = tmp2;
2752 return;
2753 } else {
2754 /* CmpwNEZ64(e) */
2755 HReg srcLo, srcHi;
2756 HReg tmp1 = newVRegI(env);
2757 HReg tmp2 = newVRegI(env);
2758 /* srcHi:srcLo = arg */
2759 iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
2760 /* tmp1 = srcHi | srcLo */
2761 addInstr(env, mk_iMOVsd_RR(srcHi,tmp1));
2762 addInstr(env, X86Instr_Alu32R(Xalu_OR,
2763 X86RMI_Reg(srcLo), tmp1));
2764 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
2765 addInstr(env, mk_iMOVsd_RR(tmp1,tmp2));
2766 addInstr(env, X86Instr_Unary32(Xun_NEG,tmp2));
2767 addInstr(env, X86Instr_Alu32R(Xalu_OR,
2768 X86RMI_Reg(tmp1), tmp2));
2769 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, tmp2));
2770 *rHi = tmp2;
2771 *rLo = tmp2;
2772 return;
2773 }
2774 }
2775
sewardj38a3f862005-01-13 15:06:51 +00002776 /* ReinterpF64asI64(e) */
2777 /* Given an IEEE754 double, produce an I64 with the same bit
2778 pattern. */
2779 case Iop_ReinterpF64asI64: {
2780 HReg rf = iselDblExpr(env, e->Iex.Unop.arg);
2781 HReg tLo = newVRegI(env);
2782 HReg tHi = newVRegI(env);
2783 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
2784 X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
2785 /* paranoia */
2786 set_FPU_rounding_default(env);
2787 /* subl $8, %esp */
2788 sub_from_esp(env, 8);
2789 /* gstD %rf, 0(%esp) */
2790 addInstr(env,
2791 X86Instr_FpLdSt(False/*store*/, 8, rf, zero_esp));
2792 /* movl 0(%esp), %tLo */
2793 addInstr(env,
2794 X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
2795 /* movl 4(%esp), %tHi */
2796 addInstr(env,
2797 X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(four_esp), tHi));
2798 /* addl $8, %esp */
2799 add_to_esp(env, 8);
2800 *rHi = tHi;
2801 *rLo = tLo;
2802 return;
2803 }
2804
sewardj18069182005-01-13 19:16:04 +00002805 case Iop_CmpNEZ32x2:
2806 fn = (HWord)h_generic_calc_CmpNEZ32x2; goto unish;
2807 case Iop_CmpNEZ16x4:
2808 fn = (HWord)h_generic_calc_CmpNEZ16x4; goto unish;
2809 case Iop_CmpNEZ8x8:
2810 fn = (HWord)h_generic_calc_CmpNEZ8x8; goto unish;
2811 unish: {
2812 /* Note: the following assumes all helpers are of
2813 signature
2814 ULong fn ( ULong ), and they are
2815 not marked as regparm functions.
2816 */
2817 HReg xLo, xHi;
2818 HReg tLo = newVRegI(env);
2819 HReg tHi = newVRegI(env);
2820 iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg);
2821 addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
2822 addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
sewardjcfe046e2013-01-17 14:23:53 +00002823 addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn,
sewardj74142b82013-08-08 10:28:59 +00002824 0, mk_RetLoc_simple(RLPri_2Int) ));
sewardj18069182005-01-13 19:16:04 +00002825 add_to_esp(env, 2*4);
2826 addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2827 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2828 *rHi = tHi;
2829 *rLo = tLo;
2830 return;
2831 }
2832
sewardj38a3f862005-01-13 15:06:51 +00002833 default:
2834 break;
2835 }
2836 } /* if (e->tag == Iex_Unop) */
2837
sewardjc4be80c2004-09-10 16:17:45 +00002838
sewardj33fa73e2004-10-24 19:19:37 +00002839 /* --------- CCALL --------- */
2840 if (e->tag == Iex_CCall) {
sewardj77352542004-10-30 20:39:01 +00002841 HReg tLo = newVRegI(env);
2842 HReg tHi = newVRegI(env);
sewardj33fa73e2004-10-24 19:19:37 +00002843
sewardj77352542004-10-30 20:39:01 +00002844 /* Marshal args, do the call, clear stack. */
sewardj74142b82013-08-08 10:28:59 +00002845 UInt addToSp = 0;
2846 RetLoc rloc = mk_RetLoc_INVALID();
2847 doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
2848 e->Iex.CCall.cee,
2849 e->Iex.CCall.retty, e->Iex.CCall.args );
2850 vassert(is_sane_RetLoc(rloc));
2851 vassert(rloc.pri == RLPri_2Int);
2852 vassert(addToSp == 0);
2853 /* */
sewardj33fa73e2004-10-24 19:19:37 +00002854
sewardjd08f2d72004-12-01 23:19:36 +00002855 addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2856 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
sewardj33fa73e2004-10-24 19:19:37 +00002857 *rHi = tHi;
2858 *rLo = tLo;
2859 return;
2860 }
2861
sewardj597b71b2004-07-19 02:51:12 +00002862 ppIRExpr(e);
sewardjd08f2d72004-12-01 23:19:36 +00002863 vpanic("iselInt64Expr");
sewardj597b71b2004-07-19 02:51:12 +00002864}
2865
2866
sewardjd08f2d72004-12-01 23:19:36 +00002867/*---------------------------------------------------------*/
2868/*--- ISEL: Floating point expressions (32 bit) ---*/
2869/*---------------------------------------------------------*/
2870
2871/* Nothing interesting here; really just wrappers for
2872 64-bit stuff. */
2873
2874static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
2875{
2876 HReg r = iselFltExpr_wrk( env, e );
2877# if 0
2878 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2879# endif
2880 vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
2881 vassert(hregIsVirtual(r));
2882 return r;
2883}
2884
2885/* DO NOT CALL THIS DIRECTLY */
2886static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
2887{
2888 IRType ty = typeOfIRExpr(env->type_env,e);
2889 vassert(ty == Ity_F32);
2890
sewardjdd40fdf2006-12-24 02:20:24 +00002891 if (e->tag == Iex_RdTmp) {
2892 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
sewardjd08f2d72004-12-01 23:19:36 +00002893 }
2894
sewardje768e922009-11-26 17:17:37 +00002895 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
sewardjd08f2d72004-12-01 23:19:36 +00002896 X86AMode* am;
2897 HReg res = newVRegF(env);
sewardjaf1ceca2005-06-30 23:31:27 +00002898 vassert(e->Iex.Load.ty == Ity_F32);
2899 am = iselIntExpr_AMode(env, e->Iex.Load.addr);
sewardjd08f2d72004-12-01 23:19:36 +00002900 addInstr(env, X86Instr_FpLdSt(True/*load*/, 4, res, am));
2901 return res;
2902 }
2903
sewardj3bca9062004-12-04 14:36:09 +00002904 if (e->tag == Iex_Binop
2905 && e->Iex.Binop.op == Iop_F64toF32) {
2906 /* Although the result is still held in a standard FPU register,
2907 we need to round it to reflect the loss of accuracy/range
2908 entailed in casting it to a 32-bit float. */
2909 HReg dst = newVRegF(env);
2910 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
2911 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2912 addInstr(env, X86Instr_Fp64to32(src,dst));
2913 set_FPU_rounding_default( env );
2914 return dst;
sewardjd08f2d72004-12-01 23:19:36 +00002915 }
2916
sewardj67e002d2004-12-02 18:16:33 +00002917 if (e->tag == Iex_Get) {
2918 X86AMode* am = X86AMode_IR( e->Iex.Get.offset,
2919 hregX86_EBP() );
2920 HReg res = newVRegF(env);
2921 addInstr(env, X86Instr_FpLdSt( True/*load*/, 4, res, am ));
2922 return res;
2923 }
2924
sewardjfd226452004-12-07 19:02:18 +00002925 if (e->tag == Iex_Unop
2926 && e->Iex.Unop.op == Iop_ReinterpI32asF32) {
2927 /* Given an I32, produce an IEEE754 float with the same bit
2928 pattern. */
2929 HReg dst = newVRegF(env);
2930 X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Unop.arg);
2931 /* paranoia */
2932 addInstr(env, X86Instr_Push(rmi));
2933 addInstr(env, X86Instr_FpLdSt(
2934 True/*load*/, 4, dst,
2935 X86AMode_IR(0, hregX86_ESP())));
2936 add_to_esp(env, 4);
2937 return dst;
2938 }
2939
sewardjb7271612010-07-23 21:23:25 +00002940 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF32toInt) {
2941 HReg rf = iselFltExpr(env, e->Iex.Binop.arg2);
2942 HReg dst = newVRegF(env);
2943
2944 /* rf now holds the value to be rounded. The first thing to do
2945 is set the FPU's rounding mode accordingly. */
2946
2947 /* Set host rounding mode */
2948 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2949
2950 /* grndint %rf, %dst */
2951 addInstr(env, X86Instr_FpUnary(Xfp_ROUND, rf, dst));
2952
2953 /* Restore default FPU rounding. */
2954 set_FPU_rounding_default( env );
2955
2956 return dst;
2957 }
2958
sewardjd08f2d72004-12-01 23:19:36 +00002959 ppIRExpr(e);
2960 vpanic("iselFltExpr_wrk");
2961}
2962
sewardj4042c7e2004-07-18 01:28:30 +00002963
sewardjc97096c2004-06-30 09:28:04 +00002964/*---------------------------------------------------------*/
sewardj3196daf2004-08-13 00:18:58 +00002965/*--- ISEL: Floating point expressions (64 bit) ---*/
2966/*---------------------------------------------------------*/
2967
2968/* Compute a 64-bit floating point value into a register, the identity
2969 of which is returned. As with iselIntExpr_R, the reg may be either
2970 real or virtual; in any case it must not be changed by subsequent
2971 code emitted by the caller. */
2972
sewardj3fc76d22004-08-31 11:47:54 +00002973/* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
2974
2975 Type S (1 bit) E (11 bits) F (52 bits)
2976 ---- --------- ----------- -----------
2977 signalling NaN u 2047 (max) .0uuuuu---u
2978 (with at least
2979 one 1 bit)
2980 quiet NaN u 2047 (max) .1uuuuu---u
2981
2982 negative infinity 1 2047 (max) .000000---0
2983
2984 positive infinity 0 2047 (max) .000000---0
2985
2986 negative zero 1 0 .000000---0
2987
2988 positive zero 0 0 .000000---0
2989*/
2990
sewardj3196daf2004-08-13 00:18:58 +00002991static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
2992{
sewardjd08f2d72004-12-01 23:19:36 +00002993 HReg r = iselDblExpr_wrk( env, e );
2994# if 0
2995 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2996# endif
2997 vassert(hregClass(r) == HRcFlt64);
2998 vassert(hregIsVirtual(r));
2999 return r;
3000}
3001
3002/* DO NOT CALL THIS DIRECTLY */
3003static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
3004{
sewardj33124f62004-08-30 17:54:18 +00003005 IRType ty = typeOfIRExpr(env->type_env,e);
sewardj3196daf2004-08-13 00:18:58 +00003006 vassert(e);
sewardj33124f62004-08-30 17:54:18 +00003007 vassert(ty == Ity_F64);
sewardj3196daf2004-08-13 00:18:58 +00003008
sewardjdd40fdf2006-12-24 02:20:24 +00003009 if (e->tag == Iex_RdTmp) {
3010 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
sewardjbb53f8c2004-08-14 11:50:01 +00003011 }
3012
sewardja58ea662004-08-15 03:12:41 +00003013 if (e->tag == Iex_Const) {
sewardj17442fe2004-09-20 14:54:28 +00003014 union { UInt u32x2[2]; ULong u64; Double f64; } u;
sewardja58ea662004-08-15 03:12:41 +00003015 HReg freg = newVRegF(env);
3016 vassert(sizeof(u) == 8);
sewardj17442fe2004-09-20 14:54:28 +00003017 vassert(sizeof(u.u64) == 8);
sewardja58ea662004-08-15 03:12:41 +00003018 vassert(sizeof(u.f64) == 8);
sewardj17442fe2004-09-20 14:54:28 +00003019 vassert(sizeof(u.u32x2) == 8);
sewardj3fc76d22004-08-31 11:47:54 +00003020
3021 if (e->Iex.Const.con->tag == Ico_F64) {
3022 u.f64 = e->Iex.Const.con->Ico.F64;
sewardj17442fe2004-09-20 14:54:28 +00003023 }
3024 else if (e->Iex.Const.con->tag == Ico_F64i) {
3025 u.u64 = e->Iex.Const.con->Ico.F64i;
sewardj3fc76d22004-08-31 11:47:54 +00003026 }
3027 else
3028 vpanic("iselDblExpr(x86): const");
3029
sewardj17442fe2004-09-20 14:54:28 +00003030 addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[1])));
3031 addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[0])));
sewardja58ea662004-08-15 03:12:41 +00003032 addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg,
3033 X86AMode_IR(0, hregX86_ESP())));
sewardj855f32d2004-12-05 21:22:38 +00003034 add_to_esp(env, 8);
sewardja58ea662004-08-15 03:12:41 +00003035 return freg;
3036 }
3037
sewardje768e922009-11-26 17:17:37 +00003038 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
sewardj3196daf2004-08-13 00:18:58 +00003039 X86AMode* am;
3040 HReg res = newVRegF(env);
sewardjaf1ceca2005-06-30 23:31:27 +00003041 vassert(e->Iex.Load.ty == Ity_F64);
3042 am = iselIntExpr_AMode(env, e->Iex.Load.addr);
sewardj3196daf2004-08-13 00:18:58 +00003043 addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, res, am));
3044 return res;
3045 }
3046
sewardjfd226452004-12-07 19:02:18 +00003047 if (e->tag == Iex_Get) {
3048 X86AMode* am = X86AMode_IR( e->Iex.Get.offset,
3049 hregX86_EBP() );
3050 HReg res = newVRegF(env);
3051 addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am ));
3052 return res;
3053 }
3054
sewardjbb53f8c2004-08-14 11:50:01 +00003055 if (e->tag == Iex_GetI) {
sewardj2d3f77c2004-09-22 23:49:09 +00003056 X86AMode* am
3057 = genGuestArrayOffset(
3058 env, e->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00003059 e->Iex.GetI.ix, e->Iex.GetI.bias );
sewardjbb53f8c2004-08-14 11:50:01 +00003060 HReg res = newVRegF(env);
sewardj2d3f77c2004-09-22 23:49:09 +00003061 addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am ));
sewardjbb53f8c2004-08-14 11:50:01 +00003062 return res;
3063 }
3064
sewardjf1b5b1a2006-02-03 22:54:17 +00003065 if (e->tag == Iex_Triop) {
sewardjbb53f8c2004-08-14 11:50:01 +00003066 X86FpOp fpop = Xfp_INVALID;
florian420bfa92012-06-02 20:29:22 +00003067 IRTriop *triop = e->Iex.Triop.details;
3068 switch (triop->op) {
sewardj06c32a02004-09-12 12:07:34 +00003069 case Iop_AddF64: fpop = Xfp_ADD; break;
3070 case Iop_SubF64: fpop = Xfp_SUB; break;
3071 case Iop_MulF64: fpop = Xfp_MUL; break;
3072 case Iop_DivF64: fpop = Xfp_DIV; break;
3073 case Iop_ScaleF64: fpop = Xfp_SCALE; break;
sewardj06c32a02004-09-12 12:07:34 +00003074 case Iop_Yl2xF64: fpop = Xfp_YL2X; break;
3075 case Iop_Yl2xp1F64: fpop = Xfp_YL2XP1; break;
sewardjf1b5b1a2006-02-03 22:54:17 +00003076 case Iop_AtanF64: fpop = Xfp_ATAN; break;
sewardjf47286e2006-02-04 15:20:13 +00003077 case Iop_PRemF64: fpop = Xfp_PREM; break;
3078 case Iop_PRem1F64: fpop = Xfp_PREM1; break;
sewardjf1b5b1a2006-02-03 22:54:17 +00003079 default: break;
3080 }
3081 if (fpop != Xfp_INVALID) {
3082 HReg res = newVRegF(env);
florian420bfa92012-06-02 20:29:22 +00003083 HReg srcL = iselDblExpr(env, triop->arg2);
3084 HReg srcR = iselDblExpr(env, triop->arg3);
sewardjf1b5b1a2006-02-03 22:54:17 +00003085 /* XXXROUNDINGFIXME */
3086 /* set roundingmode here */
3087 addInstr(env, X86Instr_FpBinary(fpop,srcL,srcR,res));
3088 if (fpop != Xfp_ADD && fpop != Xfp_SUB
3089 && fpop != Xfp_MUL && fpop != Xfp_DIV)
3090 roundToF64(env, res);
3091 return res;
3092 }
3093 }
3094
sewardjb183b852006-02-03 16:08:03 +00003095 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF64toInt) {
sewardj4cb918d2004-12-03 19:43:31 +00003096 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
3097 HReg dst = newVRegF(env);
sewardje6709112004-09-10 18:37:18 +00003098
sewardj4cb918d2004-12-03 19:43:31 +00003099 /* rf now holds the value to be rounded. The first thing to do
3100 is set the FPU's rounding mode accordingly. */
sewardje6709112004-09-10 18:37:18 +00003101
sewardj4cb918d2004-12-03 19:43:31 +00003102 /* Set host rounding mode */
3103 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
sewardje6709112004-09-10 18:37:18 +00003104
3105 /* grndint %rf, %dst */
3106 addInstr(env, X86Instr_FpUnary(Xfp_ROUND, rf, dst));
3107
sewardj4cb918d2004-12-03 19:43:31 +00003108 /* Restore default FPU rounding. */
3109 set_FPU_rounding_default( env );
sewardje6709112004-09-10 18:37:18 +00003110
sewardj4cb918d2004-12-03 19:43:31 +00003111 return dst;
3112 }
3113
sewardj6c299f32009-12-31 18:00:12 +00003114 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64StoF64) {
sewardj4cb918d2004-12-03 19:43:31 +00003115 HReg dst = newVRegF(env);
3116 HReg rHi,rLo;
3117 iselInt64Expr( &rHi, &rLo, env, e->Iex.Binop.arg2);
3118 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
3119 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
3120
3121 /* Set host rounding mode */
3122 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3123
3124 addInstr(env, X86Instr_FpLdStI(
3125 True/*load*/, 8, dst,
3126 X86AMode_IR(0, hregX86_ESP())));
3127
3128 /* Restore default FPU rounding. */
3129 set_FPU_rounding_default( env );
3130
sewardj855f32d2004-12-05 21:22:38 +00003131 add_to_esp(env, 8);
sewardje6709112004-09-10 18:37:18 +00003132 return dst;
3133 }
3134
sewardjf1b5b1a2006-02-03 22:54:17 +00003135 if (e->tag == Iex_Binop) {
3136 X86FpOp fpop = Xfp_INVALID;
3137 switch (e->Iex.Binop.op) {
3138 case Iop_SinF64: fpop = Xfp_SIN; break;
3139 case Iop_CosF64: fpop = Xfp_COS; break;
3140 case Iop_TanF64: fpop = Xfp_TAN; break;
3141 case Iop_2xm1F64: fpop = Xfp_2XM1; break;
3142 case Iop_SqrtF64: fpop = Xfp_SQRT; break;
3143 default: break;
3144 }
3145 if (fpop != Xfp_INVALID) {
3146 HReg res = newVRegF(env);
3147 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
3148 /* XXXROUNDINGFIXME */
3149 /* set roundingmode here */
sewardje9c51c92014-04-30 22:50:34 +00003150 /* Note that X86Instr_FpUnary(Xfp_TAN,..) sets the condition
3151 codes. I don't think that matters, since this insn
3152 selector never generates such an instruction intervening
3153 between an flag-setting instruction and a flag-using
3154 instruction. */
sewardjf1b5b1a2006-02-03 22:54:17 +00003155 addInstr(env, X86Instr_FpUnary(fpop,src,res));
3156 if (fpop != Xfp_SQRT
3157 && fpop != Xfp_NEG && fpop != Xfp_ABS)
3158 roundToF64(env, res);
3159 return res;
3160 }
3161 }
3162
sewardjbb53f8c2004-08-14 11:50:01 +00003163 if (e->tag == Iex_Unop) {
sewardjcfded9a2004-09-09 11:44:16 +00003164 X86FpOp fpop = Xfp_INVALID;
3165 switch (e->Iex.Unop.op) {
sewardj883b00b2004-09-11 09:30:24 +00003166 case Iop_NegF64: fpop = Xfp_NEG; break;
3167 case Iop_AbsF64: fpop = Xfp_ABS; break;
sewardjcfded9a2004-09-09 11:44:16 +00003168 default: break;
3169 }
3170 if (fpop != Xfp_INVALID) {
3171 HReg res = newVRegF(env);
3172 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
3173 addInstr(env, X86Instr_FpUnary(fpop,src,res));
sewardj633eb992013-01-20 11:38:43 +00003174 /* No need to do roundToF64(env,res) for Xfp_NEG or Xfp_ABS,
3175 but might need to do that for other unary ops. */
sewardjcfded9a2004-09-09 11:44:16 +00003176 return res;
3177 }
3178 }
3179
3180 if (e->tag == Iex_Unop) {
sewardj89cd0932004-09-08 18:23:25 +00003181 switch (e->Iex.Unop.op) {
sewardj6c299f32009-12-31 18:00:12 +00003182 case Iop_I32StoF64: {
sewardj89cd0932004-09-08 18:23:25 +00003183 HReg dst = newVRegF(env);
3184 HReg ri = iselIntExpr_R(env, e->Iex.Unop.arg);
3185 addInstr(env, X86Instr_Push(X86RMI_Reg(ri)));
sewardj4cb918d2004-12-03 19:43:31 +00003186 set_FPU_rounding_default(env);
sewardj89cd0932004-09-08 18:23:25 +00003187 addInstr(env, X86Instr_FpLdStI(
3188 True/*load*/, 4, dst,
3189 X86AMode_IR(0, hregX86_ESP())));
sewardj855f32d2004-12-05 21:22:38 +00003190 add_to_esp(env, 4);
sewardj89cd0932004-09-08 18:23:25 +00003191 return dst;
3192 }
sewardj17442fe2004-09-20 14:54:28 +00003193 case Iop_ReinterpI64asF64: {
3194 /* Given an I64, produce an IEEE754 double with the same
3195 bit pattern. */
3196 HReg dst = newVRegF(env);
3197 HReg rHi, rLo;
sewardjd08f2d72004-12-01 23:19:36 +00003198 iselInt64Expr( &rHi, &rLo, env, e->Iex.Unop.arg);
sewardj3bca9062004-12-04 14:36:09 +00003199 /* paranoia */
3200 set_FPU_rounding_default(env);
sewardj17442fe2004-09-20 14:54:28 +00003201 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
3202 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
3203 addInstr(env, X86Instr_FpLdSt(
3204 True/*load*/, 8, dst,
3205 X86AMode_IR(0, hregX86_ESP())));
sewardj855f32d2004-12-05 21:22:38 +00003206 add_to_esp(env, 8);
sewardj17442fe2004-09-20 14:54:28 +00003207 return dst;
3208 }
sewardj9c323762005-01-10 16:49:19 +00003209 case Iop_F32toF64: {
sewardj89cd0932004-09-08 18:23:25 +00003210 /* this is a no-op */
sewardj9c323762005-01-10 16:49:19 +00003211 HReg res = iselFltExpr(env, e->Iex.Unop.arg);
3212 return res;
3213 }
sewardj89cd0932004-09-08 18:23:25 +00003214 default:
3215 break;
sewardjbb53f8c2004-08-14 11:50:01 +00003216 }
3217 }
3218
sewardj33124f62004-08-30 17:54:18 +00003219 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00003220 if (e->tag == Iex_ITE) { // VFD
sewardj33124f62004-08-30 17:54:18 +00003221 if (ty == Ity_F64
florian99dd03e2013-01-29 03:56:06 +00003222 && typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
3223 HReg r1 = iselDblExpr(env, e->Iex.ITE.iftrue);
3224 HReg r0 = iselDblExpr(env, e->Iex.ITE.iffalse);
sewardjeb17e492007-08-25 23:07:44 +00003225 HReg dst = newVRegF(env);
florian99dd03e2013-01-29 03:56:06 +00003226 addInstr(env, X86Instr_FpUnary(Xfp_MOV,r1,dst));
3227 X86CondCode cc = iselCondCode(env, e->Iex.ITE.cond);
sewardj009230b2013-01-26 11:47:55 +00003228 addInstr(env, X86Instr_FpCMov(cc ^ 1, r0, dst));
sewardj33124f62004-08-30 17:54:18 +00003229 return dst;
3230 }
3231 }
3232
sewardj3196daf2004-08-13 00:18:58 +00003233 ppIRExpr(e);
sewardjd08f2d72004-12-01 23:19:36 +00003234 vpanic("iselDblExpr_wrk");
sewardj3196daf2004-08-13 00:18:58 +00003235}
3236
3237
sewardjd08f2d72004-12-01 23:19:36 +00003238/*---------------------------------------------------------*/
3239/*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/
3240/*---------------------------------------------------------*/
3241
3242static HReg iselVecExpr ( ISelEnv* env, IRExpr* e )
3243{
3244 HReg r = iselVecExpr_wrk( env, e );
3245# if 0
3246 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3247# endif
3248 vassert(hregClass(r) == HRcVec128);
3249 vassert(hregIsVirtual(r));
3250 return r;
3251}
3252
3253
3254/* DO NOT CALL THIS DIRECTLY */
3255static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
3256{
sewardj9df271d2004-12-31 22:37:42 +00003257
sewardj5117ce12006-01-27 21:20:15 +00003258# define REQUIRE_SSE1 \
mjw6c65c122013-08-27 10:19:03 +00003259 do { if (env->hwcaps == 0/*baseline, no sse*/ \
3260 || env->hwcaps == VEX_HWCAPS_X86_MMXEXT /*Integer SSE*/) \
sewardj5117ce12006-01-27 21:20:15 +00003261 goto vec_fail; \
sewardj9df271d2004-12-31 22:37:42 +00003262 } while (0)
3263
sewardj5117ce12006-01-27 21:20:15 +00003264# define REQUIRE_SSE2 \
3265 do { if (0 == (env->hwcaps & VEX_HWCAPS_X86_SSE2)) \
3266 goto vec_fail; \
sewardj9df271d2004-12-31 22:37:42 +00003267 } while (0)
3268
sewardj5117ce12006-01-27 21:20:15 +00003269# define SSE2_OR_ABOVE \
3270 (env->hwcaps & VEX_HWCAPS_X86_SSE2)
sewardj61825e02005-04-06 00:47:01 +00003271
sewardjad2c9ea2011-10-22 09:32:16 +00003272 HWord fn = 0; /* address of helper fn, if required */
sewardj61825e02005-04-06 00:47:01 +00003273 MatchInfo mi;
3274 Bool arg1isEReg = False;
3275 X86SseOp op = Xsse_INVALID;
3276 IRType ty = typeOfIRExpr(env->type_env,e);
sewardjd08f2d72004-12-01 23:19:36 +00003277 vassert(e);
3278 vassert(ty == Ity_V128);
3279
sewardj9df271d2004-12-31 22:37:42 +00003280 REQUIRE_SSE1;
3281
sewardjdd40fdf2006-12-24 02:20:24 +00003282 if (e->tag == Iex_RdTmp) {
3283 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
sewardjd08f2d72004-12-01 23:19:36 +00003284 }
3285
3286 if (e->tag == Iex_Get) {
3287 HReg dst = newVRegV(env);
3288 addInstr(env, X86Instr_SseLdSt(
3289 True/*load*/,
3290 dst,
3291 X86AMode_IR(e->Iex.Get.offset, hregX86_EBP())
3292 )
3293 );
3294 return dst;
3295 }
3296
sewardje768e922009-11-26 17:17:37 +00003297 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
sewardj1e6ad742004-12-02 16:16:11 +00003298 HReg dst = newVRegV(env);
sewardjaf1ceca2005-06-30 23:31:27 +00003299 X86AMode* am = iselIntExpr_AMode(env, e->Iex.Load.addr);
sewardj1e6ad742004-12-02 16:16:11 +00003300 addInstr(env, X86Instr_SseLdSt( True/*load*/, dst, am ));
3301 return dst;
3302 }
3303
3304 if (e->tag == Iex_Const) {
3305 HReg dst = newVRegV(env);
3306 vassert(e->Iex.Const.con->tag == Ico_V128);
3307 addInstr(env, X86Instr_SseConst(e->Iex.Const.con->Ico.V128, dst));
3308 return dst;
3309 }
3310
sewardj0bd7ce62004-12-05 02:47:40 +00003311 if (e->tag == Iex_Unop) {
sewardj61825e02005-04-06 00:47:01 +00003312
3313 if (SSE2_OR_ABOVE) {
3314 /* 64UtoV128(LDle:I64(addr)) */
3315 DECLARE_PATTERN(p_zwiden_load64);
3316 DEFINE_PATTERN(p_zwiden_load64,
sewardjaf1ceca2005-06-30 23:31:27 +00003317 unop(Iop_64UtoV128,
sewardje768e922009-11-26 17:17:37 +00003318 IRExpr_Load(Iend_LE,Ity_I64,bind(0))));
sewardj61825e02005-04-06 00:47:01 +00003319 if (matchIRExpr(&mi, p_zwiden_load64, e)) {
3320 X86AMode* am = iselIntExpr_AMode(env, mi.bindee[0]);
3321 HReg dst = newVRegV(env);
3322 addInstr(env, X86Instr_SseLdzLO(8, dst, am));
3323 return dst;
3324 }
3325 }
3326
sewardj0bd7ce62004-12-05 02:47:40 +00003327 switch (e->Iex.Unop.op) {
3328
sewardjf0c1c582005-02-07 23:47:38 +00003329 case Iop_NotV128: {
sewardj2e383862004-12-12 16:46:47 +00003330 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3331 return do_sse_Not128(env, arg);
3332 }
3333
sewardj109ffdb2004-12-10 21:45:38 +00003334 case Iop_CmpNEZ64x2: {
sewardj2e383862004-12-12 16:46:47 +00003335 /* We can use SSE2 instructions for this. */
sewardj109ffdb2004-12-10 21:45:38 +00003336 /* Ideally, we want to do a 64Ix2 comparison against zero of
3337 the operand. Problem is no such insn exists. Solution
3338 therefore is to do a 32Ix4 comparison instead, and bitwise-
3339 negate (NOT) the result. Let a,b,c,d be 32-bit lanes, and
3340 let the not'd result of this initial comparison be a:b:c:d.
3341 What we need to compute is (a|b):(a|b):(c|d):(c|d). So, use
3342 pshufd to create a value b:a:d:c, and OR that with a:b:c:d,
3343 giving the required result.
3344
3345 The required selection sequence is 2,3,0,1, which
3346 according to Intel's documentation means the pshufd
3347 literal value is 0xB1, that is,
3348 (2 << 6) | (3 << 4) | (0 << 2) | (1 << 0)
3349 */
sewardj109ffdb2004-12-10 21:45:38 +00003350 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3351 HReg tmp = newVRegV(env);
3352 HReg dst = newVRegV(env);
sewardj9df271d2004-12-31 22:37:42 +00003353 REQUIRE_SSE2;
sewardj109ffdb2004-12-10 21:45:38 +00003354 addInstr(env, X86Instr_SseReRg(Xsse_XOR, tmp, tmp));
3355 addInstr(env, X86Instr_SseReRg(Xsse_CMPEQ32, arg, tmp));
sewardj2e383862004-12-12 16:46:47 +00003356 tmp = do_sse_Not128(env, tmp);
sewardj109ffdb2004-12-10 21:45:38 +00003357 addInstr(env, X86Instr_SseShuf(0xB1, tmp, dst));
3358 addInstr(env, X86Instr_SseReRg(Xsse_OR, tmp, dst));
3359 return dst;
3360 }
3361
sewardj70f676d2004-12-10 14:59:57 +00003362 case Iop_CmpNEZ32x4: {
sewardj2e383862004-12-12 16:46:47 +00003363 /* Sigh, we have to generate lousy code since this has to
3364 work on SSE1 hosts */
sewardj70f676d2004-12-10 14:59:57 +00003365 /* basically, the idea is: for each lane:
3366 movl lane, %r ; negl %r (now CF = lane==0 ? 0 : 1)
3367 sbbl %r, %r (now %r = 1Sto32(CF))
3368 movl %r, lane
3369 */
3370 Int i;
3371 X86AMode* am;
3372 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
3373 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3374 HReg dst = newVRegV(env);
3375 HReg r32 = newVRegI(env);
3376 sub_from_esp(env, 16);
3377 addInstr(env, X86Instr_SseLdSt(False/*store*/, arg, esp0));
3378 for (i = 0; i < 4; i++) {
3379 am = X86AMode_IR(i*4, hregX86_ESP());
3380 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(am), r32));
sewardjeba63f82005-02-23 13:31:25 +00003381 addInstr(env, X86Instr_Unary32(Xun_NEG, r32));
sewardj70f676d2004-12-10 14:59:57 +00003382 addInstr(env, X86Instr_Alu32R(Xalu_SBB, X86RMI_Reg(r32), r32));
3383 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r32), am));
3384 }
3385 addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
3386 add_to_esp(env, 16);
3387 return dst;
3388 }
3389
sewardj2e383862004-12-12 16:46:47 +00003390 case Iop_CmpNEZ8x16:
3391 case Iop_CmpNEZ16x8: {
3392 /* We can use SSE2 instructions for this. */
3393 HReg arg;
3394 HReg vec0 = newVRegV(env);
3395 HReg vec1 = newVRegV(env);
3396 HReg dst = newVRegV(env);
3397 X86SseOp cmpOp
3398 = e->Iex.Unop.op==Iop_CmpNEZ16x8 ? Xsse_CMPEQ16
3399 : Xsse_CMPEQ8;
sewardj9df271d2004-12-31 22:37:42 +00003400 REQUIRE_SSE2;
sewardj2e383862004-12-12 16:46:47 +00003401 addInstr(env, X86Instr_SseReRg(Xsse_XOR, vec0, vec0));
3402 addInstr(env, mk_vMOVsd_RR(vec0, vec1));
3403 addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, vec1, vec1));
3404 /* defer arg computation to here so as to give CMPEQF as long
3405 as possible to complete */
3406 arg = iselVecExpr(env, e->Iex.Unop.arg);
3407 /* vec0 is all 0s; vec1 is all 1s */
3408 addInstr(env, mk_vMOVsd_RR(arg, dst));
3409 /* 16x8 or 8x16 comparison == */
3410 addInstr(env, X86Instr_SseReRg(cmpOp, vec0, dst));
3411 /* invert result */
3412 addInstr(env, X86Instr_SseReRg(Xsse_XOR, vec1, dst));
3413 return dst;
3414 }
3415
sewardj1ddee212014-08-24 14:00:19 +00003416 case Iop_RecipEst32Fx4: op = Xsse_RCPF; goto do_32Fx4_unary;
3417 case Iop_RSqrtEst32Fx4: op = Xsse_RSQRTF; goto do_32Fx4_unary;
3418 case Iop_Sqrt32Fx4: op = Xsse_SQRTF; goto do_32Fx4_unary;
sewardj0bd7ce62004-12-05 02:47:40 +00003419 do_32Fx4_unary:
3420 {
3421 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3422 HReg dst = newVRegV(env);
3423 addInstr(env, X86Instr_Sse32Fx4(op, arg, dst));
3424 return dst;
3425 }
3426
sewardj636ad762004-12-07 11:16:04 +00003427 case Iop_Sqrt64Fx2: op = Xsse_SQRTF; goto do_64Fx2_unary;
3428 do_64Fx2_unary:
3429 {
3430 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3431 HReg dst = newVRegV(env);
sewardj9df271d2004-12-31 22:37:42 +00003432 REQUIRE_SSE2;
sewardj636ad762004-12-07 11:16:04 +00003433 addInstr(env, X86Instr_Sse64Fx2(op, arg, dst));
3434 return dst;
3435 }
3436
sewardj1ddee212014-08-24 14:00:19 +00003437 case Iop_RecipEst32F0x4: op = Xsse_RCPF; goto do_32F0x4_unary;
3438 case Iop_RSqrtEst32F0x4: op = Xsse_RSQRTF; goto do_32F0x4_unary;
3439 case Iop_Sqrt32F0x4: op = Xsse_SQRTF; goto do_32F0x4_unary;
sewardj0bd7ce62004-12-05 02:47:40 +00003440 do_32F0x4_unary:
3441 {
sewardj129b3d92004-12-05 15:42:05 +00003442 /* A bit subtle. We have to copy the arg to the result
3443 register first, because actually doing the SSE scalar insn
3444 leaves the upper 3/4 of the destination register
3445 unchanged. Whereas the required semantics of these
3446 primops is that the upper 3/4 is simply copied in from the
3447 argument. */
sewardj0bd7ce62004-12-05 02:47:40 +00003448 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3449 HReg dst = newVRegV(env);
sewardj129b3d92004-12-05 15:42:05 +00003450 addInstr(env, mk_vMOVsd_RR(arg, dst));
sewardj0bd7ce62004-12-05 02:47:40 +00003451 addInstr(env, X86Instr_Sse32FLo(op, arg, dst));
3452 return dst;
3453 }
3454
sewardj636ad762004-12-07 11:16:04 +00003455 case Iop_Sqrt64F0x2: op = Xsse_SQRTF; goto do_64F0x2_unary;
3456 do_64F0x2_unary:
3457 {
3458 /* A bit subtle. We have to copy the arg to the result
3459 register first, because actually doing the SSE scalar insn
3460 leaves the upper half of the destination register
3461 unchanged. Whereas the required semantics of these
3462 primops is that the upper half is simply copied in from the
3463 argument. */
3464 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3465 HReg dst = newVRegV(env);
sewardj9df271d2004-12-31 22:37:42 +00003466 REQUIRE_SSE2;
sewardj636ad762004-12-07 11:16:04 +00003467 addInstr(env, mk_vMOVsd_RR(arg, dst));
3468 addInstr(env, X86Instr_Sse64FLo(op, arg, dst));
3469 return dst;
3470 }
3471
sewardjf0c1c582005-02-07 23:47:38 +00003472 case Iop_32UtoV128: {
sewardj129b3d92004-12-05 15:42:05 +00003473 HReg dst = newVRegV(env);
3474 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
3475 X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Unop.arg);
3476 addInstr(env, X86Instr_Push(rmi));
3477 addInstr(env, X86Instr_SseLdzLO(4, dst, esp0));
sewardj855f32d2004-12-05 21:22:38 +00003478 add_to_esp(env, 4);
sewardj129b3d92004-12-05 15:42:05 +00003479 return dst;
3480 }
3481
sewardjf0c1c582005-02-07 23:47:38 +00003482 case Iop_64UtoV128: {
sewardj636ad762004-12-07 11:16:04 +00003483 HReg rHi, rLo;
3484 HReg dst = newVRegV(env);
3485 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
3486 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
3487 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
3488 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
3489 addInstr(env, X86Instr_SseLdzLO(8, dst, esp0));
3490 add_to_esp(env, 8);
3491 return dst;
3492 }
3493
sewardj0bd7ce62004-12-05 02:47:40 +00003494 default:
3495 break;
3496 } /* switch (e->Iex.Unop.op) */
3497 } /* if (e->tag == Iex_Unop) */
3498
sewardjd08f2d72004-12-01 23:19:36 +00003499 if (e->tag == Iex_Binop) {
sewardj1e6ad742004-12-02 16:16:11 +00003500 switch (e->Iex.Binop.op) {
sewardj129b3d92004-12-05 15:42:05 +00003501
sewardjf0c1c582005-02-07 23:47:38 +00003502 case Iop_SetV128lo32: {
sewardj129b3d92004-12-05 15:42:05 +00003503 HReg dst = newVRegV(env);
3504 HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1);
3505 HReg srcI = iselIntExpr_R(env, e->Iex.Binop.arg2);
3506 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
sewardj855f32d2004-12-05 21:22:38 +00003507 sub_from_esp(env, 16);
sewardj129b3d92004-12-05 15:42:05 +00003508 addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0));
3509 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcI), esp0));
3510 addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
sewardj855f32d2004-12-05 21:22:38 +00003511 add_to_esp(env, 16);
sewardj129b3d92004-12-05 15:42:05 +00003512 return dst;
3513 }
3514
sewardjf0c1c582005-02-07 23:47:38 +00003515 case Iop_SetV128lo64: {
sewardj008754b2004-12-08 14:37:10 +00003516 HReg dst = newVRegV(env);
3517 HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1);
3518 HReg srcIhi, srcIlo;
3519 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
3520 X86AMode* esp4 = advance4(esp0);
3521 iselInt64Expr(&srcIhi, &srcIlo, env, e->Iex.Binop.arg2);
3522 sub_from_esp(env, 16);
3523 addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0));
3524 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIlo), esp0));
3525 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIhi), esp4));
3526 addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
3527 add_to_esp(env, 16);
3528 return dst;
3529 }
3530
sewardjf0c1c582005-02-07 23:47:38 +00003531 case Iop_64HLtoV128: {
sewardjd08f2d72004-12-01 23:19:36 +00003532 HReg r3, r2, r1, r0;
3533 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
3534 X86AMode* esp4 = advance4(esp0);
3535 X86AMode* esp8 = advance4(esp4);
3536 X86AMode* esp12 = advance4(esp8);
3537 HReg dst = newVRegV(env);
3538 /* do this via the stack (easy, convenient, etc) */
sewardj855f32d2004-12-05 21:22:38 +00003539 sub_from_esp(env, 16);
sewardjd08f2d72004-12-01 23:19:36 +00003540 /* Do the less significant 64 bits */
3541 iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2);
3542 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r0), esp0));
3543 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r1), esp4));
3544 /* Do the more significant 64 bits */
3545 iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1);
3546 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r2), esp8));
3547 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r3), esp12));
3548 /* Fetch result back from stack. */
3549 addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
sewardj855f32d2004-12-05 21:22:38 +00003550 add_to_esp(env, 16);
sewardjd08f2d72004-12-01 23:19:36 +00003551 return dst;
3552 }
sewardj1e6ad742004-12-02 16:16:11 +00003553
sewardj1e6ad742004-12-02 16:16:11 +00003554 case Iop_CmpEQ32Fx4: op = Xsse_CMPEQF; goto do_32Fx4;
3555 case Iop_CmpLT32Fx4: op = Xsse_CMPLTF; goto do_32Fx4;
3556 case Iop_CmpLE32Fx4: op = Xsse_CMPLEF; goto do_32Fx4;
sewardja26f6612005-11-05 01:54:07 +00003557 case Iop_CmpUN32Fx4: op = Xsse_CMPUNF; goto do_32Fx4;
sewardj176a59c2004-12-03 20:08:31 +00003558 case Iop_Max32Fx4: op = Xsse_MAXF; goto do_32Fx4;
3559 case Iop_Min32Fx4: op = Xsse_MINF; goto do_32Fx4;
sewardj1e6ad742004-12-02 16:16:11 +00003560 do_32Fx4:
3561 {
3562 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3563 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3564 HReg dst = newVRegV(env);
3565 addInstr(env, mk_vMOVsd_RR(argL, dst));
3566 addInstr(env, X86Instr_Sse32Fx4(op, argR, dst));
3567 return dst;
3568 }
3569
sewardj636ad762004-12-07 11:16:04 +00003570 case Iop_CmpEQ64Fx2: op = Xsse_CMPEQF; goto do_64Fx2;
3571 case Iop_CmpLT64Fx2: op = Xsse_CMPLTF; goto do_64Fx2;
3572 case Iop_CmpLE64Fx2: op = Xsse_CMPLEF; goto do_64Fx2;
sewardja26f6612005-11-05 01:54:07 +00003573 case Iop_CmpUN64Fx2: op = Xsse_CMPUNF; goto do_64Fx2;
sewardj636ad762004-12-07 11:16:04 +00003574 case Iop_Max64Fx2: op = Xsse_MAXF; goto do_64Fx2;
3575 case Iop_Min64Fx2: op = Xsse_MINF; goto do_64Fx2;
sewardj636ad762004-12-07 11:16:04 +00003576 do_64Fx2:
3577 {
3578 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3579 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3580 HReg dst = newVRegV(env);
sewardj9df271d2004-12-31 22:37:42 +00003581 REQUIRE_SSE2;
sewardj636ad762004-12-07 11:16:04 +00003582 addInstr(env, mk_vMOVsd_RR(argL, dst));
3583 addInstr(env, X86Instr_Sse64Fx2(op, argR, dst));
3584 return dst;
3585 }
3586
sewardj1e6ad742004-12-02 16:16:11 +00003587 case Iop_CmpEQ32F0x4: op = Xsse_CMPEQF; goto do_32F0x4;
3588 case Iop_CmpLT32F0x4: op = Xsse_CMPLTF; goto do_32F0x4;
3589 case Iop_CmpLE32F0x4: op = Xsse_CMPLEF; goto do_32F0x4;
sewardja26f6612005-11-05 01:54:07 +00003590 case Iop_CmpUN32F0x4: op = Xsse_CMPUNF; goto do_32F0x4;
sewardj1e6ad742004-12-02 16:16:11 +00003591 case Iop_Add32F0x4: op = Xsse_ADDF; goto do_32F0x4;
sewardj176a59c2004-12-03 20:08:31 +00003592 case Iop_Div32F0x4: op = Xsse_DIVF; goto do_32F0x4;
3593 case Iop_Max32F0x4: op = Xsse_MAXF; goto do_32F0x4;
3594 case Iop_Min32F0x4: op = Xsse_MINF; goto do_32F0x4;
sewardj9636b442004-12-04 01:38:37 +00003595 case Iop_Mul32F0x4: op = Xsse_MULF; goto do_32F0x4;
sewardjc1e7dfc2004-12-05 19:29:45 +00003596 case Iop_Sub32F0x4: op = Xsse_SUBF; goto do_32F0x4;
sewardj1e6ad742004-12-02 16:16:11 +00003597 do_32F0x4: {
3598 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3599 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3600 HReg dst = newVRegV(env);
3601 addInstr(env, mk_vMOVsd_RR(argL, dst));
3602 addInstr(env, X86Instr_Sse32FLo(op, argR, dst));
3603 return dst;
3604 }
3605
sewardj636ad762004-12-07 11:16:04 +00003606 case Iop_CmpEQ64F0x2: op = Xsse_CMPEQF; goto do_64F0x2;
3607 case Iop_CmpLT64F0x2: op = Xsse_CMPLTF; goto do_64F0x2;
3608 case Iop_CmpLE64F0x2: op = Xsse_CMPLEF; goto do_64F0x2;
sewardja26f6612005-11-05 01:54:07 +00003609 case Iop_CmpUN64F0x2: op = Xsse_CMPUNF; goto do_64F0x2;
sewardj636ad762004-12-07 11:16:04 +00003610 case Iop_Add64F0x2: op = Xsse_ADDF; goto do_64F0x2;
3611 case Iop_Div64F0x2: op = Xsse_DIVF; goto do_64F0x2;
3612 case Iop_Max64F0x2: op = Xsse_MAXF; goto do_64F0x2;
3613 case Iop_Min64F0x2: op = Xsse_MINF; goto do_64F0x2;
3614 case Iop_Mul64F0x2: op = Xsse_MULF; goto do_64F0x2;
3615 case Iop_Sub64F0x2: op = Xsse_SUBF; goto do_64F0x2;
3616 do_64F0x2: {
3617 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3618 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3619 HReg dst = newVRegV(env);
sewardj9df271d2004-12-31 22:37:42 +00003620 REQUIRE_SSE2;
sewardj636ad762004-12-07 11:16:04 +00003621 addInstr(env, mk_vMOVsd_RR(argL, dst));
3622 addInstr(env, X86Instr_Sse64FLo(op, argR, dst));
3623 return dst;
3624 }
3625
sewardj5f438dd2011-06-16 11:36:23 +00003626 case Iop_QNarrowBin32Sto16Sx8:
sewardj9e203592004-12-10 01:48:18 +00003627 op = Xsse_PACKSSD; arg1isEReg = True; goto do_SseReRg;
sewardj5f438dd2011-06-16 11:36:23 +00003628 case Iop_QNarrowBin16Sto8Sx16:
sewardj9e203592004-12-10 01:48:18 +00003629 op = Xsse_PACKSSW; arg1isEReg = True; goto do_SseReRg;
sewardj5f438dd2011-06-16 11:36:23 +00003630 case Iop_QNarrowBin16Sto8Ux16:
sewardj9e203592004-12-10 01:48:18 +00003631 op = Xsse_PACKUSW; arg1isEReg = True; goto do_SseReRg;
3632
3633 case Iop_InterleaveHI8x16:
3634 op = Xsse_UNPCKHB; arg1isEReg = True; goto do_SseReRg;
3635 case Iop_InterleaveHI16x8:
3636 op = Xsse_UNPCKHW; arg1isEReg = True; goto do_SseReRg;
3637 case Iop_InterleaveHI32x4:
3638 op = Xsse_UNPCKHD; arg1isEReg = True; goto do_SseReRg;
3639 case Iop_InterleaveHI64x2:
3640 op = Xsse_UNPCKHQ; arg1isEReg = True; goto do_SseReRg;
3641
3642 case Iop_InterleaveLO8x16:
3643 op = Xsse_UNPCKLB; arg1isEReg = True; goto do_SseReRg;
3644 case Iop_InterleaveLO16x8:
3645 op = Xsse_UNPCKLW; arg1isEReg = True; goto do_SseReRg;
3646 case Iop_InterleaveLO32x4:
3647 op = Xsse_UNPCKLD; arg1isEReg = True; goto do_SseReRg;
3648 case Iop_InterleaveLO64x2:
3649 op = Xsse_UNPCKLQ; arg1isEReg = True; goto do_SseReRg;
3650
sewardjf0c1c582005-02-07 23:47:38 +00003651 case Iop_AndV128: op = Xsse_AND; goto do_SseReRg;
3652 case Iop_OrV128: op = Xsse_OR; goto do_SseReRg;
3653 case Iop_XorV128: op = Xsse_XOR; goto do_SseReRg;
sewardje5854d62004-12-09 03:44:34 +00003654 case Iop_Add8x16: op = Xsse_ADD8; goto do_SseReRg;
3655 case Iop_Add16x8: op = Xsse_ADD16; goto do_SseReRg;
3656 case Iop_Add32x4: op = Xsse_ADD32; goto do_SseReRg;
3657 case Iop_Add64x2: op = Xsse_ADD64; goto do_SseReRg;
3658 case Iop_QAdd8Sx16: op = Xsse_QADD8S; goto do_SseReRg;
3659 case Iop_QAdd16Sx8: op = Xsse_QADD16S; goto do_SseReRg;
3660 case Iop_QAdd8Ux16: op = Xsse_QADD8U; goto do_SseReRg;
3661 case Iop_QAdd16Ux8: op = Xsse_QADD16U; goto do_SseReRg;
3662 case Iop_Avg8Ux16: op = Xsse_AVG8U; goto do_SseReRg;
3663 case Iop_Avg16Ux8: op = Xsse_AVG16U; goto do_SseReRg;
3664 case Iop_CmpEQ8x16: op = Xsse_CMPEQ8; goto do_SseReRg;
3665 case Iop_CmpEQ16x8: op = Xsse_CMPEQ16; goto do_SseReRg;
3666 case Iop_CmpEQ32x4: op = Xsse_CMPEQ32; goto do_SseReRg;
3667 case Iop_CmpGT8Sx16: op = Xsse_CMPGT8S; goto do_SseReRg;
3668 case Iop_CmpGT16Sx8: op = Xsse_CMPGT16S; goto do_SseReRg;
3669 case Iop_CmpGT32Sx4: op = Xsse_CMPGT32S; goto do_SseReRg;
3670 case Iop_Max16Sx8: op = Xsse_MAX16S; goto do_SseReRg;
3671 case Iop_Max8Ux16: op = Xsse_MAX8U; goto do_SseReRg;
3672 case Iop_Min16Sx8: op = Xsse_MIN16S; goto do_SseReRg;
3673 case Iop_Min8Ux16: op = Xsse_MIN8U; goto do_SseReRg;
3674 case Iop_MulHi16Ux8: op = Xsse_MULHI16U; goto do_SseReRg;
3675 case Iop_MulHi16Sx8: op = Xsse_MULHI16S; goto do_SseReRg;
3676 case Iop_Mul16x8: op = Xsse_MUL16; goto do_SseReRg;
sewardjb9fa69b2004-12-09 23:25:14 +00003677 case Iop_Sub8x16: op = Xsse_SUB8; goto do_SseReRg;
3678 case Iop_Sub16x8: op = Xsse_SUB16; goto do_SseReRg;
3679 case Iop_Sub32x4: op = Xsse_SUB32; goto do_SseReRg;
3680 case Iop_Sub64x2: op = Xsse_SUB64; goto do_SseReRg;
3681 case Iop_QSub8Sx16: op = Xsse_QSUB8S; goto do_SseReRg;
3682 case Iop_QSub16Sx8: op = Xsse_QSUB16S; goto do_SseReRg;
3683 case Iop_QSub8Ux16: op = Xsse_QSUB8U; goto do_SseReRg;
3684 case Iop_QSub16Ux8: op = Xsse_QSUB16U; goto do_SseReRg;
sewardj164f9272004-12-09 00:39:32 +00003685 do_SseReRg: {
3686 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3687 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3688 HReg dst = newVRegV(env);
sewardj9df271d2004-12-31 22:37:42 +00003689 if (op != Xsse_OR && op != Xsse_AND && op != Xsse_XOR)
3690 REQUIRE_SSE2;
sewardj164f9272004-12-09 00:39:32 +00003691 if (arg1isEReg) {
3692 addInstr(env, mk_vMOVsd_RR(arg2, dst));
3693 addInstr(env, X86Instr_SseReRg(op, arg1, dst));
3694 } else {
3695 addInstr(env, mk_vMOVsd_RR(arg1, dst));
3696 addInstr(env, X86Instr_SseReRg(op, arg2, dst));
3697 }
3698 return dst;
3699 }
3700
sewardjb9fa69b2004-12-09 23:25:14 +00003701 case Iop_ShlN16x8: op = Xsse_SHL16; goto do_SseShift;
3702 case Iop_ShlN32x4: op = Xsse_SHL32; goto do_SseShift;
3703 case Iop_ShlN64x2: op = Xsse_SHL64; goto do_SseShift;
3704 case Iop_SarN16x8: op = Xsse_SAR16; goto do_SseShift;
3705 case Iop_SarN32x4: op = Xsse_SAR32; goto do_SseShift;
3706 case Iop_ShrN16x8: op = Xsse_SHR16; goto do_SseShift;
3707 case Iop_ShrN32x4: op = Xsse_SHR32; goto do_SseShift;
3708 case Iop_ShrN64x2: op = Xsse_SHR64; goto do_SseShift;
3709 do_SseShift: {
3710 HReg greg = iselVecExpr(env, e->Iex.Binop.arg1);
3711 X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
3712 X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
3713 HReg ereg = newVRegV(env);
3714 HReg dst = newVRegV(env);
sewardj9df271d2004-12-31 22:37:42 +00003715 REQUIRE_SSE2;
sewardjb9fa69b2004-12-09 23:25:14 +00003716 addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
3717 addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
3718 addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
3719 addInstr(env, X86Instr_Push(rmi));
3720 addInstr(env, X86Instr_SseLdSt(True/*load*/, ereg, esp0));
3721 addInstr(env, mk_vMOVsd_RR(greg, dst));
3722 addInstr(env, X86Instr_SseReRg(op, ereg, dst));
3723 add_to_esp(env, 16);
3724 return dst;
3725 }
3726
sewardjad2c9ea2011-10-22 09:32:16 +00003727 case Iop_NarrowBin32to16x8:
3728 fn = (HWord)h_generic_calc_NarrowBin32to16x8;
3729 goto do_SseAssistedBinary;
3730 case Iop_NarrowBin16to8x16:
3731 fn = (HWord)h_generic_calc_NarrowBin16to8x16;
3732 goto do_SseAssistedBinary;
3733 do_SseAssistedBinary: {
3734 /* As with the amd64 case (where this is copied from) we
3735 generate pretty bad code. */
3736 vassert(fn != 0);
3737 HReg dst = newVRegV(env);
3738 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3739 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3740 HReg argp = newVRegI(env);
3741 /* subl $112, %esp -- make a space */
3742 sub_from_esp(env, 112);
3743 /* leal 48(%esp), %r_argp -- point into it */
3744 addInstr(env, X86Instr_Lea32(X86AMode_IR(48, hregX86_ESP()),
3745 argp));
3746 /* andl $-16, %r_argp -- 16-align the pointer */
3747 addInstr(env, X86Instr_Alu32R(Xalu_AND,
3748 X86RMI_Imm( ~(UInt)15 ),
3749 argp));
3750 /* Prepare 3 arg regs:
3751 leal 0(%r_argp), %eax
3752 leal 16(%r_argp), %edx
3753 leal 32(%r_argp), %ecx
3754 */
3755 addInstr(env, X86Instr_Lea32(X86AMode_IR(0, argp),
3756 hregX86_EAX()));
3757 addInstr(env, X86Instr_Lea32(X86AMode_IR(16, argp),
3758 hregX86_EDX()));
3759 addInstr(env, X86Instr_Lea32(X86AMode_IR(32, argp),
3760 hregX86_ECX()));
3761 /* Store the two args, at (%edx) and (%ecx):
3762 movupd %argL, 0(%edx)
3763 movupd %argR, 0(%ecx)
3764 */
3765 addInstr(env, X86Instr_SseLdSt(False/*!isLoad*/, argL,
3766 X86AMode_IR(0, hregX86_EDX())));
3767 addInstr(env, X86Instr_SseLdSt(False/*!isLoad*/, argR,
3768 X86AMode_IR(0, hregX86_ECX())));
3769 /* call the helper */
sewardjcfe046e2013-01-17 14:23:53 +00003770 addInstr(env, X86Instr_Call( Xcc_ALWAYS, (Addr32)fn,
sewardj74142b82013-08-08 10:28:59 +00003771 3, mk_RetLoc_simple(RLPri_None) ));
sewardjad2c9ea2011-10-22 09:32:16 +00003772 /* fetch the result from memory, using %r_argp, which the
3773 register allocator will keep alive across the call. */
3774 addInstr(env, X86Instr_SseLdSt(True/*isLoad*/, dst,
3775 X86AMode_IR(0, argp)));
3776 /* and finally, clear the space */
3777 add_to_esp(env, 112);
3778 return dst;
3779 }
3780
sewardjd08f2d72004-12-01 23:19:36 +00003781 default:
3782 break;
sewardj1e6ad742004-12-02 16:16:11 +00003783 } /* switch (e->Iex.Binop.op) */
sewardjd08f2d72004-12-01 23:19:36 +00003784 } /* if (e->tag == Iex_Binop) */
3785
sewardj9571dc02014-01-26 18:34:23 +00003786
3787 if (e->tag == Iex_Triop) {
3788 IRTriop *triop = e->Iex.Triop.details;
3789 switch (triop->op) {
3790
3791 case Iop_Add32Fx4: op = Xsse_ADDF; goto do_32Fx4_w_rm;
3792 case Iop_Sub32Fx4: op = Xsse_SUBF; goto do_32Fx4_w_rm;
3793 case Iop_Mul32Fx4: op = Xsse_MULF; goto do_32Fx4_w_rm;
3794 case Iop_Div32Fx4: op = Xsse_DIVF; goto do_32Fx4_w_rm;
3795 do_32Fx4_w_rm:
3796 {
3797 HReg argL = iselVecExpr(env, triop->arg2);
3798 HReg argR = iselVecExpr(env, triop->arg3);
3799 HReg dst = newVRegV(env);
3800 addInstr(env, mk_vMOVsd_RR(argL, dst));
3801 /* XXXROUNDINGFIXME */
3802 /* set roundingmode here */
3803 addInstr(env, X86Instr_Sse32Fx4(op, argR, dst));
3804 return dst;
3805 }
3806
3807 case Iop_Add64Fx2: op = Xsse_ADDF; goto do_64Fx2_w_rm;
3808 case Iop_Sub64Fx2: op = Xsse_SUBF; goto do_64Fx2_w_rm;
3809 case Iop_Mul64Fx2: op = Xsse_MULF; goto do_64Fx2_w_rm;
3810 case Iop_Div64Fx2: op = Xsse_DIVF; goto do_64Fx2_w_rm;
3811 do_64Fx2_w_rm:
3812 {
3813 HReg argL = iselVecExpr(env, triop->arg2);
3814 HReg argR = iselVecExpr(env, triop->arg3);
3815 HReg dst = newVRegV(env);
3816 REQUIRE_SSE2;
3817 addInstr(env, mk_vMOVsd_RR(argL, dst));
3818 /* XXXROUNDINGFIXME */
3819 /* set roundingmode here */
3820 addInstr(env, X86Instr_Sse64Fx2(op, argR, dst));
3821 return dst;
3822 }
3823
3824 default:
3825 break;
3826 } /* switch (triop->op) */
3827 } /* if (e->tag == Iex_Triop) */
3828
3829
florian99dd03e2013-01-29 03:56:06 +00003830 if (e->tag == Iex_ITE) { // VFD
3831 HReg r1 = iselVecExpr(env, e->Iex.ITE.iftrue);
3832 HReg r0 = iselVecExpr(env, e->Iex.ITE.iffalse);
sewardjeb17e492007-08-25 23:07:44 +00003833 HReg dst = newVRegV(env);
florian99dd03e2013-01-29 03:56:06 +00003834 addInstr(env, mk_vMOVsd_RR(r1,dst));
3835 X86CondCode cc = iselCondCode(env, e->Iex.ITE.cond);
sewardj009230b2013-01-26 11:47:55 +00003836 addInstr(env, X86Instr_SseCMov(cc ^ 1, r0, dst));
sewardjb9fa69b2004-12-09 23:25:14 +00003837 return dst;
3838 }
3839
sewardj9df271d2004-12-31 22:37:42 +00003840 vec_fail:
sewardj5117ce12006-01-27 21:20:15 +00003841 vex_printf("iselVecExpr (hwcaps = %s): can't reduce\n",
3842 LibVEX_ppVexHwCaps(VexArchX86,env->hwcaps));
sewardjd08f2d72004-12-01 23:19:36 +00003843 ppIRExpr(e);
sewardj1e6ad742004-12-02 16:16:11 +00003844 vpanic("iselVecExpr_wrk");
sewardj9df271d2004-12-31 22:37:42 +00003845
3846# undef REQUIRE_SSE1
3847# undef REQUIRE_SSE2
sewardj61825e02005-04-06 00:47:01 +00003848# undef SSE2_OR_ABOVE
sewardjd08f2d72004-12-01 23:19:36 +00003849}
3850
sewardj3196daf2004-08-13 00:18:58 +00003851
3852/*---------------------------------------------------------*/
sewardjc97096c2004-06-30 09:28:04 +00003853/*--- ISEL: Statements ---*/
3854/*---------------------------------------------------------*/
3855
sewardjf13a16a2004-07-05 17:10:14 +00003856static void iselStmt ( ISelEnv* env, IRStmt* stmt )
sewardjc97096c2004-06-30 09:28:04 +00003857{
sewardjf48ac192004-10-29 00:41:29 +00003858 if (vex_traceflags & VEX_TRACE_VCODE) {
3859 vex_printf("\n-- ");
sewardj1f40a0a2004-07-21 12:28:07 +00003860 ppIRStmt(stmt);
3861 vex_printf("\n");
3862 }
sewardj66f2f792004-06-30 16:37:16 +00003863
sewardjc97096c2004-06-30 09:28:04 +00003864 switch (stmt->tag) {
3865
sewardj60f4e3c2004-07-19 01:56:50 +00003866 /* --------- STORE --------- */
sewardjaf1ceca2005-06-30 23:31:27 +00003867 case Ist_Store: {
sewardje9d8a262009-07-01 08:06:34 +00003868 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
3869 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3870 IREndness end = stmt->Ist.Store.end;
sewardjaf1ceca2005-06-30 23:31:27 +00003871
sewardje768e922009-11-26 17:17:37 +00003872 if (tya != Ity_I32 || end != Iend_LE)
sewardjaf1ceca2005-06-30 23:31:27 +00003873 goto stmt_fail;
3874
sewardjd9c2b792004-07-08 01:44:38 +00003875 if (tyd == Ity_I32) {
sewardjbf0d86c2007-11-26 23:18:52 +00003876 X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.Store.addr);
sewardjaf1ceca2005-06-30 23:31:27 +00003877 X86RI* ri = iselIntExpr_RI(env, stmt->Ist.Store.data);
sewardjd9c2b792004-07-08 01:44:38 +00003878 addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am));
3879 return;
3880 }
sewardj60f4e3c2004-07-19 01:56:50 +00003881 if (tyd == Ity_I8 || tyd == Ity_I16) {
sewardjbf0d86c2007-11-26 23:18:52 +00003882 X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.Store.addr);
sewardjaf1ceca2005-06-30 23:31:27 +00003883 HReg r = iselIntExpr_R(env, stmt->Ist.Store.data);
sewardj428fabd2005-03-21 03:11:17 +00003884 addInstr(env, X86Instr_Store( toUChar(tyd==Ity_I8 ? 1 : 2),
3885 r,am ));
sewardj443cd9d2004-07-18 23:06:45 +00003886 return;
3887 }
sewardja58ea662004-08-15 03:12:41 +00003888 if (tyd == Ity_F64) {
sewardjbf0d86c2007-11-26 23:18:52 +00003889 X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.Store.addr);
sewardjaf1ceca2005-06-30 23:31:27 +00003890 HReg r = iselDblExpr(env, stmt->Ist.Store.data);
sewardja58ea662004-08-15 03:12:41 +00003891 addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am));
3892 return;
3893 }
sewardj89cd0932004-09-08 18:23:25 +00003894 if (tyd == Ity_F32) {
sewardjbf0d86c2007-11-26 23:18:52 +00003895 X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.Store.addr);
sewardjaf1ceca2005-06-30 23:31:27 +00003896 HReg r = iselFltExpr(env, stmt->Ist.Store.data);
sewardj89cd0932004-09-08 18:23:25 +00003897 addInstr(env, X86Instr_FpLdSt(False/*store*/, 4, r, am));
3898 return;
3899 }
sewardjcfded9a2004-09-09 11:44:16 +00003900 if (tyd == Ity_I64) {
3901 HReg vHi, vLo, rA;
sewardjaf1ceca2005-06-30 23:31:27 +00003902 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data);
3903 rA = iselIntExpr_R(env, stmt->Ist.Store.addr);
sewardjcfded9a2004-09-09 11:44:16 +00003904 addInstr(env, X86Instr_Alu32M(
3905 Xalu_MOV, X86RI_Reg(vLo), X86AMode_IR(0, rA)));
3906 addInstr(env, X86Instr_Alu32M(
3907 Xalu_MOV, X86RI_Reg(vHi), X86AMode_IR(4, rA)));
3908 return;
3909 }
sewardj9636b442004-12-04 01:38:37 +00003910 if (tyd == Ity_V128) {
sewardjbf0d86c2007-11-26 23:18:52 +00003911 X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.Store.addr);
sewardjaf1ceca2005-06-30 23:31:27 +00003912 HReg r = iselVecExpr(env, stmt->Ist.Store.data);
sewardj9636b442004-12-04 01:38:37 +00003913 addInstr(env, X86Instr_SseLdSt(False/*store*/, r, am));
3914 return;
3915 }
sewardjd9c2b792004-07-08 01:44:38 +00003916 break;
sewardj79453082004-07-02 17:29:14 +00003917 }
3918
sewardj60f4e3c2004-07-19 01:56:50 +00003919 /* --------- PUT --------- */
sewardjd9c2b792004-07-08 01:44:38 +00003920 case Ist_Put: {
sewardj6d076362004-09-23 11:06:17 +00003921 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
sewardjd9c2b792004-07-08 01:44:38 +00003922 if (ty == Ity_I32) {
3923 /* We're going to write to memory, so compute the RHS into an
3924 X86RI. */
sewardj464efa42004-11-19 22:17:29 +00003925 X86RI* ri = iselIntExpr_RI(env, stmt->Ist.Put.data);
sewardjd9c2b792004-07-08 01:44:38 +00003926 addInstr(env,
3927 X86Instr_Alu32M(
3928 Xalu_MOV,
3929 ri,
3930 X86AMode_IR(stmt->Ist.Put.offset,hregX86_EBP())
3931 ));
3932 return;
3933 }
sewardj597b71b2004-07-19 02:51:12 +00003934 if (ty == Ity_I8 || ty == Ity_I16) {
sewardj6d076362004-09-23 11:06:17 +00003935 HReg r = iselIntExpr_R(env, stmt->Ist.Put.data);
sewardj443cd9d2004-07-18 23:06:45 +00003936 addInstr(env, X86Instr_Store(
sewardj428fabd2005-03-21 03:11:17 +00003937 toUChar(ty==Ity_I8 ? 1 : 2),
sewardj597b71b2004-07-19 02:51:12 +00003938 r,
sewardj443cd9d2004-07-18 23:06:45 +00003939 X86AMode_IR(stmt->Ist.Put.offset,
3940 hregX86_EBP())));
3941 return;
3942 }
sewardj464efa42004-11-19 22:17:29 +00003943 if (ty == Ity_I64) {
3944 HReg vHi, vLo;
3945 X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP());
3946 X86AMode* am4 = advance4(am);
sewardjd08f2d72004-12-01 23:19:36 +00003947 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data);
sewardj464efa42004-11-19 22:17:29 +00003948 addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(vLo), am ));
3949 addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(vHi), am4 ));
3950 return;
3951 }
sewardjd08f2d72004-12-01 23:19:36 +00003952 if (ty == Ity_V128) {
3953 HReg vec = iselVecExpr(env, stmt->Ist.Put.data);
3954 X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP());
3955 addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, am));
3956 return;
3957 }
sewardj4cb918d2004-12-03 19:43:31 +00003958 if (ty == Ity_F32) {
3959 HReg f32 = iselFltExpr(env, stmt->Ist.Put.data);
3960 X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP());
3961 set_FPU_rounding_default(env); /* paranoia */
3962 addInstr(env, X86Instr_FpLdSt( False/*store*/, 4, f32, am ));
3963 return;
3964 }
sewardjfd226452004-12-07 19:02:18 +00003965 if (ty == Ity_F64) {
3966 HReg f64 = iselDblExpr(env, stmt->Ist.Put.data);
3967 X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP());
3968 set_FPU_rounding_default(env); /* paranoia */
3969 addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, f64, am ));
3970 return;
3971 }
sewardjd9c2b792004-07-08 01:44:38 +00003972 break;
3973 }
sewardje8e9d732004-07-16 21:03:45 +00003974
sewardj3196daf2004-08-13 00:18:58 +00003975 /* --------- Indexed PUT --------- */
3976 case Ist_PutI: {
floriand6f38b32012-05-31 15:46:18 +00003977 IRPutI *puti = stmt->Ist.PutI.details;
3978
sewardj2d3f77c2004-09-22 23:49:09 +00003979 X86AMode* am
3980 = genGuestArrayOffset(
floriand6f38b32012-05-31 15:46:18 +00003981 env, puti->descr,
3982 puti->ix, puti->bias );
sewardj3196daf2004-08-13 00:18:58 +00003983
floriand6f38b32012-05-31 15:46:18 +00003984 IRType ty = typeOfIRExpr(env->type_env, puti->data);
sewardj3196daf2004-08-13 00:18:58 +00003985 if (ty == Ity_F64) {
floriand6f38b32012-05-31 15:46:18 +00003986 HReg val = iselDblExpr(env, puti->data);
sewardj2d3f77c2004-09-22 23:49:09 +00003987 addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, val, am ));
sewardj3196daf2004-08-13 00:18:58 +00003988 return;
3989 }
sewardj3fc76d22004-08-31 11:47:54 +00003990 if (ty == Ity_I8) {
floriand6f38b32012-05-31 15:46:18 +00003991 HReg r = iselIntExpr_R(env, puti->data);
sewardj2d3f77c2004-09-22 23:49:09 +00003992 addInstr(env, X86Instr_Store( 1, r, am ));
sewardj3fc76d22004-08-31 11:47:54 +00003993 return;
3994 }
sewardje12d6442005-05-09 12:16:33 +00003995 if (ty == Ity_I32) {
floriand6f38b32012-05-31 15:46:18 +00003996 HReg r = iselIntExpr_R(env, puti->data);
sewardje12d6442005-05-09 12:16:33 +00003997 addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(r), am ));
3998 return;
3999 }
sewardj218e29f2004-11-07 18:45:15 +00004000 if (ty == Ity_I64) {
4001 HReg rHi, rLo;
4002 X86AMode* am4 = advance4(am);
floriand6f38b32012-05-31 15:46:18 +00004003 iselInt64Expr(&rHi, &rLo, env, puti->data);
sewardj218e29f2004-11-07 18:45:15 +00004004 addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rLo), am ));
4005 addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rHi), am4 ));
4006 return;
4007 }
sewardj3196daf2004-08-13 00:18:58 +00004008 break;
4009 }
4010
sewardj60f4e3c2004-07-19 01:56:50 +00004011 /* --------- TMP --------- */
sewardjdd40fdf2006-12-24 02:20:24 +00004012 case Ist_WrTmp: {
4013 IRTemp tmp = stmt->Ist.WrTmp.tmp;
sewardj17442fe2004-09-20 14:54:28 +00004014 IRType ty = typeOfIRTemp(env->type_env, tmp);
sewardj79e04f82007-03-31 14:30:12 +00004015
4016 /* optimisation: if stmt->Ist.WrTmp.data is Add32(..,..),
4017 compute it into an AMode and then use LEA. This usually
4018 produces fewer instructions, often because (for memcheck
4019 created IR) we get t = address-expression, (t is later used
4020 twice) and so doing this naturally turns address-expression
4021 back into an X86 amode. */
4022 if (ty == Ity_I32
4023 && stmt->Ist.WrTmp.data->tag == Iex_Binop
4024 && stmt->Ist.WrTmp.data->Iex.Binop.op == Iop_Add32) {
4025 X86AMode* am = iselIntExpr_AMode(env, stmt->Ist.WrTmp.data);
4026 HReg dst = lookupIRTemp(env, tmp);
4027 if (am->tag == Xam_IR && am->Xam.IR.imm == 0) {
4028 /* Hmm, iselIntExpr_AMode wimped out and just computed the
4029 value into a register. Just emit a normal reg-reg move
4030 so reg-alloc can coalesce it away in the usual way. */
4031 HReg src = am->Xam.IR.reg;
4032 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst));
4033 } else {
4034 addInstr(env, X86Instr_Lea32(am,dst));
4035 }
4036 return;
4037 }
4038
sewardj4042c7e2004-07-18 01:28:30 +00004039 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
sewardjdd40fdf2006-12-24 02:20:24 +00004040 X86RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.WrTmp.data);
sewardjd9c2b792004-07-08 01:44:38 +00004041 HReg dst = lookupIRTemp(env, tmp);
4042 addInstr(env, X86Instr_Alu32R(Xalu_MOV,rmi,dst));
4043 return;
4044 }
sewardj597b71b2004-07-19 02:51:12 +00004045 if (ty == Ity_I64) {
4046 HReg rHi, rLo, dstHi, dstLo;
sewardjdd40fdf2006-12-24 02:20:24 +00004047 iselInt64Expr(&rHi,&rLo, env, stmt->Ist.WrTmp.data);
sewardj597b71b2004-07-19 02:51:12 +00004048 lookupIRTemp64( &dstHi, &dstLo, env, tmp);
sewardjd08f2d72004-12-01 23:19:36 +00004049 addInstr(env, mk_iMOVsd_RR(rHi,dstHi) );
4050 addInstr(env, mk_iMOVsd_RR(rLo,dstLo) );
sewardj597b71b2004-07-19 02:51:12 +00004051 return;
4052 }
sewardjba999312004-11-15 15:21:17 +00004053 if (ty == Ity_I1) {
sewardjdd40fdf2006-12-24 02:20:24 +00004054 X86CondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data);
sewardjd7cb8532004-08-17 23:59:23 +00004055 HReg dst = lookupIRTemp(env, tmp);
4056 addInstr(env, X86Instr_Set32(cond, dst));
4057 return;
4058 }
sewardjbb53f8c2004-08-14 11:50:01 +00004059 if (ty == Ity_F64) {
4060 HReg dst = lookupIRTemp(env, tmp);
sewardjdd40fdf2006-12-24 02:20:24 +00004061 HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
sewardjbb53f8c2004-08-14 11:50:01 +00004062 addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst));
4063 return;
4064 }
sewardj4a8b2a52004-10-13 20:45:25 +00004065 if (ty == Ity_F32) {
4066 HReg dst = lookupIRTemp(env, tmp);
sewardjdd40fdf2006-12-24 02:20:24 +00004067 HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data);
sewardj4a8b2a52004-10-13 20:45:25 +00004068 addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst));
4069 return;
4070 }
sewardjd08f2d72004-12-01 23:19:36 +00004071 if (ty == Ity_V128) {
4072 HReg dst = lookupIRTemp(env, tmp);
sewardjdd40fdf2006-12-24 02:20:24 +00004073 HReg src = iselVecExpr(env, stmt->Ist.WrTmp.data);
sewardjd08f2d72004-12-01 23:19:36 +00004074 addInstr(env, mk_vMOVsd_RR(src,dst));
4075 return;
4076 }
sewardjd9c2b792004-07-08 01:44:38 +00004077 break;
4078 }
sewardj79453082004-07-02 17:29:14 +00004079
sewardj17442fe2004-09-20 14:54:28 +00004080 /* --------- Call to DIRTY helper --------- */
4081 case Ist_Dirty: {
sewardj17442fe2004-09-20 14:54:28 +00004082 IRDirty* d = stmt->Ist.Dirty.details;
sewardj7cb49d72004-10-24 22:31:25 +00004083
sewardjcfe046e2013-01-17 14:23:53 +00004084 /* Figure out the return type, if any. */
4085 IRType retty = Ity_INVALID;
4086 if (d->tmp != IRTemp_INVALID)
4087 retty = typeOfIRTemp(env->type_env, d->tmp);
4088
sewardj74142b82013-08-08 10:28:59 +00004089 Bool retty_ok = False;
sewardjcfe046e2013-01-17 14:23:53 +00004090 switch (retty) {
4091 case Ity_INVALID: /* function doesn't return anything */
sewardj74142b82013-08-08 10:28:59 +00004092 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
4093 case Ity_V128:
4094 retty_ok = True; break;
sewardjcfe046e2013-01-17 14:23:53 +00004095 default:
4096 break;
4097 }
sewardj74142b82013-08-08 10:28:59 +00004098 if (!retty_ok)
sewardjcfe046e2013-01-17 14:23:53 +00004099 break; /* will go to stmt_fail: */
4100
sewardj74142b82013-08-08 10:28:59 +00004101 /* Marshal args, do the call, and set the return value to
4102 0x555..555 if this is a conditional call that returns a value
4103 and the call is skipped. */
4104 UInt addToSp = 0;
4105 RetLoc rloc = mk_RetLoc_INVALID();
4106 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
4107 vassert(is_sane_RetLoc(rloc));
sewardj17442fe2004-09-20 14:54:28 +00004108
4109 /* Now figure out what to do with the returned value, if any. */
sewardj74142b82013-08-08 10:28:59 +00004110 switch (retty) {
4111 case Ity_INVALID: {
4112 /* No return value. Nothing to do. */
4113 vassert(d->tmp == IRTemp_INVALID);
4114 vassert(rloc.pri == RLPri_None);
4115 vassert(addToSp == 0);
4116 return;
4117 }
4118 case Ity_I32: case Ity_I16: case Ity_I8: {
4119 /* The returned value is in %eax. Park it in the register
4120 associated with tmp. */
4121 vassert(rloc.pri == RLPri_Int);
4122 vassert(addToSp == 0);
4123 HReg dst = lookupIRTemp(env, d->tmp);
4124 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
4125 return;
4126 }
4127 case Ity_I64: {
4128 /* The returned value is in %edx:%eax. Park it in the
4129 register-pair associated with tmp. */
4130 vassert(rloc.pri == RLPri_2Int);
4131 vassert(addToSp == 0);
4132 HReg dstHi, dstLo;
4133 lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
4134 addInstr(env, mk_iMOVsd_RR(hregX86_EDX(),dstHi) );
4135 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dstLo) );
4136 return;
4137 }
4138 case Ity_V128: {
4139 /* The returned value is on the stack, and *retloc tells
4140 us where. Fish it off the stack and then move the
4141 stack pointer upwards to clear it, as directed by
4142 doHelperCall. */
4143 vassert(rloc.pri == RLPri_V128SpRel);
4144 vassert(addToSp >= 16);
4145 HReg dst = lookupIRTemp(env, d->tmp);
4146 X86AMode* am = X86AMode_IR(rloc.spOff, hregX86_ESP());
4147 addInstr(env, X86Instr_SseLdSt( True/*load*/, dst, am ));
4148 add_to_esp(env, addToSp);
4149 return;
4150 }
4151 default:
4152 /*NOTREACHED*/
4153 vassert(0);
sewardj4b861de2004-11-03 15:24:42 +00004154 }
sewardj17442fe2004-09-20 14:54:28 +00004155 break;
4156 }
4157
sewardj3e838932005-01-07 12:09:15 +00004158 /* --------- MEM FENCE --------- */
sewardjc4356f02007-11-09 21:15:04 +00004159 case Ist_MBE:
4160 switch (stmt->Ist.MBE.event) {
4161 case Imbe_Fence:
4162 addInstr(env, X86Instr_MFence(env->hwcaps));
4163 return;
sewardjc4356f02007-11-09 21:15:04 +00004164 default:
4165 break;
4166 }
4167 break;
sewardj3e838932005-01-07 12:09:15 +00004168
sewardje9d8a262009-07-01 08:06:34 +00004169 /* --------- ACAS --------- */
4170 case Ist_CAS:
4171 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
4172 /* "normal" singleton CAS */
4173 UChar sz;
4174 IRCAS* cas = stmt->Ist.CAS.details;
4175 IRType ty = typeOfIRExpr(env->type_env, cas->dataLo);
4176 /* get: cas->expdLo into %eax, and cas->dataLo into %ebx */
4177 X86AMode* am = iselIntExpr_AMode(env, cas->addr);
4178 HReg rDataLo = iselIntExpr_R(env, cas->dataLo);
4179 HReg rExpdLo = iselIntExpr_R(env, cas->expdLo);
4180 HReg rOldLo = lookupIRTemp(env, cas->oldLo);
4181 vassert(cas->expdHi == NULL);
4182 vassert(cas->dataHi == NULL);
4183 addInstr(env, mk_iMOVsd_RR(rExpdLo, rOldLo));
4184 addInstr(env, mk_iMOVsd_RR(rExpdLo, hregX86_EAX()));
4185 addInstr(env, mk_iMOVsd_RR(rDataLo, hregX86_EBX()));
4186 switch (ty) {
4187 case Ity_I32: sz = 4; break;
4188 case Ity_I16: sz = 2; break;
4189 case Ity_I8: sz = 1; break;
4190 default: goto unhandled_cas;
4191 }
4192 addInstr(env, X86Instr_ACAS(am, sz));
4193 addInstr(env,
4194 X86Instr_CMov32(Xcc_NZ,
4195 X86RM_Reg(hregX86_EAX()), rOldLo));
4196 return;
4197 } else {
4198 /* double CAS */
4199 IRCAS* cas = stmt->Ist.CAS.details;
4200 IRType ty = typeOfIRExpr(env->type_env, cas->dataLo);
4201 /* only 32-bit allowed in this case */
4202 /* get: cas->expdLo into %eax, and cas->dataLo into %ebx */
4203 /* get: cas->expdHi into %edx, and cas->dataHi into %ecx */
4204 X86AMode* am = iselIntExpr_AMode(env, cas->addr);
4205 HReg rDataHi = iselIntExpr_R(env, cas->dataHi);
4206 HReg rDataLo = iselIntExpr_R(env, cas->dataLo);
4207 HReg rExpdHi = iselIntExpr_R(env, cas->expdHi);
4208 HReg rExpdLo = iselIntExpr_R(env, cas->expdLo);
4209 HReg rOldHi = lookupIRTemp(env, cas->oldHi);
4210 HReg rOldLo = lookupIRTemp(env, cas->oldLo);
4211 if (ty != Ity_I32)
4212 goto unhandled_cas;
4213 addInstr(env, mk_iMOVsd_RR(rExpdHi, rOldHi));
4214 addInstr(env, mk_iMOVsd_RR(rExpdLo, rOldLo));
4215 addInstr(env, mk_iMOVsd_RR(rExpdHi, hregX86_EDX()));
4216 addInstr(env, mk_iMOVsd_RR(rExpdLo, hregX86_EAX()));
4217 addInstr(env, mk_iMOVsd_RR(rDataHi, hregX86_ECX()));
4218 addInstr(env, mk_iMOVsd_RR(rDataLo, hregX86_EBX()));
4219 addInstr(env, X86Instr_DACAS(am));
4220 addInstr(env,
4221 X86Instr_CMov32(Xcc_NZ,
4222 X86RM_Reg(hregX86_EDX()), rOldHi));
4223 addInstr(env,
4224 X86Instr_CMov32(Xcc_NZ,
4225 X86RM_Reg(hregX86_EAX()), rOldLo));
4226 return;
4227 }
4228 unhandled_cas:
4229 break;
4230
sewardjf1689312005-03-16 18:19:10 +00004231 /* --------- INSTR MARK --------- */
4232 /* Doesn't generate any executable code ... */
4233 case Ist_IMark:
4234 return;
4235
sewardjd2445f62005-03-21 00:15:53 +00004236 /* --------- NO-OP --------- */
4237 /* Fairly self-explanatory, wouldn't you say? */
4238 case Ist_NoOp:
4239 return;
4240
sewardj60f4e3c2004-07-19 01:56:50 +00004241 /* --------- EXIT --------- */
sewardje8e9d732004-07-16 21:03:45 +00004242 case Ist_Exit: {
sewardj2e56f9f2004-07-24 01:24:38 +00004243 if (stmt->Ist.Exit.dst->tag != Ico_U32)
sewardjc6f970f2012-04-02 21:54:49 +00004244 vpanic("iselStmt(x86): Ist_Exit: dst is not a 32-bit value");
4245
4246 X86CondCode cc = iselCondCode(env, stmt->Ist.Exit.guard);
4247 X86AMode* amEIP = X86AMode_IR(stmt->Ist.Exit.offsIP,
4248 hregX86_EBP());
4249
4250 /* Case: boring transfer to known address */
4251 if (stmt->Ist.Exit.jk == Ijk_Boring) {
4252 if (env->chainingAllowed) {
4253 /* .. almost always true .. */
4254 /* Skip the event check at the dst if this is a forwards
4255 edge. */
4256 Bool toFastEP
4257 = ((Addr32)stmt->Ist.Exit.dst->Ico.U32) > env->max_ga;
4258 if (0) vex_printf("%s", toFastEP ? "Y" : ",");
4259 addInstr(env, X86Instr_XDirect(stmt->Ist.Exit.dst->Ico.U32,
4260 amEIP, cc, toFastEP));
4261 } else {
4262 /* .. very occasionally .. */
4263 /* We can't use chaining, so ask for an assisted transfer,
4264 as that's the only alternative that is allowable. */
4265 HReg r = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
4266 addInstr(env, X86Instr_XAssisted(r, amEIP, cc, Ijk_Boring));
4267 }
4268 return;
4269 }
4270
4271 /* Case: assisted transfer to arbitrary address */
4272 switch (stmt->Ist.Exit.jk) {
sewardj2f6902b2012-04-23 09:48:14 +00004273 /* Keep this list in sync with that in iselNext below */
4274 case Ijk_ClientReq:
4275 case Ijk_EmWarn:
sewardjc6f970f2012-04-02 21:54:49 +00004276 case Ijk_MapFail:
sewardj2f6902b2012-04-23 09:48:14 +00004277 case Ijk_NoDecode:
4278 case Ijk_NoRedir:
4279 case Ijk_SigSEGV:
4280 case Ijk_SigTRAP:
4281 case Ijk_Sys_int128:
4282 case Ijk_Sys_int129:
4283 case Ijk_Sys_int130:
tomf0bb6792014-02-09 11:40:20 +00004284 case Ijk_Sys_syscall:
sewardj2f6902b2012-04-23 09:48:14 +00004285 case Ijk_Sys_sysenter:
sewardj05f5e012014-05-04 10:52:11 +00004286 case Ijk_InvalICache:
sewardj2f6902b2012-04-23 09:48:14 +00004287 case Ijk_Yield:
4288 {
sewardjc6f970f2012-04-02 21:54:49 +00004289 HReg r = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
4290 addInstr(env, X86Instr_XAssisted(r, amEIP, cc, stmt->Ist.Exit.jk));
4291 return;
4292 }
4293 default:
4294 break;
4295 }
4296
4297 /* Do we ever expect to see any other kind? */
4298 goto stmt_fail;
sewardje8e9d732004-07-16 21:03:45 +00004299 }
4300
sewardjc97096c2004-06-30 09:28:04 +00004301 default: break;
4302 }
sewardjaf1ceca2005-06-30 23:31:27 +00004303 stmt_fail:
sewardj35421a32004-07-05 13:12:34 +00004304 ppIRStmt(stmt);
4305 vpanic("iselStmt");
sewardjc97096c2004-06-30 09:28:04 +00004306}
4307
4308
4309/*---------------------------------------------------------*/
4310/*--- ISEL: Basic block terminators (Nexts) ---*/
4311/*---------------------------------------------------------*/
4312
sewardjc6f970f2012-04-02 21:54:49 +00004313static void iselNext ( ISelEnv* env,
4314 IRExpr* next, IRJumpKind jk, Int offsIP )
sewardjc97096c2004-06-30 09:28:04 +00004315{
sewardjf48ac192004-10-29 00:41:29 +00004316 if (vex_traceflags & VEX_TRACE_VCODE) {
sewardjc6f970f2012-04-02 21:54:49 +00004317 vex_printf( "\n-- PUT(%d) = ", offsIP);
4318 ppIRExpr( next );
4319 vex_printf( "; exit-");
sewardj750f4072004-07-26 22:39:11 +00004320 ppIRJumpKind(jk);
sewardjc6f970f2012-04-02 21:54:49 +00004321 vex_printf( "\n");
sewardj1f40a0a2004-07-21 12:28:07 +00004322 }
sewardjc6f970f2012-04-02 21:54:49 +00004323
4324 /* Case: boring transfer to known address */
4325 if (next->tag == Iex_Const) {
4326 IRConst* cdst = next->Iex.Const.con;
4327 vassert(cdst->tag == Ico_U32);
4328 if (jk == Ijk_Boring || jk == Ijk_Call) {
4329 /* Boring transfer to known address */
4330 X86AMode* amEIP = X86AMode_IR(offsIP, hregX86_EBP());
4331 if (env->chainingAllowed) {
4332 /* .. almost always true .. */
4333 /* Skip the event check at the dst if this is a forwards
4334 edge. */
4335 Bool toFastEP
4336 = ((Addr64)cdst->Ico.U32) > env->max_ga;
4337 if (0) vex_printf("%s", toFastEP ? "X" : ".");
4338 addInstr(env, X86Instr_XDirect(cdst->Ico.U32,
4339 amEIP, Xcc_ALWAYS,
4340 toFastEP));
4341 } else {
4342 /* .. very occasionally .. */
4343 /* We can't use chaining, so ask for an assisted transfer,
4344 as that's the only alternative that is allowable. */
4345 HReg r = iselIntExpr_R(env, next);
4346 addInstr(env, X86Instr_XAssisted(r, amEIP, Xcc_ALWAYS,
4347 Ijk_Boring));
4348 }
4349 return;
4350 }
4351 }
4352
4353 /* Case: call/return (==boring) transfer to any address */
4354 switch (jk) {
4355 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
4356 HReg r = iselIntExpr_R(env, next);
4357 X86AMode* amEIP = X86AMode_IR(offsIP, hregX86_EBP());
4358 if (env->chainingAllowed) {
4359 addInstr(env, X86Instr_XIndir(r, amEIP, Xcc_ALWAYS));
4360 } else {
4361 addInstr(env, X86Instr_XAssisted(r, amEIP, Xcc_ALWAYS,
4362 Ijk_Boring));
4363 }
4364 return;
4365 }
4366 default:
4367 break;
4368 }
4369
sewardj2f6902b2012-04-23 09:48:14 +00004370 /* Case: assisted transfer to arbitrary address */
sewardjc6f970f2012-04-02 21:54:49 +00004371 switch (jk) {
sewardj2f6902b2012-04-23 09:48:14 +00004372 /* Keep this list in sync with that for Ist_Exit above */
4373 case Ijk_ClientReq:
4374 case Ijk_EmWarn:
4375 case Ijk_MapFail:
sewardj3d0e38e2012-04-21 07:38:29 +00004376 case Ijk_NoDecode:
sewardj2f6902b2012-04-23 09:48:14 +00004377 case Ijk_NoRedir:
4378 case Ijk_SigSEGV:
4379 case Ijk_SigTRAP:
4380 case Ijk_Sys_int128:
4381 case Ijk_Sys_int129:
4382 case Ijk_Sys_int130:
tomf0bb6792014-02-09 11:40:20 +00004383 case Ijk_Sys_syscall:
sewardj2f6902b2012-04-23 09:48:14 +00004384 case Ijk_Sys_sysenter:
sewardj05f5e012014-05-04 10:52:11 +00004385 case Ijk_InvalICache:
sewardj2f6902b2012-04-23 09:48:14 +00004386 case Ijk_Yield:
4387 {
sewardjc6f970f2012-04-02 21:54:49 +00004388 HReg r = iselIntExpr_R(env, next);
4389 X86AMode* amEIP = X86AMode_IR(offsIP, hregX86_EBP());
4390 addInstr(env, X86Instr_XAssisted(r, amEIP, Xcc_ALWAYS, jk));
4391 return;
4392 }
4393 default:
4394 break;
4395 }
4396
4397 vex_printf( "\n-- PUT(%d) = ", offsIP);
4398 ppIRExpr( next );
4399 vex_printf( "; exit-");
4400 ppIRJumpKind(jk);
4401 vex_printf( "\n");
4402 vassert(0); // are we expecting any other kind?
sewardjc97096c2004-06-30 09:28:04 +00004403}
4404
4405
4406/*---------------------------------------------------------*/
4407/*--- Insn selector top-level ---*/
4408/*---------------------------------------------------------*/
4409
sewardjdd40fdf2006-12-24 02:20:24 +00004410/* Translate an entire SB to x86 code. */
sewardj194d54a2004-07-03 19:08:18 +00004411
sewardjc6f970f2012-04-02 21:54:49 +00004412HInstrArray* iselSB_X86 ( IRSB* bb,
4413 VexArch arch_host,
floriand8c64e02014-10-08 08:54:44 +00004414 const VexArchInfo* archinfo_host,
4415 const VexAbiInfo* vbi/*UNUSED*/,
sewardjc6f970f2012-04-02 21:54:49 +00004416 Int offs_Host_EvC_Counter,
4417 Int offs_Host_EvC_FailAddr,
4418 Bool chainingAllowed,
4419 Bool addProfInc,
4420 Addr64 max_ga )
sewardjc97096c2004-06-30 09:28:04 +00004421{
sewardj5117ce12006-01-27 21:20:15 +00004422 Int i, j;
4423 HReg hreg, hregHI;
4424 ISelEnv* env;
4425 UInt hwcaps_host = archinfo_host->hwcaps;
sewardjc6f970f2012-04-02 21:54:49 +00004426 X86AMode *amCounter, *amFailAddr;
sewardjc97096c2004-06-30 09:28:04 +00004427
sewardj9df271d2004-12-31 22:37:42 +00004428 /* sanity ... */
sewardj8f073592006-05-01 02:14:17 +00004429 vassert(arch_host == VexArchX86);
sewardj536fbab2010-07-29 15:39:05 +00004430 vassert(0 == (hwcaps_host
mjw6c65c122013-08-27 10:19:03 +00004431 & ~(VEX_HWCAPS_X86_MMXEXT
4432 | VEX_HWCAPS_X86_SSE1
sewardj536fbab2010-07-29 15:39:05 +00004433 | VEX_HWCAPS_X86_SSE2
4434 | VEX_HWCAPS_X86_SSE3
4435 | VEX_HWCAPS_X86_LZCNT)));
sewardjc6f970f2012-04-02 21:54:49 +00004436 vassert(sizeof(max_ga) == 8);
4437 vassert((max_ga >> 32) == 0);
sewardj9df271d2004-12-31 22:37:42 +00004438
sewardj9b769162014-07-24 12:42:03 +00004439 /* Check that the host's endianness is as expected. */
4440 vassert(archinfo_host->endness == VexEndnessLE);
4441
sewardjc97096c2004-06-30 09:28:04 +00004442 /* Make up an initial environment to use. */
sewardj9a036bf2005-03-14 18:19:08 +00004443 env = LibVEX_Alloc(sizeof(ISelEnv));
sewardj194d54a2004-07-03 19:08:18 +00004444 env->vreg_ctr = 0;
sewardjc97096c2004-06-30 09:28:04 +00004445
4446 /* Set up output code array. */
sewardj2cd80dc2004-07-02 15:20:40 +00004447 env->code = newHInstrArray();
sewardjc97096c2004-06-30 09:28:04 +00004448
4449 /* Copy BB's type env. */
4450 env->type_env = bb->tyenv;
4451
4452 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
4453 change as we go along. */
sewardje539a402004-07-14 18:24:17 +00004454 env->n_vregmap = bb->tyenv->types_used;
4455 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
sewardje8e9d732004-07-16 21:03:45 +00004456 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
sewardjc97096c2004-06-30 09:28:04 +00004457
sewardj9df271d2004-12-31 22:37:42 +00004458 /* and finally ... */
sewardjc6f970f2012-04-02 21:54:49 +00004459 env->chainingAllowed = chainingAllowed;
4460 env->hwcaps = hwcaps_host;
4461 env->max_ga = max_ga;
sewardj9df271d2004-12-31 22:37:42 +00004462
sewardjc97096c2004-06-30 09:28:04 +00004463 /* For each IR temporary, allocate a suitably-kinded virtual
4464 register. */
sewardj597b71b2004-07-19 02:51:12 +00004465 j = 0;
sewardjc97096c2004-06-30 09:28:04 +00004466 for (i = 0; i < env->n_vregmap; i++) {
sewardje8e9d732004-07-16 21:03:45 +00004467 hregHI = hreg = INVALID_HREG;
sewardje539a402004-07-14 18:24:17 +00004468 switch (bb->tyenv->types[i]) {
sewardjba999312004-11-15 15:21:17 +00004469 case Ity_I1:
sewardje8e9d732004-07-16 21:03:45 +00004470 case Ity_I8:
sewardj4042c7e2004-07-18 01:28:30 +00004471 case Ity_I16:
sewardjd08f2d72004-12-01 23:19:36 +00004472 case Ity_I32: hreg = mkHReg(j++, HRcInt32, True); break;
4473 case Ity_I64: hreg = mkHReg(j++, HRcInt32, True);
4474 hregHI = mkHReg(j++, HRcInt32, True); break;
sewardj89cd0932004-09-08 18:23:25 +00004475 case Ity_F32:
sewardjd08f2d72004-12-01 23:19:36 +00004476 case Ity_F64: hreg = mkHReg(j++, HRcFlt64, True); break;
4477 case Ity_V128: hreg = mkHReg(j++, HRcVec128, True); break;
sewardje8e9d732004-07-16 21:03:45 +00004478 default: ppIRType(bb->tyenv->types[i]);
4479 vpanic("iselBB: IRTemp type");
sewardjc97096c2004-06-30 09:28:04 +00004480 }
sewardje8e9d732004-07-16 21:03:45 +00004481 env->vregmap[i] = hreg;
4482 env->vregmapHI[i] = hregHI;
sewardjc97096c2004-06-30 09:28:04 +00004483 }
sewardje322b0a2004-07-28 07:12:30 +00004484 env->vreg_ctr = j;
sewardjc97096c2004-06-30 09:28:04 +00004485
sewardjc6f970f2012-04-02 21:54:49 +00004486 /* The very first instruction must be an event check. */
4487 amCounter = X86AMode_IR(offs_Host_EvC_Counter, hregX86_EBP());
4488 amFailAddr = X86AMode_IR(offs_Host_EvC_FailAddr, hregX86_EBP());
4489 addInstr(env, X86Instr_EvCheck(amCounter, amFailAddr));
4490
4491 /* Possibly a block counter increment (for profiling). At this
4492 point we don't know the address of the counter, so just pretend
4493 it is zero. It will have to be patched later, but before this
4494 translation is used, by a call to LibVEX_patchProfCtr. */
4495 if (addProfInc) {
4496 addInstr(env, X86Instr_ProfInc());
4497 }
4498
sewardjc97096c2004-06-30 09:28:04 +00004499 /* Ok, finally we can iterate over the statements. */
sewardjd7cb8532004-08-17 23:59:23 +00004500 for (i = 0; i < bb->stmts_used; i++)
sewardjc6f970f2012-04-02 21:54:49 +00004501 iselStmt(env, bb->stmts[i]);
sewardjc97096c2004-06-30 09:28:04 +00004502
sewardjc6f970f2012-04-02 21:54:49 +00004503 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2cd80dc2004-07-02 15:20:40 +00004504
sewardj194d54a2004-07-03 19:08:18 +00004505 /* record the number of vregs we used. */
4506 env->code->n_vregs = env->vreg_ctr;
sewardj2cd80dc2004-07-02 15:20:40 +00004507 return env->code;
sewardjc97096c2004-06-30 09:28:04 +00004508}
sewardj887a11a2004-07-05 17:26:47 +00004509
4510
4511/*---------------------------------------------------------------*/
sewardjcef7d3e2009-07-02 12:21:59 +00004512/*--- end host_x86_isel.c ---*/
sewardj887a11a2004-07-05 17:26:47 +00004513/*---------------------------------------------------------------*/