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