2 /*---------------------------------------------------------------*/
3 /*--- begin host_arm_isel.c ---*/
4 /*---------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2004-2010 OpenWorks LLP
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 The GNU General Public License is contained in the file COPYING.
31 #include "libvex_basictypes.h"
32 #include "libvex_ir.h"
35 #include "main_util.h"
36 #include "main_globals.h"
37 #include "host_generic_regs.h"
38 #include "host_arm_defs.h"
41 /*---------------------------------------------------------*/
42 /*--- ARMvfp control word stuff ---*/
43 /*---------------------------------------------------------*/
45 /* Vex-generated code expects to run with the FPU set as follows: all
46 exceptions masked, round-to-nearest, non-vector mode, with the NZCV
47 flags cleared, and FZ (flush to zero) disabled. Curiously enough,
48 this corresponds to a FPSCR value of zero.
50 fpscr should therefore be zero on entry to Vex-generated code, and
51 should be unchanged at exit. (Or at least the bottom 28 bits
55 #define DEFAULT_FPSCR 0
58 /*---------------------------------------------------------*/
60 /*---------------------------------------------------------*/
62 /* This carries around:
64 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
65 might encounter. This is computed before insn selection starts,
68 - A mapping from IRTemp to HReg. This tells the insn selector
69 which virtual register(s) are associated with each IRTemp
70 temporary. This is computed before insn selection starts, and
71 does not change. We expect this mapping to map precisely the
72 same set of IRTemps as the type mapping does.
74 - vregmap holds the primary register for the IRTemp.
75 - vregmapHI is only used for 64-bit integer-typed
76 IRTemps. It holds the identity of a second
77 32-bit virtual HReg, which holds the high half
80 - The name of the vreg in which we stash a copy of the link reg, so
81 helper functions don't kill it.
83 - The code array, that is, the insns selected so far.
85 - A counter, for generating new virtual registers.
87 - The host hardware capabilities word. This is set at the start
90 Note, this is all host-independent. */
110 static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
113 vassert(tmp < env->n_vregmap);
114 return env->vregmap[tmp];
117 static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp )
120 vassert(tmp < env->n_vregmap);
121 vassert(env->vregmapHI[tmp] != INVALID_HREG);
122 *vrLO = env->vregmap[tmp];
123 *vrHI = env->vregmapHI[tmp];
126 static void addInstr ( ISelEnv* env, ARMInstr* instr )
128 addHInstr(env->code, instr);
129 if (vex_traceflags & VEX_TRACE_VCODE) {
135 static HReg newVRegI ( ISelEnv* env )
137 HReg reg = mkHReg(env->vreg_ctr, HRcInt32, True/*virtual reg*/);
142 static HReg newVRegD ( ISelEnv* env )
144 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/);
149 static HReg newVRegF ( ISelEnv* env )
151 HReg reg = mkHReg(env->vreg_ctr, HRcFlt32, True/*virtual reg*/);
157 /*---------------------------------------------------------*/
158 /*--- ISEL: Forward declarations ---*/
159 /*---------------------------------------------------------*/
161 /* These are organised as iselXXX and iselXXX_wrk pairs. The
162 iselXXX_wrk do the real work, but are not to be called directly.
163 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
164 checks that all returned registers are virtual. You should not
165 call the _wrk version directly.
167 static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e );
168 static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e );
170 static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e );
171 static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e );
173 static ARMAModeV* iselIntExpr_AModeV_wrk ( ISelEnv* env, IRExpr* e );
174 static ARMAModeV* iselIntExpr_AModeV ( ISelEnv* env, IRExpr* e );
176 static ARMRI84* iselIntExpr_RI84_wrk
177 ( /*OUT*/Bool* didInv, Bool mayInv, ISelEnv* env, IRExpr* e );
178 static ARMRI84* iselIntExpr_RI84
179 ( /*OUT*/Bool* didInv, Bool mayInv, ISelEnv* env, IRExpr* e );
181 static ARMRI5* iselIntExpr_RI5_wrk ( ISelEnv* env, IRExpr* e );
182 static ARMRI5* iselIntExpr_RI5 ( ISelEnv* env, IRExpr* e );
184 static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
185 static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e );
187 static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e );
188 static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e );
190 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
191 ISelEnv* env, IRExpr* e );
192 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
193 ISelEnv* env, IRExpr* e );
195 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e );
196 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e );
198 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e );
199 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e );
202 /*---------------------------------------------------------*/
203 /*--- ISEL: Misc helpers ---*/
204 /*---------------------------------------------------------*/
206 static UInt ROR32 ( UInt x, UInt sh ) {
207 vassert(sh >= 0 && sh < 32);
211 return (x << (32-sh)) | (x >> sh);
214 /* Figure out if 'u' fits in the special shifter-operand 8x4 immediate
215 form, and if so return the components. */
216 static Bool fitsIn8x4 ( /*OUT*/UInt* u8, /*OUT*/UInt* u4, UInt u )
219 for (i = 0; i < 16; i++) {
220 if (0 == (u & 0xFFFFFF00)) {
231 /* Make a int reg-reg move. */
232 static ARMInstr* mk_iMOVds_RR ( HReg dst, HReg src )
234 vassert(hregClass(src) == HRcInt32);
235 vassert(hregClass(dst) == HRcInt32);
236 return ARMInstr_Mov(dst, ARMRI84_R(src));
239 /* Set the VFP unit's rounding mode to default (round to nearest). */
240 static void set_VFP_rounding_default ( ISelEnv* env )
242 /* mov rTmp, #DEFAULT_FPSCR
245 HReg rTmp = newVRegI(env);
246 addInstr(env, ARMInstr_Imm32(rTmp, DEFAULT_FPSCR));
247 addInstr(env, ARMInstr_FPSCR(True/*toFPSCR*/, rTmp));
250 /* Mess with the VFP unit's rounding mode: 'mode' is an I32-typed
251 expression denoting a value in the range 0 .. 3, indicating a round
252 mode encoded as per type IRRoundingMode. Set FPSCR to have the
256 void set_VFP_rounding_mode ( ISelEnv* env, IRExpr* mode )
258 /* This isn't simple, because 'mode' carries an IR rounding
259 encoding, and we need to translate that to an ARMvfp one:
261 00 to nearest (the default)
270 Easy enough to do; just swap the two bits.
272 HReg irrm = iselIntExpr_R(env, mode);
273 HReg tL = newVRegI(env);
274 HReg tR = newVRegI(env);
275 HReg t3 = newVRegI(env);
277 tR = irrm >> 1; if we're lucky, these will issue together
284 addInstr(env, ARMInstr_Shift(ARMsh_SHL, tL, irrm, ARMRI5_I5(1)));
285 addInstr(env, ARMInstr_Shift(ARMsh_SHR, tR, irrm, ARMRI5_I5(1)));
286 addInstr(env, ARMInstr_Alu(ARMalu_AND, tL, tL, ARMRI84_I84(2,0)));
287 addInstr(env, ARMInstr_Alu(ARMalu_AND, tR, tR, ARMRI84_I84(1,0)));
288 addInstr(env, ARMInstr_Alu(ARMalu_OR, t3, tL, ARMRI84_R(tR)));
289 addInstr(env, ARMInstr_Shift(ARMsh_SHL, t3, t3, ARMRI5_I5(22)));
290 addInstr(env, ARMInstr_FPSCR(True/*toFPSCR*/, t3));
294 /*---------------------------------------------------------*/
295 /*--- ISEL: Function call helpers ---*/
296 /*---------------------------------------------------------*/
298 /* Used only in doHelperCall. See big comment in doHelperCall re
299 handling of register-parameter args. This function figures out
300 whether evaluation of an expression might require use of a fixed
301 register. If in doubt return True (safe but suboptimal).
304 Bool mightRequireFixedRegs ( IRExpr* e )
307 case Iex_RdTmp: case Iex_Const: case Iex_Get:
315 /* Do a complete function call. guard is a Ity_Bit expression
316 indicating whether or not the call happens. If guard==NULL, the
317 call is unconditional. Returns True iff it managed to handle this
318 combination of arg/return types, else returns False. */
321 Bool doHelperCall ( ISelEnv* env,
323 IRExpr* guard, IRCallee* cee, IRExpr** args )
326 HReg argregs[ARM_N_ARGREGS];
327 HReg tmpregs[ARM_N_ARGREGS];
329 Int n_args, i, nextArgReg;
332 vassert(ARM_N_ARGREGS == 4);
334 /* Marshal args for a call and do the call.
336 If passBBP is True, r8 (the baseblock pointer) is to be passed
339 This function only deals with a tiny set of possibilities, which
340 cover all helpers in practice. The restrictions are that only
341 arguments in registers are supported, hence only ARM_N_REGPARMS
342 x 32 integer bits in total can be passed. In fact the only
343 supported arg types are I32 and I64.
345 Generating code which is both efficient and correct when
346 parameters are to be passed in registers is difficult, for the
347 reasons elaborated in detail in comments attached to
348 doHelperCall() in priv/host-x86/isel.c. Here, we use a variant
349 of the method described in those comments.
351 The problem is split into two cases: the fast scheme and the
352 slow scheme. In the fast scheme, arguments are computed
353 directly into the target (real) registers. This is only safe
354 when we can be sure that computation of each argument will not
355 trash any real registers set by computation of any other
358 In the slow scheme, all args are first computed into vregs, and
359 once they are all done, they are moved to the relevant real
360 regs. This always gives correct code, but it also gives a bunch
361 of vreg-to-rreg moves which are usually redundant but are hard
362 for the register allocator to get rid of.
364 To decide which scheme to use, all argument expressions are
365 first examined. If they are all so simple that it is clear they
366 will be evaluated without use of any fixed registers, use the
367 fast scheme, else use the slow scheme. Note also that only
368 unconditional calls may use the fast scheme, since having to
369 compute a condition expression could itself trash real
372 Note this requires being able to examine an expression and
373 determine whether or not evaluation of it might use a fixed
374 register. That requires knowledge of how the rest of this insn
375 selector works. Currently just the following 3 are regarded as
376 safe -- hopefully they cover the majority of arguments in
377 practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
380 /* Note that the cee->regparms field is meaningless on ARM hosts
381 (since there is only one calling convention) and so we always
385 for (i = 0; args[i]; i++)
388 argregs[0] = hregARM_R0();
389 argregs[1] = hregARM_R1();
390 argregs[2] = hregARM_R2();
391 argregs[3] = hregARM_R3();
393 tmpregs[0] = tmpregs[1] = tmpregs[2] =
394 tmpregs[3] = INVALID_HREG;
396 /* First decide which scheme (slow or fast) is to be used. First
397 assume the fast scheme, and select slow if any contraindications
403 if (guard->tag == Iex_Const
404 && guard->Iex.Const.con->tag == Ico_U1
405 && guard->Iex.Const.con->Ico.U1 == True) {
408 /* Not manifestly unconditional -- be conservative. */
414 for (i = 0; i < n_args; i++) {
415 if (mightRequireFixedRegs(args[i])) {
421 /* At this point the scheme to use has been established. Generate
422 code to get the arg values into the argument rregs. If we run
423 out of arg regs, give up. */
430 addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
435 for (i = 0; i < n_args; i++) {
436 IRType aTy = typeOfIRExpr(env->type_env, args[i]);
437 if (nextArgReg >= ARM_N_ARGREGS)
438 return False; /* out of argregs */
439 if (aTy == Ity_I32) {
440 addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
441 iselIntExpr_R(env, args[i]) ));
444 else if (aTy == Ity_I64) {
445 /* 64-bit args must be passed in an a reg-pair of the form
446 n:n+1, where n is even. Hence either r0:r1 or r2:r3.
447 On a little-endian host, the less significant word is
448 passed in the lower-numbered register. */
449 if (nextArgReg & 1) {
450 if (nextArgReg >= ARM_N_ARGREGS)
451 return False; /* out of argregs */
452 addInstr(env, ARMInstr_Imm32( argregs[nextArgReg], 0xAA ));
455 if (nextArgReg >= ARM_N_ARGREGS)
456 return False; /* out of argregs */
458 iselInt64Expr(&raHi, &raLo, env, args[i]);
459 addInstr(env, mk_iMOVds_RR( argregs[nextArgReg], raLo ));
461 addInstr(env, mk_iMOVds_RR( argregs[nextArgReg], raHi ));
465 return False; /* unhandled arg type */
468 /* Fast scheme only applies for unconditional calls. Hence: */
473 /* SLOW SCHEME; move via temporaries */
477 /* This is pretty stupid; better to move directly to r0
478 after the rest of the args are done. */
479 tmpregs[nextArgReg] = newVRegI(env);
480 addInstr(env, mk_iMOVds_RR( tmpregs[nextArgReg],
485 for (i = 0; i < n_args; i++) {
486 IRType aTy = typeOfIRExpr(env->type_env, args[i]);
487 if (nextArgReg >= ARM_N_ARGREGS)
488 return False; /* out of argregs */
489 if (aTy == Ity_I32) {
490 tmpregs[nextArgReg] = iselIntExpr_R(env, args[i]);
493 else if (aTy == Ity_I64) {
494 /* Same comment applies as in the Fast-scheme case. */
497 if (nextArgReg + 1 >= ARM_N_ARGREGS)
498 return False; /* out of argregs */
500 iselInt64Expr(&raHi, &raLo, env, args[i]);
501 tmpregs[nextArgReg] = raLo;
503 tmpregs[nextArgReg] = raHi;
508 /* Now we can compute the condition. We can't do it earlier
509 because the argument computations could trash the condition
510 codes. Be a bit clever to handle the common case where the
514 if (guard->tag == Iex_Const
515 && guard->Iex.Const.con->tag == Ico_U1
516 && guard->Iex.Const.con->Ico.U1 == True) {
517 /* unconditional -- do nothing */
519 cc = iselCondCode( env, guard );
523 /* Move the args to their final destinations. */
524 for (i = 0; i < nextArgReg; i++) {
525 if (tmpregs[i] == INVALID_HREG) { // Skip invalid regs
526 addInstr(env, ARMInstr_Imm32( argregs[i], 0xAA ));
529 /* None of these insns, including any spill code that might
530 be generated, may alter the condition codes. */
531 addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) );
536 /* Should be assured by checks above */
537 vassert(nextArgReg <= ARM_N_ARGREGS);
539 target = (HWord)Ptr_to_ULong(cee->addr);
541 /* nextArgReg doles out argument registers. Since these are
542 assigned in the order r0, r1, r2, r3, its numeric value at this
543 point, which must be between 0 and 4 inclusive, is going to be
544 equal to the number of arg regs in use for the call. Hence bake
545 that number into the call (we'll need to know it when doing
546 register allocation, to know what regs the call reads.)
548 There is a bit of a twist -- harmless but worth recording.
549 Suppose the arg types are (Ity_I32, Ity_I64). Then we will have
550 the first arg in r0 and the second in r3:r2, but r1 isn't used.
551 We nevertheless have nextArgReg==4 and bake that into the call
552 instruction. This will mean the register allocator wil believe
553 this insn reads r1 when in fact it doesn't. But that's
554 harmless; it just artificially extends the live range of r1
555 unnecessarily. The best fix would be to put into the
556 instruction, a bitmask indicating which of r0/1/2/3 carry live
557 values. But that's too much hassle. */
559 /* Finally, the call itself. */
560 addInstr(env, ARMInstr_Call( cc, target, nextArgReg ));
562 return True; /* success */
566 /*---------------------------------------------------------*/
567 /*--- ISEL: Integer expressions (32/16/8 bit) ---*/
568 /*---------------------------------------------------------*/
570 /* Select insns for an integer-typed expression, and add them to the
571 code list. Return a reg holding the result. This reg will be a
572 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
573 want to modify it, ask for a new vreg, copy it in there, and modify
574 the copy. The register allocator will do its best to map both
575 vregs to the same real register, so the copies will often disappear
578 This should handle expressions of 32, 16 and 8-bit type. All
579 results are returned in a 32-bit register. For 16- and 8-bit
580 expressions, the upper 16/24 bits are arbitrary, so you should mask
581 or sign extend partial values if necessary.
584 /* --------------------- AMode1 --------------------- */
586 /* Return an AMode1 which computes the value of the specified
587 expression, possibly also adding insns to the code list as a
588 result. The expression may only be a 32-bit one.
591 static Bool sane_AMode1 ( ARMAMode1* am )
596 toBool( hregClass(am->ARMam1.RI.reg) == HRcInt32
597 && (hregIsVirtual(am->ARMam1.RI.reg)
598 || am->ARMam1.RI.reg == hregARM_R8())
599 && am->ARMam1.RI.simm13 >= -4095
600 && am->ARMam1.RI.simm13 <= 4095 );
603 toBool( hregClass(am->ARMam1.RRS.base) == HRcInt32
604 && hregIsVirtual(am->ARMam1.RRS.base)
605 && hregClass(am->ARMam1.RRS.index) == HRcInt32
606 && hregIsVirtual(am->ARMam1.RRS.index)
607 && am->ARMam1.RRS.shift >= 0
608 && am->ARMam1.RRS.shift <= 3 );
610 vpanic("sane_AMode: unknown ARM AMode1 tag");
614 static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e )
616 ARMAMode1* am = iselIntExpr_AMode1_wrk(env, e);
617 vassert(sane_AMode1(am));
621 static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e )
623 IRType ty = typeOfIRExpr(env->type_env,e);
624 vassert(ty == Ity_I32);
626 /* FIXME: add RRS matching */
628 /* {Add32,Sub32}(expr,simm13) */
629 if (e->tag == Iex_Binop
630 && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
631 && e->Iex.Binop.arg2->tag == Iex_Const
632 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
633 Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
634 if (simm >= -4095 && simm <= 4095) {
636 if (e->Iex.Binop.op == Iop_Sub32)
638 reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
639 return ARMAMode1_RI(reg, simm);
643 /* Doesn't match anything in particular. Generate it into
644 a register and use that. */
646 HReg reg = iselIntExpr_R(env, e);
647 return ARMAMode1_RI(reg, 0);
653 /* --------------------- AMode2 --------------------- */
655 /* Return an AMode2 which computes the value of the specified
656 expression, possibly also adding insns to the code list as a
657 result. The expression may only be a 32-bit one.
660 static Bool sane_AMode2 ( ARMAMode2* am )
665 toBool( hregClass(am->ARMam2.RI.reg) == HRcInt32
666 && hregIsVirtual(am->ARMam2.RI.reg)
667 && am->ARMam2.RI.simm9 >= -255
668 && am->ARMam2.RI.simm9 <= 255 );
671 toBool( hregClass(am->ARMam2.RR.base) == HRcInt32
672 && hregIsVirtual(am->ARMam2.RR.base)
673 && hregClass(am->ARMam2.RR.index) == HRcInt32
674 && hregIsVirtual(am->ARMam2.RR.index) );
676 vpanic("sane_AMode: unknown ARM AMode2 tag");
680 static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e )
682 ARMAMode2* am = iselIntExpr_AMode2_wrk(env, e);
683 vassert(sane_AMode2(am));
687 static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e )
689 IRType ty = typeOfIRExpr(env->type_env,e);
690 vassert(ty == Ity_I32);
692 /* FIXME: add RR matching */
694 /* {Add32,Sub32}(expr,simm8) */
695 if (e->tag == Iex_Binop
696 && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
697 && e->Iex.Binop.arg2->tag == Iex_Const
698 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
699 Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
700 if (simm >= -255 && simm <= 255) {
702 if (e->Iex.Binop.op == Iop_Sub32)
704 reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
705 return ARMAMode2_RI(reg, simm);
709 /* Doesn't match anything in particular. Generate it into
710 a register and use that. */
712 HReg reg = iselIntExpr_R(env, e);
713 return ARMAMode2_RI(reg, 0);
719 /* --------------------- AModeV --------------------- */
721 /* Return an AModeV which computes the value of the specified
722 expression, possibly also adding insns to the code list as a
723 result. The expression may only be a 32-bit one.
726 static Bool sane_AModeV ( ARMAModeV* am )
728 return toBool( hregClass(am->reg) == HRcInt32
729 && hregIsVirtual(am->reg)
730 && am->simm11 >= -1020 && am->simm11 <= 1020
731 && 0 == (am->simm11 & 3) );
734 static ARMAModeV* iselIntExpr_AModeV ( ISelEnv* env, IRExpr* e )
736 ARMAModeV* am = iselIntExpr_AModeV_wrk(env, e);
737 vassert(sane_AModeV(am));
741 static ARMAModeV* iselIntExpr_AModeV_wrk ( ISelEnv* env, IRExpr* e )
743 IRType ty = typeOfIRExpr(env->type_env,e);
744 vassert(ty == Ity_I32);
746 /* {Add32,Sub32}(expr, simm8 << 2) */
747 if (e->tag == Iex_Binop
748 && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
749 && e->Iex.Binop.arg2->tag == Iex_Const
750 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
751 Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
752 if (simm >= -1020 && simm <= 1020 && 0 == (simm & 3)) {
754 if (e->Iex.Binop.op == Iop_Sub32)
756 reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
757 return mkARMAModeV(reg, simm);
761 /* Doesn't match anything in particular. Generate it into
762 a register and use that. */
764 HReg reg = iselIntExpr_R(env, e);
765 return mkARMAModeV(reg, 0);
771 /* --------------------- RI84 --------------------- */
773 /* Select instructions to generate 'e' into a RI84. If mayInv is
774 true, then the caller will also accept an I84 form that denotes
775 'not e'. In this case didInv may not be NULL, and *didInv is set
776 to True. This complication is so as to allow generation of an RI84
777 which is suitable for use in either an AND or BIC instruction,
778 without knowing (before this call) which one.
780 static ARMRI84* iselIntExpr_RI84 ( /*OUT*/Bool* didInv, Bool mayInv,
781 ISelEnv* env, IRExpr* e )
785 vassert(didInv != NULL);
786 ri = iselIntExpr_RI84_wrk(didInv, mayInv, env, e);
787 /* sanity checks ... */
792 vassert(hregClass(ri->ARMri84.R.reg) == HRcInt32);
793 vassert(hregIsVirtual(ri->ARMri84.R.reg));
796 vpanic("iselIntExpr_RI84: unknown arm RI84 tag");
800 /* DO NOT CALL THIS DIRECTLY ! */
801 static ARMRI84* iselIntExpr_RI84_wrk ( /*OUT*/Bool* didInv, Bool mayInv,
802 ISelEnv* env, IRExpr* e )
804 IRType ty = typeOfIRExpr(env->type_env,e);
805 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
807 if (didInv) *didInv = False;
809 /* special case: immediate */
810 if (e->tag == Iex_Const) {
811 UInt u, u8 = 0x100, u4 = 0x10; /* both invalid */
812 switch (e->Iex.Const.con->tag) {
813 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
814 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
815 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
816 default: vpanic("iselIntExpr_RI84.Iex_Const(armh)");
818 if (fitsIn8x4(&u8, &u4, u)) {
819 return ARMRI84_I84( (UShort)u8, (UShort)u4 );
821 if (mayInv && fitsIn8x4(&u8, &u4, ~u)) {
824 return ARMRI84_I84( (UShort)u8, (UShort)u4 );
826 /* else fail, fall through to default case */
829 /* default case: calculate into a register and return that */
831 HReg r = iselIntExpr_R ( env, e );
837 /* --------------------- RI5 --------------------- */
839 /* Select instructions to generate 'e' into a RI5. */
841 static ARMRI5* iselIntExpr_RI5 ( ISelEnv* env, IRExpr* e )
843 ARMRI5* ri = iselIntExpr_RI5_wrk(env, e);
844 /* sanity checks ... */
849 vassert(hregClass(ri->ARMri5.R.reg) == HRcInt32);
850 vassert(hregIsVirtual(ri->ARMri5.R.reg));
853 vpanic("iselIntExpr_RI5: unknown arm RI5 tag");
857 /* DO NOT CALL THIS DIRECTLY ! */
858 static ARMRI5* iselIntExpr_RI5_wrk ( ISelEnv* env, IRExpr* e )
860 IRType ty = typeOfIRExpr(env->type_env,e);
861 vassert(ty == Ity_I32 || ty == Ity_I8);
863 /* special case: immediate */
864 if (e->tag == Iex_Const) {
865 UInt u; /* both invalid */
866 switch (e->Iex.Const.con->tag) {
867 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
868 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
869 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
870 default: vpanic("iselIntExpr_RI5.Iex_Const(armh)");
872 if (u >= 1 && u <= 31) {
875 /* else fail, fall through to default case */
878 /* default case: calculate into a register and return that */
880 HReg r = iselIntExpr_R ( env, e );
886 /* ------------------- CondCode ------------------- */
888 /* Generate code to evaluated a bit-typed expression, returning the
889 condition code which would correspond when the expression would
890 notionally have returned 1. */
892 static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
894 ARMCondCode cc = iselCondCode_wrk(env,e);
895 vassert(cc != ARMcc_AL && cc != ARMcc_NV);
899 static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
902 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
905 if (e->tag == Iex_RdTmp) {
906 HReg rTmp = lookupIRTemp(env, e->Iex.RdTmp.tmp);
907 /* CmpOrTst doesn't modify rTmp; so this is OK. */
908 ARMRI84* one = ARMRI84_I84(1,0);
909 addInstr(env, ARMInstr_CmpOrTst(False/*test*/, rTmp, one));
914 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
915 /* Generate code for the arg, and negate the test condition */
916 return 1 ^ iselCondCode(env, e->Iex.Unop.arg);
919 /* --- patterns rooted at: 32to1 --- */
921 if (e->tag == Iex_Unop
922 && e->Iex.Unop.op == Iop_32to1) {
923 HReg rTmp = iselIntExpr_R(env, e->Iex.Unop.arg);
924 ARMRI84* one = ARMRI84_I84(1,0);
925 addInstr(env, ARMInstr_CmpOrTst(False/*test*/, rTmp, one));
929 /* --- patterns rooted at: CmpNEZ8 --- */
931 if (e->tag == Iex_Unop
932 && e->Iex.Unop.op == Iop_CmpNEZ8) {
933 HReg r1 = iselIntExpr_R(env, e->Iex.Unop.arg);
934 ARMRI84* xFF = ARMRI84_I84(0xFF,0);
935 addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r1, xFF));
939 /* --- patterns rooted at: CmpNEZ32 --- */
941 if (e->tag == Iex_Unop
942 && e->Iex.Unop.op == Iop_CmpNEZ32) {
943 HReg r1 = iselIntExpr_R(env, e->Iex.Unop.arg);
944 ARMRI84* zero = ARMRI84_I84(0,0);
945 addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, r1, zero));
949 /* --- patterns rooted at: CmpNEZ64 --- */
951 if (e->tag == Iex_Unop
952 && e->Iex.Unop.op == Iop_CmpNEZ64) {
954 HReg tmp = newVRegI(env);
955 ARMRI84* zero = ARMRI84_I84(0,0);
956 iselInt64Expr(&tHi, &tLo, env, e->Iex.Unop.arg);
957 addInstr(env, ARMInstr_Alu(ARMalu_OR, tmp, tHi, ARMRI84_R(tLo)));
958 addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, tmp, zero));
962 /* --- Cmp*32*(x,y) --- */
963 if (e->tag == Iex_Binop
964 && (e->Iex.Binop.op == Iop_CmpEQ32
965 || e->Iex.Binop.op == Iop_CmpNE32
966 || e->Iex.Binop.op == Iop_CmpLT32S
967 || e->Iex.Binop.op == Iop_CmpLT32U
968 || e->Iex.Binop.op == Iop_CmpLE32S
969 || e->Iex.Binop.op == Iop_CmpLE32U)) {
970 HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
971 ARMRI84* argR = iselIntExpr_RI84(NULL,False,
972 env, e->Iex.Binop.arg2);
973 addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, argL, argR));
974 switch (e->Iex.Binop.op) {
975 case Iop_CmpEQ32: return ARMcc_EQ;
976 case Iop_CmpNE32: return ARMcc_NE;
977 case Iop_CmpLT32S: return ARMcc_LT;
978 case Iop_CmpLT32U: return ARMcc_LO;
979 case Iop_CmpLE32S: return ARMcc_LE;
980 case Iop_CmpLE32U: return ARMcc_LS;
981 default: vpanic("iselCondCode(arm): CmpXX32");
986 vpanic("iselCondCode");
990 /* --------------------- Reg --------------------- */
992 static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
994 HReg r = iselIntExpr_R_wrk(env, e);
995 /* sanity checks ... */
997 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
999 vassert(hregClass(r) == HRcInt32);
1000 vassert(hregIsVirtual(r));
1004 /* DO NOT CALL THIS DIRECTLY ! */
1005 static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
1007 IRType ty = typeOfIRExpr(env->type_env,e);
1008 vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
1012 /* --------- TEMP --------- */
1014 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1017 /* --------- LOAD --------- */
1019 HReg dst = newVRegI(env);
1021 if (e->Iex.Load.end != Iend_LE)
1024 if (ty == Ity_I32) {
1025 ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr );
1026 addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, dst, amode));
1029 if (ty == Ity_I16) {
1030 ARMAMode2* amode = iselIntExpr_AMode2 ( env, e->Iex.Load.addr );
1031 addInstr(env, ARMInstr_LdSt16(True/*isLoad*/, False/*!signedLoad*/,
1036 ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr );
1037 addInstr(env, ARMInstr_LdSt8U(True/*isLoad*/, dst, amode));
1041 //zz if (ty == Ity_I16) {
1042 //zz addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1045 //zz if (ty == Ity_I8) {
1046 //zz addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
1052 //zz /* --------- TERNARY OP --------- */
1053 //zz case Iex_Triop: {
1054 //zz /* C3210 flags following FPU partial remainder (fprem), both
1055 //zz IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
1056 //zz if (e->Iex.Triop.op == Iop_PRemC3210F64
1057 //zz || e->Iex.Triop.op == Iop_PRem1C3210F64) {
1058 //zz HReg junk = newVRegF(env);
1059 //zz HReg dst = newVRegI(env);
1060 //zz HReg srcL = iselDblExpr(env, e->Iex.Triop.arg2);
1061 //zz HReg srcR = iselDblExpr(env, e->Iex.Triop.arg3);
1062 //zz /* XXXROUNDINGFIXME */
1063 //zz /* set roundingmode here */
1064 //zz addInstr(env, X86Instr_FpBinary(
1065 //zz e->Iex.Binop.op==Iop_PRemC3210F64
1066 //zz ? Xfp_PREM : Xfp_PREM1,
1069 //zz /* The previous pseudo-insn will have left the FPU's C3210
1070 //zz flags set correctly. So bag them. */
1071 //zz addInstr(env, X86Instr_FpStSW_AX());
1072 //zz addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
1073 //zz addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
1080 /* --------- BINARY OP --------- */
1083 ARMAluOp aop = 0; /* invalid */
1084 ARMShiftOp sop = 0; /* invalid */
1086 /* ADD/SUB/AND/OR/XOR */
1087 switch (e->Iex.Binop.op) {
1089 Bool didInv = False;
1090 HReg dst = newVRegI(env);
1091 HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1092 ARMRI84* argR = iselIntExpr_RI84(&didInv, True/*mayInv*/,
1093 env, e->Iex.Binop.arg2);
1094 addInstr(env, ARMInstr_Alu(didInv ? ARMalu_BIC : ARMalu_AND,
1098 case Iop_Or32: aop = ARMalu_OR; goto std_binop;
1099 case Iop_Xor32: aop = ARMalu_XOR; goto std_binop;
1100 case Iop_Sub32: aop = ARMalu_SUB; goto std_binop;
1101 case Iop_Add32: aop = ARMalu_ADD; goto std_binop;
1103 HReg dst = newVRegI(env);
1104 HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1105 ARMRI84* argR = iselIntExpr_RI84(NULL, False/*mayInv*/,
1106 env, e->Iex.Binop.arg2);
1107 addInstr(env, ARMInstr_Alu(aop, dst, argL, argR));
1114 switch (e->Iex.Binop.op) {
1115 case Iop_Shl32: sop = ARMsh_SHL; goto sh_binop;
1116 case Iop_Shr32: sop = ARMsh_SHR; goto sh_binop;
1117 case Iop_Sar32: sop = ARMsh_SAR; goto sh_binop;
1119 HReg dst = newVRegI(env);
1120 HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1121 ARMRI5* argR = iselIntExpr_RI5(env, e->Iex.Binop.arg2);
1122 addInstr(env, ARMInstr_Shift(sop, dst, argL, argR));
1123 vassert(ty == Ity_I32); /* else the IR is ill-typed */
1130 if (e->Iex.Binop.op == Iop_Mul32) {
1131 HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1132 HReg argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
1133 HReg dst = newVRegI(env);
1134 addInstr(env, mk_iMOVds_RR(hregARM_R2(), argL));
1135 addInstr(env, mk_iMOVds_RR(hregARM_R3(), argR));
1136 addInstr(env, ARMInstr_Mul(ARMmul_PLAIN));
1137 addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
1141 /* Handle misc other ops. */
1143 if (e->Iex.Binop.op == Iop_Max32U) {
1144 HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1145 HReg argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
1146 HReg dst = newVRegI(env);
1147 addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, argL, ARMRI84_R(argR)));
1148 addInstr(env, mk_iMOVds_RR(dst, argL));
1149 addInstr(env, ARMInstr_CMov(ARMcc_LO, dst, ARMRI84_R(argR)));
1153 if (e->Iex.Binop.op == Iop_CmpF64) {
1154 HReg dL = iselDblExpr(env, e->Iex.Binop.arg1);
1155 HReg dR = iselDblExpr(env, e->Iex.Binop.arg2);
1156 HReg dst = newVRegI(env);
1157 /* Do the compare (FCMPD) and set NZCV in FPSCR. Then also do
1158 FMSTAT, so we can examine the results directly. */
1159 addInstr(env, ARMInstr_VCmpD(dL, dR));
1160 /* Create in dst, the IRCmpF64Result encoded result. */
1161 addInstr(env, ARMInstr_Imm32(dst, 0));
1162 addInstr(env, ARMInstr_CMov(ARMcc_EQ, dst, ARMRI84_I84(0x40,0))); //EQ
1163 addInstr(env, ARMInstr_CMov(ARMcc_MI, dst, ARMRI84_I84(0x01,0))); //LT
1164 addInstr(env, ARMInstr_CMov(ARMcc_GT, dst, ARMRI84_I84(0x00,0))); //GT
1165 addInstr(env, ARMInstr_CMov(ARMcc_VS, dst, ARMRI84_I84(0x45,0))); //UN
1169 if (e->Iex.Binop.op == Iop_F64toI32S
1170 || e->Iex.Binop.op == Iop_F64toI32U) {
1171 /* Wretched uglyness all round, due to having to deal
1172 with rounding modes. Oh well. */
1173 /* FIXME: if arg1 is a constant indicating round-to-zero,
1174 then we could skip all this arsing around with FPSCR and
1175 simply emit FTO{S,U}IZD. */
1176 Bool syned = e->Iex.Binop.op == Iop_F64toI32S;
1177 HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
1178 set_VFP_rounding_mode(env, e->Iex.Binop.arg1);
1179 /* FTO{S,U}ID valF, valD */
1180 HReg valF = newVRegF(env);
1181 addInstr(env, ARMInstr_VCvtID(False/*!iToD*/, syned,
1183 set_VFP_rounding_default(env);
1184 /* VMOV dst, valF */
1185 HReg dst = newVRegI(env);
1186 addInstr(env, ARMInstr_VXferS(False/*!toS*/, valF, dst));
1193 /* --------- UNARY OP --------- */
1196 //zz /* 1Uto8(32to1(expr32)) */
1197 //zz if (e->Iex.Unop.op == Iop_1Uto8) {
1198 //zz DECLARE_PATTERN(p_32to1_then_1Uto8);
1199 //zz DEFINE_PATTERN(p_32to1_then_1Uto8,
1200 //zz unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
1201 //zz if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
1202 //zz IRExpr* expr32 = mi.bindee[0];
1203 //zz HReg dst = newVRegI(env);
1204 //zz HReg src = iselIntExpr_R(env, expr32);
1205 //zz addInstr(env, mk_iMOVsd_RR(src,dst) );
1206 //zz addInstr(env, X86Instr_Alu32R(Xalu_AND,
1207 //zz X86RMI_Imm(1), dst));
1212 //zz /* 8Uto32(LDle(expr32)) */
1213 //zz if (e->Iex.Unop.op == Iop_8Uto32) {
1214 //zz DECLARE_PATTERN(p_LDle8_then_8Uto32);
1215 //zz DEFINE_PATTERN(p_LDle8_then_8Uto32,
1216 //zz unop(Iop_8Uto32,
1217 //zz IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
1218 //zz if (matchIRExpr(&mi,p_LDle8_then_8Uto32,e)) {
1219 //zz HReg dst = newVRegI(env);
1220 //zz X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1221 //zz addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
1226 //zz /* 8Sto32(LDle(expr32)) */
1227 //zz if (e->Iex.Unop.op == Iop_8Sto32) {
1228 //zz DECLARE_PATTERN(p_LDle8_then_8Sto32);
1229 //zz DEFINE_PATTERN(p_LDle8_then_8Sto32,
1230 //zz unop(Iop_8Sto32,
1231 //zz IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
1232 //zz if (matchIRExpr(&mi,p_LDle8_then_8Sto32,e)) {
1233 //zz HReg dst = newVRegI(env);
1234 //zz X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1235 //zz addInstr(env, X86Instr_LoadEX(1,True,amode,dst));
1240 //zz /* 16Uto32(LDle(expr32)) */
1241 //zz if (e->Iex.Unop.op == Iop_16Uto32) {
1242 //zz DECLARE_PATTERN(p_LDle16_then_16Uto32);
1243 //zz DEFINE_PATTERN(p_LDle16_then_16Uto32,
1244 //zz unop(Iop_16Uto32,
1245 //zz IRExpr_Load(Iend_LE,Ity_I16,bind(0))) );
1246 //zz if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) {
1247 //zz HReg dst = newVRegI(env);
1248 //zz X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1249 //zz addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1254 //zz /* 8Uto32(GET:I8) */
1255 //zz if (e->Iex.Unop.op == Iop_8Uto32) {
1256 //zz if (e->Iex.Unop.arg->tag == Iex_Get) {
1258 //zz X86AMode* amode;
1259 //zz vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I8);
1260 //zz dst = newVRegI(env);
1261 //zz amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
1262 //zz hregX86_EBP());
1263 //zz addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
1268 //zz /* 16to32(GET:I16) */
1269 //zz if (e->Iex.Unop.op == Iop_16Uto32) {
1270 //zz if (e->Iex.Unop.arg->tag == Iex_Get) {
1272 //zz X86AMode* amode;
1273 //zz vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I16);
1274 //zz dst = newVRegI(env);
1275 //zz amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
1276 //zz hregX86_EBP());
1277 //zz addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1282 switch (e->Iex.Unop.op) {
1284 HReg dst = newVRegI(env);
1285 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1286 addInstr(env, ARMInstr_Alu(ARMalu_AND,
1287 dst, src, ARMRI84_I84(0xFF,0)));
1290 //zz case Iop_8Uto16:
1291 //zz case Iop_8Uto32:
1292 //zz case Iop_16Uto32: {
1293 //zz HReg dst = newVRegI(env);
1294 //zz HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1295 //zz UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF;
1296 //zz addInstr(env, mk_iMOVsd_RR(src,dst) );
1297 //zz addInstr(env, X86Instr_Alu32R(Xalu_AND,
1298 //zz X86RMI_Imm(mask), dst));
1301 //zz case Iop_8Sto16:
1302 //zz case Iop_8Sto32:
1304 HReg dst = newVRegI(env);
1305 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1306 ARMRI5* amt = ARMRI5_I5(16);
1307 addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, src, amt));
1308 addInstr(env, ARMInstr_Shift(ARMsh_SHR, dst, dst, amt));
1313 HReg dst = newVRegI(env);
1314 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1315 ARMRI5* amt = ARMRI5_I5(e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24);
1316 addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, src, amt));
1317 addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
1321 //zz case Iop_Not16:
1323 HReg dst = newVRegI(env);
1324 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1325 addInstr(env, ARMInstr_Unary(ARMun_NOT, dst, src));
1328 case Iop_64HIto32: {
1330 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1331 return rHi; /* and abandon rLo .. poor wee thing :-) */
1335 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1336 return rLo; /* similar stupid comment to the above ... */
1338 //zz case Iop_16HIto8:
1339 //zz case Iop_32HIto16: {
1340 //zz HReg dst = newVRegI(env);
1341 //zz HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1342 //zz Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
1343 //zz addInstr(env, mk_iMOVsd_RR(src,dst) );
1344 //zz addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, dst));
1349 HReg dst = newVRegI(env);
1350 ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1351 addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
1352 addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
1357 HReg dst = newVRegI(env);
1358 ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1359 ARMRI5* amt = ARMRI5_I5(31);
1360 /* This is really rough. We could do much better here;
1361 perhaps mvn{cond} dst, #0 as the second insn?
1362 (same applies to 1Sto64) */
1363 addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
1364 addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
1365 addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, dst, amt));
1366 addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
1371 //zz case Iop_1Sto8:
1372 //zz case Iop_1Sto16:
1373 //zz case Iop_1Sto32: {
1374 //zz /* could do better than this, but for now ... */
1375 //zz HReg dst = newVRegI(env);
1376 //zz X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1377 //zz addInstr(env, X86Instr_Set32(cond,dst));
1378 //zz addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, dst));
1379 //zz addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, dst));
1382 //zz case Iop_Ctz32: {
1383 //zz /* Count trailing zeroes, implemented by x86 'bsfl' */
1384 //zz HReg dst = newVRegI(env);
1385 //zz HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1386 //zz addInstr(env, X86Instr_Bsfr32(True,src,dst));
1390 /* Count leading zeroes; easy on ARM. */
1391 HReg dst = newVRegI(env);
1392 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1393 addInstr(env, ARMInstr_Unary(ARMun_CLZ, dst, src));
1397 case Iop_CmpwNEZ32: {
1398 HReg dst = newVRegI(env);
1399 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1400 addInstr(env, ARMInstr_Unary(ARMun_NEG, dst, src));
1401 addInstr(env, ARMInstr_Alu(ARMalu_OR, dst, dst, ARMRI84_R(src)));
1402 addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, ARMRI5_I5(31)));
1407 HReg dst = newVRegI(env);
1408 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1409 addInstr(env, ARMInstr_Unary(ARMun_NEG, dst, src));
1410 addInstr(env, ARMInstr_Alu(ARMalu_OR, dst, dst, ARMRI84_R(src)));
1414 //zz case Iop_V128to32: {
1415 //zz HReg dst = newVRegI(env);
1416 //zz HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
1417 //zz X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
1418 //zz sub_from_esp(env, 16);
1419 //zz addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
1420 //zz addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(esp0), dst ));
1421 //zz add_to_esp(env, 16);
1425 case Iop_ReinterpF32asI32: {
1426 HReg dst = newVRegI(env);
1427 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
1428 addInstr(env, ARMInstr_VXferS(False/*!toS*/, src, dst));
1433 //zz case Iop_16to8:
1436 /* These are no-ops. */
1437 return iselIntExpr_R(env, e->Iex.Unop.arg);
1445 /* --------- GET --------- */
1448 && 0 == (e->Iex.Get.offset & 3)
1449 && e->Iex.Get.offset < 4096-4) {
1450 HReg dst = newVRegI(env);
1451 addInstr(env, ARMInstr_LdSt32(
1454 ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset)));
1457 //zz if (ty == Ity_I8 || ty == Ity_I16) {
1458 //zz HReg dst = newVRegI(env);
1459 //zz addInstr(env, X86Instr_LoadEX(
1460 //zz toUChar(ty==Ity_I8 ? 1 : 2),
1462 //zz X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()),
1469 //zz case Iex_GetI: {
1471 //zz = genGuestArrayOffset(
1472 //zz env, e->Iex.GetI.descr,
1473 //zz e->Iex.GetI.ix, e->Iex.GetI.bias );
1474 //zz HReg dst = newVRegI(env);
1475 //zz if (ty == Ity_I8) {
1476 //zz addInstr(env, X86Instr_LoadEX( 1, False, am, dst ));
1479 //zz if (ty == Ity_I32) {
1480 //zz addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(am), dst));
1486 /* --------- CCALL --------- */
1488 HReg dst = newVRegI(env);
1489 vassert(ty == e->Iex.CCall.retty);
1491 /* be very restrictive for now. Only 32/64-bit ints allowed
1492 for args, and 32 bits for return type. */
1493 if (e->Iex.CCall.retty != Ity_I32)
1496 /* Marshal args, do the call, clear stack. */
1497 Bool ok = doHelperCall( env, False,
1498 NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
1500 addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
1503 /* else fall through; will hit the irreducible: label */
1506 /* --------- LITERAL --------- */
1510 HReg dst = newVRegI(env);
1511 switch (e->Iex.Const.con->tag) {
1512 case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
1513 case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
1514 case Ico_U8: u = 0xFF & (e->Iex.Const.con->Ico.U8); break;
1515 default: vpanic("iselIntExpr_R.Iex_Const(arm)");
1517 addInstr(env, ARMInstr_Imm32(dst, u));
1521 /* --------- MULTIPLEX --------- */
1523 IRExpr* cond = e->Iex.Mux0X.cond;
1525 /* Mux0X( 32to8(1Uto32(ccexpr)), expr0, exprX ) */
1527 && cond->tag == Iex_Unop
1528 && cond->Iex.Unop.op == Iop_32to8
1529 && cond->Iex.Unop.arg->tag == Iex_Unop
1530 && cond->Iex.Unop.arg->Iex.Unop.op == Iop_1Uto32) {
1532 HReg rX = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
1533 ARMRI84* r0 = iselIntExpr_RI84(NULL, False, env, e->Iex.Mux0X.expr0);
1534 HReg dst = newVRegI(env);
1535 addInstr(env, mk_iMOVds_RR(dst, rX));
1536 cc = iselCondCode(env, cond->Iex.Unop.arg->Iex.Unop.arg);
1537 addInstr(env, ARMInstr_CMov(cc ^ 1, dst, r0));
1541 /* Mux0X(cond, expr0, exprX) (general case) */
1542 if (ty == Ity_I32) {
1544 HReg rX = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
1545 ARMRI84* r0 = iselIntExpr_RI84(NULL, False, env, e->Iex.Mux0X.expr0);
1546 HReg dst = newVRegI(env);
1547 addInstr(env, mk_iMOVds_RR(dst, rX));
1548 r8 = iselIntExpr_R(env, cond);
1549 addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
1550 ARMRI84_I84(0xFF,0)));
1551 addInstr(env, ARMInstr_CMov(ARMcc_EQ, dst, r0));
1559 } /* switch (e->tag) */
1561 /* We get here if no pattern matched. */
1564 vpanic("iselIntExpr_R: cannot reduce tree");
1568 /* -------------------- 64-bit -------------------- */
1570 /* Compute a 64-bit value into a register pair, which is returned as
1571 the first two parameters. As with iselIntExpr_R, these may be
1572 either real or virtual regs; in any case they must not be changed
1573 by subsequent code emitted by the caller. */
1575 static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1577 iselInt64Expr_wrk(rHi, rLo, env, e);
1579 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1581 vassert(hregClass(*rHi) == HRcInt32);
1582 vassert(hregIsVirtual(*rHi));
1583 vassert(hregClass(*rLo) == HRcInt32);
1584 vassert(hregIsVirtual(*rLo));
1587 /* DO NOT CALL THIS DIRECTLY ! */
1588 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1591 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
1593 /* 64-bit literal */
1594 if (e->tag == Iex_Const) {
1595 ULong w64 = e->Iex.Const.con->Ico.U64;
1596 UInt wHi = toUInt(w64 >> 32);
1597 UInt wLo = toUInt(w64);
1598 HReg tHi = newVRegI(env);
1599 HReg tLo = newVRegI(env);
1600 vassert(e->Iex.Const.con->tag == Ico_U64);
1601 addInstr(env, ARMInstr_Imm32(tHi, wHi));
1602 addInstr(env, ARMInstr_Imm32(tLo, wLo));
1608 /* read 64-bit IRTemp */
1609 if (e->tag == Iex_RdTmp) {
1610 lookupIRTemp64( rHi, rLo, env, e->Iex.RdTmp.tmp);
1615 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
1617 vassert(e->Iex.Load.ty == Ity_I64);
1618 rA = iselIntExpr_R(env, e->Iex.Load.addr);
1619 tHi = newVRegI(env);
1620 tLo = newVRegI(env);
1621 addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, ARMAMode1_RI(rA, 4)));
1622 addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, ARMAMode1_RI(rA, 0)));
1629 if (e->tag == Iex_Get) {
1630 ARMAMode1* am0 = ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset + 0);
1631 ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset + 4);
1632 HReg tHi = newVRegI(env);
1633 HReg tLo = newVRegI(env);
1634 addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, am4));
1635 addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, am0));
1641 /* --------- BINARY ops --------- */
1642 if (e->tag == Iex_Binop) {
1643 switch (e->Iex.Binop.op) {
1645 /* 32 x 32 -> 64 multiply */
1648 HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1649 HReg argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
1650 HReg tHi = newVRegI(env);
1651 HReg tLo = newVRegI(env);
1652 ARMMulOp mop = e->Iex.Binop.op == Iop_MullS32
1653 ? ARMmul_SX : ARMmul_ZX;
1654 addInstr(env, mk_iMOVds_RR(hregARM_R2(), argL));
1655 addInstr(env, mk_iMOVds_RR(hregARM_R3(), argR));
1656 addInstr(env, ARMInstr_Mul(mop));
1657 addInstr(env, mk_iMOVds_RR(tHi, hregARM_R1()));
1658 addInstr(env, mk_iMOVds_RR(tLo, hregARM_R0()));
1665 HReg xLo, xHi, yLo, yHi;
1666 HReg tHi = newVRegI(env);
1667 HReg tLo = newVRegI(env);
1668 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
1669 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
1670 addInstr(env, ARMInstr_Alu(ARMalu_OR, tHi, xHi, ARMRI84_R(yHi)));
1671 addInstr(env, ARMInstr_Alu(ARMalu_OR, tLo, xLo, ARMRI84_R(yLo)));
1678 HReg xLo, xHi, yLo, yHi;
1679 HReg tHi = newVRegI(env);
1680 HReg tLo = newVRegI(env);
1681 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
1682 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
1683 addInstr(env, ARMInstr_Alu(ARMalu_ADDS, tLo, xLo, ARMRI84_R(yLo)));
1684 addInstr(env, ARMInstr_Alu(ARMalu_ADC, tHi, xHi, ARMRI84_R(yHi)));
1690 /* 32HLto64(e1,e2) */
1691 case Iop_32HLto64: {
1692 *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
1693 *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
1702 /* --------- UNARY ops --------- */
1703 if (e->tag == Iex_Unop) {
1704 switch (e->Iex.Unop.op) {
1706 /* ReinterpF64asI64 */
1707 case Iop_ReinterpF64asI64: {
1708 HReg dstHi = newVRegI(env);
1709 HReg dstLo = newVRegI(env);
1710 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
1711 addInstr(env, ARMInstr_VXferD(False/*!toD*/, src, dstHi, dstLo));
1720 HReg tHi = newVRegI(env);
1721 HReg tLo = newVRegI(env);
1722 HReg zero = newVRegI(env);
1724 iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg);
1726 addInstr(env, ARMInstr_Imm32(zero, 0));
1727 /* tLo = 0 - yLo, and set carry */
1728 addInstr(env, ARMInstr_Alu(ARMalu_SUBS, tLo, zero, ARMRI84_R(yLo)));
1729 /* tHi = 0 - yHi - carry */
1730 addInstr(env, ARMInstr_Alu(ARMalu_SBC, tHi, zero, ARMRI84_R(yHi)));
1731 /* So now we have tHi:tLo = -arg. To finish off, or 'arg'
1732 back in, so as to give the final result
1733 tHi:tLo = arg | -arg. */
1734 addInstr(env, ARMInstr_Alu(ARMalu_OR, tHi, tHi, ARMRI84_R(yHi)));
1735 addInstr(env, ARMInstr_Alu(ARMalu_OR, tLo, tLo, ARMRI84_R(yLo)));
1742 case Iop_CmpwNEZ64: {
1744 HReg tmp1 = newVRegI(env);
1745 HReg tmp2 = newVRegI(env);
1746 /* srcHi:srcLo = arg */
1747 iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
1748 /* tmp1 = srcHi | srcLo */
1749 addInstr(env, ARMInstr_Alu(ARMalu_OR,
1750 tmp1, srcHi, ARMRI84_R(srcLo)));
1751 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
1752 addInstr(env, ARMInstr_Unary(ARMun_NEG, tmp2, tmp1));
1753 addInstr(env, ARMInstr_Alu(ARMalu_OR,
1754 tmp2, tmp2, ARMRI84_R(tmp1)));
1755 addInstr(env, ARMInstr_Shift(ARMsh_SAR,
1756 tmp2, tmp2, ARMRI5_I5(31)));
1763 HReg dst = newVRegI(env);
1764 ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1765 ARMRI5* amt = ARMRI5_I5(31);
1766 /* This is really rough. We could do much better here;
1767 perhaps mvn{cond} dst, #0 as the second insn?
1768 (same applies to 1Sto32) */
1769 addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
1770 addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
1771 addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, dst, amt));
1772 addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
1781 } /* if (e->tag == Iex_Unop) */
1783 /* --------- MULTIPLEX --------- */
1784 if (e->tag == Iex_Mux0X) {
1786 HReg r8, rXhi, rXlo, r0hi, r0lo, dstHi, dstLo;
1787 ty8 = typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond);
1788 vassert(ty8 == Ity_I8);
1789 iselInt64Expr(&rXhi, &rXlo, env, e->Iex.Mux0X.exprX);
1790 iselInt64Expr(&r0hi, &r0lo, env, e->Iex.Mux0X.expr0);
1791 dstHi = newVRegI(env);
1792 dstLo = newVRegI(env);
1793 addInstr(env, mk_iMOVds_RR(dstHi, rXhi));
1794 addInstr(env, mk_iMOVds_RR(dstLo, rXlo));
1795 r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1796 addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
1797 ARMRI84_I84(0xFF,0)));
1798 addInstr(env, ARMInstr_CMov(ARMcc_EQ, dstHi, ARMRI84_R(r0hi)));
1799 addInstr(env, ARMInstr_CMov(ARMcc_EQ, dstLo, ARMRI84_R(r0lo)));
1806 vpanic("iselInt64Expr");
1810 /*---------------------------------------------------------*/
1811 /*--- ISEL: Floating point expressions (64 bit) ---*/
1812 /*---------------------------------------------------------*/
1814 /* Compute a 64-bit floating point value into a register, the identity
1815 of which is returned. As with iselIntExpr_R, the reg may be either
1816 real or virtual; in any case it must not be changed by subsequent
1817 code emitted by the caller. */
1819 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
1821 HReg r = iselDblExpr_wrk( env, e );
1823 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1825 vassert(hregClass(r) == HRcFlt64);
1826 vassert(hregIsVirtual(r));
1830 /* DO NOT CALL THIS DIRECTLY */
1831 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
1833 IRType ty = typeOfIRExpr(env->type_env,e);
1835 vassert(ty == Ity_F64);
1837 if (e->tag == Iex_RdTmp) {
1838 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1841 if (e->tag == Iex_Const) {
1842 /* Just handle the zero case. */
1843 IRConst* con = e->Iex.Const.con;
1844 if (con->tag == Ico_F64i && con->Ico.F64i == 0ULL) {
1845 HReg z32 = newVRegI(env);
1846 HReg dst = newVRegD(env);
1847 addInstr(env, ARMInstr_Imm32(z32, 0));
1848 addInstr(env, ARMInstr_VXferD(True/*toD*/, dst, z32, z32));
1853 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
1855 HReg res = newVRegD(env);
1856 vassert(e->Iex.Load.ty == Ity_F64);
1857 am = iselIntExpr_AModeV(env, e->Iex.Load.addr);
1858 addInstr(env, ARMInstr_VLdStD(True/*isLoad*/, res, am));
1862 if (e->tag == Iex_Get) {
1863 // XXX This won't work if offset > 1020 or is not 0 % 4.
1864 // In which case we'll have to generate more longwinded code.
1865 ARMAModeV* am = mkARMAModeV(hregARM_R8(), e->Iex.Get.offset);
1866 HReg res = newVRegD(env);
1867 addInstr(env, ARMInstr_VLdStD(True/*isLoad*/, res, am));
1871 if (e->tag == Iex_Unop) {
1872 switch (e->Iex.Unop.op) {
1873 case Iop_ReinterpI64asF64: {
1875 HReg dst = newVRegD(env);
1876 iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
1877 addInstr(env, ARMInstr_VXferD(True/*toD*/, dst, srcHi, srcLo));
1881 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
1882 HReg dst = newVRegD(env);
1883 addInstr(env, ARMInstr_VUnaryD(ARMvfpu_NEG, dst, src));
1887 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
1888 HReg dst = newVRegD(env);
1889 addInstr(env, ARMInstr_VUnaryD(ARMvfpu_ABS, dst, src));
1892 case Iop_F32toF64: {
1893 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
1894 HReg dst = newVRegD(env);
1895 addInstr(env, ARMInstr_VCvtSD(True/*sToD*/, dst, src));
1899 case Iop_I32StoF64: {
1900 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1901 HReg f32 = newVRegF(env);
1902 HReg dst = newVRegD(env);
1903 Bool syned = e->Iex.Unop.op == Iop_I32StoF64;
1905 addInstr(env, ARMInstr_VXferS(True/*toS*/, f32, src));
1906 /* FSITOD dst, f32 */
1907 addInstr(env, ARMInstr_VCvtID(True/*iToD*/, syned,
1916 if (e->tag == Iex_Binop) {
1917 switch (e->Iex.Binop.op) {
1919 /* first arg is rounding mode; we ignore it. */
1920 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
1921 HReg dst = newVRegD(env);
1922 addInstr(env, ARMInstr_VUnaryD(ARMvfpu_SQRT, dst, src));
1930 if (e->tag == Iex_Triop) {
1931 switch (e->Iex.Triop.op) {
1936 ARMVfpOp op = 0; /*INVALID*/
1937 HReg argL = iselDblExpr(env, e->Iex.Triop.arg2);
1938 HReg argR = iselDblExpr(env, e->Iex.Triop.arg3);
1939 HReg dst = newVRegD(env);
1940 switch (e->Iex.Triop.op) {
1941 case Iop_DivF64: op = ARMvfp_DIV; break;
1942 case Iop_MulF64: op = ARMvfp_MUL; break;
1943 case Iop_AddF64: op = ARMvfp_ADD; break;
1944 case Iop_SubF64: op = ARMvfp_SUB; break;
1945 default: vassert(0);
1947 addInstr(env, ARMInstr_VAluD(op, dst, argL, argR));
1955 if (e->tag == Iex_Mux0X) {
1957 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
1959 HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX);
1960 HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
1961 HReg dst = newVRegD(env);
1962 addInstr(env, ARMInstr_VUnaryD(ARMvfpu_COPY, dst, rX));
1963 r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1964 addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
1965 ARMRI84_I84(0xFF,0)));
1966 addInstr(env, ARMInstr_VCMovD(ARMcc_EQ, dst, r0));
1972 vpanic("iselDblExpr_wrk");
1976 /*---------------------------------------------------------*/
1977 /*--- ISEL: Floating point expressions (32 bit) ---*/
1978 /*---------------------------------------------------------*/
1980 /* Compute a 64-bit floating point value into a register, the identity
1981 of which is returned. As with iselIntExpr_R, the reg may be either
1982 real or virtual; in any case it must not be changed by subsequent
1983 code emitted by the caller. */
1985 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
1987 HReg r = iselFltExpr_wrk( env, e );
1989 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1991 vassert(hregClass(r) == HRcFlt32);
1992 vassert(hregIsVirtual(r));
1996 /* DO NOT CALL THIS DIRECTLY */
1997 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
1999 IRType ty = typeOfIRExpr(env->type_env,e);
2001 vassert(ty == Ity_F32);
2003 if (e->tag == Iex_RdTmp) {
2004 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2007 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
2009 HReg res = newVRegF(env);
2010 vassert(e->Iex.Load.ty == Ity_F32);
2011 am = iselIntExpr_AModeV(env, e->Iex.Load.addr);
2012 addInstr(env, ARMInstr_VLdStS(True/*isLoad*/, res, am));
2016 if (e->tag == Iex_Get) {
2017 // XXX This won't work if offset > 1020 or is not 0 % 4.
2018 // In which case we'll have to generate more longwinded code.
2019 ARMAModeV* am = mkARMAModeV(hregARM_R8(), e->Iex.Get.offset);
2020 HReg res = newVRegF(env);
2021 addInstr(env, ARMInstr_VLdStS(True/*isLoad*/, res, am));
2025 if (e->tag == Iex_Unop) {
2026 switch (e->Iex.Unop.op) {
2027 case Iop_ReinterpI32asF32: {
2028 HReg dst = newVRegF(env);
2029 HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
2030 addInstr(env, ARMInstr_VXferS(True/*toS*/, dst, src));
2034 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
2035 HReg dst = newVRegF(env);
2036 addInstr(env, ARMInstr_VUnaryS(ARMvfpu_NEG, dst, src));
2040 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
2041 HReg dst = newVRegF(env);
2042 addInstr(env, ARMInstr_VUnaryS(ARMvfpu_ABS, dst, src));
2050 if (e->tag == Iex_Binop) {
2051 switch (e->Iex.Binop.op) {
2053 /* first arg is rounding mode; we ignore it. */
2054 HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
2055 HReg dst = newVRegF(env);
2056 addInstr(env, ARMInstr_VUnaryS(ARMvfpu_SQRT, dst, src));
2059 case Iop_F64toF32: {
2060 HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
2061 set_VFP_rounding_mode(env, e->Iex.Binop.arg1);
2062 HReg valS = newVRegF(env);
2063 /* FCVTSD valS, valD */
2064 addInstr(env, ARMInstr_VCvtSD(False/*!sToD*/, valS, valD));
2065 set_VFP_rounding_default(env);
2073 if (e->tag == Iex_Triop) {
2074 switch (e->Iex.Triop.op) {
2079 ARMVfpOp op = 0; /*INVALID*/
2080 HReg argL = iselFltExpr(env, e->Iex.Triop.arg2);
2081 HReg argR = iselFltExpr(env, e->Iex.Triop.arg3);
2082 HReg dst = newVRegF(env);
2083 switch (e->Iex.Triop.op) {
2084 case Iop_DivF32: op = ARMvfp_DIV; break;
2085 case Iop_MulF32: op = ARMvfp_MUL; break;
2086 case Iop_AddF32: op = ARMvfp_ADD; break;
2087 case Iop_SubF32: op = ARMvfp_SUB; break;
2088 default: vassert(0);
2090 addInstr(env, ARMInstr_VAluS(op, dst, argL, argR));
2098 if (e->tag == Iex_Mux0X) {
2100 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
2102 HReg rX = iselFltExpr(env, e->Iex.Mux0X.exprX);
2103 HReg r0 = iselFltExpr(env, e->Iex.Mux0X.expr0);
2104 HReg dst = newVRegF(env);
2105 addInstr(env, ARMInstr_VUnaryS(ARMvfpu_COPY, dst, rX));
2106 r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
2107 addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
2108 ARMRI84_I84(0xFF,0)));
2109 addInstr(env, ARMInstr_VCMovS(ARMcc_EQ, dst, r0));
2115 vpanic("iselFltExpr_wrk");
2119 /*---------------------------------------------------------*/
2120 /*--- ISEL: Statements ---*/
2121 /*---------------------------------------------------------*/
2123 static void iselStmt ( ISelEnv* env, IRStmt* stmt )
2125 if (vex_traceflags & VEX_TRACE_VCODE) {
2126 vex_printf("\n-- ");
2130 switch (stmt->tag) {
2132 /* --------- STORE --------- */
2133 /* little-endian write to memory */
2135 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
2136 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2137 IREndness end = stmt->Ist.Store.end;
2139 if (tya != Ity_I32 || end != Iend_LE)
2142 if (tyd == Ity_I32) {
2143 HReg rD = iselIntExpr_R(env, stmt->Ist.Store.data);
2144 ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr);
2145 addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am));
2148 if (tyd == Ity_I16) {
2149 HReg rD = iselIntExpr_R(env, stmt->Ist.Store.data);
2150 ARMAMode2* am = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
2151 addInstr(env, ARMInstr_LdSt16(False/*!isLoad*/,
2152 False/*!isSignedLoad*/, rD, am));
2155 if (tyd == Ity_I8) {
2156 HReg rD = iselIntExpr_R(env, stmt->Ist.Store.data);
2157 ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr);
2158 addInstr(env, ARMInstr_LdSt8U(False/*!isLoad*/, rD, am));
2161 if (tyd == Ity_I64) {
2162 HReg rDhi, rDlo, rA;
2163 iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Store.data);
2164 rA = iselIntExpr_R(env, stmt->Ist.Store.addr);
2165 addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDhi,
2166 ARMAMode1_RI(rA,4)));
2167 addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDlo,
2168 ARMAMode1_RI(rA,0)));
2171 if (tyd == Ity_F64) {
2172 HReg dD = iselDblExpr(env, stmt->Ist.Store.data);
2173 ARMAModeV* am = iselIntExpr_AModeV(env, stmt->Ist.Store.addr);
2174 addInstr(env, ARMInstr_VLdStD(False/*!isLoad*/, dD, am));
2177 if (tyd == Ity_F32) {
2178 HReg fD = iselFltExpr(env, stmt->Ist.Store.data);
2179 ARMAModeV* am = iselIntExpr_AModeV(env, stmt->Ist.Store.addr);
2180 addInstr(env, ARMInstr_VLdStS(False/*!isLoad*/, fD, am));
2187 /* --------- PUT --------- */
2188 /* write guest state, fixed offset */
2190 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2192 if (tyd == Ity_I32) {
2193 HReg rD = iselIntExpr_R(env, stmt->Ist.Put.data);
2194 ARMAMode1* am = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset);
2195 addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am));
2198 if (tyd == Ity_I64) {
2200 ARMAMode1* am0 = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset + 0);
2201 ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset + 4);
2202 iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Put.data);
2203 addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDhi, am4));
2204 addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDlo, am0));
2207 if (tyd == Ity_F64) {
2208 // XXX This won't work if offset > 1020 or is not 0 % 4.
2209 // In which case we'll have to generate more longwinded code.
2210 ARMAModeV* am = mkARMAModeV(hregARM_R8(), stmt->Ist.Put.offset);
2211 HReg rD = iselDblExpr(env, stmt->Ist.Put.data);
2212 addInstr(env, ARMInstr_VLdStD(False/*!isLoad*/, rD, am));
2215 if (tyd == Ity_F32) {
2216 // XXX This won't work if offset > 1020 or is not 0 % 4.
2217 // In which case we'll have to generate more longwinded code.
2218 ARMAModeV* am = mkARMAModeV(hregARM_R8(), stmt->Ist.Put.offset);
2219 HReg rD = iselFltExpr(env, stmt->Ist.Put.data);
2220 addInstr(env, ARMInstr_VLdStS(False/*!isLoad*/, rD, am));
2226 //zz /* --------- Indexed PUT --------- */
2227 //zz /* write guest state, run-time offset */
2228 //zz case Ist_PutI: {
2230 //zz = genGuestArrayOffset(
2231 //zz env, stmt->Ist.PutI.descr,
2232 //zz stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
2234 //zz IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
2236 //zz if (tyd == Ity_I8) {
2237 //zz HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
2238 //zz addInstr(env, ARMInstr_StoreB(reg, am2));
2241 //zz// CAB: Ity_I32, Ity_I16 ?
2245 /* --------- TMP --------- */
2246 /* assign value to temporary */
2248 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2249 IRType ty = typeOfIRTemp(env->type_env, tmp);
2251 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
2252 ARMRI84* ri84 = iselIntExpr_RI84(NULL, False,
2253 env, stmt->Ist.WrTmp.data);
2254 HReg dst = lookupIRTemp(env, tmp);
2255 addInstr(env, ARMInstr_Mov(dst,ri84));
2259 HReg dst = lookupIRTemp(env, tmp);
2260 ARMCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data);
2261 addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
2262 addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
2265 if (ty == Ity_I64) {
2266 HReg rHi, rLo, dstHi, dstLo;
2267 iselInt64Expr(&rHi,&rLo, env, stmt->Ist.WrTmp.data);
2268 lookupIRTemp64( &dstHi, &dstLo, env, tmp);
2269 addInstr(env, mk_iMOVds_RR(dstHi, rHi) );
2270 addInstr(env, mk_iMOVds_RR(dstLo, rLo) );
2273 if (ty == Ity_F64) {
2274 HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
2275 HReg dst = lookupIRTemp(env, tmp);
2276 addInstr(env, ARMInstr_VUnaryD(ARMvfpu_COPY, dst, src));
2279 if (ty == Ity_F32) {
2280 HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data);
2281 HReg dst = lookupIRTemp(env, tmp);
2282 addInstr(env, ARMInstr_VUnaryS(ARMvfpu_COPY, dst, src));
2288 /* --------- Call to DIRTY helper --------- */
2289 /* call complex ("dirty") helper function */
2292 IRDirty* d = stmt->Ist.Dirty.details;
2293 Bool passBBP = False;
2295 if (d->nFxState == 0)
2296 vassert(!d->needsBBP);
2298 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2300 /* Marshal args, do the call, clear stack. */
2301 Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args );
2303 break; /* will go to stmt_fail: */
2305 /* Now figure out what to do with the returned value, if any. */
2306 if (d->tmp == IRTemp_INVALID)
2307 /* No return value. Nothing to do. */
2310 retty = typeOfIRTemp(env->type_env, d->tmp);
2312 if (retty == Ity_I64) {
2314 /* The returned value is in r1:r0. Park it in the
2315 register-pair associated with tmp. */
2316 lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
2317 addInstr(env, mk_iMOVds_RR(dstHi, hregARM_R1()) );
2318 addInstr(env, mk_iMOVds_RR(dstLo, hregARM_R0()) );
2321 if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
2322 /* The returned value is in r0. Park it in the register
2323 associated with tmp. */
2324 HReg dst = lookupIRTemp(env, d->tmp);
2325 addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()) );
2332 /* --------- Load Linked and Store Conditional --------- */
2334 if (stmt->Ist.LLSC.storedata == NULL) {
2336 IRTemp res = stmt->Ist.LLSC.result;
2337 IRType ty = typeOfIRTemp(env->type_env, res);
2338 if (ty == Ity_I32 || ty == Ity_I8) {
2340 HReg r_dst = lookupIRTemp(env, res);
2341 HReg raddr = iselIntExpr_R(env, stmt->Ist.LLSC.addr);
2343 case Ity_I8: szB = 1; break;
2344 case Ity_I32: szB = 4; break;
2345 default: vassert(0);
2347 addInstr(env, mk_iMOVds_RR(hregARM_R1(), raddr));
2348 addInstr(env, ARMInstr_LdrEX(szB));
2349 addInstr(env, mk_iMOVds_RR(r_dst, hregARM_R0()));
2352 /* else fall thru; is unhandled */
2355 IRTemp res = stmt->Ist.LLSC.result;
2356 IRType ty = typeOfIRTemp(env->type_env, res);
2357 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.storedata);
2358 vassert(ty == Ity_I1);
2359 if (tyd == Ity_I32 || tyd == Ity_I8) {
2361 HReg r_res = lookupIRTemp(env, res);
2362 HReg rD = iselIntExpr_R(env, stmt->Ist.LLSC.storedata);
2363 HReg rA = iselIntExpr_R(env, stmt->Ist.LLSC.addr);
2364 ARMRI84* one = ARMRI84_I84(1,0);
2366 case Ity_I8: szB = 1; break;
2367 case Ity_I32: szB = 4; break;
2368 default: vassert(0);
2370 addInstr(env, mk_iMOVds_RR(hregARM_R1(), rD));
2371 addInstr(env, mk_iMOVds_RR(hregARM_R2(), rA));
2372 addInstr(env, ARMInstr_StrEX(szB));
2373 /* now r0 is 1 if failed, 0 if success. Change to IR
2374 conventions (0 is fail, 1 is success). Also transfer
2376 addInstr(env, ARMInstr_Alu(ARMalu_XOR, r_res, hregARM_R0(), one));
2377 /* And be conservative -- mask off all but the lowest bit */
2378 addInstr(env, ARMInstr_Alu(ARMalu_AND, r_res, r_res, one));
2381 /* else fall thru; is unhandled */
2386 /* --------- MEM FENCE --------- */
2388 switch (stmt->Ist.MBE.event) {
2390 addInstr(env,ARMInstr_MFence());
2397 /* --------- INSTR MARK --------- */
2398 /* Doesn't generate any executable code ... */
2402 /* --------- NO-OP --------- */
2406 /* --------- EXIT --------- */
2410 if (stmt->Ist.Exit.dst->tag != Ico_U32)
2411 vpanic("isel_arm: Ist_Exit: dst is not a 32-bit value");
2412 gnext = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
2413 cc = iselCondCode(env, stmt->Ist.Exit.guard);
2414 addInstr(env, mk_iMOVds_RR(hregARM_R14(), env->savedLR));
2415 addInstr(env, ARMInstr_Goto(stmt->Ist.Exit.jk, cc, gnext));
2427 /*---------------------------------------------------------*/
2428 /*--- ISEL: Basic block terminators (Nexts) ---*/
2429 /*---------------------------------------------------------*/
2431 static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
2434 if (vex_traceflags & VEX_TRACE_VCODE) {
2435 vex_printf("\n-- goto {");
2441 rDst = iselIntExpr_R(env, next);
2442 addInstr(env, mk_iMOVds_RR(hregARM_R14(), env->savedLR));
2443 addInstr(env, ARMInstr_Goto(jk, ARMcc_AL, rDst));
2447 /*---------------------------------------------------------*/
2448 /*--- Insn selector top-level ---*/
2449 /*---------------------------------------------------------*/
2451 /* Translate an entire SB to arm code. */
2453 HInstrArray* iselSB_ARM ( IRSB* bb, VexArch arch_host,
2454 VexArchInfo* archinfo_host,
2455 VexAbiInfo* vbi/*UNUSED*/ )
2460 UInt hwcaps_host = archinfo_host->hwcaps;
2463 vassert(arch_host == VexArchARM);
2464 vassert(0 == hwcaps_host);
2466 /* Make up an initial environment to use. */
2467 env = LibVEX_Alloc(sizeof(ISelEnv));
2470 /* Set up output code array. */
2471 env->code = newHInstrArray();
2473 /* Copy BB's type env. */
2474 env->type_env = bb->tyenv;
2476 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2477 change as we go along. */
2478 env->n_vregmap = bb->tyenv->types_used;
2479 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2480 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2482 /* For each IR temporary, allocate a suitably-kinded virtual
2485 for (i = 0; i < env->n_vregmap; i++) {
2486 hregHI = hreg = INVALID_HREG;
2487 switch (bb->tyenv->types[i]) {
2491 case Ity_I32: hreg = mkHReg(j++, HRcInt32, True); break;
2492 case Ity_I64: hregHI = mkHReg(j++, HRcInt32, True);
2493 hreg = mkHReg(j++, HRcInt32, True); break;
2494 case Ity_F32: hreg = mkHReg(j++, HRcFlt32, True); break;
2495 case Ity_F64: hreg = mkHReg(j++, HRcFlt64, True); break;
2496 //case Ity_V128: hreg = mkHReg(j++, HRcVec128, True); break;
2497 default: ppIRType(bb->tyenv->types[i]);
2498 vpanic("iselBB: IRTemp type");
2500 env->vregmap[i] = hreg;
2501 env->vregmapHI[i] = hregHI;
2505 /* Keep a copy of the link reg, since any call to a helper function
2506 will trash it, and we can't get back to the dispatcher once that
2508 env->savedLR = newVRegI(env);
2509 addInstr(env, mk_iMOVds_RR(env->savedLR, hregARM_R14()));
2511 /* Ok, finally we can iterate over the statements. */
2512 for (i = 0; i < bb->stmts_used; i++)
2513 iselStmt(env,bb->stmts[i]);
2515 iselNext(env,bb->next,bb->jumpkind);
2517 /* record the number of vregs we used. */
2518 env->code->n_vregs = env->vreg_ctr;
2523 /*---------------------------------------------------------------*/
2524 /*--- end host_arm_isel.c ---*/
2525 /*---------------------------------------------------------------*/