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