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