blob: 94d47e451111f350fe3c413e7f4aa5d13e48c490 [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 */
sewardjaf1ceca2005-06-30 23:31:27 +0000741 case Ist_Store: {
sewardj8fa42082004-12-31 17:22:04 +0000742 HReg reg;
sewardjaf1ceca2005-06-30 23:31:27 +0000743 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
744 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
745 IREndness end = stmt->Ist.Store.end;
746
747 if (tya != Ity_I32 || end != Iend_LE)
748 goto stmt_fail;
749
750 reg = iselIntExpr_R(env, stmt->Ist.Store.data);
cerioncee30312004-12-17 20:30:21 +0000751
752 if (tyd == Ity_I8) {
sewardjaf1ceca2005-06-30 23:31:27 +0000753 ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
cerioncee30312004-12-17 20:30:21 +0000754 addInstr(env, ARMInstr_StoreB(reg,am2));
755 return;
756 }
757 if (tyd == Ity_I16) {
sewardjaf1ceca2005-06-30 23:31:27 +0000758 ARMAMode3* am3 = iselIntExpr_AMode3(env, stmt->Ist.Store.addr);
cerioncee30312004-12-17 20:30:21 +0000759 addInstr(env, ARMInstr_StoreH(reg,am3));
760 return;
761 }
762 if (tyd == Ity_I32) {
sewardjaf1ceca2005-06-30 23:31:27 +0000763 ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
cerioncee30312004-12-17 20:30:21 +0000764 addInstr(env, ARMInstr_StoreW(reg,am2));
765 return;
766 }
767 }
768
769 /* --------- PUT --------- */
770 /* write guest state, fixed offset */
771 case Ist_Put: {
772 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
773 HReg reg = iselIntExpr_R(env, stmt->Ist.Put.data);
774
775 // CAB: This anywhere near right?!
776 if (tyd == Ity_I32) {
777 ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
778 addInstr(env, ARMInstr_StoreW(reg, am2));
779 return;
780 }
781 if (tyd == Ity_I16) {
782 ARMAMode3* am3 = ARMAMode3_RI(GET_BP_REG(), stmt->Ist.Put.offset);
783 addInstr(env, ARMInstr_StoreH(reg, am3));
784 return;
785 }
786 if (tyd == Ity_I8) {
787 ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
788 addInstr(env, ARMInstr_StoreB(reg, am2));
789 return;
790 }
791// CAB: Ity_I32, Ity_I16 ?
792 break;
793 }
794
795 /* --------- Indexed PUT --------- */
796 /* write guest state, run-time offset */
797 case Ist_PutI: {
798 ARMAMode2* am2
799 = genGuestArrayOffset(
800 env, stmt->Ist.PutI.descr,
801 stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
802
803 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
804
805 if (tyd == Ity_I8) {
806 HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
807 addInstr(env, ARMInstr_StoreB(reg, am2));
808 return;
809 }
810// CAB: Ity_I32, Ity_I16 ?
811 break;
812 }
813
814 /* --------- TMP --------- */
815 /* assign value to temporary */
816 case Ist_Tmp: {
817 IRTemp tmp = stmt->Ist.Tmp.tmp;
818 IRType ty = typeOfIRTemp(env->type_env, tmp);
819
820 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
821 ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Tmp.data);
822 HReg dst = lookupIRTemp(env, tmp);
823 addInstr(env, ARMInstr_DPInstr1(ARMalu_MOV,dst,am));
824 return;
825 }
826
827// CAB: Ity_I1 ?
828
829 break;
830 }
831
832 /* --------- Call to DIRTY helper --------- */
833 /* call complex ("dirty") helper function */
834 case Ist_Dirty: {
sewardja8415ff2005-01-21 20:55:36 +0000835 //IRType retty;
cerioncee30312004-12-17 20:30:21 +0000836 IRDirty* d = stmt->Ist.Dirty.details;
837 Bool passBBP = False;
838
839 if (d->nFxState == 0)
840 vassert(!d->needsBBP);
sewardj428fabd2005-03-21 03:11:17 +0000841
842 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
cerioncee30312004-12-17 20:30:21 +0000843
844 /* Marshal args, do the call, clear stack. */
845 doHelperCall( env, passBBP, d->guard, d->cee, d->args );
846
847 /* Now figure out what to do with the returned value, if any. */
848 if (d->tmp == IRTemp_INVALID)
849 /* No return value. Nothing to do. */
850 return;
851
sewardja8415ff2005-01-21 20:55:36 +0000852 //retty = typeOfIRTemp(env->type_env, d->tmp);
cerioncee30312004-12-17 20:30:21 +0000853
854// CAB: ? if (retty == Ity_I64) {
855
856#if 0
857 if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
858 /* The returned value is in %eax. Park it in the register
859 associated with tmp. */
860 HReg dst = lookupIRTemp(env, d->tmp);
861 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
862 return;
863 }
864#endif
865 break;
866 }
867
868 /* --------- EXIT --------- */
869 /* conditional exit from BB */
870 case Ist_Exit: {
871 ARMBranchDest* dst;
872 ARMCondCode cc;
873 if (stmt->Ist.Exit.dst->tag != Ico_U32)
874 vpanic("isel_arm: Ist_Exit: dst is not a 32-bit value");
875
876 // CAB: Where does jumpkind fit in ?
877 // stmt->Ist.Exit.jk
878
879 dst = iselIntExpr_BD(env, IRExpr_Const(stmt->Ist.Exit.dst));
880 cc = iselCondCode(env,stmt->Ist.Exit.guard);
881 addInstr(env, ARMInstr_Branch(cc, dst));
882 return;
883 }
884
885 default: break;
886 }
sewardjaf1ceca2005-06-30 23:31:27 +0000887 stmt_fail:
cerioncee30312004-12-17 20:30:21 +0000888 ppIRStmt(stmt);
889 vpanic("iselStmt");
890}
891
892
893/*---------------------------------------------------------*/
894/*--- ISEL: Basic block terminators (Nexts) ---*/
895/*---------------------------------------------------------*/
896
897static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
898{
899 ARMBranchDest* bd;
900 if (vex_traceflags & VEX_TRACE_VCODE) {
901 vex_printf("\n-- goto {");
902 ppIRJumpKind(jk);
903 vex_printf("} ");
904 ppIRExpr(next);
905 vex_printf("\n");
906 }
907 bd = iselIntExpr_BD(env, next);
908
909 // CAB: jk ?
910
911 addInstr( env, ARMInstr_Branch(ARMccAL, bd) );
912}
913
914
915/*---------------------------------------------------------*/
916/*--- Insn selector top-level ---*/
917/*---------------------------------------------------------*/
918
919/* Translate an entire BB to arm code. */
920
921HInstrArray* iselBB_ARM ( IRBB* bb )
922{
923 Int i, j;
924
925 /* Make up an initial environment to use. */
926 ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
927 env->vreg_ctr = 0;
928
929 /* Set up output code array. */
930 env->code = newHInstrArray();
931
932 /* Copy BB's type env. */
933 env->type_env = bb->tyenv;
934
935 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
936 change as we go along. */
937 env->n_vregmap = bb->tyenv->types_used;
938 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
939
940 /* For each IR temporary, allocate a 32bit virtual register. */
941 j = 0;
942 for (i = 0; i < env->n_vregmap; i++) {
943 env->vregmap[i] = mkHReg(j++, HRcInt32, True);
944 }
945 env->vreg_ctr = j;
946
947 /* Ok, finally we can iterate over the statements. */
948 for (i = 0; i < bb->stmts_used; i++)
949 if (bb->stmts[i])
950 iselStmt(env,bb->stmts[i]);
951
952 iselNext(env,bb->next,bb->jumpkind);
953
954 /* record the number of vregs we used. */
955 env->code->n_vregs = env->vreg_ctr;
956 return env->code;
957}
958
959
960
961
962
963/*---------------------------------------------------------------*/
964/*--- end host-x86/isel.c ---*/
965/*---------------------------------------------------------------*/