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