blob: cad0e7ed444a748be443cf73850a049eab0d85cc [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);
floriana2039c52013-12-10 16:51:15 +00001260 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res,
1261 INVALID_HREG, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001262 rounding_mode));
1263 return res;
1264 }
1265
florian5f034622013-01-13 02:29:05 +00001266 do_convert_dfp: {
1267 s390_dfp_round_t rounding_mode;
1268
1269 res = newVRegI(env);
1270 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1271
1272 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001273 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
florian5f034622013-01-13 02:29:05 +00001274 rounding_mode));
1275 return res;
1276 }
1277
1278 do_convert_dfp128: {
1279 s390_dfp_round_t rounding_mode;
1280 HReg op_hi, op_lo, f13, f15;
1281
1282 res = newVRegI(env);
1283 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1284
1285 /* We use non-virtual registers r13 and r15 as pair */
1286 f13 = make_fpr(13);
1287 f15 = make_fpr(15);
1288
1289 /* operand --> (f13, f15) */
1290 addInstr(env, s390_insn_move(8, f13, op_hi));
1291 addInstr(env, s390_insn_move(8, f15, op_lo));
1292
1293 rounding_mode = get_dfp_rounding_mode(env, arg1);
floriana2039c52013-12-10 16:51:15 +00001294 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res,
1295 INVALID_HREG, f13,
florian5f034622013-01-13 02:29:05 +00001296 f15, rounding_mode));
1297 return res;
1298 }
1299
sewardj2019a972011-03-07 16:04:07 +00001300 case Iop_8HLto16:
1301 case Iop_16HLto32:
1302 case Iop_32HLto64: {
1303 HReg h2;
1304 UInt arg_size = size / 2;
1305
1306 res = newVRegI(env);
1307 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1308 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1309
1310 addInstr(env, s390_insn_move(arg_size, res, h1));
1311 value = s390_opnd_imm(arg_size * 8);
1312 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1313 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1314 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1315 opnd = s390_opnd_reg(h2);
1316 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1317 return res;
1318 }
1319
1320 case Iop_Max32U: {
1321 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1322 res = newVRegI(env);
1323 h1 = s390_isel_int_expr(env, arg1);
1324 op2 = s390_isel_int_expr_RMI(env, arg2);
1325
1326 addInstr(env, s390_insn_move(size, res, h1));
1327 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1328 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1329 return res;
1330 }
1331
1332 case Iop_CmpF32:
1333 case Iop_CmpF64: {
1334 HReg cc_s390, h2;
1335
1336 h1 = s390_isel_float_expr(env, arg1);
1337 h2 = s390_isel_float_expr(env, arg2);
1338 cc_s390 = newVRegI(env);
1339
1340 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1341
1342 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1343
florian2d3d87f2012-12-21 21:05:17 +00001344 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001345 }
1346
1347 case Iop_CmpF128: {
1348 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1349
1350 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1351 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1352 cc_s390 = newVRegI(env);
1353
1354 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1355 f12 = make_fpr(12);
1356 f13 = make_fpr(13);
1357 f14 = make_fpr(14);
1358 f15 = make_fpr(15);
1359
1360 /* 1st operand --> (f12, f14) */
1361 addInstr(env, s390_insn_move(8, f12, op1_hi));
1362 addInstr(env, s390_insn_move(8, f14, op1_lo));
1363
1364 /* 2nd operand --> (f13, f15) */
1365 addInstr(env, s390_insn_move(8, f13, op2_hi));
1366 addInstr(env, s390_insn_move(8, f15, op2_lo));
1367
1368 res = newVRegI(env);
1369 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1370
florian2d3d87f2012-12-21 21:05:17 +00001371 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001372 }
1373
florian20c6bca2012-12-26 17:47:19 +00001374 case Iop_CmpD64:
1375 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001376 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001377 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001378
1379 h1 = s390_isel_dfp_expr(env, arg1);
1380 h2 = s390_isel_dfp_expr(env, arg2);
1381 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001382
florian20c6bca2012-12-26 17:47:19 +00001383 switch(expr->Iex.Binop.op) {
1384 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1385 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1386 default: goto irreducible;
1387 }
1388 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001389
florian2d3d87f2012-12-21 21:05:17 +00001390 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001391 }
1392
florian20c6bca2012-12-26 17:47:19 +00001393 case Iop_CmpD128:
1394 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001395 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001396 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001397
1398 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1399 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1400 cc_s390 = newVRegI(env);
1401
1402 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1403 f12 = make_fpr(12);
1404 f13 = make_fpr(13);
1405 f14 = make_fpr(14);
1406 f15 = make_fpr(15);
1407
1408 /* 1st operand --> (f12, f14) */
1409 addInstr(env, s390_insn_move(8, f12, op1_hi));
1410 addInstr(env, s390_insn_move(8, f14, op1_lo));
1411
1412 /* 2nd operand --> (f13, f15) */
1413 addInstr(env, s390_insn_move(8, f13, op2_hi));
1414 addInstr(env, s390_insn_move(8, f15, op2_lo));
1415
florian20c6bca2012-12-26 17:47:19 +00001416 switch(expr->Iex.Binop.op) {
1417 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1418 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1419 default: goto irreducible;
1420 }
1421 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1422 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001423
florian2d3d87f2012-12-21 21:05:17 +00001424 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001425 }
1426
sewardj2019a972011-03-07 16:04:07 +00001427 case Iop_Add8:
1428 case Iop_Add16:
1429 case Iop_Add32:
1430 case Iop_Add64:
1431 opkind = S390_ALU_ADD;
1432 break;
1433
1434 case Iop_Sub8:
1435 case Iop_Sub16:
1436 case Iop_Sub32:
1437 case Iop_Sub64:
1438 opkind = S390_ALU_SUB;
1439 is_commutative = False;
1440 break;
1441
1442 case Iop_And8:
1443 case Iop_And16:
1444 case Iop_And32:
1445 case Iop_And64:
1446 opkind = S390_ALU_AND;
1447 break;
1448
1449 case Iop_Or8:
1450 case Iop_Or16:
1451 case Iop_Or32:
1452 case Iop_Or64:
1453 opkind = S390_ALU_OR;
1454 break;
1455
1456 case Iop_Xor8:
1457 case Iop_Xor16:
1458 case Iop_Xor32:
1459 case Iop_Xor64:
1460 opkind = S390_ALU_XOR;
1461 break;
1462
1463 case Iop_Shl8:
1464 case Iop_Shl16:
1465 case Iop_Shl32:
1466 case Iop_Shl64:
1467 opkind = S390_ALU_LSH;
1468 is_commutative = False;
1469 break;
1470
1471 case Iop_Shr8:
1472 case Iop_Shr16:
1473 case Iop_Shr32:
1474 case Iop_Shr64:
1475 opkind = S390_ALU_RSH;
1476 is_commutative = False;
1477 break;
1478
1479 case Iop_Sar8:
1480 case Iop_Sar16:
1481 case Iop_Sar32:
1482 case Iop_Sar64:
1483 opkind = S390_ALU_RSHA;
1484 is_commutative = False;
1485 break;
1486
1487 default:
1488 goto irreducible;
1489 }
1490
1491 /* Pattern match: 0 - arg1 --> -arg1 */
1492 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1493 res = newVRegI(env);
1494 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1495 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1496 addInstr(env, insn);
1497
1498 return res;
1499 }
1500
1501 if (is_commutative) {
1502 order_commutative_operands(arg1, arg2);
1503 }
1504
1505 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1506 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1507 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001508
1509 /* As right shifts of one/two byte opreands are implemented using a
1510 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1511 switch (expr->Iex.Binop.op) {
1512 case Iop_Shr8:
1513 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1514 break;
1515 case Iop_Shr16:
1516 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1517 break;
1518 case Iop_Sar8:
1519 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1520 break;
1521 case Iop_Sar16:
1522 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1523 break;
1524 default:
1525 insn = s390_insn_move(size, res, h1);
1526 break;
1527 }
1528 addInstr(env, insn);
1529
sewardj2019a972011-03-07 16:04:07 +00001530 insn = s390_insn_alu(size, opkind, res, op2);
1531
1532 addInstr(env, insn);
1533
1534 return res;
1535 }
1536
1537 /* --------- UNARY OP --------- */
1538 case Iex_Unop: {
1539 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1540 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1541 s390_opnd_RMI opnd;
1542 s390_insn *insn;
1543 IRExpr *arg;
1544 HReg dst, h1;
1545 IROp unop, binop;
1546
1547 arg = expr->Iex.Unop.arg;
1548
1549 /* Special cases are handled here */
1550
1551 /* 32-bit multiply with 32-bit result or
1552 64-bit multiply with 64-bit result */
1553 unop = expr->Iex.Unop.op;
1554 binop = arg->Iex.Binop.op;
1555
1556 if ((arg->tag == Iex_Binop &&
1557 ((unop == Iop_64to32 &&
1558 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1559 (unop == Iop_128to64 &&
1560 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1561 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1562 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1563 dst = newVRegI(env); /* Result goes into a new register */
1564 addInstr(env, s390_insn_move(size, dst, h1));
1565 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1566
1567 return dst;
1568 }
1569
florian4d71a082011-12-18 00:08:17 +00001570 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001571 dst = newVRegI(env);
1572 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1573 addInstr(env, s390_insn_move(size, dst, h1));
1574
1575 return dst;
1576 }
1577
floriane38f6412012-12-21 17:32:12 +00001578 if (unop == Iop_ReinterpD64asI64) {
1579 dst = newVRegI(env);
1580 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1581 addInstr(env, s390_insn_move(size, dst, h1));
1582
1583 return dst;
1584 }
1585
florian5c539732013-02-14 14:27:12 +00001586 if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
1587 s390_dfp_unop_t dfpop;
1588 switch(unop) {
1589 case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
1590 case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
1591 default: goto irreducible;
1592 }
floriance9e3db2012-12-27 20:14:03 +00001593 dst = newVRegI(env);
1594 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
florian5c539732013-02-14 14:27:12 +00001595 addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
floriance9e3db2012-12-27 20:14:03 +00001596 return dst;
1597 }
1598
florian5c539732013-02-14 14:27:12 +00001599 if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
1600 s390_dfp_unop_t dfpop;
floriance9e3db2012-12-27 20:14:03 +00001601 HReg op_hi, op_lo, f13, f15;
florian5c539732013-02-14 14:27:12 +00001602
1603 switch(unop) {
1604 case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
1605 case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
1606 default: goto irreducible;
1607 }
floriance9e3db2012-12-27 20:14:03 +00001608 dst = newVRegI(env);
1609 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1610
1611 /* We use non-virtual registers r13 and r15 as pair */
1612 f13 = make_fpr(13);
1613 f15 = make_fpr(15);
1614
1615 /* operand --> (f13, f15) */
1616 addInstr(env, s390_insn_move(8, f13, op_hi));
1617 addInstr(env, s390_insn_move(8, f15, op_lo));
1618
florian5c539732013-02-14 14:27:12 +00001619 addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
floriance9e3db2012-12-27 20:14:03 +00001620 return dst;
1621 }
1622
sewardj2019a972011-03-07 16:04:07 +00001623 /* Expressions whose argument is 1-bit wide */
1624 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1625 s390_cc_t cond = s390_isel_cc(env, arg);
1626 dst = newVRegI(env); /* Result goes into a new register */
1627 addInstr(env, s390_insn_cc2bool(dst, cond));
1628
1629 switch (unop) {
1630 case Iop_1Uto8:
1631 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001632 /* Zero extend */
1633 mask.variant.imm = 1;
1634 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1635 break;
1636
sewardj2019a972011-03-07 16:04:07 +00001637 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001638 /* Zero extend */
1639 mask.variant.imm = 1;
1640 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001641 break;
1642
1643 case Iop_1Sto8:
1644 case Iop_1Sto16:
1645 case Iop_1Sto32:
1646 shift.variant.imm = 31;
1647 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1648 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1649 break;
1650
1651 case Iop_1Sto64:
1652 shift.variant.imm = 63;
1653 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1654 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1655 break;
1656
1657 default:
1658 goto irreducible;
1659 }
1660
1661 return dst;
1662 }
1663
1664 /* Regular processing */
1665
1666 if (unop == Iop_128to64) {
1667 HReg dst_hi, dst_lo;
1668
1669 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1670 return dst_lo;
1671 }
1672
1673 if (unop == Iop_128HIto64) {
1674 HReg dst_hi, dst_lo;
1675
1676 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1677 return dst_hi;
1678 }
1679
1680 dst = newVRegI(env); /* Result goes into a new register */
1681 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1682
1683 switch (unop) {
1684 case Iop_8Uto16:
1685 case Iop_8Uto32:
1686 case Iop_8Uto64:
1687 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1688 break;
1689
1690 case Iop_16Uto32:
1691 case Iop_16Uto64:
1692 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1693 break;
1694
1695 case Iop_32Uto64:
1696 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1697 break;
1698
1699 case Iop_8Sto16:
1700 case Iop_8Sto32:
1701 case Iop_8Sto64:
1702 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1703 break;
1704
1705 case Iop_16Sto32:
1706 case Iop_16Sto64:
1707 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1708 break;
1709
1710 case Iop_32Sto64:
1711 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1712 break;
1713
1714 case Iop_64to8:
1715 case Iop_64to16:
1716 case Iop_64to32:
1717 case Iop_32to8:
1718 case Iop_32to16:
1719 case Iop_16to8:
1720 /* Down-casts are no-ops. Upstream operations will only look at
1721 the bytes that make up the result of the down-cast. So there
1722 is no point setting the other bytes to 0. */
1723 insn = s390_opnd_copy(8, dst, opnd);
1724 break;
1725
1726 case Iop_64HIto32:
1727 addInstr(env, s390_opnd_copy(8, dst, opnd));
1728 shift.variant.imm = 32;
1729 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1730 break;
1731
1732 case Iop_32HIto16:
1733 addInstr(env, s390_opnd_copy(4, dst, opnd));
1734 shift.variant.imm = 16;
1735 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1736 break;
1737
1738 case Iop_16HIto8:
1739 addInstr(env, s390_opnd_copy(2, dst, opnd));
1740 shift.variant.imm = 8;
1741 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1742 break;
1743
1744 case Iop_Not8:
1745 case Iop_Not16:
1746 case Iop_Not32:
1747 case Iop_Not64:
1748 /* XOR with ffff... */
1749 mask.variant.imm = ~(ULong)0;
1750 addInstr(env, s390_opnd_copy(size, dst, opnd));
1751 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1752 break;
1753
1754 case Iop_Left8:
1755 case Iop_Left16:
1756 case Iop_Left32:
1757 case Iop_Left64:
1758 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1759 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1760 break;
1761
1762 case Iop_CmpwNEZ32:
1763 case Iop_CmpwNEZ64: {
1764 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1765 or -X will have a 1 in the MSB. */
1766 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1767 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1768 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1769 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1770 return dst;
1771 }
1772
1773 case Iop_Clz64: {
1774 HReg r10, r11;
1775
sewardj611b06e2011-03-24 08:57:29 +00001776 /* This will be implemented using FLOGR, if possible. So we need to
1777 set aside a pair of non-virtual registers. The result (number of
1778 left-most zero bits) will be in r10. The value in r11 is unspecified
1779 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001780 r10 = make_gpr(10);
1781 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001782
sewardj611b06e2011-03-24 08:57:29 +00001783 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001784 addInstr(env, s390_insn_move(8, dst, r10));
1785 return dst;
1786 }
1787
1788 default:
1789 goto irreducible;
1790 }
1791
1792 addInstr(env, insn);
1793
1794 return dst;
1795 }
1796
1797 /* --------- GET --------- */
1798 case Iex_Get: {
1799 HReg dst = newVRegI(env);
1800 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1801
1802 /* We never load more than 8 bytes from the guest state, because the
1803 floating point register pair is not contiguous. */
1804 vassert(size <= 8);
1805
1806 addInstr(env, s390_insn_load(size, dst, am));
1807
1808 return dst;
1809 }
1810
1811 case Iex_GetI:
1812 /* not needed */
1813 break;
1814
1815 /* --------- CCALL --------- */
1816 case Iex_CCall: {
1817 HReg dst = newVRegI(env);
sewardj74142b82013-08-08 10:28:59 +00001818 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
1819 UInt addToSp = 0;
1820 RetLoc rloc = mk_RetLoc_INVALID();
sewardj2019a972011-03-07 16:04:07 +00001821
sewardj74142b82013-08-08 10:28:59 +00001822 doHelperCall(&addToSp, &rloc, env, NULL, expr->Iex.CCall.cee,
1823 expr->Iex.CCall.retty, expr->Iex.CCall.args);
1824 vassert(is_sane_RetLoc(rloc));
1825 vassert(rloc.pri == RLPri_Int);
1826 vassert(addToSp == 0);
1827 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
1828
sewardj2019a972011-03-07 16:04:07 +00001829 return dst;
1830 }
1831
1832 /* --------- LITERAL --------- */
1833
1834 /* Load a literal into a register. Create a "load immediate"
1835 v-insn and return the register. */
1836 case Iex_Const: {
1837 ULong value;
1838 HReg dst = newVRegI(env);
1839 const IRConst *con = expr->Iex.Const.con;
1840
1841 /* Bitwise copy of the value. No sign/zero-extension */
1842 switch (con->tag) {
1843 case Ico_U64: value = con->Ico.U64; break;
1844 case Ico_U32: value = con->Ico.U32; break;
1845 case Ico_U16: value = con->Ico.U16; break;
1846 case Ico_U8: value = con->Ico.U8; break;
1847 default: vpanic("s390_isel_int_expr: invalid constant");
1848 }
1849
1850 addInstr(env, s390_insn_load_immediate(size, dst, value));
1851
1852 return dst;
1853 }
1854
1855 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00001856 case Iex_ITE: {
sewardj2019a972011-03-07 16:04:07 +00001857 IRExpr *cond_expr;
florian99dd03e2013-01-29 03:56:06 +00001858 HReg dst, r1;
sewardj009230b2013-01-26 11:47:55 +00001859 s390_opnd_RMI r0;
sewardj2019a972011-03-07 16:04:07 +00001860
florian99dd03e2013-01-29 03:56:06 +00001861 cond_expr = expr->Iex.ITE.cond;
sewardj2019a972011-03-07 16:04:07 +00001862
sewardj009230b2013-01-26 11:47:55 +00001863 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
1864
sewardj2019a972011-03-07 16:04:07 +00001865 dst = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00001866 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
1867 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
1868 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
sewardj2019a972011-03-07 16:04:07 +00001869
sewardj009230b2013-01-26 11:47:55 +00001870 s390_cc_t cc = s390_isel_cc(env, cond_expr);
sewardj2019a972011-03-07 16:04:07 +00001871
florian99dd03e2013-01-29 03:56:06 +00001872 addInstr(env, s390_insn_move(size, dst, r1));
sewardj009230b2013-01-26 11:47:55 +00001873 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
sewardj2019a972011-03-07 16:04:07 +00001874 return dst;
1875 }
1876
1877 default:
1878 break;
1879 }
1880
1881 /* We get here if no pattern matched. */
1882 irreducible:
1883 ppIRExpr(expr);
1884 vpanic("s390_isel_int_expr: cannot reduce tree");
1885}
1886
1887
1888static HReg
1889s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1890{
1891 HReg dst = s390_isel_int_expr_wrk(env, expr);
1892
1893 /* Sanity checks ... */
1894 vassert(hregClass(dst) == HRcInt64);
1895 vassert(hregIsVirtual(dst));
1896
1897 return dst;
1898}
1899
1900
1901static s390_opnd_RMI
1902s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1903{
1904 IRType ty = typeOfIRExpr(env->type_env, expr);
1905 s390_opnd_RMI dst;
1906
1907 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1908 ty == Ity_I64);
1909
1910 if (expr->tag == Iex_Load) {
1911 dst.tag = S390_OPND_AMODE;
1912 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1913 } else if (expr->tag == Iex_Get) {
1914 dst.tag = S390_OPND_AMODE;
1915 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1916 } else if (expr->tag == Iex_Const) {
1917 ULong value;
1918
1919 /* The bit pattern for the value will be stored as is in the least
1920 significant bits of VALUE. */
1921 switch (expr->Iex.Const.con->tag) {
1922 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1923 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1924 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1925 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1926 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1927 default:
1928 vpanic("s390_isel_int_expr_RMI");
1929 }
1930
1931 dst.tag = S390_OPND_IMMEDIATE;
1932 dst.variant.imm = value;
1933 } else {
1934 dst.tag = S390_OPND_REG;
1935 dst.variant.reg = s390_isel_int_expr(env, expr);
1936 }
1937
1938 return dst;
1939}
1940
1941
1942/*---------------------------------------------------------*/
1943/*--- ISEL: Floating point expressions (128 bit) ---*/
1944/*---------------------------------------------------------*/
1945static void
1946s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1947 IRExpr *expr)
1948{
1949 IRType ty = typeOfIRExpr(env->type_env, expr);
1950
1951 vassert(ty == Ity_F128);
1952
sewardj2019a972011-03-07 16:04:07 +00001953 switch (expr->tag) {
1954 case Iex_RdTmp:
1955 /* Return the virtual registers that hold the temporary. */
1956 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1957 return;
1958
1959 /* --------- LOAD --------- */
1960 case Iex_Load: {
1961 IRExpr *addr_hi, *addr_lo;
1962 s390_amode *am_hi, *am_lo;
1963
1964 if (expr->Iex.Load.end != Iend_BE)
1965 goto irreducible;
1966
1967 addr_hi = expr->Iex.Load.addr;
1968 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1969
1970 am_hi = s390_isel_amode(env, addr_hi);
1971 am_lo = s390_isel_amode(env, addr_lo);
1972
1973 *dst_hi = newVRegF(env);
1974 *dst_lo = newVRegF(env);
1975 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1976 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1977 return;
1978 }
1979
1980
1981 /* --------- GET --------- */
1982 case Iex_Get:
1983 /* This is not supported because loading 128-bit from the guest
1984 state is almost certainly wrong. Use get_fpr_pair instead. */
1985 vpanic("Iex_Get with F128 data");
1986
1987 /* --------- 4-ary OP --------- */
1988 case Iex_Qop:
1989 vpanic("Iex_Qop with F128 data");
1990
1991 /* --------- TERNARY OP --------- */
1992 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001993 IRTriop *triop = expr->Iex.Triop.details;
1994 IROp op = triop->op;
1995 IRExpr *left = triop->arg2;
1996 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001997 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001998 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1999
2000 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2001 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2002
2003 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2004 f12 = make_fpr(12);
2005 f13 = make_fpr(13);
2006 f14 = make_fpr(14);
2007 f15 = make_fpr(15);
2008
2009 /* 1st operand --> (f12, f14) */
2010 addInstr(env, s390_insn_move(8, f12, op1_hi));
2011 addInstr(env, s390_insn_move(8, f14, op1_lo));
2012
2013 /* 2nd operand --> (f13, f15) */
2014 addInstr(env, s390_insn_move(8, f13, op2_hi));
2015 addInstr(env, s390_insn_move(8, f15, op2_lo));
2016
2017 switch (op) {
2018 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
2019 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
2020 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
2021 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
2022 default:
2023 goto irreducible;
2024 }
2025
florian2c74d242012-09-12 19:38:42 +00002026 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2027 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002028
2029 /* Move result to virtual destination register */
2030 *dst_hi = newVRegF(env);
2031 *dst_lo = newVRegF(env);
2032 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2033 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2034
2035 return;
2036 }
2037
2038 /* --------- BINARY OP --------- */
2039 case Iex_Binop: {
sewardj2019a972011-03-07 16:04:07 +00002040 switch (expr->Iex.Binop.op) {
florian78d5ef72013-05-11 15:02:58 +00002041 case Iop_SqrtF128: {
2042 HReg op_hi, op_lo, f12, f13, f14, f15;
2043
2044 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2045 f12 = make_fpr(12);
2046 f13 = make_fpr(13);
2047 f14 = make_fpr(14);
2048 f15 = make_fpr(15);
2049
sewardj2019a972011-03-07 16:04:07 +00002050 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
2051
2052 /* operand --> (f13, f15) */
2053 addInstr(env, s390_insn_move(8, f13, op_hi));
2054 addInstr(env, s390_insn_move(8, f15, op_lo));
2055
florian2c74d242012-09-12 19:38:42 +00002056 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
2057 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
2058 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002059
2060 /* Move result to virtual destination registers */
2061 *dst_hi = newVRegF(env);
2062 *dst_lo = newVRegF(env);
2063 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2064 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2065 return;
florian78d5ef72013-05-11 15:02:58 +00002066 }
sewardj2019a972011-03-07 16:04:07 +00002067
2068 case Iop_F64HLtoF128:
2069 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
2070 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
2071 return;
2072
florian7ab421d2013-06-17 21:03:56 +00002073 case Iop_D32toF128:
2074 case Iop_D64toF128: {
2075 IRExpr *irrm;
2076 IRExpr *left;
2077 s390_dfp_round_t rm;
2078 HReg h1; /* virtual reg. to hold source */
2079 HReg f0, f2, f4, r1; /* real registers used by PFPO */
2080 s390_fp_conv_t fpconv;
2081
2082 switch (expr->Iex.Binop.op) {
2083 case Iop_D32toF128:
2084 fpconv = S390_FP_D32_TO_F128;
2085 break;
2086 case Iop_D64toF128:
2087 fpconv = S390_FP_D64_TO_F128;
2088 break;
2089 default: goto irreducible;
2090 }
2091
2092 f4 = make_fpr(4); /* source */
2093 f0 = make_fpr(0); /* destination */
2094 f2 = make_fpr(2); /* destination */
2095 r1 = make_gpr(1); /* GPR #1 clobbered */
2096 irrm = expr->Iex.Binop.arg1;
2097 left = expr->Iex.Binop.arg2;
2098 rm = get_dfp_rounding_mode(env, irrm);
2099 h1 = s390_isel_dfp_expr(env, left);
2100 addInstr(env, s390_insn_move(8, f4, h1));
2101 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
2102 f4, INVALID_HREG, r1, rm));
2103 /* (f0, f2) --> destination */
2104 *dst_hi = newVRegF(env);
2105 *dst_lo = newVRegF(env);
2106 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2107 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2108
2109 return;
2110 }
2111
florian78d5ef72013-05-11 15:02:58 +00002112 case Iop_D128toF128: {
2113 IRExpr *irrm;
2114 IRExpr *left;
2115 s390_dfp_round_t rm;
2116 HReg op_hi, op_lo;
2117 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2118
2119 f4 = make_fpr(4); /* source */
2120 f6 = make_fpr(6); /* source */
2121 f0 = make_fpr(0); /* destination */
2122 f2 = make_fpr(2); /* destination */
2123 r1 = make_gpr(1); /* GPR #1 clobbered */
2124
2125 irrm = expr->Iex.Binop.arg1;
2126 left = expr->Iex.Binop.arg2;
2127 rm = get_dfp_rounding_mode(env, irrm);
2128 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2129 /* operand --> (f4, f6) */
2130 addInstr(env, s390_insn_move(8, f4, op_hi));
2131 addInstr(env, s390_insn_move(8, f6, op_lo));
2132 addInstr(env, s390_insn_fp128_convert(16, S390_FP_D128_TO_F128, f0, f2,
2133 f4, f6, r1, rm));
2134 /* (f0, f2) --> destination */
2135 *dst_hi = newVRegF(env);
2136 *dst_lo = newVRegF(env);
2137 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2138 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2139
2140 return;
2141 }
2142
sewardj2019a972011-03-07 16:04:07 +00002143 default:
2144 goto irreducible;
2145 }
2146 }
2147
2148 /* --------- UNARY OP --------- */
2149 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00002150 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00002151 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002152 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002153 HReg op_hi, op_lo, op, f12, f13, f14, f15;
2154
2155 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2156 f12 = make_fpr(12);
2157 f13 = make_fpr(13);
2158 f14 = make_fpr(14);
2159 f15 = make_fpr(15);
2160
florian66e596d2012-09-07 15:00:53 +00002161 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00002162 case Iop_NegF128:
2163 if (left->tag == Iex_Unop &&
2164 (left->Iex.Unop.op == Iop_AbsF32 ||
2165 left->Iex.Unop.op == Iop_AbsF64))
2166 bfpop = S390_BFP_NABS;
2167 else
2168 bfpop = S390_BFP_NEG;
2169 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00002170 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2171 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2172 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2173 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2174 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2175 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2176 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00002177 default:
2178 goto irreducible;
2179 }
2180
2181 float128_opnd:
2182 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2183
2184 /* operand --> (f13, f15) */
2185 addInstr(env, s390_insn_move(8, f13, op_hi));
2186 addInstr(env, s390_insn_move(8, f15, op_lo));
2187
florian2c74d242012-09-12 19:38:42 +00002188 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002189 goto move_dst;
2190
2191 convert_float:
2192 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002193 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002194 goto move_dst;
2195
2196 convert_int:
2197 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002198 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002199 goto move_dst;
2200
2201 move_dst:
2202 /* Move result to virtual destination registers */
2203 *dst_hi = newVRegF(env);
2204 *dst_lo = newVRegF(env);
2205 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2206 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2207 return;
2208 }
2209
2210 default:
2211 goto irreducible;
2212 }
2213
2214 /* We get here if no pattern matched. */
2215 irreducible:
2216 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002217 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002218}
2219
2220/* Compute a 128-bit value into two 64-bit registers. These may be either
2221 real or virtual regs; in any case they must not be changed by subsequent
2222 code emitted by the caller. */
2223static void
2224s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2225{
2226 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2227
2228 /* Sanity checks ... */
2229 vassert(hregIsVirtual(*dst_hi));
2230 vassert(hregIsVirtual(*dst_lo));
2231 vassert(hregClass(*dst_hi) == HRcFlt64);
2232 vassert(hregClass(*dst_lo) == HRcFlt64);
2233}
2234
2235
2236/*---------------------------------------------------------*/
2237/*--- ISEL: Floating point expressions (64 bit) ---*/
2238/*---------------------------------------------------------*/
2239
2240static HReg
2241s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2242{
2243 IRType ty = typeOfIRExpr(env->type_env, expr);
2244 UChar size;
2245
2246 vassert(ty == Ity_F32 || ty == Ity_F64);
2247
2248 size = sizeofIRType(ty);
2249
2250 switch (expr->tag) {
2251 case Iex_RdTmp:
2252 /* Return the virtual register that holds the temporary. */
2253 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2254
2255 /* --------- LOAD --------- */
2256 case Iex_Load: {
2257 HReg dst = newVRegF(env);
2258 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2259
2260 if (expr->Iex.Load.end != Iend_BE)
2261 goto irreducible;
2262
2263 addInstr(env, s390_insn_load(size, dst, am));
2264
2265 return dst;
2266 }
2267
2268 /* --------- GET --------- */
2269 case Iex_Get: {
2270 HReg dst = newVRegF(env);
2271 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2272
2273 addInstr(env, s390_insn_load(size, dst, am));
2274
2275 return dst;
2276 }
2277
2278 /* --------- LITERAL --------- */
2279
2280 /* Load a literal into a register. Create a "load immediate"
2281 v-insn and return the register. */
2282 case Iex_Const: {
2283 ULong value;
2284 HReg dst = newVRegF(env);
2285 const IRConst *con = expr->Iex.Const.con;
2286
2287 /* Bitwise copy of the value. No sign/zero-extension */
2288 switch (con->tag) {
2289 case Ico_F32i: value = con->Ico.F32i; break;
2290 case Ico_F64i: value = con->Ico.F64i; break;
2291 default: vpanic("s390_isel_float_expr: invalid constant");
2292 }
2293
2294 if (value != 0) vpanic("cannot load immediate floating point constant");
2295
2296 addInstr(env, s390_insn_load_immediate(size, dst, value));
2297
2298 return dst;
2299 }
2300
2301 /* --------- 4-ary OP --------- */
2302 case Iex_Qop: {
2303 HReg op1, op2, op3, dst;
2304 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002305
florian5906a6b2012-10-16 02:53:33 +00002306 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002307 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002308 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002309 dst = newVRegF(env);
2310 addInstr(env, s390_insn_move(size, dst, op1));
2311
florian96d7cc32012-06-01 20:41:24 +00002312 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002313 case Iop_MAddF32:
2314 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2315 case Iop_MSubF32:
2316 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2317
2318 default:
2319 goto irreducible;
2320 }
2321
florian2c74d242012-09-12 19:38:42 +00002322 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2323 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002324 return dst;
2325 }
2326
2327 /* --------- TERNARY OP --------- */
2328 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002329 IRTriop *triop = expr->Iex.Triop.details;
2330 IROp op = triop->op;
2331 IRExpr *left = triop->arg2;
2332 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002333 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002334 HReg h1, op2, dst;
2335
2336 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2337 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2338 dst = newVRegF(env);
2339 addInstr(env, s390_insn_move(size, dst, h1));
2340 switch (op) {
2341 case Iop_AddF32:
2342 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2343 case Iop_SubF32:
2344 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2345 case Iop_MulF32:
2346 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2347 case Iop_DivF32:
2348 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2349
2350 default:
2351 goto irreducible;
2352 }
2353
florian2c74d242012-09-12 19:38:42 +00002354 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2355 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002356 return dst;
2357 }
2358
2359 /* --------- BINARY OP --------- */
2360 case Iex_Binop: {
2361 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002362 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002363 IRExpr *left = expr->Iex.Binop.arg2;
2364 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002365 s390_bfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002366 s390_fp_conv_t fpconv;
sewardj2019a972011-03-07 16:04:07 +00002367
2368 switch (op) {
2369 case Iop_SqrtF32:
2370 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002371 h1 = s390_isel_float_expr(env, left);
2372 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002373 set_bfp_rounding_mode_in_fpc(env, irrm);
2374 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002375 return dst;
sewardj2019a972011-03-07 16:04:07 +00002376
florian9fcff4c2012-09-10 03:09:04 +00002377 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2378 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2379 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2380 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2381 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2382 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2383 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
florian7ab421d2013-06-17 21:03:56 +00002384 case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp;
2385 case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp;
2386 case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp;
florian78d5ef72013-05-11 15:02:58 +00002387 case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp;
florian7ab421d2013-06-17 21:03:56 +00002388 case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128;
florian78d5ef72013-05-11 15:02:58 +00002389 case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00002390
florian9fcff4c2012-09-10 03:09:04 +00002391 convert_float:
2392 h1 = s390_isel_float_expr(env, left);
2393 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002394
florian9fcff4c2012-09-10 03:09:04 +00002395 convert_int:
2396 h1 = s390_isel_int_expr(env, left);
2397 goto convert;
2398
florian2c74d242012-09-12 19:38:42 +00002399 convert: {
florian125e20d2012-10-07 15:42:37 +00002400 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002401 /* convert-from-fixed and load-rounded have a rounding mode field
2402 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002403 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002404 if (s390_host_has_fpext) {
2405 rounding_mode = get_bfp_rounding_mode(env, irrm);
2406 } else {
2407 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002408 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002409 }
florian9fcff4c2012-09-10 03:09:04 +00002410 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2411 rounding_mode));
2412 return dst;
florian2c74d242012-09-12 19:38:42 +00002413 }
florian78d5ef72013-05-11 15:02:58 +00002414
2415 convert_dfp: {
2416 s390_dfp_round_t rm;
2417 HReg f0, f4, r1; /* real registers used by PFPO */
2418
2419 f4 = make_fpr(4); /* source */
2420 f0 = make_fpr(0); /* destination */
2421 r1 = make_gpr(1); /* GPR #1 clobbered */
2422 h1 = s390_isel_dfp_expr(env, left);
2423 dst = newVRegF(env);
2424 rm = get_dfp_rounding_mode(env, irrm);
2425 /* operand --> f4 */
2426 addInstr(env, s390_insn_move(8, f4, h1));
2427 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2428 /* f0 --> destination */
2429 addInstr(env, s390_insn_move(8, dst, f0));
2430 return dst;
2431 }
2432
2433 convert_dfp128: {
2434 s390_dfp_round_t rm;
2435 HReg op_hi, op_lo;
2436 HReg f0, f4, f6, r1; /* real registers used by PFPO */
2437
2438 f4 = make_fpr(4); /* source */
2439 f6 = make_fpr(6); /* source */
2440 f0 = make_fpr(0); /* destination */
2441 r1 = make_gpr(1); /* GPR #1 clobbered */
2442 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2443 dst = newVRegF(env);
2444 rm = get_dfp_rounding_mode(env, irrm);
2445 /* operand --> (f4, f6) */
2446 addInstr(env, s390_insn_move(8, f4, op_hi));
2447 addInstr(env, s390_insn_move(8, f6, op_lo));
2448 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
2449 f4, f6, r1, rm));
2450 /* f0 --> destination */
2451 addInstr(env, s390_insn_move(8, dst, f0));
2452 return dst;
2453 }
2454
sewardj2019a972011-03-07 16:04:07 +00002455 default:
2456 goto irreducible;
2457
2458 case Iop_F128toF64:
2459 case Iop_F128toF32: {
floriana2039c52013-12-10 16:51:15 +00002460 HReg op_hi, op_lo, f12, f13, f14, f15;
florian125e20d2012-10-07 15:42:37 +00002461 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002462
florian9fcff4c2012-09-10 03:09:04 +00002463 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2464 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002465
florian9fcff4c2012-09-10 03:09:04 +00002466 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002467
floriana2039c52013-12-10 16:51:15 +00002468 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2469 f12 = make_fpr(12);
sewardj2019a972011-03-07 16:04:07 +00002470 f13 = make_fpr(13);
floriana2039c52013-12-10 16:51:15 +00002471 f14 = make_fpr(14);
sewardj2019a972011-03-07 16:04:07 +00002472 f15 = make_fpr(15);
2473
2474 /* operand --> (f13, f15) */
2475 addInstr(env, s390_insn_move(8, f13, op_hi));
2476 addInstr(env, s390_insn_move(8, f15, op_lo));
2477
floriana2039c52013-12-10 16:51:15 +00002478 /* result --> (f12, f14) */
2479
florian2c74d242012-09-12 19:38:42 +00002480 /* load-rounded has a rounding mode field when the floating point
2481 extension facility is installed. */
2482 if (s390_host_has_fpext) {
2483 rounding_mode = get_bfp_rounding_mode(env, irrm);
2484 } else {
2485 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002486 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002487 }
floriana2039c52013-12-10 16:51:15 +00002488
2489 addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14,
2490 f13, f15, rounding_mode));
2491 dst = newVRegF(env);
2492 addInstr(env, s390_insn_move(8, dst, f12));
2493
sewardj2019a972011-03-07 16:04:07 +00002494 return dst;
2495 }
2496 }
sewardj2019a972011-03-07 16:04:07 +00002497 }
2498
2499 /* --------- UNARY OP --------- */
2500 case Iex_Unop: {
2501 IROp op = expr->Iex.Unop.op;
2502 IRExpr *left = expr->Iex.Unop.arg;
2503 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002504 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002505 HReg h1, dst;
2506
2507 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2508 HReg dst_hi, dst_lo;
2509
2510 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2511 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2512 }
2513
florian4d71a082011-12-18 00:08:17 +00002514 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002515 dst = newVRegF(env);
2516 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2517 addInstr(env, s390_insn_move(size, dst, h1));
2518
2519 return dst;
2520 }
2521
2522 switch (op) {
2523 case Iop_NegF32:
2524 case Iop_NegF64:
2525 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002526 (left->Iex.Unop.op == Iop_AbsF32 ||
2527 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002528 bfpop = S390_BFP_NABS;
2529 else
2530 bfpop = S390_BFP_NEG;
2531 break;
2532
2533 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002534 case Iop_AbsF64:
2535 bfpop = S390_BFP_ABS;
2536 break;
2537
2538 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2539 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2540 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2541
2542 convert_float1:
2543 h1 = s390_isel_float_expr(env, left);
2544 goto convert1;
2545
2546 convert_int1:
2547 h1 = s390_isel_int_expr(env, left);
2548 goto convert1;
2549
2550 convert1:
2551 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002552 /* No rounding mode is needed for these conversions. Just stick
2553 one in. It won't be used later on. */
2554 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002555 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002556 return dst;
2557
sewardj2019a972011-03-07 16:04:07 +00002558 default:
2559 goto irreducible;
2560 }
2561
2562 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002563 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002564 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002565 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002566 return dst;
2567 }
2568
2569 default:
2570 goto irreducible;
2571 }
2572
2573 /* We get here if no pattern matched. */
2574 irreducible:
2575 ppIRExpr(expr);
2576 vpanic("s390_isel_float_expr: cannot reduce tree");
2577}
2578
2579
2580static HReg
2581s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2582{
2583 HReg dst = s390_isel_float_expr_wrk(env, expr);
2584
2585 /* Sanity checks ... */
2586 vassert(hregClass(dst) == HRcFlt64);
2587 vassert(hregIsVirtual(dst));
2588
2589 return dst;
2590}
2591
2592
2593/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002594/*--- ISEL: Decimal point expressions (128 bit) ---*/
2595/*---------------------------------------------------------*/
2596static void
2597s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2598 IRExpr *expr)
2599{
2600 IRType ty = typeOfIRExpr(env->type_env, expr);
2601
2602 vassert(ty == Ity_D128);
2603
2604 switch (expr->tag) {
2605 case Iex_RdTmp:
2606 /* Return the virtual registers that hold the temporary. */
2607 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2608 return;
2609
2610 /* --------- LOAD --------- */
2611 case Iex_Load: {
2612 IRExpr *addr_hi, *addr_lo;
2613 s390_amode *am_hi, *am_lo;
2614
2615 if (expr->Iex.Load.end != Iend_BE)
2616 goto irreducible;
2617
2618 addr_hi = expr->Iex.Load.addr;
2619 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2620
2621 am_hi = s390_isel_amode(env, addr_hi);
2622 am_lo = s390_isel_amode(env, addr_lo);
2623
2624 *dst_hi = newVRegF(env);
2625 *dst_lo = newVRegF(env);
2626 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2627 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2628 return;
2629 }
2630
2631 /* --------- GET --------- */
2632 case Iex_Get:
2633 /* This is not supported because loading 128-bit from the guest
2634 state is almost certainly wrong. Use get_dpr_pair instead. */
2635 vpanic("Iex_Get with D128 data");
2636
2637 /* --------- 4-ary OP --------- */
2638 case Iex_Qop:
2639 vpanic("Iex_Qop with D128 data");
2640
2641 /* --------- TERNARY OP --------- */
2642 case Iex_Triop: {
2643 IRTriop *triop = expr->Iex.Triop.details;
2644 IROp op = triop->op;
2645 IRExpr *irrm = triop->arg1;
2646 IRExpr *left = triop->arg2;
2647 IRExpr *right = triop->arg3;
2648 s390_dfp_round_t rounding_mode;
2649 s390_dfp_binop_t dfpop;
2650 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2651
floriane38f6412012-12-21 17:32:12 +00002652 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2653 (f12, f14) as op2 and (f13, f15) as destination) */
2654 f9 = make_fpr(9);
2655 f11 = make_fpr(11);
2656 f12 = make_fpr(12);
2657 f13 = make_fpr(13);
2658 f14 = make_fpr(14);
2659 f15 = make_fpr(15);
2660
floriane38f6412012-12-21 17:32:12 +00002661 switch (op) {
florian5c539732013-02-14 14:27:12 +00002662 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128;
2663 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128;
2664 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128;
2665 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128;
2666 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
2667
2668 evaluate_dfp128: {
2669 /* Process 1st operand */
2670 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
2671 /* 1st operand --> (f9, f11) */
2672 addInstr(env, s390_insn_move(8, f9, op1_hi));
2673 addInstr(env, s390_insn_move(8, f11, op1_lo));
2674
2675 /* Process 2nd operand */
2676 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2677 /* 2nd operand --> (f12, f14) */
2678 addInstr(env, s390_insn_move(8, f12, op2_hi));
2679 addInstr(env, s390_insn_move(8, f14, op2_lo));
2680
2681 /* DFP arithmetic ops take rounding mode only when fpext is
2682 installed. But, DFP quantize operation takes rm irrespective
2683 of fpext facility . */
floriand18287d2013-02-21 03:03:05 +00002684 if (s390_host_has_fpext || op == Iop_QuantizeD128) {
florian5c539732013-02-14 14:27:12 +00002685 rounding_mode = get_dfp_rounding_mode(env, irrm);
2686 } else {
2687 set_dfp_rounding_mode_in_fpc(env, irrm);
2688 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2689 }
2690 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2691 f12, f14, rounding_mode));
2692 /* Move result to virtual destination register */
2693 *dst_hi = newVRegF(env);
2694 *dst_lo = newVRegF(env);
2695 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2696 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2697 return;
2698 }
2699
2700 case Iop_SignificanceRoundD128: {
2701 /* Process 1st operand */
2702 HReg op1 = s390_isel_int_expr(env, left);
2703 /* Process 2nd operand */
2704 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2705 /* 2nd operand --> (f12, f14) */
2706 addInstr(env, s390_insn_move(8, f12, op2_hi));
2707 addInstr(env, s390_insn_move(8, f14, op2_lo));
2708
2709 rounding_mode = get_dfp_rounding_mode(env, irrm);
2710 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14,
2711 rounding_mode));
2712 /* Move result to virtual destination register */
2713 *dst_hi = newVRegF(env);
2714 *dst_lo = newVRegF(env);
2715 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2716 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2717 return;
2718 }
2719
floriane38f6412012-12-21 17:32:12 +00002720 default:
2721 goto irreducible;
2722 }
floriane38f6412012-12-21 17:32:12 +00002723 }
2724
2725 /* --------- BINARY OP --------- */
2726 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002727
floriane38f6412012-12-21 17:32:12 +00002728 switch (expr->Iex.Binop.op) {
2729 case Iop_D64HLtoD128:
2730 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2731 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2732 return;
2733
florian1b901d42013-01-01 22:19:24 +00002734 case Iop_ShlD128:
florian5c539732013-02-14 14:27:12 +00002735 case Iop_ShrD128:
2736 case Iop_InsertExpD128: {
florian1b901d42013-01-01 22:19:24 +00002737 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2738 s390_dfp_intop_t intop;
florian5c539732013-02-14 14:27:12 +00002739 IRExpr *dfp_op;
2740 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00002741
2742 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00002743 case Iop_ShlD128: /* (D128, I64) -> D128 */
2744 intop = S390_DFP_SHIFT_LEFT;
2745 dfp_op = expr->Iex.Binop.arg1;
2746 int_op = expr->Iex.Binop.arg2;
2747 break;
2748 case Iop_ShrD128: /* (D128, I64) -> D128 */
2749 intop = S390_DFP_SHIFT_RIGHT;
2750 dfp_op = expr->Iex.Binop.arg1;
2751 int_op = expr->Iex.Binop.arg2;
2752 break;
2753 case Iop_InsertExpD128: /* (I64, D128) -> D128 */
2754 intop = S390_DFP_INSERT_EXP;
2755 int_op = expr->Iex.Binop.arg1;
2756 dfp_op = expr->Iex.Binop.arg2;
2757 break;
florian1b901d42013-01-01 22:19:24 +00002758 default: goto irreducible;
2759 }
2760
2761 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2762 f9 = make_fpr(9); /* 128 bit dfp operand */
2763 f11 = make_fpr(11);
2764
2765 f13 = make_fpr(13); /* 128 bit dfp destination */
2766 f15 = make_fpr(15);
2767
florian5c539732013-02-14 14:27:12 +00002768 /* Process dfp operand */
2769 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
2770 /* op1 -> (f9,f11) */
florian1b901d42013-01-01 22:19:24 +00002771 addInstr(env, s390_insn_move(8, f9, op1_hi));
2772 addInstr(env, s390_insn_move(8, f11, op1_lo));
2773
florian5c539732013-02-14 14:27:12 +00002774 op2 = s390_isel_int_expr(env, int_op); /* int operand */
florian1b901d42013-01-01 22:19:24 +00002775
2776 addInstr(env,
2777 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2778
2779 /* Move result to virtual destination register */
2780 *dst_hi = newVRegF(env);
2781 *dst_lo = newVRegF(env);
2782 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2783 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2784 return;
2785 }
2786
florian7ab421d2013-06-17 21:03:56 +00002787 case Iop_F32toD128:
florian78d5ef72013-05-11 15:02:58 +00002788 case Iop_F64toD128: {
2789 IRExpr *irrm;
2790 IRExpr *left;
2791 s390_dfp_round_t rm;
2792 HReg h1; /* virtual reg. to hold source */
2793 HReg f0, f2, f4, r1; /* real registers used by PFPO */
florian7ab421d2013-06-17 21:03:56 +00002794 s390_fp_conv_t fpconv;
2795
2796 switch (expr->Iex.Binop.op) {
2797 case Iop_F32toD128: /* (D128, I64) -> D128 */
2798 fpconv = S390_FP_F32_TO_D128;
2799 break;
2800 case Iop_F64toD128: /* (D128, I64) -> D128 */
2801 fpconv = S390_FP_F64_TO_D128;
2802 break;
2803 default: goto irreducible;
2804 }
florian78d5ef72013-05-11 15:02:58 +00002805
2806 f4 = make_fpr(4); /* source */
2807 f0 = make_fpr(0); /* destination */
2808 f2 = make_fpr(2); /* destination */
2809 r1 = make_gpr(1); /* GPR #1 clobbered */
2810 irrm = expr->Iex.Binop.arg1;
2811 left = expr->Iex.Binop.arg2;
2812 rm = get_dfp_rounding_mode(env, irrm);
2813 h1 = s390_isel_float_expr(env, left);
2814 addInstr(env, s390_insn_move(8, f4, h1));
florian7ab421d2013-06-17 21:03:56 +00002815 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
florian78d5ef72013-05-11 15:02:58 +00002816 f4, INVALID_HREG, r1, rm));
2817 /* (f0, f2) --> destination */
2818 *dst_hi = newVRegF(env);
2819 *dst_lo = newVRegF(env);
2820 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2821 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2822
2823 return;
2824 }
2825
2826 case Iop_F128toD128: {
2827 IRExpr *irrm;
2828 IRExpr *left;
2829 s390_dfp_round_t rm;
2830 HReg op_hi, op_lo;
2831 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2832
2833 f4 = make_fpr(4); /* source */
2834 f6 = make_fpr(6); /* source */
2835 f0 = make_fpr(0); /* destination */
2836 f2 = make_fpr(2); /* destination */
2837 r1 = make_gpr(1); /* GPR #1 clobbered */
2838
2839 irrm = expr->Iex.Binop.arg1;
2840 left = expr->Iex.Binop.arg2;
2841 rm = get_dfp_rounding_mode(env, irrm);
2842 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2843 /* operand --> (f4, f6) */
2844 addInstr(env, s390_insn_move(8, f4, op_hi));
2845 addInstr(env, s390_insn_move(8, f6, op_lo));
2846 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2,
2847 f4, f6, r1, rm));
2848 /* (f0, f2) --> destination */
2849 *dst_hi = newVRegF(env);
2850 *dst_lo = newVRegF(env);
2851 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2852 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2853
2854 return;
2855 }
2856
floriane38f6412012-12-21 17:32:12 +00002857 default:
2858 goto irreducible;
2859 }
2860 }
2861
2862 /* --------- UNARY OP --------- */
2863 case Iex_Unop: {
2864 IRExpr *left = expr->Iex.Unop.arg;
2865 s390_dfp_conv_t conv;
floriane38f6412012-12-21 17:32:12 +00002866 HReg op, f12, f14;
2867
floriana887acd2013-02-08 23:32:54 +00002868 /* We use non-virtual registers as pairs (f12, f14)) */
floriane38f6412012-12-21 17:32:12 +00002869 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00002870 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00002871
2872 switch (expr->Iex.Unop.op) {
2873 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002874 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
floriana887acd2013-02-08 23:32:54 +00002875 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002876 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2877 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002878 default:
2879 goto irreducible;
2880 }
2881
2882 convert_dfp:
2883 op = s390_isel_dfp_expr(env, left);
2884 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2885 goto move_dst;
2886
florian5f034622013-01-13 02:29:05 +00002887 convert_int:
2888 op = s390_isel_int_expr(env, left);
2889 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2890 goto move_dst;
2891
floriane38f6412012-12-21 17:32:12 +00002892 move_dst:
2893 /* Move result to virtual destination registers */
2894 *dst_hi = newVRegF(env);
2895 *dst_lo = newVRegF(env);
2896 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2897 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2898 return;
2899 }
2900
2901 default:
2902 goto irreducible;
2903 }
2904
2905 /* We get here if no pattern matched. */
2906 irreducible:
2907 ppIRExpr(expr);
2908 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2909
2910}
2911
2912
2913/* Compute a 128-bit value into two 64-bit registers. These may be either
2914 real or virtual regs; in any case they must not be changed by subsequent
2915 code emitted by the caller. */
2916static void
2917s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2918{
2919 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2920
2921 /* Sanity checks ... */
2922 vassert(hregIsVirtual(*dst_hi));
2923 vassert(hregIsVirtual(*dst_lo));
2924 vassert(hregClass(*dst_hi) == HRcFlt64);
2925 vassert(hregClass(*dst_lo) == HRcFlt64);
2926}
2927
2928
2929/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002930/*--- ISEL: Decimal point expressions (64 bit) ---*/
2931/*---------------------------------------------------------*/
2932
2933static HReg
2934s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2935{
2936 IRType ty = typeOfIRExpr(env->type_env, expr);
2937 UChar size;
2938
floriane38f6412012-12-21 17:32:12 +00002939 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002940
2941 size = sizeofIRType(ty);
2942
2943 switch (expr->tag) {
2944 case Iex_RdTmp:
2945 /* Return the virtual register that holds the temporary. */
2946 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2947
2948 /* --------- LOAD --------- */
2949 case Iex_Load: {
2950 HReg dst = newVRegF(env);
2951 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2952
2953 if (expr->Iex.Load.end != Iend_BE)
2954 goto irreducible;
2955
2956 addInstr(env, s390_insn_load(size, dst, am));
2957
2958 return dst;
2959 }
2960
2961 /* --------- GET --------- */
2962 case Iex_Get: {
2963 HReg dst = newVRegF(env);
2964 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2965
2966 addInstr(env, s390_insn_load(size, dst, am));
2967
2968 return dst;
2969 }
2970
floriane38f6412012-12-21 17:32:12 +00002971 /* --------- BINARY OP --------- */
2972 case Iex_Binop: {
2973 IROp op = expr->Iex.Binop.op;
2974 IRExpr *irrm = expr->Iex.Binop.arg1;
2975 IRExpr *left = expr->Iex.Binop.arg2;
2976 HReg h1, dst;
2977 s390_dfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002978 s390_fp_conv_t fpconv;
floriane38f6412012-12-21 17:32:12 +00002979
2980 switch (op) {
2981 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
floriana887acd2013-02-08 23:32:54 +00002982 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002983 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
florian7ab421d2013-06-17 21:03:56 +00002984 case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp;
2985 case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp;
2986 case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp;
florian78d5ef72013-05-11 15:02:58 +00002987 case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
florian7ab421d2013-06-17 21:03:56 +00002988 case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128;
2989 case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128;
floriane38f6412012-12-21 17:32:12 +00002990
2991 convert_dfp:
2992 h1 = s390_isel_dfp_expr(env, left);
2993 goto convert;
2994
florian5f034622013-01-13 02:29:05 +00002995 convert_int:
2996 h1 = s390_isel_int_expr(env, left);
2997 goto convert;
2998
floriane38f6412012-12-21 17:32:12 +00002999 convert: {
3000 s390_dfp_round_t rounding_mode;
3001 /* convert-from-fixed and load-rounded have a rounding mode field
3002 when the floating point extension facility is installed. */
3003 dst = newVRegF(env);
3004 if (s390_host_has_fpext) {
3005 rounding_mode = get_dfp_rounding_mode(env, irrm);
3006 } else {
3007 set_dfp_rounding_mode_in_fpc(env, irrm);
3008 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3009 }
3010 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3011 rounding_mode));
3012 return dst;
3013 }
floriane38f6412012-12-21 17:32:12 +00003014
florian78d5ef72013-05-11 15:02:58 +00003015 convert_bfp: {
3016 s390_dfp_round_t rm;
3017 HReg f0, f4, r1; /* real registers used by PFPO */
3018
3019 f4 = make_fpr(4); /* source */
3020 f0 = make_fpr(0); /* destination */
3021 r1 = make_gpr(1); /* GPR #1 clobbered */
3022 h1 = s390_isel_float_expr(env, left);
3023 dst = newVRegF(env);
3024 rm = get_dfp_rounding_mode(env, irrm);
3025 /* operand --> f4 */
3026 addInstr(env, s390_insn_move(8, f4, h1));
3027 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
3028 /* f0 --> destination */
3029 addInstr(env, s390_insn_move(8, dst, f0));
3030 return dst;
3031 }
3032
florian7ab421d2013-06-17 21:03:56 +00003033 convert_bfp128: {
3034 s390_dfp_round_t rm;
3035 HReg op_hi, op_lo;
3036 HReg f0, f4, f6, r1; /* real registers used by PFPO */
3037
3038 f4 = make_fpr(4); /* source */
3039 f6 = make_fpr(6); /* source */
3040 f0 = make_fpr(0); /* destination */
3041 r1 = make_gpr(1); /* GPR #1 clobbered */
3042 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
3043 dst = newVRegF(env);
3044 rm = get_dfp_rounding_mode(env, irrm);
3045 /* operand --> (f4, f6) */
3046 addInstr(env, s390_insn_move(8, f4, op_hi));
3047 addInstr(env, s390_insn_move(8, f6, op_lo));
3048 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
3049 f4, f6, r1, rm));
3050 /* f0 --> destination */
3051 addInstr(env, s390_insn_move(8, dst, f0));
3052 return dst;
3053 }
3054
floriane38f6412012-12-21 17:32:12 +00003055 case Iop_D128toD64: {
floriana2039c52013-12-10 16:51:15 +00003056 HReg op_hi, op_lo, f12, f13, f14, f15;
floriane38f6412012-12-21 17:32:12 +00003057 s390_dfp_round_t rounding_mode;
3058
3059 conv = S390_DFP_D128_TO_D64;
3060
3061 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
3062
floriana2039c52013-12-10 16:51:15 +00003063 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */
3064 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00003065 f13 = make_fpr(13);
floriana2039c52013-12-10 16:51:15 +00003066 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00003067 f15 = make_fpr(15);
3068
3069 /* operand --> (f13, f15) */
3070 addInstr(env, s390_insn_move(8, f13, op_hi));
3071 addInstr(env, s390_insn_move(8, f15, op_lo));
3072
floriana2039c52013-12-10 16:51:15 +00003073 /* result --> (f12, f14) */
3074
floriane38f6412012-12-21 17:32:12 +00003075 /* load-rounded has a rounding mode field when the floating point
3076 extension facility is installed. */
3077 if (s390_host_has_fpext) {
3078 rounding_mode = get_dfp_rounding_mode(env, irrm);
3079 } else {
3080 set_dfp_rounding_mode_in_fpc(env, irrm);
3081 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3082 }
floriana2039c52013-12-10 16:51:15 +00003083 addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14,
3084 f13, f15, rounding_mode));
3085 dst = newVRegF(env);
3086 addInstr(env, s390_insn_move(8, dst, f12));
3087
floriane38f6412012-12-21 17:32:12 +00003088 return dst;
3089 }
3090
florian1b901d42013-01-01 22:19:24 +00003091 case Iop_ShlD64:
florian5c539732013-02-14 14:27:12 +00003092 case Iop_ShrD64:
3093 case Iop_InsertExpD64: {
florian1b901d42013-01-01 22:19:24 +00003094 HReg op2;
3095 HReg op3;
florian5c539732013-02-14 14:27:12 +00003096 IRExpr *dfp_op;
3097 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00003098 s390_dfp_intop_t intop;
florian1b901d42013-01-01 22:19:24 +00003099
3100 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00003101 case Iop_ShlD64: /* (D64, I64) -> D64 */
3102 intop = S390_DFP_SHIFT_LEFT;
3103 dfp_op = expr->Iex.Binop.arg1;
3104 int_op = expr->Iex.Binop.arg2;
3105 break;
3106 case Iop_ShrD64: /* (D64, I64) -> D64 */
3107 intop = S390_DFP_SHIFT_RIGHT;
3108 dfp_op = expr->Iex.Binop.arg1;
3109 int_op = expr->Iex.Binop.arg2;
3110 break;
3111 case Iop_InsertExpD64: /* (I64, D64) -> D64 */
3112 intop = S390_DFP_INSERT_EXP;
3113 int_op = expr->Iex.Binop.arg1;
3114 dfp_op = expr->Iex.Binop.arg2;
3115 break;
florian1b901d42013-01-01 22:19:24 +00003116 default: goto irreducible;
3117 }
3118
florian5c539732013-02-14 14:27:12 +00003119 op2 = s390_isel_int_expr(env, int_op);
3120 op3 = s390_isel_dfp_expr(env, dfp_op);
florian1b901d42013-01-01 22:19:24 +00003121 dst = newVRegF(env);
3122
3123 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
3124 return dst;
3125 }
3126
3127 default:
3128 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00003129 }
3130 }
3131
3132 /* --------- UNARY OP --------- */
3133 case Iex_Unop: {
3134 IROp op = expr->Iex.Unop.op;
3135 IRExpr *left = expr->Iex.Unop.arg;
3136 s390_dfp_conv_t conv;
3137 HReg h1, dst;
3138
3139 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
3140 HReg dst_hi, dst_lo;
3141
3142 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
3143 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
3144 }
3145
3146 if (op == Iop_ReinterpI64asD64) {
3147 dst = newVRegF(env);
3148 h1 = s390_isel_int_expr(env, left); /* Process the operand */
3149 addInstr(env, s390_insn_move(size, dst, h1));
3150
3151 return dst;
3152 }
3153
3154 switch (op) {
3155 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00003156 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
3157 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00003158
3159 convert_dfp1:
3160 h1 = s390_isel_dfp_expr(env, left);
3161 goto convert1;
3162
florian5f034622013-01-13 02:29:05 +00003163 convert_int1:
3164 h1 = s390_isel_int_expr(env, left);
3165 goto convert1;
3166
floriane38f6412012-12-21 17:32:12 +00003167 convert1:
3168 dst = newVRegF(env);
3169 /* No rounding mode is needed for these conversions. Just stick
3170 one in. It won't be used later on. */
3171 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3172 S390_DFP_ROUND_NEAREST_EVEN_4));
3173 return dst;
3174
3175 default:
3176 goto irreducible;
3177 }
3178 }
3179
florian12390202012-11-10 22:34:14 +00003180 /* --------- TERNARY OP --------- */
3181 case Iex_Triop: {
3182 IRTriop *triop = expr->Iex.Triop.details;
3183 IROp op = triop->op;
3184 IRExpr *irrm = triop->arg1;
3185 IRExpr *left = triop->arg2;
3186 IRExpr *right = triop->arg3;
3187 s390_dfp_round_t rounding_mode;
3188 s390_dfp_binop_t dfpop;
3189 HReg op2, op3, dst;
3190
florian12390202012-11-10 22:34:14 +00003191 switch (op) {
florian5c539732013-02-14 14:27:12 +00003192 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp;
3193 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp;
3194 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp;
3195 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp;
3196 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
3197
3198 evaluate_dfp: {
3199 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
3200 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3201 dst = newVRegF(env);
3202 /* DFP arithmetic ops take rounding mode only when fpext is
3203 installed. But, DFP quantize operation takes rm irrespective
3204 of fpext facility . */
3205 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
3206 rounding_mode = get_dfp_rounding_mode(env, irrm);
3207 } else {
3208 set_dfp_rounding_mode_in_fpc(env, irrm);
3209 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3210 }
3211 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3,
3212 rounding_mode));
3213 return dst;
3214 }
3215
3216 case Iop_SignificanceRoundD64:
3217 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */
3218 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3219 dst = newVRegF(env);
3220 rounding_mode = get_dfp_rounding_mode(env, irrm);
3221 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3,
3222 rounding_mode));
3223 return dst;
3224
florian12390202012-11-10 22:34:14 +00003225 default:
3226 goto irreducible;
3227 }
florian12390202012-11-10 22:34:14 +00003228 }
3229
3230 default:
3231 goto irreducible;
3232 }
3233
3234 /* We get here if no pattern matched. */
3235 irreducible:
3236 ppIRExpr(expr);
3237 vpanic("s390_isel_dfp_expr: cannot reduce tree");
3238}
3239
3240static HReg
3241s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
3242{
3243 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
3244
3245 /* Sanity checks ... */
3246 vassert(hregClass(dst) == HRcFlt64);
3247 vassert(hregIsVirtual(dst));
3248
3249 return dst;
3250}
3251
3252
3253/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00003254/*--- ISEL: Condition Code ---*/
3255/*---------------------------------------------------------*/
3256
3257/* This function handles all operators that produce a 1-bit result */
3258static s390_cc_t
3259s390_isel_cc(ISelEnv *env, IRExpr *cond)
3260{
3261 UChar size;
3262
3263 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
3264
3265 /* Constant: either 1 or 0 */
3266 if (cond->tag == Iex_Const) {
3267 vassert(cond->Iex.Const.con->tag == Ico_U1);
3268 vassert(cond->Iex.Const.con->Ico.U1 == True
3269 || cond->Iex.Const.con->Ico.U1 == False);
3270
3271 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
3272 }
3273
3274 /* Variable: values are 1 or 0 */
3275 if (cond->tag == Iex_RdTmp) {
3276 IRTemp tmp = cond->Iex.RdTmp.tmp;
3277 HReg reg = lookupIRTemp(env, tmp);
3278
3279 /* Load-and-test does not modify REG; so this is OK. */
3280 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
3281 size = 4;
3282 else
3283 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
3284 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
3285 return S390_CC_NE;
3286 }
3287
3288 /* Unary operators */
3289 if (cond->tag == Iex_Unop) {
3290 IRExpr *arg = cond->Iex.Unop.arg;
3291
3292 switch (cond->Iex.Unop.op) {
3293 case Iop_Not1: /* Not1(cond) */
3294 /* Generate code for EXPR, and negate the test condition */
3295 return s390_cc_invert(s390_isel_cc(env, arg));
3296
3297 /* Iop_32/64to1 select the LSB from their operand */
3298 case Iop_32to1:
3299 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00003300 HReg dst = newVRegI(env);
3301 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00003302
3303 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3304
florianf366a802012-08-03 00:42:18 +00003305 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00003306 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
3307 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
3308 return S390_CC_NE;
3309 }
3310
3311 case Iop_CmpNEZ8:
3312 case Iop_CmpNEZ16: {
3313 s390_opnd_RMI src;
3314 s390_unop_t op;
3315 HReg dst;
3316
3317 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
3318 : S390_ZERO_EXTEND_16;
3319 dst = newVRegI(env);
3320 src = s390_isel_int_expr_RMI(env, arg);
3321 addInstr(env, s390_insn_unop(4, op, dst, src));
3322 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
3323 return S390_CC_NE;
3324 }
3325
3326 case Iop_CmpNEZ32:
3327 case Iop_CmpNEZ64: {
3328 s390_opnd_RMI src;
3329
3330 src = s390_isel_int_expr_RMI(env, arg);
3331 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3332 addInstr(env, s390_insn_test(size, src));
3333 return S390_CC_NE;
3334 }
3335
3336 default:
3337 goto fail;
3338 }
3339 }
3340
3341 /* Binary operators */
3342 if (cond->tag == Iex_Binop) {
3343 IRExpr *arg1 = cond->Iex.Binop.arg1;
3344 IRExpr *arg2 = cond->Iex.Binop.arg2;
3345 HReg reg1, reg2;
3346
3347 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
3348
3349 switch (cond->Iex.Binop.op) {
3350 s390_unop_t op;
3351 s390_cc_t result;
3352
3353 case Iop_CmpEQ8:
3354 case Iop_CasCmpEQ8:
3355 op = S390_ZERO_EXTEND_8;
3356 result = S390_CC_E;
3357 goto do_compare_ze;
3358
3359 case Iop_CmpNE8:
3360 case Iop_CasCmpNE8:
3361 op = S390_ZERO_EXTEND_8;
3362 result = S390_CC_NE;
3363 goto do_compare_ze;
3364
3365 case Iop_CmpEQ16:
3366 case Iop_CasCmpEQ16:
3367 op = S390_ZERO_EXTEND_16;
3368 result = S390_CC_E;
3369 goto do_compare_ze;
3370
3371 case Iop_CmpNE16:
3372 case Iop_CasCmpNE16:
3373 op = S390_ZERO_EXTEND_16;
3374 result = S390_CC_NE;
3375 goto do_compare_ze;
3376
3377 do_compare_ze: {
3378 s390_opnd_RMI op1, op2;
3379
3380 op1 = s390_isel_int_expr_RMI(env, arg1);
3381 reg1 = newVRegI(env);
3382 addInstr(env, s390_insn_unop(4, op, reg1, op1));
3383
3384 op2 = s390_isel_int_expr_RMI(env, arg2);
3385 reg2 = newVRegI(env);
3386 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
3387
3388 op2 = s390_opnd_reg(reg2);
3389 addInstr(env, s390_insn_compare(4, reg1, op2, False));
3390
3391 return result;
3392 }
3393
3394 case Iop_CmpEQ32:
3395 case Iop_CmpEQ64:
3396 case Iop_CasCmpEQ32:
3397 case Iop_CasCmpEQ64:
3398 result = S390_CC_E;
3399 goto do_compare;
3400
3401 case Iop_CmpNE32:
3402 case Iop_CmpNE64:
3403 case Iop_CasCmpNE32:
3404 case Iop_CasCmpNE64:
3405 result = S390_CC_NE;
3406 goto do_compare;
3407
3408 do_compare: {
3409 HReg op1;
3410 s390_opnd_RMI op2;
3411
3412 order_commutative_operands(arg1, arg2);
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, False));
3418
3419 return result;
3420 }
3421
3422 case Iop_CmpLT32S:
3423 case Iop_CmpLE32S:
3424 case Iop_CmpLT64S:
3425 case Iop_CmpLE64S: {
3426 HReg op1;
3427 s390_opnd_RMI op2;
3428
3429 op1 = s390_isel_int_expr(env, arg1);
3430 op2 = s390_isel_int_expr_RMI(env, arg2);
3431
3432 addInstr(env, s390_insn_compare(size, op1, op2, True));
3433
3434 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3435 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3436 }
3437
3438 case Iop_CmpLT32U:
3439 case Iop_CmpLE32U:
3440 case Iop_CmpLT64U:
3441 case Iop_CmpLE64U: {
3442 HReg op1;
3443 s390_opnd_RMI op2;
3444
3445 op1 = s390_isel_int_expr(env, arg1);
3446 op2 = s390_isel_int_expr_RMI(env, arg2);
3447
3448 addInstr(env, s390_insn_compare(size, op1, op2, False));
3449
3450 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3451 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3452 }
3453
3454 default:
3455 goto fail;
3456 }
3457 }
3458
3459 fail:
3460 ppIRExpr(cond);
3461 vpanic("s390_isel_cc: unexpected operator");
3462}
3463
3464
3465/*---------------------------------------------------------*/
3466/*--- ISEL: Statements ---*/
3467/*---------------------------------------------------------*/
3468
3469static void
3470s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3471{
3472 if (vex_traceflags & VEX_TRACE_VCODE) {
3473 vex_printf("\n -- ");
3474 ppIRStmt(stmt);
3475 vex_printf("\n");
3476 }
3477
3478 switch (stmt->tag) {
3479
3480 /* --------- STORE --------- */
3481 case Ist_Store: {
3482 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3483 s390_amode *am;
3484 HReg src;
3485
3486 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3487
3488 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3489
3490 switch (tyd) {
3491 case Ity_I8:
3492 case Ity_I16:
3493 case Ity_I32:
3494 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003495 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003496 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003497 stmt->Ist.Store.data->tag == Iex_Const) {
3498 ULong value =
3499 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3500 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003501 return;
3502 }
floriancec3a8a2013-02-02 00:16:58 +00003503 /* Check whether we can use a memcpy here. Currently, the restriction
3504 is that both amodes need to be B12, so MVC can be emitted.
3505 We do not consider a store whose data expression is a load because
3506 we don't want to deal with overlapping locations. */
3507 /* store(get) never overlaps*/
3508 if (am->tag == S390_AMODE_B12 &&
3509 stmt->Ist.Store.data->tag == Iex_Get) {
3510 UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
3511 s390_amode *from = s390_amode_for_guest_state(offset);
3512 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
3513 return;
3514 }
3515 /* General case: compile data into a register */
sewardj2019a972011-03-07 16:04:07 +00003516 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3517 break;
3518
3519 case Ity_F32:
3520 case Ity_F64:
3521 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3522 break;
3523
florianeb981ae2012-12-21 18:55:03 +00003524 case Ity_D32:
3525 case Ity_D64:
3526 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3527 break;
3528
sewardj2019a972011-03-07 16:04:07 +00003529 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003530 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003531 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003532 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003533
3534 default:
3535 goto stmt_fail;
3536 }
3537
3538 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3539 return;
3540 }
3541
3542 /* --------- PUT --------- */
3543 case Ist_Put: {
3544 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3545 HReg src;
3546 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003547 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003548
florianad43b3a2012-02-20 15:01:14 +00003549 /* Detect updates to certain guest registers. We track the contents
3550 of those registers as long as they contain constants. If the new
3551 constant is either zero or in the 8-bit neighbourhood of the
3552 current value we can use a memory-to-memory insn to do the update. */
3553
3554 Int offset = stmt->Ist.Put.offset;
3555
3556 /* Check necessary conditions:
3557 (1) must be one of the registers we care about
3558 (2) assigned value must be a constant */
3559 Int guest_reg = get_guest_reg(offset);
3560
3561 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3562
florianad43b3a2012-02-20 15:01:14 +00003563 if (stmt->Ist.Put.data->tag != Iex_Const) {
3564 /* Invalidate guest register contents */
3565 env->old_value_valid[guest_reg] = False;
3566 goto not_special;
3567 }
3568
cborntraaf7ad282012-08-08 14:11:33 +00003569 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3570 if (tyd != Ity_I64)
3571 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003572
cborntraaf7ad282012-08-08 14:11:33 +00003573 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003574
3575 old_value = env->old_value[guest_reg];
3576 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3577 env->old_value[guest_reg] = new_value;
3578
3579 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3580 env->old_value_valid[guest_reg] = True;
3581
3582 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003583 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003584 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003585 return;
florianad43b3a2012-02-20 15:01:14 +00003586 }
3587
florianad43b3a2012-02-20 15:01:14 +00003588 if (old_value_is_valid == False) goto not_special;
3589
3590 /* If the new value is in the neighbourhood of the old value
3591 we can use a memory-to-memory insn */
3592 difference = new_value - old_value;
3593
3594 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003595 am = s390_amode_for_guest_state(offset);
3596 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003597 (difference & 0xFF), new_value));
3598 return;
3599 }
3600
florianb93348d2012-12-27 00:59:43 +00003601 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003602 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003603 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003604 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003605 return;
3606 }
3607
3608 /* No special case applies... fall through */
3609
3610 not_special:
florianb93348d2012-12-27 00:59:43 +00003611 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003612
3613 switch (tyd) {
3614 case Ity_I8:
3615 case Ity_I16:
3616 case Ity_I32:
3617 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003618 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003619 stmt->Ist.Put.data->tag == Iex_Const) {
3620 ULong value =
3621 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3622 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003623 return;
3624 }
floriancec3a8a2013-02-02 00:16:58 +00003625 /* Check whether we can use a memcpy here. Currently, the restriction
3626 is that both amodes need to be B12, so MVC can be emitted. */
3627 /* put(load) never overlaps */
3628 if (am->tag == S390_AMODE_B12 &&
3629 stmt->Ist.Put.data->tag == Iex_Load) {
3630 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
3631 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
3632 s390_amode *from = s390_isel_amode(env, data);
3633 UInt size = sizeofIRType(tyd);
3634
3635 if (from->tag == S390_AMODE_B12) {
3636 /* Source can be compiled into a B12 amode. */
3637 addInstr(env, s390_insn_memcpy(size, am, from));
3638 return;
3639 }
3640
3641 src = newVRegI(env);
3642 addInstr(env, s390_insn_load(size, src, from));
3643 break;
3644 }
3645 /* put(get) */
3646 if (am->tag == S390_AMODE_B12 &&
3647 stmt->Ist.Put.data->tag == Iex_Get) {
3648 UInt put_offset = am->d;
3649 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
3650 UInt size = sizeofIRType(tyd);
3651 /* don't memcpy in case of overlap */
3652 if (put_offset + size <= get_offset ||
3653 get_offset + size <= put_offset) {
3654 s390_amode *from = s390_amode_for_guest_state(get_offset);
3655 addInstr(env, s390_insn_memcpy(size, am, from));
3656 return;
3657 }
3658 goto no_memcpy_put;
3659 }
3660 /* General case: compile data into a register */
3661no_memcpy_put:
sewardj2019a972011-03-07 16:04:07 +00003662 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3663 break;
3664
3665 case Ity_F32:
3666 case Ity_F64:
3667 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3668 break;
3669
3670 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003671 case Ity_D128:
3672 /* Does not occur. See function put_(f|d)pr_pair. */
3673 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003674
floriane38f6412012-12-21 17:32:12 +00003675 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003676 case Ity_D64:
3677 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3678 break;
3679
sewardj2019a972011-03-07 16:04:07 +00003680 default:
3681 goto stmt_fail;
3682 }
3683
3684 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3685 return;
3686 }
3687
3688 /* --------- TMP --------- */
3689 case Ist_WrTmp: {
3690 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3691 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3692 HReg src, dst;
3693
3694 switch (tyd) {
3695 case Ity_I128: {
3696 HReg dst_hi, dst_lo, res_hi, res_lo;
3697
3698 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3699 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3700
3701 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3702 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3703 return;
3704 }
3705
3706 case Ity_I8:
3707 case Ity_I16:
3708 case Ity_I32:
3709 case Ity_I64:
3710 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3711 dst = lookupIRTemp(env, tmp);
3712 break;
3713
3714 case Ity_I1: {
3715 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3716 dst = lookupIRTemp(env, tmp);
3717 addInstr(env, s390_insn_cc2bool(dst, cond));
3718 return;
3719 }
3720
3721 case Ity_F32:
3722 case Ity_F64:
3723 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3724 dst = lookupIRTemp(env, tmp);
3725 break;
3726
3727 case Ity_F128: {
3728 HReg dst_hi, dst_lo, res_hi, res_lo;
3729
3730 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3731 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3732
3733 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3734 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3735 return;
3736 }
3737
floriane38f6412012-12-21 17:32:12 +00003738 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003739 case Ity_D64:
3740 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3741 dst = lookupIRTemp(env, tmp);
3742 break;
3743
floriane38f6412012-12-21 17:32:12 +00003744 case Ity_D128: {
3745 HReg dst_hi, dst_lo, res_hi, res_lo;
3746
3747 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3748 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3749
3750 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3751 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3752 return;
3753 }
3754
sewardj2019a972011-03-07 16:04:07 +00003755 default:
3756 goto stmt_fail;
3757 }
3758
3759 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3760 return;
3761 }
3762
3763 /* --------- Call to DIRTY helper --------- */
3764 case Ist_Dirty: {
3765 IRType retty;
3766 IRDirty* d = stmt->Ist.Dirty.details;
florian01ed6e72012-05-27 16:52:43 +00003767 HReg dst;
sewardj74142b82013-08-08 10:28:59 +00003768 RetLoc rloc = mk_RetLoc_INVALID();
3769 UInt addToSp = 0;
florianad43b3a2012-02-20 15:01:14 +00003770 Int i;
3771
3772 /* Invalidate tracked values of those guest state registers that are
3773 modified by this helper. */
3774 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003775 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3776 descriptors in guest state effect descriptions. Hence: */
3777 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003778 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3779 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3780 if (guest_reg != GUEST_UNKNOWN)
3781 env->old_value_valid[guest_reg] = False;
3782 }
3783 }
sewardj2019a972011-03-07 16:04:07 +00003784
florian01ed6e72012-05-27 16:52:43 +00003785 if (d->tmp == IRTemp_INVALID) {
3786 /* No return value. */
sewardj74142b82013-08-08 10:28:59 +00003787 retty = Ity_INVALID;
3788 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3789 d->args);
3790 vassert(is_sane_RetLoc(rloc));
3791 vassert(rloc.pri == RLPri_None);
3792 vassert(addToSp == 0);
3793
sewardj2019a972011-03-07 16:04:07 +00003794 return;
florian01ed6e72012-05-27 16:52:43 +00003795 }
sewardj2019a972011-03-07 16:04:07 +00003796
3797 retty = typeOfIRTemp(env->type_env, d->tmp);
3798 if (retty == Ity_I64 || retty == Ity_I32
3799 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003800 /* Move the returned value to the destination register */
sewardj74142b82013-08-08 10:28:59 +00003801 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
3802
florian01ed6e72012-05-27 16:52:43 +00003803 dst = lookupIRTemp(env, d->tmp);
sewardj74142b82013-08-08 10:28:59 +00003804 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3805 d->args);
3806 vassert(is_sane_RetLoc(rloc));
3807 vassert(rloc.pri == RLPri_Int);
3808 vassert(addToSp == 0);
3809 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
3810
sewardj2019a972011-03-07 16:04:07 +00003811 return;
3812 }
sewardj74142b82013-08-08 10:28:59 +00003813 if (retty == Ity_V128) {
3814 /* we do not handle vector types yet */
3815 vassert(0);
3816 HReg sp = make_gpr(S390_REGNO_STACK_POINTER);
3817 s390_amode *am;
3818
3819 dst = lookupIRTemp(env, d->tmp);
3820 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3821 d->args);
3822 vassert(is_sane_RetLoc(rloc));
3823 vassert(rloc.pri == RLPri_V128SpRel);
3824 vassert(addToSp >= 16);
3825
3826 /* rloc.spOff should be zero for s390 */
3827 /* cannot use fits_unsigned_12bit(rloc.spOff), so doing
3828 it explicitly */
3829 vassert((rloc.spOff & 0xFFF) == rloc.spOff);
3830 am = s390_amode_b12(rloc.spOff, sp);
3831 // JRS 2013-Aug-08: is this correct? Looks like we're loading
3832 // only 64 bits from memory, when in fact we should be loading 128.
3833 addInstr(env, s390_insn_load(8, dst, am));
3834 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, sp,
3835 s390_opnd_imm(addToSp)));
3836 return;
3837 } else {/* if (retty == Ity_V256) */
3838 /* we do not handle vector types yet */
3839 vassert(0);
3840 }
sewardj2019a972011-03-07 16:04:07 +00003841 break;
3842 }
3843
3844 case Ist_CAS:
3845 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3846 IRCAS *cas = stmt->Ist.CAS.details;
3847 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3848 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3849 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3850 HReg old = lookupIRTemp(env, cas->oldLo);
3851
3852 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3853 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3854 } else {
3855 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3856 }
3857 return;
3858 } else {
florian448cbba2012-06-06 02:26:01 +00003859 IRCAS *cas = stmt->Ist.CAS.details;
3860 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3861 HReg r8, r9, r10, r11, r1;
3862 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3863 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3864 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3865 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3866 HReg old_low = lookupIRTemp(env, cas->oldLo);
3867 HReg old_high = lookupIRTemp(env, cas->oldHi);
3868
3869 /* Use non-virtual registers r8 and r9 as pair for op1
3870 and move op1 there */
3871 r8 = make_gpr(8);
3872 r9 = make_gpr(9);
3873 addInstr(env, s390_insn_move(8, r8, op1_high));
3874 addInstr(env, s390_insn_move(8, r9, op1_low));
3875
3876 /* Use non-virtual registers r10 and r11 as pair for op3
3877 and move op3 there */
3878 r10 = make_gpr(10);
3879 r11 = make_gpr(11);
3880 addInstr(env, s390_insn_move(8, r10, op3_high));
3881 addInstr(env, s390_insn_move(8, r11, op3_low));
3882
3883 /* Register r1 is used as a scratch register */
3884 r1 = make_gpr(1);
3885
3886 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3887 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3888 old_high, old_low, r1));
3889 } else {
3890 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3891 old_high, old_low, r1));
3892 }
3893 addInstr(env, s390_insn_move(8, op1_high, r8));
3894 addInstr(env, s390_insn_move(8, op1_low, r9));
3895 addInstr(env, s390_insn_move(8, op3_high, r10));
3896 addInstr(env, s390_insn_move(8, op3_low, r11));
3897 return;
sewardj2019a972011-03-07 16:04:07 +00003898 }
3899 break;
3900
3901 /* --------- EXIT --------- */
3902 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003903 s390_cc_t cond;
3904 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3905
3906 if (tag != Ico_U64)
3907 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3908
florian8844a632012-04-13 04:04:06 +00003909 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003910 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003911
3912 /* Case: boring transfer to known address */
3913 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3914 if (env->chaining_allowed) {
3915 /* .. almost always true .. */
3916 /* Skip the event check at the dst if this is a forwards
3917 edge. */
3918 Bool to_fast_entry
3919 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3920 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3921 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3922 guest_IA, to_fast_entry));
3923 } else {
3924 /* .. very occasionally .. */
3925 /* We can't use chaining, so ask for an assisted transfer,
3926 as that's the only alternative that is allowable. */
3927 HReg dst = s390_isel_int_expr(env,
3928 IRExpr_Const(stmt->Ist.Exit.dst));
3929 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3930 }
3931 return;
3932 }
3933
3934 /* Case: assisted transfer to arbitrary address */
3935 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003936 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003937 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003938 case Ijk_NoDecode:
sewardj05f5e012014-05-04 10:52:11 +00003939 case Ijk_InvalICache:
florian2d98d892012-04-14 20:35:17 +00003940 case Ijk_Sys_syscall:
3941 case Ijk_ClientReq:
3942 case Ijk_NoRedir:
3943 case Ijk_Yield:
3944 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003945 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3946 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3947 stmt->Ist.Exit.jk));
3948 return;
3949 }
3950 default:
3951 break;
3952 }
3953
3954 /* Do we ever expect to see any other kind? */
3955 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003956 }
3957
3958 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003959 case Ist_MBE:
3960 switch (stmt->Ist.MBE.event) {
3961 case Imbe_Fence:
3962 addInstr(env, s390_insn_mfence());
3963 return;
3964 default:
3965 break;
3966 }
sewardj2019a972011-03-07 16:04:07 +00003967 break;
3968
3969 /* --------- Miscellaneous --------- */
3970
3971 case Ist_PutI: /* Not needed */
3972 case Ist_IMark: /* Doesn't generate any executable code */
3973 case Ist_NoOp: /* Doesn't generate any executable code */
3974 case Ist_AbiHint: /* Meaningless in IR */
3975 return;
3976
3977 default:
3978 break;
3979 }
3980
3981 stmt_fail:
3982 ppIRStmt(stmt);
3983 vpanic("s390_isel_stmt");
3984}
3985
3986
3987/*---------------------------------------------------------*/
3988/*--- ISEL: Basic block terminators (Nexts) ---*/
3989/*---------------------------------------------------------*/
3990
3991static void
florianffbd84d2012-12-09 02:06:29 +00003992iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003993{
sewardj2019a972011-03-07 16:04:07 +00003994 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003995 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003996 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003997 vex_printf("; exit-");
3998 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003999 vex_printf("\n");
4000 }
4001
florian8844a632012-04-13 04:04:06 +00004002 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
4003
4004 /* Case: boring transfer to known address */
4005 if (next->tag == Iex_Const) {
4006 IRConst *cdst = next->Iex.Const.con;
4007 vassert(cdst->tag == Ico_U64);
4008 if (jk == Ijk_Boring || jk == Ijk_Call) {
4009 /* Boring transfer to known address */
4010 if (env->chaining_allowed) {
4011 /* .. almost always true .. */
4012 /* Skip the event check at the dst if this is a forwards
4013 edge. */
4014 Bool to_fast_entry
4015 = ((Addr64)cdst->Ico.U64) > env->max_ga;
4016 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
4017 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
4018 guest_IA, to_fast_entry));
4019 } else {
4020 /* .. very occasionally .. */
4021 /* We can't use chaining, so ask for an indirect transfer,
4022 as that's the cheapest alternative that is allowable. */
4023 HReg dst = s390_isel_int_expr(env, next);
4024 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
4025 Ijk_Boring));
4026 }
4027 return;
4028 }
4029 }
4030
4031 /* Case: call/return (==boring) transfer to any address */
4032 switch (jk) {
4033 case Ijk_Boring:
4034 case Ijk_Ret:
4035 case Ijk_Call: {
4036 HReg dst = s390_isel_int_expr(env, next);
4037 if (env->chaining_allowed) {
4038 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
4039 } else {
4040 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
4041 Ijk_Boring));
4042 }
4043 return;
4044 }
4045 default:
4046 break;
4047 }
4048
4049 /* Case: some other kind of transfer to any address */
4050 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00004051 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00004052 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00004053 case Ijk_NoDecode:
sewardj05f5e012014-05-04 10:52:11 +00004054 case Ijk_InvalICache:
florian8844a632012-04-13 04:04:06 +00004055 case Ijk_Sys_syscall:
4056 case Ijk_ClientReq:
4057 case Ijk_NoRedir:
4058 case Ijk_Yield:
4059 case Ijk_SigTRAP: {
4060 HReg dst = s390_isel_int_expr(env, next);
4061 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
4062 return;
4063 }
4064 default:
4065 break;
4066 }
4067
4068 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00004069}
4070
4071
4072/*---------------------------------------------------------*/
4073/*--- Insn selector top-level ---*/
4074/*---------------------------------------------------------*/
4075
florianf26994a2012-04-21 03:34:54 +00004076/* Translate an entire SB to s390 code.
4077 Note: archinfo_host is a pointer to a stack-allocated variable.
4078 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00004079
4080HInstrArray *
4081iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00004082 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
4083 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
4084 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00004085{
4086 UInt i, j;
4087 HReg hreg, hregHI;
4088 ISelEnv *env;
4089 UInt hwcaps_host = archinfo_host->hwcaps;
4090
florianf26994a2012-04-21 03:34:54 +00004091 /* KLUDGE: export hwcaps. */
4092 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00004093
sewardj2019a972011-03-07 16:04:07 +00004094 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00004095 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00004096
sewardj9b769162014-07-24 12:42:03 +00004097 /* Check that the host's endianness is as expected. */
4098 vassert(archinfo_host->endness == VexEndnessBE);
4099
sewardj2019a972011-03-07 16:04:07 +00004100 /* Make up an initial environment to use. */
4101 env = LibVEX_Alloc(sizeof(ISelEnv));
4102 env->vreg_ctr = 0;
4103
4104 /* Set up output code array. */
4105 env->code = newHInstrArray();
4106
4107 /* Copy BB's type env. */
4108 env->type_env = bb->tyenv;
4109
florianad43b3a2012-02-20 15:01:14 +00004110 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00004111 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
4112 env->old_value[i] = 0; /* just something to have a defined value */
4113 env->old_value_valid[i] = False;
4114 }
4115
sewardj2019a972011-03-07 16:04:07 +00004116 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
4117 change as we go along. For some reason types_used has Int type -- but
4118 it should be unsigned. Internally we use an unsigned type; so we
4119 assert it here. */
4120 vassert(bb->tyenv->types_used >= 0);
4121
4122 env->n_vregmap = bb->tyenv->types_used;
4123 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4124 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4125
florian2c74d242012-09-12 19:38:42 +00004126 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00004127 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00004128
sewardj2019a972011-03-07 16:04:07 +00004129 /* and finally ... */
4130 env->hwcaps = hwcaps_host;
4131
florian8844a632012-04-13 04:04:06 +00004132 env->max_ga = max_ga;
4133 env->chaining_allowed = chaining_allowed;
4134
sewardj2019a972011-03-07 16:04:07 +00004135 /* For each IR temporary, allocate a suitably-kinded virtual
4136 register. */
4137 j = 0;
4138 for (i = 0; i < env->n_vregmap; i++) {
4139 hregHI = hreg = INVALID_HREG;
4140 switch (bb->tyenv->types[i]) {
4141 case Ity_I1:
4142 case Ity_I8:
4143 case Ity_I16:
4144 case Ity_I32:
4145 hreg = mkHReg(j++, HRcInt64, True);
4146 break;
4147
4148 case Ity_I64:
4149 hreg = mkHReg(j++, HRcInt64, True);
4150 break;
4151
4152 case Ity_I128:
4153 hreg = mkHReg(j++, HRcInt64, True);
4154 hregHI = mkHReg(j++, HRcInt64, True);
4155 break;
4156
4157 case Ity_F32:
4158 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00004159 case Ity_D32:
florian12390202012-11-10 22:34:14 +00004160 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00004161 hreg = mkHReg(j++, HRcFlt64, True);
4162 break;
4163
4164 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00004165 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00004166 hreg = mkHReg(j++, HRcFlt64, True);
4167 hregHI = mkHReg(j++, HRcFlt64, True);
4168 break;
4169
4170 case Ity_V128: /* fall through */
4171 default:
4172 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00004173 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00004174 }
4175
4176 env->vregmap[i] = hreg;
4177 env->vregmapHI[i] = hregHI;
4178 }
4179 env->vreg_ctr = j;
4180
florian8844a632012-04-13 04:04:06 +00004181 /* The very first instruction must be an event check. */
4182 s390_amode *counter, *fail_addr;
4183 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
4184 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
4185 addInstr(env, s390_insn_evcheck(counter, fail_addr));
4186
4187 /* Possibly a block counter increment (for profiling). At this
4188 point we don't know the address of the counter, so just pretend
4189 it is zero. It will have to be patched later, but before this
4190 translation is used, by a call to LibVEX_patchProfInc. */
4191 if (add_profinc) {
4192 addInstr(env, s390_insn_profinc());
4193 }
4194
sewardj2019a972011-03-07 16:04:07 +00004195 /* Ok, finally we can iterate over the statements. */
4196 for (i = 0; i < bb->stmts_used; i++)
4197 if (bb->stmts[i])
4198 s390_isel_stmt(env, bb->stmts[i]);
4199
florian8844a632012-04-13 04:04:06 +00004200 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00004201
4202 /* Record the number of vregs we used. */
4203 env->code->n_vregs = env->vreg_ctr;
4204
4205 return env->code;
4206}
4207
4208/*---------------------------------------------------------------*/
4209/*--- end host_s390_isel.c ---*/
4210/*---------------------------------------------------------------*/