blob: eb992733209a6be2f57717ce10617a2eb7cc6c5c [file] [log] [blame]
sewardja3e98302005-02-01 15:55:05 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (host-amd64/isel.c) is ---*/
5/*--- Copyright (c) 2005 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
9/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
13 Copyright (C) 2004-2005 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
36#include "libvex_basictypes.h"
37#include "libvex_ir.h"
38#include "libvex.h"
39
sewardj05b3b6a2005-02-04 01:44:33 +000040#include "ir/irmatch.h"
sewardjc33671d2005-02-01 20:30:00 +000041#include "main/vex_util.h"
42#include "main/vex_globals.h"
43#include "host-generic/h_generic_regs.h"
sewardja3e98302005-02-01 15:55:05 +000044//.. #include "host-generic/h_generic_simd64.h"
sewardjc33671d2005-02-01 20:30:00 +000045#include "host-amd64/hdefs.h"
sewardja3e98302005-02-01 15:55:05 +000046//..
47//..
48//.. /*---------------------------------------------------------*/
49//.. /*--- x87 control word stuff ---*/
50//.. /*---------------------------------------------------------*/
51//..
52//.. /* Vex-generated code expects to run with the FPU set as follows: all
53//.. exceptions masked, round-to-nearest, precision = 53 bits. This
54//.. corresponds to a FPU control word value of 0x027F.
55//..
56//.. Similarly the SSE control word (%mxcsr) should be 0x1F80.
57//..
58//.. %fpucw and %mxcsr should have these values on entry to
59//.. Vex-generated code, and should those values should be
60//.. unchanged at exit.
61//.. */
62//..
63//.. #define DEFAULT_FPUCW 0x027F
64//..
65//.. /* debugging only, do not use */
66//.. /* define DEFAULT_FPUCW 0x037F */
sewardj05b3b6a2005-02-04 01:44:33 +000067
68
69/*---------------------------------------------------------*/
70/*--- misc helpers ---*/
71/*---------------------------------------------------------*/
72
73/* These are duplicated in guest-amd64/toIR.c */
74static IRExpr* unop ( IROp op, IRExpr* a )
75{
76 return IRExpr_Unop(op, a);
77}
78
79static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
80{
81 return IRExpr_Binop(op, a1, a2);
82}
83
sewardja3e98302005-02-01 15:55:05 +000084//.. static IRExpr* mkU64 ( ULong i )
85//.. {
86//.. return IRExpr_Const(IRConst_U64(i));
87//.. }
88//..
89//.. static IRExpr* mkU32 ( UInt i )
90//.. {
91//.. return IRExpr_Const(IRConst_U32(i));
92//.. }
sewardj05b3b6a2005-02-04 01:44:33 +000093
94static IRExpr* bind ( Int binder )
95{
96 return IRExpr_Binder(binder);
97}
sewardjc33671d2005-02-01 20:30:00 +000098
99
100
101/*---------------------------------------------------------*/
102/*--- ISelEnv ---*/
103/*---------------------------------------------------------*/
104
105/* This carries around:
106
107 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
108 might encounter. This is computed before insn selection starts,
109 and does not change.
110
111 - A mapping from IRTemp to HReg. This tells the insn selector
112 which virtual register is associated with each IRTemp
113 temporary. This is computed before insn selection starts, and
114 does not change. We expect this mapping to map precisely the
115 same set of IRTemps as the type mapping does.
116
117 - The code array, that is, the insns selected so far.
118
119 - A counter, for generating new virtual registers.
120
121 - The host subarchitecture we are selecting insns for.
122 This is set at the start and does not change.
123
124 Note, this is all host-independent. (JRS 20050201: well, kinda
125 ... not completely. Compare with ISelEnv for X86.)
126*/
127
128typedef
129 struct {
130 IRTypeEnv* type_env;
131
132 HReg* vregmap;
133 Int n_vregmap;
134
135 HInstrArray* code;
136
137 Int vreg_ctr;
138
139 VexSubArch subarch;
140 }
141 ISelEnv;
142
143
144static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
145{
146 vassert(tmp >= 0);
147 vassert(tmp < env->n_vregmap);
148 return env->vregmap[tmp];
149}
150
sewardja3e98302005-02-01 15:55:05 +0000151//.. static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp )
152//.. {
153//.. vassert(tmp >= 0);
154//.. vassert(tmp < env->n_vregmap);
155//.. vassert(env->vregmapHI[tmp] != INVALID_HREG);
156//.. *vrLO = env->vregmap[tmp];
157//.. *vrHI = env->vregmapHI[tmp];
158//.. }
sewardj614b3fb2005-02-02 02:16:03 +0000159
160static void addInstr ( ISelEnv* env, AMD64Instr* instr )
161{
162 addHInstr(env->code, instr);
163 if (vex_traceflags & VEX_TRACE_VCODE) {
164 ppAMD64Instr(instr);
165 vex_printf("\n");
166 }
167}
168
sewardj8258a8c2005-02-02 03:11:24 +0000169static HReg newVRegI ( ISelEnv* env )
170{
171 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True/*virtual reg*/);
172 env->vreg_ctr++;
173 return reg;
174}
175
sewardja3e98302005-02-01 15:55:05 +0000176//.. static HReg newVRegF ( ISelEnv* env )
177//.. {
178//.. HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/);
179//.. env->vreg_ctr++;
180//.. return reg;
181//.. }
182//..
183//.. static HReg newVRegV ( ISelEnv* env )
184//.. {
185//.. HReg reg = mkHReg(env->vreg_ctr, HRcVec128, True/*virtual reg*/);
186//.. env->vreg_ctr++;
187//.. return reg;
188//.. }
sewardj614b3fb2005-02-02 02:16:03 +0000189
190
191/*---------------------------------------------------------*/
192/*--- ISEL: Forward declarations ---*/
193/*---------------------------------------------------------*/
194
195/* These are organised as iselXXX and iselXXX_wrk pairs. The
196 iselXXX_wrk do the real work, but are not to be called directly.
197 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
198 checks that all returned registers are virtual. You should not
199 call the _wrk version directly.
200*/
201static AMD64RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e );
202static AMD64RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e );
203
204static AMD64RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e );
205static AMD64RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e );
206
207static AMD64RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e );
208static AMD64RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e );
209
210static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e );
211static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e );
212
213static AMD64AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e );
214static AMD64AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e );
215
216static AMD64CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
217static AMD64CondCode iselCondCode ( ISelEnv* env, IRExpr* e );
218
sewardjc2bcb6f2005-02-07 00:17:12 +0000219//static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e );
220//static HReg iselDblExpr ( ISelEnv* env, IRExpr* e );
sewardj614b3fb2005-02-02 02:16:03 +0000221
sewardjc2bcb6f2005-02-07 00:17:12 +0000222//static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e );
223//static HReg iselFltExpr ( ISelEnv* env, IRExpr* e );
sewardj614b3fb2005-02-02 02:16:03 +0000224
sewardjc2bcb6f2005-02-07 00:17:12 +0000225//static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e );
226//static HReg iselVecExpr ( ISelEnv* env, IRExpr* e );
sewardj614b3fb2005-02-02 02:16:03 +0000227
228
229/*---------------------------------------------------------*/
230/*--- ISEL: Misc helpers ---*/
231/*---------------------------------------------------------*/
232
233static Bool sane_AMode ( AMD64AMode* am )
234{
235 switch (am->tag) {
236 case Aam_IR:
237 return hregClass(am->Aam.IR.reg) == HRcInt64
238 && (hregIsVirtual(am->Aam.IR.reg)
239 || am->Aam.IR.reg == hregAMD64_RBP());
240 case Aam_IRRS:
241 return hregClass(am->Aam.IRRS.base) == HRcInt64
242 && hregIsVirtual(am->Aam.IRRS.base)
243 && hregClass(am->Aam.IRRS.index) == HRcInt64
244 && hregIsVirtual(am->Aam.IRRS.index);
245 default:
246 vpanic("sane_AMode: unknown amd64 amode tag");
247 }
248}
249
250
251/* Can the lower 32 bits be signedly widened to produce the whole
252 64-bit value? In other words, are the top 33 bits either all 0 or
253 all 1 ? */
254static Bool fitsIn32Bits ( ULong x )
255{
256 Long y0 = (Long)x;
257 Long y1 = y0;
258 y1 <<= 32;
259 y1 >>=/*s*/ 32;
260 return toBool(x == y1);
261}
262
sewardja3e98302005-02-01 15:55:05 +0000263//.. /* Is this a 32-bit zero expression? */
264//..
265//.. static Bool isZero32 ( IRExpr* e )
266//.. {
267//.. return e->tag == Iex_Const
268//.. && e->Iex.Const.con->tag == Ico_U32
269//.. && e->Iex.Const.con->Ico.U32 == 0;
270//.. }
sewardj8258a8c2005-02-02 03:11:24 +0000271
272/* Make a int reg-reg move. */
273
274static AMD64Instr* mk_iMOVsd_RR ( HReg src, HReg dst )
275{
276 vassert(hregClass(src) == HRcInt64);
277 vassert(hregClass(dst) == HRcInt64);
278 return AMD64Instr_Alu64R(Aalu_MOV, AMD64RMI_Reg(src), dst);
279}
280
281
sewardja3e98302005-02-01 15:55:05 +0000282//.. /* Make a vector reg-reg move. */
283//..
284//.. static X86Instr* mk_vMOVsd_RR ( HReg src, HReg dst )
285//.. {
286//.. vassert(hregClass(src) == HRcVec128);
287//.. vassert(hregClass(dst) == HRcVec128);
288//.. return X86Instr_SseReRg(Xsse_MOV, src, dst);
289//.. }
290//..
291//.. /* Advance/retreat %esp by n. */
292//..
293//.. static void add_to_esp ( ISelEnv* env, Int n )
294//.. {
295//.. vassert(n > 0 && n < 256 && (n%4) == 0);
296//.. addInstr(env,
297//.. X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(n), hregX86_ESP()));
298//.. }
299//..
300//.. static void sub_from_esp ( ISelEnv* env, Int n )
301//.. {
302//.. vassert(n > 0 && n < 256 && (n%4) == 0);
303//.. addInstr(env,
304//.. X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(n), hregX86_ESP()));
305//.. }
306//..
307//..
308//.. /* Given an amode, return one which references 4 bytes further
309//.. along. */
310//..
311//.. static X86AMode* advance4 ( X86AMode* am )
312//.. {
313//.. X86AMode* am4 = dopyX86AMode(am);
314//.. switch (am4->tag) {
315//.. case Xam_IRRS:
316//.. am4->Xam.IRRS.imm += 4; break;
317//.. case Xam_IR:
318//.. am4->Xam.IR.imm += 4; break;
319//.. default:
320//.. vpanic("advance4(x86,host)");
321//.. }
322//.. return am4;
323//.. }
324//..
325//..
326//.. /* Push an arg onto the host stack, in preparation for a call to a
327//.. helper function of some kind. Returns the number of 32-bit words
328//.. pushed. */
329//..
330//.. static Int pushArg ( ISelEnv* env, IRExpr* arg )
331//.. {
332//.. IRType arg_ty = typeOfIRExpr(env->type_env, arg);
333//.. if (arg_ty == Ity_I32) {
334//.. addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg)));
335//.. return 1;
336//.. } else
337//.. if (arg_ty == Ity_I64) {
338//.. HReg rHi, rLo;
339//.. iselInt64Expr(&rHi, &rLo, env, arg);
340//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
341//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
342//.. return 2;
343//.. }
344//.. ppIRExpr(arg);
345//.. vpanic("pushArg(x86): can't handle arg of this type");
346//.. }
sewardj05b3b6a2005-02-04 01:44:33 +0000347
348
349/* Used only in doHelperCall. See big comment in doHelperCall re
350 handling of register-parameter args. This function figures out
351 whether evaluation of an expression might require use of a fixed
352 register. If in doubt return True (safe but suboptimal).
353*/
354static
355Bool mightRequireFixedRegs ( IRExpr* e )
356{
357 switch (e->tag) {
358 case Iex_Tmp: case Iex_Const: case Iex_Get:
359 return False;
360 default:
361 return True;
362 }
363}
364
365
366/* Do a complete function call. guard is a Ity_Bit expression
367 indicating whether or not the call happens. If guard==NULL, the
368 call is unconditional. */
369
370static
371void doHelperCall ( ISelEnv* env,
372 Bool passBBP,
373 IRExpr* guard, IRCallee* cee, IRExpr** args )
374{
375 AMD64CondCode cc;
376 HReg argregs[6];
377 HReg tmpregs[6];
378 Bool go_fast;
379 Int n_args, i, argreg;
380
381 /* Marshal args for a call and do the call.
382
383 If passBBP is True, %rbp (the baseblock pointer) is to be passed
384 as the first arg.
385
386 This function only deals with a tiny set of possibilities, which
387 cover all helpers in practice. The restrictions are that only
388 arguments in registers are supported, hence only 6x64 integer
389 bits in total can be passed. In fact the only supported arg
390 type is I64.
391
392 Generating code which is both efficient and correct when
393 parameters are to be passed in registers is difficult, for the
394 reasons elaborated in detail in comments attached to
395 doHelperCall() in priv/host-x86/isel.c. Here, we use a variant
396 of the method described in those comments.
397
398 The problem is split into two cases: the fast scheme and the
399 slow scheme. In the fast scheme, arguments are computed
400 directly into the target (real) registers. This is only safe
401 when we can be sure that computation of each argument will not
402 trash any real registers set by computation of any other
403 argument.
404
405 In the slow scheme, all args are first computed into vregs, and
406 once they are all done, they are moved to the relevant real
407 regs. This always gives correct code, but it also gives a bunch
408 of vreg-to-rreg moves which are usually redundant but are hard
409 for the register allocator to get rid of.
410
411 To decide which scheme to use, all argument expressions are
412 first examined. If they are all so simple that it is clear they
413 will be evaluated without use of any fixed registers, use the
414 fast scheme, else use the slow scheme. Note also that only
415 unconditional calls may use the fast scheme, since having to
416 compute a condition expression could itself trash real
417 registers.
418
419 Note this requires being able to examine an expression and
420 determine whether or not evaluation of it might use a fixed
421 register. That requires knowledge of how the rest of this insn
422 selector works. Currently just the following 3 are regarded as
423 safe -- hopefully they cover the majority of arguments in
424 practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
425 */
426
427 /* Note that the cee->regparms field is meaningless on AMD64 host
428 (since there is only one calling convention) and so we always
429 ignore it. */
430
431 n_args = 0;
432 for (i = 0; args[i]; i++)
433 n_args++;
434
435 if (6 < n_args + (passBBP ? 1 : 0))
436 vpanic("doHelperCall(AMD64): cannot currently handle > 6 args");
437
438 argregs[0] = hregAMD64_RDI();
439 argregs[1] = hregAMD64_RSI();
440 argregs[2] = hregAMD64_RDX();
441 argregs[3] = hregAMD64_RCX();
442 argregs[4] = hregAMD64_R8();
443 argregs[5] = hregAMD64_R9();
444
445 tmpregs[0] = tmpregs[1] = tmpregs[2] =
446 tmpregs[3] = tmpregs[4] = tmpregs[5] = INVALID_HREG;
447
448 /* First decide which scheme (slow or fast) is to be used. First
449 assume the fast scheme, and select slow if any contraindications
450 (wow) appear. */
451
452 go_fast = True;
453
454 if (guard) {
455 if (guard->tag == Iex_Const
456 && guard->Iex.Const.con->tag == Ico_U1
457 && guard->Iex.Const.con->Ico.U1 == True) {
458 /* unconditional */
459 } else {
460 /* Not manifestly unconditional -- be conservative. */
461 go_fast = False;
462 }
463 }
464
465 if (go_fast) {
466 for (i = 0; i < n_args; i++) {
467 if (mightRequireFixedRegs(args[i])) {
468 go_fast = False;
469 break;
470 }
471 }
472 }
473
474 /* At this point the scheme to use has been established. Generate
475 code to get the arg values into the argument rregs. */
476
477 if (go_fast) {
478
479 /* FAST SCHEME */
480 argreg = 0;
481 if (passBBP) {
482 addInstr(env, mk_iMOVsd_RR( hregAMD64_RBP(), argregs[argreg]));
483 argreg++;
484 }
485
486 for (i = 0; i < n_args; i++) {
487 vassert(argreg < 6);
488 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
489 addInstr(env, AMD64Instr_Alu64R(
490 Aalu_MOV,
491 iselIntExpr_RMI(env, args[i]),
492 argregs[argreg]
493 )
494 );
495 argreg++;
496 }
497
498 /* Fast scheme only applies for unconditional calls. Hence: */
499 cc = Acc_ALWAYS;
500
501 } else {
502
503 /* SLOW SCHEME; move via temporaries */
504 argreg = 0;
505
506 if (passBBP) {
507 /* This is pretty stupid; better to move directly to rdi
508 after the rest of the args are done. */
509 tmpregs[argreg] = newVRegI(env);
510 addInstr(env, mk_iMOVsd_RR( hregAMD64_RBP(), tmpregs[argreg]));
511 argreg++;
512 }
513
514 for (i = 0; i < n_args; i++) {
515 vassert(argreg < 6);
516 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
517 tmpregs[argreg] = iselIntExpr_R(env, args[i]);
518 argreg++;
519 }
520
521 /* Now we can compute the condition. We can't do it earlier
522 because the argument computations could trash the condition
523 codes. Be a bit clever to handle the common case where the
524 guard is 1:Bit. */
525 cc = Acc_ALWAYS;
526 if (guard) {
527 if (guard->tag == Iex_Const
528 && guard->Iex.Const.con->tag == Ico_U1
529 && guard->Iex.Const.con->Ico.U1 == True) {
530 /* unconditional -- do nothing */
531 } else {
532 cc = iselCondCode( env, guard );
533 }
534 }
535
536 /* Move the args to their final destinations. */
537 for (i = 0; i < argreg; i++) {
538 /* None of these insns, including any spill code that might
539 be generated, may alter the condition codes. */
540 addInstr( env, mk_iMOVsd_RR( tmpregs[i], argregs[i] ) );
541 }
542
543 }
544
545 /* Finally, the call itself. */
546 addInstr(env, AMD64Instr_Call(
547 cc,
sewardjf3992bd2005-02-07 00:20:43 +0000548 Ptr_to_ULong(cee->addr),
sewardj05b3b6a2005-02-04 01:44:33 +0000549 n_args + (passBBP ? 1 : 0)
550 )
551 );
552}
553
554
sewardja3e98302005-02-01 15:55:05 +0000555//.. /* Given a guest-state array descriptor, an index expression and a
556//.. bias, generate an X86AMode holding the relevant guest state
557//.. offset. */
558//..
559//.. static
560//.. X86AMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr,
561//.. IRExpr* off, Int bias )
562//.. {
563//.. HReg tmp, roff;
564//.. Int elemSz = sizeofIRType(descr->elemTy);
565//.. Int nElems = descr->nElems;
566//..
567//.. /* throw out any cases not generated by an x86 front end. In
568//.. theory there might be a day where we need to handle them -- if
569//.. we ever run non-x86-guest on x86 host. */
570//..
571//.. if (nElems != 8 || (elemSz != 1 && elemSz != 8))
572//.. vpanic("genGuestArrayOffset(x86 host)");
573//..
574//.. /* Compute off into a reg, %off. Then return:
575//..
576//.. movl %off, %tmp
577//.. addl $bias, %tmp (if bias != 0)
578//.. andl %tmp, 7
579//.. ... base(%ebp, %tmp, shift) ...
580//.. */
581//.. tmp = newVRegI(env);
582//.. roff = iselIntExpr_R(env, off);
583//.. addInstr(env, mk_iMOVsd_RR(roff, tmp));
584//.. if (bias != 0) {
585//.. addInstr(env,
586//.. X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(bias), tmp));
587//.. }
588//.. addInstr(env,
589//.. X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(7), tmp));
590//.. vassert(elemSz == 1 || elemSz == 8);
591//.. return
592//.. X86AMode_IRRS( descr->base, hregX86_EBP(), tmp,
593//.. elemSz==8 ? 3 : 0);
594//.. }
595//..
596//..
597//.. /* Mess with the FPU's rounding mode: set to the default rounding mode
598//.. (DEFAULT_FPUCW). */
599//.. static
600//.. void set_FPU_rounding_default ( ISelEnv* env )
601//.. {
602//.. /* pushl $DEFAULT_FPUCW
603//.. fldcw 0(%esp)
604//.. addl $4, %esp
605//.. */
606//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
607//.. addInstr(env, X86Instr_Push(X86RMI_Imm(DEFAULT_FPUCW)));
608//.. addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
609//.. add_to_esp(env, 4);
610//.. }
611//..
612//..
613//.. /* Mess with the FPU's rounding mode: 'mode' is an I32-typed
614//.. expression denoting a value in the range 0 .. 3, indicating a round
615//.. mode encoded as per type IRRoundingMode. Set the x87 FPU to have
616//.. the same rounding.
617//.. */
618//.. static
619//.. void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
620//.. {
621//.. HReg rrm = iselIntExpr_R(env, mode);
622//.. HReg rrm2 = newVRegI(env);
623//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
624//..
625//.. /* movl %rrm, %rrm2
626//.. andl $3, %rrm2 -- shouldn't be needed; paranoia
627//.. shll $10, %rrm2
628//.. orl $DEFAULT_FPUCW, %rrm2
629//.. pushl %rrm2
630//.. fldcw 0(%esp)
631//.. addl $4, %esp
632//.. */
633//.. addInstr(env, mk_iMOVsd_RR(rrm, rrm2));
634//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));
635//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2)));
636//.. addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(DEFAULT_FPUCW), rrm2));
637//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rrm2)));
638//.. addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
639//.. add_to_esp(env, 4);
640//.. }
641//..
642//..
643//.. /* Generate !src into a new vector register, and be sure that the code
644//.. is SSE1 compatible. Amazing that Intel doesn't offer a less crappy
645//.. way to do this.
646//.. */
647//.. static HReg do_sse_Not128 ( ISelEnv* env, HReg src )
648//.. {
649//.. HReg dst = newVRegV(env);
650//.. /* Set dst to zero. Not strictly necessary, but the idea of doing
651//.. a FP comparison on whatever junk happens to be floating around
652//.. in it is just too scary. */
653//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, dst, dst));
654//.. /* And now make it all 1s ... */
655//.. addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, dst, dst));
656//.. /* Finally, xor 'src' into it. */
657//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, src, dst));
658//.. return dst;
659//.. }
660//..
661//..
662//.. /* Round an x87 FPU value to 53-bit-mantissa precision, to be used
663//.. after most non-simple FPU operations (simple = +, -, *, / and
664//.. sqrt).
665//..
666//.. This could be done a lot more efficiently if needed, by loading
667//.. zero and adding it to the value to be rounded (fldz ; faddp?).
668//.. */
669//.. static void roundToF64 ( ISelEnv* env, HReg reg )
670//.. {
671//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
672//.. sub_from_esp(env, 8);
673//.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, reg, zero_esp));
674//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, reg, zero_esp));
675//.. add_to_esp(env, 8);
676//.. }
sewardj8258a8c2005-02-02 03:11:24 +0000677
678
679/*---------------------------------------------------------*/
680/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
681/*---------------------------------------------------------*/
682
683/* Select insns for an integer-typed expression, and add them to the
684 code list. Return a reg holding the result. This reg will be a
685 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
686 want to modify it, ask for a new vreg, copy it in there, and modify
687 the copy. The register allocator will do its best to map both
688 vregs to the same real register, so the copies will often disappear
689 later in the game.
690
691 This should handle expressions of 64, 32, 16 and 8-bit type. All
692 results are returned in a 64-bit register. For 32-, 16- and 8-bit
693 expressions, the upper 32/16/24 bits are arbitrary, so you should
694 mask or sign extend partial values if necessary.
695*/
696
697static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
698{
699 HReg r = iselIntExpr_R_wrk(env, e);
700 /* sanity checks ... */
701# if 0
702 vex_printf("\niselIntExpr_R: "); ppIRExpr(e); vex_printf("\n");
703# endif
704 vassert(hregClass(r) == HRcInt64);
705 vassert(hregIsVirtual(r));
706 return r;
707}
708
709/* DO NOT CALL THIS DIRECTLY ! */
710static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
711{
sewardj05b3b6a2005-02-04 01:44:33 +0000712 MatchInfo mi;
sewardj7f039c42005-02-04 21:13:55 +0000713 DECLARE_PATTERN(p_8Uto64);
sewardj05b3b6a2005-02-04 01:44:33 +0000714 DECLARE_PATTERN(p_16Uto64);
715 DECLARE_PATTERN(p_1Uto8_32to1_64to32);
sewardja3e98302005-02-01 15:55:05 +0000716//.. DECLARE_PATTERN(p_32to1_then_1Uto8);
sewardj8258a8c2005-02-02 03:11:24 +0000717
718 IRType ty = typeOfIRExpr(env->type_env,e);
719 vassert(ty == Ity_I32 || Ity_I16 || Ity_I8);
720
721 switch (e->tag) {
722
723 /* --------- TEMP --------- */
724 case Iex_Tmp: {
725 return lookupIRTemp(env, e->Iex.Tmp.tmp);
726 }
727
728 /* --------- LOAD --------- */
729 case Iex_LDle: {
730 HReg dst = newVRegI(env);
731 AMD64AMode* amode = iselIntExpr_AMode ( env, e->Iex.LDle.addr );
sewardjf67eadf2005-02-03 03:53:52 +0000732 if (ty == Ity_I64) {
733 addInstr(env, AMD64Instr_Alu64R(Aalu_MOV,
734 AMD64RMI_Mem(amode), dst) );
735 return dst;
736 }
sewardj8258a8c2005-02-02 03:11:24 +0000737 if (ty == Ity_I32) {
738 addInstr(env, AMD64Instr_LoadEX(4,False,amode,dst));
739 return dst;
740 }
sewardj05b3b6a2005-02-04 01:44:33 +0000741 if (ty == Ity_I16) {
742 addInstr(env, AMD64Instr_LoadEX(2,False,amode,dst));
743 return dst;
744 }
sewardj7f039c42005-02-04 21:13:55 +0000745 if (ty == Ity_I8) {
746 addInstr(env, AMD64Instr_LoadEX(1,False,amode,dst));
747 return dst;
748 }
sewardj8258a8c2005-02-02 03:11:24 +0000749 break;
750 }
751
752 /* --------- BINARY OP --------- */
753 case Iex_Binop: {
754 AMD64AluOp aluOp;
755 AMD64ShiftOp shOp;
sewardja3e98302005-02-01 15:55:05 +0000756//..
757//.. /* Pattern: Sub32(0,x) */
758//.. if (e->Iex.Binop.op == Iop_Sub32 && isZero32(e->Iex.Binop.arg1)) {
759//.. HReg dst = newVRegI(env);
760//.. HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg2);
761//.. addInstr(env, mk_iMOVsd_RR(reg,dst));
762//.. addInstr(env, X86Instr_Unary32(Xun_NEG,X86RM_Reg(dst)));
763//.. return dst;
764//.. }
765//..
sewardj8258a8c2005-02-02 03:11:24 +0000766 /* Is it an addition or logical style op? */
767 switch (e->Iex.Binop.op) {
768 case Iop_Add8: case Iop_Add16: case Iop_Add32: case Iop_Add64:
769 aluOp = Aalu_ADD; break;
sewardj05b3b6a2005-02-04 01:44:33 +0000770 case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: case Iop_Sub64:
771 aluOp = Aalu_SUB; break;
772 case Iop_And8: case Iop_And16: case Iop_And32: case Iop_And64:
773 aluOp = Aalu_AND; break;
sewardj31191072005-02-05 18:24:47 +0000774 case Iop_Or8: case Iop_Or16: case Iop_Or32: case Iop_Or64:
775 aluOp = Aalu_OR; break;
sewardja3e98302005-02-01 15:55:05 +0000776//.. case Iop_Xor8: case Iop_Xor16: case Iop_Xor32:
777//.. aluOp = Xalu_XOR; break;
778//.. case Iop_Mul16: case Iop_Mul32:
779//.. aluOp = Xalu_MUL; break;
sewardj8258a8c2005-02-02 03:11:24 +0000780 default:
781 aluOp = Aalu_INVALID; break;
782 }
783 /* For commutative ops we assume any literal
784 values are on the second operand. */
785 if (aluOp != Aalu_INVALID) {
786 HReg dst = newVRegI(env);
787 HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
788 AMD64RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
789 addInstr(env, mk_iMOVsd_RR(reg,dst));
790 addInstr(env, AMD64Instr_Alu64R(aluOp, rmi, dst));
791 return dst;
792 }
793
794 /* Perhaps a shift op? */
795 switch (e->Iex.Binop.op) {
796 case Iop_Shl64: case Iop_Shl32: case Iop_Shl16: case Iop_Shl8:
797 shOp = Ash_SHL; break;
sewardja3e98302005-02-01 15:55:05 +0000798//.. case Iop_Shr32: case Iop_Shr16: case Iop_Shr8:
799//.. shOp = Xsh_SHR; break;
sewardj05b3b6a2005-02-04 01:44:33 +0000800 case Iop_Sar64: case Iop_Sar32: case Iop_Sar16: case Iop_Sar8:
801 shOp = Ash_SAR; break;
sewardj8258a8c2005-02-02 03:11:24 +0000802 default:
803 shOp = Ash_INVALID; break;
804 }
805 if (shOp != Ash_INVALID) {
806 HReg dst = newVRegI(env);
807
808 /* regL = the value to be shifted */
809 HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1);
810 addInstr(env, mk_iMOVsd_RR(regL,dst));
811
812 /* Do any necessary widening for 32/16/8 bit operands */
813 switch (e->Iex.Binop.op) {
sewardj05b3b6a2005-02-04 01:44:33 +0000814 case Iop_Shr64: case Iop_Shl64: case Iop_Sar64:
815 break;
sewardja3e98302005-02-01 15:55:05 +0000816//.. case Iop_Shr8:
817//.. addInstr(env, X86Instr_Alu32R(
818//.. Xalu_AND, X86RMI_Imm(0xFF), dst));
819//.. break;
820//.. case Iop_Shr16:
821//.. addInstr(env, X86Instr_Alu32R(
822//.. Xalu_AND, X86RMI_Imm(0xFFFF), dst));
823//.. break;
824//.. case Iop_Sar8:
825//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 24, X86RM_Reg(dst)));
826//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 24, X86RM_Reg(dst)));
827//.. break;
828//.. case Iop_Sar16:
829//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(dst)));
830//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, X86RM_Reg(dst)));
831//.. break;
sewardj05b3b6a2005-02-04 01:44:33 +0000832 case Iop_Sar32:
833 addInstr(env, AMD64Instr_Sh64(Ash_SHL, 32, AMD64RM_Reg(dst)));
834 addInstr(env, AMD64Instr_Sh64(Ash_SAR, 32, AMD64RM_Reg(dst)));
835 break;
836 default:
837 vassert(0);
sewardj8258a8c2005-02-02 03:11:24 +0000838 }
839
840 /* Now consider the shift amount. If it's a literal, we
841 can do a much better job than the general case. */
842 if (e->Iex.Binop.arg2->tag == Iex_Const) {
843 /* assert that the IR is well-typed */
844 Int nshift;
845 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
846 nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
847 vassert(nshift >= 0);
848 if (nshift > 0)
849 /* Can't allow nshift==0 since that means %cl */
850 addInstr(env, AMD64Instr_Sh64(
851 shOp,
852 nshift,
853 AMD64RM_Reg(dst)));
854 } else {
855 /* General case; we have to force the amount into %cl. */
856 HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2);
857 addInstr(env, mk_iMOVsd_RR(regR,hregAMD64_RCX()));
858 addInstr(env, AMD64Instr_Sh64(shOp, 0/* %cl */, AMD64RM_Reg(dst)));
859 }
860 return dst;
861 }
862
sewardja3e98302005-02-01 15:55:05 +0000863//.. /* Handle misc other ops. */
864//.. if (e->Iex.Binop.op == Iop_8HLto16) {
865//.. HReg hi8 = newVRegI(env);
866//.. HReg lo8 = newVRegI(env);
867//.. HReg hi8s = iselIntExpr_R(env, e->Iex.Binop.arg1);
868//.. HReg lo8s = iselIntExpr_R(env, e->Iex.Binop.arg2);
869//.. addInstr(env, mk_iMOVsd_RR(hi8s, hi8));
870//.. addInstr(env, mk_iMOVsd_RR(lo8s, lo8));
871//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 8, X86RM_Reg(hi8)));
872//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFF), lo8));
873//.. addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo8), hi8));
874//.. return hi8;
875//.. }
876//..
877//.. if (e->Iex.Binop.op == Iop_16HLto32) {
878//.. HReg hi16 = newVRegI(env);
879//.. HReg lo16 = newVRegI(env);
880//.. HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
881//.. HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
882//.. addInstr(env, mk_iMOVsd_RR(hi16s, hi16));
883//.. addInstr(env, mk_iMOVsd_RR(lo16s, lo16));
884//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, X86RM_Reg(hi16)));
885//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFFFF), lo16));
886//.. addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo16), hi16));
887//.. return hi16;
888//.. }
889//..
890//.. if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8
891//.. || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) {
892//.. HReg a16 = newVRegI(env);
893//.. HReg b16 = newVRegI(env);
894//.. HReg a16s = iselIntExpr_R(env, e->Iex.Binop.arg1);
895//.. HReg b16s = iselIntExpr_R(env, e->Iex.Binop.arg2);
896//.. Int shift = (e->Iex.Binop.op == Iop_MullS8
897//.. || e->Iex.Binop.op == Iop_MullU8)
898//.. ? 24 : 16;
899//.. X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8
900//.. || e->Iex.Binop.op == Iop_MullS16)
901//.. ? Xsh_SAR : Xsh_SHR;
902//..
903//.. addInstr(env, mk_iMOVsd_RR(a16s, a16));
904//.. addInstr(env, mk_iMOVsd_RR(b16s, b16));
905//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(a16)));
906//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, X86RM_Reg(b16)));
907//.. addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(a16)));
908//.. addInstr(env, X86Instr_Sh32(shr_op, shift, X86RM_Reg(b16)));
909//.. addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16));
910//.. return b16;
911//.. }
912//..
913//.. if (e->Iex.Binop.op == Iop_CmpF64) {
914//.. HReg fL = iselDblExpr(env, e->Iex.Binop.arg1);
915//.. HReg fR = iselDblExpr(env, e->Iex.Binop.arg2);
916//.. HReg dst = newVRegI(env);
917//.. addInstr(env, X86Instr_FpCmp(fL,fR,dst));
918//.. /* shift this right 8 bits so as to conform to CmpF64
919//.. definition. */
920//.. addInstr(env, X86Instr_Sh32(Xsh_SHR, 8, X86RM_Reg(dst)));
921//.. return dst;
922//.. }
923//..
924//.. if (e->Iex.Binop.op == Iop_F64toI32 || e->Iex.Binop.op == Iop_F64toI16) {
925//.. Int sz = e->Iex.Binop.op == Iop_F64toI16 ? 2 : 4;
926//.. HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
927//.. HReg dst = newVRegI(env);
928//..
929//.. /* Used several times ... */
930//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
931//..
932//.. /* rf now holds the value to be converted, and rrm holds the
933//.. rounding mode value, encoded as per the IRRoundingMode
934//.. enum. The first thing to do is set the FPU's rounding
935//.. mode accordingly. */
936//..
937//.. /* Create a space for the format conversion. */
938//.. /* subl $4, %esp */
939//.. sub_from_esp(env, 4);
940//..
941//.. /* Set host rounding mode */
942//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
943//..
944//.. /* gistw/l %rf, 0(%esp) */
945//.. addInstr(env, X86Instr_FpLdStI(False/*store*/, sz, rf, zero_esp));
946//..
947//.. if (sz == 2) {
948//.. /* movzwl 0(%esp), %dst */
949//.. addInstr(env, X86Instr_LoadEX(2,False,zero_esp,dst));
950//.. } else {
951//.. /* movl 0(%esp), %dst */
952//.. vassert(sz == 4);
953//.. addInstr(env, X86Instr_Alu32R(
954//.. Xalu_MOV, X86RMI_Mem(zero_esp), dst));
955//.. }
956//..
957//.. /* Restore default FPU rounding. */
958//.. set_FPU_rounding_default( env );
959//..
960//.. /* addl $4, %esp */
961//.. add_to_esp(env, 4);
962//.. return dst;
963//.. }
964//..
965//.. /* C3210 flags following FPU partial remainder (fprem), both
966//.. IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
967//.. if (e->Iex.Binop.op == Iop_PRemC3210F64
968//.. || e->Iex.Binop.op == Iop_PRem1C3210F64) {
969//.. HReg junk = newVRegF(env);
970//.. HReg dst = newVRegI(env);
971//.. HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
972//.. HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
973//.. addInstr(env, X86Instr_FpBinary(
974//.. e->Iex.Binop.op==Iop_PRemC3210F64
975//.. ? Xfp_PREM : Xfp_PREM1,
976//.. srcL,srcR,junk
977//.. ));
978//.. /* The previous pseudo-insn will have left the FPU's C3210
979//.. flags set correctly. So bag them. */
980//.. addInstr(env, X86Instr_FpStSW_AX());
981//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
982//.. addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
983//.. return dst;
984//.. }
sewardj8258a8c2005-02-02 03:11:24 +0000985
986 break;
987 }
988
sewardjf67eadf2005-02-03 03:53:52 +0000989 /* --------- UNARY OP --------- */
990 case Iex_Unop: {
sewardj05b3b6a2005-02-04 01:44:33 +0000991 /* 32Uto64(16Uto32(expr16)) */
992 DEFINE_PATTERN(p_16Uto64,
993 unop(Iop_32Uto64, unop(Iop_16Uto32, bind(0)) ) );
994 if (matchIRExpr(&mi,p_16Uto64,e)) {
995 IRExpr* expr16 = mi.bindee[0];
sewardj7f039c42005-02-04 21:13:55 +0000996 HReg dst = newVRegI(env);
997 HReg src = iselIntExpr_R(env, expr16);
sewardj05b3b6a2005-02-04 01:44:33 +0000998 addInstr(env, mk_iMOVsd_RR(src,dst) );
999 addInstr(env, AMD64Instr_Sh64(Ash_SHL, 48, AMD64RM_Reg(dst)));
1000 addInstr(env, AMD64Instr_Sh64(Ash_SHR, 48, AMD64RM_Reg(dst)));
1001 return dst;
1002 }
1003
sewardj7f039c42005-02-04 21:13:55 +00001004 /* 32Uto64(8Uto32(expr16)) */
1005 DEFINE_PATTERN(p_8Uto64,
1006 unop(Iop_32Uto64, unop(Iop_8Uto32, bind(0)) ) );
1007 if (matchIRExpr(&mi,p_8Uto64,e)) {
1008 IRExpr* expr8 = mi.bindee[0];
1009 HReg dst = newVRegI(env);
1010 HReg src = iselIntExpr_R(env, expr8);
1011 addInstr(env, mk_iMOVsd_RR(src,dst) );
1012 addInstr(env, AMD64Instr_Sh64(Ash_SHL, 56, AMD64RM_Reg(dst)));
1013 addInstr(env, AMD64Instr_Sh64(Ash_SHR, 56, AMD64RM_Reg(dst)));
1014 return dst;
1015 }
1016
sewardj05b3b6a2005-02-04 01:44:33 +00001017 /* 1Uto8(32to1(64to32(expr64))) */
1018 DEFINE_PATTERN(p_1Uto8_32to1_64to32,
1019 unop(Iop_1Uto8,
1020 unop(Iop_32to1, unop(Iop_64to32, bind(0)))));
1021 if (matchIRExpr(&mi,p_1Uto8_32to1_64to32,e)) {
1022 IRExpr* expr64 = mi.bindee[0];
1023 HReg dst = newVRegI(env);
1024 HReg src = iselIntExpr_R(env, expr64);
1025 addInstr(env, mk_iMOVsd_RR(src,dst) );
1026 addInstr(env, AMD64Instr_Alu64R(Aalu_AND,
1027 AMD64RMI_Imm(1), dst));
1028 return dst;
1029 }
1030
sewardja3e98302005-02-01 15:55:05 +00001031//.. /* 16Uto32(LDle(expr32)) */
1032//.. {
1033//.. DECLARE_PATTERN(p_LDle16_then_16Uto32);
1034//.. DEFINE_PATTERN(p_LDle16_then_16Uto32,
1035//.. unop(Iop_16Uto32,IRExpr_LDle(Ity_I16,bind(0))) );
1036//.. if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) {
1037//.. HReg dst = newVRegI(env);
1038//.. X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1039//.. addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1040//.. return dst;
1041//.. }
1042//.. }
sewardjf67eadf2005-02-03 03:53:52 +00001043
1044 switch (e->Iex.Unop.op) {
1045 case Iop_32Uto64: {
1046 HReg dst = newVRegI(env);
1047 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1048 addInstr(env, AMD64Instr_MovZLQ(src,dst) );
1049 return dst;
1050 }
sewardj05b3b6a2005-02-04 01:44:33 +00001051 case Iop_32Sto64: {
1052 HReg dst = newVRegI(env);
1053 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1054 UInt amt = 32;
1055 addInstr(env, mk_iMOVsd_RR(src,dst) );
1056 addInstr(env, AMD64Instr_Sh64(Ash_SHL, amt, AMD64RM_Reg(dst)));
1057 addInstr(env, AMD64Instr_Sh64(Ash_SAR, amt, AMD64RM_Reg(dst)));
1058 return dst;
1059 }
sewardja3e98302005-02-01 15:55:05 +00001060//.. case Iop_8Uto16:
1061//.. case Iop_8Uto32:
1062//.. case Iop_16Uto32: {
1063//.. HReg dst = newVRegI(env);
1064//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1065//.. UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF;
1066//.. addInstr(env, mk_iMOVsd_RR(src,dst) );
1067//.. addInstr(env, X86Instr_Alu32R(Xalu_AND,
1068//.. X86RMI_Imm(mask), dst));
1069//.. return dst;
1070//.. }
1071//.. case Iop_8Sto16:
1072//.. case Iop_8Sto32:
1073//.. case Iop_16Sto32: {
1074//.. HReg dst = newVRegI(env);
1075//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1076//.. UInt amt = e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24;
1077//.. addInstr(env, mk_iMOVsd_RR(src,dst) );
1078//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, amt, X86RM_Reg(dst)));
1079//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, amt, X86RM_Reg(dst)));
1080//.. return dst;
1081//.. }
1082//.. case Iop_Not8:
1083//.. case Iop_Not16:
1084//.. case Iop_Not32: {
1085//.. HReg dst = newVRegI(env);
1086//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1087//.. addInstr(env, mk_iMOVsd_RR(src,dst) );
1088//.. addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(dst)));
1089//.. return dst;
1090//.. }
1091//.. case Iop_64HIto32: {
1092//.. HReg rHi, rLo;
1093//.. iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1094//.. return rHi; /* and abandon rLo .. poor wee thing :-) */
1095//.. }
1096//.. case Iop_64to32: {
1097//.. HReg rHi, rLo;
1098//.. iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1099//.. return rLo; /* similar stupid comment to the above ... */
1100//.. }
1101//.. case Iop_16HIto8:
1102//.. case Iop_32HIto16: {
1103//.. HReg dst = newVRegI(env);
1104//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1105//.. Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
1106//.. addInstr(env, mk_iMOVsd_RR(src,dst) );
1107//.. addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst)));
1108//.. return dst;
1109//.. }
1110//.. case Iop_1Uto32:
1111//.. case Iop_1Uto8: {
1112//.. HReg dst = newVRegI(env);
1113//.. X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1114//.. addInstr(env, X86Instr_Set32(cond,dst));
1115//.. return dst;
1116//.. }
1117//.. case Iop_1Sto8:
1118//.. case Iop_1Sto16:
1119//.. case Iop_1Sto32: {
1120//.. /* could do better than this, but for now ... */
1121//.. HReg dst = newVRegI(env);
1122//.. X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1123//.. addInstr(env, X86Instr_Set32(cond,dst));
1124//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(dst)));
1125//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(dst)));
1126//.. return dst;
1127//.. }
1128//.. case Iop_Ctz32: {
1129//.. /* Count trailing zeroes, implemented by x86 'bsfl' */
1130//.. HReg dst = newVRegI(env);
1131//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1132//.. addInstr(env, X86Instr_Bsfr32(True,src,dst));
1133//.. return dst;
1134//.. }
1135//.. case Iop_Clz32: {
1136//.. /* Count leading zeroes. Do 'bsrl' to establish the index
1137//.. of the highest set bit, and subtract that value from
1138//.. 31. */
1139//.. HReg tmp = newVRegI(env);
1140//.. HReg dst = newVRegI(env);
1141//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1142//.. addInstr(env, X86Instr_Bsfr32(False,src,tmp));
1143//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV,
1144//.. X86RMI_Imm(31), dst));
1145//.. addInstr(env, X86Instr_Alu32R(Xalu_SUB,
1146//.. X86RMI_Reg(tmp), dst));
1147//.. return dst;
1148//.. }
1149//..
1150//.. case Iop_128to32: {
1151//.. HReg dst = newVRegI(env);
1152//.. HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
1153//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
1154//.. sub_from_esp(env, 16);
1155//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
1156//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(esp0), dst ));
1157//.. add_to_esp(env, 16);
1158//.. return dst;
1159//.. }
1160//..
1161//.. case Iop_16to8:
1162//.. case Iop_32to8:
1163//.. case Iop_32to16:
1164//.. /* These are no-ops. */
1165//.. return iselIntExpr_R(env, e->Iex.Unop.arg);
sewardjf67eadf2005-02-03 03:53:52 +00001166
1167 default:
1168 break;
1169 }
1170 break;
1171 }
sewardj8258a8c2005-02-02 03:11:24 +00001172
1173 /* --------- GET --------- */
1174 case Iex_Get: {
1175 if (ty == Ity_I64) {
1176 HReg dst = newVRegI(env);
1177 addInstr(env, AMD64Instr_Alu64R(
1178 Aalu_MOV,
1179 AMD64RMI_Mem(
1180 AMD64AMode_IR(e->Iex.Get.offset,
1181 hregAMD64_RBP())),
1182 dst));
1183 return dst;
1184 }
1185 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32) {
1186 HReg dst = newVRegI(env);
1187 addInstr(env, AMD64Instr_LoadEX(
1188 ty==Ity_I8 ? 1 : (ty==Ity_I16 ? 2 : 4),
1189 False,
1190 AMD64AMode_IR(e->Iex.Get.offset,hregAMD64_RBP()),
1191 dst));
1192 return dst;
1193 }
1194 break;
1195 }
1196
sewardja3e98302005-02-01 15:55:05 +00001197//.. case Iex_GetI: {
1198//.. X86AMode* am
1199//.. = genGuestArrayOffset(
1200//.. env, e->Iex.GetI.descr,
1201//.. e->Iex.GetI.ix, e->Iex.GetI.bias );
1202//.. HReg dst = newVRegI(env);
1203//.. if (ty == Ity_I8) {
1204//.. addInstr(env, X86Instr_LoadEX( 1, False, am, dst ));
1205//.. return dst;
1206//.. }
1207//.. break;
1208//.. }
sewardj05b3b6a2005-02-04 01:44:33 +00001209
1210 /* --------- CCALL --------- */
1211 case Iex_CCall: {
1212 HReg dst = newVRegI(env);
sewardj7f039c42005-02-04 21:13:55 +00001213 vassert(ty == e->Iex.CCall.retty);
sewardj05b3b6a2005-02-04 01:44:33 +00001214
1215 /* be very restrictive for now. Only 64-bit ints allowed
1216 for args, and 64 bits for return type. */
1217 if (e->Iex.CCall.retty != Ity_I64)
1218 goto irreducible;
1219
sewardj7f039c42005-02-04 21:13:55 +00001220 /* Marshal args, do the call. */
sewardj05b3b6a2005-02-04 01:44:33 +00001221 doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
1222
1223 addInstr(env, mk_iMOVsd_RR(hregAMD64_RAX(), dst));
1224 return dst;
1225 }
1226
sewardj7f039c42005-02-04 21:13:55 +00001227 /* --------- LITERAL --------- */
1228 /* 64/32/16/8-bit literals */
1229 case Iex_Const:
1230 if (ty == Ity_I64) {
1231 HReg r = newVRegI(env);
1232 addInstr(env, AMD64Instr_Imm64(e->Iex.Const.con->Ico.U64, r));
1233 return r;
1234 } else {
1235 AMD64RMI* rmi = iselIntExpr_RMI ( env, e );
1236 HReg r = newVRegI(env);
1237 addInstr(env, AMD64Instr_Alu64R(Aalu_MOV, rmi, r));
1238 return r;
1239 }
sewardj05b3b6a2005-02-04 01:44:33 +00001240
1241 /* --------- MULTIPLEX --------- */
1242 case Iex_Mux0X: {
1243 if ((ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8)
1244 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
1245 HReg r8;
1246 HReg rX = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
1247 AMD64RM* r0 = iselIntExpr_RM(env, e->Iex.Mux0X.expr0);
1248 HReg dst = newVRegI(env);
1249 addInstr(env, mk_iMOVsd_RR(rX,dst));
1250 r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1251 addInstr(env, AMD64Instr_Test64(AMD64RI_Imm(0xFF), AMD64RM_Reg(r8)));
1252 addInstr(env, AMD64Instr_CMov64(Acc_Z,r0,dst));
1253 return dst;
1254 }
1255 break;
1256 }
sewardj8258a8c2005-02-02 03:11:24 +00001257
1258 default:
1259 break;
1260 } /* switch (e->tag) */
1261
1262 /* We get here if no pattern matched. */
1263 irreducible:
1264 ppIRExpr(e);
1265 vpanic("iselIntExpr_R(amd64): cannot reduce tree");
1266}
sewardj614b3fb2005-02-02 02:16:03 +00001267
1268
1269/*---------------------------------------------------------*/
1270/*--- ISEL: Integer expression auxiliaries ---*/
1271/*---------------------------------------------------------*/
1272
1273/* --------------------- AMODEs --------------------- */
1274
1275/* Return an AMode which computes the value of the specified
1276 expression, possibly also adding insns to the code list as a
1277 result. The expression may only be a 32-bit one.
1278*/
1279
sewardj8258a8c2005-02-02 03:11:24 +00001280static AMD64AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e )
1281{
1282 AMD64AMode* am = iselIntExpr_AMode_wrk(env, e);
1283 vassert(sane_AMode(am));
1284 return am;
1285}
1286
1287/* DO NOT CALL THIS DIRECTLY ! */
1288static AMD64AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e )
1289{
sewardj05b3b6a2005-02-04 01:44:33 +00001290 MatchInfo mi;
1291 DECLARE_PATTERN(p_complex);
sewardj8258a8c2005-02-02 03:11:24 +00001292 IRType ty = typeOfIRExpr(env->type_env,e);
1293 vassert(ty == Ity_I64);
1294
sewardj05b3b6a2005-02-04 01:44:33 +00001295 /* Add64( Add64(expr1, Shl64(expr2, imm8)), simm32 ) */
1296 /* bind0 bind1 bind2 bind3 */
1297 DEFINE_PATTERN(p_complex,
1298 binop( Iop_Add64,
1299 binop( Iop_Add64,
1300 bind(0),
1301 binop(Iop_Shl64, bind(1), bind(2))
1302 ),
1303 bind(3)
1304 )
1305 );
1306 if (matchIRExpr(&mi, p_complex, e)) {
1307 IRExpr* expr1 = mi.bindee[0];
1308 IRExpr* expr2 = mi.bindee[1];
1309 IRExpr* imm8 = mi.bindee[2];
1310 IRExpr* simm32 = mi.bindee[3];
1311 if (imm8->tag == Iex_Const
1312 && imm8->Iex.Const.con->tag == Ico_U8
1313 && imm8->Iex.Const.con->Ico.U8 < 4
1314 /* imm8 is OK, now check simm32 */
1315 && simm32->tag == Iex_Const
1316 && simm32->Iex.Const.con->tag == Ico_U64
1317 && fitsIn32Bits(simm32->Iex.Const.con->Ico.U64)) {
1318 UInt shift = imm8->Iex.Const.con->Ico.U8;
1319 UInt offset = (UInt)(0xFFFFFFFF & simm32->Iex.Const.con->Ico.U64);
1320 HReg r1 = iselIntExpr_R(env, expr1);
1321 HReg r2 = iselIntExpr_R(env, expr2);
1322 vassert(shift == 0 || shift == 1 || shift == 2 || shift == 3);
1323 return AMD64AMode_IRRS(offset, r1, r2, shift);
1324 }
1325 }
1326
sewardj8258a8c2005-02-02 03:11:24 +00001327 /* Add64(expr1, Shl64(expr2, imm)) */
1328 if (e->tag == Iex_Binop
1329 && e->Iex.Binop.op == Iop_Add64
1330 && e->Iex.Binop.arg2->tag == Iex_Binop
1331 && e->Iex.Binop.arg2->Iex.Binop.op == Iop_Shl64
1332 && e->Iex.Binop.arg2->Iex.Binop.arg2->tag == Iex_Const
1333 && e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8) {
1334 UInt shift = e->Iex.Binop.arg2->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
1335 if (shift == 1 || shift == 2 || shift == 3) {
1336 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1337 HReg r2 = iselIntExpr_R(env, e->Iex.Binop.arg2->Iex.Binop.arg1 );
1338 return AMD64AMode_IRRS(0, r1, r2, shift);
1339 }
1340 }
1341
1342 /* Add64(expr,i) */
1343 if (e->tag == Iex_Binop
1344 && e->Iex.Binop.op == Iop_Add64
1345 && e->Iex.Binop.arg2->tag == Iex_Const
1346 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
1347 && fitsIn32Bits(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)) {
1348 HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1349 return AMD64AMode_IR(
1350 (UInt)(0xFFFFFFFF & e->Iex.Binop.arg2->Iex.Const.con->Ico.U64),
1351 r1
1352 );
1353 }
1354
1355 /* Doesn't match anything in particular. Generate it into
1356 a register and use that. */
1357 {
1358 HReg r1 = iselIntExpr_R(env, e);
1359 return AMD64AMode_IR(0, r1);
1360 }
1361}
sewardj614b3fb2005-02-02 02:16:03 +00001362
1363
1364/* --------------------- RMIs --------------------- */
1365
1366/* Similarly, calculate an expression into an X86RMI operand. As with
1367 iselIntExpr_R, the expression can have type 32, 16 or 8 bits. */
1368
1369static AMD64RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e )
1370{
1371 AMD64RMI* rmi = iselIntExpr_RMI_wrk(env, e);
1372 /* sanity checks ... */
1373 switch (rmi->tag) {
1374 case Armi_Imm:
1375 return rmi;
1376 case Armi_Reg:
1377 vassert(hregClass(rmi->Armi.Reg.reg) == HRcInt64);
1378 vassert(hregIsVirtual(rmi->Armi.Reg.reg));
1379 return rmi;
1380 case Armi_Mem:
1381 vassert(sane_AMode(rmi->Armi.Mem.am));
1382 return rmi;
1383 default:
1384 vpanic("iselIntExpr_RMI: unknown amd64 RMI tag");
1385 }
1386}
1387
1388/* DO NOT CALL THIS DIRECTLY ! */
1389static AMD64RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e )
1390{
1391 IRType ty = typeOfIRExpr(env->type_env,e);
1392 vassert(ty == Ity_I64 || ty == Ity_I32
1393 || ty == Ity_I16 || ty == Ity_I8);
1394
1395 /* special case: immediate 64/32/16/8 */
1396 if (e->tag == Iex_Const) {
1397 switch (e->Iex.Const.con->tag) {
1398 case Ico_U64:
1399 if (fitsIn32Bits(e->Iex.Const.con->Ico.U64)) {
1400 return AMD64RMI_Imm(0xFFFFFFFF & e->Iex.Const.con->Ico.U64);
1401 }
1402 break;
1403 case Ico_U32:
1404 return AMD64RMI_Imm(e->Iex.Const.con->Ico.U32); break;
1405 case Ico_U16:
1406 return AMD64RMI_Imm(0xFFFF & e->Iex.Const.con->Ico.U16); break;
1407 case Ico_U8:
1408 return AMD64RMI_Imm(0xFF & e->Iex.Const.con->Ico.U8); break;
1409 default:
1410 vpanic("iselIntExpr_RMI.Iex_Const(amd64)");
1411 }
1412 }
1413
1414 /* special case: 64-bit GET */
1415 if (e->tag == Iex_Get && ty == Ity_I64) {
1416 return AMD64RMI_Mem(AMD64AMode_IR(e->Iex.Get.offset,
1417 hregAMD64_RBP()));
1418 }
1419
1420 /* special case: load from memory */
1421
1422 /* default case: calculate into a register and return that */
sewardj8258a8c2005-02-02 03:11:24 +00001423 {
1424 HReg r = iselIntExpr_R ( env, e );
1425 return AMD64RMI_Reg(r);
1426 }
sewardj614b3fb2005-02-02 02:16:03 +00001427}
1428
1429
sewardjf67eadf2005-02-03 03:53:52 +00001430/* --------------------- RIs --------------------- */
1431
1432/* Calculate an expression into an AMD64RI operand. As with
1433 iselIntExpr_R, the expression can have type 64, 32, 16 or 8
1434 bits. */
1435
1436static AMD64RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e )
1437{
1438 AMD64RI* ri = iselIntExpr_RI_wrk(env, e);
1439 /* sanity checks ... */
1440 switch (ri->tag) {
1441 case Ari_Imm:
1442 return ri;
1443 case Armi_Reg:
1444 vassert(hregClass(ri->Ari.Reg.reg) == HRcInt64);
1445 vassert(hregIsVirtual(ri->Ari.Reg.reg));
1446 return ri;
1447 default:
1448 vpanic("iselIntExpr_RI: unknown amd64 RI tag");
1449 }
1450}
1451
1452/* DO NOT CALL THIS DIRECTLY ! */
1453static AMD64RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
1454{
1455 IRType ty = typeOfIRExpr(env->type_env,e);
1456 vassert(ty == Ity_I64 || ty == Ity_I32
1457 || ty == Ity_I16 || ty == Ity_I8);
1458
1459 /* special case: immediate */
1460 if (e->tag == Iex_Const) {
1461 switch (e->Iex.Const.con->tag) {
1462 case Ico_U64:
1463 if (fitsIn32Bits(e->Iex.Const.con->Ico.U64)) {
1464 return AMD64RI_Imm(0xFFFFFFFF & e->Iex.Const.con->Ico.U64);
1465 }
1466 break;
1467 case Ico_U32:
1468 return AMD64RI_Imm(e->Iex.Const.con->Ico.U32);
1469 case Ico_U16:
1470 return AMD64RI_Imm(0xFFFF & e->Iex.Const.con->Ico.U16);
1471 case Ico_U8:
1472 return AMD64RI_Imm(0xFF & e->Iex.Const.con->Ico.U8);
1473 default:
1474 vpanic("iselIntExpr_RMI.Iex_Const(amd64)");
1475 }
1476 }
1477
1478 /* default case: calculate into a register and return that */
1479 {
1480 HReg r = iselIntExpr_R ( env, e );
1481 return AMD64RI_Reg(r);
1482 }
1483}
1484
1485
sewardj05b3b6a2005-02-04 01:44:33 +00001486/* --------------------- RMs --------------------- */
1487
1488/* Similarly, calculate an expression into an AMD64RM operand. As
1489 with iselIntExpr_R, the expression can have type 64, 32, 16 or 8
1490 bits. */
1491
1492static AMD64RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e )
1493{
1494 AMD64RM* rm = iselIntExpr_RM_wrk(env, e);
1495 /* sanity checks ... */
1496 switch (rm->tag) {
1497 case Arm_Reg:
1498 vassert(hregClass(rm->Arm.Reg.reg) == HRcInt64);
1499 vassert(hregIsVirtual(rm->Arm.Reg.reg));
1500 return rm;
1501 case Arm_Mem:
1502 vassert(sane_AMode(rm->Arm.Mem.am));
1503 return rm;
1504 default:
1505 vpanic("iselIntExpr_RM: unknown amd64 RM tag");
1506 }
1507}
1508
1509/* DO NOT CALL THIS DIRECTLY ! */
1510static AMD64RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e )
1511{
1512 IRType ty = typeOfIRExpr(env->type_env,e);
1513 vassert(ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
1514
1515 /* special case: 64-bit GET */
1516 if (e->tag == Iex_Get && ty == Ity_I64) {
1517 return AMD64RM_Mem(AMD64AMode_IR(e->Iex.Get.offset,
1518 hregAMD64_RBP()));
1519 }
1520
1521 /* special case: load from memory */
1522
1523 /* default case: calculate into a register and return that */
1524 {
1525 HReg r = iselIntExpr_R ( env, e );
1526 return AMD64RM_Reg(r);
1527 }
1528}
1529
1530
1531/* --------------------- CONDCODE --------------------- */
1532
1533/* Generate code to evaluated a bit-typed expression, returning the
1534 condition code which would correspond when the expression would
1535 notionally have returned 1. */
1536
1537static AMD64CondCode iselCondCode ( ISelEnv* env, IRExpr* e )
1538{
1539 /* Uh, there's nothing we can sanity check here, unfortunately. */
1540 return iselCondCode_wrk(env,e);
1541}
1542
1543/* DO NOT CALL THIS DIRECTLY ! */
1544static AMD64CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
1545{
sewardja3e98302005-02-01 15:55:05 +00001546//.. MatchInfo mi;
1547//.. DECLARE_PATTERN(p_32to1);
1548//.. DECLARE_PATTERN(p_1Uto32_then_32to1);
1549//.. DECLARE_PATTERN(p_1Sto32_then_32to1);
sewardj05b3b6a2005-02-04 01:44:33 +00001550
1551 vassert(e);
1552 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
1553
sewardja3e98302005-02-01 15:55:05 +00001554//.. /* Constant 1:Bit */
1555//.. if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
1556//.. HReg r;
1557//.. vassert(e->Iex.Const.con->tag == Ico_U1);
1558//.. r = newVRegI(env);
1559//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV,X86RMI_Imm(0),r));
1560//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(r),r));
1561//.. return Xcc_Z;
1562//.. }
1563//..
1564//.. /* Not1(...) */
1565//.. if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
1566//.. /* Generate code for the arg, and negate the test condition */
1567//.. return 1 ^ iselCondCode(env, e->Iex.Unop.arg);
1568//.. }
1569//..
1570//.. /* 32to1(1Uto32(expr1)) -- the casts are pointless, ignore them */
1571//.. DEFINE_PATTERN(p_1Uto32_then_32to1,
1572//.. unop(Iop_32to1,unop(Iop_1Uto32,bind(0))));
1573//.. if (matchIRExpr(&mi,p_1Uto32_then_32to1,e)) {
1574//.. IRExpr* expr1 = mi.bindee[0];
1575//.. return iselCondCode(env, expr1);
1576//.. }
1577//..
1578//.. /* 32to1(1Sto32(expr1)) -- the casts are pointless, ignore them */
1579//.. DEFINE_PATTERN(p_1Sto32_then_32to1,
1580//.. unop(Iop_32to1,unop(Iop_1Sto32,bind(0))));
1581//.. if (matchIRExpr(&mi,p_1Sto32_then_32to1,e)) {
1582//.. IRExpr* expr1 = mi.bindee[0];
1583//.. return iselCondCode(env, expr1);
1584//.. }
1585//..
1586//.. /* pattern: 32to1(expr32) */
1587//.. DEFINE_PATTERN(p_32to1,
1588//.. unop(Iop_32to1,bind(0))
1589//.. );
1590//.. if (matchIRExpr(&mi,p_32to1,e)) {
1591//.. X86RM* rm = iselIntExpr_RM(env, mi.bindee[0]);
1592//.. addInstr(env, X86Instr_Test32(X86RI_Imm(1),rm));
1593//.. return Xcc_NZ;
1594//.. }
1595//..
1596//.. /* CmpEQ8 / CmpNE8 */
1597//.. if (e->tag == Iex_Binop
1598//.. && (e->Iex.Binop.op == Iop_CmpEQ8
1599//.. || e->Iex.Binop.op == Iop_CmpNE8)) {
1600//.. HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1601//.. X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1602//.. HReg r = newVRegI(env);
1603//.. addInstr(env, mk_iMOVsd_RR(r1,r));
1604//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r));
1605//.. addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(0xFF),r));
1606//.. switch (e->Iex.Binop.op) {
1607//.. case Iop_CmpEQ8: return Xcc_Z;
1608//.. case Iop_CmpNE8: return Xcc_NZ;
1609//.. default: vpanic("iselCondCode(x86): CmpXX8");
1610//.. }
1611//.. }
1612//..
1613//.. /* CmpEQ16 / CmpNE16 */
1614//.. if (e->tag == Iex_Binop
1615//.. && (e->Iex.Binop.op == Iop_CmpEQ16
1616//.. || e->Iex.Binop.op == Iop_CmpNE16)) {
1617//.. HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1618//.. X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1619//.. HReg r = newVRegI(env);
1620//.. addInstr(env, mk_iMOVsd_RR(r1,r));
1621//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,rmi2,r));
1622//.. addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(0xFFFF),r));
1623//.. switch (e->Iex.Binop.op) {
1624//.. case Iop_CmpEQ16: return Xcc_Z;
1625//.. case Iop_CmpNE16: return Xcc_NZ;
1626//.. default: vpanic("iselCondCode(x86): CmpXX16");
1627//.. }
1628//.. }
1629//..
1630//.. /* CmpNE32(1Sto32(b), 0) ==> b */
1631//.. {
1632//.. DECLARE_PATTERN(p_CmpNE32_1Sto32);
1633//.. DEFINE_PATTERN(
1634//.. p_CmpNE32_1Sto32,
1635//.. binop(Iop_CmpNE32, unop(Iop_1Sto32,bind(0)), mkU32(0)));
1636//.. if (matchIRExpr(&mi, p_CmpNE32_1Sto32, e)) {
1637//.. return iselCondCode(env, mi.bindee[0]);
1638//.. }
1639//.. }
1640//..
1641//.. /* Cmp*32*(x,y) */
1642//.. if (e->tag == Iex_Binop
1643//.. && (e->Iex.Binop.op == Iop_CmpEQ32
1644//.. || e->Iex.Binop.op == Iop_CmpNE32
1645//.. || e->Iex.Binop.op == Iop_CmpLT32S
1646//.. || e->Iex.Binop.op == Iop_CmpLT32U
1647//.. || e->Iex.Binop.op == Iop_CmpLE32S
1648//.. || e->Iex.Binop.op == Iop_CmpLE32U)) {
1649//.. HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
1650//.. X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
1651//.. addInstr(env, X86Instr_Alu32R(Xalu_CMP,rmi2,r1));
1652//.. switch (e->Iex.Binop.op) {
1653//.. case Iop_CmpEQ32: return Xcc_Z;
1654//.. case Iop_CmpNE32: return Xcc_NZ;
1655//.. case Iop_CmpLT32S: return Xcc_L;
1656//.. case Iop_CmpLT32U: return Xcc_B;
1657//.. case Iop_CmpLE32S: return Xcc_LE;
1658//.. case Iop_CmpLE32U: return Xcc_BE;
1659//.. default: vpanic("iselCondCode(x86): CmpXX32");
1660//.. }
1661//.. }
1662//..
1663//.. /* CmpNE64(1Sto64(b), 0) ==> b */
1664//.. {
1665//.. DECLARE_PATTERN(p_CmpNE64_1Sto64);
1666//.. DEFINE_PATTERN(
1667//.. p_CmpNE64_1Sto64,
1668//.. binop(Iop_CmpNE64, unop(Iop_1Sto64,bind(0)), mkU64(0)));
1669//.. if (matchIRExpr(&mi, p_CmpNE64_1Sto64, e)) {
1670//.. return iselCondCode(env, mi.bindee[0]);
1671//.. }
1672//.. }
1673//..
1674//.. /* CmpNE64(x, 0) */
1675//.. {
1676//.. DECLARE_PATTERN(p_CmpNE64_x_zero);
1677//.. DEFINE_PATTERN(
1678//.. p_CmpNE64_x_zero,
1679//.. binop(Iop_CmpNE64, bind(0), mkU64(0)) );
1680//.. if (matchIRExpr(&mi, p_CmpNE64_x_zero, e)) {
1681//.. HReg hi, lo;
1682//.. IRExpr* x = mi.bindee[0];
1683//.. HReg tmp = newVRegI(env);
1684//.. iselInt64Expr( &hi, &lo, env, x );
1685//.. addInstr(env, mk_iMOVsd_RR(hi, tmp));
1686//.. addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(lo), tmp));
1687//.. return Xcc_NZ;
1688//.. }
1689//.. }
1690//..
1691//.. /* CmpNE64 */
1692//.. if (e->tag == Iex_Binop
1693//.. && e->Iex.Binop.op == Iop_CmpNE64) {
1694//.. HReg hi1, hi2, lo1, lo2;
1695//.. HReg tHi = newVRegI(env);
1696//.. HReg tLo = newVRegI(env);
1697//.. iselInt64Expr( &hi1, &lo1, env, e->Iex.Binop.arg1 );
1698//.. iselInt64Expr( &hi2, &lo2, env, e->Iex.Binop.arg2 );
1699//.. addInstr(env, mk_iMOVsd_RR(hi1, tHi));
1700//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(hi2), tHi));
1701//.. addInstr(env, mk_iMOVsd_RR(lo1, tLo));
1702//.. addInstr(env, X86Instr_Alu32R(Xalu_XOR,X86RMI_Reg(lo2), tLo));
1703//.. addInstr(env, X86Instr_Alu32R(Xalu_OR,X86RMI_Reg(tHi), tLo));
1704//.. switch (e->Iex.Binop.op) {
1705//.. case Iop_CmpNE64: return Xcc_NZ;
1706//.. default: vpanic("iselCondCode(x86): CmpXX64");
1707//.. }
1708//.. }
1709//..
1710//.. /* var */
1711//.. if (e->tag == Iex_Tmp) {
1712//.. HReg r32 = lookupIRTemp(env, e->Iex.Tmp.tmp);
1713//.. HReg dst = newVRegI(env);
1714//.. addInstr(env, mk_iMOVsd_RR(r32,dst));
1715//.. addInstr(env, X86Instr_Alu32R(Xalu_AND,X86RMI_Imm(1),dst));
1716//.. return Xcc_NZ;
1717//.. }
sewardj05b3b6a2005-02-04 01:44:33 +00001718
1719 ppIRExpr(e);
1720 vpanic("iselCondCode(amd64)");
1721}
1722
1723
sewardja3e98302005-02-01 15:55:05 +00001724//.. /*---------------------------------------------------------*/
1725//.. /*--- ISEL: Integer expressions (64 bit) ---*/
1726//.. /*---------------------------------------------------------*/
1727//..
1728//.. /* Compute a 64-bit value into a register pair, which is returned as
1729//.. the first two parameters. As with iselIntExpr_R, these may be
1730//.. either real or virtual regs; in any case they must not be changed
1731//.. by subsequent code emitted by the caller. */
1732//..
1733//.. static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1734//.. {
1735//.. iselInt64Expr_wrk(rHi, rLo, env, e);
1736//.. # if 0
1737//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1738//.. # endif
1739//.. vassert(hregClass(*rHi) == HRcInt32);
1740//.. vassert(hregIsVirtual(*rHi));
1741//.. vassert(hregClass(*rLo) == HRcInt32);
1742//.. vassert(hregIsVirtual(*rLo));
1743//.. }
1744//..
1745//.. /* DO NOT CALL THIS DIRECTLY ! */
1746//.. static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1747//.. {
1748//.. HWord fn = 0; /* helper fn for most SIMD64 stuff */
1749//.. vassert(e);
1750//.. vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
1751//..
1752//.. /* 64-bit literal */
1753//.. if (e->tag == Iex_Const) {
1754//.. ULong w64 = e->Iex.Const.con->Ico.U64;
1755//.. UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
1756//.. UInt wLo = ((UInt)w64) & 0xFFFFFFFF;
1757//.. HReg tLo = newVRegI(env);
1758//.. HReg tHi = newVRegI(env);
1759//.. vassert(e->Iex.Const.con->tag == Ico_U64);
1760//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wHi), tHi));
1761//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(wLo), tLo));
1762//.. *rHi = tHi;
1763//.. *rLo = tLo;
1764//.. return;
1765//.. }
1766//..
1767//.. /* read 64-bit IRTemp */
1768//.. if (e->tag == Iex_Tmp) {
1769//.. lookupIRTemp64( rHi, rLo, env, e->Iex.Tmp.tmp);
1770//.. return;
1771//.. }
1772//..
1773//.. /* 64-bit load */
1774//.. if (e->tag == Iex_LDle) {
1775//.. HReg tLo, tHi;
1776//.. X86AMode *am0, *am4;
1777//.. vassert(e->Iex.LDle.ty == Ity_I64);
1778//.. tLo = newVRegI(env);
1779//.. tHi = newVRegI(env);
1780//.. am0 = iselIntExpr_AMode(env, e->Iex.LDle.addr);
1781//.. am4 = advance4(am0);
1782//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am0), tLo ));
1783//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi ));
1784//.. *rHi = tHi;
1785//.. *rLo = tLo;
1786//.. return;
1787//.. }
1788//..
1789//.. /* 64-bit GET */
1790//.. if (e->tag == Iex_Get) {
1791//.. X86AMode* am = X86AMode_IR(e->Iex.Get.offset, hregX86_EBP());
1792//.. X86AMode* am4 = advance4(am);
1793//.. HReg tLo = newVRegI(env);
1794//.. HReg tHi = newVRegI(env);
1795//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am), tLo ));
1796//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi ));
1797//.. *rHi = tHi;
1798//.. *rLo = tLo;
1799//.. return;
1800//.. }
1801//..
1802//.. /* 64-bit GETI */
1803//.. if (e->tag == Iex_GetI) {
1804//.. X86AMode* am
1805//.. = genGuestArrayOffset( env, e->Iex.GetI.descr,
1806//.. e->Iex.GetI.ix, e->Iex.GetI.bias );
1807//.. X86AMode* am4 = advance4(am);
1808//.. HReg tLo = newVRegI(env);
1809//.. HReg tHi = newVRegI(env);
1810//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am), tLo ));
1811//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(am4), tHi ));
1812//.. *rHi = tHi;
1813//.. *rLo = tLo;
1814//.. return;
1815//.. }
1816//..
1817//.. /* 64-bit Mux0X */
1818//.. if (e->tag == Iex_Mux0X) {
1819//.. HReg e0Lo, e0Hi, eXLo, eXHi, r8;
1820//.. HReg tLo = newVRegI(env);
1821//.. HReg tHi = newVRegI(env);
1822//.. iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0);
1823//.. iselInt64Expr(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX);
1824//.. addInstr(env, mk_iMOVsd_RR(eXHi, tHi));
1825//.. addInstr(env, mk_iMOVsd_RR(eXLo, tLo));
1826//.. r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1827//.. addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
1828//.. /* This assumes the first cmov32 doesn't trash the condition
1829//.. codes, so they are still available for the second cmov32 */
1830//.. addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Reg(e0Hi),tHi));
1831//.. addInstr(env, X86Instr_CMov32(Xcc_Z,X86RM_Reg(e0Lo),tLo));
1832//.. *rHi = tHi;
1833//.. *rLo = tLo;
1834//.. return;
1835//.. }
1836//..
1837//.. /* --------- BINARY ops --------- */
1838//.. if (e->tag == Iex_Binop) {
1839//.. switch (e->Iex.Binop.op) {
1840//.. /* 32 x 32 -> 64 multiply */
1841//.. case Iop_MullU32:
1842//.. case Iop_MullS32: {
1843//.. /* get one operand into %eax, and the other into a R/M.
1844//.. Need to make an educated guess about which is better in
1845//.. which. */
1846//.. HReg tLo = newVRegI(env);
1847//.. HReg tHi = newVRegI(env);
1848//.. Bool syned = e->Iex.Binop.op == Iop_MullS32;
1849//.. X86RM* rmLeft = iselIntExpr_RM(env, e->Iex.Binop.arg1);
1850//.. HReg rRight = iselIntExpr_R(env, e->Iex.Binop.arg2);
1851//.. addInstr(env, mk_iMOVsd_RR(rRight, hregX86_EAX()));
1852//.. addInstr(env, X86Instr_MulL(syned, Xss_32, rmLeft));
1853//.. /* Result is now in EDX:EAX. Tell the caller. */
1854//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
1855//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
1856//.. *rHi = tHi;
1857//.. *rLo = tLo;
1858//.. return;
1859//.. }
1860//..
1861//.. /* 64 x 32 -> (32(rem),32(div)) division */
1862//.. case Iop_DivModU64to32:
1863//.. case Iop_DivModS64to32: {
1864//.. /* Get the 64-bit operand into edx:eax, and the other into
1865//.. any old R/M. */
1866//.. HReg sHi, sLo;
1867//.. HReg tLo = newVRegI(env);
1868//.. HReg tHi = newVRegI(env);
1869//.. Bool syned = e->Iex.Binop.op == Iop_DivModS64to32;
1870//.. X86RM* rmRight = iselIntExpr_RM(env, e->Iex.Binop.arg2);
1871//.. iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
1872//.. addInstr(env, mk_iMOVsd_RR(sHi, hregX86_EDX()));
1873//.. addInstr(env, mk_iMOVsd_RR(sLo, hregX86_EAX()));
1874//.. addInstr(env, X86Instr_Div(syned, Xss_32, rmRight));
1875//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
1876//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
1877//.. *rHi = tHi;
1878//.. *rLo = tLo;
1879//.. return;
1880//.. }
1881//..
1882//.. /* Or64/And64/Xor64 */
1883//.. case Iop_Or64:
1884//.. case Iop_And64:
1885//.. case Iop_Xor64: {
1886//.. HReg xLo, xHi, yLo, yHi;
1887//.. HReg tLo = newVRegI(env);
1888//.. HReg tHi = newVRegI(env);
1889//.. X86AluOp op = e->Iex.Binop.op==Iop_Or64 ? Xalu_OR
1890//.. : e->Iex.Binop.op==Iop_And64 ? Xalu_AND
1891//.. : Xalu_XOR;
1892//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
1893//.. addInstr(env, mk_iMOVsd_RR(xHi, tHi));
1894//.. addInstr(env, mk_iMOVsd_RR(xLo, tLo));
1895//.. iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
1896//.. addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yHi), tHi));
1897//.. addInstr(env, X86Instr_Alu32R(op, X86RMI_Reg(yLo), tLo));
1898//.. *rHi = tHi;
1899//.. *rLo = tLo;
1900//.. return;
1901//.. }
1902//..
1903//.. /* Add64/Sub64 */
1904//.. case Iop_Add64:
1905//.. case Iop_Sub64: {
1906//.. HReg xLo, xHi, yLo, yHi;
1907//.. HReg tLo = newVRegI(env);
1908//.. HReg tHi = newVRegI(env);
1909//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
1910//.. addInstr(env, mk_iMOVsd_RR(xHi, tHi));
1911//.. addInstr(env, mk_iMOVsd_RR(xLo, tLo));
1912//.. iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
1913//.. if (e->Iex.Binop.op==Iop_Add64) {
1914//.. addInstr(env, X86Instr_Alu32R(Xalu_ADD, X86RMI_Reg(yLo), tLo));
1915//.. addInstr(env, X86Instr_Alu32R(Xalu_ADC, X86RMI_Reg(yHi), tHi));
1916//.. } else {
1917//.. addInstr(env, X86Instr_Alu32R(Xalu_SUB, X86RMI_Reg(yLo), tLo));
1918//.. addInstr(env, X86Instr_Alu32R(Xalu_SBB, X86RMI_Reg(yHi), tHi));
1919//.. }
1920//.. *rHi = tHi;
1921//.. *rLo = tLo;
1922//.. return;
1923//.. }
1924//..
1925//.. /* 32HLto64(e1,e2) */
1926//.. case Iop_32HLto64:
1927//.. *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
1928//.. *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
1929//.. return;
1930//..
1931//.. /* 64-bit shifts */
1932//.. case Iop_Shl64: {
1933//.. /* We use the same ingenious scheme as gcc. Put the value
1934//.. to be shifted into %hi:%lo, and the shift amount into
1935//.. %cl. Then (dsts on right, a la ATT syntax):
1936//..
1937//.. shldl %cl, %lo, %hi -- make %hi be right for the
1938//.. -- shift amt %cl % 32
1939//.. shll %cl, %lo -- make %lo be right for the
1940//.. -- shift amt %cl % 32
1941//..
1942//.. Now, if (shift amount % 64) is in the range 32 .. 63,
1943//.. we have to do a fixup, which puts the result low half
1944//.. into the result high half, and zeroes the low half:
1945//..
1946//.. testl $32, %ecx
1947//..
1948//.. cmovnz %lo, %hi
1949//.. movl $0, %tmp -- sigh; need yet another reg
1950//.. cmovnz %tmp, %lo
1951//.. */
1952//.. HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
1953//.. tLo = newVRegI(env);
1954//.. tHi = newVRegI(env);
1955//.. tTemp = newVRegI(env);
1956//.. rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
1957//.. iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
1958//.. addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX()));
1959//.. addInstr(env, mk_iMOVsd_RR(sHi, tHi));
1960//.. addInstr(env, mk_iMOVsd_RR(sLo, tLo));
1961//.. /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo
1962//.. and those regs are legitimately modifiable. */
1963//.. addInstr(env, X86Instr_Sh3232(Xsh_SHL, 0/*%cl*/, tLo, tHi));
1964//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 0/*%cl*/, X86RM_Reg(tLo)));
1965//.. addInstr(env, X86Instr_Test32(X86RI_Imm(32),
1966//.. X86RM_Reg(hregX86_ECX())));
1967//.. addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tLo), tHi));
1968//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
1969//.. addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tLo));
1970//.. *rHi = tHi;
1971//.. *rLo = tLo;
1972//.. return;
1973//.. }
1974//..
1975//.. case Iop_Shr64: {
1976//.. /* We use the same ingenious scheme as gcc. Put the value
1977//.. to be shifted into %hi:%lo, and the shift amount into
1978//.. %cl. Then:
1979//..
1980//.. shrdl %cl, %hi, %lo -- make %lo be right for the
1981//.. -- shift amt %cl % 32
1982//.. shrl %cl, %hi -- make %hi be right for the
1983//.. -- shift amt %cl % 32
1984//..
1985//.. Now, if (shift amount % 64) is in the range 32 .. 63,
1986//.. we have to do a fixup, which puts the result high half
1987//.. into the result low half, and zeroes the high half:
1988//..
1989//.. testl $32, %ecx
1990//..
1991//.. cmovnz %hi, %lo
1992//.. movl $0, %tmp -- sigh; need yet another reg
1993//.. cmovnz %tmp, %hi
1994//.. */
1995//.. HReg rAmt, sHi, sLo, tHi, tLo, tTemp;
1996//.. tLo = newVRegI(env);
1997//.. tHi = newVRegI(env);
1998//.. tTemp = newVRegI(env);
1999//.. rAmt = iselIntExpr_R(env, e->Iex.Binop.arg2);
2000//.. iselInt64Expr(&sHi,&sLo, env, e->Iex.Binop.arg1);
2001//.. addInstr(env, mk_iMOVsd_RR(rAmt, hregX86_ECX()));
2002//.. addInstr(env, mk_iMOVsd_RR(sHi, tHi));
2003//.. addInstr(env, mk_iMOVsd_RR(sLo, tLo));
2004//.. /* Ok. Now shift amt is in %ecx, and value is in tHi/tLo
2005//.. and those regs are legitimately modifiable. */
2006//.. addInstr(env, X86Instr_Sh3232(Xsh_SHR, 0/*%cl*/, tHi, tLo));
2007//.. addInstr(env, X86Instr_Sh32(Xsh_SHR, 0/*%cl*/, X86RM_Reg(tHi)));
2008//.. addInstr(env, X86Instr_Test32(X86RI_Imm(32),
2009//.. X86RM_Reg(hregX86_ECX())));
2010//.. addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tHi), tLo));
2011//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tTemp));
2012//.. addInstr(env, X86Instr_CMov32(Xcc_NZ, X86RM_Reg(tTemp), tHi));
2013//.. *rHi = tHi;
2014//.. *rLo = tLo;
2015//.. return;
2016//.. }
2017//..
2018//.. /* F64 -> I64 */
2019//.. /* Sigh, this is an almost exact copy of the F64 -> I32/I16
2020//.. case. Unfortunately I see no easy way to avoid the
2021//.. duplication. */
2022//.. case Iop_F64toI64: {
2023//.. HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
2024//.. HReg tLo = newVRegI(env);
2025//.. HReg tHi = newVRegI(env);
2026//..
2027//.. /* Used several times ... */
2028//.. /* Careful ... this sharing is only safe because
2029//.. zero_esp/four_esp do not hold any registers which the
2030//.. register allocator could attempt to swizzle later. */
2031//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
2032//.. X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
2033//..
2034//.. /* rf now holds the value to be converted, and rrm holds
2035//.. the rounding mode value, encoded as per the
2036//.. IRRoundingMode enum. The first thing to do is set the
2037//.. FPU's rounding mode accordingly. */
2038//..
2039//.. /* Create a space for the format conversion. */
2040//.. /* subl $8, %esp */
2041//.. sub_from_esp(env, 8);
2042//..
2043//.. /* Set host rounding mode */
2044//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2045//..
2046//.. /* gistll %rf, 0(%esp) */
2047//.. addInstr(env, X86Instr_FpLdStI(False/*store*/, 8, rf, zero_esp));
2048//..
2049//.. /* movl 0(%esp), %dstLo */
2050//.. /* movl 4(%esp), %dstHi */
2051//.. addInstr(env, X86Instr_Alu32R(
2052//.. Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
2053//.. addInstr(env, X86Instr_Alu32R(
2054//.. Xalu_MOV, X86RMI_Mem(four_esp), tHi));
2055//..
2056//.. /* Restore default FPU rounding. */
2057//.. set_FPU_rounding_default( env );
2058//..
2059//.. /* addl $8, %esp */
2060//.. add_to_esp(env, 8);
2061//..
2062//.. *rHi = tHi;
2063//.. *rLo = tLo;
2064//.. return;
2065//.. }
2066//..
2067//.. case Iop_Add8x8:
2068//.. fn = (HWord)h_generic_calc_Add8x8; goto binnish;
2069//.. case Iop_Add16x4:
2070//.. fn = (HWord)h_generic_calc_Add16x4; goto binnish;
2071//.. case Iop_Add32x2:
2072//.. fn = (HWord)h_generic_calc_Add32x2; goto binnish;
2073//..
2074//.. case Iop_Avg8Ux8:
2075//.. fn = (HWord)h_generic_calc_Avg8Ux8; goto binnish;
2076//.. case Iop_Avg16Ux4:
2077//.. fn = (HWord)h_generic_calc_Avg16Ux4; goto binnish;
2078//..
2079//.. case Iop_CmpEQ8x8:
2080//.. fn = (HWord)h_generic_calc_CmpEQ8x8; goto binnish;
2081//.. case Iop_CmpEQ16x4:
2082//.. fn = (HWord)h_generic_calc_CmpEQ16x4; goto binnish;
2083//.. case Iop_CmpEQ32x2:
2084//.. fn = (HWord)h_generic_calc_CmpEQ32x2; goto binnish;
2085//..
2086//.. case Iop_CmpGT8Sx8:
2087//.. fn = (HWord)h_generic_calc_CmpGT8Sx8; goto binnish;
2088//.. case Iop_CmpGT16Sx4:
2089//.. fn = (HWord)h_generic_calc_CmpGT16Sx4; goto binnish;
2090//.. case Iop_CmpGT32Sx2:
2091//.. fn = (HWord)h_generic_calc_CmpGT32Sx2; goto binnish;
2092//..
2093//.. case Iop_InterleaveHI8x8:
2094//.. fn = (HWord)h_generic_calc_InterleaveHI8x8; goto binnish;
2095//.. case Iop_InterleaveLO8x8:
2096//.. fn = (HWord)h_generic_calc_InterleaveLO8x8; goto binnish;
2097//.. case Iop_InterleaveHI16x4:
2098//.. fn = (HWord)h_generic_calc_InterleaveHI16x4; goto binnish;
2099//.. case Iop_InterleaveLO16x4:
2100//.. fn = (HWord)h_generic_calc_InterleaveLO16x4; goto binnish;
2101//.. case Iop_InterleaveHI32x2:
2102//.. fn = (HWord)h_generic_calc_InterleaveHI32x2; goto binnish;
2103//.. case Iop_InterleaveLO32x2:
2104//.. fn = (HWord)h_generic_calc_InterleaveLO32x2; goto binnish;
2105//..
2106//.. case Iop_Max8Ux8:
2107//.. fn = (HWord)h_generic_calc_Max8Ux8; goto binnish;
2108//.. case Iop_Max16Sx4:
2109//.. fn = (HWord)h_generic_calc_Max16Sx4; goto binnish;
2110//.. case Iop_Min8Ux8:
2111//.. fn = (HWord)h_generic_calc_Min8Ux8; goto binnish;
2112//.. case Iop_Min16Sx4:
2113//.. fn = (HWord)h_generic_calc_Min16Sx4; goto binnish;
2114//..
2115//.. case Iop_Mul16x4:
2116//.. fn = (HWord)h_generic_calc_Mul16x4; goto binnish;
2117//.. case Iop_MulHi16Sx4:
2118//.. fn = (HWord)h_generic_calc_MulHi16Sx4; goto binnish;
2119//.. case Iop_MulHi16Ux4:
2120//.. fn = (HWord)h_generic_calc_MulHi16Ux4; goto binnish;
2121//..
2122//.. case Iop_QAdd8Sx8:
2123//.. fn = (HWord)h_generic_calc_QAdd8Sx8; goto binnish;
2124//.. case Iop_QAdd16Sx4:
2125//.. fn = (HWord)h_generic_calc_QAdd16Sx4; goto binnish;
2126//.. case Iop_QAdd8Ux8:
2127//.. fn = (HWord)h_generic_calc_QAdd8Ux8; goto binnish;
2128//.. case Iop_QAdd16Ux4:
2129//.. fn = (HWord)h_generic_calc_QAdd16Ux4; goto binnish;
2130//..
2131//.. case Iop_QNarrow32Sx2:
2132//.. fn = (HWord)h_generic_calc_QNarrow32Sx2; goto binnish;
2133//.. case Iop_QNarrow16Sx4:
2134//.. fn = (HWord)h_generic_calc_QNarrow16Sx4; goto binnish;
2135//.. case Iop_QNarrow16Ux4:
2136//.. fn = (HWord)h_generic_calc_QNarrow16Ux4; goto binnish;
2137//..
2138//.. case Iop_QSub8Sx8:
2139//.. fn = (HWord)h_generic_calc_QSub8Sx8; goto binnish;
2140//.. case Iop_QSub16Sx4:
2141//.. fn = (HWord)h_generic_calc_QSub16Sx4; goto binnish;
2142//.. case Iop_QSub8Ux8:
2143//.. fn = (HWord)h_generic_calc_QSub8Ux8; goto binnish;
2144//.. case Iop_QSub16Ux4:
2145//.. fn = (HWord)h_generic_calc_QSub16Ux4; goto binnish;
2146//..
2147//.. case Iop_Sub8x8:
2148//.. fn = (HWord)h_generic_calc_Sub8x8; goto binnish;
2149//.. case Iop_Sub16x4:
2150//.. fn = (HWord)h_generic_calc_Sub16x4; goto binnish;
2151//.. case Iop_Sub32x2:
2152//.. fn = (HWord)h_generic_calc_Sub32x2; goto binnish;
2153//..
2154//.. binnish: {
2155//.. /* Note: the following assumes all helpers are of
2156//.. signature
2157//.. ULong fn ( ULong, ULong ), and they are
2158//.. not marked as regparm functions.
2159//.. */
2160//.. HReg xLo, xHi, yLo, yHi;
2161//.. HReg tLo = newVRegI(env);
2162//.. HReg tHi = newVRegI(env);
2163//.. iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2164//.. addInstr(env, X86Instr_Push(X86RMI_Reg(yHi)));
2165//.. addInstr(env, X86Instr_Push(X86RMI_Reg(yLo)));
2166//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2167//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
2168//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
2169//.. addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn, 0 ));
2170//.. add_to_esp(env, 4*4);
2171//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2172//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2173//.. *rHi = tHi;
2174//.. *rLo = tLo;
2175//.. return;
2176//.. }
2177//..
2178//.. case Iop_ShlN32x2:
2179//.. fn = (HWord)h_generic_calc_ShlN32x2; goto shifty;
2180//.. case Iop_ShlN16x4:
2181//.. fn = (HWord)h_generic_calc_ShlN16x4; goto shifty;
2182//.. case Iop_ShrN32x2:
2183//.. fn = (HWord)h_generic_calc_ShrN32x2; goto shifty;
2184//.. case Iop_ShrN16x4:
2185//.. fn = (HWord)h_generic_calc_ShrN16x4; goto shifty;
2186//.. case Iop_SarN32x2:
2187//.. fn = (HWord)h_generic_calc_SarN32x2; goto shifty;
2188//.. case Iop_SarN16x4:
2189//.. fn = (HWord)h_generic_calc_SarN16x4; goto shifty;
2190//.. shifty: {
2191//.. /* Note: the following assumes all helpers are of
2192//.. signature
2193//.. ULong fn ( ULong, UInt ), and they are
2194//.. not marked as regparm functions.
2195//.. */
2196//.. HReg xLo, xHi;
2197//.. HReg tLo = newVRegI(env);
2198//.. HReg tHi = newVRegI(env);
2199//.. X86RMI* y = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
2200//.. addInstr(env, X86Instr_Push(y));
2201//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2202//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
2203//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
2204//.. addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn, 0 ));
2205//.. add_to_esp(env, 3*4);
2206//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2207//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2208//.. *rHi = tHi;
2209//.. *rLo = tLo;
2210//.. return;
2211//.. }
2212//..
2213//.. default:
2214//.. break;
2215//.. }
2216//.. } /* if (e->tag == Iex_Binop) */
2217//..
2218//..
2219//.. /* --------- UNARY ops --------- */
2220//.. if (e->tag == Iex_Unop) {
2221//.. switch (e->Iex.Unop.op) {
2222//..
2223//.. /* 32Sto64(e) */
2224//.. case Iop_32Sto64: {
2225//.. HReg tLo = newVRegI(env);
2226//.. HReg tHi = newVRegI(env);
2227//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
2228//.. addInstr(env, mk_iMOVsd_RR(src,tHi));
2229//.. addInstr(env, mk_iMOVsd_RR(src,tLo));
2230//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tHi)));
2231//.. *rHi = tHi;
2232//.. *rLo = tLo;
2233//.. return;
2234//.. }
2235//..
2236//.. /* 32Uto64(e) */
2237//.. case Iop_32Uto64: {
2238//.. HReg tLo = newVRegI(env);
2239//.. HReg tHi = newVRegI(env);
2240//.. HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
2241//.. addInstr(env, mk_iMOVsd_RR(src,tLo));
2242//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0), tHi));
2243//.. *rHi = tHi;
2244//.. *rLo = tLo;
2245//.. return;
2246//.. }
2247//..
2248//.. /* 128{HI}to64 */
2249//.. case Iop_128HIto64:
2250//.. case Iop_128to64: {
2251//.. Int off = e->Iex.Unop.op==Iop_128HIto64 ? 8 : 0;
2252//.. HReg tLo = newVRegI(env);
2253//.. HReg tHi = newVRegI(env);
2254//.. HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
2255//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
2256//.. X86AMode* espLO = X86AMode_IR(off, hregX86_ESP());
2257//.. X86AMode* espHI = X86AMode_IR(off+4, hregX86_ESP());
2258//.. sub_from_esp(env, 16);
2259//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
2260//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV,
2261//.. X86RMI_Mem(espLO), tLo ));
2262//.. addInstr(env, X86Instr_Alu32R( Xalu_MOV,
2263//.. X86RMI_Mem(espHI), tHi ));
2264//.. add_to_esp(env, 16);
2265//.. *rHi = tHi;
2266//.. *rLo = tLo;
2267//.. return;
2268//.. }
2269//..
2270//.. /* could do better than this, but for now ... */
2271//.. case Iop_1Sto64: {
2272//.. HReg tLo = newVRegI(env);
2273//.. HReg tHi = newVRegI(env);
2274//.. X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
2275//.. addInstr(env, X86Instr_Set32(cond,tLo));
2276//.. addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, X86RM_Reg(tLo)));
2277//.. addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, X86RM_Reg(tLo)));
2278//.. addInstr(env, mk_iMOVsd_RR(tLo, tHi));
2279//.. *rHi = tHi;
2280//.. *rLo = tLo;
2281//.. return;
2282//.. }
2283//..
2284//.. /* Not64(e) */
2285//.. case Iop_Not64: {
2286//.. HReg tLo = newVRegI(env);
2287//.. HReg tHi = newVRegI(env);
2288//.. HReg sHi, sLo;
2289//.. iselInt64Expr(&sHi, &sLo, env, e->Iex.Unop.arg);
2290//.. addInstr(env, mk_iMOVsd_RR(sHi, tHi));
2291//.. addInstr(env, mk_iMOVsd_RR(sLo, tLo));
2292//.. addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(tHi)));
2293//.. addInstr(env, X86Instr_Unary32(Xun_NOT,X86RM_Reg(tLo)));
2294//.. *rHi = tHi;
2295//.. *rLo = tLo;
2296//.. return;
2297//.. }
2298//..
2299//.. /* ReinterpF64asI64(e) */
2300//.. /* Given an IEEE754 double, produce an I64 with the same bit
2301//.. pattern. */
2302//.. case Iop_ReinterpF64asI64: {
2303//.. HReg rf = iselDblExpr(env, e->Iex.Unop.arg);
2304//.. HReg tLo = newVRegI(env);
2305//.. HReg tHi = newVRegI(env);
2306//.. X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
2307//.. X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP());
2308//.. /* paranoia */
2309//.. set_FPU_rounding_default(env);
2310//.. /* subl $8, %esp */
2311//.. sub_from_esp(env, 8);
2312//.. /* gstD %rf, 0(%esp) */
2313//.. addInstr(env,
2314//.. X86Instr_FpLdSt(False/*store*/, 8, rf, zero_esp));
2315//.. /* movl 0(%esp), %tLo */
2316//.. addInstr(env,
2317//.. X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(zero_esp), tLo));
2318//.. /* movl 4(%esp), %tHi */
2319//.. addInstr(env,
2320//.. X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(four_esp), tHi));
2321//.. /* addl $8, %esp */
2322//.. add_to_esp(env, 8);
2323//.. *rHi = tHi;
2324//.. *rLo = tLo;
2325//.. return;
2326//.. }
2327//..
2328//.. case Iop_CmpNEZ32x2:
2329//.. fn = (HWord)h_generic_calc_CmpNEZ32x2; goto unish;
2330//.. case Iop_CmpNEZ16x4:
2331//.. fn = (HWord)h_generic_calc_CmpNEZ16x4; goto unish;
2332//.. case Iop_CmpNEZ8x8:
2333//.. fn = (HWord)h_generic_calc_CmpNEZ8x8; goto unish;
2334//.. unish: {
2335//.. /* Note: the following assumes all helpers are of
2336//.. signature
2337//.. ULong fn ( ULong ), and they are
2338//.. not marked as regparm functions.
2339//.. */
2340//.. HReg xLo, xHi;
2341//.. HReg tLo = newVRegI(env);
2342//.. HReg tHi = newVRegI(env);
2343//.. iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg);
2344//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xHi)));
2345//.. addInstr(env, X86Instr_Push(X86RMI_Reg(xLo)));
2346//.. addInstr(env, X86Instr_Call( Xcc_ALWAYS, (UInt)fn, 0 ));
2347//.. add_to_esp(env, 2*4);
2348//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2349//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2350//.. *rHi = tHi;
2351//.. *rLo = tLo;
2352//.. return;
2353//.. }
2354//..
2355//.. default:
2356//.. break;
2357//.. }
2358//.. } /* if (e->tag == Iex_Unop) */
2359//..
2360//..
2361//.. /* --------- CCALL --------- */
2362//.. if (e->tag == Iex_CCall) {
2363//.. HReg tLo = newVRegI(env);
2364//.. HReg tHi = newVRegI(env);
2365//..
2366//.. /* Marshal args, do the call, clear stack. */
2367//.. doHelperCall( env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
2368//..
2369//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(), tHi));
2370//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), tLo));
2371//.. *rHi = tHi;
2372//.. *rLo = tLo;
2373//.. return;
2374//.. }
2375//..
2376//.. ppIRExpr(e);
2377//.. vpanic("iselInt64Expr");
2378//.. }
2379//..
2380//..
2381//.. /*---------------------------------------------------------*/
2382//.. /*--- ISEL: Floating point expressions (32 bit) ---*/
2383//.. /*---------------------------------------------------------*/
2384//..
2385//.. /* Nothing interesting here; really just wrappers for
2386//.. 64-bit stuff. */
2387//..
2388//.. static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
2389//.. {
2390//.. HReg r = iselFltExpr_wrk( env, e );
2391//.. # if 0
2392//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2393//.. # endif
2394//.. vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
2395//.. vassert(hregIsVirtual(r));
2396//.. return r;
2397//.. }
2398//..
2399//.. /* DO NOT CALL THIS DIRECTLY */
2400//.. static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
2401//.. {
2402//.. IRType ty = typeOfIRExpr(env->type_env,e);
2403//.. vassert(ty == Ity_F32);
2404//..
2405//.. if (e->tag == Iex_Tmp) {
2406//.. return lookupIRTemp(env, e->Iex.Tmp.tmp);
2407//.. }
2408//..
2409//.. if (e->tag == Iex_LDle) {
2410//.. X86AMode* am;
2411//.. HReg res = newVRegF(env);
2412//.. vassert(e->Iex.LDle.ty == Ity_F32);
2413//.. am = iselIntExpr_AMode(env, e->Iex.LDle.addr);
2414//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 4, res, am));
2415//.. return res;
2416//.. }
2417//..
2418//.. if (e->tag == Iex_Binop
2419//.. && e->Iex.Binop.op == Iop_F64toF32) {
2420//.. /* Although the result is still held in a standard FPU register,
2421//.. we need to round it to reflect the loss of accuracy/range
2422//.. entailed in casting it to a 32-bit float. */
2423//.. HReg dst = newVRegF(env);
2424//.. HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
2425//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2426//.. addInstr(env, X86Instr_Fp64to32(src,dst));
2427//.. set_FPU_rounding_default( env );
2428//.. return dst;
2429//.. }
2430//..
2431//.. if (e->tag == Iex_Get) {
2432//.. X86AMode* am = X86AMode_IR( e->Iex.Get.offset,
2433//.. hregX86_EBP() );
2434//.. HReg res = newVRegF(env);
2435//.. addInstr(env, X86Instr_FpLdSt( True/*load*/, 4, res, am ));
2436//.. return res;
2437//.. }
2438//..
2439//.. if (e->tag == Iex_Unop
2440//.. && e->Iex.Unop.op == Iop_ReinterpI32asF32) {
2441//.. /* Given an I32, produce an IEEE754 float with the same bit
2442//.. pattern. */
2443//.. HReg dst = newVRegF(env);
2444//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Unop.arg);
2445//.. /* paranoia */
2446//.. addInstr(env, X86Instr_Push(rmi));
2447//.. addInstr(env, X86Instr_FpLdSt(
2448//.. True/*load*/, 4, dst,
2449//.. X86AMode_IR(0, hregX86_ESP())));
2450//.. add_to_esp(env, 4);
2451//.. return dst;
2452//.. }
2453//..
2454//.. ppIRExpr(e);
2455//.. vpanic("iselFltExpr_wrk");
2456//.. }
2457//..
2458//..
2459//.. /*---------------------------------------------------------*/
2460//.. /*--- ISEL: Floating point expressions (64 bit) ---*/
2461//.. /*---------------------------------------------------------*/
2462//..
2463//.. /* Compute a 64-bit floating point value into a register, the identity
2464//.. of which is returned. As with iselIntExpr_R, the reg may be either
2465//.. real or virtual; in any case it must not be changed by subsequent
2466//.. code emitted by the caller. */
2467//..
2468//.. /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
2469//..
2470//.. Type S (1 bit) E (11 bits) F (52 bits)
2471//.. ---- --------- ----------- -----------
2472//.. signalling NaN u 2047 (max) .0uuuuu---u
2473//.. (with at least
2474//.. one 1 bit)
2475//.. quiet NaN u 2047 (max) .1uuuuu---u
2476//..
2477//.. negative infinity 1 2047 (max) .000000---0
2478//..
2479//.. positive infinity 0 2047 (max) .000000---0
2480//..
2481//.. negative zero 1 0 .000000---0
2482//..
2483//.. positive zero 0 0 .000000---0
2484//.. */
2485//..
2486//.. static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
2487//.. {
2488//.. HReg r = iselDblExpr_wrk( env, e );
2489//.. # if 0
2490//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2491//.. # endif
2492//.. vassert(hregClass(r) == HRcFlt64);
2493//.. vassert(hregIsVirtual(r));
2494//.. return r;
2495//.. }
2496//..
2497//.. /* DO NOT CALL THIS DIRECTLY */
2498//.. static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
2499//.. {
2500//.. IRType ty = typeOfIRExpr(env->type_env,e);
2501//.. vassert(e);
2502//.. vassert(ty == Ity_F64);
2503//..
2504//.. if (e->tag == Iex_Tmp) {
2505//.. return lookupIRTemp(env, e->Iex.Tmp.tmp);
2506//.. }
2507//..
2508//.. if (e->tag == Iex_Const) {
2509//.. union { UInt u32x2[2]; ULong u64; Double f64; } u;
2510//.. HReg freg = newVRegF(env);
2511//.. vassert(sizeof(u) == 8);
2512//.. vassert(sizeof(u.u64) == 8);
2513//.. vassert(sizeof(u.f64) == 8);
2514//.. vassert(sizeof(u.u32x2) == 8);
2515//..
2516//.. if (e->Iex.Const.con->tag == Ico_F64) {
2517//.. u.f64 = e->Iex.Const.con->Ico.F64;
2518//.. }
2519//.. else if (e->Iex.Const.con->tag == Ico_F64i) {
2520//.. u.u64 = e->Iex.Const.con->Ico.F64i;
2521//.. }
2522//.. else
2523//.. vpanic("iselDblExpr(x86): const");
2524//..
2525//.. addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[1])));
2526//.. addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[0])));
2527//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg,
2528//.. X86AMode_IR(0, hregX86_ESP())));
2529//.. add_to_esp(env, 8);
2530//.. return freg;
2531//.. }
2532//..
2533//.. if (e->tag == Iex_LDle) {
2534//.. X86AMode* am;
2535//.. HReg res = newVRegF(env);
2536//.. vassert(e->Iex.LDle.ty == Ity_F64);
2537//.. am = iselIntExpr_AMode(env, e->Iex.LDle.addr);
2538//.. addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, res, am));
2539//.. return res;
2540//.. }
2541//..
2542//.. if (e->tag == Iex_Get) {
2543//.. X86AMode* am = X86AMode_IR( e->Iex.Get.offset,
2544//.. hregX86_EBP() );
2545//.. HReg res = newVRegF(env);
2546//.. addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am ));
2547//.. return res;
2548//.. }
2549//..
2550//.. if (e->tag == Iex_GetI) {
2551//.. X86AMode* am
2552//.. = genGuestArrayOffset(
2553//.. env, e->Iex.GetI.descr,
2554//.. e->Iex.GetI.ix, e->Iex.GetI.bias );
2555//.. HReg res = newVRegF(env);
2556//.. addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am ));
2557//.. return res;
2558//.. }
2559//..
2560//.. if (e->tag == Iex_Binop) {
2561//.. X86FpOp fpop = Xfp_INVALID;
2562//.. switch (e->Iex.Binop.op) {
2563//.. case Iop_AddF64: fpop = Xfp_ADD; break;
2564//.. case Iop_SubF64: fpop = Xfp_SUB; break;
2565//.. case Iop_MulF64: fpop = Xfp_MUL; break;
2566//.. case Iop_DivF64: fpop = Xfp_DIV; break;
2567//.. case Iop_ScaleF64: fpop = Xfp_SCALE; break;
2568//.. case Iop_AtanF64: fpop = Xfp_ATAN; break;
2569//.. case Iop_Yl2xF64: fpop = Xfp_YL2X; break;
2570//.. case Iop_Yl2xp1F64: fpop = Xfp_YL2XP1; break;
2571//.. case Iop_PRemF64: fpop = Xfp_PREM; break;
2572//.. case Iop_PRem1F64: fpop = Xfp_PREM1; break;
2573//.. default: break;
2574//.. }
2575//.. if (fpop != Xfp_INVALID) {
2576//.. HReg res = newVRegF(env);
2577//.. HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
2578//.. HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
2579//.. addInstr(env, X86Instr_FpBinary(fpop,srcL,srcR,res));
2580//.. if (fpop != Xfp_ADD && fpop != Xfp_SUB
2581//.. && fpop != Xfp_MUL && fpop != Xfp_DIV)
2582//.. roundToF64(env, res);
2583//.. return res;
2584//.. }
2585//.. }
2586//..
2587//.. if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF64) {
2588//.. HReg rf = iselDblExpr(env, e->Iex.Binop.arg2);
2589//.. HReg dst = newVRegF(env);
2590//..
2591//.. /* rf now holds the value to be rounded. The first thing to do
2592//.. is set the FPU's rounding mode accordingly. */
2593//..
2594//.. /* Set host rounding mode */
2595//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2596//..
2597//.. /* grndint %rf, %dst */
2598//.. addInstr(env, X86Instr_FpUnary(Xfp_ROUND, rf, dst));
2599//..
2600//.. /* Restore default FPU rounding. */
2601//.. set_FPU_rounding_default( env );
2602//..
2603//.. return dst;
2604//.. }
2605//..
2606//.. if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64toF64) {
2607//.. HReg dst = newVRegF(env);
2608//.. HReg rHi,rLo;
2609//.. iselInt64Expr( &rHi, &rLo, env, e->Iex.Binop.arg2);
2610//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
2611//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
2612//..
2613//.. /* Set host rounding mode */
2614//.. set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2615//..
2616//.. addInstr(env, X86Instr_FpLdStI(
2617//.. True/*load*/, 8, dst,
2618//.. X86AMode_IR(0, hregX86_ESP())));
2619//..
2620//.. /* Restore default FPU rounding. */
2621//.. set_FPU_rounding_default( env );
2622//..
2623//.. add_to_esp(env, 8);
2624//.. return dst;
2625//.. }
2626//..
2627//.. if (e->tag == Iex_Unop) {
2628//.. X86FpOp fpop = Xfp_INVALID;
2629//.. switch (e->Iex.Unop.op) {
2630//.. case Iop_NegF64: fpop = Xfp_NEG; break;
2631//.. case Iop_AbsF64: fpop = Xfp_ABS; break;
2632//.. case Iop_SqrtF64: fpop = Xfp_SQRT; break;
2633//.. case Iop_SinF64: fpop = Xfp_SIN; break;
2634//.. case Iop_CosF64: fpop = Xfp_COS; break;
2635//.. case Iop_TanF64: fpop = Xfp_TAN; break;
2636//.. case Iop_2xm1F64: fpop = Xfp_2XM1; break;
2637//.. default: break;
2638//.. }
2639//.. if (fpop != Xfp_INVALID) {
2640//.. HReg res = newVRegF(env);
2641//.. HReg src = iselDblExpr(env, e->Iex.Unop.arg);
2642//.. addInstr(env, X86Instr_FpUnary(fpop,src,res));
2643//.. if (fpop != Xfp_SQRT
2644//.. && fpop != Xfp_NEG && fpop != Xfp_ABS)
2645//.. roundToF64(env, res);
2646//.. return res;
2647//.. }
2648//.. }
2649//..
2650//.. if (e->tag == Iex_Unop) {
2651//.. switch (e->Iex.Unop.op) {
2652//.. case Iop_I32toF64: {
2653//.. HReg dst = newVRegF(env);
2654//.. HReg ri = iselIntExpr_R(env, e->Iex.Unop.arg);
2655//.. addInstr(env, X86Instr_Push(X86RMI_Reg(ri)));
2656//.. set_FPU_rounding_default(env);
2657//.. addInstr(env, X86Instr_FpLdStI(
2658//.. True/*load*/, 4, dst,
2659//.. X86AMode_IR(0, hregX86_ESP())));
2660//.. add_to_esp(env, 4);
2661//.. return dst;
2662//.. }
2663//.. case Iop_ReinterpI64asF64: {
2664//.. /* Given an I64, produce an IEEE754 double with the same
2665//.. bit pattern. */
2666//.. HReg dst = newVRegF(env);
2667//.. HReg rHi, rLo;
2668//.. iselInt64Expr( &rHi, &rLo, env, e->Iex.Unop.arg);
2669//.. /* paranoia */
2670//.. set_FPU_rounding_default(env);
2671//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
2672//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
2673//.. addInstr(env, X86Instr_FpLdSt(
2674//.. True/*load*/, 8, dst,
2675//.. X86AMode_IR(0, hregX86_ESP())));
2676//.. add_to_esp(env, 8);
2677//.. return dst;
2678//.. }
2679//.. case Iop_F32toF64: {
2680//.. /* this is a no-op */
2681//.. HReg res = iselFltExpr(env, e->Iex.Unop.arg);
2682//.. return res;
2683//.. }
2684//.. default:
2685//.. break;
2686//.. }
2687//.. }
2688//..
2689//.. /* --------- MULTIPLEX --------- */
2690//.. if (e->tag == Iex_Mux0X) {
2691//.. if (ty == Ity_F64
2692//.. && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
2693//.. HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
2694//.. HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX);
2695//.. HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
2696//.. HReg dst = newVRegF(env);
2697//.. addInstr(env, X86Instr_FpUnary(Xfp_MOV,rX,dst));
2698//.. addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
2699//.. addInstr(env, X86Instr_FpCMov(Xcc_Z,r0,dst));
2700//.. return dst;
2701//.. }
2702//.. }
2703//..
2704//.. ppIRExpr(e);
2705//.. vpanic("iselDblExpr_wrk");
2706//.. }
2707//..
2708//..
2709//.. /*---------------------------------------------------------*/
2710//.. /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/
2711//.. /*---------------------------------------------------------*/
2712//..
2713//.. static HReg iselVecExpr ( ISelEnv* env, IRExpr* e )
2714//.. {
2715//.. HReg r = iselVecExpr_wrk( env, e );
2716//.. # if 0
2717//.. vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2718//.. # endif
2719//.. vassert(hregClass(r) == HRcVec128);
2720//.. vassert(hregIsVirtual(r));
2721//.. return r;
2722//.. }
2723//..
2724//..
2725//.. /* DO NOT CALL THIS DIRECTLY */
2726//.. static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
2727//.. {
sewardjc2bcb6f2005-02-07 00:17:12 +00002728#if 0
2729# define REQUIRE_SSE1 \
2730 do { if (env->subarch == VexSubArchX86_sse0) \
2731 goto vec_fail; \
2732 } while (0)
2733
2734# define REQUIRE_SSE2 \
2735 do { if (env->subarch == VexSubArchX86_sse0 \
2736 || env->subarch == VexSubArchX86_sse1) \
2737 goto vec_fail; \
2738 } while (0)
2739#endif
sewardja3e98302005-02-01 15:55:05 +00002740//.. Bool arg1isEReg = False;
2741//.. X86SseOp op = Xsse_INVALID;
2742//.. IRType ty = typeOfIRExpr(env->type_env,e);
2743//.. vassert(e);
2744//.. vassert(ty == Ity_V128);
2745//..
2746//.. REQUIRE_SSE1;
2747//..
2748//.. if (e->tag == Iex_Tmp) {
2749//.. return lookupIRTemp(env, e->Iex.Tmp.tmp);
2750//.. }
2751//..
2752//.. if (e->tag == Iex_Get) {
2753//.. HReg dst = newVRegV(env);
2754//.. addInstr(env, X86Instr_SseLdSt(
2755//.. True/*load*/,
2756//.. dst,
2757//.. X86AMode_IR(e->Iex.Get.offset, hregX86_EBP())
2758//.. )
2759//.. );
2760//.. return dst;
2761//.. }
2762//..
2763//.. if (e->tag == Iex_LDle) {
2764//.. HReg dst = newVRegV(env);
2765//.. X86AMode* am = iselIntExpr_AMode(env, e->Iex.LDle.addr);
2766//.. addInstr(env, X86Instr_SseLdSt( True/*load*/, dst, am ));
2767//.. return dst;
2768//.. }
2769//..
2770//.. if (e->tag == Iex_Const) {
2771//.. HReg dst = newVRegV(env);
2772//.. vassert(e->Iex.Const.con->tag == Ico_V128);
2773//.. addInstr(env, X86Instr_SseConst(e->Iex.Const.con->Ico.V128, dst));
2774//.. return dst;
2775//.. }
2776//..
2777//.. if (e->tag == Iex_Unop) {
2778//.. switch (e->Iex.Unop.op) {
2779//..
2780//.. case Iop_Not128: {
2781//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
2782//.. return do_sse_Not128(env, arg);
2783//.. }
2784//..
2785//.. case Iop_CmpNEZ64x2: {
2786//.. /* We can use SSE2 instructions for this. */
2787//.. /* Ideally, we want to do a 64Ix2 comparison against zero of
2788//.. the operand. Problem is no such insn exists. Solution
2789//.. therefore is to do a 32Ix4 comparison instead, and bitwise-
2790//.. negate (NOT) the result. Let a,b,c,d be 32-bit lanes, and
2791//.. let the not'd result of this initial comparison be a:b:c:d.
2792//.. What we need to compute is (a|b):(a|b):(c|d):(c|d). So, use
2793//.. pshufd to create a value b:a:d:c, and OR that with a:b:c:d,
2794//.. giving the required result.
2795//..
2796//.. The required selection sequence is 2,3,0,1, which
2797//.. according to Intel's documentation means the pshufd
2798//.. literal value is 0xB1, that is,
2799//.. (2 << 6) | (3 << 4) | (0 << 2) | (1 << 0)
2800//.. */
2801//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
2802//.. HReg tmp = newVRegV(env);
2803//.. HReg dst = newVRegV(env);
2804//.. REQUIRE_SSE2;
2805//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, tmp, tmp));
2806//.. addInstr(env, X86Instr_SseReRg(Xsse_CMPEQ32, arg, tmp));
2807//.. tmp = do_sse_Not128(env, tmp);
2808//.. addInstr(env, X86Instr_SseShuf(0xB1, tmp, dst));
2809//.. addInstr(env, X86Instr_SseReRg(Xsse_OR, tmp, dst));
2810//.. return dst;
2811//.. }
2812//..
2813//.. case Iop_CmpNEZ32x4: {
2814//.. /* Sigh, we have to generate lousy code since this has to
2815//.. work on SSE1 hosts */
2816//.. /* basically, the idea is: for each lane:
2817//.. movl lane, %r ; negl %r (now CF = lane==0 ? 0 : 1)
2818//.. sbbl %r, %r (now %r = 1Sto32(CF))
2819//.. movl %r, lane
2820//.. */
2821//.. Int i;
2822//.. X86AMode* am;
2823//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
2824//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
2825//.. HReg dst = newVRegV(env);
2826//.. HReg r32 = newVRegI(env);
2827//.. sub_from_esp(env, 16);
2828//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, arg, esp0));
2829//.. for (i = 0; i < 4; i++) {
2830//.. am = X86AMode_IR(i*4, hregX86_ESP());
2831//.. addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(am), r32));
2832//.. addInstr(env, X86Instr_Unary32(Xun_NEG, X86RM_Reg(r32)));
2833//.. addInstr(env, X86Instr_Alu32R(Xalu_SBB, X86RMI_Reg(r32), r32));
2834//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r32), am));
2835//.. }
2836//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
2837//.. add_to_esp(env, 16);
2838//.. return dst;
2839//.. }
2840//..
2841//.. case Iop_CmpNEZ8x16:
2842//.. case Iop_CmpNEZ16x8: {
2843//.. /* We can use SSE2 instructions for this. */
2844//.. HReg arg;
2845//.. HReg vec0 = newVRegV(env);
2846//.. HReg vec1 = newVRegV(env);
2847//.. HReg dst = newVRegV(env);
2848//.. X86SseOp cmpOp
2849//.. = e->Iex.Unop.op==Iop_CmpNEZ16x8 ? Xsse_CMPEQ16
2850//.. : Xsse_CMPEQ8;
2851//.. REQUIRE_SSE2;
2852//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, vec0, vec0));
2853//.. addInstr(env, mk_vMOVsd_RR(vec0, vec1));
2854//.. addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, vec1, vec1));
2855//.. /* defer arg computation to here so as to give CMPEQF as long
2856//.. as possible to complete */
2857//.. arg = iselVecExpr(env, e->Iex.Unop.arg);
2858//.. /* vec0 is all 0s; vec1 is all 1s */
2859//.. addInstr(env, mk_vMOVsd_RR(arg, dst));
2860//.. /* 16x8 or 8x16 comparison == */
2861//.. addInstr(env, X86Instr_SseReRg(cmpOp, vec0, dst));
2862//.. /* invert result */
2863//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, vec1, dst));
2864//.. return dst;
2865//.. }
2866//..
2867//.. case Iop_Recip32Fx4: op = Xsse_RCPF; goto do_32Fx4_unary;
2868//.. case Iop_RSqrt32Fx4: op = Xsse_RSQRTF; goto do_32Fx4_unary;
2869//.. case Iop_Sqrt32Fx4: op = Xsse_SQRTF; goto do_32Fx4_unary;
2870//.. do_32Fx4_unary:
2871//.. {
2872//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
2873//.. HReg dst = newVRegV(env);
2874//.. addInstr(env, X86Instr_Sse32Fx4(op, arg, dst));
2875//.. return dst;
2876//.. }
2877//..
2878//.. case Iop_Recip64Fx2: op = Xsse_RCPF; goto do_64Fx2_unary;
2879//.. case Iop_RSqrt64Fx2: op = Xsse_RSQRTF; goto do_64Fx2_unary;
2880//.. case Iop_Sqrt64Fx2: op = Xsse_SQRTF; goto do_64Fx2_unary;
2881//.. do_64Fx2_unary:
2882//.. {
2883//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
2884//.. HReg dst = newVRegV(env);
2885//.. REQUIRE_SSE2;
2886//.. addInstr(env, X86Instr_Sse64Fx2(op, arg, dst));
2887//.. return dst;
2888//.. }
2889//..
2890//.. case Iop_Recip32F0x4: op = Xsse_RCPF; goto do_32F0x4_unary;
2891//.. case Iop_RSqrt32F0x4: op = Xsse_RSQRTF; goto do_32F0x4_unary;
2892//.. case Iop_Sqrt32F0x4: op = Xsse_SQRTF; goto do_32F0x4_unary;
2893//.. do_32F0x4_unary:
2894//.. {
2895//.. /* A bit subtle. We have to copy the arg to the result
2896//.. register first, because actually doing the SSE scalar insn
2897//.. leaves the upper 3/4 of the destination register
2898//.. unchanged. Whereas the required semantics of these
2899//.. primops is that the upper 3/4 is simply copied in from the
2900//.. argument. */
2901//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
2902//.. HReg dst = newVRegV(env);
2903//.. addInstr(env, mk_vMOVsd_RR(arg, dst));
2904//.. addInstr(env, X86Instr_Sse32FLo(op, arg, dst));
2905//.. return dst;
2906//.. }
2907//..
2908//.. case Iop_Recip64F0x2: op = Xsse_RCPF; goto do_64F0x2_unary;
2909//.. case Iop_RSqrt64F0x2: op = Xsse_RSQRTF; goto do_64F0x2_unary;
2910//.. case Iop_Sqrt64F0x2: op = Xsse_SQRTF; goto do_64F0x2_unary;
2911//.. do_64F0x2_unary:
2912//.. {
2913//.. /* A bit subtle. We have to copy the arg to the result
2914//.. register first, because actually doing the SSE scalar insn
2915//.. leaves the upper half of the destination register
2916//.. unchanged. Whereas the required semantics of these
2917//.. primops is that the upper half is simply copied in from the
2918//.. argument. */
2919//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
2920//.. HReg dst = newVRegV(env);
2921//.. REQUIRE_SSE2;
2922//.. addInstr(env, mk_vMOVsd_RR(arg, dst));
2923//.. addInstr(env, X86Instr_Sse64FLo(op, arg, dst));
2924//.. return dst;
2925//.. }
2926//..
2927//.. case Iop_32Uto128: {
2928//.. HReg dst = newVRegV(env);
2929//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
2930//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Unop.arg);
2931//.. addInstr(env, X86Instr_Push(rmi));
2932//.. addInstr(env, X86Instr_SseLdzLO(4, dst, esp0));
2933//.. add_to_esp(env, 4);
2934//.. return dst;
2935//.. }
2936//..
2937//.. case Iop_64Uto128: {
2938//.. HReg rHi, rLo;
2939//.. HReg dst = newVRegV(env);
2940//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
2941//.. iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
2942//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
2943//.. addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
2944//.. addInstr(env, X86Instr_SseLdzLO(8, dst, esp0));
2945//.. add_to_esp(env, 8);
2946//.. return dst;
2947//.. }
2948//..
2949//.. default:
2950//.. break;
2951//.. } /* switch (e->Iex.Unop.op) */
2952//.. } /* if (e->tag == Iex_Unop) */
2953//..
2954//.. if (e->tag == Iex_Binop) {
2955//.. switch (e->Iex.Binop.op) {
2956//..
2957//.. case Iop_Set128lo32: {
2958//.. HReg dst = newVRegV(env);
2959//.. HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1);
2960//.. HReg srcI = iselIntExpr_R(env, e->Iex.Binop.arg2);
2961//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
2962//.. sub_from_esp(env, 16);
2963//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0));
2964//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcI), esp0));
2965//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
2966//.. add_to_esp(env, 16);
2967//.. return dst;
2968//.. }
2969//..
2970//.. case Iop_Set128lo64: {
2971//.. HReg dst = newVRegV(env);
2972//.. HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1);
2973//.. HReg srcIhi, srcIlo;
2974//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
2975//.. X86AMode* esp4 = advance4(esp0);
2976//.. iselInt64Expr(&srcIhi, &srcIlo, env, e->Iex.Binop.arg2);
2977//.. sub_from_esp(env, 16);
2978//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0));
2979//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIlo), esp0));
2980//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIhi), esp4));
2981//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
2982//.. add_to_esp(env, 16);
2983//.. return dst;
2984//.. }
2985//..
2986//.. case Iop_64HLto128: {
2987//.. HReg r3, r2, r1, r0;
2988//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
2989//.. X86AMode* esp4 = advance4(esp0);
2990//.. X86AMode* esp8 = advance4(esp4);
2991//.. X86AMode* esp12 = advance4(esp8);
2992//.. HReg dst = newVRegV(env);
2993//.. /* do this via the stack (easy, convenient, etc) */
2994//.. sub_from_esp(env, 16);
2995//.. /* Do the less significant 64 bits */
2996//.. iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2);
2997//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r0), esp0));
2998//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r1), esp4));
2999//.. /* Do the more significant 64 bits */
3000//.. iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1);
3001//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r2), esp8));
3002//.. addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r3), esp12));
3003//.. /* Fetch result back from stack. */
3004//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
3005//.. add_to_esp(env, 16);
3006//.. return dst;
3007//.. }
3008//..
3009//.. case Iop_CmpEQ32Fx4: op = Xsse_CMPEQF; goto do_32Fx4;
3010//.. case Iop_CmpLT32Fx4: op = Xsse_CMPLTF; goto do_32Fx4;
3011//.. case Iop_CmpLE32Fx4: op = Xsse_CMPLEF; goto do_32Fx4;
3012//.. case Iop_Add32Fx4: op = Xsse_ADDF; goto do_32Fx4;
3013//.. case Iop_Div32Fx4: op = Xsse_DIVF; goto do_32Fx4;
3014//.. case Iop_Max32Fx4: op = Xsse_MAXF; goto do_32Fx4;
3015//.. case Iop_Min32Fx4: op = Xsse_MINF; goto do_32Fx4;
3016//.. case Iop_Mul32Fx4: op = Xsse_MULF; goto do_32Fx4;
3017//.. case Iop_Sub32Fx4: op = Xsse_SUBF; goto do_32Fx4;
3018//.. do_32Fx4:
3019//.. {
3020//.. HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3021//.. HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3022//.. HReg dst = newVRegV(env);
3023//.. addInstr(env, mk_vMOVsd_RR(argL, dst));
3024//.. addInstr(env, X86Instr_Sse32Fx4(op, argR, dst));
3025//.. return dst;
3026//.. }
3027//..
3028//.. case Iop_CmpEQ64Fx2: op = Xsse_CMPEQF; goto do_64Fx2;
3029//.. case Iop_CmpLT64Fx2: op = Xsse_CMPLTF; goto do_64Fx2;
3030//.. case Iop_CmpLE64Fx2: op = Xsse_CMPLEF; goto do_64Fx2;
3031//.. case Iop_Add64Fx2: op = Xsse_ADDF; goto do_64Fx2;
3032//.. case Iop_Div64Fx2: op = Xsse_DIVF; goto do_64Fx2;
3033//.. case Iop_Max64Fx2: op = Xsse_MAXF; goto do_64Fx2;
3034//.. case Iop_Min64Fx2: op = Xsse_MINF; goto do_64Fx2;
3035//.. case Iop_Mul64Fx2: op = Xsse_MULF; goto do_64Fx2;
3036//.. case Iop_Sub64Fx2: op = Xsse_SUBF; goto do_64Fx2;
3037//.. do_64Fx2:
3038//.. {
3039//.. HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3040//.. HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3041//.. HReg dst = newVRegV(env);
3042//.. REQUIRE_SSE2;
3043//.. addInstr(env, mk_vMOVsd_RR(argL, dst));
3044//.. addInstr(env, X86Instr_Sse64Fx2(op, argR, dst));
3045//.. return dst;
3046//.. }
3047//..
3048//.. case Iop_CmpEQ32F0x4: op = Xsse_CMPEQF; goto do_32F0x4;
3049//.. case Iop_CmpLT32F0x4: op = Xsse_CMPLTF; goto do_32F0x4;
3050//.. case Iop_CmpLE32F0x4: op = Xsse_CMPLEF; goto do_32F0x4;
3051//.. case Iop_Add32F0x4: op = Xsse_ADDF; goto do_32F0x4;
3052//.. case Iop_Div32F0x4: op = Xsse_DIVF; goto do_32F0x4;
3053//.. case Iop_Max32F0x4: op = Xsse_MAXF; goto do_32F0x4;
3054//.. case Iop_Min32F0x4: op = Xsse_MINF; goto do_32F0x4;
3055//.. case Iop_Mul32F0x4: op = Xsse_MULF; goto do_32F0x4;
3056//.. case Iop_Sub32F0x4: op = Xsse_SUBF; goto do_32F0x4;
3057//.. do_32F0x4: {
3058//.. HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3059//.. HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3060//.. HReg dst = newVRegV(env);
3061//.. addInstr(env, mk_vMOVsd_RR(argL, dst));
3062//.. addInstr(env, X86Instr_Sse32FLo(op, argR, dst));
3063//.. return dst;
3064//.. }
3065//..
3066//.. case Iop_CmpEQ64F0x2: op = Xsse_CMPEQF; goto do_64F0x2;
3067//.. case Iop_CmpLT64F0x2: op = Xsse_CMPLTF; goto do_64F0x2;
3068//.. case Iop_CmpLE64F0x2: op = Xsse_CMPLEF; goto do_64F0x2;
3069//.. case Iop_Add64F0x2: op = Xsse_ADDF; goto do_64F0x2;
3070//.. case Iop_Div64F0x2: op = Xsse_DIVF; goto do_64F0x2;
3071//.. case Iop_Max64F0x2: op = Xsse_MAXF; goto do_64F0x2;
3072//.. case Iop_Min64F0x2: op = Xsse_MINF; goto do_64F0x2;
3073//.. case Iop_Mul64F0x2: op = Xsse_MULF; goto do_64F0x2;
3074//.. case Iop_Sub64F0x2: op = Xsse_SUBF; goto do_64F0x2;
3075//.. do_64F0x2: {
3076//.. HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3077//.. HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3078//.. HReg dst = newVRegV(env);
3079//.. REQUIRE_SSE2;
3080//.. addInstr(env, mk_vMOVsd_RR(argL, dst));
3081//.. addInstr(env, X86Instr_Sse64FLo(op, argR, dst));
3082//.. return dst;
3083//.. }
3084//..
3085//.. case Iop_QNarrow32Sx4:
3086//.. op = Xsse_PACKSSD; arg1isEReg = True; goto do_SseReRg;
3087//.. case Iop_QNarrow16Sx8:
3088//.. op = Xsse_PACKSSW; arg1isEReg = True; goto do_SseReRg;
3089//.. case Iop_QNarrow16Ux8:
3090//.. op = Xsse_PACKUSW; arg1isEReg = True; goto do_SseReRg;
3091//..
3092//.. case Iop_InterleaveHI8x16:
3093//.. op = Xsse_UNPCKHB; arg1isEReg = True; goto do_SseReRg;
3094//.. case Iop_InterleaveHI16x8:
3095//.. op = Xsse_UNPCKHW; arg1isEReg = True; goto do_SseReRg;
3096//.. case Iop_InterleaveHI32x4:
3097//.. op = Xsse_UNPCKHD; arg1isEReg = True; goto do_SseReRg;
3098//.. case Iop_InterleaveHI64x2:
3099//.. op = Xsse_UNPCKHQ; arg1isEReg = True; goto do_SseReRg;
3100//..
3101//.. case Iop_InterleaveLO8x16:
3102//.. op = Xsse_UNPCKLB; arg1isEReg = True; goto do_SseReRg;
3103//.. case Iop_InterleaveLO16x8:
3104//.. op = Xsse_UNPCKLW; arg1isEReg = True; goto do_SseReRg;
3105//.. case Iop_InterleaveLO32x4:
3106//.. op = Xsse_UNPCKLD; arg1isEReg = True; goto do_SseReRg;
3107//.. case Iop_InterleaveLO64x2:
3108//.. op = Xsse_UNPCKLQ; arg1isEReg = True; goto do_SseReRg;
3109//..
3110//.. case Iop_And128: op = Xsse_AND; goto do_SseReRg;
3111//.. case Iop_Or128: op = Xsse_OR; goto do_SseReRg;
3112//.. case Iop_Xor128: op = Xsse_XOR; goto do_SseReRg;
3113//.. case Iop_Add8x16: op = Xsse_ADD8; goto do_SseReRg;
3114//.. case Iop_Add16x8: op = Xsse_ADD16; goto do_SseReRg;
3115//.. case Iop_Add32x4: op = Xsse_ADD32; goto do_SseReRg;
3116//.. case Iop_Add64x2: op = Xsse_ADD64; goto do_SseReRg;
3117//.. case Iop_QAdd8Sx16: op = Xsse_QADD8S; goto do_SseReRg;
3118//.. case Iop_QAdd16Sx8: op = Xsse_QADD16S; goto do_SseReRg;
3119//.. case Iop_QAdd8Ux16: op = Xsse_QADD8U; goto do_SseReRg;
3120//.. case Iop_QAdd16Ux8: op = Xsse_QADD16U; goto do_SseReRg;
3121//.. case Iop_Avg8Ux16: op = Xsse_AVG8U; goto do_SseReRg;
3122//.. case Iop_Avg16Ux8: op = Xsse_AVG16U; goto do_SseReRg;
3123//.. case Iop_CmpEQ8x16: op = Xsse_CMPEQ8; goto do_SseReRg;
3124//.. case Iop_CmpEQ16x8: op = Xsse_CMPEQ16; goto do_SseReRg;
3125//.. case Iop_CmpEQ32x4: op = Xsse_CMPEQ32; goto do_SseReRg;
3126//.. case Iop_CmpGT8Sx16: op = Xsse_CMPGT8S; goto do_SseReRg;
3127//.. case Iop_CmpGT16Sx8: op = Xsse_CMPGT16S; goto do_SseReRg;
3128//.. case Iop_CmpGT32Sx4: op = Xsse_CMPGT32S; goto do_SseReRg;
3129//.. case Iop_Max16Sx8: op = Xsse_MAX16S; goto do_SseReRg;
3130//.. case Iop_Max8Ux16: op = Xsse_MAX8U; goto do_SseReRg;
3131//.. case Iop_Min16Sx8: op = Xsse_MIN16S; goto do_SseReRg;
3132//.. case Iop_Min8Ux16: op = Xsse_MIN8U; goto do_SseReRg;
3133//.. case Iop_MulHi16Ux8: op = Xsse_MULHI16U; goto do_SseReRg;
3134//.. case Iop_MulHi16Sx8: op = Xsse_MULHI16S; goto do_SseReRg;
3135//.. case Iop_Mul16x8: op = Xsse_MUL16; goto do_SseReRg;
3136//.. case Iop_Sub8x16: op = Xsse_SUB8; goto do_SseReRg;
3137//.. case Iop_Sub16x8: op = Xsse_SUB16; goto do_SseReRg;
3138//.. case Iop_Sub32x4: op = Xsse_SUB32; goto do_SseReRg;
3139//.. case Iop_Sub64x2: op = Xsse_SUB64; goto do_SseReRg;
3140//.. case Iop_QSub8Sx16: op = Xsse_QSUB8S; goto do_SseReRg;
3141//.. case Iop_QSub16Sx8: op = Xsse_QSUB16S; goto do_SseReRg;
3142//.. case Iop_QSub8Ux16: op = Xsse_QSUB8U; goto do_SseReRg;
3143//.. case Iop_QSub16Ux8: op = Xsse_QSUB16U; goto do_SseReRg;
3144//.. do_SseReRg: {
3145//.. HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3146//.. HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3147//.. HReg dst = newVRegV(env);
3148//.. if (op != Xsse_OR && op != Xsse_AND && op != Xsse_XOR)
3149//.. REQUIRE_SSE2;
3150//.. if (arg1isEReg) {
3151//.. addInstr(env, mk_vMOVsd_RR(arg2, dst));
3152//.. addInstr(env, X86Instr_SseReRg(op, arg1, dst));
3153//.. } else {
3154//.. addInstr(env, mk_vMOVsd_RR(arg1, dst));
3155//.. addInstr(env, X86Instr_SseReRg(op, arg2, dst));
3156//.. }
3157//.. return dst;
3158//.. }
3159//..
3160//.. case Iop_ShlN16x8: op = Xsse_SHL16; goto do_SseShift;
3161//.. case Iop_ShlN32x4: op = Xsse_SHL32; goto do_SseShift;
3162//.. case Iop_ShlN64x2: op = Xsse_SHL64; goto do_SseShift;
3163//.. case Iop_SarN16x8: op = Xsse_SAR16; goto do_SseShift;
3164//.. case Iop_SarN32x4: op = Xsse_SAR32; goto do_SseShift;
3165//.. case Iop_ShrN16x8: op = Xsse_SHR16; goto do_SseShift;
3166//.. case Iop_ShrN32x4: op = Xsse_SHR32; goto do_SseShift;
3167//.. case Iop_ShrN64x2: op = Xsse_SHR64; goto do_SseShift;
3168//.. do_SseShift: {
3169//.. HReg greg = iselVecExpr(env, e->Iex.Binop.arg1);
3170//.. X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
3171//.. X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
3172//.. HReg ereg = newVRegV(env);
3173//.. HReg dst = newVRegV(env);
3174//.. REQUIRE_SSE2;
3175//.. addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
3176//.. addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
3177//.. addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
3178//.. addInstr(env, X86Instr_Push(rmi));
3179//.. addInstr(env, X86Instr_SseLdSt(True/*load*/, ereg, esp0));
3180//.. addInstr(env, mk_vMOVsd_RR(greg, dst));
3181//.. addInstr(env, X86Instr_SseReRg(op, ereg, dst));
3182//.. add_to_esp(env, 16);
3183//.. return dst;
3184//.. }
3185//..
3186//.. default:
3187//.. break;
3188//.. } /* switch (e->Iex.Binop.op) */
3189//.. } /* if (e->tag == Iex_Binop) */
3190//..
3191//.. if (e->tag == Iex_Mux0X) {
3192//.. HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
3193//.. HReg rX = iselVecExpr(env, e->Iex.Mux0X.exprX);
3194//.. HReg r0 = iselVecExpr(env, e->Iex.Mux0X.expr0);
3195//.. HReg dst = newVRegV(env);
3196//.. addInstr(env, mk_vMOVsd_RR(rX,dst));
3197//.. addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
3198//.. addInstr(env, X86Instr_SseCMov(Xcc_Z,r0,dst));
3199//.. return dst;
3200//.. }
3201//..
3202//.. vec_fail:
3203//.. vex_printf("iselVecExpr (subarch = %s): can't reduce\n",
3204//.. LibVEX_ppVexSubArch(env->subarch));
3205//.. ppIRExpr(e);
3206//.. vpanic("iselVecExpr_wrk");
3207//..
3208//.. # undef REQUIRE_SSE1
3209//.. # undef REQUIRE_SSE2
3210//.. }
sewardjc33671d2005-02-01 20:30:00 +00003211
3212
3213/*---------------------------------------------------------*/
3214/*--- ISEL: Statements ---*/
3215/*---------------------------------------------------------*/
3216
3217static void iselStmt ( ISelEnv* env, IRStmt* stmt )
3218{
3219 if (vex_traceflags & VEX_TRACE_VCODE) {
3220 vex_printf("\n-- ");
3221 ppIRStmt(stmt);
3222 vex_printf("\n");
3223 }
3224
3225 switch (stmt->tag) {
3226
sewardj05b3b6a2005-02-04 01:44:33 +00003227 /* --------- STORE --------- */
3228 case Ist_STle: {
3229 AMD64AMode* am;
3230 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr);
3231 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data);
3232 vassert(tya == Ity_I64);
3233 am = iselIntExpr_AMode(env, stmt->Ist.STle.addr);
sewardj31191072005-02-05 18:24:47 +00003234 if (tyd == Ity_I64) {
3235 AMD64RI* ri = iselIntExpr_RI(env, stmt->Ist.STle.data);
3236 addInstr(env, AMD64Instr_Alu64M(Aalu_MOV,ri,am));
3237 return;
3238 }
sewardj05b3b6a2005-02-04 01:44:33 +00003239 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32) {
3240 HReg r = iselIntExpr_R(env, stmt->Ist.STle.data);
3241 addInstr(env, AMD64Instr_Store(tyd==Ity_I8 ? 1 : (tyd==Ity_I16 ? 2 : 4),
3242 r,am));
3243 return;
3244 }
sewardja3e98302005-02-01 15:55:05 +00003245//.. if (tyd == Ity_F64) {
3246//.. HReg r = iselDblExpr(env, stmt->Ist.STle.data);
3247//.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, r, am));
3248//.. return;
3249//.. }
3250//.. if (tyd == Ity_F32) {
3251//.. HReg r = iselFltExpr(env, stmt->Ist.STle.data);
3252//.. addInstr(env, X86Instr_FpLdSt(False/*store*/, 4, r, am));
3253//.. return;
3254//.. }
3255//.. if (tyd == Ity_I64) {
3256//.. HReg vHi, vLo, rA;
3257//.. iselInt64Expr(&vHi, &vLo, env, stmt->Ist.STle.data);
3258//.. rA = iselIntExpr_R(env, stmt->Ist.STle.addr);
3259//.. addInstr(env, X86Instr_Alu32M(
3260//.. Xalu_MOV, X86RI_Reg(vLo), X86AMode_IR(0, rA)));
3261//.. addInstr(env, X86Instr_Alu32M(
3262//.. Xalu_MOV, X86RI_Reg(vHi), X86AMode_IR(4, rA)));
3263//.. return;
3264//.. }
3265//.. if (tyd == Ity_V128) {
3266//.. HReg r = iselVecExpr(env, stmt->Ist.STle.data);
3267//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, r, am));
3268//.. return;
3269//.. }
3270//.. break;
sewardj05b3b6a2005-02-04 01:44:33 +00003271 }
sewardjf67eadf2005-02-03 03:53:52 +00003272
3273 /* --------- PUT --------- */
3274 case Ist_Put: {
3275 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3276 if (ty == Ity_I64) {
3277 /* We're going to write to memory, so compute the RHS into an
3278 AMD64RI. */
3279 AMD64RI* ri = iselIntExpr_RI(env, stmt->Ist.Put.data);
3280 addInstr(env,
3281 AMD64Instr_Alu64M(
3282 Aalu_MOV,
3283 ri,
3284 AMD64AMode_IR(stmt->Ist.Put.offset,
3285 hregAMD64_RBP())
3286 ));
3287 return;
3288 }
sewardjf67eadf2005-02-03 03:53:52 +00003289 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32) {
3290 HReg r = iselIntExpr_R(env, stmt->Ist.Put.data);
3291 addInstr(env, AMD64Instr_Store(
3292 ty==Ity_I8 ? 1 : (ty==Ity_I16 ? 2 : 4),
3293 r,
3294 AMD64AMode_IR(stmt->Ist.Put.offset,
3295 hregAMD64_RBP())));
3296 return;
3297 }
sewardja3e98302005-02-01 15:55:05 +00003298//.. if (ty == Ity_V128) {
3299//.. HReg vec = iselVecExpr(env, stmt->Ist.Put.data);
3300//.. X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP());
3301//.. addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, am));
3302//.. return;
3303//.. }
3304//.. if (ty == Ity_F32) {
3305//.. HReg f32 = iselFltExpr(env, stmt->Ist.Put.data);
3306//.. X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP());
3307//.. set_FPU_rounding_default(env); /* paranoia */
3308//.. addInstr(env, X86Instr_FpLdSt( False/*store*/, 4, f32, am ));
3309//.. return;
3310//.. }
3311//.. if (ty == Ity_F64) {
3312//.. HReg f64 = iselDblExpr(env, stmt->Ist.Put.data);
3313//.. X86AMode* am = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP());
3314//.. set_FPU_rounding_default(env); /* paranoia */
3315//.. addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, f64, am ));
3316//.. return;
3317//.. }
sewardjf67eadf2005-02-03 03:53:52 +00003318 break;
3319 }
3320
sewardja3e98302005-02-01 15:55:05 +00003321//.. /* --------- Indexed PUT --------- */
3322//.. case Ist_PutI: {
3323//.. X86AMode* am
3324//.. = genGuestArrayOffset(
3325//.. env, stmt->Ist.PutI.descr,
3326//.. stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
3327//..
3328//.. IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
3329//.. if (ty == Ity_F64) {
3330//.. HReg val = iselDblExpr(env, stmt->Ist.PutI.data);
3331//.. addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, val, am ));
3332//.. return;
3333//.. }
3334//.. if (ty == Ity_I8) {
3335//.. HReg r = iselIntExpr_R(env, stmt->Ist.PutI.data);
3336//.. addInstr(env, X86Instr_Store( 1, r, am ));
3337//.. return;
3338//.. }
3339//.. if (ty == Ity_I64) {
3340//.. HReg rHi, rLo;
3341//.. X86AMode* am4 = advance4(am);
3342//.. iselInt64Expr(&rHi, &rLo, env, stmt->Ist.PutI.data);
3343//.. addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rLo), am ));
3344//.. addInstr(env, X86Instr_Alu32M( Xalu_MOV, X86RI_Reg(rHi), am4 ));
3345//.. return;
3346//.. }
3347//.. break;
3348//.. }
sewardj614b3fb2005-02-02 02:16:03 +00003349
3350 /* --------- TMP --------- */
3351 case Ist_Tmp: {
3352 IRTemp tmp = stmt->Ist.Tmp.tmp;
3353 IRType ty = typeOfIRTemp(env->type_env, tmp);
3354 if (ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
3355 AMD64RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.Tmp.data);
3356 HReg dst = lookupIRTemp(env, tmp);
3357 addInstr(env, AMD64Instr_Alu64R(Aalu_MOV,rmi,dst));
3358 return;
3359 }
sewardja3e98302005-02-01 15:55:05 +00003360//.. if (ty == Ity_I64) {
3361//.. HReg rHi, rLo, dstHi, dstLo;
3362//.. iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Tmp.data);
3363//.. lookupIRTemp64( &dstHi, &dstLo, env, tmp);
3364//.. addInstr(env, mk_iMOVsd_RR(rHi,dstHi) );
3365//.. addInstr(env, mk_iMOVsd_RR(rLo,dstLo) );
3366//.. return;
3367//.. }
3368//.. if (ty == Ity_I1) {
3369//.. X86CondCode cond = iselCondCode(env, stmt->Ist.Tmp.data);
3370//.. HReg dst = lookupIRTemp(env, tmp);
3371//.. addInstr(env, X86Instr_Set32(cond, dst));
3372//.. return;
3373//.. }
3374//.. if (ty == Ity_F64) {
3375//.. HReg dst = lookupIRTemp(env, tmp);
3376//.. HReg src = iselDblExpr(env, stmt->Ist.Tmp.data);
3377//.. addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst));
3378//.. return;
3379//.. }
3380//.. if (ty == Ity_F32) {
3381//.. HReg dst = lookupIRTemp(env, tmp);
3382//.. HReg src = iselFltExpr(env, stmt->Ist.Tmp.data);
3383//.. addInstr(env, X86Instr_FpUnary(Xfp_MOV,src,dst));
3384//.. return;
3385//.. }
3386//.. if (ty == Ity_V128) {
3387//.. HReg dst = lookupIRTemp(env, tmp);
3388//.. HReg src = iselVecExpr(env, stmt->Ist.Tmp.data);
3389//.. addInstr(env, mk_vMOVsd_RR(src,dst));
3390//.. return;
3391//.. }
sewardj614b3fb2005-02-02 02:16:03 +00003392 break;
3393 }
3394
sewardja3e98302005-02-01 15:55:05 +00003395//.. /* --------- Call to DIRTY helper --------- */
3396//.. case Ist_Dirty: {
3397//.. IRType retty;
3398//.. IRDirty* d = stmt->Ist.Dirty.details;
3399//.. Bool passBBP = False;
3400//..
3401//.. if (d->nFxState == 0)
3402//.. vassert(!d->needsBBP);
3403//.. passBBP = d->nFxState > 0 && d->needsBBP;
3404//..
3405//.. /* Marshal args, do the call, clear stack. */
3406//.. doHelperCall( env, passBBP, d->guard, d->cee, d->args );
3407//..
3408//.. /* Now figure out what to do with the returned value, if any. */
3409//.. if (d->tmp == IRTemp_INVALID)
3410//.. /* No return value. Nothing to do. */
3411//.. return;
3412//..
3413//.. retty = typeOfIRTemp(env->type_env, d->tmp);
3414//.. if (retty == Ity_I64) {
3415//.. HReg dstHi, dstLo;
3416//.. /* The returned value is in %edx:%eax. Park it in the
3417//.. register-pair associated with tmp. */
3418//.. lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
3419//.. addInstr(env, mk_iMOVsd_RR(hregX86_EDX(),dstHi) );
3420//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dstLo) );
3421//.. return;
3422//.. }
3423//.. if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
3424//.. /* The returned value is in %eax. Park it in the register
3425//.. associated with tmp. */
3426//.. HReg dst = lookupIRTemp(env, d->tmp);
3427//.. addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
3428//.. return;
3429//.. }
3430//.. break;
3431//.. }
3432//..
3433//.. /* --------- MEM FENCE --------- */
3434//.. case Ist_MFence:
3435//.. addInstr(env, X86Instr_MFence(env->subarch));
3436//.. return;
3437//..
3438//.. /* --------- EXIT --------- */
3439//.. case Ist_Exit: {
3440//.. X86RI* dst;
3441//.. X86CondCode cc;
3442//.. if (stmt->Ist.Exit.dst->tag != Ico_U32)
3443//.. vpanic("isel_x86: Ist_Exit: dst is not a 32-bit value");
3444//.. dst = iselIntExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
3445//.. cc = iselCondCode(env,stmt->Ist.Exit.guard);
3446//.. addInstr(env, X86Instr_Goto(stmt->Ist.Exit.jk, cc, dst));
3447//.. return;
3448//.. }
sewardjc33671d2005-02-01 20:30:00 +00003449
3450 default: break;
3451 }
3452 ppIRStmt(stmt);
3453 vpanic("iselStmt(amd64)");
3454}
3455
3456
3457/*---------------------------------------------------------*/
3458/*--- ISEL: Basic block terminators (Nexts) ---*/
3459/*---------------------------------------------------------*/
3460
3461static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
sewardjf67eadf2005-02-03 03:53:52 +00003462{
3463 AMD64RI* ri;
3464 if (vex_traceflags & VEX_TRACE_VCODE) {
3465 vex_printf("\n-- goto {");
3466 ppIRJumpKind(jk);
3467 vex_printf("} ");
3468 ppIRExpr(next);
3469 vex_printf("\n");
3470 }
3471 ri = iselIntExpr_RI(env, next);
3472 addInstr(env, AMD64Instr_Goto(jk, Acc_ALWAYS,ri));
sewardjc33671d2005-02-01 20:30:00 +00003473}
3474
3475
3476/*---------------------------------------------------------*/
3477/*--- Insn selector top-level ---*/
3478/*---------------------------------------------------------*/
3479
3480/* Translate an entire BB to amd64 code. */
3481
3482HInstrArray* iselBB_AMD64 ( IRBB* bb, VexSubArch subarch_host )
3483{
3484 Int i, j;
3485 HReg hreg;
3486
3487 /* sanity ... */
3488 vassert(subarch_host == VexSubArch_NONE);
3489
3490 /* Make up an initial environment to use. */
3491 ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
3492 env->vreg_ctr = 0;
3493
3494 /* Set up output code array. */
3495 env->code = newHInstrArray();
3496
3497 /* Copy BB's type env. */
3498 env->type_env = bb->tyenv;
3499
3500 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3501 change as we go along. */
3502 env->n_vregmap = bb->tyenv->types_used;
3503 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3504
3505 /* and finally ... */
3506 env->subarch = subarch_host;
3507
3508 /* For each IR temporary, allocate a suitably-kinded virtual
3509 register. */
3510 j = 0;
3511 for (i = 0; i < env->n_vregmap; i++) {
3512 hreg = INVALID_HREG;
3513 switch (bb->tyenv->types[i]) {
3514 case Ity_I1:
3515 case Ity_I8:
3516 case Ity_I16:
3517 case Ity_I32:
3518 case Ity_I64: hreg = mkHReg(j++, HRcInt64, True); break;
3519 case Ity_F32:
3520 case Ity_F64: hreg = mkHReg(j++, HRcFlt64, True); break;
3521 case Ity_V128: hreg = mkHReg(j++, HRcVec128, True); break;
3522 default: ppIRType(bb->tyenv->types[i]);
3523 vpanic("iselBB(amd64): IRTemp type");
3524 }
3525 env->vregmap[i] = hreg;
3526 }
3527 env->vreg_ctr = j;
3528
3529 /* Ok, finally we can iterate over the statements. */
3530 for (i = 0; i < bb->stmts_used; i++)
3531 if (bb->stmts[i])
3532 iselStmt(env,bb->stmts[i]);
3533
3534 iselNext(env,bb->next,bb->jumpkind);
3535
3536 /* record the number of vregs we used. */
3537 env->code->n_vregs = env->vreg_ctr;
3538 return env->code;
3539}
sewardja3e98302005-02-01 15:55:05 +00003540
3541
3542/*---------------------------------------------------------------*/
3543/*--- end host-amd64/isel.c ---*/
3544/*---------------------------------------------------------------*/