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