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