• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
get_guest_reg(Int offset)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
addInstr(ISelEnv * env,s390_insn * insn)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 *
mkU64(ULong value)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
lookupIRTemp(ISelEnv * env,IRTemp tmp)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
lookupIRTemp128(HReg * hi,HReg * lo,ISelEnv * env,IRTemp tmp)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
newVRegI(ISelEnv * env)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
newVRegF(ISelEnv * env)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
make_gpr(UInt regno)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
make_fpr(UInt regno)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
ulong_fits_unsigned_12bit(ULong val)261 ulong_fits_unsigned_12bit(ULong val)
262 {
263    return (val & 0xFFFu) == val;
264 }
265 
266 
267 static __inline__ Bool
ulong_fits_signed_20bit(ULong val)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
ulong_fits_signed_8bit(ULong val)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 *
s390_isel_amode_wrk(ISelEnv * env,IRExpr * expr)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 *
s390_isel_amode(ISelEnv * env,IRExpr * expr)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 *
s390_opnd_copy(UChar size,HReg dst,s390_opnd_RMI opnd)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
s390_opnd_reg(HReg reg)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
s390_opnd_imm(ULong value)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
s390_expr_is_const_zero(IRExpr * expr)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
get_const_value_as_ulong(const IRConst * con)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
doHelperCall(UInt * stackAdjustAfterCall,RetLoc * retloc,ISelEnv * env,IRExpr * guard,IRCallee * callee,IRType retTy,IRExpr ** args)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
set_bfp_rounding_mode_in_fpc(ISelEnv * env,IRExpr * irrm)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
get_bfp_rounding_mode(ISelEnv * env,IRExpr * irrm)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
set_dfp_rounding_mode_in_fpc(ISelEnv * env,IRExpr * irrm)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
get_dfp_rounding_mode(ISelEnv * env,IRExpr * irrm)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
convert_s390_to_vex_bfpcc(ISelEnv * env,HReg cc_s390)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
convert_s390_to_vex_dfpcc(ISelEnv * env,HReg cc_s390)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
s390_isel_int128_expr_wrk(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)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
s390_isel_int128_expr(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)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
s390_isel_int_expr_wrk(ISelEnv * env,IRExpr * expr)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
s390_isel_int_expr(ISelEnv * env,IRExpr * expr)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
s390_isel_int_expr_RMI(ISelEnv * env,IRExpr * expr)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
s390_isel_float128_expr_wrk(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)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
s390_isel_float128_expr(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)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
s390_isel_float_expr_wrk(ISelEnv * env,IRExpr * expr)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
s390_isel_float_expr(ISelEnv * env,IRExpr * expr)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
s390_isel_dfp128_expr_wrk(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)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
s390_isel_dfp128_expr(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)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
s390_isel_dfp_expr_wrk(ISelEnv * env,IRExpr * expr)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
s390_isel_dfp_expr(ISelEnv * env,IRExpr * expr)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
s390_isel_cc(ISelEnv * env,IRExpr * cond)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
s390_isel_stmt(ISelEnv * env,IRStmt * stmt)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
iselNext(ISelEnv * env,IRExpr * next,IRJumpKind jk,Int offsIP)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 *
iselSB_S390(IRSB * bb,VexArch arch_host,VexArchInfo * archinfo_host,VexAbiInfo * vbi,Int offset_host_evcheck_counter,Int offset_host_evcheck_fail_addr,Bool chaining_allowed,Bool add_profinc,Addr64 max_ga)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