blob: aaccff60518fe9dae2819bc3d43df0085bdd9c06 [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
florian90419562013-08-15 20:54:52 +0000489 special node IRExpr_VECRET(), in which case this routine
sewardj74142b82013-08-08 10:28:59 +0000490 generates code to allocate space on the stack for the vector
491 return value. Since we are not passing any scalars on the
492 stack, it is enough to preallocate the return space before
493 marshalling any arguments, in this case.
494
florian90419562013-08-15 20:54:52 +0000495 |args| may also contain IRExpr_BBPTR(), in which case the value
sewardj74142b82013-08-08 10:28:59 +0000496 in the guest state pointer register is passed as the
497 corresponding argument.
498
499 These are used for cross-checking that IR-level constraints on
florian90419562013-08-15 20:54:52 +0000500 the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */
sewardj74142b82013-08-08 10:28:59 +0000501 UInt nVECRETs = 0;
502 UInt nBBPTRs = 0;
503
sewardj2019a972011-03-07 16:04:07 +0000504 n_args = 0;
505 for (i = 0; args[i]; i++)
506 ++n_args;
507
sewardj74142b82013-08-08 10:28:59 +0000508 if (n_args > S390_NUM_GPRPARMS) {
sewardj2019a972011-03-07 16:04:07 +0000509 vpanic("doHelperCall: too many arguments");
510 }
511
florian11b8ee82012-08-06 13:35:33 +0000512 /* All arguments must have Ity_I64. For two reasons:
513 (1) We do not handle floating point arguments.
514 (2) The ABI requires that integer values are sign- or zero-extended
515 to 64 bit.
516 */
517 Int arg_errors = 0;
518 for (i = 0; i < n_args; ++i) {
florian90419562013-08-15 20:54:52 +0000519 if (UNLIKELY(args[i]->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000520 nVECRETs++;
florian90419562013-08-15 20:54:52 +0000521 } else if (UNLIKELY(args[i]->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000522 nBBPTRs++;
523 } else {
524 IRType type = typeOfIRExpr(env->type_env, args[i]);
525 if (type != Ity_I64) {
526 ++arg_errors;
527 vex_printf("calling %s: argument #%d has type ", callee->name, i);
528 ppIRType(type);
529 vex_printf("; Ity_I64 is required\n");
530 }
florian11b8ee82012-08-06 13:35:33 +0000531 }
532 }
533
534 if (arg_errors)
535 vpanic("cannot continue due to errors in argument passing");
536
sewardj74142b82013-08-08 10:28:59 +0000537 /* If this fails, the IR is ill-formed */
538 vassert(nBBPTRs == 0 || nBBPTRs == 1);
florian52af7bc2012-05-12 03:44:49 +0000539
sewardj74142b82013-08-08 10:28:59 +0000540 /* If we have a VECRET, allocate space on the stack for the return
541 value, and record the stack pointer after that. */
542 HReg r_vecRetAddr = INVALID_HREG;
543 if (nVECRETs == 1) {
544 /* we do not handle vector types yet */
545 vassert(0);
546 HReg sp = make_gpr(S390_REGNO_STACK_POINTER);
547 vassert(retTy == Ity_V128 || retTy == Ity_V256);
548 vassert(retTy != Ity_V256); // we don't handle that yet (if ever)
549 r_vecRetAddr = newVRegI(env);
550 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, sp, s390_opnd_imm(16)));
551 addInstr(env, s390_insn_move(sizeof(ULong), r_vecRetAddr, sp));
552
553 } else {
554 // If either of these fail, the IR is ill-formed
555 vassert(retTy != Ity_V128 && retTy != Ity_V256);
556 vassert(nVECRETs == 0);
florian52af7bc2012-05-12 03:44:49 +0000557 }
558
sewardj74142b82013-08-08 10:28:59 +0000559 argreg = 0;
560
florian52af7bc2012-05-12 03:44:49 +0000561 /* Compute the function arguments into a temporary register each */
562 for (i = 0; i < n_args; i++) {
sewardj74142b82013-08-08 10:28:59 +0000563 IRExpr *arg = args[i];
florian90419562013-08-15 20:54:52 +0000564 if(UNLIKELY(arg->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000565 /* we do not handle vector types yet */
566 vassert(0);
567 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
568 r_vecRetAddr));
florian90419562013-08-15 20:54:52 +0000569 } else if (UNLIKELY(arg->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000570 /* If we need the guest state pointer put it in a temporary arg reg */
571 tmpregs[argreg] = newVRegI(env);
572 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
573 s390_hreg_guest_state_pointer()));
574 } else {
575 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
576 }
florian52af7bc2012-05-12 03:44:49 +0000577 argreg++;
578 }
579
sewardj2019a972011-03-07 16:04:07 +0000580 /* Compute the condition */
581 cc = S390_CC_ALWAYS;
582 if (guard) {
583 if (guard->tag == Iex_Const
584 && guard->Iex.Const.con->tag == Ico_U1
585 && guard->Iex.Const.con->Ico.U1 == True) {
586 /* unconditional -- do nothing */
587 } else {
588 cc = s390_isel_cc(env, guard);
589 }
590 }
591
florian52af7bc2012-05-12 03:44:49 +0000592 /* Move the args to the final register. It is paramount, that the
593 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000594 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000595 HReg finalreg;
596
597 finalreg = make_gpr(s390_gprno_from_arg_index(i));
598 size = sizeofIRType(Ity_I64);
599 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000600 }
601
602 target = Ptr_to_ULong(callee->addr);
603
sewardj74142b82013-08-08 10:28:59 +0000604 /* Do final checks, set the return values, and generate the call
605 instruction proper. */
606 vassert(*stackAdjustAfterCall == 0);
607 vassert(is_RetLoc_INVALID(*retloc));
608 switch (retTy) {
609 case Ity_INVALID:
610 /* Function doesn't return a value. */
611 *retloc = mk_RetLoc_simple(RLPri_None);
612 break;
613 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
614 *retloc = mk_RetLoc_simple(RLPri_Int);
615 break;
616 case Ity_V128:
617 /* we do not handle vector types yet */
618 vassert(0);
619 *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
620 *stackAdjustAfterCall = 16;
621 break;
622 case Ity_V256:
623 /* we do not handle vector types yet */
624 vassert(0);
625 *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
626 *stackAdjustAfterCall = 32;
627 break;
628 default:
629 /* IR can denote other possible return types, but we don't
630 handle those here. */
631 vassert(0);
632 }
633
sewardj2019a972011-03-07 16:04:07 +0000634 /* Finally, the call itself. */
635 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
sewardj74142b82013-08-08 10:28:59 +0000636 callee->name, *retloc));
sewardj2019a972011-03-07 16:04:07 +0000637}
638
639
florian2c74d242012-09-12 19:38:42 +0000640/*---------------------------------------------------------*/
641/*--- BFP helper functions ---*/
642/*---------------------------------------------------------*/
643
644/* Set the BFP rounding mode in the FPC. This function is called for
645 all non-conversion BFP instructions as those will always get the
646 rounding mode from the FPC. */
647static void
648set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000649{
florian2c74d242012-09-12 19:38:42 +0000650 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
651
652 /* Do we need to do anything? */
653 if (env->previous_bfp_rounding_mode &&
654 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
655 irrm->tag == Iex_RdTmp &&
656 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
657 /* No - new mode is identical to previous mode. */
658 return;
659 }
660
661 /* No luck - we better set it, and remember what we set it to. */
662 env->previous_bfp_rounding_mode = irrm;
663
664 /* The incoming rounding mode is in VEX IR encoding. Need to change
665 to s390.
666
667 rounding mode | s390 | IR
668 -------------------------
669 to nearest | 00 | 00
670 to zero | 01 | 11
671 to +infinity | 10 | 10
672 to -infinity | 11 | 01
673
674 So: s390 = (4 - IR) & 3
675 */
676 HReg ir = s390_isel_int_expr(env, irrm);
677
678 HReg mode = newVRegI(env);
679
680 addInstr(env, s390_insn_load_immediate(4, mode, 4));
681 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
682 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
683
florian125e20d2012-10-07 15:42:37 +0000684 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000685}
686
687
688/* This function is invoked for insns that support a specification of
689 a rounding mode in the insn itself. In that case there is no need to
690 stick the rounding mode into the FPC -- a good thing. However, the
691 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000692static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000693get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
694{
695 if (irrm->tag == Iex_Const) { /* rounding mode is known */
696 vassert(irrm->Iex.Const.con->tag == Ico_U32);
697 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000698
699 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000700 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
701 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
702 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
703 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000704 default:
705 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000706 }
707 }
708
florian2c74d242012-09-12 19:38:42 +0000709 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000710 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000711}
712
713
florianc8e4f562012-10-27 16:19:31 +0000714/*---------------------------------------------------------*/
715/*--- DFP helper functions ---*/
716/*---------------------------------------------------------*/
717
718/* Set the DFP rounding mode in the FPC. This function is called for
719 all non-conversion DFP instructions as those will always get the
720 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000721static void
722set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
723{
724 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
725
726 /* Do we need to do anything? */
727 if (env->previous_dfp_rounding_mode &&
728 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
729 irrm->tag == Iex_RdTmp &&
730 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
731 /* No - new mode is identical to previous mode. */
732 return;
733 }
734
735 /* No luck - we better set it, and remember what we set it to. */
736 env->previous_dfp_rounding_mode = irrm;
737
738 /* The incoming rounding mode is in VEX IR encoding. Need to change
739 to s390.
740
741 rounding mode | S390 | IR
742 -----------------------------------------------
743 to nearest, ties to even | 000 | 000
744 to zero | 001 | 011
745 to +infinity | 010 | 010
746 to -infinity | 011 | 001
747 to nearest, ties away from 0 | 100 | 100
748 to nearest, ties toward 0 | 101 | 111
749 to away from 0 | 110 | 110
750 to prepare for shorter precision | 111 | 101
751
752 So: s390 = (IR ^ ((IR << 1) & 2))
753 */
754 HReg ir = s390_isel_int_expr(env, irrm);
755
756 HReg mode = newVRegI(env);
757
758 addInstr(env, s390_insn_move(4, mode, ir));
759 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
760 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
761 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
762
763 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
764}
765
766
767/* This function is invoked for insns that support a specification of
768 a rounding mode in the insn itself. In that case there is no need to
769 stick the rounding mode into the FPC -- a good thing. However, the
770 rounding mode must be known.
florianff9000d2013-02-08 20:22:03 +0000771
florian79e5a482013-06-06 19:12:46 +0000772 When mapping an Irrm_XYZ value to an S390_DFP_ROUND_ value there is
773 often a choice. For instance, Irrm_ZERO could be mapped to either
florianff9000d2013-02-08 20:22:03 +0000774 S390_DFP_ROUND_ZERO_5 or S390_DFP_ROUND_ZERO_9. The difference between
775 those two is that with S390_DFP_ROUND_ZERO_9 the recognition of the
776 quantum exception is suppressed whereas with S390_DFP_ROUND_ZERO_5 it
777 is not. As the quantum exception is not modelled we can choose either
778 value. The choice is to use S390_DFP_ROUND_.. values in the range [8:15],
779 because values in the range [1:7] have unpredictable rounding behaviour
780 when the floating point exception facility is not installed.
florianc8e4f562012-10-27 16:19:31 +0000781
782 Translation table of
783 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
784
florian79e5a482013-06-06 19:12:46 +0000785 s390(S390_DFP_ROUND_) | IR(Irrm_) | s390(S390_DFP_ROUND_)
florianc8e4f562012-10-27 16:19:31 +0000786 --------------------------------------------------------------------
florianff9000d2013-02-08 20:22:03 +0000787 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_12
florianc8e4f562012-10-27 16:19:31 +0000788 NEAREST_TIE_AWAY_0_12 | " | "
florianff9000d2013-02-08 20:22:03 +0000789 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_15
florianc8e4f562012-10-27 16:19:31 +0000790 PREPARE_SHORT_15 | " | "
florianff9000d2013-02-08 20:22:03 +0000791 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_8
florianc8e4f562012-10-27 16:19:31 +0000792 NEAREST_EVEN_8 | " | "
florianff9000d2013-02-08 20:22:03 +0000793 ZERO_5 | ZERO | ZERO_9
florianc8e4f562012-10-27 16:19:31 +0000794 ZERO_9 | " | "
florianff9000d2013-02-08 20:22:03 +0000795 POSINF_6 | PosINF | POSINF_10
florianc8e4f562012-10-27 16:19:31 +0000796 POSINF_10 | " | "
florianff9000d2013-02-08 20:22:03 +0000797 NEGINF_7 | NegINF | NEGINF_11
florianc8e4f562012-10-27 16:19:31 +0000798 NEGINF_11 | " | "
799 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
800 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
801*/
802static s390_dfp_round_t
803get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
804{
805 if (irrm->tag == Iex_Const) { /* rounding mode is known */
806 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian79e5a482013-06-06 19:12:46 +0000807 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000808
809 switch (mode) {
florian79e5a482013-06-06 19:12:46 +0000810 case Irrm_NEAREST:
florianff9000d2013-02-08 20:22:03 +0000811 return S390_DFP_ROUND_NEAREST_EVEN_8;
florian79e5a482013-06-06 19:12:46 +0000812 case Irrm_NegINF:
florianff9000d2013-02-08 20:22:03 +0000813 return S390_DFP_ROUND_NEGINF_11;
florian79e5a482013-06-06 19:12:46 +0000814 case Irrm_PosINF:
florianff9000d2013-02-08 20:22:03 +0000815 return S390_DFP_ROUND_POSINF_10;
florian79e5a482013-06-06 19:12:46 +0000816 case Irrm_ZERO:
florianff9000d2013-02-08 20:22:03 +0000817 return S390_DFP_ROUND_ZERO_9;
florian79e5a482013-06-06 19:12:46 +0000818 case Irrm_NEAREST_TIE_AWAY_0:
florianff9000d2013-02-08 20:22:03 +0000819 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12;
florian79e5a482013-06-06 19:12:46 +0000820 case Irrm_PREPARE_SHORTER:
florianff9000d2013-02-08 20:22:03 +0000821 return S390_DFP_ROUND_PREPARE_SHORT_15;
florian79e5a482013-06-06 19:12:46 +0000822 case Irrm_AWAY_FROM_ZERO:
florianc8e4f562012-10-27 16:19:31 +0000823 return S390_DFP_ROUND_AWAY_0;
florian79e5a482013-06-06 19:12:46 +0000824 case Irrm_NEAREST_TIE_TOWARD_0:
florianc8e4f562012-10-27 16:19:31 +0000825 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
826 default:
827 vpanic("get_dfp_rounding_mode");
828 }
829 }
830
831 set_dfp_rounding_mode_in_fpc(env, irrm);
832 return S390_DFP_ROUND_PER_FPC_0;
833}
florianc8e4f562012-10-27 16:19:31 +0000834
florian2d3d87f2012-12-21 21:05:17 +0000835
836/*---------------------------------------------------------*/
837/*--- Condition code helper functions ---*/
838/*---------------------------------------------------------*/
839
sewardj2019a972011-03-07 16:04:07 +0000840/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000841 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000842
843 s390 VEX b6 b2 b0 cc.1 cc.0
844 0 0x40 EQ 1 0 0 0 0
845 1 0x01 LT 0 0 1 0 1
846 2 0x00 GT 0 0 0 1 0
847 3 0x45 Unordered 1 1 1 1 1
848
849 b0 = cc.0
850 b2 = cc.0 & cc.1
851 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
852
853 VEX = b0 | (b2 << 2) | (b6 << 6);
854*/
855static HReg
florian2d3d87f2012-12-21 21:05:17 +0000856convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000857{
858 HReg cc0, cc1, b2, b6, cc_vex;
859
860 cc0 = newVRegI(env);
861 addInstr(env, s390_insn_move(4, cc0, cc_s390));
862 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
863
864 cc1 = newVRegI(env);
865 addInstr(env, s390_insn_move(4, cc1, cc_s390));
866 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
867
868 b2 = newVRegI(env);
869 addInstr(env, s390_insn_move(4, b2, cc0));
870 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
871 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
872
873 b6 = newVRegI(env);
874 addInstr(env, s390_insn_move(4, b6, cc0));
875 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
876 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
877 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
878 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
879
880 cc_vex = newVRegI(env);
881 addInstr(env, s390_insn_move(4, cc_vex, cc0));
882 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
883 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
884
885 return cc_vex;
886}
887
florian2d3d87f2012-12-21 21:05:17 +0000888/* CC_S390 holds the condition code in s390 encoding. Convert it to
889 VEX encoding (IRCmpDResult) */
890static HReg
891convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
892{
893 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
894 return convert_s390_to_vex_bfpcc(env, cc_s390);
895}
896
sewardj2019a972011-03-07 16:04:07 +0000897
898/*---------------------------------------------------------*/
899/*--- ISEL: Integer expressions (128 bit) ---*/
900/*---------------------------------------------------------*/
901static void
902s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
903 IRExpr *expr)
904{
905 IRType ty = typeOfIRExpr(env->type_env, expr);
906
907 vassert(ty == Ity_I128);
908
909 /* No need to consider the following
910 - 128-bit constants (they do not exist in VEX)
911 - 128-bit loads from memory (will not be generated)
912 */
913
914 /* Read 128-bit IRTemp */
915 if (expr->tag == Iex_RdTmp) {
916 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
917 return;
918 }
919
920 if (expr->tag == Iex_Binop) {
921 IRExpr *arg1 = expr->Iex.Binop.arg1;
922 IRExpr *arg2 = expr->Iex.Binop.arg2;
923 Bool is_signed_multiply, is_signed_divide;
924
925 switch (expr->Iex.Binop.op) {
926 case Iop_MullU64:
927 is_signed_multiply = False;
928 goto do_multiply64;
929
930 case Iop_MullS64:
931 is_signed_multiply = True;
932 goto do_multiply64;
933
934 case Iop_DivModU128to64:
935 is_signed_divide = False;
936 goto do_divide64;
937
938 case Iop_DivModS128to64:
939 is_signed_divide = True;
940 goto do_divide64;
941
942 case Iop_64HLto128:
943 *dst_hi = s390_isel_int_expr(env, arg1);
944 *dst_lo = s390_isel_int_expr(env, arg2);
945 return;
946
947 case Iop_DivModS64to64: {
948 HReg r10, r11, h1;
949 s390_opnd_RMI op2;
950
951 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
952 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
953
954 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000955 r10 = make_gpr(10);
956 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000957
958 /* Move 1st operand into r11 and */
959 addInstr(env, s390_insn_move(8, r11, h1));
960
961 /* Divide */
962 addInstr(env, s390_insn_divs(8, r10, r11, op2));
963
964 /* The result is in registers r10 (remainder) and r11 (quotient).
965 Move the result into the reg pair that is being returned such
966 such that the low 64 bits are the quotient and the upper 64 bits
967 are the remainder. (see libvex_ir.h). */
968 *dst_hi = newVRegI(env);
969 *dst_lo = newVRegI(env);
970 addInstr(env, s390_insn_move(8, *dst_hi, r10));
971 addInstr(env, s390_insn_move(8, *dst_lo, r11));
972 return;
973 }
974
975 default:
976 break;
977
978 do_multiply64: {
979 HReg r10, r11, h1;
980 s390_opnd_RMI op2;
981
982 order_commutative_operands(arg1, arg2);
983
984 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
985 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
986
987 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000988 r10 = make_gpr(10);
989 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000990
991 /* Move the first operand to r11 */
992 addInstr(env, s390_insn_move(8, r11, h1));
993
994 /* Multiply */
995 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
996
997 /* The result is in registers r10 and r11. Assign to two virtual regs
998 and return. */
999 *dst_hi = newVRegI(env);
1000 *dst_lo = newVRegI(env);
1001 addInstr(env, s390_insn_move(8, *dst_hi, r10));
1002 addInstr(env, s390_insn_move(8, *dst_lo, r11));
1003 return;
1004 }
1005
1006 do_divide64: {
1007 HReg r10, r11, hi, lo;
1008 s390_opnd_RMI op2;
1009
1010 s390_isel_int128_expr(&hi, &lo, env, arg1);
1011 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1012
1013 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001014 r10 = make_gpr(10);
1015 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001016
1017 /* Move high 64 bits of the 1st operand into r10 and
1018 the low 64 bits into r11. */
1019 addInstr(env, s390_insn_move(8, r10, hi));
1020 addInstr(env, s390_insn_move(8, r11, lo));
1021
1022 /* Divide */
1023 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
1024
1025 /* The result is in registers r10 (remainder) and r11 (quotient).
1026 Move the result into the reg pair that is being returned such
1027 such that the low 64 bits are the quotient and the upper 64 bits
1028 are the remainder. (see libvex_ir.h). */
1029 *dst_hi = newVRegI(env);
1030 *dst_lo = newVRegI(env);
1031 addInstr(env, s390_insn_move(8, *dst_hi, r10));
1032 addInstr(env, s390_insn_move(8, *dst_lo, r11));
1033 return;
1034 }
1035 }
1036 }
1037
1038 vpanic("s390_isel_int128_expr");
1039}
1040
1041
1042/* Compute a 128-bit value into two 64-bit registers. These may be either
1043 real or virtual regs; in any case they must not be changed by subsequent
1044 code emitted by the caller. */
1045static void
1046s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1047{
1048 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
1049
1050 /* Sanity checks ... */
1051 vassert(hregIsVirtual(*dst_hi));
1052 vassert(hregIsVirtual(*dst_lo));
1053 vassert(hregClass(*dst_hi) == HRcInt64);
1054 vassert(hregClass(*dst_lo) == HRcInt64);
1055}
1056
1057
1058/*---------------------------------------------------------*/
1059/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
1060/*---------------------------------------------------------*/
1061
1062/* Select insns for an integer-typed expression, and add them to the
1063 code list. Return a reg holding the result. This reg will be a
1064 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
1065 want to modify it, ask for a new vreg, copy it in there, and modify
1066 the copy. The register allocator will do its best to map both
1067 vregs to the same real register, so the copies will often disappear
1068 later in the game.
1069
1070 This should handle expressions of 64, 32, 16 and 8-bit type.
1071 All results are returned in a 64bit register.
1072 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1073 are arbitrary, so you should mask or sign extend partial values
1074 if necessary.
1075*/
1076
1077/* DO NOT CALL THIS DIRECTLY ! */
1078static HReg
1079s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
1080{
1081 IRType ty = typeOfIRExpr(env->type_env, expr);
1082 UChar size;
florian6dc90242012-12-21 21:43:00 +00001083 s390_bfp_conv_t conv;
florian67a171c2013-01-20 03:08:04 +00001084 s390_dfp_conv_t dconv;
sewardj2019a972011-03-07 16:04:07 +00001085
1086 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
1087
1088 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
1089
1090 switch (expr->tag) {
1091
1092 /* --------- TEMP --------- */
1093 case Iex_RdTmp:
1094 /* Return the virtual register that holds the temporary. */
1095 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1096
1097 /* --------- LOAD --------- */
1098 case Iex_Load: {
1099 HReg dst = newVRegI(env);
1100 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1101
1102 if (expr->Iex.Load.end != Iend_BE)
1103 goto irreducible;
1104
1105 addInstr(env, s390_insn_load(size, dst, am));
1106
1107 return dst;
1108 }
1109
1110 /* --------- BINARY OP --------- */
1111 case Iex_Binop: {
1112 IRExpr *arg1 = expr->Iex.Binop.arg1;
1113 IRExpr *arg2 = expr->Iex.Binop.arg2;
1114 HReg h1, res;
1115 s390_alu_t opkind;
1116 s390_opnd_RMI op2, value, opnd;
1117 s390_insn *insn;
1118 Bool is_commutative, is_signed_multiply, is_signed_divide;
1119
1120 is_commutative = True;
1121
1122 switch (expr->Iex.Binop.op) {
1123 case Iop_MullU8:
1124 case Iop_MullU16:
1125 case Iop_MullU32:
1126 is_signed_multiply = False;
1127 goto do_multiply;
1128
1129 case Iop_MullS8:
1130 case Iop_MullS16:
1131 case Iop_MullS32:
1132 is_signed_multiply = True;
1133 goto do_multiply;
1134
1135 do_multiply: {
1136 HReg r10, r11;
1137 UInt arg_size = size / 2;
1138
1139 order_commutative_operands(arg1, arg2);
1140
1141 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1142 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1143
1144 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001145 r10 = make_gpr(10);
1146 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001147
1148 /* Move the first operand to r11 */
1149 addInstr(env, s390_insn_move(arg_size, r11, h1));
1150
1151 /* Multiply */
1152 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1153
1154 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1155 value into the destination register. */
1156 res = newVRegI(env);
1157 addInstr(env, s390_insn_move(arg_size, res, r10));
1158 value = s390_opnd_imm(arg_size * 8);
1159 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1160 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1161 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1162 opnd = s390_opnd_reg(r11);
1163 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1164 return res;
1165 }
1166
1167 case Iop_DivModS64to32:
1168 is_signed_divide = True;
1169 goto do_divide;
1170
1171 case Iop_DivModU64to32:
1172 is_signed_divide = False;
1173 goto do_divide;
1174
1175 do_divide: {
1176 HReg r10, r11;
1177
1178 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1179 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1180
1181 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001182 r10 = make_gpr(10);
1183 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001184
1185 /* Split the first operand and put the high 32 bits into r10 and
1186 the low 32 bits into r11. */
1187 addInstr(env, s390_insn_move(8, r10, h1));
1188 addInstr(env, s390_insn_move(8, r11, h1));
1189 value = s390_opnd_imm(32);
1190 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1191
1192 /* Divide */
1193 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1194
1195 /* The result is in registers r10 (remainder) and r11 (quotient).
1196 Combine them into a 64-bit value such that the low 32 bits are
1197 the quotient and the upper 32 bits are the remainder. (see
1198 libvex_ir.h). */
1199 res = newVRegI(env);
1200 addInstr(env, s390_insn_move(8, res, r10));
1201 value = s390_opnd_imm(32);
1202 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1203 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1204 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1205 opnd = s390_opnd_reg(r11);
1206 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1207 return res;
1208 }
1209
florian9fcff4c2012-09-10 03:09:04 +00001210 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1211 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1212 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1213 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1214 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1215 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1216 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1217 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1218 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1219 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1220 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1221 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
florian67a171c2013-01-20 03:08:04 +00001222
1223 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
floriana887acd2013-02-08 23:32:54 +00001224 case Iop_D64toI64S: dconv = S390_DFP_D64_TO_I64; goto do_convert_dfp;
florian67a171c2013-01-20 03:08:04 +00001225 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1226 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1227 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
floriana887acd2013-02-08 23:32:54 +00001228 case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128;
florian67a171c2013-01-20 03:08:04 +00001229 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1230 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00001231
1232 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001233 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001234
1235 res = newVRegI(env);
1236 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1237
florian2c74d242012-09-12 19:38:42 +00001238 rounding_mode = get_bfp_rounding_mode(env, arg1);
1239 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1240 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001241 return res;
1242 }
1243
1244 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001245 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001246 HReg op_hi, op_lo, f13, f15;
1247
1248 res = newVRegI(env);
1249 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1250
1251 /* We use non-virtual registers r13 and r15 as pair */
1252 f13 = make_fpr(13);
1253 f15 = make_fpr(15);
1254
1255 /* operand --> (f13, f15) */
1256 addInstr(env, s390_insn_move(8, f13, op_hi));
1257 addInstr(env, s390_insn_move(8, f15, op_lo));
1258
florian2c74d242012-09-12 19:38:42 +00001259 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001260 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001261 rounding_mode));
1262 return res;
1263 }
1264
florian5f034622013-01-13 02:29:05 +00001265 do_convert_dfp: {
1266 s390_dfp_round_t rounding_mode;
1267
1268 res = newVRegI(env);
1269 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1270
1271 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001272 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
florian5f034622013-01-13 02:29:05 +00001273 rounding_mode));
1274 return res;
1275 }
1276
1277 do_convert_dfp128: {
1278 s390_dfp_round_t rounding_mode;
1279 HReg op_hi, op_lo, f13, f15;
1280
1281 res = newVRegI(env);
1282 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1283
1284 /* We use non-virtual registers r13 and r15 as pair */
1285 f13 = make_fpr(13);
1286 f15 = make_fpr(15);
1287
1288 /* operand --> (f13, f15) */
1289 addInstr(env, s390_insn_move(8, f13, op_hi));
1290 addInstr(env, s390_insn_move(8, f15, op_lo));
1291
1292 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001293 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res, f13,
florian5f034622013-01-13 02:29:05 +00001294 f15, rounding_mode));
1295 return res;
1296 }
1297
sewardj2019a972011-03-07 16:04:07 +00001298 case Iop_8HLto16:
1299 case Iop_16HLto32:
1300 case Iop_32HLto64: {
1301 HReg h2;
1302 UInt arg_size = size / 2;
1303
1304 res = newVRegI(env);
1305 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1306 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1307
1308 addInstr(env, s390_insn_move(arg_size, res, h1));
1309 value = s390_opnd_imm(arg_size * 8);
1310 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1311 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1312 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1313 opnd = s390_opnd_reg(h2);
1314 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1315 return res;
1316 }
1317
1318 case Iop_Max32U: {
1319 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1320 res = newVRegI(env);
1321 h1 = s390_isel_int_expr(env, arg1);
1322 op2 = s390_isel_int_expr_RMI(env, arg2);
1323
1324 addInstr(env, s390_insn_move(size, res, h1));
1325 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1326 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1327 return res;
1328 }
1329
1330 case Iop_CmpF32:
1331 case Iop_CmpF64: {
1332 HReg cc_s390, h2;
1333
1334 h1 = s390_isel_float_expr(env, arg1);
1335 h2 = s390_isel_float_expr(env, arg2);
1336 cc_s390 = newVRegI(env);
1337
1338 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1339
1340 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1341
florian2d3d87f2012-12-21 21:05:17 +00001342 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001343 }
1344
1345 case Iop_CmpF128: {
1346 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1347
1348 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1349 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1350 cc_s390 = newVRegI(env);
1351
1352 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1353 f12 = make_fpr(12);
1354 f13 = make_fpr(13);
1355 f14 = make_fpr(14);
1356 f15 = make_fpr(15);
1357
1358 /* 1st operand --> (f12, f14) */
1359 addInstr(env, s390_insn_move(8, f12, op1_hi));
1360 addInstr(env, s390_insn_move(8, f14, op1_lo));
1361
1362 /* 2nd operand --> (f13, f15) */
1363 addInstr(env, s390_insn_move(8, f13, op2_hi));
1364 addInstr(env, s390_insn_move(8, f15, op2_lo));
1365
1366 res = newVRegI(env);
1367 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1368
florian2d3d87f2012-12-21 21:05:17 +00001369 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001370 }
1371
florian20c6bca2012-12-26 17:47:19 +00001372 case Iop_CmpD64:
1373 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001374 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001375 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001376
1377 h1 = s390_isel_dfp_expr(env, arg1);
1378 h2 = s390_isel_dfp_expr(env, arg2);
1379 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001380
florian20c6bca2012-12-26 17:47:19 +00001381 switch(expr->Iex.Binop.op) {
1382 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1383 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1384 default: goto irreducible;
1385 }
1386 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001387
florian2d3d87f2012-12-21 21:05:17 +00001388 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001389 }
1390
florian20c6bca2012-12-26 17:47:19 +00001391 case Iop_CmpD128:
1392 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001393 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001394 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001395
1396 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1397 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1398 cc_s390 = newVRegI(env);
1399
1400 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1401 f12 = make_fpr(12);
1402 f13 = make_fpr(13);
1403 f14 = make_fpr(14);
1404 f15 = make_fpr(15);
1405
1406 /* 1st operand --> (f12, f14) */
1407 addInstr(env, s390_insn_move(8, f12, op1_hi));
1408 addInstr(env, s390_insn_move(8, f14, op1_lo));
1409
1410 /* 2nd operand --> (f13, f15) */
1411 addInstr(env, s390_insn_move(8, f13, op2_hi));
1412 addInstr(env, s390_insn_move(8, f15, op2_lo));
1413
florian20c6bca2012-12-26 17:47:19 +00001414 switch(expr->Iex.Binop.op) {
1415 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1416 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1417 default: goto irreducible;
1418 }
1419 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1420 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001421
florian2d3d87f2012-12-21 21:05:17 +00001422 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001423 }
1424
sewardj2019a972011-03-07 16:04:07 +00001425 case Iop_Add8:
1426 case Iop_Add16:
1427 case Iop_Add32:
1428 case Iop_Add64:
1429 opkind = S390_ALU_ADD;
1430 break;
1431
1432 case Iop_Sub8:
1433 case Iop_Sub16:
1434 case Iop_Sub32:
1435 case Iop_Sub64:
1436 opkind = S390_ALU_SUB;
1437 is_commutative = False;
1438 break;
1439
1440 case Iop_And8:
1441 case Iop_And16:
1442 case Iop_And32:
1443 case Iop_And64:
1444 opkind = S390_ALU_AND;
1445 break;
1446
1447 case Iop_Or8:
1448 case Iop_Or16:
1449 case Iop_Or32:
1450 case Iop_Or64:
1451 opkind = S390_ALU_OR;
1452 break;
1453
1454 case Iop_Xor8:
1455 case Iop_Xor16:
1456 case Iop_Xor32:
1457 case Iop_Xor64:
1458 opkind = S390_ALU_XOR;
1459 break;
1460
1461 case Iop_Shl8:
1462 case Iop_Shl16:
1463 case Iop_Shl32:
1464 case Iop_Shl64:
1465 opkind = S390_ALU_LSH;
1466 is_commutative = False;
1467 break;
1468
1469 case Iop_Shr8:
1470 case Iop_Shr16:
1471 case Iop_Shr32:
1472 case Iop_Shr64:
1473 opkind = S390_ALU_RSH;
1474 is_commutative = False;
1475 break;
1476
1477 case Iop_Sar8:
1478 case Iop_Sar16:
1479 case Iop_Sar32:
1480 case Iop_Sar64:
1481 opkind = S390_ALU_RSHA;
1482 is_commutative = False;
1483 break;
1484
1485 default:
1486 goto irreducible;
1487 }
1488
1489 /* Pattern match: 0 - arg1 --> -arg1 */
1490 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1491 res = newVRegI(env);
1492 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1493 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1494 addInstr(env, insn);
1495
1496 return res;
1497 }
1498
1499 if (is_commutative) {
1500 order_commutative_operands(arg1, arg2);
1501 }
1502
1503 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1504 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1505 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001506
1507 /* As right shifts of one/two byte opreands are implemented using a
1508 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1509 switch (expr->Iex.Binop.op) {
1510 case Iop_Shr8:
1511 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1512 break;
1513 case Iop_Shr16:
1514 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1515 break;
1516 case Iop_Sar8:
1517 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1518 break;
1519 case Iop_Sar16:
1520 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1521 break;
1522 default:
1523 insn = s390_insn_move(size, res, h1);
1524 break;
1525 }
1526 addInstr(env, insn);
1527
sewardj2019a972011-03-07 16:04:07 +00001528 insn = s390_insn_alu(size, opkind, res, op2);
1529
1530 addInstr(env, insn);
1531
1532 return res;
1533 }
1534
1535 /* --------- UNARY OP --------- */
1536 case Iex_Unop: {
1537 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1538 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1539 s390_opnd_RMI opnd;
1540 s390_insn *insn;
1541 IRExpr *arg;
1542 HReg dst, h1;
1543 IROp unop, binop;
1544
1545 arg = expr->Iex.Unop.arg;
1546
1547 /* Special cases are handled here */
1548
1549 /* 32-bit multiply with 32-bit result or
1550 64-bit multiply with 64-bit result */
1551 unop = expr->Iex.Unop.op;
1552 binop = arg->Iex.Binop.op;
1553
1554 if ((arg->tag == Iex_Binop &&
1555 ((unop == Iop_64to32 &&
1556 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1557 (unop == Iop_128to64 &&
1558 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1559 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1560 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1561 dst = newVRegI(env); /* Result goes into a new register */
1562 addInstr(env, s390_insn_move(size, dst, h1));
1563 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1564
1565 return dst;
1566 }
1567
florian4d71a082011-12-18 00:08:17 +00001568 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001569 dst = newVRegI(env);
1570 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1571 addInstr(env, s390_insn_move(size, dst, h1));
1572
1573 return dst;
1574 }
1575
floriane38f6412012-12-21 17:32:12 +00001576 if (unop == Iop_ReinterpD64asI64) {
1577 dst = newVRegI(env);
1578 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1579 addInstr(env, s390_insn_move(size, dst, h1));
1580
1581 return dst;
1582 }
1583
florian5c539732013-02-14 14:27:12 +00001584 if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
1585 s390_dfp_unop_t dfpop;
1586 switch(unop) {
1587 case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
1588 case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
1589 default: goto irreducible;
1590 }
floriance9e3db2012-12-27 20:14:03 +00001591 dst = newVRegI(env);
1592 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
florian5c539732013-02-14 14:27:12 +00001593 addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
floriance9e3db2012-12-27 20:14:03 +00001594 return dst;
1595 }
1596
florian5c539732013-02-14 14:27:12 +00001597 if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
1598 s390_dfp_unop_t dfpop;
floriance9e3db2012-12-27 20:14:03 +00001599 HReg op_hi, op_lo, f13, f15;
florian5c539732013-02-14 14:27:12 +00001600
1601 switch(unop) {
1602 case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
1603 case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
1604 default: goto irreducible;
1605 }
floriance9e3db2012-12-27 20:14:03 +00001606 dst = newVRegI(env);
1607 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1608
1609 /* We use non-virtual registers r13 and r15 as pair */
1610 f13 = make_fpr(13);
1611 f15 = make_fpr(15);
1612
1613 /* operand --> (f13, f15) */
1614 addInstr(env, s390_insn_move(8, f13, op_hi));
1615 addInstr(env, s390_insn_move(8, f15, op_lo));
1616
florian5c539732013-02-14 14:27:12 +00001617 addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
floriance9e3db2012-12-27 20:14:03 +00001618 return dst;
1619 }
1620
sewardj2019a972011-03-07 16:04:07 +00001621 /* Expressions whose argument is 1-bit wide */
1622 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1623 s390_cc_t cond = s390_isel_cc(env, arg);
1624 dst = newVRegI(env); /* Result goes into a new register */
1625 addInstr(env, s390_insn_cc2bool(dst, cond));
1626
1627 switch (unop) {
1628 case Iop_1Uto8:
1629 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001630 /* Zero extend */
1631 mask.variant.imm = 1;
1632 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1633 break;
1634
sewardj2019a972011-03-07 16:04:07 +00001635 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001636 /* Zero extend */
1637 mask.variant.imm = 1;
1638 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001639 break;
1640
1641 case Iop_1Sto8:
1642 case Iop_1Sto16:
1643 case Iop_1Sto32:
1644 shift.variant.imm = 31;
1645 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1646 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1647 break;
1648
1649 case Iop_1Sto64:
1650 shift.variant.imm = 63;
1651 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1652 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1653 break;
1654
1655 default:
1656 goto irreducible;
1657 }
1658
1659 return dst;
1660 }
1661
1662 /* Regular processing */
1663
1664 if (unop == Iop_128to64) {
1665 HReg dst_hi, dst_lo;
1666
1667 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1668 return dst_lo;
1669 }
1670
1671 if (unop == Iop_128HIto64) {
1672 HReg dst_hi, dst_lo;
1673
1674 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1675 return dst_hi;
1676 }
1677
1678 dst = newVRegI(env); /* Result goes into a new register */
1679 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1680
1681 switch (unop) {
1682 case Iop_8Uto16:
1683 case Iop_8Uto32:
1684 case Iop_8Uto64:
1685 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1686 break;
1687
1688 case Iop_16Uto32:
1689 case Iop_16Uto64:
1690 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1691 break;
1692
1693 case Iop_32Uto64:
1694 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1695 break;
1696
1697 case Iop_8Sto16:
1698 case Iop_8Sto32:
1699 case Iop_8Sto64:
1700 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1701 break;
1702
1703 case Iop_16Sto32:
1704 case Iop_16Sto64:
1705 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1706 break;
1707
1708 case Iop_32Sto64:
1709 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1710 break;
1711
1712 case Iop_64to8:
1713 case Iop_64to16:
1714 case Iop_64to32:
1715 case Iop_32to8:
1716 case Iop_32to16:
1717 case Iop_16to8:
1718 /* Down-casts are no-ops. Upstream operations will only look at
1719 the bytes that make up the result of the down-cast. So there
1720 is no point setting the other bytes to 0. */
1721 insn = s390_opnd_copy(8, dst, opnd);
1722 break;
1723
1724 case Iop_64HIto32:
1725 addInstr(env, s390_opnd_copy(8, dst, opnd));
1726 shift.variant.imm = 32;
1727 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1728 break;
1729
1730 case Iop_32HIto16:
1731 addInstr(env, s390_opnd_copy(4, dst, opnd));
1732 shift.variant.imm = 16;
1733 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1734 break;
1735
1736 case Iop_16HIto8:
1737 addInstr(env, s390_opnd_copy(2, dst, opnd));
1738 shift.variant.imm = 8;
1739 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1740 break;
1741
1742 case Iop_Not8:
1743 case Iop_Not16:
1744 case Iop_Not32:
1745 case Iop_Not64:
1746 /* XOR with ffff... */
1747 mask.variant.imm = ~(ULong)0;
1748 addInstr(env, s390_opnd_copy(size, dst, opnd));
1749 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1750 break;
1751
1752 case Iop_Left8:
1753 case Iop_Left16:
1754 case Iop_Left32:
1755 case Iop_Left64:
1756 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1757 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1758 break;
1759
1760 case Iop_CmpwNEZ32:
1761 case Iop_CmpwNEZ64: {
1762 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1763 or -X will have a 1 in the MSB. */
1764 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1765 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1766 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1767 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1768 return dst;
1769 }
1770
1771 case Iop_Clz64: {
1772 HReg r10, r11;
1773
sewardj611b06e2011-03-24 08:57:29 +00001774 /* This will be implemented using FLOGR, if possible. So we need to
1775 set aside a pair of non-virtual registers. The result (number of
1776 left-most zero bits) will be in r10. The value in r11 is unspecified
1777 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001778 r10 = make_gpr(10);
1779 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001780
sewardj611b06e2011-03-24 08:57:29 +00001781 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001782 addInstr(env, s390_insn_move(8, dst, r10));
1783 return dst;
1784 }
1785
1786 default:
1787 goto irreducible;
1788 }
1789
1790 addInstr(env, insn);
1791
1792 return dst;
1793 }
1794
1795 /* --------- GET --------- */
1796 case Iex_Get: {
1797 HReg dst = newVRegI(env);
1798 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1799
1800 /* We never load more than 8 bytes from the guest state, because the
1801 floating point register pair is not contiguous. */
1802 vassert(size <= 8);
1803
1804 addInstr(env, s390_insn_load(size, dst, am));
1805
1806 return dst;
1807 }
1808
1809 case Iex_GetI:
1810 /* not needed */
1811 break;
1812
1813 /* --------- CCALL --------- */
1814 case Iex_CCall: {
1815 HReg dst = newVRegI(env);
sewardj74142b82013-08-08 10:28:59 +00001816 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
1817 UInt addToSp = 0;
1818 RetLoc rloc = mk_RetLoc_INVALID();
sewardj2019a972011-03-07 16:04:07 +00001819
sewardj74142b82013-08-08 10:28:59 +00001820 doHelperCall(&addToSp, &rloc, env, NULL, expr->Iex.CCall.cee,
1821 expr->Iex.CCall.retty, expr->Iex.CCall.args);
1822 vassert(is_sane_RetLoc(rloc));
1823 vassert(rloc.pri == RLPri_Int);
1824 vassert(addToSp == 0);
1825 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
1826
sewardj2019a972011-03-07 16:04:07 +00001827 return dst;
1828 }
1829
1830 /* --------- LITERAL --------- */
1831
1832 /* Load a literal into a register. Create a "load immediate"
1833 v-insn and return the register. */
1834 case Iex_Const: {
1835 ULong value;
1836 HReg dst = newVRegI(env);
1837 const IRConst *con = expr->Iex.Const.con;
1838
1839 /* Bitwise copy of the value. No sign/zero-extension */
1840 switch (con->tag) {
1841 case Ico_U64: value = con->Ico.U64; break;
1842 case Ico_U32: value = con->Ico.U32; break;
1843 case Ico_U16: value = con->Ico.U16; break;
1844 case Ico_U8: value = con->Ico.U8; break;
1845 default: vpanic("s390_isel_int_expr: invalid constant");
1846 }
1847
1848 addInstr(env, s390_insn_load_immediate(size, dst, value));
1849
1850 return dst;
1851 }
1852
1853 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00001854 case Iex_ITE: {
sewardj2019a972011-03-07 16:04:07 +00001855 IRExpr *cond_expr;
florian99dd03e2013-01-29 03:56:06 +00001856 HReg dst, r1;
sewardj009230b2013-01-26 11:47:55 +00001857 s390_opnd_RMI r0;
sewardj2019a972011-03-07 16:04:07 +00001858
florian99dd03e2013-01-29 03:56:06 +00001859 cond_expr = expr->Iex.ITE.cond;
sewardj2019a972011-03-07 16:04:07 +00001860
sewardj009230b2013-01-26 11:47:55 +00001861 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
1862
sewardj2019a972011-03-07 16:04:07 +00001863 dst = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00001864 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
1865 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
1866 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
sewardj2019a972011-03-07 16:04:07 +00001867
sewardj009230b2013-01-26 11:47:55 +00001868 s390_cc_t cc = s390_isel_cc(env, cond_expr);
sewardj2019a972011-03-07 16:04:07 +00001869
florian99dd03e2013-01-29 03:56:06 +00001870 addInstr(env, s390_insn_move(size, dst, r1));
sewardj009230b2013-01-26 11:47:55 +00001871 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
sewardj2019a972011-03-07 16:04:07 +00001872 return dst;
1873 }
1874
1875 default:
1876 break;
1877 }
1878
1879 /* We get here if no pattern matched. */
1880 irreducible:
1881 ppIRExpr(expr);
1882 vpanic("s390_isel_int_expr: cannot reduce tree");
1883}
1884
1885
1886static HReg
1887s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1888{
1889 HReg dst = s390_isel_int_expr_wrk(env, expr);
1890
1891 /* Sanity checks ... */
1892 vassert(hregClass(dst) == HRcInt64);
1893 vassert(hregIsVirtual(dst));
1894
1895 return dst;
1896}
1897
1898
1899static s390_opnd_RMI
1900s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1901{
1902 IRType ty = typeOfIRExpr(env->type_env, expr);
1903 s390_opnd_RMI dst;
1904
1905 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1906 ty == Ity_I64);
1907
1908 if (expr->tag == Iex_Load) {
1909 dst.tag = S390_OPND_AMODE;
1910 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1911 } else if (expr->tag == Iex_Get) {
1912 dst.tag = S390_OPND_AMODE;
1913 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1914 } else if (expr->tag == Iex_Const) {
1915 ULong value;
1916
1917 /* The bit pattern for the value will be stored as is in the least
1918 significant bits of VALUE. */
1919 switch (expr->Iex.Const.con->tag) {
1920 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1921 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1922 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1923 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1924 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1925 default:
1926 vpanic("s390_isel_int_expr_RMI");
1927 }
1928
1929 dst.tag = S390_OPND_IMMEDIATE;
1930 dst.variant.imm = value;
1931 } else {
1932 dst.tag = S390_OPND_REG;
1933 dst.variant.reg = s390_isel_int_expr(env, expr);
1934 }
1935
1936 return dst;
1937}
1938
1939
1940/*---------------------------------------------------------*/
1941/*--- ISEL: Floating point expressions (128 bit) ---*/
1942/*---------------------------------------------------------*/
1943static void
1944s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1945 IRExpr *expr)
1946{
1947 IRType ty = typeOfIRExpr(env->type_env, expr);
1948
1949 vassert(ty == Ity_F128);
1950
sewardj2019a972011-03-07 16:04:07 +00001951 switch (expr->tag) {
1952 case Iex_RdTmp:
1953 /* Return the virtual registers that hold the temporary. */
1954 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1955 return;
1956
1957 /* --------- LOAD --------- */
1958 case Iex_Load: {
1959 IRExpr *addr_hi, *addr_lo;
1960 s390_amode *am_hi, *am_lo;
1961
1962 if (expr->Iex.Load.end != Iend_BE)
1963 goto irreducible;
1964
1965 addr_hi = expr->Iex.Load.addr;
1966 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1967
1968 am_hi = s390_isel_amode(env, addr_hi);
1969 am_lo = s390_isel_amode(env, addr_lo);
1970
1971 *dst_hi = newVRegF(env);
1972 *dst_lo = newVRegF(env);
1973 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1974 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1975 return;
1976 }
1977
1978
1979 /* --------- GET --------- */
1980 case Iex_Get:
1981 /* This is not supported because loading 128-bit from the guest
1982 state is almost certainly wrong. Use get_fpr_pair instead. */
1983 vpanic("Iex_Get with F128 data");
1984
1985 /* --------- 4-ary OP --------- */
1986 case Iex_Qop:
1987 vpanic("Iex_Qop with F128 data");
1988
1989 /* --------- TERNARY OP --------- */
1990 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001991 IRTriop *triop = expr->Iex.Triop.details;
1992 IROp op = triop->op;
1993 IRExpr *left = triop->arg2;
1994 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001995 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001996 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1997
1998 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1999 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2000
2001 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2002 f12 = make_fpr(12);
2003 f13 = make_fpr(13);
2004 f14 = make_fpr(14);
2005 f15 = make_fpr(15);
2006
2007 /* 1st operand --> (f12, f14) */
2008 addInstr(env, s390_insn_move(8, f12, op1_hi));
2009 addInstr(env, s390_insn_move(8, f14, op1_lo));
2010
2011 /* 2nd operand --> (f13, f15) */
2012 addInstr(env, s390_insn_move(8, f13, op2_hi));
2013 addInstr(env, s390_insn_move(8, f15, op2_lo));
2014
2015 switch (op) {
2016 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
2017 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
2018 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
2019 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
2020 default:
2021 goto irreducible;
2022 }
2023
florian2c74d242012-09-12 19:38:42 +00002024 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2025 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002026
2027 /* Move result to virtual destination register */
2028 *dst_hi = newVRegF(env);
2029 *dst_lo = newVRegF(env);
2030 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2031 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2032
2033 return;
2034 }
2035
2036 /* --------- BINARY OP --------- */
2037 case Iex_Binop: {
sewardj2019a972011-03-07 16:04:07 +00002038 switch (expr->Iex.Binop.op) {
florian78d5ef72013-05-11 15:02:58 +00002039 case Iop_SqrtF128: {
2040 HReg op_hi, op_lo, f12, f13, f14, f15;
2041
2042 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2043 f12 = make_fpr(12);
2044 f13 = make_fpr(13);
2045 f14 = make_fpr(14);
2046 f15 = make_fpr(15);
2047
sewardj2019a972011-03-07 16:04:07 +00002048 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
2049
2050 /* operand --> (f13, f15) */
2051 addInstr(env, s390_insn_move(8, f13, op_hi));
2052 addInstr(env, s390_insn_move(8, f15, op_lo));
2053
florian2c74d242012-09-12 19:38:42 +00002054 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
2055 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
2056 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002057
2058 /* Move result to virtual destination registers */
2059 *dst_hi = newVRegF(env);
2060 *dst_lo = newVRegF(env);
2061 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2062 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2063 return;
florian78d5ef72013-05-11 15:02:58 +00002064 }
sewardj2019a972011-03-07 16:04:07 +00002065
2066 case Iop_F64HLtoF128:
2067 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
2068 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
2069 return;
2070
florian7ab421d2013-06-17 21:03:56 +00002071 case Iop_D32toF128:
2072 case Iop_D64toF128: {
2073 IRExpr *irrm;
2074 IRExpr *left;
2075 s390_dfp_round_t rm;
2076 HReg h1; /* virtual reg. to hold source */
2077 HReg f0, f2, f4, r1; /* real registers used by PFPO */
2078 s390_fp_conv_t fpconv;
2079
2080 switch (expr->Iex.Binop.op) {
2081 case Iop_D32toF128:
2082 fpconv = S390_FP_D32_TO_F128;
2083 break;
2084 case Iop_D64toF128:
2085 fpconv = S390_FP_D64_TO_F128;
2086 break;
2087 default: goto irreducible;
2088 }
2089
2090 f4 = make_fpr(4); /* source */
2091 f0 = make_fpr(0); /* destination */
2092 f2 = make_fpr(2); /* destination */
2093 r1 = make_gpr(1); /* GPR #1 clobbered */
2094 irrm = expr->Iex.Binop.arg1;
2095 left = expr->Iex.Binop.arg2;
2096 rm = get_dfp_rounding_mode(env, irrm);
2097 h1 = s390_isel_dfp_expr(env, left);
2098 addInstr(env, s390_insn_move(8, f4, h1));
2099 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
2100 f4, INVALID_HREG, r1, rm));
2101 /* (f0, f2) --> destination */
2102 *dst_hi = newVRegF(env);
2103 *dst_lo = newVRegF(env);
2104 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2105 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2106
2107 return;
2108 }
2109
florian78d5ef72013-05-11 15:02:58 +00002110 case Iop_D128toF128: {
2111 IRExpr *irrm;
2112 IRExpr *left;
2113 s390_dfp_round_t rm;
2114 HReg op_hi, op_lo;
2115 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2116
2117 f4 = make_fpr(4); /* source */
2118 f6 = make_fpr(6); /* source */
2119 f0 = make_fpr(0); /* destination */
2120 f2 = make_fpr(2); /* destination */
2121 r1 = make_gpr(1); /* GPR #1 clobbered */
2122
2123 irrm = expr->Iex.Binop.arg1;
2124 left = expr->Iex.Binop.arg2;
2125 rm = get_dfp_rounding_mode(env, irrm);
2126 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2127 /* operand --> (f4, f6) */
2128 addInstr(env, s390_insn_move(8, f4, op_hi));
2129 addInstr(env, s390_insn_move(8, f6, op_lo));
2130 addInstr(env, s390_insn_fp128_convert(16, S390_FP_D128_TO_F128, f0, f2,
2131 f4, f6, r1, rm));
2132 /* (f0, f2) --> destination */
2133 *dst_hi = newVRegF(env);
2134 *dst_lo = newVRegF(env);
2135 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2136 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2137
2138 return;
2139 }
2140
sewardj2019a972011-03-07 16:04:07 +00002141 default:
2142 goto irreducible;
2143 }
2144 }
2145
2146 /* --------- UNARY OP --------- */
2147 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00002148 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00002149 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002150 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002151 HReg op_hi, op_lo, op, f12, f13, f14, f15;
2152
2153 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2154 f12 = make_fpr(12);
2155 f13 = make_fpr(13);
2156 f14 = make_fpr(14);
2157 f15 = make_fpr(15);
2158
florian66e596d2012-09-07 15:00:53 +00002159 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00002160 case Iop_NegF128:
2161 if (left->tag == Iex_Unop &&
2162 (left->Iex.Unop.op == Iop_AbsF32 ||
2163 left->Iex.Unop.op == Iop_AbsF64))
2164 bfpop = S390_BFP_NABS;
2165 else
2166 bfpop = S390_BFP_NEG;
2167 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00002168 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2169 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2170 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2171 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2172 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2173 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2174 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00002175 default:
2176 goto irreducible;
2177 }
2178
2179 float128_opnd:
2180 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2181
2182 /* operand --> (f13, f15) */
2183 addInstr(env, s390_insn_move(8, f13, op_hi));
2184 addInstr(env, s390_insn_move(8, f15, op_lo));
2185
florian2c74d242012-09-12 19:38:42 +00002186 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002187 goto move_dst;
2188
2189 convert_float:
2190 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002191 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002192 goto move_dst;
2193
2194 convert_int:
2195 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002196 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002197 goto move_dst;
2198
2199 move_dst:
2200 /* Move result to virtual destination registers */
2201 *dst_hi = newVRegF(env);
2202 *dst_lo = newVRegF(env);
2203 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2204 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2205 return;
2206 }
2207
2208 default:
2209 goto irreducible;
2210 }
2211
2212 /* We get here if no pattern matched. */
2213 irreducible:
2214 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002215 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002216}
2217
2218/* Compute a 128-bit value into two 64-bit registers. These may be either
2219 real or virtual regs; in any case they must not be changed by subsequent
2220 code emitted by the caller. */
2221static void
2222s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2223{
2224 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2225
2226 /* Sanity checks ... */
2227 vassert(hregIsVirtual(*dst_hi));
2228 vassert(hregIsVirtual(*dst_lo));
2229 vassert(hregClass(*dst_hi) == HRcFlt64);
2230 vassert(hregClass(*dst_lo) == HRcFlt64);
2231}
2232
2233
2234/*---------------------------------------------------------*/
2235/*--- ISEL: Floating point expressions (64 bit) ---*/
2236/*---------------------------------------------------------*/
2237
2238static HReg
2239s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2240{
2241 IRType ty = typeOfIRExpr(env->type_env, expr);
2242 UChar size;
2243
2244 vassert(ty == Ity_F32 || ty == Ity_F64);
2245
2246 size = sizeofIRType(ty);
2247
2248 switch (expr->tag) {
2249 case Iex_RdTmp:
2250 /* Return the virtual register that holds the temporary. */
2251 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2252
2253 /* --------- LOAD --------- */
2254 case Iex_Load: {
2255 HReg dst = newVRegF(env);
2256 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2257
2258 if (expr->Iex.Load.end != Iend_BE)
2259 goto irreducible;
2260
2261 addInstr(env, s390_insn_load(size, dst, am));
2262
2263 return dst;
2264 }
2265
2266 /* --------- GET --------- */
2267 case Iex_Get: {
2268 HReg dst = newVRegF(env);
2269 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2270
2271 addInstr(env, s390_insn_load(size, dst, am));
2272
2273 return dst;
2274 }
2275
2276 /* --------- LITERAL --------- */
2277
2278 /* Load a literal into a register. Create a "load immediate"
2279 v-insn and return the register. */
2280 case Iex_Const: {
2281 ULong value;
2282 HReg dst = newVRegF(env);
2283 const IRConst *con = expr->Iex.Const.con;
2284
2285 /* Bitwise copy of the value. No sign/zero-extension */
2286 switch (con->tag) {
2287 case Ico_F32i: value = con->Ico.F32i; break;
2288 case Ico_F64i: value = con->Ico.F64i; break;
2289 default: vpanic("s390_isel_float_expr: invalid constant");
2290 }
2291
2292 if (value != 0) vpanic("cannot load immediate floating point constant");
2293
2294 addInstr(env, s390_insn_load_immediate(size, dst, value));
2295
2296 return dst;
2297 }
2298
2299 /* --------- 4-ary OP --------- */
2300 case Iex_Qop: {
2301 HReg op1, op2, op3, dst;
2302 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002303
florian5906a6b2012-10-16 02:53:33 +00002304 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002305 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002306 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002307 dst = newVRegF(env);
2308 addInstr(env, s390_insn_move(size, dst, op1));
2309
florian96d7cc32012-06-01 20:41:24 +00002310 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002311 case Iop_MAddF32:
2312 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2313 case Iop_MSubF32:
2314 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2315
2316 default:
2317 goto irreducible;
2318 }
2319
florian2c74d242012-09-12 19:38:42 +00002320 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2321 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002322 return dst;
2323 }
2324
2325 /* --------- TERNARY OP --------- */
2326 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002327 IRTriop *triop = expr->Iex.Triop.details;
2328 IROp op = triop->op;
2329 IRExpr *left = triop->arg2;
2330 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002331 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002332 HReg h1, op2, dst;
2333
2334 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2335 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2336 dst = newVRegF(env);
2337 addInstr(env, s390_insn_move(size, dst, h1));
2338 switch (op) {
2339 case Iop_AddF32:
2340 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2341 case Iop_SubF32:
2342 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2343 case Iop_MulF32:
2344 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2345 case Iop_DivF32:
2346 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2347
2348 default:
2349 goto irreducible;
2350 }
2351
florian2c74d242012-09-12 19:38:42 +00002352 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2353 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002354 return dst;
2355 }
2356
2357 /* --------- BINARY OP --------- */
2358 case Iex_Binop: {
2359 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002360 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002361 IRExpr *left = expr->Iex.Binop.arg2;
2362 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002363 s390_bfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002364 s390_fp_conv_t fpconv;
sewardj2019a972011-03-07 16:04:07 +00002365
2366 switch (op) {
2367 case Iop_SqrtF32:
2368 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002369 h1 = s390_isel_float_expr(env, left);
2370 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002371 set_bfp_rounding_mode_in_fpc(env, irrm);
2372 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002373 return dst;
sewardj2019a972011-03-07 16:04:07 +00002374
florian9fcff4c2012-09-10 03:09:04 +00002375 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2376 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2377 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2378 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2379 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2380 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2381 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
florian7ab421d2013-06-17 21:03:56 +00002382 case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp;
2383 case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp;
2384 case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp;
florian78d5ef72013-05-11 15:02:58 +00002385 case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp;
florian7ab421d2013-06-17 21:03:56 +00002386 case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128;
florian78d5ef72013-05-11 15:02:58 +00002387 case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00002388
florian9fcff4c2012-09-10 03:09:04 +00002389 convert_float:
2390 h1 = s390_isel_float_expr(env, left);
2391 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002392
florian9fcff4c2012-09-10 03:09:04 +00002393 convert_int:
2394 h1 = s390_isel_int_expr(env, left);
2395 goto convert;
2396
florian2c74d242012-09-12 19:38:42 +00002397 convert: {
florian125e20d2012-10-07 15:42:37 +00002398 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002399 /* convert-from-fixed and load-rounded have a rounding mode field
2400 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002401 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002402 if (s390_host_has_fpext) {
2403 rounding_mode = get_bfp_rounding_mode(env, irrm);
2404 } else {
2405 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002406 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002407 }
florian9fcff4c2012-09-10 03:09:04 +00002408 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2409 rounding_mode));
2410 return dst;
florian2c74d242012-09-12 19:38:42 +00002411 }
florian78d5ef72013-05-11 15:02:58 +00002412
2413 convert_dfp: {
2414 s390_dfp_round_t rm;
2415 HReg f0, f4, r1; /* real registers used by PFPO */
2416
2417 f4 = make_fpr(4); /* source */
2418 f0 = make_fpr(0); /* destination */
2419 r1 = make_gpr(1); /* GPR #1 clobbered */
2420 h1 = s390_isel_dfp_expr(env, left);
2421 dst = newVRegF(env);
2422 rm = get_dfp_rounding_mode(env, irrm);
2423 /* operand --> f4 */
2424 addInstr(env, s390_insn_move(8, f4, h1));
2425 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2426 /* f0 --> destination */
2427 addInstr(env, s390_insn_move(8, dst, f0));
2428 return dst;
2429 }
2430
2431 convert_dfp128: {
2432 s390_dfp_round_t rm;
2433 HReg op_hi, op_lo;
2434 HReg f0, f4, f6, r1; /* real registers used by PFPO */
2435
2436 f4 = make_fpr(4); /* source */
2437 f6 = make_fpr(6); /* source */
2438 f0 = make_fpr(0); /* destination */
2439 r1 = make_gpr(1); /* GPR #1 clobbered */
2440 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2441 dst = newVRegF(env);
2442 rm = get_dfp_rounding_mode(env, irrm);
2443 /* operand --> (f4, f6) */
2444 addInstr(env, s390_insn_move(8, f4, op_hi));
2445 addInstr(env, s390_insn_move(8, f6, op_lo));
2446 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
2447 f4, f6, r1, rm));
2448 /* f0 --> destination */
2449 addInstr(env, s390_insn_move(8, dst, f0));
2450 return dst;
2451 }
2452
sewardj2019a972011-03-07 16:04:07 +00002453 default:
2454 goto irreducible;
2455
2456 case Iop_F128toF64:
2457 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002458 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002459 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002460
florian9fcff4c2012-09-10 03:09:04 +00002461 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2462 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002463
florian9fcff4c2012-09-10 03:09:04 +00002464 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002465
florian9fcff4c2012-09-10 03:09:04 +00002466 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002467 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002468 f15 = make_fpr(15);
2469
2470 /* operand --> (f13, f15) */
2471 addInstr(env, s390_insn_move(8, f13, op_hi));
2472 addInstr(env, s390_insn_move(8, f15, op_lo));
2473
2474 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002475 /* load-rounded has a rounding mode field when the floating point
2476 extension facility is installed. */
2477 if (s390_host_has_fpext) {
2478 rounding_mode = get_bfp_rounding_mode(env, irrm);
2479 } else {
2480 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002481 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002482 }
floriancc491a62012-09-10 23:44:37 +00002483 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002484 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002485 return dst;
2486 }
2487 }
sewardj2019a972011-03-07 16:04:07 +00002488 }
2489
2490 /* --------- UNARY OP --------- */
2491 case Iex_Unop: {
2492 IROp op = expr->Iex.Unop.op;
2493 IRExpr *left = expr->Iex.Unop.arg;
2494 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002495 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002496 HReg h1, dst;
2497
2498 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2499 HReg dst_hi, dst_lo;
2500
2501 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2502 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2503 }
2504
florian4d71a082011-12-18 00:08:17 +00002505 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002506 dst = newVRegF(env);
2507 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2508 addInstr(env, s390_insn_move(size, dst, h1));
2509
2510 return dst;
2511 }
2512
2513 switch (op) {
2514 case Iop_NegF32:
2515 case Iop_NegF64:
2516 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002517 (left->Iex.Unop.op == Iop_AbsF32 ||
2518 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002519 bfpop = S390_BFP_NABS;
2520 else
2521 bfpop = S390_BFP_NEG;
2522 break;
2523
2524 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002525 case Iop_AbsF64:
2526 bfpop = S390_BFP_ABS;
2527 break;
2528
2529 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2530 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2531 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2532
2533 convert_float1:
2534 h1 = s390_isel_float_expr(env, left);
2535 goto convert1;
2536
2537 convert_int1:
2538 h1 = s390_isel_int_expr(env, left);
2539 goto convert1;
2540
2541 convert1:
2542 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002543 /* No rounding mode is needed for these conversions. Just stick
2544 one in. It won't be used later on. */
2545 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002546 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002547 return dst;
2548
sewardj2019a972011-03-07 16:04:07 +00002549 default:
2550 goto irreducible;
2551 }
2552
2553 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002554 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002555 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002556 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002557 return dst;
2558 }
2559
2560 default:
2561 goto irreducible;
2562 }
2563
2564 /* We get here if no pattern matched. */
2565 irreducible:
2566 ppIRExpr(expr);
2567 vpanic("s390_isel_float_expr: cannot reduce tree");
2568}
2569
2570
2571static HReg
2572s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2573{
2574 HReg dst = s390_isel_float_expr_wrk(env, expr);
2575
2576 /* Sanity checks ... */
2577 vassert(hregClass(dst) == HRcFlt64);
2578 vassert(hregIsVirtual(dst));
2579
2580 return dst;
2581}
2582
2583
2584/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002585/*--- ISEL: Decimal point expressions (128 bit) ---*/
2586/*---------------------------------------------------------*/
2587static void
2588s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2589 IRExpr *expr)
2590{
2591 IRType ty = typeOfIRExpr(env->type_env, expr);
2592
2593 vassert(ty == Ity_D128);
2594
2595 switch (expr->tag) {
2596 case Iex_RdTmp:
2597 /* Return the virtual registers that hold the temporary. */
2598 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2599 return;
2600
2601 /* --------- LOAD --------- */
2602 case Iex_Load: {
2603 IRExpr *addr_hi, *addr_lo;
2604 s390_amode *am_hi, *am_lo;
2605
2606 if (expr->Iex.Load.end != Iend_BE)
2607 goto irreducible;
2608
2609 addr_hi = expr->Iex.Load.addr;
2610 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2611
2612 am_hi = s390_isel_amode(env, addr_hi);
2613 am_lo = s390_isel_amode(env, addr_lo);
2614
2615 *dst_hi = newVRegF(env);
2616 *dst_lo = newVRegF(env);
2617 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2618 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2619 return;
2620 }
2621
2622 /* --------- GET --------- */
2623 case Iex_Get:
2624 /* This is not supported because loading 128-bit from the guest
2625 state is almost certainly wrong. Use get_dpr_pair instead. */
2626 vpanic("Iex_Get with D128 data");
2627
2628 /* --------- 4-ary OP --------- */
2629 case Iex_Qop:
2630 vpanic("Iex_Qop with D128 data");
2631
2632 /* --------- TERNARY OP --------- */
2633 case Iex_Triop: {
2634 IRTriop *triop = expr->Iex.Triop.details;
2635 IROp op = triop->op;
2636 IRExpr *irrm = triop->arg1;
2637 IRExpr *left = triop->arg2;
2638 IRExpr *right = triop->arg3;
2639 s390_dfp_round_t rounding_mode;
2640 s390_dfp_binop_t dfpop;
2641 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2642
floriane38f6412012-12-21 17:32:12 +00002643 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2644 (f12, f14) as op2 and (f13, f15) as destination) */
2645 f9 = make_fpr(9);
2646 f11 = make_fpr(11);
2647 f12 = make_fpr(12);
2648 f13 = make_fpr(13);
2649 f14 = make_fpr(14);
2650 f15 = make_fpr(15);
2651
floriane38f6412012-12-21 17:32:12 +00002652 switch (op) {
florian5c539732013-02-14 14:27:12 +00002653 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128;
2654 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128;
2655 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128;
2656 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128;
2657 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
2658
2659 evaluate_dfp128: {
2660 /* Process 1st operand */
2661 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
2662 /* 1st operand --> (f9, f11) */
2663 addInstr(env, s390_insn_move(8, f9, op1_hi));
2664 addInstr(env, s390_insn_move(8, f11, op1_lo));
2665
2666 /* Process 2nd operand */
2667 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2668 /* 2nd operand --> (f12, f14) */
2669 addInstr(env, s390_insn_move(8, f12, op2_hi));
2670 addInstr(env, s390_insn_move(8, f14, op2_lo));
2671
2672 /* DFP arithmetic ops take rounding mode only when fpext is
2673 installed. But, DFP quantize operation takes rm irrespective
2674 of fpext facility . */
floriand18287d2013-02-21 03:03:05 +00002675 if (s390_host_has_fpext || op == Iop_QuantizeD128) {
florian5c539732013-02-14 14:27:12 +00002676 rounding_mode = get_dfp_rounding_mode(env, irrm);
2677 } else {
2678 set_dfp_rounding_mode_in_fpc(env, irrm);
2679 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2680 }
2681 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2682 f12, f14, rounding_mode));
2683 /* Move result to virtual destination register */
2684 *dst_hi = newVRegF(env);
2685 *dst_lo = newVRegF(env);
2686 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2687 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2688 return;
2689 }
2690
2691 case Iop_SignificanceRoundD128: {
2692 /* Process 1st operand */
2693 HReg op1 = s390_isel_int_expr(env, left);
2694 /* Process 2nd operand */
2695 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2696 /* 2nd operand --> (f12, f14) */
2697 addInstr(env, s390_insn_move(8, f12, op2_hi));
2698 addInstr(env, s390_insn_move(8, f14, op2_lo));
2699
2700 rounding_mode = get_dfp_rounding_mode(env, irrm);
2701 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14,
2702 rounding_mode));
2703 /* Move result to virtual destination register */
2704 *dst_hi = newVRegF(env);
2705 *dst_lo = newVRegF(env);
2706 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2707 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2708 return;
2709 }
2710
floriane38f6412012-12-21 17:32:12 +00002711 default:
2712 goto irreducible;
2713 }
floriane38f6412012-12-21 17:32:12 +00002714 }
2715
2716 /* --------- BINARY OP --------- */
2717 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002718
floriane38f6412012-12-21 17:32:12 +00002719 switch (expr->Iex.Binop.op) {
2720 case Iop_D64HLtoD128:
2721 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2722 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2723 return;
2724
florian1b901d42013-01-01 22:19:24 +00002725 case Iop_ShlD128:
florian5c539732013-02-14 14:27:12 +00002726 case Iop_ShrD128:
2727 case Iop_InsertExpD128: {
florian1b901d42013-01-01 22:19:24 +00002728 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2729 s390_dfp_intop_t intop;
florian5c539732013-02-14 14:27:12 +00002730 IRExpr *dfp_op;
2731 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00002732
2733 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00002734 case Iop_ShlD128: /* (D128, I64) -> D128 */
2735 intop = S390_DFP_SHIFT_LEFT;
2736 dfp_op = expr->Iex.Binop.arg1;
2737 int_op = expr->Iex.Binop.arg2;
2738 break;
2739 case Iop_ShrD128: /* (D128, I64) -> D128 */
2740 intop = S390_DFP_SHIFT_RIGHT;
2741 dfp_op = expr->Iex.Binop.arg1;
2742 int_op = expr->Iex.Binop.arg2;
2743 break;
2744 case Iop_InsertExpD128: /* (I64, D128) -> D128 */
2745 intop = S390_DFP_INSERT_EXP;
2746 int_op = expr->Iex.Binop.arg1;
2747 dfp_op = expr->Iex.Binop.arg2;
2748 break;
florian1b901d42013-01-01 22:19:24 +00002749 default: goto irreducible;
2750 }
2751
2752 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2753 f9 = make_fpr(9); /* 128 bit dfp operand */
2754 f11 = make_fpr(11);
2755
2756 f13 = make_fpr(13); /* 128 bit dfp destination */
2757 f15 = make_fpr(15);
2758
florian5c539732013-02-14 14:27:12 +00002759 /* Process dfp operand */
2760 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
2761 /* op1 -> (f9,f11) */
florian1b901d42013-01-01 22:19:24 +00002762 addInstr(env, s390_insn_move(8, f9, op1_hi));
2763 addInstr(env, s390_insn_move(8, f11, op1_lo));
2764
florian5c539732013-02-14 14:27:12 +00002765 op2 = s390_isel_int_expr(env, int_op); /* int operand */
florian1b901d42013-01-01 22:19:24 +00002766
2767 addInstr(env,
2768 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2769
2770 /* Move result to virtual destination register */
2771 *dst_hi = newVRegF(env);
2772 *dst_lo = newVRegF(env);
2773 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2774 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2775 return;
2776 }
2777
florian7ab421d2013-06-17 21:03:56 +00002778 case Iop_F32toD128:
florian78d5ef72013-05-11 15:02:58 +00002779 case Iop_F64toD128: {
2780 IRExpr *irrm;
2781 IRExpr *left;
2782 s390_dfp_round_t rm;
2783 HReg h1; /* virtual reg. to hold source */
2784 HReg f0, f2, f4, r1; /* real registers used by PFPO */
florian7ab421d2013-06-17 21:03:56 +00002785 s390_fp_conv_t fpconv;
2786
2787 switch (expr->Iex.Binop.op) {
2788 case Iop_F32toD128: /* (D128, I64) -> D128 */
2789 fpconv = S390_FP_F32_TO_D128;
2790 break;
2791 case Iop_F64toD128: /* (D128, I64) -> D128 */
2792 fpconv = S390_FP_F64_TO_D128;
2793 break;
2794 default: goto irreducible;
2795 }
florian78d5ef72013-05-11 15:02:58 +00002796
2797 f4 = make_fpr(4); /* source */
2798 f0 = make_fpr(0); /* destination */
2799 f2 = make_fpr(2); /* destination */
2800 r1 = make_gpr(1); /* GPR #1 clobbered */
2801 irrm = expr->Iex.Binop.arg1;
2802 left = expr->Iex.Binop.arg2;
2803 rm = get_dfp_rounding_mode(env, irrm);
2804 h1 = s390_isel_float_expr(env, left);
2805 addInstr(env, s390_insn_move(8, f4, h1));
florian7ab421d2013-06-17 21:03:56 +00002806 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
florian78d5ef72013-05-11 15:02:58 +00002807 f4, INVALID_HREG, r1, rm));
2808 /* (f0, f2) --> destination */
2809 *dst_hi = newVRegF(env);
2810 *dst_lo = newVRegF(env);
2811 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2812 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2813
2814 return;
2815 }
2816
2817 case Iop_F128toD128: {
2818 IRExpr *irrm;
2819 IRExpr *left;
2820 s390_dfp_round_t rm;
2821 HReg op_hi, op_lo;
2822 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2823
2824 f4 = make_fpr(4); /* source */
2825 f6 = make_fpr(6); /* source */
2826 f0 = make_fpr(0); /* destination */
2827 f2 = make_fpr(2); /* destination */
2828 r1 = make_gpr(1); /* GPR #1 clobbered */
2829
2830 irrm = expr->Iex.Binop.arg1;
2831 left = expr->Iex.Binop.arg2;
2832 rm = get_dfp_rounding_mode(env, irrm);
2833 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2834 /* operand --> (f4, f6) */
2835 addInstr(env, s390_insn_move(8, f4, op_hi));
2836 addInstr(env, s390_insn_move(8, f6, op_lo));
2837 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2,
2838 f4, f6, r1, rm));
2839 /* (f0, f2) --> destination */
2840 *dst_hi = newVRegF(env);
2841 *dst_lo = newVRegF(env);
2842 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2843 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2844
2845 return;
2846 }
2847
floriane38f6412012-12-21 17:32:12 +00002848 default:
2849 goto irreducible;
2850 }
2851 }
2852
2853 /* --------- UNARY OP --------- */
2854 case Iex_Unop: {
2855 IRExpr *left = expr->Iex.Unop.arg;
2856 s390_dfp_conv_t conv;
floriane38f6412012-12-21 17:32:12 +00002857 HReg op, f12, f14;
2858
floriana887acd2013-02-08 23:32:54 +00002859 /* We use non-virtual registers as pairs (f12, f14)) */
floriane38f6412012-12-21 17:32:12 +00002860 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00002861 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00002862
2863 switch (expr->Iex.Unop.op) {
2864 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002865 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
floriana887acd2013-02-08 23:32:54 +00002866 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002867 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2868 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002869 default:
2870 goto irreducible;
2871 }
2872
2873 convert_dfp:
2874 op = s390_isel_dfp_expr(env, left);
2875 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2876 goto move_dst;
2877
florian5f034622013-01-13 02:29:05 +00002878 convert_int:
2879 op = s390_isel_int_expr(env, left);
2880 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2881 goto move_dst;
2882
floriane38f6412012-12-21 17:32:12 +00002883 move_dst:
2884 /* Move result to virtual destination registers */
2885 *dst_hi = newVRegF(env);
2886 *dst_lo = newVRegF(env);
2887 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2888 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2889 return;
2890 }
2891
2892 default:
2893 goto irreducible;
2894 }
2895
2896 /* We get here if no pattern matched. */
2897 irreducible:
2898 ppIRExpr(expr);
2899 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2900
2901}
2902
2903
2904/* Compute a 128-bit value into two 64-bit registers. These may be either
2905 real or virtual regs; in any case they must not be changed by subsequent
2906 code emitted by the caller. */
2907static void
2908s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2909{
2910 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2911
2912 /* Sanity checks ... */
2913 vassert(hregIsVirtual(*dst_hi));
2914 vassert(hregIsVirtual(*dst_lo));
2915 vassert(hregClass(*dst_hi) == HRcFlt64);
2916 vassert(hregClass(*dst_lo) == HRcFlt64);
2917}
2918
2919
2920/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002921/*--- ISEL: Decimal point expressions (64 bit) ---*/
2922/*---------------------------------------------------------*/
2923
2924static HReg
2925s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2926{
2927 IRType ty = typeOfIRExpr(env->type_env, expr);
2928 UChar size;
2929
floriane38f6412012-12-21 17:32:12 +00002930 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002931
2932 size = sizeofIRType(ty);
2933
2934 switch (expr->tag) {
2935 case Iex_RdTmp:
2936 /* Return the virtual register that holds the temporary. */
2937 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2938
2939 /* --------- LOAD --------- */
2940 case Iex_Load: {
2941 HReg dst = newVRegF(env);
2942 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2943
2944 if (expr->Iex.Load.end != Iend_BE)
2945 goto irreducible;
2946
2947 addInstr(env, s390_insn_load(size, dst, am));
2948
2949 return dst;
2950 }
2951
2952 /* --------- GET --------- */
2953 case Iex_Get: {
2954 HReg dst = newVRegF(env);
2955 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2956
2957 addInstr(env, s390_insn_load(size, dst, am));
2958
2959 return dst;
2960 }
2961
floriane38f6412012-12-21 17:32:12 +00002962 /* --------- BINARY OP --------- */
2963 case Iex_Binop: {
2964 IROp op = expr->Iex.Binop.op;
2965 IRExpr *irrm = expr->Iex.Binop.arg1;
2966 IRExpr *left = expr->Iex.Binop.arg2;
2967 HReg h1, dst;
2968 s390_dfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002969 s390_fp_conv_t fpconv;
floriane38f6412012-12-21 17:32:12 +00002970
2971 switch (op) {
2972 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
floriana887acd2013-02-08 23:32:54 +00002973 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002974 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
florian7ab421d2013-06-17 21:03:56 +00002975 case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp;
2976 case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp;
2977 case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp;
florian78d5ef72013-05-11 15:02:58 +00002978 case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
florian7ab421d2013-06-17 21:03:56 +00002979 case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128;
2980 case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128;
floriane38f6412012-12-21 17:32:12 +00002981
2982 convert_dfp:
2983 h1 = s390_isel_dfp_expr(env, left);
2984 goto convert;
2985
florian5f034622013-01-13 02:29:05 +00002986 convert_int:
2987 h1 = s390_isel_int_expr(env, left);
2988 goto convert;
2989
floriane38f6412012-12-21 17:32:12 +00002990 convert: {
2991 s390_dfp_round_t rounding_mode;
2992 /* convert-from-fixed and load-rounded have a rounding mode field
2993 when the floating point extension facility is installed. */
2994 dst = newVRegF(env);
2995 if (s390_host_has_fpext) {
2996 rounding_mode = get_dfp_rounding_mode(env, irrm);
2997 } else {
2998 set_dfp_rounding_mode_in_fpc(env, irrm);
2999 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3000 }
3001 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3002 rounding_mode));
3003 return dst;
3004 }
floriane38f6412012-12-21 17:32:12 +00003005
florian78d5ef72013-05-11 15:02:58 +00003006 convert_bfp: {
3007 s390_dfp_round_t rm;
3008 HReg f0, f4, r1; /* real registers used by PFPO */
3009
3010 f4 = make_fpr(4); /* source */
3011 f0 = make_fpr(0); /* destination */
3012 r1 = make_gpr(1); /* GPR #1 clobbered */
3013 h1 = s390_isel_float_expr(env, left);
3014 dst = newVRegF(env);
3015 rm = get_dfp_rounding_mode(env, irrm);
3016 /* operand --> f4 */
3017 addInstr(env, s390_insn_move(8, f4, h1));
3018 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
3019 /* f0 --> destination */
3020 addInstr(env, s390_insn_move(8, dst, f0));
3021 return dst;
3022 }
3023
florian7ab421d2013-06-17 21:03:56 +00003024 convert_bfp128: {
3025 s390_dfp_round_t rm;
3026 HReg op_hi, op_lo;
3027 HReg f0, f4, f6, r1; /* real registers used by PFPO */
3028
3029 f4 = make_fpr(4); /* source */
3030 f6 = make_fpr(6); /* source */
3031 f0 = make_fpr(0); /* destination */
3032 r1 = make_gpr(1); /* GPR #1 clobbered */
3033 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
3034 dst = newVRegF(env);
3035 rm = get_dfp_rounding_mode(env, irrm);
3036 /* operand --> (f4, f6) */
3037 addInstr(env, s390_insn_move(8, f4, op_hi));
3038 addInstr(env, s390_insn_move(8, f6, op_lo));
3039 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
3040 f4, f6, r1, rm));
3041 /* f0 --> destination */
3042 addInstr(env, s390_insn_move(8, dst, f0));
3043 return dst;
3044 }
3045
floriane38f6412012-12-21 17:32:12 +00003046 case Iop_D128toD64: {
3047 HReg op_hi, op_lo, f13, f15;
3048 s390_dfp_round_t rounding_mode;
3049
3050 conv = S390_DFP_D128_TO_D64;
3051
3052 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
3053
3054 /* We use non-virtual registers as pairs (f13, f15) */
3055 f13 = make_fpr(13);
3056 f15 = make_fpr(15);
3057
3058 /* operand --> (f13, f15) */
3059 addInstr(env, s390_insn_move(8, f13, op_hi));
3060 addInstr(env, s390_insn_move(8, f15, op_lo));
3061
3062 dst = newVRegF(env);
3063 /* load-rounded has a rounding mode field when the floating point
3064 extension facility is installed. */
3065 if (s390_host_has_fpext) {
3066 rounding_mode = get_dfp_rounding_mode(env, irrm);
3067 } else {
3068 set_dfp_rounding_mode_in_fpc(env, irrm);
3069 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3070 }
3071 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
3072 rounding_mode));
3073 return dst;
3074 }
3075
florian1b901d42013-01-01 22:19:24 +00003076 case Iop_ShlD64:
florian5c539732013-02-14 14:27:12 +00003077 case Iop_ShrD64:
3078 case Iop_InsertExpD64: {
florian1b901d42013-01-01 22:19:24 +00003079 HReg op2;
3080 HReg op3;
florian5c539732013-02-14 14:27:12 +00003081 IRExpr *dfp_op;
3082 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00003083 s390_dfp_intop_t intop;
florian1b901d42013-01-01 22:19:24 +00003084
3085 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00003086 case Iop_ShlD64: /* (D64, I64) -> D64 */
3087 intop = S390_DFP_SHIFT_LEFT;
3088 dfp_op = expr->Iex.Binop.arg1;
3089 int_op = expr->Iex.Binop.arg2;
3090 break;
3091 case Iop_ShrD64: /* (D64, I64) -> D64 */
3092 intop = S390_DFP_SHIFT_RIGHT;
3093 dfp_op = expr->Iex.Binop.arg1;
3094 int_op = expr->Iex.Binop.arg2;
3095 break;
3096 case Iop_InsertExpD64: /* (I64, D64) -> D64 */
3097 intop = S390_DFP_INSERT_EXP;
3098 int_op = expr->Iex.Binop.arg1;
3099 dfp_op = expr->Iex.Binop.arg2;
3100 break;
florian1b901d42013-01-01 22:19:24 +00003101 default: goto irreducible;
3102 }
3103
florian5c539732013-02-14 14:27:12 +00003104 op2 = s390_isel_int_expr(env, int_op);
3105 op3 = s390_isel_dfp_expr(env, dfp_op);
florian1b901d42013-01-01 22:19:24 +00003106 dst = newVRegF(env);
3107
3108 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
3109 return dst;
3110 }
3111
3112 default:
3113 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00003114 }
3115 }
3116
3117 /* --------- UNARY OP --------- */
3118 case Iex_Unop: {
3119 IROp op = expr->Iex.Unop.op;
3120 IRExpr *left = expr->Iex.Unop.arg;
3121 s390_dfp_conv_t conv;
3122 HReg h1, dst;
3123
3124 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
3125 HReg dst_hi, dst_lo;
3126
3127 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
3128 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
3129 }
3130
3131 if (op == Iop_ReinterpI64asD64) {
3132 dst = newVRegF(env);
3133 h1 = s390_isel_int_expr(env, left); /* Process the operand */
3134 addInstr(env, s390_insn_move(size, dst, h1));
3135
3136 return dst;
3137 }
3138
3139 switch (op) {
3140 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00003141 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
3142 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00003143
3144 convert_dfp1:
3145 h1 = s390_isel_dfp_expr(env, left);
3146 goto convert1;
3147
florian5f034622013-01-13 02:29:05 +00003148 convert_int1:
3149 h1 = s390_isel_int_expr(env, left);
3150 goto convert1;
3151
floriane38f6412012-12-21 17:32:12 +00003152 convert1:
3153 dst = newVRegF(env);
3154 /* No rounding mode is needed for these conversions. Just stick
3155 one in. It won't be used later on. */
3156 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3157 S390_DFP_ROUND_NEAREST_EVEN_4));
3158 return dst;
3159
3160 default:
3161 goto irreducible;
3162 }
3163 }
3164
florian12390202012-11-10 22:34:14 +00003165 /* --------- TERNARY OP --------- */
3166 case Iex_Triop: {
3167 IRTriop *triop = expr->Iex.Triop.details;
3168 IROp op = triop->op;
3169 IRExpr *irrm = triop->arg1;
3170 IRExpr *left = triop->arg2;
3171 IRExpr *right = triop->arg3;
3172 s390_dfp_round_t rounding_mode;
3173 s390_dfp_binop_t dfpop;
3174 HReg op2, op3, dst;
3175
florian12390202012-11-10 22:34:14 +00003176 switch (op) {
florian5c539732013-02-14 14:27:12 +00003177 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp;
3178 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp;
3179 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp;
3180 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp;
3181 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
3182
3183 evaluate_dfp: {
3184 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
3185 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3186 dst = newVRegF(env);
3187 /* DFP arithmetic ops take rounding mode only when fpext is
3188 installed. But, DFP quantize operation takes rm irrespective
3189 of fpext facility . */
3190 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
3191 rounding_mode = get_dfp_rounding_mode(env, irrm);
3192 } else {
3193 set_dfp_rounding_mode_in_fpc(env, irrm);
3194 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3195 }
3196 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3,
3197 rounding_mode));
3198 return dst;
3199 }
3200
3201 case Iop_SignificanceRoundD64:
3202 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */
3203 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3204 dst = newVRegF(env);
3205 rounding_mode = get_dfp_rounding_mode(env, irrm);
3206 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3,
3207 rounding_mode));
3208 return dst;
3209
florian12390202012-11-10 22:34:14 +00003210 default:
3211 goto irreducible;
3212 }
florian12390202012-11-10 22:34:14 +00003213 }
3214
3215 default:
3216 goto irreducible;
3217 }
3218
3219 /* We get here if no pattern matched. */
3220 irreducible:
3221 ppIRExpr(expr);
3222 vpanic("s390_isel_dfp_expr: cannot reduce tree");
3223}
3224
3225static HReg
3226s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
3227{
3228 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
3229
3230 /* Sanity checks ... */
3231 vassert(hregClass(dst) == HRcFlt64);
3232 vassert(hregIsVirtual(dst));
3233
3234 return dst;
3235}
3236
3237
3238/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00003239/*--- ISEL: Condition Code ---*/
3240/*---------------------------------------------------------*/
3241
3242/* This function handles all operators that produce a 1-bit result */
3243static s390_cc_t
3244s390_isel_cc(ISelEnv *env, IRExpr *cond)
3245{
3246 UChar size;
3247
3248 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
3249
3250 /* Constant: either 1 or 0 */
3251 if (cond->tag == Iex_Const) {
3252 vassert(cond->Iex.Const.con->tag == Ico_U1);
3253 vassert(cond->Iex.Const.con->Ico.U1 == True
3254 || cond->Iex.Const.con->Ico.U1 == False);
3255
3256 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
3257 }
3258
3259 /* Variable: values are 1 or 0 */
3260 if (cond->tag == Iex_RdTmp) {
3261 IRTemp tmp = cond->Iex.RdTmp.tmp;
3262 HReg reg = lookupIRTemp(env, tmp);
3263
3264 /* Load-and-test does not modify REG; so this is OK. */
3265 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
3266 size = 4;
3267 else
3268 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
3269 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
3270 return S390_CC_NE;
3271 }
3272
3273 /* Unary operators */
3274 if (cond->tag == Iex_Unop) {
3275 IRExpr *arg = cond->Iex.Unop.arg;
3276
3277 switch (cond->Iex.Unop.op) {
3278 case Iop_Not1: /* Not1(cond) */
3279 /* Generate code for EXPR, and negate the test condition */
3280 return s390_cc_invert(s390_isel_cc(env, arg));
3281
3282 /* Iop_32/64to1 select the LSB from their operand */
3283 case Iop_32to1:
3284 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00003285 HReg dst = newVRegI(env);
3286 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00003287
3288 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3289
florianf366a802012-08-03 00:42:18 +00003290 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00003291 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
3292 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
3293 return S390_CC_NE;
3294 }
3295
3296 case Iop_CmpNEZ8:
3297 case Iop_CmpNEZ16: {
3298 s390_opnd_RMI src;
3299 s390_unop_t op;
3300 HReg dst;
3301
3302 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
3303 : S390_ZERO_EXTEND_16;
3304 dst = newVRegI(env);
3305 src = s390_isel_int_expr_RMI(env, arg);
3306 addInstr(env, s390_insn_unop(4, op, dst, src));
3307 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
3308 return S390_CC_NE;
3309 }
3310
3311 case Iop_CmpNEZ32:
3312 case Iop_CmpNEZ64: {
3313 s390_opnd_RMI src;
3314
3315 src = s390_isel_int_expr_RMI(env, arg);
3316 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3317 addInstr(env, s390_insn_test(size, src));
3318 return S390_CC_NE;
3319 }
3320
3321 default:
3322 goto fail;
3323 }
3324 }
3325
3326 /* Binary operators */
3327 if (cond->tag == Iex_Binop) {
3328 IRExpr *arg1 = cond->Iex.Binop.arg1;
3329 IRExpr *arg2 = cond->Iex.Binop.arg2;
3330 HReg reg1, reg2;
3331
3332 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
3333
3334 switch (cond->Iex.Binop.op) {
3335 s390_unop_t op;
3336 s390_cc_t result;
3337
3338 case Iop_CmpEQ8:
3339 case Iop_CasCmpEQ8:
3340 op = S390_ZERO_EXTEND_8;
3341 result = S390_CC_E;
3342 goto do_compare_ze;
3343
3344 case Iop_CmpNE8:
3345 case Iop_CasCmpNE8:
3346 op = S390_ZERO_EXTEND_8;
3347 result = S390_CC_NE;
3348 goto do_compare_ze;
3349
3350 case Iop_CmpEQ16:
3351 case Iop_CasCmpEQ16:
3352 op = S390_ZERO_EXTEND_16;
3353 result = S390_CC_E;
3354 goto do_compare_ze;
3355
3356 case Iop_CmpNE16:
3357 case Iop_CasCmpNE16:
3358 op = S390_ZERO_EXTEND_16;
3359 result = S390_CC_NE;
3360 goto do_compare_ze;
3361
3362 do_compare_ze: {
3363 s390_opnd_RMI op1, op2;
3364
3365 op1 = s390_isel_int_expr_RMI(env, arg1);
3366 reg1 = newVRegI(env);
3367 addInstr(env, s390_insn_unop(4, op, reg1, op1));
3368
3369 op2 = s390_isel_int_expr_RMI(env, arg2);
3370 reg2 = newVRegI(env);
3371 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
3372
3373 op2 = s390_opnd_reg(reg2);
3374 addInstr(env, s390_insn_compare(4, reg1, op2, False));
3375
3376 return result;
3377 }
3378
3379 case Iop_CmpEQ32:
3380 case Iop_CmpEQ64:
3381 case Iop_CasCmpEQ32:
3382 case Iop_CasCmpEQ64:
3383 result = S390_CC_E;
3384 goto do_compare;
3385
3386 case Iop_CmpNE32:
3387 case Iop_CmpNE64:
3388 case Iop_CasCmpNE32:
3389 case Iop_CasCmpNE64:
3390 result = S390_CC_NE;
3391 goto do_compare;
3392
3393 do_compare: {
3394 HReg op1;
3395 s390_opnd_RMI op2;
3396
3397 order_commutative_operands(arg1, arg2);
3398
3399 op1 = s390_isel_int_expr(env, arg1);
3400 op2 = s390_isel_int_expr_RMI(env, arg2);
3401
3402 addInstr(env, s390_insn_compare(size, op1, op2, False));
3403
3404 return result;
3405 }
3406
3407 case Iop_CmpLT32S:
3408 case Iop_CmpLE32S:
3409 case Iop_CmpLT64S:
3410 case Iop_CmpLE64S: {
3411 HReg op1;
3412 s390_opnd_RMI op2;
3413
3414 op1 = s390_isel_int_expr(env, arg1);
3415 op2 = s390_isel_int_expr_RMI(env, arg2);
3416
3417 addInstr(env, s390_insn_compare(size, op1, op2, True));
3418
3419 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3420 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3421 }
3422
3423 case Iop_CmpLT32U:
3424 case Iop_CmpLE32U:
3425 case Iop_CmpLT64U:
3426 case Iop_CmpLE64U: {
3427 HReg op1;
3428 s390_opnd_RMI op2;
3429
3430 op1 = s390_isel_int_expr(env, arg1);
3431 op2 = s390_isel_int_expr_RMI(env, arg2);
3432
3433 addInstr(env, s390_insn_compare(size, op1, op2, False));
3434
3435 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3436 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3437 }
3438
3439 default:
3440 goto fail;
3441 }
3442 }
3443
3444 fail:
3445 ppIRExpr(cond);
3446 vpanic("s390_isel_cc: unexpected operator");
3447}
3448
3449
3450/*---------------------------------------------------------*/
3451/*--- ISEL: Statements ---*/
3452/*---------------------------------------------------------*/
3453
3454static void
3455s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3456{
3457 if (vex_traceflags & VEX_TRACE_VCODE) {
3458 vex_printf("\n -- ");
3459 ppIRStmt(stmt);
3460 vex_printf("\n");
3461 }
3462
3463 switch (stmt->tag) {
3464
3465 /* --------- STORE --------- */
3466 case Ist_Store: {
3467 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3468 s390_amode *am;
3469 HReg src;
3470
3471 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3472
3473 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3474
3475 switch (tyd) {
3476 case Ity_I8:
3477 case Ity_I16:
3478 case Ity_I32:
3479 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003480 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003481 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003482 stmt->Ist.Store.data->tag == Iex_Const) {
3483 ULong value =
3484 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3485 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003486 return;
3487 }
floriancec3a8a2013-02-02 00:16:58 +00003488 /* Check whether we can use a memcpy here. Currently, the restriction
3489 is that both amodes need to be B12, so MVC can be emitted.
3490 We do not consider a store whose data expression is a load because
3491 we don't want to deal with overlapping locations. */
3492 /* store(get) never overlaps*/
3493 if (am->tag == S390_AMODE_B12 &&
3494 stmt->Ist.Store.data->tag == Iex_Get) {
3495 UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
3496 s390_amode *from = s390_amode_for_guest_state(offset);
3497 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
3498 return;
3499 }
3500 /* General case: compile data into a register */
sewardj2019a972011-03-07 16:04:07 +00003501 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3502 break;
3503
3504 case Ity_F32:
3505 case Ity_F64:
3506 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3507 break;
3508
florianeb981ae2012-12-21 18:55:03 +00003509 case Ity_D32:
3510 case Ity_D64:
3511 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3512 break;
3513
sewardj2019a972011-03-07 16:04:07 +00003514 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003515 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003516 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003517 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003518
3519 default:
3520 goto stmt_fail;
3521 }
3522
3523 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3524 return;
3525 }
3526
3527 /* --------- PUT --------- */
3528 case Ist_Put: {
3529 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3530 HReg src;
3531 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003532 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003533
florianad43b3a2012-02-20 15:01:14 +00003534 /* Detect updates to certain guest registers. We track the contents
3535 of those registers as long as they contain constants. If the new
3536 constant is either zero or in the 8-bit neighbourhood of the
3537 current value we can use a memory-to-memory insn to do the update. */
3538
3539 Int offset = stmt->Ist.Put.offset;
3540
3541 /* Check necessary conditions:
3542 (1) must be one of the registers we care about
3543 (2) assigned value must be a constant */
3544 Int guest_reg = get_guest_reg(offset);
3545
3546 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3547
florianad43b3a2012-02-20 15:01:14 +00003548 if (stmt->Ist.Put.data->tag != Iex_Const) {
3549 /* Invalidate guest register contents */
3550 env->old_value_valid[guest_reg] = False;
3551 goto not_special;
3552 }
3553
cborntraaf7ad282012-08-08 14:11:33 +00003554 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3555 if (tyd != Ity_I64)
3556 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003557
cborntraaf7ad282012-08-08 14:11:33 +00003558 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003559
3560 old_value = env->old_value[guest_reg];
3561 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3562 env->old_value[guest_reg] = new_value;
3563
3564 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3565 env->old_value_valid[guest_reg] = True;
3566
3567 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003568 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003569 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003570 return;
florianad43b3a2012-02-20 15:01:14 +00003571 }
3572
florianad43b3a2012-02-20 15:01:14 +00003573 if (old_value_is_valid == False) goto not_special;
3574
3575 /* If the new value is in the neighbourhood of the old value
3576 we can use a memory-to-memory insn */
3577 difference = new_value - old_value;
3578
3579 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003580 am = s390_amode_for_guest_state(offset);
3581 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003582 (difference & 0xFF), new_value));
3583 return;
3584 }
3585
florianb93348d2012-12-27 00:59:43 +00003586 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003587 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003588 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003589 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003590 return;
3591 }
3592
3593 /* No special case applies... fall through */
3594
3595 not_special:
florianb93348d2012-12-27 00:59:43 +00003596 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003597
3598 switch (tyd) {
3599 case Ity_I8:
3600 case Ity_I16:
3601 case Ity_I32:
3602 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003603 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003604 stmt->Ist.Put.data->tag == Iex_Const) {
3605 ULong value =
3606 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3607 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003608 return;
3609 }
floriancec3a8a2013-02-02 00:16:58 +00003610 /* Check whether we can use a memcpy here. Currently, the restriction
3611 is that both amodes need to be B12, so MVC can be emitted. */
3612 /* put(load) never overlaps */
3613 if (am->tag == S390_AMODE_B12 &&
3614 stmt->Ist.Put.data->tag == Iex_Load) {
3615 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
3616 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
3617 s390_amode *from = s390_isel_amode(env, data);
3618 UInt size = sizeofIRType(tyd);
3619
3620 if (from->tag == S390_AMODE_B12) {
3621 /* Source can be compiled into a B12 amode. */
3622 addInstr(env, s390_insn_memcpy(size, am, from));
3623 return;
3624 }
3625
3626 src = newVRegI(env);
3627 addInstr(env, s390_insn_load(size, src, from));
3628 break;
3629 }
3630 /* put(get) */
3631 if (am->tag == S390_AMODE_B12 &&
3632 stmt->Ist.Put.data->tag == Iex_Get) {
3633 UInt put_offset = am->d;
3634 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
3635 UInt size = sizeofIRType(tyd);
3636 /* don't memcpy in case of overlap */
3637 if (put_offset + size <= get_offset ||
3638 get_offset + size <= put_offset) {
3639 s390_amode *from = s390_amode_for_guest_state(get_offset);
3640 addInstr(env, s390_insn_memcpy(size, am, from));
3641 return;
3642 }
3643 goto no_memcpy_put;
3644 }
3645 /* General case: compile data into a register */
3646no_memcpy_put:
sewardj2019a972011-03-07 16:04:07 +00003647 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3648 break;
3649
3650 case Ity_F32:
3651 case Ity_F64:
3652 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3653 break;
3654
3655 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003656 case Ity_D128:
3657 /* Does not occur. See function put_(f|d)pr_pair. */
3658 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003659
floriane38f6412012-12-21 17:32:12 +00003660 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003661 case Ity_D64:
3662 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3663 break;
3664
sewardj2019a972011-03-07 16:04:07 +00003665 default:
3666 goto stmt_fail;
3667 }
3668
3669 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3670 return;
3671 }
3672
3673 /* --------- TMP --------- */
3674 case Ist_WrTmp: {
3675 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3676 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3677 HReg src, dst;
3678
3679 switch (tyd) {
3680 case Ity_I128: {
3681 HReg dst_hi, dst_lo, res_hi, res_lo;
3682
3683 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3684 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3685
3686 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3687 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3688 return;
3689 }
3690
3691 case Ity_I8:
3692 case Ity_I16:
3693 case Ity_I32:
3694 case Ity_I64:
3695 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3696 dst = lookupIRTemp(env, tmp);
3697 break;
3698
3699 case Ity_I1: {
3700 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3701 dst = lookupIRTemp(env, tmp);
3702 addInstr(env, s390_insn_cc2bool(dst, cond));
3703 return;
3704 }
3705
3706 case Ity_F32:
3707 case Ity_F64:
3708 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3709 dst = lookupIRTemp(env, tmp);
3710 break;
3711
3712 case Ity_F128: {
3713 HReg dst_hi, dst_lo, res_hi, res_lo;
3714
3715 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3716 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3717
3718 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3719 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3720 return;
3721 }
3722
floriane38f6412012-12-21 17:32:12 +00003723 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003724 case Ity_D64:
3725 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3726 dst = lookupIRTemp(env, tmp);
3727 break;
3728
floriane38f6412012-12-21 17:32:12 +00003729 case Ity_D128: {
3730 HReg dst_hi, dst_lo, res_hi, res_lo;
3731
3732 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3733 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3734
3735 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3736 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3737 return;
3738 }
3739
sewardj2019a972011-03-07 16:04:07 +00003740 default:
3741 goto stmt_fail;
3742 }
3743
3744 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3745 return;
3746 }
3747
3748 /* --------- Call to DIRTY helper --------- */
3749 case Ist_Dirty: {
3750 IRType retty;
3751 IRDirty* d = stmt->Ist.Dirty.details;
florian01ed6e72012-05-27 16:52:43 +00003752 HReg dst;
sewardj74142b82013-08-08 10:28:59 +00003753 RetLoc rloc = mk_RetLoc_INVALID();
3754 UInt addToSp = 0;
florianad43b3a2012-02-20 15:01:14 +00003755 Int i;
3756
3757 /* Invalidate tracked values of those guest state registers that are
3758 modified by this helper. */
3759 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003760 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3761 descriptors in guest state effect descriptions. Hence: */
3762 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003763 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3764 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3765 if (guest_reg != GUEST_UNKNOWN)
3766 env->old_value_valid[guest_reg] = False;
3767 }
3768 }
sewardj2019a972011-03-07 16:04:07 +00003769
florian01ed6e72012-05-27 16:52:43 +00003770 if (d->tmp == IRTemp_INVALID) {
3771 /* No return value. */
sewardj74142b82013-08-08 10:28:59 +00003772 retty = Ity_INVALID;
3773 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3774 d->args);
3775 vassert(is_sane_RetLoc(rloc));
3776 vassert(rloc.pri == RLPri_None);
3777 vassert(addToSp == 0);
3778
sewardj2019a972011-03-07 16:04:07 +00003779 return;
florian01ed6e72012-05-27 16:52:43 +00003780 }
sewardj2019a972011-03-07 16:04:07 +00003781
3782 retty = typeOfIRTemp(env->type_env, d->tmp);
3783 if (retty == Ity_I64 || retty == Ity_I32
3784 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003785 /* Move the returned value to the destination register */
sewardj74142b82013-08-08 10:28:59 +00003786 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
3787
florian01ed6e72012-05-27 16:52:43 +00003788 dst = lookupIRTemp(env, d->tmp);
sewardj74142b82013-08-08 10:28:59 +00003789 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3790 d->args);
3791 vassert(is_sane_RetLoc(rloc));
3792 vassert(rloc.pri == RLPri_Int);
3793 vassert(addToSp == 0);
3794 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
3795
sewardj2019a972011-03-07 16:04:07 +00003796 return;
3797 }
sewardj74142b82013-08-08 10:28:59 +00003798 if (retty == Ity_V128) {
3799 /* we do not handle vector types yet */
3800 vassert(0);
3801 HReg sp = make_gpr(S390_REGNO_STACK_POINTER);
3802 s390_amode *am;
3803
3804 dst = lookupIRTemp(env, d->tmp);
3805 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3806 d->args);
3807 vassert(is_sane_RetLoc(rloc));
3808 vassert(rloc.pri == RLPri_V128SpRel);
3809 vassert(addToSp >= 16);
3810
3811 /* rloc.spOff should be zero for s390 */
3812 /* cannot use fits_unsigned_12bit(rloc.spOff), so doing
3813 it explicitly */
3814 vassert((rloc.spOff & 0xFFF) == rloc.spOff);
3815 am = s390_amode_b12(rloc.spOff, sp);
3816 // JRS 2013-Aug-08: is this correct? Looks like we're loading
3817 // only 64 bits from memory, when in fact we should be loading 128.
3818 addInstr(env, s390_insn_load(8, dst, am));
3819 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, sp,
3820 s390_opnd_imm(addToSp)));
3821 return;
3822 } else {/* if (retty == Ity_V256) */
3823 /* we do not handle vector types yet */
3824 vassert(0);
3825 }
sewardj2019a972011-03-07 16:04:07 +00003826 break;
3827 }
3828
3829 case Ist_CAS:
3830 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3831 IRCAS *cas = stmt->Ist.CAS.details;
3832 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3833 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3834 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3835 HReg old = lookupIRTemp(env, cas->oldLo);
3836
3837 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3838 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3839 } else {
3840 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3841 }
3842 return;
3843 } else {
florian448cbba2012-06-06 02:26:01 +00003844 IRCAS *cas = stmt->Ist.CAS.details;
3845 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3846 HReg r8, r9, r10, r11, r1;
3847 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3848 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3849 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3850 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3851 HReg old_low = lookupIRTemp(env, cas->oldLo);
3852 HReg old_high = lookupIRTemp(env, cas->oldHi);
3853
3854 /* Use non-virtual registers r8 and r9 as pair for op1
3855 and move op1 there */
3856 r8 = make_gpr(8);
3857 r9 = make_gpr(9);
3858 addInstr(env, s390_insn_move(8, r8, op1_high));
3859 addInstr(env, s390_insn_move(8, r9, op1_low));
3860
3861 /* Use non-virtual registers r10 and r11 as pair for op3
3862 and move op3 there */
3863 r10 = make_gpr(10);
3864 r11 = make_gpr(11);
3865 addInstr(env, s390_insn_move(8, r10, op3_high));
3866 addInstr(env, s390_insn_move(8, r11, op3_low));
3867
3868 /* Register r1 is used as a scratch register */
3869 r1 = make_gpr(1);
3870
3871 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3872 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3873 old_high, old_low, r1));
3874 } else {
3875 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3876 old_high, old_low, r1));
3877 }
3878 addInstr(env, s390_insn_move(8, op1_high, r8));
3879 addInstr(env, s390_insn_move(8, op1_low, r9));
3880 addInstr(env, s390_insn_move(8, op3_high, r10));
3881 addInstr(env, s390_insn_move(8, op3_low, r11));
3882 return;
sewardj2019a972011-03-07 16:04:07 +00003883 }
3884 break;
3885
3886 /* --------- EXIT --------- */
3887 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003888 s390_cc_t cond;
3889 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3890
3891 if (tag != Ico_U64)
3892 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3893
florian8844a632012-04-13 04:04:06 +00003894 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003895 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003896
3897 /* Case: boring transfer to known address */
3898 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3899 if (env->chaining_allowed) {
3900 /* .. almost always true .. */
3901 /* Skip the event check at the dst if this is a forwards
3902 edge. */
3903 Bool to_fast_entry
3904 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3905 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3906 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3907 guest_IA, to_fast_entry));
3908 } else {
3909 /* .. very occasionally .. */
3910 /* We can't use chaining, so ask for an assisted transfer,
3911 as that's the only alternative that is allowable. */
3912 HReg dst = s390_isel_int_expr(env,
3913 IRExpr_Const(stmt->Ist.Exit.dst));
3914 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3915 }
3916 return;
3917 }
3918
3919 /* Case: assisted transfer to arbitrary address */
3920 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003921 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003922 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003923 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003924 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003925 case Ijk_Sys_syscall:
3926 case Ijk_ClientReq:
3927 case Ijk_NoRedir:
3928 case Ijk_Yield:
3929 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003930 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3931 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3932 stmt->Ist.Exit.jk));
3933 return;
3934 }
3935 default:
3936 break;
3937 }
3938
3939 /* Do we ever expect to see any other kind? */
3940 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003941 }
3942
3943 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003944 case Ist_MBE:
3945 switch (stmt->Ist.MBE.event) {
3946 case Imbe_Fence:
3947 addInstr(env, s390_insn_mfence());
3948 return;
3949 default:
3950 break;
3951 }
sewardj2019a972011-03-07 16:04:07 +00003952 break;
3953
3954 /* --------- Miscellaneous --------- */
3955
3956 case Ist_PutI: /* Not needed */
3957 case Ist_IMark: /* Doesn't generate any executable code */
3958 case Ist_NoOp: /* Doesn't generate any executable code */
3959 case Ist_AbiHint: /* Meaningless in IR */
3960 return;
3961
3962 default:
3963 break;
3964 }
3965
3966 stmt_fail:
3967 ppIRStmt(stmt);
3968 vpanic("s390_isel_stmt");
3969}
3970
3971
3972/*---------------------------------------------------------*/
3973/*--- ISEL: Basic block terminators (Nexts) ---*/
3974/*---------------------------------------------------------*/
3975
3976static void
florianffbd84d2012-12-09 02:06:29 +00003977iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003978{
sewardj2019a972011-03-07 16:04:07 +00003979 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003980 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003981 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003982 vex_printf("; exit-");
3983 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003984 vex_printf("\n");
3985 }
3986
florian8844a632012-04-13 04:04:06 +00003987 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3988
3989 /* Case: boring transfer to known address */
3990 if (next->tag == Iex_Const) {
3991 IRConst *cdst = next->Iex.Const.con;
3992 vassert(cdst->tag == Ico_U64);
3993 if (jk == Ijk_Boring || jk == Ijk_Call) {
3994 /* Boring transfer to known address */
3995 if (env->chaining_allowed) {
3996 /* .. almost always true .. */
3997 /* Skip the event check at the dst if this is a forwards
3998 edge. */
3999 Bool to_fast_entry
4000 = ((Addr64)cdst->Ico.U64) > env->max_ga;
4001 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
4002 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
4003 guest_IA, to_fast_entry));
4004 } else {
4005 /* .. very occasionally .. */
4006 /* We can't use chaining, so ask for an indirect transfer,
4007 as that's the cheapest alternative that is allowable. */
4008 HReg dst = s390_isel_int_expr(env, next);
4009 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
4010 Ijk_Boring));
4011 }
4012 return;
4013 }
4014 }
4015
4016 /* Case: call/return (==boring) transfer to any address */
4017 switch (jk) {
4018 case Ijk_Boring:
4019 case Ijk_Ret:
4020 case Ijk_Call: {
4021 HReg dst = s390_isel_int_expr(env, next);
4022 if (env->chaining_allowed) {
4023 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
4024 } else {
4025 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
4026 Ijk_Boring));
4027 }
4028 return;
4029 }
4030 default:
4031 break;
4032 }
4033
4034 /* Case: some other kind of transfer to any address */
4035 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00004036 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00004037 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00004038 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00004039 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00004040 case Ijk_Sys_syscall:
4041 case Ijk_ClientReq:
4042 case Ijk_NoRedir:
4043 case Ijk_Yield:
4044 case Ijk_SigTRAP: {
4045 HReg dst = s390_isel_int_expr(env, next);
4046 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
4047 return;
4048 }
4049 default:
4050 break;
4051 }
4052
4053 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00004054}
4055
4056
4057/*---------------------------------------------------------*/
4058/*--- Insn selector top-level ---*/
4059/*---------------------------------------------------------*/
4060
florianf26994a2012-04-21 03:34:54 +00004061/* Translate an entire SB to s390 code.
4062 Note: archinfo_host is a pointer to a stack-allocated variable.
4063 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00004064
4065HInstrArray *
4066iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00004067 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
4068 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
4069 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00004070{
4071 UInt i, j;
4072 HReg hreg, hregHI;
4073 ISelEnv *env;
4074 UInt hwcaps_host = archinfo_host->hwcaps;
4075
florianf26994a2012-04-21 03:34:54 +00004076 /* KLUDGE: export hwcaps. */
4077 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00004078
sewardj2019a972011-03-07 16:04:07 +00004079 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00004080 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00004081
4082 /* Make up an initial environment to use. */
4083 env = LibVEX_Alloc(sizeof(ISelEnv));
4084 env->vreg_ctr = 0;
4085
4086 /* Set up output code array. */
4087 env->code = newHInstrArray();
4088
4089 /* Copy BB's type env. */
4090 env->type_env = bb->tyenv;
4091
florianad43b3a2012-02-20 15:01:14 +00004092 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00004093 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
4094 env->old_value[i] = 0; /* just something to have a defined value */
4095 env->old_value_valid[i] = False;
4096 }
4097
sewardj2019a972011-03-07 16:04:07 +00004098 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
4099 change as we go along. For some reason types_used has Int type -- but
4100 it should be unsigned. Internally we use an unsigned type; so we
4101 assert it here. */
4102 vassert(bb->tyenv->types_used >= 0);
4103
4104 env->n_vregmap = bb->tyenv->types_used;
4105 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4106 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4107
florian2c74d242012-09-12 19:38:42 +00004108 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00004109 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00004110
sewardj2019a972011-03-07 16:04:07 +00004111 /* and finally ... */
4112 env->hwcaps = hwcaps_host;
4113
florian8844a632012-04-13 04:04:06 +00004114 env->max_ga = max_ga;
4115 env->chaining_allowed = chaining_allowed;
4116
sewardj2019a972011-03-07 16:04:07 +00004117 /* For each IR temporary, allocate a suitably-kinded virtual
4118 register. */
4119 j = 0;
4120 for (i = 0; i < env->n_vregmap; i++) {
4121 hregHI = hreg = INVALID_HREG;
4122 switch (bb->tyenv->types[i]) {
4123 case Ity_I1:
4124 case Ity_I8:
4125 case Ity_I16:
4126 case Ity_I32:
4127 hreg = mkHReg(j++, HRcInt64, True);
4128 break;
4129
4130 case Ity_I64:
4131 hreg = mkHReg(j++, HRcInt64, True);
4132 break;
4133
4134 case Ity_I128:
4135 hreg = mkHReg(j++, HRcInt64, True);
4136 hregHI = mkHReg(j++, HRcInt64, True);
4137 break;
4138
4139 case Ity_F32:
4140 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00004141 case Ity_D32:
florian12390202012-11-10 22:34:14 +00004142 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00004143 hreg = mkHReg(j++, HRcFlt64, True);
4144 break;
4145
4146 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00004147 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00004148 hreg = mkHReg(j++, HRcFlt64, True);
4149 hregHI = mkHReg(j++, HRcFlt64, True);
4150 break;
4151
4152 case Ity_V128: /* fall through */
4153 default:
4154 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00004155 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00004156 }
4157
4158 env->vregmap[i] = hreg;
4159 env->vregmapHI[i] = hregHI;
4160 }
4161 env->vreg_ctr = j;
4162
florian8844a632012-04-13 04:04:06 +00004163 /* The very first instruction must be an event check. */
4164 s390_amode *counter, *fail_addr;
4165 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
4166 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
4167 addInstr(env, s390_insn_evcheck(counter, fail_addr));
4168
4169 /* Possibly a block counter increment (for profiling). At this
4170 point we don't know the address of the counter, so just pretend
4171 it is zero. It will have to be patched later, but before this
4172 translation is used, by a call to LibVEX_patchProfInc. */
4173 if (add_profinc) {
4174 addInstr(env, s390_insn_profinc());
4175 }
4176
sewardj2019a972011-03-07 16:04:07 +00004177 /* Ok, finally we can iterate over the statements. */
4178 for (i = 0; i < bb->stmts_used; i++)
4179 if (bb->stmts[i])
4180 s390_isel_stmt(env, bb->stmts[i]);
4181
florian8844a632012-04-13 04:04:06 +00004182 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00004183
4184 /* Record the number of vregs we used. */
4185 env->code->n_vregs = env->vreg_ctr;
4186
4187 return env->code;
4188}
4189
4190/*---------------------------------------------------------------*/
4191/*--- end host_s390_isel.c ---*/
4192/*---------------------------------------------------------------*/