blob: 092d3f5e6207a39310ca96bedc8f91efcb65e83c [file] [log] [blame]
cerioncee30312004-12-17 20:30:21 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (host-x86/isel.c) is ---*/
5/*--- Copyright (c) 2004 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 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
40#include "main/vex_util.h"
41#include "main/vex_globals.h"
42#include "host-generic/h_generic_regs.h"
43#include "host-arm/hdefs.h"
44
45
cerioncee30312004-12-17 20:30:21 +000046/*---------------------------------------------------------*/
47/*--- ISelEnv ---*/
48/*---------------------------------------------------------*/
49
50/* This carries around:
51
52 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
53 might encounter. This is computed before insn selection starts,
54 and does not change.
55
56 - A mapping from IRTemp to HReg. This tells the insn selector
57 which virtual register(s) are associated with each IRTemp
58 temporary. This is computed before insn selection starts, and
59 does not change. We expect this mapping to map precisely the
60 same set of IRTemps as the type mapping does.
61
62 - vregmap holds the primary register for the IRTemp.
63
64 - The code array, that is, the insns selected so far.
65
66 - A counter, for generating new virtual registers.
67
68 Note, this is all host-independent. */
69
70typedef
71 struct {
72 IRTypeEnv* type_env;
73
74 HReg* vregmap;
75 Int n_vregmap;
76
77 HInstrArray* code;
78
79 Int vreg_ctr;
80 }
81 ISelEnv;
82
83static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
84{
85 vassert(tmp >= 0);
86 vassert(tmp < env->n_vregmap);
87 return env->vregmap[tmp];
88}
89
90static void addInstr ( ISelEnv* env, ARMInstr* instr )
91{
92 addHInstr(env->code, instr);
93 if (vex_traceflags & VEX_TRACE_VCODE) {
94 ppARMInstr(instr);
95 vex_printf("\n");
96 }
97}
98
99static HReg newVRegI ( ISelEnv* env )
100{
101 HReg reg = mkHReg(env->vreg_ctr, HRcInt32, True/*virtual reg*/);
102 env->vreg_ctr++;
103 return reg;
104}
105
106
107
108/*---------------------------------------------------------*/
109/*--- ISEL: Forward declarations ---*/
110/*---------------------------------------------------------*/
111
112/* These are organised as iselXXX and iselXXX_wrk pairs. The
113 iselXXX_wrk do the real work, but are not to be called directly.
114 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
115 checks that all returned registers are virtual. You should not
116 call the _wrk version directly.
117*/
118static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e );
119static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e );
120
121static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e );
122static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e );
123
124static ARMAMode3* iselIntExpr_AMode3_wrk ( ISelEnv* env, IRExpr* e );
125static ARMAMode3* iselIntExpr_AMode3 ( ISelEnv* env, IRExpr* e );
126
127static ARMBranchDest* iselIntExpr_BD_wrk ( ISelEnv* env, IRExpr* e );
128static ARMBranchDest* iselIntExpr_BD ( ISelEnv* env, IRExpr* e );
129
130static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
131static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e );
132
133static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e );
134static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e );
135
136#if 0
137static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
138 ISelEnv* env, IRExpr* e );
139static void iselInt64Expr ( HReg* rHi, HReg* rLo,
140 ISelEnv* env, IRExpr* e );
141#endif
142
143
144/*---------------------------------------------------------*/
145/*--- ISEL: Misc helpers ---*/
146/*---------------------------------------------------------*/
147#if 0
148/* Is this a 32-bit zero expression? */
149static Bool isZero32 ( IRExpr* e )
150{
151 return e->tag == Iex_Const
152 && e->Iex.Const.con->tag == Ico_U32
153 && e->Iex.Const.con->Ico.U32 == 0;
154}
155#endif
156
157/* Make a int reg-reg move. */
158static ARMInstr* mk_iMOVsd_RR ( HReg src, HReg dst )
159{
160 vassert(hregClass(src) == HRcInt32);
161 vassert(hregClass(dst) == HRcInt32);
162 return ARMInstr_DPInstr1(ARMalu_MOV, dst, ARMAMode1_ShlI(src, 0));
163}
164
165#if 0
166/* Advance/retreat stack pointer by n. */
167
168static void add_to_sp ( ISelEnv* env, Int n )
169{
170 HReg tmp;
171 ARMImm12A imm12a;
172 vassert(n > 0 && n < 256 && (n%4) == 0);
173
174 if ( mk_ARMImm12A( (UInt)n, &imm12a ) ) {
175 addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD,
176 GET_SP_REG(), GET_SP_REG(),
177 ARMAMode1_I12A( imm12a )));
178 } else {
179 tmp = newVRegI(env);
180 addInstr(env, ARMInstr_Literal( tmp, (UInt)n ));
181 addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD,
182 GET_SP_REG(), GET_SP_REG(),
183 ARMAMode1_ShlI( tmp, 0 )));
184 }
185}
186
187static void sub_from_sp ( ISelEnv* env, Int n )
188{
189 HReg tmp;
190 ARMImm12A imm12a;
191 vassert(n > 0 && n < 256 && (n%4) == 0);
192
193 if ( mk_ARMImm12A( (UInt)n, &imm12a ) ) {
194 addInstr(env, ARMInstr_DPInstr2(ARMalu_SUB,
195 GET_SP_REG(), GET_SP_REG(),
196 ARMAMode1_I12A( imm12a )));
197 } else {
198 tmp = newVRegI(env);
199 addInstr(env, ARMInstr_Literal( tmp, (UInt)n ));
200 addInstr(env, ARMInstr_DPInstr2(ARMalu_SUB,
201 GET_SP_REG(), GET_SP_REG(),
202 ARMAMode1_ShlI( tmp, 0 )));
203 }
204}
205#endif
206
207#if 0
208/* Push an arg onto the host stack, in preparation for a call to a
209 helper function of some kind. Returns the number of 32-bit words
210 pushed. */
211
212static Int pushArg ( ISelEnv* env, IRExpr* arg )
213{
214 IRType arg_ty = typeOfIRExpr(env->type_env, arg);
215 if (arg_ty == Ity_I32) {
216
217 // CAB: This right?
218 addInstr(env, ARMInstr_StoreW( GET_SP_REG(), iselIntExpr_AMode2(env, arg) ) );
219 return 1;
220 }
221
222#if 0
223 else
224 if (arg_ty == Ity_I64) {
225 HReg rHi, rLo;
226 iselInt64Expr(&rHi, &rLo, env, arg);
227 addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
228 addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
229 return 2;
230 }
231#endif
232 ppIRExpr(arg);
233 vpanic("pushArg(arm): can't handle arg of this type");
234}
235#endif
236
237#if 0
238/* Complete the call to a helper function, by calling the
239 helper and clearing the args off the stack. */
240
241static
242void callHelperAndClearArgs ( ISelEnv* env, ARMCondCode cc,
243 IRCallee* cee, Int n_arg_ws )
244{
245 /* Complication. Need to decide which reg to use as the fn address
246 pointer, in a way that doesn't trash regparm-passed
247 parameters. */
248 vassert(sizeof(void*) == 4);
249
250// CAB: cee->regparms ?
251
252// addInstr(env, X86Instr_Call( cc, (UInt)cee->addr, cee->regparms));
253 ARMBranchDest* dst = ARMBranchDest_Imm( (UInt)cee->addr );
254 addInstr(env, ARMInstr_BranchL(cc, dst));
255
256 if (n_arg_ws > 0)
257 add_to_sp(env, 4*n_arg_ws);
258}
259#endif
260
261#if 0
262/* Used only in doHelperCall. See big comment in doHelperCall re
263 handling of regparm args. This function figures out whether
264 evaluation of an expression might require use of a fixed register.
265 If in doubt return True (safe but suboptimal).
266*/
267static
268Bool mightRequireFixedRegs ( IRExpr* e )
269{
270 switch (e->tag) {
271 case Iex_Tmp: case Iex_Const: case Iex_Get:
272 return False;
273 default:
274 return True;
275 }
276}
277#endif
278
279/* Do a complete function call. guard is a Ity_Bit expression
280 indicating whether or not the call happens. If guard==NULL, the
281 call is unconditional. */
282
283static
284void doHelperCall ( ISelEnv* env,
285 Bool passBBP,
286 IRExpr* guard, IRCallee* cee, IRExpr** args )
287{
288#if 0
289 ARMCondCode cc;
290 HReg argregs[3];
291 HReg tmpregs[3];
292 Bool danger;
293 Int not_done_yet, n_args, n_arg_ws, stack_limit,
294 i, argreg, argregX;
295
296 /* Marshal args for a call, do the call, and clear the stack.
297 Complexities to consider:
298
299 * if passBBP is True, %ebp (the baseblock pointer) is to be
300 passed as the first arg.
301
302 * If the callee claims regparmness of 1, 2 or 3, we must pass the
303 first 1, 2 or 3 args in registers (EAX, EDX, and ECX
304 respectively). To keep things relatively simple, only args of
305 type I32 may be passed as regparms -- just bomb out if anything
306 else turns up. Clearly this depends on the front ends not
307 trying to pass any other types as regparms.
308 */
309
310 /* 16 Nov 2004: the regparm handling is complicated by the
311 following problem.
312
313 Consider a call two a function with two regparm parameters:
314 f(e1,e2). We need to compute e1 into %eax and e2 into %edx.
315 Suppose code is first generated to compute e1 into %eax. Then,
316 code is generated to compute e2 into %edx. Unfortunately, if
317 the latter code sequence uses %eax, it will trash the value of
318 e1 computed by the former sequence. This could happen if (for
319 example) e2 itself involved a function call. In the code below,
320 args are evaluated right-to-left, not left-to-right, but the
321 principle and the problem are the same.
322
323 One solution is to compute all regparm-bound args into vregs
324 first, and once they are all done, move them to the relevant
325 real regs. This always gives correct code, but it also gives
326 a bunch of vreg-to-rreg moves which are usually redundant but
327 are hard for the register allocator to get rid of.
328
329 A compromise is to first examine all regparm'd argument
330 expressions. If they are all so simple that it is clear
331 they will be evaluated without use of any fixed registers,
332 use the old compute-directly-to-fixed-target scheme. If not,
333 be safe and use the via-vregs scheme.
334
335 Note this requires being able to examine an expression and
336 determine whether or not evaluation of it might use a fixed
337 register. That requires knowledge of how the rest of this
338 insn selector works. Currently just the following 3 are
339 regarded as safe -- hopefully they cover the majority of
340 arguments in practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
341 */
342 vassert(cee->regparms >= 0 && cee->regparms <= 3);
343
344 n_args = n_arg_ws = 0;
345 while (args[n_args]) n_args++;
346
347 not_done_yet = n_args;
348 if (passBBP)
349 not_done_yet++;
350
351 stack_limit = cee->regparms;
352 if (cee->regparms > 0 && passBBP) stack_limit--;
353
354 /* ------ BEGIN marshall all arguments ------ */
355
356 /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */
357 for (i = n_args-1; i >= stack_limit; i--) {
358 n_arg_ws += pushArg(env, args[i]);
359 not_done_yet--;
360 }
361
362 /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in
363 registers. */
364
365 if (cee->regparms > 0) {
366
367 /* ------ BEGIN deal with regparms ------ */
368
369 /* deal with regparms, not forgetting %ebp if needed. */
370 argregs[0] = hregX86_EAX();
371 argregs[1] = hregX86_EDX();
372 argregs[2] = hregX86_ECX();
373 tmpregs[0] = tmpregs[1] = tmpregs[2] = INVALID_HREG;
374
375 argreg = cee->regparms;
376
377 /* In keeping with big comment above, detect potential danger
378 and use the via-vregs scheme if needed. */
379 danger = False;
380 for (i = stack_limit-1; i >= 0; i--) {
381 if (mightRequireFixedRegs(args[i])) {
382 danger = True;
383 break;
384 }
385 }
386
387 if (danger) {
388
389 /* Move via temporaries */
390 argregX = argreg;
391 for (i = stack_limit-1; i >= 0; i--) {
392
393 if (0) {
394 vex_printf("x86 host: register param is complex: ");
395 ppIRExpr(args[i]);
396 vex_printf("\n");
397 }
398
399 argreg--;
400 vassert(argreg >= 0);
401 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
402 tmpregs[argreg] = iselIntExpr_R(env, args[i]);
403 not_done_yet--;
404 }
405 for (i = stack_limit-1; i >= 0; i--) {
406 argregX--;
407 vassert(argregX >= 0);
408 addInstr( env, mk_iMOVsd_RR( tmpregs[argregX], argregs[argregX] ) );
409 }
410
411 } else {
412 /* It's safe to compute all regparm args directly into their
413 target registers. */
414 for (i = stack_limit-1; i >= 0; i--) {
415 argreg--;
416 vassert(argreg >= 0);
417 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
418 addInstr(env, X86Instr_Alu32R(Xalu_MOV,
419 iselIntExpr_RMI(env, args[i]),
420 argregs[argreg]));
421 not_done_yet--;
422 }
423
424 }
425
426 /* Not forgetting %ebp if needed. */
427 if (passBBP) {
428 vassert(argreg == 1);
429 addInstr(env, mk_iMOVsd_RR( hregX86_EBP(), argregs[0]));
430 not_done_yet--;
431 }
432
433 /* ------ END deal with regparms ------ */
434
435 } else {
436
437 /* No regparms. Heave %ebp on the stack if needed. */
438 if (passBBP) {
439 addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
440 n_arg_ws++;
441 not_done_yet--;
442 }
443
444 }
445
446 vassert(not_done_yet == 0);
447
448 /* ------ END marshall all arguments ------ */
449
450 /* Now we can compute the condition. We can't do it earlier
451 because the argument computations could trash the condition
452 codes. Be a bit clever to handle the common case where the
453 guard is 1:Bit. */
454 cc = Xcc_ALWAYS;
455 if (guard) {
456 if (guard->tag == Iex_Const
457 && guard->Iex.Const.con->tag == Ico_U1
458 && guard->Iex.Const.con->Ico.U1 == True) {
459 /* unconditional -- do nothing */
460 } else {
461 cc = iselCondCode( env, guard );
462 }
463 }
464
465 /* call the helper, and get the args off the stack afterwards. */
466 callHelperAndClearArgs( env, cc, cee, n_arg_ws );
467#endif
468}
469
470
471
472// CAB: Do we need to deal with elemSz != 8 ?
473
474/* Given a guest-state array descriptor, an index expression and a
475 bias, generate an ARMAMode holding the relevant guest state
476 offset. */
477
478static
479ARMAMode2* genGuestArrayOffset ( ISelEnv* env, IRArray* descr,
480 IRExpr* off, Int bias )
481{
482 HReg tmp, tmp2, roff;
483 Int elemSz = sizeofIRType(descr->elemTy);
484 Int nElems = descr->nElems;
485 ARMImm12A imm12a;
486
487 /* throw out any cases not generated by an x86 front end. In
488 theory there might be a day where we need to handle them -- if
489 we ever run non-x86-guest on x86 host. */
490
491 if (nElems != 8 || (elemSz != 1 && elemSz != 8))
492 vpanic("genGuestArrayOffset(arm host)");
493
494 /* Compute off into a reg, %off. Then return:
495
496 movl %off, %tmp
497 addl $bias, %tmp (if bias != 0)
498 andl %tmp, 7
499 ... base(%ebp, %tmp, shift) ...
500 */
501 tmp = newVRegI(env);
502 roff = iselIntExpr_R(env, off);
503 addInstr(env, mk_iMOVsd_RR(roff, tmp));
504 if (bias != 0) {
505 if ( mk_ARMImm12A( (UInt)bias, &imm12a ) ) {
506 addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp, tmp,
507 ARMAMode1_I12A( imm12a )));
508 } else {
509 HReg tmp3 = newVRegI(env);
510 addInstr(env, ARMInstr_Literal( tmp, (UInt)bias ));
511 addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp, tmp,
512 ARMAMode1_ShlI( tmp3, 0 )));
513 }
514 }
515
516 mk_ARMImm12A( (UInt)7, &imm12a );
517 addInstr(env, ARMInstr_DPInstr2(ARMalu_AND, tmp, tmp,
518 ARMAMode1_I12A( imm12a )));
519 vassert(elemSz == 1 || elemSz == 8);
520
521
522
523// CAB: This anywhere near correct?
524
525// X86AMode_IRRS: Immediate + Reg1 + (Reg2 << Shift)
526// return X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, elemSz==8 ? 3 : 0);
527
528 tmp2 = newVRegI(env); // tmp2 = GET_BP_REG + (tmp << 3|0)
529 addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp2, GET_BP_REG(),
530 ARMAMode1_ShlI(tmp, elemSz==8 ? 3 : 0)));
531 return ARMAMode2_RI( tmp2, descr->base );
532}
533
534
535/*---------------------------------------------------------*/
536/*--- ISEL ... ---*/
537/*---------------------------------------------------------*/
538
539/* --------------------- AMODEs --------------------- */
540
541/* Return an AMode which computes the value of the specified
542 expression, possibly also adding insns to the code list as a
543 result.
544*/
545
546/* ---------------- Addressing Mode 1 ---------------- */
547
548static Bool sane_AMode1 ( ARMAMode1* am )
549{
550 switch (am->tag) {
551 default:
552 vpanic("sane_AMode1: unknown arm amode tag");
553 }
554}
555
556static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e )
557{
558 ARMAMode1* am = iselIntExpr_AMode1_wrk(env, e);
559 vassert(sane_AMode1(am));
560 return am;
561}
562
563/* DO NOT CALL THIS DIRECTLY ! */
564static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e )
565{
566 IRType ty = typeOfIRExpr(env->type_env,e);
567 vassert(ty == Ity_I32);
568
569 // ARMam1_I12A, /* Imm12A: extended (rotated) immedate */
570 // ARMam1_ShlI, /* ShlI reg Imm5 */
571 // ARMam1_ShrI, /* ShrI reg Imm5 */
572 // ARMam1_SarI, /* SarI reg Imm5 */
573 // ARMam1_ShlR, /* ShlR reg reg */
574 // ARMam1_ShrR, /* ShrR reg reg */
575 // ARMam1_SarR, /* SarR reg reg */
576
577 // ALU ops:
578 /*
579 ARMalu_And, ARMalu_Orr, ARMalu_Eor, ARMalu_Bic, // Logic
580 ARMalu_Sub, ARMalu_Rsb, ARMalu_Add, ARMalu_Adc, ARMalu_Sbc, ARMalu_Rsc, // Arith
581 ARMalu_Tst, ARMalu_Teq, ARMalu_Cmp, ARMalu_Cmn, // test
582 ARMalu_Mov, ARMalu_Mvn // Move
583 */
584
585
586 return NULL;
587}
588
589
590
591/* ---------------- Addressing Mode 2 ---------------- */
592
593static Bool sane_AMode2 ( ARMAMode2* am )
594{
595 switch (am->tag) {
596 default:
597 vpanic("sane_AMode2: unknown arm amode tag");
598 }
599}
600
601static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e )
602{
603 ARMAMode2* am = iselIntExpr_AMode2_wrk(env, e);
604 vassert(sane_AMode2(am));
605 return am;
606}
607
608/* DO NOT CALL THIS DIRECTLY ! */
609static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e )
610{
611 IRType ty = typeOfIRExpr(env->type_env,e);
612 vassert(ty == Ity_I32);
613
614 // ARMam2_RI, /* Reg +/- Imm12 */
615 // ARMam2_RR, /* Reg +/- Reg */
616 // ARMam2_RRS, /* Reg +/- (Reg << Imm5) */
617
618 return NULL;
619}
620
621
622
623/* ---------------- Addressing Mode 3 ---------------- */
624
625static Bool sane_AMode3 ( ARMAMode3* am )
626{
627 switch (am->tag) {
628 default:
629 vpanic("sane_AMode3: unknown arm amode tag");
630 }
631}
632
633static ARMAMode3* iselIntExpr_AMode3 ( ISelEnv* env, IRExpr* e )
634{
635 ARMAMode3* am = iselIntExpr_AMode3_wrk(env, e);
636 vassert(sane_AMode3(am));
637 return am;
638}
639
640/* DO NOT CALL THIS DIRECTLY ! */
641static ARMAMode3* iselIntExpr_AMode3_wrk ( ISelEnv* env, IRExpr* e )
642{
643 IRType ty = typeOfIRExpr(env->type_env,e);
644 vassert(ty == Ity_I32);
645
646 // ARMam3_RI, /* Reg +/- Imm8 */
647 // ARMam3_RR, /* Reg +/- Reg */
648
649 return NULL;
650}
651
652
653
654/* ---------------- Branch Destination ---------------- */
655
656static ARMBranchDest* iselIntExpr_BD ( ISelEnv* env, IRExpr* e )
657{
658 ARMBranchDest* bd = iselIntExpr_BD_wrk(env, e);
659 /* sanity checks ... */
660 switch (bd->tag) {
661 case ARMbdImm:
662 return bd;
663 case ARMbdReg:
664 vassert(hregClass(bd->ARMbd.Reg.reg) == HRcInt32);
665// vassert(hregIsVirtual(bd->ARMbd.Reg.reg)); // CAB ?
666 return bd;
667 default:
668 vpanic("iselIntExpr_BD: unknown arm BD tag");
669 }
670}
671
672/* DO NOT CALL THIS DIRECTLY ! */
673static ARMBranchDest* iselIntExpr_BD_wrk ( ISelEnv* env, IRExpr* e )
674{
675 /*
676 ARMbdImm,
677 ARMbdReg
678 */
679
680 return NULL;
681}
682
683
684
685
686
687/* --------------------- CONDCODE --------------------- */
688
689/* Generate code to evaluated a bit-typed expression, returning the
690 condition code which would correspond when the expression would
691 notionally have returned 1. */
692
693static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
694{
695 /* Uh, there's nothing we can sanity check here, unfortunately. */
696 return iselCondCode_wrk(env, e);
697}
698
699/* DO NOT CALL THIS DIRECTLY ! */
700static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
701{
702#if 0
703 MatchInfo mi;
704 DECLARE_PATTERN(p_32to1);
705 DECLARE_PATTERN(p_1Uto32_then_32to1);
706#endif
707
708 return 0;
709}
710
711
712
713static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
714{
715 return iselIntExpr_R_wrk(env, e);
716}
717
718/* DO NOT CALL THIS DIRECTLY ! */
719static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
720{
721 return 0;
722}
723
724
725
726/*---------------------------------------------------------*/
727/*--- ISEL: Statements ---*/
728/*---------------------------------------------------------*/
729
730static void iselStmt ( ISelEnv* env, IRStmt* stmt )
731{
732 if (vex_traceflags & VEX_TRACE_VCODE) {
733 vex_printf("\n-- ");
734 ppIRStmt(stmt);
735 vex_printf("\n");
736 }
737 switch (stmt->tag) {
738
739 /* --------- STORE --------- */
740 /* little-endian write to memory */
741 case Ist_STle: {
742 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.STle.addr);
743 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.STle.data);
744 vassert(tya == Ity_I32);
745 HReg reg = iselIntExpr_R(env, stmt->Ist.STle.data);
746
747 if (tyd == Ity_I8) {
748 ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.STle.addr);
749 addInstr(env, ARMInstr_StoreB(reg,am2));
750 return;
751 }
752 if (tyd == Ity_I16) {
753 ARMAMode3* am3 = iselIntExpr_AMode3(env, stmt->Ist.STle.addr);
754 addInstr(env, ARMInstr_StoreH(reg,am3));
755 return;
756 }
757 if (tyd == Ity_I32) {
758 ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.STle.addr);
759 addInstr(env, ARMInstr_StoreW(reg,am2));
760 return;
761 }
762 }
763
764 /* --------- PUT --------- */
765 /* write guest state, fixed offset */
766 case Ist_Put: {
767 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
768 HReg reg = iselIntExpr_R(env, stmt->Ist.Put.data);
769
770 // CAB: This anywhere near right?!
771 if (tyd == Ity_I32) {
772 ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
773 addInstr(env, ARMInstr_StoreW(reg, am2));
774 return;
775 }
776 if (tyd == Ity_I16) {
777 ARMAMode3* am3 = ARMAMode3_RI(GET_BP_REG(), stmt->Ist.Put.offset);
778 addInstr(env, ARMInstr_StoreH(reg, am3));
779 return;
780 }
781 if (tyd == Ity_I8) {
782 ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
783 addInstr(env, ARMInstr_StoreB(reg, am2));
784 return;
785 }
786// CAB: Ity_I32, Ity_I16 ?
787 break;
788 }
789
790 /* --------- Indexed PUT --------- */
791 /* write guest state, run-time offset */
792 case Ist_PutI: {
793 ARMAMode2* am2
794 = genGuestArrayOffset(
795 env, stmt->Ist.PutI.descr,
796 stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
797
798 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
799
800 if (tyd == Ity_I8) {
801 HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
802 addInstr(env, ARMInstr_StoreB(reg, am2));
803 return;
804 }
805// CAB: Ity_I32, Ity_I16 ?
806 break;
807 }
808
809 /* --------- TMP --------- */
810 /* assign value to temporary */
811 case Ist_Tmp: {
812 IRTemp tmp = stmt->Ist.Tmp.tmp;
813 IRType ty = typeOfIRTemp(env->type_env, tmp);
814
815 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
816 ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Tmp.data);
817 HReg dst = lookupIRTemp(env, tmp);
818 addInstr(env, ARMInstr_DPInstr1(ARMalu_MOV,dst,am));
819 return;
820 }
821
822// CAB: Ity_I1 ?
823
824 break;
825 }
826
827 /* --------- Call to DIRTY helper --------- */
828 /* call complex ("dirty") helper function */
829 case Ist_Dirty: {
830 IRType retty;
831 IRDirty* d = stmt->Ist.Dirty.details;
832 Bool passBBP = False;
833
834 if (d->nFxState == 0)
835 vassert(!d->needsBBP);
836 passBBP = d->nFxState > 0 && d->needsBBP;
837
838 /* Marshal args, do the call, clear stack. */
839 doHelperCall( env, passBBP, d->guard, d->cee, d->args );
840
841 /* Now figure out what to do with the returned value, if any. */
842 if (d->tmp == IRTemp_INVALID)
843 /* No return value. Nothing to do. */
844 return;
845
846 retty = typeOfIRTemp(env->type_env, d->tmp);
847
848// CAB: ? if (retty == Ity_I64) {
849
850#if 0
851 if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
852 /* The returned value is in %eax. Park it in the register
853 associated with tmp. */
854 HReg dst = lookupIRTemp(env, d->tmp);
855 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
856 return;
857 }
858#endif
859 break;
860 }
861
862 /* --------- EXIT --------- */
863 /* conditional exit from BB */
864 case Ist_Exit: {
865 ARMBranchDest* dst;
866 ARMCondCode cc;
867 if (stmt->Ist.Exit.dst->tag != Ico_U32)
868 vpanic("isel_arm: Ist_Exit: dst is not a 32-bit value");
869
870 // CAB: Where does jumpkind fit in ?
871 // stmt->Ist.Exit.jk
872
873 dst = iselIntExpr_BD(env, IRExpr_Const(stmt->Ist.Exit.dst));
874 cc = iselCondCode(env,stmt->Ist.Exit.guard);
875 addInstr(env, ARMInstr_Branch(cc, dst));
876 return;
877 }
878
879 default: break;
880 }
881 ppIRStmt(stmt);
882 vpanic("iselStmt");
883}
884
885
886/*---------------------------------------------------------*/
887/*--- ISEL: Basic block terminators (Nexts) ---*/
888/*---------------------------------------------------------*/
889
890static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
891{
892 ARMBranchDest* bd;
893 if (vex_traceflags & VEX_TRACE_VCODE) {
894 vex_printf("\n-- goto {");
895 ppIRJumpKind(jk);
896 vex_printf("} ");
897 ppIRExpr(next);
898 vex_printf("\n");
899 }
900 bd = iselIntExpr_BD(env, next);
901
902 // CAB: jk ?
903
904 addInstr( env, ARMInstr_Branch(ARMccAL, bd) );
905}
906
907
908/*---------------------------------------------------------*/
909/*--- Insn selector top-level ---*/
910/*---------------------------------------------------------*/
911
912/* Translate an entire BB to arm code. */
913
914HInstrArray* iselBB_ARM ( IRBB* bb )
915{
916 Int i, j;
917
918 /* Make up an initial environment to use. */
919 ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
920 env->vreg_ctr = 0;
921
922 /* Set up output code array. */
923 env->code = newHInstrArray();
924
925 /* Copy BB's type env. */
926 env->type_env = bb->tyenv;
927
928 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
929 change as we go along. */
930 env->n_vregmap = bb->tyenv->types_used;
931 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
932
933 /* For each IR temporary, allocate a 32bit virtual register. */
934 j = 0;
935 for (i = 0; i < env->n_vregmap; i++) {
936 env->vregmap[i] = mkHReg(j++, HRcInt32, True);
937 }
938 env->vreg_ctr = j;
939
940 /* Ok, finally we can iterate over the statements. */
941 for (i = 0; i < bb->stmts_used; i++)
942 if (bb->stmts[i])
943 iselStmt(env,bb->stmts[i]);
944
945 iselNext(env,bb->next,bb->jumpkind);
946
947 /* record the number of vregs we used. */
948 env->code->n_vregs = env->vreg_ctr;
949 return env->code;
950}
951
952
953
954
955
956/*---------------------------------------------------------------*/
957/*--- end host-x86/isel.c ---*/
958/*---------------------------------------------------------------*/