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