blob: 09d635895da7a5a3bdee142870182af2df671eb9 [file] [log] [blame]
sewardjc97096c2004-06-30 09:28:04 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
sewardjc0ee2ed2004-07-27 10:29:41 +00004/*--- This file (host-x86/isel.c) is ---*/
sewardjc97096c2004-06-30 09:28:04 +00005/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
sewardjf8ed9d82004-11-12 17:40:23 +00009/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
13 Copyright (C) 2004 OpenWorks, LLP.
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; Version 2 dated June 1991 of the
18 license.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
23 for damages. See the GNU General Public License for more details.
24
25 Neither the names of the U.S. Department of Energy nor the
26 University of California nor the names of its contributors may be
27 used to endorse or promote products derived from this software
28 without prior written permission.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 USA.
34*/
35
sewardj887a11a2004-07-05 17:26:47 +000036#include "libvex_basictypes.h"
37#include "libvex_ir.h"
38#include "libvex.h"
sewardj35421a32004-07-05 13:12:34 +000039
sewardjc0ee2ed2004-07-27 10:29:41 +000040#include "main/vex_util.h"
41#include "main/vex_globals.h"
42#include "host-generic/h_generic_regs.h"
43#include "host-x86/hdefs.h"
sewardjc97096c2004-06-30 09:28:04 +000044
45
46/*---------------------------------------------------------*/
sewardj443cd9d2004-07-18 23:06:45 +000047/*--- Stuff for pattern matching on IR. This isn't ---*/
48/*--- x86 specific, and should be moved elsewhere. ---*/
49/*---------------------------------------------------------*/
50
51#define DECLARE_PATTERN(_patt) \
52 static IRExpr* _patt = NULL
53
54#define DEFINE_PATTERN(_patt,_expr) \
55 do { \
56 if (!(_patt)) { \
57 vassert(LibVEX_GetAllocMode() == AllocModeTEMPORARY); \
58 LibVEX_SetAllocMode(AllocModePERMANENT); \
59 _patt = (_expr); \
60 LibVEX_SetAllocMode(AllocModeTEMPORARY); \
61 vassert(LibVEX_GetAllocMode() == AllocModeTEMPORARY); \
62 } \
63 } while (0)
64
65
66#define N_MATCH_BINDERS 4
67typedef
68 struct {
69 IRExpr* bindee[N_MATCH_BINDERS];
70 }
71 MatchInfo;
72
73
74static void setBindee ( MatchInfo* mi, Int n, IRExpr* bindee )
75{
76 if (n < 0 || n >= N_MATCH_BINDERS)
77 vpanic("setBindee: out of range index");
78 if (mi->bindee[n] != NULL)
79 vpanic("setBindee: bindee already set");
80 mi->bindee[n] = bindee;
81}
82
83static Bool matchWrk ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ )
84{
85 switch (p->tag) {
86 case Iex_Binder: /* aha, what we were looking for. */
87 setBindee(mi, p->Iex.Binder.binder, e);
88 return True;
sewardj2d3f77c2004-09-22 23:49:09 +000089#if 0
sewardj08790542004-09-14 23:18:06 +000090 case Iex_GetI:
91 if (e->tag != Iex_GetI) return False;
92 if (p->Iex.GetI.ty != e->Iex.GetI.ty) return False;
93 /* we ignore the offset limit hints .. */
94 if (!matchWrk(mi, p->Iex.GetI.offset, e->Iex.GetI.offset))
95 return False;
96 return True;
sewardj2d3f77c2004-09-22 23:49:09 +000097#endif
sewardj443cd9d2004-07-18 23:06:45 +000098 case Iex_Unop:
99 if (e->tag != Iex_Unop) return False;
100 if (p->Iex.Unop.op != e->Iex.Unop.op) return False;
101 if (!matchWrk(mi, p->Iex.Unop.arg, e->Iex.Unop.arg))
102 return False;
103 return True;
104 case Iex_Binop:
105 if (e->tag != Iex_Binop) return False;
106 if (p->Iex.Binop.op != e->Iex.Binop.op) return False;
107 if (!matchWrk(mi, p->Iex.Binop.arg1, e->Iex.Binop.arg1))
108 return False;
109 if (!matchWrk(mi, p->Iex.Binop.arg2, e->Iex.Binop.arg2))
110 return False;
111 return True;
sewardjd18d1bf2004-08-25 12:49:22 +0000112 case Iex_LDle:
113 if (e->tag != Iex_LDle) return False;
114 if (p->Iex.LDle.ty != e->Iex.LDle.ty) return False;
115 if (!matchWrk(mi, p->Iex.LDle.addr, e->Iex.LDle.addr))
116 return False;
117 return True;
sewardj443cd9d2004-07-18 23:06:45 +0000118 case Iex_Const:
sewardj4345f7a2004-09-22 19:49:27 +0000119 if (e->tag != Iex_Const) return False;
120 return eqIRConst(p->Iex.Const.con, e->Iex.Const.con);
sewardj443cd9d2004-07-18 23:06:45 +0000121 default:
122 ppIRExpr(p);
123 vpanic("match");
124 }
125}
126
127static Bool matchIRExpr ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ )
128{
129 Int i;
130 for (i = 0; i < N_MATCH_BINDERS; i++)
131 mi->bindee[i] = NULL;
132 return matchWrk(mi, p, e);
133}
134
135/*-----*/
136/* These are duplicated in x86toIR.c */
137static IRExpr* unop ( IROp op, IRExpr* a )
138{
139 return IRExpr_Unop(op, a);
140}
141
142static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
143{
144 return IRExpr_Binop(op, a1, a2);
145}
sewardj08790542004-09-14 23:18:06 +0000146
sewardj6f33f752004-11-11 02:17:53 +0000147static IRExpr* mkU64 ( ULong i )
sewardj08790542004-09-14 23:18:06 +0000148{
sewardj6f33f752004-11-11 02:17:53 +0000149 return IRExpr_Const(IRConst_U64(i));
sewardj08790542004-09-14 23:18:06 +0000150}
sewardj6f33f752004-11-11 02:17:53 +0000151
152static IRExpr* mkU32 ( UInt i )
153{
154 return IRExpr_Const(IRConst_U32(i));
155}
sewardj443cd9d2004-07-18 23:06:45 +0000156
157static IRExpr* bind ( Int binder )
158{
159 return IRExpr_Binder(binder);
160}
161
162
163
164
165/*---------------------------------------------------------*/
sewardjc97096c2004-06-30 09:28:04 +0000166/*--- ISelEnv ---*/
167/*---------------------------------------------------------*/
168
169/* This carries around:
170
171 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
172 might encounter. This is computed before insn selection starts,
173 and does not change.
174
175 - A mapping from IRTemp to HReg. This tells the insn selector
sewardje8e9d732004-07-16 21:03:45 +0000176 which virtual register(s) are associated with each IRTemp
177 temporary. This is computed before insn selection starts, and
178 does not change. We expect this mapping to map precisely the
179 same set of IRTemps as the type mapping does.
180
181 - vregmap holds the primary register for the IRTemp.
182 - vregmapHI is only used for 64-bit integer-typed
183 IRTemps. It holds the identity of a second
184 32-bit virtual HReg, which holds the high half
185 of the value.
sewardjc97096c2004-06-30 09:28:04 +0000186
187 - The code array, that is, the insns selected so far.
188
189 - A counter, for generating new virtual registers.
190
sewardje8e9d732004-07-16 21:03:45 +0000191 Note, this is all host-independent. */
sewardjc97096c2004-06-30 09:28:04 +0000192
193typedef
194 struct {
sewardj194d54a2004-07-03 19:08:18 +0000195 IRTypeEnv* type_env;
sewardjc97096c2004-06-30 09:28:04 +0000196
sewardje539a402004-07-14 18:24:17 +0000197 HReg* vregmap;
sewardje8e9d732004-07-16 21:03:45 +0000198 HReg* vregmapHI;
sewardj194d54a2004-07-03 19:08:18 +0000199 Int n_vregmap;
sewardjc97096c2004-06-30 09:28:04 +0000200
sewardj2cd80dc2004-07-02 15:20:40 +0000201 HInstrArray* code;
sewardjc97096c2004-06-30 09:28:04 +0000202
sewardj194d54a2004-07-03 19:08:18 +0000203 Int vreg_ctr;
sewardjc97096c2004-06-30 09:28:04 +0000204 }
205 ISelEnv;
206
207
208static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
209{
sewardje539a402004-07-14 18:24:17 +0000210 vassert(tmp >= 0);
211 vassert(tmp < env->n_vregmap);
212 return env->vregmap[tmp];
sewardjc97096c2004-06-30 09:28:04 +0000213}
214
sewardj597b71b2004-07-19 02:51:12 +0000215static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp )
sewardje8e9d732004-07-16 21:03:45 +0000216{
217 vassert(tmp >= 0);
218 vassert(tmp < env->n_vregmap);
sewardj597b71b2004-07-19 02:51:12 +0000219 vassert(env->vregmapHI[tmp] != INVALID_HREG);
sewardje8e9d732004-07-16 21:03:45 +0000220 *vrLO = env->vregmap[tmp];
221 *vrHI = env->vregmapHI[tmp];
222}
223
sewardj2cd80dc2004-07-02 15:20:40 +0000224static void addInstr ( ISelEnv* env, X86Instr* instr )
sewardjc97096c2004-06-30 09:28:04 +0000225{
sewardj2cd80dc2004-07-02 15:20:40 +0000226 addHInstr(env->code, instr);
sewardjf48ac192004-10-29 00:41:29 +0000227 if (vex_traceflags & VEX_TRACE_VCODE) {
sewardj1f40a0a2004-07-21 12:28:07 +0000228 ppX86Instr(instr);
229 vex_printf("\n");
230 }
sewardjc97096c2004-06-30 09:28:04 +0000231}
232
233static HReg newVRegI ( ISelEnv* env )
234{
sewardj194d54a2004-07-03 19:08:18 +0000235 HReg reg = mkHReg(env->vreg_ctr, HRcInt, True/*virtual reg*/);
236 env->vreg_ctr++;
sewardjc97096c2004-06-30 09:28:04 +0000237 return reg;
238}
239
sewardj3196daf2004-08-13 00:18:58 +0000240static HReg newVRegF ( ISelEnv* env )
241{
242 HReg reg = mkHReg(env->vreg_ctr, HRcFloat, True/*virtual reg*/);
243 env->vreg_ctr++;
244 return reg;
245}
246
sewardj66f2f792004-06-30 16:37:16 +0000247
sewardjd18d1bf2004-08-25 12:49:22 +0000248/*---------------------------------------------------------*/
249/*--- ISEL: Forward declarations ---*/
250/*---------------------------------------------------------*/
251
252/* These are organised as iselXXX and iselXXX_wrk pairs. The
253 iselXXX_wrk do the real work, but are not to be called directly.
254 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
255 checks that all returned registers are virtual.
256*/
257
258static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e );
259static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e );
260
261static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e );
262static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e );
263
264static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e );
265static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e );
266
267static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e );
268static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e );
269
270static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e );
271static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e );
272
273static void iselIntExpr64_wrk ( HReg* rHi, HReg* rLo,
274 ISelEnv* env, IRExpr* e );
275static void iselIntExpr64 ( HReg* rHi, HReg* rLo,
276 ISelEnv* env, IRExpr* e );
277
278static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
279static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e );
280
sewardj89cd0932004-09-08 18:23:25 +0000281static HReg iselDblExpr ( ISelEnv* env, IRExpr* e );
282
sewardjd18d1bf2004-08-25 12:49:22 +0000283
284/*---------------------------------------------------------*/
sewardj17442fe2004-09-20 14:54:28 +0000285/*--- ISEL: Misc helpers ---*/
286/*---------------------------------------------------------*/
287
sewardjd4a4d012004-11-08 18:53:52 +0000288/* Is this a 32-bit zero expression? */
289
290static Bool isZero32 ( IRExpr* e )
291{
292 return e->tag == Iex_Const
293 && e->Iex.Const.con->tag == Ico_U32
294 && e->Iex.Const.con->Ico.U32 == 0;
295}
296
sewardj17442fe2004-09-20 14:54:28 +0000297/* Make a int reg-reg move. */
298
299static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst )
300{
301 vassert(hregClass(src) == HRcInt);
302 vassert(hregClass(dst) == HRcInt);
303 return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst);
304}
305
sewardj77352542004-10-30 20:39:01 +0000306
sewardj218e29f2004-11-07 18:45:15 +0000307/* Given an amode, return one which references 4 bytes further
308 along. */
309
310static X86AMode* advance4 ( X86AMode* am )
311{
312 X86AMode* am4 = dopyX86AMode(am);
313 /* Could also advance the _IR form, but no need yet. */
314 vassert(am4->tag == Xam_IRRS);
315 am4->Xam.IRRS.imm += 4;
316 return am4;
317}
318
319
sewardj17442fe2004-09-20 14:54:28 +0000320/* Push an arg onto the host stack, in preparation for a call to a
321 helper function of some kind. Returns the number of 32-bit words
322 pushed. */
323
324static Int pushArg ( ISelEnv* env, IRExpr* arg )
325{
326 IRType arg_ty = typeOfIRExpr(env->type_env, arg);
327 if (arg_ty == Ity_I32) {
328 addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg)));
329 return 1;
330 } else
331 if (arg_ty == Ity_I64) {
332 HReg rHi, rLo;
333 iselIntExpr64(&rHi, &rLo, env, arg);
334 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
335 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
336 return 2;
337 }
338 ppIRExpr(arg);
339 vpanic("pushArg(x86): can't handle arg of this type");
340}
341
sewardjc5fc7aa2004-10-27 23:00:55 +0000342
sewardj17442fe2004-09-20 14:54:28 +0000343/* Complete the call to a helper function, by calling the
344 helper and clearing the args off the stack. */
345
346static
sewardj4b861de2004-11-03 15:24:42 +0000347void callHelperAndClearArgs ( ISelEnv* env, X86CondCode cc,
348 IRCallee* cee, Int n_arg_ws )
sewardj17442fe2004-09-20 14:54:28 +0000349{
sewardj77352542004-10-30 20:39:01 +0000350 /* Complication. Need to decide which reg to use as the fn address
351 pointer, in a way that doesn't trash regparm-passed
352 parameters. */
sewardjf9655262004-10-31 20:02:16 +0000353 vassert(sizeof(void*) == 4);
sewardj77352542004-10-30 20:39:01 +0000354
sewardj4b861de2004-11-03 15:24:42 +0000355 addInstr(env, X86Instr_Call( cc, (UInt)cee->addr, cee->regparms));
sewardj17442fe2004-09-20 14:54:28 +0000356 if (n_arg_ws > 0)
357 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
358 X86RMI_Imm(4*n_arg_ws),
359 hregX86_ESP()));
360}
361
sewardj77352542004-10-30 20:39:01 +0000362
sewardj4b861de2004-11-03 15:24:42 +0000363/* Do a complete function call. guard is a Ity_Bit expression
364 indicating whether or not the call happens. If guard==NULL, the
365 call is unconditional. */
sewardj77352542004-10-30 20:39:01 +0000366
367static
368void doHelperCall ( ISelEnv* env,
sewardj4b861de2004-11-03 15:24:42 +0000369 Bool passBBP,
370 IRExpr* guard, IRCallee* cee, IRExpr** args )
sewardj77352542004-10-30 20:39:01 +0000371{
sewardj4b861de2004-11-03 15:24:42 +0000372 X86CondCode cc;
sewardj77352542004-10-30 20:39:01 +0000373 HReg argregs[3];
sewardj11eebbe2004-10-30 22:20:02 +0000374 Int not_done_yet, n_args, n_arg_ws, stack_limit, i, argreg;
sewardj77352542004-10-30 20:39:01 +0000375
376 /* Marshal args for a call, do the call, and clear the stack.
377 Complexities to consider:
378
379 * if passBBP is True, %ebp (the baseblock pointer) is to be
380 passed as the first arg.
381
382 * If the callee claims regparmness of 1, 2 or 3, we must pass the
383 first 1, 2 or 3 args in registers (EAX, EDX, and ECX
384 respectively). To keep things relatively simple, only args of
385 type I32 may be passed as regparms -- just bomb out if anything
386 else turns up. Clearly this depends on the front ends not
387 trying to pass any other types as regparms.
388 */
389
390 vassert(cee->regparms >= 0 && cee->regparms <= 3);
391
392 n_args = n_arg_ws = 0;
393 while (args[n_args]) n_args++;
394
sewardj11eebbe2004-10-30 22:20:02 +0000395 not_done_yet = n_args;
396 if (passBBP)
397 not_done_yet++;
398
sewardj77352542004-10-30 20:39:01 +0000399 stack_limit = cee->regparms;
400 if (cee->regparms > 0 && passBBP) stack_limit--;
401
sewardj11eebbe2004-10-30 22:20:02 +0000402 /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */
403 for (i = n_args-1; i >= stack_limit; i--) {
sewardj77352542004-10-30 20:39:01 +0000404 n_arg_ws += pushArg(env, args[i]);
sewardj11eebbe2004-10-30 22:20:02 +0000405 not_done_yet--;
406 }
sewardj77352542004-10-30 20:39:01 +0000407
408 /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in
409 registers. */
sewardj77352542004-10-30 20:39:01 +0000410
411 if (cee->regparms > 0) {
412 /* deal with regparms, not forgetting %ebp if needed. */
413 argregs[0] = hregX86_EAX();
414 argregs[1] = hregX86_EDX();
415 argregs[2] = hregX86_ECX();
416 argreg = cee->regparms;
417
418 for (i = stack_limit-1; i >= 0; i--) {
419 argreg--;
420 vassert(argreg >= 0);
421 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
422 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
423 iselIntExpr_RMI(env, args[i]),
424 argregs[argreg]));
sewardj11eebbe2004-10-30 22:20:02 +0000425 not_done_yet--;
sewardj77352542004-10-30 20:39:01 +0000426 }
427 if (passBBP) {
428 vassert(argreg == 1);
429 addInstr(env, mk_MOVsd_RR( hregX86_EBP(), argregs[0]));
sewardj11eebbe2004-10-30 22:20:02 +0000430 not_done_yet--;
sewardj77352542004-10-30 20:39:01 +0000431 }
432 } else {
433 /* No regparms. Heave %ebp on the stack if needed. */
434 if (passBBP) {
435 addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
436 n_arg_ws++;
sewardj11eebbe2004-10-30 22:20:02 +0000437 not_done_yet--;
sewardj77352542004-10-30 20:39:01 +0000438 }
439 }
440
sewardj11eebbe2004-10-30 22:20:02 +0000441 vassert(not_done_yet == 0);
442
sewardj4b861de2004-11-03 15:24:42 +0000443 /* Now we can compute the condition. We can't do it earlier
444 because the argument computations could trash the condition
445 codes. Be a bit clever to handle the common case where the
446 guard is 1:Bit. */
447 cc = Xcc_ALWAYS;
448 if (guard) {
449 if (guard->tag == Iex_Const
sewardjba999312004-11-15 15:21:17 +0000450 && guard->Iex.Const.con->tag == Ico_U1
451 && guard->Iex.Const.con->Ico.U1 == True) {
sewardj4b861de2004-11-03 15:24:42 +0000452 /* unconditional -- do nothing */
453 } else {
454 cc = iselCondCode( env, guard );
455 }
456 }
457
sewardj77352542004-10-30 20:39:01 +0000458 /* call the helper, and get the args off the stack afterwards. */
sewardj4b861de2004-11-03 15:24:42 +0000459 callHelperAndClearArgs( env, cc, cee, n_arg_ws );
sewardj77352542004-10-30 20:39:01 +0000460}
461
462
sewardj2d3f77c2004-09-22 23:49:09 +0000463/* Given a guest-state array descriptor, an index expression and a
464 bias, generate an X86AMode holding the relevant guest state
465 offset. */
466
467static
468X86AMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr,
469 IRExpr* off, Int bias )
470{
471 Int elemSz = sizeofIRType(descr->elemTy);
472 Int nElems = descr->nElems;
473
474 /* throw out any cases not generated by an x86 front end. In
475 theory there might be a day where we need to handle them -- if
476 we ever run non-x86-guest on x86 host. */
477
478 if (nElems != 8 || (elemSz != 1 && elemSz != 8))
479 vpanic("genGuestArrayOffset(x86 host)");
480
481 /* Compute off into a reg, %off. Then return:
482
483 movl %off, %tmp
484 addl $bias, %tmp (if bias != 0)
485 andl %tmp, 7
486 ... base(%ebp, %tmp, shift) ...
487 */
488 HReg tmp = newVRegI(env);
489 HReg roff = iselIntExpr_R(env, off);
490 addInstr(env, mk_MOVsd_RR(roff, tmp));
491 if (bias != 0) {
492 addInstr(env,
493 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(bias), tmp));
494 }
495 addInstr(env,
496 X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(7), tmp));
497 vassert(elemSz == 1 || elemSz == 8);
498 return
499 X86AMode_IRRS( descr->base, hregX86_EBP(), tmp,
500 elemSz==8 ? 3 : 0);
501}
502
sewardj17442fe2004-09-20 14:54:28 +0000503
504/*---------------------------------------------------------*/
sewardjd18d1bf2004-08-25 12:49:22 +0000505/*--- ISEL: Integer expressions (32/16/8 bit) ---*/
506/*---------------------------------------------------------*/
507
sewardjc97096c2004-06-30 09:28:04 +0000508/* Select insns for an integer-typed expression, and add them to the
sewardjd18d1bf2004-08-25 12:49:22 +0000509 code list. Return a reg holding the result. This reg will be a
510 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
511 want to modify it, ask for a new vreg, copy it in there, and modify
512 the copy. The register allocator will do its best to map both
513 vregs to the same real register, so the copies will often disappear
514 later in the game.
sewardj4042c7e2004-07-18 01:28:30 +0000515
516 This should handle expressions of 32, 16 and 8-bit type. All
517 results are returned in a 32-bit register. For 16- and 8-bit
sewardjd18d1bf2004-08-25 12:49:22 +0000518 expressions, the upper 16/24 bits are arbitrary, so you should mask
519 or sign extend partial values if necessary.
sewardjc97096c2004-06-30 09:28:04 +0000520*/
sewardjd18d1bf2004-08-25 12:49:22 +0000521
sewardj66f2f792004-06-30 16:37:16 +0000522static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
sewardjc97096c2004-06-30 09:28:04 +0000523{
sewardjd18d1bf2004-08-25 12:49:22 +0000524 HReg r = iselIntExpr_R_wrk(env, e);
525 /* sanity checks ... */
526# if 0
527 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
528# endif
529 vassert(hregClass(r) == HRcInt);
530 vassert(hregIsVirtual(r));
531 return r;
532}
533
534/* DO NOT CALL THIS DIRECTLY ! */
535static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
536{
sewardj443cd9d2004-07-18 23:06:45 +0000537 MatchInfo mi;
sewardj84ff0652004-08-23 16:16:08 +0000538 DECLARE_PATTERN(p_32to1_then_1Uto8);
sewardj443cd9d2004-07-18 23:06:45 +0000539
sewardje8e9d732004-07-16 21:03:45 +0000540 IRType ty = typeOfIRExpr(env->type_env,e);
sewardj4042c7e2004-07-18 01:28:30 +0000541 vassert(ty == Ity_I32 || Ity_I16 || Ity_I8);
sewardjc97096c2004-06-30 09:28:04 +0000542
543 switch (e->tag) {
544
sewardj60f4e3c2004-07-19 01:56:50 +0000545 /* --------- TEMP --------- */
sewardje8e9d732004-07-16 21:03:45 +0000546 case Iex_Tmp: {
sewardje8e9d732004-07-16 21:03:45 +0000547 return lookupIRTemp(env, e->Iex.Tmp.tmp);
548 }
sewardjc97096c2004-06-30 09:28:04 +0000549
sewardj60f4e3c2004-07-19 01:56:50 +0000550 /* --------- LOAD --------- */
sewardje8e9d732004-07-16 21:03:45 +0000551 case Iex_LDle: {
sewardje8e9d732004-07-16 21:03:45 +0000552 HReg dst = newVRegI(env);
sewardj4042c7e2004-07-18 01:28:30 +0000553 X86AMode* amode = iselIntExpr_AMode ( env, e->Iex.LDle.addr );
554 if (ty == Ity_I32) {
555 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
556 X86RMI_Mem(amode), dst) );
557 return dst;
558 }
559 if (ty == Ity_I16) {
560 addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
561 return dst;
562 }
sewardj443cd9d2004-07-18 23:06:45 +0000563 if (ty == Ity_I8) {
564 addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
565 return dst;
566 }
sewardj4042c7e2004-07-18 01:28:30 +0000567 break;
sewardje8e9d732004-07-16 21:03:45 +0000568 }
569
sewardj60f4e3c2004-07-19 01:56:50 +0000570 /* --------- BINARY OP --------- */
sewardje8e9d732004-07-16 21:03:45 +0000571 case Iex_Binop: {
572 X86AluOp aluOp;
573 X86ShiftOp shOp;
sewardj8c7f1ab2004-07-29 20:31:09 +0000574
sewardjd4a4d012004-11-08 18:53:52 +0000575 /* Pattern: Sub32(0,x) */
576 if (e->Iex.Binop.op == Iop_Sub32 && isZero32(e->Iex.Binop.arg1)) {
577 HReg dst = newVRegI(env);
578 HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg2);
579 addInstr(env, mk_MOVsd_RR(reg,dst));
580 addInstr(env, X86Instr_Unary32(Xun_NEG,X86RM_Reg(dst)));
581 return dst;
582 }
583
sewardj4042c7e2004-07-18 01:28:30 +0000584 /* Is it an addition or logical style op? */
sewardje8e9d732004-07-16 21:03:45 +0000585 switch (e->Iex.Binop.op) {
sewardja2384712004-07-29 14:36:40 +0000586 case Iop_Add8: case Iop_Add16: case Iop_Add32:
sewardj1813dbe2004-07-28 17:09:04 +0000587 aluOp = Xalu_ADD; break;
sewardj60f4e3c2004-07-19 01:56:50 +0000588 case Iop_Sub8: case Iop_Sub16: case Iop_Sub32:
589 aluOp = Xalu_SUB; break;
sewardj5c34dc92004-07-19 12:48:11 +0000590 case Iop_And8: case Iop_And16: case Iop_And32:
591 aluOp = Xalu_AND; break;
sewardj750f4072004-07-26 22:39:11 +0000592 case Iop_Or8: case Iop_Or16: case Iop_Or32:
sewardj597b71b2004-07-19 02:51:12 +0000593 aluOp = Xalu_OR; break;
sewardja2384712004-07-29 14:36:40 +0000594 case Iop_Xor8: case Iop_Xor16: case Iop_Xor32:
sewardj597b71b2004-07-19 02:51:12 +0000595 aluOp = Xalu_XOR; break;
sewardjb81f8b32004-07-30 10:17:50 +0000596 case Iop_Mul16: case Iop_Mul32:
597 aluOp = Xalu_MUL; break;
598 default:
599 aluOp = Xalu_INVALID; break;
sewardje8e9d732004-07-16 21:03:45 +0000600 }
601 /* For commutative ops we assume any literal
sewardj66f2f792004-06-30 16:37:16 +0000602 values are on the second operand. */
sewardje8e9d732004-07-16 21:03:45 +0000603 if (aluOp != Xalu_INVALID) {
sewardj66f2f792004-06-30 16:37:16 +0000604 HReg dst = newVRegI(env);
605 HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
606 X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
sewardj443cd9d2004-07-18 23:06:45 +0000607 addInstr(env, mk_MOVsd_RR(reg,dst));
sewardje8e9d732004-07-16 21:03:45 +0000608 addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst));
sewardj66f2f792004-06-30 16:37:16 +0000609 return dst;
sewardjc97096c2004-06-30 09:28:04 +0000610 }
sewardj4f391492004-08-24 22:45:30 +0000611 /* Could do better here; forcing the first arg into a reg
612 isn't always clever.
613 -- t70 = Xor32(And32(Xor32(LDle:I32(Add32(t41,0xFFFFFFA0:I32)),
614 LDle:I32(Add32(t41,0xFFFFFFA4:I32))),LDle:I32(Add32(
615 t41,0xFFFFFFA8:I32))),LDle:I32(Add32(t41,0xFFFFFFA0:I32)))
616 movl 0xFFFFFFA0(%vr41),%vr107
617 movl 0xFFFFFFA4(%vr41),%vr108
618 movl %vr107,%vr106
619 xorl %vr108,%vr106
620 movl 0xFFFFFFA8(%vr41),%vr109
621 movl %vr106,%vr105
622 andl %vr109,%vr105
623 movl 0xFFFFFFA0(%vr41),%vr110
624 movl %vr105,%vr104
625 xorl %vr110,%vr104
626 movl %vr104,%vr70
627 */
sewardj8c7f1ab2004-07-29 20:31:09 +0000628
sewardj4042c7e2004-07-18 01:28:30 +0000629 /* Perhaps a shift op? */
sewardje8e9d732004-07-16 21:03:45 +0000630 switch (e->Iex.Binop.op) {
sewardj1813dbe2004-07-28 17:09:04 +0000631 case Iop_Shl32: case Iop_Shl16: case Iop_Shl8:
632 shOp = Xsh_SHL; break;
633 case Iop_Shr32: case Iop_Shr16: case Iop_Shr8:
sewardj5c34dc92004-07-19 12:48:11 +0000634 shOp = Xsh_SHR; break;
sewardj8c7f1ab2004-07-29 20:31:09 +0000635 case Iop_Sar32: case Iop_Sar16: case Iop_Sar8:
sewardj1813dbe2004-07-28 17:09:04 +0000636 shOp = Xsh_SAR; break;
637 default:
638 shOp = Xsh_INVALID; break;
sewardje8e9d732004-07-16 21:03:45 +0000639 }
640 if (shOp != Xsh_INVALID) {
sewardj8c7f1ab2004-07-29 20:31:09 +0000641 HReg dst = newVRegI(env);
sewardj38ff3d82004-07-26 23:27:08 +0000642
643 /* regL = the value to be shifted */
sewardj96efe572004-07-03 14:48:24 +0000644 HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardj443cd9d2004-07-18 23:06:45 +0000645 addInstr(env, mk_MOVsd_RR(regL,dst));
sewardj38ff3d82004-07-26 23:27:08 +0000646
sewardj5c34dc92004-07-19 12:48:11 +0000647 /* Do any necessary widening for 16/8 bit operands */
648 switch (e->Iex.Binop.op) {
649 case Iop_Shr8:
650 addInstr(env, X86Instr_Alu32R(
651 Xalu_AND, X86RMI_Imm(0xFF), dst));
652 break;
653 case Iop_Shr16:
654 addInstr(env, X86Instr_Alu32R(
655 Xalu_AND, X86RMI_Imm(0xFFFF), dst));
656 break;
sewardj8c7f1ab2004-07-29 20:31:09 +0000657 case Iop_Sar8:
658 addInstr(env, X86Instr_Sh32(Xsh_SHL, 24, X86RM_Reg(dst)));
659 addInstr(env, X86Instr_Sh32(Xsh_SAR, 24, X86RM_Reg(dst)));
660 break;
661 case Iop_Sar16:
662 addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(dst)));
663 addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, X86RM_Reg(dst)));
664 break;
sewardj5c34dc92004-07-19 12:48:11 +0000665 default: break;
666 }
sewardj38ff3d82004-07-26 23:27:08 +0000667
668 /* Now consider the shift amount. If it's a literal, we
669 can do a much better job than the general case. */
670 if (e->Iex.Binop.arg2->tag == Iex_Const) {
671 /* assert that the IR is well-typed */
672 Int nshift;
673 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
sewardj38ff3d82004-07-26 23:27:08 +0000674 nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
sewardj3bd676c2004-07-27 10:50:38 +0000675 vassert(nshift >= 0);
sewardj38ff3d82004-07-26 23:27:08 +0000676 if (nshift > 0)
sewardjb81f8b32004-07-30 10:17:50 +0000677 /* Can't allow nshift==0 since that means %cl */
sewardj38ff3d82004-07-26 23:27:08 +0000678 addInstr(env, X86Instr_Sh32(
679 shOp,
680 nshift,
681 X86RM_Reg(dst)));
682 } else {
683 /* General case; we have to force the amount into %cl. */
684 HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2);
685 addInstr(env, mk_MOVsd_RR(regR,hregX86_ECX()));
686 addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, X86RM_Reg(dst)));
687 }
sewardjd9c2b792004-07-08 01:44:38 +0000688 return dst;
689 }
sewardj8c7f1ab2004-07-29 20:31:09 +0000690
691 /* Handle misc other ops. */
sewardjfd332772004-11-09 16:01:40 +0000692 if (e->Iex.Binop.op == Iop_8HLto16) {
693 HReg hi8 = newVRegI(env);
694 HReg lo8 = newVRegI(env);
695 HReg hi8s = iselIntExpr_R(env, e->Iex.Binop.arg1);
696 HReg lo8s = iselIntExpr_R(env, e->Iex.Binop.arg2);
697 addInstr(env, mk_MOVsd_RR(hi8s, hi8));
698 addInstr(env, mk_MOVsd_RR(lo8s, lo8));
699 addInstr(env, X86Instr_Sh32(Xsh_SHL, 8, X86RM_Reg(hi8)));
700 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFF), lo8));
701 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo8), hi8));
702 return hi8;
703 }
704
sewardj8c7f1ab2004-07-29 20:31:09 +0000705 if (e->Iex.Binop.op == Iop_16HLto32) {
706 HReg hi16 = newVRegI(env);
707 HReg lo16 = newVRegI(env);
708 HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
709 HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
710 addInstr(env, mk_MOVsd_RR(hi16s, hi16));
711 addInstr(env, mk_MOVsd_RR(lo16s, lo16));
712 addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(hi16)));
713 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFFFF), lo16));
714 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo16), hi16));
715 return hi16;
716 }
717
sewardjb81f8b32004-07-30 10:17:50 +0000718 if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8
719 || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) {
720 HReg a16 = newVRegI(env);
721 HReg b16 = newVRegI(env);
722 HReg a16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
723 HReg b16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
724 Int shift = (e->Iex.Binop.op == Iop_MullS8
725 || e->Iex.Binop.op == Iop_MullU8)
726 ? 24 : 16;
727 X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8
728 || e->Iex.Binop.op == Iop_MullS16)
729 ? Xsh_SAR : Xsh_SHR;
730
731 addInstr(env, mk_MOVsd_RR(a16s, a16));
732 addInstr(env, mk_MOVsd_RR(b16s, b16));
733 addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(a16)));
734 addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(b16)));
735 addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(a16)));
736 addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(b16)));
737 addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16));
738 return b16;
739 }
740
sewardjbdc7d212004-09-09 02:46:40 +0000741 if (e->Iex.Binop.op == Iop_CmpF64) {
742 HReg fL = iselDblExpr(env, e->Iex.Binop.arg1);
743 HReg fR = iselDblExpr(env, e->Iex.Binop.arg2);
744 HReg dst = newVRegI(env);
745 addInstr(env, X86Instr_FpCmp(fL,fR,dst));
746 /* shift this right 8 bits so as to conform to CmpF64
747 definition. */
748 addInstr(env, X86Instr_Sh32(Xsh_SHR, 8, X86RM_Reg(dst)));
749 return dst;
750 }
751
sewardj8f3debf2004-09-08 23:42:23 +0000752 if (e->Iex.Binop.op == Iop_F64toI32 || e->Iex.Binop.op == Iop_F64toI16) {
753 Int sz = e->Iex.Binop.op == Iop_F64toI16 ? 2 : 4;
754 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
755 HReg rrm = iselIntExpr_R(env, e->Iex.Binop.arg1);
756 HReg rrm2 = newVRegI(env);
757 HReg dst = newVRegI(env);
758
759 /* Used several times ... */
760 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
761
762 /* rf now holds the value to be converted, and rrm holds the
763 rounding mode value, encoded as per the IRRoundingMode
764 enum. The first thing to do is set the FPU's rounding
765 mode accordingly. */
766
767 /* Create a space, both for the control word messing, and for
sewardjbdc7d212004-09-09 02:46:40 +0000768 the actual store conversion. */
sewardj8f3debf2004-09-08 23:42:23 +0000769 /* subl $4, %esp */
770 addInstr(env,
771 X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(4), hregX86_ESP()));
772 /* movl %rrm, %rrm2
773 andl $3, %rrm2 -- shouldn't be needed; paranoia
774 shll $10, %rrm2
775 orl $0x037F, %rrm2
776 movl %rrm2, 0(%esp)
777 fldcw 0(%esp)
778 */
779 addInstr(env, mk_MOVsd_RR(rrm, rrm2));
780 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
781 addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2)));
782 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(0x037F), rrm2));
783 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(rrm2), zero_esp));
784 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
785
786 /* gistw/l %rf, 0(%esp) */
787 addInstr(env, X86Instr_FpLdStI(False/*store*/, sz, rf, zero_esp));
788
789 if (sz == 2) {
790 /* movzwl 0(%esp), %dst */
791 addInstr(env, X86Instr_LoadEX(2,False,zero_esp,dst));
792 } else {
793 /* movl 0(%esp), %dst */
794 vassert(sz == 4);
795 addInstr(env, X86Instr_Alu32R(
796 Xalu_MOV, X86RMI_Mem(zero_esp), dst));
797 }
798
799 /* Restore default FPU control.
800 movl $0x037F, 0(%esp)
801 fldcw 0(%esp)
802 */
803 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(0x037F), zero_esp));
804 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
805
806 /* addl $4, %esp */
807 addInstr(env,
808 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(4), hregX86_ESP()));
809 return dst;
810 }
811
sewardj442d0be2004-10-15 22:57:13 +0000812 /* C3210 flags following FPU partial remainder (fprem), both
813 IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
814 if (e->Iex.Binop.op == Iop_PRemC3210F64
815 || e->Iex.Binop.op == Iop_PRem1C3210F64) {
sewardj46de4072004-09-11 19:23:24 +0000816 HReg junk = newVRegF(env);
817 HReg dst = newVRegI(env);
818 HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
819 HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
sewardj442d0be2004-10-15 22:57:13 +0000820 addInstr(env, X86Instr_FpBinary(
821 e->Iex.Binop.op==Iop_PRemC3210F64 ? Xfp_PREM : Xfp_PREM1,
822 srcL,srcR,junk
823 ));
sewardj46de4072004-09-11 19:23:24 +0000824 /* The previous pseudo-insn will have left the FPU's C3210
825 flags set correctly. So bag them. */
826 addInstr(env, X86Instr_FpStSW_AX());
827 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst));
828 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
829 return dst;
830 }
831
sewardje8e9d732004-07-16 21:03:45 +0000832 break;
sewardjd9c2b792004-07-08 01:44:38 +0000833 }
834
sewardj60f4e3c2004-07-19 01:56:50 +0000835 /* --------- UNARY OP --------- */
sewardj4042c7e2004-07-18 01:28:30 +0000836 case Iex_Unop: {
sewardj443cd9d2004-07-18 23:06:45 +0000837 /* 1Uto8(32to1(expr32)) */
838 DEFINE_PATTERN(p_32to1_then_1Uto8,
sewardj38ff3d82004-07-26 23:27:08 +0000839 unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
sewardj443cd9d2004-07-18 23:06:45 +0000840 if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
841 IRExpr* expr32 = mi.bindee[0];
sewardj38ff3d82004-07-26 23:27:08 +0000842 HReg dst = newVRegI(env);
sewardj443cd9d2004-07-18 23:06:45 +0000843 HReg src = iselIntExpr_R(env, expr32);
844 addInstr(env, mk_MOVsd_RR(src,dst) );
845 addInstr(env, X86Instr_Alu32R(Xalu_AND,
846 X86RMI_Imm(1), dst));
847 return dst;
848 }
849
sewardjd18d1bf2004-08-25 12:49:22 +0000850 /* 16Uto32(LDle(expr32)) */
851 {
852 DECLARE_PATTERN(p_LDle16_then_16Uto32);
853 DEFINE_PATTERN(p_LDle16_then_16Uto32,
854 unop(Iop_16Uto32,IRExpr_LDle(Ity_I16,bind(0))) );
855 if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) {
856 HReg dst = newVRegI(env);
857 X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
858 addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
859 return dst;
860 }
861 }
862
sewardj4042c7e2004-07-18 01:28:30 +0000863 switch (e->Iex.Unop.op) {
sewardj47341042004-09-19 11:55:46 +0000864 case Iop_8Uto16:
sewardj443cd9d2004-07-18 23:06:45 +0000865 case Iop_8Uto32:
866 case Iop_16Uto32: {
sewardj4042c7e2004-07-18 01:28:30 +0000867 HReg dst = newVRegI(env);
868 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
sewardj47341042004-09-19 11:55:46 +0000869 UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF;
sewardj443cd9d2004-07-18 23:06:45 +0000870 addInstr(env, mk_MOVsd_RR(src,dst) );
sewardj4042c7e2004-07-18 01:28:30 +0000871 addInstr(env, X86Instr_Alu32R(Xalu_AND,
sewardj443cd9d2004-07-18 23:06:45 +0000872 X86RMI_Imm(mask), dst));
873 return dst;
874 }
sewardj47341042004-09-19 11:55:46 +0000875 case Iop_8Sto16:
sewardjc22a6fd2004-07-29 23:41:47 +0000876 case Iop_8Sto32:
877 case Iop_16Sto32: {
878 HReg dst = newVRegI(env);
879 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
sewardj47341042004-09-19 11:55:46 +0000880 UInt amt = e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24;
sewardjc22a6fd2004-07-29 23:41:47 +0000881 addInstr(env, mk_MOVsd_RR(src,dst) );
882 addInstr(env, X86Instr_Sh32(Xsh_SHL, amt, X86RM_Reg(dst)));
883 addInstr(env, X86Instr_Sh32(Xsh_SAR, amt, X86RM_Reg(dst)));
884 return dst;
885 }
sewardja2384712004-07-29 14:36:40 +0000886 case Iop_Not8:
887 case Iop_Not16:
sewardj443cd9d2004-07-18 23:06:45 +0000888 case Iop_Not32: {
889 HReg dst = newVRegI(env);
890 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
891 addInstr(env, mk_MOVsd_RR(src,dst) );
sewardjd4a4d012004-11-08 18:53:52 +0000892 addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(dst)));
sewardj4042c7e2004-07-18 01:28:30 +0000893 return dst;
894 }
sewardj597b71b2004-07-19 02:51:12 +0000895 case Iop_64HIto32: {
896 HReg rHi, rLo;
897 iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg);
898 return rHi; /* and abandon rLo .. poor wee thing :-) */
899 }
sewardj8c7f1ab2004-07-29 20:31:09 +0000900 case Iop_64to32: {
sewardj597b71b2004-07-19 02:51:12 +0000901 HReg rHi, rLo;
902 iselIntExpr64(&rHi,&rLo, env, e->Iex.Unop.arg);
903 return rLo; /* similar stupid comment to the above ... */
904 }
sewardjb81f8b32004-07-30 10:17:50 +0000905 case Iop_16HIto8:
sewardj8c7f1ab2004-07-29 20:31:09 +0000906 case Iop_32HIto16: {
sewardjb81f8b32004-07-30 10:17:50 +0000907 HReg dst = newVRegI(env);
908 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
909 Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
sewardj8c7f1ab2004-07-29 20:31:09 +0000910 addInstr(env, mk_MOVsd_RR(src,dst) );
sewardjb81f8b32004-07-30 10:17:50 +0000911 addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst)));
sewardj8c7f1ab2004-07-29 20:31:09 +0000912 return dst;
913 }
sewardj84ff0652004-08-23 16:16:08 +0000914 case Iop_1Uto32:
sewardjd7cb8532004-08-17 23:59:23 +0000915 case Iop_1Uto8: {
916 HReg dst = newVRegI(env);
917 X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
918 addInstr(env, X86Instr_Set32(cond,dst));
919 return dst;
920 }
sewardjfd332772004-11-09 16:01:40 +0000921 case Iop_1Sto8:
sewardj218e29f2004-11-07 18:45:15 +0000922 case Iop_1Sto16:
sewardj415d9352004-11-04 15:20:15 +0000923 case Iop_1Sto32: {
924 /* could do better than this, but for now ... */
925 HReg dst = newVRegI(env);
926 X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
927 addInstr(env, X86Instr_Set32(cond,dst));
928 addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(dst)));
929 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(dst)));
930 return dst;
931 }
sewardjce646f22004-08-31 23:55:54 +0000932 case Iop_Ctz32: {
933 /* Count trailing zeroes, implemented by x86 'bsfl' */
934 HReg dst = newVRegI(env);
935 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
936 addInstr(env, X86Instr_Bsfr32(True,src,dst));
937 return dst;
938 }
939 case Iop_Clz32: {
940 /* Count leading zeroes. Do 'bsrl' to establish the index
941 of the highest set bit, and subtract that value from
942 31. */
943 HReg tmp = newVRegI(env);
944 HReg dst = newVRegI(env);
945 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
946 addInstr(env, X86Instr_Bsfr32(False,src,tmp));
947 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
948 X86RMI_Imm(31), dst));
949 addInstr(env, X86Instr_Alu32R(Xalu_SUB,
950 X86RMI_Reg(tmp), dst));
951 return dst;
952 }
sewardj89cd0932004-09-08 18:23:25 +0000953
sewardjb81f8b32004-07-30 10:17:50 +0000954 case Iop_16to8:
sewardja2384712004-07-29 14:36:40 +0000955 case Iop_32to8:
956 case Iop_32to16:
sewardjb81f8b32004-07-30 10:17:50 +0000957 /* These are no-ops. */
sewardja2384712004-07-29 14:36:40 +0000958 return iselIntExpr_R(env, e->Iex.Unop.arg);
959
sewardj4042c7e2004-07-18 01:28:30 +0000960 default:
961 break;
962 }
963 break;
964 }
965
sewardj60f4e3c2004-07-19 01:56:50 +0000966 /* --------- GET --------- */
sewardje8e9d732004-07-16 21:03:45 +0000967 case Iex_Get: {
968 if (ty == Ity_I32) {
969 HReg dst = newVRegI(env);
970 addInstr(env, X86Instr_Alu32R(
971 Xalu_MOV,
972 X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset,
973 hregX86_EBP())),
974 dst));
975 return dst;
sewardjc97096c2004-06-30 09:28:04 +0000976 }
sewardj60f4e3c2004-07-19 01:56:50 +0000977 if (ty == Ity_I8 || ty == Ity_I16) {
sewardj4042c7e2004-07-18 01:28:30 +0000978 HReg dst = newVRegI(env);
979 addInstr(env, X86Instr_LoadEX(
sewardj60f4e3c2004-07-19 01:56:50 +0000980 ty==Ity_I8 ? 1 : 2,
981 False,
sewardj4042c7e2004-07-18 01:28:30 +0000982 X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()),
983 dst));
984 return dst;
985 }
sewardje8e9d732004-07-16 21:03:45 +0000986 break;
sewardjc97096c2004-06-30 09:28:04 +0000987 }
sewardje8e9d732004-07-16 21:03:45 +0000988
sewardj33124f62004-08-30 17:54:18 +0000989 case Iex_GetI: {
sewardj2d3f77c2004-09-22 23:49:09 +0000990 X86AMode* am
991 = genGuestArrayOffset(
992 env, e->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +0000993 e->Iex.GetI.ix, e->Iex.GetI.bias );
sewardj33124f62004-08-30 17:54:18 +0000994 HReg dst = newVRegI(env);
995 if (ty == Ity_I8) {
sewardj2d3f77c2004-09-22 23:49:09 +0000996 addInstr(env, X86Instr_LoadEX( 1, False, am, dst ));
sewardj33124f62004-08-30 17:54:18 +0000997 return dst;
998 }
sewardj2d3f77c2004-09-22 23:49:09 +0000999 break;
sewardj33124f62004-08-30 17:54:18 +00001000 }
1001
sewardj60f4e3c2004-07-19 01:56:50 +00001002 /* --------- CCALL --------- */
sewardje8e9d732004-07-16 21:03:45 +00001003 case Iex_CCall: {
sewardjd18d1bf2004-08-25 12:49:22 +00001004 HReg dst = newVRegI(env);
sewardje8e9d732004-07-16 21:03:45 +00001005 vassert(ty == Ity_I32);
sewardjc4be80c2004-09-10 16:17:45 +00001006
1007 /* be very restrictive for now. Only 32/64-bit ints allowed
1008 for args, and 32 bits for return type. */
sewardj4042c7e2004-07-18 01:28:30 +00001009 if (e->Iex.CCall.retty != Ity_I32)
sewardjd18d1bf2004-08-25 12:49:22 +00001010 goto irreducible;
sewardjc4be80c2004-09-10 16:17:45 +00001011
sewardj77352542004-10-30 20:39:01 +00001012 /* Marshal args, do the call, clear stack. */
sewardj4b861de2004-11-03 15:24:42 +00001013 doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
sewardj17442fe2004-09-20 14:54:28 +00001014
sewardjd18d1bf2004-08-25 12:49:22 +00001015 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst));
1016 return dst;
sewardje8e9d732004-07-16 21:03:45 +00001017 }
1018
sewardj60f4e3c2004-07-19 01:56:50 +00001019 /* --------- LITERAL --------- */
sewardje8e9d732004-07-16 21:03:45 +00001020 /* 32/16/8-bit literals */
1021 case Iex_Const: {
sewardj4042c7e2004-07-18 01:28:30 +00001022 X86RMI* rmi = iselIntExpr_RMI ( env, e );
1023 HReg r = newVRegI(env);
1024 addInstr(env, X86Instr_Alu32R(Xalu_MOV, rmi, r));
sewardje8e9d732004-07-16 21:03:45 +00001025 return r;
1026 }
sewardjc97096c2004-06-30 09:28:04 +00001027
sewardj60f4e3c2004-07-19 01:56:50 +00001028 /* --------- MULTIPLEX --------- */
sewardj4042c7e2004-07-18 01:28:30 +00001029 case Iex_Mux0X: {
sewardjc744e872004-08-26 11:24:39 +00001030 if ((ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8)
sewardj4042c7e2004-07-18 01:28:30 +00001031 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
sewardj2e56f9f2004-07-24 01:24:38 +00001032 HReg r8;
sewardj38ff3d82004-07-26 23:27:08 +00001033 HReg rX = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
1034 X86RM* r0 = iselIntExpr_RM(env, e->Iex.Mux0X.expr0);
1035 HReg dst = newVRegI(env);
1036 addInstr(env, mk_MOVsd_RR(rX,dst));
1037 r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1038 addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
1039 addInstr(env, X86Instr_CMov32(Xcc_Z,r0,dst));
1040 return dst;
sewardj4042c7e2004-07-18 01:28:30 +00001041 }
1042 break;
1043 }
1044
sewardjc97096c2004-06-30 09:28:04 +00001045 default:
1046 break;
1047 } /* switch (e->tag) */
1048
1049 /* We get here if no pattern matched. */
sewardje8e9d732004-07-16 21:03:45 +00001050 irreducible:
sewardj35421a32004-07-05 13:12:34 +00001051 ppIRExpr(e);
sewardjd9c2b792004-07-08 01:44:38 +00001052 vpanic("iselIntExpr_R: cannot reduce tree");
sewardjc97096c2004-06-30 09:28:04 +00001053}
1054
1055
sewardj66f2f792004-06-30 16:37:16 +00001056/*---------------------------------------------------------*/
1057/*--- ISEL: Integer expression auxiliaries ---*/
1058/*---------------------------------------------------------*/
1059
sewardjd18d1bf2004-08-25 12:49:22 +00001060/* --------------------- AMODEs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001061
sewardj66f2f792004-06-30 16:37:16 +00001062/* Return an AMode which computes the value of the specified
1063 expression, possibly also adding insns to the code list as a
sewardj4042c7e2004-07-18 01:28:30 +00001064 result. The expression may only be a 32-bit one.
sewardjc97096c2004-06-30 09:28:04 +00001065*/
sewardjd18d1bf2004-08-25 12:49:22 +00001066
1067static Bool sane_AMode ( X86AMode* am )
1068{
1069 switch (am->tag) {
1070 case Xam_IR:
1071 return hregClass(am->Xam.IR.reg) == HRcInt
1072 && (hregIsVirtual(am->Xam.IR.reg)
1073 || am->Xam.IR.reg == hregX86_EBP());
1074 case Xam_IRRS:
1075 return hregClass(am->Xam.IRRS.base) == HRcInt
1076 && hregIsVirtual(am->Xam.IRRS.base)
1077 && hregClass(am->Xam.IRRS.index) == HRcInt
1078 && hregIsVirtual(am->Xam.IRRS.index);
1079 default:
1080 vpanic("sane_AMode: unknown x86 amode tag");
1081 }
1082}
1083
sewardj66f2f792004-06-30 16:37:16 +00001084static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e )
sewardjc97096c2004-06-30 09:28:04 +00001085{
sewardjd18d1bf2004-08-25 12:49:22 +00001086 X86AMode* am = iselIntExpr_AMode_wrk(env, e);
1087 vassert(sane_AMode(am));
1088 return am;
1089}
1090
1091/* DO NOT CALL THIS DIRECTLY ! */
1092static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e )
1093{
sewardj4042c7e2004-07-18 01:28:30 +00001094 IRType ty = typeOfIRExpr(env->type_env,e);
1095 vassert(ty == Ity_I32);
sewardjc97096c2004-06-30 09:28:04 +00001096
1097 /* Add32(expr1, Shl32(expr2, imm)) */
1098 if (e->tag == Iex_Binop
1099 && e->Iex.Binop.op == Iop_Add32
1100 && e->Iex.Binop.arg2->tag == Iex_Binop
1101 && e->Iex.Binop.arg2->Iex.Binop.op == Iop_Shl32
1102 && e->Iex.Binop.arg2->Iex.Binop.arg2->tag == Iex_Const
sewardjd18d1bf2004-08-25 12:49:22 +00001103 && e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8) {
1104 UInt shift = e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
1105 if (shift == 1 || shift == 2 || shift == 3) {
sewardj66f2f792004-06-30 16:37:16 +00001106 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1107 HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg2->Iex.Binop.arg1 );
sewardjc97096c2004-06-30 09:28:04 +00001108 return X86AMode_IRRS(0, r1, r2, shift);
1109 }
1110 }
1111
1112 /* Add32(expr,i) */
1113 if (e->tag == Iex_Binop
1114 && e->Iex.Binop.op == Iop_Add32
1115 && e->Iex.Binop.arg2->tag == Iex_Const
1116 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
sewardj66f2f792004-06-30 16:37:16 +00001117 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardjd9c2b792004-07-08 01:44:38 +00001118 return X86AMode_IR(e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, r1);
sewardjc97096c2004-06-30 09:28:04 +00001119 }
1120
1121 /* Doesn't match anything in particular. Generate it into
1122 a register and use that. */
1123 {
sewardj66f2f792004-06-30 16:37:16 +00001124 HReg r1 = iselIntExpr_R(env, e);
sewardjd9c2b792004-07-08 01:44:38 +00001125 return X86AMode_IR(0, r1);
sewardjc97096c2004-06-30 09:28:04 +00001126 }
1127}
1128
1129
sewardjd18d1bf2004-08-25 12:49:22 +00001130/* --------------------- RMIs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001131
sewardj4042c7e2004-07-18 01:28:30 +00001132/* Similarly, calculate an expression into an X86RMI operand. As with
1133 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
sewardj66f2f792004-06-30 16:37:16 +00001134
1135static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e )
1136{
sewardjd18d1bf2004-08-25 12:49:22 +00001137 X86RMI* rmi = iselIntExpr_RMI_wrk(env, e);
1138 /* sanity checks ... */
1139 switch (rmi->tag) {
1140 case Xrmi_Imm:
1141 return rmi;
1142 case Xrmi_Reg:
1143 vassert(hregClass(rmi->Xrmi.Reg.reg) == HRcInt);
1144 vassert(hregIsVirtual(rmi->Xrmi.Reg.reg));
1145 return rmi;
1146 case Xrmi_Mem:
1147 vassert(sane_AMode(rmi->Xrmi.Mem.am));
1148 return rmi;
1149 default:
1150 vpanic("iselIntExpr_RMI: unknown x86 RMI tag");
1151 }
1152}
1153
1154/* DO NOT CALL THIS DIRECTLY ! */
1155static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e )
1156{
sewardj4042c7e2004-07-18 01:28:30 +00001157 IRType ty = typeOfIRExpr(env->type_env,e);
1158 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardj66f2f792004-06-30 16:37:16 +00001159
1160 /* special case: immediate */
sewardj4042c7e2004-07-18 01:28:30 +00001161 if (e->tag == Iex_Const) {
1162 UInt u;
1163 switch (e->Iex.Const.con->tag) {
1164 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
1165 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
1166 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
1167 default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)");
1168 }
1169 return X86RMI_Imm(u);
sewardj66f2f792004-06-30 16:37:16 +00001170 }
1171
sewardje8e9d732004-07-16 21:03:45 +00001172 /* special case: 32-bit GET */
sewardj4042c7e2004-07-18 01:28:30 +00001173 if (e->tag == Iex_Get && ty == Ity_I32) {
sewardje8e9d732004-07-16 21:03:45 +00001174 return X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset,
1175 hregX86_EBP()));
1176 }
1177
sewardj66f2f792004-06-30 16:37:16 +00001178 /* special case: load from memory */
1179
1180 /* default case: calculate into a register and return that */
1181 {
1182 HReg r = iselIntExpr_R ( env, e );
1183 return X86RMI_Reg(r);
1184 }
1185}
1186
1187
sewardjd18d1bf2004-08-25 12:49:22 +00001188/* --------------------- RIs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001189
sewardj4042c7e2004-07-18 01:28:30 +00001190/* Calculate an expression into an X86RI operand. As with
1191 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
sewardj66f2f792004-06-30 16:37:16 +00001192
1193static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e )
1194{
sewardjd18d1bf2004-08-25 12:49:22 +00001195 X86RI* ri = iselIntExpr_RI_wrk(env, e);
1196 /* sanity checks ... */
1197 switch (ri->tag) {
1198 case Xri_Imm:
1199 return ri;
1200 case Xrmi_Reg:
1201 vassert(hregClass(ri->Xri.Reg.reg) == HRcInt);
1202 vassert(hregIsVirtual(ri->Xri.Reg.reg));
1203 return ri;
1204 default:
1205 vpanic("iselIntExpr_RI: unknown x86 RI tag");
1206 }
1207}
1208
1209/* DO NOT CALL THIS DIRECTLY ! */
1210static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
1211{
sewardj4042c7e2004-07-18 01:28:30 +00001212 IRType ty = typeOfIRExpr(env->type_env,e);
1213 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
sewardj66f2f792004-06-30 16:37:16 +00001214
1215 /* special case: immediate */
sewardj4042c7e2004-07-18 01:28:30 +00001216 if (e->tag == Iex_Const) {
1217 UInt u;
1218 switch (e->Iex.Const.con->tag) {
1219 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
1220 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
1221 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
1222 default: vpanic("iselIntExpr_RMI.Iex_Const(x86h)");
1223 }
1224 return X86RI_Imm(u);
sewardj66f2f792004-06-30 16:37:16 +00001225 }
1226
1227 /* default case: calculate into a register and return that */
1228 {
1229 HReg r = iselIntExpr_R ( env, e );
1230 return X86RI_Reg(r);
1231 }
1232}
1233
1234
sewardjd18d1bf2004-08-25 12:49:22 +00001235/* --------------------- RMs --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001236
sewardj4042c7e2004-07-18 01:28:30 +00001237/* Similarly, calculate an expression into an X86RM operand. As with
1238 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
1239
1240static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e )
1241{
sewardjd18d1bf2004-08-25 12:49:22 +00001242 X86RM* rm = iselIntExpr_RM_wrk(env, e);
1243 /* sanity checks ... */
1244 switch (rm->tag) {
1245 case Xrm_Reg:
1246 vassert(hregClass(rm->Xrm.Reg.reg) == HRcInt);
1247 vassert(hregIsVirtual(rm->Xrm.Reg.reg));
1248 return rm;
1249 case Xrm_Mem:
1250 vassert(sane_AMode(rm->Xrm.Mem.am));
1251 return rm;
1252 default:
1253 vpanic("iselIntExpr_RM: unknown x86 RM tag");
1254 }
1255}
1256
1257/* DO NOT CALL THIS DIRECTLY ! */
1258static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e )
1259{
sewardj4042c7e2004-07-18 01:28:30 +00001260 IRType ty = typeOfIRExpr(env->type_env,e);
1261 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
1262
1263 /* special case: 32-bit GET */
1264 if (e->tag == Iex_Get && ty == Ity_I32) {
1265 return X86RM_Mem(X86AMode_IR(e->Iex.Get.offset,
1266 hregX86_EBP()));
1267 }
1268
1269 /* special case: load from memory */
1270
1271 /* default case: calculate into a register and return that */
1272 {
1273 HReg r = iselIntExpr_R ( env, e );
1274 return X86RM_Reg(r);
1275 }
1276}
1277
1278
sewardjd18d1bf2004-08-25 12:49:22 +00001279/* --------------------- CONDCODE --------------------- */
sewardj60f4e3c2004-07-19 01:56:50 +00001280
sewardj443cd9d2004-07-18 23:06:45 +00001281/* Generate code to evaluated a bit-typed expression, returning the
1282 condition code which would correspond when the expression would
1283 notionally have returned 1. */
1284
1285static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
1286{
sewardjd18d1bf2004-08-25 12:49:22 +00001287 /* Uh, there's nothing we can sanity check here, unfortunately. */
1288 return iselCondCode_wrk(env,e);
1289}
1290
1291/* DO NOT CALL THIS DIRECTLY ! */
1292static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
1293{
sewardj443cd9d2004-07-18 23:06:45 +00001294 MatchInfo mi;
1295 DECLARE_PATTERN(p_32to1);
sewardj8f3debf2004-09-08 23:42:23 +00001296 //DECLARE_PATTERN(p_eq32_literal);
1297 //DECLARE_PATTERN(p_ne32_zero);
sewardj84ff0652004-08-23 16:16:08 +00001298 DECLARE_PATTERN(p_1Uto32_then_32to1);
sewardj443cd9d2004-07-18 23:06:45 +00001299
1300 vassert(e);
sewardjba999312004-11-15 15:21:17 +00001301 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
sewardj443cd9d2004-07-18 23:06:45 +00001302
sewardj0dc3ff92004-10-16 11:31:31 +00001303 /* Constant 1:Bit */
sewardjba999312004-11-15 15:21:17 +00001304 if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
1305 vassert(e->Iex.Const.con->tag == Ico_U1);
sewardj0dc3ff92004-10-16 11:31:31 +00001306 HReg r = newVRegI(env);
1307 addInstr(env, X86Instr_Alu32R(Xalu_MOV,X86RMI_Imm(0),r));
1308 addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(r),r));
1309 return Xcc_Z;
1310 }
1311
sewardj6e797c52004-10-13 15:20:17 +00001312 /* Not1(...) */
1313 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
1314 /* Generate code for the arg, and negate the test condition */
1315 return 1 ^ iselCondCode(env, e->Iex.Unop.arg);
1316 }
1317
sewardj84ff0652004-08-23 16:16:08 +00001318 /* 32to1(1Uto32(expr1)) -- the casts are pointless, ignore them */
1319 DEFINE_PATTERN(p_1Uto32_then_32to1,
1320 unop(Iop_32to1,unop(Iop_1Uto32,bind(0))));
1321 if (matchIRExpr(&mi,p_1Uto32_then_32to1,e)) {
1322 IRExpr* expr1 = mi.bindee[0];
1323 return iselCondCode(env, expr1);
1324 }
1325
sewardj443cd9d2004-07-18 23:06:45 +00001326 /* pattern: 32to1(expr32) */
1327 DEFINE_PATTERN(p_32to1,
1328 unop(Iop_32to1,bind(0))
1329 );
1330 if (matchIRExpr(&mi,p_32to1,e)) {
sewardj09cc2fe2004-08-18 00:28:48 +00001331 X86RM* rm = iselIntExpr_RM(env, mi.bindee[0]);
1332 addInstr(env, X86Instr_Test32(X86RI_Imm(1),rm));
sewardj443cd9d2004-07-18 23:06:45 +00001333 return Xcc_NZ;
1334 }
1335
sewardjb9c5cf62004-08-24 15:10:38 +00001336 /* CmpEQ8 / CmpNE8 */
sewardj84ff0652004-08-23 16:16:08 +00001337 if (e->tag == Iex_Binop
sewardjb9c5cf62004-08-24 15:10:38 +00001338 && (e->Iex.Binop.op == Iop_CmpEQ8
1339 || e->Iex.Binop.op == Iop_CmpNE8)) {
1340 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1341 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1342 HReg r = newVRegI(env);
1343 addInstr(env, mk_MOVsd_RR(r1,r));
1344 addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r));
1345 addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(0xFF),r));
1346 switch (e->Iex.Binop.op) {
1347 case Iop_CmpEQ8: return Xcc_Z;
1348 case Iop_CmpNE8: return Xcc_NZ;
1349 default: vpanic("iselCondCode(x86): CmpXX8");
1350 }
1351 }
1352
1353 /* CmpEQ16 / CmpNE16 */
1354 if (e->tag == Iex_Binop
1355 && (e->Iex.Binop.op == Iop_CmpEQ16
1356 || e->Iex.Binop.op == Iop_CmpNE16)) {
1357 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1358 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1359 HReg r = newVRegI(env);
1360 addInstr(env, mk_MOVsd_RR(r1,r));
1361 addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r));
1362 addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(0xFFFF),r));
1363 switch (e->Iex.Binop.op) {
1364 case Iop_CmpEQ16: return Xcc_Z;
1365 case Iop_CmpNE16: return Xcc_NZ;
sewardjb5874aa2004-11-04 16:57:50 +00001366 default: vpanic("iselCondCode(x86): CmpXX16");
sewardjb9c5cf62004-08-24 15:10:38 +00001367 }
1368 }
1369
sewardj6f33f752004-11-11 02:17:53 +00001370 /* CmpNE32(1Sto32(b), 0) ==> b */
1371 {
1372 DECLARE_PATTERN(p_CmpNE32_1Sto32);
1373 DEFINE_PATTERN(
1374 p_CmpNE32_1Sto32,
1375 binop(Iop_CmpNE32, unop(Iop_1Sto32,bind(0)), mkU32(0)));
1376 if (matchIRExpr(&mi, p_CmpNE32_1Sto32, e)) {
1377 return iselCondCode(env, mi.bindee[0]);
1378 }
1379 }
1380
sewardjb9c5cf62004-08-24 15:10:38 +00001381 /* Cmp*32*(x,y) */
1382 if (e->tag == Iex_Binop
1383 && (e->Iex.Binop.op == Iop_CmpEQ32
1384 || e->Iex.Binop.op == Iop_CmpNE32
1385 || e->Iex.Binop.op == Iop_CmpLT32S
sewardj84ff0652004-08-23 16:16:08 +00001386 || e->Iex.Binop.op == Iop_CmpLT32U
1387 || e->Iex.Binop.op == Iop_CmpLE32S
1388 || e->Iex.Binop.op == Iop_CmpLE32U)) {
sewardjb9c5cf62004-08-24 15:10:38 +00001389 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
sewardj84ff0652004-08-23 16:16:08 +00001390 X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1391 addInstr(env, X86Instr_Alu32R(Xalu_CMP,rmi2,r1));
1392 switch (e->Iex.Binop.op) {
sewardjb9c5cf62004-08-24 15:10:38 +00001393 case Iop_CmpEQ32: return Xcc_Z;
1394 case Iop_CmpNE32: return Xcc_NZ;
sewardj84ff0652004-08-23 16:16:08 +00001395 case Iop_CmpLT32S: return Xcc_L;
1396 case Iop_CmpLT32U: return Xcc_B;
1397 case Iop_CmpLE32S: return Xcc_LE;
1398 case Iop_CmpLE32U: return Xcc_BE;
sewardjb9c5cf62004-08-24 15:10:38 +00001399 default: vpanic("iselCondCode(x86): CmpXX32");
sewardj84ff0652004-08-23 16:16:08 +00001400 }
1401 }
1402
sewardj6f33f752004-11-11 02:17:53 +00001403 /* CmpNE64(1Sto64(b), 0) ==> b */
1404 {
1405 DECLARE_PATTERN(p_CmpNE64_1Sto64);
1406 DEFINE_PATTERN(
1407 p_CmpNE64_1Sto64,
1408 binop(Iop_CmpNE64, unop(Iop_1Sto64,bind(0)), mkU64(0)));
1409 if (matchIRExpr(&mi, p_CmpNE64_1Sto64, e)) {
1410 return iselCondCode(env, mi.bindee[0]);
1411 }
1412 }
1413
sewardjb5874aa2004-11-04 16:57:50 +00001414 /* CmpNE64 */
1415 if (e->tag == Iex_Binop
1416 && e->Iex.Binop.op == Iop_CmpNE64) {
1417 HReg hi1, hi2, lo1, lo2;
1418 HReg tHi = newVRegI(env);
1419 HReg tLo = newVRegI(env);
1420 iselIntExpr64( &hi1, &lo1, env, e->Iex.Binop.arg1 );
1421 iselIntExpr64( &hi2, &lo2, env, e->Iex.Binop.arg2 );
1422 addInstr(env, mk_MOVsd_RR(hi1, tHi));
1423 addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(hi2), tHi));
1424 addInstr(env, mk_MOVsd_RR(lo1, tLo));
1425 addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(lo2), tLo));
1426 addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(tHi), tLo));
1427 switch (e->Iex.Binop.op) {
1428 case Iop_CmpNE64: return Xcc_NZ;
1429 default: vpanic("iselCondCode(x86): CmpXX64");
1430 }
1431 }
1432
sewardjd7cb8532004-08-17 23:59:23 +00001433 /* var */
1434 if (e->tag == Iex_Tmp) {
1435 HReg r32 = lookupIRTemp(env, e->Iex.Tmp.tmp);
1436 HReg dst = newVRegI(env);
1437 addInstr(env, mk_MOVsd_RR(r32,dst));
1438 addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst));
1439 return Xcc_NZ;
1440 }
1441
sewardj443cd9d2004-07-18 23:06:45 +00001442 ppIRExpr(e);
1443 vpanic("iselCondCode");
1444}
1445
1446
sewardj597b71b2004-07-19 02:51:12 +00001447/*---------------------------------------------------------*/
1448/*--- ISEL: Integer expressions (64 bit) ---*/
1449/*---------------------------------------------------------*/
1450
1451/* Compute a 64-bit value into a register pair, which is returned as
1452 the first two parameters. As with iselIntExpr_R, these may be
1453 either real or virtual regs; in any case they must not be changed
1454 by subsequent code emitted by the caller. */
1455
1456static void iselIntExpr64 ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1457{
sewardjd18d1bf2004-08-25 12:49:22 +00001458 iselIntExpr64_wrk(rHi, rLo, env, e);
1459# if 0
1460 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1461# endif
1462 vassert(hregClass(*rHi) == HRcInt);
1463 vassert(hregIsVirtual(*rHi));
1464 vassert(hregClass(*rLo) == HRcInt);
1465 vassert(hregIsVirtual(*rLo));
1466}
1467
1468/* DO NOT CALL THIS DIRECTLY ! */
1469static void iselIntExpr64_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1470{
sewardj597b71b2004-07-19 02:51:12 +00001471 // MatchInfo mi;
1472 vassert(e);
1473 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
1474
sewardjc09278c2004-08-19 17:15:49 +00001475 if (e->tag == Iex_Const) {
1476 ULong w64 = e->Iex.Const.con->Ico.U64;
1477 UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
1478 UInt wLo = ((UInt)w64) & 0xFFFFFFFF;
1479 HReg tLo = newVRegI(env);
1480 HReg tHi = newVRegI(env);
1481 vassert(e->Iex.Const.con->tag == Ico_U64);
1482 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wHi), tHi));
1483 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wLo), tLo));
1484 *rHi = tHi;
1485 *rLo = tLo;
1486 return;
1487 }
1488
sewardj597b71b2004-07-19 02:51:12 +00001489 /* read 64-bit IRTemp */
1490 if (e->tag == Iex_Tmp) {
1491 lookupIRTemp64( rHi, rLo, env, e->Iex.Tmp.tmp);
1492 return;
1493 }
1494
sewardjbdc7d212004-09-09 02:46:40 +00001495 /* 64-bit load */
1496 if (e->tag == Iex_LDle) {
sewardj218e29f2004-11-07 18:45:15 +00001497 /* It would be better to generate the address into an amode and
1498 then do advance4 to get the hi-half address. */
sewardjbdc7d212004-09-09 02:46:40 +00001499 vassert(e->Iex.LDle.ty == Ity_I64);
sewardj218e29f2004-11-07 18:45:15 +00001500 HReg tLo = newVRegI(env);
1501 HReg tHi = newVRegI(env);
sewardjbdc7d212004-09-09 02:46:40 +00001502 HReg rA = iselIntExpr_R(env, e->Iex.LDle.addr);
1503 addInstr(env, X86Instr_Alu32R(
1504 Xalu_MOV,
1505 X86RMI_Mem(X86AMode_IR(0, rA)), tLo));
1506 addInstr(env, X86Instr_Alu32R(
1507 Xalu_MOV,
1508 X86RMI_Mem(X86AMode_IR(4, rA)), tHi));
1509 *rHi = tHi;
1510 *rLo = tLo;
1511 return;
1512 }
1513
sewardj218e29f2004-11-07 18:45:15 +00001514 /* 64-bit GETI */
1515 if (e->tag == Iex_GetI) {
1516 X86AMode* am
1517 = genGuestArrayOffset( env, e->Iex.GetI.descr,
1518 e->Iex.GetI.ix, e->Iex.GetI.bias );
1519 X86AMode* am4 = advance4(am);
1520 HReg tLo = newVRegI(env);
1521 HReg tHi = newVRegI(env);
1522 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am), tLo ));
1523 addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi ));
1524 *rHi = tHi;
1525 *rLo = tLo;
1526 return;
1527 }
1528
1529 /* 64-bit Mux0X */
1530 if (e->tag == Iex_Mux0X) {
1531 HReg e0Lo, e0Hi, eXLo, eXHi, r8;
1532 HReg tLo = newVRegI(env);
1533 HReg tHi = newVRegI(env);
1534 iselIntExpr64(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0);
1535 iselIntExpr64(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX);
1536 addInstr(env, mk_MOVsd_RR(eXHi, tHi));
1537 addInstr(env, mk_MOVsd_RR(eXLo, tLo));
1538 r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1539 addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
1540 /* This assumes the first cmov32 doesn't trash the condition
1541 codes, so they are still available for the second cmov32 */
1542 addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Reg(e0Hi),tHi));
1543 addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Reg(e0Lo),tLo));
1544 *rHi = tHi;
1545 *rLo = tLo;
1546 return;
1547 }
1548
sewardj597b71b2004-07-19 02:51:12 +00001549 /* 32 x 32 -> 64 multiply */
1550 if (e->tag == Iex_Binop
1551 && (e->Iex.Binop.op == Iop_MullU32
1552 || e->Iex.Binop.op == Iop_MullS32)) {
1553 /* get one operand into %eax, and the other into a R/M. Need to
1554 make an educated guess about which is better in which. */
sewardjd18d1bf2004-08-25 12:49:22 +00001555 HReg tLo = newVRegI(env);
1556 HReg tHi = newVRegI(env);
sewardj597b71b2004-07-19 02:51:12 +00001557 Bool syned = e->Iex.Binop.op == Iop_MullS32;
1558 X86RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1);
1559 HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2);
1560 addInstr(env, mk_MOVsd_RR(rRight, hregX86_EAX()));
1561 addInstr(env, X86Instr_MulL(syned, Xss_32, rmLeft));
1562 /* Result is now in EDX:EAX. Tell the caller. */
sewardjd18d1bf2004-08-25 12:49:22 +00001563 addInstr(env, mk_MOVsd_RR(hregX86_EDX(), tHi));
1564 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), tLo));
1565 *rHi = tHi;
1566 *rLo = tLo;
sewardj597b71b2004-07-19 02:51:12 +00001567 return;
1568 }
1569
sewardj5c34dc92004-07-19 12:48:11 +00001570 /* 64 x 32 -> (32(rem),32(div)) division */
1571 if (e->tag == Iex_Binop
1572 && (e->Iex.Binop.op == Iop_DivModU64to32
1573 || e->Iex.Binop.op == Iop_DivModS64to32)) {
1574 /* Get the 64-bit operand into edx:eax, and the other
1575 into any old R/M. */
1576 HReg sHi, sLo;
sewardjd18d1bf2004-08-25 12:49:22 +00001577 HReg tLo = newVRegI(env);
1578 HReg tHi = newVRegI(env);
sewardjacbfdd02004-07-30 14:08:17 +00001579 Bool syned = e->Iex.Binop.op == Iop_DivModS64to32;
sewardj5c34dc92004-07-19 12:48:11 +00001580 X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
1581 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
1582 addInstr(env, mk_MOVsd_RR(sHi, hregX86_EDX()));
1583 addInstr(env, mk_MOVsd_RR(sLo, hregX86_EAX()));
1584 addInstr(env, X86Instr_Div(syned, Xss_32, rmRight));
sewardjd18d1bf2004-08-25 12:49:22 +00001585 addInstr(env, mk_MOVsd_RR(hregX86_EDX(), tHi));
1586 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), tLo));
1587 *rHi = tHi;
1588 *rLo = tLo;
sewardj5c34dc92004-07-19 12:48:11 +00001589 return;
1590 }
1591
sewardj218e29f2004-11-07 18:45:15 +00001592 /* Iop_Or64 */
1593 if (e->tag == Iex_Binop
1594 && (e->Iex.Binop.op == Iop_Or64)) {
1595 HReg xLo, xHi, yLo, yHi;
1596 HReg tLo = newVRegI(env);
1597 HReg tHi = newVRegI(env);
1598 iselIntExpr64(&xHi, &xLo, env, e->Iex.Binop.arg1);
1599 addInstr(env, mk_MOVsd_RR(xHi, tHi));
1600 addInstr(env, mk_MOVsd_RR(xLo, tLo));
1601 iselIntExpr64(&yHi, &yLo, env, e->Iex.Binop.arg2);
1602 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(yHi), tHi));
1603 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(yLo), tLo));
1604 *rHi = tHi;
1605 *rLo = tLo;
1606 return;
1607 }
1608
sewardj5c34dc92004-07-19 12:48:11 +00001609 /* 32HLto64(e1,e2) */
1610 if (e->tag == Iex_Binop
1611 && e->Iex.Binop.op == Iop_32HLto64) {
1612 *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
1613 *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
1614 return;
1615 }
1616
sewardjbb53f8c2004-08-14 11:50:01 +00001617 /* 32Sto64(e) */
1618 if (e->tag == Iex_Unop
1619 && e->Iex.Unop.op == Iop_32Sto64) {
1620 HReg tLo = newVRegI(env);
1621 HReg tHi = newVRegI(env);
1622 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1623 addInstr(env, mk_MOVsd_RR(src,tHi));
1624 addInstr(env, mk_MOVsd_RR(src,tLo));
1625 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tHi)));
1626 *rHi = tHi;
1627 *rLo = tLo;
1628 return;
1629 }
1630
sewardjb5874aa2004-11-04 16:57:50 +00001631 /* could do better than this, but for now ... */
1632 if (e->tag == Iex_Unop
1633 && e->Iex.Unop.op == Iop_1Sto64) {
1634 HReg tLo = newVRegI(env);
1635 HReg tHi = newVRegI(env);
1636 X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1637 addInstr(env, X86Instr_Set32(cond,tLo));
1638 addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(tLo)));
1639 addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tLo)));
1640 addInstr(env, mk_MOVsd_RR(tLo, tHi));
1641 *rHi = tHi;
1642 *rLo = tLo;
1643 return;
1644 }
1645
sewardje5427e82004-09-11 19:43:51 +00001646 /* 32Uto64(e) */
1647 if (e->tag == Iex_Unop
1648 && e->Iex.Unop.op == Iop_32Uto64) {
1649 HReg tLo = newVRegI(env);
1650 HReg tHi = newVRegI(env);
1651 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1652 addInstr(env, mk_MOVsd_RR(src,tLo));
1653 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi));
1654 *rHi = tHi;
1655 *rLo = tLo;
1656 return;
1657 }
1658
sewardj17442fe2004-09-20 14:54:28 +00001659 /* ReinterpF64asI64(e) */
1660 /* Given an IEEE754 double, produce an I64 with the same bit
1661 pattern. */
1662 if (e->tag == Iex_Unop
1663 && e->Iex.Unop.op == Iop_ReinterpF64asI64) {
1664 HReg rf = iselDblExpr(env, e->Iex.Unop.arg);
1665 HReg tLo = newVRegI(env);
1666 HReg tHi = newVRegI(env);
1667 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
1668 X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
1669 /* subl $8, %esp */
1670 addInstr(env,
1671 X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(8), hregX86_ESP()));
1672 /* gstD %rf, 0(%esp) */
1673 addInstr(env,
1674 X86Instr_FpLdSt(False/*store*/, 8, rf, zero_esp));
1675 /* movl 0(%esp), %tLo */
1676 addInstr(env,
1677 X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
1678 /* movl 4(%esp), %tHi */
1679 addInstr(env,
1680 X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(four_esp), tHi));
1681 /* addl $8, %esp */
1682 addInstr(env,
1683 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(8), hregX86_ESP()));
1684 *rHi = tHi;
1685 *rLo = tLo;
1686 return;
1687 }
1688
sewardj5c34dc92004-07-19 12:48:11 +00001689 /* 64-bit shifts */
1690 if (e->tag == Iex_Binop
1691 && e->Iex.Binop.op == Iop_Shl64) {
1692 /* We use the same ingenious scheme as gcc. Put the value
1693 to be shifted into %hi:%lo, and the shift amount into %cl.
1694 Then (dsts on right, a la ATT syntax):
1695
1696 shldl %cl, %lo, %hi -- make %hi be right for the shift amt
1697 -- %cl % 32
1698 shll %cl, %lo -- make %lo be right for the shift amt
1699 -- %cl % 32
1700
1701 Now, if (shift amount % 64) is in the range 32 .. 63, we have
1702 to do a fixup, which puts the result low half into the result
1703 high half, and zeroes the low half:
1704
1705 testl $32, %ecx
1706
1707 cmovnz %lo, %hi
1708 movl $0, %tmp -- sigh; need yet another reg
1709 cmovnz %tmp, %lo
1710 */
1711 HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
1712 tLo = newVRegI(env);
1713 tHi = newVRegI(env);
1714 tTemp = newVRegI(env);
1715 rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
1716 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
1717 addInstr(env, mk_MOVsd_RR(rAmt, hregX86_ECX()));
1718 addInstr(env, mk_MOVsd_RR(sHi, tHi));
1719 addInstr(env, mk_MOVsd_RR(sLo, tLo));
1720 /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
1721 those regs are legitimately modifiable. */
sewardje5f384c2004-07-30 16:17:28 +00001722 addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tLo, tHi));
sewardj5c34dc92004-07-19 12:48:11 +00001723 addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo)));
sewardje8c922f2004-07-23 01:34:11 +00001724 addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX())));
sewardj5c34dc92004-07-19 12:48:11 +00001725 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi));
1726 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
1727 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo));
1728 *rHi = tHi;
1729 *rLo = tLo;
1730 return;
1731 }
1732
sewardj68511542004-07-28 00:15:44 +00001733 if (e->tag == Iex_Binop
1734 && e->Iex.Binop.op == Iop_Shr64) {
1735 /* We use the same ingenious scheme as gcc. Put the value
1736 to be shifted into %hi:%lo, and the shift amount into %cl.
1737 Then:
1738
1739 shrdl %cl, %hi, %lo -- make %lo be right for the shift amt
1740 -- %cl % 32
sewardj80f8c302004-07-29 22:21:31 +00001741 shrl %cl, %hi -- make %hi be right for the shift amt
sewardj68511542004-07-28 00:15:44 +00001742 -- %cl % 32
1743
1744 Now, if (shift amount % 64) is in the range 32 .. 63, we have
1745 to do a fixup, which puts the result high half into the result
1746 low half, and zeroes the high half:
1747
1748 testl $32, %ecx
1749
1750 cmovnz %hi, %lo
1751 movl $0, %tmp -- sigh; need yet another reg
1752 cmovnz %tmp, %hi
1753 */
1754 HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
1755 tLo = newVRegI(env);
1756 tHi = newVRegI(env);
1757 tTemp = newVRegI(env);
1758 rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
1759 iselIntExpr64(&sHi,&sLo, env, e->Iex.Binop.arg1);
1760 addInstr(env, mk_MOVsd_RR(rAmt, hregX86_ECX()));
1761 addInstr(env, mk_MOVsd_RR(sHi, tHi));
1762 addInstr(env, mk_MOVsd_RR(sLo, tLo));
1763 /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo and
1764 those regs are legitimately modifiable. */
sewardje5f384c2004-07-30 16:17:28 +00001765 addInstr(env, X86Instr_Sh3232(Xsh_SHR, 0/*%cl*/, tHi, tLo));
sewardj68511542004-07-28 00:15:44 +00001766 addInstr(env, X86Instr_Sh32(Xsh_SHR, 0/*%cl*/, X86RM_Reg(tHi)));
1767 addInstr(env, X86Instr_Test32(X86RI_Imm(32), X86RM_Reg(hregX86_ECX())));
1768 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tHi), tLo));
1769 addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
1770 addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tHi));
1771 *rHi = tHi;
1772 *rLo = tLo;
1773 return;
1774 }
1775
sewardjcfded9a2004-09-09 11:44:16 +00001776 /* F64 -> I64 */
1777 /* Sigh, this is an almost exact copy of the F64 -> I32/I16 case.
1778 Unfortunately I see no easy way to avoid the duplication. */
1779 if (e->tag == Iex_Binop
1780 && e->Iex.Binop.op == Iop_F64toI64) {
1781 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
1782 HReg rrm = iselIntExpr_R(env, e->Iex.Binop.arg1);
1783 HReg rrm2 = newVRegI(env);
sewardjcfded9a2004-09-09 11:44:16 +00001784 HReg tLo = newVRegI(env);
1785 HReg tHi = newVRegI(env);
1786
1787 /* Used several times ... */
1788 /* Careful ... this sharing is only safe because
1789 zero_esp/four_esp do not hold any registers which the
1790 register allocator could attempt to swizzle later. */
1791 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
1792 X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
1793
1794 /* rf now holds the value to be converted, and rrm holds the
1795 rounding mode value, encoded as per the IRRoundingMode enum.
1796 The first thing to do is set the FPU's rounding mode
1797 accordingly. */
1798
1799 /* Create a space, both for the control word messing, and for
1800 the actual store conversion. */
1801 /* subl $8, %esp */
1802 addInstr(env,
1803 X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(8), hregX86_ESP()));
1804 /* movl %rrm, %rrm2
1805 andl $3, %rrm2 -- shouldn't be needed; paranoia
1806 shll $10, %rrm2
1807 orl $0x037F, %rrm2
1808 movl %rrm2, 0(%esp)
1809 fldcw 0(%esp)
1810 */
1811 addInstr(env, mk_MOVsd_RR(rrm, rrm2));
1812 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
1813 addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2)));
1814 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(0x037F), rrm2));
1815 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(rrm2), zero_esp));
1816 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
1817
1818 /* gistll %rf, 0(%esp) */
1819 addInstr(env, X86Instr_FpLdStI(False/*store*/, 8, rf, zero_esp));
1820
1821 /* movl 0(%esp), %dstLo */
1822 /* movl 4(%esp), %dstHi */
1823 addInstr(env, X86Instr_Alu32R(
1824 Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
1825 addInstr(env, X86Instr_Alu32R(
1826 Xalu_MOV, X86RMI_Mem(four_esp), tHi));
1827
1828 /* Restore default FPU control.
1829 movl $0x037F, 0(%esp)
1830 fldcw 0(%esp)
1831 */
1832 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(0x037F), zero_esp));
1833 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
1834
1835 /* addl $8, %esp */
1836 addInstr(env,
1837 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(8), hregX86_ESP()));
1838
1839 *rHi = tHi;
1840 *rLo = tLo;
sewardjc4be80c2004-09-10 16:17:45 +00001841 return;
1842 }
1843
sewardj33fa73e2004-10-24 19:19:37 +00001844 /* --------- CCALL --------- */
1845 if (e->tag == Iex_CCall) {
sewardj77352542004-10-30 20:39:01 +00001846 HReg tLo = newVRegI(env);
1847 HReg tHi = newVRegI(env);
sewardj33fa73e2004-10-24 19:19:37 +00001848
sewardj77352542004-10-30 20:39:01 +00001849 /* Marshal args, do the call, clear stack. */
sewardj4b861de2004-11-03 15:24:42 +00001850 doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
sewardj33fa73e2004-10-24 19:19:37 +00001851
1852 addInstr(env, mk_MOVsd_RR(hregX86_EDX(), tHi));
1853 addInstr(env, mk_MOVsd_RR(hregX86_EAX(), tLo));
1854 *rHi = tHi;
1855 *rLo = tLo;
1856 return;
1857 }
1858
sewardj2d3f77c2004-09-22 23:49:09 +00001859#if 0
sewardjc4be80c2004-09-10 16:17:45 +00001860 if (e->tag == Iex_GetI) {
1861 /* First off, compute the index expression into an integer reg.
1862 The referenced address will then be 0 + ebp + reg*1, that is,
1863 an X86AMode_IRRS. */
1864 vassert(e->Iex.GetI.ty == Ity_I64);
1865 HReg tLo = newVRegI(env);
1866 HReg tHi = newVRegI(env);
sewardjeeac8412004-11-02 00:26:55 +00001867 HReg idx = iselIntExpr_R(env, e->Iex.GetI.ixset);
sewardjc4be80c2004-09-10 16:17:45 +00001868
1869 /* This (x86) is a little-endian target. The front end will
1870 have laid out the baseblock in accordance with the back-end's
1871 endianness, so this hardwired assumption here that the 64-bit
1872 value is stored little-endian is OK. */
1873 addInstr(env, X86Instr_Alu32R(
1874 Xalu_MOV,
1875 X86RMI_Mem(X86AMode_IRRS(0, hregX86_EBP(), idx, 0)),
1876 tLo));
1877 addInstr(env, X86Instr_Alu32R(
1878 Xalu_MOV,
1879 X86RMI_Mem(X86AMode_IRRS(4, hregX86_EBP(), idx, 0)),
1880 tHi));
1881 *rHi = tHi;
1882 *rLo = tLo;
1883 return;
sewardjcfded9a2004-09-09 11:44:16 +00001884 }
sewardj2d3f77c2004-09-22 23:49:09 +00001885#endif
sewardjcfded9a2004-09-09 11:44:16 +00001886
sewardj597b71b2004-07-19 02:51:12 +00001887 ppIRExpr(e);
1888 vpanic("iselIntExpr64");
1889}
1890
1891
sewardj4042c7e2004-07-18 01:28:30 +00001892
sewardjc97096c2004-06-30 09:28:04 +00001893/*---------------------------------------------------------*/
sewardj3196daf2004-08-13 00:18:58 +00001894/*--- ISEL: Floating point expressions (64 bit) ---*/
1895/*---------------------------------------------------------*/
1896
1897/* Compute a 64-bit floating point value into a register, the identity
1898 of which is returned. As with iselIntExpr_R, the reg may be either
1899 real or virtual; in any case it must not be changed by subsequent
1900 code emitted by the caller. */
1901
sewardj3fc76d22004-08-31 11:47:54 +00001902/* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
1903
1904 Type S (1 bit) E (11 bits) F (52 bits)
1905 ---- --------- ----------- -----------
1906 signalling NaN u 2047 (max) .0uuuuu---u
1907 (with at least
1908 one 1 bit)
1909 quiet NaN u 2047 (max) .1uuuuu---u
1910
1911 negative infinity 1 2047 (max) .000000---0
1912
1913 positive infinity 0 2047 (max) .000000---0
1914
1915 negative zero 1 0 .000000---0
1916
1917 positive zero 0 0 .000000---0
1918*/
1919
sewardj89cd0932004-09-08 18:23:25 +00001920static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
1921{
1922 // MatchInfo mi;
1923 IRType ty = typeOfIRExpr(env->type_env,e);
1924 vassert(ty == Ity_F32);
1925
sewardj4a8b2a52004-10-13 20:45:25 +00001926 if (e->tag == Iex_Tmp) {
1927 return lookupIRTemp(env, e->Iex.Tmp.tmp);
1928 }
1929
sewardj89cd0932004-09-08 18:23:25 +00001930 if (e->tag == Iex_LDle) {
1931 X86AMode* am;
1932 HReg res = newVRegF(env);
1933 vassert(e->Iex.LDle.ty == Ity_F32);
1934 am = iselIntExpr_AMode(env, e->Iex.LDle.addr);
1935 addInstr(env, X86Instr_FpLdSt(True/*load*/, 4, res, am));
1936 return res;
1937 }
1938
1939 if (e->tag == Iex_Unop
1940 && e->Iex.Unop.op == Iop_F64toF32) {
1941 /* this is a no-op */
1942 return iselDblExpr(env, e->Iex.Unop.arg);
1943 }
1944
1945 ppIRExpr(e);
1946 vpanic("iselFltExpr");
1947}
1948
1949
sewardj3196daf2004-08-13 00:18:58 +00001950static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
1951{
sewardjfbee31b2004-10-14 21:48:59 +00001952 /* MatchInfo mi; */
sewardj33124f62004-08-30 17:54:18 +00001953 IRType ty = typeOfIRExpr(env->type_env,e);
sewardj3196daf2004-08-13 00:18:58 +00001954 vassert(e);
sewardj33124f62004-08-30 17:54:18 +00001955 vassert(ty == Ity_F64);
sewardj3196daf2004-08-13 00:18:58 +00001956
sewardjbb53f8c2004-08-14 11:50:01 +00001957 if (e->tag == Iex_Tmp) {
1958 return lookupIRTemp(env, e->Iex.Tmp.tmp);
1959 }
1960
sewardja58ea662004-08-15 03:12:41 +00001961 if (e->tag == Iex_Const) {
sewardj17442fe2004-09-20 14:54:28 +00001962 union { UInt u32x2[2]; ULong u64; Double f64; } u;
sewardja58ea662004-08-15 03:12:41 +00001963 HReg freg = newVRegF(env);
1964 vassert(sizeof(u) == 8);
sewardj17442fe2004-09-20 14:54:28 +00001965 vassert(sizeof(u.u64) == 8);
sewardja58ea662004-08-15 03:12:41 +00001966 vassert(sizeof(u.f64) == 8);
sewardj17442fe2004-09-20 14:54:28 +00001967 vassert(sizeof(u.u32x2) == 8);
sewardj3fc76d22004-08-31 11:47:54 +00001968
1969 if (e->Iex.Const.con->tag == Ico_F64) {
1970 u.f64 = e->Iex.Const.con->Ico.F64;
sewardj17442fe2004-09-20 14:54:28 +00001971 }
1972 else if (e->Iex.Const.con->tag == Ico_F64i) {
1973 u.u64 = e->Iex.Const.con->Ico.F64i;
sewardj3fc76d22004-08-31 11:47:54 +00001974 }
1975 else
1976 vpanic("iselDblExpr(x86): const");
1977
sewardj17442fe2004-09-20 14:54:28 +00001978 addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[1])));
1979 addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[0])));
sewardja58ea662004-08-15 03:12:41 +00001980 addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg,
1981 X86AMode_IR(0, hregX86_ESP())));
1982 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
1983 X86RMI_Imm(8),
1984 hregX86_ESP()));
1985 return freg;
1986 }
1987
sewardj3196daf2004-08-13 00:18:58 +00001988 if (e->tag == Iex_LDle) {
1989 X86AMode* am;
1990 HReg res = newVRegF(env);
1991 vassert(e->Iex.LDle.ty == Ity_F64);
1992 am = iselIntExpr_AMode(env, e->Iex.LDle.addr);
1993 addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, res, am));
1994 return res;
1995 }
1996
sewardj2d3f77c2004-09-22 23:49:09 +00001997#if 0
sewardj08790542004-09-14 23:18:06 +00001998 /* special-case: GetI( Add32(Shl32(y,3),const:I32) ):F64 */
1999 { DECLARE_PATTERN(p_Get_FP_reg);
2000 DEFINE_PATTERN(p_Get_FP_reg,
2001 IRExpr_GetI(
2002 binop(Iop_Add32, binop(Iop_Shl32,bind(0),mkU8(3)), bind(1)),
2003 Ity_F64,56,119
2004 )
2005 );
2006 if (matchIRExpr(&mi, p_Get_FP_reg, e)) {
2007 /* partial match, but we have to ensure bind(1) is a 32-bit
2008 literal. */
2009 IRExpr* y = mi.bindee[0];
2010 IRExpr* c = mi.bindee[1];
2011 if (c->tag == Iex_Const && c->Iex.Const.con->tag == Ico_U32) {
2012 UInt c32 = c->Iex.Const.con->Ico.U32;
2013 HReg res = newVRegF(env);
2014 HReg ry = iselIntExpr_R(env, y);
2015 addInstr(env,
2016 X86Instr_FpLdSt(
2017 True/*load*/, 8, res,
2018 X86AMode_IRRS(c32, hregX86_EBP(), ry, 3)) );
2019 return res;
2020 }
2021 }
2022 }
sewardj2d3f77c2004-09-22 23:49:09 +00002023#endif
sewardj08790542004-09-14 23:18:06 +00002024
2025 /* GetI, default case */
sewardjbb53f8c2004-08-14 11:50:01 +00002026 if (e->tag == Iex_GetI) {
sewardj2d3f77c2004-09-22 23:49:09 +00002027 X86AMode* am
2028 = genGuestArrayOffset(
2029 env, e->Iex.GetI.descr,
sewardjeeac8412004-11-02 00:26:55 +00002030 e->Iex.GetI.ix, e->Iex.GetI.bias );
sewardjbb53f8c2004-08-14 11:50:01 +00002031 HReg res = newVRegF(env);
sewardj2d3f77c2004-09-22 23:49:09 +00002032 addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am ));
sewardjbb53f8c2004-08-14 11:50:01 +00002033 return res;
2034 }
2035
2036 if (e->tag == Iex_Binop) {
2037 X86FpOp fpop = Xfp_INVALID;
2038 switch (e->Iex.Binop.op) {
sewardj06c32a02004-09-12 12:07:34 +00002039 case Iop_AddF64: fpop = Xfp_ADD; break;
2040 case Iop_SubF64: fpop = Xfp_SUB; break;
2041 case Iop_MulF64: fpop = Xfp_MUL; break;
2042 case Iop_DivF64: fpop = Xfp_DIV; break;
2043 case Iop_ScaleF64: fpop = Xfp_SCALE; break;
2044 case Iop_AtanF64: fpop = Xfp_ATAN; break;
2045 case Iop_Yl2xF64: fpop = Xfp_YL2X; break;
2046 case Iop_Yl2xp1F64: fpop = Xfp_YL2XP1; break;
2047 case Iop_PRemF64: fpop = Xfp_PREM; break;
sewardj442d0be2004-10-15 22:57:13 +00002048 case Iop_PRem1F64: fpop = Xfp_PREM1; break;
sewardjbb53f8c2004-08-14 11:50:01 +00002049 default: break;
2050 }
2051 if (fpop != Xfp_INVALID) {
2052 HReg res = newVRegF(env);
2053 HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
2054 HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
2055 addInstr(env, X86Instr_FpBinary(fpop,srcL,srcR,res));
2056 return res;
2057 }
2058 }
2059
sewardje6709112004-09-10 18:37:18 +00002060 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF64) {
2061 HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
2062 HReg rrm = iselIntExpr_R(env, e->Iex.Binop.arg1);
2063 HReg rrm2 = newVRegI(env);
2064 HReg dst = newVRegF(env);
2065
2066 /* Used several times ... */
2067 /* Careful ... this sharing is only safe because
2068 zero_esp does not hold any registers which the
2069 register allocator could attempt to swizzle later. */
2070 X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
2071
2072 /* rf now holds the value to be rounded, and rrm holds the
2073 rounding mode value, encoded as per the IRRoundingMode enum.
2074 The first thing to do is set the FPU's rounding mode
2075 accordingly. */
2076
2077 /* subl $4, %esp */
2078 addInstr(env,
2079 X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(4), hregX86_ESP()));
2080 /* movl %rrm, %rrm2
2081 andl $3, %rrm2 -- shouldn't be needed; paranoia
2082 shll $10, %rrm2
2083 orl $0x037F, %rrm2
2084 movl %rrm2, 0(%esp)
2085 fldcw 0(%esp)
2086 */
2087 addInstr(env, mk_MOVsd_RR(rrm, rrm2));
2088 addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
2089 addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2)));
2090 addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(0x037F), rrm2));
2091 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(rrm2), zero_esp));
2092 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
2093
2094 /* grndint %rf, %dst */
2095 addInstr(env, X86Instr_FpUnary(Xfp_ROUND, rf, dst));
2096
2097 /* Restore default FPU control.
2098 movl $0x037F, 0(%esp)
2099 fldcw 0(%esp)
2100 */
2101 addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(0x037F), zero_esp));
2102 addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
2103
2104 /* addl $4, %esp */
2105 addInstr(env,
2106 X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(4), hregX86_ESP()));
2107 return dst;
2108 }
2109
2110
sewardjbb53f8c2004-08-14 11:50:01 +00002111 if (e->tag == Iex_Unop) {
sewardjcfded9a2004-09-09 11:44:16 +00002112 X86FpOp fpop = Xfp_INVALID;
2113 switch (e->Iex.Unop.op) {
sewardj883b00b2004-09-11 09:30:24 +00002114 case Iop_NegF64: fpop = Xfp_NEG; break;
2115 case Iop_AbsF64: fpop = Xfp_ABS; break;
sewardjc4be80c2004-09-10 16:17:45 +00002116 case Iop_SqrtF64: fpop = Xfp_SQRT; break;
2117 case Iop_SinF64: fpop = Xfp_SIN; break;
2118 case Iop_CosF64: fpop = Xfp_COS; break;
sewardj99016a72004-10-15 22:09:17 +00002119 case Iop_TanF64: fpop = Xfp_TAN; break;
sewardj06c32a02004-09-12 12:07:34 +00002120 case Iop_2xm1F64: fpop = Xfp_2XM1; break;
sewardjcfded9a2004-09-09 11:44:16 +00002121 default: break;
2122 }
2123 if (fpop != Xfp_INVALID) {
2124 HReg res = newVRegF(env);
2125 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
2126 addInstr(env, X86Instr_FpUnary(fpop,src,res));
2127 return res;
2128 }
2129 }
2130
2131 if (e->tag == Iex_Unop) {
sewardj89cd0932004-09-08 18:23:25 +00002132 switch (e->Iex.Unop.op) {
2133 case Iop_I32toF64: {
2134 HReg dst = newVRegF(env);
2135 HReg ri = iselIntExpr_R(env, e->Iex.Unop.arg);
2136 addInstr(env, X86Instr_Push(X86RMI_Reg(ri)));
2137 addInstr(env, X86Instr_FpLdStI(
2138 True/*load*/, 4, dst,
2139 X86AMode_IR(0, hregX86_ESP())));
2140 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
2141 X86RMI_Imm(4),
2142 hregX86_ESP()));
2143 return dst;
2144 }
sewardjbdc7d212004-09-09 02:46:40 +00002145 case Iop_I64toF64: {
2146 HReg dst = newVRegF(env);
2147 HReg rHi,rLo;
2148 iselIntExpr64( &rHi, &rLo, env, e->Iex.Unop.arg);
2149 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
2150 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
2151 addInstr(env, X86Instr_FpLdStI(
2152 True/*load*/, 8, dst,
2153 X86AMode_IR(0, hregX86_ESP())));
2154 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
2155 X86RMI_Imm(8),
2156 hregX86_ESP()));
2157 return dst;
2158 }
sewardj17442fe2004-09-20 14:54:28 +00002159 case Iop_ReinterpI64asF64: {
2160 /* Given an I64, produce an IEEE754 double with the same
2161 bit pattern. */
2162 HReg dst = newVRegF(env);
2163 HReg rHi, rLo;
2164 iselIntExpr64( &rHi, &rLo, env, e->Iex.Unop.arg);
2165 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
2166 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
2167 addInstr(env, X86Instr_FpLdSt(
2168 True/*load*/, 8, dst,
2169 X86AMode_IR(0, hregX86_ESP())));
2170 addInstr(env, X86Instr_Alu32R(Xalu_ADD,
2171 X86RMI_Imm(8),
2172 hregX86_ESP()));
2173 return dst;
2174 }
sewardj89cd0932004-09-08 18:23:25 +00002175 case Iop_F32toF64:
2176 /* this is a no-op */
2177 return iselFltExpr(env, e->Iex.Unop.arg);
2178 default:
2179 break;
sewardjbb53f8c2004-08-14 11:50:01 +00002180 }
2181 }
2182
sewardj33124f62004-08-30 17:54:18 +00002183 /* --------- MULTIPLEX --------- */
2184 if (e->tag == Iex_Mux0X) {
2185 if (ty == Ity_F64
2186 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
2187 HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
2188 HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX);
2189 HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
2190 HReg dst = newVRegF(env);
sewardj3fc76d22004-08-31 11:47:54 +00002191 addInstr(env, X86Instr_FpUnary(Xfp_MOV,rX,dst));
sewardj33124f62004-08-30 17:54:18 +00002192 addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
2193 addInstr(env, X86Instr_FpCMov(Xcc_Z,r0,dst));
2194 return dst;
2195 }
2196 }
2197
sewardj3196daf2004-08-13 00:18:58 +00002198 ppIRExpr(e);
sewardjbb53f8c2004-08-14 11:50:01 +00002199 vpanic("iselDblExpr");
sewardj3196daf2004-08-13 00:18:58 +00002200}
2201
2202
2203
2204/*---------------------------------------------------------*/
sewardjc97096c2004-06-30 09:28:04 +00002205/*--- ISEL: Statements ---*/
2206/*---------------------------------------------------------*/
2207
sewardjf13a16a2004-07-05 17:10:14 +00002208static void iselStmt ( ISelEnv* env, IRStmt* stmt )
sewardjc97096c2004-06-30 09:28:04 +00002209{
sewardjf48ac192004-10-29 00:41:29 +00002210 if (vex_traceflags & VEX_TRACE_VCODE) {
2211 vex_printf("\n-- ");
sewardj1f40a0a2004-07-21 12:28:07 +00002212 ppIRStmt(stmt);
2213 vex_printf("\n");
2214 }
sewardj66f2f792004-06-30 16:37:16 +00002215
sewardjc97096c2004-06-30 09:28:04 +00002216 switch (stmt->tag) {
2217
sewardj60f4e3c2004-07-19 01:56:50 +00002218 /* --------- STORE --------- */
sewardjd9c2b792004-07-08 01:44:38 +00002219 case Ist_STle: {
sewardja58ea662004-08-15 03:12:41 +00002220 X86AMode* am;
sewardjd9c2b792004-07-08 01:44:38 +00002221 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr);
2222 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data);
2223 vassert(tya == Ity_I32);
sewardja58ea662004-08-15 03:12:41 +00002224 am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
sewardjd9c2b792004-07-08 01:44:38 +00002225 if (tyd == Ity_I32) {
sewardja58ea662004-08-15 03:12:41 +00002226 X86RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data);
sewardjd9c2b792004-07-08 01:44:38 +00002227 addInstr(env, X86Instr_Alu32M(Xalu_MOV,ri,am));
2228 return;
2229 }
sewardj60f4e3c2004-07-19 01:56:50 +00002230 if (tyd == Ity_I8 || tyd == Ity_I16) {
sewardja58ea662004-08-15 03:12:41 +00002231 HReg r = iselIntExpr_R(env, stmt->Ist.STle.data);
sewardj60f4e3c2004-07-19 01:56:50 +00002232 addInstr(env, X86Instr_Store(tyd==Ity_I8 ? 1 : 2,
2233 r,am));
sewardj443cd9d2004-07-18 23:06:45 +00002234 return;
2235 }
sewardja58ea662004-08-15 03:12:41 +00002236 if (tyd == Ity_F64) {
2237 HReg r = iselDblExpr(env, stmt->Ist.STle.data);
2238 addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am));
2239 return;
2240 }
sewardj89cd0932004-09-08 18:23:25 +00002241 if (tyd == Ity_F32) {
2242 HReg r = iselFltExpr(env, stmt->Ist.STle.data);
2243 addInstr(env, X86Instr_FpLdSt(False/*store*/, 4, r, am));
2244 return;
2245 }
sewardjcfded9a2004-09-09 11:44:16 +00002246 if (tyd == Ity_I64) {
2247 HReg vHi, vLo, rA;
2248 iselIntExpr64(&vHi, &vLo, env, stmt->Ist.STle.data);
2249 rA = iselIntExpr_R(env, stmt->Ist.STle.addr);
2250 addInstr(env, X86Instr_Alu32M(
2251 Xalu_MOV, X86RI_Reg(vLo), X86AMode_IR(0, rA)));
2252 addInstr(env, X86Instr_Alu32M(
2253 Xalu_MOV, X86RI_Reg(vHi), X86AMode_IR(4, rA)));
2254 return;
2255 }
sewardjd9c2b792004-07-08 01:44:38 +00002256 break;
sewardj79453082004-07-02 17:29:14 +00002257 }
2258
sewardj60f4e3c2004-07-19 01:56:50 +00002259 /* --------- PUT --------- */
sewardjd9c2b792004-07-08 01:44:38 +00002260 case Ist_Put: {
sewardj6d076362004-09-23 11:06:17 +00002261 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
sewardjd9c2b792004-07-08 01:44:38 +00002262 if (ty == Ity_I32) {
2263 /* We're going to write to memory, so compute the RHS into an
2264 X86RI. */
sewardj6d076362004-09-23 11:06:17 +00002265 X86RI* ri = iselIntExpr_RI(env, stmt->Ist.Put.data);
sewardjd9c2b792004-07-08 01:44:38 +00002266 addInstr(env,
2267 X86Instr_Alu32M(
2268 Xalu_MOV,
2269 ri,
2270 X86AMode_IR(stmt->Ist.Put.offset,hregX86_EBP())
2271 ));
2272 return;
2273 }
sewardj597b71b2004-07-19 02:51:12 +00002274 if (ty == Ity_I8 || ty == Ity_I16) {
sewardj6d076362004-09-23 11:06:17 +00002275 HReg r = iselIntExpr_R(env, stmt->Ist.Put.data);
sewardj443cd9d2004-07-18 23:06:45 +00002276 addInstr(env, X86Instr_Store(
sewardj597b71b2004-07-19 02:51:12 +00002277 ty==Ity_I8 ? 1 : 2,
2278 r,
sewardj443cd9d2004-07-18 23:06:45 +00002279 X86AMode_IR(stmt->Ist.Put.offset,
2280 hregX86_EBP())));
2281 return;
2282 }
sewardjd9c2b792004-07-08 01:44:38 +00002283 break;
2284 }
sewardje8e9d732004-07-16 21:03:45 +00002285
sewardj3196daf2004-08-13 00:18:58 +00002286 /* --------- Indexed PUT --------- */
2287 case Ist_PutI: {
sewardj2d3f77c2004-09-22 23:49:09 +00002288 X86AMode* am
2289 = genGuestArrayOffset(
2290 env, stmt->Ist.PutI.descr,
sewardjeeac8412004-11-02 00:26:55 +00002291 stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
sewardj3196daf2004-08-13 00:18:58 +00002292
sewardj2d3f77c2004-09-22 23:49:09 +00002293 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
sewardj3196daf2004-08-13 00:18:58 +00002294 if (ty == Ity_F64) {
sewardj2d3f77c2004-09-22 23:49:09 +00002295 HReg val = iselDblExpr(env, stmt->Ist.PutI.data);
2296 addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, val, am ));
sewardj3196daf2004-08-13 00:18:58 +00002297 return;
2298 }
sewardj3fc76d22004-08-31 11:47:54 +00002299 if (ty == Ity_I8) {
sewardj2d3f77c2004-09-22 23:49:09 +00002300 HReg r = iselIntExpr_R(env, stmt->Ist.PutI.data);
2301 addInstr(env, X86Instr_Store( 1, r, am ));
sewardj3fc76d22004-08-31 11:47:54 +00002302 return;
2303 }
sewardj218e29f2004-11-07 18:45:15 +00002304 if (ty == Ity_I64) {
2305 HReg rHi, rLo;
2306 X86AMode* am4 = advance4(am);
2307 iselIntExpr64(&rHi, &rLo, env, stmt->Ist.PutI.data);
2308 addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rLo), am ));
2309 addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rHi), am4 ));
2310 return;
2311 }
sewardj3196daf2004-08-13 00:18:58 +00002312 break;
2313 }
2314
sewardj60f4e3c2004-07-19 01:56:50 +00002315 /* --------- TMP --------- */
sewardjd9c2b792004-07-08 01:44:38 +00002316 case Ist_Tmp: {
2317 IRTemp tmp = stmt->Ist.Tmp.tmp;
sewardj17442fe2004-09-20 14:54:28 +00002318 IRType ty = typeOfIRTemp(env->type_env, tmp);
sewardj4042c7e2004-07-18 01:28:30 +00002319 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
sewardj6d076362004-09-23 11:06:17 +00002320 X86RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.Tmp.data);
sewardjd9c2b792004-07-08 01:44:38 +00002321 HReg dst = lookupIRTemp(env, tmp);
2322 addInstr(env, X86Instr_Alu32R(Xalu_MOV,rmi,dst));
2323 return;
2324 }
sewardj597b71b2004-07-19 02:51:12 +00002325 if (ty == Ity_I64) {
2326 HReg rHi, rLo, dstHi, dstLo;
sewardj6d076362004-09-23 11:06:17 +00002327 iselIntExpr64(&rHi,&rLo, env, stmt->Ist.Tmp.data);
sewardj597b71b2004-07-19 02:51:12 +00002328 lookupIRTemp64( &dstHi, &dstLo, env, tmp);
2329 addInstr(env, mk_MOVsd_RR(rHi,dstHi) );
2330 addInstr(env, mk_MOVsd_RR(rLo,dstLo) );
2331 return;
2332 }
sewardjba999312004-11-15 15:21:17 +00002333 if (ty == Ity_I1) {
sewardj6d076362004-09-23 11:06:17 +00002334 X86CondCode cond = iselCondCode(env, stmt->Ist.Tmp.data);
sewardjd7cb8532004-08-17 23:59:23 +00002335 HReg dst = lookupIRTemp(env, tmp);
2336 addInstr(env, X86Instr_Set32(cond, dst));
2337 return;
2338 }
sewardjbb53f8c2004-08-14 11:50:01 +00002339 if (ty == Ity_F64) {
2340 HReg dst = lookupIRTemp(env, tmp);
sewardj6d076362004-09-23 11:06:17 +00002341 HReg src = iselDblExpr(env, stmt->Ist.Tmp.data);
sewardjbb53f8c2004-08-14 11:50:01 +00002342 addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst));
2343 return;
2344 }
sewardj4a8b2a52004-10-13 20:45:25 +00002345 if (ty == Ity_F32) {
2346 HReg dst = lookupIRTemp(env, tmp);
2347 HReg src = iselFltExpr(env, stmt->Ist.Tmp.data);
2348 addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst));
2349 return;
2350 }
sewardjd9c2b792004-07-08 01:44:38 +00002351 break;
2352 }
sewardj79453082004-07-02 17:29:14 +00002353
sewardj17442fe2004-09-20 14:54:28 +00002354 /* --------- Call to DIRTY helper --------- */
2355 case Ist_Dirty: {
sewardj17442fe2004-09-20 14:54:28 +00002356 IRType retty;
2357 IRDirty* d = stmt->Ist.Dirty.details;
sewardj77352542004-10-30 20:39:01 +00002358 Bool passBBP = False;
sewardj17442fe2004-09-20 14:54:28 +00002359
sewardjc5fc7aa2004-10-27 23:00:55 +00002360 if (d->nFxState == 0)
2361 vassert(!d->needsBBP);
sewardj77352542004-10-30 20:39:01 +00002362 passBBP = d->nFxState > 0 && d->needsBBP;
sewardj7cb49d72004-10-24 22:31:25 +00002363
sewardj77352542004-10-30 20:39:01 +00002364 /* Marshal args, do the call, clear stack. */
sewardj4b861de2004-11-03 15:24:42 +00002365 doHelperCall( env, passBBP, d->guard, d->cee, d->args );
sewardj17442fe2004-09-20 14:54:28 +00002366
2367 /* Now figure out what to do with the returned value, if any. */
sewardj92d168d2004-11-15 14:22:12 +00002368 if (d->tmp == IRTemp_INVALID)
sewardj17442fe2004-09-20 14:54:28 +00002369 /* No return value. Nothing to do. */
2370 return;
2371
2372 retty = typeOfIRTemp(env->type_env, d->tmp);
2373 if (retty == Ity_I64) {
2374 HReg dstHi, dstLo;
2375 /* The returned value is in %edx:%eax. Park it in the
2376 register-pair associated with tmp. */
2377 lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
2378 addInstr(env, mk_MOVsd_RR(hregX86_EDX(),dstHi) );
2379 addInstr(env, mk_MOVsd_RR(hregX86_EAX(),dstLo) );
2380 return;
2381 }
sewardj415d9352004-11-04 15:20:15 +00002382 if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
sewardj4b861de2004-11-03 15:24:42 +00002383 /* The returned value is in %eax. Park it in the register
2384 associated with tmp. */
2385 HReg dst = lookupIRTemp(env, d->tmp);
2386 addInstr(env, mk_MOVsd_RR(hregX86_EAX(),dst) );
2387 return;
2388 }
sewardj17442fe2004-09-20 14:54:28 +00002389 break;
2390 }
2391
sewardj60f4e3c2004-07-19 01:56:50 +00002392 /* --------- EXIT --------- */
sewardje8e9d732004-07-16 21:03:45 +00002393 case Ist_Exit: {
sewardj2e56f9f2004-07-24 01:24:38 +00002394 X86RI* dst;
2395 X86CondCode cc;
2396 if (stmt->Ist.Exit.dst->tag != Ico_U32)
2397 vpanic("isel_x86: Ist_Exit: dst is not a 32-bit value");
2398 dst = iselIntExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
sewardj0276d4b2004-11-15 15:30:21 +00002399 cc = iselCondCode(env,stmt->Ist.Exit.guard);
sewardj750f4072004-07-26 22:39:11 +00002400 addInstr(env, X86Instr_Goto(Ijk_Boring, cc, dst));
sewardj2e56f9f2004-07-24 01:24:38 +00002401 return;
sewardje8e9d732004-07-16 21:03:45 +00002402 }
2403
sewardjc97096c2004-06-30 09:28:04 +00002404 default: break;
2405 }
sewardj35421a32004-07-05 13:12:34 +00002406 ppIRStmt(stmt);
2407 vpanic("iselStmt");
sewardjc97096c2004-06-30 09:28:04 +00002408}
2409
2410
2411/*---------------------------------------------------------*/
2412/*--- ISEL: Basic block terminators (Nexts) ---*/
2413/*---------------------------------------------------------*/
2414
sewardje539a402004-07-14 18:24:17 +00002415static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
sewardjc97096c2004-06-30 09:28:04 +00002416{
sewardje8e9d732004-07-16 21:03:45 +00002417 X86RI* ri;
sewardjf48ac192004-10-29 00:41:29 +00002418 if (vex_traceflags & VEX_TRACE_VCODE) {
2419 vex_printf("\n-- goto {");
sewardj750f4072004-07-26 22:39:11 +00002420 ppIRJumpKind(jk);
2421 vex_printf("} ");
sewardj1f40a0a2004-07-21 12:28:07 +00002422 ppIRExpr(next);
2423 vex_printf("\n");
2424 }
sewardje8e9d732004-07-16 21:03:45 +00002425 ri = iselIntExpr_RI(env, next);
sewardj750f4072004-07-26 22:39:11 +00002426 addInstr(env, X86Instr_Goto(jk, Xcc_ALWAYS,ri));
sewardjc97096c2004-06-30 09:28:04 +00002427}
2428
2429
2430/*---------------------------------------------------------*/
2431/*--- Insn selector top-level ---*/
2432/*---------------------------------------------------------*/
2433
sewardj194d54a2004-07-03 19:08:18 +00002434/* Translate an entire BB to x86 code. */
2435
sewardj8ea867b2004-10-30 19:03:02 +00002436HInstrArray* iselBB_X86 ( IRBB* bb )
sewardjc97096c2004-06-30 09:28:04 +00002437{
sewardj597b71b2004-07-19 02:51:12 +00002438 Int i, j;
sewardje8e9d732004-07-16 21:03:45 +00002439 HReg hreg, hregHI;
sewardjc97096c2004-06-30 09:28:04 +00002440
2441 /* Make up an initial environment to use. */
sewardj35421a32004-07-05 13:12:34 +00002442 ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
sewardj194d54a2004-07-03 19:08:18 +00002443 env->vreg_ctr = 0;
sewardjc97096c2004-06-30 09:28:04 +00002444
2445 /* Set up output code array. */
sewardj2cd80dc2004-07-02 15:20:40 +00002446 env->code = newHInstrArray();
sewardjc97096c2004-06-30 09:28:04 +00002447
2448 /* Copy BB's type env. */
2449 env->type_env = bb->tyenv;
2450
2451 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2452 change as we go along. */
sewardje539a402004-07-14 18:24:17 +00002453 env->n_vregmap = bb->tyenv->types_used;
2454 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
sewardje8e9d732004-07-16 21:03:45 +00002455 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
sewardjc97096c2004-06-30 09:28:04 +00002456
2457 /* For each IR temporary, allocate a suitably-kinded virtual
2458 register. */
sewardj597b71b2004-07-19 02:51:12 +00002459 j = 0;
sewardjc97096c2004-06-30 09:28:04 +00002460 for (i = 0; i < env->n_vregmap; i++) {
sewardje8e9d732004-07-16 21:03:45 +00002461 hregHI = hreg = INVALID_HREG;
sewardje539a402004-07-14 18:24:17 +00002462 switch (bb->tyenv->types[i]) {
sewardjba999312004-11-15 15:21:17 +00002463 case Ity_I1:
sewardje8e9d732004-07-16 21:03:45 +00002464 case Ity_I8:
sewardj4042c7e2004-07-18 01:28:30 +00002465 case Ity_I16:
sewardj597b71b2004-07-19 02:51:12 +00002466 case Ity_I32: hreg = mkHReg(j++, HRcInt, True); break;
2467 case Ity_I64: hreg = mkHReg(j++, HRcInt, True);
2468 hregHI = mkHReg(j++, HRcInt, True); break;
sewardj89cd0932004-09-08 18:23:25 +00002469 case Ity_F32:
sewardjbb53f8c2004-08-14 11:50:01 +00002470 case Ity_F64: hreg = mkHReg(j++, HRcFloat, True); break;
sewardje8e9d732004-07-16 21:03:45 +00002471 default: ppIRType(bb->tyenv->types[i]);
2472 vpanic("iselBB: IRTemp type");
sewardjc97096c2004-06-30 09:28:04 +00002473 }
sewardje8e9d732004-07-16 21:03:45 +00002474 env->vregmap[i] = hreg;
2475 env->vregmapHI[i] = hregHI;
sewardjc97096c2004-06-30 09:28:04 +00002476 }
sewardje322b0a2004-07-28 07:12:30 +00002477 env->vreg_ctr = j;
sewardjc97096c2004-06-30 09:28:04 +00002478
2479 /* Ok, finally we can iterate over the statements. */
sewardjd7cb8532004-08-17 23:59:23 +00002480 for (i = 0; i < bb->stmts_used; i++)
sewardj39e3f242004-08-18 16:54:52 +00002481 if (bb->stmts[i])
2482 iselStmt(env,bb->stmts[i]);
sewardjc97096c2004-06-30 09:28:04 +00002483
sewardje539a402004-07-14 18:24:17 +00002484 iselNext(env,bb->next,bb->jumpkind);
sewardj2cd80dc2004-07-02 15:20:40 +00002485
sewardj194d54a2004-07-03 19:08:18 +00002486 /* record the number of vregs we used. */
2487 env->code->n_vregs = env->vreg_ctr;
sewardj2cd80dc2004-07-02 15:20:40 +00002488 return env->code;
sewardjc97096c2004-06-30 09:28:04 +00002489}
sewardj887a11a2004-07-05 17:26:47 +00002490
2491
2492/*---------------------------------------------------------------*/
sewardjc0ee2ed2004-07-27 10:29:41 +00002493/*--- end host-x86/isel.c ---*/
sewardj887a11a2004-07-05 17:26:47 +00002494/*---------------------------------------------------------------*/