1 /* -*- mode: C; c-basic-offset: 3; -*- */ 2 3 /*---------------------------------------------------------------*/ 4 /*--- begin host_s390_isel.c ---*/ 5 /*---------------------------------------------------------------*/ 6 7 /* 8 This file is part of Valgrind, a dynamic binary instrumentation 9 framework. 10 11 Copyright IBM Corp. 2010-2013 12 Copyright (C) 2012-2013 Florian Krohm (britzel (at) acm.org) 13 14 This program is free software; you can redistribute it and/or 15 modify it under the terms of the GNU General Public License as 16 published by the Free Software Foundation; either version 2 of the 17 License, or (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, but 20 WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; if not, write to the Free Software 26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 27 02110-1301, USA. 28 29 The GNU General Public License is contained in the file COPYING. 30 */ 31 32 /* Contributed by Florian Krohm */ 33 34 #include "libvex_basictypes.h" 35 #include "libvex_ir.h" 36 #include "libvex.h" 37 #include "libvex_s390x_common.h" 38 39 #include "main_util.h" 40 #include "main_globals.h" 41 #include "guest_s390_defs.h" /* S390X_GUEST_OFFSET */ 42 #include "host_generic_regs.h" 43 #include "host_s390_defs.h" 44 45 /*---------------------------------------------------------*/ 46 /*--- ISelEnv ---*/ 47 /*---------------------------------------------------------*/ 48 49 /* This carries around: 50 51 - A mapping from IRTemp to IRType, giving the type of any IRTemp we 52 might encounter. This is computed before insn selection starts, 53 and does not change. 54 55 - A mapping from IRTemp to HReg. This tells the insn selector 56 which virtual register(s) are associated with each IRTemp 57 temporary. This is computed before insn selection starts, and 58 does not change. We expect this mapping to map precisely the 59 same set of IRTemps as the type mapping does. 60 61 - vregmap holds the primary register for the IRTemp. 62 - vregmapHI holds the secondary register for the IRTemp, 63 if any is needed. That's only for Ity_I64 temps 64 in 32 bit mode or Ity_I128 temps in 64-bit mode. 65 66 - The code array, that is, the insns selected so far. 67 68 - A counter, for generating new virtual registers. 69 70 - The host subarchitecture we are selecting insns for. 71 This is set at the start and does not change. 72 73 - A Bool for indicating whether we may generate chain-me 74 instructions for control flow transfers, or whether we must use 75 XAssisted. 76 77 - The maximum guest address of any guest insn in this block. 78 Actually, the address of the highest-addressed byte from any insn 79 in this block. Is set at the start and does not change. This is 80 used for detecting jumps which are definitely forward-edges from 81 this block, and therefore can be made (chained) to the fast entry 82 point of the destination, thereby avoiding the destination's 83 event check. 84 85 - Values of certain guest registers which are often assigned constants. 86 */ 87 88 /* Symbolic names for guest registers whose value we're tracking */ 89 enum { 90 GUEST_IA, 91 GUEST_CC_OP, 92 GUEST_CC_DEP1, 93 GUEST_CC_DEP2, 94 GUEST_CC_NDEP, 95 GUEST_SYSNO, 96 GUEST_COUNTER, 97 GUEST_UNKNOWN /* must be the last entry */ 98 }; 99 100 /* Number of registers we're tracking. */ 101 #define NUM_TRACKED_REGS GUEST_UNKNOWN 102 103 104 typedef struct { 105 IRTypeEnv *type_env; 106 107 HInstrArray *code; 108 HReg *vregmap; 109 HReg *vregmapHI; 110 UInt n_vregmap; 111 UInt vreg_ctr; 112 UInt hwcaps; 113 114 IRExpr *previous_bfp_rounding_mode; 115 IRExpr *previous_dfp_rounding_mode; 116 117 ULong old_value[NUM_TRACKED_REGS]; 118 119 /* The next two are for translation chaining */ 120 Addr64 max_ga; 121 Bool chaining_allowed; 122 123 Bool old_value_valid[NUM_TRACKED_REGS]; 124 } ISelEnv; 125 126 127 /* Forward declarations */ 128 static HReg s390_isel_int_expr(ISelEnv *, IRExpr *); 129 static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *); 130 static s390_amode *s390_isel_amode_b12_b20(ISelEnv *, IRExpr *); 131 static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *); 132 static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *); 133 static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *); 134 static HReg s390_isel_float_expr(ISelEnv *, IRExpr *); 135 static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *); 136 static HReg s390_isel_dfp_expr(ISelEnv *, IRExpr *); 137 static void s390_isel_dfp128_expr(HReg *, HReg *, ISelEnv *, IRExpr *); 138 139 140 static Int 141 get_guest_reg(Int offset) 142 { 143 switch (offset) { 144 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA; 145 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP; 146 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1; 147 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2; 148 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP; 149 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO; 150 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER; 151 152 /* Also make sure there is never a partial write to one of 153 these registers. That would complicate matters. */ 154 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7: 155 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7: 156 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7: 157 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7: 158 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7: 159 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7: 160 /* counter is used both as 4-byte and as 8-byte entity */ 161 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3: 162 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7: 163 vpanic("partial update of this guest state register is not allowed"); 164 break; 165 166 default: break; 167 } 168 169 return GUEST_UNKNOWN; 170 } 171 172 /* Add an instruction */ 173 static void 174 addInstr(ISelEnv *env, s390_insn *insn) 175 { 176 addHInstr(env->code, insn); 177 178 if (vex_traceflags & VEX_TRACE_VCODE) { 179 vex_printf("%s\n", s390_insn_as_string(insn)); 180 } 181 } 182 183 184 static __inline__ IRExpr * 185 mkU64(ULong value) 186 { 187 return IRExpr_Const(IRConst_U64(value)); 188 } 189 190 191 /*---------------------------------------------------------*/ 192 /*--- Registers ---*/ 193 /*---------------------------------------------------------*/ 194 195 /* Return the virtual register to which a given IRTemp is mapped. */ 196 static HReg 197 lookupIRTemp(ISelEnv *env, IRTemp tmp) 198 { 199 vassert(tmp < env->n_vregmap); 200 vassert(! hregIsInvalid(env->vregmap[tmp])); 201 202 return env->vregmap[tmp]; 203 } 204 205 206 /* Return the two virtual registers to which the IRTemp is mapped. */ 207 static void 208 lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp) 209 { 210 vassert(tmp < env->n_vregmap); 211 vassert(! hregIsInvalid(env->vregmapHI[tmp])); 212 213 *lo = env->vregmap[tmp]; 214 *hi = env->vregmapHI[tmp]; 215 } 216 217 218 /* Allocate a new virtual integer register */ 219 static __inline__ HReg 220 mkVRegI(UInt ix) 221 { 222 return mkHReg(/*virtual*/True, HRcInt64, /*encoding*/0, ix); 223 } 224 225 static __inline__ HReg 226 newVRegI(ISelEnv *env) 227 { 228 return mkVRegI(env->vreg_ctr++); 229 } 230 231 232 /* Allocate a new virtual floating point register */ 233 static __inline__ HReg 234 mkVRegF(UInt ix) 235 { 236 return mkHReg(/*virtual*/True, HRcFlt64, /*encoding*/0, ix); 237 } 238 239 static __inline__ HReg 240 newVRegF(ISelEnv *env) 241 { 242 return mkVRegF(env->vreg_ctr++); 243 } 244 245 246 /* Construct a non-virtual general purpose register */ 247 static __inline__ HReg 248 make_gpr(UInt regno) 249 { 250 return s390_hreg_gpr(regno); 251 } 252 253 254 /* Construct a non-virtual floating point register */ 255 static __inline__ HReg 256 make_fpr(UInt regno) 257 { 258 return s390_hreg_fpr(regno); 259 } 260 261 262 /*---------------------------------------------------------*/ 263 /*--- Amode ---*/ 264 /*---------------------------------------------------------*/ 265 266 static __inline__ Bool 267 ulong_fits_unsigned_12bit(ULong val) 268 { 269 return (val & 0xFFFu) == val; 270 } 271 272 273 static __inline__ Bool 274 ulong_fits_signed_20bit(ULong val) 275 { 276 ULong v = val & 0xFFFFFu; 277 278 v = (Long)(v << 44) >> 44; /* sign extend */ 279 280 return val == v; 281 } 282 283 284 static __inline__ Bool 285 ulong_fits_signed_8bit(ULong val) 286 { 287 ULong v = val & 0xFFu; 288 289 v = (Long)(v << 56) >> 56; /* sign extend */ 290 291 return val == v; 292 } 293 294 /* EXPR is an expression that is used as an address. Return an s390_amode 295 for it. If select_b12_b20_only is true the returned amode must be either 296 S390_AMODE_B12 or S390_AMODE_B20. */ 297 static s390_amode * 298 s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr, 299 Bool select_b12_b20_only __attribute__((unused))) 300 { 301 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) { 302 IRExpr *arg1 = expr->Iex.Binop.arg1; 303 IRExpr *arg2 = expr->Iex.Binop.arg2; 304 305 /* Move constant into right subtree */ 306 if (arg1->tag == Iex_Const) { 307 IRExpr *tmp; 308 tmp = arg1; 309 arg1 = arg2; 310 arg2 = tmp; 311 } 312 313 /* r + constant: Check for b12 first, then b20 */ 314 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) { 315 ULong value = arg2->Iex.Const.con->Ico.U64; 316 317 if (ulong_fits_unsigned_12bit(value)) { 318 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1)); 319 } 320 if (ulong_fits_signed_20bit(value)) { 321 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1)); 322 } 323 } 324 } 325 326 /* Doesn't match anything in particular. Generate it into 327 a register and use that. */ 328 return s390_amode_b12(0, s390_isel_int_expr(env, expr)); 329 } 330 331 332 static s390_amode * 333 s390_isel_amode(ISelEnv *env, IRExpr *expr) 334 { 335 s390_amode *am; 336 337 /* Address computation should yield a 64-bit value */ 338 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64); 339 340 am = s390_isel_amode_wrk(env, expr, /* B12, B20 only */ False); 341 342 /* Check post-condition */ 343 vassert(s390_amode_is_sane(am)); 344 345 return am; 346 } 347 348 349 /* Sometimes we must compile an expression into an amode that is either 350 S390_AMODE_B12 or S390_AMODE_B20. An example is the compare-and-swap 351 opcode. These opcodes do not have a variant hat accepts an addressing 352 mode with an index register. 353 Now, in theory we could, when emitting the compare-and-swap insn, 354 hack a, say, BX12 amode into a B12 amode like so: 355 356 r0 = b # save away base register 357 b = b + x # add index register to base register 358 cas(b,d,...) # emit compare-and-swap using b12 amode 359 b = r0 # restore base register 360 361 Unfortunately, emitting the compare-and-swap insn already utilises r0 362 under the covers, so the trick above is off limits, sadly. */ 363 static s390_amode * 364 s390_isel_amode_b12_b20(ISelEnv *env, IRExpr *expr) 365 { 366 s390_amode *am; 367 368 /* Address computation should yield a 64-bit value */ 369 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64); 370 371 am = s390_isel_amode_wrk(env, expr, /* B12, B20 only */ True); 372 373 /* Check post-condition */ 374 vassert(s390_amode_is_sane(am) && 375 (am->tag == S390_AMODE_B12 || am->tag == S390_AMODE_B20)); 376 377 return am; 378 } 379 380 381 /*---------------------------------------------------------*/ 382 /*--- Helper functions ---*/ 383 /*---------------------------------------------------------*/ 384 385 /* Constants and memory accesses should be right operands */ 386 #define order_commutative_operands(left, right) \ 387 do { \ 388 if (left->tag == Iex_Const || left->tag == Iex_Load || \ 389 left->tag == Iex_Get) { \ 390 IRExpr *tmp; \ 391 tmp = left; \ 392 left = right; \ 393 right = tmp; \ 394 } \ 395 } while (0) 396 397 398 /* Copy an RMI operand to the DST register */ 399 static s390_insn * 400 s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd) 401 { 402 switch (opnd.tag) { 403 case S390_OPND_AMODE: 404 return s390_insn_load(size, dst, opnd.variant.am); 405 406 case S390_OPND_REG: 407 return s390_insn_move(size, dst, opnd.variant.reg); 408 409 case S390_OPND_IMMEDIATE: 410 return s390_insn_load_immediate(size, dst, opnd.variant.imm); 411 412 default: 413 vpanic("s390_opnd_copy"); 414 } 415 } 416 417 418 /* Construct a RMI operand for a register */ 419 static __inline__ s390_opnd_RMI 420 s390_opnd_reg(HReg reg) 421 { 422 s390_opnd_RMI opnd; 423 424 opnd.tag = S390_OPND_REG; 425 opnd.variant.reg = reg; 426 427 return opnd; 428 } 429 430 431 /* Construct a RMI operand for an immediate constant */ 432 static __inline__ s390_opnd_RMI 433 s390_opnd_imm(ULong value) 434 { 435 s390_opnd_RMI opnd; 436 437 opnd.tag = S390_OPND_IMMEDIATE; 438 opnd.variant.imm = value; 439 440 return opnd; 441 } 442 443 444 /* Return 1, if EXPR represents the constant 0 */ 445 static Bool 446 s390_expr_is_const_zero(IRExpr *expr) 447 { 448 ULong value; 449 450 if (expr->tag == Iex_Const) { 451 switch (expr->Iex.Const.con->tag) { 452 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break; 453 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break; 454 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break; 455 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break; 456 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break; 457 default: 458 vpanic("s390_expr_is_const_zero"); 459 } 460 return value == 0; 461 } 462 463 return 0; 464 } 465 466 467 /* Return the value of CON as a sign-exteded ULong value */ 468 static ULong 469 get_const_value_as_ulong(const IRConst *con) 470 { 471 ULong value; 472 473 switch (con->tag) { 474 case Ico_U1: value = con->Ico.U1; return ((Long)(value << 63) >> 63); 475 case Ico_U8: value = con->Ico.U8; return ((Long)(value << 56) >> 56); 476 case Ico_U16: value = con->Ico.U16; return ((Long)(value << 48) >> 48); 477 case Ico_U32: value = con->Ico.U32; return ((Long)(value << 32) >> 32); 478 case Ico_U64: return con->Ico.U64; 479 default: 480 vpanic("get_const_value_as_ulong"); 481 } 482 } 483 484 485 /* Call a helper (clean or dirty) 486 Arguments must satisfy the following conditions: 487 488 (a) they are expressions yielding an integer result 489 (b) there can be no more than S390_NUM_GPRPARMS arguments 490 491 guard is a Ity_Bit expression indicating whether or not the 492 call happens. If guard == NULL, the call is unconditional. 493 494 Calling the helper function proceeds as follows: 495 496 (1) The helper arguments are evaluated and their value stored in 497 virtual registers. 498 (2) The condition code is evaluated 499 (3) The argument values are copied from the virtual registers to the 500 registers mandated by the ABI. 501 (4) Call the helper function. 502 503 This is not the most efficient way as step 3 generates register-to-register 504 moves. But it is the least fragile way as the only hidden dependency here 505 is that register-to-register moves (step 3) must not clobber the condition 506 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register- 507 to-register add more such dependencies. Not good. Besides, it's the job 508 of the register allocator to throw out those reg-to-reg moves. 509 */ 510 static void 511 doHelperCall(/*OUT*/UInt *stackAdjustAfterCall, 512 /*OUT*/RetLoc *retloc, 513 ISelEnv *env, IRExpr *guard, 514 IRCallee *callee, IRType retTy, IRExpr **args) 515 { 516 UInt n_args, i, argreg, size; 517 Addr64 target; 518 HReg tmpregs[S390_NUM_GPRPARMS]; 519 s390_cc_t cc; 520 521 /* Set default returns. We'll update them later if needed. */ 522 *stackAdjustAfterCall = 0; 523 *retloc = mk_RetLoc_INVALID(); 524 525 /* The return type can be I{64,32,16,8} or V{128,256}. In the 526 latter two cases, it is expected that |args| will contain the 527 special node IRExpr_VECRET(). For s390, however, V128 and V256 return 528 values do not occur as we generally do not support vector types. 529 530 |args| may also contain IRExpr_BBPTR(), in which case the value 531 in the guest state pointer register is passed as the 532 corresponding argument. 533 534 These are used for cross-checking that IR-level constraints on 535 the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */ 536 UInt nVECRETs = 0; 537 UInt nBBPTRs = 0; 538 539 n_args = 0; 540 for (i = 0; args[i]; i++) 541 ++n_args; 542 543 if (n_args > S390_NUM_GPRPARMS) { 544 vpanic("doHelperCall: too many arguments"); 545 } 546 547 /* All arguments must have Ity_I64. For two reasons: 548 (1) We do not handle floating point arguments. 549 (2) The ABI requires that integer values are sign- or zero-extended 550 to 64 bit. 551 */ 552 Int arg_errors = 0; 553 for (i = 0; i < n_args; ++i) { 554 if (UNLIKELY(args[i]->tag == Iex_VECRET)) { 555 nVECRETs++; 556 } else if (UNLIKELY(args[i]->tag == Iex_BBPTR)) { 557 nBBPTRs++; 558 } else { 559 IRType type = typeOfIRExpr(env->type_env, args[i]); 560 if (type != Ity_I64) { 561 ++arg_errors; 562 vex_printf("calling %s: argument #%d has type ", callee->name, i); 563 ppIRType(type); 564 vex_printf("; Ity_I64 is required\n"); 565 } 566 } 567 } 568 569 if (arg_errors) 570 vpanic("cannot continue due to errors in argument passing"); 571 572 /* If these fail, the IR is ill-formed */ 573 vassert(nBBPTRs == 0 || nBBPTRs == 1); 574 vassert(nVECRETs == 0); 575 576 argreg = 0; 577 578 /* Compute the function arguments into a temporary register each */ 579 for (i = 0; i < n_args; i++) { 580 IRExpr *arg = args[i]; 581 if (UNLIKELY(arg->tag == Iex_BBPTR)) { 582 /* If we need the guest state pointer put it in a temporary arg reg */ 583 tmpregs[argreg] = newVRegI(env); 584 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg], 585 s390_hreg_guest_state_pointer())); 586 } else { 587 tmpregs[argreg] = s390_isel_int_expr(env, args[i]); 588 } 589 argreg++; 590 } 591 592 /* Compute the condition */ 593 cc = S390_CC_ALWAYS; 594 if (guard) { 595 if (guard->tag == Iex_Const 596 && guard->Iex.Const.con->tag == Ico_U1 597 && guard->Iex.Const.con->Ico.U1 == True) { 598 /* unconditional -- do nothing */ 599 } else { 600 cc = s390_isel_cc(env, guard); 601 } 602 } 603 604 /* Move the args to the final register. It is paramount, that the 605 code to move the registers does not clobber the condition code ! */ 606 for (i = 0; i < argreg; i++) { 607 HReg finalreg; 608 609 finalreg = make_gpr(s390_gprno_from_arg_index(i)); 610 size = sizeofIRType(Ity_I64); 611 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i])); 612 } 613 614 target = (Addr)callee->addr; 615 616 /* Do final checks, set the return values, and generate the call 617 instruction proper. */ 618 vassert(*stackAdjustAfterCall == 0); 619 vassert(is_RetLoc_INVALID(*retloc)); 620 switch (retTy) { 621 case Ity_INVALID: 622 /* Function doesn't return a value. */ 623 *retloc = mk_RetLoc_simple(RLPri_None); 624 break; 625 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8: 626 *retloc = mk_RetLoc_simple(RLPri_Int); 627 break; 628 default: 629 /* IR can denote other possible return types, but we don't 630 handle those here. */ 631 vex_printf("calling %s: return type is ", callee->name); 632 ppIRType(retTy); 633 vex_printf("; an integer type is required\n"); 634 vassert(0); 635 } 636 637 /* Finally, the call itself. */ 638 addInstr(env, s390_insn_helper_call(cc, target, n_args, 639 callee->name, *retloc)); 640 } 641 642 643 /*---------------------------------------------------------*/ 644 /*--- BFP helper functions ---*/ 645 /*---------------------------------------------------------*/ 646 647 /* Set the BFP rounding mode in the FPC. This function is called for 648 all non-conversion BFP instructions as those will always get the 649 rounding mode from the FPC. */ 650 static void 651 set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm) 652 { 653 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32); 654 655 /* Do we need to do anything? */ 656 if (env->previous_bfp_rounding_mode && 657 env->previous_bfp_rounding_mode->tag == Iex_RdTmp && 658 irrm->tag == Iex_RdTmp && 659 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) { 660 /* No - new mode is identical to previous mode. */ 661 return; 662 } 663 664 /* No luck - we better set it, and remember what we set it to. */ 665 env->previous_bfp_rounding_mode = irrm; 666 667 /* The incoming rounding mode is in VEX IR encoding. Need to change 668 to s390. 669 670 rounding mode | s390 | IR 671 ------------------------- 672 to nearest | 00 | 00 673 to zero | 01 | 11 674 to +infinity | 10 | 10 675 to -infinity | 11 | 01 676 677 So: s390 = (4 - IR) & 3 678 */ 679 HReg ir = s390_isel_int_expr(env, irrm); 680 681 HReg mode = newVRegI(env); 682 683 addInstr(env, s390_insn_load_immediate(4, mode, 4)); 684 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir))); 685 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3))); 686 687 addInstr(env, s390_insn_set_fpc_bfprm(4, mode)); 688 } 689 690 691 /* This function is invoked for insns that support a specification of 692 a rounding mode in the insn itself. In that case there is no need to 693 stick the rounding mode into the FPC -- a good thing. However, the 694 rounding mode must be known. */ 695 static s390_bfp_round_t 696 get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm) 697 { 698 if (irrm->tag == Iex_Const) { /* rounding mode is known */ 699 vassert(irrm->Iex.Const.con->tag == Ico_U32); 700 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32; 701 702 switch (mode) { 703 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN; 704 case Irrm_ZERO: return S390_BFP_ROUND_ZERO; 705 case Irrm_PosINF: return S390_BFP_ROUND_POSINF; 706 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF; 707 default: 708 vpanic("get_bfp_rounding_mode"); 709 } 710 } 711 712 set_bfp_rounding_mode_in_fpc(env, irrm); 713 return S390_BFP_ROUND_PER_FPC; 714 } 715 716 717 /*---------------------------------------------------------*/ 718 /*--- DFP helper functions ---*/ 719 /*---------------------------------------------------------*/ 720 721 /* Set the DFP rounding mode in the FPC. This function is called for 722 all non-conversion DFP instructions as those will always get the 723 rounding mode from the FPC. */ 724 static void 725 set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm) 726 { 727 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32); 728 729 /* Do we need to do anything? */ 730 if (env->previous_dfp_rounding_mode && 731 env->previous_dfp_rounding_mode->tag == Iex_RdTmp && 732 irrm->tag == Iex_RdTmp && 733 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) { 734 /* No - new mode is identical to previous mode. */ 735 return; 736 } 737 738 /* No luck - we better set it, and remember what we set it to. */ 739 env->previous_dfp_rounding_mode = irrm; 740 741 /* The incoming rounding mode is in VEX IR encoding. Need to change 742 to s390. 743 744 rounding mode | S390 | IR 745 ----------------------------------------------- 746 to nearest, ties to even | 000 | 000 747 to zero | 001 | 011 748 to +infinity | 010 | 010 749 to -infinity | 011 | 001 750 to nearest, ties away from 0 | 100 | 100 751 to nearest, ties toward 0 | 101 | 111 752 to away from 0 | 110 | 110 753 to prepare for shorter precision | 111 | 101 754 755 So: s390 = (IR ^ ((IR << 1) & 2)) 756 */ 757 HReg ir = s390_isel_int_expr(env, irrm); 758 759 HReg mode = newVRegI(env); 760 761 addInstr(env, s390_insn_move(4, mode, ir)); 762 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1))); 763 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2))); 764 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir))); 765 766 addInstr(env, s390_insn_set_fpc_dfprm(4, mode)); 767 } 768 769 770 /* This function is invoked for insns that support a specification of 771 a rounding mode in the insn itself. In that case there is no need to 772 stick the rounding mode into the FPC -- a good thing. However, the 773 rounding mode must be known. 774 775 When mapping an Irrm_XYZ value to an S390_DFP_ROUND_ value there is 776 often a choice. For instance, Irrm_ZERO could be mapped to either 777 S390_DFP_ROUND_ZERO_5 or S390_DFP_ROUND_ZERO_9. The difference between 778 those two is that with S390_DFP_ROUND_ZERO_9 the recognition of the 779 quantum exception is suppressed whereas with S390_DFP_ROUND_ZERO_5 it 780 is not. As the quantum exception is not modelled we can choose either 781 value. The choice is to use S390_DFP_ROUND_.. values in the range [8:15], 782 because values in the range [1:7] have unpredictable rounding behaviour 783 when the floating point exception facility is not installed. 784 785 Translation table of 786 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode 787 788 s390(S390_DFP_ROUND_) | IR(Irrm_) | s390(S390_DFP_ROUND_) 789 -------------------------------------------------------------------- 790 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_12 791 NEAREST_TIE_AWAY_0_12 | " | " 792 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_15 793 PREPARE_SHORT_15 | " | " 794 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_8 795 NEAREST_EVEN_8 | " | " 796 ZERO_5 | ZERO | ZERO_9 797 ZERO_9 | " | " 798 POSINF_6 | PosINF | POSINF_10 799 POSINF_10 | " | " 800 NEGINF_7 | NegINF | NEGINF_11 801 NEGINF_11 | " | " 802 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0 803 AWAY_0 | AWAY_FROM_ZERO | AWAY_0 804 */ 805 static s390_dfp_round_t 806 get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm) 807 { 808 if (irrm->tag == Iex_Const) { /* rounding mode is known */ 809 vassert(irrm->Iex.Const.con->tag == Ico_U32); 810 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32; 811 812 switch (mode) { 813 case Irrm_NEAREST: 814 return S390_DFP_ROUND_NEAREST_EVEN_8; 815 case Irrm_NegINF: 816 return S390_DFP_ROUND_NEGINF_11; 817 case Irrm_PosINF: 818 return S390_DFP_ROUND_POSINF_10; 819 case Irrm_ZERO: 820 return S390_DFP_ROUND_ZERO_9; 821 case Irrm_NEAREST_TIE_AWAY_0: 822 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12; 823 case Irrm_PREPARE_SHORTER: 824 return S390_DFP_ROUND_PREPARE_SHORT_15; 825 case Irrm_AWAY_FROM_ZERO: 826 return S390_DFP_ROUND_AWAY_0; 827 case Irrm_NEAREST_TIE_TOWARD_0: 828 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0; 829 default: 830 vpanic("get_dfp_rounding_mode"); 831 } 832 } 833 834 set_dfp_rounding_mode_in_fpc(env, irrm); 835 return S390_DFP_ROUND_PER_FPC_0; 836 } 837 838 839 /*---------------------------------------------------------*/ 840 /*--- Condition code helper functions ---*/ 841 /*---------------------------------------------------------*/ 842 843 /* CC_S390 holds the condition code in s390 encoding. Convert it to 844 VEX encoding (IRCmpFResult) 845 846 s390 VEX b6 b2 b0 cc.1 cc.0 847 0 0x40 EQ 1 0 0 0 0 848 1 0x01 LT 0 0 1 0 1 849 2 0x00 GT 0 0 0 1 0 850 3 0x45 Unordered 1 1 1 1 1 851 852 b0 = cc.0 853 b2 = cc.0 & cc.1 854 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1 855 856 VEX = b0 | (b2 << 2) | (b6 << 6); 857 */ 858 static HReg 859 convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390) 860 { 861 HReg cc0, cc1, b2, b6, cc_vex; 862 863 cc0 = newVRegI(env); 864 addInstr(env, s390_insn_move(4, cc0, cc_s390)); 865 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1))); 866 867 cc1 = newVRegI(env); 868 addInstr(env, s390_insn_move(4, cc1, cc_s390)); 869 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1))); 870 871 b2 = newVRegI(env); 872 addInstr(env, s390_insn_move(4, b2, cc0)); 873 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1))); 874 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2))); 875 876 b6 = newVRegI(env); 877 addInstr(env, s390_insn_move(4, b6, cc0)); 878 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1))); 879 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1))); 880 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1))); 881 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6))); 882 883 cc_vex = newVRegI(env); 884 addInstr(env, s390_insn_move(4, cc_vex, cc0)); 885 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2))); 886 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6))); 887 888 return cc_vex; 889 } 890 891 /* CC_S390 holds the condition code in s390 encoding. Convert it to 892 VEX encoding (IRCmpDResult) */ 893 static HReg 894 convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390) 895 { 896 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */ 897 return convert_s390_to_vex_bfpcc(env, cc_s390); 898 } 899 900 901 /*---------------------------------------------------------*/ 902 /*--- ISEL: Integer expressions (128 bit) ---*/ 903 /*---------------------------------------------------------*/ 904 static void 905 s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 906 IRExpr *expr) 907 { 908 IRType ty = typeOfIRExpr(env->type_env, expr); 909 910 vassert(ty == Ity_I128); 911 912 /* No need to consider the following 913 - 128-bit constants (they do not exist in VEX) 914 - 128-bit loads from memory (will not be generated) 915 */ 916 917 /* Read 128-bit IRTemp */ 918 if (expr->tag == Iex_RdTmp) { 919 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp); 920 return; 921 } 922 923 if (expr->tag == Iex_Binop) { 924 IRExpr *arg1 = expr->Iex.Binop.arg1; 925 IRExpr *arg2 = expr->Iex.Binop.arg2; 926 Bool is_signed_multiply, is_signed_divide; 927 928 switch (expr->Iex.Binop.op) { 929 case Iop_MullU64: 930 is_signed_multiply = False; 931 goto do_multiply64; 932 933 case Iop_MullS64: 934 is_signed_multiply = True; 935 goto do_multiply64; 936 937 case Iop_DivModU128to64: 938 is_signed_divide = False; 939 goto do_divide64; 940 941 case Iop_DivModS128to64: 942 is_signed_divide = True; 943 goto do_divide64; 944 945 case Iop_64HLto128: 946 *dst_hi = s390_isel_int_expr(env, arg1); 947 *dst_lo = s390_isel_int_expr(env, arg2); 948 return; 949 950 case Iop_DivModS64to64: { 951 HReg r10, r11, h1; 952 s390_opnd_RMI op2; 953 954 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 955 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 956 957 /* We use non-virtual registers r10 and r11 as pair */ 958 r10 = make_gpr(10); 959 r11 = make_gpr(11); 960 961 /* Move 1st operand into r11 and */ 962 addInstr(env, s390_insn_move(8, r11, h1)); 963 964 /* Divide */ 965 addInstr(env, s390_insn_divs(8, r10, r11, op2)); 966 967 /* The result is in registers r10 (remainder) and r11 (quotient). 968 Move the result into the reg pair that is being returned such 969 such that the low 64 bits are the quotient and the upper 64 bits 970 are the remainder. (see libvex_ir.h). */ 971 *dst_hi = newVRegI(env); 972 *dst_lo = newVRegI(env); 973 addInstr(env, s390_insn_move(8, *dst_hi, r10)); 974 addInstr(env, s390_insn_move(8, *dst_lo, r11)); 975 return; 976 } 977 978 default: 979 break; 980 981 do_multiply64: { 982 HReg r10, r11, h1; 983 s390_opnd_RMI op2; 984 985 order_commutative_operands(arg1, arg2); 986 987 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 988 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 989 990 /* We use non-virtual registers r10 and r11 as pair */ 991 r10 = make_gpr(10); 992 r11 = make_gpr(11); 993 994 /* Move the first operand to r11 */ 995 addInstr(env, s390_insn_move(8, r11, h1)); 996 997 /* Multiply */ 998 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply)); 999 1000 /* The result is in registers r10 and r11. Assign to two virtual regs 1001 and return. */ 1002 *dst_hi = newVRegI(env); 1003 *dst_lo = newVRegI(env); 1004 addInstr(env, s390_insn_move(8, *dst_hi, r10)); 1005 addInstr(env, s390_insn_move(8, *dst_lo, r11)); 1006 return; 1007 } 1008 1009 do_divide64: { 1010 HReg r10, r11, hi, lo; 1011 s390_opnd_RMI op2; 1012 1013 s390_isel_int128_expr(&hi, &lo, env, arg1); 1014 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 1015 1016 /* We use non-virtual registers r10 and r11 as pair */ 1017 r10 = make_gpr(10); 1018 r11 = make_gpr(11); 1019 1020 /* Move high 64 bits of the 1st operand into r10 and 1021 the low 64 bits into r11. */ 1022 addInstr(env, s390_insn_move(8, r10, hi)); 1023 addInstr(env, s390_insn_move(8, r11, lo)); 1024 1025 /* Divide */ 1026 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide)); 1027 1028 /* The result is in registers r10 (remainder) and r11 (quotient). 1029 Move the result into the reg pair that is being returned such 1030 such that the low 64 bits are the quotient and the upper 64 bits 1031 are the remainder. (see libvex_ir.h). */ 1032 *dst_hi = newVRegI(env); 1033 *dst_lo = newVRegI(env); 1034 addInstr(env, s390_insn_move(8, *dst_hi, r10)); 1035 addInstr(env, s390_insn_move(8, *dst_lo, r11)); 1036 return; 1037 } 1038 } 1039 } 1040 1041 vpanic("s390_isel_int128_expr"); 1042 } 1043 1044 1045 /* Compute a 128-bit value into two 64-bit registers. These may be either 1046 real or virtual regs; in any case they must not be changed by subsequent 1047 code emitted by the caller. */ 1048 static void 1049 s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr) 1050 { 1051 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr); 1052 1053 /* Sanity checks ... */ 1054 vassert(hregIsVirtual(*dst_hi)); 1055 vassert(hregIsVirtual(*dst_lo)); 1056 vassert(hregClass(*dst_hi) == HRcInt64); 1057 vassert(hregClass(*dst_lo) == HRcInt64); 1058 } 1059 1060 1061 /*---------------------------------------------------------*/ 1062 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/ 1063 /*---------------------------------------------------------*/ 1064 1065 /* Select insns for an integer-typed expression, and add them to the 1066 code list. Return a reg holding the result. This reg will be a 1067 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you 1068 want to modify it, ask for a new vreg, copy it in there, and modify 1069 the copy. The register allocator will do its best to map both 1070 vregs to the same real register, so the copies will often disappear 1071 later in the game. 1072 1073 This should handle expressions of 64, 32, 16 and 8-bit type. 1074 All results are returned in a 64bit register. 1075 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits 1076 are arbitrary, so you should mask or sign extend partial values 1077 if necessary. 1078 */ 1079 1080 /* DO NOT CALL THIS DIRECTLY ! */ 1081 static HReg 1082 s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) 1083 { 1084 IRType ty = typeOfIRExpr(env->type_env, expr); 1085 UChar size; 1086 s390_bfp_conv_t conv; 1087 s390_dfp_conv_t dconv; 1088 1089 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64); 1090 1091 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */ 1092 1093 switch (expr->tag) { 1094 1095 /* --------- TEMP --------- */ 1096 case Iex_RdTmp: 1097 /* Return the virtual register that holds the temporary. */ 1098 return lookupIRTemp(env, expr->Iex.RdTmp.tmp); 1099 1100 /* --------- LOAD --------- */ 1101 case Iex_Load: { 1102 HReg dst = newVRegI(env); 1103 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr); 1104 1105 if (expr->Iex.Load.end != Iend_BE) 1106 goto irreducible; 1107 1108 addInstr(env, s390_insn_load(size, dst, am)); 1109 1110 return dst; 1111 } 1112 1113 /* --------- BINARY OP --------- */ 1114 case Iex_Binop: { 1115 IRExpr *arg1 = expr->Iex.Binop.arg1; 1116 IRExpr *arg2 = expr->Iex.Binop.arg2; 1117 HReg h1, res; 1118 s390_alu_t opkind; 1119 s390_opnd_RMI op2, value, opnd; 1120 s390_insn *insn; 1121 Bool is_commutative, is_signed_multiply, is_signed_divide; 1122 1123 is_commutative = True; 1124 1125 switch (expr->Iex.Binop.op) { 1126 case Iop_MullU8: 1127 case Iop_MullU16: 1128 case Iop_MullU32: 1129 is_signed_multiply = False; 1130 goto do_multiply; 1131 1132 case Iop_MullS8: 1133 case Iop_MullS16: 1134 case Iop_MullS32: 1135 is_signed_multiply = True; 1136 goto do_multiply; 1137 1138 do_multiply: { 1139 HReg r10, r11; 1140 UInt arg_size = size / 2; 1141 1142 order_commutative_operands(arg1, arg2); 1143 1144 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 1145 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 1146 1147 /* We use non-virtual registers r10 and r11 as pair */ 1148 r10 = make_gpr(10); 1149 r11 = make_gpr(11); 1150 1151 /* Move the first operand to r11 */ 1152 addInstr(env, s390_insn_move(arg_size, r11, h1)); 1153 1154 /* Multiply */ 1155 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply)); 1156 1157 /* The result is in registers r10 and r11. Combine them into a SIZE-bit 1158 value into the destination register. */ 1159 res = newVRegI(env); 1160 addInstr(env, s390_insn_move(arg_size, res, r10)); 1161 value = s390_opnd_imm(arg_size * 8); 1162 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value)); 1163 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1); 1164 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value)); 1165 opnd = s390_opnd_reg(r11); 1166 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd)); 1167 return res; 1168 } 1169 1170 case Iop_DivModS64to32: 1171 is_signed_divide = True; 1172 goto do_divide; 1173 1174 case Iop_DivModU64to32: 1175 is_signed_divide = False; 1176 goto do_divide; 1177 1178 do_divide: { 1179 HReg r10, r11; 1180 1181 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 1182 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 1183 1184 /* We use non-virtual registers r10 and r11 as pair */ 1185 r10 = make_gpr(10); 1186 r11 = make_gpr(11); 1187 1188 /* Split the first operand and put the high 32 bits into r10 and 1189 the low 32 bits into r11. */ 1190 addInstr(env, s390_insn_move(8, r10, h1)); 1191 addInstr(env, s390_insn_move(8, r11, h1)); 1192 value = s390_opnd_imm(32); 1193 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value)); 1194 1195 /* Divide */ 1196 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide)); 1197 1198 /* The result is in registers r10 (remainder) and r11 (quotient). 1199 Combine them into a 64-bit value such that the low 32 bits are 1200 the quotient and the upper 32 bits are the remainder. (see 1201 libvex_ir.h). */ 1202 res = newVRegI(env); 1203 addInstr(env, s390_insn_move(8, res, r10)); 1204 value = s390_opnd_imm(32); 1205 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value)); 1206 value = s390_opnd_imm((((ULong)1) << 32) - 1); 1207 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value)); 1208 opnd = s390_opnd_reg(r11); 1209 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd)); 1210 return res; 1211 } 1212 1213 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert; 1214 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert; 1215 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert; 1216 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert; 1217 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert; 1218 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert; 1219 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert; 1220 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert; 1221 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128; 1222 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128; 1223 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128; 1224 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128; 1225 1226 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp; 1227 case Iop_D64toI64S: dconv = S390_DFP_D64_TO_I64; goto do_convert_dfp; 1228 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp; 1229 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp; 1230 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128; 1231 case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128; 1232 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128; 1233 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128; 1234 1235 do_convert: { 1236 s390_bfp_round_t rounding_mode; 1237 1238 res = newVRegI(env); 1239 h1 = s390_isel_float_expr(env, arg2); /* Process operand */ 1240 1241 rounding_mode = get_bfp_rounding_mode(env, arg1); 1242 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1, 1243 rounding_mode)); 1244 return res; 1245 } 1246 1247 do_convert_128: { 1248 s390_bfp_round_t rounding_mode; 1249 HReg op_hi, op_lo, f13, f15; 1250 1251 res = newVRegI(env); 1252 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */ 1253 1254 /* We use non-virtual registers r13 and r15 as pair */ 1255 f13 = make_fpr(13); 1256 f15 = make_fpr(15); 1257 1258 /* operand --> (f13, f15) */ 1259 addInstr(env, s390_insn_move(8, f13, op_hi)); 1260 addInstr(env, s390_insn_move(8, f15, op_lo)); 1261 1262 rounding_mode = get_bfp_rounding_mode(env, arg1); 1263 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, 1264 INVALID_HREG, f13, f15, 1265 rounding_mode)); 1266 return res; 1267 } 1268 1269 do_convert_dfp: { 1270 s390_dfp_round_t rounding_mode; 1271 1272 res = newVRegI(env); 1273 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */ 1274 1275 rounding_mode = get_dfp_rounding_mode(env, arg1); 1276 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1, 1277 rounding_mode)); 1278 return res; 1279 } 1280 1281 do_convert_dfp128: { 1282 s390_dfp_round_t rounding_mode; 1283 HReg op_hi, op_lo, f13, f15; 1284 1285 res = newVRegI(env); 1286 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */ 1287 1288 /* We use non-virtual registers r13 and r15 as pair */ 1289 f13 = make_fpr(13); 1290 f15 = make_fpr(15); 1291 1292 /* operand --> (f13, f15) */ 1293 addInstr(env, s390_insn_move(8, f13, op_hi)); 1294 addInstr(env, s390_insn_move(8, f15, op_lo)); 1295 1296 rounding_mode = get_dfp_rounding_mode(env, arg1); 1297 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res, 1298 INVALID_HREG, f13, 1299 f15, rounding_mode)); 1300 return res; 1301 } 1302 1303 case Iop_8HLto16: 1304 case Iop_16HLto32: 1305 case Iop_32HLto64: { 1306 HReg h2; 1307 UInt arg_size = size / 2; 1308 1309 res = newVRegI(env); 1310 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 1311 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */ 1312 1313 addInstr(env, s390_insn_move(arg_size, res, h1)); 1314 value = s390_opnd_imm(arg_size * 8); 1315 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value)); 1316 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1); 1317 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value)); 1318 opnd = s390_opnd_reg(h2); 1319 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd)); 1320 return res; 1321 } 1322 1323 case Iop_Max32U: { 1324 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */ 1325 res = newVRegI(env); 1326 h1 = s390_isel_int_expr(env, arg1); 1327 op2 = s390_isel_int_expr_RMI(env, arg2); 1328 1329 addInstr(env, s390_insn_move(size, res, h1)); 1330 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */)); 1331 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2)); 1332 return res; 1333 } 1334 1335 case Iop_CmpF32: 1336 case Iop_CmpF64: { 1337 HReg cc_s390, h2; 1338 1339 h1 = s390_isel_float_expr(env, arg1); 1340 h2 = s390_isel_float_expr(env, arg2); 1341 cc_s390 = newVRegI(env); 1342 1343 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8; 1344 1345 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2)); 1346 1347 return convert_s390_to_vex_bfpcc(env, cc_s390); 1348 } 1349 1350 case Iop_CmpF128: { 1351 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390; 1352 1353 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */ 1354 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */ 1355 cc_s390 = newVRegI(env); 1356 1357 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 1358 f12 = make_fpr(12); 1359 f13 = make_fpr(13); 1360 f14 = make_fpr(14); 1361 f15 = make_fpr(15); 1362 1363 /* 1st operand --> (f12, f14) */ 1364 addInstr(env, s390_insn_move(8, f12, op1_hi)); 1365 addInstr(env, s390_insn_move(8, f14, op1_lo)); 1366 1367 /* 2nd operand --> (f13, f15) */ 1368 addInstr(env, s390_insn_move(8, f13, op2_hi)); 1369 addInstr(env, s390_insn_move(8, f15, op2_lo)); 1370 1371 res = newVRegI(env); 1372 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15)); 1373 1374 return convert_s390_to_vex_bfpcc(env, cc_s390); 1375 } 1376 1377 case Iop_CmpD64: 1378 case Iop_CmpExpD64: { 1379 HReg cc_s390, h2; 1380 s390_dfp_cmp_t cmp; 1381 1382 h1 = s390_isel_dfp_expr(env, arg1); 1383 h2 = s390_isel_dfp_expr(env, arg2); 1384 cc_s390 = newVRegI(env); 1385 1386 switch(expr->Iex.Binop.op) { 1387 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break; 1388 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break; 1389 default: goto irreducible; 1390 } 1391 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2)); 1392 1393 return convert_s390_to_vex_dfpcc(env, cc_s390); 1394 } 1395 1396 case Iop_CmpD128: 1397 case Iop_CmpExpD128: { 1398 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390; 1399 s390_dfp_cmp_t cmp; 1400 1401 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */ 1402 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */ 1403 cc_s390 = newVRegI(env); 1404 1405 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 1406 f12 = make_fpr(12); 1407 f13 = make_fpr(13); 1408 f14 = make_fpr(14); 1409 f15 = make_fpr(15); 1410 1411 /* 1st operand --> (f12, f14) */ 1412 addInstr(env, s390_insn_move(8, f12, op1_hi)); 1413 addInstr(env, s390_insn_move(8, f14, op1_lo)); 1414 1415 /* 2nd operand --> (f13, f15) */ 1416 addInstr(env, s390_insn_move(8, f13, op2_hi)); 1417 addInstr(env, s390_insn_move(8, f15, op2_lo)); 1418 1419 switch(expr->Iex.Binop.op) { 1420 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break; 1421 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break; 1422 default: goto irreducible; 1423 } 1424 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14, 1425 f13, f15)); 1426 1427 return convert_s390_to_vex_dfpcc(env, cc_s390); 1428 } 1429 1430 case Iop_Add8: 1431 case Iop_Add16: 1432 case Iop_Add32: 1433 case Iop_Add64: 1434 opkind = S390_ALU_ADD; 1435 break; 1436 1437 case Iop_Sub8: 1438 case Iop_Sub16: 1439 case Iop_Sub32: 1440 case Iop_Sub64: 1441 opkind = S390_ALU_SUB; 1442 is_commutative = False; 1443 break; 1444 1445 case Iop_And8: 1446 case Iop_And16: 1447 case Iop_And32: 1448 case Iop_And64: 1449 opkind = S390_ALU_AND; 1450 break; 1451 1452 case Iop_Or8: 1453 case Iop_Or16: 1454 case Iop_Or32: 1455 case Iop_Or64: 1456 opkind = S390_ALU_OR; 1457 break; 1458 1459 case Iop_Xor8: 1460 case Iop_Xor16: 1461 case Iop_Xor32: 1462 case Iop_Xor64: 1463 opkind = S390_ALU_XOR; 1464 break; 1465 1466 case Iop_Shl8: 1467 case Iop_Shl16: 1468 case Iop_Shl32: 1469 case Iop_Shl64: 1470 opkind = S390_ALU_LSH; 1471 is_commutative = False; 1472 break; 1473 1474 case Iop_Shr8: 1475 case Iop_Shr16: 1476 case Iop_Shr32: 1477 case Iop_Shr64: 1478 opkind = S390_ALU_RSH; 1479 is_commutative = False; 1480 break; 1481 1482 case Iop_Sar8: 1483 case Iop_Sar16: 1484 case Iop_Sar32: 1485 case Iop_Sar64: 1486 opkind = S390_ALU_RSHA; 1487 is_commutative = False; 1488 break; 1489 1490 default: 1491 goto irreducible; 1492 } 1493 1494 /* Pattern match: 0 - arg1 --> -arg1 */ 1495 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) { 1496 res = newVRegI(env); 1497 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 1498 insn = s390_insn_unop(size, S390_NEGATE, res, op2); 1499 addInstr(env, insn); 1500 1501 return res; 1502 } 1503 1504 if (is_commutative) { 1505 order_commutative_operands(arg1, arg2); 1506 } 1507 1508 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 1509 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 1510 res = newVRegI(env); 1511 1512 /* As right shifts of one/two byte opreands are implemented using a 1513 4-byte shift op, we first need to zero/sign-extend the shiftee. */ 1514 switch (expr->Iex.Binop.op) { 1515 case Iop_Shr8: 1516 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1)); 1517 break; 1518 case Iop_Shr16: 1519 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1)); 1520 break; 1521 case Iop_Sar8: 1522 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1)); 1523 break; 1524 case Iop_Sar16: 1525 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1)); 1526 break; 1527 default: 1528 insn = s390_insn_move(size, res, h1); 1529 break; 1530 } 1531 addInstr(env, insn); 1532 1533 insn = s390_insn_alu(size, opkind, res, op2); 1534 1535 addInstr(env, insn); 1536 1537 return res; 1538 } 1539 1540 /* --------- UNARY OP --------- */ 1541 case Iex_Unop: { 1542 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE }; 1543 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE }; 1544 s390_opnd_RMI opnd; 1545 s390_insn *insn; 1546 IRExpr *arg; 1547 HReg dst, h1; 1548 IROp unop, binop; 1549 1550 arg = expr->Iex.Unop.arg; 1551 1552 /* Special cases are handled here */ 1553 1554 /* 32-bit multiply with 32-bit result or 1555 64-bit multiply with 64-bit result */ 1556 unop = expr->Iex.Unop.op; 1557 binop = arg->Iex.Binop.op; 1558 1559 if ((arg->tag == Iex_Binop && 1560 ((unop == Iop_64to32 && 1561 (binop == Iop_MullS32 || binop == Iop_MullU32)) || 1562 (unop == Iop_128to64 && 1563 (binop == Iop_MullS64 || binop == Iop_MullU64))))) { 1564 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */ 1565 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */ 1566 dst = newVRegI(env); /* Result goes into a new register */ 1567 addInstr(env, s390_insn_move(size, dst, h1)); 1568 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd)); 1569 1570 return dst; 1571 } 1572 1573 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) { 1574 dst = newVRegI(env); 1575 h1 = s390_isel_float_expr(env, arg); /* Process the operand */ 1576 addInstr(env, s390_insn_move(size, dst, h1)); 1577 1578 return dst; 1579 } 1580 1581 if (unop == Iop_ReinterpD64asI64) { 1582 dst = newVRegI(env); 1583 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */ 1584 addInstr(env, s390_insn_move(size, dst, h1)); 1585 1586 return dst; 1587 } 1588 1589 if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) { 1590 s390_dfp_unop_t dfpop; 1591 switch(unop) { 1592 case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break; 1593 case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break; 1594 default: goto irreducible; 1595 } 1596 dst = newVRegI(env); 1597 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */ 1598 addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1)); 1599 return dst; 1600 } 1601 1602 if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) { 1603 s390_dfp_unop_t dfpop; 1604 HReg op_hi, op_lo, f13, f15; 1605 1606 switch(unop) { 1607 case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break; 1608 case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break; 1609 default: goto irreducible; 1610 } 1611 dst = newVRegI(env); 1612 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */ 1613 1614 /* We use non-virtual registers r13 and r15 as pair */ 1615 f13 = make_fpr(13); 1616 f15 = make_fpr(15); 1617 1618 /* operand --> (f13, f15) */ 1619 addInstr(env, s390_insn_move(8, f13, op_hi)); 1620 addInstr(env, s390_insn_move(8, f15, op_lo)); 1621 1622 addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15)); 1623 return dst; 1624 } 1625 1626 /* Expressions whose argument is 1-bit wide */ 1627 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) { 1628 s390_cc_t cond = s390_isel_cc(env, arg); 1629 dst = newVRegI(env); /* Result goes into a new register */ 1630 addInstr(env, s390_insn_cc2bool(dst, cond)); 1631 1632 switch (unop) { 1633 case Iop_1Uto8: 1634 case Iop_1Uto32: 1635 /* Zero extend */ 1636 mask.variant.imm = 1; 1637 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask)); 1638 break; 1639 1640 case Iop_1Uto64: 1641 /* Zero extend */ 1642 mask.variant.imm = 1; 1643 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask)); 1644 break; 1645 1646 case Iop_1Sto8: 1647 case Iop_1Sto16: 1648 case Iop_1Sto32: 1649 shift.variant.imm = 31; 1650 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift)); 1651 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift)); 1652 break; 1653 1654 case Iop_1Sto64: 1655 shift.variant.imm = 63; 1656 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift)); 1657 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift)); 1658 break; 1659 1660 default: 1661 goto irreducible; 1662 } 1663 1664 return dst; 1665 } 1666 1667 /* Regular processing */ 1668 1669 if (unop == Iop_128to64) { 1670 HReg dst_hi, dst_lo; 1671 1672 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg); 1673 return dst_lo; 1674 } 1675 1676 if (unop == Iop_128HIto64) { 1677 HReg dst_hi, dst_lo; 1678 1679 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg); 1680 return dst_hi; 1681 } 1682 1683 dst = newVRegI(env); /* Result goes into a new register */ 1684 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */ 1685 1686 switch (unop) { 1687 case Iop_8Uto16: 1688 case Iop_8Uto32: 1689 case Iop_8Uto64: 1690 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd); 1691 break; 1692 1693 case Iop_16Uto32: 1694 case Iop_16Uto64: 1695 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd); 1696 break; 1697 1698 case Iop_32Uto64: 1699 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd); 1700 break; 1701 1702 case Iop_8Sto16: 1703 case Iop_8Sto32: 1704 case Iop_8Sto64: 1705 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd); 1706 break; 1707 1708 case Iop_16Sto32: 1709 case Iop_16Sto64: 1710 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd); 1711 break; 1712 1713 case Iop_32Sto64: 1714 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd); 1715 break; 1716 1717 case Iop_64to8: 1718 case Iop_64to16: 1719 case Iop_64to32: 1720 case Iop_32to8: 1721 case Iop_32to16: 1722 case Iop_16to8: 1723 /* Down-casts are no-ops. Upstream operations will only look at 1724 the bytes that make up the result of the down-cast. So there 1725 is no point setting the other bytes to 0. */ 1726 insn = s390_opnd_copy(8, dst, opnd); 1727 break; 1728 1729 case Iop_64HIto32: 1730 addInstr(env, s390_opnd_copy(8, dst, opnd)); 1731 shift.variant.imm = 32; 1732 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift); 1733 break; 1734 1735 case Iop_32HIto16: 1736 addInstr(env, s390_opnd_copy(4, dst, opnd)); 1737 shift.variant.imm = 16; 1738 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift); 1739 break; 1740 1741 case Iop_16HIto8: 1742 addInstr(env, s390_opnd_copy(2, dst, opnd)); 1743 shift.variant.imm = 8; 1744 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift); 1745 break; 1746 1747 case Iop_Not8: 1748 case Iop_Not16: 1749 case Iop_Not32: 1750 case Iop_Not64: 1751 /* XOR with ffff... */ 1752 mask.variant.imm = ~(ULong)0; 1753 addInstr(env, s390_opnd_copy(size, dst, opnd)); 1754 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask); 1755 break; 1756 1757 case Iop_Left8: 1758 case Iop_Left16: 1759 case Iop_Left32: 1760 case Iop_Left64: 1761 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd)); 1762 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd); 1763 break; 1764 1765 case Iop_CmpwNEZ32: 1766 case Iop_CmpwNEZ64: { 1767 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X 1768 or -X will have a 1 in the MSB. */ 1769 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd)); 1770 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd)); 1771 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63; 1772 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift)); 1773 return dst; 1774 } 1775 1776 case Iop_Clz64: { 1777 HReg r10, r11; 1778 1779 /* This will be implemented using FLOGR, if possible. So we need to 1780 set aside a pair of non-virtual registers. The result (number of 1781 left-most zero bits) will be in r10. The value in r11 is unspecified 1782 and must not be used. */ 1783 r10 = make_gpr(10); 1784 r11 = make_gpr(11); 1785 1786 addInstr(env, s390_insn_clz(8, r10, r11, opnd)); 1787 addInstr(env, s390_insn_move(8, dst, r10)); 1788 return dst; 1789 } 1790 1791 default: 1792 goto irreducible; 1793 } 1794 1795 addInstr(env, insn); 1796 1797 return dst; 1798 } 1799 1800 /* --------- GET --------- */ 1801 case Iex_Get: { 1802 HReg dst = newVRegI(env); 1803 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset); 1804 1805 /* We never load more than 8 bytes from the guest state, because the 1806 floating point register pair is not contiguous. */ 1807 vassert(size <= 8); 1808 1809 addInstr(env, s390_insn_load(size, dst, am)); 1810 1811 return dst; 1812 } 1813 1814 case Iex_GetI: 1815 /* not needed */ 1816 break; 1817 1818 /* --------- CCALL --------- */ 1819 case Iex_CCall: { 1820 HReg dst = newVRegI(env); 1821 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE); 1822 UInt addToSp = 0; 1823 RetLoc rloc = mk_RetLoc_INVALID(); 1824 1825 doHelperCall(&addToSp, &rloc, env, NULL, expr->Iex.CCall.cee, 1826 expr->Iex.CCall.retty, expr->Iex.CCall.args); 1827 vassert(is_sane_RetLoc(rloc)); 1828 vassert(rloc.pri == RLPri_Int); 1829 vassert(addToSp == 0); 1830 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret)); 1831 1832 return dst; 1833 } 1834 1835 /* --------- LITERAL --------- */ 1836 1837 /* Load a literal into a register. Create a "load immediate" 1838 v-insn and return the register. */ 1839 case Iex_Const: { 1840 ULong value; 1841 HReg dst = newVRegI(env); 1842 const IRConst *con = expr->Iex.Const.con; 1843 1844 /* Bitwise copy of the value. No sign/zero-extension */ 1845 switch (con->tag) { 1846 case Ico_U64: value = con->Ico.U64; break; 1847 case Ico_U32: value = con->Ico.U32; break; 1848 case Ico_U16: value = con->Ico.U16; break; 1849 case Ico_U8: value = con->Ico.U8; break; 1850 default: vpanic("s390_isel_int_expr: invalid constant"); 1851 } 1852 1853 addInstr(env, s390_insn_load_immediate(size, dst, value)); 1854 1855 return dst; 1856 } 1857 1858 /* --------- MULTIPLEX --------- */ 1859 case Iex_ITE: { 1860 IRExpr *cond_expr; 1861 HReg dst, r1; 1862 s390_opnd_RMI r0; 1863 1864 cond_expr = expr->Iex.ITE.cond; 1865 1866 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1); 1867 1868 dst = newVRegI(env); 1869 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse); 1870 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue); 1871 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue)); 1872 1873 s390_cc_t cc = s390_isel_cc(env, cond_expr); 1874 1875 addInstr(env, s390_insn_move(size, dst, r1)); 1876 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0)); 1877 return dst; 1878 } 1879 1880 default: 1881 break; 1882 } 1883 1884 /* We get here if no pattern matched. */ 1885 irreducible: 1886 ppIRExpr(expr); 1887 vpanic("s390_isel_int_expr: cannot reduce tree"); 1888 } 1889 1890 1891 static HReg 1892 s390_isel_int_expr(ISelEnv *env, IRExpr *expr) 1893 { 1894 HReg dst = s390_isel_int_expr_wrk(env, expr); 1895 1896 /* Sanity checks ... */ 1897 vassert(hregClass(dst) == HRcInt64); 1898 vassert(hregIsVirtual(dst)); 1899 1900 return dst; 1901 } 1902 1903 1904 static s390_opnd_RMI 1905 s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr) 1906 { 1907 IRType ty = typeOfIRExpr(env->type_env, expr); 1908 s390_opnd_RMI dst; 1909 1910 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || 1911 ty == Ity_I64); 1912 1913 if (expr->tag == Iex_Load) { 1914 dst.tag = S390_OPND_AMODE; 1915 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr); 1916 } else if (expr->tag == Iex_Get) { 1917 dst.tag = S390_OPND_AMODE; 1918 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset); 1919 } else if (expr->tag == Iex_Const) { 1920 ULong value; 1921 1922 /* The bit pattern for the value will be stored as is in the least 1923 significant bits of VALUE. */ 1924 switch (expr->Iex.Const.con->tag) { 1925 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break; 1926 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break; 1927 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break; 1928 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break; 1929 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break; 1930 default: 1931 vpanic("s390_isel_int_expr_RMI"); 1932 } 1933 1934 dst.tag = S390_OPND_IMMEDIATE; 1935 dst.variant.imm = value; 1936 } else { 1937 dst.tag = S390_OPND_REG; 1938 dst.variant.reg = s390_isel_int_expr(env, expr); 1939 } 1940 1941 return dst; 1942 } 1943 1944 1945 /*---------------------------------------------------------*/ 1946 /*--- ISEL: Floating point expressions (128 bit) ---*/ 1947 /*---------------------------------------------------------*/ 1948 static void 1949 s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 1950 IRExpr *expr) 1951 { 1952 IRType ty = typeOfIRExpr(env->type_env, expr); 1953 1954 vassert(ty == Ity_F128); 1955 1956 switch (expr->tag) { 1957 case Iex_RdTmp: 1958 /* Return the virtual registers that hold the temporary. */ 1959 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp); 1960 return; 1961 1962 /* --------- LOAD --------- */ 1963 case Iex_Load: { 1964 IRExpr *addr_hi, *addr_lo; 1965 s390_amode *am_hi, *am_lo; 1966 1967 if (expr->Iex.Load.end != Iend_BE) 1968 goto irreducible; 1969 1970 addr_hi = expr->Iex.Load.addr; 1971 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8)); 1972 1973 am_hi = s390_isel_amode(env, addr_hi); 1974 am_lo = s390_isel_amode(env, addr_lo); 1975 1976 *dst_hi = newVRegF(env); 1977 *dst_lo = newVRegF(env); 1978 addInstr(env, s390_insn_load(8, *dst_hi, am_hi)); 1979 addInstr(env, s390_insn_load(8, *dst_hi, am_lo)); 1980 return; 1981 } 1982 1983 1984 /* --------- GET --------- */ 1985 case Iex_Get: 1986 /* This is not supported because loading 128-bit from the guest 1987 state is almost certainly wrong. Use get_fpr_pair instead. */ 1988 vpanic("Iex_Get with F128 data"); 1989 1990 /* --------- 4-ary OP --------- */ 1991 case Iex_Qop: 1992 vpanic("Iex_Qop with F128 data"); 1993 1994 /* --------- TERNARY OP --------- */ 1995 case Iex_Triop: { 1996 IRTriop *triop = expr->Iex.Triop.details; 1997 IROp op = triop->op; 1998 IRExpr *left = triop->arg2; 1999 IRExpr *right = triop->arg3; 2000 s390_bfp_binop_t bfpop; 2001 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15; 2002 2003 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */ 2004 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */ 2005 2006 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 2007 f12 = make_fpr(12); 2008 f13 = make_fpr(13); 2009 f14 = make_fpr(14); 2010 f15 = make_fpr(15); 2011 2012 /* 1st operand --> (f12, f14) */ 2013 addInstr(env, s390_insn_move(8, f12, op1_hi)); 2014 addInstr(env, s390_insn_move(8, f14, op1_lo)); 2015 2016 /* 2nd operand --> (f13, f15) */ 2017 addInstr(env, s390_insn_move(8, f13, op2_hi)); 2018 addInstr(env, s390_insn_move(8, f15, op2_lo)); 2019 2020 switch (op) { 2021 case Iop_AddF128: bfpop = S390_BFP_ADD; break; 2022 case Iop_SubF128: bfpop = S390_BFP_SUB; break; 2023 case Iop_MulF128: bfpop = S390_BFP_MUL; break; 2024 case Iop_DivF128: bfpop = S390_BFP_DIV; break; 2025 default: 2026 goto irreducible; 2027 } 2028 2029 set_bfp_rounding_mode_in_fpc(env, triop->arg1); 2030 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15)); 2031 2032 /* Move result to virtual destination register */ 2033 *dst_hi = newVRegF(env); 2034 *dst_lo = newVRegF(env); 2035 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 2036 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 2037 2038 return; 2039 } 2040 2041 /* --------- BINARY OP --------- */ 2042 case Iex_Binop: { 2043 switch (expr->Iex.Binop.op) { 2044 case Iop_SqrtF128: { 2045 HReg op_hi, op_lo, f12, f13, f14, f15; 2046 2047 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 2048 f12 = make_fpr(12); 2049 f13 = make_fpr(13); 2050 f14 = make_fpr(14); 2051 f15 = make_fpr(15); 2052 2053 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2); 2054 2055 /* operand --> (f13, f15) */ 2056 addInstr(env, s390_insn_move(8, f13, op_hi)); 2057 addInstr(env, s390_insn_move(8, f15, op_lo)); 2058 2059 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1); 2060 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14, 2061 f13, f15)); 2062 2063 /* Move result to virtual destination registers */ 2064 *dst_hi = newVRegF(env); 2065 *dst_lo = newVRegF(env); 2066 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 2067 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 2068 return; 2069 } 2070 2071 case Iop_F64HLtoF128: 2072 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1); 2073 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2); 2074 return; 2075 2076 case Iop_D32toF128: 2077 case Iop_D64toF128: { 2078 IRExpr *irrm; 2079 IRExpr *left; 2080 s390_dfp_round_t rm; 2081 HReg h1; /* virtual reg. to hold source */ 2082 HReg f0, f2, f4, r1; /* real registers used by PFPO */ 2083 s390_fp_conv_t fpconv; 2084 2085 switch (expr->Iex.Binop.op) { 2086 case Iop_D32toF128: 2087 fpconv = S390_FP_D32_TO_F128; 2088 break; 2089 case Iop_D64toF128: 2090 fpconv = S390_FP_D64_TO_F128; 2091 break; 2092 default: goto irreducible; 2093 } 2094 2095 f4 = make_fpr(4); /* source */ 2096 f0 = make_fpr(0); /* destination */ 2097 f2 = make_fpr(2); /* destination */ 2098 r1 = make_gpr(1); /* GPR #1 clobbered */ 2099 irrm = expr->Iex.Binop.arg1; 2100 left = expr->Iex.Binop.arg2; 2101 rm = get_dfp_rounding_mode(env, irrm); 2102 h1 = s390_isel_dfp_expr(env, left); 2103 addInstr(env, s390_insn_move(8, f4, h1)); 2104 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2, 2105 f4, INVALID_HREG, r1, rm)); 2106 /* (f0, f2) --> destination */ 2107 *dst_hi = newVRegF(env); 2108 *dst_lo = newVRegF(env); 2109 addInstr(env, s390_insn_move(8, *dst_hi, f0)); 2110 addInstr(env, s390_insn_move(8, *dst_lo, f2)); 2111 2112 return; 2113 } 2114 2115 case Iop_D128toF128: { 2116 IRExpr *irrm; 2117 IRExpr *left; 2118 s390_dfp_round_t rm; 2119 HReg op_hi, op_lo; 2120 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */ 2121 2122 f4 = make_fpr(4); /* source */ 2123 f6 = make_fpr(6); /* source */ 2124 f0 = make_fpr(0); /* destination */ 2125 f2 = make_fpr(2); /* destination */ 2126 r1 = make_gpr(1); /* GPR #1 clobbered */ 2127 2128 irrm = expr->Iex.Binop.arg1; 2129 left = expr->Iex.Binop.arg2; 2130 rm = get_dfp_rounding_mode(env, irrm); 2131 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left); 2132 /* operand --> (f4, f6) */ 2133 addInstr(env, s390_insn_move(8, f4, op_hi)); 2134 addInstr(env, s390_insn_move(8, f6, op_lo)); 2135 addInstr(env, s390_insn_fp128_convert(16, S390_FP_D128_TO_F128, f0, f2, 2136 f4, f6, r1, rm)); 2137 /* (f0, f2) --> destination */ 2138 *dst_hi = newVRegF(env); 2139 *dst_lo = newVRegF(env); 2140 addInstr(env, s390_insn_move(8, *dst_hi, f0)); 2141 addInstr(env, s390_insn_move(8, *dst_lo, f2)); 2142 2143 return; 2144 } 2145 2146 default: 2147 goto irreducible; 2148 } 2149 } 2150 2151 /* --------- UNARY OP --------- */ 2152 case Iex_Unop: { 2153 IRExpr *left = expr->Iex.Unop.arg; 2154 s390_bfp_unop_t bfpop; 2155 s390_bfp_conv_t conv; 2156 HReg op_hi, op_lo, op, f12, f13, f14, f15; 2157 2158 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 2159 f12 = make_fpr(12); 2160 f13 = make_fpr(13); 2161 f14 = make_fpr(14); 2162 f15 = make_fpr(15); 2163 2164 switch (expr->Iex.Unop.op) { 2165 case Iop_NegF128: 2166 if (left->tag == Iex_Unop && 2167 (left->Iex.Unop.op == Iop_AbsF32 || 2168 left->Iex.Unop.op == Iop_AbsF64)) 2169 bfpop = S390_BFP_NABS; 2170 else 2171 bfpop = S390_BFP_NEG; 2172 goto float128_opnd; 2173 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd; 2174 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int; 2175 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int; 2176 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int; 2177 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int; 2178 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float; 2179 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float; 2180 default: 2181 goto irreducible; 2182 } 2183 2184 float128_opnd: 2185 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 2186 2187 /* operand --> (f13, f15) */ 2188 addInstr(env, s390_insn_move(8, f13, op_hi)); 2189 addInstr(env, s390_insn_move(8, f15, op_lo)); 2190 2191 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15)); 2192 goto move_dst; 2193 2194 convert_float: 2195 op = s390_isel_float_expr(env, left); 2196 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op)); 2197 goto move_dst; 2198 2199 convert_int: 2200 op = s390_isel_int_expr(env, left); 2201 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op)); 2202 goto move_dst; 2203 2204 move_dst: 2205 /* Move result to virtual destination registers */ 2206 *dst_hi = newVRegF(env); 2207 *dst_lo = newVRegF(env); 2208 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 2209 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 2210 return; 2211 } 2212 2213 default: 2214 goto irreducible; 2215 } 2216 2217 /* We get here if no pattern matched. */ 2218 irreducible: 2219 ppIRExpr(expr); 2220 vpanic("s390_isel_float128_expr: cannot reduce tree"); 2221 } 2222 2223 /* Compute a 128-bit value into two 64-bit registers. These may be either 2224 real or virtual regs; in any case they must not be changed by subsequent 2225 code emitted by the caller. */ 2226 static void 2227 s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr) 2228 { 2229 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr); 2230 2231 /* Sanity checks ... */ 2232 vassert(hregIsVirtual(*dst_hi)); 2233 vassert(hregIsVirtual(*dst_lo)); 2234 vassert(hregClass(*dst_hi) == HRcFlt64); 2235 vassert(hregClass(*dst_lo) == HRcFlt64); 2236 } 2237 2238 2239 /*---------------------------------------------------------*/ 2240 /*--- ISEL: Floating point expressions (64 bit) ---*/ 2241 /*---------------------------------------------------------*/ 2242 2243 static HReg 2244 s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr) 2245 { 2246 IRType ty = typeOfIRExpr(env->type_env, expr); 2247 UChar size; 2248 2249 vassert(ty == Ity_F32 || ty == Ity_F64); 2250 2251 size = sizeofIRType(ty); 2252 2253 switch (expr->tag) { 2254 case Iex_RdTmp: 2255 /* Return the virtual register that holds the temporary. */ 2256 return lookupIRTemp(env, expr->Iex.RdTmp.tmp); 2257 2258 /* --------- LOAD --------- */ 2259 case Iex_Load: { 2260 HReg dst = newVRegF(env); 2261 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr); 2262 2263 if (expr->Iex.Load.end != Iend_BE) 2264 goto irreducible; 2265 2266 addInstr(env, s390_insn_load(size, dst, am)); 2267 2268 return dst; 2269 } 2270 2271 /* --------- GET --------- */ 2272 case Iex_Get: { 2273 HReg dst = newVRegF(env); 2274 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset); 2275 2276 addInstr(env, s390_insn_load(size, dst, am)); 2277 2278 return dst; 2279 } 2280 2281 /* --------- LITERAL --------- */ 2282 2283 /* Load a literal into a register. Create a "load immediate" 2284 v-insn and return the register. */ 2285 case Iex_Const: { 2286 ULong value; 2287 HReg dst = newVRegF(env); 2288 const IRConst *con = expr->Iex.Const.con; 2289 2290 /* Bitwise copy of the value. No sign/zero-extension */ 2291 switch (con->tag) { 2292 case Ico_F32i: value = con->Ico.F32i; break; 2293 case Ico_F64i: value = con->Ico.F64i; break; 2294 default: vpanic("s390_isel_float_expr: invalid constant"); 2295 } 2296 2297 if (value != 0) vpanic("cannot load immediate floating point constant"); 2298 2299 addInstr(env, s390_insn_load_immediate(size, dst, value)); 2300 2301 return dst; 2302 } 2303 2304 /* --------- 4-ary OP --------- */ 2305 case Iex_Qop: { 2306 HReg op1, op2, op3, dst; 2307 s390_bfp_triop_t bfpop; 2308 2309 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2); 2310 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3); 2311 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4); 2312 dst = newVRegF(env); 2313 addInstr(env, s390_insn_move(size, dst, op1)); 2314 2315 switch (expr->Iex.Qop.details->op) { 2316 case Iop_MAddF32: 2317 case Iop_MAddF64: bfpop = S390_BFP_MADD; break; 2318 case Iop_MSubF32: 2319 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break; 2320 2321 default: 2322 goto irreducible; 2323 } 2324 2325 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1); 2326 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3)); 2327 return dst; 2328 } 2329 2330 /* --------- TERNARY OP --------- */ 2331 case Iex_Triop: { 2332 IRTriop *triop = expr->Iex.Triop.details; 2333 IROp op = triop->op; 2334 IRExpr *left = triop->arg2; 2335 IRExpr *right = triop->arg3; 2336 s390_bfp_binop_t bfpop; 2337 HReg h1, op2, dst; 2338 2339 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */ 2340 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */ 2341 dst = newVRegF(env); 2342 addInstr(env, s390_insn_move(size, dst, h1)); 2343 switch (op) { 2344 case Iop_AddF32: 2345 case Iop_AddF64: bfpop = S390_BFP_ADD; break; 2346 case Iop_SubF32: 2347 case Iop_SubF64: bfpop = S390_BFP_SUB; break; 2348 case Iop_MulF32: 2349 case Iop_MulF64: bfpop = S390_BFP_MUL; break; 2350 case Iop_DivF32: 2351 case Iop_DivF64: bfpop = S390_BFP_DIV; break; 2352 2353 default: 2354 goto irreducible; 2355 } 2356 2357 set_bfp_rounding_mode_in_fpc(env, triop->arg1); 2358 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2)); 2359 return dst; 2360 } 2361 2362 /* --------- BINARY OP --------- */ 2363 case Iex_Binop: { 2364 IROp op = expr->Iex.Binop.op; 2365 IRExpr *irrm = expr->Iex.Binop.arg1; 2366 IRExpr *left = expr->Iex.Binop.arg2; 2367 HReg h1, dst; 2368 s390_bfp_conv_t conv; 2369 s390_fp_conv_t fpconv; 2370 2371 switch (op) { 2372 case Iop_SqrtF32: 2373 case Iop_SqrtF64: 2374 h1 = s390_isel_float_expr(env, left); 2375 dst = newVRegF(env); 2376 set_bfp_rounding_mode_in_fpc(env, irrm); 2377 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1)); 2378 return dst; 2379 2380 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float; 2381 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int; 2382 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int; 2383 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int; 2384 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int; 2385 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int; 2386 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int; 2387 case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp; 2388 case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp; 2389 case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp; 2390 case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp; 2391 case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128; 2392 case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128; 2393 2394 convert_float: 2395 h1 = s390_isel_float_expr(env, left); 2396 goto convert; 2397 2398 convert_int: 2399 h1 = s390_isel_int_expr(env, left); 2400 goto convert; 2401 2402 convert: { 2403 s390_bfp_round_t rounding_mode; 2404 /* convert-from-fixed and load-rounded have a rounding mode field 2405 when the floating point extension facility is installed. */ 2406 dst = newVRegF(env); 2407 if (s390_host_has_fpext) { 2408 rounding_mode = get_bfp_rounding_mode(env, irrm); 2409 } else { 2410 set_bfp_rounding_mode_in_fpc(env, irrm); 2411 rounding_mode = S390_BFP_ROUND_PER_FPC; 2412 } 2413 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1, 2414 rounding_mode)); 2415 return dst; 2416 } 2417 2418 convert_dfp: { 2419 s390_dfp_round_t rm; 2420 HReg f0, f4, r1; /* real registers used by PFPO */ 2421 2422 f4 = make_fpr(4); /* source */ 2423 f0 = make_fpr(0); /* destination */ 2424 r1 = make_gpr(1); /* GPR #1 clobbered */ 2425 h1 = s390_isel_dfp_expr(env, left); 2426 dst = newVRegF(env); 2427 rm = get_dfp_rounding_mode(env, irrm); 2428 /* operand --> f4 */ 2429 addInstr(env, s390_insn_move(8, f4, h1)); 2430 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm)); 2431 /* f0 --> destination */ 2432 addInstr(env, s390_insn_move(8, dst, f0)); 2433 return dst; 2434 } 2435 2436 convert_dfp128: { 2437 s390_dfp_round_t rm; 2438 HReg op_hi, op_lo; 2439 HReg f0, f4, f6, r1; /* real registers used by PFPO */ 2440 2441 f4 = make_fpr(4); /* source */ 2442 f6 = make_fpr(6); /* source */ 2443 f0 = make_fpr(0); /* destination */ 2444 r1 = make_gpr(1); /* GPR #1 clobbered */ 2445 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left); 2446 dst = newVRegF(env); 2447 rm = get_dfp_rounding_mode(env, irrm); 2448 /* operand --> (f4, f6) */ 2449 addInstr(env, s390_insn_move(8, f4, op_hi)); 2450 addInstr(env, s390_insn_move(8, f6, op_lo)); 2451 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG, 2452 f4, f6, r1, rm)); 2453 /* f0 --> destination */ 2454 addInstr(env, s390_insn_move(8, dst, f0)); 2455 return dst; 2456 } 2457 2458 default: 2459 goto irreducible; 2460 2461 case Iop_F128toF64: 2462 case Iop_F128toF32: { 2463 HReg op_hi, op_lo, f12, f13, f14, f15; 2464 s390_bfp_round_t rounding_mode; 2465 2466 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32 2467 : S390_BFP_F128_TO_F64; 2468 2469 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 2470 2471 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 2472 f12 = make_fpr(12); 2473 f13 = make_fpr(13); 2474 f14 = make_fpr(14); 2475 f15 = make_fpr(15); 2476 2477 /* operand --> (f13, f15) */ 2478 addInstr(env, s390_insn_move(8, f13, op_hi)); 2479 addInstr(env, s390_insn_move(8, f15, op_lo)); 2480 2481 /* result --> (f12, f14) */ 2482 2483 /* load-rounded has a rounding mode field when the floating point 2484 extension facility is installed. */ 2485 if (s390_host_has_fpext) { 2486 rounding_mode = get_bfp_rounding_mode(env, irrm); 2487 } else { 2488 set_bfp_rounding_mode_in_fpc(env, irrm); 2489 rounding_mode = S390_BFP_ROUND_PER_FPC; 2490 } 2491 2492 addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14, 2493 f13, f15, rounding_mode)); 2494 dst = newVRegF(env); 2495 addInstr(env, s390_insn_move(8, dst, f12)); 2496 2497 return dst; 2498 } 2499 } 2500 } 2501 2502 /* --------- UNARY OP --------- */ 2503 case Iex_Unop: { 2504 IROp op = expr->Iex.Unop.op; 2505 IRExpr *left = expr->Iex.Unop.arg; 2506 s390_bfp_unop_t bfpop; 2507 s390_bfp_conv_t conv; 2508 HReg h1, dst; 2509 2510 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) { 2511 HReg dst_hi, dst_lo; 2512 2513 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left); 2514 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi; 2515 } 2516 2517 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) { 2518 dst = newVRegF(env); 2519 h1 = s390_isel_int_expr(env, left); /* Process the operand */ 2520 addInstr(env, s390_insn_move(size, dst, h1)); 2521 2522 return dst; 2523 } 2524 2525 switch (op) { 2526 case Iop_NegF32: 2527 case Iop_NegF64: 2528 if (left->tag == Iex_Unop && 2529 (left->Iex.Unop.op == Iop_AbsF32 || 2530 left->Iex.Unop.op == Iop_AbsF64)) 2531 bfpop = S390_BFP_NABS; 2532 else 2533 bfpop = S390_BFP_NEG; 2534 break; 2535 2536 case Iop_AbsF32: 2537 case Iop_AbsF64: 2538 bfpop = S390_BFP_ABS; 2539 break; 2540 2541 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1; 2542 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1; 2543 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1; 2544 2545 convert_float1: 2546 h1 = s390_isel_float_expr(env, left); 2547 goto convert1; 2548 2549 convert_int1: 2550 h1 = s390_isel_int_expr(env, left); 2551 goto convert1; 2552 2553 convert1: 2554 dst = newVRegF(env); 2555 /* No rounding mode is needed for these conversions. Just stick 2556 one in. It won't be used later on. */ 2557 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1, 2558 S390_BFP_ROUND_NEAREST_EVEN)); 2559 return dst; 2560 2561 default: 2562 goto irreducible; 2563 } 2564 2565 /* Process operand */ 2566 h1 = s390_isel_float_expr(env, left); 2567 dst = newVRegF(env); 2568 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1)); 2569 return dst; 2570 } 2571 2572 default: 2573 goto irreducible; 2574 } 2575 2576 /* We get here if no pattern matched. */ 2577 irreducible: 2578 ppIRExpr(expr); 2579 vpanic("s390_isel_float_expr: cannot reduce tree"); 2580 } 2581 2582 2583 static HReg 2584 s390_isel_float_expr(ISelEnv *env, IRExpr *expr) 2585 { 2586 HReg dst = s390_isel_float_expr_wrk(env, expr); 2587 2588 /* Sanity checks ... */ 2589 vassert(hregClass(dst) == HRcFlt64); 2590 vassert(hregIsVirtual(dst)); 2591 2592 return dst; 2593 } 2594 2595 2596 /*---------------------------------------------------------*/ 2597 /*--- ISEL: Decimal point expressions (128 bit) ---*/ 2598 /*---------------------------------------------------------*/ 2599 static void 2600 s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 2601 IRExpr *expr) 2602 { 2603 IRType ty = typeOfIRExpr(env->type_env, expr); 2604 2605 vassert(ty == Ity_D128); 2606 2607 switch (expr->tag) { 2608 case Iex_RdTmp: 2609 /* Return the virtual registers that hold the temporary. */ 2610 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp); 2611 return; 2612 2613 /* --------- LOAD --------- */ 2614 case Iex_Load: { 2615 IRExpr *addr_hi, *addr_lo; 2616 s390_amode *am_hi, *am_lo; 2617 2618 if (expr->Iex.Load.end != Iend_BE) 2619 goto irreducible; 2620 2621 addr_hi = expr->Iex.Load.addr; 2622 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8)); 2623 2624 am_hi = s390_isel_amode(env, addr_hi); 2625 am_lo = s390_isel_amode(env, addr_lo); 2626 2627 *dst_hi = newVRegF(env); 2628 *dst_lo = newVRegF(env); 2629 addInstr(env, s390_insn_load(8, *dst_hi, am_hi)); 2630 addInstr(env, s390_insn_load(8, *dst_hi, am_lo)); 2631 return; 2632 } 2633 2634 /* --------- GET --------- */ 2635 case Iex_Get: 2636 /* This is not supported because loading 128-bit from the guest 2637 state is almost certainly wrong. Use get_dpr_pair instead. */ 2638 vpanic("Iex_Get with D128 data"); 2639 2640 /* --------- 4-ary OP --------- */ 2641 case Iex_Qop: 2642 vpanic("Iex_Qop with D128 data"); 2643 2644 /* --------- TERNARY OP --------- */ 2645 case Iex_Triop: { 2646 IRTriop *triop = expr->Iex.Triop.details; 2647 IROp op = triop->op; 2648 IRExpr *irrm = triop->arg1; 2649 IRExpr *left = triop->arg2; 2650 IRExpr *right = triop->arg3; 2651 s390_dfp_round_t rounding_mode; 2652 s390_dfp_binop_t dfpop; 2653 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15; 2654 2655 /* We use non-virtual registers as pairs with (f9, f11) as op1, 2656 (f12, f14) as op2 and (f13, f15) as destination) */ 2657 f9 = make_fpr(9); 2658 f11 = make_fpr(11); 2659 f12 = make_fpr(12); 2660 f13 = make_fpr(13); 2661 f14 = make_fpr(14); 2662 f15 = make_fpr(15); 2663 2664 switch (op) { 2665 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128; 2666 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128; 2667 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128; 2668 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128; 2669 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128; 2670 2671 evaluate_dfp128: { 2672 /* Process 1st operand */ 2673 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); 2674 /* 1st operand --> (f9, f11) */ 2675 addInstr(env, s390_insn_move(8, f9, op1_hi)); 2676 addInstr(env, s390_insn_move(8, f11, op1_lo)); 2677 2678 /* Process 2nd operand */ 2679 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); 2680 /* 2nd operand --> (f12, f14) */ 2681 addInstr(env, s390_insn_move(8, f12, op2_hi)); 2682 addInstr(env, s390_insn_move(8, f14, op2_lo)); 2683 2684 /* DFP arithmetic ops take rounding mode only when fpext is 2685 installed. But, DFP quantize operation takes rm irrespective 2686 of fpext facility . */ 2687 if (s390_host_has_fpext || op == Iop_QuantizeD128) { 2688 rounding_mode = get_dfp_rounding_mode(env, irrm); 2689 } else { 2690 set_dfp_rounding_mode_in_fpc(env, irrm); 2691 rounding_mode = S390_DFP_ROUND_PER_FPC_0; 2692 } 2693 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11, 2694 f12, f14, rounding_mode)); 2695 /* Move result to virtual destination register */ 2696 *dst_hi = newVRegF(env); 2697 *dst_lo = newVRegF(env); 2698 addInstr(env, s390_insn_move(8, *dst_hi, f13)); 2699 addInstr(env, s390_insn_move(8, *dst_lo, f15)); 2700 return; 2701 } 2702 2703 case Iop_SignificanceRoundD128: { 2704 /* Process 1st operand */ 2705 HReg op1 = s390_isel_int_expr(env, left); 2706 /* Process 2nd operand */ 2707 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); 2708 /* 2nd operand --> (f12, f14) */ 2709 addInstr(env, s390_insn_move(8, f12, op2_hi)); 2710 addInstr(env, s390_insn_move(8, f14, op2_lo)); 2711 2712 rounding_mode = get_dfp_rounding_mode(env, irrm); 2713 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14, 2714 rounding_mode)); 2715 /* Move result to virtual destination register */ 2716 *dst_hi = newVRegF(env); 2717 *dst_lo = newVRegF(env); 2718 addInstr(env, s390_insn_move(8, *dst_hi, f13)); 2719 addInstr(env, s390_insn_move(8, *dst_lo, f15)); 2720 return; 2721 } 2722 2723 default: 2724 goto irreducible; 2725 } 2726 } 2727 2728 /* --------- BINARY OP --------- */ 2729 case Iex_Binop: { 2730 2731 switch (expr->Iex.Binop.op) { 2732 case Iop_D64HLtoD128: 2733 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1); 2734 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2); 2735 return; 2736 2737 case Iop_ShlD128: 2738 case Iop_ShrD128: 2739 case Iop_InsertExpD128: { 2740 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15; 2741 s390_dfp_intop_t intop; 2742 IRExpr *dfp_op; 2743 IRExpr *int_op; 2744 2745 switch (expr->Iex.Binop.op) { 2746 case Iop_ShlD128: /* (D128, I64) -> D128 */ 2747 intop = S390_DFP_SHIFT_LEFT; 2748 dfp_op = expr->Iex.Binop.arg1; 2749 int_op = expr->Iex.Binop.arg2; 2750 break; 2751 case Iop_ShrD128: /* (D128, I64) -> D128 */ 2752 intop = S390_DFP_SHIFT_RIGHT; 2753 dfp_op = expr->Iex.Binop.arg1; 2754 int_op = expr->Iex.Binop.arg2; 2755 break; 2756 case Iop_InsertExpD128: /* (I64, D128) -> D128 */ 2757 intop = S390_DFP_INSERT_EXP; 2758 int_op = expr->Iex.Binop.arg1; 2759 dfp_op = expr->Iex.Binop.arg2; 2760 break; 2761 default: goto irreducible; 2762 } 2763 2764 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */ 2765 f9 = make_fpr(9); /* 128 bit dfp operand */ 2766 f11 = make_fpr(11); 2767 2768 f13 = make_fpr(13); /* 128 bit dfp destination */ 2769 f15 = make_fpr(15); 2770 2771 /* Process dfp operand */ 2772 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op); 2773 /* op1 -> (f9,f11) */ 2774 addInstr(env, s390_insn_move(8, f9, op1_hi)); 2775 addInstr(env, s390_insn_move(8, f11, op1_lo)); 2776 2777 op2 = s390_isel_int_expr(env, int_op); /* int operand */ 2778 2779 addInstr(env, 2780 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11)); 2781 2782 /* Move result to virtual destination register */ 2783 *dst_hi = newVRegF(env); 2784 *dst_lo = newVRegF(env); 2785 addInstr(env, s390_insn_move(8, *dst_hi, f13)); 2786 addInstr(env, s390_insn_move(8, *dst_lo, f15)); 2787 return; 2788 } 2789 2790 case Iop_F32toD128: 2791 case Iop_F64toD128: { 2792 IRExpr *irrm; 2793 IRExpr *left; 2794 s390_dfp_round_t rm; 2795 HReg h1; /* virtual reg. to hold source */ 2796 HReg f0, f2, f4, r1; /* real registers used by PFPO */ 2797 s390_fp_conv_t fpconv; 2798 2799 switch (expr->Iex.Binop.op) { 2800 case Iop_F32toD128: /* (D128, I64) -> D128 */ 2801 fpconv = S390_FP_F32_TO_D128; 2802 break; 2803 case Iop_F64toD128: /* (D128, I64) -> D128 */ 2804 fpconv = S390_FP_F64_TO_D128; 2805 break; 2806 default: goto irreducible; 2807 } 2808 2809 f4 = make_fpr(4); /* source */ 2810 f0 = make_fpr(0); /* destination */ 2811 f2 = make_fpr(2); /* destination */ 2812 r1 = make_gpr(1); /* GPR #1 clobbered */ 2813 irrm = expr->Iex.Binop.arg1; 2814 left = expr->Iex.Binop.arg2; 2815 rm = get_dfp_rounding_mode(env, irrm); 2816 h1 = s390_isel_float_expr(env, left); 2817 addInstr(env, s390_insn_move(8, f4, h1)); 2818 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2, 2819 f4, INVALID_HREG, r1, rm)); 2820 /* (f0, f2) --> destination */ 2821 *dst_hi = newVRegF(env); 2822 *dst_lo = newVRegF(env); 2823 addInstr(env, s390_insn_move(8, *dst_hi, f0)); 2824 addInstr(env, s390_insn_move(8, *dst_lo, f2)); 2825 2826 return; 2827 } 2828 2829 case Iop_F128toD128: { 2830 IRExpr *irrm; 2831 IRExpr *left; 2832 s390_dfp_round_t rm; 2833 HReg op_hi, op_lo; 2834 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */ 2835 2836 f4 = make_fpr(4); /* source */ 2837 f6 = make_fpr(6); /* source */ 2838 f0 = make_fpr(0); /* destination */ 2839 f2 = make_fpr(2); /* destination */ 2840 r1 = make_gpr(1); /* GPR #1 clobbered */ 2841 2842 irrm = expr->Iex.Binop.arg1; 2843 left = expr->Iex.Binop.arg2; 2844 rm = get_dfp_rounding_mode(env, irrm); 2845 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 2846 /* operand --> (f4, f6) */ 2847 addInstr(env, s390_insn_move(8, f4, op_hi)); 2848 addInstr(env, s390_insn_move(8, f6, op_lo)); 2849 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2, 2850 f4, f6, r1, rm)); 2851 /* (f0, f2) --> destination */ 2852 *dst_hi = newVRegF(env); 2853 *dst_lo = newVRegF(env); 2854 addInstr(env, s390_insn_move(8, *dst_hi, f0)); 2855 addInstr(env, s390_insn_move(8, *dst_lo, f2)); 2856 2857 return; 2858 } 2859 2860 default: 2861 goto irreducible; 2862 } 2863 } 2864 2865 /* --------- UNARY OP --------- */ 2866 case Iex_Unop: { 2867 IRExpr *left = expr->Iex.Unop.arg; 2868 s390_dfp_conv_t conv; 2869 HReg op, f12, f14; 2870 2871 /* We use non-virtual registers as pairs (f12, f14)) */ 2872 f12 = make_fpr(12); 2873 f14 = make_fpr(14); 2874 2875 switch (expr->Iex.Unop.op) { 2876 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp; 2877 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int; 2878 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int; 2879 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int; 2880 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int; 2881 default: 2882 goto irreducible; 2883 } 2884 2885 convert_dfp: 2886 op = s390_isel_dfp_expr(env, left); 2887 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op)); 2888 goto move_dst; 2889 2890 convert_int: 2891 op = s390_isel_int_expr(env, left); 2892 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op)); 2893 goto move_dst; 2894 2895 move_dst: 2896 /* Move result to virtual destination registers */ 2897 *dst_hi = newVRegF(env); 2898 *dst_lo = newVRegF(env); 2899 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 2900 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 2901 return; 2902 } 2903 2904 default: 2905 goto irreducible; 2906 } 2907 2908 /* We get here if no pattern matched. */ 2909 irreducible: 2910 ppIRExpr(expr); 2911 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree"); 2912 2913 } 2914 2915 2916 /* Compute a 128-bit value into two 64-bit registers. These may be either 2917 real or virtual regs; in any case they must not be changed by subsequent 2918 code emitted by the caller. */ 2919 static void 2920 s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr) 2921 { 2922 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr); 2923 2924 /* Sanity checks ... */ 2925 vassert(hregIsVirtual(*dst_hi)); 2926 vassert(hregIsVirtual(*dst_lo)); 2927 vassert(hregClass(*dst_hi) == HRcFlt64); 2928 vassert(hregClass(*dst_lo) == HRcFlt64); 2929 } 2930 2931 2932 /*---------------------------------------------------------*/ 2933 /*--- ISEL: Decimal point expressions (64 bit) ---*/ 2934 /*---------------------------------------------------------*/ 2935 2936 static HReg 2937 s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) 2938 { 2939 IRType ty = typeOfIRExpr(env->type_env, expr); 2940 UChar size; 2941 2942 vassert(ty == Ity_D64 || ty == Ity_D32); 2943 2944 size = sizeofIRType(ty); 2945 2946 switch (expr->tag) { 2947 case Iex_RdTmp: 2948 /* Return the virtual register that holds the temporary. */ 2949 return lookupIRTemp(env, expr->Iex.RdTmp.tmp); 2950 2951 /* --------- LOAD --------- */ 2952 case Iex_Load: { 2953 HReg dst = newVRegF(env); 2954 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr); 2955 2956 if (expr->Iex.Load.end != Iend_BE) 2957 goto irreducible; 2958 2959 addInstr(env, s390_insn_load(size, dst, am)); 2960 2961 return dst; 2962 } 2963 2964 /* --------- GET --------- */ 2965 case Iex_Get: { 2966 HReg dst = newVRegF(env); 2967 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset); 2968 2969 addInstr(env, s390_insn_load(size, dst, am)); 2970 2971 return dst; 2972 } 2973 2974 /* --------- BINARY OP --------- */ 2975 case Iex_Binop: { 2976 IROp op = expr->Iex.Binop.op; 2977 IRExpr *irrm = expr->Iex.Binop.arg1; 2978 IRExpr *left = expr->Iex.Binop.arg2; 2979 HReg h1, dst; 2980 s390_dfp_conv_t conv; 2981 s390_fp_conv_t fpconv; 2982 2983 switch (op) { 2984 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp; 2985 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int; 2986 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int; 2987 case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp; 2988 case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp; 2989 case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp; 2990 case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp; 2991 case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128; 2992 case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128; 2993 2994 convert_dfp: 2995 h1 = s390_isel_dfp_expr(env, left); 2996 goto convert; 2997 2998 convert_int: 2999 h1 = s390_isel_int_expr(env, left); 3000 goto convert; 3001 3002 convert: { 3003 s390_dfp_round_t rounding_mode; 3004 /* convert-from-fixed and load-rounded have a rounding mode field 3005 when the floating point extension facility is installed. */ 3006 dst = newVRegF(env); 3007 if (s390_host_has_fpext) { 3008 rounding_mode = get_dfp_rounding_mode(env, irrm); 3009 } else { 3010 set_dfp_rounding_mode_in_fpc(env, irrm); 3011 rounding_mode = S390_DFP_ROUND_PER_FPC_0; 3012 } 3013 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1, 3014 rounding_mode)); 3015 return dst; 3016 } 3017 3018 convert_bfp: { 3019 s390_dfp_round_t rm; 3020 HReg f0, f4, r1; /* real registers used by PFPO */ 3021 3022 f4 = make_fpr(4); /* source */ 3023 f0 = make_fpr(0); /* destination */ 3024 r1 = make_gpr(1); /* GPR #1 clobbered */ 3025 h1 = s390_isel_float_expr(env, left); 3026 dst = newVRegF(env); 3027 rm = get_dfp_rounding_mode(env, irrm); 3028 /* operand --> f4 */ 3029 addInstr(env, s390_insn_move(8, f4, h1)); 3030 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm)); 3031 /* f0 --> destination */ 3032 addInstr(env, s390_insn_move(8, dst, f0)); 3033 return dst; 3034 } 3035 3036 convert_bfp128: { 3037 s390_dfp_round_t rm; 3038 HReg op_hi, op_lo; 3039 HReg f0, f4, f6, r1; /* real registers used by PFPO */ 3040 3041 f4 = make_fpr(4); /* source */ 3042 f6 = make_fpr(6); /* source */ 3043 f0 = make_fpr(0); /* destination */ 3044 r1 = make_gpr(1); /* GPR #1 clobbered */ 3045 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 3046 dst = newVRegF(env); 3047 rm = get_dfp_rounding_mode(env, irrm); 3048 /* operand --> (f4, f6) */ 3049 addInstr(env, s390_insn_move(8, f4, op_hi)); 3050 addInstr(env, s390_insn_move(8, f6, op_lo)); 3051 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG, 3052 f4, f6, r1, rm)); 3053 /* f0 --> destination */ 3054 addInstr(env, s390_insn_move(8, dst, f0)); 3055 return dst; 3056 } 3057 3058 case Iop_D128toD64: { 3059 HReg op_hi, op_lo, f12, f13, f14, f15; 3060 s390_dfp_round_t rounding_mode; 3061 3062 conv = S390_DFP_D128_TO_D64; 3063 3064 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left); 3065 3066 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */ 3067 f12 = make_fpr(12); 3068 f13 = make_fpr(13); 3069 f14 = make_fpr(14); 3070 f15 = make_fpr(15); 3071 3072 /* operand --> (f13, f15) */ 3073 addInstr(env, s390_insn_move(8, f13, op_hi)); 3074 addInstr(env, s390_insn_move(8, f15, op_lo)); 3075 3076 /* result --> (f12, f14) */ 3077 3078 /* load-rounded has a rounding mode field when the floating point 3079 extension facility is installed. */ 3080 if (s390_host_has_fpext) { 3081 rounding_mode = get_dfp_rounding_mode(env, irrm); 3082 } else { 3083 set_dfp_rounding_mode_in_fpc(env, irrm); 3084 rounding_mode = S390_DFP_ROUND_PER_FPC_0; 3085 } 3086 addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14, 3087 f13, f15, rounding_mode)); 3088 dst = newVRegF(env); 3089 addInstr(env, s390_insn_move(8, dst, f12)); 3090 3091 return dst; 3092 } 3093 3094 case Iop_ShlD64: 3095 case Iop_ShrD64: 3096 case Iop_InsertExpD64: { 3097 HReg op2; 3098 HReg op3; 3099 IRExpr *dfp_op; 3100 IRExpr *int_op; 3101 s390_dfp_intop_t intop; 3102 3103 switch (expr->Iex.Binop.op) { 3104 case Iop_ShlD64: /* (D64, I64) -> D64 */ 3105 intop = S390_DFP_SHIFT_LEFT; 3106 dfp_op = expr->Iex.Binop.arg1; 3107 int_op = expr->Iex.Binop.arg2; 3108 break; 3109 case Iop_ShrD64: /* (D64, I64) -> D64 */ 3110 intop = S390_DFP_SHIFT_RIGHT; 3111 dfp_op = expr->Iex.Binop.arg1; 3112 int_op = expr->Iex.Binop.arg2; 3113 break; 3114 case Iop_InsertExpD64: /* (I64, D64) -> D64 */ 3115 intop = S390_DFP_INSERT_EXP; 3116 int_op = expr->Iex.Binop.arg1; 3117 dfp_op = expr->Iex.Binop.arg2; 3118 break; 3119 default: goto irreducible; 3120 } 3121 3122 op2 = s390_isel_int_expr(env, int_op); 3123 op3 = s390_isel_dfp_expr(env, dfp_op); 3124 dst = newVRegF(env); 3125 3126 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3)); 3127 return dst; 3128 } 3129 3130 default: 3131 goto irreducible; 3132 } 3133 } 3134 3135 /* --------- UNARY OP --------- */ 3136 case Iex_Unop: { 3137 IROp op = expr->Iex.Unop.op; 3138 IRExpr *left = expr->Iex.Unop.arg; 3139 s390_dfp_conv_t conv; 3140 HReg h1, dst; 3141 3142 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) { 3143 HReg dst_hi, dst_lo; 3144 3145 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left); 3146 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi; 3147 } 3148 3149 if (op == Iop_ReinterpI64asD64) { 3150 dst = newVRegF(env); 3151 h1 = s390_isel_int_expr(env, left); /* Process the operand */ 3152 addInstr(env, s390_insn_move(size, dst, h1)); 3153 3154 return dst; 3155 } 3156 3157 switch (op) { 3158 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1; 3159 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1; 3160 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1; 3161 3162 convert_dfp1: 3163 h1 = s390_isel_dfp_expr(env, left); 3164 goto convert1; 3165 3166 convert_int1: 3167 h1 = s390_isel_int_expr(env, left); 3168 goto convert1; 3169 3170 convert1: 3171 dst = newVRegF(env); 3172 /* No rounding mode is needed for these conversions. Just stick 3173 one in. It won't be used later on. */ 3174 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1, 3175 S390_DFP_ROUND_NEAREST_EVEN_4)); 3176 return dst; 3177 3178 default: 3179 goto irreducible; 3180 } 3181 } 3182 3183 /* --------- TERNARY OP --------- */ 3184 case Iex_Triop: { 3185 IRTriop *triop = expr->Iex.Triop.details; 3186 IROp op = triop->op; 3187 IRExpr *irrm = triop->arg1; 3188 IRExpr *left = triop->arg2; 3189 IRExpr *right = triop->arg3; 3190 s390_dfp_round_t rounding_mode; 3191 s390_dfp_binop_t dfpop; 3192 HReg op2, op3, dst; 3193 3194 switch (op) { 3195 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp; 3196 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp; 3197 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp; 3198 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp; 3199 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp; 3200 3201 evaluate_dfp: { 3202 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */ 3203 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */ 3204 dst = newVRegF(env); 3205 /* DFP arithmetic ops take rounding mode only when fpext is 3206 installed. But, DFP quantize operation takes rm irrespective 3207 of fpext facility . */ 3208 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) { 3209 rounding_mode = get_dfp_rounding_mode(env, irrm); 3210 } else { 3211 set_dfp_rounding_mode_in_fpc(env, irrm); 3212 rounding_mode = S390_DFP_ROUND_PER_FPC_0; 3213 } 3214 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3, 3215 rounding_mode)); 3216 return dst; 3217 } 3218 3219 case Iop_SignificanceRoundD64: 3220 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */ 3221 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */ 3222 dst = newVRegF(env); 3223 rounding_mode = get_dfp_rounding_mode(env, irrm); 3224 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3, 3225 rounding_mode)); 3226 return dst; 3227 3228 default: 3229 goto irreducible; 3230 } 3231 } 3232 3233 default: 3234 goto irreducible; 3235 } 3236 3237 /* We get here if no pattern matched. */ 3238 irreducible: 3239 ppIRExpr(expr); 3240 vpanic("s390_isel_dfp_expr: cannot reduce tree"); 3241 } 3242 3243 static HReg 3244 s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr) 3245 { 3246 HReg dst = s390_isel_dfp_expr_wrk(env, expr); 3247 3248 /* Sanity checks ... */ 3249 vassert(hregClass(dst) == HRcFlt64); 3250 vassert(hregIsVirtual(dst)); 3251 3252 return dst; 3253 } 3254 3255 3256 /*---------------------------------------------------------*/ 3257 /*--- ISEL: Condition Code ---*/ 3258 /*---------------------------------------------------------*/ 3259 3260 /* This function handles all operators that produce a 1-bit result */ 3261 static s390_cc_t 3262 s390_isel_cc(ISelEnv *env, IRExpr *cond) 3263 { 3264 UChar size; 3265 3266 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1); 3267 3268 /* Constant: either 1 or 0 */ 3269 if (cond->tag == Iex_Const) { 3270 vassert(cond->Iex.Const.con->tag == Ico_U1); 3271 vassert(cond->Iex.Const.con->Ico.U1 == True 3272 || cond->Iex.Const.con->Ico.U1 == False); 3273 3274 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER; 3275 } 3276 3277 /* Variable: values are 1 or 0 */ 3278 if (cond->tag == Iex_RdTmp) { 3279 IRTemp tmp = cond->Iex.RdTmp.tmp; 3280 HReg reg = lookupIRTemp(env, tmp); 3281 3282 /* Load-and-test does not modify REG; so this is OK. */ 3283 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1) 3284 size = 4; 3285 else 3286 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp)); 3287 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg))); 3288 return S390_CC_NE; 3289 } 3290 3291 /* Unary operators */ 3292 if (cond->tag == Iex_Unop) { 3293 IRExpr *arg = cond->Iex.Unop.arg; 3294 3295 switch (cond->Iex.Unop.op) { 3296 case Iop_Not1: /* Not1(cond) */ 3297 /* Generate code for EXPR, and negate the test condition */ 3298 return s390_cc_invert(s390_isel_cc(env, arg)); 3299 3300 /* Iop_32/64to1 select the LSB from their operand */ 3301 case Iop_32to1: 3302 case Iop_64to1: { 3303 HReg dst = newVRegI(env); 3304 HReg h1 = s390_isel_int_expr(env, arg); 3305 3306 size = sizeofIRType(typeOfIRExpr(env->type_env, arg)); 3307 3308 addInstr(env, s390_insn_move(size, dst, h1)); 3309 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1))); 3310 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst))); 3311 return S390_CC_NE; 3312 } 3313 3314 case Iop_CmpNEZ8: 3315 case Iop_CmpNEZ16: { 3316 s390_opnd_RMI src; 3317 s390_unop_t op; 3318 HReg dst; 3319 3320 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8 3321 : S390_ZERO_EXTEND_16; 3322 dst = newVRegI(env); 3323 src = s390_isel_int_expr_RMI(env, arg); 3324 addInstr(env, s390_insn_unop(4, op, dst, src)); 3325 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst))); 3326 return S390_CC_NE; 3327 } 3328 3329 case Iop_CmpNEZ32: 3330 case Iop_CmpNEZ64: { 3331 s390_opnd_RMI src; 3332 3333 src = s390_isel_int_expr_RMI(env, arg); 3334 size = sizeofIRType(typeOfIRExpr(env->type_env, arg)); 3335 addInstr(env, s390_insn_test(size, src)); 3336 return S390_CC_NE; 3337 } 3338 3339 default: 3340 goto fail; 3341 } 3342 } 3343 3344 /* Binary operators */ 3345 if (cond->tag == Iex_Binop) { 3346 IRExpr *arg1 = cond->Iex.Binop.arg1; 3347 IRExpr *arg2 = cond->Iex.Binop.arg2; 3348 HReg reg1, reg2; 3349 3350 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1)); 3351 3352 switch (cond->Iex.Binop.op) { 3353 s390_unop_t op; 3354 s390_cc_t result; 3355 3356 case Iop_CmpEQ8: 3357 case Iop_CasCmpEQ8: 3358 op = S390_ZERO_EXTEND_8; 3359 result = S390_CC_E; 3360 goto do_compare_ze; 3361 3362 case Iop_CmpNE8: 3363 case Iop_CasCmpNE8: 3364 op = S390_ZERO_EXTEND_8; 3365 result = S390_CC_NE; 3366 goto do_compare_ze; 3367 3368 case Iop_CmpEQ16: 3369 case Iop_CasCmpEQ16: 3370 op = S390_ZERO_EXTEND_16; 3371 result = S390_CC_E; 3372 goto do_compare_ze; 3373 3374 case Iop_CmpNE16: 3375 case Iop_CasCmpNE16: 3376 op = S390_ZERO_EXTEND_16; 3377 result = S390_CC_NE; 3378 goto do_compare_ze; 3379 3380 do_compare_ze: { 3381 s390_opnd_RMI op1, op2; 3382 3383 op1 = s390_isel_int_expr_RMI(env, arg1); 3384 reg1 = newVRegI(env); 3385 addInstr(env, s390_insn_unop(4, op, reg1, op1)); 3386 3387 op2 = s390_isel_int_expr_RMI(env, arg2); 3388 reg2 = newVRegI(env); 3389 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */ 3390 3391 op2 = s390_opnd_reg(reg2); 3392 addInstr(env, s390_insn_compare(4, reg1, op2, False)); 3393 3394 return result; 3395 } 3396 3397 case Iop_CmpEQ32: 3398 case Iop_CmpEQ64: 3399 case Iop_CasCmpEQ32: 3400 case Iop_CasCmpEQ64: 3401 result = S390_CC_E; 3402 goto do_compare; 3403 3404 case Iop_CmpNE32: 3405 case Iop_CmpNE64: 3406 case Iop_CasCmpNE32: 3407 case Iop_CasCmpNE64: 3408 result = S390_CC_NE; 3409 goto do_compare; 3410 3411 do_compare: { 3412 HReg op1; 3413 s390_opnd_RMI op2; 3414 3415 order_commutative_operands(arg1, arg2); 3416 3417 op1 = s390_isel_int_expr(env, arg1); 3418 op2 = s390_isel_int_expr_RMI(env, arg2); 3419 3420 addInstr(env, s390_insn_compare(size, op1, op2, False)); 3421 3422 return result; 3423 } 3424 3425 case Iop_CmpLT32S: 3426 case Iop_CmpLE32S: 3427 case Iop_CmpLT64S: 3428 case Iop_CmpLE64S: { 3429 HReg op1; 3430 s390_opnd_RMI op2; 3431 3432 op1 = s390_isel_int_expr(env, arg1); 3433 op2 = s390_isel_int_expr_RMI(env, arg2); 3434 3435 addInstr(env, s390_insn_compare(size, op1, op2, True)); 3436 3437 return (cond->Iex.Binop.op == Iop_CmpLT32S || 3438 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE; 3439 } 3440 3441 case Iop_CmpLT32U: 3442 case Iop_CmpLE32U: 3443 case Iop_CmpLT64U: 3444 case Iop_CmpLE64U: { 3445 HReg op1; 3446 s390_opnd_RMI op2; 3447 3448 op1 = s390_isel_int_expr(env, arg1); 3449 op2 = s390_isel_int_expr_RMI(env, arg2); 3450 3451 addInstr(env, s390_insn_compare(size, op1, op2, False)); 3452 3453 return (cond->Iex.Binop.op == Iop_CmpLT32U || 3454 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE; 3455 } 3456 3457 default: 3458 goto fail; 3459 } 3460 } 3461 3462 fail: 3463 ppIRExpr(cond); 3464 vpanic("s390_isel_cc: unexpected operator"); 3465 } 3466 3467 3468 /*---------------------------------------------------------*/ 3469 /*--- ISEL: Statements ---*/ 3470 /*---------------------------------------------------------*/ 3471 3472 static void 3473 s390_isel_stmt(ISelEnv *env, IRStmt *stmt) 3474 { 3475 if (vex_traceflags & VEX_TRACE_VCODE) { 3476 vex_printf("\n -- "); 3477 ppIRStmt(stmt); 3478 vex_printf("\n"); 3479 } 3480 3481 switch (stmt->tag) { 3482 3483 /* --------- STORE --------- */ 3484 case Ist_Store: { 3485 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data); 3486 s390_amode *am; 3487 HReg src; 3488 3489 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail; 3490 3491 am = s390_isel_amode(env, stmt->Ist.Store.addr); 3492 3493 switch (tyd) { 3494 case Ity_I8: 3495 case Ity_I16: 3496 case Ity_I32: 3497 case Ity_I64: 3498 /* fixs390: We could check for INSN_MADD here. */ 3499 if (am->tag == S390_AMODE_B12 && 3500 stmt->Ist.Store.data->tag == Iex_Const) { 3501 ULong value = 3502 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con); 3503 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value)); 3504 return; 3505 } 3506 /* Check whether we can use a memcpy here. Currently, the restriction 3507 is that both amodes need to be B12, so MVC can be emitted. 3508 We do not consider a store whose data expression is a load because 3509 we don't want to deal with overlapping locations. */ 3510 /* store(get) never overlaps*/ 3511 if (am->tag == S390_AMODE_B12 && 3512 stmt->Ist.Store.data->tag == Iex_Get) { 3513 UInt offset = stmt->Ist.Store.data->Iex.Get.offset; 3514 s390_amode *from = s390_amode_for_guest_state(offset); 3515 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from)); 3516 return; 3517 } 3518 /* General case: compile data into a register */ 3519 src = s390_isel_int_expr(env, stmt->Ist.Store.data); 3520 break; 3521 3522 case Ity_F32: 3523 case Ity_F64: 3524 src = s390_isel_float_expr(env, stmt->Ist.Store.data); 3525 break; 3526 3527 case Ity_D32: 3528 case Ity_D64: 3529 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data); 3530 break; 3531 3532 case Ity_F128: 3533 case Ity_D128: 3534 /* Cannot occur. No such instruction */ 3535 vpanic("Ist_Store with 128-bit floating point data"); 3536 3537 default: 3538 goto stmt_fail; 3539 } 3540 3541 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src)); 3542 return; 3543 } 3544 3545 /* --------- PUT --------- */ 3546 case Ist_Put: { 3547 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); 3548 HReg src; 3549 s390_amode *am; 3550 ULong new_value, old_value, difference; 3551 3552 /* Detect updates to certain guest registers. We track the contents 3553 of those registers as long as they contain constants. If the new 3554 constant is either zero or in the 8-bit neighbourhood of the 3555 current value we can use a memory-to-memory insn to do the update. */ 3556 3557 Int offset = stmt->Ist.Put.offset; 3558 3559 /* Check necessary conditions: 3560 (1) must be one of the registers we care about 3561 (2) assigned value must be a constant */ 3562 Int guest_reg = get_guest_reg(offset); 3563 3564 if (guest_reg == GUEST_UNKNOWN) goto not_special; 3565 3566 if (stmt->Ist.Put.data->tag != Iex_Const) { 3567 /* Invalidate guest register contents */ 3568 env->old_value_valid[guest_reg] = False; 3569 goto not_special; 3570 } 3571 3572 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */ 3573 if (tyd != Ity_I64) 3574 goto not_special; 3575 3576 /* OK. Necessary conditions are satisfied. */ 3577 3578 old_value = env->old_value[guest_reg]; 3579 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64; 3580 env->old_value[guest_reg] = new_value; 3581 3582 Bool old_value_is_valid = env->old_value_valid[guest_reg]; 3583 env->old_value_valid[guest_reg] = True; 3584 3585 /* If the register already contains the new value, there is nothing 3586 to do here. */ 3587 if (old_value_is_valid && new_value == old_value) { 3588 return; 3589 } 3590 3591 if (old_value_is_valid == False) goto not_special; 3592 3593 /* If the new value is in the neighbourhood of the old value 3594 we can use a memory-to-memory insn */ 3595 difference = new_value - old_value; 3596 3597 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) { 3598 am = s390_amode_for_guest_state(offset); 3599 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am, 3600 (difference & 0xFF), new_value)); 3601 return; 3602 } 3603 3604 /* If the high word is the same it is sufficient to load the low word. */ 3605 if ((old_value >> 32) == (new_value >> 32)) { 3606 am = s390_amode_for_guest_state(offset + 4); 3607 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF)); 3608 return; 3609 } 3610 3611 /* No special case applies... fall through */ 3612 3613 not_special: 3614 am = s390_amode_for_guest_state(offset); 3615 3616 switch (tyd) { 3617 case Ity_I8: 3618 case Ity_I16: 3619 case Ity_I32: 3620 case Ity_I64: 3621 if (am->tag == S390_AMODE_B12 && 3622 stmt->Ist.Put.data->tag == Iex_Const) { 3623 ULong value = 3624 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con); 3625 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value)); 3626 return; 3627 } 3628 /* Check whether we can use a memcpy here. Currently, the restriction 3629 is that both amodes need to be B12, so MVC can be emitted. */ 3630 /* put(load) never overlaps */ 3631 if (am->tag == S390_AMODE_B12 && 3632 stmt->Ist.Put.data->tag == Iex_Load) { 3633 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail; 3634 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr; 3635 s390_amode *from = s390_isel_amode(env, data); 3636 UInt size = sizeofIRType(tyd); 3637 3638 if (from->tag == S390_AMODE_B12) { 3639 /* Source can be compiled into a B12 amode. */ 3640 addInstr(env, s390_insn_memcpy(size, am, from)); 3641 return; 3642 } 3643 3644 src = newVRegI(env); 3645 addInstr(env, s390_insn_load(size, src, from)); 3646 break; 3647 } 3648 /* put(get) */ 3649 if (am->tag == S390_AMODE_B12 && 3650 stmt->Ist.Put.data->tag == Iex_Get) { 3651 UInt put_offset = am->d; 3652 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset; 3653 UInt size = sizeofIRType(tyd); 3654 /* don't memcpy in case of overlap */ 3655 if (put_offset + size <= get_offset || 3656 get_offset + size <= put_offset) { 3657 s390_amode *from = s390_amode_for_guest_state(get_offset); 3658 addInstr(env, s390_insn_memcpy(size, am, from)); 3659 return; 3660 } 3661 goto no_memcpy_put; 3662 } 3663 /* General case: compile data into a register */ 3664 no_memcpy_put: 3665 src = s390_isel_int_expr(env, stmt->Ist.Put.data); 3666 break; 3667 3668 case Ity_F32: 3669 case Ity_F64: 3670 src = s390_isel_float_expr(env, stmt->Ist.Put.data); 3671 break; 3672 3673 case Ity_F128: 3674 case Ity_D128: 3675 /* Does not occur. See function put_(f|d)pr_pair. */ 3676 vpanic("Ist_Put with 128-bit floating point data"); 3677 3678 case Ity_D32: 3679 case Ity_D64: 3680 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data); 3681 break; 3682 3683 default: 3684 goto stmt_fail; 3685 } 3686 3687 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src)); 3688 return; 3689 } 3690 3691 /* --------- TMP --------- */ 3692 case Ist_WrTmp: { 3693 IRTemp tmp = stmt->Ist.WrTmp.tmp; 3694 IRType tyd = typeOfIRTemp(env->type_env, tmp); 3695 HReg src, dst; 3696 3697 switch (tyd) { 3698 case Ity_I128: { 3699 HReg dst_hi, dst_lo, res_hi, res_lo; 3700 3701 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data); 3702 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp); 3703 3704 addInstr(env, s390_insn_move(8, dst_hi, res_hi)); 3705 addInstr(env, s390_insn_move(8, dst_lo, res_lo)); 3706 return; 3707 } 3708 3709 case Ity_I8: 3710 case Ity_I16: 3711 case Ity_I32: 3712 case Ity_I64: 3713 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data); 3714 dst = lookupIRTemp(env, tmp); 3715 break; 3716 3717 case Ity_I1: { 3718 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data); 3719 dst = lookupIRTemp(env, tmp); 3720 addInstr(env, s390_insn_cc2bool(dst, cond)); 3721 return; 3722 } 3723 3724 case Ity_F32: 3725 case Ity_F64: 3726 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data); 3727 dst = lookupIRTemp(env, tmp); 3728 break; 3729 3730 case Ity_F128: { 3731 HReg dst_hi, dst_lo, res_hi, res_lo; 3732 3733 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data); 3734 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp); 3735 3736 addInstr(env, s390_insn_move(8, dst_hi, res_hi)); 3737 addInstr(env, s390_insn_move(8, dst_lo, res_lo)); 3738 return; 3739 } 3740 3741 case Ity_D32: 3742 case Ity_D64: 3743 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data); 3744 dst = lookupIRTemp(env, tmp); 3745 break; 3746 3747 case Ity_D128: { 3748 HReg dst_hi, dst_lo, res_hi, res_lo; 3749 3750 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data); 3751 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp); 3752 3753 addInstr(env, s390_insn_move(8, dst_hi, res_hi)); 3754 addInstr(env, s390_insn_move(8, dst_lo, res_lo)); 3755 return; 3756 } 3757 3758 default: 3759 goto stmt_fail; 3760 } 3761 3762 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src)); 3763 return; 3764 } 3765 3766 /* --------- Call to DIRTY helper --------- */ 3767 case Ist_Dirty: { 3768 IRType retty; 3769 IRDirty* d = stmt->Ist.Dirty.details; 3770 HReg dst; 3771 RetLoc rloc = mk_RetLoc_INVALID(); 3772 UInt addToSp = 0; 3773 Int i; 3774 3775 /* Invalidate tracked values of those guest state registers that are 3776 modified by this helper. */ 3777 for (i = 0; i < d->nFxState; ++i) { 3778 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat' 3779 descriptors in guest state effect descriptions. Hence: */ 3780 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0); 3781 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) { 3782 Int guest_reg = get_guest_reg(d->fxState[i].offset); 3783 if (guest_reg != GUEST_UNKNOWN) 3784 env->old_value_valid[guest_reg] = False; 3785 } 3786 } 3787 3788 if (d->tmp == IRTemp_INVALID) { 3789 /* No return value. */ 3790 retty = Ity_INVALID; 3791 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty, 3792 d->args); 3793 vassert(is_sane_RetLoc(rloc)); 3794 vassert(rloc.pri == RLPri_None); 3795 vassert(addToSp == 0); 3796 3797 return; 3798 } 3799 3800 retty = typeOfIRTemp(env->type_env, d->tmp); 3801 if (retty == Ity_I64 || retty == Ity_I32 3802 || retty == Ity_I16 || retty == Ity_I8) { 3803 /* Move the returned value to the destination register */ 3804 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE); 3805 3806 dst = lookupIRTemp(env, d->tmp); 3807 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty, 3808 d->args); 3809 vassert(is_sane_RetLoc(rloc)); 3810 vassert(rloc.pri == RLPri_Int); 3811 vassert(addToSp == 0); 3812 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret)); 3813 3814 return; 3815 } 3816 break; 3817 } 3818 3819 case Ist_CAS: 3820 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) { 3821 IRCAS *cas = stmt->Ist.CAS.details; 3822 s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr); 3823 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */ 3824 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */ 3825 HReg old = lookupIRTemp(env, cas->oldLo); 3826 3827 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) { 3828 addInstr(env, s390_insn_cas(4, op1, op2, op3, old)); 3829 } else { 3830 addInstr(env, s390_insn_cas(8, op1, op2, op3, old)); 3831 } 3832 return; 3833 } else { 3834 IRCAS *cas = stmt->Ist.CAS.details; 3835 s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr); 3836 HReg r8, r9, r10, r11, r1; 3837 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */ 3838 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */ 3839 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */ 3840 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */ 3841 HReg old_low = lookupIRTemp(env, cas->oldLo); 3842 HReg old_high = lookupIRTemp(env, cas->oldHi); 3843 3844 /* Use non-virtual registers r8 and r9 as pair for op1 3845 and move op1 there */ 3846 r8 = make_gpr(8); 3847 r9 = make_gpr(9); 3848 addInstr(env, s390_insn_move(8, r8, op1_high)); 3849 addInstr(env, s390_insn_move(8, r9, op1_low)); 3850 3851 /* Use non-virtual registers r10 and r11 as pair for op3 3852 and move op3 there */ 3853 r10 = make_gpr(10); 3854 r11 = make_gpr(11); 3855 addInstr(env, s390_insn_move(8, r10, op3_high)); 3856 addInstr(env, s390_insn_move(8, r11, op3_low)); 3857 3858 /* Register r1 is used as a scratch register */ 3859 r1 = make_gpr(1); 3860 3861 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) { 3862 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11, 3863 old_high, old_low, r1)); 3864 } else { 3865 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11, 3866 old_high, old_low, r1)); 3867 } 3868 addInstr(env, s390_insn_move(8, op1_high, r8)); 3869 addInstr(env, s390_insn_move(8, op1_low, r9)); 3870 addInstr(env, s390_insn_move(8, op3_high, r10)); 3871 addInstr(env, s390_insn_move(8, op3_low, r11)); 3872 return; 3873 } 3874 break; 3875 3876 /* --------- EXIT --------- */ 3877 case Ist_Exit: { 3878 s390_cc_t cond; 3879 IRConstTag tag = stmt->Ist.Exit.dst->tag; 3880 3881 if (tag != Ico_U64) 3882 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value"); 3883 3884 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP); 3885 cond = s390_isel_cc(env, stmt->Ist.Exit.guard); 3886 3887 /* Case: boring transfer to known address */ 3888 if (stmt->Ist.Exit.jk == Ijk_Boring) { 3889 if (env->chaining_allowed) { 3890 /* .. almost always true .. */ 3891 /* Skip the event check at the dst if this is a forwards 3892 edge. */ 3893 Bool to_fast_entry 3894 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga; 3895 if (0) vex_printf("%s", to_fast_entry ? "Y" : ","); 3896 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64, 3897 guest_IA, to_fast_entry)); 3898 } else { 3899 /* .. very occasionally .. */ 3900 /* We can't use chaining, so ask for an assisted transfer, 3901 as that's the only alternative that is allowable. */ 3902 HReg dst = s390_isel_int_expr(env, 3903 IRExpr_Const(stmt->Ist.Exit.dst)); 3904 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring)); 3905 } 3906 return; 3907 } 3908 3909 /* Case: assisted transfer to arbitrary address */ 3910 switch (stmt->Ist.Exit.jk) { 3911 case Ijk_EmFail: 3912 case Ijk_EmWarn: 3913 case Ijk_NoDecode: 3914 case Ijk_InvalICache: 3915 case Ijk_Sys_syscall: 3916 case Ijk_ClientReq: 3917 case Ijk_NoRedir: 3918 case Ijk_Yield: 3919 case Ijk_SigTRAP: { 3920 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst)); 3921 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, 3922 stmt->Ist.Exit.jk)); 3923 return; 3924 } 3925 default: 3926 break; 3927 } 3928 3929 /* Do we ever expect to see any other kind? */ 3930 goto stmt_fail; 3931 } 3932 3933 /* --------- MEM FENCE --------- */ 3934 case Ist_MBE: 3935 switch (stmt->Ist.MBE.event) { 3936 case Imbe_Fence: 3937 addInstr(env, s390_insn_mfence()); 3938 return; 3939 default: 3940 break; 3941 } 3942 break; 3943 3944 /* --------- Miscellaneous --------- */ 3945 3946 case Ist_PutI: /* Not needed */ 3947 case Ist_IMark: /* Doesn't generate any executable code */ 3948 case Ist_NoOp: /* Doesn't generate any executable code */ 3949 case Ist_AbiHint: /* Meaningless in IR */ 3950 return; 3951 3952 default: 3953 break; 3954 } 3955 3956 stmt_fail: 3957 ppIRStmt(stmt); 3958 vpanic("s390_isel_stmt"); 3959 } 3960 3961 3962 /*---------------------------------------------------------*/ 3963 /*--- ISEL: Basic block terminators (Nexts) ---*/ 3964 /*---------------------------------------------------------*/ 3965 3966 static void 3967 iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP) 3968 { 3969 if (vex_traceflags & VEX_TRACE_VCODE) { 3970 vex_printf("\n-- PUT(%d) = ", offsIP); 3971 ppIRExpr(next); 3972 vex_printf("; exit-"); 3973 ppIRJumpKind(jk); 3974 vex_printf("\n"); 3975 } 3976 3977 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP); 3978 3979 /* Case: boring transfer to known address */ 3980 if (next->tag == Iex_Const) { 3981 IRConst *cdst = next->Iex.Const.con; 3982 vassert(cdst->tag == Ico_U64); 3983 if (jk == Ijk_Boring || jk == Ijk_Call) { 3984 /* Boring transfer to known address */ 3985 if (env->chaining_allowed) { 3986 /* .. almost always true .. */ 3987 /* Skip the event check at the dst if this is a forwards 3988 edge. */ 3989 Bool to_fast_entry 3990 = ((Addr64)cdst->Ico.U64) > env->max_ga; 3991 if (0) vex_printf("%s", to_fast_entry ? "X" : "."); 3992 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64, 3993 guest_IA, to_fast_entry)); 3994 } else { 3995 /* .. very occasionally .. */ 3996 /* We can't use chaining, so ask for an indirect transfer, 3997 as that's the cheapest alternative that is allowable. */ 3998 HReg dst = s390_isel_int_expr(env, next); 3999 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, 4000 Ijk_Boring)); 4001 } 4002 return; 4003 } 4004 } 4005 4006 /* Case: call/return (==boring) transfer to any address */ 4007 switch (jk) { 4008 case Ijk_Boring: 4009 case Ijk_Ret: 4010 case Ijk_Call: { 4011 HReg dst = s390_isel_int_expr(env, next); 4012 if (env->chaining_allowed) { 4013 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA)); 4014 } else { 4015 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, 4016 Ijk_Boring)); 4017 } 4018 return; 4019 } 4020 default: 4021 break; 4022 } 4023 4024 /* Case: some other kind of transfer to any address */ 4025 switch (jk) { 4026 case Ijk_EmFail: 4027 case Ijk_EmWarn: 4028 case Ijk_NoDecode: 4029 case Ijk_InvalICache: 4030 case Ijk_Sys_syscall: 4031 case Ijk_ClientReq: 4032 case Ijk_NoRedir: 4033 case Ijk_Yield: 4034 case Ijk_SigTRAP: { 4035 HReg dst = s390_isel_int_expr(env, next); 4036 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk)); 4037 return; 4038 } 4039 default: 4040 break; 4041 } 4042 4043 vpanic("iselNext"); 4044 } 4045 4046 4047 /*---------------------------------------------------------*/ 4048 /*--- Insn selector top-level ---*/ 4049 /*---------------------------------------------------------*/ 4050 4051 /* Translate an entire SB to s390 code. 4052 Note: archinfo_host is a pointer to a stack-allocated variable. 4053 Do not assign it to a global variable! */ 4054 4055 HInstrArray * 4056 iselSB_S390(const IRSB *bb, VexArch arch_host, const VexArchInfo *archinfo_host, 4057 const VexAbiInfo *vbi, Int offset_host_evcheck_counter, 4058 Int offset_host_evcheck_fail_addr, Bool chaining_allowed, 4059 Bool add_profinc, Addr max_ga) 4060 { 4061 UInt i, j; 4062 HReg hreg, hregHI; 4063 ISelEnv *env; 4064 UInt hwcaps_host = archinfo_host->hwcaps; 4065 4066 /* Do some sanity checks */ 4067 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0); 4068 4069 /* Check that the host's endianness is as expected. */ 4070 vassert(archinfo_host->endness == VexEndnessBE); 4071 4072 /* Make up an initial environment to use. */ 4073 env = LibVEX_Alloc_inline(sizeof(ISelEnv)); 4074 env->vreg_ctr = 0; 4075 4076 /* Set up output code array. */ 4077 env->code = newHInstrArray(); 4078 4079 /* Copy BB's type env. */ 4080 env->type_env = bb->tyenv; 4081 4082 /* Set up data structures for tracking guest register values. */ 4083 for (i = 0; i < NUM_TRACKED_REGS; ++i) { 4084 env->old_value[i] = 0; /* just something to have a defined value */ 4085 env->old_value_valid[i] = False; 4086 } 4087 4088 /* Make up an IRTemp -> virtual HReg mapping. This doesn't 4089 change as we go along. For some reason types_used has Int type -- but 4090 it should be unsigned. Internally we use an unsigned type; so we 4091 assert it here. */ 4092 vassert(bb->tyenv->types_used >= 0); 4093 4094 env->n_vregmap = bb->tyenv->types_used; 4095 env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 4096 env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 4097 4098 env->previous_bfp_rounding_mode = NULL; 4099 env->previous_dfp_rounding_mode = NULL; 4100 4101 /* and finally ... */ 4102 env->hwcaps = hwcaps_host; 4103 4104 env->max_ga = max_ga; 4105 env->chaining_allowed = chaining_allowed; 4106 4107 /* For each IR temporary, allocate a suitably-kinded virtual 4108 register. */ 4109 j = 0; 4110 for (i = 0; i < env->n_vregmap; i++) { 4111 hregHI = hreg = INVALID_HREG; 4112 switch (bb->tyenv->types[i]) { 4113 case Ity_I1: 4114 case Ity_I8: 4115 case Ity_I16: 4116 case Ity_I32: 4117 case Ity_I64: 4118 hreg = mkVRegI(j++); 4119 break; 4120 4121 case Ity_I128: 4122 hreg = mkVRegI(j++); 4123 hregHI = mkVRegI(j++); 4124 break; 4125 4126 case Ity_F32: 4127 case Ity_F64: 4128 case Ity_D32: 4129 case Ity_D64: 4130 hreg = mkVRegF(j++); 4131 break; 4132 4133 case Ity_F128: 4134 case Ity_D128: 4135 hreg = mkVRegF(j++); 4136 hregHI = mkVRegF(j++); 4137 break; 4138 4139 case Ity_V128: /* fall through */ 4140 default: 4141 ppIRType(bb->tyenv->types[i]); 4142 vpanic("iselSB_S390: IRTemp type"); 4143 } 4144 4145 env->vregmap[i] = hreg; 4146 env->vregmapHI[i] = hregHI; 4147 } 4148 env->vreg_ctr = j; 4149 4150 /* The very first instruction must be an event check. */ 4151 s390_amode *counter, *fail_addr; 4152 counter = s390_amode_for_guest_state(offset_host_evcheck_counter); 4153 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr); 4154 addInstr(env, s390_insn_evcheck(counter, fail_addr)); 4155 4156 /* Possibly a block counter increment (for profiling). At this 4157 point we don't know the address of the counter, so just pretend 4158 it is zero. It will have to be patched later, but before this 4159 translation is used, by a call to LibVEX_patchProfInc. */ 4160 if (add_profinc) { 4161 addInstr(env, s390_insn_profinc()); 4162 } 4163 4164 /* Ok, finally we can iterate over the statements. */ 4165 for (i = 0; i < bb->stmts_used; i++) 4166 if (bb->stmts[i]) 4167 s390_isel_stmt(env, bb->stmts[i]); 4168 4169 iselNext(env, bb->next, bb->jumpkind, bb->offsIP); 4170 4171 /* Record the number of vregs we used. */ 4172 env->code->n_vregs = env->vreg_ctr; 4173 4174 return env->code; 4175 } 4176 4177 /*---------------------------------------------------------------*/ 4178 /*--- end host_s390_isel.c ---*/ 4179 /*---------------------------------------------------------------*/ 4180