1 2 /*---------------------------------------------------------------*/ 3 /*--- begin host_tilegx_isel.c ---*/ 4 /*---------------------------------------------------------------*/ 5 6 /* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2010-2015 Tilera Corp. 11 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 */ 95 typedef 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 119 static HReg lookupIRTemp ( ISelEnv * env, IRTemp tmp ) 120 { 121 vassert(tmp >= 0); 122 vassert(tmp < env->n_vregmap); 123 return env->vregmap[tmp]; 124 } 125 126 static 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 135 static 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 */ 158 static TILEGXRH *iselWordExpr_RH_wrk ( ISelEnv * env, Bool syned, IRExpr * e ); 159 static TILEGXRH *iselWordExpr_RH ( ISelEnv * env, Bool syned, IRExpr * e ); 160 161 static TILEGXRH *iselWordExpr_RH6u_wrk ( ISelEnv * env, IRExpr * e ); 162 static TILEGXRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e ); 163 164 /* compute an I8/I16/I32/I64 into a GPR*/ 165 static HReg iselWordExpr_R_wrk ( ISelEnv * env, IRExpr * e ); 166 static HReg iselWordExpr_R ( ISelEnv * env, IRExpr * e ); 167 168 /* compute an I64 into an AMode. */ 169 static TILEGXAMode *iselWordExpr_AMode_wrk ( ISelEnv * env, IRExpr * e, 170 IRType xferTy ); 171 static TILEGXAMode *iselWordExpr_AMode ( ISelEnv * env, IRExpr * e, 172 IRType xferTy ); 173 174 static TILEGXCondCode iselCondCode_wrk ( ISelEnv * env, IRExpr * e ); 175 static TILEGXCondCode iselCondCode ( ISelEnv * env, IRExpr * e ); 176 177 /*---------------------------------------------------------*/ 178 /*--- ISEL: Misc helpers ---*/ 179 /*---------------------------------------------------------*/ 180 181 /* Make an int reg-reg move. */ 182 static 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 */ 198 static 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 214 static 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) 250 vex_printf("nVECRETs=%u, nBBPTRs=%u\n", 251 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 372 static Bool uInt_fits_in_16_bits ( UInt u ) 373 { 374 UInt v = u & 0xFFFF; 375 376 v = (Int)(v << 16) >> 16; /* sign extend */ 377 378 return u == v; 379 } 380 381 static 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 391 static 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 ! */ 400 static 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 */ 441 static 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 ! */ 452 static 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 484 case Iop_Add8: 485 case Iop_Add16: 486 case Iop_Add32: 487 case Iop_Add64: 488 aluOp = GXalu_ADD; 489 break; 490 491 case Iop_Sub8: 492 case Iop_Sub16: 493 case Iop_Sub32: 494 case Iop_Sub64: 495 aluOp = GXalu_SUB; 496 break; 497 498 case Iop_And8: 499 case Iop_And16: 500 case Iop_And32: 501 case Iop_And64: 502 aluOp = GXalu_AND; 503 break; 504 505 case Iop_Or8: 506 case Iop_Or16: 507 case Iop_Or32: 508 case Iop_Or64: 509 aluOp = GXalu_OR; 510 break; 511 512 case Iop_Xor8: 513 case Iop_Xor16: 514 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 1122 static 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 ! */ 1142 static 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 1191 static 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 ! */ 1211 static 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 1243 static 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 ! */ 1251 static 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 1399 static 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 1677 static 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. */ 1771 HInstrArray *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 /*---------------------------------------------------------------*/ 1865