blob: ac51e90db403d819c13f1ce84e65973b6cfd29c3 [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
florian61f23c12012-08-06 18:33:21 +000011 Copyright IBM Corp. 2010-2012
florian2c74d242012-09-12 19:38:42 +000012 Copyright (C) 2012-2012 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
473doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000474 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000475{
florian52af7bc2012-05-12 03:44:49 +0000476 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000477 ULong target;
478 HReg tmpregs[S390_NUM_GPRPARMS];
479 s390_cc_t cc;
480
481 n_args = 0;
482 for (i = 0; args[i]; i++)
483 ++n_args;
484
485 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
486 vpanic("doHelperCall: too many arguments");
487 }
488
florian11b8ee82012-08-06 13:35:33 +0000489 /* All arguments must have Ity_I64. For two reasons:
490 (1) We do not handle floating point arguments.
491 (2) The ABI requires that integer values are sign- or zero-extended
492 to 64 bit.
493 */
494 Int arg_errors = 0;
495 for (i = 0; i < n_args; ++i) {
496 IRType type = typeOfIRExpr(env->type_env, args[i]);
497 if (type != Ity_I64) {
498 ++arg_errors;
499 vex_printf("calling %s: argument #%d has type ", callee->name, i);
500 ppIRType(type);
501 vex_printf("; Ity_I64 is required\n");
502 }
503 }
504
505 if (arg_errors)
506 vpanic("cannot continue due to errors in argument passing");
507
florian52af7bc2012-05-12 03:44:49 +0000508 argreg = 0;
509
510 /* If we need the guest state pointer put it in a temporary arg reg */
511 if (passBBP) {
512 tmpregs[argreg] = newVRegI(env);
513 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
514 s390_hreg_guest_state_pointer()));
515 argreg++;
516 }
517
518 /* Compute the function arguments into a temporary register each */
519 for (i = 0; i < n_args; i++) {
520 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
521 argreg++;
522 }
523
sewardj2019a972011-03-07 16:04:07 +0000524 /* Compute the condition */
525 cc = S390_CC_ALWAYS;
526 if (guard) {
527 if (guard->tag == Iex_Const
528 && guard->Iex.Const.con->tag == Ico_U1
529 && guard->Iex.Const.con->Ico.U1 == True) {
530 /* unconditional -- do nothing */
531 } else {
532 cc = s390_isel_cc(env, guard);
533 }
534 }
535
florian52af7bc2012-05-12 03:44:49 +0000536 /* Move the args to the final register. It is paramount, that the
537 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000538 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000539 HReg finalreg;
540
541 finalreg = make_gpr(s390_gprno_from_arg_index(i));
542 size = sizeofIRType(Ity_I64);
543 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000544 }
545
546 target = Ptr_to_ULong(callee->addr);
547
548 /* Finally, the call itself. */
549 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000550 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000551}
552
553
florian2c74d242012-09-12 19:38:42 +0000554/*---------------------------------------------------------*/
555/*--- BFP helper functions ---*/
556/*---------------------------------------------------------*/
557
558/* Set the BFP rounding mode in the FPC. This function is called for
559 all non-conversion BFP instructions as those will always get the
560 rounding mode from the FPC. */
561static void
562set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000563{
florian2c74d242012-09-12 19:38:42 +0000564 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
565
566 /* Do we need to do anything? */
567 if (env->previous_bfp_rounding_mode &&
568 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
569 irrm->tag == Iex_RdTmp &&
570 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
571 /* No - new mode is identical to previous mode. */
572 return;
573 }
574
575 /* No luck - we better set it, and remember what we set it to. */
576 env->previous_bfp_rounding_mode = irrm;
577
578 /* The incoming rounding mode is in VEX IR encoding. Need to change
579 to s390.
580
581 rounding mode | s390 | IR
582 -------------------------
583 to nearest | 00 | 00
584 to zero | 01 | 11
585 to +infinity | 10 | 10
586 to -infinity | 11 | 01
587
588 So: s390 = (4 - IR) & 3
589 */
590 HReg ir = s390_isel_int_expr(env, irrm);
591
592 HReg mode = newVRegI(env);
593
594 addInstr(env, s390_insn_load_immediate(4, mode, 4));
595 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
596 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
597
florian125e20d2012-10-07 15:42:37 +0000598 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000599}
600
601
602/* This function is invoked for insns that support a specification of
603 a rounding mode in the insn itself. In that case there is no need to
604 stick the rounding mode into the FPC -- a good thing. However, the
605 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000606static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000607get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
608{
609 if (irrm->tag == Iex_Const) { /* rounding mode is known */
610 vassert(irrm->Iex.Const.con->tag == Ico_U32);
611 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000612
613 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000614 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
615 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
616 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
617 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000618 default:
619 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000620 }
621 }
622
florian2c74d242012-09-12 19:38:42 +0000623 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000624 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000625}
626
627
florianc8e4f562012-10-27 16:19:31 +0000628/*---------------------------------------------------------*/
629/*--- DFP helper functions ---*/
630/*---------------------------------------------------------*/
631
632/* Set the DFP rounding mode in the FPC. This function is called for
633 all non-conversion DFP instructions as those will always get the
634 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000635static void
636set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
637{
638 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
639
640 /* Do we need to do anything? */
641 if (env->previous_dfp_rounding_mode &&
642 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
643 irrm->tag == Iex_RdTmp &&
644 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
645 /* No - new mode is identical to previous mode. */
646 return;
647 }
648
649 /* No luck - we better set it, and remember what we set it to. */
650 env->previous_dfp_rounding_mode = irrm;
651
652 /* The incoming rounding mode is in VEX IR encoding. Need to change
653 to s390.
654
655 rounding mode | S390 | IR
656 -----------------------------------------------
657 to nearest, ties to even | 000 | 000
658 to zero | 001 | 011
659 to +infinity | 010 | 010
660 to -infinity | 011 | 001
661 to nearest, ties away from 0 | 100 | 100
662 to nearest, ties toward 0 | 101 | 111
663 to away from 0 | 110 | 110
664 to prepare for shorter precision | 111 | 101
665
666 So: s390 = (IR ^ ((IR << 1) & 2))
667 */
668 HReg ir = s390_isel_int_expr(env, irrm);
669
670 HReg mode = newVRegI(env);
671
672 addInstr(env, s390_insn_move(4, mode, ir));
673 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
674 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
675 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
676
677 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
678}
679
680
681/* This function is invoked for insns that support a specification of
682 a rounding mode in the insn itself. In that case there is no need to
683 stick the rounding mode into the FPC -- a good thing. However, the
684 rounding mode must be known.
florianff9000d2013-02-08 20:22:03 +0000685
686 When mapping an Irrm_DFP_ value to an S390_DFP_ROUND_ value there is
687 often a choice. For instance, Irrm_DFP_ZERO could be mapped to either
688 S390_DFP_ROUND_ZERO_5 or S390_DFP_ROUND_ZERO_9. The difference between
689 those two is that with S390_DFP_ROUND_ZERO_9 the recognition of the
690 quantum exception is suppressed whereas with S390_DFP_ROUND_ZERO_5 it
691 is not. As the quantum exception is not modelled we can choose either
692 value. The choice is to use S390_DFP_ROUND_.. values in the range [8:15],
693 because values in the range [1:7] have unpredictable rounding behaviour
694 when the floating point exception facility is not installed.
florianc8e4f562012-10-27 16:19:31 +0000695
696 Translation table of
697 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
698
699 s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
700 --------------------------------------------------------------------
florianff9000d2013-02-08 20:22:03 +0000701 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_12
florianc8e4f562012-10-27 16:19:31 +0000702 NEAREST_TIE_AWAY_0_12 | " | "
florianff9000d2013-02-08 20:22:03 +0000703 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_15
florianc8e4f562012-10-27 16:19:31 +0000704 PREPARE_SHORT_15 | " | "
florianff9000d2013-02-08 20:22:03 +0000705 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_8
florianc8e4f562012-10-27 16:19:31 +0000706 NEAREST_EVEN_8 | " | "
florianff9000d2013-02-08 20:22:03 +0000707 ZERO_5 | ZERO | ZERO_9
florianc8e4f562012-10-27 16:19:31 +0000708 ZERO_9 | " | "
florianff9000d2013-02-08 20:22:03 +0000709 POSINF_6 | PosINF | POSINF_10
florianc8e4f562012-10-27 16:19:31 +0000710 POSINF_10 | " | "
florianff9000d2013-02-08 20:22:03 +0000711 NEGINF_7 | NegINF | NEGINF_11
florianc8e4f562012-10-27 16:19:31 +0000712 NEGINF_11 | " | "
713 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
714 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
715*/
716static s390_dfp_round_t
717get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
718{
719 if (irrm->tag == Iex_Const) { /* rounding mode is known */
720 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian3d6a4222012-11-19 16:29:31 +0000721 IRRoundingModeDFP mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000722
723 switch (mode) {
724 case Irrm_DFP_NEAREST:
florianff9000d2013-02-08 20:22:03 +0000725 return S390_DFP_ROUND_NEAREST_EVEN_8;
florianc8e4f562012-10-27 16:19:31 +0000726 case Irrm_DFP_NegINF:
florianff9000d2013-02-08 20:22:03 +0000727 return S390_DFP_ROUND_NEGINF_11;
florianc8e4f562012-10-27 16:19:31 +0000728 case Irrm_DFP_PosINF:
florianff9000d2013-02-08 20:22:03 +0000729 return S390_DFP_ROUND_POSINF_10;
florianc8e4f562012-10-27 16:19:31 +0000730 case Irrm_DFP_ZERO:
florianff9000d2013-02-08 20:22:03 +0000731 return S390_DFP_ROUND_ZERO_9;
florianc8e4f562012-10-27 16:19:31 +0000732 case Irrm_DFP_NEAREST_TIE_AWAY_0:
florianff9000d2013-02-08 20:22:03 +0000733 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12;
florianc8e4f562012-10-27 16:19:31 +0000734 case Irrm_DFP_PREPARE_SHORTER:
florianff9000d2013-02-08 20:22:03 +0000735 return S390_DFP_ROUND_PREPARE_SHORT_15;
florianc8e4f562012-10-27 16:19:31 +0000736 case Irrm_DFP_AWAY_FROM_ZERO:
737 return S390_DFP_ROUND_AWAY_0;
738 case Irrm_DFP_NEAREST_TIE_TOWARD_0:
739 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
740 default:
741 vpanic("get_dfp_rounding_mode");
742 }
743 }
744
745 set_dfp_rounding_mode_in_fpc(env, irrm);
746 return S390_DFP_ROUND_PER_FPC_0;
747}
florianc8e4f562012-10-27 16:19:31 +0000748
florian2d3d87f2012-12-21 21:05:17 +0000749
750/*---------------------------------------------------------*/
751/*--- Condition code helper functions ---*/
752/*---------------------------------------------------------*/
753
sewardj2019a972011-03-07 16:04:07 +0000754/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000755 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000756
757 s390 VEX b6 b2 b0 cc.1 cc.0
758 0 0x40 EQ 1 0 0 0 0
759 1 0x01 LT 0 0 1 0 1
760 2 0x00 GT 0 0 0 1 0
761 3 0x45 Unordered 1 1 1 1 1
762
763 b0 = cc.0
764 b2 = cc.0 & cc.1
765 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
766
767 VEX = b0 | (b2 << 2) | (b6 << 6);
768*/
769static HReg
florian2d3d87f2012-12-21 21:05:17 +0000770convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000771{
772 HReg cc0, cc1, b2, b6, cc_vex;
773
774 cc0 = newVRegI(env);
775 addInstr(env, s390_insn_move(4, cc0, cc_s390));
776 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
777
778 cc1 = newVRegI(env);
779 addInstr(env, s390_insn_move(4, cc1, cc_s390));
780 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
781
782 b2 = newVRegI(env);
783 addInstr(env, s390_insn_move(4, b2, cc0));
784 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
785 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
786
787 b6 = newVRegI(env);
788 addInstr(env, s390_insn_move(4, b6, cc0));
789 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
790 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
791 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
792 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
793
794 cc_vex = newVRegI(env);
795 addInstr(env, s390_insn_move(4, cc_vex, cc0));
796 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
797 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
798
799 return cc_vex;
800}
801
florian2d3d87f2012-12-21 21:05:17 +0000802/* CC_S390 holds the condition code in s390 encoding. Convert it to
803 VEX encoding (IRCmpDResult) */
804static HReg
805convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
806{
807 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
808 return convert_s390_to_vex_bfpcc(env, cc_s390);
809}
810
sewardj2019a972011-03-07 16:04:07 +0000811
812/*---------------------------------------------------------*/
813/*--- ISEL: Integer expressions (128 bit) ---*/
814/*---------------------------------------------------------*/
815static void
816s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
817 IRExpr *expr)
818{
819 IRType ty = typeOfIRExpr(env->type_env, expr);
820
821 vassert(ty == Ity_I128);
822
823 /* No need to consider the following
824 - 128-bit constants (they do not exist in VEX)
825 - 128-bit loads from memory (will not be generated)
826 */
827
828 /* Read 128-bit IRTemp */
829 if (expr->tag == Iex_RdTmp) {
830 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
831 return;
832 }
833
834 if (expr->tag == Iex_Binop) {
835 IRExpr *arg1 = expr->Iex.Binop.arg1;
836 IRExpr *arg2 = expr->Iex.Binop.arg2;
837 Bool is_signed_multiply, is_signed_divide;
838
839 switch (expr->Iex.Binop.op) {
840 case Iop_MullU64:
841 is_signed_multiply = False;
842 goto do_multiply64;
843
844 case Iop_MullS64:
845 is_signed_multiply = True;
846 goto do_multiply64;
847
848 case Iop_DivModU128to64:
849 is_signed_divide = False;
850 goto do_divide64;
851
852 case Iop_DivModS128to64:
853 is_signed_divide = True;
854 goto do_divide64;
855
856 case Iop_64HLto128:
857 *dst_hi = s390_isel_int_expr(env, arg1);
858 *dst_lo = s390_isel_int_expr(env, arg2);
859 return;
860
861 case Iop_DivModS64to64: {
862 HReg r10, r11, h1;
863 s390_opnd_RMI op2;
864
865 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
866 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
867
868 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000869 r10 = make_gpr(10);
870 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000871
872 /* Move 1st operand into r11 and */
873 addInstr(env, s390_insn_move(8, r11, h1));
874
875 /* Divide */
876 addInstr(env, s390_insn_divs(8, r10, r11, op2));
877
878 /* The result is in registers r10 (remainder) and r11 (quotient).
879 Move the result into the reg pair that is being returned such
880 such that the low 64 bits are the quotient and the upper 64 bits
881 are the remainder. (see libvex_ir.h). */
882 *dst_hi = newVRegI(env);
883 *dst_lo = newVRegI(env);
884 addInstr(env, s390_insn_move(8, *dst_hi, r10));
885 addInstr(env, s390_insn_move(8, *dst_lo, r11));
886 return;
887 }
888
889 default:
890 break;
891
892 do_multiply64: {
893 HReg r10, r11, h1;
894 s390_opnd_RMI op2;
895
896 order_commutative_operands(arg1, arg2);
897
898 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
899 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
900
901 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000902 r10 = make_gpr(10);
903 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000904
905 /* Move the first operand to r11 */
906 addInstr(env, s390_insn_move(8, r11, h1));
907
908 /* Multiply */
909 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
910
911 /* The result is in registers r10 and r11. Assign to two virtual regs
912 and return. */
913 *dst_hi = newVRegI(env);
914 *dst_lo = newVRegI(env);
915 addInstr(env, s390_insn_move(8, *dst_hi, r10));
916 addInstr(env, s390_insn_move(8, *dst_lo, r11));
917 return;
918 }
919
920 do_divide64: {
921 HReg r10, r11, hi, lo;
922 s390_opnd_RMI op2;
923
924 s390_isel_int128_expr(&hi, &lo, env, arg1);
925 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
926
927 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000928 r10 = make_gpr(10);
929 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000930
931 /* Move high 64 bits of the 1st operand into r10 and
932 the low 64 bits into r11. */
933 addInstr(env, s390_insn_move(8, r10, hi));
934 addInstr(env, s390_insn_move(8, r11, lo));
935
936 /* Divide */
937 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
938
939 /* The result is in registers r10 (remainder) and r11 (quotient).
940 Move the result into the reg pair that is being returned such
941 such that the low 64 bits are the quotient and the upper 64 bits
942 are the remainder. (see libvex_ir.h). */
943 *dst_hi = newVRegI(env);
944 *dst_lo = newVRegI(env);
945 addInstr(env, s390_insn_move(8, *dst_hi, r10));
946 addInstr(env, s390_insn_move(8, *dst_lo, r11));
947 return;
948 }
949 }
950 }
951
952 vpanic("s390_isel_int128_expr");
953}
954
955
956/* Compute a 128-bit value into two 64-bit registers. These may be either
957 real or virtual regs; in any case they must not be changed by subsequent
958 code emitted by the caller. */
959static void
960s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
961{
962 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
963
964 /* Sanity checks ... */
965 vassert(hregIsVirtual(*dst_hi));
966 vassert(hregIsVirtual(*dst_lo));
967 vassert(hregClass(*dst_hi) == HRcInt64);
968 vassert(hregClass(*dst_lo) == HRcInt64);
969}
970
971
972/*---------------------------------------------------------*/
973/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
974/*---------------------------------------------------------*/
975
976/* Select insns for an integer-typed expression, and add them to the
977 code list. Return a reg holding the result. This reg will be a
978 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
979 want to modify it, ask for a new vreg, copy it in there, and modify
980 the copy. The register allocator will do its best to map both
981 vregs to the same real register, so the copies will often disappear
982 later in the game.
983
984 This should handle expressions of 64, 32, 16 and 8-bit type.
985 All results are returned in a 64bit register.
986 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
987 are arbitrary, so you should mask or sign extend partial values
988 if necessary.
989*/
990
991/* DO NOT CALL THIS DIRECTLY ! */
992static HReg
993s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
994{
995 IRType ty = typeOfIRExpr(env->type_env, expr);
996 UChar size;
florian6dc90242012-12-21 21:43:00 +0000997 s390_bfp_conv_t conv;
florian67a171c2013-01-20 03:08:04 +0000998 s390_dfp_conv_t dconv;
sewardj2019a972011-03-07 16:04:07 +0000999
1000 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
1001
1002 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
1003
1004 switch (expr->tag) {
1005
1006 /* --------- TEMP --------- */
1007 case Iex_RdTmp:
1008 /* Return the virtual register that holds the temporary. */
1009 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1010
1011 /* --------- LOAD --------- */
1012 case Iex_Load: {
1013 HReg dst = newVRegI(env);
1014 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1015
1016 if (expr->Iex.Load.end != Iend_BE)
1017 goto irreducible;
1018
1019 addInstr(env, s390_insn_load(size, dst, am));
1020
1021 return dst;
1022 }
1023
1024 /* --------- BINARY OP --------- */
1025 case Iex_Binop: {
1026 IRExpr *arg1 = expr->Iex.Binop.arg1;
1027 IRExpr *arg2 = expr->Iex.Binop.arg2;
1028 HReg h1, res;
1029 s390_alu_t opkind;
1030 s390_opnd_RMI op2, value, opnd;
1031 s390_insn *insn;
1032 Bool is_commutative, is_signed_multiply, is_signed_divide;
1033
1034 is_commutative = True;
1035
1036 switch (expr->Iex.Binop.op) {
1037 case Iop_MullU8:
1038 case Iop_MullU16:
1039 case Iop_MullU32:
1040 is_signed_multiply = False;
1041 goto do_multiply;
1042
1043 case Iop_MullS8:
1044 case Iop_MullS16:
1045 case Iop_MullS32:
1046 is_signed_multiply = True;
1047 goto do_multiply;
1048
1049 do_multiply: {
1050 HReg r10, r11;
1051 UInt arg_size = size / 2;
1052
1053 order_commutative_operands(arg1, arg2);
1054
1055 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1056 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1057
1058 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001059 r10 = make_gpr(10);
1060 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001061
1062 /* Move the first operand to r11 */
1063 addInstr(env, s390_insn_move(arg_size, r11, h1));
1064
1065 /* Multiply */
1066 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1067
1068 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1069 value into the destination register. */
1070 res = newVRegI(env);
1071 addInstr(env, s390_insn_move(arg_size, res, r10));
1072 value = s390_opnd_imm(arg_size * 8);
1073 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1074 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1075 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1076 opnd = s390_opnd_reg(r11);
1077 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1078 return res;
1079 }
1080
1081 case Iop_DivModS64to32:
1082 is_signed_divide = True;
1083 goto do_divide;
1084
1085 case Iop_DivModU64to32:
1086 is_signed_divide = False;
1087 goto do_divide;
1088
1089 do_divide: {
1090 HReg r10, r11;
1091
1092 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1093 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1094
1095 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001096 r10 = make_gpr(10);
1097 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001098
1099 /* Split the first operand and put the high 32 bits into r10 and
1100 the low 32 bits into r11. */
1101 addInstr(env, s390_insn_move(8, r10, h1));
1102 addInstr(env, s390_insn_move(8, r11, h1));
1103 value = s390_opnd_imm(32);
1104 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1105
1106 /* Divide */
1107 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1108
1109 /* The result is in registers r10 (remainder) and r11 (quotient).
1110 Combine them into a 64-bit value such that the low 32 bits are
1111 the quotient and the upper 32 bits are the remainder. (see
1112 libvex_ir.h). */
1113 res = newVRegI(env);
1114 addInstr(env, s390_insn_move(8, res, r10));
1115 value = s390_opnd_imm(32);
1116 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1117 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1118 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1119 opnd = s390_opnd_reg(r11);
1120 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1121 return res;
1122 }
1123
florian9fcff4c2012-09-10 03:09:04 +00001124 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1125 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1126 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1127 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1128 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1129 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1130 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1131 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1132 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1133 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1134 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1135 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
florian67a171c2013-01-20 03:08:04 +00001136
1137 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
floriana887acd2013-02-08 23:32:54 +00001138 case Iop_D64toI64S: dconv = S390_DFP_D64_TO_I64; goto do_convert_dfp;
florian67a171c2013-01-20 03:08:04 +00001139 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1140 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1141 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
floriana887acd2013-02-08 23:32:54 +00001142 case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128;
florian67a171c2013-01-20 03:08:04 +00001143 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1144 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00001145
1146 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001147 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001148
1149 res = newVRegI(env);
1150 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1151
florian2c74d242012-09-12 19:38:42 +00001152 rounding_mode = get_bfp_rounding_mode(env, arg1);
1153 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1154 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001155 return res;
1156 }
1157
1158 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001159 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001160 HReg op_hi, op_lo, f13, f15;
1161
1162 res = newVRegI(env);
1163 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1164
1165 /* We use non-virtual registers r13 and r15 as pair */
1166 f13 = make_fpr(13);
1167 f15 = make_fpr(15);
1168
1169 /* operand --> (f13, f15) */
1170 addInstr(env, s390_insn_move(8, f13, op_hi));
1171 addInstr(env, s390_insn_move(8, f15, op_lo));
1172
florian2c74d242012-09-12 19:38:42 +00001173 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001174 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001175 rounding_mode));
1176 return res;
1177 }
1178
florian5f034622013-01-13 02:29:05 +00001179 do_convert_dfp: {
1180 s390_dfp_round_t rounding_mode;
1181
1182 res = newVRegI(env);
1183 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1184
1185 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001186 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
florian5f034622013-01-13 02:29:05 +00001187 rounding_mode));
1188 return res;
1189 }
1190
1191 do_convert_dfp128: {
1192 s390_dfp_round_t rounding_mode;
1193 HReg op_hi, op_lo, f13, f15;
1194
1195 res = newVRegI(env);
1196 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1197
1198 /* We use non-virtual registers r13 and r15 as pair */
1199 f13 = make_fpr(13);
1200 f15 = make_fpr(15);
1201
1202 /* operand --> (f13, f15) */
1203 addInstr(env, s390_insn_move(8, f13, op_hi));
1204 addInstr(env, s390_insn_move(8, f15, op_lo));
1205
1206 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001207 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res, f13,
florian5f034622013-01-13 02:29:05 +00001208 f15, rounding_mode));
1209 return res;
1210 }
1211
sewardj2019a972011-03-07 16:04:07 +00001212 case Iop_8HLto16:
1213 case Iop_16HLto32:
1214 case Iop_32HLto64: {
1215 HReg h2;
1216 UInt arg_size = size / 2;
1217
1218 res = newVRegI(env);
1219 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1220 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1221
1222 addInstr(env, s390_insn_move(arg_size, res, h1));
1223 value = s390_opnd_imm(arg_size * 8);
1224 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1225 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1226 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1227 opnd = s390_opnd_reg(h2);
1228 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1229 return res;
1230 }
1231
1232 case Iop_Max32U: {
1233 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1234 res = newVRegI(env);
1235 h1 = s390_isel_int_expr(env, arg1);
1236 op2 = s390_isel_int_expr_RMI(env, arg2);
1237
1238 addInstr(env, s390_insn_move(size, res, h1));
1239 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1240 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1241 return res;
1242 }
1243
1244 case Iop_CmpF32:
1245 case Iop_CmpF64: {
1246 HReg cc_s390, h2;
1247
1248 h1 = s390_isel_float_expr(env, arg1);
1249 h2 = s390_isel_float_expr(env, arg2);
1250 cc_s390 = newVRegI(env);
1251
1252 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1253
1254 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1255
florian2d3d87f2012-12-21 21:05:17 +00001256 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001257 }
1258
1259 case Iop_CmpF128: {
1260 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1261
1262 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1263 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1264 cc_s390 = newVRegI(env);
1265
1266 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1267 f12 = make_fpr(12);
1268 f13 = make_fpr(13);
1269 f14 = make_fpr(14);
1270 f15 = make_fpr(15);
1271
1272 /* 1st operand --> (f12, f14) */
1273 addInstr(env, s390_insn_move(8, f12, op1_hi));
1274 addInstr(env, s390_insn_move(8, f14, op1_lo));
1275
1276 /* 2nd operand --> (f13, f15) */
1277 addInstr(env, s390_insn_move(8, f13, op2_hi));
1278 addInstr(env, s390_insn_move(8, f15, op2_lo));
1279
1280 res = newVRegI(env);
1281 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1282
florian2d3d87f2012-12-21 21:05:17 +00001283 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001284 }
1285
florian20c6bca2012-12-26 17:47:19 +00001286 case Iop_CmpD64:
1287 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001288 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001289 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001290
1291 h1 = s390_isel_dfp_expr(env, arg1);
1292 h2 = s390_isel_dfp_expr(env, arg2);
1293 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001294
florian20c6bca2012-12-26 17:47:19 +00001295 switch(expr->Iex.Binop.op) {
1296 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1297 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1298 default: goto irreducible;
1299 }
1300 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001301
florian2d3d87f2012-12-21 21:05:17 +00001302 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001303 }
1304
florian20c6bca2012-12-26 17:47:19 +00001305 case Iop_CmpD128:
1306 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001307 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001308 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001309
1310 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1311 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1312 cc_s390 = newVRegI(env);
1313
1314 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1315 f12 = make_fpr(12);
1316 f13 = make_fpr(13);
1317 f14 = make_fpr(14);
1318 f15 = make_fpr(15);
1319
1320 /* 1st operand --> (f12, f14) */
1321 addInstr(env, s390_insn_move(8, f12, op1_hi));
1322 addInstr(env, s390_insn_move(8, f14, op1_lo));
1323
1324 /* 2nd operand --> (f13, f15) */
1325 addInstr(env, s390_insn_move(8, f13, op2_hi));
1326 addInstr(env, s390_insn_move(8, f15, op2_lo));
1327
florian20c6bca2012-12-26 17:47:19 +00001328 switch(expr->Iex.Binop.op) {
1329 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1330 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1331 default: goto irreducible;
1332 }
1333 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1334 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001335
florian2d3d87f2012-12-21 21:05:17 +00001336 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001337 }
1338
sewardj2019a972011-03-07 16:04:07 +00001339 case Iop_Add8:
1340 case Iop_Add16:
1341 case Iop_Add32:
1342 case Iop_Add64:
1343 opkind = S390_ALU_ADD;
1344 break;
1345
1346 case Iop_Sub8:
1347 case Iop_Sub16:
1348 case Iop_Sub32:
1349 case Iop_Sub64:
1350 opkind = S390_ALU_SUB;
1351 is_commutative = False;
1352 break;
1353
1354 case Iop_And8:
1355 case Iop_And16:
1356 case Iop_And32:
1357 case Iop_And64:
1358 opkind = S390_ALU_AND;
1359 break;
1360
1361 case Iop_Or8:
1362 case Iop_Or16:
1363 case Iop_Or32:
1364 case Iop_Or64:
1365 opkind = S390_ALU_OR;
1366 break;
1367
1368 case Iop_Xor8:
1369 case Iop_Xor16:
1370 case Iop_Xor32:
1371 case Iop_Xor64:
1372 opkind = S390_ALU_XOR;
1373 break;
1374
1375 case Iop_Shl8:
1376 case Iop_Shl16:
1377 case Iop_Shl32:
1378 case Iop_Shl64:
1379 opkind = S390_ALU_LSH;
1380 is_commutative = False;
1381 break;
1382
1383 case Iop_Shr8:
1384 case Iop_Shr16:
1385 case Iop_Shr32:
1386 case Iop_Shr64:
1387 opkind = S390_ALU_RSH;
1388 is_commutative = False;
1389 break;
1390
1391 case Iop_Sar8:
1392 case Iop_Sar16:
1393 case Iop_Sar32:
1394 case Iop_Sar64:
1395 opkind = S390_ALU_RSHA;
1396 is_commutative = False;
1397 break;
1398
1399 default:
1400 goto irreducible;
1401 }
1402
1403 /* Pattern match: 0 - arg1 --> -arg1 */
1404 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1405 res = newVRegI(env);
1406 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1407 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1408 addInstr(env, insn);
1409
1410 return res;
1411 }
1412
1413 if (is_commutative) {
1414 order_commutative_operands(arg1, arg2);
1415 }
1416
1417 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1418 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1419 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001420
1421 /* As right shifts of one/two byte opreands are implemented using a
1422 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1423 switch (expr->Iex.Binop.op) {
1424 case Iop_Shr8:
1425 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1426 break;
1427 case Iop_Shr16:
1428 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1429 break;
1430 case Iop_Sar8:
1431 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1432 break;
1433 case Iop_Sar16:
1434 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1435 break;
1436 default:
1437 insn = s390_insn_move(size, res, h1);
1438 break;
1439 }
1440 addInstr(env, insn);
1441
sewardj2019a972011-03-07 16:04:07 +00001442 insn = s390_insn_alu(size, opkind, res, op2);
1443
1444 addInstr(env, insn);
1445
1446 return res;
1447 }
1448
1449 /* --------- UNARY OP --------- */
1450 case Iex_Unop: {
1451 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1452 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1453 s390_opnd_RMI opnd;
1454 s390_insn *insn;
1455 IRExpr *arg;
1456 HReg dst, h1;
1457 IROp unop, binop;
1458
1459 arg = expr->Iex.Unop.arg;
1460
1461 /* Special cases are handled here */
1462
1463 /* 32-bit multiply with 32-bit result or
1464 64-bit multiply with 64-bit result */
1465 unop = expr->Iex.Unop.op;
1466 binop = arg->Iex.Binop.op;
1467
1468 if ((arg->tag == Iex_Binop &&
1469 ((unop == Iop_64to32 &&
1470 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1471 (unop == Iop_128to64 &&
1472 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1473 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1474 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1475 dst = newVRegI(env); /* Result goes into a new register */
1476 addInstr(env, s390_insn_move(size, dst, h1));
1477 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1478
1479 return dst;
1480 }
1481
florian4d71a082011-12-18 00:08:17 +00001482 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001483 dst = newVRegI(env);
1484 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1485 addInstr(env, s390_insn_move(size, dst, h1));
1486
1487 return dst;
1488 }
1489
floriane38f6412012-12-21 17:32:12 +00001490 if (unop == Iop_ReinterpD64asI64) {
1491 dst = newVRegI(env);
1492 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1493 addInstr(env, s390_insn_move(size, dst, h1));
1494
1495 return dst;
1496 }
1497
florian5c539732013-02-14 14:27:12 +00001498 if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
1499 s390_dfp_unop_t dfpop;
1500 switch(unop) {
1501 case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
1502 case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
1503 default: goto irreducible;
1504 }
floriance9e3db2012-12-27 20:14:03 +00001505 dst = newVRegI(env);
1506 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
florian5c539732013-02-14 14:27:12 +00001507 addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
floriance9e3db2012-12-27 20:14:03 +00001508 return dst;
1509 }
1510
florian5c539732013-02-14 14:27:12 +00001511 if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
1512 s390_dfp_unop_t dfpop;
floriance9e3db2012-12-27 20:14:03 +00001513 HReg op_hi, op_lo, f13, f15;
florian5c539732013-02-14 14:27:12 +00001514
1515 switch(unop) {
1516 case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
1517 case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
1518 default: goto irreducible;
1519 }
floriance9e3db2012-12-27 20:14:03 +00001520 dst = newVRegI(env);
1521 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1522
1523 /* We use non-virtual registers r13 and r15 as pair */
1524 f13 = make_fpr(13);
1525 f15 = make_fpr(15);
1526
1527 /* operand --> (f13, f15) */
1528 addInstr(env, s390_insn_move(8, f13, op_hi));
1529 addInstr(env, s390_insn_move(8, f15, op_lo));
1530
florian5c539732013-02-14 14:27:12 +00001531 addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
floriance9e3db2012-12-27 20:14:03 +00001532 return dst;
1533 }
1534
sewardj2019a972011-03-07 16:04:07 +00001535 /* Expressions whose argument is 1-bit wide */
1536 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1537 s390_cc_t cond = s390_isel_cc(env, arg);
1538 dst = newVRegI(env); /* Result goes into a new register */
1539 addInstr(env, s390_insn_cc2bool(dst, cond));
1540
1541 switch (unop) {
1542 case Iop_1Uto8:
1543 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001544 /* Zero extend */
1545 mask.variant.imm = 1;
1546 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1547 break;
1548
sewardj2019a972011-03-07 16:04:07 +00001549 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001550 /* Zero extend */
1551 mask.variant.imm = 1;
1552 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001553 break;
1554
1555 case Iop_1Sto8:
1556 case Iop_1Sto16:
1557 case Iop_1Sto32:
1558 shift.variant.imm = 31;
1559 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1560 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1561 break;
1562
1563 case Iop_1Sto64:
1564 shift.variant.imm = 63;
1565 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1566 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1567 break;
1568
1569 default:
1570 goto irreducible;
1571 }
1572
1573 return dst;
1574 }
1575
1576 /* Regular processing */
1577
1578 if (unop == Iop_128to64) {
1579 HReg dst_hi, dst_lo;
1580
1581 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1582 return dst_lo;
1583 }
1584
1585 if (unop == Iop_128HIto64) {
1586 HReg dst_hi, dst_lo;
1587
1588 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1589 return dst_hi;
1590 }
1591
1592 dst = newVRegI(env); /* Result goes into a new register */
1593 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1594
1595 switch (unop) {
1596 case Iop_8Uto16:
1597 case Iop_8Uto32:
1598 case Iop_8Uto64:
1599 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1600 break;
1601
1602 case Iop_16Uto32:
1603 case Iop_16Uto64:
1604 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1605 break;
1606
1607 case Iop_32Uto64:
1608 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1609 break;
1610
1611 case Iop_8Sto16:
1612 case Iop_8Sto32:
1613 case Iop_8Sto64:
1614 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1615 break;
1616
1617 case Iop_16Sto32:
1618 case Iop_16Sto64:
1619 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1620 break;
1621
1622 case Iop_32Sto64:
1623 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1624 break;
1625
1626 case Iop_64to8:
1627 case Iop_64to16:
1628 case Iop_64to32:
1629 case Iop_32to8:
1630 case Iop_32to16:
1631 case Iop_16to8:
1632 /* Down-casts are no-ops. Upstream operations will only look at
1633 the bytes that make up the result of the down-cast. So there
1634 is no point setting the other bytes to 0. */
1635 insn = s390_opnd_copy(8, dst, opnd);
1636 break;
1637
1638 case Iop_64HIto32:
1639 addInstr(env, s390_opnd_copy(8, dst, opnd));
1640 shift.variant.imm = 32;
1641 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1642 break;
1643
1644 case Iop_32HIto16:
1645 addInstr(env, s390_opnd_copy(4, dst, opnd));
1646 shift.variant.imm = 16;
1647 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1648 break;
1649
1650 case Iop_16HIto8:
1651 addInstr(env, s390_opnd_copy(2, dst, opnd));
1652 shift.variant.imm = 8;
1653 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1654 break;
1655
1656 case Iop_Not8:
1657 case Iop_Not16:
1658 case Iop_Not32:
1659 case Iop_Not64:
1660 /* XOR with ffff... */
1661 mask.variant.imm = ~(ULong)0;
1662 addInstr(env, s390_opnd_copy(size, dst, opnd));
1663 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1664 break;
1665
1666 case Iop_Left8:
1667 case Iop_Left16:
1668 case Iop_Left32:
1669 case Iop_Left64:
1670 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1671 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1672 break;
1673
1674 case Iop_CmpwNEZ32:
1675 case Iop_CmpwNEZ64: {
1676 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1677 or -X will have a 1 in the MSB. */
1678 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1679 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1680 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1681 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1682 return dst;
1683 }
1684
1685 case Iop_Clz64: {
1686 HReg r10, r11;
1687
sewardj611b06e2011-03-24 08:57:29 +00001688 /* This will be implemented using FLOGR, if possible. So we need to
1689 set aside a pair of non-virtual registers. The result (number of
1690 left-most zero bits) will be in r10. The value in r11 is unspecified
1691 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001692 r10 = make_gpr(10);
1693 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001694
sewardj611b06e2011-03-24 08:57:29 +00001695 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001696 addInstr(env, s390_insn_move(8, dst, r10));
1697 return dst;
1698 }
1699
1700 default:
1701 goto irreducible;
1702 }
1703
1704 addInstr(env, insn);
1705
1706 return dst;
1707 }
1708
1709 /* --------- GET --------- */
1710 case Iex_Get: {
1711 HReg dst = newVRegI(env);
1712 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1713
1714 /* We never load more than 8 bytes from the guest state, because the
1715 floating point register pair is not contiguous. */
1716 vassert(size <= 8);
1717
1718 addInstr(env, s390_insn_load(size, dst, am));
1719
1720 return dst;
1721 }
1722
1723 case Iex_GetI:
1724 /* not needed */
1725 break;
1726
1727 /* --------- CCALL --------- */
1728 case Iex_CCall: {
1729 HReg dst = newVRegI(env);
1730
1731 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001732 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001733 return dst;
1734 }
1735
1736 /* --------- LITERAL --------- */
1737
1738 /* Load a literal into a register. Create a "load immediate"
1739 v-insn and return the register. */
1740 case Iex_Const: {
1741 ULong value;
1742 HReg dst = newVRegI(env);
1743 const IRConst *con = expr->Iex.Const.con;
1744
1745 /* Bitwise copy of the value. No sign/zero-extension */
1746 switch (con->tag) {
1747 case Ico_U64: value = con->Ico.U64; break;
1748 case Ico_U32: value = con->Ico.U32; break;
1749 case Ico_U16: value = con->Ico.U16; break;
1750 case Ico_U8: value = con->Ico.U8; break;
1751 default: vpanic("s390_isel_int_expr: invalid constant");
1752 }
1753
1754 addInstr(env, s390_insn_load_immediate(size, dst, value));
1755
1756 return dst;
1757 }
1758
1759 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00001760 case Iex_ITE: {
sewardj2019a972011-03-07 16:04:07 +00001761 IRExpr *cond_expr;
florian99dd03e2013-01-29 03:56:06 +00001762 HReg dst, r1;
sewardj009230b2013-01-26 11:47:55 +00001763 s390_opnd_RMI r0;
sewardj2019a972011-03-07 16:04:07 +00001764
florian99dd03e2013-01-29 03:56:06 +00001765 cond_expr = expr->Iex.ITE.cond;
sewardj2019a972011-03-07 16:04:07 +00001766
sewardj009230b2013-01-26 11:47:55 +00001767 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
1768
sewardj2019a972011-03-07 16:04:07 +00001769 dst = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00001770 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
1771 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
1772 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
sewardj2019a972011-03-07 16:04:07 +00001773
sewardj009230b2013-01-26 11:47:55 +00001774 s390_cc_t cc = s390_isel_cc(env, cond_expr);
sewardj2019a972011-03-07 16:04:07 +00001775
florian99dd03e2013-01-29 03:56:06 +00001776 addInstr(env, s390_insn_move(size, dst, r1));
sewardj009230b2013-01-26 11:47:55 +00001777 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
sewardj2019a972011-03-07 16:04:07 +00001778 return dst;
1779 }
1780
1781 default:
1782 break;
1783 }
1784
1785 /* We get here if no pattern matched. */
1786 irreducible:
1787 ppIRExpr(expr);
1788 vpanic("s390_isel_int_expr: cannot reduce tree");
1789}
1790
1791
1792static HReg
1793s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1794{
1795 HReg dst = s390_isel_int_expr_wrk(env, expr);
1796
1797 /* Sanity checks ... */
1798 vassert(hregClass(dst) == HRcInt64);
1799 vassert(hregIsVirtual(dst));
1800
1801 return dst;
1802}
1803
1804
1805static s390_opnd_RMI
1806s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1807{
1808 IRType ty = typeOfIRExpr(env->type_env, expr);
1809 s390_opnd_RMI dst;
1810
1811 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1812 ty == Ity_I64);
1813
1814 if (expr->tag == Iex_Load) {
1815 dst.tag = S390_OPND_AMODE;
1816 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1817 } else if (expr->tag == Iex_Get) {
1818 dst.tag = S390_OPND_AMODE;
1819 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1820 } else if (expr->tag == Iex_Const) {
1821 ULong value;
1822
1823 /* The bit pattern for the value will be stored as is in the least
1824 significant bits of VALUE. */
1825 switch (expr->Iex.Const.con->tag) {
1826 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1827 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1828 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1829 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1830 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1831 default:
1832 vpanic("s390_isel_int_expr_RMI");
1833 }
1834
1835 dst.tag = S390_OPND_IMMEDIATE;
1836 dst.variant.imm = value;
1837 } else {
1838 dst.tag = S390_OPND_REG;
1839 dst.variant.reg = s390_isel_int_expr(env, expr);
1840 }
1841
1842 return dst;
1843}
1844
1845
1846/*---------------------------------------------------------*/
1847/*--- ISEL: Floating point expressions (128 bit) ---*/
1848/*---------------------------------------------------------*/
1849static void
1850s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1851 IRExpr *expr)
1852{
1853 IRType ty = typeOfIRExpr(env->type_env, expr);
1854
1855 vassert(ty == Ity_F128);
1856
sewardj2019a972011-03-07 16:04:07 +00001857 switch (expr->tag) {
1858 case Iex_RdTmp:
1859 /* Return the virtual registers that hold the temporary. */
1860 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1861 return;
1862
1863 /* --------- LOAD --------- */
1864 case Iex_Load: {
1865 IRExpr *addr_hi, *addr_lo;
1866 s390_amode *am_hi, *am_lo;
1867
1868 if (expr->Iex.Load.end != Iend_BE)
1869 goto irreducible;
1870
1871 addr_hi = expr->Iex.Load.addr;
1872 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1873
1874 am_hi = s390_isel_amode(env, addr_hi);
1875 am_lo = s390_isel_amode(env, addr_lo);
1876
1877 *dst_hi = newVRegF(env);
1878 *dst_lo = newVRegF(env);
1879 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1880 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1881 return;
1882 }
1883
1884
1885 /* --------- GET --------- */
1886 case Iex_Get:
1887 /* This is not supported because loading 128-bit from the guest
1888 state is almost certainly wrong. Use get_fpr_pair instead. */
1889 vpanic("Iex_Get with F128 data");
1890
1891 /* --------- 4-ary OP --------- */
1892 case Iex_Qop:
1893 vpanic("Iex_Qop with F128 data");
1894
1895 /* --------- TERNARY OP --------- */
1896 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001897 IRTriop *triop = expr->Iex.Triop.details;
1898 IROp op = triop->op;
1899 IRExpr *left = triop->arg2;
1900 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001901 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001902 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1903
1904 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1905 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1906
1907 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1908 f12 = make_fpr(12);
1909 f13 = make_fpr(13);
1910 f14 = make_fpr(14);
1911 f15 = make_fpr(15);
1912
1913 /* 1st operand --> (f12, f14) */
1914 addInstr(env, s390_insn_move(8, f12, op1_hi));
1915 addInstr(env, s390_insn_move(8, f14, op1_lo));
1916
1917 /* 2nd operand --> (f13, f15) */
1918 addInstr(env, s390_insn_move(8, f13, op2_hi));
1919 addInstr(env, s390_insn_move(8, f15, op2_lo));
1920
1921 switch (op) {
1922 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1923 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1924 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1925 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1926 default:
1927 goto irreducible;
1928 }
1929
florian2c74d242012-09-12 19:38:42 +00001930 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1931 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001932
1933 /* Move result to virtual destination register */
1934 *dst_hi = newVRegF(env);
1935 *dst_lo = newVRegF(env);
1936 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1937 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1938
1939 return;
1940 }
1941
1942 /* --------- BINARY OP --------- */
1943 case Iex_Binop: {
sewardj2019a972011-03-07 16:04:07 +00001944 switch (expr->Iex.Binop.op) {
florian78d5ef72013-05-11 15:02:58 +00001945 case Iop_SqrtF128: {
1946 HReg op_hi, op_lo, f12, f13, f14, f15;
1947
1948 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1949 f12 = make_fpr(12);
1950 f13 = make_fpr(13);
1951 f14 = make_fpr(14);
1952 f15 = make_fpr(15);
1953
sewardj2019a972011-03-07 16:04:07 +00001954 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1955
1956 /* operand --> (f13, f15) */
1957 addInstr(env, s390_insn_move(8, f13, op_hi));
1958 addInstr(env, s390_insn_move(8, f15, op_lo));
1959
florian2c74d242012-09-12 19:38:42 +00001960 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1961 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1962 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001963
1964 /* Move result to virtual destination registers */
1965 *dst_hi = newVRegF(env);
1966 *dst_lo = newVRegF(env);
1967 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1968 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1969 return;
florian78d5ef72013-05-11 15:02:58 +00001970 }
sewardj2019a972011-03-07 16:04:07 +00001971
1972 case Iop_F64HLtoF128:
1973 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1974 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1975 return;
1976
florian78d5ef72013-05-11 15:02:58 +00001977 case Iop_D128toF128: {
1978 IRExpr *irrm;
1979 IRExpr *left;
1980 s390_dfp_round_t rm;
1981 HReg op_hi, op_lo;
1982 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
1983
1984 f4 = make_fpr(4); /* source */
1985 f6 = make_fpr(6); /* source */
1986 f0 = make_fpr(0); /* destination */
1987 f2 = make_fpr(2); /* destination */
1988 r1 = make_gpr(1); /* GPR #1 clobbered */
1989
1990 irrm = expr->Iex.Binop.arg1;
1991 left = expr->Iex.Binop.arg2;
1992 rm = get_dfp_rounding_mode(env, irrm);
1993 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
1994 /* operand --> (f4, f6) */
1995 addInstr(env, s390_insn_move(8, f4, op_hi));
1996 addInstr(env, s390_insn_move(8, f6, op_lo));
1997 addInstr(env, s390_insn_fp128_convert(16, S390_FP_D128_TO_F128, f0, f2,
1998 f4, f6, r1, rm));
1999 /* (f0, f2) --> destination */
2000 *dst_hi = newVRegF(env);
2001 *dst_lo = newVRegF(env);
2002 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2003 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2004
2005 return;
2006 }
2007
sewardj2019a972011-03-07 16:04:07 +00002008 default:
2009 goto irreducible;
2010 }
2011 }
2012
2013 /* --------- UNARY OP --------- */
2014 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00002015 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00002016 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002017 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002018 HReg op_hi, op_lo, op, f12, f13, f14, f15;
2019
2020 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2021 f12 = make_fpr(12);
2022 f13 = make_fpr(13);
2023 f14 = make_fpr(14);
2024 f15 = make_fpr(15);
2025
florian66e596d2012-09-07 15:00:53 +00002026 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00002027 case Iop_NegF128:
2028 if (left->tag == Iex_Unop &&
2029 (left->Iex.Unop.op == Iop_AbsF32 ||
2030 left->Iex.Unop.op == Iop_AbsF64))
2031 bfpop = S390_BFP_NABS;
2032 else
2033 bfpop = S390_BFP_NEG;
2034 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00002035 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2036 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2037 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2038 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2039 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2040 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2041 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00002042 default:
2043 goto irreducible;
2044 }
2045
2046 float128_opnd:
2047 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2048
2049 /* operand --> (f13, f15) */
2050 addInstr(env, s390_insn_move(8, f13, op_hi));
2051 addInstr(env, s390_insn_move(8, f15, op_lo));
2052
florian2c74d242012-09-12 19:38:42 +00002053 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002054 goto move_dst;
2055
2056 convert_float:
2057 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002058 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002059 goto move_dst;
2060
2061 convert_int:
2062 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002063 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002064 goto move_dst;
2065
2066 move_dst:
2067 /* Move result to virtual destination registers */
2068 *dst_hi = newVRegF(env);
2069 *dst_lo = newVRegF(env);
2070 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2071 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2072 return;
2073 }
2074
2075 default:
2076 goto irreducible;
2077 }
2078
2079 /* We get here if no pattern matched. */
2080 irreducible:
2081 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002082 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002083}
2084
2085/* Compute a 128-bit value into two 64-bit registers. These may be either
2086 real or virtual regs; in any case they must not be changed by subsequent
2087 code emitted by the caller. */
2088static void
2089s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2090{
2091 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2092
2093 /* Sanity checks ... */
2094 vassert(hregIsVirtual(*dst_hi));
2095 vassert(hregIsVirtual(*dst_lo));
2096 vassert(hregClass(*dst_hi) == HRcFlt64);
2097 vassert(hregClass(*dst_lo) == HRcFlt64);
2098}
2099
2100
2101/*---------------------------------------------------------*/
2102/*--- ISEL: Floating point expressions (64 bit) ---*/
2103/*---------------------------------------------------------*/
2104
2105static HReg
2106s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2107{
2108 IRType ty = typeOfIRExpr(env->type_env, expr);
2109 UChar size;
2110
2111 vassert(ty == Ity_F32 || ty == Ity_F64);
2112
2113 size = sizeofIRType(ty);
2114
2115 switch (expr->tag) {
2116 case Iex_RdTmp:
2117 /* Return the virtual register that holds the temporary. */
2118 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2119
2120 /* --------- LOAD --------- */
2121 case Iex_Load: {
2122 HReg dst = newVRegF(env);
2123 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2124
2125 if (expr->Iex.Load.end != Iend_BE)
2126 goto irreducible;
2127
2128 addInstr(env, s390_insn_load(size, dst, am));
2129
2130 return dst;
2131 }
2132
2133 /* --------- GET --------- */
2134 case Iex_Get: {
2135 HReg dst = newVRegF(env);
2136 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2137
2138 addInstr(env, s390_insn_load(size, dst, am));
2139
2140 return dst;
2141 }
2142
2143 /* --------- LITERAL --------- */
2144
2145 /* Load a literal into a register. Create a "load immediate"
2146 v-insn and return the register. */
2147 case Iex_Const: {
2148 ULong value;
2149 HReg dst = newVRegF(env);
2150 const IRConst *con = expr->Iex.Const.con;
2151
2152 /* Bitwise copy of the value. No sign/zero-extension */
2153 switch (con->tag) {
2154 case Ico_F32i: value = con->Ico.F32i; break;
2155 case Ico_F64i: value = con->Ico.F64i; break;
2156 default: vpanic("s390_isel_float_expr: invalid constant");
2157 }
2158
2159 if (value != 0) vpanic("cannot load immediate floating point constant");
2160
2161 addInstr(env, s390_insn_load_immediate(size, dst, value));
2162
2163 return dst;
2164 }
2165
2166 /* --------- 4-ary OP --------- */
2167 case Iex_Qop: {
2168 HReg op1, op2, op3, dst;
2169 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002170
florian5906a6b2012-10-16 02:53:33 +00002171 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002172 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002173 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002174 dst = newVRegF(env);
2175 addInstr(env, s390_insn_move(size, dst, op1));
2176
florian96d7cc32012-06-01 20:41:24 +00002177 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002178 case Iop_MAddF32:
2179 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2180 case Iop_MSubF32:
2181 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2182
2183 default:
2184 goto irreducible;
2185 }
2186
florian2c74d242012-09-12 19:38:42 +00002187 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2188 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002189 return dst;
2190 }
2191
2192 /* --------- TERNARY OP --------- */
2193 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002194 IRTriop *triop = expr->Iex.Triop.details;
2195 IROp op = triop->op;
2196 IRExpr *left = triop->arg2;
2197 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002198 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002199 HReg h1, op2, dst;
2200
2201 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2202 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2203 dst = newVRegF(env);
2204 addInstr(env, s390_insn_move(size, dst, h1));
2205 switch (op) {
2206 case Iop_AddF32:
2207 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2208 case Iop_SubF32:
2209 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2210 case Iop_MulF32:
2211 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2212 case Iop_DivF32:
2213 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2214
2215 default:
2216 goto irreducible;
2217 }
2218
florian2c74d242012-09-12 19:38:42 +00002219 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2220 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002221 return dst;
2222 }
2223
2224 /* --------- BINARY OP --------- */
2225 case Iex_Binop: {
2226 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002227 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002228 IRExpr *left = expr->Iex.Binop.arg2;
2229 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002230 s390_bfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002231 s390_fp_conv_t fpconv;
sewardj2019a972011-03-07 16:04:07 +00002232
2233 switch (op) {
2234 case Iop_SqrtF32:
2235 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002236 h1 = s390_isel_float_expr(env, left);
2237 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002238 set_bfp_rounding_mode_in_fpc(env, irrm);
2239 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002240 return dst;
sewardj2019a972011-03-07 16:04:07 +00002241
florian9fcff4c2012-09-10 03:09:04 +00002242 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2243 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2244 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2245 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2246 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2247 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2248 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
florian78d5ef72013-05-11 15:02:58 +00002249 case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp;
2250 case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00002251
florian9fcff4c2012-09-10 03:09:04 +00002252 convert_float:
2253 h1 = s390_isel_float_expr(env, left);
2254 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002255
florian9fcff4c2012-09-10 03:09:04 +00002256 convert_int:
2257 h1 = s390_isel_int_expr(env, left);
2258 goto convert;
2259
florian2c74d242012-09-12 19:38:42 +00002260 convert: {
florian125e20d2012-10-07 15:42:37 +00002261 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002262 /* convert-from-fixed and load-rounded have a rounding mode field
2263 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002264 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002265 if (s390_host_has_fpext) {
2266 rounding_mode = get_bfp_rounding_mode(env, irrm);
2267 } else {
2268 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002269 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002270 }
florian9fcff4c2012-09-10 03:09:04 +00002271 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2272 rounding_mode));
2273 return dst;
florian2c74d242012-09-12 19:38:42 +00002274 }
florian78d5ef72013-05-11 15:02:58 +00002275
2276 convert_dfp: {
2277 s390_dfp_round_t rm;
2278 HReg f0, f4, r1; /* real registers used by PFPO */
2279
2280 f4 = make_fpr(4); /* source */
2281 f0 = make_fpr(0); /* destination */
2282 r1 = make_gpr(1); /* GPR #1 clobbered */
2283 h1 = s390_isel_dfp_expr(env, left);
2284 dst = newVRegF(env);
2285 rm = get_dfp_rounding_mode(env, irrm);
2286 /* operand --> f4 */
2287 addInstr(env, s390_insn_move(8, f4, h1));
2288 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2289 /* f0 --> destination */
2290 addInstr(env, s390_insn_move(8, dst, f0));
2291 return dst;
2292 }
2293
2294 convert_dfp128: {
2295 s390_dfp_round_t rm;
2296 HReg op_hi, op_lo;
2297 HReg f0, f4, f6, r1; /* real registers used by PFPO */
2298
2299 f4 = make_fpr(4); /* source */
2300 f6 = make_fpr(6); /* source */
2301 f0 = make_fpr(0); /* destination */
2302 r1 = make_gpr(1); /* GPR #1 clobbered */
2303 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2304 dst = newVRegF(env);
2305 rm = get_dfp_rounding_mode(env, irrm);
2306 /* operand --> (f4, f6) */
2307 addInstr(env, s390_insn_move(8, f4, op_hi));
2308 addInstr(env, s390_insn_move(8, f6, op_lo));
2309 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
2310 f4, f6, r1, rm));
2311 /* f0 --> destination */
2312 addInstr(env, s390_insn_move(8, dst, f0));
2313 return dst;
2314 }
2315
sewardj2019a972011-03-07 16:04:07 +00002316 default:
2317 goto irreducible;
2318
2319 case Iop_F128toF64:
2320 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002321 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002322 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002323
florian9fcff4c2012-09-10 03:09:04 +00002324 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2325 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002326
florian9fcff4c2012-09-10 03:09:04 +00002327 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002328
florian9fcff4c2012-09-10 03:09:04 +00002329 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002330 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002331 f15 = make_fpr(15);
2332
2333 /* operand --> (f13, f15) */
2334 addInstr(env, s390_insn_move(8, f13, op_hi));
2335 addInstr(env, s390_insn_move(8, f15, op_lo));
2336
2337 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002338 /* load-rounded has a rounding mode field when the floating point
2339 extension facility is installed. */
2340 if (s390_host_has_fpext) {
2341 rounding_mode = get_bfp_rounding_mode(env, irrm);
2342 } else {
2343 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002344 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002345 }
floriancc491a62012-09-10 23:44:37 +00002346 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002347 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002348 return dst;
2349 }
2350 }
sewardj2019a972011-03-07 16:04:07 +00002351 }
2352
2353 /* --------- UNARY OP --------- */
2354 case Iex_Unop: {
2355 IROp op = expr->Iex.Unop.op;
2356 IRExpr *left = expr->Iex.Unop.arg;
2357 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002358 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002359 HReg h1, dst;
2360
2361 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2362 HReg dst_hi, dst_lo;
2363
2364 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2365 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2366 }
2367
florian4d71a082011-12-18 00:08:17 +00002368 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002369 dst = newVRegF(env);
2370 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2371 addInstr(env, s390_insn_move(size, dst, h1));
2372
2373 return dst;
2374 }
2375
2376 switch (op) {
2377 case Iop_NegF32:
2378 case Iop_NegF64:
2379 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002380 (left->Iex.Unop.op == Iop_AbsF32 ||
2381 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002382 bfpop = S390_BFP_NABS;
2383 else
2384 bfpop = S390_BFP_NEG;
2385 break;
2386
2387 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002388 case Iop_AbsF64:
2389 bfpop = S390_BFP_ABS;
2390 break;
2391
2392 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2393 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2394 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2395
2396 convert_float1:
2397 h1 = s390_isel_float_expr(env, left);
2398 goto convert1;
2399
2400 convert_int1:
2401 h1 = s390_isel_int_expr(env, left);
2402 goto convert1;
2403
2404 convert1:
2405 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002406 /* No rounding mode is needed for these conversions. Just stick
2407 one in. It won't be used later on. */
2408 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002409 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002410 return dst;
2411
sewardj2019a972011-03-07 16:04:07 +00002412 default:
2413 goto irreducible;
2414 }
2415
2416 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002417 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002418 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002419 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002420 return dst;
2421 }
2422
2423 default:
2424 goto irreducible;
2425 }
2426
2427 /* We get here if no pattern matched. */
2428 irreducible:
2429 ppIRExpr(expr);
2430 vpanic("s390_isel_float_expr: cannot reduce tree");
2431}
2432
2433
2434static HReg
2435s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2436{
2437 HReg dst = s390_isel_float_expr_wrk(env, expr);
2438
2439 /* Sanity checks ... */
2440 vassert(hregClass(dst) == HRcFlt64);
2441 vassert(hregIsVirtual(dst));
2442
2443 return dst;
2444}
2445
2446
2447/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002448/*--- ISEL: Decimal point expressions (128 bit) ---*/
2449/*---------------------------------------------------------*/
2450static void
2451s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2452 IRExpr *expr)
2453{
2454 IRType ty = typeOfIRExpr(env->type_env, expr);
2455
2456 vassert(ty == Ity_D128);
2457
2458 switch (expr->tag) {
2459 case Iex_RdTmp:
2460 /* Return the virtual registers that hold the temporary. */
2461 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2462 return;
2463
2464 /* --------- LOAD --------- */
2465 case Iex_Load: {
2466 IRExpr *addr_hi, *addr_lo;
2467 s390_amode *am_hi, *am_lo;
2468
2469 if (expr->Iex.Load.end != Iend_BE)
2470 goto irreducible;
2471
2472 addr_hi = expr->Iex.Load.addr;
2473 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2474
2475 am_hi = s390_isel_amode(env, addr_hi);
2476 am_lo = s390_isel_amode(env, addr_lo);
2477
2478 *dst_hi = newVRegF(env);
2479 *dst_lo = newVRegF(env);
2480 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2481 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2482 return;
2483 }
2484
2485 /* --------- GET --------- */
2486 case Iex_Get:
2487 /* This is not supported because loading 128-bit from the guest
2488 state is almost certainly wrong. Use get_dpr_pair instead. */
2489 vpanic("Iex_Get with D128 data");
2490
2491 /* --------- 4-ary OP --------- */
2492 case Iex_Qop:
2493 vpanic("Iex_Qop with D128 data");
2494
2495 /* --------- TERNARY OP --------- */
2496 case Iex_Triop: {
2497 IRTriop *triop = expr->Iex.Triop.details;
2498 IROp op = triop->op;
2499 IRExpr *irrm = triop->arg1;
2500 IRExpr *left = triop->arg2;
2501 IRExpr *right = triop->arg3;
2502 s390_dfp_round_t rounding_mode;
2503 s390_dfp_binop_t dfpop;
2504 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2505
floriane38f6412012-12-21 17:32:12 +00002506 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2507 (f12, f14) as op2 and (f13, f15) as destination) */
2508 f9 = make_fpr(9);
2509 f11 = make_fpr(11);
2510 f12 = make_fpr(12);
2511 f13 = make_fpr(13);
2512 f14 = make_fpr(14);
2513 f15 = make_fpr(15);
2514
floriane38f6412012-12-21 17:32:12 +00002515 switch (op) {
florian5c539732013-02-14 14:27:12 +00002516 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128;
2517 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128;
2518 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128;
2519 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128;
2520 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
2521
2522 evaluate_dfp128: {
2523 /* Process 1st operand */
2524 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
2525 /* 1st operand --> (f9, f11) */
2526 addInstr(env, s390_insn_move(8, f9, op1_hi));
2527 addInstr(env, s390_insn_move(8, f11, op1_lo));
2528
2529 /* Process 2nd operand */
2530 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2531 /* 2nd operand --> (f12, f14) */
2532 addInstr(env, s390_insn_move(8, f12, op2_hi));
2533 addInstr(env, s390_insn_move(8, f14, op2_lo));
2534
2535 /* DFP arithmetic ops take rounding mode only when fpext is
2536 installed. But, DFP quantize operation takes rm irrespective
2537 of fpext facility . */
floriand18287d2013-02-21 03:03:05 +00002538 if (s390_host_has_fpext || op == Iop_QuantizeD128) {
florian5c539732013-02-14 14:27:12 +00002539 rounding_mode = get_dfp_rounding_mode(env, irrm);
2540 } else {
2541 set_dfp_rounding_mode_in_fpc(env, irrm);
2542 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2543 }
2544 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2545 f12, f14, rounding_mode));
2546 /* Move result to virtual destination register */
2547 *dst_hi = newVRegF(env);
2548 *dst_lo = newVRegF(env);
2549 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2550 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2551 return;
2552 }
2553
2554 case Iop_SignificanceRoundD128: {
2555 /* Process 1st operand */
2556 HReg op1 = s390_isel_int_expr(env, left);
2557 /* Process 2nd operand */
2558 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2559 /* 2nd operand --> (f12, f14) */
2560 addInstr(env, s390_insn_move(8, f12, op2_hi));
2561 addInstr(env, s390_insn_move(8, f14, op2_lo));
2562
2563 rounding_mode = get_dfp_rounding_mode(env, irrm);
2564 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14,
2565 rounding_mode));
2566 /* Move result to virtual destination register */
2567 *dst_hi = newVRegF(env);
2568 *dst_lo = newVRegF(env);
2569 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2570 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2571 return;
2572 }
2573
floriane38f6412012-12-21 17:32:12 +00002574 default:
2575 goto irreducible;
2576 }
floriane38f6412012-12-21 17:32:12 +00002577 }
2578
2579 /* --------- BINARY OP --------- */
2580 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002581
floriane38f6412012-12-21 17:32:12 +00002582 switch (expr->Iex.Binop.op) {
2583 case Iop_D64HLtoD128:
2584 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2585 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2586 return;
2587
florian1b901d42013-01-01 22:19:24 +00002588 case Iop_ShlD128:
florian5c539732013-02-14 14:27:12 +00002589 case Iop_ShrD128:
2590 case Iop_InsertExpD128: {
florian1b901d42013-01-01 22:19:24 +00002591 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2592 s390_dfp_intop_t intop;
florian5c539732013-02-14 14:27:12 +00002593 IRExpr *dfp_op;
2594 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00002595
2596 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00002597 case Iop_ShlD128: /* (D128, I64) -> D128 */
2598 intop = S390_DFP_SHIFT_LEFT;
2599 dfp_op = expr->Iex.Binop.arg1;
2600 int_op = expr->Iex.Binop.arg2;
2601 break;
2602 case Iop_ShrD128: /* (D128, I64) -> D128 */
2603 intop = S390_DFP_SHIFT_RIGHT;
2604 dfp_op = expr->Iex.Binop.arg1;
2605 int_op = expr->Iex.Binop.arg2;
2606 break;
2607 case Iop_InsertExpD128: /* (I64, D128) -> D128 */
2608 intop = S390_DFP_INSERT_EXP;
2609 int_op = expr->Iex.Binop.arg1;
2610 dfp_op = expr->Iex.Binop.arg2;
2611 break;
florian1b901d42013-01-01 22:19:24 +00002612 default: goto irreducible;
2613 }
2614
2615 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2616 f9 = make_fpr(9); /* 128 bit dfp operand */
2617 f11 = make_fpr(11);
2618
2619 f13 = make_fpr(13); /* 128 bit dfp destination */
2620 f15 = make_fpr(15);
2621
florian5c539732013-02-14 14:27:12 +00002622 /* Process dfp operand */
2623 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
2624 /* op1 -> (f9,f11) */
florian1b901d42013-01-01 22:19:24 +00002625 addInstr(env, s390_insn_move(8, f9, op1_hi));
2626 addInstr(env, s390_insn_move(8, f11, op1_lo));
2627
florian5c539732013-02-14 14:27:12 +00002628 op2 = s390_isel_int_expr(env, int_op); /* int operand */
florian1b901d42013-01-01 22:19:24 +00002629
2630 addInstr(env,
2631 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2632
2633 /* Move result to virtual destination register */
2634 *dst_hi = newVRegF(env);
2635 *dst_lo = newVRegF(env);
2636 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2637 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2638 return;
2639 }
2640
florian78d5ef72013-05-11 15:02:58 +00002641 case Iop_F64toD128: {
2642 IRExpr *irrm;
2643 IRExpr *left;
2644 s390_dfp_round_t rm;
2645 HReg h1; /* virtual reg. to hold source */
2646 HReg f0, f2, f4, r1; /* real registers used by PFPO */
2647
2648 f4 = make_fpr(4); /* source */
2649 f0 = make_fpr(0); /* destination */
2650 f2 = make_fpr(2); /* destination */
2651 r1 = make_gpr(1); /* GPR #1 clobbered */
2652 irrm = expr->Iex.Binop.arg1;
2653 left = expr->Iex.Binop.arg2;
2654 rm = get_dfp_rounding_mode(env, irrm);
2655 h1 = s390_isel_float_expr(env, left);
2656 addInstr(env, s390_insn_move(8, f4, h1));
2657 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F64_TO_D128, f0, f2,
2658 f4, INVALID_HREG, r1, rm));
2659 /* (f0, f2) --> destination */
2660 *dst_hi = newVRegF(env);
2661 *dst_lo = newVRegF(env);
2662 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2663 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2664
2665 return;
2666 }
2667
2668 case Iop_F128toD128: {
2669 IRExpr *irrm;
2670 IRExpr *left;
2671 s390_dfp_round_t rm;
2672 HReg op_hi, op_lo;
2673 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2674
2675 f4 = make_fpr(4); /* source */
2676 f6 = make_fpr(6); /* source */
2677 f0 = make_fpr(0); /* destination */
2678 f2 = make_fpr(2); /* destination */
2679 r1 = make_gpr(1); /* GPR #1 clobbered */
2680
2681 irrm = expr->Iex.Binop.arg1;
2682 left = expr->Iex.Binop.arg2;
2683 rm = get_dfp_rounding_mode(env, irrm);
2684 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2685 /* operand --> (f4, f6) */
2686 addInstr(env, s390_insn_move(8, f4, op_hi));
2687 addInstr(env, s390_insn_move(8, f6, op_lo));
2688 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2,
2689 f4, f6, r1, rm));
2690 /* (f0, f2) --> destination */
2691 *dst_hi = newVRegF(env);
2692 *dst_lo = newVRegF(env);
2693 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2694 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2695
2696 return;
2697 }
2698
floriane38f6412012-12-21 17:32:12 +00002699 default:
2700 goto irreducible;
2701 }
2702 }
2703
2704 /* --------- UNARY OP --------- */
2705 case Iex_Unop: {
2706 IRExpr *left = expr->Iex.Unop.arg;
2707 s390_dfp_conv_t conv;
floriane38f6412012-12-21 17:32:12 +00002708 HReg op, f12, f14;
2709
floriana887acd2013-02-08 23:32:54 +00002710 /* We use non-virtual registers as pairs (f12, f14)) */
floriane38f6412012-12-21 17:32:12 +00002711 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00002712 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00002713
2714 switch (expr->Iex.Unop.op) {
2715 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002716 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
floriana887acd2013-02-08 23:32:54 +00002717 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002718 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2719 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002720 default:
2721 goto irreducible;
2722 }
2723
2724 convert_dfp:
2725 op = s390_isel_dfp_expr(env, left);
2726 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2727 goto move_dst;
2728
florian5f034622013-01-13 02:29:05 +00002729 convert_int:
2730 op = s390_isel_int_expr(env, left);
2731 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2732 goto move_dst;
2733
floriane38f6412012-12-21 17:32:12 +00002734 move_dst:
2735 /* Move result to virtual destination registers */
2736 *dst_hi = newVRegF(env);
2737 *dst_lo = newVRegF(env);
2738 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2739 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2740 return;
2741 }
2742
2743 default:
2744 goto irreducible;
2745 }
2746
2747 /* We get here if no pattern matched. */
2748 irreducible:
2749 ppIRExpr(expr);
2750 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2751
2752}
2753
2754
2755/* Compute a 128-bit value into two 64-bit registers. These may be either
2756 real or virtual regs; in any case they must not be changed by subsequent
2757 code emitted by the caller. */
2758static void
2759s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2760{
2761 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2762
2763 /* Sanity checks ... */
2764 vassert(hregIsVirtual(*dst_hi));
2765 vassert(hregIsVirtual(*dst_lo));
2766 vassert(hregClass(*dst_hi) == HRcFlt64);
2767 vassert(hregClass(*dst_lo) == HRcFlt64);
2768}
2769
2770
2771/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002772/*--- ISEL: Decimal point expressions (64 bit) ---*/
2773/*---------------------------------------------------------*/
2774
2775static HReg
2776s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2777{
2778 IRType ty = typeOfIRExpr(env->type_env, expr);
2779 UChar size;
2780
floriane38f6412012-12-21 17:32:12 +00002781 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002782
2783 size = sizeofIRType(ty);
2784
2785 switch (expr->tag) {
2786 case Iex_RdTmp:
2787 /* Return the virtual register that holds the temporary. */
2788 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2789
2790 /* --------- LOAD --------- */
2791 case Iex_Load: {
2792 HReg dst = newVRegF(env);
2793 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2794
2795 if (expr->Iex.Load.end != Iend_BE)
2796 goto irreducible;
2797
2798 addInstr(env, s390_insn_load(size, dst, am));
2799
2800 return dst;
2801 }
2802
2803 /* --------- GET --------- */
2804 case Iex_Get: {
2805 HReg dst = newVRegF(env);
2806 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2807
2808 addInstr(env, s390_insn_load(size, dst, am));
2809
2810 return dst;
2811 }
2812
floriane38f6412012-12-21 17:32:12 +00002813 /* --------- BINARY OP --------- */
2814 case Iex_Binop: {
2815 IROp op = expr->Iex.Binop.op;
2816 IRExpr *irrm = expr->Iex.Binop.arg1;
2817 IRExpr *left = expr->Iex.Binop.arg2;
2818 HReg h1, dst;
2819 s390_dfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002820 s390_fp_conv_t fpconv;
floriane38f6412012-12-21 17:32:12 +00002821
2822 switch (op) {
2823 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
floriana887acd2013-02-08 23:32:54 +00002824 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002825 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
florian78d5ef72013-05-11 15:02:58 +00002826 case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
floriane38f6412012-12-21 17:32:12 +00002827
2828 convert_dfp:
2829 h1 = s390_isel_dfp_expr(env, left);
2830 goto convert;
2831
florian5f034622013-01-13 02:29:05 +00002832 convert_int:
2833 h1 = s390_isel_int_expr(env, left);
2834 goto convert;
2835
floriane38f6412012-12-21 17:32:12 +00002836 convert: {
2837 s390_dfp_round_t rounding_mode;
2838 /* convert-from-fixed and load-rounded have a rounding mode field
2839 when the floating point extension facility is installed. */
2840 dst = newVRegF(env);
2841 if (s390_host_has_fpext) {
2842 rounding_mode = get_dfp_rounding_mode(env, irrm);
2843 } else {
2844 set_dfp_rounding_mode_in_fpc(env, irrm);
2845 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2846 }
2847 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2848 rounding_mode));
2849 return dst;
2850 }
floriane38f6412012-12-21 17:32:12 +00002851
florian78d5ef72013-05-11 15:02:58 +00002852 convert_bfp: {
2853 s390_dfp_round_t rm;
2854 HReg f0, f4, r1; /* real registers used by PFPO */
2855
2856 f4 = make_fpr(4); /* source */
2857 f0 = make_fpr(0); /* destination */
2858 r1 = make_gpr(1); /* GPR #1 clobbered */
2859 h1 = s390_isel_float_expr(env, left);
2860 dst = newVRegF(env);
2861 rm = get_dfp_rounding_mode(env, irrm);
2862 /* operand --> f4 */
2863 addInstr(env, s390_insn_move(8, f4, h1));
2864 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2865 /* f0 --> destination */
2866 addInstr(env, s390_insn_move(8, dst, f0));
2867 return dst;
2868 }
2869
floriane38f6412012-12-21 17:32:12 +00002870 case Iop_D128toD64: {
2871 HReg op_hi, op_lo, f13, f15;
2872 s390_dfp_round_t rounding_mode;
2873
2874 conv = S390_DFP_D128_TO_D64;
2875
2876 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2877
2878 /* We use non-virtual registers as pairs (f13, f15) */
2879 f13 = make_fpr(13);
2880 f15 = make_fpr(15);
2881
2882 /* operand --> (f13, f15) */
2883 addInstr(env, s390_insn_move(8, f13, op_hi));
2884 addInstr(env, s390_insn_move(8, f15, op_lo));
2885
2886 dst = newVRegF(env);
2887 /* load-rounded has a rounding mode field when the floating point
2888 extension facility is installed. */
2889 if (s390_host_has_fpext) {
2890 rounding_mode = get_dfp_rounding_mode(env, irrm);
2891 } else {
2892 set_dfp_rounding_mode_in_fpc(env, irrm);
2893 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2894 }
2895 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2896 rounding_mode));
2897 return dst;
2898 }
2899
florian1b901d42013-01-01 22:19:24 +00002900 case Iop_ShlD64:
florian5c539732013-02-14 14:27:12 +00002901 case Iop_ShrD64:
2902 case Iop_InsertExpD64: {
florian1b901d42013-01-01 22:19:24 +00002903 HReg op2;
2904 HReg op3;
florian5c539732013-02-14 14:27:12 +00002905 IRExpr *dfp_op;
2906 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00002907 s390_dfp_intop_t intop;
florian1b901d42013-01-01 22:19:24 +00002908
2909 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00002910 case Iop_ShlD64: /* (D64, I64) -> D64 */
2911 intop = S390_DFP_SHIFT_LEFT;
2912 dfp_op = expr->Iex.Binop.arg1;
2913 int_op = expr->Iex.Binop.arg2;
2914 break;
2915 case Iop_ShrD64: /* (D64, I64) -> D64 */
2916 intop = S390_DFP_SHIFT_RIGHT;
2917 dfp_op = expr->Iex.Binop.arg1;
2918 int_op = expr->Iex.Binop.arg2;
2919 break;
2920 case Iop_InsertExpD64: /* (I64, D64) -> D64 */
2921 intop = S390_DFP_INSERT_EXP;
2922 int_op = expr->Iex.Binop.arg1;
2923 dfp_op = expr->Iex.Binop.arg2;
2924 break;
florian1b901d42013-01-01 22:19:24 +00002925 default: goto irreducible;
2926 }
2927
florian5c539732013-02-14 14:27:12 +00002928 op2 = s390_isel_int_expr(env, int_op);
2929 op3 = s390_isel_dfp_expr(env, dfp_op);
florian1b901d42013-01-01 22:19:24 +00002930 dst = newVRegF(env);
2931
2932 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
2933 return dst;
2934 }
2935
2936 default:
2937 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00002938 }
2939 }
2940
2941 /* --------- UNARY OP --------- */
2942 case Iex_Unop: {
2943 IROp op = expr->Iex.Unop.op;
2944 IRExpr *left = expr->Iex.Unop.arg;
2945 s390_dfp_conv_t conv;
2946 HReg h1, dst;
2947
2948 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2949 HReg dst_hi, dst_lo;
2950
2951 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2952 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2953 }
2954
2955 if (op == Iop_ReinterpI64asD64) {
2956 dst = newVRegF(env);
2957 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2958 addInstr(env, s390_insn_move(size, dst, h1));
2959
2960 return dst;
2961 }
2962
2963 switch (op) {
2964 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00002965 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
2966 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00002967
2968 convert_dfp1:
2969 h1 = s390_isel_dfp_expr(env, left);
2970 goto convert1;
2971
florian5f034622013-01-13 02:29:05 +00002972 convert_int1:
2973 h1 = s390_isel_int_expr(env, left);
2974 goto convert1;
2975
floriane38f6412012-12-21 17:32:12 +00002976 convert1:
2977 dst = newVRegF(env);
2978 /* No rounding mode is needed for these conversions. Just stick
2979 one in. It won't be used later on. */
2980 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2981 S390_DFP_ROUND_NEAREST_EVEN_4));
2982 return dst;
2983
2984 default:
2985 goto irreducible;
2986 }
2987 }
2988
florian12390202012-11-10 22:34:14 +00002989 /* --------- TERNARY OP --------- */
2990 case Iex_Triop: {
2991 IRTriop *triop = expr->Iex.Triop.details;
2992 IROp op = triop->op;
2993 IRExpr *irrm = triop->arg1;
2994 IRExpr *left = triop->arg2;
2995 IRExpr *right = triop->arg3;
2996 s390_dfp_round_t rounding_mode;
2997 s390_dfp_binop_t dfpop;
2998 HReg op2, op3, dst;
2999
florian12390202012-11-10 22:34:14 +00003000 switch (op) {
florian5c539732013-02-14 14:27:12 +00003001 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp;
3002 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp;
3003 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp;
3004 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp;
3005 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
3006
3007 evaluate_dfp: {
3008 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
3009 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3010 dst = newVRegF(env);
3011 /* DFP arithmetic ops take rounding mode only when fpext is
3012 installed. But, DFP quantize operation takes rm irrespective
3013 of fpext facility . */
3014 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
3015 rounding_mode = get_dfp_rounding_mode(env, irrm);
3016 } else {
3017 set_dfp_rounding_mode_in_fpc(env, irrm);
3018 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3019 }
3020 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3,
3021 rounding_mode));
3022 return dst;
3023 }
3024
3025 case Iop_SignificanceRoundD64:
3026 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */
3027 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3028 dst = newVRegF(env);
3029 rounding_mode = get_dfp_rounding_mode(env, irrm);
3030 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3,
3031 rounding_mode));
3032 return dst;
3033
florian12390202012-11-10 22:34:14 +00003034 default:
3035 goto irreducible;
3036 }
florian12390202012-11-10 22:34:14 +00003037 }
3038
3039 default:
3040 goto irreducible;
3041 }
3042
3043 /* We get here if no pattern matched. */
3044 irreducible:
3045 ppIRExpr(expr);
3046 vpanic("s390_isel_dfp_expr: cannot reduce tree");
3047}
3048
3049static HReg
3050s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
3051{
3052 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
3053
3054 /* Sanity checks ... */
3055 vassert(hregClass(dst) == HRcFlt64);
3056 vassert(hregIsVirtual(dst));
3057
3058 return dst;
3059}
3060
3061
3062/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00003063/*--- ISEL: Condition Code ---*/
3064/*---------------------------------------------------------*/
3065
3066/* This function handles all operators that produce a 1-bit result */
3067static s390_cc_t
3068s390_isel_cc(ISelEnv *env, IRExpr *cond)
3069{
3070 UChar size;
3071
3072 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
3073
3074 /* Constant: either 1 or 0 */
3075 if (cond->tag == Iex_Const) {
3076 vassert(cond->Iex.Const.con->tag == Ico_U1);
3077 vassert(cond->Iex.Const.con->Ico.U1 == True
3078 || cond->Iex.Const.con->Ico.U1 == False);
3079
3080 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
3081 }
3082
3083 /* Variable: values are 1 or 0 */
3084 if (cond->tag == Iex_RdTmp) {
3085 IRTemp tmp = cond->Iex.RdTmp.tmp;
3086 HReg reg = lookupIRTemp(env, tmp);
3087
3088 /* Load-and-test does not modify REG; so this is OK. */
3089 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
3090 size = 4;
3091 else
3092 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
3093 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
3094 return S390_CC_NE;
3095 }
3096
3097 /* Unary operators */
3098 if (cond->tag == Iex_Unop) {
3099 IRExpr *arg = cond->Iex.Unop.arg;
3100
3101 switch (cond->Iex.Unop.op) {
3102 case Iop_Not1: /* Not1(cond) */
3103 /* Generate code for EXPR, and negate the test condition */
3104 return s390_cc_invert(s390_isel_cc(env, arg));
3105
3106 /* Iop_32/64to1 select the LSB from their operand */
3107 case Iop_32to1:
3108 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00003109 HReg dst = newVRegI(env);
3110 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00003111
3112 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3113
florianf366a802012-08-03 00:42:18 +00003114 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00003115 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
3116 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
3117 return S390_CC_NE;
3118 }
3119
3120 case Iop_CmpNEZ8:
3121 case Iop_CmpNEZ16: {
3122 s390_opnd_RMI src;
3123 s390_unop_t op;
3124 HReg dst;
3125
3126 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
3127 : S390_ZERO_EXTEND_16;
3128 dst = newVRegI(env);
3129 src = s390_isel_int_expr_RMI(env, arg);
3130 addInstr(env, s390_insn_unop(4, op, dst, src));
3131 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
3132 return S390_CC_NE;
3133 }
3134
3135 case Iop_CmpNEZ32:
3136 case Iop_CmpNEZ64: {
3137 s390_opnd_RMI src;
3138
3139 src = s390_isel_int_expr_RMI(env, arg);
3140 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3141 addInstr(env, s390_insn_test(size, src));
3142 return S390_CC_NE;
3143 }
3144
3145 default:
3146 goto fail;
3147 }
3148 }
3149
3150 /* Binary operators */
3151 if (cond->tag == Iex_Binop) {
3152 IRExpr *arg1 = cond->Iex.Binop.arg1;
3153 IRExpr *arg2 = cond->Iex.Binop.arg2;
3154 HReg reg1, reg2;
3155
3156 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
3157
3158 switch (cond->Iex.Binop.op) {
3159 s390_unop_t op;
3160 s390_cc_t result;
3161
3162 case Iop_CmpEQ8:
3163 case Iop_CasCmpEQ8:
3164 op = S390_ZERO_EXTEND_8;
3165 result = S390_CC_E;
3166 goto do_compare_ze;
3167
3168 case Iop_CmpNE8:
3169 case Iop_CasCmpNE8:
3170 op = S390_ZERO_EXTEND_8;
3171 result = S390_CC_NE;
3172 goto do_compare_ze;
3173
3174 case Iop_CmpEQ16:
3175 case Iop_CasCmpEQ16:
3176 op = S390_ZERO_EXTEND_16;
3177 result = S390_CC_E;
3178 goto do_compare_ze;
3179
3180 case Iop_CmpNE16:
3181 case Iop_CasCmpNE16:
3182 op = S390_ZERO_EXTEND_16;
3183 result = S390_CC_NE;
3184 goto do_compare_ze;
3185
3186 do_compare_ze: {
3187 s390_opnd_RMI op1, op2;
3188
3189 op1 = s390_isel_int_expr_RMI(env, arg1);
3190 reg1 = newVRegI(env);
3191 addInstr(env, s390_insn_unop(4, op, reg1, op1));
3192
3193 op2 = s390_isel_int_expr_RMI(env, arg2);
3194 reg2 = newVRegI(env);
3195 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
3196
3197 op2 = s390_opnd_reg(reg2);
3198 addInstr(env, s390_insn_compare(4, reg1, op2, False));
3199
3200 return result;
3201 }
3202
3203 case Iop_CmpEQ32:
3204 case Iop_CmpEQ64:
3205 case Iop_CasCmpEQ32:
3206 case Iop_CasCmpEQ64:
3207 result = S390_CC_E;
3208 goto do_compare;
3209
3210 case Iop_CmpNE32:
3211 case Iop_CmpNE64:
3212 case Iop_CasCmpNE32:
3213 case Iop_CasCmpNE64:
3214 result = S390_CC_NE;
3215 goto do_compare;
3216
3217 do_compare: {
3218 HReg op1;
3219 s390_opnd_RMI op2;
3220
3221 order_commutative_operands(arg1, arg2);
3222
3223 op1 = s390_isel_int_expr(env, arg1);
3224 op2 = s390_isel_int_expr_RMI(env, arg2);
3225
3226 addInstr(env, s390_insn_compare(size, op1, op2, False));
3227
3228 return result;
3229 }
3230
3231 case Iop_CmpLT32S:
3232 case Iop_CmpLE32S:
3233 case Iop_CmpLT64S:
3234 case Iop_CmpLE64S: {
3235 HReg op1;
3236 s390_opnd_RMI op2;
3237
3238 op1 = s390_isel_int_expr(env, arg1);
3239 op2 = s390_isel_int_expr_RMI(env, arg2);
3240
3241 addInstr(env, s390_insn_compare(size, op1, op2, True));
3242
3243 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3244 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3245 }
3246
3247 case Iop_CmpLT32U:
3248 case Iop_CmpLE32U:
3249 case Iop_CmpLT64U:
3250 case Iop_CmpLE64U: {
3251 HReg op1;
3252 s390_opnd_RMI op2;
3253
3254 op1 = s390_isel_int_expr(env, arg1);
3255 op2 = s390_isel_int_expr_RMI(env, arg2);
3256
3257 addInstr(env, s390_insn_compare(size, op1, op2, False));
3258
3259 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3260 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3261 }
3262
3263 default:
3264 goto fail;
3265 }
3266 }
3267
3268 fail:
3269 ppIRExpr(cond);
3270 vpanic("s390_isel_cc: unexpected operator");
3271}
3272
3273
3274/*---------------------------------------------------------*/
3275/*--- ISEL: Statements ---*/
3276/*---------------------------------------------------------*/
3277
3278static void
3279s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3280{
3281 if (vex_traceflags & VEX_TRACE_VCODE) {
3282 vex_printf("\n -- ");
3283 ppIRStmt(stmt);
3284 vex_printf("\n");
3285 }
3286
3287 switch (stmt->tag) {
3288
3289 /* --------- STORE --------- */
3290 case Ist_Store: {
3291 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3292 s390_amode *am;
3293 HReg src;
3294
3295 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3296
3297 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3298
3299 switch (tyd) {
3300 case Ity_I8:
3301 case Ity_I16:
3302 case Ity_I32:
3303 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003304 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003305 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003306 stmt->Ist.Store.data->tag == Iex_Const) {
3307 ULong value =
3308 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3309 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003310 return;
3311 }
floriancec3a8a2013-02-02 00:16:58 +00003312 /* Check whether we can use a memcpy here. Currently, the restriction
3313 is that both amodes need to be B12, so MVC can be emitted.
3314 We do not consider a store whose data expression is a load because
3315 we don't want to deal with overlapping locations. */
3316 /* store(get) never overlaps*/
3317 if (am->tag == S390_AMODE_B12 &&
3318 stmt->Ist.Store.data->tag == Iex_Get) {
3319 UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
3320 s390_amode *from = s390_amode_for_guest_state(offset);
3321 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
3322 return;
3323 }
3324 /* General case: compile data into a register */
sewardj2019a972011-03-07 16:04:07 +00003325 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3326 break;
3327
3328 case Ity_F32:
3329 case Ity_F64:
3330 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3331 break;
3332
florianeb981ae2012-12-21 18:55:03 +00003333 case Ity_D32:
3334 case Ity_D64:
3335 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3336 break;
3337
sewardj2019a972011-03-07 16:04:07 +00003338 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003339 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003340 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003341 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003342
3343 default:
3344 goto stmt_fail;
3345 }
3346
3347 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3348 return;
3349 }
3350
3351 /* --------- PUT --------- */
3352 case Ist_Put: {
3353 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3354 HReg src;
3355 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003356 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003357
florianad43b3a2012-02-20 15:01:14 +00003358 /* Detect updates to certain guest registers. We track the contents
3359 of those registers as long as they contain constants. If the new
3360 constant is either zero or in the 8-bit neighbourhood of the
3361 current value we can use a memory-to-memory insn to do the update. */
3362
3363 Int offset = stmt->Ist.Put.offset;
3364
3365 /* Check necessary conditions:
3366 (1) must be one of the registers we care about
3367 (2) assigned value must be a constant */
3368 Int guest_reg = get_guest_reg(offset);
3369
3370 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3371
florianad43b3a2012-02-20 15:01:14 +00003372 if (stmt->Ist.Put.data->tag != Iex_Const) {
3373 /* Invalidate guest register contents */
3374 env->old_value_valid[guest_reg] = False;
3375 goto not_special;
3376 }
3377
cborntraaf7ad282012-08-08 14:11:33 +00003378 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3379 if (tyd != Ity_I64)
3380 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003381
cborntraaf7ad282012-08-08 14:11:33 +00003382 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003383
3384 old_value = env->old_value[guest_reg];
3385 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3386 env->old_value[guest_reg] = new_value;
3387
3388 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3389 env->old_value_valid[guest_reg] = True;
3390
3391 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003392 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003393 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003394 return;
florianad43b3a2012-02-20 15:01:14 +00003395 }
3396
florianad43b3a2012-02-20 15:01:14 +00003397 if (old_value_is_valid == False) goto not_special;
3398
3399 /* If the new value is in the neighbourhood of the old value
3400 we can use a memory-to-memory insn */
3401 difference = new_value - old_value;
3402
3403 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003404 am = s390_amode_for_guest_state(offset);
3405 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003406 (difference & 0xFF), new_value));
3407 return;
3408 }
3409
florianb93348d2012-12-27 00:59:43 +00003410 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003411 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003412 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003413 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003414 return;
3415 }
3416
3417 /* No special case applies... fall through */
3418
3419 not_special:
florianb93348d2012-12-27 00:59:43 +00003420 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003421
3422 switch (tyd) {
3423 case Ity_I8:
3424 case Ity_I16:
3425 case Ity_I32:
3426 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003427 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003428 stmt->Ist.Put.data->tag == Iex_Const) {
3429 ULong value =
3430 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3431 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003432 return;
3433 }
floriancec3a8a2013-02-02 00:16:58 +00003434 /* Check whether we can use a memcpy here. Currently, the restriction
3435 is that both amodes need to be B12, so MVC can be emitted. */
3436 /* put(load) never overlaps */
3437 if (am->tag == S390_AMODE_B12 &&
3438 stmt->Ist.Put.data->tag == Iex_Load) {
3439 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
3440 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
3441 s390_amode *from = s390_isel_amode(env, data);
3442 UInt size = sizeofIRType(tyd);
3443
3444 if (from->tag == S390_AMODE_B12) {
3445 /* Source can be compiled into a B12 amode. */
3446 addInstr(env, s390_insn_memcpy(size, am, from));
3447 return;
3448 }
3449
3450 src = newVRegI(env);
3451 addInstr(env, s390_insn_load(size, src, from));
3452 break;
3453 }
3454 /* put(get) */
3455 if (am->tag == S390_AMODE_B12 &&
3456 stmt->Ist.Put.data->tag == Iex_Get) {
3457 UInt put_offset = am->d;
3458 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
3459 UInt size = sizeofIRType(tyd);
3460 /* don't memcpy in case of overlap */
3461 if (put_offset + size <= get_offset ||
3462 get_offset + size <= put_offset) {
3463 s390_amode *from = s390_amode_for_guest_state(get_offset);
3464 addInstr(env, s390_insn_memcpy(size, am, from));
3465 return;
3466 }
3467 goto no_memcpy_put;
3468 }
3469 /* General case: compile data into a register */
3470no_memcpy_put:
sewardj2019a972011-03-07 16:04:07 +00003471 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3472 break;
3473
3474 case Ity_F32:
3475 case Ity_F64:
3476 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3477 break;
3478
3479 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003480 case Ity_D128:
3481 /* Does not occur. See function put_(f|d)pr_pair. */
3482 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003483
floriane38f6412012-12-21 17:32:12 +00003484 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003485 case Ity_D64:
3486 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3487 break;
3488
sewardj2019a972011-03-07 16:04:07 +00003489 default:
3490 goto stmt_fail;
3491 }
3492
3493 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3494 return;
3495 }
3496
3497 /* --------- TMP --------- */
3498 case Ist_WrTmp: {
3499 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3500 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3501 HReg src, dst;
3502
3503 switch (tyd) {
3504 case Ity_I128: {
3505 HReg dst_hi, dst_lo, res_hi, res_lo;
3506
3507 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3508 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3509
3510 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3511 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3512 return;
3513 }
3514
3515 case Ity_I8:
3516 case Ity_I16:
3517 case Ity_I32:
3518 case Ity_I64:
3519 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3520 dst = lookupIRTemp(env, tmp);
3521 break;
3522
3523 case Ity_I1: {
3524 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3525 dst = lookupIRTemp(env, tmp);
3526 addInstr(env, s390_insn_cc2bool(dst, cond));
3527 return;
3528 }
3529
3530 case Ity_F32:
3531 case Ity_F64:
3532 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3533 dst = lookupIRTemp(env, tmp);
3534 break;
3535
3536 case Ity_F128: {
3537 HReg dst_hi, dst_lo, res_hi, res_lo;
3538
3539 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3540 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3541
3542 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3543 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3544 return;
3545 }
3546
floriane38f6412012-12-21 17:32:12 +00003547 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003548 case Ity_D64:
3549 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3550 dst = lookupIRTemp(env, tmp);
3551 break;
3552
floriane38f6412012-12-21 17:32:12 +00003553 case Ity_D128: {
3554 HReg dst_hi, dst_lo, res_hi, res_lo;
3555
3556 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3557 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3558
3559 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3560 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3561 return;
3562 }
3563
sewardj2019a972011-03-07 16:04:07 +00003564 default:
3565 goto stmt_fail;
3566 }
3567
3568 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3569 return;
3570 }
3571
3572 /* --------- Call to DIRTY helper --------- */
3573 case Ist_Dirty: {
3574 IRType retty;
3575 IRDirty* d = stmt->Ist.Dirty.details;
3576 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003577 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003578 Int i;
3579
3580 /* Invalidate tracked values of those guest state registers that are
3581 modified by this helper. */
3582 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003583 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3584 descriptors in guest state effect descriptions. Hence: */
3585 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003586 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3587 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3588 if (guest_reg != GUEST_UNKNOWN)
3589 env->old_value_valid[guest_reg] = False;
3590 }
3591 }
sewardj2019a972011-03-07 16:04:07 +00003592
3593 if (d->nFxState == 0)
3594 vassert(!d->needsBBP);
3595
3596 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3597
florian01ed6e72012-05-27 16:52:43 +00003598 if (d->tmp == IRTemp_INVALID) {
3599 /* No return value. */
3600 dst = INVALID_HREG;
3601 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003602 return;
florian01ed6e72012-05-27 16:52:43 +00003603 }
sewardj2019a972011-03-07 16:04:07 +00003604
3605 retty = typeOfIRTemp(env->type_env, d->tmp);
3606 if (retty == Ity_I64 || retty == Ity_I32
3607 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003608 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003609 dst = lookupIRTemp(env, d->tmp);
3610 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003611 return;
3612 }
3613 break;
3614 }
3615
3616 case Ist_CAS:
3617 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3618 IRCAS *cas = stmt->Ist.CAS.details;
3619 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3620 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3621 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3622 HReg old = lookupIRTemp(env, cas->oldLo);
3623
3624 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3625 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3626 } else {
3627 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3628 }
3629 return;
3630 } else {
florian448cbba2012-06-06 02:26:01 +00003631 IRCAS *cas = stmt->Ist.CAS.details;
3632 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3633 HReg r8, r9, r10, r11, r1;
3634 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3635 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3636 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3637 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3638 HReg old_low = lookupIRTemp(env, cas->oldLo);
3639 HReg old_high = lookupIRTemp(env, cas->oldHi);
3640
3641 /* Use non-virtual registers r8 and r9 as pair for op1
3642 and move op1 there */
3643 r8 = make_gpr(8);
3644 r9 = make_gpr(9);
3645 addInstr(env, s390_insn_move(8, r8, op1_high));
3646 addInstr(env, s390_insn_move(8, r9, op1_low));
3647
3648 /* Use non-virtual registers r10 and r11 as pair for op3
3649 and move op3 there */
3650 r10 = make_gpr(10);
3651 r11 = make_gpr(11);
3652 addInstr(env, s390_insn_move(8, r10, op3_high));
3653 addInstr(env, s390_insn_move(8, r11, op3_low));
3654
3655 /* Register r1 is used as a scratch register */
3656 r1 = make_gpr(1);
3657
3658 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3659 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3660 old_high, old_low, r1));
3661 } else {
3662 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3663 old_high, old_low, r1));
3664 }
3665 addInstr(env, s390_insn_move(8, op1_high, r8));
3666 addInstr(env, s390_insn_move(8, op1_low, r9));
3667 addInstr(env, s390_insn_move(8, op3_high, r10));
3668 addInstr(env, s390_insn_move(8, op3_low, r11));
3669 return;
sewardj2019a972011-03-07 16:04:07 +00003670 }
3671 break;
3672
3673 /* --------- EXIT --------- */
3674 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003675 s390_cc_t cond;
3676 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3677
3678 if (tag != Ico_U64)
3679 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3680
florian8844a632012-04-13 04:04:06 +00003681 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003682 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003683
3684 /* Case: boring transfer to known address */
3685 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3686 if (env->chaining_allowed) {
3687 /* .. almost always true .. */
3688 /* Skip the event check at the dst if this is a forwards
3689 edge. */
3690 Bool to_fast_entry
3691 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3692 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3693 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3694 guest_IA, to_fast_entry));
3695 } else {
3696 /* .. very occasionally .. */
3697 /* We can't use chaining, so ask for an assisted transfer,
3698 as that's the only alternative that is allowable. */
3699 HReg dst = s390_isel_int_expr(env,
3700 IRExpr_Const(stmt->Ist.Exit.dst));
3701 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3702 }
3703 return;
3704 }
3705
3706 /* Case: assisted transfer to arbitrary address */
3707 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003708 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003709 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003710 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003711 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003712 case Ijk_Sys_syscall:
3713 case Ijk_ClientReq:
3714 case Ijk_NoRedir:
3715 case Ijk_Yield:
3716 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003717 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3718 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3719 stmt->Ist.Exit.jk));
3720 return;
3721 }
3722 default:
3723 break;
3724 }
3725
3726 /* Do we ever expect to see any other kind? */
3727 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003728 }
3729
3730 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003731 case Ist_MBE:
3732 switch (stmt->Ist.MBE.event) {
3733 case Imbe_Fence:
3734 addInstr(env, s390_insn_mfence());
3735 return;
3736 default:
3737 break;
3738 }
sewardj2019a972011-03-07 16:04:07 +00003739 break;
3740
3741 /* --------- Miscellaneous --------- */
3742
3743 case Ist_PutI: /* Not needed */
3744 case Ist_IMark: /* Doesn't generate any executable code */
3745 case Ist_NoOp: /* Doesn't generate any executable code */
3746 case Ist_AbiHint: /* Meaningless in IR */
3747 return;
3748
3749 default:
3750 break;
3751 }
3752
3753 stmt_fail:
3754 ppIRStmt(stmt);
3755 vpanic("s390_isel_stmt");
3756}
3757
3758
3759/*---------------------------------------------------------*/
3760/*--- ISEL: Basic block terminators (Nexts) ---*/
3761/*---------------------------------------------------------*/
3762
3763static void
florianffbd84d2012-12-09 02:06:29 +00003764iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003765{
sewardj2019a972011-03-07 16:04:07 +00003766 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003767 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003768 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003769 vex_printf("; exit-");
3770 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003771 vex_printf("\n");
3772 }
3773
florian8844a632012-04-13 04:04:06 +00003774 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3775
3776 /* Case: boring transfer to known address */
3777 if (next->tag == Iex_Const) {
3778 IRConst *cdst = next->Iex.Const.con;
3779 vassert(cdst->tag == Ico_U64);
3780 if (jk == Ijk_Boring || jk == Ijk_Call) {
3781 /* Boring transfer to known address */
3782 if (env->chaining_allowed) {
3783 /* .. almost always true .. */
3784 /* Skip the event check at the dst if this is a forwards
3785 edge. */
3786 Bool to_fast_entry
3787 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3788 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3789 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3790 guest_IA, to_fast_entry));
3791 } else {
3792 /* .. very occasionally .. */
3793 /* We can't use chaining, so ask for an indirect transfer,
3794 as that's the cheapest alternative that is allowable. */
3795 HReg dst = s390_isel_int_expr(env, next);
3796 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3797 Ijk_Boring));
3798 }
3799 return;
3800 }
3801 }
3802
3803 /* Case: call/return (==boring) transfer to any address */
3804 switch (jk) {
3805 case Ijk_Boring:
3806 case Ijk_Ret:
3807 case Ijk_Call: {
3808 HReg dst = s390_isel_int_expr(env, next);
3809 if (env->chaining_allowed) {
3810 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3811 } else {
3812 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3813 Ijk_Boring));
3814 }
3815 return;
3816 }
3817 default:
3818 break;
3819 }
3820
3821 /* Case: some other kind of transfer to any address */
3822 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003823 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003824 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003825 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003826 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003827 case Ijk_Sys_syscall:
3828 case Ijk_ClientReq:
3829 case Ijk_NoRedir:
3830 case Ijk_Yield:
3831 case Ijk_SigTRAP: {
3832 HReg dst = s390_isel_int_expr(env, next);
3833 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3834 return;
3835 }
3836 default:
3837 break;
3838 }
3839
3840 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003841}
3842
3843
3844/*---------------------------------------------------------*/
3845/*--- Insn selector top-level ---*/
3846/*---------------------------------------------------------*/
3847
florianf26994a2012-04-21 03:34:54 +00003848/* Translate an entire SB to s390 code.
3849 Note: archinfo_host is a pointer to a stack-allocated variable.
3850 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003851
3852HInstrArray *
3853iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003854 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3855 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3856 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003857{
3858 UInt i, j;
3859 HReg hreg, hregHI;
3860 ISelEnv *env;
3861 UInt hwcaps_host = archinfo_host->hwcaps;
3862
florianf26994a2012-04-21 03:34:54 +00003863 /* KLUDGE: export hwcaps. */
3864 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003865
sewardj2019a972011-03-07 16:04:07 +00003866 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003867 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003868
3869 /* Make up an initial environment to use. */
3870 env = LibVEX_Alloc(sizeof(ISelEnv));
3871 env->vreg_ctr = 0;
3872
3873 /* Set up output code array. */
3874 env->code = newHInstrArray();
3875
3876 /* Copy BB's type env. */
3877 env->type_env = bb->tyenv;
3878
florianad43b3a2012-02-20 15:01:14 +00003879 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00003880 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3881 env->old_value[i] = 0; /* just something to have a defined value */
3882 env->old_value_valid[i] = False;
3883 }
3884
sewardj2019a972011-03-07 16:04:07 +00003885 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3886 change as we go along. For some reason types_used has Int type -- but
3887 it should be unsigned. Internally we use an unsigned type; so we
3888 assert it here. */
3889 vassert(bb->tyenv->types_used >= 0);
3890
3891 env->n_vregmap = bb->tyenv->types_used;
3892 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3893 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3894
florian2c74d242012-09-12 19:38:42 +00003895 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003896 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003897
sewardj2019a972011-03-07 16:04:07 +00003898 /* and finally ... */
3899 env->hwcaps = hwcaps_host;
3900
florian8844a632012-04-13 04:04:06 +00003901 env->max_ga = max_ga;
3902 env->chaining_allowed = chaining_allowed;
3903
sewardj2019a972011-03-07 16:04:07 +00003904 /* For each IR temporary, allocate a suitably-kinded virtual
3905 register. */
3906 j = 0;
3907 for (i = 0; i < env->n_vregmap; i++) {
3908 hregHI = hreg = INVALID_HREG;
3909 switch (bb->tyenv->types[i]) {
3910 case Ity_I1:
3911 case Ity_I8:
3912 case Ity_I16:
3913 case Ity_I32:
3914 hreg = mkHReg(j++, HRcInt64, True);
3915 break;
3916
3917 case Ity_I64:
3918 hreg = mkHReg(j++, HRcInt64, True);
3919 break;
3920
3921 case Ity_I128:
3922 hreg = mkHReg(j++, HRcInt64, True);
3923 hregHI = mkHReg(j++, HRcInt64, True);
3924 break;
3925
3926 case Ity_F32:
3927 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003928 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003929 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003930 hreg = mkHReg(j++, HRcFlt64, True);
3931 break;
3932
3933 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003934 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003935 hreg = mkHReg(j++, HRcFlt64, True);
3936 hregHI = mkHReg(j++, HRcFlt64, True);
3937 break;
3938
3939 case Ity_V128: /* fall through */
3940 default:
3941 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003942 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003943 }
3944
3945 env->vregmap[i] = hreg;
3946 env->vregmapHI[i] = hregHI;
3947 }
3948 env->vreg_ctr = j;
3949
florian8844a632012-04-13 04:04:06 +00003950 /* The very first instruction must be an event check. */
3951 s390_amode *counter, *fail_addr;
3952 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3953 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3954 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3955
3956 /* Possibly a block counter increment (for profiling). At this
3957 point we don't know the address of the counter, so just pretend
3958 it is zero. It will have to be patched later, but before this
3959 translation is used, by a call to LibVEX_patchProfInc. */
3960 if (add_profinc) {
3961 addInstr(env, s390_insn_profinc());
3962 }
3963
sewardj2019a972011-03-07 16:04:07 +00003964 /* Ok, finally we can iterate over the statements. */
3965 for (i = 0; i < bb->stmts_used; i++)
3966 if (bb->stmts[i])
3967 s390_isel_stmt(env, bb->stmts[i]);
3968
florian8844a632012-04-13 04:04:06 +00003969 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003970
3971 /* Record the number of vregs we used. */
3972 env->code->n_vregs = env->vreg_ctr;
3973
3974 return env->code;
3975}
3976
3977/*---------------------------------------------------------------*/
3978/*--- end host_s390_isel.c ---*/
3979/*---------------------------------------------------------------*/