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