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-2012 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of the 16 License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 along with this program; if not, write to the Free Software 25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 26 02110-1301, USA. 27 28 The GNU General Public License is contained in the file COPYING. 29 */ 30 31 /* Contributed by Florian Krohm */ 32 33 #include "libvex_basictypes.h" 34 #include "libvex_ir.h" 35 #include "libvex.h" 36 #include "libvex_s390x_common.h" 37 38 #include "main_util.h" 39 #include "main_globals.h" 40 #include "guest_s390_defs.h" /* guest_s390x_state_requires_precise_mem_exns */ 41 #include "host_generic_regs.h" 42 #include "host_s390_defs.h" 43 44 /*---------------------------------------------------------*/ 45 /*--- ISelEnv ---*/ 46 /*---------------------------------------------------------*/ 47 48 /* This carries around: 49 50 - A mapping from IRTemp to IRType, giving the type of any IRTemp we 51 might encounter. This is computed before insn selection starts, 52 and does not change. 53 54 - A mapping from IRTemp to HReg. This tells the insn selector 55 which virtual register(s) are associated with each IRTemp 56 temporary. This is computed before insn selection starts, and 57 does not change. We expect this mapping to map precisely the 58 same set of IRTemps as the type mapping does. 59 60 - vregmap holds the primary register for the IRTemp. 61 - vregmapHI holds the secondary register for the IRTemp, 62 if any is needed. That's only for Ity_I64 temps 63 in 32 bit mode or Ity_I128 temps in 64-bit mode. 64 65 - The code array, that is, the insns selected so far. 66 67 - A counter, for generating new virtual registers. 68 69 - The host subarchitecture we are selecting insns for. 70 This is set at the start and does not change. 71 72 - A Bool for indicating whether we may generate chain-me 73 instructions for control flow transfers, or whether we must use 74 XAssisted. 75 76 - The maximum guest address of any guest insn in this block. 77 Actually, the address of the highest-addressed byte from any insn 78 in this block. Is set at the start and does not change. This is 79 used for detecting jumps which are definitely forward-edges from 80 this block, and therefore can be made (chained) to the fast entry 81 point of the destination, thereby avoiding the destination's 82 event check. 83 84 - A flag to indicate whether the guest IA has been assigned to. 85 86 - Values of certain guest registers which are often assigned constants. 87 */ 88 89 /* Symbolic names for guest registers whose value we're tracking */ 90 enum { 91 GUEST_IA, 92 GUEST_CC_OP, 93 GUEST_CC_DEP1, 94 GUEST_CC_DEP2, 95 GUEST_CC_NDEP, 96 GUEST_SYSNO, 97 GUEST_COUNTER, 98 GUEST_UNKNOWN /* must be the last entry */ 99 }; 100 101 /* Number of registers we're tracking. */ 102 #define NUM_TRACKED_REGS GUEST_UNKNOWN 103 104 105 typedef struct { 106 IRTypeEnv *type_env; 107 108 HInstrArray *code; 109 HReg *vregmap; 110 HReg *vregmapHI; 111 UInt n_vregmap; 112 UInt vreg_ctr; 113 UInt hwcaps; 114 115 ULong old_value[NUM_TRACKED_REGS]; 116 117 /* The next two are for translation chaining */ 118 Addr64 max_ga; 119 Bool chaining_allowed; 120 121 Bool first_IA_assignment; 122 Bool old_value_valid[NUM_TRACKED_REGS]; 123 } ISelEnv; 124 125 126 /* Forward declarations */ 127 static HReg s390_isel_int_expr(ISelEnv *, IRExpr *); 128 static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *); 129 static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *); 130 static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *); 131 static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *); 132 static HReg s390_isel_float_expr(ISelEnv *, IRExpr *); 133 static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *); 134 135 136 static Int 137 get_guest_reg(Int offset) 138 { 139 switch (offset) { 140 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA; 141 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP; 142 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1; 143 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2; 144 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP; 145 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO; 146 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER; 147 148 /* Also make sure there is never a partial write to one of 149 these registers. That would complicate matters. */ 150 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7: 151 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7: 152 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7: 153 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7: 154 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7: 155 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7: 156 /* counter is used both as 4-byte and as 8-byte entity */ 157 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3: 158 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7: 159 vpanic("partial update of this guest state register is not allowed"); 160 break; 161 162 default: break; 163 } 164 165 return GUEST_UNKNOWN; 166 } 167 168 /* Add an instruction */ 169 static void 170 addInstr(ISelEnv *env, s390_insn *insn) 171 { 172 addHInstr(env->code, insn); 173 174 if (vex_traceflags & VEX_TRACE_VCODE) { 175 vex_printf("%s\n", s390_insn_as_string(insn)); 176 } 177 } 178 179 180 static __inline__ IRExpr * 181 mkU64(ULong value) 182 { 183 return IRExpr_Const(IRConst_U64(value)); 184 } 185 186 187 /*---------------------------------------------------------*/ 188 /*--- Registers ---*/ 189 /*---------------------------------------------------------*/ 190 191 /* Return the virtual register to which a given IRTemp is mapped. */ 192 static HReg 193 lookupIRTemp(ISelEnv *env, IRTemp tmp) 194 { 195 vassert(tmp < env->n_vregmap); 196 vassert(env->vregmap[tmp] != INVALID_HREG); 197 198 return env->vregmap[tmp]; 199 } 200 201 202 /* Return the two virtual registers to which the IRTemp is mapped. */ 203 static void 204 lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp) 205 { 206 vassert(tmp < env->n_vregmap); 207 vassert(env->vregmapHI[tmp] != INVALID_HREG); 208 209 *lo = env->vregmap[tmp]; 210 *hi = env->vregmapHI[tmp]; 211 } 212 213 214 /* Allocate a new integer register */ 215 static HReg 216 newVRegI(ISelEnv *env) 217 { 218 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ ); 219 env->vreg_ctr++; 220 221 return reg; 222 } 223 224 225 /* Allocate a new floating point register */ 226 static HReg 227 newVRegF(ISelEnv *env) 228 { 229 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ ); 230 231 env->vreg_ctr++; 232 233 return reg; 234 } 235 236 237 /* Construct a non-virtual general purpose register */ 238 static __inline__ HReg 239 make_gpr(UInt regno) 240 { 241 return mkHReg(regno, HRcInt64, False /* virtual */ ); 242 } 243 244 245 /* Construct a non-virtual floating point register */ 246 static __inline__ HReg 247 make_fpr(UInt regno) 248 { 249 return mkHReg(regno, HRcFlt64, False /* virtual */ ); 250 } 251 252 253 /*---------------------------------------------------------*/ 254 /*--- Amode ---*/ 255 /*---------------------------------------------------------*/ 256 257 static __inline__ Bool 258 ulong_fits_unsigned_12bit(ULong val) 259 { 260 return (val & 0xFFFu) == val; 261 } 262 263 264 static __inline__ Bool 265 ulong_fits_signed_20bit(ULong val) 266 { 267 Long v = val & 0xFFFFFu; 268 269 v = (v << 44) >> 44; /* sign extend */ 270 271 return val == (ULong)v; 272 } 273 274 275 static __inline__ Bool 276 ulong_fits_signed_8bit(ULong val) 277 { 278 Long v = val & 0xFFu; 279 280 v = (v << 56) >> 56; /* sign extend */ 281 282 return val == (ULong)v; 283 } 284 285 /* EXPR is an expression that is used as an address. Return an s390_amode 286 for it. */ 287 static s390_amode * 288 s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr) 289 { 290 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) { 291 IRExpr *arg1 = expr->Iex.Binop.arg1; 292 IRExpr *arg2 = expr->Iex.Binop.arg2; 293 294 /* Move constant into right subtree */ 295 if (arg1->tag == Iex_Const) { 296 IRExpr *tmp; 297 tmp = arg1; 298 arg1 = arg2; 299 arg2 = tmp; 300 } 301 302 /* r + constant: Check for b12 first, then b20 */ 303 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) { 304 ULong value = arg2->Iex.Const.con->Ico.U64; 305 306 if (ulong_fits_unsigned_12bit(value)) { 307 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1)); 308 } 309 /* If long-displacement is not available, do not construct B20 or 310 BX20 amodes because code generation cannot handle them. */ 311 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) { 312 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1)); 313 } 314 } 315 } 316 317 /* Doesn't match anything in particular. Generate it into 318 a register and use that. */ 319 return s390_amode_b12(0, s390_isel_int_expr(env, expr)); 320 } 321 322 323 static s390_amode * 324 s390_isel_amode(ISelEnv *env, IRExpr *expr) 325 { 326 s390_amode *am; 327 328 /* Address computation should yield a 64-bit value */ 329 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64); 330 331 am = s390_isel_amode_wrk(env, expr); 332 333 /* Check post-condition */ 334 vassert(s390_amode_is_sane(am)); 335 336 return am; 337 } 338 339 340 /*---------------------------------------------------------*/ 341 /*--- Helper functions ---*/ 342 /*---------------------------------------------------------*/ 343 344 /* Constants and memory accesses should be right operands */ 345 #define order_commutative_operands(left, right) \ 346 do { \ 347 if (left->tag == Iex_Const || left->tag == Iex_Load || \ 348 left->tag == Iex_Get) { \ 349 IRExpr *tmp; \ 350 tmp = left; \ 351 left = right; \ 352 right = tmp; \ 353 } \ 354 } while (0) 355 356 357 /* Copy an RMI operand to the DST register */ 358 static s390_insn * 359 s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd) 360 { 361 switch (opnd.tag) { 362 case S390_OPND_AMODE: 363 return s390_insn_load(size, dst, opnd.variant.am); 364 365 case S390_OPND_REG: 366 return s390_insn_move(size, dst, opnd.variant.reg); 367 368 case S390_OPND_IMMEDIATE: 369 return s390_insn_load_immediate(size, dst, opnd.variant.imm); 370 371 default: 372 vpanic("s390_opnd_copy"); 373 } 374 } 375 376 377 /* Construct a RMI operand for a register */ 378 static __inline__ s390_opnd_RMI 379 s390_opnd_reg(HReg reg) 380 { 381 s390_opnd_RMI opnd; 382 383 opnd.tag = S390_OPND_REG; 384 opnd.variant.reg = reg; 385 386 return opnd; 387 } 388 389 390 /* Construct a RMI operand for an immediate constant */ 391 static __inline__ s390_opnd_RMI 392 s390_opnd_imm(ULong value) 393 { 394 s390_opnd_RMI opnd; 395 396 opnd.tag = S390_OPND_IMMEDIATE; 397 opnd.variant.imm = value; 398 399 return opnd; 400 } 401 402 403 /* Return 1, if EXPR represents the cosntant 0 */ 404 static int 405 s390_expr_is_const_zero(IRExpr *expr) 406 { 407 ULong value; 408 409 if (expr->tag == Iex_Const) { 410 switch (expr->Iex.Const.con->tag) { 411 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break; 412 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break; 413 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break; 414 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break; 415 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break; 416 default: 417 vpanic("s390_expr_is_const_zero"); 418 } 419 return value == 0; 420 } 421 422 return 0; 423 } 424 425 426 /* Call a helper (clean or dirty) 427 Arguments must satisfy the following conditions: 428 429 (a) they are expressions yielding an integer result 430 (b) there can be no more than S390_NUM_GPRPARMS arguments 431 432 guard is a Ity_Bit expression indicating whether or not the 433 call happens. If guard == NULL, the call is unconditional. 434 435 Calling the helper function proceeds as follows: 436 437 (1) The helper arguments are evaluated and their value stored in 438 virtual registers. 439 (2) The condition code is evaluated 440 (3) The argument values are copied from the virtual registers to the 441 registers mandated by the ABI. 442 (4) Call the helper function. 443 444 This is not the most efficient way as step 3 generates register-to-register 445 moves. But it is the least fragile way as the only hidden dependency here 446 is that register-to-register moves (step 3) must not clobber the condition 447 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register- 448 to-register add more such dependencies. Not good. Besides, it's the job 449 of the register allocator to throw out those reg-to-reg moves. 450 */ 451 static void 452 doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard, 453 IRCallee *callee, IRExpr **args, HReg dst) 454 { 455 UInt n_args, i, argreg, size; 456 ULong target; 457 HReg tmpregs[S390_NUM_GPRPARMS]; 458 s390_cc_t cc; 459 460 n_args = 0; 461 for (i = 0; args[i]; i++) 462 ++n_args; 463 464 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) { 465 vpanic("doHelperCall: too many arguments"); 466 } 467 468 /* All arguments must have Ity_I64. For two reasons: 469 (1) We do not handle floating point arguments. 470 (2) The ABI requires that integer values are sign- or zero-extended 471 to 64 bit. 472 */ 473 Int arg_errors = 0; 474 for (i = 0; i < n_args; ++i) { 475 IRType type = typeOfIRExpr(env->type_env, args[i]); 476 if (type != Ity_I64) { 477 ++arg_errors; 478 vex_printf("calling %s: argument #%d has type ", callee->name, i); 479 ppIRType(type); 480 vex_printf("; Ity_I64 is required\n"); 481 } 482 } 483 484 if (arg_errors) 485 vpanic("cannot continue due to errors in argument passing"); 486 487 argreg = 0; 488 489 /* If we need the guest state pointer put it in a temporary arg reg */ 490 if (passBBP) { 491 tmpregs[argreg] = newVRegI(env); 492 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg], 493 s390_hreg_guest_state_pointer())); 494 argreg++; 495 } 496 497 /* Compute the function arguments into a temporary register each */ 498 for (i = 0; i < n_args; i++) { 499 tmpregs[argreg] = s390_isel_int_expr(env, args[i]); 500 argreg++; 501 } 502 503 /* Compute the condition */ 504 cc = S390_CC_ALWAYS; 505 if (guard) { 506 if (guard->tag == Iex_Const 507 && guard->Iex.Const.con->tag == Ico_U1 508 && guard->Iex.Const.con->Ico.U1 == True) { 509 /* unconditional -- do nothing */ 510 } else { 511 cc = s390_isel_cc(env, guard); 512 } 513 } 514 515 /* Move the args to the final register. It is paramount, that the 516 code to move the registers does not clobber the condition code ! */ 517 for (i = 0; i < argreg; i++) { 518 HReg finalreg; 519 520 finalreg = make_gpr(s390_gprno_from_arg_index(i)); 521 size = sizeofIRType(Ity_I64); 522 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i])); 523 } 524 525 target = Ptr_to_ULong(callee->addr); 526 527 /* Finally, the call itself. */ 528 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args, 529 callee->name, dst)); 530 } 531 532 533 /* Given an expression representing a rounding mode using IRRoundingMode 534 encoding convert it to an s390_round_t value. */ 535 static s390_round_t 536 decode_rounding_mode(IRExpr *rounding_expr) 537 { 538 if (rounding_expr->tag == Iex_Const && 539 rounding_expr->Iex.Const.con->tag == Ico_U32) { 540 IRRoundingMode mode = rounding_expr->Iex.Const.con->Ico.U32; 541 542 switch (mode) { 543 case Irrm_NEAREST: return S390_ROUND_NEAREST_EVEN; 544 case Irrm_ZERO: return S390_ROUND_ZERO; 545 case Irrm_PosINF: return S390_ROUND_POSINF; 546 case Irrm_NegINF: return S390_ROUND_NEGINF; 547 } 548 } 549 550 vpanic("decode_rounding_mode"); 551 } 552 553 554 /* CC_S390 holds the condition code in s390 encoding. Convert it to 555 VEX encoding 556 557 s390 VEX b6 b2 b0 cc.1 cc.0 558 0 0x40 EQ 1 0 0 0 0 559 1 0x01 LT 0 0 1 0 1 560 2 0x00 GT 0 0 0 1 0 561 3 0x45 Unordered 1 1 1 1 1 562 563 b0 = cc.0 564 b2 = cc.0 & cc.1 565 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1 566 567 VEX = b0 | (b2 << 2) | (b6 << 6); 568 */ 569 static HReg 570 convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390) 571 { 572 HReg cc0, cc1, b2, b6, cc_vex; 573 574 cc0 = newVRegI(env); 575 addInstr(env, s390_insn_move(4, cc0, cc_s390)); 576 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1))); 577 578 cc1 = newVRegI(env); 579 addInstr(env, s390_insn_move(4, cc1, cc_s390)); 580 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1))); 581 582 b2 = newVRegI(env); 583 addInstr(env, s390_insn_move(4, b2, cc0)); 584 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1))); 585 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2))); 586 587 b6 = newVRegI(env); 588 addInstr(env, s390_insn_move(4, b6, cc0)); 589 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1))); 590 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1))); 591 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1))); 592 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6))); 593 594 cc_vex = newVRegI(env); 595 addInstr(env, s390_insn_move(4, cc_vex, cc0)); 596 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2))); 597 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6))); 598 599 return cc_vex; 600 } 601 602 603 /*---------------------------------------------------------*/ 604 /*--- ISEL: Integer expressions (128 bit) ---*/ 605 /*---------------------------------------------------------*/ 606 static void 607 s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 608 IRExpr *expr) 609 { 610 IRType ty = typeOfIRExpr(env->type_env, expr); 611 612 vassert(ty == Ity_I128); 613 614 /* No need to consider the following 615 - 128-bit constants (they do not exist in VEX) 616 - 128-bit loads from memory (will not be generated) 617 */ 618 619 /* Read 128-bit IRTemp */ 620 if (expr->tag == Iex_RdTmp) { 621 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp); 622 return; 623 } 624 625 if (expr->tag == Iex_Binop) { 626 IRExpr *arg1 = expr->Iex.Binop.arg1; 627 IRExpr *arg2 = expr->Iex.Binop.arg2; 628 Bool is_signed_multiply, is_signed_divide; 629 630 switch (expr->Iex.Binop.op) { 631 case Iop_MullU64: 632 is_signed_multiply = False; 633 goto do_multiply64; 634 635 case Iop_MullS64: 636 is_signed_multiply = True; 637 goto do_multiply64; 638 639 case Iop_DivModU128to64: 640 is_signed_divide = False; 641 goto do_divide64; 642 643 case Iop_DivModS128to64: 644 is_signed_divide = True; 645 goto do_divide64; 646 647 case Iop_64HLto128: 648 *dst_hi = s390_isel_int_expr(env, arg1); 649 *dst_lo = s390_isel_int_expr(env, arg2); 650 return; 651 652 case Iop_DivModS64to64: { 653 HReg r10, r11, h1; 654 s390_opnd_RMI op2; 655 656 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 657 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 658 659 /* We use non-virtual registers r10 and r11 as pair */ 660 r10 = make_gpr(10); 661 r11 = make_gpr(11); 662 663 /* Move 1st operand into r11 and */ 664 addInstr(env, s390_insn_move(8, r11, h1)); 665 666 /* Divide */ 667 addInstr(env, s390_insn_divs(8, r10, r11, op2)); 668 669 /* The result is in registers r10 (remainder) and r11 (quotient). 670 Move the result into the reg pair that is being returned such 671 such that the low 64 bits are the quotient and the upper 64 bits 672 are the remainder. (see libvex_ir.h). */ 673 *dst_hi = newVRegI(env); 674 *dst_lo = newVRegI(env); 675 addInstr(env, s390_insn_move(8, *dst_hi, r10)); 676 addInstr(env, s390_insn_move(8, *dst_lo, r11)); 677 return; 678 } 679 680 default: 681 break; 682 683 do_multiply64: { 684 HReg r10, r11, h1; 685 s390_opnd_RMI op2; 686 687 order_commutative_operands(arg1, arg2); 688 689 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 690 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 691 692 /* We use non-virtual registers r10 and r11 as pair */ 693 r10 = make_gpr(10); 694 r11 = make_gpr(11); 695 696 /* Move the first operand to r11 */ 697 addInstr(env, s390_insn_move(8, r11, h1)); 698 699 /* Multiply */ 700 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply)); 701 702 /* The result is in registers r10 and r11. Assign to two virtual regs 703 and return. */ 704 *dst_hi = newVRegI(env); 705 *dst_lo = newVRegI(env); 706 addInstr(env, s390_insn_move(8, *dst_hi, r10)); 707 addInstr(env, s390_insn_move(8, *dst_lo, r11)); 708 return; 709 } 710 711 do_divide64: { 712 HReg r10, r11, hi, lo; 713 s390_opnd_RMI op2; 714 715 s390_isel_int128_expr(&hi, &lo, env, arg1); 716 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 717 718 /* We use non-virtual registers r10 and r11 as pair */ 719 r10 = make_gpr(10); 720 r11 = make_gpr(11); 721 722 /* Move high 64 bits of the 1st operand into r10 and 723 the low 64 bits into r11. */ 724 addInstr(env, s390_insn_move(8, r10, hi)); 725 addInstr(env, s390_insn_move(8, r11, lo)); 726 727 /* Divide */ 728 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide)); 729 730 /* The result is in registers r10 (remainder) and r11 (quotient). 731 Move the result into the reg pair that is being returned such 732 such that the low 64 bits are the quotient and the upper 64 bits 733 are the remainder. (see libvex_ir.h). */ 734 *dst_hi = newVRegI(env); 735 *dst_lo = newVRegI(env); 736 addInstr(env, s390_insn_move(8, *dst_hi, r10)); 737 addInstr(env, s390_insn_move(8, *dst_lo, r11)); 738 return; 739 } 740 } 741 } 742 743 vpanic("s390_isel_int128_expr"); 744 } 745 746 747 /* Compute a 128-bit value into two 64-bit registers. These may be either 748 real or virtual regs; in any case they must not be changed by subsequent 749 code emitted by the caller. */ 750 static void 751 s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr) 752 { 753 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr); 754 755 /* Sanity checks ... */ 756 vassert(hregIsVirtual(*dst_hi)); 757 vassert(hregIsVirtual(*dst_lo)); 758 vassert(hregClass(*dst_hi) == HRcInt64); 759 vassert(hregClass(*dst_lo) == HRcInt64); 760 } 761 762 763 /*---------------------------------------------------------*/ 764 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/ 765 /*---------------------------------------------------------*/ 766 767 /* Select insns for an integer-typed expression, and add them to the 768 code list. Return a reg holding the result. This reg will be a 769 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you 770 want to modify it, ask for a new vreg, copy it in there, and modify 771 the copy. The register allocator will do its best to map both 772 vregs to the same real register, so the copies will often disappear 773 later in the game. 774 775 This should handle expressions of 64, 32, 16 and 8-bit type. 776 All results are returned in a 64bit register. 777 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits 778 are arbitrary, so you should mask or sign extend partial values 779 if necessary. 780 */ 781 782 /* DO NOT CALL THIS DIRECTLY ! */ 783 static HReg 784 s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr) 785 { 786 IRType ty = typeOfIRExpr(env->type_env, expr); 787 UChar size; 788 s390_bfp_unop_t bfpop; 789 790 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64); 791 792 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */ 793 794 switch (expr->tag) { 795 796 /* --------- TEMP --------- */ 797 case Iex_RdTmp: 798 /* Return the virtual register that holds the temporary. */ 799 return lookupIRTemp(env, expr->Iex.RdTmp.tmp); 800 801 /* --------- LOAD --------- */ 802 case Iex_Load: { 803 HReg dst = newVRegI(env); 804 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr); 805 806 if (expr->Iex.Load.end != Iend_BE) 807 goto irreducible; 808 809 addInstr(env, s390_insn_load(size, dst, am)); 810 811 return dst; 812 } 813 814 /* --------- BINARY OP --------- */ 815 case Iex_Binop: { 816 IRExpr *arg1 = expr->Iex.Binop.arg1; 817 IRExpr *arg2 = expr->Iex.Binop.arg2; 818 HReg h1, res; 819 s390_alu_t opkind; 820 s390_opnd_RMI op2, value, opnd; 821 s390_insn *insn; 822 Bool is_commutative, is_signed_multiply, is_signed_divide; 823 824 is_commutative = True; 825 826 switch (expr->Iex.Binop.op) { 827 case Iop_MullU8: 828 case Iop_MullU16: 829 case Iop_MullU32: 830 is_signed_multiply = False; 831 goto do_multiply; 832 833 case Iop_MullS8: 834 case Iop_MullS16: 835 case Iop_MullS32: 836 is_signed_multiply = True; 837 goto do_multiply; 838 839 do_multiply: { 840 HReg r10, r11; 841 UInt arg_size = size / 2; 842 843 order_commutative_operands(arg1, arg2); 844 845 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 846 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 847 848 /* We use non-virtual registers r10 and r11 as pair */ 849 r10 = make_gpr(10); 850 r11 = make_gpr(11); 851 852 /* Move the first operand to r11 */ 853 addInstr(env, s390_insn_move(arg_size, r11, h1)); 854 855 /* Multiply */ 856 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply)); 857 858 /* The result is in registers r10 and r11. Combine them into a SIZE-bit 859 value into the destination register. */ 860 res = newVRegI(env); 861 addInstr(env, s390_insn_move(arg_size, res, r10)); 862 value = s390_opnd_imm(arg_size * 8); 863 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value)); 864 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1); 865 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value)); 866 opnd = s390_opnd_reg(r11); 867 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd)); 868 return res; 869 } 870 871 case Iop_DivModS64to32: 872 is_signed_divide = True; 873 goto do_divide; 874 875 case Iop_DivModU64to32: 876 is_signed_divide = False; 877 goto do_divide; 878 879 do_divide: { 880 HReg r10, r11; 881 882 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 883 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 884 885 /* We use non-virtual registers r10 and r11 as pair */ 886 r10 = make_gpr(10); 887 r11 = make_gpr(11); 888 889 /* Split the first operand and put the high 32 bits into r10 and 890 the low 32 bits into r11. */ 891 addInstr(env, s390_insn_move(8, r10, h1)); 892 addInstr(env, s390_insn_move(8, r11, h1)); 893 value = s390_opnd_imm(32); 894 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value)); 895 896 /* Divide */ 897 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide)); 898 899 /* The result is in registers r10 (remainder) and r11 (quotient). 900 Combine them into a 64-bit value such that the low 32 bits are 901 the quotient and the upper 32 bits are the remainder. (see 902 libvex_ir.h). */ 903 res = newVRegI(env); 904 addInstr(env, s390_insn_move(8, res, r10)); 905 value = s390_opnd_imm(32); 906 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value)); 907 value = s390_opnd_imm((((ULong)1) << 32) - 1); 908 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value)); 909 opnd = s390_opnd_reg(r11); 910 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd)); 911 return res; 912 } 913 914 case Iop_F32toI32S: bfpop = S390_BFP_F32_TO_I32; goto do_convert; 915 case Iop_F32toI64S: bfpop = S390_BFP_F32_TO_I64; goto do_convert; 916 case Iop_F64toI32S: bfpop = S390_BFP_F64_TO_I32; goto do_convert; 917 case Iop_F64toI64S: bfpop = S390_BFP_F64_TO_I64; goto do_convert; 918 case Iop_F128toI32S: bfpop = S390_BFP_F128_TO_I32; goto do_convert_128; 919 case Iop_F128toI64S: bfpop = S390_BFP_F128_TO_I64; goto do_convert_128; 920 921 do_convert: { 922 s390_round_t rounding_mode; 923 924 res = newVRegI(env); 925 h1 = s390_isel_float_expr(env, arg2); /* Process operand */ 926 927 rounding_mode = decode_rounding_mode(arg1); 928 addInstr(env, s390_insn_bfp_unop(size, bfpop, res, h1, rounding_mode)); 929 return res; 930 } 931 932 do_convert_128: { 933 s390_round_t rounding_mode; 934 HReg op_hi, op_lo, f13, f15; 935 936 res = newVRegI(env); 937 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */ 938 939 /* We use non-virtual registers r13 and r15 as pair */ 940 f13 = make_fpr(13); 941 f15 = make_fpr(15); 942 943 /* operand --> (f13, f15) */ 944 addInstr(env, s390_insn_move(8, f13, op_hi)); 945 addInstr(env, s390_insn_move(8, f15, op_lo)); 946 947 rounding_mode = decode_rounding_mode(arg1); 948 addInstr(env, s390_insn_bfp128_convert_from(size, bfpop, res, f13, f15, 949 rounding_mode)); 950 return res; 951 } 952 953 case Iop_8HLto16: 954 case Iop_16HLto32: 955 case Iop_32HLto64: { 956 HReg h2; 957 UInt arg_size = size / 2; 958 959 res = newVRegI(env); 960 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 961 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */ 962 963 addInstr(env, s390_insn_move(arg_size, res, h1)); 964 value = s390_opnd_imm(arg_size * 8); 965 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value)); 966 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1); 967 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value)); 968 opnd = s390_opnd_reg(h2); 969 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd)); 970 return res; 971 } 972 973 case Iop_Max32U: { 974 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */ 975 res = newVRegI(env); 976 h1 = s390_isel_int_expr(env, arg1); 977 op2 = s390_isel_int_expr_RMI(env, arg2); 978 979 addInstr(env, s390_insn_move(size, res, h1)); 980 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */)); 981 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2)); 982 return res; 983 } 984 985 case Iop_CmpF32: 986 case Iop_CmpF64: { 987 HReg cc_s390, h2; 988 989 h1 = s390_isel_float_expr(env, arg1); 990 h2 = s390_isel_float_expr(env, arg2); 991 cc_s390 = newVRegI(env); 992 993 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8; 994 995 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2)); 996 997 return convert_s390_fpcc_to_vex(env, cc_s390); 998 } 999 1000 case Iop_CmpF128: { 1001 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390; 1002 1003 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */ 1004 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */ 1005 cc_s390 = newVRegI(env); 1006 1007 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 1008 f12 = make_fpr(12); 1009 f13 = make_fpr(13); 1010 f14 = make_fpr(14); 1011 f15 = make_fpr(15); 1012 1013 /* 1st operand --> (f12, f14) */ 1014 addInstr(env, s390_insn_move(8, f12, op1_hi)); 1015 addInstr(env, s390_insn_move(8, f14, op1_lo)); 1016 1017 /* 2nd operand --> (f13, f15) */ 1018 addInstr(env, s390_insn_move(8, f13, op2_hi)); 1019 addInstr(env, s390_insn_move(8, f15, op2_lo)); 1020 1021 res = newVRegI(env); 1022 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15)); 1023 1024 return convert_s390_fpcc_to_vex(env, cc_s390); 1025 } 1026 1027 case Iop_Add8: 1028 case Iop_Add16: 1029 case Iop_Add32: 1030 case Iop_Add64: 1031 opkind = S390_ALU_ADD; 1032 break; 1033 1034 case Iop_Sub8: 1035 case Iop_Sub16: 1036 case Iop_Sub32: 1037 case Iop_Sub64: 1038 opkind = S390_ALU_SUB; 1039 is_commutative = False; 1040 break; 1041 1042 case Iop_And8: 1043 case Iop_And16: 1044 case Iop_And32: 1045 case Iop_And64: 1046 opkind = S390_ALU_AND; 1047 break; 1048 1049 case Iop_Or8: 1050 case Iop_Or16: 1051 case Iop_Or32: 1052 case Iop_Or64: 1053 opkind = S390_ALU_OR; 1054 break; 1055 1056 case Iop_Xor8: 1057 case Iop_Xor16: 1058 case Iop_Xor32: 1059 case Iop_Xor64: 1060 opkind = S390_ALU_XOR; 1061 break; 1062 1063 case Iop_Shl8: 1064 case Iop_Shl16: 1065 case Iop_Shl32: 1066 case Iop_Shl64: 1067 opkind = S390_ALU_LSH; 1068 is_commutative = False; 1069 break; 1070 1071 case Iop_Shr8: 1072 case Iop_Shr16: 1073 case Iop_Shr32: 1074 case Iop_Shr64: 1075 opkind = S390_ALU_RSH; 1076 is_commutative = False; 1077 break; 1078 1079 case Iop_Sar8: 1080 case Iop_Sar16: 1081 case Iop_Sar32: 1082 case Iop_Sar64: 1083 opkind = S390_ALU_RSHA; 1084 is_commutative = False; 1085 break; 1086 1087 default: 1088 goto irreducible; 1089 } 1090 1091 /* Pattern match: 0 - arg1 --> -arg1 */ 1092 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) { 1093 res = newVRegI(env); 1094 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 1095 insn = s390_insn_unop(size, S390_NEGATE, res, op2); 1096 addInstr(env, insn); 1097 1098 return res; 1099 } 1100 1101 if (is_commutative) { 1102 order_commutative_operands(arg1, arg2); 1103 } 1104 1105 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */ 1106 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */ 1107 res = newVRegI(env); 1108 addInstr(env, s390_insn_move(size, res, h1)); 1109 insn = s390_insn_alu(size, opkind, res, op2); 1110 1111 addInstr(env, insn); 1112 1113 return res; 1114 } 1115 1116 /* --------- UNARY OP --------- */ 1117 case Iex_Unop: { 1118 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE }; 1119 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE }; 1120 s390_opnd_RMI opnd; 1121 s390_insn *insn; 1122 IRExpr *arg; 1123 HReg dst, h1; 1124 IROp unop, binop; 1125 1126 arg = expr->Iex.Unop.arg; 1127 1128 /* Special cases are handled here */ 1129 1130 /* 32-bit multiply with 32-bit result or 1131 64-bit multiply with 64-bit result */ 1132 unop = expr->Iex.Unop.op; 1133 binop = arg->Iex.Binop.op; 1134 1135 if ((arg->tag == Iex_Binop && 1136 ((unop == Iop_64to32 && 1137 (binop == Iop_MullS32 || binop == Iop_MullU32)) || 1138 (unop == Iop_128to64 && 1139 (binop == Iop_MullS64 || binop == Iop_MullU64))))) { 1140 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */ 1141 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */ 1142 dst = newVRegI(env); /* Result goes into a new register */ 1143 addInstr(env, s390_insn_move(size, dst, h1)); 1144 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd)); 1145 1146 return dst; 1147 } 1148 1149 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) { 1150 dst = newVRegI(env); 1151 h1 = s390_isel_float_expr(env, arg); /* Process the operand */ 1152 addInstr(env, s390_insn_move(size, dst, h1)); 1153 1154 return dst; 1155 } 1156 1157 /* Expressions whose argument is 1-bit wide */ 1158 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) { 1159 s390_cc_t cond = s390_isel_cc(env, arg); 1160 dst = newVRegI(env); /* Result goes into a new register */ 1161 addInstr(env, s390_insn_cc2bool(dst, cond)); 1162 1163 switch (unop) { 1164 case Iop_1Uto8: 1165 case Iop_1Uto32: 1166 /* Zero extend */ 1167 mask.variant.imm = 1; 1168 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask)); 1169 break; 1170 1171 case Iop_1Uto64: 1172 /* Zero extend */ 1173 mask.variant.imm = 1; 1174 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask)); 1175 break; 1176 1177 case Iop_1Sto8: 1178 case Iop_1Sto16: 1179 case Iop_1Sto32: 1180 shift.variant.imm = 31; 1181 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift)); 1182 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift)); 1183 break; 1184 1185 case Iop_1Sto64: 1186 shift.variant.imm = 63; 1187 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift)); 1188 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift)); 1189 break; 1190 1191 default: 1192 goto irreducible; 1193 } 1194 1195 return dst; 1196 } 1197 1198 /* Regular processing */ 1199 1200 if (unop == Iop_128to64) { 1201 HReg dst_hi, dst_lo; 1202 1203 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg); 1204 return dst_lo; 1205 } 1206 1207 if (unop == Iop_128HIto64) { 1208 HReg dst_hi, dst_lo; 1209 1210 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg); 1211 return dst_hi; 1212 } 1213 1214 dst = newVRegI(env); /* Result goes into a new register */ 1215 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */ 1216 1217 switch (unop) { 1218 case Iop_8Uto16: 1219 case Iop_8Uto32: 1220 case Iop_8Uto64: 1221 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd); 1222 break; 1223 1224 case Iop_16Uto32: 1225 case Iop_16Uto64: 1226 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd); 1227 break; 1228 1229 case Iop_32Uto64: 1230 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd); 1231 break; 1232 1233 case Iop_8Sto16: 1234 case Iop_8Sto32: 1235 case Iop_8Sto64: 1236 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd); 1237 break; 1238 1239 case Iop_16Sto32: 1240 case Iop_16Sto64: 1241 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd); 1242 break; 1243 1244 case Iop_32Sto64: 1245 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd); 1246 break; 1247 1248 case Iop_64to8: 1249 case Iop_64to16: 1250 case Iop_64to32: 1251 case Iop_32to8: 1252 case Iop_32to16: 1253 case Iop_16to8: 1254 /* Down-casts are no-ops. Upstream operations will only look at 1255 the bytes that make up the result of the down-cast. So there 1256 is no point setting the other bytes to 0. */ 1257 insn = s390_opnd_copy(8, dst, opnd); 1258 break; 1259 1260 case Iop_64HIto32: 1261 addInstr(env, s390_opnd_copy(8, dst, opnd)); 1262 shift.variant.imm = 32; 1263 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift); 1264 break; 1265 1266 case Iop_32HIto16: 1267 addInstr(env, s390_opnd_copy(4, dst, opnd)); 1268 shift.variant.imm = 16; 1269 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift); 1270 break; 1271 1272 case Iop_16HIto8: 1273 addInstr(env, s390_opnd_copy(2, dst, opnd)); 1274 shift.variant.imm = 8; 1275 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift); 1276 break; 1277 1278 case Iop_Not8: 1279 case Iop_Not16: 1280 case Iop_Not32: 1281 case Iop_Not64: 1282 /* XOR with ffff... */ 1283 mask.variant.imm = ~(ULong)0; 1284 addInstr(env, s390_opnd_copy(size, dst, opnd)); 1285 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask); 1286 break; 1287 1288 case Iop_Left8: 1289 case Iop_Left16: 1290 case Iop_Left32: 1291 case Iop_Left64: 1292 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd)); 1293 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd); 1294 break; 1295 1296 case Iop_CmpwNEZ32: 1297 case Iop_CmpwNEZ64: { 1298 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X 1299 or -X will have a 1 in the MSB. */ 1300 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd)); 1301 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd)); 1302 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63; 1303 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift)); 1304 return dst; 1305 } 1306 1307 case Iop_Clz64: { 1308 HReg r10, r11; 1309 1310 /* This will be implemented using FLOGR, if possible. So we need to 1311 set aside a pair of non-virtual registers. The result (number of 1312 left-most zero bits) will be in r10. The value in r11 is unspecified 1313 and must not be used. */ 1314 r10 = make_gpr(10); 1315 r11 = make_gpr(11); 1316 1317 addInstr(env, s390_insn_clz(8, r10, r11, opnd)); 1318 addInstr(env, s390_insn_move(8, dst, r10)); 1319 return dst; 1320 } 1321 1322 default: 1323 goto irreducible; 1324 } 1325 1326 addInstr(env, insn); 1327 1328 return dst; 1329 } 1330 1331 /* --------- GET --------- */ 1332 case Iex_Get: { 1333 HReg dst = newVRegI(env); 1334 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset); 1335 1336 /* We never load more than 8 bytes from the guest state, because the 1337 floating point register pair is not contiguous. */ 1338 vassert(size <= 8); 1339 1340 addInstr(env, s390_insn_load(size, dst, am)); 1341 1342 return dst; 1343 } 1344 1345 case Iex_GetI: 1346 /* not needed */ 1347 break; 1348 1349 /* --------- CCALL --------- */ 1350 case Iex_CCall: { 1351 HReg dst = newVRegI(env); 1352 1353 doHelperCall(env, False, NULL, expr->Iex.CCall.cee, 1354 expr->Iex.CCall.args, dst); 1355 return dst; 1356 } 1357 1358 /* --------- LITERAL --------- */ 1359 1360 /* Load a literal into a register. Create a "load immediate" 1361 v-insn and return the register. */ 1362 case Iex_Const: { 1363 ULong value; 1364 HReg dst = newVRegI(env); 1365 const IRConst *con = expr->Iex.Const.con; 1366 1367 /* Bitwise copy of the value. No sign/zero-extension */ 1368 switch (con->tag) { 1369 case Ico_U64: value = con->Ico.U64; break; 1370 case Ico_U32: value = con->Ico.U32; break; 1371 case Ico_U16: value = con->Ico.U16; break; 1372 case Ico_U8: value = con->Ico.U8; break; 1373 default: vpanic("s390_isel_int_expr: invalid constant"); 1374 } 1375 1376 addInstr(env, s390_insn_load_immediate(size, dst, value)); 1377 1378 return dst; 1379 } 1380 1381 /* --------- MULTIPLEX --------- */ 1382 case Iex_Mux0X: { 1383 IRExpr *cond_expr; 1384 HReg dst, tmp, rX; 1385 s390_opnd_RMI cond, r0, zero; 1386 1387 cond_expr = expr->Iex.Mux0X.cond; 1388 1389 dst = newVRegI(env); 1390 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0); 1391 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX); 1392 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX)); 1393 1394 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) { 1395 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg); 1396 1397 addInstr(env, s390_insn_move(size, dst, rX)); 1398 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0)); 1399 return dst; 1400 } 1401 1402 /* Assume the condition is true and move rX to the destination reg. */ 1403 addInstr(env, s390_insn_move(size, dst, rX)); 1404 1405 /* Compute the condition ... */ 1406 cond = s390_isel_int_expr_RMI(env, cond_expr); 1407 1408 /* tmp = cond & 0xFF */ 1409 tmp = newVRegI(env); 1410 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF)); 1411 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond)); 1412 1413 /* ... and compare it with zero */ 1414 zero = s390_opnd_imm(0); 1415 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */)); 1416 1417 /* ... and if it compared equal move r0 to the destination reg. */ 1418 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0)); 1419 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0)); 1420 1421 return dst; 1422 } 1423 1424 default: 1425 break; 1426 } 1427 1428 /* We get here if no pattern matched. */ 1429 irreducible: 1430 ppIRExpr(expr); 1431 vpanic("s390_isel_int_expr: cannot reduce tree"); 1432 } 1433 1434 1435 static HReg 1436 s390_isel_int_expr(ISelEnv *env, IRExpr *expr) 1437 { 1438 HReg dst = s390_isel_int_expr_wrk(env, expr); 1439 1440 /* Sanity checks ... */ 1441 vassert(hregClass(dst) == HRcInt64); 1442 vassert(hregIsVirtual(dst)); 1443 1444 return dst; 1445 } 1446 1447 1448 static s390_opnd_RMI 1449 s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr) 1450 { 1451 IRType ty = typeOfIRExpr(env->type_env, expr); 1452 s390_opnd_RMI dst; 1453 1454 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || 1455 ty == Ity_I64); 1456 1457 if (expr->tag == Iex_Load) { 1458 dst.tag = S390_OPND_AMODE; 1459 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr); 1460 } else if (expr->tag == Iex_Get) { 1461 dst.tag = S390_OPND_AMODE; 1462 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset); 1463 } else if (expr->tag == Iex_Const) { 1464 ULong value; 1465 1466 /* The bit pattern for the value will be stored as is in the least 1467 significant bits of VALUE. */ 1468 switch (expr->Iex.Const.con->tag) { 1469 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break; 1470 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break; 1471 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break; 1472 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break; 1473 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break; 1474 default: 1475 vpanic("s390_isel_int_expr_RMI"); 1476 } 1477 1478 dst.tag = S390_OPND_IMMEDIATE; 1479 dst.variant.imm = value; 1480 } else { 1481 dst.tag = S390_OPND_REG; 1482 dst.variant.reg = s390_isel_int_expr(env, expr); 1483 } 1484 1485 return dst; 1486 } 1487 1488 1489 /*---------------------------------------------------------*/ 1490 /*--- ISEL: Floating point expressions (128 bit) ---*/ 1491 /*---------------------------------------------------------*/ 1492 static void 1493 s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, 1494 IRExpr *expr) 1495 { 1496 IRType ty = typeOfIRExpr(env->type_env, expr); 1497 1498 vassert(ty == Ity_F128); 1499 1500 /* Read 128-bit IRTemp */ 1501 if (expr->tag == Iex_RdTmp) { 1502 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp); 1503 return; 1504 } 1505 1506 switch (expr->tag) { 1507 case Iex_RdTmp: 1508 /* Return the virtual registers that hold the temporary. */ 1509 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp); 1510 return; 1511 1512 /* --------- LOAD --------- */ 1513 case Iex_Load: { 1514 IRExpr *addr_hi, *addr_lo; 1515 s390_amode *am_hi, *am_lo; 1516 1517 if (expr->Iex.Load.end != Iend_BE) 1518 goto irreducible; 1519 1520 addr_hi = expr->Iex.Load.addr; 1521 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8)); 1522 1523 am_hi = s390_isel_amode(env, addr_hi); 1524 am_lo = s390_isel_amode(env, addr_lo); 1525 1526 *dst_hi = newVRegF(env); 1527 *dst_lo = newVRegF(env); 1528 addInstr(env, s390_insn_load(8, *dst_hi, am_hi)); 1529 addInstr(env, s390_insn_load(8, *dst_hi, am_lo)); 1530 return; 1531 } 1532 1533 1534 /* --------- GET --------- */ 1535 case Iex_Get: 1536 /* This is not supported because loading 128-bit from the guest 1537 state is almost certainly wrong. Use get_fpr_pair instead. */ 1538 vpanic("Iex_Get with F128 data"); 1539 1540 /* --------- 4-ary OP --------- */ 1541 case Iex_Qop: 1542 vpanic("Iex_Qop with F128 data"); 1543 1544 /* --------- TERNARY OP --------- */ 1545 case Iex_Triop: { 1546 IRTriop *triop = expr->Iex.Triop.details; 1547 IROp op = triop->op; 1548 IRExpr *left = triop->arg2; 1549 IRExpr *right = triop->arg3; 1550 s390_bfp_binop_t bfpop; 1551 s390_round_t rounding_mode; 1552 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15; 1553 1554 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */ 1555 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */ 1556 1557 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 1558 f12 = make_fpr(12); 1559 f13 = make_fpr(13); 1560 f14 = make_fpr(14); 1561 f15 = make_fpr(15); 1562 1563 /* 1st operand --> (f12, f14) */ 1564 addInstr(env, s390_insn_move(8, f12, op1_hi)); 1565 addInstr(env, s390_insn_move(8, f14, op1_lo)); 1566 1567 /* 2nd operand --> (f13, f15) */ 1568 addInstr(env, s390_insn_move(8, f13, op2_hi)); 1569 addInstr(env, s390_insn_move(8, f15, op2_lo)); 1570 1571 switch (op) { 1572 case Iop_AddF128: bfpop = S390_BFP_ADD; break; 1573 case Iop_SubF128: bfpop = S390_BFP_SUB; break; 1574 case Iop_MulF128: bfpop = S390_BFP_MUL; break; 1575 case Iop_DivF128: bfpop = S390_BFP_DIV; break; 1576 default: 1577 goto irreducible; 1578 } 1579 1580 rounding_mode = decode_rounding_mode(triop->arg1); 1581 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, 1582 f15, rounding_mode)); 1583 1584 /* Move result to virtual destination register */ 1585 *dst_hi = newVRegF(env); 1586 *dst_lo = newVRegF(env); 1587 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 1588 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 1589 1590 return; 1591 } 1592 1593 /* --------- BINARY OP --------- */ 1594 case Iex_Binop: { 1595 HReg op_hi, op_lo, f12, f13, f14, f15; 1596 s390_bfp_unop_t bfpop; 1597 s390_round_t rounding_mode; 1598 1599 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 1600 f12 = make_fpr(12); 1601 f13 = make_fpr(13); 1602 f14 = make_fpr(14); 1603 f15 = make_fpr(15); 1604 1605 switch (expr->Iex.Binop.op) { 1606 case Iop_SqrtF128: 1607 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2); 1608 1609 /* operand --> (f13, f15) */ 1610 addInstr(env, s390_insn_move(8, f13, op_hi)); 1611 addInstr(env, s390_insn_move(8, f15, op_lo)); 1612 1613 bfpop = S390_BFP_SQRT; 1614 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1); 1615 1616 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15, 1617 rounding_mode)); 1618 1619 /* Move result to virtual destination registers */ 1620 *dst_hi = newVRegF(env); 1621 *dst_lo = newVRegF(env); 1622 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 1623 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 1624 return; 1625 1626 case Iop_F64HLtoF128: 1627 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1); 1628 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2); 1629 return; 1630 1631 default: 1632 goto irreducible; 1633 } 1634 } 1635 1636 /* --------- UNARY OP --------- */ 1637 case Iex_Unop: { 1638 IRExpr *left = expr->Iex.Unop.arg; 1639 s390_bfp_unop_t bfpop; 1640 s390_round_t rounding_mode; 1641 HReg op_hi, op_lo, op, f12, f13, f14, f15; 1642 1643 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 1644 f12 = make_fpr(12); 1645 f13 = make_fpr(13); 1646 f14 = make_fpr(14); 1647 f15 = make_fpr(15); 1648 1649 switch (expr->Iex.Unop.op) { 1650 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd; 1651 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd; 1652 case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int; 1653 case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int; 1654 case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float; 1655 case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float; 1656 default: 1657 goto irreducible; 1658 } 1659 1660 float128_opnd: 1661 s390_isel_float128_expr(&op_hi, &op_lo, env, left); 1662 1663 /* operand --> (f13, f15) */ 1664 addInstr(env, s390_insn_move(8, f13, op_hi)); 1665 addInstr(env, s390_insn_move(8, f15, op_lo)); 1666 1667 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */ 1668 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15, 1669 rounding_mode)); 1670 goto move_dst; 1671 1672 convert_float: 1673 op = s390_isel_float_expr(env, left); 1674 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14, 1675 op)); 1676 goto move_dst; 1677 1678 convert_int: 1679 op = s390_isel_int_expr(env, left); 1680 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14, 1681 op)); 1682 goto move_dst; 1683 1684 move_dst: 1685 /* Move result to virtual destination registers */ 1686 *dst_hi = newVRegF(env); 1687 *dst_lo = newVRegF(env); 1688 addInstr(env, s390_insn_move(8, *dst_hi, f12)); 1689 addInstr(env, s390_insn_move(8, *dst_lo, f14)); 1690 return; 1691 } 1692 1693 default: 1694 goto irreducible; 1695 } 1696 1697 /* We get here if no pattern matched. */ 1698 irreducible: 1699 ppIRExpr(expr); 1700 vpanic("s390_isel_int_expr: cannot reduce tree"); 1701 } 1702 1703 /* Compute a 128-bit value into two 64-bit registers. These may be either 1704 real or virtual regs; in any case they must not be changed by subsequent 1705 code emitted by the caller. */ 1706 static void 1707 s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr) 1708 { 1709 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr); 1710 1711 /* Sanity checks ... */ 1712 vassert(hregIsVirtual(*dst_hi)); 1713 vassert(hregIsVirtual(*dst_lo)); 1714 vassert(hregClass(*dst_hi) == HRcFlt64); 1715 vassert(hregClass(*dst_lo) == HRcFlt64); 1716 } 1717 1718 1719 /*---------------------------------------------------------*/ 1720 /*--- ISEL: Floating point expressions (64 bit) ---*/ 1721 /*---------------------------------------------------------*/ 1722 1723 static HReg 1724 s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr) 1725 { 1726 IRType ty = typeOfIRExpr(env->type_env, expr); 1727 UChar size; 1728 1729 vassert(ty == Ity_F32 || ty == Ity_F64); 1730 1731 size = sizeofIRType(ty); 1732 1733 switch (expr->tag) { 1734 case Iex_RdTmp: 1735 /* Return the virtual register that holds the temporary. */ 1736 return lookupIRTemp(env, expr->Iex.RdTmp.tmp); 1737 1738 /* --------- LOAD --------- */ 1739 case Iex_Load: { 1740 HReg dst = newVRegF(env); 1741 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr); 1742 1743 if (expr->Iex.Load.end != Iend_BE) 1744 goto irreducible; 1745 1746 addInstr(env, s390_insn_load(size, dst, am)); 1747 1748 return dst; 1749 } 1750 1751 /* --------- GET --------- */ 1752 case Iex_Get: { 1753 HReg dst = newVRegF(env); 1754 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset); 1755 1756 addInstr(env, s390_insn_load(size, dst, am)); 1757 1758 return dst; 1759 } 1760 1761 /* --------- LITERAL --------- */ 1762 1763 /* Load a literal into a register. Create a "load immediate" 1764 v-insn and return the register. */ 1765 case Iex_Const: { 1766 ULong value; 1767 HReg dst = newVRegF(env); 1768 const IRConst *con = expr->Iex.Const.con; 1769 1770 /* Bitwise copy of the value. No sign/zero-extension */ 1771 switch (con->tag) { 1772 case Ico_F32i: value = con->Ico.F32i; break; 1773 case Ico_F64i: value = con->Ico.F64i; break; 1774 default: vpanic("s390_isel_float_expr: invalid constant"); 1775 } 1776 1777 if (value != 0) vpanic("cannot load immediate floating point constant"); 1778 1779 addInstr(env, s390_insn_load_immediate(size, dst, value)); 1780 1781 return dst; 1782 } 1783 1784 /* --------- 4-ary OP --------- */ 1785 case Iex_Qop: { 1786 HReg op1, op2, op3, dst; 1787 s390_bfp_triop_t bfpop; 1788 s390_round_t rounding_mode; 1789 1790 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2); 1791 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3); 1792 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4); 1793 dst = newVRegF(env); 1794 addInstr(env, s390_insn_move(size, dst, op1)); 1795 1796 switch (expr->Iex.Qop.details->op) { 1797 case Iop_MAddF32: 1798 case Iop_MAddF64: bfpop = S390_BFP_MADD; break; 1799 case Iop_MSubF32: 1800 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break; 1801 1802 default: 1803 goto irreducible; 1804 } 1805 1806 rounding_mode = decode_rounding_mode(expr->Iex.Qop.details->arg1); 1807 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3, 1808 rounding_mode)); 1809 return dst; 1810 } 1811 1812 /* --------- TERNARY OP --------- */ 1813 case Iex_Triop: { 1814 IRTriop *triop = expr->Iex.Triop.details; 1815 IROp op = triop->op; 1816 IRExpr *left = triop->arg2; 1817 IRExpr *right = triop->arg3; 1818 s390_bfp_binop_t bfpop; 1819 s390_round_t rounding_mode; 1820 HReg h1, op2, dst; 1821 1822 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */ 1823 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */ 1824 dst = newVRegF(env); 1825 addInstr(env, s390_insn_move(size, dst, h1)); 1826 switch (op) { 1827 case Iop_AddF32: 1828 case Iop_AddF64: bfpop = S390_BFP_ADD; break; 1829 case Iop_SubF32: 1830 case Iop_SubF64: bfpop = S390_BFP_SUB; break; 1831 case Iop_MulF32: 1832 case Iop_MulF64: bfpop = S390_BFP_MUL; break; 1833 case Iop_DivF32: 1834 case Iop_DivF64: bfpop = S390_BFP_DIV; break; 1835 1836 default: 1837 goto irreducible; 1838 } 1839 1840 rounding_mode = decode_rounding_mode(triop->arg1); 1841 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode)); 1842 return dst; 1843 } 1844 1845 /* --------- BINARY OP --------- */ 1846 case Iex_Binop: { 1847 IROp op = expr->Iex.Binop.op; 1848 IRExpr *left = expr->Iex.Binop.arg2; 1849 HReg h1, dst; 1850 s390_bfp_unop_t bfpop; 1851 s390_round_t rounding_mode; 1852 Int integer_operand; 1853 1854 integer_operand = 1; 1855 1856 switch (op) { 1857 case Iop_SqrtF32: 1858 case Iop_SqrtF64: 1859 bfpop = S390_BFP_SQRT; 1860 integer_operand = 0; 1861 break; 1862 1863 case Iop_F64toF32: 1864 bfpop = S390_BFP_F64_TO_F32; 1865 integer_operand = 0; 1866 break; 1867 1868 case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break; 1869 case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break; 1870 case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break; 1871 default: 1872 goto irreducible; 1873 1874 case Iop_F128toF64: 1875 case Iop_F128toF32: { 1876 HReg op_hi, op_lo, f12, f13, f14, f15; 1877 1878 bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32 1879 : S390_BFP_F128_TO_F64; 1880 1881 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1); 1882 1883 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2); 1884 1885 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */ 1886 f12 = make_fpr(12); 1887 f13 = make_fpr(13); 1888 f14 = make_fpr(14); 1889 f15 = make_fpr(15); 1890 1891 /* operand --> (f13, f15) */ 1892 addInstr(env, s390_insn_move(8, f13, op_hi)); 1893 addInstr(env, s390_insn_move(8, f15, op_lo)); 1894 1895 dst = newVRegF(env); 1896 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15, 1897 rounding_mode)); 1898 1899 /* Move result to virtual destination registers */ 1900 addInstr(env, s390_insn_move(8, dst, f12)); 1901 return dst; 1902 } 1903 } 1904 1905 /* Process operand */ 1906 if (integer_operand) { 1907 h1 = s390_isel_int_expr(env, left); 1908 } else { 1909 h1 = s390_isel_float_expr(env, left); 1910 } 1911 1912 dst = newVRegF(env); 1913 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1); 1914 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode)); 1915 return dst; 1916 } 1917 1918 /* --------- UNARY OP --------- */ 1919 case Iex_Unop: { 1920 IROp op = expr->Iex.Unop.op; 1921 IRExpr *left = expr->Iex.Unop.arg; 1922 s390_bfp_unop_t bfpop; 1923 s390_round_t rounding_mode; 1924 HReg h1, dst; 1925 1926 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) { 1927 HReg dst_hi, dst_lo; 1928 1929 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left); 1930 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi; 1931 } 1932 1933 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) { 1934 dst = newVRegF(env); 1935 h1 = s390_isel_int_expr(env, left); /* Process the operand */ 1936 addInstr(env, s390_insn_move(size, dst, h1)); 1937 1938 return dst; 1939 } 1940 1941 switch (op) { 1942 case Iop_NegF32: 1943 case Iop_NegF64: 1944 if (left->tag == Iex_Unop && 1945 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64)) 1946 bfpop = S390_BFP_NABS; 1947 else 1948 bfpop = S390_BFP_NEG; 1949 break; 1950 1951 case Iop_AbsF32: 1952 case Iop_AbsF64: bfpop = S390_BFP_ABS; break; 1953 case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break; 1954 case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break; 1955 default: 1956 goto irreducible; 1957 } 1958 1959 /* Process operand */ 1960 if (op == Iop_I32StoF64) 1961 h1 = s390_isel_int_expr(env, left); 1962 else if (bfpop == S390_BFP_NABS) 1963 h1 = s390_isel_float_expr(env, left->Iex.Unop.arg); 1964 else 1965 h1 = s390_isel_float_expr(env, left); 1966 1967 dst = newVRegF(env); 1968 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */ 1969 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode)); 1970 return dst; 1971 } 1972 1973 default: 1974 goto irreducible; 1975 } 1976 1977 /* We get here if no pattern matched. */ 1978 irreducible: 1979 ppIRExpr(expr); 1980 vpanic("s390_isel_float_expr: cannot reduce tree"); 1981 } 1982 1983 1984 static HReg 1985 s390_isel_float_expr(ISelEnv *env, IRExpr *expr) 1986 { 1987 HReg dst = s390_isel_float_expr_wrk(env, expr); 1988 1989 /* Sanity checks ... */ 1990 vassert(hregClass(dst) == HRcFlt64); 1991 vassert(hregIsVirtual(dst)); 1992 1993 return dst; 1994 } 1995 1996 1997 /*---------------------------------------------------------*/ 1998 /*--- ISEL: Condition Code ---*/ 1999 /*---------------------------------------------------------*/ 2000 2001 /* This function handles all operators that produce a 1-bit result */ 2002 static s390_cc_t 2003 s390_isel_cc(ISelEnv *env, IRExpr *cond) 2004 { 2005 UChar size; 2006 2007 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1); 2008 2009 /* Constant: either 1 or 0 */ 2010 if (cond->tag == Iex_Const) { 2011 vassert(cond->Iex.Const.con->tag == Ico_U1); 2012 vassert(cond->Iex.Const.con->Ico.U1 == True 2013 || cond->Iex.Const.con->Ico.U1 == False); 2014 2015 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER; 2016 } 2017 2018 /* Variable: values are 1 or 0 */ 2019 if (cond->tag == Iex_RdTmp) { 2020 IRTemp tmp = cond->Iex.RdTmp.tmp; 2021 HReg reg = lookupIRTemp(env, tmp); 2022 2023 /* Load-and-test does not modify REG; so this is OK. */ 2024 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1) 2025 size = 4; 2026 else 2027 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp)); 2028 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg))); 2029 return S390_CC_NE; 2030 } 2031 2032 /* Unary operators */ 2033 if (cond->tag == Iex_Unop) { 2034 IRExpr *arg = cond->Iex.Unop.arg; 2035 2036 switch (cond->Iex.Unop.op) { 2037 case Iop_Not1: /* Not1(cond) */ 2038 /* Generate code for EXPR, and negate the test condition */ 2039 return s390_cc_invert(s390_isel_cc(env, arg)); 2040 2041 /* Iop_32/64to1 select the LSB from their operand */ 2042 case Iop_32to1: 2043 case Iop_64to1: { 2044 HReg dst = newVRegI(env); 2045 HReg h1 = s390_isel_int_expr(env, arg); 2046 2047 size = sizeofIRType(typeOfIRExpr(env->type_env, arg)); 2048 2049 addInstr(env, s390_insn_move(size, dst, h1)); 2050 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1))); 2051 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst))); 2052 return S390_CC_NE; 2053 } 2054 2055 case Iop_CmpNEZ8: 2056 case Iop_CmpNEZ16: { 2057 s390_opnd_RMI src; 2058 s390_unop_t op; 2059 HReg dst; 2060 2061 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8 2062 : S390_ZERO_EXTEND_16; 2063 dst = newVRegI(env); 2064 src = s390_isel_int_expr_RMI(env, arg); 2065 addInstr(env, s390_insn_unop(4, op, dst, src)); 2066 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst))); 2067 return S390_CC_NE; 2068 } 2069 2070 case Iop_CmpNEZ32: 2071 case Iop_CmpNEZ64: { 2072 s390_opnd_RMI src; 2073 2074 src = s390_isel_int_expr_RMI(env, arg); 2075 size = sizeofIRType(typeOfIRExpr(env->type_env, arg)); 2076 addInstr(env, s390_insn_test(size, src)); 2077 return S390_CC_NE; 2078 } 2079 2080 default: 2081 goto fail; 2082 } 2083 } 2084 2085 /* Binary operators */ 2086 if (cond->tag == Iex_Binop) { 2087 IRExpr *arg1 = cond->Iex.Binop.arg1; 2088 IRExpr *arg2 = cond->Iex.Binop.arg2; 2089 HReg reg1, reg2; 2090 2091 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1)); 2092 2093 switch (cond->Iex.Binop.op) { 2094 s390_unop_t op; 2095 s390_cc_t result; 2096 2097 case Iop_CmpEQ8: 2098 case Iop_CasCmpEQ8: 2099 op = S390_ZERO_EXTEND_8; 2100 result = S390_CC_E; 2101 goto do_compare_ze; 2102 2103 case Iop_CmpNE8: 2104 case Iop_CasCmpNE8: 2105 op = S390_ZERO_EXTEND_8; 2106 result = S390_CC_NE; 2107 goto do_compare_ze; 2108 2109 case Iop_CmpEQ16: 2110 case Iop_CasCmpEQ16: 2111 op = S390_ZERO_EXTEND_16; 2112 result = S390_CC_E; 2113 goto do_compare_ze; 2114 2115 case Iop_CmpNE16: 2116 case Iop_CasCmpNE16: 2117 op = S390_ZERO_EXTEND_16; 2118 result = S390_CC_NE; 2119 goto do_compare_ze; 2120 2121 do_compare_ze: { 2122 s390_opnd_RMI op1, op2; 2123 2124 op1 = s390_isel_int_expr_RMI(env, arg1); 2125 reg1 = newVRegI(env); 2126 addInstr(env, s390_insn_unop(4, op, reg1, op1)); 2127 2128 op2 = s390_isel_int_expr_RMI(env, arg2); 2129 reg2 = newVRegI(env); 2130 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */ 2131 2132 op2 = s390_opnd_reg(reg2); 2133 addInstr(env, s390_insn_compare(4, reg1, op2, False)); 2134 2135 return result; 2136 } 2137 2138 case Iop_CmpEQ32: 2139 case Iop_CmpEQ64: 2140 case Iop_CasCmpEQ32: 2141 case Iop_CasCmpEQ64: 2142 result = S390_CC_E; 2143 goto do_compare; 2144 2145 case Iop_CmpNE32: 2146 case Iop_CmpNE64: 2147 case Iop_CasCmpNE32: 2148 case Iop_CasCmpNE64: 2149 result = S390_CC_NE; 2150 goto do_compare; 2151 2152 do_compare: { 2153 HReg op1; 2154 s390_opnd_RMI op2; 2155 2156 order_commutative_operands(arg1, arg2); 2157 2158 op1 = s390_isel_int_expr(env, arg1); 2159 op2 = s390_isel_int_expr_RMI(env, arg2); 2160 2161 addInstr(env, s390_insn_compare(size, op1, op2, False)); 2162 2163 return result; 2164 } 2165 2166 case Iop_CmpLT32S: 2167 case Iop_CmpLE32S: 2168 case Iop_CmpLT64S: 2169 case Iop_CmpLE64S: { 2170 HReg op1; 2171 s390_opnd_RMI op2; 2172 2173 op1 = s390_isel_int_expr(env, arg1); 2174 op2 = s390_isel_int_expr_RMI(env, arg2); 2175 2176 addInstr(env, s390_insn_compare(size, op1, op2, True)); 2177 2178 return (cond->Iex.Binop.op == Iop_CmpLT32S || 2179 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE; 2180 } 2181 2182 case Iop_CmpLT32U: 2183 case Iop_CmpLE32U: 2184 case Iop_CmpLT64U: 2185 case Iop_CmpLE64U: { 2186 HReg op1; 2187 s390_opnd_RMI op2; 2188 2189 op1 = s390_isel_int_expr(env, arg1); 2190 op2 = s390_isel_int_expr_RMI(env, arg2); 2191 2192 addInstr(env, s390_insn_compare(size, op1, op2, False)); 2193 2194 return (cond->Iex.Binop.op == Iop_CmpLT32U || 2195 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE; 2196 } 2197 2198 default: 2199 goto fail; 2200 } 2201 } 2202 2203 fail: 2204 ppIRExpr(cond); 2205 vpanic("s390_isel_cc: unexpected operator"); 2206 } 2207 2208 2209 /*---------------------------------------------------------*/ 2210 /*--- ISEL: Statements ---*/ 2211 /*---------------------------------------------------------*/ 2212 2213 static void 2214 s390_isel_stmt(ISelEnv *env, IRStmt *stmt) 2215 { 2216 if (vex_traceflags & VEX_TRACE_VCODE) { 2217 vex_printf("\n -- "); 2218 ppIRStmt(stmt); 2219 vex_printf("\n"); 2220 } 2221 2222 switch (stmt->tag) { 2223 2224 /* --------- STORE --------- */ 2225 case Ist_Store: { 2226 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data); 2227 s390_amode *am; 2228 HReg src; 2229 2230 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail; 2231 2232 am = s390_isel_amode(env, stmt->Ist.Store.addr); 2233 2234 switch (tyd) { 2235 case Ity_I8: 2236 case Ity_I16: 2237 case Ity_I32: 2238 case Ity_I64: 2239 src = s390_isel_int_expr(env, stmt->Ist.Store.data); 2240 break; 2241 2242 case Ity_F32: 2243 case Ity_F64: 2244 src = s390_isel_float_expr(env, stmt->Ist.Store.data); 2245 break; 2246 2247 case Ity_F128: 2248 /* Cannot occur. No such instruction */ 2249 vpanic("Ist_Store with F128 data"); 2250 2251 default: 2252 goto stmt_fail; 2253 } 2254 2255 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src)); 2256 return; 2257 } 2258 2259 /* --------- PUT --------- */ 2260 case Ist_Put: { 2261 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); 2262 HReg src; 2263 s390_amode *am; 2264 ULong new_value, old_value, difference; 2265 2266 /* Detect updates to certain guest registers. We track the contents 2267 of those registers as long as they contain constants. If the new 2268 constant is either zero or in the 8-bit neighbourhood of the 2269 current value we can use a memory-to-memory insn to do the update. */ 2270 2271 Int offset = stmt->Ist.Put.offset; 2272 2273 /* Check necessary conditions: 2274 (1) must be one of the registers we care about 2275 (2) assigned value must be a constant */ 2276 Int guest_reg = get_guest_reg(offset); 2277 2278 if (guest_reg == GUEST_UNKNOWN) goto not_special; 2279 2280 if (guest_reg == GUEST_IA) { 2281 /* If this is the first assignment to the IA reg, don't special case 2282 it. We need to do a full 8-byte assignment here. The reason is 2283 that in case of a redirected translation the guest IA does not 2284 contain the redirected-to address. Instead it contains the 2285 redirected-from address and those can be far apart. So in order to 2286 do incremnetal updates if the IA in the future we need to get the 2287 initial address of the super block correct. */ 2288 if (env->first_IA_assignment) { 2289 env->first_IA_assignment = False; 2290 goto not_special; 2291 } 2292 } 2293 2294 if (stmt->Ist.Put.data->tag != Iex_Const) { 2295 /* Invalidate guest register contents */ 2296 env->old_value_valid[guest_reg] = False; 2297 goto not_special; 2298 } 2299 2300 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */ 2301 if (tyd != Ity_I64) 2302 goto not_special; 2303 2304 /* OK. Necessary conditions are satisfied. */ 2305 2306 old_value = env->old_value[guest_reg]; 2307 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64; 2308 env->old_value[guest_reg] = new_value; 2309 2310 Bool old_value_is_valid = env->old_value_valid[guest_reg]; 2311 env->old_value_valid[guest_reg] = True; 2312 2313 /* If the register already contains the new value, there is nothing 2314 to do here. Unless the guest register requires precise memory 2315 exceptions. */ 2316 if (old_value_is_valid && new_value == old_value) { 2317 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) { 2318 return; 2319 } 2320 } 2321 2322 /* guest register = 0 */ 2323 if (new_value == 0) { 2324 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset)); 2325 return; 2326 } 2327 2328 if (old_value_is_valid == False) goto not_special; 2329 2330 /* If the new value is in the neighbourhood of the old value 2331 we can use a memory-to-memory insn */ 2332 difference = new_value - old_value; 2333 2334 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) { 2335 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset, 2336 (difference & 0xFF), new_value)); 2337 return; 2338 } 2339 2340 /* If the high word is the same it is sufficient to load the low word. 2341 Use R0 as a scratch reg. */ 2342 if ((old_value >> 32) == (new_value >> 32)) { 2343 HReg r0 = make_gpr(0); 2344 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER); 2345 s390_amode *gam; 2346 2347 gam = s390_amode_b12(offset + 4, gsp); 2348 addInstr(env, s390_insn_load_immediate(4, r0, 2349 new_value & 0xFFFFFFFF)); 2350 addInstr(env, s390_insn_store(4, gam, r0)); 2351 return; 2352 } 2353 2354 /* No special case applies... fall through */ 2355 2356 not_special: 2357 am = s390_amode_for_guest_state(stmt->Ist.Put.offset); 2358 2359 switch (tyd) { 2360 case Ity_I8: 2361 case Ity_I16: 2362 case Ity_I32: 2363 case Ity_I64: 2364 src = s390_isel_int_expr(env, stmt->Ist.Put.data); 2365 break; 2366 2367 case Ity_F32: 2368 case Ity_F64: 2369 src = s390_isel_float_expr(env, stmt->Ist.Put.data); 2370 break; 2371 2372 case Ity_F128: 2373 /* Does not occur. See function put_fpr_pair. */ 2374 vpanic("Ist_Put with F128 data"); 2375 2376 default: 2377 goto stmt_fail; 2378 } 2379 2380 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src)); 2381 return; 2382 } 2383 2384 /* --------- TMP --------- */ 2385 case Ist_WrTmp: { 2386 IRTemp tmp = stmt->Ist.WrTmp.tmp; 2387 IRType tyd = typeOfIRTemp(env->type_env, tmp); 2388 HReg src, dst; 2389 2390 switch (tyd) { 2391 case Ity_I128: { 2392 HReg dst_hi, dst_lo, res_hi, res_lo; 2393 2394 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data); 2395 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp); 2396 2397 addInstr(env, s390_insn_move(8, dst_hi, res_hi)); 2398 addInstr(env, s390_insn_move(8, dst_lo, res_lo)); 2399 return; 2400 } 2401 2402 case Ity_I8: 2403 case Ity_I16: 2404 case Ity_I32: 2405 case Ity_I64: 2406 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data); 2407 dst = lookupIRTemp(env, tmp); 2408 break; 2409 2410 case Ity_I1: { 2411 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data); 2412 dst = lookupIRTemp(env, tmp); 2413 addInstr(env, s390_insn_cc2bool(dst, cond)); 2414 return; 2415 } 2416 2417 case Ity_F32: 2418 case Ity_F64: 2419 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data); 2420 dst = lookupIRTemp(env, tmp); 2421 break; 2422 2423 case Ity_F128: { 2424 HReg dst_hi, dst_lo, res_hi, res_lo; 2425 2426 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data); 2427 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp); 2428 2429 addInstr(env, s390_insn_move(8, dst_hi, res_hi)); 2430 addInstr(env, s390_insn_move(8, dst_lo, res_lo)); 2431 return; 2432 } 2433 2434 default: 2435 goto stmt_fail; 2436 } 2437 2438 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src)); 2439 return; 2440 } 2441 2442 /* --------- Call to DIRTY helper --------- */ 2443 case Ist_Dirty: { 2444 IRType retty; 2445 IRDirty* d = stmt->Ist.Dirty.details; 2446 Bool passBBP; 2447 HReg dst; 2448 Int i; 2449 2450 /* Invalidate tracked values of those guest state registers that are 2451 modified by this helper. */ 2452 for (i = 0; i < d->nFxState; ++i) { 2453 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat' 2454 descriptors in guest state effect descriptions. Hence: */ 2455 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0); 2456 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) { 2457 Int guest_reg = get_guest_reg(d->fxState[i].offset); 2458 if (guest_reg != GUEST_UNKNOWN) 2459 env->old_value_valid[guest_reg] = False; 2460 } 2461 } 2462 2463 if (d->nFxState == 0) 2464 vassert(!d->needsBBP); 2465 2466 passBBP = toBool(d->nFxState > 0 && d->needsBBP); 2467 2468 if (d->tmp == IRTemp_INVALID) { 2469 /* No return value. */ 2470 dst = INVALID_HREG; 2471 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst); 2472 return; 2473 } 2474 2475 retty = typeOfIRTemp(env->type_env, d->tmp); 2476 if (retty == Ity_I64 || retty == Ity_I32 2477 || retty == Ity_I16 || retty == Ity_I8) { 2478 /* Move the returned value to the destination register */ 2479 dst = lookupIRTemp(env, d->tmp); 2480 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst); 2481 return; 2482 } 2483 break; 2484 } 2485 2486 case Ist_CAS: 2487 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) { 2488 IRCAS *cas = stmt->Ist.CAS.details; 2489 s390_amode *op2 = s390_isel_amode(env, cas->addr); 2490 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */ 2491 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */ 2492 HReg old = lookupIRTemp(env, cas->oldLo); 2493 2494 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) { 2495 addInstr(env, s390_insn_cas(4, op1, op2, op3, old)); 2496 } else { 2497 addInstr(env, s390_insn_cas(8, op1, op2, op3, old)); 2498 } 2499 return; 2500 } else { 2501 IRCAS *cas = stmt->Ist.CAS.details; 2502 s390_amode *op2 = s390_isel_amode(env, cas->addr); 2503 HReg r8, r9, r10, r11, r1; 2504 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */ 2505 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */ 2506 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */ 2507 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */ 2508 HReg old_low = lookupIRTemp(env, cas->oldLo); 2509 HReg old_high = lookupIRTemp(env, cas->oldHi); 2510 2511 /* Use non-virtual registers r8 and r9 as pair for op1 2512 and move op1 there */ 2513 r8 = make_gpr(8); 2514 r9 = make_gpr(9); 2515 addInstr(env, s390_insn_move(8, r8, op1_high)); 2516 addInstr(env, s390_insn_move(8, r9, op1_low)); 2517 2518 /* Use non-virtual registers r10 and r11 as pair for op3 2519 and move op3 there */ 2520 r10 = make_gpr(10); 2521 r11 = make_gpr(11); 2522 addInstr(env, s390_insn_move(8, r10, op3_high)); 2523 addInstr(env, s390_insn_move(8, r11, op3_low)); 2524 2525 /* Register r1 is used as a scratch register */ 2526 r1 = make_gpr(1); 2527 2528 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) { 2529 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11, 2530 old_high, old_low, r1)); 2531 } else { 2532 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11, 2533 old_high, old_low, r1)); 2534 } 2535 addInstr(env, s390_insn_move(8, op1_high, r8)); 2536 addInstr(env, s390_insn_move(8, op1_low, r9)); 2537 addInstr(env, s390_insn_move(8, op3_high, r10)); 2538 addInstr(env, s390_insn_move(8, op3_low, r11)); 2539 return; 2540 } 2541 break; 2542 2543 /* --------- EXIT --------- */ 2544 case Ist_Exit: { 2545 s390_cc_t cond; 2546 IRConstTag tag = stmt->Ist.Exit.dst->tag; 2547 2548 if (tag != Ico_U64) 2549 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value"); 2550 2551 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP); 2552 cond = s390_isel_cc(env, stmt->Ist.Exit.guard); 2553 2554 /* Case: boring transfer to known address */ 2555 if (stmt->Ist.Exit.jk == Ijk_Boring) { 2556 if (env->chaining_allowed) { 2557 /* .. almost always true .. */ 2558 /* Skip the event check at the dst if this is a forwards 2559 edge. */ 2560 Bool to_fast_entry 2561 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga; 2562 if (0) vex_printf("%s", to_fast_entry ? "Y" : ","); 2563 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64, 2564 guest_IA, to_fast_entry)); 2565 } else { 2566 /* .. very occasionally .. */ 2567 /* We can't use chaining, so ask for an assisted transfer, 2568 as that's the only alternative that is allowable. */ 2569 HReg dst = s390_isel_int_expr(env, 2570 IRExpr_Const(stmt->Ist.Exit.dst)); 2571 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring)); 2572 } 2573 return; 2574 } 2575 2576 /* Case: assisted transfer to arbitrary address */ 2577 switch (stmt->Ist.Exit.jk) { 2578 case Ijk_NoDecode: 2579 case Ijk_TInval: 2580 case Ijk_Sys_syscall: 2581 case Ijk_ClientReq: 2582 case Ijk_NoRedir: 2583 case Ijk_Yield: 2584 case Ijk_SigTRAP: { 2585 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst)); 2586 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, 2587 stmt->Ist.Exit.jk)); 2588 return; 2589 } 2590 default: 2591 break; 2592 } 2593 2594 /* Do we ever expect to see any other kind? */ 2595 goto stmt_fail; 2596 } 2597 2598 /* --------- MEM FENCE --------- */ 2599 case Ist_MBE: 2600 switch (stmt->Ist.MBE.event) { 2601 case Imbe_Fence: 2602 addInstr(env, s390_insn_mfence()); 2603 return; 2604 default: 2605 break; 2606 } 2607 break; 2608 2609 /* --------- Miscellaneous --------- */ 2610 2611 case Ist_PutI: /* Not needed */ 2612 case Ist_IMark: /* Doesn't generate any executable code */ 2613 case Ist_NoOp: /* Doesn't generate any executable code */ 2614 case Ist_AbiHint: /* Meaningless in IR */ 2615 return; 2616 2617 default: 2618 break; 2619 } 2620 2621 stmt_fail: 2622 ppIRStmt(stmt); 2623 vpanic("s390_isel_stmt"); 2624 } 2625 2626 2627 /*---------------------------------------------------------*/ 2628 /*--- ISEL: Basic block terminators (Nexts) ---*/ 2629 /*---------------------------------------------------------*/ 2630 2631 static void 2632 iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP) 2633 { 2634 if (vex_traceflags & VEX_TRACE_VCODE) { 2635 vex_printf("\n-- PUT(%d) = ", offsIP); 2636 ppIRExpr(next); 2637 vex_printf("; exit-"); 2638 ppIRJumpKind(jk); 2639 vex_printf("\n"); 2640 } 2641 2642 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP); 2643 2644 /* Case: boring transfer to known address */ 2645 if (next->tag == Iex_Const) { 2646 IRConst *cdst = next->Iex.Const.con; 2647 vassert(cdst->tag == Ico_U64); 2648 if (jk == Ijk_Boring || jk == Ijk_Call) { 2649 /* Boring transfer to known address */ 2650 if (env->chaining_allowed) { 2651 /* .. almost always true .. */ 2652 /* Skip the event check at the dst if this is a forwards 2653 edge. */ 2654 Bool to_fast_entry 2655 = ((Addr64)cdst->Ico.U64) > env->max_ga; 2656 if (0) vex_printf("%s", to_fast_entry ? "X" : "."); 2657 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64, 2658 guest_IA, to_fast_entry)); 2659 } else { 2660 /* .. very occasionally .. */ 2661 /* We can't use chaining, so ask for an indirect transfer, 2662 as that's the cheapest alternative that is allowable. */ 2663 HReg dst = s390_isel_int_expr(env, next); 2664 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, 2665 Ijk_Boring)); 2666 } 2667 return; 2668 } 2669 } 2670 2671 /* Case: call/return (==boring) transfer to any address */ 2672 switch (jk) { 2673 case Ijk_Boring: 2674 case Ijk_Ret: 2675 case Ijk_Call: { 2676 HReg dst = s390_isel_int_expr(env, next); 2677 if (env->chaining_allowed) { 2678 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA)); 2679 } else { 2680 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, 2681 Ijk_Boring)); 2682 } 2683 return; 2684 } 2685 default: 2686 break; 2687 } 2688 2689 /* Case: some other kind of transfer to any address */ 2690 switch (jk) { 2691 case Ijk_NoDecode: 2692 case Ijk_TInval: 2693 case Ijk_Sys_syscall: 2694 case Ijk_ClientReq: 2695 case Ijk_NoRedir: 2696 case Ijk_Yield: 2697 case Ijk_SigTRAP: { 2698 HReg dst = s390_isel_int_expr(env, next); 2699 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk)); 2700 return; 2701 } 2702 default: 2703 break; 2704 } 2705 2706 vpanic("iselNext"); 2707 } 2708 2709 2710 /*---------------------------------------------------------*/ 2711 /*--- Insn selector top-level ---*/ 2712 /*---------------------------------------------------------*/ 2713 2714 /* Translate an entire SB to s390 code. 2715 Note: archinfo_host is a pointer to a stack-allocated variable. 2716 Do not assign it to a global variable! */ 2717 2718 HInstrArray * 2719 iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host, 2720 VexAbiInfo *vbi, Int offset_host_evcheck_counter, 2721 Int offset_host_evcheck_fail_addr, Bool chaining_allowed, 2722 Bool add_profinc, Addr64 max_ga) 2723 { 2724 UInt i, j; 2725 HReg hreg, hregHI; 2726 ISelEnv *env; 2727 UInt hwcaps_host = archinfo_host->hwcaps; 2728 2729 /* KLUDGE: export hwcaps. */ 2730 s390_host_hwcaps = hwcaps_host; 2731 2732 /* Do some sanity checks */ 2733 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0); 2734 2735 /* Make up an initial environment to use. */ 2736 env = LibVEX_Alloc(sizeof(ISelEnv)); 2737 env->vreg_ctr = 0; 2738 2739 /* Set up output code array. */ 2740 env->code = newHInstrArray(); 2741 2742 /* Copy BB's type env. */ 2743 env->type_env = bb->tyenv; 2744 2745 /* Set up data structures for tracking guest register values. */ 2746 env->first_IA_assignment = True; 2747 for (i = 0; i < NUM_TRACKED_REGS; ++i) { 2748 env->old_value[i] = 0; /* just something to have a defined value */ 2749 env->old_value_valid[i] = False; 2750 } 2751 2752 /* Make up an IRTemp -> virtual HReg mapping. This doesn't 2753 change as we go along. For some reason types_used has Int type -- but 2754 it should be unsigned. Internally we use an unsigned type; so we 2755 assert it here. */ 2756 vassert(bb->tyenv->types_used >= 0); 2757 2758 env->n_vregmap = bb->tyenv->types_used; 2759 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); 2760 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); 2761 2762 /* and finally ... */ 2763 env->hwcaps = hwcaps_host; 2764 2765 env->max_ga = max_ga; 2766 env->chaining_allowed = chaining_allowed; 2767 2768 /* For each IR temporary, allocate a suitably-kinded virtual 2769 register. */ 2770 j = 0; 2771 for (i = 0; i < env->n_vregmap; i++) { 2772 hregHI = hreg = INVALID_HREG; 2773 switch (bb->tyenv->types[i]) { 2774 case Ity_I1: 2775 case Ity_I8: 2776 case Ity_I16: 2777 case Ity_I32: 2778 hreg = mkHReg(j++, HRcInt64, True); 2779 break; 2780 2781 case Ity_I64: 2782 hreg = mkHReg(j++, HRcInt64, True); 2783 break; 2784 2785 case Ity_I128: 2786 hreg = mkHReg(j++, HRcInt64, True); 2787 hregHI = mkHReg(j++, HRcInt64, True); 2788 break; 2789 2790 case Ity_F32: 2791 case Ity_F64: 2792 hreg = mkHReg(j++, HRcFlt64, True); 2793 break; 2794 2795 case Ity_F128: 2796 hreg = mkHReg(j++, HRcFlt64, True); 2797 hregHI = mkHReg(j++, HRcFlt64, True); 2798 break; 2799 2800 case Ity_V128: /* fall through */ 2801 default: 2802 ppIRType(bb->tyenv->types[i]); 2803 vpanic("s390_isel_sb: IRTemp type"); 2804 } 2805 2806 env->vregmap[i] = hreg; 2807 env->vregmapHI[i] = hregHI; 2808 } 2809 env->vreg_ctr = j; 2810 2811 /* The very first instruction must be an event check. */ 2812 s390_amode *counter, *fail_addr; 2813 counter = s390_amode_for_guest_state(offset_host_evcheck_counter); 2814 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr); 2815 addInstr(env, s390_insn_evcheck(counter, fail_addr)); 2816 2817 /* Possibly a block counter increment (for profiling). At this 2818 point we don't know the address of the counter, so just pretend 2819 it is zero. It will have to be patched later, but before this 2820 translation is used, by a call to LibVEX_patchProfInc. */ 2821 if (add_profinc) { 2822 addInstr(env, s390_insn_profinc()); 2823 } 2824 2825 /* Ok, finally we can iterate over the statements. */ 2826 for (i = 0; i < bb->stmts_used; i++) 2827 if (bb->stmts[i]) 2828 s390_isel_stmt(env, bb->stmts[i]); 2829 2830 iselNext(env, bb->next, bb->jumpkind, bb->offsIP); 2831 2832 /* Record the number of vregs we used. */ 2833 env->code->n_vregs = env->vreg_ctr; 2834 2835 return env->code; 2836 } 2837 2838 /*---------------------------------------------------------------*/ 2839 /*--- end host_s390_isel.c ---*/ 2840 /*---------------------------------------------------------------*/ 2841