blob: 6142b271e93997767cf9e3ebd04cc81b5c9edb39 [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);
199 vassert(env->vregmap[tmp] != INVALID_HREG);
200
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);
210 vassert(env->vregmapHI[tmp] != INVALID_HREG);
211
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.
685 The IR to s390 encoding is chosen in the range 0:7 except
686 S390_DFP_ROUND_NEAREST_TIE_TOWARD_0 and
687 S390_DFP_ROUND_AWAY_0 which have no choice within the range.
688 Since the s390 dfp rounding mode encoding in 8:15 is not used, the
689 quantum excpetion is not suppressed and this is fine as valgrind does
690 not model this exception.
691
692 Translation table of
693 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
694
695 s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
696 --------------------------------------------------------------------
697 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_1
698 NEAREST_TIE_AWAY_0_12 | " | "
699 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_3
700 PREPARE_SHORT_15 | " | "
701 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_4
702 NEAREST_EVEN_8 | " | "
703 ZERO_5 | ZERO | ZERO_5
704 ZERO_9 | " | "
705 POSINF_6 | PosINF | POSINF_6
706 POSINF_10 | " | "
707 NEGINF_7 | NegINF | NEGINF_7
708 NEGINF_11 | " | "
709 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
710 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
711*/
712static s390_dfp_round_t
713get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
714{
715 if (irrm->tag == Iex_Const) { /* rounding mode is known */
716 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian3d6a4222012-11-19 16:29:31 +0000717 IRRoundingModeDFP mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000718
719 switch (mode) {
720 case Irrm_DFP_NEAREST:
721 return S390_DFP_ROUND_NEAREST_EVEN_4;
722 case Irrm_DFP_NegINF:
723 return S390_DFP_ROUND_NEGINF_7;
724 case Irrm_DFP_PosINF:
725 return S390_DFP_ROUND_POSINF_6;
726 case Irrm_DFP_ZERO:
727 return S390_DFP_ROUND_ZERO_5;
728 case Irrm_DFP_NEAREST_TIE_AWAY_0:
729 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1;
730 case Irrm_DFP_PREPARE_SHORTER:
731 return S390_DFP_ROUND_PREPARE_SHORT_3;
732 case Irrm_DFP_AWAY_FROM_ZERO:
733 return S390_DFP_ROUND_AWAY_0;
734 case Irrm_DFP_NEAREST_TIE_TOWARD_0:
735 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
736 default:
737 vpanic("get_dfp_rounding_mode");
738 }
739 }
740
741 set_dfp_rounding_mode_in_fpc(env, irrm);
742 return S390_DFP_ROUND_PER_FPC_0;
743}
florianc8e4f562012-10-27 16:19:31 +0000744
florian2d3d87f2012-12-21 21:05:17 +0000745
746/*---------------------------------------------------------*/
747/*--- Condition code helper functions ---*/
748/*---------------------------------------------------------*/
749
sewardj2019a972011-03-07 16:04:07 +0000750/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000751 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000752
753 s390 VEX b6 b2 b0 cc.1 cc.0
754 0 0x40 EQ 1 0 0 0 0
755 1 0x01 LT 0 0 1 0 1
756 2 0x00 GT 0 0 0 1 0
757 3 0x45 Unordered 1 1 1 1 1
758
759 b0 = cc.0
760 b2 = cc.0 & cc.1
761 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
762
763 VEX = b0 | (b2 << 2) | (b6 << 6);
764*/
765static HReg
florian2d3d87f2012-12-21 21:05:17 +0000766convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000767{
768 HReg cc0, cc1, b2, b6, cc_vex;
769
770 cc0 = newVRegI(env);
771 addInstr(env, s390_insn_move(4, cc0, cc_s390));
772 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
773
774 cc1 = newVRegI(env);
775 addInstr(env, s390_insn_move(4, cc1, cc_s390));
776 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
777
778 b2 = newVRegI(env);
779 addInstr(env, s390_insn_move(4, b2, cc0));
780 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
781 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
782
783 b6 = newVRegI(env);
784 addInstr(env, s390_insn_move(4, b6, cc0));
785 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
786 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
787 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
788 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
789
790 cc_vex = newVRegI(env);
791 addInstr(env, s390_insn_move(4, cc_vex, cc0));
792 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
793 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
794
795 return cc_vex;
796}
797
florian2d3d87f2012-12-21 21:05:17 +0000798/* CC_S390 holds the condition code in s390 encoding. Convert it to
799 VEX encoding (IRCmpDResult) */
800static HReg
801convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
802{
803 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
804 return convert_s390_to_vex_bfpcc(env, cc_s390);
805}
806
sewardj2019a972011-03-07 16:04:07 +0000807
808/*---------------------------------------------------------*/
809/*--- ISEL: Integer expressions (128 bit) ---*/
810/*---------------------------------------------------------*/
811static void
812s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
813 IRExpr *expr)
814{
815 IRType ty = typeOfIRExpr(env->type_env, expr);
816
817 vassert(ty == Ity_I128);
818
819 /* No need to consider the following
820 - 128-bit constants (they do not exist in VEX)
821 - 128-bit loads from memory (will not be generated)
822 */
823
824 /* Read 128-bit IRTemp */
825 if (expr->tag == Iex_RdTmp) {
826 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
827 return;
828 }
829
830 if (expr->tag == Iex_Binop) {
831 IRExpr *arg1 = expr->Iex.Binop.arg1;
832 IRExpr *arg2 = expr->Iex.Binop.arg2;
833 Bool is_signed_multiply, is_signed_divide;
834
835 switch (expr->Iex.Binop.op) {
836 case Iop_MullU64:
837 is_signed_multiply = False;
838 goto do_multiply64;
839
840 case Iop_MullS64:
841 is_signed_multiply = True;
842 goto do_multiply64;
843
844 case Iop_DivModU128to64:
845 is_signed_divide = False;
846 goto do_divide64;
847
848 case Iop_DivModS128to64:
849 is_signed_divide = True;
850 goto do_divide64;
851
852 case Iop_64HLto128:
853 *dst_hi = s390_isel_int_expr(env, arg1);
854 *dst_lo = s390_isel_int_expr(env, arg2);
855 return;
856
857 case Iop_DivModS64to64: {
858 HReg r10, r11, h1;
859 s390_opnd_RMI op2;
860
861 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
862 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
863
864 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000865 r10 = make_gpr(10);
866 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000867
868 /* Move 1st operand into r11 and */
869 addInstr(env, s390_insn_move(8, r11, h1));
870
871 /* Divide */
872 addInstr(env, s390_insn_divs(8, r10, r11, op2));
873
874 /* The result is in registers r10 (remainder) and r11 (quotient).
875 Move the result into the reg pair that is being returned such
876 such that the low 64 bits are the quotient and the upper 64 bits
877 are the remainder. (see libvex_ir.h). */
878 *dst_hi = newVRegI(env);
879 *dst_lo = newVRegI(env);
880 addInstr(env, s390_insn_move(8, *dst_hi, r10));
881 addInstr(env, s390_insn_move(8, *dst_lo, r11));
882 return;
883 }
884
885 default:
886 break;
887
888 do_multiply64: {
889 HReg r10, r11, h1;
890 s390_opnd_RMI op2;
891
892 order_commutative_operands(arg1, arg2);
893
894 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
895 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
896
897 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000898 r10 = make_gpr(10);
899 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000900
901 /* Move the first operand to r11 */
902 addInstr(env, s390_insn_move(8, r11, h1));
903
904 /* Multiply */
905 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
906
907 /* The result is in registers r10 and r11. Assign to two virtual regs
908 and return. */
909 *dst_hi = newVRegI(env);
910 *dst_lo = newVRegI(env);
911 addInstr(env, s390_insn_move(8, *dst_hi, r10));
912 addInstr(env, s390_insn_move(8, *dst_lo, r11));
913 return;
914 }
915
916 do_divide64: {
917 HReg r10, r11, hi, lo;
918 s390_opnd_RMI op2;
919
920 s390_isel_int128_expr(&hi, &lo, env, arg1);
921 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
922
923 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000924 r10 = make_gpr(10);
925 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000926
927 /* Move high 64 bits of the 1st operand into r10 and
928 the low 64 bits into r11. */
929 addInstr(env, s390_insn_move(8, r10, hi));
930 addInstr(env, s390_insn_move(8, r11, lo));
931
932 /* Divide */
933 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
934
935 /* The result is in registers r10 (remainder) and r11 (quotient).
936 Move the result into the reg pair that is being returned such
937 such that the low 64 bits are the quotient and the upper 64 bits
938 are the remainder. (see libvex_ir.h). */
939 *dst_hi = newVRegI(env);
940 *dst_lo = newVRegI(env);
941 addInstr(env, s390_insn_move(8, *dst_hi, r10));
942 addInstr(env, s390_insn_move(8, *dst_lo, r11));
943 return;
944 }
945 }
946 }
947
948 vpanic("s390_isel_int128_expr");
949}
950
951
952/* Compute a 128-bit value into two 64-bit registers. These may be either
953 real or virtual regs; in any case they must not be changed by subsequent
954 code emitted by the caller. */
955static void
956s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
957{
958 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
959
960 /* Sanity checks ... */
961 vassert(hregIsVirtual(*dst_hi));
962 vassert(hregIsVirtual(*dst_lo));
963 vassert(hregClass(*dst_hi) == HRcInt64);
964 vassert(hregClass(*dst_lo) == HRcInt64);
965}
966
967
968/*---------------------------------------------------------*/
969/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
970/*---------------------------------------------------------*/
971
972/* Select insns for an integer-typed expression, and add them to the
973 code list. Return a reg holding the result. This reg will be a
974 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
975 want to modify it, ask for a new vreg, copy it in there, and modify
976 the copy. The register allocator will do its best to map both
977 vregs to the same real register, so the copies will often disappear
978 later in the game.
979
980 This should handle expressions of 64, 32, 16 and 8-bit type.
981 All results are returned in a 64bit register.
982 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
983 are arbitrary, so you should mask or sign extend partial values
984 if necessary.
985*/
986
987/* DO NOT CALL THIS DIRECTLY ! */
988static HReg
989s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
990{
991 IRType ty = typeOfIRExpr(env->type_env, expr);
992 UChar size;
florian6dc90242012-12-21 21:43:00 +0000993 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +0000994
995 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
996
997 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
998
999 switch (expr->tag) {
1000
1001 /* --------- TEMP --------- */
1002 case Iex_RdTmp:
1003 /* Return the virtual register that holds the temporary. */
1004 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1005
1006 /* --------- LOAD --------- */
1007 case Iex_Load: {
1008 HReg dst = newVRegI(env);
1009 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1010
1011 if (expr->Iex.Load.end != Iend_BE)
1012 goto irreducible;
1013
1014 addInstr(env, s390_insn_load(size, dst, am));
1015
1016 return dst;
1017 }
1018
1019 /* --------- BINARY OP --------- */
1020 case Iex_Binop: {
1021 IRExpr *arg1 = expr->Iex.Binop.arg1;
1022 IRExpr *arg2 = expr->Iex.Binop.arg2;
1023 HReg h1, res;
1024 s390_alu_t opkind;
1025 s390_opnd_RMI op2, value, opnd;
1026 s390_insn *insn;
1027 Bool is_commutative, is_signed_multiply, is_signed_divide;
1028
1029 is_commutative = True;
1030
1031 switch (expr->Iex.Binop.op) {
1032 case Iop_MullU8:
1033 case Iop_MullU16:
1034 case Iop_MullU32:
1035 is_signed_multiply = False;
1036 goto do_multiply;
1037
1038 case Iop_MullS8:
1039 case Iop_MullS16:
1040 case Iop_MullS32:
1041 is_signed_multiply = True;
1042 goto do_multiply;
1043
1044 do_multiply: {
1045 HReg r10, r11;
1046 UInt arg_size = size / 2;
1047
1048 order_commutative_operands(arg1, arg2);
1049
1050 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1051 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1052
1053 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001054 r10 = make_gpr(10);
1055 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001056
1057 /* Move the first operand to r11 */
1058 addInstr(env, s390_insn_move(arg_size, r11, h1));
1059
1060 /* Multiply */
1061 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1062
1063 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1064 value into the destination register. */
1065 res = newVRegI(env);
1066 addInstr(env, s390_insn_move(arg_size, res, r10));
1067 value = s390_opnd_imm(arg_size * 8);
1068 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1069 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1070 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1071 opnd = s390_opnd_reg(r11);
1072 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1073 return res;
1074 }
1075
1076 case Iop_DivModS64to32:
1077 is_signed_divide = True;
1078 goto do_divide;
1079
1080 case Iop_DivModU64to32:
1081 is_signed_divide = False;
1082 goto do_divide;
1083
1084 do_divide: {
1085 HReg r10, r11;
1086
1087 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1088 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1089
1090 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001091 r10 = make_gpr(10);
1092 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001093
1094 /* Split the first operand and put the high 32 bits into r10 and
1095 the low 32 bits into r11. */
1096 addInstr(env, s390_insn_move(8, r10, h1));
1097 addInstr(env, s390_insn_move(8, r11, h1));
1098 value = s390_opnd_imm(32);
1099 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1100
1101 /* Divide */
1102 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1103
1104 /* The result is in registers r10 (remainder) and r11 (quotient).
1105 Combine them into a 64-bit value such that the low 32 bits are
1106 the quotient and the upper 32 bits are the remainder. (see
1107 libvex_ir.h). */
1108 res = newVRegI(env);
1109 addInstr(env, s390_insn_move(8, res, r10));
1110 value = s390_opnd_imm(32);
1111 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1112 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1113 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1114 opnd = s390_opnd_reg(r11);
1115 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1116 return res;
1117 }
1118
florian9fcff4c2012-09-10 03:09:04 +00001119 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1120 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1121 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1122 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1123 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1124 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1125 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1126 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1127 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1128 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1129 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1130 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
florian5f034622013-01-13 02:29:05 +00001131 case Iop_D64toI32S: conv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
1132 case Iop_D64toI32U: conv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1133 case Iop_D64toI64U: conv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1134 case Iop_D128toI32S: conv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
1135 case Iop_D128toI32U: conv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1136 case Iop_D128toI64U: conv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00001137
1138 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001139 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001140
1141 res = newVRegI(env);
1142 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1143
florian2c74d242012-09-12 19:38:42 +00001144 rounding_mode = get_bfp_rounding_mode(env, arg1);
1145 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1146 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001147 return res;
1148 }
1149
1150 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001151 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001152 HReg op_hi, op_lo, f13, f15;
1153
1154 res = newVRegI(env);
1155 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1156
1157 /* We use non-virtual registers r13 and r15 as pair */
1158 f13 = make_fpr(13);
1159 f15 = make_fpr(15);
1160
1161 /* operand --> (f13, f15) */
1162 addInstr(env, s390_insn_move(8, f13, op_hi));
1163 addInstr(env, s390_insn_move(8, f15, op_lo));
1164
florian2c74d242012-09-12 19:38:42 +00001165 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001166 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001167 rounding_mode));
1168 return res;
1169 }
1170
florian5f034622013-01-13 02:29:05 +00001171 do_convert_dfp: {
1172 s390_dfp_round_t rounding_mode;
1173
1174 res = newVRegI(env);
1175 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1176
1177 rounding_mode = get_dfp_rounding_mode(env, arg1);
1178 addInstr(env, s390_insn_dfp_convert(size, conv, res, h1,
1179 rounding_mode));
1180 return res;
1181 }
1182
1183 do_convert_dfp128: {
1184 s390_dfp_round_t rounding_mode;
1185 HReg op_hi, op_lo, f13, f15;
1186
1187 res = newVRegI(env);
1188 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1189
1190 /* We use non-virtual registers r13 and r15 as pair */
1191 f13 = make_fpr(13);
1192 f15 = make_fpr(15);
1193
1194 /* operand --> (f13, f15) */
1195 addInstr(env, s390_insn_move(8, f13, op_hi));
1196 addInstr(env, s390_insn_move(8, f15, op_lo));
1197
1198 rounding_mode = get_dfp_rounding_mode(env, arg1);
1199 addInstr(env, s390_insn_dfp128_convert_from(size, conv, res, f13,
1200 f15, rounding_mode));
1201 return res;
1202 }
1203
sewardj2019a972011-03-07 16:04:07 +00001204 case Iop_8HLto16:
1205 case Iop_16HLto32:
1206 case Iop_32HLto64: {
1207 HReg h2;
1208 UInt arg_size = size / 2;
1209
1210 res = newVRegI(env);
1211 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1212 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1213
1214 addInstr(env, s390_insn_move(arg_size, res, h1));
1215 value = s390_opnd_imm(arg_size * 8);
1216 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1217 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1218 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1219 opnd = s390_opnd_reg(h2);
1220 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1221 return res;
1222 }
1223
1224 case Iop_Max32U: {
1225 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1226 res = newVRegI(env);
1227 h1 = s390_isel_int_expr(env, arg1);
1228 op2 = s390_isel_int_expr_RMI(env, arg2);
1229
1230 addInstr(env, s390_insn_move(size, res, h1));
1231 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1232 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1233 return res;
1234 }
1235
1236 case Iop_CmpF32:
1237 case Iop_CmpF64: {
1238 HReg cc_s390, h2;
1239
1240 h1 = s390_isel_float_expr(env, arg1);
1241 h2 = s390_isel_float_expr(env, arg2);
1242 cc_s390 = newVRegI(env);
1243
1244 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1245
1246 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1247
florian2d3d87f2012-12-21 21:05:17 +00001248 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001249 }
1250
1251 case Iop_CmpF128: {
1252 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1253
1254 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1255 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1256 cc_s390 = newVRegI(env);
1257
1258 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1259 f12 = make_fpr(12);
1260 f13 = make_fpr(13);
1261 f14 = make_fpr(14);
1262 f15 = make_fpr(15);
1263
1264 /* 1st operand --> (f12, f14) */
1265 addInstr(env, s390_insn_move(8, f12, op1_hi));
1266 addInstr(env, s390_insn_move(8, f14, op1_lo));
1267
1268 /* 2nd operand --> (f13, f15) */
1269 addInstr(env, s390_insn_move(8, f13, op2_hi));
1270 addInstr(env, s390_insn_move(8, f15, op2_lo));
1271
1272 res = newVRegI(env);
1273 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1274
florian2d3d87f2012-12-21 21:05:17 +00001275 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001276 }
1277
florian20c6bca2012-12-26 17:47:19 +00001278 case Iop_CmpD64:
1279 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001280 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001281 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001282
1283 h1 = s390_isel_dfp_expr(env, arg1);
1284 h2 = s390_isel_dfp_expr(env, arg2);
1285 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001286
florian20c6bca2012-12-26 17:47:19 +00001287 switch(expr->Iex.Binop.op) {
1288 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1289 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1290 default: goto irreducible;
1291 }
1292 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001293
florian2d3d87f2012-12-21 21:05:17 +00001294 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001295 }
1296
florian20c6bca2012-12-26 17:47:19 +00001297 case Iop_CmpD128:
1298 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001299 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001300 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001301
1302 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1303 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1304 cc_s390 = newVRegI(env);
1305
1306 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1307 f12 = make_fpr(12);
1308 f13 = make_fpr(13);
1309 f14 = make_fpr(14);
1310 f15 = make_fpr(15);
1311
1312 /* 1st operand --> (f12, f14) */
1313 addInstr(env, s390_insn_move(8, f12, op1_hi));
1314 addInstr(env, s390_insn_move(8, f14, op1_lo));
1315
1316 /* 2nd operand --> (f13, f15) */
1317 addInstr(env, s390_insn_move(8, f13, op2_hi));
1318 addInstr(env, s390_insn_move(8, f15, op2_lo));
1319
florian20c6bca2012-12-26 17:47:19 +00001320 switch(expr->Iex.Binop.op) {
1321 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1322 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1323 default: goto irreducible;
1324 }
1325 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1326 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001327
florian2d3d87f2012-12-21 21:05:17 +00001328 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001329 }
1330
sewardj2019a972011-03-07 16:04:07 +00001331 case Iop_Add8:
1332 case Iop_Add16:
1333 case Iop_Add32:
1334 case Iop_Add64:
1335 opkind = S390_ALU_ADD;
1336 break;
1337
1338 case Iop_Sub8:
1339 case Iop_Sub16:
1340 case Iop_Sub32:
1341 case Iop_Sub64:
1342 opkind = S390_ALU_SUB;
1343 is_commutative = False;
1344 break;
1345
1346 case Iop_And8:
1347 case Iop_And16:
1348 case Iop_And32:
1349 case Iop_And64:
1350 opkind = S390_ALU_AND;
1351 break;
1352
1353 case Iop_Or8:
1354 case Iop_Or16:
1355 case Iop_Or32:
1356 case Iop_Or64:
1357 opkind = S390_ALU_OR;
1358 break;
1359
1360 case Iop_Xor8:
1361 case Iop_Xor16:
1362 case Iop_Xor32:
1363 case Iop_Xor64:
1364 opkind = S390_ALU_XOR;
1365 break;
1366
1367 case Iop_Shl8:
1368 case Iop_Shl16:
1369 case Iop_Shl32:
1370 case Iop_Shl64:
1371 opkind = S390_ALU_LSH;
1372 is_commutative = False;
1373 break;
1374
1375 case Iop_Shr8:
1376 case Iop_Shr16:
1377 case Iop_Shr32:
1378 case Iop_Shr64:
1379 opkind = S390_ALU_RSH;
1380 is_commutative = False;
1381 break;
1382
1383 case Iop_Sar8:
1384 case Iop_Sar16:
1385 case Iop_Sar32:
1386 case Iop_Sar64:
1387 opkind = S390_ALU_RSHA;
1388 is_commutative = False;
1389 break;
1390
1391 default:
1392 goto irreducible;
1393 }
1394
1395 /* Pattern match: 0 - arg1 --> -arg1 */
1396 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1397 res = newVRegI(env);
1398 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1399 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1400 addInstr(env, insn);
1401
1402 return res;
1403 }
1404
1405 if (is_commutative) {
1406 order_commutative_operands(arg1, arg2);
1407 }
1408
1409 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1410 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1411 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001412
1413 /* As right shifts of one/two byte opreands are implemented using a
1414 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1415 switch (expr->Iex.Binop.op) {
1416 case Iop_Shr8:
1417 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1418 break;
1419 case Iop_Shr16:
1420 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1421 break;
1422 case Iop_Sar8:
1423 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1424 break;
1425 case Iop_Sar16:
1426 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1427 break;
1428 default:
1429 insn = s390_insn_move(size, res, h1);
1430 break;
1431 }
1432 addInstr(env, insn);
1433
sewardj2019a972011-03-07 16:04:07 +00001434 insn = s390_insn_alu(size, opkind, res, op2);
1435
1436 addInstr(env, insn);
1437
1438 return res;
1439 }
1440
1441 /* --------- UNARY OP --------- */
1442 case Iex_Unop: {
1443 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1444 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1445 s390_opnd_RMI opnd;
1446 s390_insn *insn;
1447 IRExpr *arg;
1448 HReg dst, h1;
1449 IROp unop, binop;
1450
1451 arg = expr->Iex.Unop.arg;
1452
1453 /* Special cases are handled here */
1454
1455 /* 32-bit multiply with 32-bit result or
1456 64-bit multiply with 64-bit result */
1457 unop = expr->Iex.Unop.op;
1458 binop = arg->Iex.Binop.op;
1459
1460 if ((arg->tag == Iex_Binop &&
1461 ((unop == Iop_64to32 &&
1462 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1463 (unop == Iop_128to64 &&
1464 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1465 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1466 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1467 dst = newVRegI(env); /* Result goes into a new register */
1468 addInstr(env, s390_insn_move(size, dst, h1));
1469 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1470
1471 return dst;
1472 }
1473
florian4d71a082011-12-18 00:08:17 +00001474 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001475 dst = newVRegI(env);
1476 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1477 addInstr(env, s390_insn_move(size, dst, h1));
1478
1479 return dst;
1480 }
1481
floriane38f6412012-12-21 17:32:12 +00001482 if (unop == Iop_ReinterpD64asI64) {
1483 dst = newVRegI(env);
1484 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1485 addInstr(env, s390_insn_move(size, dst, h1));
1486
1487 return dst;
1488 }
1489
floriance9e3db2012-12-27 20:14:03 +00001490 if (unop == Iop_ExtractSigD64) {
1491 dst = newVRegI(env);
1492 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1493 addInstr(env,
1494 s390_insn_dfp_unop(size, S390_DFP_EXTRACT_SIG_D64, dst, h1));
1495 return dst;
1496 }
1497
1498 if (unop == Iop_ExtractSigD128) {
1499 HReg op_hi, op_lo, f13, f15;
1500 dst = newVRegI(env);
1501 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1502
1503 /* We use non-virtual registers r13 and r15 as pair */
1504 f13 = make_fpr(13);
1505 f15 = make_fpr(15);
1506
1507 /* operand --> (f13, f15) */
1508 addInstr(env, s390_insn_move(8, f13, op_hi));
1509 addInstr(env, s390_insn_move(8, f15, op_lo));
1510
1511 addInstr(env, s390_insn_dfp128_unop(size, S390_DFP_EXTRACT_SIG_D128,
1512 dst, f13, f15));
1513 return dst;
1514 }
1515
sewardj2019a972011-03-07 16:04:07 +00001516 /* Expressions whose argument is 1-bit wide */
1517 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1518 s390_cc_t cond = s390_isel_cc(env, arg);
1519 dst = newVRegI(env); /* Result goes into a new register */
1520 addInstr(env, s390_insn_cc2bool(dst, cond));
1521
1522 switch (unop) {
1523 case Iop_1Uto8:
1524 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001525 /* Zero extend */
1526 mask.variant.imm = 1;
1527 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1528 break;
1529
sewardj2019a972011-03-07 16:04:07 +00001530 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001531 /* Zero extend */
1532 mask.variant.imm = 1;
1533 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001534 break;
1535
1536 case Iop_1Sto8:
1537 case Iop_1Sto16:
1538 case Iop_1Sto32:
1539 shift.variant.imm = 31;
1540 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1541 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1542 break;
1543
1544 case Iop_1Sto64:
1545 shift.variant.imm = 63;
1546 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1547 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1548 break;
1549
1550 default:
1551 goto irreducible;
1552 }
1553
1554 return dst;
1555 }
1556
1557 /* Regular processing */
1558
1559 if (unop == Iop_128to64) {
1560 HReg dst_hi, dst_lo;
1561
1562 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1563 return dst_lo;
1564 }
1565
1566 if (unop == Iop_128HIto64) {
1567 HReg dst_hi, dst_lo;
1568
1569 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1570 return dst_hi;
1571 }
1572
1573 dst = newVRegI(env); /* Result goes into a new register */
1574 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1575
1576 switch (unop) {
1577 case Iop_8Uto16:
1578 case Iop_8Uto32:
1579 case Iop_8Uto64:
1580 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1581 break;
1582
1583 case Iop_16Uto32:
1584 case Iop_16Uto64:
1585 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1586 break;
1587
1588 case Iop_32Uto64:
1589 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1590 break;
1591
1592 case Iop_8Sto16:
1593 case Iop_8Sto32:
1594 case Iop_8Sto64:
1595 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1596 break;
1597
1598 case Iop_16Sto32:
1599 case Iop_16Sto64:
1600 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1601 break;
1602
1603 case Iop_32Sto64:
1604 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1605 break;
1606
1607 case Iop_64to8:
1608 case Iop_64to16:
1609 case Iop_64to32:
1610 case Iop_32to8:
1611 case Iop_32to16:
1612 case Iop_16to8:
1613 /* Down-casts are no-ops. Upstream operations will only look at
1614 the bytes that make up the result of the down-cast. So there
1615 is no point setting the other bytes to 0. */
1616 insn = s390_opnd_copy(8, dst, opnd);
1617 break;
1618
1619 case Iop_64HIto32:
1620 addInstr(env, s390_opnd_copy(8, dst, opnd));
1621 shift.variant.imm = 32;
1622 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1623 break;
1624
1625 case Iop_32HIto16:
1626 addInstr(env, s390_opnd_copy(4, dst, opnd));
1627 shift.variant.imm = 16;
1628 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1629 break;
1630
1631 case Iop_16HIto8:
1632 addInstr(env, s390_opnd_copy(2, dst, opnd));
1633 shift.variant.imm = 8;
1634 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1635 break;
1636
1637 case Iop_Not8:
1638 case Iop_Not16:
1639 case Iop_Not32:
1640 case Iop_Not64:
1641 /* XOR with ffff... */
1642 mask.variant.imm = ~(ULong)0;
1643 addInstr(env, s390_opnd_copy(size, dst, opnd));
1644 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1645 break;
1646
1647 case Iop_Left8:
1648 case Iop_Left16:
1649 case Iop_Left32:
1650 case Iop_Left64:
1651 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1652 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1653 break;
1654
1655 case Iop_CmpwNEZ32:
1656 case Iop_CmpwNEZ64: {
1657 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1658 or -X will have a 1 in the MSB. */
1659 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1660 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1661 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1662 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1663 return dst;
1664 }
1665
1666 case Iop_Clz64: {
1667 HReg r10, r11;
1668
sewardj611b06e2011-03-24 08:57:29 +00001669 /* This will be implemented using FLOGR, if possible. So we need to
1670 set aside a pair of non-virtual registers. The result (number of
1671 left-most zero bits) will be in r10. The value in r11 is unspecified
1672 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001673 r10 = make_gpr(10);
1674 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001675
sewardj611b06e2011-03-24 08:57:29 +00001676 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001677 addInstr(env, s390_insn_move(8, dst, r10));
1678 return dst;
1679 }
1680
1681 default:
1682 goto irreducible;
1683 }
1684
1685 addInstr(env, insn);
1686
1687 return dst;
1688 }
1689
1690 /* --------- GET --------- */
1691 case Iex_Get: {
1692 HReg dst = newVRegI(env);
1693 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1694
1695 /* We never load more than 8 bytes from the guest state, because the
1696 floating point register pair is not contiguous. */
1697 vassert(size <= 8);
1698
1699 addInstr(env, s390_insn_load(size, dst, am));
1700
1701 return dst;
1702 }
1703
1704 case Iex_GetI:
1705 /* not needed */
1706 break;
1707
1708 /* --------- CCALL --------- */
1709 case Iex_CCall: {
1710 HReg dst = newVRegI(env);
1711
1712 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001713 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001714 return dst;
1715 }
1716
1717 /* --------- LITERAL --------- */
1718
1719 /* Load a literal into a register. Create a "load immediate"
1720 v-insn and return the register. */
1721 case Iex_Const: {
1722 ULong value;
1723 HReg dst = newVRegI(env);
1724 const IRConst *con = expr->Iex.Const.con;
1725
1726 /* Bitwise copy of the value. No sign/zero-extension */
1727 switch (con->tag) {
1728 case Ico_U64: value = con->Ico.U64; break;
1729 case Ico_U32: value = con->Ico.U32; break;
1730 case Ico_U16: value = con->Ico.U16; break;
1731 case Ico_U8: value = con->Ico.U8; break;
1732 default: vpanic("s390_isel_int_expr: invalid constant");
1733 }
1734
1735 addInstr(env, s390_insn_load_immediate(size, dst, value));
1736
1737 return dst;
1738 }
1739
1740 /* --------- MULTIPLEX --------- */
1741 case Iex_Mux0X: {
1742 IRExpr *cond_expr;
1743 HReg dst, tmp, rX;
1744 s390_opnd_RMI cond, r0, zero;
1745
1746 cond_expr = expr->Iex.Mux0X.cond;
1747
1748 dst = newVRegI(env);
1749 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1750 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1751 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1752
1753 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1754 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1755
1756 addInstr(env, s390_insn_move(size, dst, rX));
1757 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1758 return dst;
1759 }
1760
1761 /* Assume the condition is true and move rX to the destination reg. */
1762 addInstr(env, s390_insn_move(size, dst, rX));
1763
1764 /* Compute the condition ... */
1765 cond = s390_isel_int_expr_RMI(env, cond_expr);
1766
1767 /* tmp = cond & 0xFF */
1768 tmp = newVRegI(env);
1769 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1770 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1771
1772 /* ... and compare it with zero */
1773 zero = s390_opnd_imm(0);
1774 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1775
1776 /* ... and if it compared equal move r0 to the destination reg. */
1777 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1778 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1779
1780 return dst;
1781 }
1782
1783 default:
1784 break;
1785 }
1786
1787 /* We get here if no pattern matched. */
1788 irreducible:
1789 ppIRExpr(expr);
1790 vpanic("s390_isel_int_expr: cannot reduce tree");
1791}
1792
1793
1794static HReg
1795s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1796{
1797 HReg dst = s390_isel_int_expr_wrk(env, expr);
1798
1799 /* Sanity checks ... */
1800 vassert(hregClass(dst) == HRcInt64);
1801 vassert(hregIsVirtual(dst));
1802
1803 return dst;
1804}
1805
1806
1807static s390_opnd_RMI
1808s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1809{
1810 IRType ty = typeOfIRExpr(env->type_env, expr);
1811 s390_opnd_RMI dst;
1812
1813 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1814 ty == Ity_I64);
1815
1816 if (expr->tag == Iex_Load) {
1817 dst.tag = S390_OPND_AMODE;
1818 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1819 } else if (expr->tag == Iex_Get) {
1820 dst.tag = S390_OPND_AMODE;
1821 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1822 } else if (expr->tag == Iex_Const) {
1823 ULong value;
1824
1825 /* The bit pattern for the value will be stored as is in the least
1826 significant bits of VALUE. */
1827 switch (expr->Iex.Const.con->tag) {
1828 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1829 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1830 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1831 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1832 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1833 default:
1834 vpanic("s390_isel_int_expr_RMI");
1835 }
1836
1837 dst.tag = S390_OPND_IMMEDIATE;
1838 dst.variant.imm = value;
1839 } else {
1840 dst.tag = S390_OPND_REG;
1841 dst.variant.reg = s390_isel_int_expr(env, expr);
1842 }
1843
1844 return dst;
1845}
1846
1847
1848/*---------------------------------------------------------*/
1849/*--- ISEL: Floating point expressions (128 bit) ---*/
1850/*---------------------------------------------------------*/
1851static void
1852s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1853 IRExpr *expr)
1854{
1855 IRType ty = typeOfIRExpr(env->type_env, expr);
1856
1857 vassert(ty == Ity_F128);
1858
sewardj2019a972011-03-07 16:04:07 +00001859 switch (expr->tag) {
1860 case Iex_RdTmp:
1861 /* Return the virtual registers that hold the temporary. */
1862 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1863 return;
1864
1865 /* --------- LOAD --------- */
1866 case Iex_Load: {
1867 IRExpr *addr_hi, *addr_lo;
1868 s390_amode *am_hi, *am_lo;
1869
1870 if (expr->Iex.Load.end != Iend_BE)
1871 goto irreducible;
1872
1873 addr_hi = expr->Iex.Load.addr;
1874 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1875
1876 am_hi = s390_isel_amode(env, addr_hi);
1877 am_lo = s390_isel_amode(env, addr_lo);
1878
1879 *dst_hi = newVRegF(env);
1880 *dst_lo = newVRegF(env);
1881 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1882 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1883 return;
1884 }
1885
1886
1887 /* --------- GET --------- */
1888 case Iex_Get:
1889 /* This is not supported because loading 128-bit from the guest
1890 state is almost certainly wrong. Use get_fpr_pair instead. */
1891 vpanic("Iex_Get with F128 data");
1892
1893 /* --------- 4-ary OP --------- */
1894 case Iex_Qop:
1895 vpanic("Iex_Qop with F128 data");
1896
1897 /* --------- TERNARY OP --------- */
1898 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001899 IRTriop *triop = expr->Iex.Triop.details;
1900 IROp op = triop->op;
1901 IRExpr *left = triop->arg2;
1902 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001903 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001904 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1905
1906 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1907 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1908
1909 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1910 f12 = make_fpr(12);
1911 f13 = make_fpr(13);
1912 f14 = make_fpr(14);
1913 f15 = make_fpr(15);
1914
1915 /* 1st operand --> (f12, f14) */
1916 addInstr(env, s390_insn_move(8, f12, op1_hi));
1917 addInstr(env, s390_insn_move(8, f14, op1_lo));
1918
1919 /* 2nd operand --> (f13, f15) */
1920 addInstr(env, s390_insn_move(8, f13, op2_hi));
1921 addInstr(env, s390_insn_move(8, f15, op2_lo));
1922
1923 switch (op) {
1924 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1925 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1926 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1927 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1928 default:
1929 goto irreducible;
1930 }
1931
florian2c74d242012-09-12 19:38:42 +00001932 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1933 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001934
1935 /* Move result to virtual destination register */
1936 *dst_hi = newVRegF(env);
1937 *dst_lo = newVRegF(env);
1938 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1939 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1940
1941 return;
1942 }
1943
1944 /* --------- BINARY OP --------- */
1945 case Iex_Binop: {
1946 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001947
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
1954 switch (expr->Iex.Binop.op) {
1955 case Iop_SqrtF128:
1956 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1957
1958 /* operand --> (f13, f15) */
1959 addInstr(env, s390_insn_move(8, f13, op_hi));
1960 addInstr(env, s390_insn_move(8, f15, op_lo));
1961
florian2c74d242012-09-12 19:38:42 +00001962 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1963 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1964 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001965
1966 /* Move result to virtual destination registers */
1967 *dst_hi = newVRegF(env);
1968 *dst_lo = newVRegF(env);
1969 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1970 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1971 return;
1972
1973 case Iop_F64HLtoF128:
1974 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1975 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1976 return;
1977
1978 default:
1979 goto irreducible;
1980 }
1981 }
1982
1983 /* --------- UNARY OP --------- */
1984 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001985 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001986 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00001987 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001988 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1989
1990 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1991 f12 = make_fpr(12);
1992 f13 = make_fpr(13);
1993 f14 = make_fpr(14);
1994 f15 = make_fpr(15);
1995
florian66e596d2012-09-07 15:00:53 +00001996 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001997 case Iop_NegF128:
1998 if (left->tag == Iex_Unop &&
1999 (left->Iex.Unop.op == Iop_AbsF32 ||
2000 left->Iex.Unop.op == Iop_AbsF64))
2001 bfpop = S390_BFP_NABS;
2002 else
2003 bfpop = S390_BFP_NEG;
2004 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00002005 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2006 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2007 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2008 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2009 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2010 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2011 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00002012 default:
2013 goto irreducible;
2014 }
2015
2016 float128_opnd:
2017 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2018
2019 /* operand --> (f13, f15) */
2020 addInstr(env, s390_insn_move(8, f13, op_hi));
2021 addInstr(env, s390_insn_move(8, f15, op_lo));
2022
florian2c74d242012-09-12 19:38:42 +00002023 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002024 goto move_dst;
2025
2026 convert_float:
2027 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002028 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002029 goto move_dst;
2030
2031 convert_int:
2032 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002033 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002034 goto move_dst;
2035
2036 move_dst:
2037 /* Move result to virtual destination registers */
2038 *dst_hi = newVRegF(env);
2039 *dst_lo = newVRegF(env);
2040 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2041 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2042 return;
2043 }
2044
2045 default:
2046 goto irreducible;
2047 }
2048
2049 /* We get here if no pattern matched. */
2050 irreducible:
2051 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002052 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002053}
2054
2055/* Compute a 128-bit value into two 64-bit registers. These may be either
2056 real or virtual regs; in any case they must not be changed by subsequent
2057 code emitted by the caller. */
2058static void
2059s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2060{
2061 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2062
2063 /* Sanity checks ... */
2064 vassert(hregIsVirtual(*dst_hi));
2065 vassert(hregIsVirtual(*dst_lo));
2066 vassert(hregClass(*dst_hi) == HRcFlt64);
2067 vassert(hregClass(*dst_lo) == HRcFlt64);
2068}
2069
2070
2071/*---------------------------------------------------------*/
2072/*--- ISEL: Floating point expressions (64 bit) ---*/
2073/*---------------------------------------------------------*/
2074
2075static HReg
2076s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2077{
2078 IRType ty = typeOfIRExpr(env->type_env, expr);
2079 UChar size;
2080
2081 vassert(ty == Ity_F32 || ty == Ity_F64);
2082
2083 size = sizeofIRType(ty);
2084
2085 switch (expr->tag) {
2086 case Iex_RdTmp:
2087 /* Return the virtual register that holds the temporary. */
2088 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2089
2090 /* --------- LOAD --------- */
2091 case Iex_Load: {
2092 HReg dst = newVRegF(env);
2093 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2094
2095 if (expr->Iex.Load.end != Iend_BE)
2096 goto irreducible;
2097
2098 addInstr(env, s390_insn_load(size, dst, am));
2099
2100 return dst;
2101 }
2102
2103 /* --------- GET --------- */
2104 case Iex_Get: {
2105 HReg dst = newVRegF(env);
2106 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2107
2108 addInstr(env, s390_insn_load(size, dst, am));
2109
2110 return dst;
2111 }
2112
2113 /* --------- LITERAL --------- */
2114
2115 /* Load a literal into a register. Create a "load immediate"
2116 v-insn and return the register. */
2117 case Iex_Const: {
2118 ULong value;
2119 HReg dst = newVRegF(env);
2120 const IRConst *con = expr->Iex.Const.con;
2121
2122 /* Bitwise copy of the value. No sign/zero-extension */
2123 switch (con->tag) {
2124 case Ico_F32i: value = con->Ico.F32i; break;
2125 case Ico_F64i: value = con->Ico.F64i; break;
2126 default: vpanic("s390_isel_float_expr: invalid constant");
2127 }
2128
2129 if (value != 0) vpanic("cannot load immediate floating point constant");
2130
2131 addInstr(env, s390_insn_load_immediate(size, dst, value));
2132
2133 return dst;
2134 }
2135
2136 /* --------- 4-ary OP --------- */
2137 case Iex_Qop: {
2138 HReg op1, op2, op3, dst;
2139 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002140
florian5906a6b2012-10-16 02:53:33 +00002141 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002142 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002143 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002144 dst = newVRegF(env);
2145 addInstr(env, s390_insn_move(size, dst, op1));
2146
florian96d7cc32012-06-01 20:41:24 +00002147 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002148 case Iop_MAddF32:
2149 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2150 case Iop_MSubF32:
2151 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2152
2153 default:
2154 goto irreducible;
2155 }
2156
florian2c74d242012-09-12 19:38:42 +00002157 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2158 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002159 return dst;
2160 }
2161
2162 /* --------- TERNARY OP --------- */
2163 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002164 IRTriop *triop = expr->Iex.Triop.details;
2165 IROp op = triop->op;
2166 IRExpr *left = triop->arg2;
2167 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002168 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002169 HReg h1, op2, dst;
2170
2171 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2172 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2173 dst = newVRegF(env);
2174 addInstr(env, s390_insn_move(size, dst, h1));
2175 switch (op) {
2176 case Iop_AddF32:
2177 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2178 case Iop_SubF32:
2179 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2180 case Iop_MulF32:
2181 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2182 case Iop_DivF32:
2183 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2184
2185 default:
2186 goto irreducible;
2187 }
2188
florian2c74d242012-09-12 19:38:42 +00002189 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2190 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002191 return dst;
2192 }
2193
2194 /* --------- BINARY OP --------- */
2195 case Iex_Binop: {
2196 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002197 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002198 IRExpr *left = expr->Iex.Binop.arg2;
2199 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002200 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002201
2202 switch (op) {
2203 case Iop_SqrtF32:
2204 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002205 h1 = s390_isel_float_expr(env, left);
2206 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002207 set_bfp_rounding_mode_in_fpc(env, irrm);
2208 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002209 return dst;
sewardj2019a972011-03-07 16:04:07 +00002210
florian9fcff4c2012-09-10 03:09:04 +00002211 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2212 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2213 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2214 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2215 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2216 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2217 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002218
florian9fcff4c2012-09-10 03:09:04 +00002219 convert_float:
2220 h1 = s390_isel_float_expr(env, left);
2221 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002222
florian9fcff4c2012-09-10 03:09:04 +00002223 convert_int:
2224 h1 = s390_isel_int_expr(env, left);
2225 goto convert;
2226
florian2c74d242012-09-12 19:38:42 +00002227 convert: {
florian125e20d2012-10-07 15:42:37 +00002228 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002229 /* convert-from-fixed and load-rounded have a rounding mode field
2230 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002231 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002232 if (s390_host_has_fpext) {
2233 rounding_mode = get_bfp_rounding_mode(env, irrm);
2234 } else {
2235 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002236 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002237 }
florian9fcff4c2012-09-10 03:09:04 +00002238 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2239 rounding_mode));
2240 return dst;
florian2c74d242012-09-12 19:38:42 +00002241 }
florian9fcff4c2012-09-10 03:09:04 +00002242
sewardj2019a972011-03-07 16:04:07 +00002243 default:
2244 goto irreducible;
2245
2246 case Iop_F128toF64:
2247 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002248 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002249 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002250
florian9fcff4c2012-09-10 03:09:04 +00002251 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2252 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002253
florian9fcff4c2012-09-10 03:09:04 +00002254 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002255
florian9fcff4c2012-09-10 03:09:04 +00002256 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002257 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002258 f15 = make_fpr(15);
2259
2260 /* operand --> (f13, f15) */
2261 addInstr(env, s390_insn_move(8, f13, op_hi));
2262 addInstr(env, s390_insn_move(8, f15, op_lo));
2263
2264 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002265 /* load-rounded has a rounding mode field when the floating point
2266 extension facility is installed. */
2267 if (s390_host_has_fpext) {
2268 rounding_mode = get_bfp_rounding_mode(env, irrm);
2269 } else {
2270 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002271 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002272 }
floriancc491a62012-09-10 23:44:37 +00002273 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002274 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002275 return dst;
2276 }
2277 }
sewardj2019a972011-03-07 16:04:07 +00002278 }
2279
2280 /* --------- UNARY OP --------- */
2281 case Iex_Unop: {
2282 IROp op = expr->Iex.Unop.op;
2283 IRExpr *left = expr->Iex.Unop.arg;
2284 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002285 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002286 HReg h1, dst;
2287
2288 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2289 HReg dst_hi, dst_lo;
2290
2291 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2292 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2293 }
2294
florian4d71a082011-12-18 00:08:17 +00002295 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002296 dst = newVRegF(env);
2297 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2298 addInstr(env, s390_insn_move(size, dst, h1));
2299
2300 return dst;
2301 }
2302
2303 switch (op) {
2304 case Iop_NegF32:
2305 case Iop_NegF64:
2306 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002307 (left->Iex.Unop.op == Iop_AbsF32 ||
2308 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002309 bfpop = S390_BFP_NABS;
2310 else
2311 bfpop = S390_BFP_NEG;
2312 break;
2313
2314 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002315 case Iop_AbsF64:
2316 bfpop = S390_BFP_ABS;
2317 break;
2318
2319 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2320 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2321 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2322
2323 convert_float1:
2324 h1 = s390_isel_float_expr(env, left);
2325 goto convert1;
2326
2327 convert_int1:
2328 h1 = s390_isel_int_expr(env, left);
2329 goto convert1;
2330
2331 convert1:
2332 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002333 /* No rounding mode is needed for these conversions. Just stick
2334 one in. It won't be used later on. */
2335 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002336 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002337 return dst;
2338
sewardj2019a972011-03-07 16:04:07 +00002339 default:
2340 goto irreducible;
2341 }
2342
2343 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002344 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002345 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002346 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002347 return dst;
2348 }
2349
2350 default:
2351 goto irreducible;
2352 }
2353
2354 /* We get here if no pattern matched. */
2355 irreducible:
2356 ppIRExpr(expr);
2357 vpanic("s390_isel_float_expr: cannot reduce tree");
2358}
2359
2360
2361static HReg
2362s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2363{
2364 HReg dst = s390_isel_float_expr_wrk(env, expr);
2365
2366 /* Sanity checks ... */
2367 vassert(hregClass(dst) == HRcFlt64);
2368 vassert(hregIsVirtual(dst));
2369
2370 return dst;
2371}
2372
2373
2374/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002375/*--- ISEL: Decimal point expressions (128 bit) ---*/
2376/*---------------------------------------------------------*/
2377static void
2378s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2379 IRExpr *expr)
2380{
2381 IRType ty = typeOfIRExpr(env->type_env, expr);
2382
2383 vassert(ty == Ity_D128);
2384
2385 switch (expr->tag) {
2386 case Iex_RdTmp:
2387 /* Return the virtual registers that hold the temporary. */
2388 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2389 return;
2390
2391 /* --------- LOAD --------- */
2392 case Iex_Load: {
2393 IRExpr *addr_hi, *addr_lo;
2394 s390_amode *am_hi, *am_lo;
2395
2396 if (expr->Iex.Load.end != Iend_BE)
2397 goto irreducible;
2398
2399 addr_hi = expr->Iex.Load.addr;
2400 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2401
2402 am_hi = s390_isel_amode(env, addr_hi);
2403 am_lo = s390_isel_amode(env, addr_lo);
2404
2405 *dst_hi = newVRegF(env);
2406 *dst_lo = newVRegF(env);
2407 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2408 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2409 return;
2410 }
2411
2412 /* --------- GET --------- */
2413 case Iex_Get:
2414 /* This is not supported because loading 128-bit from the guest
2415 state is almost certainly wrong. Use get_dpr_pair instead. */
2416 vpanic("Iex_Get with D128 data");
2417
2418 /* --------- 4-ary OP --------- */
2419 case Iex_Qop:
2420 vpanic("Iex_Qop with D128 data");
2421
2422 /* --------- TERNARY OP --------- */
2423 case Iex_Triop: {
2424 IRTriop *triop = expr->Iex.Triop.details;
2425 IROp op = triop->op;
2426 IRExpr *irrm = triop->arg1;
2427 IRExpr *left = triop->arg2;
2428 IRExpr *right = triop->arg3;
2429 s390_dfp_round_t rounding_mode;
2430 s390_dfp_binop_t dfpop;
2431 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2432
2433 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2434 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2435
2436 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2437 (f12, f14) as op2 and (f13, f15) as destination) */
2438 f9 = make_fpr(9);
2439 f11 = make_fpr(11);
2440 f12 = make_fpr(12);
2441 f13 = make_fpr(13);
2442 f14 = make_fpr(14);
2443 f15 = make_fpr(15);
2444
2445 /* 1st operand --> (f9, f11) */
2446 addInstr(env, s390_insn_move(8, f9, op1_hi));
2447 addInstr(env, s390_insn_move(8, f11, op1_lo));
2448
2449 /* 2nd operand --> (f12, f14) */
2450 addInstr(env, s390_insn_move(8, f12, op2_hi));
2451 addInstr(env, s390_insn_move(8, f14, op2_lo));
2452
2453 switch (op) {
2454 case Iop_AddD128: dfpop = S390_DFP_ADD; break;
2455 case Iop_SubD128: dfpop = S390_DFP_SUB; break;
2456 case Iop_MulD128: dfpop = S390_DFP_MUL; break;
2457 case Iop_DivD128: dfpop = S390_DFP_DIV; break;
2458 default:
2459 goto irreducible;
2460 }
2461
2462 /* DFP binary ops have insns with rounding mode field
2463 when the floating point extension facility is installed. */
2464 if (s390_host_has_fpext) {
2465 rounding_mode = get_dfp_rounding_mode(env, irrm);
2466 } else {
2467 set_dfp_rounding_mode_in_fpc(env, irrm);
2468 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2469 }
2470
2471 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2472 f12, f14, rounding_mode));
2473
2474 /* Move result to virtual destination register */
2475 *dst_hi = newVRegF(env);
2476 *dst_lo = newVRegF(env);
2477 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2478 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2479
2480 return;
2481 }
2482
2483 /* --------- BINARY OP --------- */
2484 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002485
floriane38f6412012-12-21 17:32:12 +00002486 switch (expr->Iex.Binop.op) {
2487 case Iop_D64HLtoD128:
2488 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2489 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2490 return;
2491
florian1b901d42013-01-01 22:19:24 +00002492 case Iop_ShlD128:
2493 case Iop_ShrD128: {
2494 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2495 s390_dfp_intop_t intop;
2496 IRExpr *left = expr->Iex.Binop.arg1;
2497 IRExpr *right = expr->Iex.Binop.arg2;
2498
2499 switch (expr->Iex.Binop.op) {
2500 case Iop_ShlD128: intop = S390_DFP_SHIFT_LEFT; break;
2501 case Iop_ShrD128: intop = S390_DFP_SHIFT_RIGHT; break;
2502 default: goto irreducible;
2503 }
2504
2505 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2506 f9 = make_fpr(9); /* 128 bit dfp operand */
2507 f11 = make_fpr(11);
2508
2509 f13 = make_fpr(13); /* 128 bit dfp destination */
2510 f15 = make_fpr(15);
2511
2512 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* dfp operand */
2513 addInstr(env, s390_insn_move(8, f9, op1_hi));
2514 addInstr(env, s390_insn_move(8, f11, op1_lo));
2515
2516 op2 = s390_isel_int_expr(env, right); /* int operand */
2517
2518 addInstr(env,
2519 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2520
2521 /* Move result to virtual destination register */
2522 *dst_hi = newVRegF(env);
2523 *dst_lo = newVRegF(env);
2524 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2525 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2526 return;
2527 }
2528
floriane38f6412012-12-21 17:32:12 +00002529 default:
2530 goto irreducible;
2531 }
2532 }
2533
2534 /* --------- UNARY OP --------- */
2535 case Iex_Unop: {
2536 IRExpr *left = expr->Iex.Unop.arg;
2537 s390_dfp_conv_t conv;
2538 // HReg op, f12, f13, f14, f15;
2539 HReg op, f12, f14;
2540
2541 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2542 f12 = make_fpr(12);
2543 // f13 = make_fpr(13);
2544 f14 = make_fpr(14);
2545 // f15 = make_fpr(15);
2546
2547 switch (expr->Iex.Unop.op) {
2548 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002549 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
2550 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2551 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002552 default:
2553 goto irreducible;
2554 }
2555
2556 convert_dfp:
2557 op = s390_isel_dfp_expr(env, left);
2558 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2559 goto move_dst;
2560
florian5f034622013-01-13 02:29:05 +00002561 convert_int:
2562 op = s390_isel_int_expr(env, left);
2563 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2564 goto move_dst;
2565
floriane38f6412012-12-21 17:32:12 +00002566 move_dst:
2567 /* Move result to virtual destination registers */
2568 *dst_hi = newVRegF(env);
2569 *dst_lo = newVRegF(env);
2570 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2571 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2572 return;
2573 }
2574
2575 default:
2576 goto irreducible;
2577 }
2578
2579 /* We get here if no pattern matched. */
2580 irreducible:
2581 ppIRExpr(expr);
2582 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2583
2584}
2585
2586
2587/* Compute a 128-bit value into two 64-bit registers. These may be either
2588 real or virtual regs; in any case they must not be changed by subsequent
2589 code emitted by the caller. */
2590static void
2591s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2592{
2593 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2594
2595 /* Sanity checks ... */
2596 vassert(hregIsVirtual(*dst_hi));
2597 vassert(hregIsVirtual(*dst_lo));
2598 vassert(hregClass(*dst_hi) == HRcFlt64);
2599 vassert(hregClass(*dst_lo) == HRcFlt64);
2600}
2601
2602
2603/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002604/*--- ISEL: Decimal point expressions (64 bit) ---*/
2605/*---------------------------------------------------------*/
2606
2607static HReg
2608s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2609{
2610 IRType ty = typeOfIRExpr(env->type_env, expr);
2611 UChar size;
2612
floriane38f6412012-12-21 17:32:12 +00002613 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002614
2615 size = sizeofIRType(ty);
2616
2617 switch (expr->tag) {
2618 case Iex_RdTmp:
2619 /* Return the virtual register that holds the temporary. */
2620 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2621
2622 /* --------- LOAD --------- */
2623 case Iex_Load: {
2624 HReg dst = newVRegF(env);
2625 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2626
2627 if (expr->Iex.Load.end != Iend_BE)
2628 goto irreducible;
2629
2630 addInstr(env, s390_insn_load(size, dst, am));
2631
2632 return dst;
2633 }
2634
2635 /* --------- GET --------- */
2636 case Iex_Get: {
2637 HReg dst = newVRegF(env);
2638 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2639
2640 addInstr(env, s390_insn_load(size, dst, am));
2641
2642 return dst;
2643 }
2644
floriane38f6412012-12-21 17:32:12 +00002645 /* --------- BINARY OP --------- */
2646 case Iex_Binop: {
2647 IROp op = expr->Iex.Binop.op;
2648 IRExpr *irrm = expr->Iex.Binop.arg1;
2649 IRExpr *left = expr->Iex.Binop.arg2;
2650 HReg h1, dst;
2651 s390_dfp_conv_t conv;
2652
2653 switch (op) {
2654 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002655 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002656
2657 convert_dfp:
2658 h1 = s390_isel_dfp_expr(env, left);
2659 goto convert;
2660
florian5f034622013-01-13 02:29:05 +00002661 convert_int:
2662 h1 = s390_isel_int_expr(env, left);
2663 goto convert;
2664
floriane38f6412012-12-21 17:32:12 +00002665 convert: {
2666 s390_dfp_round_t rounding_mode;
2667 /* convert-from-fixed and load-rounded have a rounding mode field
2668 when the floating point extension facility is installed. */
2669 dst = newVRegF(env);
2670 if (s390_host_has_fpext) {
2671 rounding_mode = get_dfp_rounding_mode(env, irrm);
2672 } else {
2673 set_dfp_rounding_mode_in_fpc(env, irrm);
2674 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2675 }
2676 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2677 rounding_mode));
2678 return dst;
2679 }
floriane38f6412012-12-21 17:32:12 +00002680
2681 case Iop_D128toD64: {
2682 HReg op_hi, op_lo, f13, f15;
2683 s390_dfp_round_t rounding_mode;
2684
2685 conv = S390_DFP_D128_TO_D64;
2686
2687 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2688
2689 /* We use non-virtual registers as pairs (f13, f15) */
2690 f13 = make_fpr(13);
2691 f15 = make_fpr(15);
2692
2693 /* operand --> (f13, f15) */
2694 addInstr(env, s390_insn_move(8, f13, op_hi));
2695 addInstr(env, s390_insn_move(8, f15, op_lo));
2696
2697 dst = newVRegF(env);
2698 /* load-rounded has a rounding mode field when the floating point
2699 extension facility is installed. */
2700 if (s390_host_has_fpext) {
2701 rounding_mode = get_dfp_rounding_mode(env, irrm);
2702 } else {
2703 set_dfp_rounding_mode_in_fpc(env, irrm);
2704 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2705 }
2706 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2707 rounding_mode));
2708 return dst;
2709 }
2710
florian1b901d42013-01-01 22:19:24 +00002711 case Iop_ShlD64:
2712 case Iop_ShrD64: {
2713 HReg op2;
2714 HReg op3;
2715 s390_dfp_intop_t intop;
2716 IRExpr *op1 = expr->Iex.Binop.arg1;
2717 IRExpr *shift = expr->Iex.Binop.arg2;
2718
2719 switch (expr->Iex.Binop.op) {
2720 case Iop_ShlD64: intop = S390_DFP_SHIFT_LEFT; break;
2721 case Iop_ShrD64: intop = S390_DFP_SHIFT_RIGHT; break;
2722 default: goto irreducible;
2723 }
2724
2725 op2 = s390_isel_int_expr(env, shift);
2726 op3 = s390_isel_dfp_expr(env, op1);
2727 dst = newVRegF(env);
2728
2729 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
2730 return dst;
2731 }
2732
2733 default:
2734 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00002735 }
2736 }
2737
2738 /* --------- UNARY OP --------- */
2739 case Iex_Unop: {
2740 IROp op = expr->Iex.Unop.op;
2741 IRExpr *left = expr->Iex.Unop.arg;
2742 s390_dfp_conv_t conv;
2743 HReg h1, dst;
2744
2745 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2746 HReg dst_hi, dst_lo;
2747
2748 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2749 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2750 }
2751
2752 if (op == Iop_ReinterpI64asD64) {
2753 dst = newVRegF(env);
2754 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2755 addInstr(env, s390_insn_move(size, dst, h1));
2756
2757 return dst;
2758 }
2759
2760 switch (op) {
2761 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00002762 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
2763 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00002764
2765 convert_dfp1:
2766 h1 = s390_isel_dfp_expr(env, left);
2767 goto convert1;
2768
florian5f034622013-01-13 02:29:05 +00002769 convert_int1:
2770 h1 = s390_isel_int_expr(env, left);
2771 goto convert1;
2772
floriane38f6412012-12-21 17:32:12 +00002773 convert1:
2774 dst = newVRegF(env);
2775 /* No rounding mode is needed for these conversions. Just stick
2776 one in. It won't be used later on. */
2777 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2778 S390_DFP_ROUND_NEAREST_EVEN_4));
2779 return dst;
2780
2781 default:
2782 goto irreducible;
2783 }
2784 }
2785
florian12390202012-11-10 22:34:14 +00002786 /* --------- TERNARY OP --------- */
2787 case Iex_Triop: {
2788 IRTriop *triop = expr->Iex.Triop.details;
2789 IROp op = triop->op;
2790 IRExpr *irrm = triop->arg1;
2791 IRExpr *left = triop->arg2;
2792 IRExpr *right = triop->arg3;
2793 s390_dfp_round_t rounding_mode;
2794 s390_dfp_binop_t dfpop;
2795 HReg op2, op3, dst;
2796
2797 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2798 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2799 dst = newVRegF(env);
2800 switch (op) {
2801 case Iop_AddD64: dfpop = S390_DFP_ADD; break;
2802 case Iop_SubD64: dfpop = S390_DFP_SUB; break;
2803 case Iop_MulD64: dfpop = S390_DFP_MUL; break;
2804 case Iop_DivD64: dfpop = S390_DFP_DIV; break;
2805 default:
2806 goto irreducible;
2807 }
2808 /* DFP binary ops have insns with rounding mode field
2809 when the floating point extension facility is installed. */
2810 if (s390_host_has_fpext) {
2811 rounding_mode = get_dfp_rounding_mode(env, irrm);
2812 } else {
2813 set_dfp_rounding_mode_in_fpc(env, irrm);
2814 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2815 }
2816
2817 addInstr(env,
2818 s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
2819 return dst;
2820 }
2821
2822 default:
2823 goto irreducible;
2824 }
2825
2826 /* We get here if no pattern matched. */
2827 irreducible:
2828 ppIRExpr(expr);
2829 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2830}
2831
2832static HReg
2833s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2834{
2835 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2836
2837 /* Sanity checks ... */
2838 vassert(hregClass(dst) == HRcFlt64);
2839 vassert(hregIsVirtual(dst));
2840
2841 return dst;
2842}
2843
2844
2845/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002846/*--- ISEL: Condition Code ---*/
2847/*---------------------------------------------------------*/
2848
2849/* This function handles all operators that produce a 1-bit result */
2850static s390_cc_t
2851s390_isel_cc(ISelEnv *env, IRExpr *cond)
2852{
2853 UChar size;
2854
2855 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2856
2857 /* Constant: either 1 or 0 */
2858 if (cond->tag == Iex_Const) {
2859 vassert(cond->Iex.Const.con->tag == Ico_U1);
2860 vassert(cond->Iex.Const.con->Ico.U1 == True
2861 || cond->Iex.Const.con->Ico.U1 == False);
2862
2863 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2864 }
2865
2866 /* Variable: values are 1 or 0 */
2867 if (cond->tag == Iex_RdTmp) {
2868 IRTemp tmp = cond->Iex.RdTmp.tmp;
2869 HReg reg = lookupIRTemp(env, tmp);
2870
2871 /* Load-and-test does not modify REG; so this is OK. */
2872 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2873 size = 4;
2874 else
2875 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2876 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2877 return S390_CC_NE;
2878 }
2879
2880 /* Unary operators */
2881 if (cond->tag == Iex_Unop) {
2882 IRExpr *arg = cond->Iex.Unop.arg;
2883
2884 switch (cond->Iex.Unop.op) {
2885 case Iop_Not1: /* Not1(cond) */
2886 /* Generate code for EXPR, and negate the test condition */
2887 return s390_cc_invert(s390_isel_cc(env, arg));
2888
2889 /* Iop_32/64to1 select the LSB from their operand */
2890 case Iop_32to1:
2891 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002892 HReg dst = newVRegI(env);
2893 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002894
2895 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2896
florianf366a802012-08-03 00:42:18 +00002897 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002898 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2899 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2900 return S390_CC_NE;
2901 }
2902
2903 case Iop_CmpNEZ8:
2904 case Iop_CmpNEZ16: {
2905 s390_opnd_RMI src;
2906 s390_unop_t op;
2907 HReg dst;
2908
2909 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2910 : S390_ZERO_EXTEND_16;
2911 dst = newVRegI(env);
2912 src = s390_isel_int_expr_RMI(env, arg);
2913 addInstr(env, s390_insn_unop(4, op, dst, src));
2914 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2915 return S390_CC_NE;
2916 }
2917
2918 case Iop_CmpNEZ32:
2919 case Iop_CmpNEZ64: {
2920 s390_opnd_RMI src;
2921
2922 src = s390_isel_int_expr_RMI(env, arg);
2923 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2924 addInstr(env, s390_insn_test(size, src));
2925 return S390_CC_NE;
2926 }
2927
2928 default:
2929 goto fail;
2930 }
2931 }
2932
2933 /* Binary operators */
2934 if (cond->tag == Iex_Binop) {
2935 IRExpr *arg1 = cond->Iex.Binop.arg1;
2936 IRExpr *arg2 = cond->Iex.Binop.arg2;
2937 HReg reg1, reg2;
2938
2939 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2940
2941 switch (cond->Iex.Binop.op) {
2942 s390_unop_t op;
2943 s390_cc_t result;
2944
2945 case Iop_CmpEQ8:
2946 case Iop_CasCmpEQ8:
2947 op = S390_ZERO_EXTEND_8;
2948 result = S390_CC_E;
2949 goto do_compare_ze;
2950
2951 case Iop_CmpNE8:
2952 case Iop_CasCmpNE8:
2953 op = S390_ZERO_EXTEND_8;
2954 result = S390_CC_NE;
2955 goto do_compare_ze;
2956
2957 case Iop_CmpEQ16:
2958 case Iop_CasCmpEQ16:
2959 op = S390_ZERO_EXTEND_16;
2960 result = S390_CC_E;
2961 goto do_compare_ze;
2962
2963 case Iop_CmpNE16:
2964 case Iop_CasCmpNE16:
2965 op = S390_ZERO_EXTEND_16;
2966 result = S390_CC_NE;
2967 goto do_compare_ze;
2968
2969 do_compare_ze: {
2970 s390_opnd_RMI op1, op2;
2971
2972 op1 = s390_isel_int_expr_RMI(env, arg1);
2973 reg1 = newVRegI(env);
2974 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2975
2976 op2 = s390_isel_int_expr_RMI(env, arg2);
2977 reg2 = newVRegI(env);
2978 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2979
2980 op2 = s390_opnd_reg(reg2);
2981 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2982
2983 return result;
2984 }
2985
2986 case Iop_CmpEQ32:
2987 case Iop_CmpEQ64:
2988 case Iop_CasCmpEQ32:
2989 case Iop_CasCmpEQ64:
2990 result = S390_CC_E;
2991 goto do_compare;
2992
2993 case Iop_CmpNE32:
2994 case Iop_CmpNE64:
2995 case Iop_CasCmpNE32:
2996 case Iop_CasCmpNE64:
2997 result = S390_CC_NE;
2998 goto do_compare;
2999
3000 do_compare: {
3001 HReg op1;
3002 s390_opnd_RMI op2;
3003
3004 order_commutative_operands(arg1, arg2);
3005
3006 op1 = s390_isel_int_expr(env, arg1);
3007 op2 = s390_isel_int_expr_RMI(env, arg2);
3008
3009 addInstr(env, s390_insn_compare(size, op1, op2, False));
3010
3011 return result;
3012 }
3013
3014 case Iop_CmpLT32S:
3015 case Iop_CmpLE32S:
3016 case Iop_CmpLT64S:
3017 case Iop_CmpLE64S: {
3018 HReg op1;
3019 s390_opnd_RMI op2;
3020
3021 op1 = s390_isel_int_expr(env, arg1);
3022 op2 = s390_isel_int_expr_RMI(env, arg2);
3023
3024 addInstr(env, s390_insn_compare(size, op1, op2, True));
3025
3026 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3027 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3028 }
3029
3030 case Iop_CmpLT32U:
3031 case Iop_CmpLE32U:
3032 case Iop_CmpLT64U:
3033 case Iop_CmpLE64U: {
3034 HReg op1;
3035 s390_opnd_RMI op2;
3036
3037 op1 = s390_isel_int_expr(env, arg1);
3038 op2 = s390_isel_int_expr_RMI(env, arg2);
3039
3040 addInstr(env, s390_insn_compare(size, op1, op2, False));
3041
3042 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3043 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3044 }
3045
3046 default:
3047 goto fail;
3048 }
3049 }
3050
3051 fail:
3052 ppIRExpr(cond);
3053 vpanic("s390_isel_cc: unexpected operator");
3054}
3055
3056
3057/*---------------------------------------------------------*/
3058/*--- ISEL: Statements ---*/
3059/*---------------------------------------------------------*/
3060
3061static void
3062s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3063{
3064 if (vex_traceflags & VEX_TRACE_VCODE) {
3065 vex_printf("\n -- ");
3066 ppIRStmt(stmt);
3067 vex_printf("\n");
3068 }
3069
3070 switch (stmt->tag) {
3071
3072 /* --------- STORE --------- */
3073 case Ist_Store: {
3074 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3075 s390_amode *am;
3076 HReg src;
3077
3078 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3079
3080 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3081
3082 switch (tyd) {
3083 case Ity_I8:
3084 case Ity_I16:
3085 case Ity_I32:
3086 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003087 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003088 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003089 stmt->Ist.Store.data->tag == Iex_Const) {
3090 ULong value =
3091 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3092 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003093 return;
3094 }
sewardj2019a972011-03-07 16:04:07 +00003095 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3096 break;
3097
3098 case Ity_F32:
3099 case Ity_F64:
3100 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3101 break;
3102
florianeb981ae2012-12-21 18:55:03 +00003103 case Ity_D32:
3104 case Ity_D64:
3105 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3106 break;
3107
sewardj2019a972011-03-07 16:04:07 +00003108 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003109 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003110 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003111 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003112
3113 default:
3114 goto stmt_fail;
3115 }
3116
3117 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3118 return;
3119 }
3120
3121 /* --------- PUT --------- */
3122 case Ist_Put: {
3123 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3124 HReg src;
3125 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003126 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003127
florianad43b3a2012-02-20 15:01:14 +00003128 /* Detect updates to certain guest registers. We track the contents
3129 of those registers as long as they contain constants. If the new
3130 constant is either zero or in the 8-bit neighbourhood of the
3131 current value we can use a memory-to-memory insn to do the update. */
3132
3133 Int offset = stmt->Ist.Put.offset;
3134
3135 /* Check necessary conditions:
3136 (1) must be one of the registers we care about
3137 (2) assigned value must be a constant */
3138 Int guest_reg = get_guest_reg(offset);
3139
3140 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3141
florianad43b3a2012-02-20 15:01:14 +00003142 if (stmt->Ist.Put.data->tag != Iex_Const) {
3143 /* Invalidate guest register contents */
3144 env->old_value_valid[guest_reg] = False;
3145 goto not_special;
3146 }
3147
cborntraaf7ad282012-08-08 14:11:33 +00003148 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3149 if (tyd != Ity_I64)
3150 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003151
cborntraaf7ad282012-08-08 14:11:33 +00003152 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003153
3154 old_value = env->old_value[guest_reg];
3155 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3156 env->old_value[guest_reg] = new_value;
3157
3158 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3159 env->old_value_valid[guest_reg] = True;
3160
3161 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003162 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003163 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003164 return;
florianad43b3a2012-02-20 15:01:14 +00003165 }
3166
florianad43b3a2012-02-20 15:01:14 +00003167 if (old_value_is_valid == False) goto not_special;
3168
3169 /* If the new value is in the neighbourhood of the old value
3170 we can use a memory-to-memory insn */
3171 difference = new_value - old_value;
3172
3173 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003174 am = s390_amode_for_guest_state(offset);
3175 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003176 (difference & 0xFF), new_value));
3177 return;
3178 }
3179
florianb93348d2012-12-27 00:59:43 +00003180 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003181 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003182 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003183 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003184 return;
3185 }
3186
3187 /* No special case applies... fall through */
3188
3189 not_special:
florianb93348d2012-12-27 00:59:43 +00003190 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003191
3192 switch (tyd) {
3193 case Ity_I8:
3194 case Ity_I16:
3195 case Ity_I32:
3196 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003197 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003198 stmt->Ist.Put.data->tag == Iex_Const) {
3199 ULong value =
3200 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3201 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003202 return;
3203 }
sewardj2019a972011-03-07 16:04:07 +00003204 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3205 break;
3206
3207 case Ity_F32:
3208 case Ity_F64:
3209 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3210 break;
3211
3212 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003213 case Ity_D128:
3214 /* Does not occur. See function put_(f|d)pr_pair. */
3215 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003216
floriane38f6412012-12-21 17:32:12 +00003217 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003218 case Ity_D64:
3219 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3220 break;
3221
sewardj2019a972011-03-07 16:04:07 +00003222 default:
3223 goto stmt_fail;
3224 }
3225
3226 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3227 return;
3228 }
3229
3230 /* --------- TMP --------- */
3231 case Ist_WrTmp: {
3232 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3233 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3234 HReg src, dst;
3235
3236 switch (tyd) {
3237 case Ity_I128: {
3238 HReg dst_hi, dst_lo, res_hi, res_lo;
3239
3240 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3241 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3242
3243 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3244 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3245 return;
3246 }
3247
3248 case Ity_I8:
3249 case Ity_I16:
3250 case Ity_I32:
3251 case Ity_I64:
3252 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3253 dst = lookupIRTemp(env, tmp);
3254 break;
3255
3256 case Ity_I1: {
3257 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3258 dst = lookupIRTemp(env, tmp);
3259 addInstr(env, s390_insn_cc2bool(dst, cond));
3260 return;
3261 }
3262
3263 case Ity_F32:
3264 case Ity_F64:
3265 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3266 dst = lookupIRTemp(env, tmp);
3267 break;
3268
3269 case Ity_F128: {
3270 HReg dst_hi, dst_lo, res_hi, res_lo;
3271
3272 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3273 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3274
3275 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3276 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3277 return;
3278 }
3279
floriane38f6412012-12-21 17:32:12 +00003280 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003281 case Ity_D64:
3282 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3283 dst = lookupIRTemp(env, tmp);
3284 break;
3285
floriane38f6412012-12-21 17:32:12 +00003286 case Ity_D128: {
3287 HReg dst_hi, dst_lo, res_hi, res_lo;
3288
3289 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3290 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3291
3292 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3293 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3294 return;
3295 }
3296
sewardj2019a972011-03-07 16:04:07 +00003297 default:
3298 goto stmt_fail;
3299 }
3300
3301 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3302 return;
3303 }
3304
3305 /* --------- Call to DIRTY helper --------- */
3306 case Ist_Dirty: {
3307 IRType retty;
3308 IRDirty* d = stmt->Ist.Dirty.details;
3309 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003310 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003311 Int i;
3312
3313 /* Invalidate tracked values of those guest state registers that are
3314 modified by this helper. */
3315 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003316 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3317 descriptors in guest state effect descriptions. Hence: */
3318 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003319 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3320 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3321 if (guest_reg != GUEST_UNKNOWN)
3322 env->old_value_valid[guest_reg] = False;
3323 }
3324 }
sewardj2019a972011-03-07 16:04:07 +00003325
3326 if (d->nFxState == 0)
3327 vassert(!d->needsBBP);
3328
3329 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3330
florian01ed6e72012-05-27 16:52:43 +00003331 if (d->tmp == IRTemp_INVALID) {
3332 /* No return value. */
3333 dst = INVALID_HREG;
3334 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003335 return;
florian01ed6e72012-05-27 16:52:43 +00003336 }
sewardj2019a972011-03-07 16:04:07 +00003337
3338 retty = typeOfIRTemp(env->type_env, d->tmp);
3339 if (retty == Ity_I64 || retty == Ity_I32
3340 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003341 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003342 dst = lookupIRTemp(env, d->tmp);
3343 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003344 return;
3345 }
3346 break;
3347 }
3348
3349 case Ist_CAS:
3350 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3351 IRCAS *cas = stmt->Ist.CAS.details;
3352 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3353 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3354 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3355 HReg old = lookupIRTemp(env, cas->oldLo);
3356
3357 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3358 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3359 } else {
3360 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3361 }
3362 return;
3363 } else {
florian448cbba2012-06-06 02:26:01 +00003364 IRCAS *cas = stmt->Ist.CAS.details;
3365 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3366 HReg r8, r9, r10, r11, r1;
3367 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3368 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3369 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3370 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3371 HReg old_low = lookupIRTemp(env, cas->oldLo);
3372 HReg old_high = lookupIRTemp(env, cas->oldHi);
3373
3374 /* Use non-virtual registers r8 and r9 as pair for op1
3375 and move op1 there */
3376 r8 = make_gpr(8);
3377 r9 = make_gpr(9);
3378 addInstr(env, s390_insn_move(8, r8, op1_high));
3379 addInstr(env, s390_insn_move(8, r9, op1_low));
3380
3381 /* Use non-virtual registers r10 and r11 as pair for op3
3382 and move op3 there */
3383 r10 = make_gpr(10);
3384 r11 = make_gpr(11);
3385 addInstr(env, s390_insn_move(8, r10, op3_high));
3386 addInstr(env, s390_insn_move(8, r11, op3_low));
3387
3388 /* Register r1 is used as a scratch register */
3389 r1 = make_gpr(1);
3390
3391 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3392 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3393 old_high, old_low, r1));
3394 } else {
3395 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3396 old_high, old_low, r1));
3397 }
3398 addInstr(env, s390_insn_move(8, op1_high, r8));
3399 addInstr(env, s390_insn_move(8, op1_low, r9));
3400 addInstr(env, s390_insn_move(8, op3_high, r10));
3401 addInstr(env, s390_insn_move(8, op3_low, r11));
3402 return;
sewardj2019a972011-03-07 16:04:07 +00003403 }
3404 break;
3405
3406 /* --------- EXIT --------- */
3407 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003408 s390_cc_t cond;
3409 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3410
3411 if (tag != Ico_U64)
3412 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3413
florian8844a632012-04-13 04:04:06 +00003414 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003415 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003416
3417 /* Case: boring transfer to known address */
3418 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3419 if (env->chaining_allowed) {
3420 /* .. almost always true .. */
3421 /* Skip the event check at the dst if this is a forwards
3422 edge. */
3423 Bool to_fast_entry
3424 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3425 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3426 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3427 guest_IA, to_fast_entry));
3428 } else {
3429 /* .. very occasionally .. */
3430 /* We can't use chaining, so ask for an assisted transfer,
3431 as that's the only alternative that is allowable. */
3432 HReg dst = s390_isel_int_expr(env,
3433 IRExpr_Const(stmt->Ist.Exit.dst));
3434 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3435 }
3436 return;
3437 }
3438
3439 /* Case: assisted transfer to arbitrary address */
3440 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003441 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003442 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003443 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003444 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003445 case Ijk_Sys_syscall:
3446 case Ijk_ClientReq:
3447 case Ijk_NoRedir:
3448 case Ijk_Yield:
3449 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003450 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3451 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3452 stmt->Ist.Exit.jk));
3453 return;
3454 }
3455 default:
3456 break;
3457 }
3458
3459 /* Do we ever expect to see any other kind? */
3460 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003461 }
3462
3463 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003464 case Ist_MBE:
3465 switch (stmt->Ist.MBE.event) {
3466 case Imbe_Fence:
3467 addInstr(env, s390_insn_mfence());
3468 return;
3469 default:
3470 break;
3471 }
sewardj2019a972011-03-07 16:04:07 +00003472 break;
3473
3474 /* --------- Miscellaneous --------- */
3475
3476 case Ist_PutI: /* Not needed */
3477 case Ist_IMark: /* Doesn't generate any executable code */
3478 case Ist_NoOp: /* Doesn't generate any executable code */
3479 case Ist_AbiHint: /* Meaningless in IR */
3480 return;
3481
3482 default:
3483 break;
3484 }
3485
3486 stmt_fail:
3487 ppIRStmt(stmt);
3488 vpanic("s390_isel_stmt");
3489}
3490
3491
3492/*---------------------------------------------------------*/
3493/*--- ISEL: Basic block terminators (Nexts) ---*/
3494/*---------------------------------------------------------*/
3495
3496static void
florianffbd84d2012-12-09 02:06:29 +00003497iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003498{
sewardj2019a972011-03-07 16:04:07 +00003499 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003500 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003501 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003502 vex_printf("; exit-");
3503 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003504 vex_printf("\n");
3505 }
3506
florian8844a632012-04-13 04:04:06 +00003507 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3508
3509 /* Case: boring transfer to known address */
3510 if (next->tag == Iex_Const) {
3511 IRConst *cdst = next->Iex.Const.con;
3512 vassert(cdst->tag == Ico_U64);
3513 if (jk == Ijk_Boring || jk == Ijk_Call) {
3514 /* Boring transfer to known address */
3515 if (env->chaining_allowed) {
3516 /* .. almost always true .. */
3517 /* Skip the event check at the dst if this is a forwards
3518 edge. */
3519 Bool to_fast_entry
3520 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3521 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3522 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3523 guest_IA, to_fast_entry));
3524 } else {
3525 /* .. very occasionally .. */
3526 /* We can't use chaining, so ask for an indirect transfer,
3527 as that's the cheapest alternative that is allowable. */
3528 HReg dst = s390_isel_int_expr(env, next);
3529 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3530 Ijk_Boring));
3531 }
3532 return;
3533 }
3534 }
3535
3536 /* Case: call/return (==boring) transfer to any address */
3537 switch (jk) {
3538 case Ijk_Boring:
3539 case Ijk_Ret:
3540 case Ijk_Call: {
3541 HReg dst = s390_isel_int_expr(env, next);
3542 if (env->chaining_allowed) {
3543 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3544 } else {
3545 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3546 Ijk_Boring));
3547 }
3548 return;
3549 }
3550 default:
3551 break;
3552 }
3553
3554 /* Case: some other kind of transfer to any address */
3555 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003556 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003557 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003558 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003559 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003560 case Ijk_Sys_syscall:
3561 case Ijk_ClientReq:
3562 case Ijk_NoRedir:
3563 case Ijk_Yield:
3564 case Ijk_SigTRAP: {
3565 HReg dst = s390_isel_int_expr(env, next);
3566 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3567 return;
3568 }
3569 default:
3570 break;
3571 }
3572
3573 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003574}
3575
3576
3577/*---------------------------------------------------------*/
3578/*--- Insn selector top-level ---*/
3579/*---------------------------------------------------------*/
3580
florianf26994a2012-04-21 03:34:54 +00003581/* Translate an entire SB to s390 code.
3582 Note: archinfo_host is a pointer to a stack-allocated variable.
3583 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003584
3585HInstrArray *
3586iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003587 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3588 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3589 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003590{
3591 UInt i, j;
3592 HReg hreg, hregHI;
3593 ISelEnv *env;
3594 UInt hwcaps_host = archinfo_host->hwcaps;
3595
florianf26994a2012-04-21 03:34:54 +00003596 /* KLUDGE: export hwcaps. */
3597 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003598
sewardj2019a972011-03-07 16:04:07 +00003599 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003600 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003601
3602 /* Make up an initial environment to use. */
3603 env = LibVEX_Alloc(sizeof(ISelEnv));
3604 env->vreg_ctr = 0;
3605
3606 /* Set up output code array. */
3607 env->code = newHInstrArray();
3608
3609 /* Copy BB's type env. */
3610 env->type_env = bb->tyenv;
3611
florianad43b3a2012-02-20 15:01:14 +00003612 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00003613 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3614 env->old_value[i] = 0; /* just something to have a defined value */
3615 env->old_value_valid[i] = False;
3616 }
3617
sewardj2019a972011-03-07 16:04:07 +00003618 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3619 change as we go along. For some reason types_used has Int type -- but
3620 it should be unsigned. Internally we use an unsigned type; so we
3621 assert it here. */
3622 vassert(bb->tyenv->types_used >= 0);
3623
3624 env->n_vregmap = bb->tyenv->types_used;
3625 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3626 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3627
florian2c74d242012-09-12 19:38:42 +00003628 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003629 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003630
sewardj2019a972011-03-07 16:04:07 +00003631 /* and finally ... */
3632 env->hwcaps = hwcaps_host;
3633
florian8844a632012-04-13 04:04:06 +00003634 env->max_ga = max_ga;
3635 env->chaining_allowed = chaining_allowed;
3636
sewardj2019a972011-03-07 16:04:07 +00003637 /* For each IR temporary, allocate a suitably-kinded virtual
3638 register. */
3639 j = 0;
3640 for (i = 0; i < env->n_vregmap; i++) {
3641 hregHI = hreg = INVALID_HREG;
3642 switch (bb->tyenv->types[i]) {
3643 case Ity_I1:
3644 case Ity_I8:
3645 case Ity_I16:
3646 case Ity_I32:
3647 hreg = mkHReg(j++, HRcInt64, True);
3648 break;
3649
3650 case Ity_I64:
3651 hreg = mkHReg(j++, HRcInt64, True);
3652 break;
3653
3654 case Ity_I128:
3655 hreg = mkHReg(j++, HRcInt64, True);
3656 hregHI = mkHReg(j++, HRcInt64, True);
3657 break;
3658
3659 case Ity_F32:
3660 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003661 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003662 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003663 hreg = mkHReg(j++, HRcFlt64, True);
3664 break;
3665
3666 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003667 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003668 hreg = mkHReg(j++, HRcFlt64, True);
3669 hregHI = mkHReg(j++, HRcFlt64, True);
3670 break;
3671
3672 case Ity_V128: /* fall through */
3673 default:
3674 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003675 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003676 }
3677
3678 env->vregmap[i] = hreg;
3679 env->vregmapHI[i] = hregHI;
3680 }
3681 env->vreg_ctr = j;
3682
florian8844a632012-04-13 04:04:06 +00003683 /* The very first instruction must be an event check. */
3684 s390_amode *counter, *fail_addr;
3685 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3686 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3687 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3688
3689 /* Possibly a block counter increment (for profiling). At this
3690 point we don't know the address of the counter, so just pretend
3691 it is zero. It will have to be patched later, but before this
3692 translation is used, by a call to LibVEX_patchProfInc. */
3693 if (add_profinc) {
3694 addInstr(env, s390_insn_profinc());
3695 }
3696
sewardj2019a972011-03-07 16:04:07 +00003697 /* Ok, finally we can iterate over the statements. */
3698 for (i = 0; i < bb->stmts_used; i++)
3699 if (bb->stmts[i])
3700 s390_isel_stmt(env, bb->stmts[i]);
3701
florian8844a632012-04-13 04:04:06 +00003702 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003703
3704 /* Record the number of vregs we used. */
3705 env->code->n_vregs = env->vreg_ctr;
3706
3707 return env->code;
3708}
3709
3710/*---------------------------------------------------------------*/
3711/*--- end host_s390_isel.c ---*/
3712/*---------------------------------------------------------------*/