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