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