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