blob: 6affc04957dc8d699b29a2aecf9bb2f4413bb43b [file] [log] [blame]
sewardj2019a972011-03-07 16:04:07 +00001/* -*- 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
sewardj89ae8472013-10-18 14:12:58 +000011 Copyright IBM Corp. 2010-2013
12 Copyright (C) 2012-2013 Florian Krohm (britzel@acm.org)
sewardj2019a972011-03-07 16:04:07 +000013
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
sewardj2019a972011-03-07 16:04:07 +000039#include "main_util.h"
40#include "main_globals.h"
florian9f42ab42012-12-23 01:09:16 +000041#include "guest_s390_defs.h" /* S390X_GUEST_OFFSET */
sewardj2019a972011-03-07 16:04:07 +000042#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.
florianad43b3a2012-02-20 15:01:14 +000072
florian8844a632012-04-13 04:04:06 +000073 - 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
florianad43b3a2012-02-20 15:01:14 +000085 - Values of certain guest registers which are often assigned constants.
sewardj2019a972011-03-07 16:04:07 +000086*/
87
florianad43b3a2012-02-20 15:01:14 +000088/* Symbolic names for guest registers whose value we're tracking */
89enum {
90 GUEST_IA,
91 GUEST_CC_OP,
92 GUEST_CC_DEP1,
93 GUEST_CC_DEP2,
94 GUEST_CC_NDEP,
95 GUEST_SYSNO,
florian7d117ba2012-05-06 03:34:55 +000096 GUEST_COUNTER,
florianad43b3a2012-02-20 15:01:14 +000097 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
sewardj2019a972011-03-07 16:04:07 +0000104typedef struct {
105 IRTypeEnv *type_env;
106
florian8844a632012-04-13 04:04:06 +0000107 HInstrArray *code;
sewardj2019a972011-03-07 16:04:07 +0000108 HReg *vregmap;
109 HReg *vregmapHI;
110 UInt n_vregmap;
florian8844a632012-04-13 04:04:06 +0000111 UInt vreg_ctr;
112 UInt hwcaps;
sewardj2019a972011-03-07 16:04:07 +0000113
florian2c74d242012-09-12 19:38:42 +0000114 IRExpr *previous_bfp_rounding_mode;
florianc8e4f562012-10-27 16:19:31 +0000115 IRExpr *previous_dfp_rounding_mode;
florian2c74d242012-09-12 19:38:42 +0000116
florianad43b3a2012-02-20 15:01:14 +0000117 ULong old_value[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000118
florian8844a632012-04-13 04:04:06 +0000119 /* The next two are for translation chaining */
120 Addr64 max_ga;
121 Bool chaining_allowed;
122
florianad43b3a2012-02-20 15:01:14 +0000123 Bool old_value_valid[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000124} ISelEnv;
125
126
127/* Forward declarations */
128static HReg s390_isel_int_expr(ISelEnv *, IRExpr *);
129static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *);
130static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
131static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
132static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
133static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
134static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
florian12390202012-11-10 22:34:14 +0000135static HReg s390_isel_dfp_expr(ISelEnv *, IRExpr *);
floriane38f6412012-12-21 17:32:12 +0000136static void s390_isel_dfp128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
sewardj2019a972011-03-07 16:04:07 +0000137
138
florianad43b3a2012-02-20 15:01:14 +0000139static Int
140get_guest_reg(Int offset)
141{
142 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000143 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
144 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
145 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
146 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
147 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
148 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000149 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000150
151 /* Also make sure there is never a partial write to one of
152 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000153 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
154 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
155 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
156 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
157 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000158 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
159 /* counter is used both as 4-byte and as 8-byte entity */
160 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
161 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianaf50a192012-07-13 14:13:06 +0000162 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000163 break;
164
165 default: break;
166 }
167
168 return GUEST_UNKNOWN;
169}
170
sewardj2019a972011-03-07 16:04:07 +0000171/* Add an instruction */
172static void
173addInstr(ISelEnv *env, s390_insn *insn)
174{
175 addHInstr(env->code, insn);
176
177 if (vex_traceflags & VEX_TRACE_VCODE) {
178 vex_printf("%s\n", s390_insn_as_string(insn));
179 }
180}
181
182
183static __inline__ IRExpr *
184mkU64(ULong value)
185{
186 return IRExpr_Const(IRConst_U64(value));
187}
188
189
190/*---------------------------------------------------------*/
191/*--- Registers ---*/
192/*---------------------------------------------------------*/
193
194/* Return the virtual register to which a given IRTemp is mapped. */
195static HReg
196lookupIRTemp(ISelEnv *env, IRTemp tmp)
197{
198 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000199 vassert(! hregIsInvalid(env->vregmap[tmp]));
sewardj2019a972011-03-07 16:04:07 +0000200
201 return env->vregmap[tmp];
202}
203
204
205/* Return the two virtual registers to which the IRTemp is mapped. */
206static void
207lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
208{
209 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000210 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardj2019a972011-03-07 16:04:07 +0000211
212 *lo = env->vregmap[tmp];
213 *hi = env->vregmapHI[tmp];
214}
215
216
217/* Allocate a new integer register */
218static HReg
219newVRegI(ISelEnv *env)
220{
221 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
222 env->vreg_ctr++;
223
224 return reg;
225}
226
227
228/* Allocate a new floating point register */
229static HReg
230newVRegF(ISelEnv *env)
231{
232 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
233
234 env->vreg_ctr++;
235
236 return reg;
237}
238
239
240/* Construct a non-virtual general purpose register */
241static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000242make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000243{
244 return mkHReg(regno, HRcInt64, False /* virtual */ );
245}
246
247
248/* Construct a non-virtual floating point register */
249static __inline__ HReg
250make_fpr(UInt regno)
251{
252 return mkHReg(regno, HRcFlt64, False /* virtual */ );
253}
254
255
256/*---------------------------------------------------------*/
257/*--- Amode ---*/
258/*---------------------------------------------------------*/
259
260static __inline__ Bool
261ulong_fits_unsigned_12bit(ULong val)
262{
263 return (val & 0xFFFu) == val;
264}
265
266
267static __inline__ Bool
268ulong_fits_signed_20bit(ULong val)
269{
270 Long v = val & 0xFFFFFu;
271
272 v = (v << 44) >> 44; /* sign extend */
273
274 return val == (ULong)v;
275}
276
277
florianad43b3a2012-02-20 15:01:14 +0000278static __inline__ Bool
279ulong_fits_signed_8bit(ULong val)
280{
281 Long v = val & 0xFFu;
282
283 v = (v << 56) >> 56; /* sign extend */
284
285 return val == (ULong)v;
286}
287
sewardj2019a972011-03-07 16:04:07 +0000288/* EXPR is an expression that is used as an address. Return an s390_amode
289 for it. */
290static s390_amode *
291s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
292{
293 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
294 IRExpr *arg1 = expr->Iex.Binop.arg1;
295 IRExpr *arg2 = expr->Iex.Binop.arg2;
296
297 /* Move constant into right subtree */
298 if (arg1->tag == Iex_Const) {
299 IRExpr *tmp;
300 tmp = arg1;
301 arg1 = arg2;
302 arg2 = tmp;
303 }
304
305 /* r + constant: Check for b12 first, then b20 */
306 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
307 ULong value = arg2->Iex.Const.con->Ico.U64;
308
309 if (ulong_fits_unsigned_12bit(value)) {
310 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
311 }
sewardj652b56a2011-04-13 15:38:17 +0000312 /* If long-displacement is not available, do not construct B20 or
313 BX20 amodes because code generation cannot handle them. */
314 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000315 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
316 }
317 }
318 }
319
320 /* Doesn't match anything in particular. Generate it into
321 a register and use that. */
322 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
323}
324
325
326static s390_amode *
327s390_isel_amode(ISelEnv *env, IRExpr *expr)
328{
florian35da8612011-06-25 02:25:41 +0000329 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000330
331 /* Address computation should yield a 64-bit value */
332 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
333
334 am = s390_isel_amode_wrk(env, expr);
335
336 /* Check post-condition */
337 vassert(s390_amode_is_sane(am));
338
339 return am;
340}
341
342
343/*---------------------------------------------------------*/
344/*--- Helper functions ---*/
345/*---------------------------------------------------------*/
346
347/* Constants and memory accesses should be right operands */
348#define order_commutative_operands(left, right) \
349 do { \
350 if (left->tag == Iex_Const || left->tag == Iex_Load || \
351 left->tag == Iex_Get) { \
352 IRExpr *tmp; \
353 tmp = left; \
354 left = right; \
355 right = tmp; \
356 } \
357 } while (0)
358
359
360/* Copy an RMI operand to the DST register */
361static s390_insn *
362s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
363{
364 switch (opnd.tag) {
365 case S390_OPND_AMODE:
366 return s390_insn_load(size, dst, opnd.variant.am);
367
368 case S390_OPND_REG:
369 return s390_insn_move(size, dst, opnd.variant.reg);
370
371 case S390_OPND_IMMEDIATE:
372 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
373
374 default:
375 vpanic("s390_opnd_copy");
376 }
377}
378
379
380/* Construct a RMI operand for a register */
381static __inline__ s390_opnd_RMI
382s390_opnd_reg(HReg reg)
383{
384 s390_opnd_RMI opnd;
385
386 opnd.tag = S390_OPND_REG;
387 opnd.variant.reg = reg;
388
389 return opnd;
390}
391
392
393/* Construct a RMI operand for an immediate constant */
394static __inline__ s390_opnd_RMI
395s390_opnd_imm(ULong value)
396{
397 s390_opnd_RMI opnd;
398
399 opnd.tag = S390_OPND_IMMEDIATE;
400 opnd.variant.imm = value;
401
402 return opnd;
403}
404
405
florianffbd84d2012-12-09 02:06:29 +0000406/* Return 1, if EXPR represents the constant 0 */
407static Bool
sewardj2019a972011-03-07 16:04:07 +0000408s390_expr_is_const_zero(IRExpr *expr)
409{
410 ULong value;
411
412 if (expr->tag == Iex_Const) {
413 switch (expr->Iex.Const.con->tag) {
414 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
415 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
416 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
417 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
418 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
419 default:
420 vpanic("s390_expr_is_const_zero");
421 }
422 return value == 0;
423 }
424
425 return 0;
426}
427
428
florianb93348d2012-12-27 00:59:43 +0000429/* Return the value of CON as a sign-exteded ULong value */
430static ULong
431get_const_value_as_ulong(const IRConst *con)
432{
433 Long value;
434
435 switch (con->tag) {
436 case Ico_U1: value = con->Ico.U1; return (ULong) ((value << 63) >> 63);
437 case Ico_U8: value = con->Ico.U8; return (ULong) ((value << 56) >> 56);
438 case Ico_U16: value = con->Ico.U16; return (ULong) ((value << 48) >> 48);
439 case Ico_U32: value = con->Ico.U32; return (ULong) ((value << 32) >> 32);
440 case Ico_U64: return con->Ico.U64;
441 default:
442 vpanic("get_const_value_as_ulong");
443 }
444}
445
446
sewardj2019a972011-03-07 16:04:07 +0000447/* Call a helper (clean or dirty)
448 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000449
sewardj2019a972011-03-07 16:04:07 +0000450 (a) they are expressions yielding an integer result
451 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000452
453 guard is a Ity_Bit expression indicating whether or not the
454 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000455
456 Calling the helper function proceeds as follows:
457
458 (1) The helper arguments are evaluated and their value stored in
459 virtual registers.
460 (2) The condition code is evaluated
461 (3) The argument values are copied from the virtual registers to the
462 registers mandated by the ABI.
463 (4) Call the helper function.
464
465 This is not the most efficient way as step 3 generates register-to-register
466 moves. But it is the least fragile way as the only hidden dependency here
467 is that register-to-register moves (step 3) must not clobber the condition
468 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
469 to-register add more such dependencies. Not good. Besides, it's the job
470 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000471*/
472static void
sewardj74142b82013-08-08 10:28:59 +0000473doHelperCall(/*OUT*/UInt *stackAdjustAfterCall,
474 /*OUT*/RetLoc *retloc,
475 ISelEnv *env, IRExpr *guard,
476 IRCallee *callee, IRType retTy, IRExpr **args)
sewardj2019a972011-03-07 16:04:07 +0000477{
florian52af7bc2012-05-12 03:44:49 +0000478 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000479 ULong target;
480 HReg tmpregs[S390_NUM_GPRPARMS];
481 s390_cc_t cc;
482
sewardj74142b82013-08-08 10:28:59 +0000483 /* Set default returns. We'll update them later if needed. */
484 *stackAdjustAfterCall = 0;
485 *retloc = mk_RetLoc_INVALID();
486
487 /* The return type can be I{64,32,16,8} or V{128,256}. In the
488 latter two cases, it is expected that |args| will contain the
florian608e5602014-11-21 21:40:45 +0000489 special node IRExpr_VECRET(). For s390, however, V128 and V256 return
490 values do not occur as we generally do not support vector types.
sewardj74142b82013-08-08 10:28:59 +0000491
florian90419562013-08-15 20:54:52 +0000492 |args| may also contain IRExpr_BBPTR(), in which case the value
sewardj74142b82013-08-08 10:28:59 +0000493 in the guest state pointer register is passed as the
494 corresponding argument.
495
496 These are used for cross-checking that IR-level constraints on
florian90419562013-08-15 20:54:52 +0000497 the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */
sewardj74142b82013-08-08 10:28:59 +0000498 UInt nVECRETs = 0;
499 UInt nBBPTRs = 0;
500
sewardj2019a972011-03-07 16:04:07 +0000501 n_args = 0;
502 for (i = 0; args[i]; i++)
503 ++n_args;
504
sewardj74142b82013-08-08 10:28:59 +0000505 if (n_args > S390_NUM_GPRPARMS) {
sewardj2019a972011-03-07 16:04:07 +0000506 vpanic("doHelperCall: too many arguments");
507 }
508
florian11b8ee82012-08-06 13:35:33 +0000509 /* All arguments must have Ity_I64. For two reasons:
510 (1) We do not handle floating point arguments.
511 (2) The ABI requires that integer values are sign- or zero-extended
512 to 64 bit.
513 */
514 Int arg_errors = 0;
515 for (i = 0; i < n_args; ++i) {
florian90419562013-08-15 20:54:52 +0000516 if (UNLIKELY(args[i]->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000517 nVECRETs++;
florian90419562013-08-15 20:54:52 +0000518 } else if (UNLIKELY(args[i]->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000519 nBBPTRs++;
520 } else {
521 IRType type = typeOfIRExpr(env->type_env, args[i]);
522 if (type != Ity_I64) {
523 ++arg_errors;
524 vex_printf("calling %s: argument #%d has type ", callee->name, i);
525 ppIRType(type);
526 vex_printf("; Ity_I64 is required\n");
527 }
florian11b8ee82012-08-06 13:35:33 +0000528 }
529 }
530
531 if (arg_errors)
532 vpanic("cannot continue due to errors in argument passing");
533
florian608e5602014-11-21 21:40:45 +0000534 /* If these fail, the IR is ill-formed */
sewardj74142b82013-08-08 10:28:59 +0000535 vassert(nBBPTRs == 0 || nBBPTRs == 1);
florian608e5602014-11-21 21:40:45 +0000536 vassert(nVECRETs == 0);
florian52af7bc2012-05-12 03:44:49 +0000537
sewardj74142b82013-08-08 10:28:59 +0000538 argreg = 0;
539
florian52af7bc2012-05-12 03:44:49 +0000540 /* Compute the function arguments into a temporary register each */
541 for (i = 0; i < n_args; i++) {
sewardj74142b82013-08-08 10:28:59 +0000542 IRExpr *arg = args[i];
florian608e5602014-11-21 21:40:45 +0000543 if (UNLIKELY(arg->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000544 /* If we need the guest state pointer put it in a temporary arg reg */
545 tmpregs[argreg] = newVRegI(env);
546 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
547 s390_hreg_guest_state_pointer()));
548 } else {
549 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
550 }
florian52af7bc2012-05-12 03:44:49 +0000551 argreg++;
552 }
553
sewardj2019a972011-03-07 16:04:07 +0000554 /* Compute the condition */
555 cc = S390_CC_ALWAYS;
556 if (guard) {
557 if (guard->tag == Iex_Const
558 && guard->Iex.Const.con->tag == Ico_U1
559 && guard->Iex.Const.con->Ico.U1 == True) {
560 /* unconditional -- do nothing */
561 } else {
562 cc = s390_isel_cc(env, guard);
563 }
564 }
565
florian52af7bc2012-05-12 03:44:49 +0000566 /* Move the args to the final register. It is paramount, that the
567 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000568 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000569 HReg finalreg;
570
571 finalreg = make_gpr(s390_gprno_from_arg_index(i));
572 size = sizeofIRType(Ity_I64);
573 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000574 }
575
576 target = Ptr_to_ULong(callee->addr);
577
sewardj74142b82013-08-08 10:28:59 +0000578 /* Do final checks, set the return values, and generate the call
579 instruction proper. */
580 vassert(*stackAdjustAfterCall == 0);
581 vassert(is_RetLoc_INVALID(*retloc));
582 switch (retTy) {
583 case Ity_INVALID:
584 /* Function doesn't return a value. */
585 *retloc = mk_RetLoc_simple(RLPri_None);
586 break;
587 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
588 *retloc = mk_RetLoc_simple(RLPri_Int);
589 break;
sewardj74142b82013-08-08 10:28:59 +0000590 default:
591 /* IR can denote other possible return types, but we don't
592 handle those here. */
florian608e5602014-11-21 21:40:45 +0000593 vex_printf("calling %s: return type is ", callee->name);
594 ppIRType(retTy);
595 vex_printf("; an integer type is required\n");
sewardj74142b82013-08-08 10:28:59 +0000596 vassert(0);
597 }
598
sewardj2019a972011-03-07 16:04:07 +0000599 /* Finally, the call itself. */
600 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
sewardj74142b82013-08-08 10:28:59 +0000601 callee->name, *retloc));
sewardj2019a972011-03-07 16:04:07 +0000602}
603
604
florian2c74d242012-09-12 19:38:42 +0000605/*---------------------------------------------------------*/
606/*--- BFP helper functions ---*/
607/*---------------------------------------------------------*/
608
609/* Set the BFP rounding mode in the FPC. This function is called for
610 all non-conversion BFP instructions as those will always get the
611 rounding mode from the FPC. */
612static void
613set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000614{
florian2c74d242012-09-12 19:38:42 +0000615 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
616
617 /* Do we need to do anything? */
618 if (env->previous_bfp_rounding_mode &&
619 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
620 irrm->tag == Iex_RdTmp &&
621 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
622 /* No - new mode is identical to previous mode. */
623 return;
624 }
625
626 /* No luck - we better set it, and remember what we set it to. */
627 env->previous_bfp_rounding_mode = irrm;
628
629 /* The incoming rounding mode is in VEX IR encoding. Need to change
630 to s390.
631
632 rounding mode | s390 | IR
633 -------------------------
634 to nearest | 00 | 00
635 to zero | 01 | 11
636 to +infinity | 10 | 10
637 to -infinity | 11 | 01
638
639 So: s390 = (4 - IR) & 3
640 */
641 HReg ir = s390_isel_int_expr(env, irrm);
642
643 HReg mode = newVRegI(env);
644
645 addInstr(env, s390_insn_load_immediate(4, mode, 4));
646 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
647 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
648
florian125e20d2012-10-07 15:42:37 +0000649 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000650}
651
652
653/* This function is invoked for insns that support a specification of
654 a rounding mode in the insn itself. In that case there is no need to
655 stick the rounding mode into the FPC -- a good thing. However, the
656 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000657static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000658get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
659{
660 if (irrm->tag == Iex_Const) { /* rounding mode is known */
661 vassert(irrm->Iex.Const.con->tag == Ico_U32);
662 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000663
664 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000665 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
666 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
667 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
668 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000669 default:
670 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000671 }
672 }
673
florian2c74d242012-09-12 19:38:42 +0000674 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000675 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000676}
677
678
florianc8e4f562012-10-27 16:19:31 +0000679/*---------------------------------------------------------*/
680/*--- DFP helper functions ---*/
681/*---------------------------------------------------------*/
682
683/* Set the DFP rounding mode in the FPC. This function is called for
684 all non-conversion DFP instructions as those will always get the
685 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000686static void
687set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
688{
689 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
690
691 /* Do we need to do anything? */
692 if (env->previous_dfp_rounding_mode &&
693 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
694 irrm->tag == Iex_RdTmp &&
695 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
696 /* No - new mode is identical to previous mode. */
697 return;
698 }
699
700 /* No luck - we better set it, and remember what we set it to. */
701 env->previous_dfp_rounding_mode = irrm;
702
703 /* The incoming rounding mode is in VEX IR encoding. Need to change
704 to s390.
705
706 rounding mode | S390 | IR
707 -----------------------------------------------
708 to nearest, ties to even | 000 | 000
709 to zero | 001 | 011
710 to +infinity | 010 | 010
711 to -infinity | 011 | 001
712 to nearest, ties away from 0 | 100 | 100
713 to nearest, ties toward 0 | 101 | 111
714 to away from 0 | 110 | 110
715 to prepare for shorter precision | 111 | 101
716
717 So: s390 = (IR ^ ((IR << 1) & 2))
718 */
719 HReg ir = s390_isel_int_expr(env, irrm);
720
721 HReg mode = newVRegI(env);
722
723 addInstr(env, s390_insn_move(4, mode, ir));
724 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
725 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
726 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
727
728 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
729}
730
731
732/* This function is invoked for insns that support a specification of
733 a rounding mode in the insn itself. In that case there is no need to
734 stick the rounding mode into the FPC -- a good thing. However, the
735 rounding mode must be known.
florianff9000d2013-02-08 20:22:03 +0000736
florian79e5a482013-06-06 19:12:46 +0000737 When mapping an Irrm_XYZ value to an S390_DFP_ROUND_ value there is
738 often a choice. For instance, Irrm_ZERO could be mapped to either
florianff9000d2013-02-08 20:22:03 +0000739 S390_DFP_ROUND_ZERO_5 or S390_DFP_ROUND_ZERO_9. The difference between
740 those two is that with S390_DFP_ROUND_ZERO_9 the recognition of the
741 quantum exception is suppressed whereas with S390_DFP_ROUND_ZERO_5 it
742 is not. As the quantum exception is not modelled we can choose either
743 value. The choice is to use S390_DFP_ROUND_.. values in the range [8:15],
744 because values in the range [1:7] have unpredictable rounding behaviour
745 when the floating point exception facility is not installed.
florianc8e4f562012-10-27 16:19:31 +0000746
747 Translation table of
748 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
749
florian79e5a482013-06-06 19:12:46 +0000750 s390(S390_DFP_ROUND_) | IR(Irrm_) | s390(S390_DFP_ROUND_)
florianc8e4f562012-10-27 16:19:31 +0000751 --------------------------------------------------------------------
florianff9000d2013-02-08 20:22:03 +0000752 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_12
florianc8e4f562012-10-27 16:19:31 +0000753 NEAREST_TIE_AWAY_0_12 | " | "
florianff9000d2013-02-08 20:22:03 +0000754 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_15
florianc8e4f562012-10-27 16:19:31 +0000755 PREPARE_SHORT_15 | " | "
florianff9000d2013-02-08 20:22:03 +0000756 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_8
florianc8e4f562012-10-27 16:19:31 +0000757 NEAREST_EVEN_8 | " | "
florianff9000d2013-02-08 20:22:03 +0000758 ZERO_5 | ZERO | ZERO_9
florianc8e4f562012-10-27 16:19:31 +0000759 ZERO_9 | " | "
florianff9000d2013-02-08 20:22:03 +0000760 POSINF_6 | PosINF | POSINF_10
florianc8e4f562012-10-27 16:19:31 +0000761 POSINF_10 | " | "
florianff9000d2013-02-08 20:22:03 +0000762 NEGINF_7 | NegINF | NEGINF_11
florianc8e4f562012-10-27 16:19:31 +0000763 NEGINF_11 | " | "
764 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
765 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
766*/
767static s390_dfp_round_t
768get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
769{
770 if (irrm->tag == Iex_Const) { /* rounding mode is known */
771 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian79e5a482013-06-06 19:12:46 +0000772 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000773
774 switch (mode) {
florian79e5a482013-06-06 19:12:46 +0000775 case Irrm_NEAREST:
florianff9000d2013-02-08 20:22:03 +0000776 return S390_DFP_ROUND_NEAREST_EVEN_8;
florian79e5a482013-06-06 19:12:46 +0000777 case Irrm_NegINF:
florianff9000d2013-02-08 20:22:03 +0000778 return S390_DFP_ROUND_NEGINF_11;
florian79e5a482013-06-06 19:12:46 +0000779 case Irrm_PosINF:
florianff9000d2013-02-08 20:22:03 +0000780 return S390_DFP_ROUND_POSINF_10;
florian79e5a482013-06-06 19:12:46 +0000781 case Irrm_ZERO:
florianff9000d2013-02-08 20:22:03 +0000782 return S390_DFP_ROUND_ZERO_9;
florian79e5a482013-06-06 19:12:46 +0000783 case Irrm_NEAREST_TIE_AWAY_0:
florianff9000d2013-02-08 20:22:03 +0000784 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12;
florian79e5a482013-06-06 19:12:46 +0000785 case Irrm_PREPARE_SHORTER:
florianff9000d2013-02-08 20:22:03 +0000786 return S390_DFP_ROUND_PREPARE_SHORT_15;
florian79e5a482013-06-06 19:12:46 +0000787 case Irrm_AWAY_FROM_ZERO:
florianc8e4f562012-10-27 16:19:31 +0000788 return S390_DFP_ROUND_AWAY_0;
florian79e5a482013-06-06 19:12:46 +0000789 case Irrm_NEAREST_TIE_TOWARD_0:
florianc8e4f562012-10-27 16:19:31 +0000790 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
791 default:
792 vpanic("get_dfp_rounding_mode");
793 }
794 }
795
796 set_dfp_rounding_mode_in_fpc(env, irrm);
797 return S390_DFP_ROUND_PER_FPC_0;
798}
florianc8e4f562012-10-27 16:19:31 +0000799
florian2d3d87f2012-12-21 21:05:17 +0000800
801/*---------------------------------------------------------*/
802/*--- Condition code helper functions ---*/
803/*---------------------------------------------------------*/
804
sewardj2019a972011-03-07 16:04:07 +0000805/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000806 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000807
808 s390 VEX b6 b2 b0 cc.1 cc.0
809 0 0x40 EQ 1 0 0 0 0
810 1 0x01 LT 0 0 1 0 1
811 2 0x00 GT 0 0 0 1 0
812 3 0x45 Unordered 1 1 1 1 1
813
814 b0 = cc.0
815 b2 = cc.0 & cc.1
816 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
817
818 VEX = b0 | (b2 << 2) | (b6 << 6);
819*/
820static HReg
florian2d3d87f2012-12-21 21:05:17 +0000821convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000822{
823 HReg cc0, cc1, b2, b6, cc_vex;
824
825 cc0 = newVRegI(env);
826 addInstr(env, s390_insn_move(4, cc0, cc_s390));
827 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
828
829 cc1 = newVRegI(env);
830 addInstr(env, s390_insn_move(4, cc1, cc_s390));
831 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
832
833 b2 = newVRegI(env);
834 addInstr(env, s390_insn_move(4, b2, cc0));
835 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
836 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
837
838 b6 = newVRegI(env);
839 addInstr(env, s390_insn_move(4, b6, cc0));
840 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
841 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
842 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
843 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
844
845 cc_vex = newVRegI(env);
846 addInstr(env, s390_insn_move(4, cc_vex, cc0));
847 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
848 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
849
850 return cc_vex;
851}
852
florian2d3d87f2012-12-21 21:05:17 +0000853/* CC_S390 holds the condition code in s390 encoding. Convert it to
854 VEX encoding (IRCmpDResult) */
855static HReg
856convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
857{
858 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
859 return convert_s390_to_vex_bfpcc(env, cc_s390);
860}
861
sewardj2019a972011-03-07 16:04:07 +0000862
863/*---------------------------------------------------------*/
864/*--- ISEL: Integer expressions (128 bit) ---*/
865/*---------------------------------------------------------*/
866static void
867s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
868 IRExpr *expr)
869{
870 IRType ty = typeOfIRExpr(env->type_env, expr);
871
872 vassert(ty == Ity_I128);
873
874 /* No need to consider the following
875 - 128-bit constants (they do not exist in VEX)
876 - 128-bit loads from memory (will not be generated)
877 */
878
879 /* Read 128-bit IRTemp */
880 if (expr->tag == Iex_RdTmp) {
881 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
882 return;
883 }
884
885 if (expr->tag == Iex_Binop) {
886 IRExpr *arg1 = expr->Iex.Binop.arg1;
887 IRExpr *arg2 = expr->Iex.Binop.arg2;
888 Bool is_signed_multiply, is_signed_divide;
889
890 switch (expr->Iex.Binop.op) {
891 case Iop_MullU64:
892 is_signed_multiply = False;
893 goto do_multiply64;
894
895 case Iop_MullS64:
896 is_signed_multiply = True;
897 goto do_multiply64;
898
899 case Iop_DivModU128to64:
900 is_signed_divide = False;
901 goto do_divide64;
902
903 case Iop_DivModS128to64:
904 is_signed_divide = True;
905 goto do_divide64;
906
907 case Iop_64HLto128:
908 *dst_hi = s390_isel_int_expr(env, arg1);
909 *dst_lo = s390_isel_int_expr(env, arg2);
910 return;
911
912 case Iop_DivModS64to64: {
913 HReg r10, r11, h1;
914 s390_opnd_RMI op2;
915
916 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
917 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
918
919 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000920 r10 = make_gpr(10);
921 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000922
923 /* Move 1st operand into r11 and */
924 addInstr(env, s390_insn_move(8, r11, h1));
925
926 /* Divide */
927 addInstr(env, s390_insn_divs(8, r10, r11, op2));
928
929 /* The result is in registers r10 (remainder) and r11 (quotient).
930 Move the result into the reg pair that is being returned such
931 such that the low 64 bits are the quotient and the upper 64 bits
932 are the remainder. (see libvex_ir.h). */
933 *dst_hi = newVRegI(env);
934 *dst_lo = newVRegI(env);
935 addInstr(env, s390_insn_move(8, *dst_hi, r10));
936 addInstr(env, s390_insn_move(8, *dst_lo, r11));
937 return;
938 }
939
940 default:
941 break;
942
943 do_multiply64: {
944 HReg r10, r11, h1;
945 s390_opnd_RMI op2;
946
947 order_commutative_operands(arg1, arg2);
948
949 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
950 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
951
952 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000953 r10 = make_gpr(10);
954 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000955
956 /* Move the first operand to r11 */
957 addInstr(env, s390_insn_move(8, r11, h1));
958
959 /* Multiply */
960 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
961
962 /* The result is in registers r10 and r11. Assign to two virtual regs
963 and return. */
964 *dst_hi = newVRegI(env);
965 *dst_lo = newVRegI(env);
966 addInstr(env, s390_insn_move(8, *dst_hi, r10));
967 addInstr(env, s390_insn_move(8, *dst_lo, r11));
968 return;
969 }
970
971 do_divide64: {
972 HReg r10, r11, hi, lo;
973 s390_opnd_RMI op2;
974
975 s390_isel_int128_expr(&hi, &lo, env, arg1);
976 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
977
978 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000979 r10 = make_gpr(10);
980 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000981
982 /* Move high 64 bits of the 1st operand into r10 and
983 the low 64 bits into r11. */
984 addInstr(env, s390_insn_move(8, r10, hi));
985 addInstr(env, s390_insn_move(8, r11, lo));
986
987 /* Divide */
988 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
989
990 /* The result is in registers r10 (remainder) and r11 (quotient).
991 Move the result into the reg pair that is being returned such
992 such that the low 64 bits are the quotient and the upper 64 bits
993 are the remainder. (see libvex_ir.h). */
994 *dst_hi = newVRegI(env);
995 *dst_lo = newVRegI(env);
996 addInstr(env, s390_insn_move(8, *dst_hi, r10));
997 addInstr(env, s390_insn_move(8, *dst_lo, r11));
998 return;
999 }
1000 }
1001 }
1002
1003 vpanic("s390_isel_int128_expr");
1004}
1005
1006
1007/* Compute a 128-bit value into two 64-bit registers. These may be either
1008 real or virtual regs; in any case they must not be changed by subsequent
1009 code emitted by the caller. */
1010static void
1011s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1012{
1013 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
1014
1015 /* Sanity checks ... */
1016 vassert(hregIsVirtual(*dst_hi));
1017 vassert(hregIsVirtual(*dst_lo));
1018 vassert(hregClass(*dst_hi) == HRcInt64);
1019 vassert(hregClass(*dst_lo) == HRcInt64);
1020}
1021
1022
1023/*---------------------------------------------------------*/
1024/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
1025/*---------------------------------------------------------*/
1026
1027/* Select insns for an integer-typed expression, and add them to the
1028 code list. Return a reg holding the result. This reg will be a
1029 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
1030 want to modify it, ask for a new vreg, copy it in there, and modify
1031 the copy. The register allocator will do its best to map both
1032 vregs to the same real register, so the copies will often disappear
1033 later in the game.
1034
1035 This should handle expressions of 64, 32, 16 and 8-bit type.
1036 All results are returned in a 64bit register.
1037 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1038 are arbitrary, so you should mask or sign extend partial values
1039 if necessary.
1040*/
1041
1042/* DO NOT CALL THIS DIRECTLY ! */
1043static HReg
1044s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
1045{
1046 IRType ty = typeOfIRExpr(env->type_env, expr);
1047 UChar size;
florian6dc90242012-12-21 21:43:00 +00001048 s390_bfp_conv_t conv;
florian67a171c2013-01-20 03:08:04 +00001049 s390_dfp_conv_t dconv;
sewardj2019a972011-03-07 16:04:07 +00001050
1051 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
1052
1053 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
1054
1055 switch (expr->tag) {
1056
1057 /* --------- TEMP --------- */
1058 case Iex_RdTmp:
1059 /* Return the virtual register that holds the temporary. */
1060 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1061
1062 /* --------- LOAD --------- */
1063 case Iex_Load: {
1064 HReg dst = newVRegI(env);
1065 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1066
1067 if (expr->Iex.Load.end != Iend_BE)
1068 goto irreducible;
1069
1070 addInstr(env, s390_insn_load(size, dst, am));
1071
1072 return dst;
1073 }
1074
1075 /* --------- BINARY OP --------- */
1076 case Iex_Binop: {
1077 IRExpr *arg1 = expr->Iex.Binop.arg1;
1078 IRExpr *arg2 = expr->Iex.Binop.arg2;
1079 HReg h1, res;
1080 s390_alu_t opkind;
1081 s390_opnd_RMI op2, value, opnd;
1082 s390_insn *insn;
1083 Bool is_commutative, is_signed_multiply, is_signed_divide;
1084
1085 is_commutative = True;
1086
1087 switch (expr->Iex.Binop.op) {
1088 case Iop_MullU8:
1089 case Iop_MullU16:
1090 case Iop_MullU32:
1091 is_signed_multiply = False;
1092 goto do_multiply;
1093
1094 case Iop_MullS8:
1095 case Iop_MullS16:
1096 case Iop_MullS32:
1097 is_signed_multiply = True;
1098 goto do_multiply;
1099
1100 do_multiply: {
1101 HReg r10, r11;
1102 UInt arg_size = size / 2;
1103
1104 order_commutative_operands(arg1, arg2);
1105
1106 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1107 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1108
1109 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001110 r10 = make_gpr(10);
1111 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001112
1113 /* Move the first operand to r11 */
1114 addInstr(env, s390_insn_move(arg_size, r11, h1));
1115
1116 /* Multiply */
1117 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1118
1119 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1120 value into the destination register. */
1121 res = newVRegI(env);
1122 addInstr(env, s390_insn_move(arg_size, res, r10));
1123 value = s390_opnd_imm(arg_size * 8);
1124 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1125 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1126 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1127 opnd = s390_opnd_reg(r11);
1128 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1129 return res;
1130 }
1131
1132 case Iop_DivModS64to32:
1133 is_signed_divide = True;
1134 goto do_divide;
1135
1136 case Iop_DivModU64to32:
1137 is_signed_divide = False;
1138 goto do_divide;
1139
1140 do_divide: {
1141 HReg r10, r11;
1142
1143 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1144 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1145
1146 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001147 r10 = make_gpr(10);
1148 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001149
1150 /* Split the first operand and put the high 32 bits into r10 and
1151 the low 32 bits into r11. */
1152 addInstr(env, s390_insn_move(8, r10, h1));
1153 addInstr(env, s390_insn_move(8, r11, h1));
1154 value = s390_opnd_imm(32);
1155 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1156
1157 /* Divide */
1158 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1159
1160 /* The result is in registers r10 (remainder) and r11 (quotient).
1161 Combine them into a 64-bit value such that the low 32 bits are
1162 the quotient and the upper 32 bits are the remainder. (see
1163 libvex_ir.h). */
1164 res = newVRegI(env);
1165 addInstr(env, s390_insn_move(8, res, r10));
1166 value = s390_opnd_imm(32);
1167 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1168 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1169 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1170 opnd = s390_opnd_reg(r11);
1171 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1172 return res;
1173 }
1174
florian9fcff4c2012-09-10 03:09:04 +00001175 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1176 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1177 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1178 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1179 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1180 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1181 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1182 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1183 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1184 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1185 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1186 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
florian67a171c2013-01-20 03:08:04 +00001187
1188 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
floriana887acd2013-02-08 23:32:54 +00001189 case Iop_D64toI64S: dconv = S390_DFP_D64_TO_I64; goto do_convert_dfp;
florian67a171c2013-01-20 03:08:04 +00001190 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1191 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1192 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
floriana887acd2013-02-08 23:32:54 +00001193 case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128;
florian67a171c2013-01-20 03:08:04 +00001194 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1195 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00001196
1197 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001198 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001199
1200 res = newVRegI(env);
1201 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1202
florian2c74d242012-09-12 19:38:42 +00001203 rounding_mode = get_bfp_rounding_mode(env, arg1);
1204 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1205 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001206 return res;
1207 }
1208
1209 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001210 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001211 HReg op_hi, op_lo, f13, f15;
1212
1213 res = newVRegI(env);
1214 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1215
1216 /* We use non-virtual registers r13 and r15 as pair */
1217 f13 = make_fpr(13);
1218 f15 = make_fpr(15);
1219
1220 /* operand --> (f13, f15) */
1221 addInstr(env, s390_insn_move(8, f13, op_hi));
1222 addInstr(env, s390_insn_move(8, f15, op_lo));
1223
florian2c74d242012-09-12 19:38:42 +00001224 rounding_mode = get_bfp_rounding_mode(env, arg1);
floriana2039c52013-12-10 16:51:15 +00001225 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res,
1226 INVALID_HREG, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001227 rounding_mode));
1228 return res;
1229 }
1230
florian5f034622013-01-13 02:29:05 +00001231 do_convert_dfp: {
1232 s390_dfp_round_t rounding_mode;
1233
1234 res = newVRegI(env);
1235 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1236
1237 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001238 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
florian5f034622013-01-13 02:29:05 +00001239 rounding_mode));
1240 return res;
1241 }
1242
1243 do_convert_dfp128: {
1244 s390_dfp_round_t rounding_mode;
1245 HReg op_hi, op_lo, f13, f15;
1246
1247 res = newVRegI(env);
1248 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1249
1250 /* We use non-virtual registers r13 and r15 as pair */
1251 f13 = make_fpr(13);
1252 f15 = make_fpr(15);
1253
1254 /* operand --> (f13, f15) */
1255 addInstr(env, s390_insn_move(8, f13, op_hi));
1256 addInstr(env, s390_insn_move(8, f15, op_lo));
1257
1258 rounding_mode = get_dfp_rounding_mode(env, arg1);
floriana2039c52013-12-10 16:51:15 +00001259 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res,
1260 INVALID_HREG, f13,
florian5f034622013-01-13 02:29:05 +00001261 f15, rounding_mode));
1262 return res;
1263 }
1264
sewardj2019a972011-03-07 16:04:07 +00001265 case Iop_8HLto16:
1266 case Iop_16HLto32:
1267 case Iop_32HLto64: {
1268 HReg h2;
1269 UInt arg_size = size / 2;
1270
1271 res = newVRegI(env);
1272 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1273 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1274
1275 addInstr(env, s390_insn_move(arg_size, res, h1));
1276 value = s390_opnd_imm(arg_size * 8);
1277 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1278 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1279 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1280 opnd = s390_opnd_reg(h2);
1281 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1282 return res;
1283 }
1284
1285 case Iop_Max32U: {
1286 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1287 res = newVRegI(env);
1288 h1 = s390_isel_int_expr(env, arg1);
1289 op2 = s390_isel_int_expr_RMI(env, arg2);
1290
1291 addInstr(env, s390_insn_move(size, res, h1));
1292 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1293 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1294 return res;
1295 }
1296
1297 case Iop_CmpF32:
1298 case Iop_CmpF64: {
1299 HReg cc_s390, h2;
1300
1301 h1 = s390_isel_float_expr(env, arg1);
1302 h2 = s390_isel_float_expr(env, arg2);
1303 cc_s390 = newVRegI(env);
1304
1305 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1306
1307 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1308
florian2d3d87f2012-12-21 21:05:17 +00001309 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001310 }
1311
1312 case Iop_CmpF128: {
1313 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1314
1315 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1316 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1317 cc_s390 = newVRegI(env);
1318
1319 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1320 f12 = make_fpr(12);
1321 f13 = make_fpr(13);
1322 f14 = make_fpr(14);
1323 f15 = make_fpr(15);
1324
1325 /* 1st operand --> (f12, f14) */
1326 addInstr(env, s390_insn_move(8, f12, op1_hi));
1327 addInstr(env, s390_insn_move(8, f14, op1_lo));
1328
1329 /* 2nd operand --> (f13, f15) */
1330 addInstr(env, s390_insn_move(8, f13, op2_hi));
1331 addInstr(env, s390_insn_move(8, f15, op2_lo));
1332
1333 res = newVRegI(env);
1334 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1335
florian2d3d87f2012-12-21 21:05:17 +00001336 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001337 }
1338
florian20c6bca2012-12-26 17:47:19 +00001339 case Iop_CmpD64:
1340 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001341 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001342 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001343
1344 h1 = s390_isel_dfp_expr(env, arg1);
1345 h2 = s390_isel_dfp_expr(env, arg2);
1346 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001347
florian20c6bca2012-12-26 17:47:19 +00001348 switch(expr->Iex.Binop.op) {
1349 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1350 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1351 default: goto irreducible;
1352 }
1353 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001354
florian2d3d87f2012-12-21 21:05:17 +00001355 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001356 }
1357
florian20c6bca2012-12-26 17:47:19 +00001358 case Iop_CmpD128:
1359 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001360 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001361 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001362
1363 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1364 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1365 cc_s390 = newVRegI(env);
1366
1367 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1368 f12 = make_fpr(12);
1369 f13 = make_fpr(13);
1370 f14 = make_fpr(14);
1371 f15 = make_fpr(15);
1372
1373 /* 1st operand --> (f12, f14) */
1374 addInstr(env, s390_insn_move(8, f12, op1_hi));
1375 addInstr(env, s390_insn_move(8, f14, op1_lo));
1376
1377 /* 2nd operand --> (f13, f15) */
1378 addInstr(env, s390_insn_move(8, f13, op2_hi));
1379 addInstr(env, s390_insn_move(8, f15, op2_lo));
1380
florian20c6bca2012-12-26 17:47:19 +00001381 switch(expr->Iex.Binop.op) {
1382 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1383 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1384 default: goto irreducible;
1385 }
1386 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1387 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001388
florian2d3d87f2012-12-21 21:05:17 +00001389 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001390 }
1391
sewardj2019a972011-03-07 16:04:07 +00001392 case Iop_Add8:
1393 case Iop_Add16:
1394 case Iop_Add32:
1395 case Iop_Add64:
1396 opkind = S390_ALU_ADD;
1397 break;
1398
1399 case Iop_Sub8:
1400 case Iop_Sub16:
1401 case Iop_Sub32:
1402 case Iop_Sub64:
1403 opkind = S390_ALU_SUB;
1404 is_commutative = False;
1405 break;
1406
1407 case Iop_And8:
1408 case Iop_And16:
1409 case Iop_And32:
1410 case Iop_And64:
1411 opkind = S390_ALU_AND;
1412 break;
1413
1414 case Iop_Or8:
1415 case Iop_Or16:
1416 case Iop_Or32:
1417 case Iop_Or64:
1418 opkind = S390_ALU_OR;
1419 break;
1420
1421 case Iop_Xor8:
1422 case Iop_Xor16:
1423 case Iop_Xor32:
1424 case Iop_Xor64:
1425 opkind = S390_ALU_XOR;
1426 break;
1427
1428 case Iop_Shl8:
1429 case Iop_Shl16:
1430 case Iop_Shl32:
1431 case Iop_Shl64:
1432 opkind = S390_ALU_LSH;
1433 is_commutative = False;
1434 break;
1435
1436 case Iop_Shr8:
1437 case Iop_Shr16:
1438 case Iop_Shr32:
1439 case Iop_Shr64:
1440 opkind = S390_ALU_RSH;
1441 is_commutative = False;
1442 break;
1443
1444 case Iop_Sar8:
1445 case Iop_Sar16:
1446 case Iop_Sar32:
1447 case Iop_Sar64:
1448 opkind = S390_ALU_RSHA;
1449 is_commutative = False;
1450 break;
1451
1452 default:
1453 goto irreducible;
1454 }
1455
1456 /* Pattern match: 0 - arg1 --> -arg1 */
1457 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1458 res = newVRegI(env);
1459 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1460 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1461 addInstr(env, insn);
1462
1463 return res;
1464 }
1465
1466 if (is_commutative) {
1467 order_commutative_operands(arg1, arg2);
1468 }
1469
1470 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1471 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1472 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001473
1474 /* As right shifts of one/two byte opreands are implemented using a
1475 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1476 switch (expr->Iex.Binop.op) {
1477 case Iop_Shr8:
1478 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1479 break;
1480 case Iop_Shr16:
1481 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1482 break;
1483 case Iop_Sar8:
1484 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1485 break;
1486 case Iop_Sar16:
1487 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1488 break;
1489 default:
1490 insn = s390_insn_move(size, res, h1);
1491 break;
1492 }
1493 addInstr(env, insn);
1494
sewardj2019a972011-03-07 16:04:07 +00001495 insn = s390_insn_alu(size, opkind, res, op2);
1496
1497 addInstr(env, insn);
1498
1499 return res;
1500 }
1501
1502 /* --------- UNARY OP --------- */
1503 case Iex_Unop: {
1504 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1505 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1506 s390_opnd_RMI opnd;
1507 s390_insn *insn;
1508 IRExpr *arg;
1509 HReg dst, h1;
1510 IROp unop, binop;
1511
1512 arg = expr->Iex.Unop.arg;
1513
1514 /* Special cases are handled here */
1515
1516 /* 32-bit multiply with 32-bit result or
1517 64-bit multiply with 64-bit result */
1518 unop = expr->Iex.Unop.op;
1519 binop = arg->Iex.Binop.op;
1520
1521 if ((arg->tag == Iex_Binop &&
1522 ((unop == Iop_64to32 &&
1523 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1524 (unop == Iop_128to64 &&
1525 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1526 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1527 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1528 dst = newVRegI(env); /* Result goes into a new register */
1529 addInstr(env, s390_insn_move(size, dst, h1));
1530 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1531
1532 return dst;
1533 }
1534
florian4d71a082011-12-18 00:08:17 +00001535 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001536 dst = newVRegI(env);
1537 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1538 addInstr(env, s390_insn_move(size, dst, h1));
1539
1540 return dst;
1541 }
1542
floriane38f6412012-12-21 17:32:12 +00001543 if (unop == Iop_ReinterpD64asI64) {
1544 dst = newVRegI(env);
1545 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1546 addInstr(env, s390_insn_move(size, dst, h1));
1547
1548 return dst;
1549 }
1550
florian5c539732013-02-14 14:27:12 +00001551 if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
1552 s390_dfp_unop_t dfpop;
1553 switch(unop) {
1554 case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
1555 case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
1556 default: goto irreducible;
1557 }
floriance9e3db2012-12-27 20:14:03 +00001558 dst = newVRegI(env);
1559 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
florian5c539732013-02-14 14:27:12 +00001560 addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
floriance9e3db2012-12-27 20:14:03 +00001561 return dst;
1562 }
1563
florian5c539732013-02-14 14:27:12 +00001564 if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
1565 s390_dfp_unop_t dfpop;
floriance9e3db2012-12-27 20:14:03 +00001566 HReg op_hi, op_lo, f13, f15;
florian5c539732013-02-14 14:27:12 +00001567
1568 switch(unop) {
1569 case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
1570 case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
1571 default: goto irreducible;
1572 }
floriance9e3db2012-12-27 20:14:03 +00001573 dst = newVRegI(env);
1574 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1575
1576 /* We use non-virtual registers r13 and r15 as pair */
1577 f13 = make_fpr(13);
1578 f15 = make_fpr(15);
1579
1580 /* operand --> (f13, f15) */
1581 addInstr(env, s390_insn_move(8, f13, op_hi));
1582 addInstr(env, s390_insn_move(8, f15, op_lo));
1583
florian5c539732013-02-14 14:27:12 +00001584 addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
floriance9e3db2012-12-27 20:14:03 +00001585 return dst;
1586 }
1587
sewardj2019a972011-03-07 16:04:07 +00001588 /* Expressions whose argument is 1-bit wide */
1589 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1590 s390_cc_t cond = s390_isel_cc(env, arg);
1591 dst = newVRegI(env); /* Result goes into a new register */
1592 addInstr(env, s390_insn_cc2bool(dst, cond));
1593
1594 switch (unop) {
1595 case Iop_1Uto8:
1596 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001597 /* Zero extend */
1598 mask.variant.imm = 1;
1599 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1600 break;
1601
sewardj2019a972011-03-07 16:04:07 +00001602 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001603 /* Zero extend */
1604 mask.variant.imm = 1;
1605 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001606 break;
1607
1608 case Iop_1Sto8:
1609 case Iop_1Sto16:
1610 case Iop_1Sto32:
1611 shift.variant.imm = 31;
1612 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1613 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1614 break;
1615
1616 case Iop_1Sto64:
1617 shift.variant.imm = 63;
1618 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1619 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1620 break;
1621
1622 default:
1623 goto irreducible;
1624 }
1625
1626 return dst;
1627 }
1628
1629 /* Regular processing */
1630
1631 if (unop == Iop_128to64) {
1632 HReg dst_hi, dst_lo;
1633
1634 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1635 return dst_lo;
1636 }
1637
1638 if (unop == Iop_128HIto64) {
1639 HReg dst_hi, dst_lo;
1640
1641 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1642 return dst_hi;
1643 }
1644
1645 dst = newVRegI(env); /* Result goes into a new register */
1646 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1647
1648 switch (unop) {
1649 case Iop_8Uto16:
1650 case Iop_8Uto32:
1651 case Iop_8Uto64:
1652 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1653 break;
1654
1655 case Iop_16Uto32:
1656 case Iop_16Uto64:
1657 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1658 break;
1659
1660 case Iop_32Uto64:
1661 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1662 break;
1663
1664 case Iop_8Sto16:
1665 case Iop_8Sto32:
1666 case Iop_8Sto64:
1667 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1668 break;
1669
1670 case Iop_16Sto32:
1671 case Iop_16Sto64:
1672 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1673 break;
1674
1675 case Iop_32Sto64:
1676 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1677 break;
1678
1679 case Iop_64to8:
1680 case Iop_64to16:
1681 case Iop_64to32:
1682 case Iop_32to8:
1683 case Iop_32to16:
1684 case Iop_16to8:
1685 /* Down-casts are no-ops. Upstream operations will only look at
1686 the bytes that make up the result of the down-cast. So there
1687 is no point setting the other bytes to 0. */
1688 insn = s390_opnd_copy(8, dst, opnd);
1689 break;
1690
1691 case Iop_64HIto32:
1692 addInstr(env, s390_opnd_copy(8, dst, opnd));
1693 shift.variant.imm = 32;
1694 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1695 break;
1696
1697 case Iop_32HIto16:
1698 addInstr(env, s390_opnd_copy(4, dst, opnd));
1699 shift.variant.imm = 16;
1700 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1701 break;
1702
1703 case Iop_16HIto8:
1704 addInstr(env, s390_opnd_copy(2, dst, opnd));
1705 shift.variant.imm = 8;
1706 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1707 break;
1708
1709 case Iop_Not8:
1710 case Iop_Not16:
1711 case Iop_Not32:
1712 case Iop_Not64:
1713 /* XOR with ffff... */
1714 mask.variant.imm = ~(ULong)0;
1715 addInstr(env, s390_opnd_copy(size, dst, opnd));
1716 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1717 break;
1718
1719 case Iop_Left8:
1720 case Iop_Left16:
1721 case Iop_Left32:
1722 case Iop_Left64:
1723 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1724 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1725 break;
1726
1727 case Iop_CmpwNEZ32:
1728 case Iop_CmpwNEZ64: {
1729 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1730 or -X will have a 1 in the MSB. */
1731 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1732 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1733 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1734 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1735 return dst;
1736 }
1737
1738 case Iop_Clz64: {
1739 HReg r10, r11;
1740
sewardj611b06e2011-03-24 08:57:29 +00001741 /* This will be implemented using FLOGR, if possible. So we need to
1742 set aside a pair of non-virtual registers. The result (number of
1743 left-most zero bits) will be in r10. The value in r11 is unspecified
1744 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001745 r10 = make_gpr(10);
1746 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001747
sewardj611b06e2011-03-24 08:57:29 +00001748 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001749 addInstr(env, s390_insn_move(8, dst, r10));
1750 return dst;
1751 }
1752
1753 default:
1754 goto irreducible;
1755 }
1756
1757 addInstr(env, insn);
1758
1759 return dst;
1760 }
1761
1762 /* --------- GET --------- */
1763 case Iex_Get: {
1764 HReg dst = newVRegI(env);
1765 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1766
1767 /* We never load more than 8 bytes from the guest state, because the
1768 floating point register pair is not contiguous. */
1769 vassert(size <= 8);
1770
1771 addInstr(env, s390_insn_load(size, dst, am));
1772
1773 return dst;
1774 }
1775
1776 case Iex_GetI:
1777 /* not needed */
1778 break;
1779
1780 /* --------- CCALL --------- */
1781 case Iex_CCall: {
1782 HReg dst = newVRegI(env);
sewardj74142b82013-08-08 10:28:59 +00001783 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
1784 UInt addToSp = 0;
1785 RetLoc rloc = mk_RetLoc_INVALID();
sewardj2019a972011-03-07 16:04:07 +00001786
sewardj74142b82013-08-08 10:28:59 +00001787 doHelperCall(&addToSp, &rloc, env, NULL, expr->Iex.CCall.cee,
1788 expr->Iex.CCall.retty, expr->Iex.CCall.args);
1789 vassert(is_sane_RetLoc(rloc));
1790 vassert(rloc.pri == RLPri_Int);
1791 vassert(addToSp == 0);
1792 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
1793
sewardj2019a972011-03-07 16:04:07 +00001794 return dst;
1795 }
1796
1797 /* --------- LITERAL --------- */
1798
1799 /* Load a literal into a register. Create a "load immediate"
1800 v-insn and return the register. */
1801 case Iex_Const: {
1802 ULong value;
1803 HReg dst = newVRegI(env);
1804 const IRConst *con = expr->Iex.Const.con;
1805
1806 /* Bitwise copy of the value. No sign/zero-extension */
1807 switch (con->tag) {
1808 case Ico_U64: value = con->Ico.U64; break;
1809 case Ico_U32: value = con->Ico.U32; break;
1810 case Ico_U16: value = con->Ico.U16; break;
1811 case Ico_U8: value = con->Ico.U8; break;
1812 default: vpanic("s390_isel_int_expr: invalid constant");
1813 }
1814
1815 addInstr(env, s390_insn_load_immediate(size, dst, value));
1816
1817 return dst;
1818 }
1819
1820 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00001821 case Iex_ITE: {
sewardj2019a972011-03-07 16:04:07 +00001822 IRExpr *cond_expr;
florian99dd03e2013-01-29 03:56:06 +00001823 HReg dst, r1;
sewardj009230b2013-01-26 11:47:55 +00001824 s390_opnd_RMI r0;
sewardj2019a972011-03-07 16:04:07 +00001825
florian99dd03e2013-01-29 03:56:06 +00001826 cond_expr = expr->Iex.ITE.cond;
sewardj2019a972011-03-07 16:04:07 +00001827
sewardj009230b2013-01-26 11:47:55 +00001828 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
1829
sewardj2019a972011-03-07 16:04:07 +00001830 dst = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00001831 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
1832 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
1833 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
sewardj2019a972011-03-07 16:04:07 +00001834
sewardj009230b2013-01-26 11:47:55 +00001835 s390_cc_t cc = s390_isel_cc(env, cond_expr);
sewardj2019a972011-03-07 16:04:07 +00001836
florian99dd03e2013-01-29 03:56:06 +00001837 addInstr(env, s390_insn_move(size, dst, r1));
sewardj009230b2013-01-26 11:47:55 +00001838 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
sewardj2019a972011-03-07 16:04:07 +00001839 return dst;
1840 }
1841
1842 default:
1843 break;
1844 }
1845
1846 /* We get here if no pattern matched. */
1847 irreducible:
1848 ppIRExpr(expr);
1849 vpanic("s390_isel_int_expr: cannot reduce tree");
1850}
1851
1852
1853static HReg
1854s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1855{
1856 HReg dst = s390_isel_int_expr_wrk(env, expr);
1857
1858 /* Sanity checks ... */
1859 vassert(hregClass(dst) == HRcInt64);
1860 vassert(hregIsVirtual(dst));
1861
1862 return dst;
1863}
1864
1865
1866static s390_opnd_RMI
1867s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1868{
1869 IRType ty = typeOfIRExpr(env->type_env, expr);
1870 s390_opnd_RMI dst;
1871
1872 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1873 ty == Ity_I64);
1874
1875 if (expr->tag == Iex_Load) {
1876 dst.tag = S390_OPND_AMODE;
1877 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1878 } else if (expr->tag == Iex_Get) {
1879 dst.tag = S390_OPND_AMODE;
1880 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1881 } else if (expr->tag == Iex_Const) {
1882 ULong value;
1883
1884 /* The bit pattern for the value will be stored as is in the least
1885 significant bits of VALUE. */
1886 switch (expr->Iex.Const.con->tag) {
1887 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1888 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1889 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1890 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1891 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1892 default:
1893 vpanic("s390_isel_int_expr_RMI");
1894 }
1895
1896 dst.tag = S390_OPND_IMMEDIATE;
1897 dst.variant.imm = value;
1898 } else {
1899 dst.tag = S390_OPND_REG;
1900 dst.variant.reg = s390_isel_int_expr(env, expr);
1901 }
1902
1903 return dst;
1904}
1905
1906
1907/*---------------------------------------------------------*/
1908/*--- ISEL: Floating point expressions (128 bit) ---*/
1909/*---------------------------------------------------------*/
1910static void
1911s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1912 IRExpr *expr)
1913{
1914 IRType ty = typeOfIRExpr(env->type_env, expr);
1915
1916 vassert(ty == Ity_F128);
1917
sewardj2019a972011-03-07 16:04:07 +00001918 switch (expr->tag) {
1919 case Iex_RdTmp:
1920 /* Return the virtual registers that hold the temporary. */
1921 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1922 return;
1923
1924 /* --------- LOAD --------- */
1925 case Iex_Load: {
1926 IRExpr *addr_hi, *addr_lo;
1927 s390_amode *am_hi, *am_lo;
1928
1929 if (expr->Iex.Load.end != Iend_BE)
1930 goto irreducible;
1931
1932 addr_hi = expr->Iex.Load.addr;
1933 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1934
1935 am_hi = s390_isel_amode(env, addr_hi);
1936 am_lo = s390_isel_amode(env, addr_lo);
1937
1938 *dst_hi = newVRegF(env);
1939 *dst_lo = newVRegF(env);
1940 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1941 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1942 return;
1943 }
1944
1945
1946 /* --------- GET --------- */
1947 case Iex_Get:
1948 /* This is not supported because loading 128-bit from the guest
1949 state is almost certainly wrong. Use get_fpr_pair instead. */
1950 vpanic("Iex_Get with F128 data");
1951
1952 /* --------- 4-ary OP --------- */
1953 case Iex_Qop:
1954 vpanic("Iex_Qop with F128 data");
1955
1956 /* --------- TERNARY OP --------- */
1957 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001958 IRTriop *triop = expr->Iex.Triop.details;
1959 IROp op = triop->op;
1960 IRExpr *left = triop->arg2;
1961 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001962 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001963 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1964
1965 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1966 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1967
1968 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1969 f12 = make_fpr(12);
1970 f13 = make_fpr(13);
1971 f14 = make_fpr(14);
1972 f15 = make_fpr(15);
1973
1974 /* 1st operand --> (f12, f14) */
1975 addInstr(env, s390_insn_move(8, f12, op1_hi));
1976 addInstr(env, s390_insn_move(8, f14, op1_lo));
1977
1978 /* 2nd operand --> (f13, f15) */
1979 addInstr(env, s390_insn_move(8, f13, op2_hi));
1980 addInstr(env, s390_insn_move(8, f15, op2_lo));
1981
1982 switch (op) {
1983 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1984 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1985 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1986 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1987 default:
1988 goto irreducible;
1989 }
1990
florian2c74d242012-09-12 19:38:42 +00001991 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1992 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001993
1994 /* Move result to virtual destination register */
1995 *dst_hi = newVRegF(env);
1996 *dst_lo = newVRegF(env);
1997 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1998 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1999
2000 return;
2001 }
2002
2003 /* --------- BINARY OP --------- */
2004 case Iex_Binop: {
sewardj2019a972011-03-07 16:04:07 +00002005 switch (expr->Iex.Binop.op) {
florian78d5ef72013-05-11 15:02:58 +00002006 case Iop_SqrtF128: {
2007 HReg op_hi, op_lo, f12, f13, f14, f15;
2008
2009 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2010 f12 = make_fpr(12);
2011 f13 = make_fpr(13);
2012 f14 = make_fpr(14);
2013 f15 = make_fpr(15);
2014
sewardj2019a972011-03-07 16:04:07 +00002015 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
2016
2017 /* operand --> (f13, f15) */
2018 addInstr(env, s390_insn_move(8, f13, op_hi));
2019 addInstr(env, s390_insn_move(8, f15, op_lo));
2020
florian2c74d242012-09-12 19:38:42 +00002021 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
2022 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
2023 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002024
2025 /* Move result to virtual destination registers */
2026 *dst_hi = newVRegF(env);
2027 *dst_lo = newVRegF(env);
2028 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2029 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2030 return;
florian78d5ef72013-05-11 15:02:58 +00002031 }
sewardj2019a972011-03-07 16:04:07 +00002032
2033 case Iop_F64HLtoF128:
2034 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
2035 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
2036 return;
2037
florian7ab421d2013-06-17 21:03:56 +00002038 case Iop_D32toF128:
2039 case Iop_D64toF128: {
2040 IRExpr *irrm;
2041 IRExpr *left;
2042 s390_dfp_round_t rm;
2043 HReg h1; /* virtual reg. to hold source */
2044 HReg f0, f2, f4, r1; /* real registers used by PFPO */
2045 s390_fp_conv_t fpconv;
2046
2047 switch (expr->Iex.Binop.op) {
2048 case Iop_D32toF128:
2049 fpconv = S390_FP_D32_TO_F128;
2050 break;
2051 case Iop_D64toF128:
2052 fpconv = S390_FP_D64_TO_F128;
2053 break;
2054 default: goto irreducible;
2055 }
2056
2057 f4 = make_fpr(4); /* source */
2058 f0 = make_fpr(0); /* destination */
2059 f2 = make_fpr(2); /* destination */
2060 r1 = make_gpr(1); /* GPR #1 clobbered */
2061 irrm = expr->Iex.Binop.arg1;
2062 left = expr->Iex.Binop.arg2;
2063 rm = get_dfp_rounding_mode(env, irrm);
2064 h1 = s390_isel_dfp_expr(env, left);
2065 addInstr(env, s390_insn_move(8, f4, h1));
2066 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
2067 f4, INVALID_HREG, r1, rm));
2068 /* (f0, f2) --> destination */
2069 *dst_hi = newVRegF(env);
2070 *dst_lo = newVRegF(env);
2071 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2072 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2073
2074 return;
2075 }
2076
florian78d5ef72013-05-11 15:02:58 +00002077 case Iop_D128toF128: {
2078 IRExpr *irrm;
2079 IRExpr *left;
2080 s390_dfp_round_t rm;
2081 HReg op_hi, op_lo;
2082 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2083
2084 f4 = make_fpr(4); /* source */
2085 f6 = make_fpr(6); /* source */
2086 f0 = make_fpr(0); /* destination */
2087 f2 = make_fpr(2); /* destination */
2088 r1 = make_gpr(1); /* GPR #1 clobbered */
2089
2090 irrm = expr->Iex.Binop.arg1;
2091 left = expr->Iex.Binop.arg2;
2092 rm = get_dfp_rounding_mode(env, irrm);
2093 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2094 /* operand --> (f4, f6) */
2095 addInstr(env, s390_insn_move(8, f4, op_hi));
2096 addInstr(env, s390_insn_move(8, f6, op_lo));
2097 addInstr(env, s390_insn_fp128_convert(16, S390_FP_D128_TO_F128, f0, f2,
2098 f4, f6, r1, rm));
2099 /* (f0, f2) --> destination */
2100 *dst_hi = newVRegF(env);
2101 *dst_lo = newVRegF(env);
2102 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2103 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2104
2105 return;
2106 }
2107
sewardj2019a972011-03-07 16:04:07 +00002108 default:
2109 goto irreducible;
2110 }
2111 }
2112
2113 /* --------- UNARY OP --------- */
2114 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00002115 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00002116 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002117 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002118 HReg op_hi, op_lo, op, f12, f13, f14, f15;
2119
2120 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2121 f12 = make_fpr(12);
2122 f13 = make_fpr(13);
2123 f14 = make_fpr(14);
2124 f15 = make_fpr(15);
2125
florian66e596d2012-09-07 15:00:53 +00002126 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00002127 case Iop_NegF128:
2128 if (left->tag == Iex_Unop &&
2129 (left->Iex.Unop.op == Iop_AbsF32 ||
2130 left->Iex.Unop.op == Iop_AbsF64))
2131 bfpop = S390_BFP_NABS;
2132 else
2133 bfpop = S390_BFP_NEG;
2134 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00002135 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2136 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2137 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2138 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2139 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2140 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2141 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00002142 default:
2143 goto irreducible;
2144 }
2145
2146 float128_opnd:
2147 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2148
2149 /* operand --> (f13, f15) */
2150 addInstr(env, s390_insn_move(8, f13, op_hi));
2151 addInstr(env, s390_insn_move(8, f15, op_lo));
2152
florian2c74d242012-09-12 19:38:42 +00002153 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002154 goto move_dst;
2155
2156 convert_float:
2157 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002158 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002159 goto move_dst;
2160
2161 convert_int:
2162 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002163 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002164 goto move_dst;
2165
2166 move_dst:
2167 /* Move result to virtual destination registers */
2168 *dst_hi = newVRegF(env);
2169 *dst_lo = newVRegF(env);
2170 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2171 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2172 return;
2173 }
2174
2175 default:
2176 goto irreducible;
2177 }
2178
2179 /* We get here if no pattern matched. */
2180 irreducible:
2181 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002182 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002183}
2184
2185/* Compute a 128-bit value into two 64-bit registers. These may be either
2186 real or virtual regs; in any case they must not be changed by subsequent
2187 code emitted by the caller. */
2188static void
2189s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2190{
2191 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2192
2193 /* Sanity checks ... */
2194 vassert(hregIsVirtual(*dst_hi));
2195 vassert(hregIsVirtual(*dst_lo));
2196 vassert(hregClass(*dst_hi) == HRcFlt64);
2197 vassert(hregClass(*dst_lo) == HRcFlt64);
2198}
2199
2200
2201/*---------------------------------------------------------*/
2202/*--- ISEL: Floating point expressions (64 bit) ---*/
2203/*---------------------------------------------------------*/
2204
2205static HReg
2206s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2207{
2208 IRType ty = typeOfIRExpr(env->type_env, expr);
2209 UChar size;
2210
2211 vassert(ty == Ity_F32 || ty == Ity_F64);
2212
2213 size = sizeofIRType(ty);
2214
2215 switch (expr->tag) {
2216 case Iex_RdTmp:
2217 /* Return the virtual register that holds the temporary. */
2218 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2219
2220 /* --------- LOAD --------- */
2221 case Iex_Load: {
2222 HReg dst = newVRegF(env);
2223 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2224
2225 if (expr->Iex.Load.end != Iend_BE)
2226 goto irreducible;
2227
2228 addInstr(env, s390_insn_load(size, dst, am));
2229
2230 return dst;
2231 }
2232
2233 /* --------- GET --------- */
2234 case Iex_Get: {
2235 HReg dst = newVRegF(env);
2236 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2237
2238 addInstr(env, s390_insn_load(size, dst, am));
2239
2240 return dst;
2241 }
2242
2243 /* --------- LITERAL --------- */
2244
2245 /* Load a literal into a register. Create a "load immediate"
2246 v-insn and return the register. */
2247 case Iex_Const: {
2248 ULong value;
2249 HReg dst = newVRegF(env);
2250 const IRConst *con = expr->Iex.Const.con;
2251
2252 /* Bitwise copy of the value. No sign/zero-extension */
2253 switch (con->tag) {
2254 case Ico_F32i: value = con->Ico.F32i; break;
2255 case Ico_F64i: value = con->Ico.F64i; break;
2256 default: vpanic("s390_isel_float_expr: invalid constant");
2257 }
2258
2259 if (value != 0) vpanic("cannot load immediate floating point constant");
2260
2261 addInstr(env, s390_insn_load_immediate(size, dst, value));
2262
2263 return dst;
2264 }
2265
2266 /* --------- 4-ary OP --------- */
2267 case Iex_Qop: {
2268 HReg op1, op2, op3, dst;
2269 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002270
florian5906a6b2012-10-16 02:53:33 +00002271 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002272 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002273 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002274 dst = newVRegF(env);
2275 addInstr(env, s390_insn_move(size, dst, op1));
2276
florian96d7cc32012-06-01 20:41:24 +00002277 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002278 case Iop_MAddF32:
2279 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2280 case Iop_MSubF32:
2281 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2282
2283 default:
2284 goto irreducible;
2285 }
2286
florian2c74d242012-09-12 19:38:42 +00002287 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2288 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002289 return dst;
2290 }
2291
2292 /* --------- TERNARY OP --------- */
2293 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002294 IRTriop *triop = expr->Iex.Triop.details;
2295 IROp op = triop->op;
2296 IRExpr *left = triop->arg2;
2297 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002298 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002299 HReg h1, op2, dst;
2300
2301 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2302 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2303 dst = newVRegF(env);
2304 addInstr(env, s390_insn_move(size, dst, h1));
2305 switch (op) {
2306 case Iop_AddF32:
2307 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2308 case Iop_SubF32:
2309 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2310 case Iop_MulF32:
2311 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2312 case Iop_DivF32:
2313 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2314
2315 default:
2316 goto irreducible;
2317 }
2318
florian2c74d242012-09-12 19:38:42 +00002319 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2320 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002321 return dst;
2322 }
2323
2324 /* --------- BINARY OP --------- */
2325 case Iex_Binop: {
2326 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002327 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002328 IRExpr *left = expr->Iex.Binop.arg2;
2329 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002330 s390_bfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002331 s390_fp_conv_t fpconv;
sewardj2019a972011-03-07 16:04:07 +00002332
2333 switch (op) {
2334 case Iop_SqrtF32:
2335 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002336 h1 = s390_isel_float_expr(env, left);
2337 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002338 set_bfp_rounding_mode_in_fpc(env, irrm);
2339 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002340 return dst;
sewardj2019a972011-03-07 16:04:07 +00002341
florian9fcff4c2012-09-10 03:09:04 +00002342 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2343 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2344 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2345 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2346 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2347 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2348 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
florian7ab421d2013-06-17 21:03:56 +00002349 case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp;
2350 case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp;
2351 case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp;
florian78d5ef72013-05-11 15:02:58 +00002352 case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp;
florian7ab421d2013-06-17 21:03:56 +00002353 case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128;
florian78d5ef72013-05-11 15:02:58 +00002354 case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00002355
florian9fcff4c2012-09-10 03:09:04 +00002356 convert_float:
2357 h1 = s390_isel_float_expr(env, left);
2358 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002359
florian9fcff4c2012-09-10 03:09:04 +00002360 convert_int:
2361 h1 = s390_isel_int_expr(env, left);
2362 goto convert;
2363
florian2c74d242012-09-12 19:38:42 +00002364 convert: {
florian125e20d2012-10-07 15:42:37 +00002365 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002366 /* convert-from-fixed and load-rounded have a rounding mode field
2367 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002368 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002369 if (s390_host_has_fpext) {
2370 rounding_mode = get_bfp_rounding_mode(env, irrm);
2371 } else {
2372 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002373 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002374 }
florian9fcff4c2012-09-10 03:09:04 +00002375 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2376 rounding_mode));
2377 return dst;
florian2c74d242012-09-12 19:38:42 +00002378 }
florian78d5ef72013-05-11 15:02:58 +00002379
2380 convert_dfp: {
2381 s390_dfp_round_t rm;
2382 HReg f0, f4, r1; /* real registers used by PFPO */
2383
2384 f4 = make_fpr(4); /* source */
2385 f0 = make_fpr(0); /* destination */
2386 r1 = make_gpr(1); /* GPR #1 clobbered */
2387 h1 = s390_isel_dfp_expr(env, left);
2388 dst = newVRegF(env);
2389 rm = get_dfp_rounding_mode(env, irrm);
2390 /* operand --> f4 */
2391 addInstr(env, s390_insn_move(8, f4, h1));
2392 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2393 /* f0 --> destination */
2394 addInstr(env, s390_insn_move(8, dst, f0));
2395 return dst;
2396 }
2397
2398 convert_dfp128: {
2399 s390_dfp_round_t rm;
2400 HReg op_hi, op_lo;
2401 HReg f0, f4, f6, r1; /* real registers used by PFPO */
2402
2403 f4 = make_fpr(4); /* source */
2404 f6 = make_fpr(6); /* source */
2405 f0 = make_fpr(0); /* destination */
2406 r1 = make_gpr(1); /* GPR #1 clobbered */
2407 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2408 dst = newVRegF(env);
2409 rm = get_dfp_rounding_mode(env, irrm);
2410 /* operand --> (f4, f6) */
2411 addInstr(env, s390_insn_move(8, f4, op_hi));
2412 addInstr(env, s390_insn_move(8, f6, op_lo));
2413 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
2414 f4, f6, r1, rm));
2415 /* f0 --> destination */
2416 addInstr(env, s390_insn_move(8, dst, f0));
2417 return dst;
2418 }
2419
sewardj2019a972011-03-07 16:04:07 +00002420 default:
2421 goto irreducible;
2422
2423 case Iop_F128toF64:
2424 case Iop_F128toF32: {
floriana2039c52013-12-10 16:51:15 +00002425 HReg op_hi, op_lo, f12, f13, f14, f15;
florian125e20d2012-10-07 15:42:37 +00002426 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002427
florian9fcff4c2012-09-10 03:09:04 +00002428 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2429 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002430
florian9fcff4c2012-09-10 03:09:04 +00002431 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002432
floriana2039c52013-12-10 16:51:15 +00002433 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2434 f12 = make_fpr(12);
sewardj2019a972011-03-07 16:04:07 +00002435 f13 = make_fpr(13);
floriana2039c52013-12-10 16:51:15 +00002436 f14 = make_fpr(14);
sewardj2019a972011-03-07 16:04:07 +00002437 f15 = make_fpr(15);
2438
2439 /* operand --> (f13, f15) */
2440 addInstr(env, s390_insn_move(8, f13, op_hi));
2441 addInstr(env, s390_insn_move(8, f15, op_lo));
2442
floriana2039c52013-12-10 16:51:15 +00002443 /* result --> (f12, f14) */
2444
florian2c74d242012-09-12 19:38:42 +00002445 /* load-rounded has a rounding mode field when the floating point
2446 extension facility is installed. */
2447 if (s390_host_has_fpext) {
2448 rounding_mode = get_bfp_rounding_mode(env, irrm);
2449 } else {
2450 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002451 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002452 }
floriana2039c52013-12-10 16:51:15 +00002453
2454 addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14,
2455 f13, f15, rounding_mode));
2456 dst = newVRegF(env);
2457 addInstr(env, s390_insn_move(8, dst, f12));
2458
sewardj2019a972011-03-07 16:04:07 +00002459 return dst;
2460 }
2461 }
sewardj2019a972011-03-07 16:04:07 +00002462 }
2463
2464 /* --------- UNARY OP --------- */
2465 case Iex_Unop: {
2466 IROp op = expr->Iex.Unop.op;
2467 IRExpr *left = expr->Iex.Unop.arg;
2468 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002469 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002470 HReg h1, dst;
2471
2472 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2473 HReg dst_hi, dst_lo;
2474
2475 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2476 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2477 }
2478
florian4d71a082011-12-18 00:08:17 +00002479 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002480 dst = newVRegF(env);
2481 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2482 addInstr(env, s390_insn_move(size, dst, h1));
2483
2484 return dst;
2485 }
2486
2487 switch (op) {
2488 case Iop_NegF32:
2489 case Iop_NegF64:
2490 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002491 (left->Iex.Unop.op == Iop_AbsF32 ||
2492 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002493 bfpop = S390_BFP_NABS;
2494 else
2495 bfpop = S390_BFP_NEG;
2496 break;
2497
2498 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002499 case Iop_AbsF64:
2500 bfpop = S390_BFP_ABS;
2501 break;
2502
2503 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2504 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2505 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2506
2507 convert_float1:
2508 h1 = s390_isel_float_expr(env, left);
2509 goto convert1;
2510
2511 convert_int1:
2512 h1 = s390_isel_int_expr(env, left);
2513 goto convert1;
2514
2515 convert1:
2516 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002517 /* No rounding mode is needed for these conversions. Just stick
2518 one in. It won't be used later on. */
2519 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002520 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002521 return dst;
2522
sewardj2019a972011-03-07 16:04:07 +00002523 default:
2524 goto irreducible;
2525 }
2526
2527 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002528 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002529 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002530 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002531 return dst;
2532 }
2533
2534 default:
2535 goto irreducible;
2536 }
2537
2538 /* We get here if no pattern matched. */
2539 irreducible:
2540 ppIRExpr(expr);
2541 vpanic("s390_isel_float_expr: cannot reduce tree");
2542}
2543
2544
2545static HReg
2546s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2547{
2548 HReg dst = s390_isel_float_expr_wrk(env, expr);
2549
2550 /* Sanity checks ... */
2551 vassert(hregClass(dst) == HRcFlt64);
2552 vassert(hregIsVirtual(dst));
2553
2554 return dst;
2555}
2556
2557
2558/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002559/*--- ISEL: Decimal point expressions (128 bit) ---*/
2560/*---------------------------------------------------------*/
2561static void
2562s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2563 IRExpr *expr)
2564{
2565 IRType ty = typeOfIRExpr(env->type_env, expr);
2566
2567 vassert(ty == Ity_D128);
2568
2569 switch (expr->tag) {
2570 case Iex_RdTmp:
2571 /* Return the virtual registers that hold the temporary. */
2572 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2573 return;
2574
2575 /* --------- LOAD --------- */
2576 case Iex_Load: {
2577 IRExpr *addr_hi, *addr_lo;
2578 s390_amode *am_hi, *am_lo;
2579
2580 if (expr->Iex.Load.end != Iend_BE)
2581 goto irreducible;
2582
2583 addr_hi = expr->Iex.Load.addr;
2584 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2585
2586 am_hi = s390_isel_amode(env, addr_hi);
2587 am_lo = s390_isel_amode(env, addr_lo);
2588
2589 *dst_hi = newVRegF(env);
2590 *dst_lo = newVRegF(env);
2591 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2592 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2593 return;
2594 }
2595
2596 /* --------- GET --------- */
2597 case Iex_Get:
2598 /* This is not supported because loading 128-bit from the guest
2599 state is almost certainly wrong. Use get_dpr_pair instead. */
2600 vpanic("Iex_Get with D128 data");
2601
2602 /* --------- 4-ary OP --------- */
2603 case Iex_Qop:
2604 vpanic("Iex_Qop with D128 data");
2605
2606 /* --------- TERNARY OP --------- */
2607 case Iex_Triop: {
2608 IRTriop *triop = expr->Iex.Triop.details;
2609 IROp op = triop->op;
2610 IRExpr *irrm = triop->arg1;
2611 IRExpr *left = triop->arg2;
2612 IRExpr *right = triop->arg3;
2613 s390_dfp_round_t rounding_mode;
2614 s390_dfp_binop_t dfpop;
2615 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2616
floriane38f6412012-12-21 17:32:12 +00002617 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2618 (f12, f14) as op2 and (f13, f15) as destination) */
2619 f9 = make_fpr(9);
2620 f11 = make_fpr(11);
2621 f12 = make_fpr(12);
2622 f13 = make_fpr(13);
2623 f14 = make_fpr(14);
2624 f15 = make_fpr(15);
2625
floriane38f6412012-12-21 17:32:12 +00002626 switch (op) {
florian5c539732013-02-14 14:27:12 +00002627 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128;
2628 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128;
2629 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128;
2630 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128;
2631 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
2632
2633 evaluate_dfp128: {
2634 /* Process 1st operand */
2635 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
2636 /* 1st operand --> (f9, f11) */
2637 addInstr(env, s390_insn_move(8, f9, op1_hi));
2638 addInstr(env, s390_insn_move(8, f11, op1_lo));
2639
2640 /* Process 2nd operand */
2641 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2642 /* 2nd operand --> (f12, f14) */
2643 addInstr(env, s390_insn_move(8, f12, op2_hi));
2644 addInstr(env, s390_insn_move(8, f14, op2_lo));
2645
2646 /* DFP arithmetic ops take rounding mode only when fpext is
2647 installed. But, DFP quantize operation takes rm irrespective
2648 of fpext facility . */
floriand18287d2013-02-21 03:03:05 +00002649 if (s390_host_has_fpext || op == Iop_QuantizeD128) {
florian5c539732013-02-14 14:27:12 +00002650 rounding_mode = get_dfp_rounding_mode(env, irrm);
2651 } else {
2652 set_dfp_rounding_mode_in_fpc(env, irrm);
2653 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2654 }
2655 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2656 f12, f14, rounding_mode));
2657 /* Move result to virtual destination register */
2658 *dst_hi = newVRegF(env);
2659 *dst_lo = newVRegF(env);
2660 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2661 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2662 return;
2663 }
2664
2665 case Iop_SignificanceRoundD128: {
2666 /* Process 1st operand */
2667 HReg op1 = s390_isel_int_expr(env, left);
2668 /* Process 2nd operand */
2669 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2670 /* 2nd operand --> (f12, f14) */
2671 addInstr(env, s390_insn_move(8, f12, op2_hi));
2672 addInstr(env, s390_insn_move(8, f14, op2_lo));
2673
2674 rounding_mode = get_dfp_rounding_mode(env, irrm);
2675 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14,
2676 rounding_mode));
2677 /* Move result to virtual destination register */
2678 *dst_hi = newVRegF(env);
2679 *dst_lo = newVRegF(env);
2680 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2681 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2682 return;
2683 }
2684
floriane38f6412012-12-21 17:32:12 +00002685 default:
2686 goto irreducible;
2687 }
floriane38f6412012-12-21 17:32:12 +00002688 }
2689
2690 /* --------- BINARY OP --------- */
2691 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002692
floriane38f6412012-12-21 17:32:12 +00002693 switch (expr->Iex.Binop.op) {
2694 case Iop_D64HLtoD128:
2695 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2696 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2697 return;
2698
florian1b901d42013-01-01 22:19:24 +00002699 case Iop_ShlD128:
florian5c539732013-02-14 14:27:12 +00002700 case Iop_ShrD128:
2701 case Iop_InsertExpD128: {
florian1b901d42013-01-01 22:19:24 +00002702 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2703 s390_dfp_intop_t intop;
florian5c539732013-02-14 14:27:12 +00002704 IRExpr *dfp_op;
2705 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00002706
2707 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00002708 case Iop_ShlD128: /* (D128, I64) -> D128 */
2709 intop = S390_DFP_SHIFT_LEFT;
2710 dfp_op = expr->Iex.Binop.arg1;
2711 int_op = expr->Iex.Binop.arg2;
2712 break;
2713 case Iop_ShrD128: /* (D128, I64) -> D128 */
2714 intop = S390_DFP_SHIFT_RIGHT;
2715 dfp_op = expr->Iex.Binop.arg1;
2716 int_op = expr->Iex.Binop.arg2;
2717 break;
2718 case Iop_InsertExpD128: /* (I64, D128) -> D128 */
2719 intop = S390_DFP_INSERT_EXP;
2720 int_op = expr->Iex.Binop.arg1;
2721 dfp_op = expr->Iex.Binop.arg2;
2722 break;
florian1b901d42013-01-01 22:19:24 +00002723 default: goto irreducible;
2724 }
2725
2726 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2727 f9 = make_fpr(9); /* 128 bit dfp operand */
2728 f11 = make_fpr(11);
2729
2730 f13 = make_fpr(13); /* 128 bit dfp destination */
2731 f15 = make_fpr(15);
2732
florian5c539732013-02-14 14:27:12 +00002733 /* Process dfp operand */
2734 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
2735 /* op1 -> (f9,f11) */
florian1b901d42013-01-01 22:19:24 +00002736 addInstr(env, s390_insn_move(8, f9, op1_hi));
2737 addInstr(env, s390_insn_move(8, f11, op1_lo));
2738
florian5c539732013-02-14 14:27:12 +00002739 op2 = s390_isel_int_expr(env, int_op); /* int operand */
florian1b901d42013-01-01 22:19:24 +00002740
2741 addInstr(env,
2742 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2743
2744 /* Move result to virtual destination register */
2745 *dst_hi = newVRegF(env);
2746 *dst_lo = newVRegF(env);
2747 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2748 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2749 return;
2750 }
2751
florian7ab421d2013-06-17 21:03:56 +00002752 case Iop_F32toD128:
florian78d5ef72013-05-11 15:02:58 +00002753 case Iop_F64toD128: {
2754 IRExpr *irrm;
2755 IRExpr *left;
2756 s390_dfp_round_t rm;
2757 HReg h1; /* virtual reg. to hold source */
2758 HReg f0, f2, f4, r1; /* real registers used by PFPO */
florian7ab421d2013-06-17 21:03:56 +00002759 s390_fp_conv_t fpconv;
2760
2761 switch (expr->Iex.Binop.op) {
2762 case Iop_F32toD128: /* (D128, I64) -> D128 */
2763 fpconv = S390_FP_F32_TO_D128;
2764 break;
2765 case Iop_F64toD128: /* (D128, I64) -> D128 */
2766 fpconv = S390_FP_F64_TO_D128;
2767 break;
2768 default: goto irreducible;
2769 }
florian78d5ef72013-05-11 15:02:58 +00002770
2771 f4 = make_fpr(4); /* source */
2772 f0 = make_fpr(0); /* destination */
2773 f2 = make_fpr(2); /* destination */
2774 r1 = make_gpr(1); /* GPR #1 clobbered */
2775 irrm = expr->Iex.Binop.arg1;
2776 left = expr->Iex.Binop.arg2;
2777 rm = get_dfp_rounding_mode(env, irrm);
2778 h1 = s390_isel_float_expr(env, left);
2779 addInstr(env, s390_insn_move(8, f4, h1));
florian7ab421d2013-06-17 21:03:56 +00002780 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
florian78d5ef72013-05-11 15:02:58 +00002781 f4, INVALID_HREG, r1, rm));
2782 /* (f0, f2) --> destination */
2783 *dst_hi = newVRegF(env);
2784 *dst_lo = newVRegF(env);
2785 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2786 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2787
2788 return;
2789 }
2790
2791 case Iop_F128toD128: {
2792 IRExpr *irrm;
2793 IRExpr *left;
2794 s390_dfp_round_t rm;
2795 HReg op_hi, op_lo;
2796 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2797
2798 f4 = make_fpr(4); /* source */
2799 f6 = make_fpr(6); /* source */
2800 f0 = make_fpr(0); /* destination */
2801 f2 = make_fpr(2); /* destination */
2802 r1 = make_gpr(1); /* GPR #1 clobbered */
2803
2804 irrm = expr->Iex.Binop.arg1;
2805 left = expr->Iex.Binop.arg2;
2806 rm = get_dfp_rounding_mode(env, irrm);
2807 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2808 /* operand --> (f4, f6) */
2809 addInstr(env, s390_insn_move(8, f4, op_hi));
2810 addInstr(env, s390_insn_move(8, f6, op_lo));
2811 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2,
2812 f4, f6, r1, rm));
2813 /* (f0, f2) --> destination */
2814 *dst_hi = newVRegF(env);
2815 *dst_lo = newVRegF(env);
2816 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2817 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2818
2819 return;
2820 }
2821
floriane38f6412012-12-21 17:32:12 +00002822 default:
2823 goto irreducible;
2824 }
2825 }
2826
2827 /* --------- UNARY OP --------- */
2828 case Iex_Unop: {
2829 IRExpr *left = expr->Iex.Unop.arg;
2830 s390_dfp_conv_t conv;
floriane38f6412012-12-21 17:32:12 +00002831 HReg op, f12, f14;
2832
floriana887acd2013-02-08 23:32:54 +00002833 /* We use non-virtual registers as pairs (f12, f14)) */
floriane38f6412012-12-21 17:32:12 +00002834 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00002835 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00002836
2837 switch (expr->Iex.Unop.op) {
2838 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002839 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
floriana887acd2013-02-08 23:32:54 +00002840 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002841 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2842 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002843 default:
2844 goto irreducible;
2845 }
2846
2847 convert_dfp:
2848 op = s390_isel_dfp_expr(env, left);
2849 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2850 goto move_dst;
2851
florian5f034622013-01-13 02:29:05 +00002852 convert_int:
2853 op = s390_isel_int_expr(env, left);
2854 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2855 goto move_dst;
2856
floriane38f6412012-12-21 17:32:12 +00002857 move_dst:
2858 /* Move result to virtual destination registers */
2859 *dst_hi = newVRegF(env);
2860 *dst_lo = newVRegF(env);
2861 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2862 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2863 return;
2864 }
2865
2866 default:
2867 goto irreducible;
2868 }
2869
2870 /* We get here if no pattern matched. */
2871 irreducible:
2872 ppIRExpr(expr);
2873 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2874
2875}
2876
2877
2878/* Compute a 128-bit value into two 64-bit registers. These may be either
2879 real or virtual regs; in any case they must not be changed by subsequent
2880 code emitted by the caller. */
2881static void
2882s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2883{
2884 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2885
2886 /* Sanity checks ... */
2887 vassert(hregIsVirtual(*dst_hi));
2888 vassert(hregIsVirtual(*dst_lo));
2889 vassert(hregClass(*dst_hi) == HRcFlt64);
2890 vassert(hregClass(*dst_lo) == HRcFlt64);
2891}
2892
2893
2894/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002895/*--- ISEL: Decimal point expressions (64 bit) ---*/
2896/*---------------------------------------------------------*/
2897
2898static HReg
2899s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2900{
2901 IRType ty = typeOfIRExpr(env->type_env, expr);
2902 UChar size;
2903
floriane38f6412012-12-21 17:32:12 +00002904 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002905
2906 size = sizeofIRType(ty);
2907
2908 switch (expr->tag) {
2909 case Iex_RdTmp:
2910 /* Return the virtual register that holds the temporary. */
2911 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2912
2913 /* --------- LOAD --------- */
2914 case Iex_Load: {
2915 HReg dst = newVRegF(env);
2916 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2917
2918 if (expr->Iex.Load.end != Iend_BE)
2919 goto irreducible;
2920
2921 addInstr(env, s390_insn_load(size, dst, am));
2922
2923 return dst;
2924 }
2925
2926 /* --------- GET --------- */
2927 case Iex_Get: {
2928 HReg dst = newVRegF(env);
2929 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2930
2931 addInstr(env, s390_insn_load(size, dst, am));
2932
2933 return dst;
2934 }
2935
floriane38f6412012-12-21 17:32:12 +00002936 /* --------- BINARY OP --------- */
2937 case Iex_Binop: {
2938 IROp op = expr->Iex.Binop.op;
2939 IRExpr *irrm = expr->Iex.Binop.arg1;
2940 IRExpr *left = expr->Iex.Binop.arg2;
2941 HReg h1, dst;
2942 s390_dfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002943 s390_fp_conv_t fpconv;
floriane38f6412012-12-21 17:32:12 +00002944
2945 switch (op) {
2946 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
floriana887acd2013-02-08 23:32:54 +00002947 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002948 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
florian7ab421d2013-06-17 21:03:56 +00002949 case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp;
2950 case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp;
2951 case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp;
florian78d5ef72013-05-11 15:02:58 +00002952 case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
florian7ab421d2013-06-17 21:03:56 +00002953 case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128;
2954 case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128;
floriane38f6412012-12-21 17:32:12 +00002955
2956 convert_dfp:
2957 h1 = s390_isel_dfp_expr(env, left);
2958 goto convert;
2959
florian5f034622013-01-13 02:29:05 +00002960 convert_int:
2961 h1 = s390_isel_int_expr(env, left);
2962 goto convert;
2963
floriane38f6412012-12-21 17:32:12 +00002964 convert: {
2965 s390_dfp_round_t rounding_mode;
2966 /* convert-from-fixed and load-rounded have a rounding mode field
2967 when the floating point extension facility is installed. */
2968 dst = newVRegF(env);
2969 if (s390_host_has_fpext) {
2970 rounding_mode = get_dfp_rounding_mode(env, irrm);
2971 } else {
2972 set_dfp_rounding_mode_in_fpc(env, irrm);
2973 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2974 }
2975 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2976 rounding_mode));
2977 return dst;
2978 }
floriane38f6412012-12-21 17:32:12 +00002979
florian78d5ef72013-05-11 15:02:58 +00002980 convert_bfp: {
2981 s390_dfp_round_t rm;
2982 HReg f0, f4, r1; /* real registers used by PFPO */
2983
2984 f4 = make_fpr(4); /* source */
2985 f0 = make_fpr(0); /* destination */
2986 r1 = make_gpr(1); /* GPR #1 clobbered */
2987 h1 = s390_isel_float_expr(env, left);
2988 dst = newVRegF(env);
2989 rm = get_dfp_rounding_mode(env, irrm);
2990 /* operand --> f4 */
2991 addInstr(env, s390_insn_move(8, f4, h1));
2992 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2993 /* f0 --> destination */
2994 addInstr(env, s390_insn_move(8, dst, f0));
2995 return dst;
2996 }
2997
florian7ab421d2013-06-17 21:03:56 +00002998 convert_bfp128: {
2999 s390_dfp_round_t rm;
3000 HReg op_hi, op_lo;
3001 HReg f0, f4, f6, r1; /* real registers used by PFPO */
3002
3003 f4 = make_fpr(4); /* source */
3004 f6 = make_fpr(6); /* source */
3005 f0 = make_fpr(0); /* destination */
3006 r1 = make_gpr(1); /* GPR #1 clobbered */
3007 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
3008 dst = newVRegF(env);
3009 rm = get_dfp_rounding_mode(env, irrm);
3010 /* operand --> (f4, f6) */
3011 addInstr(env, s390_insn_move(8, f4, op_hi));
3012 addInstr(env, s390_insn_move(8, f6, op_lo));
3013 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
3014 f4, f6, r1, rm));
3015 /* f0 --> destination */
3016 addInstr(env, s390_insn_move(8, dst, f0));
3017 return dst;
3018 }
3019
floriane38f6412012-12-21 17:32:12 +00003020 case Iop_D128toD64: {
floriana2039c52013-12-10 16:51:15 +00003021 HReg op_hi, op_lo, f12, f13, f14, f15;
floriane38f6412012-12-21 17:32:12 +00003022 s390_dfp_round_t rounding_mode;
3023
3024 conv = S390_DFP_D128_TO_D64;
3025
3026 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
3027
floriana2039c52013-12-10 16:51:15 +00003028 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */
3029 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00003030 f13 = make_fpr(13);
floriana2039c52013-12-10 16:51:15 +00003031 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00003032 f15 = make_fpr(15);
3033
3034 /* operand --> (f13, f15) */
3035 addInstr(env, s390_insn_move(8, f13, op_hi));
3036 addInstr(env, s390_insn_move(8, f15, op_lo));
3037
floriana2039c52013-12-10 16:51:15 +00003038 /* result --> (f12, f14) */
3039
floriane38f6412012-12-21 17:32:12 +00003040 /* load-rounded has a rounding mode field when the floating point
3041 extension facility is installed. */
3042 if (s390_host_has_fpext) {
3043 rounding_mode = get_dfp_rounding_mode(env, irrm);
3044 } else {
3045 set_dfp_rounding_mode_in_fpc(env, irrm);
3046 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3047 }
floriana2039c52013-12-10 16:51:15 +00003048 addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14,
3049 f13, f15, rounding_mode));
3050 dst = newVRegF(env);
3051 addInstr(env, s390_insn_move(8, dst, f12));
3052
floriane38f6412012-12-21 17:32:12 +00003053 return dst;
3054 }
3055
florian1b901d42013-01-01 22:19:24 +00003056 case Iop_ShlD64:
florian5c539732013-02-14 14:27:12 +00003057 case Iop_ShrD64:
3058 case Iop_InsertExpD64: {
florian1b901d42013-01-01 22:19:24 +00003059 HReg op2;
3060 HReg op3;
florian5c539732013-02-14 14:27:12 +00003061 IRExpr *dfp_op;
3062 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00003063 s390_dfp_intop_t intop;
florian1b901d42013-01-01 22:19:24 +00003064
3065 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00003066 case Iop_ShlD64: /* (D64, I64) -> D64 */
3067 intop = S390_DFP_SHIFT_LEFT;
3068 dfp_op = expr->Iex.Binop.arg1;
3069 int_op = expr->Iex.Binop.arg2;
3070 break;
3071 case Iop_ShrD64: /* (D64, I64) -> D64 */
3072 intop = S390_DFP_SHIFT_RIGHT;
3073 dfp_op = expr->Iex.Binop.arg1;
3074 int_op = expr->Iex.Binop.arg2;
3075 break;
3076 case Iop_InsertExpD64: /* (I64, D64) -> D64 */
3077 intop = S390_DFP_INSERT_EXP;
3078 int_op = expr->Iex.Binop.arg1;
3079 dfp_op = expr->Iex.Binop.arg2;
3080 break;
florian1b901d42013-01-01 22:19:24 +00003081 default: goto irreducible;
3082 }
3083
florian5c539732013-02-14 14:27:12 +00003084 op2 = s390_isel_int_expr(env, int_op);
3085 op3 = s390_isel_dfp_expr(env, dfp_op);
florian1b901d42013-01-01 22:19:24 +00003086 dst = newVRegF(env);
3087
3088 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
3089 return dst;
3090 }
3091
3092 default:
3093 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00003094 }
3095 }
3096
3097 /* --------- UNARY OP --------- */
3098 case Iex_Unop: {
3099 IROp op = expr->Iex.Unop.op;
3100 IRExpr *left = expr->Iex.Unop.arg;
3101 s390_dfp_conv_t conv;
3102 HReg h1, dst;
3103
3104 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
3105 HReg dst_hi, dst_lo;
3106
3107 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
3108 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
3109 }
3110
3111 if (op == Iop_ReinterpI64asD64) {
3112 dst = newVRegF(env);
3113 h1 = s390_isel_int_expr(env, left); /* Process the operand */
3114 addInstr(env, s390_insn_move(size, dst, h1));
3115
3116 return dst;
3117 }
3118
3119 switch (op) {
3120 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00003121 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
3122 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00003123
3124 convert_dfp1:
3125 h1 = s390_isel_dfp_expr(env, left);
3126 goto convert1;
3127
florian5f034622013-01-13 02:29:05 +00003128 convert_int1:
3129 h1 = s390_isel_int_expr(env, left);
3130 goto convert1;
3131
floriane38f6412012-12-21 17:32:12 +00003132 convert1:
3133 dst = newVRegF(env);
3134 /* No rounding mode is needed for these conversions. Just stick
3135 one in. It won't be used later on. */
3136 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3137 S390_DFP_ROUND_NEAREST_EVEN_4));
3138 return dst;
3139
3140 default:
3141 goto irreducible;
3142 }
3143 }
3144
florian12390202012-11-10 22:34:14 +00003145 /* --------- TERNARY OP --------- */
3146 case Iex_Triop: {
3147 IRTriop *triop = expr->Iex.Triop.details;
3148 IROp op = triop->op;
3149 IRExpr *irrm = triop->arg1;
3150 IRExpr *left = triop->arg2;
3151 IRExpr *right = triop->arg3;
3152 s390_dfp_round_t rounding_mode;
3153 s390_dfp_binop_t dfpop;
3154 HReg op2, op3, dst;
3155
florian12390202012-11-10 22:34:14 +00003156 switch (op) {
florian5c539732013-02-14 14:27:12 +00003157 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp;
3158 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp;
3159 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp;
3160 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp;
3161 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
3162
3163 evaluate_dfp: {
3164 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
3165 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3166 dst = newVRegF(env);
3167 /* DFP arithmetic ops take rounding mode only when fpext is
3168 installed. But, DFP quantize operation takes rm irrespective
3169 of fpext facility . */
3170 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
3171 rounding_mode = get_dfp_rounding_mode(env, irrm);
3172 } else {
3173 set_dfp_rounding_mode_in_fpc(env, irrm);
3174 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3175 }
3176 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3,
3177 rounding_mode));
3178 return dst;
3179 }
3180
3181 case Iop_SignificanceRoundD64:
3182 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */
3183 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3184 dst = newVRegF(env);
3185 rounding_mode = get_dfp_rounding_mode(env, irrm);
3186 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3,
3187 rounding_mode));
3188 return dst;
3189
florian12390202012-11-10 22:34:14 +00003190 default:
3191 goto irreducible;
3192 }
florian12390202012-11-10 22:34:14 +00003193 }
3194
3195 default:
3196 goto irreducible;
3197 }
3198
3199 /* We get here if no pattern matched. */
3200 irreducible:
3201 ppIRExpr(expr);
3202 vpanic("s390_isel_dfp_expr: cannot reduce tree");
3203}
3204
3205static HReg
3206s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
3207{
3208 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
3209
3210 /* Sanity checks ... */
3211 vassert(hregClass(dst) == HRcFlt64);
3212 vassert(hregIsVirtual(dst));
3213
3214 return dst;
3215}
3216
3217
3218/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00003219/*--- ISEL: Condition Code ---*/
3220/*---------------------------------------------------------*/
3221
3222/* This function handles all operators that produce a 1-bit result */
3223static s390_cc_t
3224s390_isel_cc(ISelEnv *env, IRExpr *cond)
3225{
3226 UChar size;
3227
3228 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
3229
3230 /* Constant: either 1 or 0 */
3231 if (cond->tag == Iex_Const) {
3232 vassert(cond->Iex.Const.con->tag == Ico_U1);
3233 vassert(cond->Iex.Const.con->Ico.U1 == True
3234 || cond->Iex.Const.con->Ico.U1 == False);
3235
3236 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
3237 }
3238
3239 /* Variable: values are 1 or 0 */
3240 if (cond->tag == Iex_RdTmp) {
3241 IRTemp tmp = cond->Iex.RdTmp.tmp;
3242 HReg reg = lookupIRTemp(env, tmp);
3243
3244 /* Load-and-test does not modify REG; so this is OK. */
3245 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
3246 size = 4;
3247 else
3248 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
3249 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
3250 return S390_CC_NE;
3251 }
3252
3253 /* Unary operators */
3254 if (cond->tag == Iex_Unop) {
3255 IRExpr *arg = cond->Iex.Unop.arg;
3256
3257 switch (cond->Iex.Unop.op) {
3258 case Iop_Not1: /* Not1(cond) */
3259 /* Generate code for EXPR, and negate the test condition */
3260 return s390_cc_invert(s390_isel_cc(env, arg));
3261
3262 /* Iop_32/64to1 select the LSB from their operand */
3263 case Iop_32to1:
3264 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00003265 HReg dst = newVRegI(env);
3266 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00003267
3268 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3269
florianf366a802012-08-03 00:42:18 +00003270 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00003271 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
3272 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
3273 return S390_CC_NE;
3274 }
3275
3276 case Iop_CmpNEZ8:
3277 case Iop_CmpNEZ16: {
3278 s390_opnd_RMI src;
3279 s390_unop_t op;
3280 HReg dst;
3281
3282 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
3283 : S390_ZERO_EXTEND_16;
3284 dst = newVRegI(env);
3285 src = s390_isel_int_expr_RMI(env, arg);
3286 addInstr(env, s390_insn_unop(4, op, dst, src));
3287 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
3288 return S390_CC_NE;
3289 }
3290
3291 case Iop_CmpNEZ32:
3292 case Iop_CmpNEZ64: {
3293 s390_opnd_RMI src;
3294
3295 src = s390_isel_int_expr_RMI(env, arg);
3296 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3297 addInstr(env, s390_insn_test(size, src));
3298 return S390_CC_NE;
3299 }
3300
3301 default:
3302 goto fail;
3303 }
3304 }
3305
3306 /* Binary operators */
3307 if (cond->tag == Iex_Binop) {
3308 IRExpr *arg1 = cond->Iex.Binop.arg1;
3309 IRExpr *arg2 = cond->Iex.Binop.arg2;
3310 HReg reg1, reg2;
3311
3312 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
3313
3314 switch (cond->Iex.Binop.op) {
3315 s390_unop_t op;
3316 s390_cc_t result;
3317
3318 case Iop_CmpEQ8:
3319 case Iop_CasCmpEQ8:
3320 op = S390_ZERO_EXTEND_8;
3321 result = S390_CC_E;
3322 goto do_compare_ze;
3323
3324 case Iop_CmpNE8:
3325 case Iop_CasCmpNE8:
3326 op = S390_ZERO_EXTEND_8;
3327 result = S390_CC_NE;
3328 goto do_compare_ze;
3329
3330 case Iop_CmpEQ16:
3331 case Iop_CasCmpEQ16:
3332 op = S390_ZERO_EXTEND_16;
3333 result = S390_CC_E;
3334 goto do_compare_ze;
3335
3336 case Iop_CmpNE16:
3337 case Iop_CasCmpNE16:
3338 op = S390_ZERO_EXTEND_16;
3339 result = S390_CC_NE;
3340 goto do_compare_ze;
3341
3342 do_compare_ze: {
3343 s390_opnd_RMI op1, op2;
3344
3345 op1 = s390_isel_int_expr_RMI(env, arg1);
3346 reg1 = newVRegI(env);
3347 addInstr(env, s390_insn_unop(4, op, reg1, op1));
3348
3349 op2 = s390_isel_int_expr_RMI(env, arg2);
3350 reg2 = newVRegI(env);
3351 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
3352
3353 op2 = s390_opnd_reg(reg2);
3354 addInstr(env, s390_insn_compare(4, reg1, op2, False));
3355
3356 return result;
3357 }
3358
3359 case Iop_CmpEQ32:
3360 case Iop_CmpEQ64:
3361 case Iop_CasCmpEQ32:
3362 case Iop_CasCmpEQ64:
3363 result = S390_CC_E;
3364 goto do_compare;
3365
3366 case Iop_CmpNE32:
3367 case Iop_CmpNE64:
3368 case Iop_CasCmpNE32:
3369 case Iop_CasCmpNE64:
3370 result = S390_CC_NE;
3371 goto do_compare;
3372
3373 do_compare: {
3374 HReg op1;
3375 s390_opnd_RMI op2;
3376
3377 order_commutative_operands(arg1, arg2);
3378
3379 op1 = s390_isel_int_expr(env, arg1);
3380 op2 = s390_isel_int_expr_RMI(env, arg2);
3381
3382 addInstr(env, s390_insn_compare(size, op1, op2, False));
3383
3384 return result;
3385 }
3386
3387 case Iop_CmpLT32S:
3388 case Iop_CmpLE32S:
3389 case Iop_CmpLT64S:
3390 case Iop_CmpLE64S: {
3391 HReg op1;
3392 s390_opnd_RMI op2;
3393
3394 op1 = s390_isel_int_expr(env, arg1);
3395 op2 = s390_isel_int_expr_RMI(env, arg2);
3396
3397 addInstr(env, s390_insn_compare(size, op1, op2, True));
3398
3399 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3400 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3401 }
3402
3403 case Iop_CmpLT32U:
3404 case Iop_CmpLE32U:
3405 case Iop_CmpLT64U:
3406 case Iop_CmpLE64U: {
3407 HReg op1;
3408 s390_opnd_RMI op2;
3409
3410 op1 = s390_isel_int_expr(env, arg1);
3411 op2 = s390_isel_int_expr_RMI(env, arg2);
3412
3413 addInstr(env, s390_insn_compare(size, op1, op2, False));
3414
3415 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3416 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3417 }
3418
3419 default:
3420 goto fail;
3421 }
3422 }
3423
3424 fail:
3425 ppIRExpr(cond);
3426 vpanic("s390_isel_cc: unexpected operator");
3427}
3428
3429
3430/*---------------------------------------------------------*/
3431/*--- ISEL: Statements ---*/
3432/*---------------------------------------------------------*/
3433
3434static void
3435s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3436{
3437 if (vex_traceflags & VEX_TRACE_VCODE) {
3438 vex_printf("\n -- ");
3439 ppIRStmt(stmt);
3440 vex_printf("\n");
3441 }
3442
3443 switch (stmt->tag) {
3444
3445 /* --------- STORE --------- */
3446 case Ist_Store: {
3447 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3448 s390_amode *am;
3449 HReg src;
3450
3451 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3452
3453 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3454
3455 switch (tyd) {
3456 case Ity_I8:
3457 case Ity_I16:
3458 case Ity_I32:
3459 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003460 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003461 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003462 stmt->Ist.Store.data->tag == Iex_Const) {
3463 ULong value =
3464 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3465 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003466 return;
3467 }
floriancec3a8a2013-02-02 00:16:58 +00003468 /* Check whether we can use a memcpy here. Currently, the restriction
3469 is that both amodes need to be B12, so MVC can be emitted.
3470 We do not consider a store whose data expression is a load because
3471 we don't want to deal with overlapping locations. */
3472 /* store(get) never overlaps*/
3473 if (am->tag == S390_AMODE_B12 &&
3474 stmt->Ist.Store.data->tag == Iex_Get) {
3475 UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
3476 s390_amode *from = s390_amode_for_guest_state(offset);
3477 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
3478 return;
3479 }
3480 /* General case: compile data into a register */
sewardj2019a972011-03-07 16:04:07 +00003481 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3482 break;
3483
3484 case Ity_F32:
3485 case Ity_F64:
3486 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3487 break;
3488
florianeb981ae2012-12-21 18:55:03 +00003489 case Ity_D32:
3490 case Ity_D64:
3491 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3492 break;
3493
sewardj2019a972011-03-07 16:04:07 +00003494 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003495 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003496 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003497 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003498
3499 default:
3500 goto stmt_fail;
3501 }
3502
3503 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3504 return;
3505 }
3506
3507 /* --------- PUT --------- */
3508 case Ist_Put: {
3509 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3510 HReg src;
3511 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003512 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003513
florianad43b3a2012-02-20 15:01:14 +00003514 /* Detect updates to certain guest registers. We track the contents
3515 of those registers as long as they contain constants. If the new
3516 constant is either zero or in the 8-bit neighbourhood of the
3517 current value we can use a memory-to-memory insn to do the update. */
3518
3519 Int offset = stmt->Ist.Put.offset;
3520
3521 /* Check necessary conditions:
3522 (1) must be one of the registers we care about
3523 (2) assigned value must be a constant */
3524 Int guest_reg = get_guest_reg(offset);
3525
3526 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3527
florianad43b3a2012-02-20 15:01:14 +00003528 if (stmt->Ist.Put.data->tag != Iex_Const) {
3529 /* Invalidate guest register contents */
3530 env->old_value_valid[guest_reg] = False;
3531 goto not_special;
3532 }
3533
cborntraaf7ad282012-08-08 14:11:33 +00003534 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3535 if (tyd != Ity_I64)
3536 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003537
cborntraaf7ad282012-08-08 14:11:33 +00003538 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003539
3540 old_value = env->old_value[guest_reg];
3541 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3542 env->old_value[guest_reg] = new_value;
3543
3544 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3545 env->old_value_valid[guest_reg] = True;
3546
3547 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003548 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003549 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003550 return;
florianad43b3a2012-02-20 15:01:14 +00003551 }
3552
florianad43b3a2012-02-20 15:01:14 +00003553 if (old_value_is_valid == False) goto not_special;
3554
3555 /* If the new value is in the neighbourhood of the old value
3556 we can use a memory-to-memory insn */
3557 difference = new_value - old_value;
3558
3559 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003560 am = s390_amode_for_guest_state(offset);
3561 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003562 (difference & 0xFF), new_value));
3563 return;
3564 }
3565
florianb93348d2012-12-27 00:59:43 +00003566 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003567 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003568 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003569 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003570 return;
3571 }
3572
3573 /* No special case applies... fall through */
3574
3575 not_special:
florianb93348d2012-12-27 00:59:43 +00003576 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003577
3578 switch (tyd) {
3579 case Ity_I8:
3580 case Ity_I16:
3581 case Ity_I32:
3582 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003583 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003584 stmt->Ist.Put.data->tag == Iex_Const) {
3585 ULong value =
3586 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3587 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003588 return;
3589 }
floriancec3a8a2013-02-02 00:16:58 +00003590 /* Check whether we can use a memcpy here. Currently, the restriction
3591 is that both amodes need to be B12, so MVC can be emitted. */
3592 /* put(load) never overlaps */
3593 if (am->tag == S390_AMODE_B12 &&
3594 stmt->Ist.Put.data->tag == Iex_Load) {
3595 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
3596 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
3597 s390_amode *from = s390_isel_amode(env, data);
3598 UInt size = sizeofIRType(tyd);
3599
3600 if (from->tag == S390_AMODE_B12) {
3601 /* Source can be compiled into a B12 amode. */
3602 addInstr(env, s390_insn_memcpy(size, am, from));
3603 return;
3604 }
3605
3606 src = newVRegI(env);
3607 addInstr(env, s390_insn_load(size, src, from));
3608 break;
3609 }
3610 /* put(get) */
3611 if (am->tag == S390_AMODE_B12 &&
3612 stmt->Ist.Put.data->tag == Iex_Get) {
3613 UInt put_offset = am->d;
3614 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
3615 UInt size = sizeofIRType(tyd);
3616 /* don't memcpy in case of overlap */
3617 if (put_offset + size <= get_offset ||
3618 get_offset + size <= put_offset) {
3619 s390_amode *from = s390_amode_for_guest_state(get_offset);
3620 addInstr(env, s390_insn_memcpy(size, am, from));
3621 return;
3622 }
3623 goto no_memcpy_put;
3624 }
3625 /* General case: compile data into a register */
3626no_memcpy_put:
sewardj2019a972011-03-07 16:04:07 +00003627 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3628 break;
3629
3630 case Ity_F32:
3631 case Ity_F64:
3632 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3633 break;
3634
3635 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003636 case Ity_D128:
3637 /* Does not occur. See function put_(f|d)pr_pair. */
3638 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003639
floriane38f6412012-12-21 17:32:12 +00003640 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003641 case Ity_D64:
3642 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3643 break;
3644
sewardj2019a972011-03-07 16:04:07 +00003645 default:
3646 goto stmt_fail;
3647 }
3648
3649 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3650 return;
3651 }
3652
3653 /* --------- TMP --------- */
3654 case Ist_WrTmp: {
3655 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3656 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3657 HReg src, dst;
3658
3659 switch (tyd) {
3660 case Ity_I128: {
3661 HReg dst_hi, dst_lo, res_hi, res_lo;
3662
3663 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3664 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3665
3666 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3667 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3668 return;
3669 }
3670
3671 case Ity_I8:
3672 case Ity_I16:
3673 case Ity_I32:
3674 case Ity_I64:
3675 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3676 dst = lookupIRTemp(env, tmp);
3677 break;
3678
3679 case Ity_I1: {
3680 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3681 dst = lookupIRTemp(env, tmp);
3682 addInstr(env, s390_insn_cc2bool(dst, cond));
3683 return;
3684 }
3685
3686 case Ity_F32:
3687 case Ity_F64:
3688 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3689 dst = lookupIRTemp(env, tmp);
3690 break;
3691
3692 case Ity_F128: {
3693 HReg dst_hi, dst_lo, res_hi, res_lo;
3694
3695 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3696 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3697
3698 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3699 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3700 return;
3701 }
3702
floriane38f6412012-12-21 17:32:12 +00003703 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003704 case Ity_D64:
3705 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3706 dst = lookupIRTemp(env, tmp);
3707 break;
3708
floriane38f6412012-12-21 17:32:12 +00003709 case Ity_D128: {
3710 HReg dst_hi, dst_lo, res_hi, res_lo;
3711
3712 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3713 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3714
3715 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3716 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3717 return;
3718 }
3719
sewardj2019a972011-03-07 16:04:07 +00003720 default:
3721 goto stmt_fail;
3722 }
3723
3724 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3725 return;
3726 }
3727
3728 /* --------- Call to DIRTY helper --------- */
3729 case Ist_Dirty: {
3730 IRType retty;
3731 IRDirty* d = stmt->Ist.Dirty.details;
florian01ed6e72012-05-27 16:52:43 +00003732 HReg dst;
sewardj74142b82013-08-08 10:28:59 +00003733 RetLoc rloc = mk_RetLoc_INVALID();
3734 UInt addToSp = 0;
florianad43b3a2012-02-20 15:01:14 +00003735 Int i;
3736
3737 /* Invalidate tracked values of those guest state registers that are
3738 modified by this helper. */
3739 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003740 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3741 descriptors in guest state effect descriptions. Hence: */
3742 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003743 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3744 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3745 if (guest_reg != GUEST_UNKNOWN)
3746 env->old_value_valid[guest_reg] = False;
3747 }
3748 }
sewardj2019a972011-03-07 16:04:07 +00003749
florian01ed6e72012-05-27 16:52:43 +00003750 if (d->tmp == IRTemp_INVALID) {
3751 /* No return value. */
sewardj74142b82013-08-08 10:28:59 +00003752 retty = Ity_INVALID;
3753 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3754 d->args);
3755 vassert(is_sane_RetLoc(rloc));
3756 vassert(rloc.pri == RLPri_None);
3757 vassert(addToSp == 0);
3758
sewardj2019a972011-03-07 16:04:07 +00003759 return;
florian01ed6e72012-05-27 16:52:43 +00003760 }
sewardj2019a972011-03-07 16:04:07 +00003761
3762 retty = typeOfIRTemp(env->type_env, d->tmp);
3763 if (retty == Ity_I64 || retty == Ity_I32
3764 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003765 /* Move the returned value to the destination register */
sewardj74142b82013-08-08 10:28:59 +00003766 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
3767
florian01ed6e72012-05-27 16:52:43 +00003768 dst = lookupIRTemp(env, d->tmp);
sewardj74142b82013-08-08 10:28:59 +00003769 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3770 d->args);
3771 vassert(is_sane_RetLoc(rloc));
3772 vassert(rloc.pri == RLPri_Int);
3773 vassert(addToSp == 0);
3774 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
3775
sewardj2019a972011-03-07 16:04:07 +00003776 return;
3777 }
3778 break;
3779 }
3780
3781 case Ist_CAS:
3782 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3783 IRCAS *cas = stmt->Ist.CAS.details;
3784 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3785 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3786 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3787 HReg old = lookupIRTemp(env, cas->oldLo);
3788
3789 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3790 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3791 } else {
3792 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3793 }
3794 return;
3795 } else {
florian448cbba2012-06-06 02:26:01 +00003796 IRCAS *cas = stmt->Ist.CAS.details;
3797 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3798 HReg r8, r9, r10, r11, r1;
3799 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3800 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3801 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3802 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3803 HReg old_low = lookupIRTemp(env, cas->oldLo);
3804 HReg old_high = lookupIRTemp(env, cas->oldHi);
3805
3806 /* Use non-virtual registers r8 and r9 as pair for op1
3807 and move op1 there */
3808 r8 = make_gpr(8);
3809 r9 = make_gpr(9);
3810 addInstr(env, s390_insn_move(8, r8, op1_high));
3811 addInstr(env, s390_insn_move(8, r9, op1_low));
3812
3813 /* Use non-virtual registers r10 and r11 as pair for op3
3814 and move op3 there */
3815 r10 = make_gpr(10);
3816 r11 = make_gpr(11);
3817 addInstr(env, s390_insn_move(8, r10, op3_high));
3818 addInstr(env, s390_insn_move(8, r11, op3_low));
3819
3820 /* Register r1 is used as a scratch register */
3821 r1 = make_gpr(1);
3822
3823 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3824 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3825 old_high, old_low, r1));
3826 } else {
3827 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3828 old_high, old_low, r1));
3829 }
3830 addInstr(env, s390_insn_move(8, op1_high, r8));
3831 addInstr(env, s390_insn_move(8, op1_low, r9));
3832 addInstr(env, s390_insn_move(8, op3_high, r10));
3833 addInstr(env, s390_insn_move(8, op3_low, r11));
3834 return;
sewardj2019a972011-03-07 16:04:07 +00003835 }
3836 break;
3837
3838 /* --------- EXIT --------- */
3839 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003840 s390_cc_t cond;
3841 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3842
3843 if (tag != Ico_U64)
3844 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3845
florian8844a632012-04-13 04:04:06 +00003846 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003847 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003848
3849 /* Case: boring transfer to known address */
3850 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3851 if (env->chaining_allowed) {
3852 /* .. almost always true .. */
3853 /* Skip the event check at the dst if this is a forwards
3854 edge. */
3855 Bool to_fast_entry
3856 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3857 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3858 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3859 guest_IA, to_fast_entry));
3860 } else {
3861 /* .. very occasionally .. */
3862 /* We can't use chaining, so ask for an assisted transfer,
3863 as that's the only alternative that is allowable. */
3864 HReg dst = s390_isel_int_expr(env,
3865 IRExpr_Const(stmt->Ist.Exit.dst));
3866 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3867 }
3868 return;
3869 }
3870
3871 /* Case: assisted transfer to arbitrary address */
3872 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003873 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003874 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003875 case Ijk_NoDecode:
sewardj05f5e012014-05-04 10:52:11 +00003876 case Ijk_InvalICache:
florian2d98d892012-04-14 20:35:17 +00003877 case Ijk_Sys_syscall:
3878 case Ijk_ClientReq:
3879 case Ijk_NoRedir:
3880 case Ijk_Yield:
3881 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003882 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3883 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3884 stmt->Ist.Exit.jk));
3885 return;
3886 }
3887 default:
3888 break;
3889 }
3890
3891 /* Do we ever expect to see any other kind? */
3892 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003893 }
3894
3895 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003896 case Ist_MBE:
3897 switch (stmt->Ist.MBE.event) {
3898 case Imbe_Fence:
3899 addInstr(env, s390_insn_mfence());
3900 return;
3901 default:
3902 break;
3903 }
sewardj2019a972011-03-07 16:04:07 +00003904 break;
3905
3906 /* --------- Miscellaneous --------- */
3907
3908 case Ist_PutI: /* Not needed */
3909 case Ist_IMark: /* Doesn't generate any executable code */
3910 case Ist_NoOp: /* Doesn't generate any executable code */
3911 case Ist_AbiHint: /* Meaningless in IR */
3912 return;
3913
3914 default:
3915 break;
3916 }
3917
3918 stmt_fail:
3919 ppIRStmt(stmt);
3920 vpanic("s390_isel_stmt");
3921}
3922
3923
3924/*---------------------------------------------------------*/
3925/*--- ISEL: Basic block terminators (Nexts) ---*/
3926/*---------------------------------------------------------*/
3927
3928static void
florianffbd84d2012-12-09 02:06:29 +00003929iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003930{
sewardj2019a972011-03-07 16:04:07 +00003931 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003932 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003933 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003934 vex_printf("; exit-");
3935 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003936 vex_printf("\n");
3937 }
3938
florian8844a632012-04-13 04:04:06 +00003939 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3940
3941 /* Case: boring transfer to known address */
3942 if (next->tag == Iex_Const) {
3943 IRConst *cdst = next->Iex.Const.con;
3944 vassert(cdst->tag == Ico_U64);
3945 if (jk == Ijk_Boring || jk == Ijk_Call) {
3946 /* Boring transfer to known address */
3947 if (env->chaining_allowed) {
3948 /* .. almost always true .. */
3949 /* Skip the event check at the dst if this is a forwards
3950 edge. */
3951 Bool to_fast_entry
3952 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3953 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3954 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3955 guest_IA, to_fast_entry));
3956 } else {
3957 /* .. very occasionally .. */
3958 /* We can't use chaining, so ask for an indirect transfer,
3959 as that's the cheapest alternative that is allowable. */
3960 HReg dst = s390_isel_int_expr(env, next);
3961 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3962 Ijk_Boring));
3963 }
3964 return;
3965 }
3966 }
3967
3968 /* Case: call/return (==boring) transfer to any address */
3969 switch (jk) {
3970 case Ijk_Boring:
3971 case Ijk_Ret:
3972 case Ijk_Call: {
3973 HReg dst = s390_isel_int_expr(env, next);
3974 if (env->chaining_allowed) {
3975 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3976 } else {
3977 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3978 Ijk_Boring));
3979 }
3980 return;
3981 }
3982 default:
3983 break;
3984 }
3985
3986 /* Case: some other kind of transfer to any address */
3987 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003988 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003989 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003990 case Ijk_NoDecode:
sewardj05f5e012014-05-04 10:52:11 +00003991 case Ijk_InvalICache:
florian8844a632012-04-13 04:04:06 +00003992 case Ijk_Sys_syscall:
3993 case Ijk_ClientReq:
3994 case Ijk_NoRedir:
3995 case Ijk_Yield:
3996 case Ijk_SigTRAP: {
3997 HReg dst = s390_isel_int_expr(env, next);
3998 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3999 return;
4000 }
4001 default:
4002 break;
4003 }
4004
4005 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00004006}
4007
4008
4009/*---------------------------------------------------------*/
4010/*--- Insn selector top-level ---*/
4011/*---------------------------------------------------------*/
4012
florianf26994a2012-04-21 03:34:54 +00004013/* Translate an entire SB to s390 code.
4014 Note: archinfo_host is a pointer to a stack-allocated variable.
4015 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00004016
4017HInstrArray *
floriand8c64e02014-10-08 08:54:44 +00004018iselSB_S390(IRSB *bb, VexArch arch_host, const VexArchInfo *archinfo_host,
4019 const VexAbiInfo *vbi, Int offset_host_evcheck_counter,
florian8844a632012-04-13 04:04:06 +00004020 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
4021 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00004022{
4023 UInt i, j;
4024 HReg hreg, hregHI;
4025 ISelEnv *env;
4026 UInt hwcaps_host = archinfo_host->hwcaps;
4027
florianf26994a2012-04-21 03:34:54 +00004028 /* KLUDGE: export hwcaps. */
4029 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00004030
sewardj2019a972011-03-07 16:04:07 +00004031 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00004032 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00004033
sewardj9b769162014-07-24 12:42:03 +00004034 /* Check that the host's endianness is as expected. */
4035 vassert(archinfo_host->endness == VexEndnessBE);
4036
sewardj2019a972011-03-07 16:04:07 +00004037 /* Make up an initial environment to use. */
4038 env = LibVEX_Alloc(sizeof(ISelEnv));
4039 env->vreg_ctr = 0;
4040
4041 /* Set up output code array. */
4042 env->code = newHInstrArray();
4043
4044 /* Copy BB's type env. */
4045 env->type_env = bb->tyenv;
4046
florianad43b3a2012-02-20 15:01:14 +00004047 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00004048 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
4049 env->old_value[i] = 0; /* just something to have a defined value */
4050 env->old_value_valid[i] = False;
4051 }
4052
sewardj2019a972011-03-07 16:04:07 +00004053 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
4054 change as we go along. For some reason types_used has Int type -- but
4055 it should be unsigned. Internally we use an unsigned type; so we
4056 assert it here. */
4057 vassert(bb->tyenv->types_used >= 0);
4058
4059 env->n_vregmap = bb->tyenv->types_used;
4060 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4061 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4062
florian2c74d242012-09-12 19:38:42 +00004063 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00004064 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00004065
sewardj2019a972011-03-07 16:04:07 +00004066 /* and finally ... */
4067 env->hwcaps = hwcaps_host;
4068
florian8844a632012-04-13 04:04:06 +00004069 env->max_ga = max_ga;
4070 env->chaining_allowed = chaining_allowed;
4071
sewardj2019a972011-03-07 16:04:07 +00004072 /* For each IR temporary, allocate a suitably-kinded virtual
4073 register. */
4074 j = 0;
4075 for (i = 0; i < env->n_vregmap; i++) {
4076 hregHI = hreg = INVALID_HREG;
4077 switch (bb->tyenv->types[i]) {
4078 case Ity_I1:
4079 case Ity_I8:
4080 case Ity_I16:
4081 case Ity_I32:
4082 hreg = mkHReg(j++, HRcInt64, True);
4083 break;
4084
4085 case Ity_I64:
4086 hreg = mkHReg(j++, HRcInt64, True);
4087 break;
4088
4089 case Ity_I128:
4090 hreg = mkHReg(j++, HRcInt64, True);
4091 hregHI = mkHReg(j++, HRcInt64, True);
4092 break;
4093
4094 case Ity_F32:
4095 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00004096 case Ity_D32:
florian12390202012-11-10 22:34:14 +00004097 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00004098 hreg = mkHReg(j++, HRcFlt64, True);
4099 break;
4100
4101 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00004102 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00004103 hreg = mkHReg(j++, HRcFlt64, True);
4104 hregHI = mkHReg(j++, HRcFlt64, True);
4105 break;
4106
4107 case Ity_V128: /* fall through */
4108 default:
4109 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00004110 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00004111 }
4112
4113 env->vregmap[i] = hreg;
4114 env->vregmapHI[i] = hregHI;
4115 }
4116 env->vreg_ctr = j;
4117
florian8844a632012-04-13 04:04:06 +00004118 /* The very first instruction must be an event check. */
4119 s390_amode *counter, *fail_addr;
4120 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
4121 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
4122 addInstr(env, s390_insn_evcheck(counter, fail_addr));
4123
4124 /* Possibly a block counter increment (for profiling). At this
4125 point we don't know the address of the counter, so just pretend
4126 it is zero. It will have to be patched later, but before this
4127 translation is used, by a call to LibVEX_patchProfInc. */
4128 if (add_profinc) {
4129 addInstr(env, s390_insn_profinc());
4130 }
4131
sewardj2019a972011-03-07 16:04:07 +00004132 /* Ok, finally we can iterate over the statements. */
4133 for (i = 0; i < bb->stmts_used; i++)
4134 if (bb->stmts[i])
4135 s390_isel_stmt(env, bb->stmts[i]);
4136
florian8844a632012-04-13 04:04:06 +00004137 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00004138
4139 /* Record the number of vregs we used. */
4140 env->code->n_vregs = env->vreg_ctr;
4141
4142 return env->code;
4143}
4144
4145/*---------------------------------------------------------------*/
4146/*--- end host_s390_isel.c ---*/
4147/*---------------------------------------------------------------*/