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