host_s390_isel.c revision b32f58018498ea2225959b0ba11c18f0c433deef
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
73typedef 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 */
90static HReg          s390_isel_int_expr(ISelEnv *, IRExpr *);
91static s390_amode   *s390_isel_amode(ISelEnv *, IRExpr *);
92static s390_cc_t     s390_isel_cc(ISelEnv *, IRExpr *);
93static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
94static void          s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
95static HReg          s390_isel_float_expr(ISelEnv *, IRExpr *);
96static void          s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
97
98
99/* Add an instruction */
100static void
101addInstr(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
111static __inline__ IRExpr *
112mkU64(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. */
123static HReg
124lookupIRTemp(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. */
134static void
135lookupIRTemp128(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 */
146static HReg
147newVRegI(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 */
157static HReg
158newVRegF(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 */
169static __inline__ HReg
170make_gpr(ISelEnv *env, UInt regno)
171{
172   return mkHReg(regno, HRcInt64, False /* virtual */ );
173}
174
175
176/* Construct a non-virtual floating point register */
177static __inline__ HReg
178make_fpr(UInt regno)
179{
180   return mkHReg(regno, HRcFlt64, False /* virtual */ );
181}
182
183
184/*---------------------------------------------------------*/
185/*--- Amode                                             ---*/
186/*---------------------------------------------------------*/
187
188static __inline__ Bool
189ulong_fits_unsigned_12bit(ULong val)
190{
191   return (val & 0xFFFu) == val;
192}
193
194
195static __inline__ Bool
196ulong_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. */
208static s390_amode *
209s390_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
244static s390_amode *
245s390_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 */
279static s390_insn *
280s390_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 */
299static __inline__ s390_opnd_RMI
300s390_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 */
312static __inline__ s390_opnd_RMI
313s390_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 */
325static int
326s390_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*/
354static void
355doHelperCall(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.  */
419static s390_round_t
420decode_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*/
453static HReg
454convert_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/*---------------------------------------------------------*/
490static void
491s390_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. */
634static void
635s390_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 ! */
667static HReg
668s390_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
1317static HReg
1318s390_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
1330static s390_opnd_RMI
1331s390_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/*---------------------------------------------------------*/
1374static void
1375s390_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. */
1587static void
1588s390_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
1604static HReg
1605s390_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
1864static HReg
1865s390_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 */
1882static s390_cc_t
1883s390_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
2091static void
2092s390_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
2326static void
2327iselNext(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
2350HInstrArray *
2351iselSB_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