• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-basic-offset: 3; -*- */
2 
3 /*---------------------------------------------------------------*/
4 /*--- begin                                  host_s390_isel.c ---*/
5 /*---------------------------------------------------------------*/
6 
7 /*
8    This file is part of Valgrind, a dynamic binary instrumentation
9    framework.
10 
11    Copyright IBM Corp. 2010-2012
12 
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of the
16    License, or (at your option) any later version.
17 
18    This program is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26    02110-1301, USA.
27 
28    The GNU General Public License is contained in the file COPYING.
29 */
30 
31 /* Contributed by Florian Krohm */
32 
33 #include "libvex_basictypes.h"
34 #include "libvex_ir.h"
35 #include "libvex.h"
36 #include "libvex_s390x_common.h"
37 
38 #include "main_util.h"
39 #include "main_globals.h"
40 #include "guest_s390_defs.h"   /* guest_s390x_state_requires_precise_mem_exns */
41 #include "host_generic_regs.h"
42 #include "host_s390_defs.h"
43 
44 /*---------------------------------------------------------*/
45 /*--- ISelEnv                                           ---*/
46 /*---------------------------------------------------------*/
47 
48 /* This carries around:
49 
50    - A mapping from IRTemp to IRType, giving the type of any IRTemp we
51      might encounter.  This is computed before insn selection starts,
52      and does not change.
53 
54    - A mapping from IRTemp to HReg.  This tells the insn selector
55      which virtual register(s) are associated with each IRTemp
56       temporary.  This is computed before insn selection starts, and
57       does not change.  We expect this mapping to map precisely the
58       same set of IRTemps as the type mapping does.
59 
60          - vregmap   holds the primary register for the IRTemp.
61          - vregmapHI holds the secondary register for the IRTemp,
62               if any is needed.  That's only for Ity_I64 temps
63               in 32 bit mode or Ity_I128 temps in 64-bit mode.
64 
65     - The code array, that is, the insns selected so far.
66 
67     - A counter, for generating new virtual registers.
68 
69     - The host subarchitecture we are selecting insns for.
70       This is set at the start and does not change.
71 
72    - A Bool for indicating whether we may generate chain-me
73      instructions for control flow transfers, or whether we must use
74      XAssisted.
75 
76    - The maximum guest address of any guest insn in this block.
77      Actually, the address of the highest-addressed byte from any insn
78      in this block.  Is set at the start and does not change.  This is
79      used for detecting jumps which are definitely forward-edges from
80      this block, and therefore can be made (chained) to the fast entry
81      point of the destination, thereby avoiding the destination's
82      event check.
83 
84     - A flag to indicate whether the guest IA has been assigned to.
85 
86     - Values of certain guest registers which are often assigned constants.
87 */
88 
89 /* Symbolic names for guest registers whose value we're tracking */
90 enum {
91    GUEST_IA,
92    GUEST_CC_OP,
93    GUEST_CC_DEP1,
94    GUEST_CC_DEP2,
95    GUEST_CC_NDEP,
96    GUEST_SYSNO,
97    GUEST_COUNTER,
98    GUEST_UNKNOWN    /* must be the last entry */
99 };
100 
101 /* Number of registers we're tracking. */
102 #define NUM_TRACKED_REGS GUEST_UNKNOWN
103 
104 
105 typedef struct {
106    IRTypeEnv   *type_env;
107 
108    HInstrArray *code;
109    HReg        *vregmap;
110    HReg        *vregmapHI;
111    UInt         n_vregmap;
112    UInt         vreg_ctr;
113    UInt         hwcaps;
114 
115    ULong        old_value[NUM_TRACKED_REGS];
116 
117    /* The next two are for translation chaining */
118    Addr64       max_ga;
119    Bool         chaining_allowed;
120 
121    Bool         first_IA_assignment;
122    Bool         old_value_valid[NUM_TRACKED_REGS];
123 } ISelEnv;
124 
125 
126 /* Forward declarations */
127 static HReg          s390_isel_int_expr(ISelEnv *, IRExpr *);
128 static s390_amode   *s390_isel_amode(ISelEnv *, IRExpr *);
129 static s390_cc_t     s390_isel_cc(ISelEnv *, IRExpr *);
130 static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
131 static void          s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
132 static HReg          s390_isel_float_expr(ISelEnv *, IRExpr *);
133 static void          s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
134 
135 
136 static Int
get_guest_reg(Int offset)137 get_guest_reg(Int offset)
138 {
139    switch (offset) {
140    case S390X_GUEST_OFFSET(guest_IA):        return GUEST_IA;
141    case S390X_GUEST_OFFSET(guest_CC_OP):     return GUEST_CC_OP;
142    case S390X_GUEST_OFFSET(guest_CC_DEP1):   return GUEST_CC_DEP1;
143    case S390X_GUEST_OFFSET(guest_CC_DEP2):   return GUEST_CC_DEP2;
144    case S390X_GUEST_OFFSET(guest_CC_NDEP):   return GUEST_CC_NDEP;
145    case S390X_GUEST_OFFSET(guest_SYSNO):     return GUEST_SYSNO;
146    case S390X_GUEST_OFFSET(guest_counter):   return GUEST_COUNTER;
147 
148       /* Also make sure there is never a partial write to one of
149          these registers. That would complicate matters. */
150    case S390X_GUEST_OFFSET(guest_IA)+1      ... S390X_GUEST_OFFSET(guest_IA)+7:
151    case S390X_GUEST_OFFSET(guest_CC_OP)+1   ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
152    case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
153    case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
154    case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
155    case S390X_GUEST_OFFSET(guest_SYSNO)+1   ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
156       /* counter is used both as 4-byte and as 8-byte entity */
157    case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
158    case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
159       vpanic("partial update of this guest state register is not allowed");
160       break;
161 
162    default: break;
163    }
164 
165    return GUEST_UNKNOWN;
166 }
167 
168 /* Add an instruction */
169 static void
addInstr(ISelEnv * env,s390_insn * insn)170 addInstr(ISelEnv *env, s390_insn *insn)
171 {
172    addHInstr(env->code, insn);
173 
174    if (vex_traceflags & VEX_TRACE_VCODE) {
175       vex_printf("%s\n", s390_insn_as_string(insn));
176    }
177 }
178 
179 
180 static __inline__ IRExpr *
mkU64(ULong value)181 mkU64(ULong value)
182 {
183    return IRExpr_Const(IRConst_U64(value));
184 }
185 
186 
187 /*---------------------------------------------------------*/
188 /*--- Registers                                         ---*/
189 /*---------------------------------------------------------*/
190 
191 /* Return the virtual register to which a given IRTemp is mapped. */
192 static HReg
lookupIRTemp(ISelEnv * env,IRTemp tmp)193 lookupIRTemp(ISelEnv *env, IRTemp tmp)
194 {
195    vassert(tmp < env->n_vregmap);
196    vassert(env->vregmap[tmp] != INVALID_HREG);
197 
198    return env->vregmap[tmp];
199 }
200 
201 
202 /* Return the two virtual registers to which the IRTemp is mapped. */
203 static void
lookupIRTemp128(HReg * hi,HReg * lo,ISelEnv * env,IRTemp tmp)204 lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
205 {
206    vassert(tmp < env->n_vregmap);
207    vassert(env->vregmapHI[tmp] != INVALID_HREG);
208 
209    *lo = env->vregmap[tmp];
210    *hi = env->vregmapHI[tmp];
211 }
212 
213 
214 /* Allocate a new integer register */
215 static HReg
newVRegI(ISelEnv * env)216 newVRegI(ISelEnv *env)
217 {
218    HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
219    env->vreg_ctr++;
220 
221    return reg;
222 }
223 
224 
225 /* Allocate a new floating point register */
226 static HReg
newVRegF(ISelEnv * env)227 newVRegF(ISelEnv *env)
228 {
229    HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
230 
231    env->vreg_ctr++;
232 
233    return reg;
234 }
235 
236 
237 /* Construct a non-virtual general purpose register */
238 static __inline__ HReg
make_gpr(UInt regno)239 make_gpr(UInt regno)
240 {
241    return mkHReg(regno, HRcInt64, False /* virtual */ );
242 }
243 
244 
245 /* Construct a non-virtual floating point register */
246 static __inline__ HReg
make_fpr(UInt regno)247 make_fpr(UInt regno)
248 {
249    return mkHReg(regno, HRcFlt64, False /* virtual */ );
250 }
251 
252 
253 /*---------------------------------------------------------*/
254 /*--- Amode                                             ---*/
255 /*---------------------------------------------------------*/
256 
257 static __inline__ Bool
ulong_fits_unsigned_12bit(ULong val)258 ulong_fits_unsigned_12bit(ULong val)
259 {
260    return (val & 0xFFFu) == val;
261 }
262 
263 
264 static __inline__ Bool
ulong_fits_signed_20bit(ULong val)265 ulong_fits_signed_20bit(ULong val)
266 {
267    Long v = val & 0xFFFFFu;
268 
269    v = (v << 44) >> 44;  /* sign extend */
270 
271    return val == (ULong)v;
272 }
273 
274 
275 static __inline__ Bool
ulong_fits_signed_8bit(ULong val)276 ulong_fits_signed_8bit(ULong val)
277 {
278    Long v = val & 0xFFu;
279 
280    v = (v << 56) >> 56;  /* sign extend */
281 
282    return val == (ULong)v;
283 }
284 
285 /* EXPR is an expression that is used as an address. Return an s390_amode
286    for it. */
287 static s390_amode *
s390_isel_amode_wrk(ISelEnv * env,IRExpr * expr)288 s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
289 {
290    if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
291       IRExpr *arg1 = expr->Iex.Binop.arg1;
292       IRExpr *arg2 = expr->Iex.Binop.arg2;
293 
294       /* Move constant into right subtree */
295       if (arg1->tag == Iex_Const) {
296          IRExpr *tmp;
297          tmp  = arg1;
298          arg1 = arg2;
299          arg2 = tmp;
300       }
301 
302       /* r + constant: Check for b12 first, then b20 */
303       if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
304          ULong value = arg2->Iex.Const.con->Ico.U64;
305 
306          if (ulong_fits_unsigned_12bit(value)) {
307             return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
308          }
309          /* If long-displacement is not available, do not construct B20 or
310             BX20 amodes because code generation cannot handle them. */
311          if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
312             return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
313          }
314       }
315    }
316 
317    /* Doesn't match anything in particular.  Generate it into
318       a register and use that. */
319    return s390_amode_b12(0, s390_isel_int_expr(env, expr));
320 }
321 
322 
323 static s390_amode *
s390_isel_amode(ISelEnv * env,IRExpr * expr)324 s390_isel_amode(ISelEnv *env, IRExpr *expr)
325 {
326    s390_amode *am;
327 
328    /* Address computation should yield a 64-bit value */
329    vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
330 
331    am = s390_isel_amode_wrk(env, expr);
332 
333    /* Check post-condition */
334    vassert(s390_amode_is_sane(am));
335 
336    return am;
337 }
338 
339 
340 /*---------------------------------------------------------*/
341 /*--- Helper functions                                  ---*/
342 /*---------------------------------------------------------*/
343 
344 /* Constants and memory accesses should be right operands */
345 #define order_commutative_operands(left, right)                   \
346         do {                                                      \
347           if (left->tag == Iex_Const || left->tag == Iex_Load ||  \
348               left->tag == Iex_Get) {                             \
349             IRExpr *tmp;                                          \
350             tmp   = left;                                         \
351             left  = right;                                        \
352             right = tmp;                                          \
353           }                                                       \
354         } while (0)
355 
356 
357 /* Copy an RMI operand to the DST register */
358 static s390_insn *
s390_opnd_copy(UChar size,HReg dst,s390_opnd_RMI opnd)359 s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
360 {
361    switch (opnd.tag) {
362    case S390_OPND_AMODE:
363       return s390_insn_load(size, dst, opnd.variant.am);
364 
365    case S390_OPND_REG:
366       return s390_insn_move(size, dst, opnd.variant.reg);
367 
368    case S390_OPND_IMMEDIATE:
369       return s390_insn_load_immediate(size, dst, opnd.variant.imm);
370 
371    default:
372       vpanic("s390_opnd_copy");
373    }
374 }
375 
376 
377 /* Construct a RMI operand for a register */
378 static __inline__ s390_opnd_RMI
s390_opnd_reg(HReg reg)379 s390_opnd_reg(HReg reg)
380 {
381    s390_opnd_RMI opnd;
382 
383    opnd.tag  = S390_OPND_REG;
384    opnd.variant.reg = reg;
385 
386    return opnd;
387 }
388 
389 
390 /* Construct a RMI operand for an immediate constant */
391 static __inline__ s390_opnd_RMI
s390_opnd_imm(ULong value)392 s390_opnd_imm(ULong value)
393 {
394    s390_opnd_RMI opnd;
395 
396    opnd.tag  = S390_OPND_IMMEDIATE;
397    opnd.variant.imm = value;
398 
399    return opnd;
400 }
401 
402 
403 /* Return 1, if EXPR represents the cosntant 0 */
404 static int
s390_expr_is_const_zero(IRExpr * expr)405 s390_expr_is_const_zero(IRExpr *expr)
406 {
407    ULong value;
408 
409    if (expr->tag == Iex_Const) {
410       switch (expr->Iex.Const.con->tag) {
411       case Ico_U1:  value = expr->Iex.Const.con->Ico.U1;  break;
412       case Ico_U8:  value = expr->Iex.Const.con->Ico.U8;  break;
413       case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
414       case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
415       case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
416       default:
417          vpanic("s390_expr_is_const_zero");
418       }
419       return value == 0;
420    }
421 
422    return 0;
423 }
424 
425 
426 /* Call a helper (clean or dirty)
427    Arguments must satisfy the following conditions:
428 
429    (a) they are expressions yielding an integer result
430    (b) there can be no more than S390_NUM_GPRPARMS arguments
431 
432    guard is a Ity_Bit expression indicating whether or not the
433    call happens.  If guard == NULL, the call is unconditional.
434 
435    Calling the helper function proceeds as follows:
436 
437    (1) The helper arguments are evaluated and their value stored in
438        virtual registers.
439    (2) The condition code is evaluated
440    (3) The argument values are copied from the virtual registers to the
441        registers mandated by the ABI.
442    (4) Call the helper function.
443 
444    This is not the most efficient way as step 3 generates register-to-register
445    moves. But it is the least fragile way as the only hidden dependency here
446    is that register-to-register moves (step 3) must not clobber the condition
447    code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
448    to-register add more such dependencies. Not good. Besides, it's the job
449    of the register allocator to throw out those reg-to-reg moves.
450 */
451 static void
doHelperCall(ISelEnv * env,Bool passBBP,IRExpr * guard,IRCallee * callee,IRExpr ** args,HReg dst)452 doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
453              IRCallee *callee, IRExpr **args, HReg dst)
454 {
455    UInt n_args, i, argreg, size;
456    ULong target;
457    HReg tmpregs[S390_NUM_GPRPARMS];
458    s390_cc_t cc;
459 
460    n_args = 0;
461    for (i = 0; args[i]; i++)
462       ++n_args;
463 
464    if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
465       vpanic("doHelperCall: too many arguments");
466    }
467 
468    /* All arguments must have Ity_I64. For two reasons:
469       (1) We do not handle floating point arguments.
470       (2) The ABI requires that integer values are sign- or zero-extended
471            to 64 bit.
472    */
473    Int arg_errors = 0;
474    for (i = 0; i < n_args; ++i) {
475       IRType type = typeOfIRExpr(env->type_env, args[i]);
476       if (type != Ity_I64) {
477          ++arg_errors;
478          vex_printf("calling %s: argument #%d has type ", callee->name, i);
479          ppIRType(type);
480          vex_printf("; Ity_I64 is required\n");
481       }
482    }
483 
484    if (arg_errors)
485       vpanic("cannot continue due to errors in argument passing");
486 
487    argreg = 0;
488 
489    /* If we need the guest state pointer put it in a temporary arg reg */
490    if (passBBP) {
491       tmpregs[argreg] = newVRegI(env);
492       addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
493                                    s390_hreg_guest_state_pointer()));
494       argreg++;
495    }
496 
497    /* Compute the function arguments into a temporary register each */
498    for (i = 0; i < n_args; i++) {
499       tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
500       argreg++;
501    }
502 
503    /* Compute the condition */
504    cc = S390_CC_ALWAYS;
505    if (guard) {
506       if (guard->tag == Iex_Const
507           && guard->Iex.Const.con->tag == Ico_U1
508           && guard->Iex.Const.con->Ico.U1 == True) {
509          /* unconditional -- do nothing */
510       } else {
511          cc = s390_isel_cc(env, guard);
512       }
513    }
514 
515    /* Move the args to the final register. It is paramount, that the
516       code to move the registers does not clobber the condition code ! */
517    for (i = 0; i < argreg; i++) {
518       HReg finalreg;
519 
520       finalreg = make_gpr(s390_gprno_from_arg_index(i));
521       size = sizeofIRType(Ity_I64);
522       addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
523    }
524 
525    target = Ptr_to_ULong(callee->addr);
526 
527    /* Finally, the call itself. */
528    addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
529                                        callee->name, dst));
530 }
531 
532 
533 /* Given an expression representing a rounding mode using IRRoundingMode
534    encoding convert it to an s390_round_t value.  */
535 static s390_round_t
decode_rounding_mode(IRExpr * rounding_expr)536 decode_rounding_mode(IRExpr *rounding_expr)
537 {
538    if (rounding_expr->tag == Iex_Const &&
539        rounding_expr->Iex.Const.con->tag == Ico_U32) {
540       IRRoundingMode mode = rounding_expr->Iex.Const.con->Ico.U32;
541 
542       switch (mode) {
543       case Irrm_NEAREST:       return S390_ROUND_NEAREST_EVEN;
544       case Irrm_ZERO:          return S390_ROUND_ZERO;
545       case Irrm_PosINF:        return S390_ROUND_POSINF;
546       case Irrm_NegINF:        return S390_ROUND_NEGINF;
547       }
548    }
549 
550    vpanic("decode_rounding_mode");
551 }
552 
553 
554 /* CC_S390 holds the condition code in s390 encoding. Convert it to
555    VEX encoding
556 
557    s390     VEX              b6 b2 b0   cc.1  cc.0
558    0      0x40 EQ             1  0  0     0     0
559    1      0x01 LT             0  0  1     0     1
560    2      0x00 GT             0  0  0     1     0
561    3      0x45 Unordered      1  1  1     1     1
562 
563    b0 = cc.0
564    b2 = cc.0 & cc.1
565    b6 = ~(cc.0 ^ cc.1)   // ((cc.0 - cc.1) + 0x1 ) & 0x1
566 
567    VEX = b0 | (b2 << 2) | (b6 << 6);
568 */
569 static HReg
convert_s390_fpcc_to_vex(ISelEnv * env,HReg cc_s390)570 convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390)
571 {
572    HReg cc0, cc1, b2, b6, cc_vex;
573 
574    cc0 = newVRegI(env);
575    addInstr(env, s390_insn_move(4, cc0, cc_s390));
576    addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
577 
578    cc1 = newVRegI(env);
579    addInstr(env, s390_insn_move(4, cc1, cc_s390));
580    addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
581 
582    b2 = newVRegI(env);
583    addInstr(env, s390_insn_move(4, b2, cc0));
584    addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
585    addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
586 
587    b6 = newVRegI(env);
588    addInstr(env, s390_insn_move(4, b6, cc0));
589    addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
590    addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
591    addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
592    addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
593 
594    cc_vex = newVRegI(env);
595    addInstr(env, s390_insn_move(4, cc_vex, cc0));
596    addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
597    addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
598 
599    return cc_vex;
600 }
601 
602 
603 /*---------------------------------------------------------*/
604 /*--- ISEL: Integer expressions (128 bit)               ---*/
605 /*---------------------------------------------------------*/
606 static void
s390_isel_int128_expr_wrk(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)607 s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
608                           IRExpr *expr)
609 {
610    IRType ty = typeOfIRExpr(env->type_env, expr);
611 
612    vassert(ty == Ity_I128);
613 
614    /* No need to consider the following
615       - 128-bit constants (they do not exist in VEX)
616       - 128-bit loads from memory (will not be generated)
617    */
618 
619    /* Read 128-bit IRTemp */
620    if (expr->tag == Iex_RdTmp) {
621       lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
622       return;
623    }
624 
625    if (expr->tag == Iex_Binop) {
626       IRExpr *arg1 = expr->Iex.Binop.arg1;
627       IRExpr *arg2 = expr->Iex.Binop.arg2;
628       Bool is_signed_multiply, is_signed_divide;
629 
630       switch (expr->Iex.Binop.op) {
631       case Iop_MullU64:
632          is_signed_multiply = False;
633          goto do_multiply64;
634 
635       case Iop_MullS64:
636          is_signed_multiply = True;
637          goto do_multiply64;
638 
639       case Iop_DivModU128to64:
640          is_signed_divide = False;
641          goto do_divide64;
642 
643       case Iop_DivModS128to64:
644          is_signed_divide = True;
645          goto do_divide64;
646 
647       case Iop_64HLto128:
648          *dst_hi = s390_isel_int_expr(env, arg1);
649          *dst_lo = s390_isel_int_expr(env, arg2);
650          return;
651 
652       case Iop_DivModS64to64: {
653          HReg r10, r11, h1;
654          s390_opnd_RMI op2;
655 
656          h1  = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
657          op2 = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
658 
659          /* We use non-virtual registers r10 and r11 as pair */
660          r10  = make_gpr(10);
661          r11  = make_gpr(11);
662 
663          /* Move 1st operand into r11 and */
664          addInstr(env, s390_insn_move(8, r11, h1));
665 
666          /* Divide */
667          addInstr(env, s390_insn_divs(8, r10, r11, op2));
668 
669          /* The result is in registers r10 (remainder) and r11 (quotient).
670             Move the result into the reg pair that is being returned such
671             such that the low 64 bits are the quotient and the upper 64 bits
672             are the remainder. (see libvex_ir.h). */
673          *dst_hi = newVRegI(env);
674          *dst_lo = newVRegI(env);
675          addInstr(env, s390_insn_move(8, *dst_hi, r10));
676          addInstr(env, s390_insn_move(8, *dst_lo, r11));
677          return;
678       }
679 
680       default:
681          break;
682 
683       do_multiply64: {
684             HReg r10, r11, h1;
685             s390_opnd_RMI op2;
686 
687             order_commutative_operands(arg1, arg2);
688 
689             h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
690             op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
691 
692             /* We use non-virtual registers r10 and r11 as pair */
693             r10  = make_gpr(10);
694             r11  = make_gpr(11);
695 
696             /* Move the first operand to r11 */
697             addInstr(env, s390_insn_move(8, r11, h1));
698 
699             /* Multiply */
700             addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
701 
702             /* The result is in registers r10 and r11. Assign to two virtual regs
703                and return. */
704             *dst_hi = newVRegI(env);
705             *dst_lo = newVRegI(env);
706             addInstr(env, s390_insn_move(8, *dst_hi, r10));
707             addInstr(env, s390_insn_move(8, *dst_lo, r11));
708             return;
709          }
710 
711       do_divide64: {
712          HReg r10, r11, hi, lo;
713          s390_opnd_RMI op2;
714 
715          s390_isel_int128_expr(&hi, &lo, env, arg1);
716          op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
717 
718          /* We use non-virtual registers r10 and r11 as pair */
719          r10  = make_gpr(10);
720          r11  = make_gpr(11);
721 
722          /* Move high 64 bits of the 1st operand into r10 and
723             the low 64 bits into r11. */
724          addInstr(env, s390_insn_move(8, r10, hi));
725          addInstr(env, s390_insn_move(8, r11, lo));
726 
727          /* Divide */
728          addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
729 
730          /* The result is in registers r10 (remainder) and r11 (quotient).
731             Move the result into the reg pair that is being returned such
732             such that the low 64 bits are the quotient and the upper 64 bits
733             are the remainder. (see libvex_ir.h). */
734          *dst_hi = newVRegI(env);
735          *dst_lo = newVRegI(env);
736          addInstr(env, s390_insn_move(8, *dst_hi, r10));
737          addInstr(env, s390_insn_move(8, *dst_lo, r11));
738          return;
739       }
740       }
741    }
742 
743    vpanic("s390_isel_int128_expr");
744 }
745 
746 
747 /* Compute a 128-bit value into two 64-bit registers. These may be either
748    real or virtual regs; in any case they must not be changed by subsequent
749    code emitted by the caller. */
750 static void
s390_isel_int128_expr(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)751 s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
752 {
753    s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
754 
755    /* Sanity checks ... */
756    vassert(hregIsVirtual(*dst_hi));
757    vassert(hregIsVirtual(*dst_lo));
758    vassert(hregClass(*dst_hi) == HRcInt64);
759    vassert(hregClass(*dst_lo) == HRcInt64);
760 }
761 
762 
763 /*---------------------------------------------------------*/
764 /*--- ISEL: Integer expressions (64/32/16/8 bit)        ---*/
765 /*---------------------------------------------------------*/
766 
767 /* Select insns for an integer-typed expression, and add them to the
768    code list.  Return a reg holding the result.  This reg will be a
769    virtual register.  THE RETURNED REG MUST NOT BE MODIFIED.  If you
770    want to modify it, ask for a new vreg, copy it in there, and modify
771    the copy.  The register allocator will do its best to map both
772    vregs to the same real register, so the copies will often disappear
773    later in the game.
774 
775    This should handle expressions of 64, 32, 16 and 8-bit type.
776    All results are returned in a 64bit register.
777    For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
778    are arbitrary, so you should mask or sign extend partial values
779    if necessary.
780 */
781 
782 /* DO NOT CALL THIS DIRECTLY ! */
783 static HReg
s390_isel_int_expr_wrk(ISelEnv * env,IRExpr * expr)784 s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
785 {
786    IRType ty = typeOfIRExpr(env->type_env, expr);
787    UChar size;
788    s390_bfp_unop_t bfpop;
789 
790    vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
791 
792    size = sizeofIRType(ty);   /* size of the result after evaluating EXPR */
793 
794    switch (expr->tag) {
795 
796       /* --------- TEMP --------- */
797    case Iex_RdTmp:
798       /* Return the virtual register that holds the temporary. */
799       return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
800 
801       /* --------- LOAD --------- */
802    case Iex_Load: {
803       HReg        dst = newVRegI(env);
804       s390_amode *am  = s390_isel_amode(env, expr->Iex.Load.addr);
805 
806       if (expr->Iex.Load.end != Iend_BE)
807          goto irreducible;
808 
809       addInstr(env, s390_insn_load(size, dst, am));
810 
811       return dst;
812    }
813 
814       /* --------- BINARY OP --------- */
815    case Iex_Binop: {
816       IRExpr *arg1 = expr->Iex.Binop.arg1;
817       IRExpr *arg2 = expr->Iex.Binop.arg2;
818       HReg h1, res;
819       s390_alu_t opkind;
820       s390_opnd_RMI op2, value, opnd;
821       s390_insn *insn;
822       Bool is_commutative, is_signed_multiply, is_signed_divide;
823 
824       is_commutative = True;
825 
826       switch (expr->Iex.Binop.op) {
827       case Iop_MullU8:
828       case Iop_MullU16:
829       case Iop_MullU32:
830          is_signed_multiply = False;
831          goto do_multiply;
832 
833       case Iop_MullS8:
834       case Iop_MullS16:
835       case Iop_MullS32:
836          is_signed_multiply = True;
837          goto do_multiply;
838 
839       do_multiply: {
840             HReg r10, r11;
841             UInt arg_size = size / 2;
842 
843             order_commutative_operands(arg1, arg2);
844 
845             h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
846             op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
847 
848             /* We use non-virtual registers r10 and r11 as pair */
849             r10  = make_gpr(10);
850             r11  = make_gpr(11);
851 
852             /* Move the first operand to r11 */
853             addInstr(env, s390_insn_move(arg_size, r11, h1));
854 
855             /* Multiply */
856             addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
857 
858             /* The result is in registers r10 and r11. Combine them into a SIZE-bit
859                value into the destination register. */
860             res  = newVRegI(env);
861             addInstr(env, s390_insn_move(arg_size, res, r10));
862             value = s390_opnd_imm(arg_size * 8);
863             addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
864             value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
865             addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
866             opnd = s390_opnd_reg(r11);
867             addInstr(env, s390_insn_alu(size, S390_ALU_OR,  res, opnd));
868             return res;
869          }
870 
871       case Iop_DivModS64to32:
872          is_signed_divide = True;
873          goto do_divide;
874 
875       case Iop_DivModU64to32:
876          is_signed_divide = False;
877          goto do_divide;
878 
879       do_divide: {
880             HReg r10, r11;
881 
882             h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
883             op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
884 
885             /* We use non-virtual registers r10 and r11 as pair */
886             r10  = make_gpr(10);
887             r11  = make_gpr(11);
888 
889             /* Split the first operand and put the high 32 bits into r10 and
890                the low 32 bits into r11. */
891             addInstr(env, s390_insn_move(8, r10, h1));
892             addInstr(env, s390_insn_move(8, r11, h1));
893             value = s390_opnd_imm(32);
894             addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
895 
896             /* Divide */
897             addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
898 
899             /* The result is in registers r10 (remainder) and r11 (quotient).
900                Combine them into a 64-bit value such that the low 32 bits are
901                the quotient and the upper 32 bits are the remainder. (see
902                libvex_ir.h). */
903             res  = newVRegI(env);
904             addInstr(env, s390_insn_move(8, res, r10));
905             value = s390_opnd_imm(32);
906             addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
907             value = s390_opnd_imm((((ULong)1) << 32) - 1);
908             addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
909             opnd = s390_opnd_reg(r11);
910             addInstr(env, s390_insn_alu(8, S390_ALU_OR,  res, opnd));
911             return res;
912          }
913 
914       case Iop_F32toI32S:  bfpop = S390_BFP_F32_TO_I32;  goto do_convert;
915       case Iop_F32toI64S:  bfpop = S390_BFP_F32_TO_I64;  goto do_convert;
916       case Iop_F64toI32S:  bfpop = S390_BFP_F64_TO_I32;  goto do_convert;
917       case Iop_F64toI64S:  bfpop = S390_BFP_F64_TO_I64;  goto do_convert;
918       case Iop_F128toI32S: bfpop = S390_BFP_F128_TO_I32; goto do_convert_128;
919       case Iop_F128toI64S: bfpop = S390_BFP_F128_TO_I64; goto do_convert_128;
920 
921       do_convert: {
922          s390_round_t rounding_mode;
923 
924          res  = newVRegI(env);
925          h1   = s390_isel_float_expr(env, arg2);   /* Process operand */
926 
927          rounding_mode = decode_rounding_mode(arg1);
928          addInstr(env, s390_insn_bfp_unop(size, bfpop, res, h1, rounding_mode));
929          return res;
930       }
931 
932       do_convert_128: {
933          s390_round_t rounding_mode;
934          HReg op_hi, op_lo, f13, f15;
935 
936          res = newVRegI(env);
937          s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
938 
939          /* We use non-virtual registers r13 and r15 as pair */
940          f13 = make_fpr(13);
941          f15 = make_fpr(15);
942 
943          /* operand --> (f13, f15) */
944          addInstr(env, s390_insn_move(8, f13, op_hi));
945          addInstr(env, s390_insn_move(8, f15, op_lo));
946 
947          rounding_mode = decode_rounding_mode(arg1);
948          addInstr(env, s390_insn_bfp128_convert_from(size, bfpop, res, f13, f15,
949                                                      rounding_mode));
950          return res;
951       }
952 
953       case Iop_8HLto16:
954       case Iop_16HLto32:
955       case Iop_32HLto64: {
956          HReg h2;
957          UInt arg_size = size / 2;
958 
959          res  = newVRegI(env);
960          h1   = s390_isel_int_expr(env, arg1);   /* Process 1st operand */
961          h2   = s390_isel_int_expr(env, arg2);   /* Process 2nd operand */
962 
963          addInstr(env, s390_insn_move(arg_size, res, h1));
964          value = s390_opnd_imm(arg_size * 8);
965          addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
966          value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
967          addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
968          opnd = s390_opnd_reg(h2);
969          addInstr(env, s390_insn_alu(size, S390_ALU_OR,  res, opnd));
970          return res;
971       }
972 
973       case Iop_Max32U: {
974          /* arg1 > arg2 ? arg1 : arg2   using uint32_t arguments */
975          res = newVRegI(env);
976          h1  = s390_isel_int_expr(env, arg1);
977          op2 = s390_isel_int_expr_RMI(env, arg2);
978 
979          addInstr(env, s390_insn_move(size, res, h1));
980          addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
981          addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
982          return res;
983       }
984 
985       case Iop_CmpF32:
986       case Iop_CmpF64: {
987          HReg cc_s390, h2;
988 
989          h1 = s390_isel_float_expr(env, arg1);
990          h2 = s390_isel_float_expr(env, arg2);
991          cc_s390 = newVRegI(env);
992 
993          size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
994 
995          addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
996 
997          return convert_s390_fpcc_to_vex(env, cc_s390);
998       }
999 
1000       case Iop_CmpF128: {
1001          HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1002 
1003          s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1004          s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1005          cc_s390 = newVRegI(env);
1006 
1007          /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1008          f12 = make_fpr(12);
1009          f13 = make_fpr(13);
1010          f14 = make_fpr(14);
1011          f15 = make_fpr(15);
1012 
1013          /* 1st operand --> (f12, f14) */
1014          addInstr(env, s390_insn_move(8, f12, op1_hi));
1015          addInstr(env, s390_insn_move(8, f14, op1_lo));
1016 
1017          /* 2nd operand --> (f13, f15) */
1018          addInstr(env, s390_insn_move(8, f13, op2_hi));
1019          addInstr(env, s390_insn_move(8, f15, op2_lo));
1020 
1021          res = newVRegI(env);
1022          addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1023 
1024          return convert_s390_fpcc_to_vex(env, cc_s390);
1025       }
1026 
1027       case Iop_Add8:
1028       case Iop_Add16:
1029       case Iop_Add32:
1030       case Iop_Add64:
1031          opkind = S390_ALU_ADD;
1032          break;
1033 
1034       case Iop_Sub8:
1035       case Iop_Sub16:
1036       case Iop_Sub32:
1037       case Iop_Sub64:
1038          opkind = S390_ALU_SUB;
1039          is_commutative = False;
1040          break;
1041 
1042       case Iop_And8:
1043       case Iop_And16:
1044       case Iop_And32:
1045       case Iop_And64:
1046          opkind = S390_ALU_AND;
1047          break;
1048 
1049       case Iop_Or8:
1050       case Iop_Or16:
1051       case Iop_Or32:
1052       case Iop_Or64:
1053          opkind = S390_ALU_OR;
1054          break;
1055 
1056       case Iop_Xor8:
1057       case Iop_Xor16:
1058       case Iop_Xor32:
1059       case Iop_Xor64:
1060          opkind = S390_ALU_XOR;
1061          break;
1062 
1063       case Iop_Shl8:
1064       case Iop_Shl16:
1065       case Iop_Shl32:
1066       case Iop_Shl64:
1067          opkind = S390_ALU_LSH;
1068          is_commutative = False;
1069          break;
1070 
1071       case Iop_Shr8:
1072       case Iop_Shr16:
1073       case Iop_Shr32:
1074       case Iop_Shr64:
1075          opkind = S390_ALU_RSH;
1076          is_commutative = False;
1077          break;
1078 
1079       case Iop_Sar8:
1080       case Iop_Sar16:
1081       case Iop_Sar32:
1082       case Iop_Sar64:
1083          opkind = S390_ALU_RSHA;
1084          is_commutative = False;
1085          break;
1086 
1087       default:
1088          goto irreducible;
1089       }
1090 
1091       /* Pattern match: 0 - arg1  -->  -arg1   */
1092       if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1093          res  = newVRegI(env);
1094          op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1095          insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1096          addInstr(env, insn);
1097 
1098          return res;
1099       }
1100 
1101       if (is_commutative) {
1102          order_commutative_operands(arg1, arg2);
1103       }
1104 
1105       h1   = s390_isel_int_expr(env, arg1);       /* Process 1st operand */
1106       op2  = s390_isel_int_expr_RMI(env, arg2);   /* Process 2nd operand */
1107       res  = newVRegI(env);
1108       addInstr(env, s390_insn_move(size, res, h1));
1109       insn = s390_insn_alu(size, opkind, res, op2);
1110 
1111       addInstr(env, insn);
1112 
1113       return res;
1114    }
1115 
1116       /* --------- UNARY OP --------- */
1117    case Iex_Unop: {
1118       static s390_opnd_RMI mask  = { S390_OPND_IMMEDIATE };
1119       static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1120       s390_opnd_RMI opnd;
1121       s390_insn    *insn;
1122       IRExpr *arg;
1123       HReg    dst, h1;
1124       IROp    unop, binop;
1125 
1126       arg = expr->Iex.Unop.arg;
1127 
1128       /* Special cases are handled here */
1129 
1130       /* 32-bit multiply with 32-bit result or
1131          64-bit multiply with 64-bit result */
1132       unop  = expr->Iex.Unop.op;
1133       binop = arg->Iex.Binop.op;
1134 
1135       if ((arg->tag == Iex_Binop &&
1136            ((unop == Iop_64to32 &&
1137              (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1138             (unop == Iop_128to64 &&
1139              (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1140          h1   = s390_isel_int_expr(env, arg->Iex.Binop.arg1);     /* 1st opnd */
1141          opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1142          dst  = newVRegI(env);     /* Result goes into a new register */
1143          addInstr(env, s390_insn_move(size, dst, h1));
1144          addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1145 
1146          return dst;
1147       }
1148 
1149       if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
1150          dst = newVRegI(env);
1151          h1  = s390_isel_float_expr(env, arg);     /* Process the operand */
1152          addInstr(env, s390_insn_move(size, dst, h1));
1153 
1154          return dst;
1155       }
1156 
1157       /* Expressions whose argument is 1-bit wide */
1158       if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1159          s390_cc_t cond = s390_isel_cc(env, arg);
1160          dst = newVRegI(env);     /* Result goes into a new register */
1161          addInstr(env, s390_insn_cc2bool(dst, cond));
1162 
1163          switch (unop) {
1164          case Iop_1Uto8:
1165          case Iop_1Uto32:
1166             /* Zero extend */
1167             mask.variant.imm = 1;
1168             addInstr(env, s390_insn_alu(4, S390_ALU_AND,  dst, mask));
1169             break;
1170 
1171          case Iop_1Uto64:
1172             /* Zero extend */
1173             mask.variant.imm = 1;
1174             addInstr(env, s390_insn_alu(8, S390_ALU_AND,  dst, mask));
1175             break;
1176 
1177          case Iop_1Sto8:
1178          case Iop_1Sto16:
1179          case Iop_1Sto32:
1180             shift.variant.imm = 31;
1181             addInstr(env, s390_insn_alu(4, S390_ALU_LSH,  dst, shift));
1182             addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1183             break;
1184 
1185          case Iop_1Sto64:
1186             shift.variant.imm = 63;
1187             addInstr(env, s390_insn_alu(8, S390_ALU_LSH,  dst, shift));
1188             addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1189             break;
1190 
1191          default:
1192             goto irreducible;
1193          }
1194 
1195          return dst;
1196       }
1197 
1198       /* Regular processing */
1199 
1200       if (unop == Iop_128to64) {
1201          HReg dst_hi, dst_lo;
1202 
1203          s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1204          return dst_lo;
1205       }
1206 
1207       if (unop == Iop_128HIto64) {
1208          HReg dst_hi, dst_lo;
1209 
1210          s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1211          return dst_hi;
1212       }
1213 
1214       dst  = newVRegI(env);     /* Result goes into a new register */
1215       opnd = s390_isel_int_expr_RMI(env, arg);     /* Process the operand */
1216 
1217       switch (unop) {
1218       case Iop_8Uto16:
1219       case Iop_8Uto32:
1220       case Iop_8Uto64:
1221          insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1222          break;
1223 
1224       case Iop_16Uto32:
1225       case Iop_16Uto64:
1226          insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1227          break;
1228 
1229       case Iop_32Uto64:
1230          insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1231          break;
1232 
1233       case Iop_8Sto16:
1234       case Iop_8Sto32:
1235       case Iop_8Sto64:
1236          insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1237          break;
1238 
1239       case Iop_16Sto32:
1240       case Iop_16Sto64:
1241          insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1242          break;
1243 
1244       case Iop_32Sto64:
1245          insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1246          break;
1247 
1248       case Iop_64to8:
1249       case Iop_64to16:
1250       case Iop_64to32:
1251       case Iop_32to8:
1252       case Iop_32to16:
1253       case Iop_16to8:
1254          /* Down-casts are no-ops. Upstream operations will only look at
1255             the bytes that make up the result of the down-cast. So there
1256             is no point setting the other bytes to 0. */
1257          insn = s390_opnd_copy(8, dst, opnd);
1258          break;
1259 
1260       case Iop_64HIto32:
1261          addInstr(env, s390_opnd_copy(8, dst, opnd));
1262          shift.variant.imm = 32;
1263          insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1264          break;
1265 
1266       case Iop_32HIto16:
1267          addInstr(env, s390_opnd_copy(4, dst, opnd));
1268          shift.variant.imm = 16;
1269          insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1270          break;
1271 
1272       case Iop_16HIto8:
1273          addInstr(env, s390_opnd_copy(2, dst, opnd));
1274          shift.variant.imm = 8;
1275          insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1276          break;
1277 
1278       case Iop_Not8:
1279       case Iop_Not16:
1280       case Iop_Not32:
1281       case Iop_Not64:
1282          /* XOR with ffff... */
1283          mask.variant.imm = ~(ULong)0;
1284          addInstr(env, s390_opnd_copy(size, dst, opnd));
1285          insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1286          break;
1287 
1288       case Iop_Left8:
1289       case Iop_Left16:
1290       case Iop_Left32:
1291       case Iop_Left64:
1292          addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1293          insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1294          break;
1295 
1296       case Iop_CmpwNEZ32:
1297       case Iop_CmpwNEZ64: {
1298          /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1299             or -X will have a 1 in the MSB. */
1300          addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1301          addInstr(env, s390_insn_alu(size, S390_ALU_OR,  dst, opnd));
1302          shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1303          addInstr(env, s390_insn_alu(size, S390_ALU_RSHA,  dst, shift));
1304          return dst;
1305       }
1306 
1307       case Iop_Clz64: {
1308          HReg r10, r11;
1309 
1310          /* This will be implemented using FLOGR, if possible. So we need to
1311             set aside a pair of non-virtual registers. The result (number of
1312             left-most zero bits) will be in r10. The value in r11 is unspecified
1313             and must not be used. */
1314          r10  = make_gpr(10);
1315          r11  = make_gpr(11);
1316 
1317          addInstr(env, s390_insn_clz(8, r10, r11, opnd));
1318          addInstr(env, s390_insn_move(8, dst, r10));
1319          return dst;
1320       }
1321 
1322       default:
1323          goto irreducible;
1324       }
1325 
1326       addInstr(env, insn);
1327 
1328       return dst;
1329    }
1330 
1331       /* --------- GET --------- */
1332    case Iex_Get: {
1333       HReg dst = newVRegI(env);
1334       s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1335 
1336       /* We never load more than 8 bytes from the guest state, because the
1337          floating point register pair is not contiguous. */
1338       vassert(size <= 8);
1339 
1340       addInstr(env, s390_insn_load(size, dst, am));
1341 
1342       return dst;
1343    }
1344 
1345    case Iex_GetI:
1346       /* not needed */
1347       break;
1348 
1349       /* --------- CCALL --------- */
1350    case Iex_CCall: {
1351       HReg dst = newVRegI(env);
1352 
1353       doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
1354                    expr->Iex.CCall.args, dst);
1355       return dst;
1356    }
1357 
1358       /* --------- LITERAL --------- */
1359 
1360       /* Load a literal into a register. Create a "load immediate"
1361          v-insn and return the register. */
1362    case Iex_Const: {
1363       ULong value;
1364       HReg  dst = newVRegI(env);
1365       const IRConst *con = expr->Iex.Const.con;
1366 
1367       /* Bitwise copy of the value. No sign/zero-extension */
1368       switch (con->tag) {
1369       case Ico_U64: value = con->Ico.U64; break;
1370       case Ico_U32: value = con->Ico.U32; break;
1371       case Ico_U16: value = con->Ico.U16; break;
1372       case Ico_U8:  value = con->Ico.U8;  break;
1373       default:      vpanic("s390_isel_int_expr: invalid constant");
1374       }
1375 
1376       addInstr(env, s390_insn_load_immediate(size, dst, value));
1377 
1378       return dst;
1379    }
1380 
1381       /* --------- MULTIPLEX --------- */
1382    case Iex_Mux0X: {
1383       IRExpr *cond_expr;
1384       HReg dst, tmp, rX;
1385       s390_opnd_RMI cond, r0, zero;
1386 
1387       cond_expr = expr->Iex.Mux0X.cond;
1388 
1389       dst  = newVRegI(env);
1390       r0   = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1391       rX   = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1392       size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1393 
1394       if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1395          s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1396 
1397          addInstr(env, s390_insn_move(size, dst, rX));
1398          addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1399          return dst;
1400       }
1401 
1402       /* Assume the condition is true and move rX to the destination reg. */
1403       addInstr(env, s390_insn_move(size, dst, rX));
1404 
1405       /* Compute the condition ... */
1406       cond = s390_isel_int_expr_RMI(env, cond_expr);
1407 
1408       /* tmp = cond & 0xFF */
1409       tmp  = newVRegI(env);
1410       addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1411       addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1412 
1413       /* ... and compare it with zero */
1414       zero = s390_opnd_imm(0);
1415       addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1416 
1417       /* ... and if it compared equal move r0 to the destination reg. */
1418       size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1419       addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1420 
1421       return dst;
1422    }
1423 
1424    default:
1425       break;
1426    }
1427 
1428    /* We get here if no pattern matched. */
1429  irreducible:
1430    ppIRExpr(expr);
1431    vpanic("s390_isel_int_expr: cannot reduce tree");
1432 }
1433 
1434 
1435 static HReg
s390_isel_int_expr(ISelEnv * env,IRExpr * expr)1436 s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1437 {
1438    HReg dst = s390_isel_int_expr_wrk(env, expr);
1439 
1440    /* Sanity checks ... */
1441    vassert(hregClass(dst) == HRcInt64);
1442    vassert(hregIsVirtual(dst));
1443 
1444    return dst;
1445 }
1446 
1447 
1448 static s390_opnd_RMI
s390_isel_int_expr_RMI(ISelEnv * env,IRExpr * expr)1449 s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1450 {
1451    IRType ty = typeOfIRExpr(env->type_env, expr);
1452    s390_opnd_RMI dst;
1453 
1454    vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1455            ty == Ity_I64);
1456 
1457    if (expr->tag == Iex_Load) {
1458       dst.tag = S390_OPND_AMODE;
1459       dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1460    } else if (expr->tag == Iex_Get) {
1461       dst.tag = S390_OPND_AMODE;
1462       dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1463    } else if (expr->tag == Iex_Const) {
1464       ULong value;
1465 
1466       /* The bit pattern for the value will be stored as is in the least
1467          significant bits of VALUE. */
1468       switch (expr->Iex.Const.con->tag) {
1469       case Ico_U1:  value = expr->Iex.Const.con->Ico.U1;  break;
1470       case Ico_U8:  value = expr->Iex.Const.con->Ico.U8;  break;
1471       case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1472       case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1473       case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1474       default:
1475          vpanic("s390_isel_int_expr_RMI");
1476       }
1477 
1478       dst.tag = S390_OPND_IMMEDIATE;
1479       dst.variant.imm = value;
1480    } else {
1481       dst.tag = S390_OPND_REG;
1482       dst.variant.reg = s390_isel_int_expr(env, expr);
1483    }
1484 
1485    return dst;
1486 }
1487 
1488 
1489 /*---------------------------------------------------------*/
1490 /*--- ISEL: Floating point expressions (128 bit)        ---*/
1491 /*---------------------------------------------------------*/
1492 static void
s390_isel_float128_expr_wrk(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)1493 s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1494                             IRExpr *expr)
1495 {
1496    IRType ty = typeOfIRExpr(env->type_env, expr);
1497 
1498    vassert(ty == Ity_F128);
1499 
1500    /* Read 128-bit IRTemp */
1501    if (expr->tag == Iex_RdTmp) {
1502       lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1503       return;
1504    }
1505 
1506    switch (expr->tag) {
1507    case Iex_RdTmp:
1508       /* Return the virtual registers that hold the temporary. */
1509       lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1510       return;
1511 
1512       /* --------- LOAD --------- */
1513    case Iex_Load: {
1514       IRExpr *addr_hi, *addr_lo;
1515       s390_amode *am_hi, *am_lo;
1516 
1517       if (expr->Iex.Load.end != Iend_BE)
1518          goto irreducible;
1519 
1520       addr_hi = expr->Iex.Load.addr;
1521       addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1522 
1523       am_hi  = s390_isel_amode(env, addr_hi);
1524       am_lo  = s390_isel_amode(env, addr_lo);
1525 
1526       *dst_hi = newVRegF(env);
1527       *dst_lo = newVRegF(env);
1528       addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1529       addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1530       return;
1531    }
1532 
1533 
1534       /* --------- GET --------- */
1535    case Iex_Get:
1536       /* This is not supported because loading 128-bit from the guest
1537          state is almost certainly wrong. Use get_fpr_pair instead. */
1538       vpanic("Iex_Get with F128 data");
1539 
1540       /* --------- 4-ary OP --------- */
1541    case Iex_Qop:
1542       vpanic("Iex_Qop with F128 data");
1543 
1544       /* --------- TERNARY OP --------- */
1545    case Iex_Triop: {
1546       IRTriop *triop = expr->Iex.Triop.details;
1547       IROp    op     = triop->op;
1548       IRExpr *left   = triop->arg2;
1549       IRExpr *right  = triop->arg3;
1550       s390_bfp_binop_t bfpop;
1551       s390_round_t rounding_mode;
1552       HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1553 
1554       s390_isel_float128_expr(&op1_hi, &op1_lo, env, left);  /* 1st operand */
1555       s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1556 
1557       /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1558       f12 = make_fpr(12);
1559       f13 = make_fpr(13);
1560       f14 = make_fpr(14);
1561       f15 = make_fpr(15);
1562 
1563       /* 1st operand --> (f12, f14) */
1564       addInstr(env, s390_insn_move(8, f12, op1_hi));
1565       addInstr(env, s390_insn_move(8, f14, op1_lo));
1566 
1567       /* 2nd operand --> (f13, f15) */
1568       addInstr(env, s390_insn_move(8, f13, op2_hi));
1569       addInstr(env, s390_insn_move(8, f15, op2_lo));
1570 
1571       switch (op) {
1572       case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1573       case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1574       case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1575       case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1576       default:
1577          goto irreducible;
1578       }
1579 
1580       rounding_mode = decode_rounding_mode(triop->arg1);
1581       addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1582                                            f15, rounding_mode));
1583 
1584       /* Move result to virtual destination register */
1585       *dst_hi = newVRegF(env);
1586       *dst_lo = newVRegF(env);
1587       addInstr(env, s390_insn_move(8, *dst_hi, f12));
1588       addInstr(env, s390_insn_move(8, *dst_lo, f14));
1589 
1590       return;
1591    }
1592 
1593       /* --------- BINARY OP --------- */
1594    case Iex_Binop: {
1595       HReg op_hi, op_lo, f12, f13, f14, f15;
1596       s390_bfp_unop_t bfpop;
1597       s390_round_t rounding_mode;
1598 
1599       /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1600       f12 = make_fpr(12);
1601       f13 = make_fpr(13);
1602       f14 = make_fpr(14);
1603       f15 = make_fpr(15);
1604 
1605       switch (expr->Iex.Binop.op) {
1606       case Iop_SqrtF128:
1607          s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1608 
1609          /* operand --> (f13, f15) */
1610          addInstr(env, s390_insn_move(8, f13, op_hi));
1611          addInstr(env, s390_insn_move(8, f15, op_lo));
1612 
1613          bfpop = S390_BFP_SQRT;
1614          rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1615 
1616          addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1617                                              rounding_mode));
1618 
1619          /* Move result to virtual destination registers */
1620          *dst_hi = newVRegF(env);
1621          *dst_lo = newVRegF(env);
1622          addInstr(env, s390_insn_move(8, *dst_hi, f12));
1623          addInstr(env, s390_insn_move(8, *dst_lo, f14));
1624          return;
1625 
1626       case Iop_F64HLtoF128:
1627          *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1628          *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1629          return;
1630 
1631       default:
1632          goto irreducible;
1633       }
1634    }
1635 
1636       /* --------- UNARY OP --------- */
1637    case Iex_Unop: {
1638       IRExpr *left = expr->Iex.Unop.arg;
1639       s390_bfp_unop_t bfpop;
1640       s390_round_t rounding_mode;
1641       HReg op_hi, op_lo, op, f12, f13, f14, f15;
1642 
1643       /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1644       f12 = make_fpr(12);
1645       f13 = make_fpr(13);
1646       f14 = make_fpr(14);
1647       f15 = make_fpr(15);
1648 
1649       switch (expr->Iex.Unop.op) {
1650       case Iop_NegF128:       bfpop = S390_BFP_NEG;          goto float128_opnd;
1651       case Iop_AbsF128:       bfpop = S390_BFP_ABS;          goto float128_opnd;
1652       case Iop_I32StoF128:    bfpop = S390_BFP_I32_TO_F128;  goto convert_int;
1653       case Iop_I64StoF128:    bfpop = S390_BFP_I64_TO_F128;  goto convert_int;
1654       case Iop_F32toF128:     bfpop = S390_BFP_F32_TO_F128;  goto convert_float;
1655       case Iop_F64toF128:     bfpop = S390_BFP_F64_TO_F128;  goto convert_float;
1656       default:
1657          goto irreducible;
1658       }
1659 
1660    float128_opnd:
1661       s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1662 
1663       /* operand --> (f13, f15) */
1664       addInstr(env, s390_insn_move(8, f13, op_hi));
1665       addInstr(env, s390_insn_move(8, f15, op_lo));
1666 
1667       rounding_mode = S390_ROUND_NEAREST_EVEN;  /* will not be used later on */
1668       addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1669                                           rounding_mode));
1670       goto move_dst;
1671 
1672    convert_float:
1673       op  = s390_isel_float_expr(env, left);
1674       addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1675                                                 op));
1676       goto move_dst;
1677 
1678    convert_int:
1679       op  = s390_isel_int_expr(env, left);
1680       addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1681                                                 op));
1682       goto move_dst;
1683 
1684    move_dst:
1685       /* Move result to virtual destination registers */
1686       *dst_hi = newVRegF(env);
1687       *dst_lo = newVRegF(env);
1688       addInstr(env, s390_insn_move(8, *dst_hi, f12));
1689       addInstr(env, s390_insn_move(8, *dst_lo, f14));
1690       return;
1691    }
1692 
1693    default:
1694       goto irreducible;
1695    }
1696 
1697    /* We get here if no pattern matched. */
1698  irreducible:
1699    ppIRExpr(expr);
1700    vpanic("s390_isel_int_expr: cannot reduce tree");
1701 }
1702 
1703 /* Compute a 128-bit value into two 64-bit registers. These may be either
1704    real or virtual regs; in any case they must not be changed by subsequent
1705    code emitted by the caller. */
1706 static void
s390_isel_float128_expr(HReg * dst_hi,HReg * dst_lo,ISelEnv * env,IRExpr * expr)1707 s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1708 {
1709    s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1710 
1711    /* Sanity checks ... */
1712    vassert(hregIsVirtual(*dst_hi));
1713    vassert(hregIsVirtual(*dst_lo));
1714    vassert(hregClass(*dst_hi) == HRcFlt64);
1715    vassert(hregClass(*dst_lo) == HRcFlt64);
1716 }
1717 
1718 
1719 /*---------------------------------------------------------*/
1720 /*--- ISEL: Floating point expressions (64 bit)         ---*/
1721 /*---------------------------------------------------------*/
1722 
1723 static HReg
s390_isel_float_expr_wrk(ISelEnv * env,IRExpr * expr)1724 s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1725 {
1726    IRType ty = typeOfIRExpr(env->type_env, expr);
1727    UChar size;
1728 
1729    vassert(ty == Ity_F32 || ty == Ity_F64);
1730 
1731    size = sizeofIRType(ty);
1732 
1733    switch (expr->tag) {
1734    case Iex_RdTmp:
1735       /* Return the virtual register that holds the temporary. */
1736       return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1737 
1738       /* --------- LOAD --------- */
1739    case Iex_Load: {
1740       HReg        dst = newVRegF(env);
1741       s390_amode *am  = s390_isel_amode(env, expr->Iex.Load.addr);
1742 
1743       if (expr->Iex.Load.end != Iend_BE)
1744          goto irreducible;
1745 
1746       addInstr(env, s390_insn_load(size, dst, am));
1747 
1748       return dst;
1749    }
1750 
1751       /* --------- GET --------- */
1752    case Iex_Get: {
1753       HReg dst = newVRegF(env);
1754       s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1755 
1756       addInstr(env, s390_insn_load(size, dst, am));
1757 
1758       return dst;
1759    }
1760 
1761       /* --------- LITERAL --------- */
1762 
1763       /* Load a literal into a register. Create a "load immediate"
1764          v-insn and return the register. */
1765    case Iex_Const: {
1766       ULong value;
1767       HReg  dst = newVRegF(env);
1768       const IRConst *con = expr->Iex.Const.con;
1769 
1770       /* Bitwise copy of the value. No sign/zero-extension */
1771       switch (con->tag) {
1772       case Ico_F32i: value = con->Ico.F32i; break;
1773       case Ico_F64i: value = con->Ico.F64i; break;
1774       default:       vpanic("s390_isel_float_expr: invalid constant");
1775       }
1776 
1777       if (value != 0) vpanic("cannot load immediate floating point constant");
1778 
1779       addInstr(env, s390_insn_load_immediate(size, dst, value));
1780 
1781       return dst;
1782    }
1783 
1784       /* --------- 4-ary OP --------- */
1785    case Iex_Qop: {
1786       HReg op1, op2, op3, dst;
1787       s390_bfp_triop_t bfpop;
1788       s390_round_t rounding_mode;
1789 
1790       op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
1791       op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
1792       op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
1793       dst = newVRegF(env);
1794       addInstr(env, s390_insn_move(size, dst, op1));
1795 
1796       switch (expr->Iex.Qop.details->op) {
1797       case Iop_MAddF32:
1798       case Iop_MAddF64:  bfpop = S390_BFP_MADD; break;
1799       case Iop_MSubF32:
1800       case Iop_MSubF64:  bfpop = S390_BFP_MSUB; break;
1801 
1802       default:
1803          goto irreducible;
1804       }
1805 
1806       rounding_mode = decode_rounding_mode(expr->Iex.Qop.details->arg1);
1807       addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1808                                         rounding_mode));
1809       return dst;
1810    }
1811 
1812       /* --------- TERNARY OP --------- */
1813    case Iex_Triop: {
1814       IRTriop *triop = expr->Iex.Triop.details;
1815       IROp    op     = triop->op;
1816       IRExpr *left   = triop->arg2;
1817       IRExpr *right  = triop->arg3;
1818       s390_bfp_binop_t bfpop;
1819       s390_round_t rounding_mode;
1820       HReg h1, op2, dst;
1821 
1822       h1   = s390_isel_float_expr(env, left);  /* Process 1st operand */
1823       op2  = s390_isel_float_expr(env, right); /* Process 2nd operand */
1824       dst  = newVRegF(env);
1825       addInstr(env, s390_insn_move(size, dst, h1));
1826       switch (op) {
1827       case Iop_AddF32:
1828       case Iop_AddF64:  bfpop = S390_BFP_ADD; break;
1829       case Iop_SubF32:
1830       case Iop_SubF64:  bfpop = S390_BFP_SUB; break;
1831       case Iop_MulF32:
1832       case Iop_MulF64:  bfpop = S390_BFP_MUL; break;
1833       case Iop_DivF32:
1834       case Iop_DivF64:  bfpop = S390_BFP_DIV; break;
1835 
1836       default:
1837          goto irreducible;
1838       }
1839 
1840       rounding_mode = decode_rounding_mode(triop->arg1);
1841       addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1842       return dst;
1843    }
1844 
1845       /* --------- BINARY OP --------- */
1846    case Iex_Binop: {
1847       IROp    op   = expr->Iex.Binop.op;
1848       IRExpr *left = expr->Iex.Binop.arg2;
1849       HReg h1, dst;
1850       s390_bfp_unop_t bfpop;
1851       s390_round_t rounding_mode;
1852       Int integer_operand;
1853 
1854       integer_operand = 1;
1855 
1856       switch (op) {
1857       case Iop_SqrtF32:
1858       case Iop_SqrtF64:
1859          bfpop = S390_BFP_SQRT;
1860          integer_operand = 0;
1861          break;
1862 
1863       case Iop_F64toF32:
1864          bfpop = S390_BFP_F64_TO_F32;
1865          integer_operand = 0;
1866          break;
1867 
1868       case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break;
1869       case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break;
1870       case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break;
1871       default:
1872          goto irreducible;
1873 
1874       case Iop_F128toF64:
1875       case Iop_F128toF32: {
1876          HReg op_hi, op_lo, f12, f13, f14, f15;
1877 
1878          bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1879             : S390_BFP_F128_TO_F64;
1880 
1881          rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1882 
1883          s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1884 
1885          /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1886          f12 = make_fpr(12);
1887          f13 = make_fpr(13);
1888          f14 = make_fpr(14);
1889          f15 = make_fpr(15);
1890 
1891          /* operand --> (f13, f15) */
1892          addInstr(env, s390_insn_move(8, f13, op_hi));
1893          addInstr(env, s390_insn_move(8, f15, op_lo));
1894 
1895          dst = newVRegF(env);
1896          addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1897                                              rounding_mode));
1898 
1899          /* Move result to virtual destination registers */
1900          addInstr(env, s390_insn_move(8, dst, f12));
1901          return dst;
1902       }
1903       }
1904 
1905       /* Process operand */
1906       if (integer_operand) {
1907          h1  = s390_isel_int_expr(env, left);
1908       } else {
1909          h1  = s390_isel_float_expr(env, left);
1910       }
1911 
1912       dst = newVRegF(env);
1913       rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1914       addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1915       return dst;
1916    }
1917 
1918       /* --------- UNARY OP --------- */
1919    case Iex_Unop: {
1920       IROp    op   = expr->Iex.Unop.op;
1921       IRExpr *left = expr->Iex.Unop.arg;
1922       s390_bfp_unop_t bfpop;
1923       s390_round_t rounding_mode;
1924       HReg h1, dst;
1925 
1926       if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1927          HReg dst_hi, dst_lo;
1928 
1929          s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1930          return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1931       }
1932 
1933       if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
1934          dst = newVRegF(env);
1935          h1  = s390_isel_int_expr(env, left);     /* Process the operand */
1936          addInstr(env, s390_insn_move(size, dst, h1));
1937 
1938          return dst;
1939       }
1940 
1941       switch (op) {
1942       case Iop_NegF32:
1943       case Iop_NegF64:
1944          if (left->tag == Iex_Unop &&
1945              (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1946             bfpop = S390_BFP_NABS;
1947          else
1948             bfpop = S390_BFP_NEG;
1949          break;
1950 
1951       case Iop_AbsF32:
1952       case Iop_AbsF64:        bfpop = S390_BFP_ABS;  break;
1953       case Iop_I32StoF64:     bfpop = S390_BFP_I32_TO_F64;  break;
1954       case Iop_F32toF64:      bfpop = S390_BFP_F32_TO_F64;  break;
1955       default:
1956          goto irreducible;
1957       }
1958 
1959       /* Process operand */
1960       if (op == Iop_I32StoF64)
1961          h1 = s390_isel_int_expr(env, left);
1962       else if (bfpop == S390_BFP_NABS)
1963          h1 = s390_isel_float_expr(env, left->Iex.Unop.arg);
1964       else
1965          h1 = s390_isel_float_expr(env, left);
1966 
1967       dst = newVRegF(env);
1968       rounding_mode = S390_ROUND_NEAREST_EVEN;  /* will not be used later on */
1969       addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1970       return dst;
1971    }
1972 
1973    default:
1974       goto irreducible;
1975    }
1976 
1977    /* We get here if no pattern matched. */
1978  irreducible:
1979    ppIRExpr(expr);
1980    vpanic("s390_isel_float_expr: cannot reduce tree");
1981 }
1982 
1983 
1984 static HReg
s390_isel_float_expr(ISelEnv * env,IRExpr * expr)1985 s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
1986 {
1987    HReg dst = s390_isel_float_expr_wrk(env, expr);
1988 
1989    /* Sanity checks ... */
1990    vassert(hregClass(dst) == HRcFlt64);
1991    vassert(hregIsVirtual(dst));
1992 
1993    return dst;
1994 }
1995 
1996 
1997 /*---------------------------------------------------------*/
1998 /*--- ISEL: Condition Code                              ---*/
1999 /*---------------------------------------------------------*/
2000 
2001 /* This function handles all operators that produce a 1-bit result */
2002 static s390_cc_t
s390_isel_cc(ISelEnv * env,IRExpr * cond)2003 s390_isel_cc(ISelEnv *env, IRExpr *cond)
2004 {
2005    UChar size;
2006 
2007    vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2008 
2009    /* Constant: either 1 or 0 */
2010    if (cond->tag == Iex_Const) {
2011       vassert(cond->Iex.Const.con->tag == Ico_U1);
2012       vassert(cond->Iex.Const.con->Ico.U1 == True
2013               || cond->Iex.Const.con->Ico.U1 == False);
2014 
2015       return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2016    }
2017 
2018    /* Variable: values are 1 or 0 */
2019    if (cond->tag == Iex_RdTmp) {
2020       IRTemp tmp = cond->Iex.RdTmp.tmp;
2021       HReg   reg = lookupIRTemp(env, tmp);
2022 
2023       /* Load-and-test does not modify REG; so this is OK. */
2024       if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2025          size = 4;
2026       else
2027          size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2028       addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2029       return S390_CC_NE;
2030    }
2031 
2032    /* Unary operators */
2033    if (cond->tag == Iex_Unop) {
2034       IRExpr *arg = cond->Iex.Unop.arg;
2035 
2036       switch (cond->Iex.Unop.op) {
2037       case Iop_Not1:  /* Not1(cond) */
2038          /* Generate code for EXPR, and negate the test condition */
2039          return s390_cc_invert(s390_isel_cc(env, arg));
2040 
2041          /* Iop_32/64to1  select the LSB from their operand */
2042       case Iop_32to1:
2043       case Iop_64to1: {
2044          HReg dst = newVRegI(env);
2045          HReg h1  = s390_isel_int_expr(env, arg);
2046 
2047          size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2048 
2049          addInstr(env, s390_insn_move(size, dst, h1));
2050          addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2051          addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2052          return S390_CC_NE;
2053       }
2054 
2055       case Iop_CmpNEZ8:
2056       case Iop_CmpNEZ16: {
2057          s390_opnd_RMI src;
2058          s390_unop_t   op;
2059          HReg dst;
2060 
2061          op  = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2062             : S390_ZERO_EXTEND_16;
2063          dst = newVRegI(env);
2064          src = s390_isel_int_expr_RMI(env, arg);
2065          addInstr(env, s390_insn_unop(4, op, dst, src));
2066          addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2067          return S390_CC_NE;
2068       }
2069 
2070       case Iop_CmpNEZ32:
2071       case Iop_CmpNEZ64: {
2072          s390_opnd_RMI src;
2073 
2074          src = s390_isel_int_expr_RMI(env, arg);
2075          size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2076          addInstr(env, s390_insn_test(size, src));
2077          return S390_CC_NE;
2078       }
2079 
2080       default:
2081          goto fail;
2082       }
2083    }
2084 
2085    /* Binary operators */
2086    if (cond->tag == Iex_Binop) {
2087       IRExpr *arg1 = cond->Iex.Binop.arg1;
2088       IRExpr *arg2 = cond->Iex.Binop.arg2;
2089       HReg reg1, reg2;
2090 
2091       size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2092 
2093       switch (cond->Iex.Binop.op) {
2094          s390_unop_t op;
2095          s390_cc_t   result;
2096 
2097       case Iop_CmpEQ8:
2098       case Iop_CasCmpEQ8:
2099          op     = S390_ZERO_EXTEND_8;
2100          result = S390_CC_E;
2101          goto do_compare_ze;
2102 
2103       case Iop_CmpNE8:
2104       case Iop_CasCmpNE8:
2105          op     = S390_ZERO_EXTEND_8;
2106          result = S390_CC_NE;
2107          goto do_compare_ze;
2108 
2109       case Iop_CmpEQ16:
2110       case Iop_CasCmpEQ16:
2111          op     = S390_ZERO_EXTEND_16;
2112          result = S390_CC_E;
2113          goto do_compare_ze;
2114 
2115       case Iop_CmpNE16:
2116       case Iop_CasCmpNE16:
2117          op     = S390_ZERO_EXTEND_16;
2118          result = S390_CC_NE;
2119          goto do_compare_ze;
2120 
2121       do_compare_ze: {
2122             s390_opnd_RMI op1, op2;
2123 
2124             op1  = s390_isel_int_expr_RMI(env, arg1);
2125             reg1 = newVRegI(env);
2126             addInstr(env, s390_insn_unop(4, op, reg1, op1));
2127 
2128             op2  = s390_isel_int_expr_RMI(env, arg2);
2129             reg2 = newVRegI(env);
2130             addInstr(env, s390_insn_unop(4, op, reg2, op2));  /* zero extend */
2131 
2132             op2 = s390_opnd_reg(reg2);
2133             addInstr(env, s390_insn_compare(4, reg1, op2, False));
2134 
2135             return result;
2136          }
2137 
2138       case Iop_CmpEQ32:
2139       case Iop_CmpEQ64:
2140       case Iop_CasCmpEQ32:
2141       case Iop_CasCmpEQ64:
2142          result = S390_CC_E;
2143          goto do_compare;
2144 
2145       case Iop_CmpNE32:
2146       case Iop_CmpNE64:
2147       case Iop_CasCmpNE32:
2148       case Iop_CasCmpNE64:
2149          result = S390_CC_NE;
2150          goto do_compare;
2151 
2152       do_compare: {
2153             HReg op1;
2154             s390_opnd_RMI op2;
2155 
2156             order_commutative_operands(arg1, arg2);
2157 
2158             op1 = s390_isel_int_expr(env, arg1);
2159             op2 = s390_isel_int_expr_RMI(env, arg2);
2160 
2161             addInstr(env, s390_insn_compare(size, op1, op2, False));
2162 
2163             return result;
2164          }
2165 
2166       case Iop_CmpLT32S:
2167       case Iop_CmpLE32S:
2168       case Iop_CmpLT64S:
2169       case Iop_CmpLE64S: {
2170          HReg op1;
2171          s390_opnd_RMI op2;
2172 
2173          op1 = s390_isel_int_expr(env, arg1);
2174          op2 = s390_isel_int_expr_RMI(env, arg2);
2175 
2176          addInstr(env, s390_insn_compare(size, op1, op2, True));
2177 
2178          return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2179                  cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2180       }
2181 
2182       case Iop_CmpLT32U:
2183       case Iop_CmpLE32U:
2184       case Iop_CmpLT64U:
2185       case Iop_CmpLE64U: {
2186          HReg op1;
2187          s390_opnd_RMI op2;
2188 
2189          op1 = s390_isel_int_expr(env, arg1);
2190          op2 = s390_isel_int_expr_RMI(env, arg2);
2191 
2192          addInstr(env, s390_insn_compare(size, op1, op2, False));
2193 
2194          return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2195                  cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2196       }
2197 
2198       default:
2199          goto fail;
2200       }
2201    }
2202 
2203  fail:
2204    ppIRExpr(cond);
2205    vpanic("s390_isel_cc: unexpected operator");
2206 }
2207 
2208 
2209 /*---------------------------------------------------------*/
2210 /*--- ISEL: Statements                                  ---*/
2211 /*---------------------------------------------------------*/
2212 
2213 static void
s390_isel_stmt(ISelEnv * env,IRStmt * stmt)2214 s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2215 {
2216    if (vex_traceflags & VEX_TRACE_VCODE) {
2217       vex_printf("\n -- ");
2218       ppIRStmt(stmt);
2219       vex_printf("\n");
2220    }
2221 
2222    switch (stmt->tag) {
2223 
2224       /* --------- STORE --------- */
2225    case Ist_Store: {
2226       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2227       s390_amode *am;
2228       HReg src;
2229 
2230       if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2231 
2232       am = s390_isel_amode(env, stmt->Ist.Store.addr);
2233 
2234       switch (tyd) {
2235       case Ity_I8:
2236       case Ity_I16:
2237       case Ity_I32:
2238       case Ity_I64:
2239          src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2240          break;
2241 
2242       case Ity_F32:
2243       case Ity_F64:
2244          src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2245          break;
2246 
2247       case Ity_F128:
2248          /* Cannot occur. No such instruction */
2249          vpanic("Ist_Store with F128 data");
2250 
2251       default:
2252          goto stmt_fail;
2253       }
2254 
2255       addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2256       return;
2257    }
2258 
2259       /* --------- PUT --------- */
2260    case Ist_Put: {
2261       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2262       HReg src;
2263       s390_amode *am;
2264       ULong new_value, old_value, difference;
2265 
2266       /* Detect updates to certain guest registers. We track the contents
2267          of those registers as long as they contain constants. If the new
2268          constant is either zero or in the 8-bit neighbourhood of the
2269          current value we can use a memory-to-memory insn to do the update. */
2270 
2271       Int offset = stmt->Ist.Put.offset;
2272 
2273       /* Check necessary conditions:
2274          (1) must be one of the registers we care about
2275          (2) assigned value must be a constant */
2276       Int guest_reg = get_guest_reg(offset);
2277 
2278       if (guest_reg == GUEST_UNKNOWN) goto not_special;
2279 
2280       if (guest_reg == GUEST_IA) {
2281          /* If this is the first assignment to the IA reg, don't special case
2282             it. We need to do a full 8-byte assignment here. The reason is
2283             that in case of a redirected translation the guest IA does not
2284             contain the redirected-to address. Instead it contains the
2285             redirected-from address and those can be far apart. So in order to
2286             do incremnetal updates if the IA in the future we need to get the
2287             initial address of the super block correct. */
2288          if (env->first_IA_assignment) {
2289             env->first_IA_assignment = False;
2290             goto not_special;
2291          }
2292       }
2293 
2294       if (stmt->Ist.Put.data->tag != Iex_Const) {
2295          /* Invalidate guest register contents */
2296          env->old_value_valid[guest_reg] = False;
2297          goto not_special;
2298       }
2299 
2300       /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2301       if (tyd != Ity_I64)
2302          goto not_special;
2303 
2304       /* OK. Necessary conditions are satisfied. */
2305 
2306       old_value = env->old_value[guest_reg];
2307       new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2308       env->old_value[guest_reg] = new_value;
2309 
2310       Bool old_value_is_valid = env->old_value_valid[guest_reg];
2311       env->old_value_valid[guest_reg] = True;
2312 
2313       /* If the register already contains the new value, there is nothing
2314          to do here. Unless the guest register requires precise memory
2315          exceptions. */
2316       if (old_value_is_valid && new_value == old_value) {
2317          if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2318             return;
2319          }
2320       }
2321 
2322       /* guest register = 0 */
2323       if (new_value == 0) {
2324          addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2325          return;
2326       }
2327 
2328       if (old_value_is_valid == False) goto not_special;
2329 
2330       /* If the new value is in the neighbourhood of the old value
2331          we can use a memory-to-memory insn */
2332       difference = new_value - old_value;
2333 
2334       if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2335          addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2336                                       (difference & 0xFF), new_value));
2337          return;
2338       }
2339 
2340       /* If the high word is the same it is sufficient to load the low word.
2341          Use R0 as a scratch reg. */
2342       if ((old_value >> 32) == (new_value >> 32)) {
2343          HReg r0  = make_gpr(0);
2344          HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
2345          s390_amode *gam;
2346 
2347          gam = s390_amode_b12(offset + 4, gsp);
2348          addInstr(env, s390_insn_load_immediate(4, r0,
2349                                                 new_value & 0xFFFFFFFF));
2350          addInstr(env, s390_insn_store(4, gam, r0));
2351          return;
2352       }
2353 
2354       /* No special case applies... fall through */
2355 
2356    not_special:
2357       am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2358 
2359       switch (tyd) {
2360       case Ity_I8:
2361       case Ity_I16:
2362       case Ity_I32:
2363       case Ity_I64:
2364          src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2365          break;
2366 
2367       case Ity_F32:
2368       case Ity_F64:
2369          src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2370          break;
2371 
2372       case Ity_F128:
2373          /* Does not occur. See function put_fpr_pair. */
2374          vpanic("Ist_Put with F128 data");
2375 
2376       default:
2377          goto stmt_fail;
2378       }
2379 
2380       addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2381       return;
2382    }
2383 
2384       /* --------- TMP --------- */
2385    case Ist_WrTmp: {
2386       IRTemp tmp = stmt->Ist.WrTmp.tmp;
2387       IRType tyd = typeOfIRTemp(env->type_env, tmp);
2388       HReg src, dst;
2389 
2390       switch (tyd) {
2391       case Ity_I128: {
2392          HReg dst_hi, dst_lo, res_hi, res_lo;
2393 
2394          s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2395          lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2396 
2397          addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2398          addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2399          return;
2400       }
2401 
2402       case Ity_I8:
2403       case Ity_I16:
2404       case Ity_I32:
2405       case Ity_I64:
2406          src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2407          dst = lookupIRTemp(env, tmp);
2408          break;
2409 
2410       case Ity_I1: {
2411          s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2412          dst = lookupIRTemp(env, tmp);
2413          addInstr(env, s390_insn_cc2bool(dst, cond));
2414          return;
2415       }
2416 
2417       case Ity_F32:
2418       case Ity_F64:
2419          src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2420          dst = lookupIRTemp(env, tmp);
2421          break;
2422 
2423       case Ity_F128: {
2424          HReg dst_hi, dst_lo, res_hi, res_lo;
2425 
2426          s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2427          lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2428 
2429          addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2430          addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2431          return;
2432       }
2433 
2434       default:
2435          goto stmt_fail;
2436       }
2437 
2438       addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2439       return;
2440    }
2441 
2442       /* --------- Call to DIRTY helper --------- */
2443    case Ist_Dirty: {
2444       IRType   retty;
2445       IRDirty* d = stmt->Ist.Dirty.details;
2446       Bool     passBBP;
2447       HReg dst;
2448       Int i;
2449 
2450       /* Invalidate tracked values of those guest state registers that are
2451          modified by this helper. */
2452       for (i = 0; i < d->nFxState; ++i) {
2453          /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2454             descriptors in guest state effect descriptions.  Hence: */
2455          vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
2456          if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2457             Int guest_reg = get_guest_reg(d->fxState[i].offset);
2458             if (guest_reg != GUEST_UNKNOWN)
2459                env->old_value_valid[guest_reg] = False;
2460          }
2461       }
2462 
2463       if (d->nFxState == 0)
2464          vassert(!d->needsBBP);
2465 
2466       passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2467 
2468       if (d->tmp == IRTemp_INVALID) {
2469          /* No return value. */
2470          dst = INVALID_HREG;
2471          doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
2472          return;
2473       }
2474 
2475       retty = typeOfIRTemp(env->type_env, d->tmp);
2476       if (retty == Ity_I64 || retty == Ity_I32
2477           || retty == Ity_I16 || retty == Ity_I8) {
2478          /* Move the returned value to the destination register */
2479          dst = lookupIRTemp(env, d->tmp);
2480          doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
2481          return;
2482       }
2483       break;
2484    }
2485 
2486    case Ist_CAS:
2487       if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2488          IRCAS *cas = stmt->Ist.CAS.details;
2489          s390_amode *op2 = s390_isel_amode(env, cas->addr);
2490          HReg op3 = s390_isel_int_expr(env, cas->dataLo);  /* new value */
2491          HReg op1 = s390_isel_int_expr(env, cas->expdLo);  /* expected value */
2492          HReg old = lookupIRTemp(env, cas->oldLo);
2493 
2494          if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2495             addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2496          } else {
2497             addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2498          }
2499          return;
2500       } else {
2501          IRCAS *cas = stmt->Ist.CAS.details;
2502          s390_amode *op2 = s390_isel_amode(env,  cas->addr);
2503          HReg r8, r9, r10, r11, r1;
2504          HReg op3_high = s390_isel_int_expr(env, cas->dataHi);  /* new value */
2505          HReg op3_low  = s390_isel_int_expr(env, cas->dataLo);  /* new value */
2506          HReg op1_high = s390_isel_int_expr(env, cas->expdHi);  /* expected value */
2507          HReg op1_low  = s390_isel_int_expr(env, cas->expdLo);  /* expected value */
2508          HReg old_low  = lookupIRTemp(env, cas->oldLo);
2509          HReg old_high = lookupIRTemp(env, cas->oldHi);
2510 
2511          /* Use non-virtual registers r8 and r9 as pair for op1
2512             and move op1 there */
2513          r8 = make_gpr(8);
2514          r9 = make_gpr(9);
2515          addInstr(env, s390_insn_move(8, r8, op1_high));
2516          addInstr(env, s390_insn_move(8, r9, op1_low));
2517 
2518          /* Use non-virtual registers r10 and r11 as pair for op3
2519             and move op3 there */
2520          r10 = make_gpr(10);
2521          r11 = make_gpr(11);
2522          addInstr(env, s390_insn_move(8, r10, op3_high));
2523          addInstr(env, s390_insn_move(8, r11, op3_low));
2524 
2525          /* Register r1 is used as a scratch register */
2526          r1 = make_gpr(1);
2527 
2528          if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2529             addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2530                                          old_high, old_low, r1));
2531          } else {
2532             addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2533                                          old_high, old_low, r1));
2534          }
2535          addInstr(env, s390_insn_move(8, op1_high, r8));
2536          addInstr(env, s390_insn_move(8, op1_low,  r9));
2537          addInstr(env, s390_insn_move(8, op3_high, r10));
2538          addInstr(env, s390_insn_move(8, op3_low,  r11));
2539          return;
2540       }
2541       break;
2542 
2543       /* --------- EXIT --------- */
2544    case Ist_Exit: {
2545       s390_cc_t cond;
2546       IRConstTag tag = stmt->Ist.Exit.dst->tag;
2547 
2548       if (tag != Ico_U64)
2549          vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2550 
2551       s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
2552       cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
2553 
2554       /* Case: boring transfer to known address */
2555       if (stmt->Ist.Exit.jk == Ijk_Boring) {
2556          if (env->chaining_allowed) {
2557             /* .. almost always true .. */
2558             /* Skip the event check at the dst if this is a forwards
2559                edge. */
2560             Bool to_fast_entry
2561                = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2562             if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2563             addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2564                                             guest_IA, to_fast_entry));
2565          } else {
2566             /* .. very occasionally .. */
2567             /* We can't use chaining, so ask for an assisted transfer,
2568                as that's the only alternative that is allowable. */
2569             HReg dst = s390_isel_int_expr(env,
2570                                           IRExpr_Const(stmt->Ist.Exit.dst));
2571             addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2572          }
2573          return;
2574       }
2575 
2576       /* Case: assisted transfer to arbitrary address */
2577       switch (stmt->Ist.Exit.jk) {
2578       case Ijk_NoDecode:
2579       case Ijk_TInval:
2580       case Ijk_Sys_syscall:
2581       case Ijk_ClientReq:
2582       case Ijk_NoRedir:
2583       case Ijk_Yield:
2584       case Ijk_SigTRAP: {
2585          HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2586          addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2587                                            stmt->Ist.Exit.jk));
2588          return;
2589       }
2590       default:
2591          break;
2592       }
2593 
2594       /* Do we ever expect to see any other kind? */
2595       goto stmt_fail;
2596    }
2597 
2598       /* --------- MEM FENCE --------- */
2599    case Ist_MBE:
2600       switch (stmt->Ist.MBE.event) {
2601          case Imbe_Fence:
2602             addInstr(env, s390_insn_mfence());
2603             return;
2604          default:
2605             break;
2606       }
2607       break;
2608 
2609       /* --------- Miscellaneous --------- */
2610 
2611    case Ist_PutI:    /* Not needed */
2612    case Ist_IMark:   /* Doesn't generate any executable code */
2613    case Ist_NoOp:    /* Doesn't generate any executable code */
2614    case Ist_AbiHint: /* Meaningless in IR */
2615       return;
2616 
2617    default:
2618       break;
2619    }
2620 
2621  stmt_fail:
2622    ppIRStmt(stmt);
2623    vpanic("s390_isel_stmt");
2624 }
2625 
2626 
2627 /*---------------------------------------------------------*/
2628 /*--- ISEL: Basic block terminators (Nexts)             ---*/
2629 /*---------------------------------------------------------*/
2630 
2631 static void
iselNext(ISelEnv * env,IRExpr * next,IRJumpKind jk,int offsIP)2632 iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
2633 {
2634    if (vex_traceflags & VEX_TRACE_VCODE) {
2635       vex_printf("\n-- PUT(%d) = ", offsIP);
2636       ppIRExpr(next);
2637       vex_printf("; exit-");
2638       ppIRJumpKind(jk);
2639       vex_printf("\n");
2640    }
2641 
2642    s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2643 
2644    /* Case: boring transfer to known address */
2645    if (next->tag == Iex_Const) {
2646       IRConst *cdst = next->Iex.Const.con;
2647       vassert(cdst->tag == Ico_U64);
2648       if (jk == Ijk_Boring || jk == Ijk_Call) {
2649          /* Boring transfer to known address */
2650          if (env->chaining_allowed) {
2651             /* .. almost always true .. */
2652             /* Skip the event check at the dst if this is a forwards
2653                edge. */
2654             Bool to_fast_entry
2655                = ((Addr64)cdst->Ico.U64) > env->max_ga;
2656             if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2657             addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2658                                             guest_IA, to_fast_entry));
2659          } else {
2660             /* .. very occasionally .. */
2661             /* We can't use chaining, so ask for an indirect transfer,
2662                as that's the cheapest alternative that is allowable. */
2663             HReg dst = s390_isel_int_expr(env, next);
2664             addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2665                                               Ijk_Boring));
2666          }
2667          return;
2668       }
2669    }
2670 
2671    /* Case: call/return (==boring) transfer to any address */
2672    switch (jk) {
2673    case Ijk_Boring:
2674    case Ijk_Ret:
2675    case Ijk_Call: {
2676       HReg dst = s390_isel_int_expr(env, next);
2677       if (env->chaining_allowed) {
2678          addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2679       } else {
2680          addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2681                                            Ijk_Boring));
2682       }
2683       return;
2684    }
2685    default:
2686       break;
2687    }
2688 
2689    /* Case: some other kind of transfer to any address */
2690    switch (jk) {
2691    case Ijk_NoDecode:
2692    case Ijk_TInval:
2693    case Ijk_Sys_syscall:
2694    case Ijk_ClientReq:
2695    case Ijk_NoRedir:
2696    case Ijk_Yield:
2697    case Ijk_SigTRAP: {
2698       HReg dst = s390_isel_int_expr(env, next);
2699       addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2700       return;
2701    }
2702    default:
2703       break;
2704    }
2705 
2706    vpanic("iselNext");
2707 }
2708 
2709 
2710 /*---------------------------------------------------------*/
2711 /*--- Insn selector top-level                           ---*/
2712 /*---------------------------------------------------------*/
2713 
2714 /* Translate an entire SB to s390 code.
2715    Note: archinfo_host is a pointer to a stack-allocated variable.
2716    Do not assign it to a global variable! */
2717 
2718 HInstrArray *
iselSB_S390(IRSB * bb,VexArch arch_host,VexArchInfo * archinfo_host,VexAbiInfo * vbi,Int offset_host_evcheck_counter,Int offset_host_evcheck_fail_addr,Bool chaining_allowed,Bool add_profinc,Addr64 max_ga)2719 iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
2720             VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2721             Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2722             Bool add_profinc, Addr64 max_ga)
2723 {
2724    UInt     i, j;
2725    HReg     hreg, hregHI;
2726    ISelEnv *env;
2727    UInt     hwcaps_host = archinfo_host->hwcaps;
2728 
2729    /* KLUDGE: export hwcaps. */
2730    s390_host_hwcaps = hwcaps_host;
2731 
2732    /* Do some sanity checks */
2733    vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
2734 
2735    /* Make up an initial environment to use. */
2736    env = LibVEX_Alloc(sizeof(ISelEnv));
2737    env->vreg_ctr = 0;
2738 
2739    /* Set up output code array. */
2740    env->code = newHInstrArray();
2741 
2742    /* Copy BB's type env. */
2743    env->type_env = bb->tyenv;
2744 
2745    /* Set up data structures for tracking guest register values. */
2746    env->first_IA_assignment = True;
2747    for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2748       env->old_value[i] = 0;  /* just something to have a defined value */
2749       env->old_value_valid[i] = False;
2750    }
2751 
2752    /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
2753       change as we go along. For some reason types_used has Int type -- but
2754       it should be unsigned. Internally we use an unsigned type; so we
2755       assert it here. */
2756    vassert(bb->tyenv->types_used >= 0);
2757 
2758    env->n_vregmap = bb->tyenv->types_used;
2759    env->vregmap   = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2760    env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2761 
2762    /* and finally ... */
2763    env->hwcaps    = hwcaps_host;
2764 
2765    env->max_ga = max_ga;
2766    env->chaining_allowed = chaining_allowed;
2767 
2768    /* For each IR temporary, allocate a suitably-kinded virtual
2769       register. */
2770    j = 0;
2771    for (i = 0; i < env->n_vregmap; i++) {
2772       hregHI = hreg = INVALID_HREG;
2773       switch (bb->tyenv->types[i]) {
2774       case Ity_I1:
2775       case Ity_I8:
2776       case Ity_I16:
2777       case Ity_I32:
2778          hreg = mkHReg(j++, HRcInt64, True);
2779          break;
2780 
2781       case Ity_I64:
2782          hreg   = mkHReg(j++, HRcInt64, True);
2783          break;
2784 
2785       case Ity_I128:
2786          hreg   = mkHReg(j++, HRcInt64, True);
2787          hregHI = mkHReg(j++, HRcInt64, True);
2788          break;
2789 
2790       case Ity_F32:
2791       case Ity_F64:
2792          hreg = mkHReg(j++, HRcFlt64, True);
2793          break;
2794 
2795       case Ity_F128:
2796          hreg   = mkHReg(j++, HRcFlt64, True);
2797          hregHI = mkHReg(j++, HRcFlt64, True);
2798          break;
2799 
2800       case Ity_V128: /* fall through */
2801       default:
2802          ppIRType(bb->tyenv->types[i]);
2803          vpanic("s390_isel_sb: IRTemp type");
2804       }
2805 
2806       env->vregmap[i]   = hreg;
2807       env->vregmapHI[i] = hregHI;
2808    }
2809    env->vreg_ctr = j;
2810 
2811    /* The very first instruction must be an event check. */
2812    s390_amode *counter, *fail_addr;
2813    counter   = s390_amode_for_guest_state(offset_host_evcheck_counter);
2814    fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2815    addInstr(env, s390_insn_evcheck(counter, fail_addr));
2816 
2817    /* Possibly a block counter increment (for profiling).  At this
2818       point we don't know the address of the counter, so just pretend
2819       it is zero.  It will have to be patched later, but before this
2820       translation is used, by a call to LibVEX_patchProfInc. */
2821    if (add_profinc) {
2822       addInstr(env, s390_insn_profinc());
2823    }
2824 
2825    /* Ok, finally we can iterate over the statements. */
2826    for (i = 0; i < bb->stmts_used; i++)
2827       if (bb->stmts[i])
2828          s390_isel_stmt(env, bb->stmts[i]);
2829 
2830    iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
2831 
2832    /* Record the number of vregs we used. */
2833    env->code->n_vregs = env->vreg_ctr;
2834 
2835    return env->code;
2836 }
2837 
2838 /*---------------------------------------------------------------*/
2839 /*--- end                                    host_s390_isel.c ---*/
2840 /*---------------------------------------------------------------*/
2841