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-2017
12    Copyright (C) 2012-2017  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 static HReg          s390_isel_vec_expr(ISelEnv *, IRExpr *);
139 
140 
141 static Int
get_guest_reg(Int offset)142 get_guest_reg(Int offset)
143 {
144    switch (offset) {
145    case S390X_GUEST_OFFSET(guest_IA):        return GUEST_IA;
146    case S390X_GUEST_OFFSET(guest_CC_OP):     return GUEST_CC_OP;
147    case S390X_GUEST_OFFSET(guest_CC_DEP1):   return GUEST_CC_DEP1;
148    case S390X_GUEST_OFFSET(guest_CC_DEP2):   return GUEST_CC_DEP2;
149    case S390X_GUEST_OFFSET(guest_CC_NDEP):   return GUEST_CC_NDEP;
150    case S390X_GUEST_OFFSET(guest_SYSNO):     return GUEST_SYSNO;
151    case S390X_GUEST_OFFSET(guest_counter):   return GUEST_COUNTER;
152 
153       /* Also make sure there is never a partial write to one of
154          these registers. That would complicate matters. */
155    case S390X_GUEST_OFFSET(guest_IA)+1      ... S390X_GUEST_OFFSET(guest_IA)+7:
156    case S390X_GUEST_OFFSET(guest_CC_OP)+1   ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
157    case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
158    case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
159    case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
160    case S390X_GUEST_OFFSET(guest_SYSNO)+1   ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
161       /* counter is used both as 4-byte and as 8-byte entity */
162    case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
163    case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
164       vpanic("partial update of this guest state register is not allowed");
165       break;
166 
167    default: break;
168    }
169 
170    return GUEST_UNKNOWN;
171 }
172 
173 /* Add an instruction */
174 static void
addInstr(ISelEnv * env,s390_insn * insn)175 addInstr(ISelEnv *env, s390_insn *insn)
176 {
177    addHInstr(env->code, insn);
178 
179    if (vex_traceflags & VEX_TRACE_VCODE) {
180       vex_printf("%s\n", s390_insn_as_string(insn));
181    }
182 }
183 
184 
185 static __inline__ IRExpr *
mkU64(ULong value)186 mkU64(ULong value)
187 {
188    return IRExpr_Const(IRConst_U64(value));
189 }
190 
191 
192 /*---------------------------------------------------------*/
193 /*--- Registers                                         ---*/
194 /*---------------------------------------------------------*/
195 
196 /* Return the virtual register to which a given IRTemp is mapped. */
197 static HReg
lookupIRTemp(ISelEnv * env,IRTemp tmp)198 lookupIRTemp(ISelEnv *env, IRTemp tmp)
199 {
200    vassert(tmp < env->n_vregmap);
201    vassert(! hregIsInvalid(env->vregmap[tmp]));
202 
203    return env->vregmap[tmp];
204 }
205 
206 
207 /* Return the two virtual registers to which the IRTemp is mapped. */
208 static void
lookupIRTemp128(HReg * hi,HReg * lo,ISelEnv * env,IRTemp tmp)209 lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
210 {
211    vassert(tmp < env->n_vregmap);
212    vassert(! hregIsInvalid(env->vregmapHI[tmp]));
213 
214    *lo = env->vregmap[tmp];
215    *hi = env->vregmapHI[tmp];
216 }
217 
218 
219 /* Allocate a new virtual integer register */
220 static __inline__ HReg
mkVRegI(UInt ix)221 mkVRegI(UInt ix)
222 {
223    return mkHReg(/*virtual*/True, HRcInt64, /*encoding*/0, ix);
224 }
225 
226 static __inline__ HReg
newVRegI(ISelEnv * env)227 newVRegI(ISelEnv *env)
228 {
229    return mkVRegI(env->vreg_ctr++);
230 }
231 
232 
233 /* Allocate a new virtual floating point register */
234 static __inline__ HReg
mkVRegF(UInt ix)235 mkVRegF(UInt ix)
236 {
237    return mkHReg(/*virtual*/True, HRcFlt64, /*encoding*/0, ix);
238 }
239 
240 static __inline__ HReg
newVRegF(ISelEnv * env)241 newVRegF(ISelEnv *env)
242 {
243    return mkVRegF(env->vreg_ctr++);
244 }
245 
246 /* Allocate a new virtual vector register */
247 static HReg
mkVRegV(UInt ix)248 mkVRegV(UInt ix)
249 {
250    return mkHReg(/*virtual*/True, HRcVec128, /*encoding*/0, ix);
251 }
252 
253 static HReg
newVRegV(ISelEnv * env)254 newVRegV(ISelEnv *env)
255 {
256    return mkVRegV(env->vreg_ctr++);
257 }
258 
259 /* Construct a non-virtual general purpose register */
260 static __inline__ HReg
make_gpr(UInt regno)261 make_gpr(UInt regno)
262 {
263    return s390_hreg_gpr(regno);
264 }
265 
266 
267 /* Construct a non-virtual floating point register */
268 static __inline__ HReg
make_fpr(UInt regno)269 make_fpr(UInt regno)
270 {
271    return s390_hreg_fpr(regno);
272 }
273 
274 
275 /*---------------------------------------------------------*/
276 /*--- Amode                                             ---*/
277 /*---------------------------------------------------------*/
278 
279 static __inline__ Bool
ulong_fits_unsigned_12bit(ULong val)280 ulong_fits_unsigned_12bit(ULong val)
281 {
282    return (val & 0xFFFu) == val;
283 }
284 
285 
286 static __inline__ Bool
ulong_fits_signed_20bit(ULong val)287 ulong_fits_signed_20bit(ULong val)
288 {
289    ULong v = val & 0xFFFFFu;
290 
291    v = (Long)(v << 44) >> 44;  /* sign extend */
292 
293    return val == v;
294 }
295 
296 
297 static __inline__ Bool
ulong_fits_signed_8bit(ULong val)298 ulong_fits_signed_8bit(ULong val)
299 {
300    ULong v = val & 0xFFu;
301 
302    v = (Long)(v << 56) >> 56;  /* sign extend */
303 
304    return val == v;
305 }
306 
307 /* EXPR is an expression that is used as an address. Return an s390_amode
308    for it. If select_b12_b20_only is true the returned amode must be either
309    S390_AMODE_B12 or S390_AMODE_B20. */
310 static s390_amode *
s390_isel_amode_wrk(ISelEnv * env,IRExpr * expr,Bool select_b12_b20_only)311 s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr,
312                     Bool select_b12_b20_only __attribute__((unused)))
313 {
314    if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
315       IRExpr *arg1 = expr->Iex.Binop.arg1;
316       IRExpr *arg2 = expr->Iex.Binop.arg2;
317 
318       /* Move constant into right subtree */
319       if (arg1->tag == Iex_Const) {
320          IRExpr *tmp;
321          tmp  = arg1;
322          arg1 = arg2;
323          arg2 = tmp;
324       }
325 
326       /* r + constant: Check for b12 first, then b20 */
327       if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
328          ULong value = arg2->Iex.Const.con->Ico.U64;
329 
330          if (ulong_fits_unsigned_12bit(value)) {
331             return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
332          }
333          if (ulong_fits_signed_20bit(value)) {
334             return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
335          }
336       }
337    }
338 
339    /* Doesn't match anything in particular.  Generate it into
340       a register and use that. */
341    return s390_amode_b12(0, s390_isel_int_expr(env, expr));
342 }
343 
344 
345 static s390_amode *
s390_isel_amode(ISelEnv * env,IRExpr * expr)346 s390_isel_amode(ISelEnv *env, IRExpr *expr)
347 {
348    s390_amode *am;
349 
350    /* Address computation should yield a 64-bit value */
351    vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
352 
353    am = s390_isel_amode_wrk(env, expr, /* B12, B20 only */ False);
354 
355    /* Check post-condition */
356    vassert(s390_amode_is_sane(am));
357 
358    return am;
359 }
360 
361 
362 /* Sometimes we must compile an expression into an amode that is either
363    S390_AMODE_B12 or S390_AMODE_B20. An example is the compare-and-swap
364    opcode. These opcodes do not have a variant hat accepts an addressing
365    mode with an index register.
366    Now, in theory we could, when emitting the compare-and-swap insn,
367    hack a, say, BX12 amode into a B12 amode like so:
368 
369       r0 = b       # save away base register
370       b  = b + x   # add index register to base register
371       cas(b,d,...) # emit compare-and-swap using b12 amode
372       b  = r0      # restore base register
373 
374    Unfortunately, emitting the compare-and-swap insn already utilises r0
375    under the covers, so the trick above is off limits, sadly. */
376 static s390_amode *
s390_isel_amode_b12_b20(ISelEnv * env,IRExpr * expr)377 s390_isel_amode_b12_b20(ISelEnv *env, IRExpr *expr)
378 {
379    s390_amode *am;
380 
381    /* Address computation should yield a 64-bit value */
382    vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
383 
384    am = s390_isel_amode_wrk(env, expr, /* B12, B20 only */ True);
385 
386    /* Check post-condition */
387    vassert(s390_amode_is_sane(am) &&
388            (am->tag == S390_AMODE_B12 || am->tag == S390_AMODE_B20));
389 
390    return am;
391 }
392 
393 
394 /*---------------------------------------------------------*/
395 /*--- Helper functions                                  ---*/
396 /*---------------------------------------------------------*/
397 
398 /* Constants and memory accesses should be right operands */
399 #define order_commutative_operands(left, right)                   \
400         do {                                                      \
401           if (left->tag == Iex_Const || left->tag == Iex_Load ||  \
402               left->tag == Iex_Get) {                             \
403             IRExpr *tmp;                                          \
404             tmp   = left;                                         \
405             left  = right;                                        \
406             right = tmp;                                          \
407           }                                                       \
408         } while (0)
409 
410 
411 /* Copy an RMI operand to the DST register */
412 static s390_insn *
s390_opnd_copy(UChar size,HReg dst,s390_opnd_RMI opnd)413 s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
414 {
415    switch (opnd.tag) {
416    case S390_OPND_AMODE:
417       return s390_insn_load(size, dst, opnd.variant.am);
418 
419    case S390_OPND_REG:
420       return s390_insn_move(size, dst, opnd.variant.reg);
421 
422    case S390_OPND_IMMEDIATE:
423       return s390_insn_load_immediate(size, dst, opnd.variant.imm);
424 
425    default:
426       vpanic("s390_opnd_copy");
427    }
428 }
429 
430 
431 /* Construct a RMI operand for a register */
432 static __inline__ s390_opnd_RMI
s390_opnd_reg(HReg reg)433 s390_opnd_reg(HReg reg)
434 {
435    s390_opnd_RMI opnd;
436 
437    opnd.tag  = S390_OPND_REG;
438    opnd.variant.reg = reg;
439 
440    return opnd;
441 }
442 
443 
444 /* Construct a RMI operand for an immediate constant */
445 static __inline__ s390_opnd_RMI
s390_opnd_imm(ULong value)446 s390_opnd_imm(ULong value)
447 {
448    s390_opnd_RMI opnd;
449 
450    opnd.tag  = S390_OPND_IMMEDIATE;
451    opnd.variant.imm = value;
452 
453    return opnd;
454 }
455 
456 
457 /* Return 1, if EXPR represents the constant 0 */
458 static Bool
s390_expr_is_const_zero(IRExpr * expr)459 s390_expr_is_const_zero(IRExpr *expr)
460 {
461    ULong value;
462 
463    if (expr->tag == Iex_Const) {
464       switch (expr->Iex.Const.con->tag) {
465       case Ico_U1:  value = expr->Iex.Const.con->Ico.U1;  break;
466       case Ico_U8:  value = expr->Iex.Const.con->Ico.U8;  break;
467       case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
468       case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
469       case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
470       default:
471          vpanic("s390_expr_is_const_zero");
472       }
473       return value == 0;
474    }
475 
476    return 0;
477 }
478 
479 
480 /* Return the value of CON as a sign-exteded ULong value */
481 static ULong
get_const_value_as_ulong(const IRConst * con)482 get_const_value_as_ulong(const IRConst *con)
483 {
484    ULong value;
485 
486    switch (con->tag) {
487    case Ico_U1:  value = con->Ico.U1;  return ((Long)(value << 63) >> 63);
488    case Ico_U8:  value = con->Ico.U8;  return ((Long)(value << 56) >> 56);
489    case Ico_U16: value = con->Ico.U16; return ((Long)(value << 48) >> 48);
490    case Ico_U32: value = con->Ico.U32; return ((Long)(value << 32) >> 32);
491    case Ico_U64: return con->Ico.U64;
492    default:
493       vpanic("get_const_value_as_ulong");
494    }
495 }
496 
497 
498 /*  Substract n from stack pointer. Assumes 0 <= n <= 256 && n % 8 == 0. */
499 static void
sub_from_SP(ISelEnv * env,UInt n)500 sub_from_SP ( ISelEnv* env, UInt n )
501 {
502    HReg sp;
503    vassert( n < 256 && (n%8) == 0);
504    sp = s390_hreg_stack_pointer();
505    addInstr(env, s390_insn_alu(sizeof(ULong), S390_ALU_SUB, sp, s390_opnd_imm(n)));
506 }
507 
508 
509 /*  Substract n from stack pointer. Assumes 0 <= n <= 256 && n % 8 == 0. */
510 static void
add_to_SP(ISelEnv * env,UInt n)511 add_to_SP ( ISelEnv* env, UInt n )
512 {
513    HReg sp;
514    vassert(n < 256 && (n%8) == 0);
515    sp = s390_hreg_stack_pointer();
516    addInstr(env, s390_insn_alu(sizeof(ULong), S390_ALU_ADD, sp, s390_opnd_imm(n)));
517 }
518 
519 
520 static HReg
vec_generate_zeroes(ISelEnv * env)521 vec_generate_zeroes(ISelEnv* env)
522 {
523    HReg dst = newVRegV(env);
524    addInstr(env, s390_insn_unop(16, S390_VEC_FILL, dst, s390_opnd_imm(0x00)));
525    return dst;
526 }
527 
528 static HReg
vec_do_notV128(ISelEnv * env,HReg arg)529 vec_do_notV128(ISelEnv* env, HReg arg)
530 {
531    HReg dst = newVRegV(env);
532    addInstr(env, s390_insn_vec_binop(16, S390_VEC_NOR, dst, arg, arg));
533    return dst;
534 }
535 
536 #define IRCONST_IS_EQUAL_U8(arg, val)                   \
537    ( ((arg)->tag == Iex_Const)                          \
538      && ((arg)->Iex.Const.con->tag == Ico_U8)           \
539      && ((arg)->Iex.Const.con->Ico.U8 == (val)) )
540 
541 /* Returns true if (expr & 0x7 == 0) */
542 static Bool
vec_is_bytes_only_shift(const IRExpr * expr)543 vec_is_bytes_only_shift(const IRExpr* expr)
544 {
545    const Bool is_good_const =
546                   (expr->tag == Iex_Const) &&
547                   ((expr->Iex.Const.con->Ico.U8 & 0b00000111) == 0);
548 
549    const Bool good_mask_applied =
550                   (expr->tag == Iex_Binop) && (expr->Iex.Binop.op == Iop_And8) &&
551                      (IRCONST_IS_EQUAL_U8(expr->Iex.Binop.arg1, 0b01111000)
552                         ||
553                       IRCONST_IS_EQUAL_U8(expr->Iex.Binop.arg2, 0b01111000)
554                      );
555 
556    return is_good_const || good_mask_applied;
557 }
558 #undef IRCONST_IS_EQUAL_U8
559 
560 /* Call a helper (clean or dirty)
561    Arguments must satisfy the following conditions:
562 
563    (a) they are expressions yielding an integer result
564    (b) there can be no more than S390_NUM_GPRPARMS arguments
565 
566    guard is a Ity_Bit expression indicating whether or not the
567    call happens.  If guard == NULL, the call is unconditional.
568 
569    Calling the helper function proceeds as follows:
570 
571    (1) The helper arguments are evaluated and their value stored in
572        virtual registers.
573    (2) The condition code is evaluated
574    (3) The argument values are copied from the virtual registers to the
575        registers mandated by the ABI.
576    (4) Call the helper function.
577 
578    This is not the most efficient way as step 3 generates register-to-register
579    moves. But it is the least fragile way as the only hidden dependency here
580    is that register-to-register moves (step 3) must not clobber the condition
581    code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
582    to-register add more such dependencies. Not good. Besides, it's the job
583    of the register allocator to throw out those reg-to-reg moves.
584 */
585 static void
doHelperCall(UInt * stackAdjustAfterCall,RetLoc * retloc,ISelEnv * env,IRExpr * guard,IRCallee * callee,IRType retTy,IRExpr ** args)586 doHelperCall(/*OUT*/UInt *stackAdjustAfterCall,
587              /*OUT*/RetLoc *retloc,
588              ISelEnv *env, IRExpr *guard,
589              IRCallee *callee, IRType retTy, IRExpr **args)
590 {
591    UInt n_args, i, argreg, size;
592    Addr64 target;
593    HReg tmpregs[S390_NUM_GPRPARMS];
594    s390_cc_t cc;
595 
596    /* Set default returns.  We'll update them later if needed. */
597    *stackAdjustAfterCall = 0;
598    *retloc               = mk_RetLoc_INVALID();
599 
600    /* The return type can be I{64,32,16,8} or V{128,256}.  In the
601       latter two cases, it is expected that |args| will contain the
602       special node IRExpr_VECRET().
603 
604       |args| may also contain IRExpr_GSPTR(), in which case the value
605       in the guest state pointer register is passed as the
606       corresponding argument.
607 
608       These are used for cross-checking that IR-level constraints on
609       the use of IRExpr_VECRET() and IRExpr_GSPTR() are observed. */
610    UInt nVECRETs = 0;
611    UInt nGSPTRs  = 0;
612 
613    n_args = 0;
614    for (i = 0; args[i]; i++)
615       ++n_args;
616 
617    if (n_args > S390_NUM_GPRPARMS) {
618       vpanic("doHelperCall: too many arguments");
619    }
620 
621    /* All arguments must have Ity_I64. For two reasons:
622       (1) We do not handle floating point arguments.
623       (2) The ABI requires that integer values are sign- or zero-extended
624            to 64 bit.
625    */
626    Int arg_errors = 0;
627    for (i = 0; i < n_args; ++i) {
628       if (UNLIKELY(args[i]->tag == Iex_VECRET)) {
629          nVECRETs++;
630       } else if (UNLIKELY(args[i]->tag == Iex_GSPTR)) {
631          nGSPTRs++;
632       } else {
633          IRType type = typeOfIRExpr(env->type_env, args[i]);
634          if (type != Ity_I64) {
635             ++arg_errors;
636             vex_printf("calling %s: argument #%u has type ", callee->name, i);
637             ppIRType(type);
638             vex_printf("; Ity_I64 or Ity_V128 is required\n");
639          }
640       }
641    }
642 
643    if (arg_errors)
644       vpanic("cannot continue due to errors in argument passing");
645 
646    /* If these fail, the IR is ill-formed */
647    vassert(nGSPTRs == 0 || nGSPTRs == 1);
648    if (UNLIKELY(retTy == Ity_V128)) {
649       vassert(nVECRETs == 1);
650    } else {
651       vassert(nVECRETs == 0);
652    }
653 
654    argreg = 0;
655 
656    /* Compute the function arguments into a temporary register each */
657    for (i = 0; i < n_args; i++) {
658       IRExpr *arg = args[i];
659       if (UNLIKELY(arg->tag == Iex_GSPTR)) {
660          /* If we need the guest state pointer put it in a temporary arg reg */
661          tmpregs[argreg] = newVRegI(env);
662          addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
663                                       s390_hreg_guest_state_pointer()));
664       } else if(UNLIKELY(arg->tag == Iex_VECRET)) {
665          /* Return vector via stack */
666          tmpregs[argreg] = newVRegI(env);
667          sub_from_SP(env, sizeofIRType(Ity_V128));
668          addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg], s390_hreg_stack_pointer()));
669       } else {
670          tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
671       }
672       argreg++;
673    }
674 
675    /* Compute the condition */
676    cc = S390_CC_ALWAYS;
677    if (guard) {
678       if (guard->tag == Iex_Const
679           && guard->Iex.Const.con->tag == Ico_U1
680           && guard->Iex.Const.con->Ico.U1 == True) {
681          /* unconditional -- do nothing */
682       } else {
683          cc = s390_isel_cc(env, guard);
684       }
685    }
686 
687    /* Move the args to the final register. It is paramount, that the
688       code to move the registers does not clobber the condition code ! */
689    for (i = 0; i < argreg; i++) {
690       HReg finalreg;
691 
692       finalreg = make_gpr(s390_gprno_from_arg_index(i));
693       size = sizeofIRType(Ity_I64);
694       addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
695    }
696 
697    target = (Addr)callee->addr;
698 
699    /* Do final checks, set the return values, and generate the call
700       instruction proper. */
701    vassert(*stackAdjustAfterCall == 0);
702    vassert(is_RetLoc_INVALID(*retloc));
703    switch (retTy) {
704    case Ity_INVALID:
705       /* Function doesn't return a value. */
706       *retloc = mk_RetLoc_simple(RLPri_None);
707       break;
708    case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
709       *retloc = mk_RetLoc_simple(RLPri_Int);
710       break;
711    case Ity_V128:
712       *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
713       *stackAdjustAfterCall = sizeof(V128);
714       break;
715    default:
716       /* IR can denote other possible return types, but we don't
717          handle those here. */
718       vex_printf("calling %s: return type is ", callee->name);
719       ppIRType(retTy);
720       vex_printf("; an integer type is required\n");
721       vassert(0);
722    }
723 
724    /* Finally, the call itself. */
725    addInstr(env, s390_insn_helper_call(cc, target, n_args,
726                                        callee->name, *retloc));
727 }
728 
729 
730 /*---------------------------------------------------------*/
731 /*--- BFP helper functions                              ---*/
732 /*---------------------------------------------------------*/
733 
734 /* Set the BFP rounding mode in the FPC. This function is called for
735    all non-conversion BFP instructions as those will always get the
736    rounding mode from the FPC. */
737 static void
set_bfp_rounding_mode_in_fpc(ISelEnv * env,IRExpr * irrm)738 set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
739 {
740    vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
741 
742    /* Do we need to do anything? */
743    if (env->previous_bfp_rounding_mode &&
744        env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
745        irrm->tag == Iex_RdTmp &&
746        env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
747       /* No - new mode is identical to previous mode.  */
748       return;
749    }
750 
751    /* No luck - we better set it, and remember what we set it to. */
752    env->previous_bfp_rounding_mode = irrm;
753 
754    /* The incoming rounding mode is in VEX IR encoding. Need to change
755       to s390.
756 
757       rounding mode | s390 | IR
758       -------------------------
759       to nearest    |  00  | 00
760       to zero       |  01  | 11
761       to +infinity  |  10  | 10
762       to -infinity  |  11  | 01
763 
764       So: s390 = (4 - IR) & 3
765    */
766    HReg ir = s390_isel_int_expr(env, irrm);
767 
768    HReg mode = newVRegI(env);
769 
770    addInstr(env, s390_insn_load_immediate(4, mode, 4));
771    addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
772    addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
773 
774    addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
775 }
776 
777 
778 /* This function is invoked for insns that support a specification of
779    a rounding mode in the insn itself. In that case there is no need to
780    stick the rounding mode into the FPC -- a good thing. However, the
781    rounding mode must be known. */
782 static s390_bfp_round_t
get_bfp_rounding_mode(ISelEnv * env,IRExpr * irrm)783 get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
784 {
785    if (irrm->tag == Iex_Const) {          /* rounding mode is known */
786       vassert(irrm->Iex.Const.con->tag == Ico_U32);
787       IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
788 
789       switch (mode) {
790       case Irrm_NEAREST_TIE_AWAY_0: return S390_BFP_ROUND_NEAREST_AWAY;
791       case Irrm_PREPARE_SHORTER:    return S390_BFP_ROUND_PREPARE_SHORT;
792       case Irrm_NEAREST:            return S390_BFP_ROUND_NEAREST_EVEN;
793       case Irrm_ZERO:               return S390_BFP_ROUND_ZERO;
794       case Irrm_PosINF:             return S390_BFP_ROUND_POSINF;
795       case Irrm_NegINF:             return S390_BFP_ROUND_NEGINF;
796       default:
797          vpanic("get_bfp_rounding_mode");
798       }
799    }
800 
801    set_bfp_rounding_mode_in_fpc(env, irrm);
802    return S390_BFP_ROUND_PER_FPC;
803 }
804 
805 
806 /*---------------------------------------------------------*/
807 /*--- DFP helper functions                              ---*/
808 /*---------------------------------------------------------*/
809 
810 /* Set the DFP rounding mode in the FPC. This function is called for
811    all non-conversion DFP instructions as those will always get the
812    rounding mode from the FPC. */
813 static void
set_dfp_rounding_mode_in_fpc(ISelEnv * env,IRExpr * irrm)814 set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
815 {
816    vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
817 
818    /* Do we need to do anything? */
819    if (env->previous_dfp_rounding_mode &&
820        env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
821        irrm->tag == Iex_RdTmp &&
822        env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
823       /* No - new mode is identical to previous mode.  */
824       return;
825    }
826 
827    /* No luck - we better set it, and remember what we set it to. */
828    env->previous_dfp_rounding_mode = irrm;
829 
830    /* The incoming rounding mode is in VEX IR encoding. Need to change
831       to s390.
832 
833       rounding mode                     | S390 |  IR
834       -----------------------------------------------
835       to nearest, ties to even          | 000  | 000
836       to zero                           | 001  | 011
837       to +infinity                      | 010  | 010
838       to -infinity                      | 011  | 001
839       to nearest, ties away from 0      | 100  | 100
840       to nearest, ties toward 0         | 101  | 111
841       to away from 0                    | 110  | 110
842       to prepare for shorter precision  | 111  | 101
843 
844       So: s390 = (IR ^ ((IR << 1) & 2))
845    */
846    HReg ir = s390_isel_int_expr(env, irrm);
847 
848    HReg mode = newVRegI(env);
849 
850    addInstr(env, s390_insn_move(4, mode, ir));
851    addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
852    addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
853    addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
854 
855    addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
856 }
857 
858 
859 /* This function is invoked for insns that support a specification of
860    a rounding mode in the insn itself. In that case there is no need to
861    stick the rounding mode into the FPC -- a good thing. However, the
862    rounding mode must be known.
863 
864    When mapping an Irrm_XYZ value to an S390_DFP_ROUND_ value there is
865    often a choice. For instance, Irrm_ZERO could be mapped to either
866    S390_DFP_ROUND_ZERO_5 or S390_DFP_ROUND_ZERO_9. The difference between
867    those two is that with S390_DFP_ROUND_ZERO_9 the recognition of the
868    quantum exception is suppressed whereas with S390_DFP_ROUND_ZERO_5 it
869    is not.  As the quantum exception is not modelled we can choose either
870    value. The choice is to use S390_DFP_ROUND_.. values in the range [8:15],
871    because values in the range [1:7] have unpredictable rounding behaviour
872    when the floating point exception facility is not installed.
873 
874    Translation table of
875    s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
876 
877    s390(S390_DFP_ROUND_)  |  IR(Irrm_)           |  s390(S390_DFP_ROUND_)
878    --------------------------------------------------------------------
879    NEAREST_TIE_AWAY_0_1   |  NEAREST_TIE_AWAY_0  |  NEAREST_TIE_AWAY_0_12
880    NEAREST_TIE_AWAY_0_12  |     "                |     "
881    PREPARE_SHORT_3        |  PREPARE_SHORTER     |  PREPARE_SHORT_15
882    PREPARE_SHORT_15       |     "                |     "
883    NEAREST_EVEN_4         |  NEAREST             |  NEAREST_EVEN_8
884    NEAREST_EVEN_8         |     "                |     "
885    ZERO_5                 |  ZERO                |  ZERO_9
886    ZERO_9                 |     "                |     "
887    POSINF_6               |  PosINF              |  POSINF_10
888    POSINF_10              |     "                |     "
889    NEGINF_7               |  NegINF              |  NEGINF_11
890    NEGINF_11              |     "                |     "
891    NEAREST_TIE_TOWARD_0   |  NEAREST_TIE_TOWARD_0|  NEAREST_TIE_TOWARD_0
892    AWAY_0                 |  AWAY_FROM_ZERO      |  AWAY_0
893 */
894 static s390_dfp_round_t
get_dfp_rounding_mode(ISelEnv * env,IRExpr * irrm)895 get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
896 {
897    if (irrm->tag == Iex_Const) {          /* rounding mode is known */
898       vassert(irrm->Iex.Const.con->tag == Ico_U32);
899       IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
900 
901       switch (mode) {
902       case Irrm_NEAREST:
903          return S390_DFP_ROUND_NEAREST_EVEN_8;
904       case Irrm_NegINF:
905          return S390_DFP_ROUND_NEGINF_11;
906       case Irrm_PosINF:
907          return S390_DFP_ROUND_POSINF_10;
908       case Irrm_ZERO:
909          return S390_DFP_ROUND_ZERO_9;
910       case Irrm_NEAREST_TIE_AWAY_0:
911          return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12;
912       case Irrm_PREPARE_SHORTER:
913           return S390_DFP_ROUND_PREPARE_SHORT_15;
914       case Irrm_AWAY_FROM_ZERO:
915          return S390_DFP_ROUND_AWAY_0;
916       case Irrm_NEAREST_TIE_TOWARD_0:
917          return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
918       default:
919          vpanic("get_dfp_rounding_mode");
920       }
921    }
922 
923    set_dfp_rounding_mode_in_fpc(env, irrm);
924    return S390_DFP_ROUND_PER_FPC_0;
925 }
926 
927 
928 /*---------------------------------------------------------*/
929 /*--- Condition code helper functions                   ---*/
930 /*---------------------------------------------------------*/
931 
932 /* CC_S390 holds the condition code in s390 encoding. Convert it to
933    VEX encoding (IRCmpFResult)
934 
935    s390     VEX              b6 b2 b0   cc.1  cc.0
936    0      0x40 EQ             1  0  0     0     0
937    1      0x01 LT             0  0  1     0     1
938    2      0x00 GT             0  0  0     1     0
939    3      0x45 Unordered      1  1  1     1     1
940 
941    b0 = cc.0
942    b2 = cc.0 & cc.1
943    b6 = ~(cc.0 ^ cc.1)   // ((cc.0 - cc.1) + 0x1 ) & 0x1
944 
945    VEX = b0 | (b2 << 2) | (b6 << 6);
946 */
947 static HReg
convert_s390_to_vex_bfpcc(ISelEnv * env,HReg cc_s390)948 convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
949 {
950    HReg cc0, cc1, b2, b6, cc_vex;
951 
952    cc0 = newVRegI(env);
953    addInstr(env, s390_insn_move(4, cc0, cc_s390));
954    addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
955 
956    cc1 = newVRegI(env);
957    addInstr(env, s390_insn_move(4, cc1, cc_s390));
958    addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
959 
960    b2 = newVRegI(env);
961    addInstr(env, s390_insn_move(4, b2, cc0));
962    addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
963    addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
964 
965    b6 = newVRegI(env);
966    addInstr(env, s390_insn_move(4, b6, cc0));
967    addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
968    addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
969    addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
970    addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
971 
972    cc_vex = newVRegI(env);
973    addInstr(env, s390_insn_move(4, cc_vex, cc0));
974    addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
975    addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
976 
977    return cc_vex;
978 }
979 
980 /* CC_S390 holds the condition code in s390 encoding. Convert it to
981    VEX encoding (IRCmpDResult) */
982 static HReg
convert_s390_to_vex_dfpcc(ISelEnv * env,HReg cc_s390)983 convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
984 {
985    /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
986    return convert_s390_to_vex_bfpcc(env, cc_s390);
987 }
988 
989 
990 /*---------------------------------------------------------*/
991 /*--- ISEL: Integer expressions (128 bit)               ---*/
992 /*---------------------------------------------------------*/
993 static void
s390_isel_int128_expr_wrk(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)994 s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
995                           IRExpr *expr)
996 {
997    IRType ty = typeOfIRExpr(env->type_env, expr);
998 
999    vassert(ty == Ity_I128);
1000 
1001    /* No need to consider the following
1002       - 128-bit constants (they do not exist in VEX)
1003       - 128-bit loads from memory (will not be generated)
1004    */
1005 
1006    /* Read 128-bit IRTemp */
1007    if (expr->tag == Iex_RdTmp) {
1008       lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1009       return;
1010    }
1011 
1012    if (expr->tag == Iex_Binop) {
1013       IRExpr *arg1 = expr->Iex.Binop.arg1;
1014       IRExpr *arg2 = expr->Iex.Binop.arg2;
1015       Bool is_signed_multiply, is_signed_divide;
1016 
1017       switch (expr->Iex.Binop.op) {
1018       case Iop_MullU64:
1019          is_signed_multiply = False;
1020          goto do_multiply64;
1021 
1022       case Iop_MullS64:
1023          is_signed_multiply = True;
1024          goto do_multiply64;
1025 
1026       case Iop_DivModU128to64:
1027          is_signed_divide = False;
1028          goto do_divide64;
1029 
1030       case Iop_DivModS128to64:
1031          is_signed_divide = True;
1032          goto do_divide64;
1033 
1034       case Iop_64HLto128:
1035          *dst_hi = s390_isel_int_expr(env, arg1);
1036          *dst_lo = s390_isel_int_expr(env, arg2);
1037          return;
1038 
1039       case Iop_DivModS64to64: {
1040          HReg r10, r11, h1;
1041          s390_opnd_RMI op2;
1042 
1043          h1  = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
1044          op2 = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1045 
1046          /* We use non-virtual registers r10 and r11 as pair */
1047          r10  = make_gpr(10);
1048          r11  = make_gpr(11);
1049 
1050          /* Move 1st operand into r11 and */
1051          addInstr(env, s390_insn_move(8, r11, h1));
1052 
1053          /* Divide */
1054          addInstr(env, s390_insn_divs(8, r10, r11, op2));
1055 
1056          /* The result is in registers r10 (remainder) and r11 (quotient).
1057             Move the result into the reg pair that is being returned such
1058             such that the low 64 bits are the quotient and the upper 64 bits
1059             are the remainder. (see libvex_ir.h). */
1060          *dst_hi = newVRegI(env);
1061          *dst_lo = newVRegI(env);
1062          addInstr(env, s390_insn_move(8, *dst_hi, r10));
1063          addInstr(env, s390_insn_move(8, *dst_lo, r11));
1064          return;
1065       }
1066 
1067       default:
1068          break;
1069 
1070       do_multiply64: {
1071             HReg r10, r11, h1;
1072             s390_opnd_RMI op2;
1073 
1074             order_commutative_operands(arg1, arg2);
1075 
1076             h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
1077             op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1078 
1079             /* We use non-virtual registers r10 and r11 as pair */
1080             r10  = make_gpr(10);
1081             r11  = make_gpr(11);
1082 
1083             /* Move the first operand to r11 */
1084             addInstr(env, s390_insn_move(8, r11, h1));
1085 
1086             /* Multiply */
1087             addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
1088 
1089             /* The result is in registers r10 and r11. Assign to two virtual regs
1090                and return. */
1091             *dst_hi = newVRegI(env);
1092             *dst_lo = newVRegI(env);
1093             addInstr(env, s390_insn_move(8, *dst_hi, r10));
1094             addInstr(env, s390_insn_move(8, *dst_lo, r11));
1095             return;
1096          }
1097 
1098       do_divide64: {
1099          HReg r10, r11, hi, lo;
1100          s390_opnd_RMI op2;
1101 
1102          s390_isel_int128_expr(&hi, &lo, env, arg1);
1103          op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1104 
1105          /* We use non-virtual registers r10 and r11 as pair */
1106          r10  = make_gpr(10);
1107          r11  = make_gpr(11);
1108 
1109          /* Move high 64 bits of the 1st operand into r10 and
1110             the low 64 bits into r11. */
1111          addInstr(env, s390_insn_move(8, r10, hi));
1112          addInstr(env, s390_insn_move(8, r11, lo));
1113 
1114          /* Divide */
1115          addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
1116 
1117          /* The result is in registers r10 (remainder) and r11 (quotient).
1118             Move the result into the reg pair that is being returned such
1119             such that the low 64 bits are the quotient and the upper 64 bits
1120             are the remainder. (see libvex_ir.h). */
1121          *dst_hi = newVRegI(env);
1122          *dst_lo = newVRegI(env);
1123          addInstr(env, s390_insn_move(8, *dst_hi, r10));
1124          addInstr(env, s390_insn_move(8, *dst_lo, r11));
1125          return;
1126       }
1127       }
1128    }
1129 
1130    vpanic("s390_isel_int128_expr");
1131 }
1132 
1133 
1134 /* Compute a 128-bit value into two 64-bit registers. These may be either
1135    real or virtual regs; in any case they must not be changed by subsequent
1136    code emitted by the caller. */
1137 static void
s390_isel_int128_expr(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)1138 s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1139 {
1140    s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
1141 
1142    /* Sanity checks ... */
1143    vassert(hregIsVirtual(*dst_hi));
1144    vassert(hregIsVirtual(*dst_lo));
1145    vassert(hregClass(*dst_hi) == HRcInt64);
1146    vassert(hregClass(*dst_lo) == HRcInt64);
1147 }
1148 
1149 
1150 /*---------------------------------------------------------*/
1151 /*--- ISEL: Integer expressions (64/32/16/8 bit)        ---*/
1152 /*---------------------------------------------------------*/
1153 
1154 /* Select insns for an integer-typed expression, and add them to the
1155    code list.  Return a reg holding the result.  This reg will be a
1156    virtual register.  THE RETURNED REG MUST NOT BE MODIFIED.  If you
1157    want to modify it, ask for a new vreg, copy it in there, and modify
1158    the copy.  The register allocator will do its best to map both
1159    vregs to the same real register, so the copies will often disappear
1160    later in the game.
1161 
1162    This should handle expressions of 64, 32, 16 and 8-bit type.
1163    All results are returned in a 64bit register.
1164    For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1165    are arbitrary, so you should mask or sign extend partial values
1166    if necessary.
1167 */
1168 
1169 /* DO NOT CALL THIS DIRECTLY ! */
1170 static HReg
s390_isel_int_expr_wrk(ISelEnv * env,IRExpr * expr)1171 s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
1172 {
1173    IRType ty = typeOfIRExpr(env->type_env, expr);
1174    UChar size;
1175    s390_bfp_conv_t conv;
1176    s390_dfp_conv_t dconv;
1177 
1178    vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
1179 
1180    size = sizeofIRType(ty);   /* size of the result after evaluating EXPR */
1181 
1182    switch (expr->tag) {
1183 
1184       /* --------- TEMP --------- */
1185    case Iex_RdTmp:
1186       /* Return the virtual register that holds the temporary. */
1187       return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1188 
1189       /* --------- LOAD --------- */
1190    case Iex_Load: {
1191       HReg        dst = newVRegI(env);
1192       s390_amode *am  = s390_isel_amode(env, expr->Iex.Load.addr);
1193 
1194       if (expr->Iex.Load.end != Iend_BE)
1195          goto irreducible;
1196 
1197       addInstr(env, s390_insn_load(size, dst, am));
1198 
1199       return dst;
1200    }
1201 
1202       /* --------- BINARY OP --------- */
1203    case Iex_Binop: {
1204       IRExpr *arg1 = expr->Iex.Binop.arg1;
1205       IRExpr *arg2 = expr->Iex.Binop.arg2;
1206       HReg h1, res;
1207       s390_alu_t opkind;
1208       s390_opnd_RMI op2, value, opnd;
1209       s390_insn *insn;
1210       Bool is_commutative, is_signed_multiply, is_signed_divide;
1211 
1212       is_commutative = True;
1213 
1214       switch (expr->Iex.Binop.op) {
1215       case Iop_MullU8:
1216       case Iop_MullU16:
1217       case Iop_MullU32:
1218          is_signed_multiply = False;
1219          goto do_multiply;
1220 
1221       case Iop_MullS8:
1222       case Iop_MullS16:
1223       case Iop_MullS32:
1224          is_signed_multiply = True;
1225          goto do_multiply;
1226 
1227       do_multiply: {
1228             HReg r10, r11;
1229             UInt arg_size = size / 2;
1230 
1231             order_commutative_operands(arg1, arg2);
1232 
1233             h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
1234             op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1235 
1236             /* We use non-virtual registers r10 and r11 as pair */
1237             r10  = make_gpr(10);
1238             r11  = make_gpr(11);
1239 
1240             /* Move the first operand to r11 */
1241             addInstr(env, s390_insn_move(arg_size, r11, h1));
1242 
1243             /* Multiply */
1244             addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1245 
1246             /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1247                value into the destination register. */
1248             res  = newVRegI(env);
1249             addInstr(env, s390_insn_move(arg_size, res, r10));
1250             value = s390_opnd_imm(arg_size * 8);
1251             addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1252             value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1253             addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1254             opnd = s390_opnd_reg(r11);
1255             addInstr(env, s390_insn_alu(size, S390_ALU_OR,  res, opnd));
1256             return res;
1257          }
1258 
1259       case Iop_DivModS64to32:
1260          is_signed_divide = True;
1261          goto do_divide;
1262 
1263       case Iop_DivModU64to32:
1264          is_signed_divide = False;
1265          goto do_divide;
1266 
1267       do_divide: {
1268             HReg r10, r11;
1269 
1270             h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
1271             op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1272 
1273             /* We use non-virtual registers r10 and r11 as pair */
1274             r10  = make_gpr(10);
1275             r11  = make_gpr(11);
1276 
1277             /* Split the first operand and put the high 32 bits into r10 and
1278                the low 32 bits into r11. */
1279             addInstr(env, s390_insn_move(8, r10, h1));
1280             addInstr(env, s390_insn_move(8, r11, h1));
1281             value = s390_opnd_imm(32);
1282             addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1283 
1284             /* Divide */
1285             addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1286 
1287             /* The result is in registers r10 (remainder) and r11 (quotient).
1288                Combine them into a 64-bit value such that the low 32 bits are
1289                the quotient and the upper 32 bits are the remainder. (see
1290                libvex_ir.h). */
1291             res  = newVRegI(env);
1292             addInstr(env, s390_insn_move(8, res, r10));
1293             value = s390_opnd_imm(32);
1294             addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1295             value = s390_opnd_imm((((ULong)1) << 32) - 1);
1296             addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1297             opnd = s390_opnd_reg(r11);
1298             addInstr(env, s390_insn_alu(8, S390_ALU_OR,  res, opnd));
1299             return res;
1300          }
1301 
1302       case Iop_F32toI32S:  conv = S390_BFP_F32_TO_I32;  goto do_convert;
1303       case Iop_F32toI64S:  conv = S390_BFP_F32_TO_I64;  goto do_convert;
1304       case Iop_F32toI32U:  conv = S390_BFP_F32_TO_U32;  goto do_convert;
1305       case Iop_F32toI64U:  conv = S390_BFP_F32_TO_U64;  goto do_convert;
1306       case Iop_F64toI32S:  conv = S390_BFP_F64_TO_I32;  goto do_convert;
1307       case Iop_F64toI64S:  conv = S390_BFP_F64_TO_I64;  goto do_convert;
1308       case Iop_F64toI32U:  conv = S390_BFP_F64_TO_U32;  goto do_convert;
1309       case Iop_F64toI64U:  conv = S390_BFP_F64_TO_U64;  goto do_convert;
1310       case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1311       case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1312       case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1313       case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
1314 
1315       case Iop_D64toI32S:  dconv = S390_DFP_D64_TO_I32;  goto do_convert_dfp;
1316       case Iop_D64toI64S:  dconv = S390_DFP_D64_TO_I64;  goto do_convert_dfp;
1317       case Iop_D64toI32U:  dconv = S390_DFP_D64_TO_U32;  goto do_convert_dfp;
1318       case Iop_D64toI64U:  dconv = S390_DFP_D64_TO_U64;  goto do_convert_dfp;
1319       case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
1320       case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128;
1321       case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1322       case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
1323 
1324       do_convert: {
1325          s390_bfp_round_t rounding_mode;
1326 
1327          res  = newVRegI(env);
1328          h1   = s390_isel_float_expr(env, arg2);   /* Process operand */
1329 
1330          rounding_mode = get_bfp_rounding_mode(env, arg1);
1331          addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1332                                              rounding_mode));
1333          return res;
1334       }
1335 
1336       do_convert_128: {
1337          s390_bfp_round_t rounding_mode;
1338          HReg op_hi, op_lo, f13, f15;
1339 
1340          res = newVRegI(env);
1341          s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1342 
1343          /* We use non-virtual registers r13 and r15 as pair */
1344          f13 = make_fpr(13);
1345          f15 = make_fpr(15);
1346 
1347          /* operand --> (f13, f15) */
1348          addInstr(env, s390_insn_move(8, f13, op_hi));
1349          addInstr(env, s390_insn_move(8, f15, op_lo));
1350 
1351          rounding_mode = get_bfp_rounding_mode(env, arg1);
1352          addInstr(env, s390_insn_bfp128_convert_from(size, conv, res,
1353                                                      INVALID_HREG, f13, f15,
1354                                                      rounding_mode));
1355          return res;
1356       }
1357 
1358       do_convert_dfp: {
1359             s390_dfp_round_t rounding_mode;
1360 
1361             res  = newVRegI(env);
1362             h1   = s390_isel_dfp_expr(env, arg2);   /* Process operand */
1363 
1364             rounding_mode = get_dfp_rounding_mode(env, arg1);
1365             addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
1366                                                 rounding_mode));
1367             return res;
1368          }
1369 
1370       do_convert_dfp128: {
1371             s390_dfp_round_t rounding_mode;
1372             HReg op_hi, op_lo, f13, f15;
1373 
1374             res = newVRegI(env);
1375             s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1376 
1377             /* We use non-virtual registers r13 and r15 as pair */
1378             f13 = make_fpr(13);
1379             f15 = make_fpr(15);
1380 
1381             /* operand --> (f13, f15) */
1382             addInstr(env, s390_insn_move(8, f13, op_hi));
1383             addInstr(env, s390_insn_move(8, f15, op_lo));
1384 
1385             rounding_mode = get_dfp_rounding_mode(env, arg1);
1386             addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res,
1387                                                         INVALID_HREG, f13,
1388                                                         f15, rounding_mode));
1389             return res;
1390          }
1391 
1392       case Iop_8HLto16:
1393       case Iop_16HLto32:
1394       case Iop_32HLto64: {
1395          HReg h2;
1396          UInt arg_size = size / 2;
1397 
1398          res  = newVRegI(env);
1399          h1   = s390_isel_int_expr(env, arg1);   /* Process 1st operand */
1400          h2   = s390_isel_int_expr(env, arg2);   /* Process 2nd operand */
1401 
1402          addInstr(env, s390_insn_move(arg_size, res, h1));
1403          value = s390_opnd_imm(arg_size * 8);
1404          addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1405          value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1406          addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1407          opnd = s390_opnd_reg(h2);
1408          addInstr(env, s390_insn_alu(size, S390_ALU_OR,  res, opnd));
1409          return res;
1410       }
1411 
1412       case Iop_Max32U: {
1413          /* arg1 > arg2 ? arg1 : arg2   using uint32_t arguments */
1414          res = newVRegI(env);
1415          h1  = s390_isel_int_expr(env, arg1);
1416          op2 = s390_isel_int_expr_RMI(env, arg2);
1417 
1418          addInstr(env, s390_insn_move(size, res, h1));
1419          addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1420          addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1421          return res;
1422       }
1423 
1424       case Iop_CmpF32:
1425       case Iop_CmpF64: {
1426          HReg cc_s390, h2;
1427 
1428          h1 = s390_isel_float_expr(env, arg1);
1429          h2 = s390_isel_float_expr(env, arg2);
1430          cc_s390 = newVRegI(env);
1431 
1432          size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1433 
1434          addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1435 
1436          return convert_s390_to_vex_bfpcc(env, cc_s390);
1437       }
1438 
1439       case Iop_CmpF128: {
1440          HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1441 
1442          s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1443          s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1444          cc_s390 = newVRegI(env);
1445 
1446          /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1447          f12 = make_fpr(12);
1448          f13 = make_fpr(13);
1449          f14 = make_fpr(14);
1450          f15 = make_fpr(15);
1451 
1452          /* 1st operand --> (f12, f14) */
1453          addInstr(env, s390_insn_move(8, f12, op1_hi));
1454          addInstr(env, s390_insn_move(8, f14, op1_lo));
1455 
1456          /* 2nd operand --> (f13, f15) */
1457          addInstr(env, s390_insn_move(8, f13, op2_hi));
1458          addInstr(env, s390_insn_move(8, f15, op2_lo));
1459 
1460          res = newVRegI(env);
1461          addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1462 
1463          return convert_s390_to_vex_bfpcc(env, cc_s390);
1464       }
1465 
1466       case Iop_CmpD64:
1467       case Iop_CmpExpD64: {
1468          HReg cc_s390, h2;
1469          s390_dfp_cmp_t cmp;
1470 
1471          h1 = s390_isel_dfp_expr(env, arg1);
1472          h2 = s390_isel_dfp_expr(env, arg2);
1473          cc_s390 = newVRegI(env);
1474 
1475          switch(expr->Iex.Binop.op) {
1476          case Iop_CmpD64:    cmp = S390_DFP_COMPARE; break;
1477          case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1478          default: goto irreducible;
1479          }
1480          addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
1481 
1482          return convert_s390_to_vex_dfpcc(env, cc_s390);
1483       }
1484 
1485       case Iop_CmpD128:
1486       case Iop_CmpExpD128: {
1487          HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1488          s390_dfp_cmp_t cmp;
1489 
1490          s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1491          s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1492          cc_s390 = newVRegI(env);
1493 
1494          /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1495          f12 = make_fpr(12);
1496          f13 = make_fpr(13);
1497          f14 = make_fpr(14);
1498          f15 = make_fpr(15);
1499 
1500          /* 1st operand --> (f12, f14) */
1501          addInstr(env, s390_insn_move(8, f12, op1_hi));
1502          addInstr(env, s390_insn_move(8, f14, op1_lo));
1503 
1504          /* 2nd operand --> (f13, f15) */
1505          addInstr(env, s390_insn_move(8, f13, op2_hi));
1506          addInstr(env, s390_insn_move(8, f15, op2_lo));
1507 
1508          switch(expr->Iex.Binop.op) {
1509          case Iop_CmpD128:    cmp = S390_DFP_COMPARE; break;
1510          case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1511          default: goto irreducible;
1512          }
1513          addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1514                                                 f13, f15));
1515 
1516          return convert_s390_to_vex_dfpcc(env, cc_s390);
1517       }
1518 
1519       case Iop_Add8:
1520       case Iop_Add16:
1521       case Iop_Add32:
1522       case Iop_Add64:
1523          opkind = S390_ALU_ADD;
1524          break;
1525 
1526       case Iop_Sub8:
1527       case Iop_Sub16:
1528       case Iop_Sub32:
1529       case Iop_Sub64:
1530          opkind = S390_ALU_SUB;
1531          is_commutative = False;
1532          break;
1533 
1534       case Iop_And8:
1535       case Iop_And16:
1536       case Iop_And32:
1537       case Iop_And64:
1538          opkind = S390_ALU_AND;
1539          break;
1540 
1541       case Iop_Or8:
1542       case Iop_Or16:
1543       case Iop_Or32:
1544       case Iop_Or64:
1545          opkind = S390_ALU_OR;
1546          break;
1547 
1548       case Iop_Xor8:
1549       case Iop_Xor16:
1550       case Iop_Xor32:
1551       case Iop_Xor64:
1552          opkind = S390_ALU_XOR;
1553          break;
1554 
1555       case Iop_Shl8:
1556       case Iop_Shl16:
1557       case Iop_Shl32:
1558       case Iop_Shl64:
1559          opkind = S390_ALU_LSH;
1560          is_commutative = False;
1561          break;
1562 
1563       case Iop_Shr8:
1564       case Iop_Shr16:
1565       case Iop_Shr32:
1566       case Iop_Shr64:
1567          opkind = S390_ALU_RSH;
1568          is_commutative = False;
1569          break;
1570 
1571       case Iop_Sar8:
1572       case Iop_Sar16:
1573       case Iop_Sar32:
1574       case Iop_Sar64:
1575          opkind = S390_ALU_RSHA;
1576          is_commutative = False;
1577          break;
1578 
1579       case Iop_GetElem8x16:
1580       case Iop_GetElem16x8:
1581       case Iop_GetElem32x4:
1582       case Iop_GetElem64x2:{
1583          HReg dst = newVRegI(env);
1584          HReg vec = s390_isel_vec_expr(env, arg1);
1585          s390_amode* operand = s390_isel_amode(env,IRExpr_Unop(Iop_8Uto64, arg2));
1586          switch (expr->Iex.Binop.op) {
1587          case Iop_GetElem8x16:
1588             size = 1;
1589             break;
1590          case Iop_GetElem16x8:
1591             size = 2;
1592             break;
1593          case Iop_GetElem32x4:
1594             size = 4;
1595             break;
1596          case Iop_GetElem64x2:
1597             size = 8;
1598             break;
1599          default:
1600             vpanic("s390_isel_int_expr: impossible Iop_GetElem type");
1601          }
1602          addInstr(env, s390_insn_vec_amodeop(size, S390_VEC_GET_ELEM, dst, vec, operand));
1603          return dst;
1604       }
1605       default:
1606          goto irreducible;
1607       }
1608 
1609       /* Pattern match: 0 - arg1  -->  -arg1   */
1610       if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1611          res  = newVRegI(env);
1612          op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1613          insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1614          addInstr(env, insn);
1615 
1616          return res;
1617       }
1618 
1619       if (is_commutative) {
1620          order_commutative_operands(arg1, arg2);
1621       }
1622 
1623       h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
1624       op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1625       res  = newVRegI(env);
1626 
1627       /* As right shifts of one/two byte opreands are implemented using a
1628          4-byte shift op, we first need to zero/sign-extend the shiftee. */
1629       switch (expr->Iex.Binop.op) {
1630       case Iop_Shr8:
1631          insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1632          break;
1633       case Iop_Shr16:
1634          insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1635          break;
1636       case Iop_Sar8:
1637          insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1638          break;
1639       case Iop_Sar16:
1640          insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1641          break;
1642       default:
1643          insn = s390_insn_move(size, res, h1);
1644          break;
1645       }
1646       addInstr(env, insn);
1647 
1648       insn = s390_insn_alu(size, opkind, res, op2);
1649 
1650       addInstr(env, insn);
1651 
1652       return res;
1653    }
1654 
1655       /* --------- UNARY OP --------- */
1656    case Iex_Unop: {
1657       static s390_opnd_RMI mask  = { S390_OPND_IMMEDIATE };
1658       static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1659       s390_opnd_RMI opnd;
1660       s390_insn    *insn;
1661       IRExpr *arg;
1662       HReg    dst, h1;
1663       IROp    unop, binop;
1664 
1665       arg = expr->Iex.Unop.arg;
1666 
1667       /* Special cases are handled here */
1668 
1669       /* 32-bit multiply with 32-bit result or
1670          64-bit multiply with 64-bit result */
1671       unop  = expr->Iex.Unop.op;
1672       binop = arg->Iex.Binop.op;
1673 
1674       if ((arg->tag == Iex_Binop &&
1675            ((unop == Iop_64to32 &&
1676              (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1677             (unop == Iop_128to64 &&
1678              (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1679          h1   = s390_isel_int_expr(env, arg->Iex.Binop.arg1);     /* 1st opnd */
1680          opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1681          dst  = newVRegI(env);     /* Result goes into a new register */
1682          addInstr(env, s390_insn_move(size, dst, h1));
1683          addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1684 
1685          return dst;
1686       }
1687 
1688       if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
1689          dst = newVRegI(env);
1690          h1  = s390_isel_float_expr(env, arg);     /* Process the operand */
1691          addInstr(env, s390_insn_move(size, dst, h1));
1692 
1693          return dst;
1694       }
1695 
1696       if (unop == Iop_ReinterpD64asI64) {
1697          dst = newVRegI(env);
1698          h1  = s390_isel_dfp_expr(env, arg);     /* Process the operand */
1699          addInstr(env, s390_insn_move(size, dst, h1));
1700 
1701          return dst;
1702       }
1703 
1704       if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
1705          s390_dfp_unop_t dfpop;
1706          switch(unop) {
1707          case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
1708          case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
1709          default: goto irreducible;
1710          }
1711          dst = newVRegI(env);
1712          h1  = s390_isel_dfp_expr(env, arg);     /* Process the operand */
1713          addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
1714          return dst;
1715       }
1716 
1717       if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
1718          s390_dfp_unop_t dfpop;
1719          HReg op_hi, op_lo, f13, f15;
1720 
1721          switch(unop) {
1722          case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
1723          case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
1724          default: goto irreducible;
1725          }
1726          dst = newVRegI(env);
1727          s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1728 
1729          /* We use non-virtual registers r13 and r15 as pair */
1730          f13 = make_fpr(13);
1731          f15 = make_fpr(15);
1732 
1733          /* operand --> (f13, f15) */
1734          addInstr(env, s390_insn_move(8, f13, op_hi));
1735          addInstr(env, s390_insn_move(8, f15, op_lo));
1736 
1737          addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
1738          return dst;
1739       }
1740 
1741       /* Expressions whose argument is 1-bit wide */
1742       if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1743          s390_cc_t cond = s390_isel_cc(env, arg);
1744          dst = newVRegI(env);     /* Result goes into a new register */
1745          addInstr(env, s390_insn_cc2bool(dst, cond));
1746 
1747          switch (unop) {
1748          case Iop_1Uto8:
1749          case Iop_1Uto32:
1750             /* Zero extend */
1751             mask.variant.imm = 1;
1752             addInstr(env, s390_insn_alu(4, S390_ALU_AND,  dst, mask));
1753             break;
1754 
1755          case Iop_1Uto64:
1756             /* Zero extend */
1757             mask.variant.imm = 1;
1758             addInstr(env, s390_insn_alu(8, S390_ALU_AND,  dst, mask));
1759             break;
1760 
1761          case Iop_1Sto8:
1762          case Iop_1Sto16:
1763          case Iop_1Sto32:
1764             shift.variant.imm = 31;
1765             addInstr(env, s390_insn_alu(4, S390_ALU_LSH,  dst, shift));
1766             addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1767             break;
1768 
1769          case Iop_1Sto64:
1770             shift.variant.imm = 63;
1771             addInstr(env, s390_insn_alu(8, S390_ALU_LSH,  dst, shift));
1772             addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1773             break;
1774 
1775          default:
1776             goto irreducible;
1777          }
1778 
1779          return dst;
1780       }
1781 
1782       /* Regular processing */
1783 
1784       if (unop == Iop_128to64) {
1785          HReg dst_hi, dst_lo;
1786 
1787          s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1788          return dst_lo;
1789       }
1790 
1791       if (unop == Iop_128HIto64) {
1792          HReg dst_hi, dst_lo;
1793 
1794          s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1795          return dst_hi;
1796       }
1797 
1798       if(unop == Iop_V128to64 || unop == Iop_V128HIto64 || unop == Iop_V128to32) {
1799          dst = newVRegI(env);
1800          HReg vec = s390_isel_vec_expr(env, arg);
1801          /* This is big-endian machine */
1802          Int off;
1803          switch (unop) {
1804             case Iop_V128HIto64:
1805                off = 0;
1806                break;
1807             case Iop_V128to64:
1808                off = 8;
1809                break;
1810             case Iop_V128to32:
1811                off = 12;
1812                break;
1813             default:
1814                ppIROp(unop);
1815                vpanic("s390_isel_int_expr: unhandled V128toSMTH operation");
1816          }
1817          s390_amode* m16_sp = s390_amode_for_stack_pointer(0);
1818          s390_amode* off_sp = s390_amode_for_stack_pointer(off);
1819 
1820          /* We could use negative displacement but vector instructions
1821             require 12bit unsigned ones. So we have to allocate space on
1822             stack just for one load and free it after. */
1823          sub_from_SP(env, 16);
1824          addInstr(env, s390_insn_store(sizeof(V128), m16_sp, vec));
1825          addInstr(env, s390_insn_load(sizeof(ULong), dst, off_sp));
1826          add_to_SP(env, 16);
1827          return dst;
1828       }
1829 
1830       dst  = newVRegI(env);     /* Result goes into a new register */
1831       opnd = s390_isel_int_expr_RMI(env, arg);     /* Process the operand */
1832 
1833       switch (unop) {
1834       case Iop_8Uto16:
1835       case Iop_8Uto32:
1836       case Iop_8Uto64:
1837          insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1838          break;
1839 
1840       case Iop_16Uto32:
1841       case Iop_16Uto64:
1842          insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1843          break;
1844 
1845       case Iop_32Uto64:
1846          insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1847          break;
1848 
1849       case Iop_8Sto16:
1850       case Iop_8Sto32:
1851       case Iop_8Sto64:
1852          insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1853          break;
1854 
1855       case Iop_16Sto32:
1856       case Iop_16Sto64:
1857          insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1858          break;
1859 
1860       case Iop_32Sto64:
1861          insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1862          break;
1863 
1864       case Iop_64to8:
1865       case Iop_64to16:
1866       case Iop_64to32:
1867       case Iop_32to8:
1868       case Iop_32to16:
1869       case Iop_16to8:
1870          /* Down-casts are no-ops. Upstream operations will only look at
1871             the bytes that make up the result of the down-cast. So there
1872             is no point setting the other bytes to 0. */
1873          insn = s390_opnd_copy(8, dst, opnd);
1874          break;
1875 
1876       case Iop_64HIto32:
1877          addInstr(env, s390_opnd_copy(8, dst, opnd));
1878          shift.variant.imm = 32;
1879          insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1880          break;
1881 
1882       case Iop_32HIto16:
1883          addInstr(env, s390_opnd_copy(4, dst, opnd));
1884          shift.variant.imm = 16;
1885          insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1886          break;
1887 
1888       case Iop_16HIto8:
1889          addInstr(env, s390_opnd_copy(2, dst, opnd));
1890          shift.variant.imm = 8;
1891          insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1892          break;
1893 
1894       case Iop_Not8:
1895       case Iop_Not16:
1896       case Iop_Not32:
1897       case Iop_Not64:
1898          /* XOR with ffff... */
1899          mask.variant.imm = ~(ULong)0;
1900          addInstr(env, s390_opnd_copy(size, dst, opnd));
1901          insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1902          break;
1903 
1904       case Iop_Left8:
1905       case Iop_Left16:
1906       case Iop_Left32:
1907       case Iop_Left64:
1908          addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1909          insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1910          break;
1911 
1912       case Iop_CmpwNEZ32:
1913       case Iop_CmpwNEZ64: {
1914          /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1915             or -X will have a 1 in the MSB. */
1916          addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1917          addInstr(env, s390_insn_alu(size, S390_ALU_OR,  dst, opnd));
1918          shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1919          addInstr(env, s390_insn_alu(size, S390_ALU_RSHA,  dst, shift));
1920          return dst;
1921       }
1922 
1923       case Iop_Clz64: {
1924          HReg r10, r11;
1925 
1926          /* This will be implemented using FLOGR, if possible. So we need to
1927             set aside a pair of non-virtual registers. The result (number of
1928             left-most zero bits) will be in r10. The value in r11 is unspecified
1929             and must not be used. */
1930          r10  = make_gpr(10);
1931          r11  = make_gpr(11);
1932 
1933          addInstr(env, s390_insn_clz(8, r10, r11, opnd));
1934          addInstr(env, s390_insn_move(8, dst, r10));
1935          return dst;
1936       }
1937 
1938       default:
1939          goto irreducible;
1940       }
1941 
1942       addInstr(env, insn);
1943 
1944       return dst;
1945    }
1946 
1947       /* --------- GET --------- */
1948    case Iex_Get: {
1949       HReg dst = newVRegI(env);
1950       s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1951 
1952       /* We never load more than 8 bytes from the guest state, because the
1953          floating point register pair is not contiguous. */
1954       vassert(size <= 8);
1955 
1956       addInstr(env, s390_insn_load(size, dst, am));
1957 
1958       return dst;
1959    }
1960 
1961    case Iex_GetI:
1962       /* not needed */
1963       break;
1964 
1965       /* --------- CCALL --------- */
1966    case Iex_CCall: {
1967       HReg dst = newVRegI(env);
1968       HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
1969       UInt   addToSp = 0;
1970       RetLoc rloc    = mk_RetLoc_INVALID();
1971 
1972       doHelperCall(&addToSp, &rloc, env, NULL, expr->Iex.CCall.cee,
1973                    expr->Iex.CCall.retty, expr->Iex.CCall.args);
1974       vassert(is_sane_RetLoc(rloc));
1975       vassert(rloc.pri == RLPri_Int);
1976       vassert(addToSp == 0);
1977       addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
1978 
1979       return dst;
1980    }
1981 
1982       /* --------- LITERAL --------- */
1983 
1984       /* Load a literal into a register. Create a "load immediate"
1985          v-insn and return the register. */
1986    case Iex_Const: {
1987       ULong value;
1988       HReg  dst = newVRegI(env);
1989       const IRConst *con = expr->Iex.Const.con;
1990 
1991       /* Bitwise copy of the value. No sign/zero-extension */
1992       switch (con->tag) {
1993       case Ico_U64: value = con->Ico.U64; break;
1994       case Ico_U32: value = con->Ico.U32; break;
1995       case Ico_U16: value = con->Ico.U16; break;
1996       case Ico_U8:  value = con->Ico.U8;  break;
1997       default:      vpanic("s390_isel_int_expr: invalid constant");
1998       }
1999 
2000       addInstr(env, s390_insn_load_immediate(size, dst, value));
2001 
2002       return dst;
2003    }
2004 
2005       /* --------- MULTIPLEX --------- */
2006    case Iex_ITE: {
2007       IRExpr *cond_expr;
2008       HReg dst, r1;
2009       s390_opnd_RMI r0;
2010 
2011       cond_expr = expr->Iex.ITE.cond;
2012 
2013       vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
2014 
2015       dst  = newVRegI(env);
2016       r0   = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
2017       r1   = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
2018       size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
2019 
2020       s390_cc_t cc = s390_isel_cc(env, cond_expr);
2021 
2022       addInstr(env, s390_insn_move(size, dst, r1));
2023       addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
2024       return dst;
2025    }
2026 
2027    default:
2028       break;
2029    }
2030 
2031    /* We get here if no pattern matched. */
2032  irreducible:
2033    ppIRExpr(expr);
2034    vpanic("s390_isel_int_expr: cannot reduce tree");
2035 }
2036 
2037 
2038 static HReg
s390_isel_int_expr(ISelEnv * env,IRExpr * expr)2039 s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
2040 {
2041    HReg dst = s390_isel_int_expr_wrk(env, expr);
2042 
2043    /* Sanity checks ... */
2044    vassert(hregClass(dst) == HRcInt64);
2045    vassert(hregIsVirtual(dst));
2046 
2047    return dst;
2048 }
2049 
2050 
2051 static s390_opnd_RMI
s390_isel_int_expr_RMI(ISelEnv * env,IRExpr * expr)2052 s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
2053 {
2054    IRType ty = typeOfIRExpr(env->type_env, expr);
2055    s390_opnd_RMI dst;
2056 
2057    vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
2058            ty == Ity_I64);
2059 
2060    if (expr->tag == Iex_Load) {
2061       dst.tag = S390_OPND_AMODE;
2062       dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
2063    } else if (expr->tag == Iex_Get) {
2064       dst.tag = S390_OPND_AMODE;
2065       dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2066    } else if (expr->tag == Iex_Const) {
2067       ULong value;
2068 
2069       /* The bit pattern for the value will be stored as is in the least
2070          significant bits of VALUE. */
2071       switch (expr->Iex.Const.con->tag) {
2072       case Ico_U1:  value = expr->Iex.Const.con->Ico.U1;  break;
2073       case Ico_U8:  value = expr->Iex.Const.con->Ico.U8;  break;
2074       case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
2075       case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
2076       case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
2077       default:
2078          vpanic("s390_isel_int_expr_RMI");
2079       }
2080 
2081       dst.tag = S390_OPND_IMMEDIATE;
2082       dst.variant.imm = value;
2083    } else {
2084       dst.tag = S390_OPND_REG;
2085       dst.variant.reg = s390_isel_int_expr(env, expr);
2086    }
2087 
2088    return dst;
2089 }
2090 
2091 
2092 /*---------------------------------------------------------*/
2093 /*--- ISEL: Floating point expressions (128 bit)        ---*/
2094 /*---------------------------------------------------------*/
2095 static void
s390_isel_float128_expr_wrk(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)2096 s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2097                             IRExpr *expr)
2098 {
2099    IRType ty = typeOfIRExpr(env->type_env, expr);
2100 
2101    vassert(ty == Ity_F128);
2102 
2103    switch (expr->tag) {
2104    case Iex_RdTmp:
2105       /* Return the virtual registers that hold the temporary. */
2106       lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2107       return;
2108 
2109       /* --------- LOAD --------- */
2110    case Iex_Load: {
2111       IRExpr *addr_hi, *addr_lo;
2112       s390_amode *am_hi, *am_lo;
2113 
2114       if (expr->Iex.Load.end != Iend_BE)
2115          goto irreducible;
2116 
2117       addr_hi = expr->Iex.Load.addr;
2118       addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2119 
2120       am_hi  = s390_isel_amode(env, addr_hi);
2121       am_lo  = s390_isel_amode(env, addr_lo);
2122 
2123       *dst_hi = newVRegF(env);
2124       *dst_lo = newVRegF(env);
2125       addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2126       addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2127       return;
2128    }
2129 
2130 
2131       /* --------- GET --------- */
2132    case Iex_Get:
2133       /* This is not supported because loading 128-bit from the guest
2134          state is almost certainly wrong. Use get_fpr_pair instead. */
2135       vpanic("Iex_Get with F128 data");
2136 
2137       /* --------- 4-ary OP --------- */
2138    case Iex_Qop:
2139       vpanic("Iex_Qop with F128 data");
2140 
2141       /* --------- TERNARY OP --------- */
2142    case Iex_Triop: {
2143       IRTriop *triop = expr->Iex.Triop.details;
2144       IROp    op     = triop->op;
2145       IRExpr *left   = triop->arg2;
2146       IRExpr *right  = triop->arg3;
2147       s390_bfp_binop_t bfpop;
2148       HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
2149 
2150       s390_isel_float128_expr(&op1_hi, &op1_lo, env, left);  /* 1st operand */
2151       s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2152 
2153       /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2154       f12 = make_fpr(12);
2155       f13 = make_fpr(13);
2156       f14 = make_fpr(14);
2157       f15 = make_fpr(15);
2158 
2159       /* 1st operand --> (f12, f14) */
2160       addInstr(env, s390_insn_move(8, f12, op1_hi));
2161       addInstr(env, s390_insn_move(8, f14, op1_lo));
2162 
2163       /* 2nd operand --> (f13, f15) */
2164       addInstr(env, s390_insn_move(8, f13, op2_hi));
2165       addInstr(env, s390_insn_move(8, f15, op2_lo));
2166 
2167       switch (op) {
2168       case Iop_AddF128: bfpop = S390_BFP_ADD; break;
2169       case Iop_SubF128: bfpop = S390_BFP_SUB; break;
2170       case Iop_MulF128: bfpop = S390_BFP_MUL; break;
2171       case Iop_DivF128: bfpop = S390_BFP_DIV; break;
2172       default:
2173          goto irreducible;
2174       }
2175 
2176       set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2177       addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
2178 
2179       /* Move result to virtual destination register */
2180       *dst_hi = newVRegF(env);
2181       *dst_lo = newVRegF(env);
2182       addInstr(env, s390_insn_move(8, *dst_hi, f12));
2183       addInstr(env, s390_insn_move(8, *dst_lo, f14));
2184 
2185       return;
2186    }
2187 
2188       /* --------- BINARY OP --------- */
2189    case Iex_Binop: {
2190       switch (expr->Iex.Binop.op) {
2191       case Iop_SqrtF128: {
2192          HReg op_hi, op_lo, f12, f13, f14, f15;
2193 
2194          /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2195          f12 = make_fpr(12);
2196          f13 = make_fpr(13);
2197          f14 = make_fpr(14);
2198          f15 = make_fpr(15);
2199 
2200          s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
2201 
2202          /* operand --> (f13, f15) */
2203          addInstr(env, s390_insn_move(8, f13, op_hi));
2204          addInstr(env, s390_insn_move(8, f15, op_lo));
2205 
2206          set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
2207          addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
2208                                              f13, f15));
2209 
2210          /* Move result to virtual destination registers */
2211          *dst_hi = newVRegF(env);
2212          *dst_lo = newVRegF(env);
2213          addInstr(env, s390_insn_move(8, *dst_hi, f12));
2214          addInstr(env, s390_insn_move(8, *dst_lo, f14));
2215          return;
2216       }
2217 
2218       case Iop_F64HLtoF128:
2219          *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
2220          *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
2221          return;
2222 
2223       case Iop_D32toF128:
2224       case Iop_D64toF128: {
2225          IRExpr *irrm;
2226          IRExpr *left;
2227          s390_dfp_round_t rm;
2228          HReg h1; /* virtual reg. to hold source */
2229          HReg f0, f2, f4, r1; /* real registers used by PFPO */
2230          s390_fp_conv_t fpconv;
2231 
2232          switch (expr->Iex.Binop.op) {
2233          case Iop_D32toF128:
2234             fpconv = S390_FP_D32_TO_F128;
2235             break;
2236          case Iop_D64toF128:
2237             fpconv = S390_FP_D64_TO_F128;
2238             break;
2239          default: goto irreducible;
2240          }
2241 
2242          f4 = make_fpr(4); /* source */
2243          f0 = make_fpr(0); /* destination */
2244          f2 = make_fpr(2); /* destination */
2245          r1 = make_gpr(1); /* GPR #1 clobbered */
2246          irrm = expr->Iex.Binop.arg1;
2247          left = expr->Iex.Binop.arg2;
2248          rm = get_dfp_rounding_mode(env, irrm);
2249          h1 = s390_isel_dfp_expr(env, left);
2250          addInstr(env, s390_insn_move(8, f4, h1));
2251          addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
2252                                                f4, INVALID_HREG, r1, rm));
2253          /* (f0, f2) --> destination */
2254          *dst_hi = newVRegF(env);
2255          *dst_lo = newVRegF(env);
2256          addInstr(env, s390_insn_move(8, *dst_hi, f0));
2257          addInstr(env, s390_insn_move(8, *dst_lo, f2));
2258 
2259          return;
2260       }
2261 
2262       case Iop_D128toF128: {
2263          IRExpr *irrm;
2264          IRExpr *left;
2265          s390_dfp_round_t rm;
2266          HReg op_hi, op_lo;
2267          HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2268 
2269          f4 = make_fpr(4); /* source */
2270          f6 = make_fpr(6); /* source */
2271          f0 = make_fpr(0); /* destination */
2272          f2 = make_fpr(2); /* destination */
2273          r1 = make_gpr(1); /* GPR #1 clobbered */
2274 
2275          irrm = expr->Iex.Binop.arg1;
2276          left = expr->Iex.Binop.arg2;
2277          rm = get_dfp_rounding_mode(env, irrm);
2278          s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2279          /* operand --> (f4, f6) */
2280          addInstr(env, s390_insn_move(8, f4, op_hi));
2281          addInstr(env, s390_insn_move(8, f6, op_lo));
2282          addInstr(env, s390_insn_fp128_convert(16, S390_FP_D128_TO_F128, f0, f2,
2283                                                f4, f6, r1, rm));
2284          /* (f0, f2) --> destination */
2285          *dst_hi = newVRegF(env);
2286          *dst_lo = newVRegF(env);
2287          addInstr(env, s390_insn_move(8, *dst_hi, f0));
2288          addInstr(env, s390_insn_move(8, *dst_lo, f2));
2289 
2290          return;
2291       }
2292 
2293       case Iop_RoundF128toInt: {
2294          IRExpr *irrm;
2295          IRExpr *left;
2296          s390_bfp_round_t rm;
2297          HReg op_hi, op_lo;
2298          HReg f0, f2, f4, f6;           /* real registers */
2299 
2300          f4 = make_fpr(4); /* source */
2301          f6 = make_fpr(6); /* source */
2302          f0 = make_fpr(0); /* destination */
2303          f2 = make_fpr(2); /* destination */
2304 
2305          irrm = expr->Iex.Binop.arg1;
2306          left = expr->Iex.Binop.arg2;
2307 
2308          if (s390_host_has_fpext) {
2309             rm = get_bfp_rounding_mode(env, irrm);
2310          } else {
2311             set_bfp_rounding_mode_in_fpc(env, irrm);
2312             rm = S390_BFP_ROUND_PER_FPC;
2313          }
2314 
2315          s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2316          /* operand --> (f4, f6) */
2317          addInstr(env, s390_insn_move(8, f4, op_hi));
2318          addInstr(env, s390_insn_move(8, f6, op_lo));
2319          addInstr(env, s390_insn_bfp128_convert(16, S390_BFP_F128_TO_F128I,
2320                                                 f0, f2, f4, f6, rm));
2321          /* (f0, f2) --> destination */
2322          *dst_hi = newVRegF(env);
2323          *dst_lo = newVRegF(env);
2324          addInstr(env, s390_insn_move(8, *dst_hi, f0));
2325          addInstr(env, s390_insn_move(8, *dst_lo, f2));
2326          return;
2327       }
2328 
2329       default:
2330          goto irreducible;
2331       }
2332    }
2333 
2334       /* --------- UNARY OP --------- */
2335    case Iex_Unop: {
2336       IRExpr *left = expr->Iex.Unop.arg;
2337       s390_bfp_unop_t bfpop;
2338       s390_bfp_conv_t conv;
2339       HReg op_hi, op_lo, op, f12, f13, f14, f15;
2340 
2341       /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2342       f12 = make_fpr(12);
2343       f13 = make_fpr(13);
2344       f14 = make_fpr(14);
2345       f15 = make_fpr(15);
2346 
2347       switch (expr->Iex.Unop.op) {
2348       case Iop_NegF128:
2349          if (left->tag == Iex_Unop &&
2350              (left->Iex.Unop.op == Iop_AbsF32 ||
2351               left->Iex.Unop.op == Iop_AbsF64))
2352             bfpop = S390_BFP_NABS;
2353          else
2354             bfpop = S390_BFP_NEG;
2355          goto float128_opnd;
2356       case Iop_AbsF128:     bfpop = S390_BFP_ABS;         goto float128_opnd;
2357       case Iop_I32StoF128:  conv = S390_BFP_I32_TO_F128;  goto convert_int;
2358       case Iop_I64StoF128:  conv = S390_BFP_I64_TO_F128;  goto convert_int;
2359       case Iop_I32UtoF128:  conv = S390_BFP_U32_TO_F128;  goto convert_int;
2360       case Iop_I64UtoF128:  conv = S390_BFP_U64_TO_F128;  goto convert_int;
2361       case Iop_F32toF128:   conv = S390_BFP_F32_TO_F128;  goto convert_float;
2362       case Iop_F64toF128:   conv = S390_BFP_F64_TO_F128;  goto convert_float;
2363       default:
2364          goto irreducible;
2365       }
2366 
2367    float128_opnd:
2368       s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2369 
2370       /* operand --> (f13, f15) */
2371       addInstr(env, s390_insn_move(8, f13, op_hi));
2372       addInstr(env, s390_insn_move(8, f15, op_lo));
2373 
2374       addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
2375       goto move_dst;
2376 
2377    convert_float:
2378       op  = s390_isel_float_expr(env, left);
2379       addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
2380       goto move_dst;
2381 
2382    convert_int:
2383       op  = s390_isel_int_expr(env, left);
2384       addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
2385       goto move_dst;
2386 
2387    move_dst:
2388       /* Move result to virtual destination registers */
2389       *dst_hi = newVRegF(env);
2390       *dst_lo = newVRegF(env);
2391       addInstr(env, s390_insn_move(8, *dst_hi, f12));
2392       addInstr(env, s390_insn_move(8, *dst_lo, f14));
2393       return;
2394    }
2395 
2396    default:
2397       goto irreducible;
2398    }
2399 
2400    /* We get here if no pattern matched. */
2401  irreducible:
2402    ppIRExpr(expr);
2403    vpanic("s390_isel_float128_expr: cannot reduce tree");
2404 }
2405 
2406 /* Compute a 128-bit value into two 64-bit registers. These may be either
2407    real or virtual regs; in any case they must not be changed by subsequent
2408    code emitted by the caller. */
2409 static void
s390_isel_float128_expr(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)2410 s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2411 {
2412    s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2413 
2414    /* Sanity checks ... */
2415    vassert(hregIsVirtual(*dst_hi));
2416    vassert(hregIsVirtual(*dst_lo));
2417    vassert(hregClass(*dst_hi) == HRcFlt64);
2418    vassert(hregClass(*dst_lo) == HRcFlt64);
2419 }
2420 
2421 
2422 /*---------------------------------------------------------*/
2423 /*--- ISEL: Floating point expressions (64 bit)         ---*/
2424 /*---------------------------------------------------------*/
2425 
2426 static HReg
s390_isel_float_expr_wrk(ISelEnv * env,IRExpr * expr)2427 s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2428 {
2429    IRType ty = typeOfIRExpr(env->type_env, expr);
2430    UChar size;
2431 
2432    vassert(ty == Ity_F32 || ty == Ity_F64);
2433 
2434    size = sizeofIRType(ty);
2435 
2436    switch (expr->tag) {
2437    case Iex_RdTmp:
2438       /* Return the virtual register that holds the temporary. */
2439       return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2440 
2441       /* --------- LOAD --------- */
2442    case Iex_Load: {
2443       HReg        dst = newVRegF(env);
2444       s390_amode *am  = s390_isel_amode(env, expr->Iex.Load.addr);
2445 
2446       if (expr->Iex.Load.end != Iend_BE)
2447          goto irreducible;
2448 
2449       addInstr(env, s390_insn_load(size, dst, am));
2450 
2451       return dst;
2452    }
2453 
2454       /* --------- GET --------- */
2455    case Iex_Get: {
2456       HReg dst = newVRegF(env);
2457       s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2458 
2459       addInstr(env, s390_insn_load(size, dst, am));
2460 
2461       return dst;
2462    }
2463 
2464       /* --------- LITERAL --------- */
2465 
2466       /* Load a literal into a register. Create a "load immediate"
2467          v-insn and return the register. */
2468    case Iex_Const: {
2469       ULong value;
2470       HReg  dst = newVRegF(env);
2471       const IRConst *con = expr->Iex.Const.con;
2472 
2473       /* Bitwise copy of the value. No sign/zero-extension */
2474       switch (con->tag) {
2475       case Ico_F32i: value = con->Ico.F32i; break;
2476       case Ico_F64i: value = con->Ico.F64i; break;
2477       default:       vpanic("s390_isel_float_expr: invalid constant");
2478       }
2479 
2480       if (value != 0) vpanic("cannot load immediate floating point constant");
2481 
2482       addInstr(env, s390_insn_load_immediate(size, dst, value));
2483 
2484       return dst;
2485    }
2486 
2487       /* --------- 4-ary OP --------- */
2488    case Iex_Qop: {
2489       HReg op1, op2, op3, dst;
2490       s390_bfp_triop_t bfpop;
2491 
2492       op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
2493       op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
2494       op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
2495       dst = newVRegF(env);
2496       addInstr(env, s390_insn_move(size, dst, op1));
2497 
2498       switch (expr->Iex.Qop.details->op) {
2499       case Iop_MAddF32:
2500       case Iop_MAddF64:  bfpop = S390_BFP_MADD; break;
2501       case Iop_MSubF32:
2502       case Iop_MSubF64:  bfpop = S390_BFP_MSUB; break;
2503 
2504       default:
2505          goto irreducible;
2506       }
2507 
2508       set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2509       addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
2510       return dst;
2511    }
2512 
2513       /* --------- TERNARY OP --------- */
2514    case Iex_Triop: {
2515       IRTriop *triop = expr->Iex.Triop.details;
2516       IROp    op     = triop->op;
2517       IRExpr *left   = triop->arg2;
2518       IRExpr *right  = triop->arg3;
2519       s390_bfp_binop_t bfpop;
2520       HReg h1, op2, dst;
2521 
2522       h1   = s390_isel_float_expr(env, left);  /* Process 1st operand */
2523       op2  = s390_isel_float_expr(env, right); /* Process 2nd operand */
2524       dst  = newVRegF(env);
2525       addInstr(env, s390_insn_move(size, dst, h1));
2526       switch (op) {
2527       case Iop_AddF32:
2528       case Iop_AddF64:  bfpop = S390_BFP_ADD; break;
2529       case Iop_SubF32:
2530       case Iop_SubF64:  bfpop = S390_BFP_SUB; break;
2531       case Iop_MulF32:
2532       case Iop_MulF64:  bfpop = S390_BFP_MUL; break;
2533       case Iop_DivF32:
2534       case Iop_DivF64:  bfpop = S390_BFP_DIV; break;
2535 
2536       default:
2537          goto irreducible;
2538       }
2539 
2540       set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2541       addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
2542       return dst;
2543    }
2544 
2545       /* --------- BINARY OP --------- */
2546    case Iex_Binop: {
2547       IROp    op   = expr->Iex.Binop.op;
2548       IRExpr *irrm = expr->Iex.Binop.arg1;
2549       IRExpr *left = expr->Iex.Binop.arg2;
2550       HReg h1, dst;
2551       s390_bfp_conv_t  conv;
2552       s390_fp_conv_t fpconv;
2553 
2554       switch (op) {
2555       case Iop_SqrtF32:
2556       case Iop_SqrtF64:
2557          h1  = s390_isel_float_expr(env, left);
2558          dst = newVRegF(env);
2559          set_bfp_rounding_mode_in_fpc(env, irrm);
2560          addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
2561          return dst;
2562 
2563       case Iop_F64toF32:  conv = S390_BFP_F64_TO_F32; goto convert_float;
2564       case Iop_RoundF32toInt: conv = S390_BFP_F32_TO_F32I; goto convert_float;
2565       case Iop_RoundF64toInt: conv = S390_BFP_F64_TO_F64I; goto convert_float;
2566       case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2567       case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2568       case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2569       case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2570       case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2571       case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
2572       case Iop_D32toF32:  fpconv = S390_FP_D32_TO_F32;  goto convert_dfp;
2573       case Iop_D32toF64:  fpconv = S390_FP_D32_TO_F64;  goto convert_dfp;
2574       case Iop_D64toF32:  fpconv = S390_FP_D64_TO_F32;  goto convert_dfp;
2575       case Iop_D64toF64:  fpconv = S390_FP_D64_TO_F64;  goto convert_dfp;
2576       case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128;
2577       case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
2578 
2579       convert_float:
2580          h1 = s390_isel_float_expr(env, left);
2581          goto convert;
2582 
2583       convert_int:
2584          h1 = s390_isel_int_expr(env, left);
2585          goto convert;
2586 
2587       convert: {
2588          s390_bfp_round_t rounding_mode;
2589          /* convert-from-fixed and load-rounded have a rounding mode field
2590             when the floating point extension facility is installed. */
2591          dst = newVRegF(env);
2592          if (s390_host_has_fpext) {
2593             rounding_mode = get_bfp_rounding_mode(env, irrm);
2594          } else {
2595             set_bfp_rounding_mode_in_fpc(env, irrm);
2596             rounding_mode = S390_BFP_ROUND_PER_FPC;
2597          }
2598          addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2599                                              rounding_mode));
2600          return dst;
2601       }
2602 
2603       convert_dfp: {
2604          s390_dfp_round_t rm;
2605          HReg f0, f4, r1; /* real registers used by PFPO */
2606 
2607          f4 = make_fpr(4); /* source */
2608          f0 = make_fpr(0); /* destination */
2609          r1 = make_gpr(1); /* GPR #1 clobbered */
2610          h1 = s390_isel_dfp_expr(env, left);
2611          dst = newVRegF(env);
2612          rm = get_dfp_rounding_mode(env, irrm);
2613          /* operand --> f4 */
2614          addInstr(env, s390_insn_move(8, f4, h1));
2615          addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2616          /* f0 --> destination */
2617          addInstr(env, s390_insn_move(8, dst, f0));
2618          return dst;
2619       }
2620 
2621       convert_dfp128: {
2622          s390_dfp_round_t rm;
2623          HReg op_hi, op_lo;
2624          HReg f0, f4, f6, r1; /* real registers used by PFPO */
2625 
2626          f4 = make_fpr(4); /* source */
2627          f6 = make_fpr(6); /* source */
2628          f0 = make_fpr(0); /* destination */
2629          r1 = make_gpr(1); /* GPR #1 clobbered */
2630          s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2631          dst = newVRegF(env);
2632          rm = get_dfp_rounding_mode(env, irrm);
2633          /* operand --> (f4, f6) */
2634          addInstr(env, s390_insn_move(8, f4, op_hi));
2635          addInstr(env, s390_insn_move(8, f6, op_lo));
2636          addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
2637                                                f4, f6, r1, rm));
2638          /* f0 --> destination */
2639          addInstr(env, s390_insn_move(8, dst, f0));
2640          return dst;
2641       }
2642 
2643       default:
2644          goto irreducible;
2645 
2646       case Iop_F128toF64:
2647       case Iop_F128toF32: {
2648          HReg op_hi, op_lo, f12, f13, f14, f15;
2649          s390_bfp_round_t rounding_mode;
2650 
2651          conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2652                                     : S390_BFP_F128_TO_F64;
2653 
2654          s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2655 
2656          /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2657          f12 = make_fpr(12);
2658          f13 = make_fpr(13);
2659          f14 = make_fpr(14);
2660          f15 = make_fpr(15);
2661 
2662          /* operand --> (f13, f15) */
2663          addInstr(env, s390_insn_move(8, f13, op_hi));
2664          addInstr(env, s390_insn_move(8, f15, op_lo));
2665 
2666          /* result --> (f12, f14) */
2667 
2668          /* load-rounded has a rounding mode field when the floating point
2669             extension facility is installed. */
2670          if (s390_host_has_fpext) {
2671             rounding_mode = get_bfp_rounding_mode(env, irrm);
2672          } else {
2673             set_bfp_rounding_mode_in_fpc(env, irrm);
2674             rounding_mode = S390_BFP_ROUND_PER_FPC;
2675          }
2676 
2677          addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14,
2678                                                      f13, f15, rounding_mode));
2679          dst = newVRegF(env);
2680          addInstr(env, s390_insn_move(8, dst, f12));
2681 
2682          return dst;
2683       }
2684       }
2685    }
2686 
2687       /* --------- UNARY OP --------- */
2688    case Iex_Unop: {
2689       IROp    op   = expr->Iex.Unop.op;
2690       IRExpr *left = expr->Iex.Unop.arg;
2691       s390_bfp_unop_t bfpop;
2692       s390_bfp_conv_t conv;
2693       HReg h1, dst;
2694 
2695       if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2696          HReg dst_hi, dst_lo;
2697 
2698          s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2699          return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2700       }
2701 
2702       if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
2703          dst = newVRegF(env);
2704          h1  = s390_isel_int_expr(env, left);     /* Process the operand */
2705          addInstr(env, s390_insn_move(size, dst, h1));
2706 
2707          return dst;
2708       }
2709 
2710       switch (op) {
2711       case Iop_NegF32:
2712       case Iop_NegF64:
2713          if (left->tag == Iex_Unop &&
2714              (left->Iex.Unop.op == Iop_AbsF32 ||
2715               left->Iex.Unop.op == Iop_AbsF64))
2716             bfpop = S390_BFP_NABS;
2717          else
2718             bfpop = S390_BFP_NEG;
2719          break;
2720 
2721       case Iop_AbsF32:
2722       case Iop_AbsF64:
2723          bfpop = S390_BFP_ABS;
2724          break;
2725 
2726       case Iop_I32StoF64:  conv = S390_BFP_I32_TO_F64;  goto convert_int1;
2727       case Iop_I32UtoF64:  conv = S390_BFP_U32_TO_F64;  goto convert_int1;
2728       case Iop_F32toF64:   conv = S390_BFP_F32_TO_F64;  goto convert_float1;
2729 
2730       convert_float1:
2731          h1 = s390_isel_float_expr(env, left);
2732          goto convert1;
2733 
2734       convert_int1:
2735          h1 = s390_isel_int_expr(env, left);
2736          goto convert1;
2737 
2738       convert1:
2739          dst = newVRegF(env);
2740          /* No rounding mode is needed for these conversions. Just stick
2741             one in. It won't be used later on. */
2742          addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2743                                              S390_BFP_ROUND_NEAREST_EVEN));
2744          return dst;
2745 
2746       default:
2747          goto irreducible;
2748       }
2749 
2750       /* Process operand */
2751       h1  = s390_isel_float_expr(env, left);
2752       dst = newVRegF(env);
2753       addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
2754       return dst;
2755    }
2756 
2757    default:
2758       goto irreducible;
2759    }
2760 
2761    /* We get here if no pattern matched. */
2762  irreducible:
2763    ppIRExpr(expr);
2764    vpanic("s390_isel_float_expr: cannot reduce tree");
2765 }
2766 
2767 
2768 static HReg
s390_isel_float_expr(ISelEnv * env,IRExpr * expr)2769 s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2770 {
2771    HReg dst = s390_isel_float_expr_wrk(env, expr);
2772 
2773    /* Sanity checks ... */
2774    vassert(hregClass(dst) == HRcFlt64);
2775    vassert(hregIsVirtual(dst));
2776 
2777    return dst;
2778 }
2779 
2780 
2781 /*---------------------------------------------------------*/
2782 /*--- ISEL: Decimal point expressions (128 bit)         ---*/
2783 /*---------------------------------------------------------*/
2784 static void
s390_isel_dfp128_expr_wrk(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)2785 s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2786                           IRExpr *expr)
2787 {
2788    IRType ty = typeOfIRExpr(env->type_env, expr);
2789 
2790    vassert(ty == Ity_D128);
2791 
2792    switch (expr->tag) {
2793    case Iex_RdTmp:
2794       /* Return the virtual registers that hold the temporary. */
2795       lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2796       return;
2797 
2798       /* --------- LOAD --------- */
2799    case Iex_Load: {
2800       IRExpr *addr_hi, *addr_lo;
2801       s390_amode *am_hi, *am_lo;
2802 
2803       if (expr->Iex.Load.end != Iend_BE)
2804          goto irreducible;
2805 
2806       addr_hi = expr->Iex.Load.addr;
2807       addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2808 
2809       am_hi  = s390_isel_amode(env, addr_hi);
2810       am_lo  = s390_isel_amode(env, addr_lo);
2811 
2812       *dst_hi = newVRegF(env);
2813       *dst_lo = newVRegF(env);
2814       addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2815       addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2816       return;
2817    }
2818 
2819       /* --------- GET --------- */
2820    case Iex_Get:
2821       /* This is not supported because loading 128-bit from the guest
2822          state is almost certainly wrong. Use get_dpr_pair instead. */
2823       vpanic("Iex_Get with D128 data");
2824 
2825       /* --------- 4-ary OP --------- */
2826    case Iex_Qop:
2827       vpanic("Iex_Qop with D128 data");
2828 
2829       /* --------- TERNARY OP --------- */
2830    case Iex_Triop: {
2831       IRTriop *triop = expr->Iex.Triop.details;
2832       IROp    op     = triop->op;
2833       IRExpr *irrm   = triop->arg1;
2834       IRExpr *left   = triop->arg2;
2835       IRExpr *right  = triop->arg3;
2836       s390_dfp_round_t rounding_mode;
2837       s390_dfp_binop_t dfpop;
2838       HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2839 
2840       /* We use non-virtual registers as pairs with (f9, f11) as op1,
2841          (f12, f14) as op2 and (f13, f15)  as destination) */
2842       f9  = make_fpr(9);
2843       f11 = make_fpr(11);
2844       f12 = make_fpr(12);
2845       f13 = make_fpr(13);
2846       f14 = make_fpr(14);
2847       f15 = make_fpr(15);
2848 
2849       switch (op) {
2850       case Iop_AddD128:       dfpop = S390_DFP_ADD;      goto evaluate_dfp128;
2851       case Iop_SubD128:       dfpop = S390_DFP_SUB;      goto evaluate_dfp128;
2852       case Iop_MulD128:       dfpop = S390_DFP_MUL;      goto evaluate_dfp128;
2853       case Iop_DivD128:       dfpop = S390_DFP_DIV;      goto evaluate_dfp128;
2854       case Iop_QuantizeD128:  dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
2855 
2856       evaluate_dfp128: {
2857          /* Process 1st operand */
2858          s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
2859          /* 1st operand --> (f9, f11) */
2860          addInstr(env, s390_insn_move(8, f9,  op1_hi));
2861          addInstr(env, s390_insn_move(8, f11, op1_lo));
2862 
2863          /* Process 2nd operand */
2864          s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2865          /* 2nd operand --> (f12, f14) */
2866          addInstr(env, s390_insn_move(8, f12, op2_hi));
2867          addInstr(env, s390_insn_move(8, f14, op2_lo));
2868 
2869          /* DFP arithmetic ops take rounding mode only when fpext is
2870             installed. But, DFP quantize operation takes rm irrespective
2871             of fpext facility . */
2872          if (s390_host_has_fpext || op == Iop_QuantizeD128) {
2873             rounding_mode = get_dfp_rounding_mode(env, irrm);
2874          } else {
2875             set_dfp_rounding_mode_in_fpc(env, irrm);
2876             rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2877          }
2878          addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2879                                               f12, f14, rounding_mode));
2880          /* Move result to virtual destination register */
2881          *dst_hi = newVRegF(env);
2882          *dst_lo = newVRegF(env);
2883          addInstr(env, s390_insn_move(8, *dst_hi, f13));
2884          addInstr(env, s390_insn_move(8, *dst_lo, f15));
2885          return;
2886       }
2887 
2888       case Iop_SignificanceRoundD128: {
2889          /* Process 1st operand */
2890          HReg op1 = s390_isel_int_expr(env, left);
2891          /* Process 2nd operand */
2892          s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2893          /* 2nd operand --> (f12, f14) */
2894          addInstr(env, s390_insn_move(8, f12, op2_hi));
2895          addInstr(env, s390_insn_move(8, f14, op2_lo));
2896 
2897          rounding_mode = get_dfp_rounding_mode(env, irrm);
2898          addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14,
2899                                                 rounding_mode));
2900          /* Move result to virtual destination register */
2901          *dst_hi = newVRegF(env);
2902          *dst_lo = newVRegF(env);
2903          addInstr(env, s390_insn_move(8, *dst_hi, f13));
2904          addInstr(env, s390_insn_move(8, *dst_lo, f15));
2905          return;
2906       }
2907 
2908       default:
2909          goto irreducible;
2910       }
2911    }
2912 
2913       /* --------- BINARY OP --------- */
2914    case Iex_Binop: {
2915 
2916       switch (expr->Iex.Binop.op) {
2917       case Iop_D64HLtoD128:
2918          *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2919          *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2920          return;
2921 
2922       case Iop_ShlD128:
2923       case Iop_ShrD128:
2924       case Iop_InsertExpD128: {
2925          HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2926          s390_dfp_intop_t intop;
2927          IRExpr *dfp_op;
2928          IRExpr *int_op;
2929 
2930          switch (expr->Iex.Binop.op) {
2931          case Iop_ShlD128:       /* (D128, I64) -> D128 */
2932             intop = S390_DFP_SHIFT_LEFT;
2933             dfp_op = expr->Iex.Binop.arg1;
2934             int_op = expr->Iex.Binop.arg2;
2935             break;
2936          case Iop_ShrD128:       /* (D128, I64) -> D128 */
2937             intop = S390_DFP_SHIFT_RIGHT;
2938             dfp_op = expr->Iex.Binop.arg1;
2939             int_op = expr->Iex.Binop.arg2;
2940             break;
2941          case Iop_InsertExpD128: /* (I64, D128) -> D128 */
2942             intop = S390_DFP_INSERT_EXP;
2943             int_op = expr->Iex.Binop.arg1;
2944             dfp_op = expr->Iex.Binop.arg2;
2945             break;
2946          default: goto irreducible;
2947          }
2948 
2949          /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2950          f9  = make_fpr(9); /* 128 bit dfp operand */
2951          f11 = make_fpr(11);
2952 
2953          f13 = make_fpr(13); /* 128 bit dfp destination */
2954          f15 = make_fpr(15);
2955 
2956          /* Process dfp operand */
2957          s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
2958          /* op1 -> (f9,f11) */
2959          addInstr(env, s390_insn_move(8, f9,  op1_hi));
2960          addInstr(env, s390_insn_move(8, f11, op1_lo));
2961 
2962          op2 = s390_isel_int_expr(env, int_op);  /* int operand */
2963 
2964          addInstr(env,
2965                   s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2966 
2967          /* Move result to virtual destination register */
2968          *dst_hi = newVRegF(env);
2969          *dst_lo = newVRegF(env);
2970          addInstr(env, s390_insn_move(8, *dst_hi, f13));
2971          addInstr(env, s390_insn_move(8, *dst_lo, f15));
2972          return;
2973       }
2974 
2975       case Iop_F32toD128:
2976       case Iop_F64toD128: {
2977          IRExpr *irrm;
2978          IRExpr *left;
2979          s390_dfp_round_t rm;
2980          HReg h1; /* virtual reg. to hold source */
2981          HReg f0, f2, f4, r1; /* real registers used by PFPO */
2982          s390_fp_conv_t fpconv;
2983 
2984          switch (expr->Iex.Binop.op) {
2985          case Iop_F32toD128:       /* (D128, I64) -> D128 */
2986             fpconv = S390_FP_F32_TO_D128;
2987             break;
2988          case Iop_F64toD128:       /* (D128, I64) -> D128 */
2989             fpconv = S390_FP_F64_TO_D128;
2990             break;
2991          default: goto irreducible;
2992          }
2993 
2994          f4 = make_fpr(4); /* source */
2995          f0 = make_fpr(0); /* destination */
2996          f2 = make_fpr(2); /* destination */
2997          r1 = make_gpr(1); /* GPR #1 clobbered */
2998          irrm = expr->Iex.Binop.arg1;
2999          left = expr->Iex.Binop.arg2;
3000          rm = get_dfp_rounding_mode(env, irrm);
3001          h1 = s390_isel_float_expr(env, left);
3002          addInstr(env, s390_insn_move(8, f4, h1));
3003          addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
3004                                                f4, INVALID_HREG, r1, rm));
3005          /* (f0, f2) --> destination */
3006          *dst_hi = newVRegF(env);
3007          *dst_lo = newVRegF(env);
3008          addInstr(env, s390_insn_move(8, *dst_hi, f0));
3009          addInstr(env, s390_insn_move(8, *dst_lo, f2));
3010 
3011          return;
3012       }
3013 
3014       case Iop_F128toD128: {
3015          IRExpr *irrm;
3016          IRExpr *left;
3017          s390_dfp_round_t rm;
3018          HReg op_hi, op_lo;
3019          HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
3020 
3021          f4 = make_fpr(4); /* source */
3022          f6 = make_fpr(6); /* source */
3023          f0 = make_fpr(0); /* destination */
3024          f2 = make_fpr(2); /* destination */
3025          r1 = make_gpr(1); /* GPR #1 clobbered */
3026 
3027          irrm = expr->Iex.Binop.arg1;
3028          left = expr->Iex.Binop.arg2;
3029          rm = get_dfp_rounding_mode(env, irrm);
3030          s390_isel_float128_expr(&op_hi, &op_lo, env, left);
3031          /* operand --> (f4, f6) */
3032          addInstr(env, s390_insn_move(8, f4, op_hi));
3033          addInstr(env, s390_insn_move(8, f6, op_lo));
3034          addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2,
3035                                                f4, f6, r1, rm));
3036          /* (f0, f2) --> destination */
3037          *dst_hi = newVRegF(env);
3038          *dst_lo = newVRegF(env);
3039          addInstr(env, s390_insn_move(8, *dst_hi, f0));
3040          addInstr(env, s390_insn_move(8, *dst_lo, f2));
3041 
3042          return;
3043       }
3044 
3045       default:
3046          goto irreducible;
3047       }
3048    }
3049 
3050       /* --------- UNARY OP --------- */
3051    case Iex_Unop: {
3052       IRExpr *left = expr->Iex.Unop.arg;
3053       s390_dfp_conv_t conv;
3054       HReg op, f12, f14;
3055 
3056       /* We use non-virtual registers as pairs (f12, f14)) */
3057       f12 = make_fpr(12);
3058       f14 = make_fpr(14);
3059 
3060       switch (expr->Iex.Unop.op) {
3061       case Iop_D64toD128:   conv = S390_DFP_D64_TO_D128;  goto convert_dfp;
3062       case Iop_I32StoD128:  conv = S390_DFP_I32_TO_D128;  goto convert_int;
3063       case Iop_I64StoD128:  conv = S390_DFP_I64_TO_D128;  goto convert_int;
3064       case Iop_I32UtoD128:  conv = S390_DFP_U32_TO_D128;  goto convert_int;
3065       case Iop_I64UtoD128:  conv = S390_DFP_U64_TO_D128;  goto convert_int;
3066       default:
3067          goto irreducible;
3068       }
3069 
3070    convert_dfp:
3071       op  = s390_isel_dfp_expr(env, left);
3072       addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
3073       goto move_dst;
3074 
3075    convert_int:
3076       op  = s390_isel_int_expr(env, left);
3077       addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
3078       goto move_dst;
3079 
3080    move_dst:
3081       /* Move result to virtual destination registers */
3082       *dst_hi = newVRegF(env);
3083       *dst_lo = newVRegF(env);
3084       addInstr(env, s390_insn_move(8, *dst_hi, f12));
3085       addInstr(env, s390_insn_move(8, *dst_lo, f14));
3086       return;
3087    }
3088 
3089    default:
3090       goto irreducible;
3091    }
3092 
3093    /* We get here if no pattern matched. */
3094  irreducible:
3095    ppIRExpr(expr);
3096    vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
3097 
3098 }
3099 
3100 
3101 /* Compute a 128-bit value into two 64-bit registers. These may be either
3102    real or virtual regs; in any case they must not be changed by subsequent
3103    code emitted by the caller. */
3104 static void
s390_isel_dfp128_expr(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)3105 s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
3106 {
3107    s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
3108 
3109    /* Sanity checks ... */
3110    vassert(hregIsVirtual(*dst_hi));
3111    vassert(hregIsVirtual(*dst_lo));
3112    vassert(hregClass(*dst_hi) == HRcFlt64);
3113    vassert(hregClass(*dst_lo) == HRcFlt64);
3114 }
3115 
3116 
3117 /*---------------------------------------------------------*/
3118 /*--- ISEL: Decimal point expressions (64 bit)          ---*/
3119 /*---------------------------------------------------------*/
3120 
3121 static HReg
s390_isel_dfp_expr_wrk(ISelEnv * env,IRExpr * expr)3122 s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
3123 {
3124    IRType ty = typeOfIRExpr(env->type_env, expr);
3125    UChar size;
3126 
3127    vassert(ty == Ity_D64 || ty == Ity_D32);
3128 
3129    size = sizeofIRType(ty);
3130 
3131    switch (expr->tag) {
3132    case Iex_RdTmp:
3133       /* Return the virtual register that holds the temporary. */
3134       return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
3135 
3136       /* --------- LOAD --------- */
3137    case Iex_Load: {
3138       HReg        dst = newVRegF(env);
3139       s390_amode *am  = s390_isel_amode(env, expr->Iex.Load.addr);
3140 
3141       if (expr->Iex.Load.end != Iend_BE)
3142          goto irreducible;
3143 
3144       addInstr(env, s390_insn_load(size, dst, am));
3145 
3146       return dst;
3147    }
3148 
3149       /* --------- GET --------- */
3150    case Iex_Get: {
3151       HReg dst = newVRegF(env);
3152       s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
3153 
3154       addInstr(env, s390_insn_load(size, dst, am));
3155 
3156       return dst;
3157    }
3158 
3159       /* --------- BINARY OP --------- */
3160    case Iex_Binop: {
3161       IROp    op   = expr->Iex.Binop.op;
3162       IRExpr *irrm = expr->Iex.Binop.arg1;
3163       IRExpr *left = expr->Iex.Binop.arg2;
3164       HReg h1, dst;
3165       s390_dfp_conv_t  conv;
3166       s390_fp_conv_t  fpconv;
3167 
3168       switch (op) {
3169       case Iop_D64toD32:  conv = S390_DFP_D64_TO_D32; goto convert_dfp;
3170       case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
3171       case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
3172       case Iop_F32toD32:  fpconv = S390_FP_F32_TO_D32; goto convert_bfp;
3173       case Iop_F32toD64:  fpconv = S390_FP_F32_TO_D64; goto convert_bfp;
3174       case Iop_F64toD32:  fpconv = S390_FP_F64_TO_D32; goto convert_bfp;
3175       case Iop_F64toD64:  fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
3176       case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128;
3177       case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128;
3178 
3179       convert_dfp:
3180          h1 = s390_isel_dfp_expr(env, left);
3181          goto convert;
3182 
3183       convert_int:
3184          h1 = s390_isel_int_expr(env, left);
3185          goto convert;
3186 
3187       convert: {
3188             s390_dfp_round_t rounding_mode;
3189             /* convert-from-fixed and load-rounded have a rounding mode field
3190                when the floating point extension facility is installed. */
3191             dst = newVRegF(env);
3192             if (s390_host_has_fpext) {
3193                rounding_mode = get_dfp_rounding_mode(env, irrm);
3194             } else {
3195                set_dfp_rounding_mode_in_fpc(env, irrm);
3196                rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3197             }
3198             addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3199                                                 rounding_mode));
3200             return dst;
3201          }
3202 
3203       convert_bfp: {
3204          s390_dfp_round_t rm;
3205          HReg f0, f4, r1; /* real registers used by PFPO */
3206 
3207          f4 = make_fpr(4); /* source */
3208          f0 = make_fpr(0); /* destination */
3209          r1 = make_gpr(1); /* GPR #1 clobbered */
3210          h1 = s390_isel_float_expr(env, left);
3211          dst = newVRegF(env);
3212          rm = get_dfp_rounding_mode(env, irrm);
3213          /* operand --> f4 */
3214          addInstr(env, s390_insn_move(8, f4, h1));
3215          addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
3216          /* f0 --> destination */
3217          addInstr(env, s390_insn_move(8, dst, f0));
3218          return dst;
3219       }
3220 
3221       convert_bfp128: {
3222          s390_dfp_round_t rm;
3223          HReg op_hi, op_lo;
3224          HReg f0, f4, f6, r1; /* real registers used by PFPO */
3225 
3226          f4 = make_fpr(4); /* source */
3227          f6 = make_fpr(6); /* source */
3228          f0 = make_fpr(0); /* destination */
3229          r1 = make_gpr(1); /* GPR #1 clobbered */
3230          s390_isel_float128_expr(&op_hi, &op_lo, env, left);
3231          dst = newVRegF(env);
3232          rm = get_dfp_rounding_mode(env, irrm);
3233          /* operand --> (f4, f6) */
3234          addInstr(env, s390_insn_move(8, f4, op_hi));
3235          addInstr(env, s390_insn_move(8, f6, op_lo));
3236          addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
3237                                                f4, f6, r1, rm));
3238          /* f0 --> destination */
3239          addInstr(env, s390_insn_move(8, dst, f0));
3240          return dst;
3241       }
3242 
3243       case Iop_D128toD64: {
3244          HReg op_hi, op_lo, f12, f13, f14, f15;
3245          s390_dfp_round_t rounding_mode;
3246 
3247          conv = S390_DFP_D128_TO_D64;
3248 
3249          s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
3250 
3251          /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */
3252          f12 = make_fpr(12);
3253          f13 = make_fpr(13);
3254          f14 = make_fpr(14);
3255          f15 = make_fpr(15);
3256 
3257          /* operand --> (f13, f15) */
3258          addInstr(env, s390_insn_move(8, f13, op_hi));
3259          addInstr(env, s390_insn_move(8, f15, op_lo));
3260 
3261          /* result --> (f12, f14) */
3262 
3263          /* load-rounded has a rounding mode field when the floating point
3264             extension facility is installed. */
3265          if (s390_host_has_fpext) {
3266             rounding_mode = get_dfp_rounding_mode(env, irrm);
3267          } else {
3268             set_dfp_rounding_mode_in_fpc(env, irrm);
3269             rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3270          }
3271          addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14,
3272                                                      f13, f15, rounding_mode));
3273          dst = newVRegF(env);
3274          addInstr(env, s390_insn_move(8, dst, f12));
3275 
3276          return dst;
3277       }
3278 
3279       case Iop_ShlD64:
3280       case Iop_ShrD64:
3281       case Iop_InsertExpD64: {
3282          HReg op2;
3283          HReg op3;
3284          IRExpr *dfp_op;
3285          IRExpr *int_op;
3286          s390_dfp_intop_t intop;
3287 
3288          switch (expr->Iex.Binop.op) {
3289          case Iop_ShlD64:       /* (D64, I64) -> D64 */
3290             intop = S390_DFP_SHIFT_LEFT;
3291             dfp_op = expr->Iex.Binop.arg1;
3292             int_op = expr->Iex.Binop.arg2;
3293             break;
3294          case Iop_ShrD64:       /* (D64, I64) -> D64 */
3295             intop = S390_DFP_SHIFT_RIGHT;
3296             dfp_op = expr->Iex.Binop.arg1;
3297             int_op = expr->Iex.Binop.arg2;
3298             break;
3299          case Iop_InsertExpD64: /* (I64, D64) -> D64 */
3300             intop = S390_DFP_INSERT_EXP;
3301             int_op = expr->Iex.Binop.arg1;
3302             dfp_op = expr->Iex.Binop.arg2;
3303             break;
3304          default: goto irreducible;
3305          }
3306 
3307          op2 = s390_isel_int_expr(env, int_op);
3308          op3 = s390_isel_dfp_expr(env, dfp_op);
3309          dst = newVRegF(env);
3310 
3311          addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
3312          return dst;
3313       }
3314 
3315       default:
3316          goto irreducible;
3317       }
3318    }
3319 
3320       /* --------- UNARY OP --------- */
3321    case Iex_Unop: {
3322       IROp    op   = expr->Iex.Unop.op;
3323       IRExpr *left = expr->Iex.Unop.arg;
3324       s390_dfp_conv_t conv;
3325       HReg h1, dst;
3326 
3327       if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
3328          HReg dst_hi, dst_lo;
3329 
3330          s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
3331          return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
3332       }
3333 
3334       if (op == Iop_ReinterpI64asD64) {
3335          dst = newVRegF(env);
3336          h1  = s390_isel_int_expr(env, left);     /* Process the operand */
3337          addInstr(env, s390_insn_move(size, dst, h1));
3338 
3339          return dst;
3340       }
3341 
3342       switch (op) {
3343       case Iop_D32toD64:  conv = S390_DFP_D32_TO_D64;  goto convert_dfp1;
3344       case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64;  goto convert_int1;
3345       case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64;  goto convert_int1;
3346 
3347       convert_dfp1:
3348          h1 = s390_isel_dfp_expr(env, left);
3349          goto convert1;
3350 
3351       convert_int1:
3352          h1 = s390_isel_int_expr(env, left);
3353          goto convert1;
3354 
3355       convert1:
3356          dst = newVRegF(env);
3357          /* No rounding mode is needed for these conversions. Just stick
3358             one in. It won't be used later on. */
3359          addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3360                                              S390_DFP_ROUND_NEAREST_EVEN_4));
3361          return dst;
3362 
3363       default:
3364          goto irreducible;
3365       }
3366    }
3367 
3368       /* --------- TERNARY OP --------- */
3369    case Iex_Triop: {
3370       IRTriop *triop = expr->Iex.Triop.details;
3371       IROp    op     = triop->op;
3372       IRExpr *irrm   = triop->arg1;
3373       IRExpr *left   = triop->arg2;
3374       IRExpr *right  = triop->arg3;
3375       s390_dfp_round_t rounding_mode;
3376       s390_dfp_binop_t dfpop;
3377       HReg op2, op3, dst;
3378 
3379       switch (op) {
3380       case Iop_AddD64:      dfpop = S390_DFP_ADD;      goto evaluate_dfp;
3381       case Iop_SubD64:      dfpop = S390_DFP_SUB;      goto evaluate_dfp;
3382       case Iop_MulD64:      dfpop = S390_DFP_MUL;      goto evaluate_dfp;
3383       case Iop_DivD64:      dfpop = S390_DFP_DIV;      goto evaluate_dfp;
3384       case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
3385 
3386       evaluate_dfp: {
3387          op2  = s390_isel_dfp_expr(env, left);  /* Process 1st operand */
3388          op3  = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3389          dst  = newVRegF(env);
3390          /* DFP arithmetic ops take rounding mode only when fpext is
3391             installed. But, DFP quantize operation takes rm irrespective
3392             of fpext facility . */
3393          if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
3394             rounding_mode = get_dfp_rounding_mode(env, irrm);
3395          } else {
3396             set_dfp_rounding_mode_in_fpc(env, irrm);
3397             rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3398          }
3399          addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3,
3400                                            rounding_mode));
3401          return dst;
3402       }
3403 
3404       case Iop_SignificanceRoundD64:
3405          op2  = s390_isel_int_expr(env, left);  /* Process 1st operand */
3406          op3  = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3407          dst  = newVRegF(env);
3408          rounding_mode = get_dfp_rounding_mode(env, irrm);
3409          addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3,
3410                                              rounding_mode));
3411          return dst;
3412 
3413       default:
3414          goto irreducible;
3415       }
3416    }
3417 
3418    default:
3419       goto irreducible;
3420    }
3421 
3422    /* We get here if no pattern matched. */
3423  irreducible:
3424    ppIRExpr(expr);
3425    vpanic("s390_isel_dfp_expr: cannot reduce tree");
3426 }
3427 
3428 static HReg
s390_isel_dfp_expr(ISelEnv * env,IRExpr * expr)3429 s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
3430 {
3431    HReg dst = s390_isel_dfp_expr_wrk(env, expr);
3432 
3433    /* Sanity checks ... */
3434    vassert(hregClass(dst) == HRcFlt64);
3435    vassert(hregIsVirtual(dst));
3436 
3437    return dst;
3438 }
3439 
3440 
3441 /*---------------------------------------------------------*/
3442 /*--- ISEL: Condition Code                              ---*/
3443 /*---------------------------------------------------------*/
3444 
3445 /* This function handles all operators that produce a 1-bit result */
3446 static s390_cc_t
s390_isel_cc(ISelEnv * env,IRExpr * cond)3447 s390_isel_cc(ISelEnv *env, IRExpr *cond)
3448 {
3449    UChar size;
3450 
3451    vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
3452 
3453    /* Constant: either 1 or 0 */
3454    if (cond->tag == Iex_Const) {
3455       vassert(cond->Iex.Const.con->tag == Ico_U1);
3456       vassert(cond->Iex.Const.con->Ico.U1 == True
3457               || cond->Iex.Const.con->Ico.U1 == False);
3458 
3459       return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
3460    }
3461 
3462    /* Variable: values are 1 or 0 */
3463    if (cond->tag == Iex_RdTmp) {
3464       IRTemp tmp = cond->Iex.RdTmp.tmp;
3465       HReg   reg = lookupIRTemp(env, tmp);
3466 
3467       /* Load-and-test does not modify REG; so this is OK. */
3468       if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
3469          size = 4;
3470       else
3471          size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
3472       addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
3473       return S390_CC_NE;
3474    }
3475 
3476    /* Unary operators */
3477    if (cond->tag == Iex_Unop) {
3478       IRExpr *arg = cond->Iex.Unop.arg;
3479 
3480       switch (cond->Iex.Unop.op) {
3481       case Iop_Not1:  /* Not1(cond) */
3482          /* Generate code for EXPR, and negate the test condition */
3483          return s390_cc_invert(s390_isel_cc(env, arg));
3484 
3485          /* Iop_32/64to1  select the LSB from their operand */
3486       case Iop_32to1:
3487       case Iop_64to1: {
3488          HReg dst = newVRegI(env);
3489          HReg h1  = s390_isel_int_expr(env, arg);
3490 
3491          size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3492 
3493          addInstr(env, s390_insn_move(size, dst, h1));
3494          addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
3495          addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
3496          return S390_CC_NE;
3497       }
3498 
3499       case Iop_CmpNEZ8:
3500       case Iop_CmpNEZ16: {
3501          s390_opnd_RMI src;
3502          s390_unop_t   op;
3503          HReg dst;
3504 
3505          op  = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
3506             : S390_ZERO_EXTEND_16;
3507          dst = newVRegI(env);
3508          src = s390_isel_int_expr_RMI(env, arg);
3509          addInstr(env, s390_insn_unop(4, op, dst, src));
3510          addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
3511          return S390_CC_NE;
3512       }
3513 
3514       case Iop_CmpNEZ32:
3515       case Iop_CmpNEZ64: {
3516          s390_opnd_RMI src;
3517 
3518          src = s390_isel_int_expr_RMI(env, arg);
3519          size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3520          addInstr(env, s390_insn_test(size, src));
3521          return S390_CC_NE;
3522       }
3523 
3524       default:
3525          goto fail;
3526       }
3527    }
3528 
3529    /* Binary operators */
3530    if (cond->tag == Iex_Binop) {
3531       IRExpr *arg1 = cond->Iex.Binop.arg1;
3532       IRExpr *arg2 = cond->Iex.Binop.arg2;
3533       HReg reg1, reg2;
3534 
3535       size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
3536 
3537       switch (cond->Iex.Binop.op) {
3538          s390_unop_t op;
3539          s390_cc_t   result;
3540 
3541       case Iop_CmpEQ8:
3542       case Iop_CasCmpEQ8:
3543          op     = S390_ZERO_EXTEND_8;
3544          result = S390_CC_E;
3545          goto do_compare_ze;
3546 
3547       case Iop_CmpNE8:
3548       case Iop_CasCmpNE8:
3549          op     = S390_ZERO_EXTEND_8;
3550          result = S390_CC_NE;
3551          goto do_compare_ze;
3552 
3553       case Iop_CmpEQ16:
3554       case Iop_CasCmpEQ16:
3555          op     = S390_ZERO_EXTEND_16;
3556          result = S390_CC_E;
3557          goto do_compare_ze;
3558 
3559       case Iop_CmpNE16:
3560       case Iop_CasCmpNE16:
3561          op     = S390_ZERO_EXTEND_16;
3562          result = S390_CC_NE;
3563          goto do_compare_ze;
3564 
3565       do_compare_ze: {
3566             s390_opnd_RMI op1, op2;
3567 
3568             op1  = s390_isel_int_expr_RMI(env, arg1);
3569             reg1 = newVRegI(env);
3570             addInstr(env, s390_insn_unop(4, op, reg1, op1));
3571 
3572             op2  = s390_isel_int_expr_RMI(env, arg2);
3573             reg2 = newVRegI(env);
3574             addInstr(env, s390_insn_unop(4, op, reg2, op2));  /* zero extend */
3575 
3576             op2 = s390_opnd_reg(reg2);
3577             addInstr(env, s390_insn_compare(4, reg1, op2, False));
3578 
3579             return result;
3580          }
3581 
3582       case Iop_CmpEQ32:
3583       case Iop_CmpEQ64:
3584       case Iop_CasCmpEQ32:
3585       case Iop_CasCmpEQ64:
3586          result = S390_CC_E;
3587          goto do_compare;
3588 
3589       case Iop_CmpNE32:
3590       case Iop_CmpNE64:
3591       case Iop_CasCmpNE32:
3592       case Iop_CasCmpNE64:
3593          result = S390_CC_NE;
3594          goto do_compare;
3595 
3596       do_compare: {
3597             HReg op1;
3598             s390_opnd_RMI op2;
3599 
3600             order_commutative_operands(arg1, arg2);
3601 
3602             op1 = s390_isel_int_expr(env, arg1);
3603             op2 = s390_isel_int_expr_RMI(env, arg2);
3604 
3605             addInstr(env, s390_insn_compare(size, op1, op2, False));
3606 
3607             return result;
3608          }
3609 
3610       case Iop_CmpLT32S:
3611       case Iop_CmpLE32S:
3612       case Iop_CmpLT64S:
3613       case Iop_CmpLE64S: {
3614          HReg op1;
3615          s390_opnd_RMI op2;
3616 
3617          op1 = s390_isel_int_expr(env, arg1);
3618          op2 = s390_isel_int_expr_RMI(env, arg2);
3619 
3620          addInstr(env, s390_insn_compare(size, op1, op2, True));
3621 
3622          return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3623                  cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3624       }
3625 
3626       case Iop_CmpLT32U:
3627       case Iop_CmpLE32U:
3628       case Iop_CmpLT64U:
3629       case Iop_CmpLE64U: {
3630          HReg op1;
3631          s390_opnd_RMI op2;
3632 
3633          op1 = s390_isel_int_expr(env, arg1);
3634          op2 = s390_isel_int_expr_RMI(env, arg2);
3635 
3636          addInstr(env, s390_insn_compare(size, op1, op2, False));
3637 
3638          return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3639                  cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3640       }
3641 
3642       default:
3643          goto fail;
3644       }
3645    }
3646 
3647  fail:
3648    ppIRExpr(cond);
3649    vpanic("s390_isel_cc: unexpected operator");
3650 }
3651 
3652 
3653 /*---------------------------------------------------------*/
3654 /*--- ISEL: Vector expressions (128 bit)                ---*/
3655 /*---------------------------------------------------------*/
3656 
3657 static HReg
s390_isel_vec_expr_wrk(ISelEnv * env,IRExpr * expr)3658 s390_isel_vec_expr_wrk(ISelEnv *env, IRExpr *expr)
3659 {
3660    IRType ty = typeOfIRExpr(env->type_env, expr);
3661    UChar size;
3662 
3663    vassert(ty == Ity_V128);
3664 
3665    size = sizeofIRType(ty);
3666 
3667    switch (expr->tag) {
3668    case Iex_RdTmp:
3669       /* Return the virtual register that holds the temporary. */
3670       return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
3671 
3672    /* --------- LOAD --------- */
3673    case Iex_Load: {
3674       HReg        dst = newVRegV(env);
3675       s390_amode *am  = s390_isel_amode(env, expr->Iex.Load.addr);
3676 
3677       if (expr->Iex.Load.end != Iend_BE)
3678          goto irreducible;
3679 
3680       addInstr(env, s390_insn_load(size, dst, am));
3681 
3682       return dst;
3683    }
3684 
3685    /* --------- GET --------- */
3686    case Iex_Get: {
3687       HReg dst = newVRegV(env);
3688       s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
3689 
3690       addInstr(env, s390_insn_load(size, dst, am));
3691 
3692       return dst;
3693    }
3694 
3695    case Iex_Const: {
3696       HReg dst = newVRegV(env);
3697       vassert(expr->Iex.Const.con->tag == Ico_V128);
3698 
3699       addInstr(env, s390_insn_unop(16, S390_VEC_FILL, dst, s390_opnd_imm(expr->Iex.Const.con->Ico.V128)));
3700       return dst;
3701    }
3702    /* --------- UNARY OP --------- */
3703    case Iex_Unop: {
3704       UChar size_for_int_arg = 0;
3705       HReg dst;
3706       HReg reg1;
3707       s390_unop_t vec_op;
3708       IROp op = expr->Iex.Unop.op;
3709       IRExpr* arg = expr->Iex.Unop.arg;
3710       switch(op) {
3711       case Iop_NotV128:
3712          /* Not(Or(arg1, arg2)) -> Nor(arg1, arg2) */
3713          if(UNLIKELY((arg->tag == Iex_Binop ) && (arg->Iex.Binop.op == Iop_OrV128)))
3714          {
3715             dst = newVRegV(env);
3716             addInstr(env,
3717                      s390_insn_vec_binop(16,
3718                                          S390_VEC_NOR,
3719                                          dst,
3720                                          s390_isel_vec_expr(env, arg->Iex.Binop.arg1),
3721                                          s390_isel_vec_expr(env, arg->Iex.Binop.arg2)
3722                                         )
3723                      );
3724             return dst;
3725          }
3726          reg1 = s390_isel_vec_expr(env, arg);
3727          return vec_do_notV128(env, reg1);
3728 
3729       case Iop_CmpNEZ8x16:
3730          size = 1;
3731          goto Iop_CmpNEZ_wrk;
3732       case Iop_CmpNEZ16x8:
3733          size = 2;
3734          goto Iop_CmpNEZ_wrk;
3735       case Iop_CmpNEZ32x4:
3736          size = 4;
3737          goto Iop_CmpNEZ_wrk;
3738       case Iop_CmpNEZ64x2:
3739          size = 8;
3740 
3741          Iop_CmpNEZ_wrk: {
3742             dst = newVRegV(env);
3743             reg1 = s390_isel_vec_expr(env, arg);
3744             addInstr(env, s390_insn_vec_binop(size, S390_VEC_COMPARE_EQUAL, dst,
3745                      reg1, vec_generate_zeroes(env)));
3746             return vec_do_notV128(env, dst);
3747          }
3748 
3749       case Iop_CmpNEZ128x1: {
3750          IRExpr* low64     = IRExpr_Unop(Iop_V128to64, arg);
3751          IRExpr* high64    = IRExpr_Unop(Iop_V128HIto64, arg);
3752          IRExpr* both      = IRExpr_Binop(Iop_Or64, low64, high64);
3753          IRExpr* anyNonZ   = IRExpr_Unop(Iop_CmpNEZ64, both);
3754          IRExpr* anyNonZ64 = IRExpr_Unop(Iop_1Sto64, anyNonZ);
3755          reg1 = s390_isel_int_expr(env, anyNonZ64);
3756 
3757          dst = newVRegV(env);
3758          addInstr(env, s390_insn_vec_binop(size, S390_VEC_INIT_FROM_GPRS,
3759                                            dst, reg1, reg1));
3760          return dst;
3761       }
3762 
3763       case Iop_Dup8x16:
3764          size = size_for_int_arg = 1;
3765          vec_op = S390_VEC_DUPLICATE;
3766          goto Iop_V_int_wrk;
3767       case Iop_Dup16x8:
3768          size = size_for_int_arg = 2;
3769          vec_op = S390_VEC_DUPLICATE;
3770          goto Iop_V_int_wrk;
3771       case Iop_Dup32x4:
3772          size = size_for_int_arg = 4;
3773          vec_op = S390_VEC_DUPLICATE;
3774          goto Iop_V_int_wrk;
3775 
3776       case Iop_Widen8Sto16x8:
3777          size = 1;
3778          size_for_int_arg = 8;
3779          vec_op = S390_VEC_UNPACKLOWS;
3780          goto Iop_V_int_wrk;
3781       case Iop_Widen16Sto32x4:
3782          size = 2;
3783          size_for_int_arg = 8;
3784          vec_op = S390_VEC_UNPACKLOWS;
3785          goto Iop_V_int_wrk;
3786       case Iop_Widen32Sto64x2:
3787          size = 4;
3788          size_for_int_arg = 8;
3789          vec_op = S390_VEC_UNPACKLOWS;
3790          goto Iop_V_int_wrk;
3791       case Iop_Widen8Uto16x8:
3792          size = 1;
3793          size_for_int_arg = 8;
3794          vec_op = S390_VEC_UNPACKLOWU;
3795          goto Iop_V_int_wrk;
3796       case Iop_Widen16Uto32x4:
3797          size = 2;
3798          size_for_int_arg = 8;
3799          vec_op = S390_VEC_UNPACKLOWU;
3800          goto Iop_V_int_wrk;
3801       case Iop_Widen32Uto64x2:
3802          size = 4;
3803          size_for_int_arg = 8;
3804          vec_op = S390_VEC_UNPACKLOWU;
3805          goto Iop_V_int_wrk;
3806 
3807       Iop_V_int_wrk: {
3808          HReg vr1 = vec_generate_zeroes(env);
3809          s390_amode* amode2 = s390_isel_amode(env, IRExpr_Const(IRConst_U64(0)));
3810          reg1 = s390_isel_int_expr(env, arg);
3811 
3812          addInstr(env,
3813                   s390_insn_vec_amodeintop(size_for_int_arg, S390_VEC_SET_ELEM,
3814                                            vr1, amode2, reg1));
3815 
3816          dst = newVRegV(env);
3817          addInstr(env, s390_insn_unop(size, vec_op, dst, s390_opnd_reg(vr1)));
3818          return dst;
3819       }
3820 
3821       case Iop_Abs8x16:
3822          size = 1;
3823          vec_op = S390_VEC_ABS;
3824          goto Iop_V_wrk;
3825       case Iop_Abs16x8:
3826          size = 2;
3827          vec_op = S390_VEC_ABS;
3828          goto Iop_V_wrk;
3829       case Iop_Abs32x4:
3830          size = 4;
3831          vec_op = S390_VEC_ABS;
3832          goto Iop_V_wrk;
3833       case Iop_Abs64x2:
3834          size = 8;
3835          vec_op = S390_VEC_ABS;
3836          goto Iop_V_wrk;
3837 
3838       case Iop_Clz8x16:
3839          size = 1;
3840          vec_op = S390_VEC_COUNT_LEADING_ZEROES;
3841          goto Iop_V_wrk;
3842       case Iop_Ctz8x16:
3843          size = 1;
3844          vec_op = S390_VEC_COUNT_TRAILING_ZEROES;
3845          goto Iop_V_wrk;
3846       case Iop_Clz16x8:
3847          size = 2;
3848          vec_op = S390_VEC_COUNT_LEADING_ZEROES;
3849          goto Iop_V_wrk;
3850       case Iop_Ctz16x8:
3851          size = 2;
3852          vec_op = S390_VEC_COUNT_TRAILING_ZEROES;
3853          goto Iop_V_wrk;
3854       case Iop_Clz32x4:
3855          size = 4;
3856          vec_op = S390_VEC_COUNT_LEADING_ZEROES;
3857          goto Iop_V_wrk;
3858       case Iop_Ctz32x4:
3859          size = 4;
3860          vec_op = S390_VEC_COUNT_TRAILING_ZEROES;
3861          goto Iop_V_wrk;
3862       case Iop_Clz64x2:
3863          size = 8;
3864          vec_op = S390_VEC_COUNT_LEADING_ZEROES;
3865          goto Iop_V_wrk;
3866       case Iop_Ctz64x2:
3867          size = 8;
3868          vec_op = S390_VEC_COUNT_TRAILING_ZEROES;
3869          goto Iop_V_wrk;
3870 
3871       case Iop_Cnt8x16:
3872          size = 1;
3873          vec_op = S390_VEC_COUNT_ONES;
3874          goto Iop_V_wrk;
3875 
3876       case Iop_Neg64Fx2:
3877          size = 8;
3878          vec_op = S390_VEC_FLOAT_NEG;
3879          goto Iop_V_wrk;
3880 
3881       case Iop_Abs64Fx2:
3882          size = 8;
3883          vec_op = S390_VEC_FLOAT_ABS;
3884          goto Iop_V_wrk;
3885 
3886 
3887       Iop_V_wrk: {
3888          dst = newVRegV(env);
3889          reg1 = s390_isel_vec_expr(env, arg);
3890 
3891          addInstr(env,
3892                   s390_insn_unop(size, vec_op, dst, s390_opnd_reg(reg1)));
3893          return dst;
3894       }
3895 
3896       case Iop_PwAddL8Ux16: {
3897          /* There is no such instruction. We have to emulate it. */
3898          IRExpr *even = IRExpr_Binop(Iop_InterleaveEvenLanes8x16,
3899                                      IRExpr_Const(IRConst_V128(0x0000)),
3900                                      arg);
3901          IRExpr *odd = IRExpr_Binop(Iop_InterleaveOddLanes8x16,
3902                                     IRExpr_Const(IRConst_V128(0x0000)),
3903                                     arg);
3904          dst = s390_isel_vec_expr(env, IRExpr_Binop(Iop_Add16x8, even, odd));
3905          return dst;
3906       }
3907 
3908       case Iop_PwAddL16Ux8:
3909          if (arg->tag == Iex_Unop && arg->Iex.Unop.op == Iop_PwAddL8Ux16) {
3910             size = 1;
3911             arg = arg->Iex.Unop.arg;
3912          } else {
3913             size = 2;
3914          }
3915          vec_op = S390_VEC_PWSUM_W;
3916          goto Iop_Pairwise_wrk;
3917 
3918       case Iop_PwAddL32Ux4:
3919          if (arg->tag == Iex_Unop && arg->Iex.Unop.op == Iop_PwAddL16Ux8) {
3920             size = 2;
3921             arg = arg->Iex.Unop.arg;
3922          } else {
3923             size = 4;
3924          }
3925          vec_op = S390_VEC_PWSUM_DW;
3926          goto Iop_Pairwise_wrk;
3927 
3928       case Iop_PwAddL64Ux2:
3929          if (arg->tag == Iex_Unop && arg->Iex.Unop.op == Iop_PwAddL32Ux4) {
3930             size = 4;
3931             arg = arg->Iex.Unop.arg;
3932          } else {
3933             size = 8;
3934          }
3935          vec_op = S390_VEC_PWSUM_QW;
3936          goto Iop_Pairwise_wrk;
3937 
3938       Iop_Pairwise_wrk: {
3939          dst = newVRegV(env);
3940          reg1 = s390_isel_vec_expr(env, arg);
3941 
3942          addInstr(env,
3943                   s390_insn_vec_binop(size, vec_op, dst, reg1,
3944                                       vec_generate_zeroes(env)));
3945          return dst;
3946       }
3947 
3948       default:
3949          goto irreducible;
3950       }
3951    }
3952 
3953    /* --------- BINARY OP --------- */
3954    case Iex_Binop: {
3955       HReg dst = newVRegV(env);
3956       HReg reg1, reg2;
3957       IROp op = expr->Iex.Binop.op;
3958       s390_vec_binop_t vec_op = 0;
3959       s390_vec_amodeop_t shift_op = 0;
3960       IRExpr* arg1 = expr->Iex.Binop.arg1;
3961       IRExpr* arg2 = expr->Iex.Binop.arg2;
3962       switch(op) {
3963       case Iop_QNarrowBin16Uto8Ux16:
3964          size = 2;
3965          vec_op = S390_VEC_PACK_SATURU;
3966          goto Iop_VV_wrk;
3967       case Iop_QNarrowBin16Sto8Sx16:
3968          size = 2;
3969          vec_op = S390_VEC_PACK_SATURS;
3970          goto Iop_VV_wrk;
3971       case Iop_QNarrowBin32Uto16Ux8:
3972          size = 4;
3973          vec_op = S390_VEC_PACK_SATURU;
3974          goto Iop_VV_wrk;
3975       case Iop_QNarrowBin32Sto16Sx8:
3976          size = 4;
3977          vec_op = S390_VEC_PACK_SATURS;
3978          goto Iop_VV_wrk;
3979       case Iop_QNarrowBin64Uto32Ux4:
3980          size = 8;
3981          vec_op = S390_VEC_PACK_SATURU;
3982          goto Iop_VV_wrk;
3983       case Iop_QNarrowBin64Sto32Sx4:
3984          size = 8;
3985          vec_op = S390_VEC_PACK_SATURS;
3986          goto Iop_VV_wrk;
3987 
3988       case Iop_NarrowBin16to8x16:
3989          size = 2;
3990          vec_op = S390_VEC_PACK;
3991          goto Iop_VV_wrk;
3992       case Iop_NarrowBin32to16x8:
3993          size = 4;
3994          vec_op = S390_VEC_PACK;
3995          goto Iop_VV_wrk;
3996       case Iop_NarrowBin64to32x4:
3997          size = 8;
3998          vec_op = S390_VEC_PACK;
3999          goto Iop_VV_wrk;
4000 
4001       case Iop_OrV128:
4002          size = 16;
4003          vec_op = S390_VEC_OR;
4004          goto Iop_VV_wrk;
4005 
4006       case Iop_XorV128:
4007          size = 16;
4008          vec_op = S390_VEC_XOR;
4009          goto Iop_VV_wrk;
4010 
4011       case Iop_AndV128:
4012          size = 16;
4013          vec_op = S390_VEC_AND;
4014          goto Iop_VV_wrk;
4015 
4016       case Iop_InterleaveLO8x16:
4017          size = 1;
4018          vec_op = S390_VEC_MERGEL;
4019          goto Iop_VV_wrk;
4020       case Iop_InterleaveLO16x8:
4021          size = 2;
4022          vec_op = S390_VEC_MERGEL;
4023          goto Iop_VV_wrk;
4024       case Iop_InterleaveLO32x4:
4025          size = 4;
4026          vec_op = S390_VEC_MERGEL;
4027          goto Iop_VV_wrk;
4028       case Iop_InterleaveLO64x2:
4029          size = 8;
4030          vec_op = S390_VEC_MERGEL;
4031          goto Iop_VV_wrk;
4032 
4033       case Iop_InterleaveHI8x16:
4034          size = 1;
4035          vec_op = S390_VEC_MERGEH;
4036          goto Iop_VV_wrk;
4037       case Iop_InterleaveHI16x8:
4038          size = 2;
4039          vec_op = S390_VEC_MERGEH;
4040          goto Iop_VV_wrk;
4041       case Iop_InterleaveHI32x4:
4042          size = 4;
4043          vec_op = S390_VEC_MERGEH;
4044          goto Iop_VV_wrk;
4045       case Iop_InterleaveHI64x2:
4046          size = 8;
4047          vec_op = S390_VEC_MERGEH;
4048          goto Iop_VV_wrk;
4049 
4050       case Iop_InterleaveEvenLanes8x16: {
4051          /* There is no such instruction. We have to emulate it. */
4052          IRExpr* mask = IRExpr_Binop(Iop_64HLtoV128,
4053                                      mkU64(0x0010021204140616ULL),
4054                                      mkU64(0x08180a1a0c1c0e1eULL));
4055          HReg reg_mask = s390_isel_vec_expr(env, mask);
4056          reg1 = s390_isel_vec_expr(env, arg1);
4057          reg2 = s390_isel_vec_expr(env, arg2);
4058 
4059          addInstr(env,
4060                   s390_insn_vec_triop(16, S390_VEC_PERM, dst, reg1, reg2,
4061                                       reg_mask)
4062                   );
4063 
4064          return dst;
4065       }
4066       case Iop_InterleaveOddLanes8x16: {
4067          /* There is no such instruction. We have to emulate it. */
4068          IRExpr* mask = IRExpr_Binop(Iop_64HLtoV128,
4069                                      mkU64(0x0111031305150717ULL),
4070                                      mkU64(0x09190b1b0d1d0f1fULL));
4071          HReg reg_mask = s390_isel_vec_expr(env, mask);
4072          reg1 = s390_isel_vec_expr(env, arg1);
4073          reg2 = s390_isel_vec_expr(env, arg2);
4074 
4075          addInstr(env,
4076                   s390_insn_vec_triop(16, S390_VEC_PERM, dst, reg1, reg2, reg_mask)
4077                   );
4078 
4079          return dst;
4080       }
4081 
4082       case Iop_CmpEQ8x16:
4083          size = 1;
4084          vec_op = S390_VEC_COMPARE_EQUAL;
4085          goto Iop_VV_wrk;
4086       case Iop_CmpEQ16x8:
4087          size = 2;
4088          vec_op = S390_VEC_COMPARE_EQUAL;
4089          goto Iop_VV_wrk;
4090       case Iop_CmpEQ32x4:
4091          size = 4;
4092          vec_op = S390_VEC_COMPARE_EQUAL;
4093          goto Iop_VV_wrk;
4094       case Iop_CmpEQ64x2:
4095          size = 8;
4096          vec_op = S390_VEC_COMPARE_EQUAL;
4097          goto Iop_VV_wrk;
4098 
4099       case Iop_Add8x16:
4100          size = 1;
4101          vec_op = S390_VEC_INT_ADD;
4102          goto Iop_VV_wrk;
4103       case Iop_Add16x8:
4104          size = 2;
4105          vec_op = S390_VEC_INT_ADD;
4106          goto Iop_VV_wrk;
4107       case Iop_Add32x4:
4108          size = 4;
4109          vec_op = S390_VEC_INT_ADD;
4110          goto Iop_VV_wrk;
4111       case Iop_Add64x2:
4112          size = 8;
4113          vec_op = S390_VEC_INT_ADD;
4114          goto Iop_VV_wrk;
4115       case Iop_Add128x1:
4116          size = 16;
4117          vec_op = S390_VEC_INT_ADD;
4118          goto Iop_VV_wrk;
4119 
4120       case Iop_Sub8x16:
4121          size = 1;
4122          vec_op = S390_VEC_INT_SUB;
4123          goto Iop_VV_wrk;
4124       case Iop_Sub16x8:
4125          size = 2;
4126          vec_op = S390_VEC_INT_SUB;
4127          goto Iop_VV_wrk;
4128       case Iop_Sub32x4:
4129          size = 4;
4130          vec_op = S390_VEC_INT_SUB;
4131          goto Iop_VV_wrk;
4132       case Iop_Sub64x2:
4133          size = 8;
4134          vec_op = S390_VEC_INT_SUB;
4135          goto Iop_VV_wrk;
4136       case Iop_Sub128x1:
4137          size = 16;
4138          vec_op = S390_VEC_INT_SUB;
4139          goto Iop_VV_wrk;
4140 
4141       case Iop_Max8Ux16:
4142          size = 1;
4143          vec_op = S390_VEC_MAXU;
4144          goto Iop_VV_wrk;
4145       case Iop_Max8Sx16:
4146          size = 1;
4147          vec_op = S390_VEC_MAXS;
4148          goto Iop_VV_wrk;
4149       case Iop_Max16Ux8:
4150          size = 2;
4151          vec_op = S390_VEC_MAXU;
4152          goto Iop_VV_wrk;
4153       case Iop_Max16Sx8:
4154          size = 2;
4155          vec_op = S390_VEC_MAXS;
4156          goto Iop_VV_wrk;
4157       case Iop_Max32Ux4:
4158          size = 4;
4159          vec_op = S390_VEC_MAXU;
4160          goto Iop_VV_wrk;
4161       case Iop_Max32Sx4:
4162          size = 4;
4163          vec_op = S390_VEC_MAXS;
4164          goto Iop_VV_wrk;
4165       case Iop_Max64Ux2:
4166          size = 8;
4167          vec_op = S390_VEC_MAXU;
4168          goto Iop_VV_wrk;
4169       case Iop_Max64Sx2:
4170          size = 8;
4171          vec_op = S390_VEC_MAXS;
4172          goto Iop_VV_wrk;
4173 
4174       case Iop_Min8Ux16:
4175          size = 1;
4176          vec_op = S390_VEC_MINU;
4177          goto Iop_VV_wrk;
4178       case Iop_Min8Sx16:
4179          size = 1;
4180          vec_op = S390_VEC_MINS;
4181          goto Iop_VV_wrk;
4182       case Iop_Min16Ux8:
4183          size = 2;
4184          vec_op = S390_VEC_MINU;
4185          goto Iop_VV_wrk;
4186       case Iop_Min16Sx8:
4187          size = 2;
4188          vec_op = S390_VEC_MINS;
4189          goto Iop_VV_wrk;
4190       case Iop_Min32Ux4:
4191          size = 4;
4192          vec_op = S390_VEC_MINU;
4193          goto Iop_VV_wrk;
4194       case Iop_Min32Sx4:
4195          size = 4;
4196          vec_op = S390_VEC_MINS;
4197          goto Iop_VV_wrk;
4198       case Iop_Min64Ux2:
4199          size = 8;
4200          vec_op = S390_VEC_MINU;
4201          goto Iop_VV_wrk;
4202       case Iop_Min64Sx2:
4203          size = 8;
4204          vec_op = S390_VEC_MINS;
4205          goto Iop_VV_wrk;
4206 
4207       case Iop_Avg8Ux16:
4208          size = 1;
4209          vec_op = S390_VEC_AVGU;
4210          goto Iop_VV_wrk;
4211       case Iop_Avg8Sx16:
4212          size = 1;
4213          vec_op = S390_VEC_AVGS;
4214          goto Iop_VV_wrk;
4215       case Iop_Avg16Ux8:
4216          size = 2;
4217          vec_op = S390_VEC_AVGU;
4218          goto Iop_VV_wrk;
4219       case Iop_Avg16Sx8:
4220          size = 2;
4221          vec_op = S390_VEC_AVGS;
4222          goto Iop_VV_wrk;
4223       case Iop_Avg32Ux4:
4224          size = 4;
4225          vec_op = S390_VEC_AVGU;
4226          goto Iop_VV_wrk;
4227       case Iop_Avg32Sx4:
4228          size = 4;
4229          vec_op = S390_VEC_AVGS;
4230          goto Iop_VV_wrk;
4231       case Iop_Avg64Ux2:
4232          size = 8;
4233          vec_op = S390_VEC_AVGU;
4234          goto Iop_VV_wrk;
4235       case Iop_Avg64Sx2:
4236          size = 8;
4237          vec_op = S390_VEC_AVGS;
4238          goto Iop_VV_wrk;
4239 
4240       case Iop_CmpGT8Ux16:
4241          size = 1;
4242          vec_op = S390_VEC_COMPARE_GREATERU;
4243          goto Iop_VV_wrk;
4244       case Iop_CmpGT8Sx16:
4245          size = 1;
4246          vec_op = S390_VEC_COMPARE_GREATERS;
4247          goto Iop_VV_wrk;
4248       case Iop_CmpGT16Ux8:
4249          size = 2;
4250          vec_op = S390_VEC_COMPARE_GREATERU;
4251          goto Iop_VV_wrk;
4252       case Iop_CmpGT16Sx8:
4253          size = 2;
4254          vec_op = S390_VEC_COMPARE_GREATERS;
4255          goto Iop_VV_wrk;
4256       case Iop_CmpGT32Ux4:
4257          size = 4;
4258          vec_op = S390_VEC_COMPARE_GREATERU;
4259          goto Iop_VV_wrk;
4260       case Iop_CmpGT32Sx4:
4261          size = 4;
4262          vec_op = S390_VEC_COMPARE_GREATERS;
4263          goto Iop_VV_wrk;
4264       case Iop_CmpGT64Ux2:
4265          size = 8;
4266          vec_op = S390_VEC_COMPARE_GREATERU;
4267          goto Iop_VV_wrk;
4268       case Iop_CmpGT64Sx2:
4269          size = 8;
4270          vec_op = S390_VEC_COMPARE_GREATERS;
4271          goto Iop_VV_wrk;
4272 
4273       case Iop_MulHi8Ux16:
4274          size = 1;
4275          vec_op = S390_VEC_INT_MUL_HIGHU;
4276          goto Iop_VV_wrk;
4277       case Iop_MulHi8Sx16:
4278          size = 1;
4279          vec_op = S390_VEC_INT_MUL_HIGHS;
4280          goto Iop_VV_wrk;
4281       case Iop_MulHi16Ux8:
4282          size = 2;
4283          vec_op = S390_VEC_INT_MUL_HIGHU;
4284          goto Iop_VV_wrk;
4285       case Iop_MulHi16Sx8:
4286          size = 2;
4287          vec_op = S390_VEC_INT_MUL_HIGHS;
4288          goto Iop_VV_wrk;
4289       case Iop_MulHi32Ux4:
4290          size = 4;
4291          vec_op = S390_VEC_INT_MUL_HIGHU;
4292          goto Iop_VV_wrk;
4293       case Iop_MulHi32Sx4:
4294          size = 4;
4295          vec_op = S390_VEC_INT_MUL_HIGHS;
4296          goto Iop_VV_wrk;
4297 
4298       case Iop_Mul8x16:
4299          size = 1;
4300          vec_op = S390_VEC_INT_MUL_LOW;
4301          goto Iop_VV_wrk;
4302       case Iop_Mul16x8:
4303          size = 2;
4304          vec_op = S390_VEC_INT_MUL_LOW;
4305          goto Iop_VV_wrk;
4306       case Iop_Mul32x4:
4307          size = 4;
4308          vec_op = S390_VEC_INT_MUL_LOW;
4309          goto Iop_VV_wrk;
4310 
4311       case Iop_MullEven8Sx16:
4312          size = 1;
4313          vec_op = S390_VEC_INT_MUL_EVENS;
4314          goto Iop_VV_wrk;
4315       case Iop_MullEven8Ux16:
4316          size = 1;
4317          vec_op = S390_VEC_INT_MUL_EVENU;
4318          goto Iop_VV_wrk;
4319       case Iop_MullEven16Sx8:
4320          size = 2;
4321          vec_op = S390_VEC_INT_MUL_EVENS;
4322          goto Iop_VV_wrk;
4323       case Iop_MullEven16Ux8:
4324          size = 2;
4325          vec_op = S390_VEC_INT_MUL_EVENU;
4326          goto Iop_VV_wrk;
4327       case Iop_MullEven32Sx4:
4328          size = 4;
4329          vec_op = S390_VEC_INT_MUL_EVENS;
4330          goto Iop_VV_wrk;
4331       case Iop_MullEven32Ux4:
4332          size = 4;
4333          vec_op = S390_VEC_INT_MUL_EVENU;
4334          goto Iop_VV_wrk;
4335 
4336       case Iop_Shl8x16:
4337          size = 1;
4338          vec_op = S390_VEC_ELEM_SHL_V;
4339          goto Iop_VV_wrk;
4340       case Iop_Shl16x8:
4341          size = 2;
4342          vec_op = S390_VEC_ELEM_SHL_V;
4343          goto Iop_VV_wrk;
4344       case Iop_Shl32x4:
4345          size = 4;
4346          vec_op = S390_VEC_ELEM_SHL_V;
4347          goto Iop_VV_wrk;
4348       case Iop_Shl64x2:
4349          size = 8;
4350          vec_op = S390_VEC_ELEM_SHL_V;
4351          goto Iop_VV_wrk;
4352 
4353       case Iop_Shr8x16:
4354          size = 1;
4355          vec_op = S390_VEC_ELEM_SHRL_V;
4356          goto Iop_VV_wrk;
4357       case Iop_Shr16x8:
4358          size = 2;
4359          vec_op = S390_VEC_ELEM_SHRL_V;
4360          goto Iop_VV_wrk;
4361       case Iop_Shr32x4:
4362          size = 4;
4363          vec_op = S390_VEC_ELEM_SHRL_V;
4364          goto Iop_VV_wrk;
4365       case Iop_Shr64x2:
4366          size = 8;
4367          vec_op = S390_VEC_ELEM_SHRL_V;
4368          goto Iop_VV_wrk;
4369 
4370       case Iop_Sar8x16:
4371          size = 1;
4372          vec_op = S390_VEC_ELEM_SHRA_V;
4373          goto Iop_VV_wrk;
4374       case Iop_Sar16x8:
4375          size = 2;
4376          vec_op = S390_VEC_ELEM_SHRA_V;
4377          goto Iop_VV_wrk;
4378       case Iop_Sar32x4:
4379          size = 4;
4380          vec_op = S390_VEC_ELEM_SHRA_V;
4381          goto Iop_VV_wrk;
4382       case Iop_Sar64x2:
4383          size = 8;
4384          vec_op = S390_VEC_ELEM_SHRA_V;
4385          goto Iop_VV_wrk;
4386 
4387       case Iop_Rol8x16:
4388          size = 1;
4389          vec_op = S390_VEC_ELEM_ROLL_V;
4390          goto Iop_VV_wrk;
4391       case Iop_Rol16x8:
4392          size = 2;
4393          vec_op = S390_VEC_ELEM_ROLL_V;
4394          goto Iop_VV_wrk;
4395       case Iop_Rol32x4:
4396          size = 4;
4397          vec_op = S390_VEC_ELEM_ROLL_V;
4398          goto Iop_VV_wrk;
4399       case Iop_Rol64x2:
4400          size = 8;
4401          vec_op = S390_VEC_ELEM_ROLL_V;
4402          goto Iop_VV_wrk;
4403 
4404       case Iop_CmpEQ64Fx2:
4405          size = 8;
4406          vec_op = S390_VEC_FLOAT_COMPARE_EQUAL;
4407          goto Iop_VV_wrk;
4408 
4409       case Iop_CmpLE64Fx2: {
4410          size = 8;
4411          vec_op = S390_VEC_FLOAT_COMPARE_LESS_OR_EQUAL;
4412          goto Iop_VV_wrk;
4413       }
4414 
4415       case Iop_CmpLT64Fx2: {
4416          size = 8;
4417          vec_op = S390_VEC_FLOAT_COMPARE_LESS;
4418          goto Iop_VV_wrk;
4419       }
4420 
4421       case Iop_Sqrt64Fx2:
4422          size = 8;
4423          vec_op = S390_VEC_FLOAT_SQRT;
4424          goto Iop_irrm_V_wrk;
4425 
4426       case Iop_ShlN8x16:
4427          size = 1;
4428          shift_op = S390_VEC_ELEM_SHL_INT;
4429          goto Iop_ShiftN_wrk;
4430       case Iop_ShlN16x8:
4431          size = 2;
4432          shift_op = S390_VEC_ELEM_SHL_INT;
4433          goto Iop_ShiftN_wrk;
4434       case Iop_ShlN32x4:
4435          size = 4;
4436          shift_op = S390_VEC_ELEM_SHL_INT;
4437          goto Iop_ShiftN_wrk;
4438       case Iop_ShlN64x2:
4439          size = 8;
4440          shift_op = S390_VEC_ELEM_SHL_INT;
4441          goto Iop_ShiftN_wrk;
4442 
4443       case Iop_ShrN8x16:
4444          size = 1;
4445          shift_op = S390_VEC_ELEM_SHRL_INT;
4446          goto Iop_ShiftN_wrk;
4447       case Iop_ShrN16x8:
4448          size = 2;
4449          shift_op = S390_VEC_ELEM_SHRL_INT;
4450          goto Iop_ShiftN_wrk;
4451       case Iop_ShrN32x4:
4452          size = 4;
4453          shift_op = S390_VEC_ELEM_SHRL_INT;
4454          goto Iop_ShiftN_wrk;
4455       case Iop_ShrN64x2:
4456          size = 8;
4457          shift_op = S390_VEC_ELEM_SHRL_INT;
4458          goto Iop_ShiftN_wrk;
4459 
4460       case Iop_SarN8x16:
4461          size = 1;
4462          shift_op = S390_VEC_ELEM_SHRA_INT;
4463          goto Iop_ShiftN_wrk;
4464       case Iop_SarN16x8:
4465          size = 2;
4466          shift_op = S390_VEC_ELEM_SHRA_INT;
4467          goto Iop_ShiftN_wrk;
4468       case Iop_SarN32x4:
4469          size = 4;
4470          shift_op = S390_VEC_ELEM_SHRA_INT;
4471          goto Iop_ShiftN_wrk;
4472       case Iop_SarN64x2:
4473          size = 8;
4474          shift_op = S390_VEC_ELEM_SHRA_INT;
4475          goto Iop_ShiftN_wrk;
4476 
4477          Iop_ShiftN_wrk: {
4478             HReg vec = s390_isel_vec_expr(env, arg1);
4479             s390_amode* number = s390_isel_amode(env,IRExpr_Unop(Iop_8Uto64, arg2));
4480 
4481             addInstr(env,
4482                      s390_insn_vec_amodeop(size, shift_op, dst, vec, number));
4483 
4484          return dst;
4485          }
4486 
4487       case Iop_ShlV128:
4488          vec_op = S390_VEC_SHL_BITS;
4489          goto Iop_ShiftVV_wrk;
4490       case Iop_ShrV128:
4491          vec_op = S390_VEC_SHRL_BITS;
4492          goto Iop_ShiftVV_wrk;
4493       case Iop_SarV128:
4494          vec_op = S390_VEC_SHRA_BITS;
4495          goto Iop_ShiftVV_wrk;
4496 
4497       Iop_ShiftVV_wrk: {
4498          reg1 = s390_isel_vec_expr(env, arg1);
4499          reg2 = s390_isel_vec_expr(env, IRExpr_Unop(Iop_Dup8x16, arg2));
4500 
4501          /* Handle special case */
4502          if (vec_is_bytes_only_shift(arg2))
4503          {
4504             /* In this case we skip the BITS shift step. */
4505             addInstr(env, s390_insn_vec_binop(16, (vec_op + 1),
4506                      dst, reg1, reg2));
4507 
4508             return dst;
4509          }
4510 
4511          /* General case (BYTES shift & BITS shift) */
4512          addInstr(env, s390_insn_vec_binop(16, (vec_op + 1),
4513                   dst, reg1, reg2));
4514 
4515          addInstr(env, s390_insn_vec_binop(16, vec_op,
4516                   dst, dst, reg2));
4517 
4518          return dst;
4519       }
4520 
4521       Iop_VV_wrk: {
4522          reg1 = s390_isel_vec_expr(env, arg1);
4523          reg2 = s390_isel_vec_expr(env, arg2);
4524 
4525          addInstr(env, s390_insn_vec_binop(size, vec_op,
4526                   dst, reg1, reg2));
4527 
4528          return dst;
4529       }
4530 
4531       Iop_irrm_V_wrk: {
4532          set_bfp_rounding_mode_in_fpc(env, arg1);
4533          reg1 = s390_isel_vec_expr(env, arg2);
4534 
4535          addInstr(env, s390_insn_unop(size, vec_op, dst, s390_opnd_reg(reg1)));
4536          return dst;
4537       }
4538 
4539       case Iop_64HLtoV128:
4540          reg1 = s390_isel_int_expr(env, arg1);
4541          reg2 = s390_isel_int_expr(env, arg2);
4542 
4543          addInstr(env, s390_insn_vec_binop(size, S390_VEC_INIT_FROM_GPRS,
4544                   dst, reg1, reg2));
4545 
4546          return dst;
4547 
4548       default:
4549          goto irreducible;
4550       }
4551    }
4552 
4553    /* --------- TERNARY OP --------- */
4554    case Iex_Triop: {
4555       HReg dst = newVRegV(env);
4556       s390_amode* amode2;
4557       HReg reg1, reg2, reg3;
4558       IROp op = expr->Iex.Triop.details->op;
4559       IRExpr* arg1 = expr->Iex.Triop.details->arg1;
4560       IRExpr* arg2 = expr->Iex.Triop.details->arg2;
4561       IRExpr* arg3 = expr->Iex.Triop.details->arg3;
4562       IROp vec_op;
4563       switch (op) {
4564       case Iop_SetElem8x16:
4565          size = 1;
4566          goto Iop_SetElem_wrk;
4567       case Iop_SetElem16x8:
4568          size = 2;
4569          goto Iop_SetElem_wrk;
4570       case Iop_SetElem32x4:
4571          size = 4;
4572          goto Iop_SetElem_wrk;
4573       case Iop_SetElem64x2: {
4574          size = 8;
4575 
4576          Iop_SetElem_wrk:{
4577             reg1 = s390_isel_vec_expr(env, arg1);
4578             amode2 = s390_isel_amode(env, IRExpr_Unop(Iop_8Uto64, arg2));
4579             reg3 = s390_isel_int_expr(env, arg3);
4580 
4581             addInstr(env, s390_insn_move(16, dst, reg1));
4582             addInstr(env, s390_insn_vec_amodeintop(size, S390_VEC_SET_ELEM,
4583                      dst, amode2, reg3));
4584             return dst;
4585          }
4586       }
4587 
4588       case Iop_Perm8x16x2:
4589          size = 16;
4590          reg1 = s390_isel_vec_expr(env, arg1);
4591          reg2 = s390_isel_vec_expr(env, arg2);
4592          reg3 = s390_isel_vec_expr(env, arg3);
4593 
4594          addInstr(env, s390_insn_vec_triop(size, S390_VEC_PERM,
4595                                            dst, reg1, reg2, reg3));
4596          return dst;
4597 
4598       case Iop_Add64Fx2:
4599          size = 8;
4600          vec_op = S390_VEC_FLOAT_ADD;
4601          goto Iop_irrm_VV_wrk;
4602 
4603       case Iop_Sub64Fx2:
4604          size = 8;
4605          vec_op = S390_VEC_FLOAT_SUB;
4606          goto Iop_irrm_VV_wrk;
4607 
4608       case Iop_Mul64Fx2:
4609          size = 8;
4610          vec_op = S390_VEC_FLOAT_MUL;
4611          goto Iop_irrm_VV_wrk;
4612       case Iop_Div64Fx2:
4613          size = 8;
4614          vec_op = S390_VEC_FLOAT_DIV;
4615          goto Iop_irrm_VV_wrk;
4616 
4617       Iop_irrm_VV_wrk: {
4618          set_bfp_rounding_mode_in_fpc(env, arg1);
4619          reg1 = s390_isel_vec_expr(env, arg2);
4620          reg2 = s390_isel_vec_expr(env, arg3);
4621 
4622          addInstr(env, s390_insn_vec_binop(size, vec_op,
4623                                            dst, reg1, reg2));
4624 
4625          return dst;
4626        }
4627 
4628       default:
4629          goto irreducible;
4630       }
4631    }
4632 
4633    default:
4634       goto irreducible;
4635    }
4636 
4637    /* We get here if no pattern matched. */
4638  irreducible:
4639    ppIRExpr(expr);
4640    vpanic("s390_isel_vec_expr: cannot reduce tree");
4641 }
4642 
4643 static HReg
s390_isel_vec_expr(ISelEnv * env,IRExpr * expr)4644 s390_isel_vec_expr(ISelEnv *env, IRExpr *expr)
4645 {
4646    HReg dst = s390_isel_vec_expr_wrk(env, expr);
4647 
4648    /* Sanity checks ... */
4649    vassert(hregClass(dst) == HRcVec128);
4650    vassert(hregIsVirtual(dst));
4651 
4652    return dst;
4653 }
4654 
4655 
4656 /*---------------------------------------------------------*/
4657 /*--- ISEL: Statements                                  ---*/
4658 /*---------------------------------------------------------*/
4659 
4660 static void
s390_isel_stmt(ISelEnv * env,IRStmt * stmt)4661 s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
4662 {
4663    if (vex_traceflags & VEX_TRACE_VCODE) {
4664       vex_printf("\n -- ");
4665       ppIRStmt(stmt);
4666       vex_printf("\n");
4667    }
4668 
4669    switch (stmt->tag) {
4670 
4671       /* --------- STORE --------- */
4672    case Ist_Store: {
4673       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
4674       s390_amode *am;
4675       HReg src;
4676 
4677       if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
4678 
4679       am = s390_isel_amode(env, stmt->Ist.Store.addr);
4680 
4681       switch (tyd) {
4682       case Ity_I8:
4683       case Ity_I16:
4684       case Ity_I32:
4685       case Ity_I64:
4686          /* fixs390: We could check for INSN_MADD here. */
4687          if (am->tag == S390_AMODE_B12 &&
4688              stmt->Ist.Store.data->tag == Iex_Const) {
4689             ULong value =
4690                get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
4691             addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
4692             return;
4693          }
4694          /* Check whether we can use a memcpy here. Currently, the restriction
4695             is that both amodes need to be B12, so MVC can be emitted.
4696             We do not consider a store whose data expression is a load because
4697             we don't want to deal with overlapping locations. */
4698          /* store(get) never overlaps*/
4699          if (am->tag == S390_AMODE_B12 &&
4700              stmt->Ist.Store.data->tag == Iex_Get) {
4701             UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
4702             s390_amode *from = s390_amode_for_guest_state(offset);
4703             addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
4704             return;
4705          }
4706          /* General case: compile data into a register */
4707          src = s390_isel_int_expr(env, stmt->Ist.Store.data);
4708          break;
4709 
4710       case Ity_F32:
4711       case Ity_F64:
4712          src = s390_isel_float_expr(env, stmt->Ist.Store.data);
4713          break;
4714 
4715       case Ity_D32:
4716       case Ity_D64:
4717          src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
4718          break;
4719 
4720       case Ity_F128:
4721       case Ity_D128:
4722          /* Cannot occur. No such instruction */
4723          vpanic("Ist_Store with 128-bit floating point data");
4724 
4725       case Ity_V128:
4726          src = s390_isel_vec_expr(env, stmt->Ist.Store.data);
4727          break;
4728       default:
4729          goto stmt_fail;
4730       }
4731 
4732       addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
4733       return;
4734    }
4735 
4736       /* --------- PUT --------- */
4737    case Ist_Put: {
4738       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
4739       HReg src;
4740       s390_amode *am;
4741       ULong new_value, old_value, difference;
4742 
4743       /* Detect updates to certain guest registers. We track the contents
4744          of those registers as long as they contain constants. If the new
4745          constant is either zero or in the 8-bit neighbourhood of the
4746          current value we can use a memory-to-memory insn to do the update. */
4747 
4748       Int offset = stmt->Ist.Put.offset;
4749 
4750       /* Check necessary conditions:
4751          (1) must be one of the registers we care about
4752          (2) assigned value must be a constant */
4753       Int guest_reg = get_guest_reg(offset);
4754 
4755       if (guest_reg == GUEST_UNKNOWN) goto not_special;
4756 
4757       if (stmt->Ist.Put.data->tag != Iex_Const) {
4758          /* Invalidate guest register contents */
4759          env->old_value_valid[guest_reg] = False;
4760          goto not_special;
4761       }
4762 
4763       /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
4764       if (tyd != Ity_I64)
4765          goto not_special;
4766 
4767       /* OK. Necessary conditions are satisfied. */
4768 
4769       old_value = env->old_value[guest_reg];
4770       new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
4771       env->old_value[guest_reg] = new_value;
4772 
4773       Bool old_value_is_valid = env->old_value_valid[guest_reg];
4774       env->old_value_valid[guest_reg] = True;
4775 
4776       /* If the register already contains the new value, there is nothing
4777          to do here. */
4778       if (old_value_is_valid && new_value == old_value) {
4779          return;
4780       }
4781 
4782       if (old_value_is_valid == False) goto not_special;
4783 
4784       /* If the new value is in the neighbourhood of the old value
4785          we can use a memory-to-memory insn */
4786       difference = new_value - old_value;
4787 
4788       if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
4789          am = s390_amode_for_guest_state(offset);
4790          addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
4791                                       (difference & 0xFF), new_value));
4792          return;
4793       }
4794 
4795       /* If the high word is the same it is sufficient to load the low word. */
4796       if ((old_value >> 32) == (new_value >> 32)) {
4797          am = s390_amode_for_guest_state(offset + 4);
4798          addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
4799          return;
4800       }
4801 
4802       /* No special case applies... fall through */
4803 
4804    not_special:
4805       am = s390_amode_for_guest_state(offset);
4806 
4807       switch (tyd) {
4808       case Ity_I8:
4809       case Ity_I16:
4810       case Ity_I32:
4811       case Ity_I64:
4812          if (am->tag == S390_AMODE_B12 &&
4813              stmt->Ist.Put.data->tag == Iex_Const) {
4814             ULong value =
4815                get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
4816             addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
4817             return;
4818          }
4819          /* Check whether we can use a memcpy here. Currently, the restriction
4820             is that both amodes need to be B12, so MVC can be emitted. */
4821          /* put(load) never overlaps */
4822          if (am->tag == S390_AMODE_B12 &&
4823              stmt->Ist.Put.data->tag == Iex_Load) {
4824             if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
4825             IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
4826             s390_amode *from = s390_isel_amode(env, data);
4827             UInt size = sizeofIRType(tyd);
4828 
4829             if (from->tag == S390_AMODE_B12) {
4830                /* Source can be compiled into a B12 amode. */
4831                addInstr(env, s390_insn_memcpy(size, am, from));
4832                return;
4833             }
4834 
4835             src = newVRegI(env);
4836             addInstr(env, s390_insn_load(size, src, from));
4837             break;
4838          }
4839          /* put(get) */
4840          if (am->tag == S390_AMODE_B12 &&
4841              stmt->Ist.Put.data->tag == Iex_Get) {
4842             UInt put_offset = am->d;
4843             UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
4844             UInt size = sizeofIRType(tyd);
4845             /* don't memcpy in case of overlap */
4846             if (put_offset + size <= get_offset ||
4847                 get_offset + size <= put_offset) {
4848                s390_amode *from = s390_amode_for_guest_state(get_offset);
4849                addInstr(env, s390_insn_memcpy(size, am, from));
4850                return;
4851             }
4852             goto no_memcpy_put;
4853          }
4854          /* General case: compile data into a register */
4855 no_memcpy_put:
4856          src = s390_isel_int_expr(env, stmt->Ist.Put.data);
4857          break;
4858 
4859       case Ity_F32:
4860       case Ity_F64:
4861          src = s390_isel_float_expr(env, stmt->Ist.Put.data);
4862          break;
4863 
4864       case Ity_F128:
4865       case Ity_D128:
4866          /* Does not occur. See function put_(f|d)pr_pair. */
4867          vpanic("Ist_Put with 128-bit floating point data");
4868 
4869       case Ity_D32:
4870       case Ity_D64:
4871          src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
4872          break;
4873 
4874       case Ity_V128:
4875          src = s390_isel_vec_expr(env, stmt->Ist.Put.data);
4876          break;
4877       default:
4878          goto stmt_fail;
4879       }
4880 
4881       addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
4882       return;
4883    }
4884 
4885       /* --------- TMP --------- */
4886    case Ist_WrTmp: {
4887       IRTemp tmp = stmt->Ist.WrTmp.tmp;
4888       IRType tyd = typeOfIRTemp(env->type_env, tmp);
4889       HReg src, dst;
4890 
4891       switch (tyd) {
4892       case Ity_I128: {
4893          HReg dst_hi, dst_lo, res_hi, res_lo;
4894 
4895          s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
4896          lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
4897 
4898          addInstr(env, s390_insn_move(8, dst_hi, res_hi));
4899          addInstr(env, s390_insn_move(8, dst_lo, res_lo));
4900          return;
4901       }
4902 
4903       case Ity_I8:
4904       case Ity_I16:
4905       case Ity_I32:
4906       case Ity_I64:
4907          src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
4908          dst = lookupIRTemp(env, tmp);
4909          break;
4910 
4911       case Ity_I1: {
4912          s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
4913          dst = lookupIRTemp(env, tmp);
4914          addInstr(env, s390_insn_cc2bool(dst, cond));
4915          return;
4916       }
4917 
4918       case Ity_F32:
4919       case Ity_F64:
4920          src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
4921          dst = lookupIRTemp(env, tmp);
4922          break;
4923 
4924       case Ity_F128: {
4925          HReg dst_hi, dst_lo, res_hi, res_lo;
4926 
4927          s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
4928          lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
4929 
4930          addInstr(env, s390_insn_move(8, dst_hi, res_hi));
4931          addInstr(env, s390_insn_move(8, dst_lo, res_lo));
4932          return;
4933       }
4934 
4935       case Ity_D32:
4936       case Ity_D64:
4937          src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
4938          dst = lookupIRTemp(env, tmp);
4939          break;
4940 
4941       case Ity_D128: {
4942          HReg dst_hi, dst_lo, res_hi, res_lo;
4943 
4944          s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
4945          lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
4946 
4947          addInstr(env, s390_insn_move(8, dst_hi, res_hi));
4948          addInstr(env, s390_insn_move(8, dst_lo, res_lo));
4949          return;
4950       }
4951 
4952       case Ity_V128:
4953          src = s390_isel_vec_expr(env, stmt->Ist.WrTmp.data);
4954          dst = lookupIRTemp(env, tmp);
4955          break;
4956 
4957       default:
4958          goto stmt_fail;
4959       }
4960 
4961       addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
4962       return;
4963    }
4964 
4965       /* --------- Call to DIRTY helper --------- */
4966    case Ist_Dirty: {
4967       IRType   retty;
4968       IRDirty* d = stmt->Ist.Dirty.details;
4969       HReg dst;
4970       RetLoc rloc    = mk_RetLoc_INVALID();
4971       UInt   addToSp = 0;
4972       Int i;
4973 
4974       /* Invalidate tracked values of those guest state registers that are
4975          modified by this helper. */
4976       for (i = 0; i < d->nFxState; ++i) {
4977          /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
4978             descriptors in guest state effect descriptions.  Hence: */
4979          vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
4980          if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
4981             Int guest_reg = get_guest_reg(d->fxState[i].offset);
4982             if (guest_reg != GUEST_UNKNOWN)
4983                env->old_value_valid[guest_reg] = False;
4984          }
4985       }
4986 
4987       if (d->tmp == IRTemp_INVALID) {
4988          /* No return value. */
4989          retty = Ity_INVALID;
4990          doHelperCall(&addToSp, &rloc, env, d->guard,  d->cee, retty,
4991                       d->args);
4992          vassert(is_sane_RetLoc(rloc));
4993          vassert(rloc.pri == RLPri_None);
4994          vassert(addToSp == 0);
4995 
4996          return;
4997       }
4998 
4999       retty = typeOfIRTemp(env->type_env, d->tmp);
5000       if (retty == Ity_I64 || retty == Ity_I32
5001           || retty == Ity_I16 || retty == Ity_I8 || retty == Ity_V128) {
5002          /* Move the returned value to the destination register */
5003          HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
5004 
5005          dst = lookupIRTemp(env, d->tmp);
5006          doHelperCall(&addToSp, &rloc, env, d->guard,  d->cee, retty,
5007                       d->args);
5008          vassert(is_sane_RetLoc(rloc));
5009 
5010          switch(retty)
5011          {
5012             case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
5013                vassert(rloc.pri == RLPri_Int);
5014                vassert(addToSp == 0);
5015                addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
5016                break;
5017             case Ity_V128:
5018                /* The returned value is on the stack, and rloc.spOff
5019                   tells us where.  Fish it off the stack and then move
5020                   the stack pointer upwards to clear it, as directed by
5021                   doHelperCall. */
5022                vassert(rloc.pri == RLPri_V128SpRel);
5023                vassert(addToSp == sizeof(V128));
5024                s390_amode* am  = s390_amode_b12(rloc.spOff, s390_hreg_stack_pointer());
5025                addInstr(env, s390_insn_load(sizeof(V128), dst, am));
5026                add_to_SP(env, addToSp);
5027                break;
5028             default:
5029                vpanic("s390_isel_stmt: invalid return type from dirty helper");
5030          }
5031          return;
5032       }
5033       break;
5034    }
5035 
5036    case Ist_CAS:
5037       if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
5038          IRCAS *cas = stmt->Ist.CAS.details;
5039          s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr);
5040          HReg op3 = s390_isel_int_expr(env, cas->dataLo);  /* new value */
5041          HReg op1 = s390_isel_int_expr(env, cas->expdLo);  /* expected value */
5042          HReg old = lookupIRTemp(env, cas->oldLo);
5043 
5044          if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
5045             addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
5046          } else {
5047             addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
5048          }
5049          return;
5050       } else {
5051          IRCAS *cas = stmt->Ist.CAS.details;
5052          s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr);
5053          HReg r8, r9, r10, r11, r1;
5054          HReg op3_high = s390_isel_int_expr(env, cas->dataHi);  /* new value */
5055          HReg op3_low  = s390_isel_int_expr(env, cas->dataLo);  /* new value */
5056          HReg op1_high = s390_isel_int_expr(env, cas->expdHi);  /* expected value */
5057          HReg op1_low  = s390_isel_int_expr(env, cas->expdLo);  /* expected value */
5058          HReg old_low  = lookupIRTemp(env, cas->oldLo);
5059          HReg old_high = lookupIRTemp(env, cas->oldHi);
5060 
5061          /* Use non-virtual registers r8 and r9 as pair for op1
5062             and move op1 there */
5063          r8 = make_gpr(8);
5064          r9 = make_gpr(9);
5065          addInstr(env, s390_insn_move(8, r8, op1_high));
5066          addInstr(env, s390_insn_move(8, r9, op1_low));
5067 
5068          /* Use non-virtual registers r10 and r11 as pair for op3
5069             and move op3 there */
5070          r10 = make_gpr(10);
5071          r11 = make_gpr(11);
5072          addInstr(env, s390_insn_move(8, r10, op3_high));
5073          addInstr(env, s390_insn_move(8, r11, op3_low));
5074 
5075          /* Register r1 is used as a scratch register */
5076          r1 = make_gpr(1);
5077 
5078          if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
5079             addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
5080                                          old_high, old_low, r1));
5081          } else {
5082             addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
5083                                          old_high, old_low, r1));
5084          }
5085          addInstr(env, s390_insn_move(8, op1_high, r8));
5086          addInstr(env, s390_insn_move(8, op1_low,  r9));
5087          addInstr(env, s390_insn_move(8, op3_high, r10));
5088          addInstr(env, s390_insn_move(8, op3_low,  r11));
5089          return;
5090       }
5091       break;
5092 
5093       /* --------- EXIT --------- */
5094    case Ist_Exit: {
5095       s390_cc_t cond;
5096       IRConstTag tag = stmt->Ist.Exit.dst->tag;
5097 
5098       if (tag != Ico_U64)
5099          vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
5100 
5101       s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
5102       cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
5103 
5104       /* Case: boring transfer to known address */
5105       if (stmt->Ist.Exit.jk == Ijk_Boring) {
5106          if (env->chaining_allowed) {
5107             /* .. almost always true .. */
5108             /* Skip the event check at the dst if this is a forwards
5109                edge. */
5110             Bool to_fast_entry
5111                = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
5112             if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
5113             addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
5114                                             guest_IA, to_fast_entry));
5115          } else {
5116             /* .. very occasionally .. */
5117             /* We can't use chaining, so ask for an assisted transfer,
5118                as that's the only alternative that is allowable. */
5119             HReg dst = s390_isel_int_expr(env,
5120                                           IRExpr_Const(stmt->Ist.Exit.dst));
5121             addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
5122          }
5123          return;
5124       }
5125 
5126       /* Case: assisted transfer to arbitrary address */
5127       switch (stmt->Ist.Exit.jk) {
5128       case Ijk_EmFail:
5129       case Ijk_EmWarn:
5130       case Ijk_NoDecode:
5131       case Ijk_InvalICache:
5132       case Ijk_Sys_syscall:
5133       case Ijk_ClientReq:
5134       case Ijk_NoRedir:
5135       case Ijk_Yield:
5136       case Ijk_SigTRAP:
5137       case Ijk_SigFPE: {
5138          HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
5139          addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
5140                                            stmt->Ist.Exit.jk));
5141          return;
5142       }
5143       default:
5144          break;
5145       }
5146 
5147       /* Do we ever expect to see any other kind? */
5148       goto stmt_fail;
5149    }
5150 
5151       /* --------- MEM FENCE --------- */
5152    case Ist_MBE:
5153       switch (stmt->Ist.MBE.event) {
5154          case Imbe_Fence:
5155             addInstr(env, s390_insn_mfence());
5156             return;
5157          default:
5158             break;
5159       }
5160       break;
5161 
5162       /* --------- Miscellaneous --------- */
5163 
5164    case Ist_PutI:    /* Not needed */
5165    case Ist_IMark:   /* Doesn't generate any executable code */
5166    case Ist_NoOp:    /* Doesn't generate any executable code */
5167    case Ist_AbiHint: /* Meaningless in IR */
5168       return;
5169 
5170    default:
5171       break;
5172    }
5173 
5174  stmt_fail:
5175    ppIRStmt(stmt);
5176    vpanic("s390_isel_stmt");
5177 }
5178 
5179 
5180 /*---------------------------------------------------------*/
5181 /*--- ISEL: Basic block terminators (Nexts)             ---*/
5182 /*---------------------------------------------------------*/
5183 
5184 static void
iselNext(ISelEnv * env,IRExpr * next,IRJumpKind jk,Int offsIP)5185 iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
5186 {
5187    if (vex_traceflags & VEX_TRACE_VCODE) {
5188       vex_printf("\n-- PUT(%d) = ", offsIP);
5189       ppIRExpr(next);
5190       vex_printf("; exit-");
5191       ppIRJumpKind(jk);
5192       vex_printf("\n");
5193    }
5194 
5195    s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
5196 
5197    /* Case: boring transfer to known address */
5198    if (next->tag == Iex_Const) {
5199       IRConst *cdst = next->Iex.Const.con;
5200       vassert(cdst->tag == Ico_U64);
5201       if (jk == Ijk_Boring || jk == Ijk_Call) {
5202          /* Boring transfer to known address */
5203          if (env->chaining_allowed) {
5204             /* .. almost always true .. */
5205             /* Skip the event check at the dst if this is a forwards
5206                edge. */
5207             Bool to_fast_entry
5208                = ((Addr64)cdst->Ico.U64) > env->max_ga;
5209             if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
5210             addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
5211                                             guest_IA, to_fast_entry));
5212          } else {
5213             /* .. very occasionally .. */
5214             /* We can't use chaining, so ask for an indirect transfer,
5215                as that's the cheapest alternative that is allowable. */
5216             HReg dst = s390_isel_int_expr(env, next);
5217             addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
5218                                               Ijk_Boring));
5219          }
5220          return;
5221       }
5222    }
5223 
5224    /* Case: call/return (==boring) transfer to any address */
5225    switch (jk) {
5226    case Ijk_Boring:
5227    case Ijk_Ret:
5228    case Ijk_Call: {
5229       HReg dst = s390_isel_int_expr(env, next);
5230       if (env->chaining_allowed) {
5231          addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
5232       } else {
5233          addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
5234                                            Ijk_Boring));
5235       }
5236       return;
5237    }
5238    default:
5239       break;
5240    }
5241 
5242    /* Case: some other kind of transfer to any address */
5243    switch (jk) {
5244    case Ijk_EmFail:
5245    case Ijk_EmWarn:
5246    case Ijk_NoDecode:
5247    case Ijk_InvalICache:
5248    case Ijk_Sys_syscall:
5249    case Ijk_ClientReq:
5250    case Ijk_NoRedir:
5251    case Ijk_Yield:
5252    case Ijk_SigTRAP:
5253    case Ijk_SigFPE: {
5254       HReg dst = s390_isel_int_expr(env, next);
5255       addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
5256       return;
5257    }
5258    default:
5259       break;
5260    }
5261 
5262    vpanic("iselNext");
5263 }
5264 
5265 
5266 /*---------------------------------------------------------*/
5267 /*--- Insn selector top-level                           ---*/
5268 /*---------------------------------------------------------*/
5269 
5270 /* Translate an entire SB to s390 code.
5271    Note: archinfo_host is a pointer to a stack-allocated variable.
5272    Do not assign it to a global variable! */
5273 
5274 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)5275 iselSB_S390(const IRSB *bb, VexArch arch_host, const VexArchInfo *archinfo_host,
5276             const VexAbiInfo *vbi, Int offset_host_evcheck_counter,
5277             Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
5278             Bool add_profinc, Addr max_ga)
5279 {
5280    UInt     i, j;
5281    HReg     hreg, hregHI;
5282    ISelEnv *env;
5283    UInt     hwcaps_host = archinfo_host->hwcaps;
5284 
5285    /* Do some sanity checks */
5286    vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
5287 
5288    /* Check that the host's endianness is as expected. */
5289    vassert(archinfo_host->endness == VexEndnessBE);
5290 
5291    /* Make up an initial environment to use. */
5292    env = LibVEX_Alloc_inline(sizeof(ISelEnv));
5293    env->vreg_ctr = 0;
5294 
5295    /* Set up output code array. */
5296    env->code = newHInstrArray();
5297 
5298    /* Copy BB's type env. */
5299    env->type_env = bb->tyenv;
5300 
5301    /* Set up data structures for tracking guest register values. */
5302    for (i = 0; i < NUM_TRACKED_REGS; ++i) {
5303       env->old_value[i] = 0;  /* just something to have a defined value */
5304       env->old_value_valid[i] = False;
5305    }
5306 
5307    /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
5308       change as we go along. For some reason types_used has Int type -- but
5309       it should be unsigned. Internally we use an unsigned type; so we
5310       assert it here. */
5311    vassert(bb->tyenv->types_used >= 0);
5312 
5313    env->n_vregmap = bb->tyenv->types_used;
5314    env->vregmap   = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
5315    env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
5316 
5317    env->previous_bfp_rounding_mode = NULL;
5318    env->previous_dfp_rounding_mode = NULL;
5319 
5320    /* and finally ... */
5321    env->hwcaps    = hwcaps_host;
5322 
5323    env->max_ga = max_ga;
5324    env->chaining_allowed = chaining_allowed;
5325 
5326    /* For each IR temporary, allocate a suitably-kinded virtual
5327       register. */
5328    j = 0;
5329    for (i = 0; i < env->n_vregmap; i++) {
5330       hregHI = hreg = INVALID_HREG;
5331       switch (bb->tyenv->types[i]) {
5332       case Ity_I1:
5333       case Ity_I8:
5334       case Ity_I16:
5335       case Ity_I32:
5336       case Ity_I64:
5337          hreg = mkVRegI(j++);
5338          break;
5339 
5340       case Ity_I128:
5341          hreg   = mkVRegI(j++);
5342          hregHI = mkVRegI(j++);
5343          break;
5344 
5345       case Ity_F32:
5346       case Ity_F64:
5347       case Ity_D32:
5348       case Ity_D64:
5349          hreg = mkVRegF(j++);
5350          break;
5351 
5352       case Ity_F128:
5353       case Ity_D128:
5354          hreg   = mkVRegF(j++);
5355          hregHI = mkVRegF(j++);
5356          break;
5357 
5358       case Ity_V128:
5359          hreg   = mkVRegV(j++);
5360          break;
5361 
5362       default:
5363          ppIRType(bb->tyenv->types[i]);
5364          vpanic("iselSB_S390: IRTemp type");
5365       }
5366 
5367       env->vregmap[i]   = hreg;
5368       env->vregmapHI[i] = hregHI;
5369    }
5370    env->vreg_ctr = j;
5371 
5372    /* The very first instruction must be an event check. */
5373    s390_amode *counter, *fail_addr;
5374    counter   = s390_amode_for_guest_state(offset_host_evcheck_counter);
5375    fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
5376    addInstr(env, s390_insn_evcheck(counter, fail_addr));
5377 
5378    /* Possibly a block counter increment (for profiling).  At this
5379       point we don't know the address of the counter, so just pretend
5380       it is zero.  It will have to be patched later, but before this
5381       translation is used, by a call to LibVEX_patchProfInc. */
5382    if (add_profinc) {
5383       addInstr(env, s390_insn_profinc());
5384    }
5385 
5386    /* Ok, finally we can iterate over the statements. */
5387    for (i = 0; i < bb->stmts_used; i++)
5388       if (bb->stmts[i])
5389          s390_isel_stmt(env, bb->stmts[i]);
5390 
5391    iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
5392 
5393    /* Record the number of vregs we used. */
5394    env->code->n_vregs = env->vreg_ctr;
5395 
5396    return env->code;
5397 }
5398 
5399 /*---------------------------------------------------------------*/
5400 /*--- end                                    host_s390_isel.c ---*/
5401 /*---------------------------------------------------------------*/
5402