blob: 6659c9546621cbc3e9d23bd299af1cb8ac0da034 [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
sewardj48b279b2007-11-16 12:43:32 +0000132/* static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e ); */
cerioncee30312004-12-17 20:30:21 +0000133static 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
sewardj48b279b2007-11-16 12:43:32 +0000604__attribute__((unused))
cerioncee30312004-12-17 20:30:21 +0000605static Bool sane_AMode2 ( ARMAMode2* am )
606{
607 switch (am->tag) {
608 default:
609 vpanic("sane_AMode2: unknown arm amode tag");
610 }
611}
612
sewardj48b279b2007-11-16 12:43:32 +0000613/* Apparently unused
cerioncee30312004-12-17 20:30:21 +0000614static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e )
615{
616 ARMAMode2* am = iselIntExpr_AMode2_wrk(env, e);
617 vassert(sane_AMode2(am));
618 return am;
619}
sewardj48b279b2007-11-16 12:43:32 +0000620*/
cerioncee30312004-12-17 20:30:21 +0000621
622/* DO NOT CALL THIS DIRECTLY ! */
623static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e )
624{
625 IRType ty = typeOfIRExpr(env->type_env,e);
626 vassert(ty == Ity_I32);
627
628 // ARMam2_RI, /* Reg +/- Imm12 */
629 // ARMam2_RR, /* Reg +/- Reg */
630 // ARMam2_RRS, /* Reg +/- (Reg << Imm5) */
631
632 return NULL;
633}
634
635
636
637/* ---------------- Addressing Mode 3 ---------------- */
638
639static Bool sane_AMode3 ( ARMAMode3* am )
640{
641 switch (am->tag) {
642 default:
643 vpanic("sane_AMode3: unknown arm amode tag");
644 }
645}
646
647static ARMAMode3* iselIntExpr_AMode3 ( ISelEnv* env, IRExpr* e )
648{
649 ARMAMode3* am = iselIntExpr_AMode3_wrk(env, e);
650 vassert(sane_AMode3(am));
651 return am;
652}
653
654/* DO NOT CALL THIS DIRECTLY ! */
655static ARMAMode3* iselIntExpr_AMode3_wrk ( ISelEnv* env, IRExpr* e )
656{
657 IRType ty = typeOfIRExpr(env->type_env,e);
658 vassert(ty == Ity_I32);
659
660 // ARMam3_RI, /* Reg +/- Imm8 */
661 // ARMam3_RR, /* Reg +/- Reg */
662
663 return NULL;
664}
665
666
667
668/* ---------------- Branch Destination ---------------- */
669
670static ARMBranchDest* iselIntExpr_BD ( ISelEnv* env, IRExpr* e )
671{
672 ARMBranchDest* bd = iselIntExpr_BD_wrk(env, e);
673 /* sanity checks ... */
674 switch (bd->tag) {
675 case ARMbdImm:
676 return bd;
677 case ARMbdReg:
678 vassert(hregClass(bd->ARMbd.Reg.reg) == HRcInt32);
679// vassert(hregIsVirtual(bd->ARMbd.Reg.reg)); // CAB ?
680 return bd;
681 default:
682 vpanic("iselIntExpr_BD: unknown arm BD tag");
683 }
684}
685
686/* DO NOT CALL THIS DIRECTLY ! */
687static ARMBranchDest* iselIntExpr_BD_wrk ( ISelEnv* env, IRExpr* e )
688{
689 /*
690 ARMbdImm,
691 ARMbdReg
692 */
693
694 return NULL;
695}
696
697
698
699
700
701/* --------------------- CONDCODE --------------------- */
702
703/* Generate code to evaluated a bit-typed expression, returning the
704 condition code which would correspond when the expression would
705 notionally have returned 1. */
706
707static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
708{
709 /* Uh, there's nothing we can sanity check here, unfortunately. */
710 return iselCondCode_wrk(env, e);
711}
712
713/* DO NOT CALL THIS DIRECTLY ! */
714static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
715{
716#if 0
717 MatchInfo mi;
718 DECLARE_PATTERN(p_32to1);
719 DECLARE_PATTERN(p_1Uto32_then_32to1);
720#endif
721
722 return 0;
723}
724
725
726
727static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
728{
729 return iselIntExpr_R_wrk(env, e);
730}
731
732/* DO NOT CALL THIS DIRECTLY ! */
733static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
734{
735 return 0;
736}
737
738
739
740/*---------------------------------------------------------*/
741/*--- ISEL: Statements ---*/
742/*---------------------------------------------------------*/
743
744static void iselStmt ( ISelEnv* env, IRStmt* stmt )
745{
746 if (vex_traceflags & VEX_TRACE_VCODE) {
747 vex_printf("\n-- ");
748 ppIRStmt(stmt);
749 vex_printf("\n");
750 }
751 switch (stmt->tag) {
752
753 /* --------- STORE --------- */
754 /* little-endian write to memory */
sewardjaf1ceca2005-06-30 23:31:27 +0000755 case Ist_Store: {
sewardj8fa42082004-12-31 17:22:04 +0000756 HReg reg;
sewardjaf1ceca2005-06-30 23:31:27 +0000757 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
758 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
759 IREndness end = stmt->Ist.Store.end;
760
761 if (tya != Ity_I32 || end != Iend_LE)
762 goto stmt_fail;
763
764 reg = iselIntExpr_R(env, stmt->Ist.Store.data);
cerioncee30312004-12-17 20:30:21 +0000765
766 if (tyd == Ity_I8) {
sewardjaf1ceca2005-06-30 23:31:27 +0000767 ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
cerioncee30312004-12-17 20:30:21 +0000768 addInstr(env, ARMInstr_StoreB(reg,am2));
769 return;
770 }
771 if (tyd == Ity_I16) {
sewardjaf1ceca2005-06-30 23:31:27 +0000772 ARMAMode3* am3 = iselIntExpr_AMode3(env, stmt->Ist.Store.addr);
cerioncee30312004-12-17 20:30:21 +0000773 addInstr(env, ARMInstr_StoreH(reg,am3));
774 return;
775 }
776 if (tyd == Ity_I32) {
sewardjaf1ceca2005-06-30 23:31:27 +0000777 ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
cerioncee30312004-12-17 20:30:21 +0000778 addInstr(env, ARMInstr_StoreW(reg,am2));
779 return;
780 }
781 }
782
783 /* --------- PUT --------- */
784 /* write guest state, fixed offset */
785 case Ist_Put: {
786 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
787 HReg reg = iselIntExpr_R(env, stmt->Ist.Put.data);
788
789 // CAB: This anywhere near right?!
790 if (tyd == Ity_I32) {
791 ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
792 addInstr(env, ARMInstr_StoreW(reg, am2));
793 return;
794 }
795 if (tyd == Ity_I16) {
796 ARMAMode3* am3 = ARMAMode3_RI(GET_BP_REG(), stmt->Ist.Put.offset);
797 addInstr(env, ARMInstr_StoreH(reg, am3));
798 return;
799 }
800 if (tyd == Ity_I8) {
801 ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
802 addInstr(env, ARMInstr_StoreB(reg, am2));
803 return;
804 }
805// CAB: Ity_I32, Ity_I16 ?
806 break;
807 }
808
809 /* --------- Indexed PUT --------- */
810 /* write guest state, run-time offset */
811 case Ist_PutI: {
812 ARMAMode2* am2
813 = genGuestArrayOffset(
814 env, stmt->Ist.PutI.descr,
815 stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
816
817 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
818
819 if (tyd == Ity_I8) {
820 HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
821 addInstr(env, ARMInstr_StoreB(reg, am2));
822 return;
823 }
824// CAB: Ity_I32, Ity_I16 ?
825 break;
826 }
827
828 /* --------- TMP --------- */
829 /* assign value to temporary */
sewardjdd40fdf2006-12-24 02:20:24 +0000830 case Ist_WrTmp: {
831 IRTemp tmp = stmt->Ist.WrTmp.tmp;
cerioncee30312004-12-17 20:30:21 +0000832 IRType ty = typeOfIRTemp(env->type_env, tmp);
833
834 if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
sewardjdd40fdf2006-12-24 02:20:24 +0000835 ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.WrTmp.data);
cerioncee30312004-12-17 20:30:21 +0000836 HReg dst = lookupIRTemp(env, tmp);
837 addInstr(env, ARMInstr_DPInstr1(ARMalu_MOV,dst,am));
838 return;
839 }
840
841// CAB: Ity_I1 ?
842
843 break;
844 }
845
846 /* --------- Call to DIRTY helper --------- */
847 /* call complex ("dirty") helper function */
848 case Ist_Dirty: {
sewardja8415ff2005-01-21 20:55:36 +0000849 //IRType retty;
cerioncee30312004-12-17 20:30:21 +0000850 IRDirty* d = stmt->Ist.Dirty.details;
851 Bool passBBP = False;
852
853 if (d->nFxState == 0)
854 vassert(!d->needsBBP);
sewardj428fabd2005-03-21 03:11:17 +0000855
856 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
cerioncee30312004-12-17 20:30:21 +0000857
858 /* Marshal args, do the call, clear stack. */
859 doHelperCall( env, passBBP, d->guard, d->cee, d->args );
860
861 /* Now figure out what to do with the returned value, if any. */
862 if (d->tmp == IRTemp_INVALID)
863 /* No return value. Nothing to do. */
864 return;
865
sewardja8415ff2005-01-21 20:55:36 +0000866 //retty = typeOfIRTemp(env->type_env, d->tmp);
cerioncee30312004-12-17 20:30:21 +0000867
868// CAB: ? if (retty == Ity_I64) {
869
870#if 0
871 if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
872 /* The returned value is in %eax. Park it in the register
873 associated with tmp. */
874 HReg dst = lookupIRTemp(env, d->tmp);
875 addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
876 return;
877 }
878#endif
879 break;
880 }
881
882 /* --------- EXIT --------- */
883 /* conditional exit from BB */
884 case Ist_Exit: {
885 ARMBranchDest* dst;
886 ARMCondCode cc;
887 if (stmt->Ist.Exit.dst->tag != Ico_U32)
888 vpanic("isel_arm: Ist_Exit: dst is not a 32-bit value");
889
890 // CAB: Where does jumpkind fit in ?
891 // stmt->Ist.Exit.jk
892
893 dst = iselIntExpr_BD(env, IRExpr_Const(stmt->Ist.Exit.dst));
894 cc = iselCondCode(env,stmt->Ist.Exit.guard);
895 addInstr(env, ARMInstr_Branch(cc, dst));
896 return;
897 }
898
899 default: break;
900 }
sewardjaf1ceca2005-06-30 23:31:27 +0000901 stmt_fail:
cerioncee30312004-12-17 20:30:21 +0000902 ppIRStmt(stmt);
903 vpanic("iselStmt");
904}
905
906
907/*---------------------------------------------------------*/
908/*--- ISEL: Basic block terminators (Nexts) ---*/
909/*---------------------------------------------------------*/
910
911static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
912{
913 ARMBranchDest* bd;
914 if (vex_traceflags & VEX_TRACE_VCODE) {
915 vex_printf("\n-- goto {");
916 ppIRJumpKind(jk);
917 vex_printf("} ");
918 ppIRExpr(next);
919 vex_printf("\n");
920 }
921 bd = iselIntExpr_BD(env, next);
922
923 // CAB: jk ?
924
925 addInstr( env, ARMInstr_Branch(ARMccAL, bd) );
926}
927
928
929/*---------------------------------------------------------*/
930/*--- Insn selector top-level ---*/
931/*---------------------------------------------------------*/
932
sewardjdd40fdf2006-12-24 02:20:24 +0000933/* Translate an entire SB to arm code. */
cerioncee30312004-12-17 20:30:21 +0000934
sewardjdd40fdf2006-12-24 02:20:24 +0000935HInstrArray* iselSB_ARM ( IRSB* bb )
cerioncee30312004-12-17 20:30:21 +0000936{
937 Int i, j;
938
939 /* Make up an initial environment to use. */
940 ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
941 env->vreg_ctr = 0;
942
943 /* Set up output code array. */
944 env->code = newHInstrArray();
945
946 /* Copy BB's type env. */
947 env->type_env = bb->tyenv;
948
949 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
950 change as we go along. */
951 env->n_vregmap = bb->tyenv->types_used;
952 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
953
954 /* For each IR temporary, allocate a 32bit virtual register. */
955 j = 0;
956 for (i = 0; i < env->n_vregmap; i++) {
957 env->vregmap[i] = mkHReg(j++, HRcInt32, True);
958 }
959 env->vreg_ctr = j;
960
961 /* Ok, finally we can iterate over the statements. */
962 for (i = 0; i < bb->stmts_used; i++)
963 if (bb->stmts[i])
964 iselStmt(env,bb->stmts[i]);
965
966 iselNext(env,bb->next,bb->jumpkind);
967
968 /* record the number of vregs we used. */
969 env->code->n_vregs = env->vreg_ctr;
970 return env->code;
971}
972
973
974
975
976
977/*---------------------------------------------------------------*/
978/*--- end host-x86/isel.c ---*/
979/*---------------------------------------------------------------*/