'grail' fixes for s390x:
[valgrind.git] / VEX / priv / host_s390_isel.c
blob97614c873fbd837366c3a452082682c16cfb2389
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 if (!(env->hwcaps & VEX_HWCAPS_S390X_MI2))
1022 goto irreducible;
1023 is_signed_multiply = True;
1024 goto do_multiply64;
1026 case Iop_DivModU128to64:
1027 is_signed_divide = False;
1028 goto do_divide64;
1030 case Iop_DivModS128to64:
1031 is_signed_divide = True;
1032 goto do_divide64;
1034 case Iop_64HLto128:
1035 *dst_hi = s390_isel_int_expr(env, arg1);
1036 *dst_lo = s390_isel_int_expr(env, arg2);
1037 return;
1039 case Iop_DivModS64to64: {
1040 HReg r10, r11, h1;
1041 s390_opnd_RMI op2;
1043 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1044 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1046 /* We use non-virtual registers r10 and r11 as pair */
1047 r10 = make_gpr(10);
1048 r11 = make_gpr(11);
1050 /* Move 1st operand into r11 and */
1051 addInstr(env, s390_insn_move(8, r11, h1));
1053 /* Divide */
1054 addInstr(env, s390_insn_divs(8, r10, r11, op2));
1056 /* The result is in registers r10 (remainder) and r11 (quotient).
1057 Move the result into the reg pair that is being returned such
1058 such that the low 64 bits are the quotient and the upper 64 bits
1059 are the remainder. (see libvex_ir.h). */
1060 *dst_hi = newVRegI(env);
1061 *dst_lo = newVRegI(env);
1062 addInstr(env, s390_insn_move(8, *dst_hi, r10));
1063 addInstr(env, s390_insn_move(8, *dst_lo, r11));
1064 return;
1067 default:
1068 break;
1070 do_multiply64: {
1071 HReg r10, r11, h1;
1072 s390_opnd_RMI op2;
1074 order_commutative_operands(arg1, arg2);
1076 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1077 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1079 /* We use non-virtual registers r10 and r11 as pair */
1080 r10 = make_gpr(10);
1081 r11 = make_gpr(11);
1083 /* Move the first operand to r11 */
1084 addInstr(env, s390_insn_move(8, r11, h1));
1086 /* Multiply */
1087 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
1089 /* The result is in registers r10 and r11. Assign to two virtual regs
1090 and return. */
1091 *dst_hi = newVRegI(env);
1092 *dst_lo = newVRegI(env);
1093 addInstr(env, s390_insn_move(8, *dst_hi, r10));
1094 addInstr(env, s390_insn_move(8, *dst_lo, r11));
1095 return;
1098 do_divide64: {
1099 HReg r10, r11, hi, lo;
1100 s390_opnd_RMI op2;
1102 s390_isel_int128_expr(&hi, &lo, env, arg1);
1103 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1105 /* We use non-virtual registers r10 and r11 as pair */
1106 r10 = make_gpr(10);
1107 r11 = make_gpr(11);
1109 /* Move high 64 bits of the 1st operand into r10 and
1110 the low 64 bits into r11. */
1111 addInstr(env, s390_insn_move(8, r10, hi));
1112 addInstr(env, s390_insn_move(8, r11, lo));
1114 /* Divide */
1115 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
1117 /* The result is in registers r10 (remainder) and r11 (quotient).
1118 Move the result into the reg pair that is being returned such
1119 such that the low 64 bits are the quotient and the upper 64 bits
1120 are the remainder. (see libvex_ir.h). */
1121 *dst_hi = newVRegI(env);
1122 *dst_lo = newVRegI(env);
1123 addInstr(env, s390_insn_move(8, *dst_hi, r10));
1124 addInstr(env, s390_insn_move(8, *dst_lo, r11));
1125 return;
1130 /* We get here if no pattern matched. */
1131 irreducible:
1132 ppIRExpr(expr);
1133 vpanic("s390_isel_int128_expr: cannot reduce tree");
1137 /* Compute a 128-bit value into two 64-bit registers. These may be either
1138 real or virtual regs; in any case they must not be changed by subsequent
1139 code emitted by the caller. */
1140 static void
1141 s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1143 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
1145 /* Sanity checks ... */
1146 vassert(hregIsVirtual(*dst_hi));
1147 vassert(hregIsVirtual(*dst_lo));
1148 vassert(hregClass(*dst_hi) == HRcInt64);
1149 vassert(hregClass(*dst_lo) == HRcInt64);
1153 /*---------------------------------------------------------*/
1154 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
1155 /*---------------------------------------------------------*/
1157 /* Select insns for an integer-typed expression, and add them to the
1158 code list. Return a reg holding the result. This reg will be a
1159 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
1160 want to modify it, ask for a new vreg, copy it in there, and modify
1161 the copy. The register allocator will do its best to map both
1162 vregs to the same real register, so the copies will often disappear
1163 later in the game.
1165 This should handle expressions of 64, 32, 16 and 8-bit type.
1166 All results are returned in a 64bit register.
1167 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1168 are arbitrary, so you should mask or sign extend partial values
1169 if necessary.
1172 /* DO NOT CALL THIS DIRECTLY ! */
1173 static HReg
1174 s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
1176 IRType ty = typeOfIRExpr(env->type_env, expr);
1177 UChar size;
1178 s390_bfp_conv_t conv;
1179 s390_dfp_conv_t dconv;
1181 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
1183 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
1185 switch (expr->tag) {
1187 /* --------- TEMP --------- */
1188 case Iex_RdTmp:
1189 /* Return the virtual register that holds the temporary. */
1190 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1192 /* --------- LOAD --------- */
1193 case Iex_Load: {
1194 HReg dst = newVRegI(env);
1195 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1197 if (expr->Iex.Load.end != Iend_BE)
1198 goto irreducible;
1200 addInstr(env, s390_insn_load(size, dst, am));
1202 return dst;
1205 /* --------- BINARY OP --------- */
1206 case Iex_Binop: {
1207 IRExpr *arg1 = expr->Iex.Binop.arg1;
1208 IRExpr *arg2 = expr->Iex.Binop.arg2;
1209 HReg h1, res;
1210 s390_alu_t opkind;
1211 s390_opnd_RMI op2, value, opnd;
1212 s390_insn *insn;
1213 Bool is_commutative, is_signed_multiply, is_signed_divide;
1215 is_commutative = True;
1217 switch (expr->Iex.Binop.op) {
1218 case Iop_MullU8:
1219 case Iop_MullU16:
1220 case Iop_MullU32:
1221 is_signed_multiply = False;
1222 goto do_multiply;
1224 case Iop_MullS8:
1225 case Iop_MullS16:
1226 case Iop_MullS32:
1227 is_signed_multiply = True;
1228 goto do_multiply;
1230 do_multiply: {
1231 HReg r10, r11;
1232 UInt arg_size = size / 2;
1234 order_commutative_operands(arg1, arg2);
1236 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1237 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1239 /* We use non-virtual registers r10 and r11 as pair */
1240 r10 = make_gpr(10);
1241 r11 = make_gpr(11);
1243 /* Move the first operand to r11 */
1244 addInstr(env, s390_insn_move(arg_size, r11, h1));
1246 /* Multiply */
1247 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1249 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1250 value into the destination register. */
1251 res = newVRegI(env);
1252 addInstr(env, s390_insn_move(arg_size, res, r10));
1253 value = s390_opnd_imm(arg_size * 8);
1254 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1255 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1256 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1257 opnd = s390_opnd_reg(r11);
1258 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1259 return res;
1262 case Iop_DivModS64to32:
1263 is_signed_divide = True;
1264 goto do_divide;
1266 case Iop_DivModU64to32:
1267 is_signed_divide = False;
1268 goto do_divide;
1270 do_divide: {
1271 HReg r10, r11;
1273 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1274 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1276 /* We use non-virtual registers r10 and r11 as pair */
1277 r10 = make_gpr(10);
1278 r11 = make_gpr(11);
1280 /* Split the first operand and put the high 32 bits into r10 and
1281 the low 32 bits into r11. */
1282 addInstr(env, s390_insn_move(8, r10, h1));
1283 addInstr(env, s390_insn_move(8, r11, h1));
1284 value = s390_opnd_imm(32);
1285 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1287 /* Divide */
1288 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1290 /* The result is in registers r10 (remainder) and r11 (quotient).
1291 Combine them into a 64-bit value such that the low 32 bits are
1292 the quotient and the upper 32 bits are the remainder. (see
1293 libvex_ir.h). */
1294 res = newVRegI(env);
1295 addInstr(env, s390_insn_move(8, res, r10));
1296 value = s390_opnd_imm(32);
1297 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1298 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1299 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1300 opnd = s390_opnd_reg(r11);
1301 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1302 return res;
1305 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1306 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1307 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1308 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1309 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1310 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1311 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1312 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1313 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1314 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1315 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1316 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
1318 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
1319 case Iop_D64toI64S: dconv = S390_DFP_D64_TO_I64; goto do_convert_dfp;
1320 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1321 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1322 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
1323 case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128;
1324 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1325 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
1327 do_convert: {
1328 s390_bfp_round_t rounding_mode;
1330 res = newVRegI(env);
1331 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1333 rounding_mode = get_bfp_rounding_mode(env, arg1);
1334 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1335 rounding_mode));
1336 return res;
1339 do_convert_128: {
1340 s390_bfp_round_t rounding_mode;
1341 HReg op_hi, op_lo, f13, f15;
1343 res = newVRegI(env);
1344 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1346 /* We use non-virtual registers r13 and r15 as pair */
1347 f13 = make_fpr(13);
1348 f15 = make_fpr(15);
1350 /* operand --> (f13, f15) */
1351 addInstr(env, s390_insn_move(8, f13, op_hi));
1352 addInstr(env, s390_insn_move(8, f15, op_lo));
1354 rounding_mode = get_bfp_rounding_mode(env, arg1);
1355 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res,
1356 INVALID_HREG, f13, f15,
1357 rounding_mode));
1358 return res;
1361 do_convert_dfp: {
1362 s390_dfp_round_t rounding_mode;
1364 res = newVRegI(env);
1365 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1367 rounding_mode = get_dfp_rounding_mode(env, arg1);
1368 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
1369 rounding_mode));
1370 return res;
1373 do_convert_dfp128: {
1374 s390_dfp_round_t rounding_mode;
1375 HReg op_hi, op_lo, f13, f15;
1377 res = newVRegI(env);
1378 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1380 /* We use non-virtual registers r13 and r15 as pair */
1381 f13 = make_fpr(13);
1382 f15 = make_fpr(15);
1384 /* operand --> (f13, f15) */
1385 addInstr(env, s390_insn_move(8, f13, op_hi));
1386 addInstr(env, s390_insn_move(8, f15, op_lo));
1388 rounding_mode = get_dfp_rounding_mode(env, arg1);
1389 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res,
1390 INVALID_HREG, f13,
1391 f15, rounding_mode));
1392 return res;
1395 case Iop_8HLto16:
1396 case Iop_16HLto32:
1397 case Iop_32HLto64: {
1398 HReg h2;
1399 UInt arg_size = size / 2;
1401 res = newVRegI(env);
1402 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1403 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1405 addInstr(env, s390_insn_move(arg_size, res, h1));
1406 value = s390_opnd_imm(arg_size * 8);
1407 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1408 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1409 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1410 opnd = s390_opnd_reg(h2);
1411 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1412 return res;
1415 case Iop_Max32U: {
1416 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1417 res = newVRegI(env);
1418 h1 = s390_isel_int_expr(env, arg1);
1419 op2 = s390_isel_int_expr_RMI(env, arg2);
1421 addInstr(env, s390_insn_move(size, res, h1));
1422 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1423 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1424 return res;
1427 case Iop_CmpF32:
1428 case Iop_CmpF64: {
1429 HReg cc_s390, h2;
1431 h1 = s390_isel_float_expr(env, arg1);
1432 h2 = s390_isel_float_expr(env, arg2);
1433 cc_s390 = newVRegI(env);
1435 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1437 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1439 return convert_s390_to_vex_bfpcc(env, cc_s390);
1442 case Iop_CmpF128: {
1443 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1445 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1446 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1447 cc_s390 = newVRegI(env);
1449 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1450 f12 = make_fpr(12);
1451 f13 = make_fpr(13);
1452 f14 = make_fpr(14);
1453 f15 = make_fpr(15);
1455 /* 1st operand --> (f12, f14) */
1456 addInstr(env, s390_insn_move(8, f12, op1_hi));
1457 addInstr(env, s390_insn_move(8, f14, op1_lo));
1459 /* 2nd operand --> (f13, f15) */
1460 addInstr(env, s390_insn_move(8, f13, op2_hi));
1461 addInstr(env, s390_insn_move(8, f15, op2_lo));
1463 res = newVRegI(env);
1464 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1466 return convert_s390_to_vex_bfpcc(env, cc_s390);
1469 case Iop_CmpD64:
1470 case Iop_CmpExpD64: {
1471 HReg cc_s390, h2;
1472 s390_dfp_cmp_t cmp;
1474 h1 = s390_isel_dfp_expr(env, arg1);
1475 h2 = s390_isel_dfp_expr(env, arg2);
1476 cc_s390 = newVRegI(env);
1478 switch(expr->Iex.Binop.op) {
1479 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1480 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1481 default: goto irreducible;
1483 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
1485 return convert_s390_to_vex_dfpcc(env, cc_s390);
1488 case Iop_CmpD128:
1489 case Iop_CmpExpD128: {
1490 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1491 s390_dfp_cmp_t cmp;
1493 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1494 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1495 cc_s390 = newVRegI(env);
1497 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1498 f12 = make_fpr(12);
1499 f13 = make_fpr(13);
1500 f14 = make_fpr(14);
1501 f15 = make_fpr(15);
1503 /* 1st operand --> (f12, f14) */
1504 addInstr(env, s390_insn_move(8, f12, op1_hi));
1505 addInstr(env, s390_insn_move(8, f14, op1_lo));
1507 /* 2nd operand --> (f13, f15) */
1508 addInstr(env, s390_insn_move(8, f13, op2_hi));
1509 addInstr(env, s390_insn_move(8, f15, op2_lo));
1511 switch(expr->Iex.Binop.op) {
1512 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1513 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1514 default: goto irreducible;
1516 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1517 f13, f15));
1519 return convert_s390_to_vex_dfpcc(env, cc_s390);
1522 case Iop_Add8:
1523 case Iop_Add16:
1524 case Iop_Add32:
1525 case Iop_Add64:
1526 opkind = S390_ALU_ADD;
1527 break;
1529 case Iop_Sub8:
1530 case Iop_Sub16:
1531 case Iop_Sub32:
1532 case Iop_Sub64:
1533 opkind = S390_ALU_SUB;
1534 is_commutative = False;
1535 break;
1537 case Iop_And8:
1538 case Iop_And16:
1539 case Iop_And32:
1540 case Iop_And64:
1541 opkind = S390_ALU_AND;
1542 break;
1544 case Iop_Or8:
1545 case Iop_Or16:
1546 case Iop_Or32:
1547 case Iop_Or64:
1548 opkind = S390_ALU_OR;
1549 break;
1551 case Iop_Xor8:
1552 case Iop_Xor16:
1553 case Iop_Xor32:
1554 case Iop_Xor64:
1555 opkind = S390_ALU_XOR;
1556 break;
1558 case Iop_Shl8:
1559 case Iop_Shl16:
1560 case Iop_Shl32:
1561 case Iop_Shl64:
1562 opkind = S390_ALU_LSH;
1563 is_commutative = False;
1564 break;
1566 case Iop_Shr8:
1567 case Iop_Shr16:
1568 case Iop_Shr32:
1569 case Iop_Shr64:
1570 opkind = S390_ALU_RSH;
1571 is_commutative = False;
1572 break;
1574 case Iop_Sar8:
1575 case Iop_Sar16:
1576 case Iop_Sar32:
1577 case Iop_Sar64:
1578 opkind = S390_ALU_RSHA;
1579 is_commutative = False;
1580 break;
1582 case Iop_GetElem8x16:
1583 case Iop_GetElem16x8:
1584 case Iop_GetElem32x4:
1585 case Iop_GetElem64x2:{
1586 HReg dst = newVRegI(env);
1587 HReg vec = s390_isel_vec_expr(env, arg1);
1588 s390_amode* operand = s390_isel_amode(env,IRExpr_Unop(Iop_8Uto64, arg2));
1589 switch (expr->Iex.Binop.op) {
1590 case Iop_GetElem8x16:
1591 size = 1;
1592 break;
1593 case Iop_GetElem16x8:
1594 size = 2;
1595 break;
1596 case Iop_GetElem32x4:
1597 size = 4;
1598 break;
1599 case Iop_GetElem64x2:
1600 size = 8;
1601 break;
1602 default:
1603 vpanic("s390_isel_int_expr: impossible Iop_GetElem type");
1605 addInstr(env, s390_insn_vec_amodeop(size, S390_VEC_GET_ELEM, dst, vec, operand));
1606 return dst;
1608 default:
1609 goto irreducible;
1612 /* Pattern match: 0 - arg1 --> -arg1 */
1613 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1614 res = newVRegI(env);
1615 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1616 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1617 addInstr(env, insn);
1619 return res;
1622 if (is_commutative) {
1623 order_commutative_operands(arg1, arg2);
1626 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1627 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1628 res = newVRegI(env);
1630 /* As right shifts of one/two byte opreands are implemented using a
1631 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1632 switch (expr->Iex.Binop.op) {
1633 case Iop_Shr8:
1634 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1635 break;
1636 case Iop_Shr16:
1637 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1638 break;
1639 case Iop_Sar8:
1640 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1641 break;
1642 case Iop_Sar16:
1643 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1644 break;
1645 default:
1646 insn = s390_insn_move(size, res, h1);
1647 break;
1649 addInstr(env, insn);
1651 insn = s390_insn_alu(size, opkind, res, op2);
1653 addInstr(env, insn);
1655 return res;
1658 /* --------- UNARY OP --------- */
1659 case Iex_Unop: {
1660 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1661 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1662 s390_opnd_RMI opnd;
1663 s390_insn *insn;
1664 IRExpr *arg;
1665 HReg dst, h1;
1666 IROp unop, binop;
1668 arg = expr->Iex.Unop.arg;
1670 /* Special cases are handled here */
1672 /* 32-bit multiply with 32-bit result or
1673 64-bit multiply with 64-bit result */
1674 unop = expr->Iex.Unop.op;
1675 binop = arg->Iex.Binop.op;
1677 if ((arg->tag == Iex_Binop &&
1678 ((unop == Iop_64to32 &&
1679 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1680 (unop == Iop_128to64 &&
1681 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1682 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1683 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1684 dst = newVRegI(env); /* Result goes into a new register */
1685 addInstr(env, s390_insn_move(size, dst, h1));
1686 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1688 return dst;
1691 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
1692 dst = newVRegI(env);
1693 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1694 addInstr(env, s390_insn_move(size, dst, h1));
1696 return dst;
1699 if (unop == Iop_ReinterpD64asI64) {
1700 dst = newVRegI(env);
1701 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1702 addInstr(env, s390_insn_move(size, dst, h1));
1704 return dst;
1707 if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
1708 s390_dfp_unop_t dfpop;
1709 switch(unop) {
1710 case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
1711 case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
1712 default: goto irreducible;
1714 dst = newVRegI(env);
1715 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1716 addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
1717 return dst;
1720 if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
1721 s390_dfp_unop_t dfpop;
1722 HReg op_hi, op_lo, f13, f15;
1724 switch(unop) {
1725 case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
1726 case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
1727 default: goto irreducible;
1729 dst = newVRegI(env);
1730 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1732 /* We use non-virtual registers r13 and r15 as pair */
1733 f13 = make_fpr(13);
1734 f15 = make_fpr(15);
1736 /* operand --> (f13, f15) */
1737 addInstr(env, s390_insn_move(8, f13, op_hi));
1738 addInstr(env, s390_insn_move(8, f15, op_lo));
1740 addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
1741 return dst;
1744 /* Expressions whose argument is 1-bit wide */
1745 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1746 s390_cc_t cond = s390_isel_cc(env, arg);
1747 dst = newVRegI(env); /* Result goes into a new register */
1748 addInstr(env, s390_insn_cc2bool(dst, cond));
1750 switch (unop) {
1751 case Iop_1Uto8:
1752 case Iop_1Uto32:
1753 /* Zero extend */
1754 mask.variant.imm = 1;
1755 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1756 break;
1758 case Iop_1Uto64:
1759 /* Zero extend */
1760 mask.variant.imm = 1;
1761 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
1762 break;
1764 case Iop_1Sto8:
1765 case Iop_1Sto16:
1766 case Iop_1Sto32:
1767 shift.variant.imm = 31;
1768 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1769 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1770 break;
1772 case Iop_1Sto64:
1773 shift.variant.imm = 63;
1774 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1775 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1776 break;
1778 default:
1779 goto irreducible;
1782 return dst;
1785 /* Regular processing */
1787 if (unop == Iop_128to64) {
1788 HReg dst_hi, dst_lo;
1790 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1791 return dst_lo;
1794 if (unop == Iop_128HIto64) {
1795 HReg dst_hi, dst_lo;
1797 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1798 return dst_hi;
1801 if(unop == Iop_V128to64 || unop == Iop_V128HIto64 || unop == Iop_V128to32) {
1802 dst = newVRegI(env);
1803 HReg vec = s390_isel_vec_expr(env, arg);
1804 /* This is big-endian machine */
1805 Int off;
1806 switch (unop) {
1807 case Iop_V128HIto64:
1808 off = 0;
1809 break;
1810 case Iop_V128to64:
1811 off = 8;
1812 break;
1813 case Iop_V128to32:
1814 off = 12;
1815 break;
1816 default:
1817 ppIROp(unop);
1818 vpanic("s390_isel_int_expr: unhandled V128toSMTH operation");
1820 s390_amode* m16_sp = s390_amode_for_stack_pointer(0);
1821 s390_amode* off_sp = s390_amode_for_stack_pointer(off);
1823 /* We could use negative displacement but vector instructions
1824 require 12bit unsigned ones. So we have to allocate space on
1825 stack just for one load and free it after. */
1826 sub_from_SP(env, 16);
1827 addInstr(env, s390_insn_store(sizeof(V128), m16_sp, vec));
1828 addInstr(env, s390_insn_load(sizeof(ULong), dst, off_sp));
1829 add_to_SP(env, 16);
1830 return dst;
1833 dst = newVRegI(env); /* Result goes into a new register */
1834 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1836 switch (unop) {
1837 case Iop_8Uto16:
1838 case Iop_8Uto32:
1839 case Iop_8Uto64:
1840 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1841 break;
1843 case Iop_16Uto32:
1844 case Iop_16Uto64:
1845 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1846 break;
1848 case Iop_32Uto64:
1849 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1850 break;
1852 case Iop_8Sto16:
1853 case Iop_8Sto32:
1854 case Iop_8Sto64:
1855 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1856 break;
1858 case Iop_16Sto32:
1859 case Iop_16Sto64:
1860 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1861 break;
1863 case Iop_32Sto64:
1864 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1865 break;
1867 case Iop_64to8:
1868 case Iop_64to16:
1869 case Iop_64to32:
1870 case Iop_32to8:
1871 case Iop_32to16:
1872 case Iop_16to8:
1873 /* Down-casts are no-ops. Upstream operations will only look at
1874 the bytes that make up the result of the down-cast. So there
1875 is no point setting the other bytes to 0. */
1876 insn = s390_opnd_copy(8, dst, opnd);
1877 break;
1879 case Iop_64HIto32:
1880 addInstr(env, s390_opnd_copy(8, dst, opnd));
1881 shift.variant.imm = 32;
1882 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1883 break;
1885 case Iop_32HIto16:
1886 addInstr(env, s390_opnd_copy(4, dst, opnd));
1887 shift.variant.imm = 16;
1888 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1889 break;
1891 case Iop_16HIto8:
1892 addInstr(env, s390_opnd_copy(2, dst, opnd));
1893 shift.variant.imm = 8;
1894 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1895 break;
1897 case Iop_Not8:
1898 case Iop_Not16:
1899 case Iop_Not32:
1900 case Iop_Not64:
1901 /* XOR with ffff... */
1902 mask.variant.imm = ~(ULong)0;
1903 addInstr(env, s390_opnd_copy(size, dst, opnd));
1904 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1905 break;
1907 case Iop_Left8:
1908 case Iop_Left16:
1909 case Iop_Left32:
1910 case Iop_Left64:
1911 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1912 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1913 break;
1915 case Iop_CmpwNEZ32:
1916 case Iop_CmpwNEZ64: {
1917 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1918 or -X will have a 1 in the MSB. */
1919 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1920 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1921 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1922 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1923 return dst;
1926 case Iop_Clz64: {
1927 HReg r10, r11;
1929 /* This will be implemented using FLOGR, if possible. So we need to
1930 set aside a pair of non-virtual registers. The result (number of
1931 left-most zero bits) will be in r10. The value in r11 is unspecified
1932 and must not be used. */
1933 r10 = make_gpr(10);
1934 r11 = make_gpr(11);
1936 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
1937 addInstr(env, s390_insn_move(8, dst, r10));
1938 return dst;
1941 default:
1942 goto irreducible;
1945 addInstr(env, insn);
1947 return dst;
1950 /* --------- GET --------- */
1951 case Iex_Get: {
1952 HReg dst = newVRegI(env);
1953 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1955 /* We never load more than 8 bytes from the guest state, because the
1956 floating point register pair is not contiguous. */
1957 vassert(size <= 8);
1959 addInstr(env, s390_insn_load(size, dst, am));
1961 return dst;
1964 case Iex_GetI:
1965 /* not needed */
1966 break;
1968 /* --------- CCALL --------- */
1969 case Iex_CCall: {
1970 HReg dst = newVRegI(env);
1971 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
1972 UInt addToSp = 0;
1973 RetLoc rloc = mk_RetLoc_INVALID();
1975 doHelperCall(&addToSp, &rloc, env, NULL, expr->Iex.CCall.cee,
1976 expr->Iex.CCall.retty, expr->Iex.CCall.args);
1977 vassert(is_sane_RetLoc(rloc));
1978 vassert(rloc.pri == RLPri_Int);
1979 vassert(addToSp == 0);
1980 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
1982 return dst;
1985 /* --------- LITERAL --------- */
1987 /* Load a literal into a register. Create a "load immediate"
1988 v-insn and return the register. */
1989 case Iex_Const: {
1990 ULong value;
1991 HReg dst = newVRegI(env);
1992 const IRConst *con = expr->Iex.Const.con;
1994 /* Bitwise copy of the value. No sign/zero-extension */
1995 switch (con->tag) {
1996 case Ico_U64: value = con->Ico.U64; break;
1997 case Ico_U32: value = con->Ico.U32; break;
1998 case Ico_U16: value = con->Ico.U16; break;
1999 case Ico_U8: value = con->Ico.U8; break;
2000 default: vpanic("s390_isel_int_expr: invalid constant");
2003 addInstr(env, s390_insn_load_immediate(size, dst, value));
2005 return dst;
2008 /* --------- MULTIPLEX --------- */
2009 case Iex_ITE: {
2010 IRExpr *cond_expr;
2011 HReg dst, r1;
2012 s390_opnd_RMI r0;
2014 cond_expr = expr->Iex.ITE.cond;
2016 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
2018 dst = newVRegI(env);
2019 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
2020 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
2021 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
2023 s390_cc_t cc = s390_isel_cc(env, cond_expr);
2025 addInstr(env, s390_insn_move(size, dst, r1));
2026 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
2027 return dst;
2030 default:
2031 break;
2034 /* We get here if no pattern matched. */
2035 irreducible:
2036 ppIRExpr(expr);
2037 vpanic("s390_isel_int_expr: cannot reduce tree");
2041 static HReg
2042 s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
2044 HReg dst = s390_isel_int_expr_wrk(env, expr);
2046 /* Sanity checks ... */
2047 vassert(hregClass(dst) == HRcInt64);
2048 vassert(hregIsVirtual(dst));
2050 return dst;
2054 static s390_opnd_RMI
2055 s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
2057 IRType ty = typeOfIRExpr(env->type_env, expr);
2058 s390_opnd_RMI dst;
2060 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
2061 ty == Ity_I64);
2063 if (expr->tag == Iex_Load) {
2064 dst.tag = S390_OPND_AMODE;
2065 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
2066 } else if (expr->tag == Iex_Get) {
2067 dst.tag = S390_OPND_AMODE;
2068 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2069 } else if (expr->tag == Iex_Const) {
2070 ULong value;
2072 /* The bit pattern for the value will be stored as is in the least
2073 significant bits of VALUE. */
2074 switch (expr->Iex.Const.con->tag) {
2075 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
2076 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
2077 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
2078 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
2079 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
2080 default:
2081 vpanic("s390_isel_int_expr_RMI");
2084 dst.tag = S390_OPND_IMMEDIATE;
2085 dst.variant.imm = value;
2086 } else {
2087 dst.tag = S390_OPND_REG;
2088 dst.variant.reg = s390_isel_int_expr(env, expr);
2091 return dst;
2095 /*---------------------------------------------------------*/
2096 /*--- ISEL: Floating point expressions (128 bit) ---*/
2097 /*---------------------------------------------------------*/
2098 static void
2099 s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2100 IRExpr *expr)
2102 IRType ty = typeOfIRExpr(env->type_env, expr);
2104 vassert(ty == Ity_F128);
2106 switch (expr->tag) {
2107 case Iex_RdTmp:
2108 /* Return the virtual registers that hold the temporary. */
2109 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2110 return;
2112 /* --------- LOAD --------- */
2113 case Iex_Load: {
2114 IRExpr *addr_hi, *addr_lo;
2115 s390_amode *am_hi, *am_lo;
2117 if (expr->Iex.Load.end != Iend_BE)
2118 goto irreducible;
2120 addr_hi = expr->Iex.Load.addr;
2121 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2123 am_hi = s390_isel_amode(env, addr_hi);
2124 am_lo = s390_isel_amode(env, addr_lo);
2126 *dst_hi = newVRegF(env);
2127 *dst_lo = newVRegF(env);
2128 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2129 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2130 return;
2134 /* --------- GET --------- */
2135 case Iex_Get:
2136 /* This is not supported because loading 128-bit from the guest
2137 state is almost certainly wrong. Use get_fpr_pair instead. */
2138 vpanic("Iex_Get with F128 data");
2140 /* --------- 4-ary OP --------- */
2141 case Iex_Qop:
2142 vpanic("Iex_Qop with F128 data");
2144 /* --------- TERNARY OP --------- */
2145 case Iex_Triop: {
2146 IRTriop *triop = expr->Iex.Triop.details;
2147 IROp op = triop->op;
2148 IRExpr *left = triop->arg2;
2149 IRExpr *right = triop->arg3;
2150 s390_bfp_binop_t bfpop;
2151 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
2153 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2154 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2156 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2157 f12 = make_fpr(12);
2158 f13 = make_fpr(13);
2159 f14 = make_fpr(14);
2160 f15 = make_fpr(15);
2162 /* 1st operand --> (f12, f14) */
2163 addInstr(env, s390_insn_move(8, f12, op1_hi));
2164 addInstr(env, s390_insn_move(8, f14, op1_lo));
2166 /* 2nd operand --> (f13, f15) */
2167 addInstr(env, s390_insn_move(8, f13, op2_hi));
2168 addInstr(env, s390_insn_move(8, f15, op2_lo));
2170 switch (op) {
2171 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
2172 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
2173 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
2174 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
2175 default:
2176 goto irreducible;
2179 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2180 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
2182 /* Move result to virtual destination register */
2183 *dst_hi = newVRegF(env);
2184 *dst_lo = newVRegF(env);
2185 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2186 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2188 return;
2191 /* --------- BINARY OP --------- */
2192 case Iex_Binop: {
2193 switch (expr->Iex.Binop.op) {
2194 case Iop_SqrtF128: {
2195 HReg op_hi, op_lo, f12, f13, f14, f15;
2197 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2198 f12 = make_fpr(12);
2199 f13 = make_fpr(13);
2200 f14 = make_fpr(14);
2201 f15 = make_fpr(15);
2203 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
2205 /* operand --> (f13, f15) */
2206 addInstr(env, s390_insn_move(8, f13, op_hi));
2207 addInstr(env, s390_insn_move(8, f15, op_lo));
2209 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
2210 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
2211 f13, f15));
2213 /* Move result to virtual destination registers */
2214 *dst_hi = newVRegF(env);
2215 *dst_lo = newVRegF(env);
2216 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2217 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2218 return;
2221 case Iop_F64HLtoF128:
2222 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
2223 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
2224 return;
2226 case Iop_D32toF128:
2227 case Iop_D64toF128: {
2228 IRExpr *irrm;
2229 IRExpr *left;
2230 s390_dfp_round_t rm;
2231 HReg h1; /* virtual reg. to hold source */
2232 HReg f0, f2, f4, r1; /* real registers used by PFPO */
2233 s390_fp_conv_t fpconv;
2235 switch (expr->Iex.Binop.op) {
2236 case Iop_D32toF128:
2237 fpconv = S390_FP_D32_TO_F128;
2238 break;
2239 case Iop_D64toF128:
2240 fpconv = S390_FP_D64_TO_F128;
2241 break;
2242 default: goto irreducible;
2245 f4 = make_fpr(4); /* source */
2246 f0 = make_fpr(0); /* destination */
2247 f2 = make_fpr(2); /* destination */
2248 r1 = make_gpr(1); /* GPR #1 clobbered */
2249 irrm = expr->Iex.Binop.arg1;
2250 left = expr->Iex.Binop.arg2;
2251 rm = get_dfp_rounding_mode(env, irrm);
2252 h1 = s390_isel_dfp_expr(env, left);
2253 addInstr(env, s390_insn_move(8, f4, h1));
2254 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
2255 f4, INVALID_HREG, r1, rm));
2256 /* (f0, f2) --> destination */
2257 *dst_hi = newVRegF(env);
2258 *dst_lo = newVRegF(env);
2259 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2260 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2262 return;
2265 case Iop_D128toF128: {
2266 IRExpr *irrm;
2267 IRExpr *left;
2268 s390_dfp_round_t rm;
2269 HReg op_hi, op_lo;
2270 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2272 f4 = make_fpr(4); /* source */
2273 f6 = make_fpr(6); /* source */
2274 f0 = make_fpr(0); /* destination */
2275 f2 = make_fpr(2); /* destination */
2276 r1 = make_gpr(1); /* GPR #1 clobbered */
2278 irrm = expr->Iex.Binop.arg1;
2279 left = expr->Iex.Binop.arg2;
2280 rm = get_dfp_rounding_mode(env, irrm);
2281 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2282 /* operand --> (f4, f6) */
2283 addInstr(env, s390_insn_move(8, f4, op_hi));
2284 addInstr(env, s390_insn_move(8, f6, op_lo));
2285 addInstr(env, s390_insn_fp128_convert(16, S390_FP_D128_TO_F128, f0, f2,
2286 f4, f6, r1, rm));
2287 /* (f0, f2) --> destination */
2288 *dst_hi = newVRegF(env);
2289 *dst_lo = newVRegF(env);
2290 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2291 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2293 return;
2296 case Iop_RoundF128toInt: {
2297 IRExpr *irrm;
2298 IRExpr *left;
2299 s390_bfp_round_t rm;
2300 HReg op_hi, op_lo;
2301 HReg f0, f2, f4, f6; /* real registers */
2303 f4 = make_fpr(4); /* source */
2304 f6 = make_fpr(6); /* source */
2305 f0 = make_fpr(0); /* destination */
2306 f2 = make_fpr(2); /* destination */
2308 irrm = expr->Iex.Binop.arg1;
2309 left = expr->Iex.Binop.arg2;
2311 if (s390_host_has_fpext) {
2312 rm = get_bfp_rounding_mode(env, irrm);
2313 } else {
2314 set_bfp_rounding_mode_in_fpc(env, irrm);
2315 rm = S390_BFP_ROUND_PER_FPC;
2318 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2319 /* operand --> (f4, f6) */
2320 addInstr(env, s390_insn_move(8, f4, op_hi));
2321 addInstr(env, s390_insn_move(8, f6, op_lo));
2322 addInstr(env, s390_insn_bfp128_convert(16, S390_BFP_F128_TO_F128I,
2323 f0, f2, f4, f6, rm));
2324 /* (f0, f2) --> destination */
2325 *dst_hi = newVRegF(env);
2326 *dst_lo = newVRegF(env);
2327 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2328 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2329 return;
2332 default:
2333 goto irreducible;
2337 /* --------- UNARY OP --------- */
2338 case Iex_Unop: {
2339 IRExpr *left = expr->Iex.Unop.arg;
2340 s390_bfp_unop_t bfpop;
2341 s390_bfp_conv_t conv;
2342 HReg op_hi, op_lo, op, f12, f13, f14, f15;
2344 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2345 f12 = make_fpr(12);
2346 f13 = make_fpr(13);
2347 f14 = make_fpr(14);
2348 f15 = make_fpr(15);
2350 switch (expr->Iex.Unop.op) {
2351 case Iop_NegF128:
2352 if (left->tag == Iex_Unop &&
2353 (left->Iex.Unop.op == Iop_AbsF32 ||
2354 left->Iex.Unop.op == Iop_AbsF64))
2355 bfpop = S390_BFP_NABS;
2356 else
2357 bfpop = S390_BFP_NEG;
2358 goto float128_opnd;
2359 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2360 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2361 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2362 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2363 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2364 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2365 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
2366 default:
2367 goto irreducible;
2370 float128_opnd:
2371 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2373 /* operand --> (f13, f15) */
2374 addInstr(env, s390_insn_move(8, f13, op_hi));
2375 addInstr(env, s390_insn_move(8, f15, op_lo));
2377 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
2378 goto move_dst;
2380 convert_float:
2381 op = s390_isel_float_expr(env, left);
2382 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
2383 goto move_dst;
2385 convert_int:
2386 op = s390_isel_int_expr(env, left);
2387 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
2388 goto move_dst;
2390 move_dst:
2391 /* Move result to virtual destination registers */
2392 *dst_hi = newVRegF(env);
2393 *dst_lo = newVRegF(env);
2394 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2395 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2396 return;
2399 default:
2400 goto irreducible;
2403 /* We get here if no pattern matched. */
2404 irreducible:
2405 ppIRExpr(expr);
2406 vpanic("s390_isel_float128_expr: cannot reduce tree");
2409 /* Compute a 128-bit value into two 64-bit registers. These may be either
2410 real or virtual regs; in any case they must not be changed by subsequent
2411 code emitted by the caller. */
2412 static void
2413 s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2415 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2417 /* Sanity checks ... */
2418 vassert(hregIsVirtual(*dst_hi));
2419 vassert(hregIsVirtual(*dst_lo));
2420 vassert(hregClass(*dst_hi) == HRcFlt64);
2421 vassert(hregClass(*dst_lo) == HRcFlt64);
2425 /*---------------------------------------------------------*/
2426 /*--- ISEL: Floating point expressions (64 bit) ---*/
2427 /*---------------------------------------------------------*/
2429 static HReg
2430 s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2432 IRType ty = typeOfIRExpr(env->type_env, expr);
2433 UChar size;
2435 vassert(ty == Ity_F32 || ty == Ity_F64);
2437 size = sizeofIRType(ty);
2439 switch (expr->tag) {
2440 case Iex_RdTmp:
2441 /* Return the virtual register that holds the temporary. */
2442 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2444 /* --------- LOAD --------- */
2445 case Iex_Load: {
2446 HReg dst = newVRegF(env);
2447 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2449 if (expr->Iex.Load.end != Iend_BE)
2450 goto irreducible;
2452 addInstr(env, s390_insn_load(size, dst, am));
2454 return dst;
2457 /* --------- GET --------- */
2458 case Iex_Get: {
2459 HReg dst = newVRegF(env);
2460 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2462 addInstr(env, s390_insn_load(size, dst, am));
2464 return dst;
2467 /* --------- LITERAL --------- */
2469 /* Load a literal into a register. Create a "load immediate"
2470 v-insn and return the register. */
2471 case Iex_Const: {
2472 ULong value;
2473 HReg dst = newVRegF(env);
2474 const IRConst *con = expr->Iex.Const.con;
2476 /* Bitwise copy of the value. No sign/zero-extension */
2477 switch (con->tag) {
2478 case Ico_F32i: value = con->Ico.F32i; break;
2479 case Ico_F64i: value = con->Ico.F64i; break;
2480 default: vpanic("s390_isel_float_expr: invalid constant");
2483 if (value != 0) vpanic("cannot load immediate floating point constant");
2485 addInstr(env, s390_insn_load_immediate(size, dst, value));
2487 return dst;
2490 /* --------- 4-ary OP --------- */
2491 case Iex_Qop: {
2492 HReg op1, op2, op3, dst;
2493 s390_bfp_triop_t bfpop;
2495 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
2496 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
2497 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
2498 dst = newVRegF(env);
2499 addInstr(env, s390_insn_move(size, dst, op1));
2501 switch (expr->Iex.Qop.details->op) {
2502 case Iop_MAddF32:
2503 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2504 case Iop_MSubF32:
2505 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2507 default:
2508 goto irreducible;
2511 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2512 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
2513 return dst;
2516 /* --------- TERNARY OP --------- */
2517 case Iex_Triop: {
2518 IRTriop *triop = expr->Iex.Triop.details;
2519 IROp op = triop->op;
2520 IRExpr *left = triop->arg2;
2521 IRExpr *right = triop->arg3;
2522 s390_bfp_binop_t bfpop;
2523 HReg h1, op2, dst;
2525 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2526 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2527 dst = newVRegF(env);
2528 addInstr(env, s390_insn_move(size, dst, h1));
2529 switch (op) {
2530 case Iop_AddF32:
2531 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2532 case Iop_SubF32:
2533 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2534 case Iop_MulF32:
2535 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2536 case Iop_DivF32:
2537 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2539 default:
2540 goto irreducible;
2543 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2544 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
2545 return dst;
2548 /* --------- BINARY OP --------- */
2549 case Iex_Binop: {
2550 IROp op = expr->Iex.Binop.op;
2551 IRExpr *irrm = expr->Iex.Binop.arg1;
2552 IRExpr *left = expr->Iex.Binop.arg2;
2553 HReg h1, dst;
2554 s390_bfp_conv_t conv;
2555 s390_fp_conv_t fpconv;
2557 switch (op) {
2558 case Iop_SqrtF32:
2559 case Iop_SqrtF64:
2560 h1 = s390_isel_float_expr(env, left);
2561 dst = newVRegF(env);
2562 set_bfp_rounding_mode_in_fpc(env, irrm);
2563 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
2564 return dst;
2566 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2567 case Iop_RoundF32toInt: conv = S390_BFP_F32_TO_F32I; goto convert_float;
2568 case Iop_RoundF64toInt: conv = S390_BFP_F64_TO_F64I; goto convert_float;
2569 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2570 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2571 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2572 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2573 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2574 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
2575 case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp;
2576 case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp;
2577 case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp;
2578 case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp;
2579 case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128;
2580 case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
2582 convert_float:
2583 h1 = s390_isel_float_expr(env, left);
2584 goto convert;
2586 convert_int:
2587 h1 = s390_isel_int_expr(env, left);
2588 goto convert;
2590 convert: {
2591 s390_bfp_round_t rounding_mode;
2592 /* convert-from-fixed and load-rounded have a rounding mode field
2593 when the floating point extension facility is installed. */
2594 dst = newVRegF(env);
2595 if (s390_host_has_fpext) {
2596 rounding_mode = get_bfp_rounding_mode(env, irrm);
2597 } else {
2598 set_bfp_rounding_mode_in_fpc(env, irrm);
2599 rounding_mode = S390_BFP_ROUND_PER_FPC;
2601 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2602 rounding_mode));
2603 return dst;
2606 convert_dfp: {
2607 s390_dfp_round_t rm;
2608 HReg f0, f4, r1; /* real registers used by PFPO */
2610 f4 = make_fpr(4); /* source */
2611 f0 = make_fpr(0); /* destination */
2612 r1 = make_gpr(1); /* GPR #1 clobbered */
2613 h1 = s390_isel_dfp_expr(env, left);
2614 dst = newVRegF(env);
2615 rm = get_dfp_rounding_mode(env, irrm);
2616 /* operand --> f4 */
2617 addInstr(env, s390_insn_move(8, f4, h1));
2618 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2619 /* f0 --> destination */
2620 addInstr(env, s390_insn_move(8, dst, f0));
2621 return dst;
2624 convert_dfp128: {
2625 s390_dfp_round_t rm;
2626 HReg op_hi, op_lo;
2627 HReg f0, f4, f6, r1; /* real registers used by PFPO */
2629 f4 = make_fpr(4); /* source */
2630 f6 = make_fpr(6); /* source */
2631 f0 = make_fpr(0); /* destination */
2632 r1 = make_gpr(1); /* GPR #1 clobbered */
2633 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2634 dst = newVRegF(env);
2635 rm = get_dfp_rounding_mode(env, irrm);
2636 /* operand --> (f4, f6) */
2637 addInstr(env, s390_insn_move(8, f4, op_hi));
2638 addInstr(env, s390_insn_move(8, f6, op_lo));
2639 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
2640 f4, f6, r1, rm));
2641 /* f0 --> destination */
2642 addInstr(env, s390_insn_move(8, dst, f0));
2643 return dst;
2646 default:
2647 goto irreducible;
2649 case Iop_F128toF64:
2650 case Iop_F128toF32: {
2651 HReg op_hi, op_lo, f12, f13, f14, f15;
2652 s390_bfp_round_t rounding_mode;
2654 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2655 : S390_BFP_F128_TO_F64;
2657 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2659 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2660 f12 = make_fpr(12);
2661 f13 = make_fpr(13);
2662 f14 = make_fpr(14);
2663 f15 = make_fpr(15);
2665 /* operand --> (f13, f15) */
2666 addInstr(env, s390_insn_move(8, f13, op_hi));
2667 addInstr(env, s390_insn_move(8, f15, op_lo));
2669 /* result --> (f12, f14) */
2671 /* load-rounded has a rounding mode field when the floating point
2672 extension facility is installed. */
2673 if (s390_host_has_fpext) {
2674 rounding_mode = get_bfp_rounding_mode(env, irrm);
2675 } else {
2676 set_bfp_rounding_mode_in_fpc(env, irrm);
2677 rounding_mode = S390_BFP_ROUND_PER_FPC;
2680 addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14,
2681 f13, f15, rounding_mode));
2682 dst = newVRegF(env);
2683 addInstr(env, s390_insn_move(8, dst, f12));
2685 return dst;
2690 /* --------- UNARY OP --------- */
2691 case Iex_Unop: {
2692 IROp op = expr->Iex.Unop.op;
2693 IRExpr *left = expr->Iex.Unop.arg;
2694 s390_bfp_unop_t bfpop;
2695 s390_bfp_conv_t conv;
2696 HReg h1, dst;
2698 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2699 HReg dst_hi, dst_lo;
2701 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2702 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2705 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
2706 dst = newVRegF(env);
2707 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2708 addInstr(env, s390_insn_move(size, dst, h1));
2710 return dst;
2713 switch (op) {
2714 case Iop_NegF32:
2715 case Iop_NegF64:
2716 if (left->tag == Iex_Unop &&
2717 (left->Iex.Unop.op == Iop_AbsF32 ||
2718 left->Iex.Unop.op == Iop_AbsF64))
2719 bfpop = S390_BFP_NABS;
2720 else
2721 bfpop = S390_BFP_NEG;
2722 break;
2724 case Iop_AbsF32:
2725 case Iop_AbsF64:
2726 bfpop = S390_BFP_ABS;
2727 break;
2729 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2730 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2731 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2733 convert_float1:
2734 h1 = s390_isel_float_expr(env, left);
2735 goto convert1;
2737 convert_int1:
2738 h1 = s390_isel_int_expr(env, left);
2739 goto convert1;
2741 convert1:
2742 dst = newVRegF(env);
2743 /* No rounding mode is needed for these conversions. Just stick
2744 one in. It won't be used later on. */
2745 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2746 S390_BFP_ROUND_NEAREST_EVEN));
2747 return dst;
2749 default:
2750 goto irreducible;
2753 /* Process operand */
2754 h1 = s390_isel_float_expr(env, left);
2755 dst = newVRegF(env);
2756 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
2757 return dst;
2760 default:
2761 goto irreducible;
2764 /* We get here if no pattern matched. */
2765 irreducible:
2766 ppIRExpr(expr);
2767 vpanic("s390_isel_float_expr: cannot reduce tree");
2771 static HReg
2772 s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2774 HReg dst = s390_isel_float_expr_wrk(env, expr);
2776 /* Sanity checks ... */
2777 vassert(hregClass(dst) == HRcFlt64);
2778 vassert(hregIsVirtual(dst));
2780 return dst;
2784 /*---------------------------------------------------------*/
2785 /*--- ISEL: Decimal point expressions (128 bit) ---*/
2786 /*---------------------------------------------------------*/
2787 static void
2788 s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2789 IRExpr *expr)
2791 IRType ty = typeOfIRExpr(env->type_env, expr);
2793 vassert(ty == Ity_D128);
2795 switch (expr->tag) {
2796 case Iex_RdTmp:
2797 /* Return the virtual registers that hold the temporary. */
2798 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2799 return;
2801 /* --------- LOAD --------- */
2802 case Iex_Load: {
2803 IRExpr *addr_hi, *addr_lo;
2804 s390_amode *am_hi, *am_lo;
2806 if (expr->Iex.Load.end != Iend_BE)
2807 goto irreducible;
2809 addr_hi = expr->Iex.Load.addr;
2810 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2812 am_hi = s390_isel_amode(env, addr_hi);
2813 am_lo = s390_isel_amode(env, addr_lo);
2815 *dst_hi = newVRegF(env);
2816 *dst_lo = newVRegF(env);
2817 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2818 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2819 return;
2822 /* --------- GET --------- */
2823 case Iex_Get:
2824 /* This is not supported because loading 128-bit from the guest
2825 state is almost certainly wrong. Use get_dpr_pair instead. */
2826 vpanic("Iex_Get with D128 data");
2828 /* --------- 4-ary OP --------- */
2829 case Iex_Qop:
2830 vpanic("Iex_Qop with D128 data");
2832 /* --------- TERNARY OP --------- */
2833 case Iex_Triop: {
2834 IRTriop *triop = expr->Iex.Triop.details;
2835 IROp op = triop->op;
2836 IRExpr *irrm = triop->arg1;
2837 IRExpr *left = triop->arg2;
2838 IRExpr *right = triop->arg3;
2839 s390_dfp_round_t rounding_mode;
2840 s390_dfp_binop_t dfpop;
2841 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2843 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2844 (f12, f14) as op2 and (f13, f15) as destination) */
2845 f9 = make_fpr(9);
2846 f11 = make_fpr(11);
2847 f12 = make_fpr(12);
2848 f13 = make_fpr(13);
2849 f14 = make_fpr(14);
2850 f15 = make_fpr(15);
2852 switch (op) {
2853 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128;
2854 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128;
2855 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128;
2856 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128;
2857 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
2859 evaluate_dfp128: {
2860 /* Process 1st operand */
2861 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
2862 /* 1st operand --> (f9, f11) */
2863 addInstr(env, s390_insn_move(8, f9, op1_hi));
2864 addInstr(env, s390_insn_move(8, f11, op1_lo));
2866 /* Process 2nd operand */
2867 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2868 /* 2nd operand --> (f12, f14) */
2869 addInstr(env, s390_insn_move(8, f12, op2_hi));
2870 addInstr(env, s390_insn_move(8, f14, op2_lo));
2872 /* DFP arithmetic ops take rounding mode only when fpext is
2873 installed. But, DFP quantize operation takes rm irrespective
2874 of fpext facility . */
2875 if (s390_host_has_fpext || op == Iop_QuantizeD128) {
2876 rounding_mode = get_dfp_rounding_mode(env, irrm);
2877 } else {
2878 set_dfp_rounding_mode_in_fpc(env, irrm);
2879 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2881 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2882 f12, f14, rounding_mode));
2883 /* Move result to virtual destination register */
2884 *dst_hi = newVRegF(env);
2885 *dst_lo = newVRegF(env);
2886 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2887 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2888 return;
2891 case Iop_SignificanceRoundD128: {
2892 /* Process 1st operand */
2893 HReg op1 = s390_isel_int_expr(env, left);
2894 /* Process 2nd operand */
2895 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2896 /* 2nd operand --> (f12, f14) */
2897 addInstr(env, s390_insn_move(8, f12, op2_hi));
2898 addInstr(env, s390_insn_move(8, f14, op2_lo));
2900 rounding_mode = get_dfp_rounding_mode(env, irrm);
2901 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14,
2902 rounding_mode));
2903 /* Move result to virtual destination register */
2904 *dst_hi = newVRegF(env);
2905 *dst_lo = newVRegF(env);
2906 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2907 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2908 return;
2911 default:
2912 goto irreducible;
2916 /* --------- BINARY OP --------- */
2917 case Iex_Binop: {
2919 switch (expr->Iex.Binop.op) {
2920 case Iop_D64HLtoD128:
2921 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2922 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2923 return;
2925 case Iop_ShlD128:
2926 case Iop_ShrD128:
2927 case Iop_InsertExpD128: {
2928 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2929 s390_dfp_intop_t intop;
2930 IRExpr *dfp_op;
2931 IRExpr *int_op;
2933 switch (expr->Iex.Binop.op) {
2934 case Iop_ShlD128: /* (D128, I64) -> D128 */
2935 intop = S390_DFP_SHIFT_LEFT;
2936 dfp_op = expr->Iex.Binop.arg1;
2937 int_op = expr->Iex.Binop.arg2;
2938 break;
2939 case Iop_ShrD128: /* (D128, I64) -> D128 */
2940 intop = S390_DFP_SHIFT_RIGHT;
2941 dfp_op = expr->Iex.Binop.arg1;
2942 int_op = expr->Iex.Binop.arg2;
2943 break;
2944 case Iop_InsertExpD128: /* (I64, D128) -> D128 */
2945 intop = S390_DFP_INSERT_EXP;
2946 int_op = expr->Iex.Binop.arg1;
2947 dfp_op = expr->Iex.Binop.arg2;
2948 break;
2949 default: goto irreducible;
2952 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2953 f9 = make_fpr(9); /* 128 bit dfp operand */
2954 f11 = make_fpr(11);
2956 f13 = make_fpr(13); /* 128 bit dfp destination */
2957 f15 = make_fpr(15);
2959 /* Process dfp operand */
2960 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
2961 /* op1 -> (f9,f11) */
2962 addInstr(env, s390_insn_move(8, f9, op1_hi));
2963 addInstr(env, s390_insn_move(8, f11, op1_lo));
2965 op2 = s390_isel_int_expr(env, int_op); /* int operand */
2967 addInstr(env,
2968 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2970 /* Move result to virtual destination register */
2971 *dst_hi = newVRegF(env);
2972 *dst_lo = newVRegF(env);
2973 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2974 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2975 return;
2978 case Iop_F32toD128:
2979 case Iop_F64toD128: {
2980 IRExpr *irrm;
2981 IRExpr *left;
2982 s390_dfp_round_t rm;
2983 HReg h1; /* virtual reg. to hold source */
2984 HReg f0, f2, f4, r1; /* real registers used by PFPO */
2985 s390_fp_conv_t fpconv;
2987 switch (expr->Iex.Binop.op) {
2988 case Iop_F32toD128: /* (D128, I64) -> D128 */
2989 fpconv = S390_FP_F32_TO_D128;
2990 break;
2991 case Iop_F64toD128: /* (D128, I64) -> D128 */
2992 fpconv = S390_FP_F64_TO_D128;
2993 break;
2994 default: goto irreducible;
2997 f4 = make_fpr(4); /* source */
2998 f0 = make_fpr(0); /* destination */
2999 f2 = make_fpr(2); /* destination */
3000 r1 = make_gpr(1); /* GPR #1 clobbered */
3001 irrm = expr->Iex.Binop.arg1;
3002 left = expr->Iex.Binop.arg2;
3003 rm = get_dfp_rounding_mode(env, irrm);
3004 h1 = s390_isel_float_expr(env, left);
3005 addInstr(env, s390_insn_move(8, f4, h1));
3006 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
3007 f4, INVALID_HREG, r1, rm));
3008 /* (f0, f2) --> destination */
3009 *dst_hi = newVRegF(env);
3010 *dst_lo = newVRegF(env);
3011 addInstr(env, s390_insn_move(8, *dst_hi, f0));
3012 addInstr(env, s390_insn_move(8, *dst_lo, f2));
3014 return;
3017 case Iop_F128toD128: {
3018 IRExpr *irrm;
3019 IRExpr *left;
3020 s390_dfp_round_t rm;
3021 HReg op_hi, op_lo;
3022 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
3024 f4 = make_fpr(4); /* source */
3025 f6 = make_fpr(6); /* source */
3026 f0 = make_fpr(0); /* destination */
3027 f2 = make_fpr(2); /* destination */
3028 r1 = make_gpr(1); /* GPR #1 clobbered */
3030 irrm = expr->Iex.Binop.arg1;
3031 left = expr->Iex.Binop.arg2;
3032 rm = get_dfp_rounding_mode(env, irrm);
3033 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
3034 /* operand --> (f4, f6) */
3035 addInstr(env, s390_insn_move(8, f4, op_hi));
3036 addInstr(env, s390_insn_move(8, f6, op_lo));
3037 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2,
3038 f4, f6, r1, rm));
3039 /* (f0, f2) --> destination */
3040 *dst_hi = newVRegF(env);
3041 *dst_lo = newVRegF(env);
3042 addInstr(env, s390_insn_move(8, *dst_hi, f0));
3043 addInstr(env, s390_insn_move(8, *dst_lo, f2));
3045 return;
3048 default:
3049 goto irreducible;
3053 /* --------- UNARY OP --------- */
3054 case Iex_Unop: {
3055 IRExpr *left = expr->Iex.Unop.arg;
3056 s390_dfp_conv_t conv;
3057 HReg op, f12, f14;
3059 /* We use non-virtual registers as pairs (f12, f14)) */
3060 f12 = make_fpr(12);
3061 f14 = make_fpr(14);
3063 switch (expr->Iex.Unop.op) {
3064 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
3065 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
3066 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int;
3067 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
3068 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
3069 default:
3070 goto irreducible;
3073 convert_dfp:
3074 op = s390_isel_dfp_expr(env, left);
3075 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
3076 goto move_dst;
3078 convert_int:
3079 op = s390_isel_int_expr(env, left);
3080 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
3081 goto move_dst;
3083 move_dst:
3084 /* Move result to virtual destination registers */
3085 *dst_hi = newVRegF(env);
3086 *dst_lo = newVRegF(env);
3087 addInstr(env, s390_insn_move(8, *dst_hi, f12));
3088 addInstr(env, s390_insn_move(8, *dst_lo, f14));
3089 return;
3092 default:
3093 goto irreducible;
3096 /* We get here if no pattern matched. */
3097 irreducible:
3098 ppIRExpr(expr);
3099 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
3104 /* Compute a 128-bit value into two 64-bit registers. These may be either
3105 real or virtual regs; in any case they must not be changed by subsequent
3106 code emitted by the caller. */
3107 static void
3108 s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
3110 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
3112 /* Sanity checks ... */
3113 vassert(hregIsVirtual(*dst_hi));
3114 vassert(hregIsVirtual(*dst_lo));
3115 vassert(hregClass(*dst_hi) == HRcFlt64);
3116 vassert(hregClass(*dst_lo) == HRcFlt64);
3120 /*---------------------------------------------------------*/
3121 /*--- ISEL: Decimal point expressions (64 bit) ---*/
3122 /*---------------------------------------------------------*/
3124 static HReg
3125 s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
3127 IRType ty = typeOfIRExpr(env->type_env, expr);
3128 UChar size;
3130 vassert(ty == Ity_D64 || ty == Ity_D32);
3132 size = sizeofIRType(ty);
3134 switch (expr->tag) {
3135 case Iex_RdTmp:
3136 /* Return the virtual register that holds the temporary. */
3137 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
3139 /* --------- LOAD --------- */
3140 case Iex_Load: {
3141 HReg dst = newVRegF(env);
3142 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
3144 if (expr->Iex.Load.end != Iend_BE)
3145 goto irreducible;
3147 addInstr(env, s390_insn_load(size, dst, am));
3149 return dst;
3152 /* --------- GET --------- */
3153 case Iex_Get: {
3154 HReg dst = newVRegF(env);
3155 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
3157 addInstr(env, s390_insn_load(size, dst, am));
3159 return dst;
3162 /* --------- BINARY OP --------- */
3163 case Iex_Binop: {
3164 IROp op = expr->Iex.Binop.op;
3165 IRExpr *irrm = expr->Iex.Binop.arg1;
3166 IRExpr *left = expr->Iex.Binop.arg2;
3167 HReg h1, dst;
3168 s390_dfp_conv_t conv;
3169 s390_fp_conv_t fpconv;
3171 switch (op) {
3172 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
3173 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
3174 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
3175 case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp;
3176 case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp;
3177 case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp;
3178 case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
3179 case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128;
3180 case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128;
3182 convert_dfp:
3183 h1 = s390_isel_dfp_expr(env, left);
3184 goto convert;
3186 convert_int:
3187 h1 = s390_isel_int_expr(env, left);
3188 goto convert;
3190 convert: {
3191 s390_dfp_round_t rounding_mode;
3192 /* convert-from-fixed and load-rounded have a rounding mode field
3193 when the floating point extension facility is installed. */
3194 dst = newVRegF(env);
3195 if (s390_host_has_fpext) {
3196 rounding_mode = get_dfp_rounding_mode(env, irrm);
3197 } else {
3198 set_dfp_rounding_mode_in_fpc(env, irrm);
3199 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3201 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3202 rounding_mode));
3203 return dst;
3206 convert_bfp: {
3207 s390_dfp_round_t rm;
3208 HReg f0, f4, r1; /* real registers used by PFPO */
3210 f4 = make_fpr(4); /* source */
3211 f0 = make_fpr(0); /* destination */
3212 r1 = make_gpr(1); /* GPR #1 clobbered */
3213 h1 = s390_isel_float_expr(env, left);
3214 dst = newVRegF(env);
3215 rm = get_dfp_rounding_mode(env, irrm);
3216 /* operand --> f4 */
3217 addInstr(env, s390_insn_move(8, f4, h1));
3218 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
3219 /* f0 --> destination */
3220 addInstr(env, s390_insn_move(8, dst, f0));
3221 return dst;
3224 convert_bfp128: {
3225 s390_dfp_round_t rm;
3226 HReg op_hi, op_lo;
3227 HReg f0, f4, f6, r1; /* real registers used by PFPO */
3229 f4 = make_fpr(4); /* source */
3230 f6 = make_fpr(6); /* source */
3231 f0 = make_fpr(0); /* destination */
3232 r1 = make_gpr(1); /* GPR #1 clobbered */
3233 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
3234 dst = newVRegF(env);
3235 rm = get_dfp_rounding_mode(env, irrm);
3236 /* operand --> (f4, f6) */
3237 addInstr(env, s390_insn_move(8, f4, op_hi));
3238 addInstr(env, s390_insn_move(8, f6, op_lo));
3239 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
3240 f4, f6, r1, rm));
3241 /* f0 --> destination */
3242 addInstr(env, s390_insn_move(8, dst, f0));
3243 return dst;
3246 case Iop_D128toD64: {
3247 HReg op_hi, op_lo, f12, f13, f14, f15;
3248 s390_dfp_round_t rounding_mode;
3250 conv = S390_DFP_D128_TO_D64;
3252 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
3254 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */
3255 f12 = make_fpr(12);
3256 f13 = make_fpr(13);
3257 f14 = make_fpr(14);
3258 f15 = make_fpr(15);
3260 /* operand --> (f13, f15) */
3261 addInstr(env, s390_insn_move(8, f13, op_hi));
3262 addInstr(env, s390_insn_move(8, f15, op_lo));
3264 /* result --> (f12, f14) */
3266 /* load-rounded has a rounding mode field when the floating point
3267 extension facility is installed. */
3268 if (s390_host_has_fpext) {
3269 rounding_mode = get_dfp_rounding_mode(env, irrm);
3270 } else {
3271 set_dfp_rounding_mode_in_fpc(env, irrm);
3272 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3274 addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14,
3275 f13, f15, rounding_mode));
3276 dst = newVRegF(env);
3277 addInstr(env, s390_insn_move(8, dst, f12));
3279 return dst;
3282 case Iop_ShlD64:
3283 case Iop_ShrD64:
3284 case Iop_InsertExpD64: {
3285 HReg op2;
3286 HReg op3;
3287 IRExpr *dfp_op;
3288 IRExpr *int_op;
3289 s390_dfp_intop_t intop;
3291 switch (expr->Iex.Binop.op) {
3292 case Iop_ShlD64: /* (D64, I64) -> D64 */
3293 intop = S390_DFP_SHIFT_LEFT;
3294 dfp_op = expr->Iex.Binop.arg1;
3295 int_op = expr->Iex.Binop.arg2;
3296 break;
3297 case Iop_ShrD64: /* (D64, I64) -> D64 */
3298 intop = S390_DFP_SHIFT_RIGHT;
3299 dfp_op = expr->Iex.Binop.arg1;
3300 int_op = expr->Iex.Binop.arg2;
3301 break;
3302 case Iop_InsertExpD64: /* (I64, D64) -> D64 */
3303 intop = S390_DFP_INSERT_EXP;
3304 int_op = expr->Iex.Binop.arg1;
3305 dfp_op = expr->Iex.Binop.arg2;
3306 break;
3307 default: goto irreducible;
3310 op2 = s390_isel_int_expr(env, int_op);
3311 op3 = s390_isel_dfp_expr(env, dfp_op);
3312 dst = newVRegF(env);
3314 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
3315 return dst;
3318 default:
3319 goto irreducible;
3323 /* --------- UNARY OP --------- */
3324 case Iex_Unop: {
3325 IROp op = expr->Iex.Unop.op;
3326 IRExpr *left = expr->Iex.Unop.arg;
3327 s390_dfp_conv_t conv;
3328 HReg h1, dst;
3330 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
3331 HReg dst_hi, dst_lo;
3333 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
3334 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
3337 if (op == Iop_ReinterpI64asD64) {
3338 dst = newVRegF(env);
3339 h1 = s390_isel_int_expr(env, left); /* Process the operand */
3340 addInstr(env, s390_insn_move(size, dst, h1));
3342 return dst;
3345 switch (op) {
3346 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
3347 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
3348 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
3350 convert_dfp1:
3351 h1 = s390_isel_dfp_expr(env, left);
3352 goto convert1;
3354 convert_int1:
3355 h1 = s390_isel_int_expr(env, left);
3356 goto convert1;
3358 convert1:
3359 dst = newVRegF(env);
3360 /* No rounding mode is needed for these conversions. Just stick
3361 one in. It won't be used later on. */
3362 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3363 S390_DFP_ROUND_NEAREST_EVEN_4));
3364 return dst;
3366 default:
3367 goto irreducible;
3371 /* --------- TERNARY OP --------- */
3372 case Iex_Triop: {
3373 IRTriop *triop = expr->Iex.Triop.details;
3374 IROp op = triop->op;
3375 IRExpr *irrm = triop->arg1;
3376 IRExpr *left = triop->arg2;
3377 IRExpr *right = triop->arg3;
3378 s390_dfp_round_t rounding_mode;
3379 s390_dfp_binop_t dfpop;
3380 HReg op2, op3, dst;
3382 switch (op) {
3383 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp;
3384 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp;
3385 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp;
3386 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp;
3387 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
3389 evaluate_dfp: {
3390 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
3391 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3392 dst = newVRegF(env);
3393 /* DFP arithmetic ops take rounding mode only when fpext is
3394 installed. But, DFP quantize operation takes rm irrespective
3395 of fpext facility . */
3396 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
3397 rounding_mode = get_dfp_rounding_mode(env, irrm);
3398 } else {
3399 set_dfp_rounding_mode_in_fpc(env, irrm);
3400 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3402 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3,
3403 rounding_mode));
3404 return dst;
3407 case Iop_SignificanceRoundD64:
3408 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */
3409 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3410 dst = newVRegF(env);
3411 rounding_mode = get_dfp_rounding_mode(env, irrm);
3412 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3,
3413 rounding_mode));
3414 return dst;
3416 default:
3417 goto irreducible;
3421 default:
3422 goto irreducible;
3425 /* We get here if no pattern matched. */
3426 irreducible:
3427 ppIRExpr(expr);
3428 vpanic("s390_isel_dfp_expr: cannot reduce tree");
3431 static HReg
3432 s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
3434 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
3436 /* Sanity checks ... */
3437 vassert(hregClass(dst) == HRcFlt64);
3438 vassert(hregIsVirtual(dst));
3440 return dst;
3444 /*---------------------------------------------------------*/
3445 /*--- ISEL: Condition Code ---*/
3446 /*---------------------------------------------------------*/
3448 /* This function handles all operators that produce a 1-bit result */
3449 static s390_cc_t
3450 s390_isel_cc(ISelEnv *env, IRExpr *cond)
3452 UChar size;
3454 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
3456 /* Constant: either 1 or 0 */
3457 if (cond->tag == Iex_Const) {
3458 vassert(cond->Iex.Const.con->tag == Ico_U1);
3459 vassert(cond->Iex.Const.con->Ico.U1 == True
3460 || cond->Iex.Const.con->Ico.U1 == False);
3462 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
3465 /* Variable: values are 1 or 0 */
3466 if (cond->tag == Iex_RdTmp) {
3467 IRTemp tmp = cond->Iex.RdTmp.tmp;
3468 HReg reg = lookupIRTemp(env, tmp);
3470 /* Load-and-test does not modify REG; so this is OK. */
3471 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
3472 size = 4;
3473 else
3474 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
3475 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
3476 return S390_CC_NE;
3479 /* Unary operators */
3480 if (cond->tag == Iex_Unop) {
3481 IRExpr *arg = cond->Iex.Unop.arg;
3483 switch (cond->Iex.Unop.op) {
3484 case Iop_Not1: /* Not1(cond) */
3485 /* Generate code for EXPR, and negate the test condition */
3486 return s390_cc_invert(s390_isel_cc(env, arg));
3488 /* Iop_32/64to1 select the LSB from their operand */
3489 case Iop_32to1:
3490 case Iop_64to1: {
3491 HReg dst = newVRegI(env);
3492 HReg h1 = s390_isel_int_expr(env, arg);
3494 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3496 addInstr(env, s390_insn_move(size, dst, h1));
3497 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
3498 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
3499 return S390_CC_NE;
3502 case Iop_CmpNEZ8:
3503 case Iop_CmpNEZ16: {
3504 s390_opnd_RMI src;
3505 s390_unop_t op;
3506 HReg dst;
3508 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
3509 : S390_ZERO_EXTEND_16;
3510 dst = newVRegI(env);
3511 src = s390_isel_int_expr_RMI(env, arg);
3512 addInstr(env, s390_insn_unop(4, op, dst, src));
3513 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
3514 return S390_CC_NE;
3517 case Iop_CmpNEZ32:
3518 case Iop_CmpNEZ64: {
3519 s390_opnd_RMI src;
3521 src = s390_isel_int_expr_RMI(env, arg);
3522 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3523 addInstr(env, s390_insn_test(size, src));
3524 return S390_CC_NE;
3527 default:
3528 goto fail;
3532 /* Binary operators */
3533 if (cond->tag == Iex_Binop) {
3534 IRExpr *arg1 = cond->Iex.Binop.arg1;
3535 IRExpr *arg2 = cond->Iex.Binop.arg2;
3536 HReg reg1, reg2;
3538 /* sewardj 2019Nov30: This will be needed when chasing through conditional
3539 branches in guest_generic_bb_to_IR.c is enabled on s390x.
3540 Unfortunately that is currently disabled on s390x as it causes
3541 mysterious segfaults and also exposes some unhandled Iex_ITE cases in
3542 this instruction selector. The following Iop_And1/Iop_Or1 cases are
3543 also needed when enabled. The code below is *believed* to be correct,
3544 and has been lightly tested, but it is #if 0'd until such time as we
3545 need it. */
3546 # if 0
3547 /* FIXME: We could (and probably should) do a lot better here, by using
3548 the iselCondCode_C/_R scheme used in the amd64 insn selector. */
3549 if (cond->Iex.Binop.op == Iop_And1 || cond->Iex.Binop.op == Iop_Or1) {
3550 /* In short: force both operands into registers, AND or OR them, mask
3551 off all but the lowest bit, then convert the result back into a
3552 condition code. */
3553 const s390_opnd_RMI one = s390_opnd_imm(1);
3555 HReg x_as_64 = newVRegI(env);
3556 s390_cc_t cc_x = s390_isel_cc(env, arg1);
3557 addInstr(env, s390_insn_cc2bool(x_as_64, cc_x));
3558 addInstr(env, s390_insn_alu(8, S390_ALU_AND, x_as_64, one));
3560 HReg y_as_64 = newVRegI(env);
3561 s390_cc_t cc_y = s390_isel_cc(env, arg2);
3562 addInstr(env, s390_insn_cc2bool(y_as_64, cc_y));
3563 addInstr(env, s390_insn_alu(8, S390_ALU_AND, y_as_64, one));
3565 s390_alu_t opkind
3566 = cond->Iex.Binop.op == Iop_And1 ? S390_ALU_AND : S390_ALU_OR;
3567 addInstr(env, s390_insn_alu(/*size=*/8,
3568 opkind, x_as_64, s390_opnd_reg(y_as_64)));
3570 addInstr(env, s390_insn_alu(/*size=*/8, S390_ALU_AND, x_as_64, one));
3571 addInstr(env, s390_insn_test(/*size=*/8, s390_opnd_reg(x_as_64)));
3572 return S390_CC_NE;
3574 # endif /* 0 */
3576 // |sizeofIRType| asserts on Ity_I1, so we can't do it until after we're
3577 // sure that Iop_And1 and Iop_Or1 can't make it this far.
3578 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
3580 switch (cond->Iex.Binop.op) {
3581 s390_unop_t op;
3582 s390_cc_t result;
3584 case Iop_CmpEQ8:
3585 case Iop_CasCmpEQ8:
3586 op = S390_ZERO_EXTEND_8;
3587 result = S390_CC_E;
3588 goto do_compare_ze;
3590 case Iop_CmpNE8:
3591 case Iop_CasCmpNE8:
3592 op = S390_ZERO_EXTEND_8;
3593 result = S390_CC_NE;
3594 goto do_compare_ze;
3596 case Iop_CmpEQ16:
3597 case Iop_CasCmpEQ16:
3598 op = S390_ZERO_EXTEND_16;
3599 result = S390_CC_E;
3600 goto do_compare_ze;
3602 case Iop_CmpNE16:
3603 case Iop_CasCmpNE16:
3604 op = S390_ZERO_EXTEND_16;
3605 result = S390_CC_NE;
3606 goto do_compare_ze;
3608 do_compare_ze: {
3609 s390_opnd_RMI op1, op2;
3611 op1 = s390_isel_int_expr_RMI(env, arg1);
3612 reg1 = newVRegI(env);
3613 addInstr(env, s390_insn_unop(4, op, reg1, op1));
3615 op2 = s390_isel_int_expr_RMI(env, arg2);
3616 reg2 = newVRegI(env);
3617 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
3619 op2 = s390_opnd_reg(reg2);
3620 addInstr(env, s390_insn_compare(4, reg1, op2, False));
3622 return result;
3625 case Iop_CmpEQ32:
3626 case Iop_CmpEQ64:
3627 case Iop_CasCmpEQ32:
3628 case Iop_CasCmpEQ64:
3629 result = S390_CC_E;
3630 goto do_compare;
3632 case Iop_CmpNE32:
3633 case Iop_CmpNE64:
3634 case Iop_CasCmpNE32:
3635 case Iop_CasCmpNE64:
3636 result = S390_CC_NE;
3637 goto do_compare;
3639 do_compare: {
3640 HReg op1;
3641 s390_opnd_RMI op2;
3643 order_commutative_operands(arg1, arg2);
3645 op1 = s390_isel_int_expr(env, arg1);
3646 op2 = s390_isel_int_expr_RMI(env, arg2);
3648 addInstr(env, s390_insn_compare(size, op1, op2, False));
3650 return result;
3653 case Iop_CmpLT32S:
3654 case Iop_CmpLE32S:
3655 case Iop_CmpLT64S:
3656 case Iop_CmpLE64S: {
3657 HReg op1;
3658 s390_opnd_RMI op2;
3660 op1 = s390_isel_int_expr(env, arg1);
3661 op2 = s390_isel_int_expr_RMI(env, arg2);
3663 addInstr(env, s390_insn_compare(size, op1, op2, True));
3665 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3666 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3669 case Iop_CmpLT32U:
3670 case Iop_CmpLE32U:
3671 case Iop_CmpLT64U:
3672 case Iop_CmpLE64U: {
3673 HReg op1;
3674 s390_opnd_RMI op2;
3676 op1 = s390_isel_int_expr(env, arg1);
3677 op2 = s390_isel_int_expr_RMI(env, arg2);
3679 addInstr(env, s390_insn_compare(size, op1, op2, False));
3681 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3682 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3685 default:
3686 goto fail;
3690 fail:
3691 ppIRExpr(cond);
3692 vpanic("s390_isel_cc: unexpected operator");
3696 /*---------------------------------------------------------*/
3697 /*--- ISEL: Vector expressions (128 bit) ---*/
3698 /*---------------------------------------------------------*/
3700 static HReg
3701 s390_isel_vec_expr_wrk(ISelEnv *env, IRExpr *expr)
3703 IRType ty = typeOfIRExpr(env->type_env, expr);
3704 UChar size;
3706 vassert(ty == Ity_V128);
3708 size = sizeofIRType(ty);
3710 switch (expr->tag) {
3711 case Iex_RdTmp:
3712 /* Return the virtual register that holds the temporary. */
3713 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
3715 /* --------- LOAD --------- */
3716 case Iex_Load: {
3717 HReg dst = newVRegV(env);
3718 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
3720 if (expr->Iex.Load.end != Iend_BE)
3721 goto irreducible;
3723 addInstr(env, s390_insn_load(size, dst, am));
3725 return dst;
3728 /* --------- GET --------- */
3729 case Iex_Get: {
3730 HReg dst = newVRegV(env);
3731 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
3733 addInstr(env, s390_insn_load(size, dst, am));
3735 return dst;
3738 case Iex_Const: {
3739 HReg dst = newVRegV(env);
3740 vassert(expr->Iex.Const.con->tag == Ico_V128);
3742 addInstr(env, s390_insn_unop(16, S390_VEC_FILL, dst, s390_opnd_imm(expr->Iex.Const.con->Ico.V128)));
3743 return dst;
3745 /* --------- UNARY OP --------- */
3746 case Iex_Unop: {
3747 UChar size_for_int_arg = 0;
3748 HReg dst = INVALID_HREG;
3749 HReg reg1 = INVALID_HREG;
3750 s390_unop_t vec_unop = S390_UNOP_T_INVALID;
3751 s390_vec_binop_t vec_binop = S390_VEC_BINOP_T_INVALID;
3752 IROp op = expr->Iex.Unop.op;
3753 IRExpr* arg = expr->Iex.Unop.arg;
3754 switch(op) {
3755 case Iop_NotV128:
3756 /* Not(Or(arg1, arg2)) -> Nor(arg1, arg2) */
3757 if(UNLIKELY((arg->tag == Iex_Binop ) && (arg->Iex.Binop.op == Iop_OrV128)))
3759 dst = newVRegV(env);
3760 addInstr(env,
3761 s390_insn_vec_binop(16,
3762 S390_VEC_NOR,
3763 dst,
3764 s390_isel_vec_expr(env, arg->Iex.Binop.arg1),
3765 s390_isel_vec_expr(env, arg->Iex.Binop.arg2)
3768 return dst;
3770 reg1 = s390_isel_vec_expr(env, arg);
3771 return vec_do_notV128(env, reg1);
3773 case Iop_CmpNEZ8x16:
3774 size = 1;
3775 goto Iop_CmpNEZ_wrk;
3776 case Iop_CmpNEZ16x8:
3777 size = 2;
3778 goto Iop_CmpNEZ_wrk;
3779 case Iop_CmpNEZ32x4:
3780 size = 4;
3781 goto Iop_CmpNEZ_wrk;
3782 case Iop_CmpNEZ64x2:
3783 size = 8;
3785 Iop_CmpNEZ_wrk: {
3786 dst = newVRegV(env);
3787 reg1 = s390_isel_vec_expr(env, arg);
3788 addInstr(env, s390_insn_vec_binop(size, S390_VEC_COMPARE_EQUAL, dst,
3789 reg1, vec_generate_zeroes(env)));
3790 return vec_do_notV128(env, dst);
3793 case Iop_CmpNEZ128x1: {
3794 IRExpr* low64 = IRExpr_Unop(Iop_V128to64, arg);
3795 IRExpr* high64 = IRExpr_Unop(Iop_V128HIto64, arg);
3796 IRExpr* both = IRExpr_Binop(Iop_Or64, low64, high64);
3797 IRExpr* anyNonZ = IRExpr_Unop(Iop_CmpNEZ64, both);
3798 IRExpr* anyNonZ64 = IRExpr_Unop(Iop_1Sto64, anyNonZ);
3799 reg1 = s390_isel_int_expr(env, anyNonZ64);
3801 dst = newVRegV(env);
3802 addInstr(env, s390_insn_vec_binop(size, S390_VEC_INIT_FROM_GPRS,
3803 dst, reg1, reg1));
3804 return dst;
3807 case Iop_Dup8x16:
3808 size = size_for_int_arg = 1;
3809 vec_unop = S390_VEC_DUPLICATE;
3810 goto Iop_V_int_wrk;
3811 case Iop_Dup16x8:
3812 size = size_for_int_arg = 2;
3813 vec_unop = S390_VEC_DUPLICATE;
3814 goto Iop_V_int_wrk;
3815 case Iop_Dup32x4:
3816 size = size_for_int_arg = 4;
3817 vec_unop = S390_VEC_DUPLICATE;
3818 goto Iop_V_int_wrk;
3820 case Iop_Widen8Sto16x8:
3821 size = 1;
3822 size_for_int_arg = 8;
3823 vec_unop = S390_VEC_UNPACKLOWS;
3824 goto Iop_V_int_wrk;
3825 case Iop_Widen16Sto32x4:
3826 size = 2;
3827 size_for_int_arg = 8;
3828 vec_unop = S390_VEC_UNPACKLOWS;
3829 goto Iop_V_int_wrk;
3830 case Iop_Widen32Sto64x2:
3831 size = 4;
3832 size_for_int_arg = 8;
3833 vec_unop = S390_VEC_UNPACKLOWS;
3834 goto Iop_V_int_wrk;
3835 case Iop_Widen8Uto16x8:
3836 size = 1;
3837 size_for_int_arg = 8;
3838 vec_unop = S390_VEC_UNPACKLOWU;
3839 goto Iop_V_int_wrk;
3840 case Iop_Widen16Uto32x4:
3841 size = 2;
3842 size_for_int_arg = 8;
3843 vec_unop = S390_VEC_UNPACKLOWU;
3844 goto Iop_V_int_wrk;
3845 case Iop_Widen32Uto64x2:
3846 size = 4;
3847 size_for_int_arg = 8;
3848 vec_unop = S390_VEC_UNPACKLOWU;
3849 goto Iop_V_int_wrk;
3851 Iop_V_int_wrk: {
3852 HReg vr1 = vec_generate_zeroes(env);
3853 s390_amode* amode2 = s390_isel_amode(env, IRExpr_Const(IRConst_U64(0)));
3854 reg1 = s390_isel_int_expr(env, arg);
3856 vassert(vec_unop != S390_UNOP_T_INVALID);
3857 addInstr(env,
3858 s390_insn_vec_amodeintop(size_for_int_arg, S390_VEC_SET_ELEM,
3859 vr1, amode2, reg1));
3861 dst = newVRegV(env);
3862 addInstr(env, s390_insn_unop(size, vec_unop, dst, s390_opnd_reg(vr1)));
3863 return dst;
3866 case Iop_Abs8x16:
3867 size = 1;
3868 vec_unop = S390_VEC_ABS;
3869 goto Iop_V_wrk;
3870 case Iop_Abs16x8:
3871 size = 2;
3872 vec_unop = S390_VEC_ABS;
3873 goto Iop_V_wrk;
3874 case Iop_Abs32x4:
3875 size = 4;
3876 vec_unop = S390_VEC_ABS;
3877 goto Iop_V_wrk;
3878 case Iop_Abs64x2:
3879 size = 8;
3880 vec_unop = S390_VEC_ABS;
3881 goto Iop_V_wrk;
3883 case Iop_Clz8x16:
3884 size = 1;
3885 vec_unop = S390_VEC_COUNT_LEADING_ZEROES;
3886 goto Iop_V_wrk;
3887 case Iop_Ctz8x16:
3888 size = 1;
3889 vec_unop = S390_VEC_COUNT_TRAILING_ZEROES;
3890 goto Iop_V_wrk;
3891 case Iop_Clz16x8:
3892 size = 2;
3893 vec_unop = S390_VEC_COUNT_LEADING_ZEROES;
3894 goto Iop_V_wrk;
3895 case Iop_Ctz16x8:
3896 size = 2;
3897 vec_unop = S390_VEC_COUNT_TRAILING_ZEROES;
3898 goto Iop_V_wrk;
3899 case Iop_Clz32x4:
3900 size = 4;
3901 vec_unop = S390_VEC_COUNT_LEADING_ZEROES;
3902 goto Iop_V_wrk;
3903 case Iop_Ctz32x4:
3904 size = 4;
3905 vec_unop = S390_VEC_COUNT_TRAILING_ZEROES;
3906 goto Iop_V_wrk;
3907 case Iop_Clz64x2:
3908 size = 8;
3909 vec_unop = S390_VEC_COUNT_LEADING_ZEROES;
3910 goto Iop_V_wrk;
3911 case Iop_Ctz64x2:
3912 size = 8;
3913 vec_unop = S390_VEC_COUNT_TRAILING_ZEROES;
3914 goto Iop_V_wrk;
3916 case Iop_Cnt8x16:
3917 size = 1;
3918 vec_unop = S390_VEC_COUNT_ONES;
3919 goto Iop_V_wrk;
3921 case Iop_Neg64Fx2:
3922 size = 8;
3923 vec_unop = S390_VEC_FLOAT_NEG;
3924 goto Iop_V_wrk;
3926 case Iop_Abs64Fx2:
3927 size = 8;
3928 vec_unop = S390_VEC_FLOAT_ABS;
3929 goto Iop_V_wrk;
3932 Iop_V_wrk: {
3933 dst = newVRegV(env);
3934 reg1 = s390_isel_vec_expr(env, arg);
3936 vassert(vec_unop != S390_UNOP_T_INVALID);
3937 addInstr(env,
3938 s390_insn_unop(size, vec_unop, dst, s390_opnd_reg(reg1)));
3939 return dst;
3942 case Iop_PwAddL8Ux16: {
3943 /* There is no such instruction. We have to emulate it. */
3944 IRExpr *even = IRExpr_Binop(Iop_InterleaveEvenLanes8x16,
3945 IRExpr_Const(IRConst_V128(0x0000)),
3946 arg);
3947 IRExpr *odd = IRExpr_Binop(Iop_InterleaveOddLanes8x16,
3948 IRExpr_Const(IRConst_V128(0x0000)),
3949 arg);
3950 dst = s390_isel_vec_expr(env, IRExpr_Binop(Iop_Add16x8, even, odd));
3951 return dst;
3954 case Iop_PwAddL16Ux8:
3955 if (arg->tag == Iex_Unop && arg->Iex.Unop.op == Iop_PwAddL8Ux16) {
3956 size = 1;
3957 arg = arg->Iex.Unop.arg;
3958 } else {
3959 size = 2;
3961 vec_binop = S390_VEC_PWSUM_W;
3962 goto Iop_Pairwise_wrk;
3964 case Iop_PwAddL32Ux4:
3965 if (arg->tag == Iex_Unop && arg->Iex.Unop.op == Iop_PwAddL16Ux8) {
3966 size = 2;
3967 arg = arg->Iex.Unop.arg;
3968 } else {
3969 size = 4;
3971 vec_binop = S390_VEC_PWSUM_DW;
3972 goto Iop_Pairwise_wrk;
3974 case Iop_PwAddL64Ux2:
3975 if (arg->tag == Iex_Unop && arg->Iex.Unop.op == Iop_PwAddL32Ux4) {
3976 size = 4;
3977 arg = arg->Iex.Unop.arg;
3978 } else {
3979 size = 8;
3981 vec_binop = S390_VEC_PWSUM_QW;
3982 goto Iop_Pairwise_wrk;
3984 Iop_Pairwise_wrk: {
3985 dst = newVRegV(env);
3986 reg1 = s390_isel_vec_expr(env, arg);
3987 vassert(vec_binop != S390_VEC_BINOP_T_INVALID);
3988 addInstr(env,
3989 s390_insn_vec_binop(size, vec_binop, dst, reg1,
3990 vec_generate_zeroes(env)));
3991 return dst;
3994 default:
3995 goto irreducible;
3999 /* --------- BINARY OP --------- */
4000 case Iex_Binop: {
4001 HReg dst = newVRegV(env);
4002 HReg reg1 = INVALID_HREG, reg2 = INVALID_HREG;
4003 IROp op = expr->Iex.Binop.op;
4004 s390_unop_t vec_unop = S390_UNOP_T_INVALID;
4005 s390_vec_binop_t vec_binop = S390_VEC_BINOP_T_INVALID;
4006 s390_vec_amodeop_t shift_op = S390_VEC_AMODEOP_T_INVALID;
4007 IRExpr* arg1 = expr->Iex.Binop.arg1;
4008 IRExpr* arg2 = expr->Iex.Binop.arg2;
4009 switch(op) {
4010 case Iop_QNarrowBin16Uto8Ux16:
4011 size = 2;
4012 vec_binop = S390_VEC_PACK_SATURU;
4013 goto Iop_VV_wrk;
4014 case Iop_QNarrowBin16Sto8Sx16:
4015 size = 2;
4016 vec_binop = S390_VEC_PACK_SATURS;
4017 goto Iop_VV_wrk;
4018 case Iop_QNarrowBin32Uto16Ux8:
4019 size = 4;
4020 vec_binop = S390_VEC_PACK_SATURU;
4021 goto Iop_VV_wrk;
4022 case Iop_QNarrowBin32Sto16Sx8:
4023 size = 4;
4024 vec_binop = S390_VEC_PACK_SATURS;
4025 goto Iop_VV_wrk;
4026 case Iop_QNarrowBin64Uto32Ux4:
4027 size = 8;
4028 vec_binop = S390_VEC_PACK_SATURU;
4029 goto Iop_VV_wrk;
4030 case Iop_QNarrowBin64Sto32Sx4:
4031 size = 8;
4032 vec_binop = S390_VEC_PACK_SATURS;
4033 goto Iop_VV_wrk;
4035 case Iop_NarrowBin16to8x16:
4036 size = 2;
4037 vec_binop = S390_VEC_PACK;
4038 goto Iop_VV_wrk;
4039 case Iop_NarrowBin32to16x8:
4040 size = 4;
4041 vec_binop = S390_VEC_PACK;
4042 goto Iop_VV_wrk;
4043 case Iop_NarrowBin64to32x4:
4044 size = 8;
4045 vec_binop = S390_VEC_PACK;
4046 goto Iop_VV_wrk;
4048 case Iop_OrV128:
4049 size = 16;
4050 vec_binop = S390_VEC_OR;
4051 goto Iop_VV_wrk;
4053 case Iop_XorV128:
4054 size = 16;
4055 vec_binop = S390_VEC_XOR;
4056 goto Iop_VV_wrk;
4058 case Iop_AndV128:
4059 size = 16;
4060 vec_binop = S390_VEC_AND;
4061 goto Iop_VV_wrk;
4063 case Iop_InterleaveLO8x16:
4064 size = 1;
4065 vec_binop = S390_VEC_MERGEL;
4066 goto Iop_VV_wrk;
4067 case Iop_InterleaveLO16x8:
4068 size = 2;
4069 vec_binop = S390_VEC_MERGEL;
4070 goto Iop_VV_wrk;
4071 case Iop_InterleaveLO32x4:
4072 size = 4;
4073 vec_binop = S390_VEC_MERGEL;
4074 goto Iop_VV_wrk;
4075 case Iop_InterleaveLO64x2:
4076 size = 8;
4077 vec_binop = S390_VEC_MERGEL;
4078 goto Iop_VV_wrk;
4080 case Iop_InterleaveHI8x16:
4081 size = 1;
4082 vec_binop = S390_VEC_MERGEH;
4083 goto Iop_VV_wrk;
4084 case Iop_InterleaveHI16x8:
4085 size = 2;
4086 vec_binop = S390_VEC_MERGEH;
4087 goto Iop_VV_wrk;
4088 case Iop_InterleaveHI32x4:
4089 size = 4;
4090 vec_binop = S390_VEC_MERGEH;
4091 goto Iop_VV_wrk;
4092 case Iop_InterleaveHI64x2:
4093 size = 8;
4094 vec_binop = S390_VEC_MERGEH;
4095 goto Iop_VV_wrk;
4097 case Iop_InterleaveEvenLanes8x16: {
4098 /* There is no such instruction. We have to emulate it. */
4099 IRExpr* mask = IRExpr_Binop(Iop_64HLtoV128,
4100 mkU64(0x0010021204140616ULL),
4101 mkU64(0x08180a1a0c1c0e1eULL));
4102 HReg reg_mask = s390_isel_vec_expr(env, mask);
4103 reg1 = s390_isel_vec_expr(env, arg1);
4104 reg2 = s390_isel_vec_expr(env, arg2);
4106 addInstr(env,
4107 s390_insn_vec_triop(16, S390_VEC_PERM, dst, reg1, reg2,
4108 reg_mask)
4111 return dst;
4113 case Iop_InterleaveOddLanes8x16: {
4114 /* There is no such instruction. We have to emulate it. */
4115 IRExpr* mask = IRExpr_Binop(Iop_64HLtoV128,
4116 mkU64(0x0111031305150717ULL),
4117 mkU64(0x09190b1b0d1d0f1fULL));
4118 HReg reg_mask = s390_isel_vec_expr(env, mask);
4119 reg1 = s390_isel_vec_expr(env, arg1);
4120 reg2 = s390_isel_vec_expr(env, arg2);
4122 addInstr(env,
4123 s390_insn_vec_triop(16, S390_VEC_PERM, dst, reg1, reg2, reg_mask)
4126 return dst;
4129 case Iop_CmpEQ8x16:
4130 size = 1;
4131 vec_binop = S390_VEC_COMPARE_EQUAL;
4132 goto Iop_VV_wrk;
4133 case Iop_CmpEQ16x8:
4134 size = 2;
4135 vec_binop = S390_VEC_COMPARE_EQUAL;
4136 goto Iop_VV_wrk;
4137 case Iop_CmpEQ32x4:
4138 size = 4;
4139 vec_binop = S390_VEC_COMPARE_EQUAL;
4140 goto Iop_VV_wrk;
4141 case Iop_CmpEQ64x2:
4142 size = 8;
4143 vec_binop = S390_VEC_COMPARE_EQUAL;
4144 goto Iop_VV_wrk;
4146 case Iop_Add8x16:
4147 size = 1;
4148 vec_binop = S390_VEC_INT_ADD;
4149 goto Iop_VV_wrk;
4150 case Iop_Add16x8:
4151 size = 2;
4152 vec_binop = S390_VEC_INT_ADD;
4153 goto Iop_VV_wrk;
4154 case Iop_Add32x4:
4155 size = 4;
4156 vec_binop = S390_VEC_INT_ADD;
4157 goto Iop_VV_wrk;
4158 case Iop_Add64x2:
4159 size = 8;
4160 vec_binop = S390_VEC_INT_ADD;
4161 goto Iop_VV_wrk;
4162 case Iop_Add128x1:
4163 size = 16;
4164 vec_binop = S390_VEC_INT_ADD;
4165 goto Iop_VV_wrk;
4167 case Iop_Sub8x16:
4168 size = 1;
4169 vec_binop = S390_VEC_INT_SUB;
4170 goto Iop_VV_wrk;
4171 case Iop_Sub16x8:
4172 size = 2;
4173 vec_binop = S390_VEC_INT_SUB;
4174 goto Iop_VV_wrk;
4175 case Iop_Sub32x4:
4176 size = 4;
4177 vec_binop = S390_VEC_INT_SUB;
4178 goto Iop_VV_wrk;
4179 case Iop_Sub64x2:
4180 size = 8;
4181 vec_binop = S390_VEC_INT_SUB;
4182 goto Iop_VV_wrk;
4183 case Iop_Sub128x1:
4184 size = 16;
4185 vec_binop = S390_VEC_INT_SUB;
4186 goto Iop_VV_wrk;
4188 case Iop_Max8Ux16:
4189 size = 1;
4190 vec_binop = S390_VEC_MAXU;
4191 goto Iop_VV_wrk;
4192 case Iop_Max8Sx16:
4193 size = 1;
4194 vec_binop = S390_VEC_MAXS;
4195 goto Iop_VV_wrk;
4196 case Iop_Max16Ux8:
4197 size = 2;
4198 vec_binop = S390_VEC_MAXU;
4199 goto Iop_VV_wrk;
4200 case Iop_Max16Sx8:
4201 size = 2;
4202 vec_binop = S390_VEC_MAXS;
4203 goto Iop_VV_wrk;
4204 case Iop_Max32Ux4:
4205 size = 4;
4206 vec_binop = S390_VEC_MAXU;
4207 goto Iop_VV_wrk;
4208 case Iop_Max32Sx4:
4209 size = 4;
4210 vec_binop = S390_VEC_MAXS;
4211 goto Iop_VV_wrk;
4212 case Iop_Max64Ux2:
4213 size = 8;
4214 vec_binop = S390_VEC_MAXU;
4215 goto Iop_VV_wrk;
4216 case Iop_Max64Sx2:
4217 size = 8;
4218 vec_binop = S390_VEC_MAXS;
4219 goto Iop_VV_wrk;
4221 case Iop_Min8Ux16:
4222 size = 1;
4223 vec_binop = S390_VEC_MINU;
4224 goto Iop_VV_wrk;
4225 case Iop_Min8Sx16:
4226 size = 1;
4227 vec_binop = S390_VEC_MINS;
4228 goto Iop_VV_wrk;
4229 case Iop_Min16Ux8:
4230 size = 2;
4231 vec_binop = S390_VEC_MINU;
4232 goto Iop_VV_wrk;
4233 case Iop_Min16Sx8:
4234 size = 2;
4235 vec_binop = S390_VEC_MINS;
4236 goto Iop_VV_wrk;
4237 case Iop_Min32Ux4:
4238 size = 4;
4239 vec_binop = S390_VEC_MINU;
4240 goto Iop_VV_wrk;
4241 case Iop_Min32Sx4:
4242 size = 4;
4243 vec_binop = S390_VEC_MINS;
4244 goto Iop_VV_wrk;
4245 case Iop_Min64Ux2:
4246 size = 8;
4247 vec_binop = S390_VEC_MINU;
4248 goto Iop_VV_wrk;
4249 case Iop_Min64Sx2:
4250 size = 8;
4251 vec_binop = S390_VEC_MINS;
4252 goto Iop_VV_wrk;
4254 case Iop_Avg8Ux16:
4255 size = 1;
4256 vec_binop = S390_VEC_AVGU;
4257 goto Iop_VV_wrk;
4258 case Iop_Avg8Sx16:
4259 size = 1;
4260 vec_binop = S390_VEC_AVGS;
4261 goto Iop_VV_wrk;
4262 case Iop_Avg16Ux8:
4263 size = 2;
4264 vec_binop = S390_VEC_AVGU;
4265 goto Iop_VV_wrk;
4266 case Iop_Avg16Sx8:
4267 size = 2;
4268 vec_binop = S390_VEC_AVGS;
4269 goto Iop_VV_wrk;
4270 case Iop_Avg32Ux4:
4271 size = 4;
4272 vec_binop = S390_VEC_AVGU;
4273 goto Iop_VV_wrk;
4274 case Iop_Avg32Sx4:
4275 size = 4;
4276 vec_binop = S390_VEC_AVGS;
4277 goto Iop_VV_wrk;
4278 case Iop_Avg64Ux2:
4279 size = 8;
4280 vec_binop = S390_VEC_AVGU;
4281 goto Iop_VV_wrk;
4282 case Iop_Avg64Sx2:
4283 size = 8;
4284 vec_binop = S390_VEC_AVGS;
4285 goto Iop_VV_wrk;
4287 case Iop_CmpGT8Ux16:
4288 size = 1;
4289 vec_binop = S390_VEC_COMPARE_GREATERU;
4290 goto Iop_VV_wrk;
4291 case Iop_CmpGT8Sx16:
4292 size = 1;
4293 vec_binop = S390_VEC_COMPARE_GREATERS;
4294 goto Iop_VV_wrk;
4295 case Iop_CmpGT16Ux8:
4296 size = 2;
4297 vec_binop = S390_VEC_COMPARE_GREATERU;
4298 goto Iop_VV_wrk;
4299 case Iop_CmpGT16Sx8:
4300 size = 2;
4301 vec_binop = S390_VEC_COMPARE_GREATERS;
4302 goto Iop_VV_wrk;
4303 case Iop_CmpGT32Ux4:
4304 size = 4;
4305 vec_binop = S390_VEC_COMPARE_GREATERU;
4306 goto Iop_VV_wrk;
4307 case Iop_CmpGT32Sx4:
4308 size = 4;
4309 vec_binop = S390_VEC_COMPARE_GREATERS;
4310 goto Iop_VV_wrk;
4311 case Iop_CmpGT64Ux2:
4312 size = 8;
4313 vec_binop = S390_VEC_COMPARE_GREATERU;
4314 goto Iop_VV_wrk;
4315 case Iop_CmpGT64Sx2:
4316 size = 8;
4317 vec_binop = S390_VEC_COMPARE_GREATERS;
4318 goto Iop_VV_wrk;
4320 case Iop_MulHi8Ux16:
4321 size = 1;
4322 vec_binop = S390_VEC_INT_MUL_HIGHU;
4323 goto Iop_VV_wrk;
4324 case Iop_MulHi8Sx16:
4325 size = 1;
4326 vec_binop = S390_VEC_INT_MUL_HIGHS;
4327 goto Iop_VV_wrk;
4328 case Iop_MulHi16Ux8:
4329 size = 2;
4330 vec_binop = S390_VEC_INT_MUL_HIGHU;
4331 goto Iop_VV_wrk;
4332 case Iop_MulHi16Sx8:
4333 size = 2;
4334 vec_binop = S390_VEC_INT_MUL_HIGHS;
4335 goto Iop_VV_wrk;
4336 case Iop_MulHi32Ux4:
4337 size = 4;
4338 vec_binop = S390_VEC_INT_MUL_HIGHU;
4339 goto Iop_VV_wrk;
4340 case Iop_MulHi32Sx4:
4341 size = 4;
4342 vec_binop = S390_VEC_INT_MUL_HIGHS;
4343 goto Iop_VV_wrk;
4345 case Iop_Mul8x16:
4346 size = 1;
4347 vec_binop = S390_VEC_INT_MUL_LOW;
4348 goto Iop_VV_wrk;
4349 case Iop_Mul16x8:
4350 size = 2;
4351 vec_binop = S390_VEC_INT_MUL_LOW;
4352 goto Iop_VV_wrk;
4353 case Iop_Mul32x4:
4354 size = 4;
4355 vec_binop = S390_VEC_INT_MUL_LOW;
4356 goto Iop_VV_wrk;
4358 case Iop_MullEven8Sx16:
4359 size = 1;
4360 vec_binop = S390_VEC_INT_MUL_EVENS;
4361 goto Iop_VV_wrk;
4362 case Iop_MullEven8Ux16:
4363 size = 1;
4364 vec_binop = S390_VEC_INT_MUL_EVENU;
4365 goto Iop_VV_wrk;
4366 case Iop_MullEven16Sx8:
4367 size = 2;
4368 vec_binop = S390_VEC_INT_MUL_EVENS;
4369 goto Iop_VV_wrk;
4370 case Iop_MullEven16Ux8:
4371 size = 2;
4372 vec_binop = S390_VEC_INT_MUL_EVENU;
4373 goto Iop_VV_wrk;
4374 case Iop_MullEven32Sx4:
4375 size = 4;
4376 vec_binop = S390_VEC_INT_MUL_EVENS;
4377 goto Iop_VV_wrk;
4378 case Iop_MullEven32Ux4:
4379 size = 4;
4380 vec_binop = S390_VEC_INT_MUL_EVENU;
4381 goto Iop_VV_wrk;
4383 case Iop_Shl8x16:
4384 size = 1;
4385 vec_binop = S390_VEC_ELEM_SHL_V;
4386 goto Iop_VV_wrk;
4387 case Iop_Shl16x8:
4388 size = 2;
4389 vec_binop = S390_VEC_ELEM_SHL_V;
4390 goto Iop_VV_wrk;
4391 case Iop_Shl32x4:
4392 size = 4;
4393 vec_binop = S390_VEC_ELEM_SHL_V;
4394 goto Iop_VV_wrk;
4395 case Iop_Shl64x2:
4396 size = 8;
4397 vec_binop = S390_VEC_ELEM_SHL_V;
4398 goto Iop_VV_wrk;
4400 case Iop_Shr8x16:
4401 size = 1;
4402 vec_binop = S390_VEC_ELEM_SHRL_V;
4403 goto Iop_VV_wrk;
4404 case Iop_Shr16x8:
4405 size = 2;
4406 vec_binop = S390_VEC_ELEM_SHRL_V;
4407 goto Iop_VV_wrk;
4408 case Iop_Shr32x4:
4409 size = 4;
4410 vec_binop = S390_VEC_ELEM_SHRL_V;
4411 goto Iop_VV_wrk;
4412 case Iop_Shr64x2:
4413 size = 8;
4414 vec_binop = S390_VEC_ELEM_SHRL_V;
4415 goto Iop_VV_wrk;
4417 case Iop_Sar8x16:
4418 size = 1;
4419 vec_binop = S390_VEC_ELEM_SHRA_V;
4420 goto Iop_VV_wrk;
4421 case Iop_Sar16x8:
4422 size = 2;
4423 vec_binop = S390_VEC_ELEM_SHRA_V;
4424 goto Iop_VV_wrk;
4425 case Iop_Sar32x4:
4426 size = 4;
4427 vec_binop = S390_VEC_ELEM_SHRA_V;
4428 goto Iop_VV_wrk;
4429 case Iop_Sar64x2:
4430 size = 8;
4431 vec_binop = S390_VEC_ELEM_SHRA_V;
4432 goto Iop_VV_wrk;
4434 case Iop_Rol8x16:
4435 size = 1;
4436 vec_binop = S390_VEC_ELEM_ROLL_V;
4437 goto Iop_VV_wrk;
4438 case Iop_Rol16x8:
4439 size = 2;
4440 vec_binop = S390_VEC_ELEM_ROLL_V;
4441 goto Iop_VV_wrk;
4442 case Iop_Rol32x4:
4443 size = 4;
4444 vec_binop = S390_VEC_ELEM_ROLL_V;
4445 goto Iop_VV_wrk;
4446 case Iop_Rol64x2:
4447 size = 8;
4448 vec_binop = S390_VEC_ELEM_ROLL_V;
4449 goto Iop_VV_wrk;
4451 case Iop_CmpEQ64Fx2:
4452 size = 8;
4453 vec_binop = S390_VEC_FLOAT_COMPARE_EQUAL;
4454 goto Iop_VV_wrk;
4456 case Iop_CmpLE64Fx2: {
4457 size = 8;
4458 vec_binop = S390_VEC_FLOAT_COMPARE_LESS_OR_EQUAL;
4459 goto Iop_VV_wrk;
4462 case Iop_CmpLT64Fx2: {
4463 size = 8;
4464 vec_binop = S390_VEC_FLOAT_COMPARE_LESS;
4465 goto Iop_VV_wrk;
4468 case Iop_Sqrt64Fx2:
4469 size = 8;
4470 vec_unop = S390_VEC_FLOAT_SQRT;
4471 goto Iop_irrm_V_wrk;
4473 case Iop_ShlN8x16:
4474 size = 1;
4475 shift_op = S390_VEC_ELEM_SHL_INT;
4476 goto Iop_ShiftN_wrk;
4477 case Iop_ShlN16x8:
4478 size = 2;
4479 shift_op = S390_VEC_ELEM_SHL_INT;
4480 goto Iop_ShiftN_wrk;
4481 case Iop_ShlN32x4:
4482 size = 4;
4483 shift_op = S390_VEC_ELEM_SHL_INT;
4484 goto Iop_ShiftN_wrk;
4485 case Iop_ShlN64x2:
4486 size = 8;
4487 shift_op = S390_VEC_ELEM_SHL_INT;
4488 goto Iop_ShiftN_wrk;
4490 case Iop_ShrN8x16:
4491 size = 1;
4492 shift_op = S390_VEC_ELEM_SHRL_INT;
4493 goto Iop_ShiftN_wrk;
4494 case Iop_ShrN16x8:
4495 size = 2;
4496 shift_op = S390_VEC_ELEM_SHRL_INT;
4497 goto Iop_ShiftN_wrk;
4498 case Iop_ShrN32x4:
4499 size = 4;
4500 shift_op = S390_VEC_ELEM_SHRL_INT;
4501 goto Iop_ShiftN_wrk;
4502 case Iop_ShrN64x2:
4503 size = 8;
4504 shift_op = S390_VEC_ELEM_SHRL_INT;
4505 goto Iop_ShiftN_wrk;
4507 case Iop_SarN8x16:
4508 size = 1;
4509 shift_op = S390_VEC_ELEM_SHRA_INT;
4510 goto Iop_ShiftN_wrk;
4511 case Iop_SarN16x8:
4512 size = 2;
4513 shift_op = S390_VEC_ELEM_SHRA_INT;
4514 goto Iop_ShiftN_wrk;
4515 case Iop_SarN32x4:
4516 size = 4;
4517 shift_op = S390_VEC_ELEM_SHRA_INT;
4518 goto Iop_ShiftN_wrk;
4519 case Iop_SarN64x2:
4520 size = 8;
4521 shift_op = S390_VEC_ELEM_SHRA_INT;
4522 goto Iop_ShiftN_wrk;
4524 Iop_ShiftN_wrk: {
4525 HReg vec = s390_isel_vec_expr(env, arg1);
4526 s390_amode* number = s390_isel_amode(env,IRExpr_Unop(Iop_8Uto64, arg2));
4528 addInstr(env,
4529 s390_insn_vec_amodeop(size, shift_op, dst, vec, number));
4531 return dst;
4534 case Iop_ShlV128:
4535 vec_binop = S390_VEC_SHL_BITS;
4536 goto Iop_ShiftVV_wrk;
4537 case Iop_ShrV128:
4538 vec_binop = S390_VEC_SHRL_BITS;
4539 goto Iop_ShiftVV_wrk;
4540 case Iop_SarV128:
4541 vec_binop = S390_VEC_SHRA_BITS;
4542 goto Iop_ShiftVV_wrk;
4544 Iop_ShiftVV_wrk: {
4545 vassert(vec_binop != S390_VEC_BINOP_T_INVALID);
4546 reg1 = s390_isel_vec_expr(env, arg1);
4547 reg2 = s390_isel_vec_expr(env, IRExpr_Unop(Iop_Dup8x16, arg2));
4549 /* Handle special case */
4550 if (vec_is_bytes_only_shift(arg2))
4552 /* In this case we skip the BITS shift step. */
4553 addInstr(env, s390_insn_vec_binop(16, (vec_binop + 1),
4554 dst, reg1, reg2));
4556 return dst;
4559 /* General case (BYTES shift & BITS shift) */
4560 addInstr(env, s390_insn_vec_binop(16, (vec_binop + 1),
4561 dst, reg1, reg2));
4563 addInstr(env, s390_insn_vec_binop(16, vec_binop,
4564 dst, dst, reg2));
4566 return dst;
4569 Iop_VV_wrk: {
4570 vassert(vec_binop != S390_VEC_BINOP_T_INVALID);
4571 reg1 = s390_isel_vec_expr(env, arg1);
4572 reg2 = s390_isel_vec_expr(env, arg2);
4574 addInstr(env, s390_insn_vec_binop(size, vec_binop,
4575 dst, reg1, reg2));
4577 return dst;
4580 Iop_irrm_V_wrk: {
4581 vassert(vec_unop != S390_UNOP_T_INVALID);
4582 set_bfp_rounding_mode_in_fpc(env, arg1);
4583 reg1 = s390_isel_vec_expr(env, arg2);
4585 addInstr(env, s390_insn_unop(size, vec_unop, dst, s390_opnd_reg(reg1)));
4586 return dst;
4589 case Iop_64HLtoV128:
4590 reg1 = s390_isel_int_expr(env, arg1);
4591 reg2 = s390_isel_int_expr(env, arg2);
4593 addInstr(env, s390_insn_vec_binop(size, S390_VEC_INIT_FROM_GPRS,
4594 dst, reg1, reg2));
4596 return dst;
4598 default:
4599 goto irreducible;
4603 /* --------- TERNARY OP --------- */
4604 case Iex_Triop: {
4605 HReg dst = newVRegV(env);
4606 s390_amode* amode2 = NULL;
4607 HReg reg1 = INVALID_HREG, reg2 = INVALID_HREG, reg3 = INVALID_HREG;
4608 IROp op = expr->Iex.Triop.details->op;
4609 IRExpr* arg1 = expr->Iex.Triop.details->arg1;
4610 IRExpr* arg2 = expr->Iex.Triop.details->arg2;
4611 IRExpr* arg3 = expr->Iex.Triop.details->arg3;
4612 s390_vec_binop_t vec_binop = S390_VEC_BINOP_T_INVALID;
4613 switch (op) {
4614 case Iop_SetElem8x16:
4615 size = 1;
4616 goto Iop_SetElem_wrk;
4617 case Iop_SetElem16x8:
4618 size = 2;
4619 goto Iop_SetElem_wrk;
4620 case Iop_SetElem32x4:
4621 size = 4;
4622 goto Iop_SetElem_wrk;
4623 case Iop_SetElem64x2: {
4624 size = 8;
4626 Iop_SetElem_wrk:{
4627 reg1 = s390_isel_vec_expr(env, arg1);
4628 amode2 = s390_isel_amode(env, IRExpr_Unop(Iop_8Uto64, arg2));
4629 reg3 = s390_isel_int_expr(env, arg3);
4631 addInstr(env, s390_insn_move(16, dst, reg1));
4632 addInstr(env, s390_insn_vec_amodeintop(size, S390_VEC_SET_ELEM,
4633 dst, amode2, reg3));
4634 return dst;
4638 case Iop_Perm8x16x2:
4639 size = 16;
4640 reg1 = s390_isel_vec_expr(env, arg1);
4641 reg2 = s390_isel_vec_expr(env, arg2);
4642 reg3 = s390_isel_vec_expr(env, arg3);
4644 addInstr(env, s390_insn_vec_triop(size, S390_VEC_PERM,
4645 dst, reg1, reg2, reg3));
4646 return dst;
4648 case Iop_Add64Fx2:
4649 size = 8;
4650 vec_binop = S390_VEC_FLOAT_ADD;
4651 goto Iop_irrm_VV_wrk;
4653 case Iop_Sub64Fx2:
4654 size = 8;
4655 vec_binop = S390_VEC_FLOAT_SUB;
4656 goto Iop_irrm_VV_wrk;
4658 case Iop_Mul64Fx2:
4659 size = 8;
4660 vec_binop = S390_VEC_FLOAT_MUL;
4661 goto Iop_irrm_VV_wrk;
4662 case Iop_Div64Fx2:
4663 size = 8;
4664 vec_binop = S390_VEC_FLOAT_DIV;
4665 goto Iop_irrm_VV_wrk;
4667 Iop_irrm_VV_wrk: {
4668 vassert(vec_binop != S390_VEC_BINOP_T_INVALID);
4669 set_bfp_rounding_mode_in_fpc(env, arg1);
4670 reg1 = s390_isel_vec_expr(env, arg2);
4671 reg2 = s390_isel_vec_expr(env, arg3);
4673 addInstr(env, s390_insn_vec_binop(size, vec_binop,
4674 dst, reg1, reg2));
4676 return dst;
4679 default:
4680 goto irreducible;
4684 default:
4685 goto irreducible;
4688 /* We get here if no pattern matched. */
4689 irreducible:
4690 ppIRExpr(expr);
4691 vpanic("s390_isel_vec_expr: cannot reduce tree");
4694 static HReg
4695 s390_isel_vec_expr(ISelEnv *env, IRExpr *expr)
4697 HReg dst = s390_isel_vec_expr_wrk(env, expr);
4699 /* Sanity checks ... */
4700 vassert(hregClass(dst) == HRcVec128);
4701 vassert(hregIsVirtual(dst));
4703 return dst;
4707 /*---------------------------------------------------------*/
4708 /*--- ISEL: Statements ---*/
4709 /*---------------------------------------------------------*/
4711 static void
4712 s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
4714 if (vex_traceflags & VEX_TRACE_VCODE) {
4715 vex_printf("\n -- ");
4716 ppIRStmt(stmt);
4717 vex_printf("\n");
4720 switch (stmt->tag) {
4722 /* --------- STORE --------- */
4723 case Ist_Store: {
4724 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
4725 s390_amode *am;
4726 HReg src;
4728 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
4730 am = s390_isel_amode(env, stmt->Ist.Store.addr);
4732 switch (tyd) {
4733 case Ity_I8:
4734 case Ity_I16:
4735 case Ity_I32:
4736 case Ity_I64:
4737 /* fixs390: We could check for INSN_MADD here. */
4738 if (am->tag == S390_AMODE_B12 &&
4739 stmt->Ist.Store.data->tag == Iex_Const) {
4740 ULong value =
4741 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
4742 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
4743 return;
4745 /* Check whether we can use a memcpy here. Currently, the restriction
4746 is that both amodes need to be B12, so MVC can be emitted.
4747 We do not consider a store whose data expression is a load because
4748 we don't want to deal with overlapping locations. */
4749 /* store(get) never overlaps*/
4750 if (am->tag == S390_AMODE_B12 &&
4751 stmt->Ist.Store.data->tag == Iex_Get) {
4752 UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
4753 s390_amode *from = s390_amode_for_guest_state(offset);
4754 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
4755 return;
4757 /* General case: compile data into a register */
4758 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
4759 break;
4761 case Ity_F32:
4762 case Ity_F64:
4763 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
4764 break;
4766 case Ity_D32:
4767 case Ity_D64:
4768 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
4769 break;
4771 case Ity_F128:
4772 case Ity_D128:
4773 /* Cannot occur. No such instruction */
4774 vpanic("Ist_Store with 128-bit floating point data");
4776 case Ity_V128:
4777 src = s390_isel_vec_expr(env, stmt->Ist.Store.data);
4778 break;
4779 default:
4780 goto stmt_fail;
4783 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
4784 return;
4787 /* --------- PUT --------- */
4788 case Ist_Put: {
4789 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
4790 HReg src;
4791 s390_amode *am;
4792 ULong new_value, old_value, difference;
4794 /* Detect updates to certain guest registers. We track the contents
4795 of those registers as long as they contain constants. If the new
4796 constant is either zero or in the 8-bit neighbourhood of the
4797 current value we can use a memory-to-memory insn to do the update. */
4799 Int offset = stmt->Ist.Put.offset;
4801 /* Check necessary conditions:
4802 (1) must be one of the registers we care about
4803 (2) assigned value must be a constant */
4804 Int guest_reg = get_guest_reg(offset);
4806 if (guest_reg == GUEST_UNKNOWN) goto not_special;
4808 if (stmt->Ist.Put.data->tag != Iex_Const) {
4809 /* Invalidate guest register contents */
4810 env->old_value_valid[guest_reg] = False;
4811 goto not_special;
4814 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
4815 if (tyd != Ity_I64)
4816 goto not_special;
4818 /* OK. Necessary conditions are satisfied. */
4820 old_value = env->old_value[guest_reg];
4821 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
4822 env->old_value[guest_reg] = new_value;
4824 Bool old_value_is_valid = env->old_value_valid[guest_reg];
4825 env->old_value_valid[guest_reg] = True;
4827 /* If the register already contains the new value, there is nothing
4828 to do here. */
4829 if (old_value_is_valid && new_value == old_value) {
4830 return;
4833 if (old_value_is_valid == False) goto not_special;
4835 /* If the new value is in the neighbourhood of the old value
4836 we can use a memory-to-memory insn */
4837 difference = new_value - old_value;
4839 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
4840 am = s390_amode_for_guest_state(offset);
4841 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
4842 (difference & 0xFF), new_value));
4843 return;
4846 /* If the high word is the same it is sufficient to load the low word. */
4847 if ((old_value >> 32) == (new_value >> 32)) {
4848 am = s390_amode_for_guest_state(offset + 4);
4849 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
4850 return;
4853 /* No special case applies... fall through */
4855 not_special:
4856 am = s390_amode_for_guest_state(offset);
4858 switch (tyd) {
4859 case Ity_I8:
4860 case Ity_I16:
4861 case Ity_I32:
4862 case Ity_I64:
4863 if (am->tag == S390_AMODE_B12 &&
4864 stmt->Ist.Put.data->tag == Iex_Const) {
4865 ULong value =
4866 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
4867 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
4868 return;
4870 /* Check whether we can use a memcpy here. Currently, the restriction
4871 is that both amodes need to be B12, so MVC can be emitted. */
4872 /* put(load) never overlaps */
4873 if (am->tag == S390_AMODE_B12 &&
4874 stmt->Ist.Put.data->tag == Iex_Load) {
4875 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
4876 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
4877 s390_amode *from = s390_isel_amode(env, data);
4878 UInt size = sizeofIRType(tyd);
4880 if (from->tag == S390_AMODE_B12) {
4881 /* Source can be compiled into a B12 amode. */
4882 addInstr(env, s390_insn_memcpy(size, am, from));
4883 return;
4886 src = newVRegI(env);
4887 addInstr(env, s390_insn_load(size, src, from));
4888 break;
4890 /* put(get) */
4891 if (am->tag == S390_AMODE_B12 &&
4892 stmt->Ist.Put.data->tag == Iex_Get) {
4893 UInt put_offset = am->d;
4894 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
4895 UInt size = sizeofIRType(tyd);
4896 /* don't memcpy in case of overlap */
4897 if (put_offset + size <= get_offset ||
4898 get_offset + size <= put_offset) {
4899 s390_amode *from = s390_amode_for_guest_state(get_offset);
4900 addInstr(env, s390_insn_memcpy(size, am, from));
4901 return;
4903 goto no_memcpy_put;
4905 /* General case: compile data into a register */
4906 no_memcpy_put:
4907 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
4908 break;
4910 case Ity_F32:
4911 case Ity_F64:
4912 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
4913 break;
4915 case Ity_F128:
4916 case Ity_D128:
4917 /* Does not occur. See function put_(f|d)pr_pair. */
4918 vpanic("Ist_Put with 128-bit floating point data");
4920 case Ity_D32:
4921 case Ity_D64:
4922 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
4923 break;
4925 case Ity_V128:
4926 src = s390_isel_vec_expr(env, stmt->Ist.Put.data);
4927 break;
4928 default:
4929 goto stmt_fail;
4932 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
4933 return;
4936 /* --------- TMP --------- */
4937 case Ist_WrTmp: {
4938 IRTemp tmp = stmt->Ist.WrTmp.tmp;
4939 IRType tyd = typeOfIRTemp(env->type_env, tmp);
4940 HReg src, dst;
4942 switch (tyd) {
4943 case Ity_I128: {
4944 HReg dst_hi, dst_lo, res_hi, res_lo;
4946 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
4947 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
4949 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
4950 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
4951 return;
4954 case Ity_I8:
4955 case Ity_I16:
4956 case Ity_I32:
4957 case Ity_I64:
4958 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
4959 dst = lookupIRTemp(env, tmp);
4960 break;
4962 case Ity_I1: {
4963 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
4964 dst = lookupIRTemp(env, tmp);
4965 addInstr(env, s390_insn_cc2bool(dst, cond));
4966 return;
4969 case Ity_F32:
4970 case Ity_F64:
4971 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
4972 dst = lookupIRTemp(env, tmp);
4973 break;
4975 case Ity_F128: {
4976 HReg dst_hi, dst_lo, res_hi, res_lo;
4978 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
4979 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
4981 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
4982 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
4983 return;
4986 case Ity_D32:
4987 case Ity_D64:
4988 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
4989 dst = lookupIRTemp(env, tmp);
4990 break;
4992 case Ity_D128: {
4993 HReg dst_hi, dst_lo, res_hi, res_lo;
4995 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
4996 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
4998 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
4999 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
5000 return;
5003 case Ity_V128:
5004 src = s390_isel_vec_expr(env, stmt->Ist.WrTmp.data);
5005 dst = lookupIRTemp(env, tmp);
5006 break;
5008 default:
5009 goto stmt_fail;
5012 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
5013 return;
5016 /* --------- Call to DIRTY helper --------- */
5017 case Ist_Dirty: {
5018 IRType retty;
5019 IRDirty* d = stmt->Ist.Dirty.details;
5020 HReg dst;
5021 RetLoc rloc = mk_RetLoc_INVALID();
5022 UInt addToSp = 0;
5023 Int i;
5025 /* Invalidate tracked values of those guest state registers that are
5026 modified by this helper. */
5027 for (i = 0; i < d->nFxState; ++i) {
5028 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
5029 descriptors in guest state effect descriptions. Hence: */
5030 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
5031 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
5032 Int guest_reg = get_guest_reg(d->fxState[i].offset);
5033 if (guest_reg != GUEST_UNKNOWN)
5034 env->old_value_valid[guest_reg] = False;
5038 if (d->tmp == IRTemp_INVALID) {
5039 /* No return value. */
5040 retty = Ity_INVALID;
5041 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
5042 d->args);
5043 vassert(is_sane_RetLoc(rloc));
5044 vassert(rloc.pri == RLPri_None);
5045 vassert(addToSp == 0);
5047 return;
5050 retty = typeOfIRTemp(env->type_env, d->tmp);
5051 if (retty == Ity_I64 || retty == Ity_I32
5052 || retty == Ity_I16 || retty == Ity_I8 || retty == Ity_V128) {
5053 /* Move the returned value to the destination register */
5054 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
5056 dst = lookupIRTemp(env, d->tmp);
5057 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
5058 d->args);
5059 vassert(is_sane_RetLoc(rloc));
5061 switch(retty)
5063 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
5064 vassert(rloc.pri == RLPri_Int);
5065 vassert(addToSp == 0);
5066 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
5067 break;
5068 case Ity_V128:
5069 /* The returned value is on the stack, and rloc.spOff
5070 tells us where. Fish it off the stack and then move
5071 the stack pointer upwards to clear it, as directed by
5072 doHelperCall. */
5073 vassert(rloc.pri == RLPri_V128SpRel);
5074 vassert(addToSp == sizeof(V128));
5075 s390_amode* am = s390_amode_b12(rloc.spOff, s390_hreg_stack_pointer());
5076 addInstr(env, s390_insn_load(sizeof(V128), dst, am));
5077 add_to_SP(env, addToSp);
5078 break;
5079 default:
5080 vpanic("s390_isel_stmt: invalid return type from dirty helper");
5082 return;
5084 break;
5087 case Ist_CAS:
5088 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
5089 IRCAS *cas = stmt->Ist.CAS.details;
5090 s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr);
5091 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
5092 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
5093 HReg old = lookupIRTemp(env, cas->oldLo);
5095 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
5096 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
5097 } else {
5098 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
5100 return;
5101 } else {
5102 IRCAS *cas = stmt->Ist.CAS.details;
5103 s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr);
5104 HReg r8, r9, r10, r11, r1;
5105 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
5106 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
5107 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
5108 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
5109 HReg old_low = lookupIRTemp(env, cas->oldLo);
5110 HReg old_high = lookupIRTemp(env, cas->oldHi);
5112 /* Use non-virtual registers r8 and r9 as pair for op1
5113 and move op1 there */
5114 r8 = make_gpr(8);
5115 r9 = make_gpr(9);
5116 addInstr(env, s390_insn_move(8, r8, op1_high));
5117 addInstr(env, s390_insn_move(8, r9, op1_low));
5119 /* Use non-virtual registers r10 and r11 as pair for op3
5120 and move op3 there */
5121 r10 = make_gpr(10);
5122 r11 = make_gpr(11);
5123 addInstr(env, s390_insn_move(8, r10, op3_high));
5124 addInstr(env, s390_insn_move(8, r11, op3_low));
5126 /* Register r1 is used as a scratch register */
5127 r1 = make_gpr(1);
5129 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
5130 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
5131 old_high, old_low, r1));
5132 } else {
5133 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
5134 old_high, old_low, r1));
5136 addInstr(env, s390_insn_move(8, op1_high, r8));
5137 addInstr(env, s390_insn_move(8, op1_low, r9));
5138 addInstr(env, s390_insn_move(8, op3_high, r10));
5139 addInstr(env, s390_insn_move(8, op3_low, r11));
5140 return;
5142 break;
5144 /* --------- EXIT --------- */
5145 case Ist_Exit: {
5146 s390_cc_t cond;
5147 IRConstTag tag = stmt->Ist.Exit.dst->tag;
5149 if (tag != Ico_U64)
5150 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
5152 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
5153 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
5155 /* Case: boring transfer to known address */
5156 if (stmt->Ist.Exit.jk == Ijk_Boring) {
5157 if (env->chaining_allowed) {
5158 /* .. almost always true .. */
5159 /* Skip the event check at the dst if this is a forwards
5160 edge. */
5161 Bool to_fast_entry
5162 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
5163 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
5164 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
5165 guest_IA, to_fast_entry));
5166 } else {
5167 /* .. very occasionally .. */
5168 /* We can't use chaining, so ask for an assisted transfer,
5169 as that's the only alternative that is allowable. */
5170 HReg dst = s390_isel_int_expr(env,
5171 IRExpr_Const(stmt->Ist.Exit.dst));
5172 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
5174 return;
5177 /* Case: assisted transfer to arbitrary address */
5178 switch (stmt->Ist.Exit.jk) {
5179 case Ijk_EmFail:
5180 case Ijk_EmWarn:
5181 case Ijk_NoDecode:
5182 case Ijk_InvalICache:
5183 case Ijk_Sys_syscall:
5184 case Ijk_ClientReq:
5185 case Ijk_NoRedir:
5186 case Ijk_Yield:
5187 case Ijk_SigTRAP:
5188 case Ijk_SigFPE: {
5189 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
5190 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
5191 stmt->Ist.Exit.jk));
5192 return;
5194 default:
5195 break;
5198 /* Do we ever expect to see any other kind? */
5199 goto stmt_fail;
5202 /* --------- MEM FENCE --------- */
5203 case Ist_MBE:
5204 switch (stmt->Ist.MBE.event) {
5205 case Imbe_Fence:
5206 addInstr(env, s390_insn_mfence());
5207 return;
5208 default:
5209 break;
5211 break;
5213 /* --------- Miscellaneous --------- */
5215 case Ist_PutI: /* Not needed */
5216 case Ist_IMark: /* Doesn't generate any executable code */
5217 case Ist_NoOp: /* Doesn't generate any executable code */
5218 case Ist_AbiHint: /* Meaningless in IR */
5219 return;
5221 default:
5222 break;
5225 stmt_fail:
5226 ppIRStmt(stmt);
5227 vpanic("s390_isel_stmt");
5231 /*---------------------------------------------------------*/
5232 /*--- ISEL: Basic block terminators (Nexts) ---*/
5233 /*---------------------------------------------------------*/
5235 static void
5236 iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
5238 if (vex_traceflags & VEX_TRACE_VCODE) {
5239 vex_printf("\n-- PUT(%d) = ", offsIP);
5240 ppIRExpr(next);
5241 vex_printf("; exit-");
5242 ppIRJumpKind(jk);
5243 vex_printf("\n");
5246 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
5248 /* Case: boring transfer to known address */
5249 if (next->tag == Iex_Const) {
5250 IRConst *cdst = next->Iex.Const.con;
5251 vassert(cdst->tag == Ico_U64);
5252 if (jk == Ijk_Boring || jk == Ijk_Call) {
5253 /* Boring transfer to known address */
5254 if (env->chaining_allowed) {
5255 /* .. almost always true .. */
5256 /* Skip the event check at the dst if this is a forwards
5257 edge. */
5258 Bool to_fast_entry
5259 = ((Addr64)cdst->Ico.U64) > env->max_ga;
5260 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
5261 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
5262 guest_IA, to_fast_entry));
5263 } else {
5264 /* .. very occasionally .. */
5265 /* We can't use chaining, so ask for an indirect transfer,
5266 as that's the cheapest alternative that is allowable. */
5267 HReg dst = s390_isel_int_expr(env, next);
5268 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
5269 Ijk_Boring));
5271 return;
5275 /* Case: call/return (==boring) transfer to any address */
5276 switch (jk) {
5277 case Ijk_Boring:
5278 case Ijk_Ret:
5279 case Ijk_Call: {
5280 HReg dst = s390_isel_int_expr(env, next);
5281 if (env->chaining_allowed) {
5282 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
5283 } else {
5284 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
5285 Ijk_Boring));
5287 return;
5289 default:
5290 break;
5293 /* Case: some other kind of transfer to any address */
5294 switch (jk) {
5295 case Ijk_EmFail:
5296 case Ijk_EmWarn:
5297 case Ijk_NoDecode:
5298 case Ijk_InvalICache:
5299 case Ijk_Sys_syscall:
5300 case Ijk_ClientReq:
5301 case Ijk_NoRedir:
5302 case Ijk_Yield:
5303 case Ijk_SigTRAP:
5304 case Ijk_SigFPE: {
5305 HReg dst = s390_isel_int_expr(env, next);
5306 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
5307 return;
5309 default:
5310 break;
5313 vpanic("iselNext");
5317 /*---------------------------------------------------------*/
5318 /*--- Insn selector top-level ---*/
5319 /*---------------------------------------------------------*/
5321 /* Translate an entire SB to s390 code.
5322 Note: archinfo_host is a pointer to a stack-allocated variable.
5323 Do not assign it to a global variable! */
5325 HInstrArray *
5326 iselSB_S390(const IRSB *bb, VexArch arch_host, const VexArchInfo *archinfo_host,
5327 const VexAbiInfo *vbi, Int offset_host_evcheck_counter,
5328 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
5329 Bool add_profinc, Addr max_ga)
5331 UInt i, j;
5332 HReg hreg, hregHI;
5333 ISelEnv *env;
5334 UInt hwcaps_host = archinfo_host->hwcaps;
5336 /* Do some sanity checks */
5337 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
5339 /* Check that the host's endianness is as expected. */
5340 vassert(archinfo_host->endness == VexEndnessBE);
5342 /* Make up an initial environment to use. */
5343 env = LibVEX_Alloc_inline(sizeof(ISelEnv));
5344 env->vreg_ctr = 0;
5346 /* Set up output code array. */
5347 env->code = newHInstrArray();
5349 /* Copy BB's type env. */
5350 env->type_env = bb->tyenv;
5352 /* Set up data structures for tracking guest register values. */
5353 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
5354 env->old_value[i] = 0; /* just something to have a defined value */
5355 env->old_value_valid[i] = False;
5358 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
5359 change as we go along. For some reason types_used has Int type -- but
5360 it should be unsigned. Internally we use an unsigned type; so we
5361 assert it here. */
5362 vassert(bb->tyenv->types_used >= 0);
5364 env->n_vregmap = bb->tyenv->types_used;
5365 env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
5366 env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
5368 env->previous_bfp_rounding_mode = NULL;
5369 env->previous_dfp_rounding_mode = NULL;
5371 /* and finally ... */
5372 env->hwcaps = hwcaps_host;
5374 env->max_ga = max_ga;
5375 env->chaining_allowed = chaining_allowed;
5377 /* For each IR temporary, allocate a suitably-kinded virtual
5378 register. */
5379 j = 0;
5380 for (i = 0; i < env->n_vregmap; i++) {
5381 hregHI = hreg = INVALID_HREG;
5382 switch (bb->tyenv->types[i]) {
5383 case Ity_I1:
5384 case Ity_I8:
5385 case Ity_I16:
5386 case Ity_I32:
5387 case Ity_I64:
5388 hreg = mkVRegI(j++);
5389 break;
5391 case Ity_I128:
5392 hreg = mkVRegI(j++);
5393 hregHI = mkVRegI(j++);
5394 break;
5396 case Ity_F32:
5397 case Ity_F64:
5398 case Ity_D32:
5399 case Ity_D64:
5400 hreg = mkVRegF(j++);
5401 break;
5403 case Ity_F128:
5404 case Ity_D128:
5405 hreg = mkVRegF(j++);
5406 hregHI = mkVRegF(j++);
5407 break;
5409 case Ity_V128:
5410 hreg = mkVRegV(j++);
5411 break;
5413 default:
5414 ppIRType(bb->tyenv->types[i]);
5415 vpanic("iselSB_S390: IRTemp type");
5418 env->vregmap[i] = hreg;
5419 env->vregmapHI[i] = hregHI;
5421 env->vreg_ctr = j;
5423 /* The very first instruction must be an event check. */
5424 s390_amode *counter, *fail_addr;
5425 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
5426 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
5427 addInstr(env, s390_insn_evcheck(counter, fail_addr));
5429 /* Possibly a block counter increment (for profiling). At this
5430 point we don't know the address of the counter, so just pretend
5431 it is zero. It will have to be patched later, but before this
5432 translation is used, by a call to LibVEX_patchProfInc. */
5433 if (add_profinc) {
5434 addInstr(env, s390_insn_profinc());
5437 /* Ok, finally we can iterate over the statements. */
5438 for (i = 0; i < bb->stmts_used; i++)
5439 if (bb->stmts[i])
5440 s390_isel_stmt(env, bb->stmts[i]);
5442 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
5444 /* Record the number of vregs we used. */
5445 env->code->n_vregs = env->vreg_ctr;
5447 return env->code;
5450 /*---------------------------------------------------------------*/
5451 /*--- end host_s390_isel.c ---*/
5452 /*---------------------------------------------------------------*/