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