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-2015 12 Copyright (C) 2012-2015 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 #%u 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 case Iop_RoundF128toInt: { 2147 IRExpr *irrm; 2148 IRExpr *left; 2149 s390_bfp_round_t rm; 2150 HReg op_hi, op_lo; 2151 HReg f0, f2, f4, f6; /* real registers */ 2152 2153 f4 = make_fpr(4); /* source */ 2154 f6 = make_fpr(6); /* source */ 2155 f0 = make_fpr(0); /* destination */ 2156 f2 = make_fpr(2); /* destination */ 2157 2158 irrm = expr->Iex.Binop.arg1; 2159 left = expr->Iex.Binop.arg2; 2160 2161 if (s390_host_has_fpext) { 2162 rm = get_bfp_rounding_mode(env, irrm); 2163 } else { 2164 set_bfp_rounding_mode_in_fpc(env, irrm); 2165 rm = S390_BFP_ROUND_PER_FPC; 2166 } 2167 2168 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 2169 /* operand --> (f4, f6) */ 2170 addInstr(env, s390_insn_move(8, f4, op_hi)); 2171 addInstr(env, s390_insn_move(8, f6, op_lo)); 2172 addInstr(env, s390_insn_bfp128_convert(16, S390_BFP_F128_TO_F128I, 2173 f0, f2, f4, f6, rm)); 2174 /* (f0, f2) --> destination */ 2175 *dst_hi = newVRegF(env); 2176 *dst_lo = newVRegF(env); 2177 addInstr(env, s390_insn_move(8, *dst_hi, f0)); 2178 addInstr(env, s390_insn_move(8, *dst_lo, f2)); 2179 return; 2180 } 2181 2182 default: 2183 goto irreducible; 2184 } 2185 } 2186 2187 /* --------- UNARY OP --------- */ 2188 case Iex_Unop: { 2189 IRExpr *left = expr->Iex.Unop.arg; 2190 s390_bfp_unop_t bfpop; 2191 s390_bfp_conv_t conv; 2192 HReg op_hi, op_lo, op, f12, f13, f14, f15; 2193 2194 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 2195 f12 = make_fpr(12); 2196 f13 = make_fpr(13); 2197 f14 = make_fpr(14); 2198 f15 = make_fpr(15); 2199 2200 switch (expr->Iex.Unop.op) { 2201 case Iop_NegF128: 2202 if (left->tag == Iex_Unop && 2203 (left->Iex.Unop.op == Iop_AbsF32 || 2204 left->Iex.Unop.op == Iop_AbsF64)) 2205 bfpop = S390_BFP_NABS; 2206 else 2207 bfpop = S390_BFP_NEG; 2208 goto float128_opnd; 2209 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd; 2210 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int; 2211 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int; 2212 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int; 2213 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int; 2214 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float; 2215 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float; 2216 default: 2217 goto irreducible; 2218 } 2219 2220 float128_opnd: 2221 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 2222 2223 /* operand --> (f13, f15) */ 2224 addInstr(env, s390_insn_move(8, f13, op_hi)); 2225 addInstr(env, s390_insn_move(8, f15, op_lo)); 2226 2227 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15)); 2228 goto move_dst; 2229 2230 convert_float: 2231 op = s390_isel_float_expr(env, left); 2232 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op)); 2233 goto move_dst; 2234 2235 convert_int: 2236 op = s390_isel_int_expr(env, left); 2237 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op)); 2238 goto move_dst; 2239 2240 move_dst: 2241 /* Move result to virtual destination registers */ 2242 *dst_hi = newVRegF(env); 2243 *dst_lo = newVRegF(env); 2244 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 2245 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 2246 return; 2247 } 2248 2249 default: 2250 goto irreducible; 2251 } 2252 2253 /* We get here if no pattern matched. */ 2254 irreducible: 2255 ppIRExpr(expr); 2256 vpanic("s390_isel_float128_expr: cannot reduce tree"); 2257 } 2258 2259 /* Compute a 128-bit value into two 64-bit registers. These may be either 2260 real or virtual regs; in any case they must not be changed by subsequent 2261 code emitted by the caller. */ 2262 static void 2263 s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr) 2264 { 2265 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr); 2266 2267 /* Sanity checks ... */ 2268 vassert(hregIsVirtual(*dst_hi)); 2269 vassert(hregIsVirtual(*dst_lo)); 2270 vassert(hregClass(*dst_hi) == HRcFlt64); 2271 vassert(hregClass(*dst_lo) == HRcFlt64); 2272 } 2273 2274 2275 /*---------------------------------------------------------*/ 2276 /*--- ISEL: Floating point expressions (64 bit) ---*/ 2277 /*---------------------------------------------------------*/ 2278 2279 static HReg 2280 s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr) 2281 { 2282 IRType ty = typeOfIRExpr(env->type_env, expr); 2283 UChar size; 2284 2285 vassert(ty == Ity_F32 || ty == Ity_F64); 2286 2287 size = sizeofIRType(ty); 2288 2289 switch (expr->tag) { 2290 case Iex_RdTmp: 2291 /* Return the virtual register that holds the temporary. */ 2292 return lookupIRTemp(env, expr->Iex.RdTmp.tmp); 2293 2294 /* --------- LOAD --------- */ 2295 case Iex_Load: { 2296 HReg dst = newVRegF(env); 2297 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr); 2298 2299 if (expr->Iex.Load.end != Iend_BE) 2300 goto irreducible; 2301 2302 addInstr(env, s390_insn_load(size, dst, am)); 2303 2304 return dst; 2305 } 2306 2307 /* --------- GET --------- */ 2308 case Iex_Get: { 2309 HReg dst = newVRegF(env); 2310 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset); 2311 2312 addInstr(env, s390_insn_load(size, dst, am)); 2313 2314 return dst; 2315 } 2316 2317 /* --------- LITERAL --------- */ 2318 2319 /* Load a literal into a register. Create a "load immediate" 2320 v-insn and return the register. */ 2321 case Iex_Const: { 2322 ULong value; 2323 HReg dst = newVRegF(env); 2324 const IRConst *con = expr->Iex.Const.con; 2325 2326 /* Bitwise copy of the value. No sign/zero-extension */ 2327 switch (con->tag) { 2328 case Ico_F32i: value = con->Ico.F32i; break; 2329 case Ico_F64i: value = con->Ico.F64i; break; 2330 default: vpanic("s390_isel_float_expr: invalid constant"); 2331 } 2332 2333 if (value != 0) vpanic("cannot load immediate floating point constant"); 2334 2335 addInstr(env, s390_insn_load_immediate(size, dst, value)); 2336 2337 return dst; 2338 } 2339 2340 /* --------- 4-ary OP --------- */ 2341 case Iex_Qop: { 2342 HReg op1, op2, op3, dst; 2343 s390_bfp_triop_t bfpop; 2344 2345 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2); 2346 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3); 2347 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4); 2348 dst = newVRegF(env); 2349 addInstr(env, s390_insn_move(size, dst, op1)); 2350 2351 switch (expr->Iex.Qop.details->op) { 2352 case Iop_MAddF32: 2353 case Iop_MAddF64: bfpop = S390_BFP_MADD; break; 2354 case Iop_MSubF32: 2355 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break; 2356 2357 default: 2358 goto irreducible; 2359 } 2360 2361 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1); 2362 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3)); 2363 return dst; 2364 } 2365 2366 /* --------- TERNARY OP --------- */ 2367 case Iex_Triop: { 2368 IRTriop *triop = expr->Iex.Triop.details; 2369 IROp op = triop->op; 2370 IRExpr *left = triop->arg2; 2371 IRExpr *right = triop->arg3; 2372 s390_bfp_binop_t bfpop; 2373 HReg h1, op2, dst; 2374 2375 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */ 2376 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */ 2377 dst = newVRegF(env); 2378 addInstr(env, s390_insn_move(size, dst, h1)); 2379 switch (op) { 2380 case Iop_AddF32: 2381 case Iop_AddF64: bfpop = S390_BFP_ADD; break; 2382 case Iop_SubF32: 2383 case Iop_SubF64: bfpop = S390_BFP_SUB; break; 2384 case Iop_MulF32: 2385 case Iop_MulF64: bfpop = S390_BFP_MUL; break; 2386 case Iop_DivF32: 2387 case Iop_DivF64: bfpop = S390_BFP_DIV; break; 2388 2389 default: 2390 goto irreducible; 2391 } 2392 2393 set_bfp_rounding_mode_in_fpc(env, triop->arg1); 2394 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2)); 2395 return dst; 2396 } 2397 2398 /* --------- BINARY OP --------- */ 2399 case Iex_Binop: { 2400 IROp op = expr->Iex.Binop.op; 2401 IRExpr *irrm = expr->Iex.Binop.arg1; 2402 IRExpr *left = expr->Iex.Binop.arg2; 2403 HReg h1, dst; 2404 s390_bfp_conv_t conv; 2405 s390_fp_conv_t fpconv; 2406 2407 switch (op) { 2408 case Iop_SqrtF32: 2409 case Iop_SqrtF64: 2410 h1 = s390_isel_float_expr(env, left); 2411 dst = newVRegF(env); 2412 set_bfp_rounding_mode_in_fpc(env, irrm); 2413 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1)); 2414 return dst; 2415 2416 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float; 2417 case Iop_RoundF32toInt: conv = S390_BFP_F32_TO_F32I; goto convert_float; 2418 case Iop_RoundF64toInt: conv = S390_BFP_F64_TO_F64I; goto convert_float; 2419 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int; 2420 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int; 2421 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int; 2422 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int; 2423 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int; 2424 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int; 2425 case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp; 2426 case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp; 2427 case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp; 2428 case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp; 2429 case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128; 2430 case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128; 2431 2432 convert_float: 2433 h1 = s390_isel_float_expr(env, left); 2434 goto convert; 2435 2436 convert_int: 2437 h1 = s390_isel_int_expr(env, left); 2438 goto convert; 2439 2440 convert: { 2441 s390_bfp_round_t rounding_mode; 2442 /* convert-from-fixed and load-rounded have a rounding mode field 2443 when the floating point extension facility is installed. */ 2444 dst = newVRegF(env); 2445 if (s390_host_has_fpext) { 2446 rounding_mode = get_bfp_rounding_mode(env, irrm); 2447 } else { 2448 set_bfp_rounding_mode_in_fpc(env, irrm); 2449 rounding_mode = S390_BFP_ROUND_PER_FPC; 2450 } 2451 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1, 2452 rounding_mode)); 2453 return dst; 2454 } 2455 2456 convert_dfp: { 2457 s390_dfp_round_t rm; 2458 HReg f0, f4, r1; /* real registers used by PFPO */ 2459 2460 f4 = make_fpr(4); /* source */ 2461 f0 = make_fpr(0); /* destination */ 2462 r1 = make_gpr(1); /* GPR #1 clobbered */ 2463 h1 = s390_isel_dfp_expr(env, left); 2464 dst = newVRegF(env); 2465 rm = get_dfp_rounding_mode(env, irrm); 2466 /* operand --> f4 */ 2467 addInstr(env, s390_insn_move(8, f4, h1)); 2468 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm)); 2469 /* f0 --> destination */ 2470 addInstr(env, s390_insn_move(8, dst, f0)); 2471 return dst; 2472 } 2473 2474 convert_dfp128: { 2475 s390_dfp_round_t rm; 2476 HReg op_hi, op_lo; 2477 HReg f0, f4, f6, r1; /* real registers used by PFPO */ 2478 2479 f4 = make_fpr(4); /* source */ 2480 f6 = make_fpr(6); /* source */ 2481 f0 = make_fpr(0); /* destination */ 2482 r1 = make_gpr(1); /* GPR #1 clobbered */ 2483 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left); 2484 dst = newVRegF(env); 2485 rm = get_dfp_rounding_mode(env, irrm); 2486 /* operand --> (f4, f6) */ 2487 addInstr(env, s390_insn_move(8, f4, op_hi)); 2488 addInstr(env, s390_insn_move(8, f6, op_lo)); 2489 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG, 2490 f4, f6, r1, rm)); 2491 /* f0 --> destination */ 2492 addInstr(env, s390_insn_move(8, dst, f0)); 2493 return dst; 2494 } 2495 2496 default: 2497 goto irreducible; 2498 2499 case Iop_F128toF64: 2500 case Iop_F128toF32: { 2501 HReg op_hi, op_lo, f12, f13, f14, f15; 2502 s390_bfp_round_t rounding_mode; 2503 2504 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32 2505 : S390_BFP_F128_TO_F64; 2506 2507 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 2508 2509 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 2510 f12 = make_fpr(12); 2511 f13 = make_fpr(13); 2512 f14 = make_fpr(14); 2513 f15 = make_fpr(15); 2514 2515 /* operand --> (f13, f15) */ 2516 addInstr(env, s390_insn_move(8, f13, op_hi)); 2517 addInstr(env, s390_insn_move(8, f15, op_lo)); 2518 2519 /* result --> (f12, f14) */ 2520 2521 /* load-rounded has a rounding mode field when the floating point 2522 extension facility is installed. */ 2523 if (s390_host_has_fpext) { 2524 rounding_mode = get_bfp_rounding_mode(env, irrm); 2525 } else { 2526 set_bfp_rounding_mode_in_fpc(env, irrm); 2527 rounding_mode = S390_BFP_ROUND_PER_FPC; 2528 } 2529 2530 addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14, 2531 f13, f15, rounding_mode)); 2532 dst = newVRegF(env); 2533 addInstr(env, s390_insn_move(8, dst, f12)); 2534 2535 return dst; 2536 } 2537 } 2538 } 2539 2540 /* --------- UNARY OP --------- */ 2541 case Iex_Unop: { 2542 IROp op = expr->Iex.Unop.op; 2543 IRExpr *left = expr->Iex.Unop.arg; 2544 s390_bfp_unop_t bfpop; 2545 s390_bfp_conv_t conv; 2546 HReg h1, dst; 2547 2548 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) { 2549 HReg dst_hi, dst_lo; 2550 2551 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left); 2552 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi; 2553 } 2554 2555 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) { 2556 dst = newVRegF(env); 2557 h1 = s390_isel_int_expr(env, left); /* Process the operand */ 2558 addInstr(env, s390_insn_move(size, dst, h1)); 2559 2560 return dst; 2561 } 2562 2563 switch (op) { 2564 case Iop_NegF32: 2565 case Iop_NegF64: 2566 if (left->tag == Iex_Unop && 2567 (left->Iex.Unop.op == Iop_AbsF32 || 2568 left->Iex.Unop.op == Iop_AbsF64)) 2569 bfpop = S390_BFP_NABS; 2570 else 2571 bfpop = S390_BFP_NEG; 2572 break; 2573 2574 case Iop_AbsF32: 2575 case Iop_AbsF64: 2576 bfpop = S390_BFP_ABS; 2577 break; 2578 2579 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1; 2580 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1; 2581 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1; 2582 2583 convert_float1: 2584 h1 = s390_isel_float_expr(env, left); 2585 goto convert1; 2586 2587 convert_int1: 2588 h1 = s390_isel_int_expr(env, left); 2589 goto convert1; 2590 2591 convert1: 2592 dst = newVRegF(env); 2593 /* No rounding mode is needed for these conversions. Just stick 2594 one in. It won't be used later on. */ 2595 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1, 2596 S390_BFP_ROUND_NEAREST_EVEN)); 2597 return dst; 2598 2599 default: 2600 goto irreducible; 2601 } 2602 2603 /* Process operand */ 2604 h1 = s390_isel_float_expr(env, left); 2605 dst = newVRegF(env); 2606 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1)); 2607 return dst; 2608 } 2609 2610 default: 2611 goto irreducible; 2612 } 2613 2614 /* We get here if no pattern matched. */ 2615 irreducible: 2616 ppIRExpr(expr); 2617 vpanic("s390_isel_float_expr: cannot reduce tree"); 2618 } 2619 2620 2621 static HReg 2622 s390_isel_float_expr(ISelEnv *env, IRExpr *expr) 2623 { 2624 HReg dst = s390_isel_float_expr_wrk(env, expr); 2625 2626 /* Sanity checks ... */ 2627 vassert(hregClass(dst) == HRcFlt64); 2628 vassert(hregIsVirtual(dst)); 2629 2630 return dst; 2631 } 2632 2633 2634 /*---------------------------------------------------------*/ 2635 /*--- ISEL: Decimal point expressions (128 bit) ---*/ 2636 /*---------------------------------------------------------*/ 2637 static void 2638 s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 2639 IRExpr *expr) 2640 { 2641 IRType ty = typeOfIRExpr(env->type_env, expr); 2642 2643 vassert(ty == Ity_D128); 2644 2645 switch (expr->tag) { 2646 case Iex_RdTmp: 2647 /* Return the virtual registers that hold the temporary. */ 2648 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp); 2649 return; 2650 2651 /* --------- LOAD --------- */ 2652 case Iex_Load: { 2653 IRExpr *addr_hi, *addr_lo; 2654 s390_amode *am_hi, *am_lo; 2655 2656 if (expr->Iex.Load.end != Iend_BE) 2657 goto irreducible; 2658 2659 addr_hi = expr->Iex.Load.addr; 2660 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8)); 2661 2662 am_hi = s390_isel_amode(env, addr_hi); 2663 am_lo = s390_isel_amode(env, addr_lo); 2664 2665 *dst_hi = newVRegF(env); 2666 *dst_lo = newVRegF(env); 2667 addInstr(env, s390_insn_load(8, *dst_hi, am_hi)); 2668 addInstr(env, s390_insn_load(8, *dst_hi, am_lo)); 2669 return; 2670 } 2671 2672 /* --------- GET --------- */ 2673 case Iex_Get: 2674 /* This is not supported because loading 128-bit from the guest 2675 state is almost certainly wrong. Use get_dpr_pair instead. */ 2676 vpanic("Iex_Get with D128 data"); 2677 2678 /* --------- 4-ary OP --------- */ 2679 case Iex_Qop: 2680 vpanic("Iex_Qop with D128 data"); 2681 2682 /* --------- TERNARY OP --------- */ 2683 case Iex_Triop: { 2684 IRTriop *triop = expr->Iex.Triop.details; 2685 IROp op = triop->op; 2686 IRExpr *irrm = triop->arg1; 2687 IRExpr *left = triop->arg2; 2688 IRExpr *right = triop->arg3; 2689 s390_dfp_round_t rounding_mode; 2690 s390_dfp_binop_t dfpop; 2691 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15; 2692 2693 /* We use non-virtual registers as pairs with (f9, f11) as op1, 2694 (f12, f14) as op2 and (f13, f15) as destination) */ 2695 f9 = make_fpr(9); 2696 f11 = make_fpr(11); 2697 f12 = make_fpr(12); 2698 f13 = make_fpr(13); 2699 f14 = make_fpr(14); 2700 f15 = make_fpr(15); 2701 2702 switch (op) { 2703 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128; 2704 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128; 2705 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128; 2706 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128; 2707 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128; 2708 2709 evaluate_dfp128: { 2710 /* Process 1st operand */ 2711 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); 2712 /* 1st operand --> (f9, f11) */ 2713 addInstr(env, s390_insn_move(8, f9, op1_hi)); 2714 addInstr(env, s390_insn_move(8, f11, op1_lo)); 2715 2716 /* Process 2nd operand */ 2717 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); 2718 /* 2nd operand --> (f12, f14) */ 2719 addInstr(env, s390_insn_move(8, f12, op2_hi)); 2720 addInstr(env, s390_insn_move(8, f14, op2_lo)); 2721 2722 /* DFP arithmetic ops take rounding mode only when fpext is 2723 installed. But, DFP quantize operation takes rm irrespective 2724 of fpext facility . */ 2725 if (s390_host_has_fpext || op == Iop_QuantizeD128) { 2726 rounding_mode = get_dfp_rounding_mode(env, irrm); 2727 } else { 2728 set_dfp_rounding_mode_in_fpc(env, irrm); 2729 rounding_mode = S390_DFP_ROUND_PER_FPC_0; 2730 } 2731 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11, 2732 f12, f14, rounding_mode)); 2733 /* Move result to virtual destination register */ 2734 *dst_hi = newVRegF(env); 2735 *dst_lo = newVRegF(env); 2736 addInstr(env, s390_insn_move(8, *dst_hi, f13)); 2737 addInstr(env, s390_insn_move(8, *dst_lo, f15)); 2738 return; 2739 } 2740 2741 case Iop_SignificanceRoundD128: { 2742 /* Process 1st operand */ 2743 HReg op1 = s390_isel_int_expr(env, left); 2744 /* Process 2nd operand */ 2745 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); 2746 /* 2nd operand --> (f12, f14) */ 2747 addInstr(env, s390_insn_move(8, f12, op2_hi)); 2748 addInstr(env, s390_insn_move(8, f14, op2_lo)); 2749 2750 rounding_mode = get_dfp_rounding_mode(env, irrm); 2751 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14, 2752 rounding_mode)); 2753 /* Move result to virtual destination register */ 2754 *dst_hi = newVRegF(env); 2755 *dst_lo = newVRegF(env); 2756 addInstr(env, s390_insn_move(8, *dst_hi, f13)); 2757 addInstr(env, s390_insn_move(8, *dst_lo, f15)); 2758 return; 2759 } 2760 2761 default: 2762 goto irreducible; 2763 } 2764 } 2765 2766 /* --------- BINARY OP --------- */ 2767 case Iex_Binop: { 2768 2769 switch (expr->Iex.Binop.op) { 2770 case Iop_D64HLtoD128: 2771 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1); 2772 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2); 2773 return; 2774 2775 case Iop_ShlD128: 2776 case Iop_ShrD128: 2777 case Iop_InsertExpD128: { 2778 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15; 2779 s390_dfp_intop_t intop; 2780 IRExpr *dfp_op; 2781 IRExpr *int_op; 2782 2783 switch (expr->Iex.Binop.op) { 2784 case Iop_ShlD128: /* (D128, I64) -> D128 */ 2785 intop = S390_DFP_SHIFT_LEFT; 2786 dfp_op = expr->Iex.Binop.arg1; 2787 int_op = expr->Iex.Binop.arg2; 2788 break; 2789 case Iop_ShrD128: /* (D128, I64) -> D128 */ 2790 intop = S390_DFP_SHIFT_RIGHT; 2791 dfp_op = expr->Iex.Binop.arg1; 2792 int_op = expr->Iex.Binop.arg2; 2793 break; 2794 case Iop_InsertExpD128: /* (I64, D128) -> D128 */ 2795 intop = S390_DFP_INSERT_EXP; 2796 int_op = expr->Iex.Binop.arg1; 2797 dfp_op = expr->Iex.Binop.arg2; 2798 break; 2799 default: goto irreducible; 2800 } 2801 2802 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */ 2803 f9 = make_fpr(9); /* 128 bit dfp operand */ 2804 f11 = make_fpr(11); 2805 2806 f13 = make_fpr(13); /* 128 bit dfp destination */ 2807 f15 = make_fpr(15); 2808 2809 /* Process dfp operand */ 2810 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op); 2811 /* op1 -> (f9,f11) */ 2812 addInstr(env, s390_insn_move(8, f9, op1_hi)); 2813 addInstr(env, s390_insn_move(8, f11, op1_lo)); 2814 2815 op2 = s390_isel_int_expr(env, int_op); /* int operand */ 2816 2817 addInstr(env, 2818 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11)); 2819 2820 /* Move result to virtual destination register */ 2821 *dst_hi = newVRegF(env); 2822 *dst_lo = newVRegF(env); 2823 addInstr(env, s390_insn_move(8, *dst_hi, f13)); 2824 addInstr(env, s390_insn_move(8, *dst_lo, f15)); 2825 return; 2826 } 2827 2828 case Iop_F32toD128: 2829 case Iop_F64toD128: { 2830 IRExpr *irrm; 2831 IRExpr *left; 2832 s390_dfp_round_t rm; 2833 HReg h1; /* virtual reg. to hold source */ 2834 HReg f0, f2, f4, r1; /* real registers used by PFPO */ 2835 s390_fp_conv_t fpconv; 2836 2837 switch (expr->Iex.Binop.op) { 2838 case Iop_F32toD128: /* (D128, I64) -> D128 */ 2839 fpconv = S390_FP_F32_TO_D128; 2840 break; 2841 case Iop_F64toD128: /* (D128, I64) -> D128 */ 2842 fpconv = S390_FP_F64_TO_D128; 2843 break; 2844 default: goto irreducible; 2845 } 2846 2847 f4 = make_fpr(4); /* source */ 2848 f0 = make_fpr(0); /* destination */ 2849 f2 = make_fpr(2); /* destination */ 2850 r1 = make_gpr(1); /* GPR #1 clobbered */ 2851 irrm = expr->Iex.Binop.arg1; 2852 left = expr->Iex.Binop.arg2; 2853 rm = get_dfp_rounding_mode(env, irrm); 2854 h1 = s390_isel_float_expr(env, left); 2855 addInstr(env, s390_insn_move(8, f4, h1)); 2856 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2, 2857 f4, INVALID_HREG, r1, rm)); 2858 /* (f0, f2) --> destination */ 2859 *dst_hi = newVRegF(env); 2860 *dst_lo = newVRegF(env); 2861 addInstr(env, s390_insn_move(8, *dst_hi, f0)); 2862 addInstr(env, s390_insn_move(8, *dst_lo, f2)); 2863 2864 return; 2865 } 2866 2867 case Iop_F128toD128: { 2868 IRExpr *irrm; 2869 IRExpr *left; 2870 s390_dfp_round_t rm; 2871 HReg op_hi, op_lo; 2872 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */ 2873 2874 f4 = make_fpr(4); /* source */ 2875 f6 = make_fpr(6); /* source */ 2876 f0 = make_fpr(0); /* destination */ 2877 f2 = make_fpr(2); /* destination */ 2878 r1 = make_gpr(1); /* GPR #1 clobbered */ 2879 2880 irrm = expr->Iex.Binop.arg1; 2881 left = expr->Iex.Binop.arg2; 2882 rm = get_dfp_rounding_mode(env, irrm); 2883 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 2884 /* operand --> (f4, f6) */ 2885 addInstr(env, s390_insn_move(8, f4, op_hi)); 2886 addInstr(env, s390_insn_move(8, f6, op_lo)); 2887 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2, 2888 f4, f6, r1, rm)); 2889 /* (f0, f2) --> destination */ 2890 *dst_hi = newVRegF(env); 2891 *dst_lo = newVRegF(env); 2892 addInstr(env, s390_insn_move(8, *dst_hi, f0)); 2893 addInstr(env, s390_insn_move(8, *dst_lo, f2)); 2894 2895 return; 2896 } 2897 2898 default: 2899 goto irreducible; 2900 } 2901 } 2902 2903 /* --------- UNARY OP --------- */ 2904 case Iex_Unop: { 2905 IRExpr *left = expr->Iex.Unop.arg; 2906 s390_dfp_conv_t conv; 2907 HReg op, f12, f14; 2908 2909 /* We use non-virtual registers as pairs (f12, f14)) */ 2910 f12 = make_fpr(12); 2911 f14 = make_fpr(14); 2912 2913 switch (expr->Iex.Unop.op) { 2914 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp; 2915 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int; 2916 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int; 2917 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int; 2918 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int; 2919 default: 2920 goto irreducible; 2921 } 2922 2923 convert_dfp: 2924 op = s390_isel_dfp_expr(env, left); 2925 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op)); 2926 goto move_dst; 2927 2928 convert_int: 2929 op = s390_isel_int_expr(env, left); 2930 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op)); 2931 goto move_dst; 2932 2933 move_dst: 2934 /* Move result to virtual destination registers */ 2935 *dst_hi = newVRegF(env); 2936 *dst_lo = newVRegF(env); 2937 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 2938 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 2939 return; 2940 } 2941 2942 default: 2943 goto irreducible; 2944 } 2945 2946 /* We get here if no pattern matched. */ 2947 irreducible: 2948 ppIRExpr(expr); 2949 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree"); 2950 2951 } 2952 2953 2954 /* Compute a 128-bit value into two 64-bit registers. These may be either 2955 real or virtual regs; in any case they must not be changed by subsequent 2956 code emitted by the caller. */ 2957 static void 2958 s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr) 2959 { 2960 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr); 2961 2962 /* Sanity checks ... */ 2963 vassert(hregIsVirtual(*dst_hi)); 2964 vassert(hregIsVirtual(*dst_lo)); 2965 vassert(hregClass(*dst_hi) == HRcFlt64); 2966 vassert(hregClass(*dst_lo) == HRcFlt64); 2967 } 2968 2969 2970 /*---------------------------------------------------------*/ 2971 /*--- ISEL: Decimal point expressions (64 bit) ---*/ 2972 /*---------------------------------------------------------*/ 2973 2974 static HReg 2975 s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr) 2976 { 2977 IRType ty = typeOfIRExpr(env->type_env, expr); 2978 UChar size; 2979 2980 vassert(ty == Ity_D64 || ty == Ity_D32); 2981 2982 size = sizeofIRType(ty); 2983 2984 switch (expr->tag) { 2985 case Iex_RdTmp: 2986 /* Return the virtual register that holds the temporary. */ 2987 return lookupIRTemp(env, expr->Iex.RdTmp.tmp); 2988 2989 /* --------- LOAD --------- */ 2990 case Iex_Load: { 2991 HReg dst = newVRegF(env); 2992 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr); 2993 2994 if (expr->Iex.Load.end != Iend_BE) 2995 goto irreducible; 2996 2997 addInstr(env, s390_insn_load(size, dst, am)); 2998 2999 return dst; 3000 } 3001 3002 /* --------- GET --------- */ 3003 case Iex_Get: { 3004 HReg dst = newVRegF(env); 3005 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset); 3006 3007 addInstr(env, s390_insn_load(size, dst, am)); 3008 3009 return dst; 3010 } 3011 3012 /* --------- BINARY OP --------- */ 3013 case Iex_Binop: { 3014 IROp op = expr->Iex.Binop.op; 3015 IRExpr *irrm = expr->Iex.Binop.arg1; 3016 IRExpr *left = expr->Iex.Binop.arg2; 3017 HReg h1, dst; 3018 s390_dfp_conv_t conv; 3019 s390_fp_conv_t fpconv; 3020 3021 switch (op) { 3022 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp; 3023 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int; 3024 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int; 3025 case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp; 3026 case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp; 3027 case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp; 3028 case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp; 3029 case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128; 3030 case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128; 3031 3032 convert_dfp: 3033 h1 = s390_isel_dfp_expr(env, left); 3034 goto convert; 3035 3036 convert_int: 3037 h1 = s390_isel_int_expr(env, left); 3038 goto convert; 3039 3040 convert: { 3041 s390_dfp_round_t rounding_mode; 3042 /* convert-from-fixed and load-rounded have a rounding mode field 3043 when the floating point extension facility is installed. */ 3044 dst = newVRegF(env); 3045 if (s390_host_has_fpext) { 3046 rounding_mode = get_dfp_rounding_mode(env, irrm); 3047 } else { 3048 set_dfp_rounding_mode_in_fpc(env, irrm); 3049 rounding_mode = S390_DFP_ROUND_PER_FPC_0; 3050 } 3051 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1, 3052 rounding_mode)); 3053 return dst; 3054 } 3055 3056 convert_bfp: { 3057 s390_dfp_round_t rm; 3058 HReg f0, f4, r1; /* real registers used by PFPO */ 3059 3060 f4 = make_fpr(4); /* source */ 3061 f0 = make_fpr(0); /* destination */ 3062 r1 = make_gpr(1); /* GPR #1 clobbered */ 3063 h1 = s390_isel_float_expr(env, left); 3064 dst = newVRegF(env); 3065 rm = get_dfp_rounding_mode(env, irrm); 3066 /* operand --> f4 */ 3067 addInstr(env, s390_insn_move(8, f4, h1)); 3068 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm)); 3069 /* f0 --> destination */ 3070 addInstr(env, s390_insn_move(8, dst, f0)); 3071 return dst; 3072 } 3073 3074 convert_bfp128: { 3075 s390_dfp_round_t rm; 3076 HReg op_hi, op_lo; 3077 HReg f0, f4, f6, r1; /* real registers used by PFPO */ 3078 3079 f4 = make_fpr(4); /* source */ 3080 f6 = make_fpr(6); /* source */ 3081 f0 = make_fpr(0); /* destination */ 3082 r1 = make_gpr(1); /* GPR #1 clobbered */ 3083 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 3084 dst = newVRegF(env); 3085 rm = get_dfp_rounding_mode(env, irrm); 3086 /* operand --> (f4, f6) */ 3087 addInstr(env, s390_insn_move(8, f4, op_hi)); 3088 addInstr(env, s390_insn_move(8, f6, op_lo)); 3089 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG, 3090 f4, f6, r1, rm)); 3091 /* f0 --> destination */ 3092 addInstr(env, s390_insn_move(8, dst, f0)); 3093 return dst; 3094 } 3095 3096 case Iop_D128toD64: { 3097 HReg op_hi, op_lo, f12, f13, f14, f15; 3098 s390_dfp_round_t rounding_mode; 3099 3100 conv = S390_DFP_D128_TO_D64; 3101 3102 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left); 3103 3104 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */ 3105 f12 = make_fpr(12); 3106 f13 = make_fpr(13); 3107 f14 = make_fpr(14); 3108 f15 = make_fpr(15); 3109 3110 /* operand --> (f13, f15) */ 3111 addInstr(env, s390_insn_move(8, f13, op_hi)); 3112 addInstr(env, s390_insn_move(8, f15, op_lo)); 3113 3114 /* result --> (f12, f14) */ 3115 3116 /* load-rounded has a rounding mode field when the floating point 3117 extension facility is installed. */ 3118 if (s390_host_has_fpext) { 3119 rounding_mode = get_dfp_rounding_mode(env, irrm); 3120 } else { 3121 set_dfp_rounding_mode_in_fpc(env, irrm); 3122 rounding_mode = S390_DFP_ROUND_PER_FPC_0; 3123 } 3124 addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14, 3125 f13, f15, rounding_mode)); 3126 dst = newVRegF(env); 3127 addInstr(env, s390_insn_move(8, dst, f12)); 3128 3129 return dst; 3130 } 3131 3132 case Iop_ShlD64: 3133 case Iop_ShrD64: 3134 case Iop_InsertExpD64: { 3135 HReg op2; 3136 HReg op3; 3137 IRExpr *dfp_op; 3138 IRExpr *int_op; 3139 s390_dfp_intop_t intop; 3140 3141 switch (expr->Iex.Binop.op) { 3142 case Iop_ShlD64: /* (D64, I64) -> D64 */ 3143 intop = S390_DFP_SHIFT_LEFT; 3144 dfp_op = expr->Iex.Binop.arg1; 3145 int_op = expr->Iex.Binop.arg2; 3146 break; 3147 case Iop_ShrD64: /* (D64, I64) -> D64 */ 3148 intop = S390_DFP_SHIFT_RIGHT; 3149 dfp_op = expr->Iex.Binop.arg1; 3150 int_op = expr->Iex.Binop.arg2; 3151 break; 3152 case Iop_InsertExpD64: /* (I64, D64) -> D64 */ 3153 intop = S390_DFP_INSERT_EXP; 3154 int_op = expr->Iex.Binop.arg1; 3155 dfp_op = expr->Iex.Binop.arg2; 3156 break; 3157 default: goto irreducible; 3158 } 3159 3160 op2 = s390_isel_int_expr(env, int_op); 3161 op3 = s390_isel_dfp_expr(env, dfp_op); 3162 dst = newVRegF(env); 3163 3164 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3)); 3165 return dst; 3166 } 3167 3168 default: 3169 goto irreducible; 3170 } 3171 } 3172 3173 /* --------- UNARY OP --------- */ 3174 case Iex_Unop: { 3175 IROp op = expr->Iex.Unop.op; 3176 IRExpr *left = expr->Iex.Unop.arg; 3177 s390_dfp_conv_t conv; 3178 HReg h1, dst; 3179 3180 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) { 3181 HReg dst_hi, dst_lo; 3182 3183 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left); 3184 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi; 3185 } 3186 3187 if (op == Iop_ReinterpI64asD64) { 3188 dst = newVRegF(env); 3189 h1 = s390_isel_int_expr(env, left); /* Process the operand */ 3190 addInstr(env, s390_insn_move(size, dst, h1)); 3191 3192 return dst; 3193 } 3194 3195 switch (op) { 3196 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1; 3197 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1; 3198 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1; 3199 3200 convert_dfp1: 3201 h1 = s390_isel_dfp_expr(env, left); 3202 goto convert1; 3203 3204 convert_int1: 3205 h1 = s390_isel_int_expr(env, left); 3206 goto convert1; 3207 3208 convert1: 3209 dst = newVRegF(env); 3210 /* No rounding mode is needed for these conversions. Just stick 3211 one in. It won't be used later on. */ 3212 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1, 3213 S390_DFP_ROUND_NEAREST_EVEN_4)); 3214 return dst; 3215 3216 default: 3217 goto irreducible; 3218 } 3219 } 3220 3221 /* --------- TERNARY OP --------- */ 3222 case Iex_Triop: { 3223 IRTriop *triop = expr->Iex.Triop.details; 3224 IROp op = triop->op; 3225 IRExpr *irrm = triop->arg1; 3226 IRExpr *left = triop->arg2; 3227 IRExpr *right = triop->arg3; 3228 s390_dfp_round_t rounding_mode; 3229 s390_dfp_binop_t dfpop; 3230 HReg op2, op3, dst; 3231 3232 switch (op) { 3233 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp; 3234 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp; 3235 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp; 3236 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp; 3237 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp; 3238 3239 evaluate_dfp: { 3240 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */ 3241 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */ 3242 dst = newVRegF(env); 3243 /* DFP arithmetic ops take rounding mode only when fpext is 3244 installed. But, DFP quantize operation takes rm irrespective 3245 of fpext facility . */ 3246 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) { 3247 rounding_mode = get_dfp_rounding_mode(env, irrm); 3248 } else { 3249 set_dfp_rounding_mode_in_fpc(env, irrm); 3250 rounding_mode = S390_DFP_ROUND_PER_FPC_0; 3251 } 3252 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3, 3253 rounding_mode)); 3254 return dst; 3255 } 3256 3257 case Iop_SignificanceRoundD64: 3258 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */ 3259 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */ 3260 dst = newVRegF(env); 3261 rounding_mode = get_dfp_rounding_mode(env, irrm); 3262 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3, 3263 rounding_mode)); 3264 return dst; 3265 3266 default: 3267 goto irreducible; 3268 } 3269 } 3270 3271 default: 3272 goto irreducible; 3273 } 3274 3275 /* We get here if no pattern matched. */ 3276 irreducible: 3277 ppIRExpr(expr); 3278 vpanic("s390_isel_dfp_expr: cannot reduce tree"); 3279 } 3280 3281 static HReg 3282 s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr) 3283 { 3284 HReg dst = s390_isel_dfp_expr_wrk(env, expr); 3285 3286 /* Sanity checks ... */ 3287 vassert(hregClass(dst) == HRcFlt64); 3288 vassert(hregIsVirtual(dst)); 3289 3290 return dst; 3291 } 3292 3293 3294 /*---------------------------------------------------------*/ 3295 /*--- ISEL: Condition Code ---*/ 3296 /*---------------------------------------------------------*/ 3297 3298 /* This function handles all operators that produce a 1-bit result */ 3299 static s390_cc_t 3300 s390_isel_cc(ISelEnv *env, IRExpr *cond) 3301 { 3302 UChar size; 3303 3304 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1); 3305 3306 /* Constant: either 1 or 0 */ 3307 if (cond->tag == Iex_Const) { 3308 vassert(cond->Iex.Const.con->tag == Ico_U1); 3309 vassert(cond->Iex.Const.con->Ico.U1 == True 3310 || cond->Iex.Const.con->Ico.U1 == False); 3311 3312 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER; 3313 } 3314 3315 /* Variable: values are 1 or 0 */ 3316 if (cond->tag == Iex_RdTmp) { 3317 IRTemp tmp = cond->Iex.RdTmp.tmp; 3318 HReg reg = lookupIRTemp(env, tmp); 3319 3320 /* Load-and-test does not modify REG; so this is OK. */ 3321 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1) 3322 size = 4; 3323 else 3324 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp)); 3325 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg))); 3326 return S390_CC_NE; 3327 } 3328 3329 /* Unary operators */ 3330 if (cond->tag == Iex_Unop) { 3331 IRExpr *arg = cond->Iex.Unop.arg; 3332 3333 switch (cond->Iex.Unop.op) { 3334 case Iop_Not1: /* Not1(cond) */ 3335 /* Generate code for EXPR, and negate the test condition */ 3336 return s390_cc_invert(s390_isel_cc(env, arg)); 3337 3338 /* Iop_32/64to1 select the LSB from their operand */ 3339 case Iop_32to1: 3340 case Iop_64to1: { 3341 HReg dst = newVRegI(env); 3342 HReg h1 = s390_isel_int_expr(env, arg); 3343 3344 size = sizeofIRType(typeOfIRExpr(env->type_env, arg)); 3345 3346 addInstr(env, s390_insn_move(size, dst, h1)); 3347 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1))); 3348 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst))); 3349 return S390_CC_NE; 3350 } 3351 3352 case Iop_CmpNEZ8: 3353 case Iop_CmpNEZ16: { 3354 s390_opnd_RMI src; 3355 s390_unop_t op; 3356 HReg dst; 3357 3358 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8 3359 : S390_ZERO_EXTEND_16; 3360 dst = newVRegI(env); 3361 src = s390_isel_int_expr_RMI(env, arg); 3362 addInstr(env, s390_insn_unop(4, op, dst, src)); 3363 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst))); 3364 return S390_CC_NE; 3365 } 3366 3367 case Iop_CmpNEZ32: 3368 case Iop_CmpNEZ64: { 3369 s390_opnd_RMI src; 3370 3371 src = s390_isel_int_expr_RMI(env, arg); 3372 size = sizeofIRType(typeOfIRExpr(env->type_env, arg)); 3373 addInstr(env, s390_insn_test(size, src)); 3374 return S390_CC_NE; 3375 } 3376 3377 default: 3378 goto fail; 3379 } 3380 } 3381 3382 /* Binary operators */ 3383 if (cond->tag == Iex_Binop) { 3384 IRExpr *arg1 = cond->Iex.Binop.arg1; 3385 IRExpr *arg2 = cond->Iex.Binop.arg2; 3386 HReg reg1, reg2; 3387 3388 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1)); 3389 3390 switch (cond->Iex.Binop.op) { 3391 s390_unop_t op; 3392 s390_cc_t result; 3393 3394 case Iop_CmpEQ8: 3395 case Iop_CasCmpEQ8: 3396 op = S390_ZERO_EXTEND_8; 3397 result = S390_CC_E; 3398 goto do_compare_ze; 3399 3400 case Iop_CmpNE8: 3401 case Iop_CasCmpNE8: 3402 op = S390_ZERO_EXTEND_8; 3403 result = S390_CC_NE; 3404 goto do_compare_ze; 3405 3406 case Iop_CmpEQ16: 3407 case Iop_CasCmpEQ16: 3408 op = S390_ZERO_EXTEND_16; 3409 result = S390_CC_E; 3410 goto do_compare_ze; 3411 3412 case Iop_CmpNE16: 3413 case Iop_CasCmpNE16: 3414 op = S390_ZERO_EXTEND_16; 3415 result = S390_CC_NE; 3416 goto do_compare_ze; 3417 3418 do_compare_ze: { 3419 s390_opnd_RMI op1, op2; 3420 3421 op1 = s390_isel_int_expr_RMI(env, arg1); 3422 reg1 = newVRegI(env); 3423 addInstr(env, s390_insn_unop(4, op, reg1, op1)); 3424 3425 op2 = s390_isel_int_expr_RMI(env, arg2); 3426 reg2 = newVRegI(env); 3427 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */ 3428 3429 op2 = s390_opnd_reg(reg2); 3430 addInstr(env, s390_insn_compare(4, reg1, op2, False)); 3431 3432 return result; 3433 } 3434 3435 case Iop_CmpEQ32: 3436 case Iop_CmpEQ64: 3437 case Iop_CasCmpEQ32: 3438 case Iop_CasCmpEQ64: 3439 result = S390_CC_E; 3440 goto do_compare; 3441 3442 case Iop_CmpNE32: 3443 case Iop_CmpNE64: 3444 case Iop_CasCmpNE32: 3445 case Iop_CasCmpNE64: 3446 result = S390_CC_NE; 3447 goto do_compare; 3448 3449 do_compare: { 3450 HReg op1; 3451 s390_opnd_RMI op2; 3452 3453 order_commutative_operands(arg1, arg2); 3454 3455 op1 = s390_isel_int_expr(env, arg1); 3456 op2 = s390_isel_int_expr_RMI(env, arg2); 3457 3458 addInstr(env, s390_insn_compare(size, op1, op2, False)); 3459 3460 return result; 3461 } 3462 3463 case Iop_CmpLT32S: 3464 case Iop_CmpLE32S: 3465 case Iop_CmpLT64S: 3466 case Iop_CmpLE64S: { 3467 HReg op1; 3468 s390_opnd_RMI op2; 3469 3470 op1 = s390_isel_int_expr(env, arg1); 3471 op2 = s390_isel_int_expr_RMI(env, arg2); 3472 3473 addInstr(env, s390_insn_compare(size, op1, op2, True)); 3474 3475 return (cond->Iex.Binop.op == Iop_CmpLT32S || 3476 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE; 3477 } 3478 3479 case Iop_CmpLT32U: 3480 case Iop_CmpLE32U: 3481 case Iop_CmpLT64U: 3482 case Iop_CmpLE64U: { 3483 HReg op1; 3484 s390_opnd_RMI op2; 3485 3486 op1 = s390_isel_int_expr(env, arg1); 3487 op2 = s390_isel_int_expr_RMI(env, arg2); 3488 3489 addInstr(env, s390_insn_compare(size, op1, op2, False)); 3490 3491 return (cond->Iex.Binop.op == Iop_CmpLT32U || 3492 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE; 3493 } 3494 3495 default: 3496 goto fail; 3497 } 3498 } 3499 3500 fail: 3501 ppIRExpr(cond); 3502 vpanic("s390_isel_cc: unexpected operator"); 3503 } 3504 3505 3506 /*---------------------------------------------------------*/ 3507 /*--- ISEL: Statements ---*/ 3508 /*---------------------------------------------------------*/ 3509 3510 static void 3511 s390_isel_stmt(ISelEnv *env, IRStmt *stmt) 3512 { 3513 if (vex_traceflags & VEX_TRACE_VCODE) { 3514 vex_printf("\n -- "); 3515 ppIRStmt(stmt); 3516 vex_printf("\n"); 3517 } 3518 3519 switch (stmt->tag) { 3520 3521 /* --------- STORE --------- */ 3522 case Ist_Store: { 3523 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data); 3524 s390_amode *am; 3525 HReg src; 3526 3527 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail; 3528 3529 am = s390_isel_amode(env, stmt->Ist.Store.addr); 3530 3531 switch (tyd) { 3532 case Ity_I8: 3533 case Ity_I16: 3534 case Ity_I32: 3535 case Ity_I64: 3536 /* fixs390: We could check for INSN_MADD here. */ 3537 if (am->tag == S390_AMODE_B12 && 3538 stmt->Ist.Store.data->tag == Iex_Const) { 3539 ULong value = 3540 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con); 3541 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value)); 3542 return; 3543 } 3544 /* Check whether we can use a memcpy here. Currently, the restriction 3545 is that both amodes need to be B12, so MVC can be emitted. 3546 We do not consider a store whose data expression is a load because 3547 we don't want to deal with overlapping locations. */ 3548 /* store(get) never overlaps*/ 3549 if (am->tag == S390_AMODE_B12 && 3550 stmt->Ist.Store.data->tag == Iex_Get) { 3551 UInt offset = stmt->Ist.Store.data->Iex.Get.offset; 3552 s390_amode *from = s390_amode_for_guest_state(offset); 3553 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from)); 3554 return; 3555 } 3556 /* General case: compile data into a register */ 3557 src = s390_isel_int_expr(env, stmt->Ist.Store.data); 3558 break; 3559 3560 case Ity_F32: 3561 case Ity_F64: 3562 src = s390_isel_float_expr(env, stmt->Ist.Store.data); 3563 break; 3564 3565 case Ity_D32: 3566 case Ity_D64: 3567 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data); 3568 break; 3569 3570 case Ity_F128: 3571 case Ity_D128: 3572 /* Cannot occur. No such instruction */ 3573 vpanic("Ist_Store with 128-bit floating point data"); 3574 3575 default: 3576 goto stmt_fail; 3577 } 3578 3579 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src)); 3580 return; 3581 } 3582 3583 /* --------- PUT --------- */ 3584 case Ist_Put: { 3585 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); 3586 HReg src; 3587 s390_amode *am; 3588 ULong new_value, old_value, difference; 3589 3590 /* Detect updates to certain guest registers. We track the contents 3591 of those registers as long as they contain constants. If the new 3592 constant is either zero or in the 8-bit neighbourhood of the 3593 current value we can use a memory-to-memory insn to do the update. */ 3594 3595 Int offset = stmt->Ist.Put.offset; 3596 3597 /* Check necessary conditions: 3598 (1) must be one of the registers we care about 3599 (2) assigned value must be a constant */ 3600 Int guest_reg = get_guest_reg(offset); 3601 3602 if (guest_reg == GUEST_UNKNOWN) goto not_special; 3603 3604 if (stmt->Ist.Put.data->tag != Iex_Const) { 3605 /* Invalidate guest register contents */ 3606 env->old_value_valid[guest_reg] = False; 3607 goto not_special; 3608 } 3609 3610 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */ 3611 if (tyd != Ity_I64) 3612 goto not_special; 3613 3614 /* OK. Necessary conditions are satisfied. */ 3615 3616 old_value = env->old_value[guest_reg]; 3617 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64; 3618 env->old_value[guest_reg] = new_value; 3619 3620 Bool old_value_is_valid = env->old_value_valid[guest_reg]; 3621 env->old_value_valid[guest_reg] = True; 3622 3623 /* If the register already contains the new value, there is nothing 3624 to do here. */ 3625 if (old_value_is_valid && new_value == old_value) { 3626 return; 3627 } 3628 3629 if (old_value_is_valid == False) goto not_special; 3630 3631 /* If the new value is in the neighbourhood of the old value 3632 we can use a memory-to-memory insn */ 3633 difference = new_value - old_value; 3634 3635 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) { 3636 am = s390_amode_for_guest_state(offset); 3637 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am, 3638 (difference & 0xFF), new_value)); 3639 return; 3640 } 3641 3642 /* If the high word is the same it is sufficient to load the low word. */ 3643 if ((old_value >> 32) == (new_value >> 32)) { 3644 am = s390_amode_for_guest_state(offset + 4); 3645 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF)); 3646 return; 3647 } 3648 3649 /* No special case applies... fall through */ 3650 3651 not_special: 3652 am = s390_amode_for_guest_state(offset); 3653 3654 switch (tyd) { 3655 case Ity_I8: 3656 case Ity_I16: 3657 case Ity_I32: 3658 case Ity_I64: 3659 if (am->tag == S390_AMODE_B12 && 3660 stmt->Ist.Put.data->tag == Iex_Const) { 3661 ULong value = 3662 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con); 3663 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value)); 3664 return; 3665 } 3666 /* Check whether we can use a memcpy here. Currently, the restriction 3667 is that both amodes need to be B12, so MVC can be emitted. */ 3668 /* put(load) never overlaps */ 3669 if (am->tag == S390_AMODE_B12 && 3670 stmt->Ist.Put.data->tag == Iex_Load) { 3671 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail; 3672 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr; 3673 s390_amode *from = s390_isel_amode(env, data); 3674 UInt size = sizeofIRType(tyd); 3675 3676 if (from->tag == S390_AMODE_B12) { 3677 /* Source can be compiled into a B12 amode. */ 3678 addInstr(env, s390_insn_memcpy(size, am, from)); 3679 return; 3680 } 3681 3682 src = newVRegI(env); 3683 addInstr(env, s390_insn_load(size, src, from)); 3684 break; 3685 } 3686 /* put(get) */ 3687 if (am->tag == S390_AMODE_B12 && 3688 stmt->Ist.Put.data->tag == Iex_Get) { 3689 UInt put_offset = am->d; 3690 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset; 3691 UInt size = sizeofIRType(tyd); 3692 /* don't memcpy in case of overlap */ 3693 if (put_offset + size <= get_offset || 3694 get_offset + size <= put_offset) { 3695 s390_amode *from = s390_amode_for_guest_state(get_offset); 3696 addInstr(env, s390_insn_memcpy(size, am, from)); 3697 return; 3698 } 3699 goto no_memcpy_put; 3700 } 3701 /* General case: compile data into a register */ 3702 no_memcpy_put: 3703 src = s390_isel_int_expr(env, stmt->Ist.Put.data); 3704 break; 3705 3706 case Ity_F32: 3707 case Ity_F64: 3708 src = s390_isel_float_expr(env, stmt->Ist.Put.data); 3709 break; 3710 3711 case Ity_F128: 3712 case Ity_D128: 3713 /* Does not occur. See function put_(f|d)pr_pair. */ 3714 vpanic("Ist_Put with 128-bit floating point data"); 3715 3716 case Ity_D32: 3717 case Ity_D64: 3718 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data); 3719 break; 3720 3721 default: 3722 goto stmt_fail; 3723 } 3724 3725 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src)); 3726 return; 3727 } 3728 3729 /* --------- TMP --------- */ 3730 case Ist_WrTmp: { 3731 IRTemp tmp = stmt->Ist.WrTmp.tmp; 3732 IRType tyd = typeOfIRTemp(env->type_env, tmp); 3733 HReg src, dst; 3734 3735 switch (tyd) { 3736 case Ity_I128: { 3737 HReg dst_hi, dst_lo, res_hi, res_lo; 3738 3739 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data); 3740 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp); 3741 3742 addInstr(env, s390_insn_move(8, dst_hi, res_hi)); 3743 addInstr(env, s390_insn_move(8, dst_lo, res_lo)); 3744 return; 3745 } 3746 3747 case Ity_I8: 3748 case Ity_I16: 3749 case Ity_I32: 3750 case Ity_I64: 3751 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data); 3752 dst = lookupIRTemp(env, tmp); 3753 break; 3754 3755 case Ity_I1: { 3756 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data); 3757 dst = lookupIRTemp(env, tmp); 3758 addInstr(env, s390_insn_cc2bool(dst, cond)); 3759 return; 3760 } 3761 3762 case Ity_F32: 3763 case Ity_F64: 3764 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data); 3765 dst = lookupIRTemp(env, tmp); 3766 break; 3767 3768 case Ity_F128: { 3769 HReg dst_hi, dst_lo, res_hi, res_lo; 3770 3771 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data); 3772 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp); 3773 3774 addInstr(env, s390_insn_move(8, dst_hi, res_hi)); 3775 addInstr(env, s390_insn_move(8, dst_lo, res_lo)); 3776 return; 3777 } 3778 3779 case Ity_D32: 3780 case Ity_D64: 3781 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data); 3782 dst = lookupIRTemp(env, tmp); 3783 break; 3784 3785 case Ity_D128: { 3786 HReg dst_hi, dst_lo, res_hi, res_lo; 3787 3788 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data); 3789 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp); 3790 3791 addInstr(env, s390_insn_move(8, dst_hi, res_hi)); 3792 addInstr(env, s390_insn_move(8, dst_lo, res_lo)); 3793 return; 3794 } 3795 3796 default: 3797 goto stmt_fail; 3798 } 3799 3800 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src)); 3801 return; 3802 } 3803 3804 /* --------- Call to DIRTY helper --------- */ 3805 case Ist_Dirty: { 3806 IRType retty; 3807 IRDirty* d = stmt->Ist.Dirty.details; 3808 HReg dst; 3809 RetLoc rloc = mk_RetLoc_INVALID(); 3810 UInt addToSp = 0; 3811 Int i; 3812 3813 /* Invalidate tracked values of those guest state registers that are 3814 modified by this helper. */ 3815 for (i = 0; i < d->nFxState; ++i) { 3816 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat' 3817 descriptors in guest state effect descriptions. Hence: */ 3818 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0); 3819 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) { 3820 Int guest_reg = get_guest_reg(d->fxState[i].offset); 3821 if (guest_reg != GUEST_UNKNOWN) 3822 env->old_value_valid[guest_reg] = False; 3823 } 3824 } 3825 3826 if (d->tmp == IRTemp_INVALID) { 3827 /* No return value. */ 3828 retty = Ity_INVALID; 3829 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty, 3830 d->args); 3831 vassert(is_sane_RetLoc(rloc)); 3832 vassert(rloc.pri == RLPri_None); 3833 vassert(addToSp == 0); 3834 3835 return; 3836 } 3837 3838 retty = typeOfIRTemp(env->type_env, d->tmp); 3839 if (retty == Ity_I64 || retty == Ity_I32 3840 || retty == Ity_I16 || retty == Ity_I8) { 3841 /* Move the returned value to the destination register */ 3842 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE); 3843 3844 dst = lookupIRTemp(env, d->tmp); 3845 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty, 3846 d->args); 3847 vassert(is_sane_RetLoc(rloc)); 3848 vassert(rloc.pri == RLPri_Int); 3849 vassert(addToSp == 0); 3850 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret)); 3851 3852 return; 3853 } 3854 break; 3855 } 3856 3857 case Ist_CAS: 3858 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) { 3859 IRCAS *cas = stmt->Ist.CAS.details; 3860 s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr); 3861 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */ 3862 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */ 3863 HReg old = lookupIRTemp(env, cas->oldLo); 3864 3865 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) { 3866 addInstr(env, s390_insn_cas(4, op1, op2, op3, old)); 3867 } else { 3868 addInstr(env, s390_insn_cas(8, op1, op2, op3, old)); 3869 } 3870 return; 3871 } else { 3872 IRCAS *cas = stmt->Ist.CAS.details; 3873 s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr); 3874 HReg r8, r9, r10, r11, r1; 3875 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */ 3876 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */ 3877 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */ 3878 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */ 3879 HReg old_low = lookupIRTemp(env, cas->oldLo); 3880 HReg old_high = lookupIRTemp(env, cas->oldHi); 3881 3882 /* Use non-virtual registers r8 and r9 as pair for op1 3883 and move op1 there */ 3884 r8 = make_gpr(8); 3885 r9 = make_gpr(9); 3886 addInstr(env, s390_insn_move(8, r8, op1_high)); 3887 addInstr(env, s390_insn_move(8, r9, op1_low)); 3888 3889 /* Use non-virtual registers r10 and r11 as pair for op3 3890 and move op3 there */ 3891 r10 = make_gpr(10); 3892 r11 = make_gpr(11); 3893 addInstr(env, s390_insn_move(8, r10, op3_high)); 3894 addInstr(env, s390_insn_move(8, r11, op3_low)); 3895 3896 /* Register r1 is used as a scratch register */ 3897 r1 = make_gpr(1); 3898 3899 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) { 3900 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11, 3901 old_high, old_low, r1)); 3902 } else { 3903 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11, 3904 old_high, old_low, r1)); 3905 } 3906 addInstr(env, s390_insn_move(8, op1_high, r8)); 3907 addInstr(env, s390_insn_move(8, op1_low, r9)); 3908 addInstr(env, s390_insn_move(8, op3_high, r10)); 3909 addInstr(env, s390_insn_move(8, op3_low, r11)); 3910 return; 3911 } 3912 break; 3913 3914 /* --------- EXIT --------- */ 3915 case Ist_Exit: { 3916 s390_cc_t cond; 3917 IRConstTag tag = stmt->Ist.Exit.dst->tag; 3918 3919 if (tag != Ico_U64) 3920 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value"); 3921 3922 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP); 3923 cond = s390_isel_cc(env, stmt->Ist.Exit.guard); 3924 3925 /* Case: boring transfer to known address */ 3926 if (stmt->Ist.Exit.jk == Ijk_Boring) { 3927 if (env->chaining_allowed) { 3928 /* .. almost always true .. */ 3929 /* Skip the event check at the dst if this is a forwards 3930 edge. */ 3931 Bool to_fast_entry 3932 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga; 3933 if (0) vex_printf("%s", to_fast_entry ? "Y" : ","); 3934 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64, 3935 guest_IA, to_fast_entry)); 3936 } else { 3937 /* .. very occasionally .. */ 3938 /* We can't use chaining, so ask for an assisted transfer, 3939 as that's the only alternative that is allowable. */ 3940 HReg dst = s390_isel_int_expr(env, 3941 IRExpr_Const(stmt->Ist.Exit.dst)); 3942 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring)); 3943 } 3944 return; 3945 } 3946 3947 /* Case: assisted transfer to arbitrary address */ 3948 switch (stmt->Ist.Exit.jk) { 3949 case Ijk_EmFail: 3950 case Ijk_EmWarn: 3951 case Ijk_NoDecode: 3952 case Ijk_InvalICache: 3953 case Ijk_Sys_syscall: 3954 case Ijk_ClientReq: 3955 case Ijk_NoRedir: 3956 case Ijk_Yield: 3957 case Ijk_SigTRAP: { 3958 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst)); 3959 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, 3960 stmt->Ist.Exit.jk)); 3961 return; 3962 } 3963 default: 3964 break; 3965 } 3966 3967 /* Do we ever expect to see any other kind? */ 3968 goto stmt_fail; 3969 } 3970 3971 /* --------- MEM FENCE --------- */ 3972 case Ist_MBE: 3973 switch (stmt->Ist.MBE.event) { 3974 case Imbe_Fence: 3975 addInstr(env, s390_insn_mfence()); 3976 return; 3977 default: 3978 break; 3979 } 3980 break; 3981 3982 /* --------- Miscellaneous --------- */ 3983 3984 case Ist_PutI: /* Not needed */ 3985 case Ist_IMark: /* Doesn't generate any executable code */ 3986 case Ist_NoOp: /* Doesn't generate any executable code */ 3987 case Ist_AbiHint: /* Meaningless in IR */ 3988 return; 3989 3990 default: 3991 break; 3992 } 3993 3994 stmt_fail: 3995 ppIRStmt(stmt); 3996 vpanic("s390_isel_stmt"); 3997 } 3998 3999 4000 /*---------------------------------------------------------*/ 4001 /*--- ISEL: Basic block terminators (Nexts) ---*/ 4002 /*---------------------------------------------------------*/ 4003 4004 static void 4005 iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP) 4006 { 4007 if (vex_traceflags & VEX_TRACE_VCODE) { 4008 vex_printf("\n-- PUT(%d) = ", offsIP); 4009 ppIRExpr(next); 4010 vex_printf("; exit-"); 4011 ppIRJumpKind(jk); 4012 vex_printf("\n"); 4013 } 4014 4015 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP); 4016 4017 /* Case: boring transfer to known address */ 4018 if (next->tag == Iex_Const) { 4019 IRConst *cdst = next->Iex.Const.con; 4020 vassert(cdst->tag == Ico_U64); 4021 if (jk == Ijk_Boring || jk == Ijk_Call) { 4022 /* Boring transfer to known address */ 4023 if (env->chaining_allowed) { 4024 /* .. almost always true .. */ 4025 /* Skip the event check at the dst if this is a forwards 4026 edge. */ 4027 Bool to_fast_entry 4028 = ((Addr64)cdst->Ico.U64) > env->max_ga; 4029 if (0) vex_printf("%s", to_fast_entry ? "X" : "."); 4030 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64, 4031 guest_IA, to_fast_entry)); 4032 } else { 4033 /* .. very occasionally .. */ 4034 /* We can't use chaining, so ask for an indirect transfer, 4035 as that's the cheapest alternative that is allowable. */ 4036 HReg dst = s390_isel_int_expr(env, next); 4037 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, 4038 Ijk_Boring)); 4039 } 4040 return; 4041 } 4042 } 4043 4044 /* Case: call/return (==boring) transfer to any address */ 4045 switch (jk) { 4046 case Ijk_Boring: 4047 case Ijk_Ret: 4048 case Ijk_Call: { 4049 HReg dst = s390_isel_int_expr(env, next); 4050 if (env->chaining_allowed) { 4051 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA)); 4052 } else { 4053 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, 4054 Ijk_Boring)); 4055 } 4056 return; 4057 } 4058 default: 4059 break; 4060 } 4061 4062 /* Case: some other kind of transfer to any address */ 4063 switch (jk) { 4064 case Ijk_EmFail: 4065 case Ijk_EmWarn: 4066 case Ijk_NoDecode: 4067 case Ijk_InvalICache: 4068 case Ijk_Sys_syscall: 4069 case Ijk_ClientReq: 4070 case Ijk_NoRedir: 4071 case Ijk_Yield: 4072 case Ijk_SigTRAP: { 4073 HReg dst = s390_isel_int_expr(env, next); 4074 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk)); 4075 return; 4076 } 4077 default: 4078 break; 4079 } 4080 4081 vpanic("iselNext"); 4082 } 4083 4084 4085 /*---------------------------------------------------------*/ 4086 /*--- Insn selector top-level ---*/ 4087 /*---------------------------------------------------------*/ 4088 4089 /* Translate an entire SB to s390 code. 4090 Note: archinfo_host is a pointer to a stack-allocated variable. 4091 Do not assign it to a global variable! */ 4092 4093 HInstrArray * 4094 iselSB_S390(const IRSB *bb, VexArch arch_host, const VexArchInfo *archinfo_host, 4095 const VexAbiInfo *vbi, Int offset_host_evcheck_counter, 4096 Int offset_host_evcheck_fail_addr, Bool chaining_allowed, 4097 Bool add_profinc, Addr max_ga) 4098 { 4099 UInt i, j; 4100 HReg hreg, hregHI; 4101 ISelEnv *env; 4102 UInt hwcaps_host = archinfo_host->hwcaps; 4103 4104 /* Do some sanity checks */ 4105 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0); 4106 4107 /* Check that the host's endianness is as expected. */ 4108 vassert(archinfo_host->endness == VexEndnessBE); 4109 4110 /* Make up an initial environment to use. */ 4111 env = LibVEX_Alloc_inline(sizeof(ISelEnv)); 4112 env->vreg_ctr = 0; 4113 4114 /* Set up output code array. */ 4115 env->code = newHInstrArray(); 4116 4117 /* Copy BB's type env. */ 4118 env->type_env = bb->tyenv; 4119 4120 /* Set up data structures for tracking guest register values. */ 4121 for (i = 0; i < NUM_TRACKED_REGS; ++i) { 4122 env->old_value[i] = 0; /* just something to have a defined value */ 4123 env->old_value_valid[i] = False; 4124 } 4125 4126 /* Make up an IRTemp -> virtual HReg mapping. This doesn't 4127 change as we go along. For some reason types_used has Int type -- but 4128 it should be unsigned. Internally we use an unsigned type; so we 4129 assert it here. */ 4130 vassert(bb->tyenv->types_used >= 0); 4131 4132 env->n_vregmap = bb->tyenv->types_used; 4133 env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 4134 env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 4135 4136 env->previous_bfp_rounding_mode = NULL; 4137 env->previous_dfp_rounding_mode = NULL; 4138 4139 /* and finally ... */ 4140 env->hwcaps = hwcaps_host; 4141 4142 env->max_ga = max_ga; 4143 env->chaining_allowed = chaining_allowed; 4144 4145 /* For each IR temporary, allocate a suitably-kinded virtual 4146 register. */ 4147 j = 0; 4148 for (i = 0; i < env->n_vregmap; i++) { 4149 hregHI = hreg = INVALID_HREG; 4150 switch (bb->tyenv->types[i]) { 4151 case Ity_I1: 4152 case Ity_I8: 4153 case Ity_I16: 4154 case Ity_I32: 4155 case Ity_I64: 4156 hreg = mkVRegI(j++); 4157 break; 4158 4159 case Ity_I128: 4160 hreg = mkVRegI(j++); 4161 hregHI = mkVRegI(j++); 4162 break; 4163 4164 case Ity_F32: 4165 case Ity_F64: 4166 case Ity_D32: 4167 case Ity_D64: 4168 hreg = mkVRegF(j++); 4169 break; 4170 4171 case Ity_F128: 4172 case Ity_D128: 4173 hreg = mkVRegF(j++); 4174 hregHI = mkVRegF(j++); 4175 break; 4176 4177 case Ity_V128: /* fall through */ 4178 default: 4179 ppIRType(bb->tyenv->types[i]); 4180 vpanic("iselSB_S390: IRTemp type"); 4181 } 4182 4183 env->vregmap[i] = hreg; 4184 env->vregmapHI[i] = hregHI; 4185 } 4186 env->vreg_ctr = j; 4187 4188 /* The very first instruction must be an event check. */ 4189 s390_amode *counter, *fail_addr; 4190 counter = s390_amode_for_guest_state(offset_host_evcheck_counter); 4191 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr); 4192 addInstr(env, s390_insn_evcheck(counter, fail_addr)); 4193 4194 /* Possibly a block counter increment (for profiling). At this 4195 point we don't know the address of the counter, so just pretend 4196 it is zero. It will have to be patched later, but before this 4197 translation is used, by a call to LibVEX_patchProfInc. */ 4198 if (add_profinc) { 4199 addInstr(env, s390_insn_profinc()); 4200 } 4201 4202 /* Ok, finally we can iterate over the statements. */ 4203 for (i = 0; i < bb->stmts_used; i++) 4204 if (bb->stmts[i]) 4205 s390_isel_stmt(env, bb->stmts[i]); 4206 4207 iselNext(env, bb->next, bb->jumpkind, bb->offsIP); 4208 4209 /* Record the number of vregs we used. */ 4210 env->code->n_vregs = env->vreg_ctr; 4211 4212 return env->code; 4213 } 4214 4215 /*---------------------------------------------------------------*/ 4216 /*--- end host_s390_isel.c ---*/ 4217 /*---------------------------------------------------------------*/ 4218