blob: 0c9ea6514fae9ed38caec4027279e31386e3a269 [file] [log] [blame]
sewardj0de80192015-04-10 12:27:40 +00001
2/*---------------------------------------------------------------*/
3/*--- begin host_tilegx_isel.c ---*/
4/*---------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
sewardj785952d2015-08-21 11:29:16 +000010 Copyright (C) 2010-2015 Tilera Corp.
sewardj0de80192015-04-10 12:27:40 +000011
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 02110-1301, USA.
26
27 The GNU General Public License is contained in the file COPYING.
28*/
29
30 /* Contributed by Zhi-Gang Liu <zliu at tilera dot com> */
31
32#include "libvex_basictypes.h"
33#include "libvex_ir.h"
34#include "libvex.h"
35
36#include "main_util.h"
37#include "main_globals.h"
38#include "host_generic_regs.h"
39#include "host_tilegx_defs.h"
40#include "tilegx_disasm.h"
41
42/*---------------------------------------------------------*/
43/*--- Register Usage Conventions ---*/
44/*---------------------------------------------------------*/
45
46/* GPR register class for tilegx */
47#define HRcGPR() HRcInt64
48
49/* guest_COND offset. */
50#define COND_OFFSET() (608)
51
52/*---------------------------------------------------------*/
53/*--- ISelEnv ---*/
54/*---------------------------------------------------------*/
55
56/* This carries around:
57
58 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
59 might encounter. This is computed before insn selection starts,
60 and does not change.
61
62 - A mapping from IRTemp to HReg. This tells the insn selector
63 which virtual register(s) are associated with each IRTemp
64 temporary. This is computed before insn selection starts, and
65 does not change. We expect this mapping to map precisely the
66 same set of IRTemps as the type mapping does.
67
68 - vregmap holds the primary register for the IRTemp.
69 - vregmapHI holds the secondary register for the IRTemp,
70 if any is needed. That's only for Ity_I64 temps
71 in 32 bit mode or Ity_I128 temps in 64-bit mode.
72
73 - The name of the vreg in which we stash a copy of the link reg,
74 so helper functions don't kill it.
75
76 - The code array, that is, the insns selected so far.
77
78 - A counter, for generating new virtual registers.
79
80 - The host subarchitecture we are selecting insns for.
81 This is set at the start and does not change.
82
83 - A Bool to tell us if the host is 32 or 64bit.
84 This is set at the start and does not change.
85
86 - An IRExpr*, which may be NULL, holding the IR expression (an
87 IRRoundingMode-encoded value) to which the FPU's rounding mode
88 was most recently set. Setting to NULL is always safe. Used to
89 avoid redundant settings of the FPU's rounding mode, as
90 described in set_FPU_rounding_mode below.
91
92 - A VexMiscInfo*, needed for knowing how to generate
93 function calls for this target
94*/
95typedef struct {
96 IRTypeEnv *type_env;
97
98 HReg *vregmap;
99
100 Int n_vregmap;
101
102 HInstrArray *code;
103
104 Int vreg_ctr;
105
106 UInt hwcaps;
107
108 Bool mode64;
109
110 Bool chainingAllowed;
111
112 Addr64 max_ga;
113
114 IRExpr *previous_rm;
115
116 VexAbiInfo *vbi;
117} ISelEnv;
118
119static HReg lookupIRTemp ( ISelEnv * env, IRTemp tmp )
120{
121 vassert(tmp >= 0);
122 vassert(tmp < env->n_vregmap);
123 return env->vregmap[tmp];
124}
125
126static void addInstr ( ISelEnv * env, TILEGXInstr * instr )
127{
128 addHInstr(env->code, instr);
129 if (vex_traceflags & VEX_TRACE_VCODE) {
130 ppTILEGXInstr(instr);
131 vex_printf("\n");
132 }
133}
134
135static HReg newVRegI ( ISelEnv * env )
136{
137 HReg reg = mkHReg(True /*virtual R*/, HRcGPR(), 0, env->vreg_ctr);
138 env->vreg_ctr++;
139 return reg;
140}
141
142/*---------------------------------------------------------*/
143/*--- ISEL: Forward declarations ---*/
144/*---------------------------------------------------------*/
145
146/* These are organised as iselXXX and iselXXX_wrk pairs. The
147 iselXXX_wrk do the real work, but are not to be called directly.
148 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
149 checks that all returned registers are virtual. You should not
150 call the _wrk version directly.
151*/
152/* Compute an I8/I16/I32/I64 into a RH (reg-or-halfword-immediate).
153 It's important to specify whether the immediate is to be regarded
154 as signed or not. If yes, this will never return -32768 as an
155 immediate; this guaranteed that all signed immediates that are
156 return can have their sign inverted if need be.
157*/
158static TILEGXRH *iselWordExpr_RH_wrk ( ISelEnv * env, Bool syned, IRExpr * e );
159static TILEGXRH *iselWordExpr_RH ( ISelEnv * env, Bool syned, IRExpr * e );
160
161static TILEGXRH *iselWordExpr_RH6u_wrk ( ISelEnv * env, IRExpr * e );
162static TILEGXRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e );
163
164/* compute an I8/I16/I32/I64 into a GPR*/
165static HReg iselWordExpr_R_wrk ( ISelEnv * env, IRExpr * e );
166static HReg iselWordExpr_R ( ISelEnv * env, IRExpr * e );
167
168/* compute an I64 into an AMode. */
169static TILEGXAMode *iselWordExpr_AMode_wrk ( ISelEnv * env, IRExpr * e,
170 IRType xferTy );
171static TILEGXAMode *iselWordExpr_AMode ( ISelEnv * env, IRExpr * e,
172 IRType xferTy );
173
174static TILEGXCondCode iselCondCode_wrk ( ISelEnv * env, IRExpr * e );
175static TILEGXCondCode iselCondCode ( ISelEnv * env, IRExpr * e );
176
177/*---------------------------------------------------------*/
178/*--- ISEL: Misc helpers ---*/
179/*---------------------------------------------------------*/
180
181/* Make an int reg-reg move. */
182static TILEGXInstr *mk_iMOVds_RR ( HReg r_dst, HReg r_src )
183{
184 vassert(hregClass(r_dst) == hregClass(r_src));
185 vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64);
186 return TILEGXInstr_Alu(GXalu_OR, r_dst, r_src, TILEGXRH_Reg(r_src));
187}
188
189/*---------------------------------------------------------*/
190/*--- ISEL: Function call helpers ---*/
191/*---------------------------------------------------------*/
192
193/* Used only in doHelperCall. See big comment in doHelperCall
194 handling of register-parameter args. This function figures out
195 whether evaluation of an expression might require use of a fixed
196 register.
197*/
198static Bool mightRequireFixedRegs ( IRExpr * e )
199{
200 switch (e->tag) {
201 case Iex_RdTmp:
202 case Iex_Const:
203 case Iex_Get:
204 return False;
205 default:
206 return True;
207 }
208}
209
210/* Do a complete function call. guard is a Ity_Bit expression
211 indicating whether or not the call happens. If guard==NULL, the
212 call is unconditional. */
213
214static void doHelperCall ( ISelEnv * env, IRExpr * guard, IRCallee * cee,
215 IRExpr ** args, IRType retTy )
216{
217 TILEGXCondCode cc;
218 HReg argregs[TILEGX_N_REGPARMS];
219 HReg tmpregs[TILEGX_N_REGPARMS];
220 Bool go_fast;
221 Long n_args, i, argreg;
222 ULong argiregs;
223 ULong target;
224 HReg src = INVALID_HREG;
225
226
227 UInt nVECRETs = 0;
228 UInt nBBPTRs = 0;
229
230 /* TILEGX calling convention: up to 10 registers (r0 ... r9)
231 are allowed to be used for passing integer arguments. They correspond
232 to regs GPR0 ... GPR9. */
233
234 /* Note that the cee->regparms field is meaningless on ARM64 hosts
235 (since there is only one calling convention) and so we always
236 ignore it. */
237
238 n_args = 0;
239 for (i = 0; args[i]; i++) {
240 n_args++;
241 IRExpr* arg = args[i];
242 if (UNLIKELY(arg->tag == Iex_VECRET)) {
243 nVECRETs++;
244 } else if (UNLIKELY(arg->tag == Iex_BBPTR)) {
245 nBBPTRs++;
246 }
247 }
248
249 if (nVECRETs || nBBPTRs)
florianb1737742015-08-03 16:03:13 +0000250 vex_printf("nVECRETs=%u, nBBPTRs=%u\n",
sewardj0de80192015-04-10 12:27:40 +0000251 nVECRETs, nBBPTRs);
252
253 if (TILEGX_N_REGPARMS < n_args) {
254 vpanic("doHelperCall(TILEGX): cannot currently handle > 10 args");
255 }
256 argregs[0] = hregTILEGX_R0();
257 argregs[1] = hregTILEGX_R1();
258 argregs[2] = hregTILEGX_R2();
259 argregs[3] = hregTILEGX_R3();
260 argregs[4] = hregTILEGX_R4();
261 argregs[5] = hregTILEGX_R5();
262 argregs[6] = hregTILEGX_R6();
263 argregs[7] = hregTILEGX_R7();
264 argregs[8] = hregTILEGX_R8();
265 argregs[9] = hregTILEGX_R9();
266 argiregs = 0;
267
268 for (i = 0; i < TILEGX_N_REGPARMS; i++)
269 tmpregs[i] = INVALID_HREG;
270
271 /* First decide which scheme (slow or fast) is to be used. First
272 assume the fast scheme, and select slow if any contraindications
273 (wow) appear. */
274
275 go_fast = True;
276
277 if (guard) {
278 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
279 && guard->Iex.Const.con->Ico.U1 == True) {
280 /* unconditional */
281 } else {
282 /* Not manifestly unconditional -- be conservative. */
283 go_fast = False;
284 }
285 }
286
287 if (go_fast) {
288 for (i = 0; i < n_args; i++) {
289 if (mightRequireFixedRegs(args[i])) {
290 go_fast = False;
291 break;
292 }
293 }
294 }
295
296 /* At this point the scheme to use has been established. Generate
297 code to get the arg values into the argument rregs. */
298 if (go_fast) {
299 /* FAST SCHEME */
300 argreg = 0;
301
302 for (i = 0; i < n_args; i++) {
303 vassert(argreg < TILEGX_N_REGPARMS);
304 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 ||
305 typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
306
307 argiregs |= (1 << (argreg));
308 addInstr(env, mk_iMOVds_RR(argregs[argreg],
309 iselWordExpr_R(env,
310 args[i])));
311 argreg++;
312 }
313 /* Fast scheme only applies for unconditional calls. Hence: */
314 cc = TILEGXcc_AL;
315 } else {
316 /* SLOW SCHEME; move via temporaries */
317 argreg = 0;
318
319 for (i = 0; i < n_args; i++) {
320 vassert(argreg < TILEGX_N_REGPARMS);
321 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32
322 || typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
323 tmpregs[argreg] = iselWordExpr_R(env, args[i]);
324 argreg++;
325 }
326
327 /* Now we can compute the condition. We can't do it earlier
328 because the argument computations could trash the condition
329 codes. Be a bit clever to handle the common case where the
330 guard is 1:Bit. */
331 cc = TILEGXcc_AL;
332 if (guard) {
333 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
334 && guard->Iex.Const.con->Ico.U1 == True) {
335 /* unconditional -- do nothing */
336 } else {
337 cc = iselCondCode(env, guard);
338 src = iselWordExpr_R(env, guard);
339 }
340 }
341 /* Move the args to their final destinations. */
342 for (i = 0; i < argreg; i++) {
343 if (hregIsInvalid(tmpregs[i])) // Skip invalid regs
344 continue;
345 /* None of these insns, including any spill code that might
346 be generated, may alter the condition codes. */
347 argiregs |= (1 << (i));
348 addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i]));
349 }
350 }
351
352 target = (Addr)(cee->addr);
353
354 /* Finally, the call itself. */
355 if (cc == TILEGXcc_AL)
356 addInstr(env, TILEGXInstr_CallAlways(cc, target, argiregs));
357 else
358 addInstr(env, TILEGXInstr_Call(cc, target, argiregs, src));
359}
360
361/*---------------------------------------------------------*/
362/*--- ISEL: Integer expression auxiliaries ---*/
363/*---------------------------------------------------------*/
364
365/* --------------------- AMODEs --------------------- */
366
367/* Return an AMode which computes the value of the specified
368 expression, possibly also adding insns to the code list as a
369 result. The expression may only be a word-size one.
370*/
371
florian36f940a2015-06-22 11:53:48 +0000372static Bool uInt_fits_in_16_bits ( UInt u )
sewardj0de80192015-04-10 12:27:40 +0000373{
florian36f940a2015-06-22 11:53:48 +0000374 UInt v = u & 0xFFFF;
375
376 v = (Int)(v << 16) >> 16; /* sign extend */
377
378 return u == v;
sewardj0de80192015-04-10 12:27:40 +0000379}
380
381static Bool sane_AMode ( ISelEnv * env, TILEGXAMode * am )
382{
383 if (am->tag == GXam_IR)
384 return toBool(hregClass(am->GXam.IR.base) == HRcGPR() &&
385 hregIsVirtual(am->GXam.IR.base) &&
386 uInt_fits_in_16_bits(am->GXam.IR.index));
387
388 vpanic("sane_AMode: unknown tilegx amode tag");
389}
390
391static TILEGXAMode *iselWordExpr_AMode ( ISelEnv * env, IRExpr * e,
392 IRType xferTy )
393{
394 TILEGXAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy);
395 vassert(sane_AMode(env, am));
396 return am;
397}
398
399/* DO NOT CALL THIS DIRECTLY ! */
400static TILEGXAMode *iselWordExpr_AMode_wrk ( ISelEnv * env, IRExpr * e,
401 IRType xferTy )
402{
403 IRType ty = typeOfIRExpr(env->type_env, e);
404
405 vassert(ty == Ity_I64);
406 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
407 if (e->tag == Iex_Binop
408 && e->Iex.Binop.op == Iop_Add64
409 && e->Iex.Binop.arg2->tag == Iex_Const
410 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
411 && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)) {
412
413 return TILEGXAMode_IR((Long) e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
414 iselWordExpr_R(env, e->Iex.Binop.arg1));
415 }
416
417 /* Doesn't match anything in particular. Generate it into
418 a register and use that. */
419 return TILEGXAMode_IR(0, iselWordExpr_R(env, e));
420}
421
422
423
424
425
426/*---------------------------------------------------------*/
427/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
428/*---------------------------------------------------------*/
429
430/* Select insns for an integer-typed expression, and add them to the
431 code list. Return a reg holding the result. This reg will be a
432 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
433 want to modify it, ask for a new vreg, copy it in there, and modify
434 the copy. The register allocator will do its best to map both
435 add vregs to the same real register, so the copies will often disappear
436 later in the game.
437
438 This should handle expressions of 64, 32, 16 and 8-bit type.
439 All results are returned in a 64bit register.
440*/
441static HReg iselWordExpr_R ( ISelEnv * env, IRExpr * e )
442{
443 HReg r = iselWordExpr_R_wrk(env, e);
444 /* sanity checks ... */
445
446 vassert(hregClass(r) == HRcGPR());
447 vassert(hregIsVirtual(r));
448 return r;
449}
450
451/* DO NOT CALL THIS DIRECTLY ! */
452static HReg iselWordExpr_R_wrk ( ISelEnv * env, IRExpr * e )
453{
454 IRType ty = typeOfIRExpr(env->type_env, e);
455 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
456 ty == Ity_I1 || ty == Ity_I64);
457
458 switch (e->tag) {
459 /* --------- TEMP --------- */
460 case Iex_RdTmp:
461 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
462
463 /* --------- LOAD --------- */
464 case Iex_Load: {
465 HReg r_dst = newVRegI(env);
466 TILEGXAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
467
468 if (e->Iex.Load.end != Iend_LE
469 && e->Iex.Load.end != Iend_BE)
470 goto irreducible;
471
472 addInstr(env, TILEGXInstr_Load(toUChar(sizeofIRType(ty)),
473 r_dst, am_addr));
474 return r_dst;
475 break;
476 }
477 /* --------- BINARY OP --------- */
478 case Iex_Binop: {
479 TILEGXAluOp aluOp;
480 TILEGXShftOp shftOp;
481
482 switch (e->Iex.Binop.op) {
483
zliu009b5fc2015-04-15 03:11:38 +0000484 case Iop_Add8:
485 case Iop_Add16:
sewardj0de80192015-04-10 12:27:40 +0000486 case Iop_Add32:
487 case Iop_Add64:
488 aluOp = GXalu_ADD;
489 break;
490
zliu009b5fc2015-04-15 03:11:38 +0000491 case Iop_Sub8:
492 case Iop_Sub16:
sewardj0de80192015-04-10 12:27:40 +0000493 case Iop_Sub32:
494 case Iop_Sub64:
495 aluOp = GXalu_SUB;
496 break;
497
zliu009b5fc2015-04-15 03:11:38 +0000498 case Iop_And8:
499 case Iop_And16:
sewardj0de80192015-04-10 12:27:40 +0000500 case Iop_And32:
501 case Iop_And64:
502 aluOp = GXalu_AND;
503 break;
504
zliu009b5fc2015-04-15 03:11:38 +0000505 case Iop_Or8:
506 case Iop_Or16:
sewardj0de80192015-04-10 12:27:40 +0000507 case Iop_Or32:
508 case Iop_Or64:
509 aluOp = GXalu_OR;
510 break;
511
zliu009b5fc2015-04-15 03:11:38 +0000512 case Iop_Xor8:
513 case Iop_Xor16:
sewardj0de80192015-04-10 12:27:40 +0000514 case Iop_Xor32:
515 case Iop_Xor64:
516 aluOp = GXalu_XOR;
517 break;
518
519 default:
520 aluOp = GXalu_INVALID;
521 break;
522 }
523
524 /* For commutative ops we assume any literal
525 values are on the second operand. */
526 if (aluOp != GXalu_INVALID) {
527 HReg r_dst = newVRegI(env);
528 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
529 TILEGXRH *ri_srcR = NULL;
530 /* get right arg into an RH, in the appropriate way */
531 switch (aluOp) {
532 case GXalu_ADD:
533 case GXalu_SUB:
534 ri_srcR = iselWordExpr_RH(env, True /*signed */ ,
535 e->Iex.Binop.arg2);
536 break;
537 case GXalu_AND:
538 case GXalu_OR:
539 case GXalu_XOR:
540 ri_srcR = iselWordExpr_RH(env, True /*signed */,
541 e->Iex.Binop.arg2);
542 break;
543 default:
544 vpanic("iselWordExpr_R_wrk-aluOp-arg2");
545 }
546 addInstr(env, TILEGXInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
547 return r_dst;
548 }
549
550 /* a shift? */
551 switch (e->Iex.Binop.op) {
552 case Iop_Shl32:
553 case Iop_Shl64:
554 shftOp = GXshft_SLL;
555 break;
556 case Iop_Shr32:
557 case Iop_Shr64:
558 shftOp = GXshft_SRL;
559 break;
560 case Iop_Sar64:
561 shftOp = GXshft_SRA;
562 break;
563 case Iop_Shl8x8:
564 shftOp = GXshft_SLL8x8;
565 break;
566 case Iop_Shr8x8:
567 shftOp = GXshft_SRL8x8;
568 break;
569 default:
570 shftOp = GXshft_INVALID;
571 break;
572 }
573
574 /* we assume any literal values are on the second operand. */
575 if (shftOp != GXshft_INVALID) {
576 HReg r_dst = newVRegI(env);
577 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
578 TILEGXRH *ri_srcR = NULL;
579 /* get right arg into an RH, in the appropriate way */
580 switch (shftOp) {
581 case GXshft_SLL:
582 case GXshft_SRL:
583 case GXshft_SRA:
584 //ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
585 //break;
586 case GXshft_SLL8x8:
587 case GXshft_SRL8x8:
588 //if (e->Iex.Binop.arg2->tag == GXrh_Imm)
589 //{
590 // ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
591 // break;
592 //}
593 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
594 break;
595 default:
596 vpanic("iselIntExpr_R_wrk-shftOp-arg2");
597 }
598 /* widen the left arg if needed */
599 /*TODO do we need this? */
600 if (ty == Ity_I8 || ty == Ity_I16)
601 goto irreducible;
602 if (ty == Ity_I64) {
603 addInstr(env, TILEGXInstr_Shft(shftOp, False/*64bit shift */,
604 r_dst, r_srcL, ri_srcR));
605 } else {
606 addInstr(env, TILEGXInstr_Shft(shftOp, True /*32bit shift */,
607 r_dst, r_srcL, ri_srcR));
608 }
609 return r_dst;
610 }
611
612 /* Cmp*32*(x,y) ? */
613 if (e->Iex.Binop.op == Iop_CasCmpEQ32
614 || e->Iex.Binop.op == Iop_CmpEQ32
615 || e->Iex.Binop.op == Iop_CasCmpNE32
616 || e->Iex.Binop.op == Iop_CmpNE32
617 || e->Iex.Binop.op == Iop_CmpNE64
618 || e->Iex.Binop.op == Iop_CmpLT32S
619 || e->Iex.Binop.op == Iop_CmpLT32U
620 || e->Iex.Binop.op == Iop_CmpLT64U
621 || e->Iex.Binop.op == Iop_CmpLE32S
622 || e->Iex.Binop.op == Iop_CmpLE64S
623 || e->Iex.Binop.op == Iop_CmpLE64U
624 || e->Iex.Binop.op == Iop_CmpLT64S
625 || e->Iex.Binop.op == Iop_CmpEQ64
626 || e->Iex.Binop.op == Iop_CasCmpEQ64
627 || e->Iex.Binop.op == Iop_CasCmpNE64) {
628
629 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
630 || e->Iex.Binop.op == Iop_CmpLE32S
631 || e->Iex.Binop.op == Iop_CmpLT64S
632 || e->Iex.Binop.op == Iop_CmpLE64S);
633 Bool size32;
634 HReg dst = newVRegI(env);
635 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
636 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
637 TILEGXCondCode cc;
638
639 switch (e->Iex.Binop.op) {
640 case Iop_CasCmpEQ32:
641 case Iop_CmpEQ32:
642 cc = TILEGXcc_EQ;
643 size32 = True;
644 break;
645 case Iop_CasCmpNE32:
646 case Iop_CmpNE32:
647 cc = TILEGXcc_NE;
648 size32 = True;
649 break;
650 case Iop_CasCmpNE64:
651 case Iop_CmpNE64:
652 cc = TILEGXcc_NE;
653 size32 = True;
654 break;
655 case Iop_CmpLT32S:
656 cc = TILEGXcc_LT;
657 size32 = True;
658 break;
659 case Iop_CmpLT32U:
660 cc = TILEGXcc_LO;
661 size32 = True;
662 break;
663 case Iop_CmpLT64U:
664 cc = TILEGXcc_LT;
665 size32 = False;
666 break;
667 case Iop_CmpLE32S:
668 cc = TILEGXcc_LE;
669 size32 = True;
670 break;
671 case Iop_CmpLE64S:
672 cc = TILEGXcc_LE;
673 size32 = False;
674 break;
675 case Iop_CmpLE64U:
676 cc = TILEGXcc_LE;
677 size32 = False;
678 break;
679 case Iop_CmpLT64S:
680 cc = TILEGXcc_LT;
681 size32 = False;
682 break;
683 case Iop_CasCmpEQ64:
684 case Iop_CmpEQ64:
685 cc = TILEGXcc_EQ;
686 size32 = False;
687 break;
688 default:
689 vpanic
690 ("iselCondCode(tilegx): CmpXX32 or CmpXX64");
691 }
692
693 addInstr(env, TILEGXInstr_Cmp(syned, size32, dst, r1, r2, cc));
694 return dst;
695
696 break;
697
698 }
699
700 if (e->Iex.Binop.op == Iop_CmpEQ8x8) {
701
702 Bool syned = False;
703
704 Bool size32;
705 HReg dst = newVRegI(env);
706 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
707 TILEGXRH *r2 = iselWordExpr_RH(env, True, e->Iex.Binop.arg2);
708 TILEGXCondCode cc;
709
710 switch (e->Iex.Binop.op) {
711 case Iop_CmpEQ8x8:
712 cc = TILEGXcc_EQ8x8;
713 size32 = False;
714 break;
715
716 default:
717 vassert(0);
718 }
719
720 addInstr(env, TILEGXInstr_CmpI(syned, size32, dst, r1, r2, cc));
721 return dst;
722
723 break;
724 }
725
726 if (e->Iex.Binop.op == Iop_Max32U) {
727 /*
728 tmp = argL - argR;
729 tmp &= (1<<31)
730 dst = (tmp) ? (argL) ? (argR)
731 */
732 HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1);
733 TILEGXRH *argR = iselWordExpr_RH(env, False /*signed */ ,
734 e->Iex.Binop.arg2);
735 HReg dst = newVRegI(env);
736 HReg tmp = newVRegI(env);
737 // temp = argL - argR
738 addInstr(env, TILEGXInstr_Alu(GXalu_SUB, tmp, argL, argR));
739 // tmp &= bit31
740 addInstr(env, TILEGXInstr_Bf(GXbf_EXTU, tmp, tmp , 31, 31));
741 // (tmp == 0) ? (argL) : (argR)
742 addInstr(env, TILEGXInstr_MovCond(dst, argL, argR, tmp, TILEGXcc_EZ));
743 return dst;
744 }
745
746 if (e->Iex.Binop.op == Iop_MullS32 || e->Iex.Binop.op == Iop_MullU32) {
747 Bool syned = (e->Iex.Binop.op == Iop_MullS32);
748 Bool sz32 = (e->Iex.Binop.op == Iop_Mul32);
749 HReg r_dst = newVRegI(env);
750 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
751 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
752 addInstr(env, TILEGXInstr_Mul(syned /*Unsigned or Signed */ ,
753 True /*widen */ ,
754 sz32 /*32bit or 64bit */,
755 r_dst, r_srcL, r_srcR));
756 return r_dst;
757 }
758
759 if (e->Iex.Binop.op == Iop_32HLto64) {
760 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
761 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
762 HReg tLo_1 = newVRegI(env);
763 HReg tHi_1 = newVRegI(env);
764 HReg r_dst = newVRegI(env);
765 HReg mask = newVRegI(env);
766
767 addInstr(env, TILEGXInstr_Shft(GXshft_SLL, False, tHi_1, tHi,
768 TILEGXRH_Imm(False, 32)));
769
770 addInstr(env, TILEGXInstr_LI(mask, 0xffffffff));
771 addInstr(env, TILEGXInstr_Alu(GXalu_AND, tLo_1, tLo,
772 TILEGXRH_Reg(mask)));
773 addInstr(env, TILEGXInstr_Alu(GXalu_OR, r_dst, tHi_1,
774 TILEGXRH_Reg(tLo_1)));
775
776 return r_dst;
777 }
778
779 /* Anything reached here !*/
780 goto irreducible;
781 }
782
783 /* --------- UNARY OP --------- */
784 case Iex_Unop: {
785
786 IROp op_unop = e->Iex.Unop.op;
787
788 switch (op_unop) {
789 case Iop_Not1: {
790 HReg r_dst = newVRegI(env);
791 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
792 TILEGXRH *r_srcR = TILEGXRH_Reg(r_srcL);
793
794 addInstr(env, TILEGXInstr_LI(r_dst, 0x1));
795 addInstr(env, TILEGXInstr_Alu(GXalu_SUB, r_dst, r_dst, r_srcR));
796 return r_dst;
797 }
798
799 case Iop_Not8:
800 case Iop_Not16:
801 case Iop_Not32:
802 case Iop_Not64: {
803 /* not x = nor x, x */
804 HReg r_dst = newVRegI(env);
805 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
806 TILEGXRH *r_srcR = TILEGXRH_Reg(r_srcL);
807
808 addInstr(env, TILEGXInstr_Alu(GXalu_NOR, r_dst, r_srcL, r_srcR));
809 return r_dst;
810 }
811
812 case Iop_CmpNEZ8x8: {
813
814 Bool syned = False;
815 Bool size32;
816 HReg dst = newVRegI(env);
817 HReg r1;
818 TILEGXCondCode cc = TILEGXcc_NE8x8;
819 size32 = False;
820 r1 = iselWordExpr_R(env, e->Iex.Unop.arg);
821 addInstr(env, TILEGXInstr_CmpI(syned, size32, dst, hregTILEGX_R63(),
822 TILEGXRH_Reg(r1), cc));
823
824 return dst;
825 break;
826 }
827
828 case Iop_16to8:
829 case Iop_32to8:
830 case Iop_64to8:
831 case Iop_32to16:
832 case Iop_64to16:
833 case Iop_64to32:
834 case Iop_128to64:
835
836 return iselWordExpr_R(env, e->Iex.Unop.arg);
837
838 case Iop_1Uto64:
839 case Iop_1Uto32:
840 case Iop_1Uto8: {
841 HReg dst = newVRegI(env);
842 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
843 addInstr(env, TILEGXInstr_Alu(GXalu_AND, dst, src, TILEGXRH_Imm(False, 1)));
844 return dst;
845 }
846 case Iop_8Uto16:
847 case Iop_8Uto32:
848 case Iop_8Uto64:
849 case Iop_16Uto32:
850 case Iop_16Uto64: {
851
852 HReg dst = newVRegI(env);
853 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
854 Bool srcIs16 = toBool( e->Iex.Unop.op==Iop_16Uto32
855 || e->Iex.Unop.op==Iop_16Uto64 );
856
857 addInstr(env, TILEGXInstr_Bf(GXbf_EXTU, dst, src,
858 0,
859 srcIs16 ? 15 : 7));
860
861 return dst;
862 }
863
864 case Iop_32to1:
865 case Iop_64to1:
866 {
867 HReg r_dst = newVRegI(env);
868 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
869
870 addInstr(env, TILEGXInstr_Bf(GXbf_EXTU, r_dst, r_src, 0, 0));
871 return r_dst;
872 }
873 case Iop_1Sto32:
874 case Iop_1Sto64:
875 {
876 HReg r_dst = newVRegI(env);
877 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
878
879 addInstr(env, TILEGXInstr_Bf(GXbf_EXTS, r_dst, r_src, 0, 0));
880 return r_dst;
881 }
882 case Iop_8Sto16:
883 case Iop_8Sto32:
884 case Iop_8Sto64:
885 {
886 HReg r_dst = newVRegI(env);
887 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
888
889 addInstr(env, TILEGXInstr_Bf(GXbf_EXTS, r_dst, r_src, 0, 7));
890 return r_dst;
891 }
892 case Iop_16Sto32:
893 case Iop_16Sto64:
894 {
895 HReg r_dst = newVRegI(env);
896 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
897
898 addInstr(env, TILEGXInstr_Bf(GXbf_EXTS, r_dst, r_src, 0, 15));
899 return r_dst;
900 }
901 case Iop_32Uto64:
902 {
903 HReg r_dst = newVRegI(env);
904 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
905
906 addInstr(env, TILEGXInstr_Bf(GXbf_EXTU, r_dst, r_src, 0, 31));
907 return r_dst;
908 }
909 case Iop_32Sto64:
910 {
911 HReg r_dst = newVRegI(env);
912 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
913
914 addInstr(env, TILEGXInstr_Bf(GXbf_EXTS, r_dst, r_src, 0, 31));
915 return r_dst;
916 }
917
918 case Iop_CmpNEZ8: {
919 HReg r_dst = newVRegI(env);
920 HReg tmp = newVRegI(env);
921 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
922
923 TILEGXCondCode cc;
924
925 cc = TILEGXcc_NE;
926 addInstr(env, TILEGXInstr_Alu(GXalu_AND, tmp, r_src,
927 TILEGXRH_Imm(False, 0xFF)));
928 addInstr(env, TILEGXInstr_Cmp(False, True, r_dst, tmp,
929 hregTILEGX_R63(), cc));
930 return r_dst;
931 }
932
933 case Iop_CmpNEZ32: {
934 HReg r_dst = newVRegI(env);
935 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
936
937 TILEGXCondCode cc;
938
939 cc = TILEGXcc_NE;
940
941 addInstr(env, TILEGXInstr_Cmp(False, True, r_dst, r_src,
942 hregTILEGX_R63(), cc));
943 return r_dst;
944 }
945
946 case Iop_CmpwNEZ32: {
947 HReg r_dst = newVRegI(env);
948 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
949
950 addInstr(env, TILEGXInstr_Alu(GXalu_SUB, r_dst, hregTILEGX_R63(),
951 TILEGXRH_Reg(r_src)));
952
953 addInstr(env, TILEGXInstr_Alu(GXalu_OR, r_dst, r_dst,
954 TILEGXRH_Reg(r_src)));
955 addInstr(env, TILEGXInstr_Shft(GXshft_SRA, True, r_dst, r_dst,
956 TILEGXRH_Imm(False, 31)));
957 return r_dst;
958 }
959
960 case Iop_Left8:
961 case Iop_Left16:
962 case Iop_Left32:
963 case Iop_Left64: {
964
965 HReg r_dst = newVRegI(env);
966 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
967 addInstr(env, TILEGXInstr_Alu(GXalu_SUB, r_dst, hregTILEGX_R63(),
968 TILEGXRH_Reg(r_src)));
969 addInstr(env, TILEGXInstr_Alu(GXalu_OR, r_dst, r_dst,
970 TILEGXRH_Reg(r_src)));
971 return r_dst;
972 }
973
974 case Iop_Ctz64:
975 case Iop_Clz64: {
976 HReg r_dst = newVRegI(env);
977 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
978 if (op_unop == Iop_Clz64)
979 addInstr(env, TILEGXInstr_Unary(GXun_CLZ, r_dst, r_src));
980 else
981 addInstr(env, TILEGXInstr_Unary(GXun_CTZ, r_dst, r_src));
982 return r_dst;
983 }
984
985 case Iop_CmpNEZ64: {
986
987 HReg r_dst = newVRegI(env);
988 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
989
990 TILEGXCondCode cc;
991
992 cc = TILEGXcc_NE;
993
994 addInstr(env, TILEGXInstr_Cmp(False, False, r_dst, r_src,
995 hregTILEGX_R63(), cc));
996 return r_dst;
997 }
998
999 case Iop_CmpwNEZ64: {
1000 HReg tmp1;
1001 HReg tmp2 = newVRegI(env);
1002
1003 tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg);
1004
1005 addInstr(env, TILEGXInstr_Alu(GXalu_SUB, tmp2, hregTILEGX_R63(),
1006 TILEGXRH_Reg(tmp1)));
1007
1008 addInstr(env, TILEGXInstr_Alu(GXalu_OR, tmp2, tmp2, TILEGXRH_Reg(tmp1)));
1009 addInstr(env, TILEGXInstr_Shft(GXshft_SRA, False, tmp2, tmp2,
1010 TILEGXRH_Imm (False, 63)));
1011 return tmp2;
1012 }
1013
1014 default:
1015 goto irreducible;
1016 break;
1017 }
1018 break;
1019 }
1020
1021 /* --------- GET --------- */
1022 case Iex_Get: {
1023 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32
1024 || ((ty == Ity_I64))) {
1025 HReg r_dst;
1026 TILEGXAMode *am_addr;
1027 r_dst = newVRegI(env);
1028 am_addr = TILEGXAMode_IR(e->Iex.Get.offset,
1029 TILEGXGuestStatePointer());
1030 addInstr(env, TILEGXInstr_Load(toUChar(sizeofIRType(ty)),
1031 r_dst, am_addr));
1032 return r_dst;
1033 }
1034 }
1035
1036 /* --------- ITE --------- */
1037 case Iex_ITE: {
1038 if ((ty == Ity_I8 || ty == Ity_I16 ||
1039 ty == Ity_I32 || ((ty == Ity_I64))) &&
1040 typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
1041
1042 HReg r0 = iselWordExpr_R(env, e->Iex.ITE.iffalse);
1043 HReg r1 = iselWordExpr_R(env, e->Iex.ITE.iftrue);
1044 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
1045 HReg r_dst = newVRegI(env);
1046
1047 /* r_dst = (r_cond) ? r1 : r0 */
1048
1049 addInstr(env, TILEGXInstr_MovCond(r_dst, r0, TILEGXRH_Reg(r1),
1050 r_cond, TILEGXcc_EZ));
1051
1052 return r_dst;
1053 }
1054 }
1055
1056 /* --------- LITERAL --------- */
1057 /* 32/16/8-bit literals */
1058 case Iex_Const: {
1059 Long l;
1060 HReg r_dst = newVRegI(env);
1061 IRConst *con = e->Iex.Const.con;
1062 switch (con->tag) {
1063 case Ico_U64:
1064
1065 l = (Long) con->Ico.U64;
1066 break;
1067 case Ico_U32:
1068 l = (Long) (Int) con->Ico.U32;
1069 break;
1070 case Ico_U16:
1071 l = (Long) (Int) (Short) con->Ico.U16;
1072 break;
1073 case Ico_U8:
1074 l = (Long) (Int) (Char) con->Ico.U8;
1075 break;
1076 default:
1077 vpanic("iselIntExpr_R.const(tilegx)");
1078 }
1079 addInstr(env, TILEGXInstr_LI(r_dst, (ULong) l));
1080 return r_dst;
1081 }
1082
1083 /* --------- CCALL --------- */
1084 case Iex_CCall: {
1085 HReg r_dst = newVRegI(env);
1086 vassert(ty == e->Iex.CCall.retty);
1087
1088 /* Marshal args, do the call, clear stack. */
1089 doHelperCall(env, NULL, e->Iex.CCall.cee, e->Iex.CCall.args,
1090 e->Iex.CCall.retty);
1091
1092 /* r0 is the return value. */
1093 addInstr(env, mk_iMOVds_RR(r_dst, hregTILEGX_R0()));
1094
1095 return r_dst;
1096 }
1097
1098 default:
1099 goto irreducible;
1100 break;
1101 } /* end switch(e->tag) */
1102
1103 /* We get here if no pattern matched. */
1104 irreducible:
1105 vex_printf("--------------->\n");
1106 if (e->tag == Iex_RdTmp)
1107 vex_printf("Iex_RdTmp \n");
1108 ppIRExpr(e);
1109
1110 vpanic("iselWordExpr_R(tilegx): cannot reduce tree");
1111}
1112
1113/* --------------------- RH --------------------- */
1114
1115/* Compute an I8/I16/I32/I64 into a RH
1116 (reg-or-halfword-immediate). It's important to specify whether the
1117 immediate is to be regarded as signed or not. If yes, this will
1118 never return -32768 as an immediate; this guaranteed that all
1119 signed immediates that are return can have their sign inverted if
1120 need be. */
1121
1122static TILEGXRH *iselWordExpr_RH ( ISelEnv * env, Bool syned, IRExpr * e )
1123{
1124 TILEGXRH *ri = iselWordExpr_RH_wrk(env, syned, e);
1125 /* sanity checks ... */
1126 switch (ri->tag) {
1127 case GXrh_Imm:
1128 vassert(ri->GXrh.Imm.syned == syned);
1129 if (syned)
1130 vassert(ri->GXrh.Imm.imm16 != 0x8000);
1131 return ri;
1132 case GXrh_Reg:
1133 vassert(hregClass(ri->GXrh.Reg.reg) == HRcGPR());
1134 vassert(hregIsVirtual(ri->GXrh.Reg.reg));
1135 return ri;
1136 default:
1137 vpanic("iselIntExpr_RH: unknown tilegx RH tag");
1138 }
1139}
1140
1141/* DO NOT CALL THIS DIRECTLY ! */
1142static TILEGXRH *iselWordExpr_RH_wrk ( ISelEnv * env, Bool syned, IRExpr * e )
1143{
1144 ULong u;
1145 Long l;
1146 IRType ty = typeOfIRExpr(env->type_env, e);
1147 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1148 ((ty == Ity_I64)));
1149
1150 /* special case: immediate */
1151 if (e->tag == Iex_Const) {
1152 IRConst *con = e->Iex.Const.con;
1153 /* What value are we aiming to generate? */
1154 switch (con->tag) {
1155 /* Note: Not sign-extending - we carry 'syned' around */
1156 case Ico_U64:
1157 u = con->Ico.U64;
1158 break;
1159 case Ico_U32:
1160 u = 0xFFFFFFFF & con->Ico.U32;
1161 break;
1162 case Ico_U16:
1163 u = 0x0000FFFF & con->Ico.U16;
1164 break;
1165 case Ico_U8:
1166 u = 0x000000FF & con->Ico.U8;
1167 break;
1168 default:
1169 vpanic("iselIntExpr_RH.Iex_Const(tilegx)");
1170 }
1171 l = (Long) u;
1172 /* Now figure out if it's representable. */
1173 if (!syned && u <= 255) {
1174 return TILEGXRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF));
1175 }
1176 if (syned && l >= -127 && l <= 127) {
1177 return TILEGXRH_Imm(True /*signed */ , toUShort(u & 0xFFFF));
1178 }
1179 /* no luck; use the Slow Way. */
1180 }
1181 /* default case: calculate into a register and return that */
1182 return TILEGXRH_Reg(iselWordExpr_R(env, e));
1183}
1184
1185/* --------------------- RH6u --------------------- */
1186
1187/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
1188 being an immediate in the range 0 .. 63 inclusive. Used for doing
1189 shift amounts. */
1190
1191static TILEGXRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e )
1192{
1193 TILEGXRH *ri;
1194 ri = iselWordExpr_RH6u_wrk(env, e);
1195 /* sanity checks ... */
1196 switch (ri->tag) {
1197 case GXrh_Imm:
1198 vassert(ri->GXrh.Imm.imm16 >= 1 && ri->GXrh.Imm.imm16 <= 63);
1199 vassert(!ri->GXrh.Imm.syned);
1200 return ri;
1201 case GXrh_Reg:
1202 vassert(hregClass(ri->GXrh.Reg.reg) == HRcInt64);
1203 vassert(hregIsVirtual(ri->GXrh.Reg.reg));
1204 return ri;
1205 default:
1206 vpanic("iselIntExpr_RH6u: unknown tilegx RH tag");
1207 }
1208}
1209
1210/* DO NOT CALL THIS DIRECTLY ! */
1211static TILEGXRH *iselWordExpr_RH6u_wrk ( ISelEnv * env, IRExpr * e )
1212{
1213 IRType ty = typeOfIRExpr(env->type_env, e);
1214
1215 /* special case: immediate */
1216 if (e->tag == Iex_Const)
1217 {
1218 if (ty == Ity_I8)
1219 {
1220 if(e->Iex.Const.con->tag == Ico_U8
1221 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 63)
1222 return TILEGXRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8);
1223 }
1224 else if (ty == Ity_I64)
1225 {
1226 if(e->Iex.Const.con->tag == Ico_U64
1227 && e->Iex.Const.con->Ico.U64 >= 1
1228 && e->Iex.Const.con->Ico.U64 <= 63)
1229 return TILEGXRH_Imm(False /*unsigned */, e->Iex.Const.con->Ico.U64);
1230 }
1231 }
1232
1233 /* default case: calculate into a register and return that */
1234 return TILEGXRH_Reg(iselWordExpr_R(env, e));
1235}
1236
1237/* --------------------- CONDCODE --------------------- */
1238
1239/* Generate code to evaluated a bit-typed expression, returning the
1240 condition code which would correspond when the expression would
1241 notionally have returned 1. */
1242
1243static TILEGXCondCode iselCondCode(ISelEnv * env, IRExpr * e)
1244{
1245 TILEGXCondCode cc = iselCondCode_wrk(env,e);
1246 vassert(cc != TILEGXcc_NV);
1247 return cc;
1248}
1249
1250/* DO NOT CALL THIS DIRECTLY ! */
1251static TILEGXCondCode iselCondCode_wrk ( ISelEnv * env, IRExpr * e )
1252{
1253 vassert(e);
1254 vassert(typeOfIRExpr(env->type_env, e) == Ity_I1);
1255
1256 /* Cmp*(x,y) ? */
1257 if (e->Iex.Binop.op == Iop_CmpEQ32
1258 || e->Iex.Binop.op == Iop_CmpNE32
1259 || e->Iex.Binop.op == Iop_CmpNE64
1260 || e->Iex.Binop.op == Iop_CmpLT32S
1261 || e->Iex.Binop.op == Iop_CmpLT32U
1262 || e->Iex.Binop.op == Iop_CmpLT64U
1263 || e->Iex.Binop.op == Iop_CmpLE32S
1264 || e->Iex.Binop.op == Iop_CmpLE64S
1265 || e->Iex.Binop.op == Iop_CmpLT64S
1266 || e->Iex.Binop.op == Iop_CmpEQ64
1267 || e->Iex.Binop.op == Iop_CasCmpEQ32
1268 || e->Iex.Binop.op == Iop_CasCmpEQ64) {
1269
1270 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
1271 || e->Iex.Binop.op == Iop_CmpLE32S
1272 || e->Iex.Binop.op == Iop_CmpLT64S
1273 || e->Iex.Binop.op == Iop_CmpLE64S);
1274 Bool size32;
1275 HReg dst = newVRegI(env);
1276 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
1277 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
1278
1279 TILEGXCondCode cc;
1280
1281 switch (e->Iex.Binop.op) {
1282 case Iop_CmpEQ32:
1283 case Iop_CasCmpEQ32:
1284 cc = TILEGXcc_EQ;
1285 size32 = True;
1286 break;
1287 case Iop_CmpNE32:
1288 cc = TILEGXcc_NE;
1289 size32 = True;
1290 break;
1291 case Iop_CmpNE64:
1292 cc = TILEGXcc_NE;
1293 size32 = True;
1294 break;
1295 case Iop_CmpLT32S:
1296 cc = TILEGXcc_LT;
1297 size32 = True;
1298 break;
1299 case Iop_CmpLT32U:
1300 cc = TILEGXcc_LO;
1301 size32 = True;
1302 break;
1303 case Iop_CmpLT64U:
1304 cc = TILEGXcc_LO;
1305 size32 = False;
1306 break;
1307 case Iop_CmpLE32S:
1308 cc = TILEGXcc_LE;
1309 size32 = True;
1310 break;
1311 case Iop_CmpLE64S:
1312 cc = TILEGXcc_LE;
1313 size32 = False;
1314 break;
1315 case Iop_CmpLT64S:
1316 cc = TILEGXcc_LT;
1317 size32 = False;
1318 break;
1319 case Iop_CmpEQ64:
1320 case Iop_CasCmpEQ64:
1321 cc = TILEGXcc_EQ;
1322 size32 = False;
1323 break;
1324 default:
1325 vpanic("iselCondCode(tilegx): CmpXX32 or CmpXX64");
1326 break;
1327 }
1328
1329 addInstr(env, TILEGXInstr_Cmp(syned, size32, dst, r1, r2, cc));
1330 /* Store result to guest_COND */
1331 TILEGXAMode *am_addr = TILEGXAMode_IR(0, TILEGXGuestStatePointer());
1332
1333 addInstr(env, TILEGXInstr_Store(8,
1334 TILEGXAMode_IR(am_addr->GXam.IR.index +
1335 COND_OFFSET(),
1336 am_addr->GXam.IR.base),
1337 dst));
1338 return cc;
1339 }
1340
1341 if (e->Iex.Binop.op == Iop_Not1) {
1342 HReg r_dst = newVRegI(env);
1343 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1344 TILEGXRH *r_srcR = TILEGXRH_Reg(r_srcL);
1345
1346 addInstr(env, TILEGXInstr_LI(r_dst, 0x1));
1347 addInstr(env, TILEGXInstr_Alu(GXalu_SUB, r_dst, r_dst, r_srcR));
1348
1349 /* Store result to guest_COND */
1350 TILEGXAMode *am_addr = TILEGXAMode_IR(0, TILEGXGuestStatePointer());
1351
1352 addInstr(env, TILEGXInstr_Store(8,
1353 TILEGXAMode_IR(am_addr->GXam.IR.index +
1354 COND_OFFSET(),
1355 am_addr->GXam.IR.base),
1356 r_dst));
1357 return TILEGXcc_NE;
1358 }
1359
1360 if (e->tag == Iex_RdTmp || e->tag == Iex_Unop) {
1361 HReg r_dst = iselWordExpr_R_wrk(env, e);
1362 /* Store result to guest_COND */
1363 TILEGXAMode *am_addr = TILEGXAMode_IR(0, TILEGXGuestStatePointer());
1364
1365 addInstr(env, TILEGXInstr_Store(8,
1366 TILEGXAMode_IR(am_addr->GXam.IR.index +
1367 COND_OFFSET(),
1368 am_addr->GXam.IR.base),
1369 r_dst));
1370 return TILEGXcc_EQ;
1371 }
1372
1373 vex_printf("iselCondCode(tilegx): No such tag(%u)\n", e->tag);
1374 ppIRExpr(e);
1375 vpanic("iselCondCode(tilegx)");
1376
1377 /* Constant 1:Bit */
1378 if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True)
1379 return TILEGXcc_AL;
1380
1381 if (e->tag == Iex_RdTmp)
1382 return TILEGXcc_EQ;
1383
1384 if (e->tag == Iex_Binop)
1385 return TILEGXcc_EQ;
1386
1387 if (e->tag == Iex_Unop)
1388 return TILEGXcc_EQ;
1389
1390 vex_printf("iselCondCode(tilegx): No such tag(%u)\n", e->tag);
1391 ppIRExpr(e);
1392 vpanic("iselCondCode(tilegx)");
1393}
1394
1395/*---------------------------------------------------------*/
1396/*--- ISEL: Statements ---*/
1397/*---------------------------------------------------------*/
1398
1399static void iselStmt ( ISelEnv * env, IRStmt * stmt )
1400{
1401 if (vex_traceflags & VEX_TRACE_VCODE) {
1402 vex_printf("\n-- ");
1403 ppIRStmt(stmt);
1404 vex_printf("\n");
1405 }
1406
1407 switch (stmt->tag) {
1408 /* --------- STORE --------- */
1409 case Ist_Store: {
1410 TILEGXAMode *am_addr;
1411 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
1412
1413 /*constructs addressing mode from address provided */
1414 am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd);
1415
1416 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
1417 (tyd == Ity_I64)) {
1418 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
1419 addInstr(env, TILEGXInstr_Store(toUChar(sizeofIRType(tyd)),
1420 am_addr, r_src));
1421 return;
1422 }
1423 break;
1424 }
1425
1426 /* --------- PUT --------- */
1427 case Ist_Put: {
1428 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
1429
1430 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1431 (ty == Ity_I64)) {
1432 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
1433 TILEGXAMode *am_addr = TILEGXAMode_IR(stmt->Ist.Put.offset,
1434 TILEGXGuestStatePointer());
1435 addInstr(env, TILEGXInstr_Store(toUChar(sizeofIRType(ty)),
1436 am_addr, r_src));
1437 return;
1438 }
1439 break;
1440 }
1441
1442 /* --------- TMP --------- */
1443 case Ist_WrTmp: {
1444 IRTemp tmp = stmt->Ist.WrTmp.tmp;
1445 IRType ty = typeOfIRTemp(env->type_env, tmp);
1446 HReg r_dst = lookupIRTemp(env, tmp);
1447 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
1448 IRType dty = typeOfIRExpr(env->type_env, stmt->Ist.WrTmp.data);
1449
1450 if (ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8 ||
1451 (ty == dty))
1452 {
1453 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
1454 return;
1455 }
1456 else if (ty == Ity_I1) {
1457 switch (dty)
1458 {
1459 case Ity_I32:
1460 addInstr(env, TILEGXInstr_Bf(GXbf_EXTU, r_src, r_src, 0, 31));
1461 break;
1462 case Ity_I16:
1463 addInstr(env, TILEGXInstr_Bf(GXbf_EXTU, r_src, r_src, 0, 15));
1464 break;
1465 case Ity_I8:
1466 addInstr(env, TILEGXInstr_Bf(GXbf_EXTU, r_src, r_src, 0, 7));
1467 break;
1468 default:
1469 vassert(0);
1470 }
1471
1472 addInstr(env, TILEGXInstr_MovCond(r_dst,
1473 hregTILEGX_R63(),
1474 TILEGXRH_Imm(False, 1),
1475 r_src,
1476 TILEGXcc_EZ));
1477 return;
1478 }
1479 break;
1480 }
1481
1482 /* --------- Call to DIRTY helper --------- */
1483 case Ist_Dirty: {
1484 IRType retty;
1485 IRDirty *d = stmt->Ist.Dirty.details;
1486
1487 /* Marshal args, do the call, clear stack. */
1488 doHelperCall(env, d->guard, d->cee, d->args, -1);
1489
1490 /* Now figure out what to do with the returned value, if any. */
1491 if (d->tmp == IRTemp_INVALID)
1492 /* No return value. Nothing to do. */
1493 return;
1494
1495 retty = typeOfIRTemp(env->type_env, d->tmp);
1496
1497 if (retty == Ity_I8 || retty == Ity_I16 || retty == Ity_I32
1498 || (retty == Ity_I64)) {
1499 /* The returned value is in r0. Park it in the register
1500 associated with tmp. */
1501 HReg r_dst = lookupIRTemp(env, d->tmp);
1502 addInstr(env, mk_iMOVds_RR(r_dst, hregTILEGX_R0()));
1503 return;
1504 }
1505 break;
1506 }
1507
1508
1509 /* --------- ACAS --------- */
1510 case Ist_CAS:
1511 {
1512 UChar sz;
1513 IRCAS* cas = stmt->Ist.CAS.details;
1514 IRType ty = typeOfIRExpr(env->type_env, cas->dataLo);
1515
1516 TILEGXAMode *r_addr = iselWordExpr_AMode(env, cas->addr, Ity_I64);
1517 HReg r_new = iselWordExpr_R(env, cas->dataLo);
1518 HReg r_old = lookupIRTemp(env, cas->oldLo);
1519 HReg r_exp = INVALID_HREG;
1520
1521 vassert(cas->expdHi == NULL);
1522 vassert(cas->dataHi == NULL);
1523 vassert(r_addr->tag == GXam_IR);
1524 vassert(r_addr->GXam.IR.index == 0);
1525
1526 switch (ty)
1527 {
1528 case Ity_I64: sz = 8; break;
1529 case Ity_I32: sz = 4; break;
1530 default: vassert(0);
1531 }
1532
1533 if (cas->expdLo->tag != Iex_Const)
1534 {
1535 r_exp = iselWordExpr_R(env, cas->expdLo);
1536 addInstr(env, TILEGXInstr_Acas(GXacas_CMPEXCH, r_old,
1537 r_addr->GXam.IR.base, r_exp,
1538 r_new, sz));
1539 }
1540 else
1541 {
1542 if((sz == 8 && cas->expdLo->Iex.Const.con->Ico.U64 == 0) ||
1543 (sz == 4 && cas->expdLo->Iex.Const.con->Ico.U32 == 0))
1544 {
1545 addInstr(env, TILEGXInstr_Acas(GXacas_EXCH, r_old,
1546 r_addr->GXam.IR.base,
1547 r_exp, r_new, sz));
1548 }
1549 else if((sz == 8 && cas->expdLo->Iex.Const.con->Ico.U64 == 2) ||
1550 (sz == 4 && cas->expdLo->Iex.Const.con->Ico.U32 == 2))
1551 {
1552 addInstr(env, TILEGXInstr_Acas(GXacas_FetchAnd, r_old,
1553 r_addr->GXam.IR.base, r_exp,
1554 r_new, sz));
1555 }
1556 else if((sz == 8 && cas->expdLo->Iex.Const.con->Ico.U64 == 3) ||
1557 (sz == 4 && cas->expdLo->Iex.Const.con->Ico.U32 == 3))
1558 {
1559 addInstr(env, TILEGXInstr_Acas(GXacas_FetchAdd, r_old,
1560 r_addr->GXam.IR.base,
1561 r_exp, r_new, sz));
1562 }
1563 else if((sz == 8 && cas->expdLo->Iex.Const.con->Ico.U64 == 4) ||
1564 (sz == 4 && cas->expdLo->Iex.Const.con->Ico.U32 == 4))
1565 {
1566 addInstr(env, TILEGXInstr_Acas(GXacas_FetchOr, r_old,
1567 r_addr->GXam.IR.base, r_exp,
1568 r_new, sz));
1569 }
1570 else if((sz == 8 && cas->expdLo->Iex.Const.con->Ico.U64 == 5) ||
1571 (sz == 4 && cas->expdLo->Iex.Const.con->Ico.U32 == 5))
1572 {
1573 addInstr(env, TILEGXInstr_Acas(GXacas_FetchAddgez, r_old,
1574 r_addr->GXam.IR.base, r_exp,
1575 r_new, sz));
1576 }
1577 else
1578 {
1579 vassert(0);
1580 }
1581 }
1582 return;
1583 }
1584
1585 /* --------- INSTR MARK --------- */
1586 /* Doesn't generate any executable code ... */
1587 case Ist_IMark:
1588 return;
1589
1590 /* --------- ABI HINT --------- */
1591 /* These have no meaning (denotation in the IR) and so we ignore
1592 them ... if any actually made it this far. */
1593 case Ist_AbiHint:
1594 return;
1595
1596 /* --------- NO-OP --------- */
1597 /* Fairly self-explanatory, wouldn't you say? */
1598 case Ist_NoOp:
1599 return;
1600
1601 /* --------- EXIT --------- */
1602 case Ist_Exit: {
1603
1604 TILEGXCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard);
1605 TILEGXAMode* amPC = TILEGXAMode_IR(stmt->Ist.Exit.offsIP,
1606 TILEGXGuestStatePointer());
1607
1608 /* Case: boring transfer to known address */
1609 if (stmt->Ist.Exit.jk == Ijk_Boring
1610 || stmt->Ist.Exit.jk == Ijk_Call
1611 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
1612 if (env->chainingAllowed) {
1613 /* .. almost always true .. */
1614 /* Skip the event check at the dst if this is a forwards
1615 edge. */
1616 Bool toFastEP =
1617 ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > ((Addr64)env->max_ga);
1618
1619 if (0) vex_printf("%s", toFastEP ? "Y" : ",");
1620 addInstr(env, TILEGXInstr_XDirect(
1621 (Addr64)stmt->Ist.Exit.dst->Ico.U64,
1622 amPC, cc, toFastEP));
1623 } else {
1624 /* .. very occasionally .. */
1625 /* We can't use chaining, so ask for an assisted transfer,
1626 as that's the only alternative that is allowable. */
1627 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
1628 addInstr(env, TILEGXInstr_XAssisted(r, amPC, cc, Ijk_Boring));
1629 }
1630 return;
1631 }
1632
1633 /* Case: assisted transfer to arbitrary address */
1634 switch (stmt->Ist.Exit.jk) {
1635 /* Keep this list in sync with that in iselNext below */
1636 case Ijk_ClientReq:
1637 case Ijk_EmFail:
1638 case Ijk_EmWarn:
1639 case Ijk_NoDecode:
1640 case Ijk_NoRedir:
1641 case Ijk_SigBUS:
1642 case Ijk_Yield:
1643 case Ijk_SigTRAP:
1644 case Ijk_SigFPE_IntDiv:
1645 case Ijk_SigFPE_IntOvf:
1646 case Ijk_Sys_syscall:
1647 case Ijk_InvalICache:
1648 case Ijk_Ret:
1649 {
1650 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
1651 addInstr(env, TILEGXInstr_XAssisted(r, amPC, cc,
1652 stmt->Ist.Exit.jk));
1653 return;
1654 }
1655 default:
1656 break;
1657 }
1658
1659 /* Do we ever expect to see any other kind? */
1660 goto stmt_fail;
1661 }
1662
1663 default:
1664 break;
1665 }
1666
1667 stmt_fail:
1668 vex_printf("stmt_fail tag: 0x%x\n", stmt->tag);
1669 ppIRStmt(stmt);
1670 vpanic("iselStmt:\n");
1671}
1672
1673/*---------------------------------------------------------*/
1674/*--- ISEL: Basic block terminators (Nexts) ---*/
1675/*---------------------------------------------------------*/
1676
1677static void iselNext ( ISelEnv * env, IRExpr * next, IRJumpKind jk,
1678 Int offsIP )
1679{
1680
1681 if (vex_traceflags & VEX_TRACE_VCODE) {
1682 vex_printf("\n-- PUT(%d) = ", offsIP);
1683 ppIRExpr(next);
1684 vex_printf( "; exit-");
1685 ppIRJumpKind(jk);
1686 vex_printf( "\n");
1687 }
1688
1689 /* Case: boring transfer to known address */
1690 if (next->tag == Iex_Const) {
1691 IRConst* cdst = next->Iex.Const.con;
1692 if (jk == Ijk_Boring || jk == Ijk_Call) {
1693 /* Boring transfer to known address */
1694 TILEGXAMode* amPC = TILEGXAMode_IR(offsIP, TILEGXGuestStatePointer());
1695 if (env->chainingAllowed) {
1696 /* .. almost always true .. */
1697 /* Skip the event check at the dst if this is a forwards
1698 edge. */
1699 Bool toFastEP = ((Addr64)cdst->Ico.U64) > ((Addr64)env->max_ga);
1700
1701 if (0) vex_printf("%s", toFastEP ? "X" : ".");
1702 addInstr(env, TILEGXInstr_XDirect((Addr64)cdst->Ico.U64,
1703 amPC, TILEGXcc_AL, toFastEP));
1704 } else {
1705 /* .. very occasionally .. */
1706 /* We can't use chaining, so ask for an assisted transfer,
1707 as that's the only alternative that is allowable. */
1708 HReg r = iselWordExpr_R(env, next);
1709 addInstr(env, TILEGXInstr_XAssisted(r, amPC, TILEGXcc_AL,
1710 Ijk_Boring));
1711 }
1712 return;
1713 }
1714 }
1715
1716 /* Case: call/return (==boring) transfer to any address */
1717 switch (jk) {
1718 case Ijk_Boring: case Ijk_Call: {
1719 HReg r = iselWordExpr_R(env, next);
1720 TILEGXAMode* amPC = TILEGXAMode_IR(offsIP,
1721 TILEGXGuestStatePointer());
1722 if (env->chainingAllowed)
1723 addInstr(env, TILEGXInstr_XIndir(r, amPC, TILEGXcc_AL));
1724 else
1725 addInstr(env, TILEGXInstr_XAssisted(r, amPC, TILEGXcc_AL,
1726 Ijk_Boring));
1727 return;
1728 }
1729 default:
1730 break;
1731 }
1732
1733 /* Case: assisted transfer to arbitrary address */
1734 switch (jk) {
1735 /* Keep this list in sync with that for Ist_Exit above */
1736 case Ijk_ClientReq:
1737 case Ijk_EmFail:
1738 case Ijk_EmWarn:
1739 case Ijk_NoDecode:
1740 case Ijk_NoRedir:
1741 case Ijk_SigBUS:
1742 case Ijk_SigILL:
1743 case Ijk_SigTRAP:
1744 case Ijk_SigFPE_IntDiv:
1745 case Ijk_SigFPE_IntOvf:
1746 case Ijk_Sys_syscall:
1747 case Ijk_InvalICache:
1748 case Ijk_Ret: {
1749 HReg r = iselWordExpr_R(env, next);
1750 TILEGXAMode* amPC = TILEGXAMode_IR(offsIP, TILEGXGuestStatePointer());
1751 addInstr(env, TILEGXInstr_XAssisted(r, amPC, TILEGXcc_AL, jk));
1752 return;
1753 }
1754 default:
1755 break;
1756 }
1757
1758 vex_printf("\n-- PUT(%d) = ", offsIP);
1759 ppIRExpr(next );
1760 vex_printf("; exit-");
1761 ppIRJumpKind(jk);
1762 vex_printf("\n");
1763 vassert(0); /* are we expecting any other kind? */
1764}
1765
1766/*---------------------------------------------------------*/
1767/*--- Insn selector top-level ---*/
1768/*---------------------------------------------------------*/
1769
1770/* Translate an entire BB to tilegx code. */
1771HInstrArray *iselSB_TILEGX ( const IRSB* bb,
1772 VexArch arch_host,
1773 const VexArchInfo* archinfo_host,
1774 const VexAbiInfo* vbi,
1775 Int offs_Host_EvC_Counter,
1776 Int offs_Host_EvC_FailAddr,
1777 Bool chainingAllowed,
1778 Bool addProfInc,
1779 Addr max_ga )
1780{
1781 Int i, j;
1782 HReg hreg;
1783 ISelEnv *env;
1784 UInt hwcaps_host = archinfo_host->hwcaps;
1785 TILEGXAMode *amCounter, *amFailAddr;
1786
1787 /* sanity ... */
1788 vassert(arch_host == VexArchTILEGX);
1789
1790 /* Make up an initial environment to use. */
1791 env = LibVEX_Alloc(sizeof(ISelEnv));
1792 env->vreg_ctr = 0;
1793 env->mode64 = True;
1794
1795 /* Set up output code array. */
1796 env->code = newHInstrArray();
1797
1798 /* Copy BB's type env. */
1799 env->type_env = bb->tyenv;
1800
1801 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
1802 change as we go along. */
1803 env->n_vregmap = bb->tyenv->types_used;
1804 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
1805
1806 /* and finally ... */
1807 env->hwcaps = hwcaps_host;
1808 env->chainingAllowed = chainingAllowed;
1809 env->hwcaps = hwcaps_host;
1810 env->max_ga = max_ga;
1811
1812 /* For each IR temporary, allocate a suitably-kinded virtual
1813 register. */
1814 j = 0;
1815
1816 for (i = 0; i < env->n_vregmap; i++) {
1817 hreg = INVALID_HREG;
1818 switch (bb->tyenv->types[i]) {
1819 case Ity_I1:
1820 case Ity_I8:
1821 case Ity_I16:
1822 case Ity_I32:
1823 hreg = mkHReg(True, HRcInt64, 0, j++);
1824 break;
1825 case Ity_I64:
1826 hreg = mkHReg(True, HRcInt64, 0, j++);
1827 break;
1828 default:
1829 ppIRType(bb->tyenv->types[i]);
1830 vpanic("iselBB(tilegx): IRTemp type");
1831 }
1832 env->vregmap[i] = hreg;
1833 }
1834 env->vreg_ctr = j;
1835
1836 /* The very first instruction must be an event check. */
1837 amCounter = TILEGXAMode_IR(offs_Host_EvC_Counter,
1838 TILEGXGuestStatePointer());
1839 amFailAddr = TILEGXAMode_IR(offs_Host_EvC_FailAddr,
1840 TILEGXGuestStatePointer());
1841 addInstr(env, TILEGXInstr_EvCheck(amCounter, amFailAddr));
1842
1843 /* Possibly a block counter increment (for profiling). At this
1844 point we don't know the address of the counter, so just pretend
1845 it is zero. It will have to be patched later, but before this
1846 translation is used, by a call to LibVEX_patchProfCtr. */
1847 if (addProfInc) {
1848 addInstr(env, TILEGXInstr_ProfInc());
1849 }
1850
1851 /* Ok, finally we can iterate over the statements. */
1852 for (i = 0; i < bb->stmts_used; i++)
1853 iselStmt(env, bb->stmts[i]);
1854
1855 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
1856
1857 /* record the number of vregs we used. */
1858 env->code->n_vregs = env->vreg_ctr;
1859 return env->code;
1860}
1861
1862/*---------------------------------------------------------------*/
1863/*--- end host_tilegx_isel.c ---*/
1864/*---------------------------------------------------------------*/