blob: e8b1821a849454477309bef06aeee4c9cad3c2cd [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;
florian67a171c2013-01-20 03:08:04 +0000994 s390_dfp_conv_t dconv;
sewardj2019a972011-03-07 16:04:07 +0000995
996 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
997
998 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
999
1000 switch (expr->tag) {
1001
1002 /* --------- TEMP --------- */
1003 case Iex_RdTmp:
1004 /* Return the virtual register that holds the temporary. */
1005 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1006
1007 /* --------- LOAD --------- */
1008 case Iex_Load: {
1009 HReg dst = newVRegI(env);
1010 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1011
1012 if (expr->Iex.Load.end != Iend_BE)
1013 goto irreducible;
1014
1015 addInstr(env, s390_insn_load(size, dst, am));
1016
1017 return dst;
1018 }
1019
1020 /* --------- BINARY OP --------- */
1021 case Iex_Binop: {
1022 IRExpr *arg1 = expr->Iex.Binop.arg1;
1023 IRExpr *arg2 = expr->Iex.Binop.arg2;
1024 HReg h1, res;
1025 s390_alu_t opkind;
1026 s390_opnd_RMI op2, value, opnd;
1027 s390_insn *insn;
1028 Bool is_commutative, is_signed_multiply, is_signed_divide;
1029
1030 is_commutative = True;
1031
1032 switch (expr->Iex.Binop.op) {
1033 case Iop_MullU8:
1034 case Iop_MullU16:
1035 case Iop_MullU32:
1036 is_signed_multiply = False;
1037 goto do_multiply;
1038
1039 case Iop_MullS8:
1040 case Iop_MullS16:
1041 case Iop_MullS32:
1042 is_signed_multiply = True;
1043 goto do_multiply;
1044
1045 do_multiply: {
1046 HReg r10, r11;
1047 UInt arg_size = size / 2;
1048
1049 order_commutative_operands(arg1, arg2);
1050
1051 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1052 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1053
1054 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001055 r10 = make_gpr(10);
1056 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001057
1058 /* Move the first operand to r11 */
1059 addInstr(env, s390_insn_move(arg_size, r11, h1));
1060
1061 /* Multiply */
1062 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1063
1064 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1065 value into the destination register. */
1066 res = newVRegI(env);
1067 addInstr(env, s390_insn_move(arg_size, res, r10));
1068 value = s390_opnd_imm(arg_size * 8);
1069 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1070 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1071 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1072 opnd = s390_opnd_reg(r11);
1073 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1074 return res;
1075 }
1076
1077 case Iop_DivModS64to32:
1078 is_signed_divide = True;
1079 goto do_divide;
1080
1081 case Iop_DivModU64to32:
1082 is_signed_divide = False;
1083 goto do_divide;
1084
1085 do_divide: {
1086 HReg r10, r11;
1087
1088 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1089 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1090
1091 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001092 r10 = make_gpr(10);
1093 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001094
1095 /* Split the first operand and put the high 32 bits into r10 and
1096 the low 32 bits into r11. */
1097 addInstr(env, s390_insn_move(8, r10, h1));
1098 addInstr(env, s390_insn_move(8, r11, h1));
1099 value = s390_opnd_imm(32);
1100 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1101
1102 /* Divide */
1103 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1104
1105 /* The result is in registers r10 (remainder) and r11 (quotient).
1106 Combine them into a 64-bit value such that the low 32 bits are
1107 the quotient and the upper 32 bits are the remainder. (see
1108 libvex_ir.h). */
1109 res = newVRegI(env);
1110 addInstr(env, s390_insn_move(8, res, r10));
1111 value = s390_opnd_imm(32);
1112 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1113 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1114 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1115 opnd = s390_opnd_reg(r11);
1116 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1117 return res;
1118 }
1119
florian9fcff4c2012-09-10 03:09:04 +00001120 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1121 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1122 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1123 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1124 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1125 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1126 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1127 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1128 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1129 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1130 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1131 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
florian67a171c2013-01-20 03:08:04 +00001132
1133 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
1134 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1135 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1136 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
1137 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1138 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00001139
1140 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001141 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001142
1143 res = newVRegI(env);
1144 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1145
florian2c74d242012-09-12 19:38:42 +00001146 rounding_mode = get_bfp_rounding_mode(env, arg1);
1147 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1148 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001149 return res;
1150 }
1151
1152 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001153 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001154 HReg op_hi, op_lo, f13, f15;
1155
1156 res = newVRegI(env);
1157 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1158
1159 /* We use non-virtual registers r13 and r15 as pair */
1160 f13 = make_fpr(13);
1161 f15 = make_fpr(15);
1162
1163 /* operand --> (f13, f15) */
1164 addInstr(env, s390_insn_move(8, f13, op_hi));
1165 addInstr(env, s390_insn_move(8, f15, op_lo));
1166
florian2c74d242012-09-12 19:38:42 +00001167 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001168 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001169 rounding_mode));
1170 return res;
1171 }
1172
florian5f034622013-01-13 02:29:05 +00001173 do_convert_dfp: {
1174 s390_dfp_round_t rounding_mode;
1175
1176 res = newVRegI(env);
1177 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1178
1179 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001180 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
florian5f034622013-01-13 02:29:05 +00001181 rounding_mode));
1182 return res;
1183 }
1184
1185 do_convert_dfp128: {
1186 s390_dfp_round_t rounding_mode;
1187 HReg op_hi, op_lo, f13, f15;
1188
1189 res = newVRegI(env);
1190 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1191
1192 /* We use non-virtual registers r13 and r15 as pair */
1193 f13 = make_fpr(13);
1194 f15 = make_fpr(15);
1195
1196 /* operand --> (f13, f15) */
1197 addInstr(env, s390_insn_move(8, f13, op_hi));
1198 addInstr(env, s390_insn_move(8, f15, op_lo));
1199
1200 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001201 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res, f13,
florian5f034622013-01-13 02:29:05 +00001202 f15, rounding_mode));
1203 return res;
1204 }
1205
sewardj2019a972011-03-07 16:04:07 +00001206 case Iop_8HLto16:
1207 case Iop_16HLto32:
1208 case Iop_32HLto64: {
1209 HReg h2;
1210 UInt arg_size = size / 2;
1211
1212 res = newVRegI(env);
1213 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1214 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1215
1216 addInstr(env, s390_insn_move(arg_size, res, h1));
1217 value = s390_opnd_imm(arg_size * 8);
1218 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1219 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1220 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1221 opnd = s390_opnd_reg(h2);
1222 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1223 return res;
1224 }
1225
1226 case Iop_Max32U: {
1227 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1228 res = newVRegI(env);
1229 h1 = s390_isel_int_expr(env, arg1);
1230 op2 = s390_isel_int_expr_RMI(env, arg2);
1231
1232 addInstr(env, s390_insn_move(size, res, h1));
1233 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1234 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1235 return res;
1236 }
1237
1238 case Iop_CmpF32:
1239 case Iop_CmpF64: {
1240 HReg cc_s390, h2;
1241
1242 h1 = s390_isel_float_expr(env, arg1);
1243 h2 = s390_isel_float_expr(env, arg2);
1244 cc_s390 = newVRegI(env);
1245
1246 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1247
1248 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1249
florian2d3d87f2012-12-21 21:05:17 +00001250 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001251 }
1252
1253 case Iop_CmpF128: {
1254 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1255
1256 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1257 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1258 cc_s390 = newVRegI(env);
1259
1260 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1261 f12 = make_fpr(12);
1262 f13 = make_fpr(13);
1263 f14 = make_fpr(14);
1264 f15 = make_fpr(15);
1265
1266 /* 1st operand --> (f12, f14) */
1267 addInstr(env, s390_insn_move(8, f12, op1_hi));
1268 addInstr(env, s390_insn_move(8, f14, op1_lo));
1269
1270 /* 2nd operand --> (f13, f15) */
1271 addInstr(env, s390_insn_move(8, f13, op2_hi));
1272 addInstr(env, s390_insn_move(8, f15, op2_lo));
1273
1274 res = newVRegI(env);
1275 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1276
florian2d3d87f2012-12-21 21:05:17 +00001277 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001278 }
1279
florian20c6bca2012-12-26 17:47:19 +00001280 case Iop_CmpD64:
1281 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001282 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001283 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001284
1285 h1 = s390_isel_dfp_expr(env, arg1);
1286 h2 = s390_isel_dfp_expr(env, arg2);
1287 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001288
florian20c6bca2012-12-26 17:47:19 +00001289 switch(expr->Iex.Binop.op) {
1290 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1291 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1292 default: goto irreducible;
1293 }
1294 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001295
florian2d3d87f2012-12-21 21:05:17 +00001296 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001297 }
1298
florian20c6bca2012-12-26 17:47:19 +00001299 case Iop_CmpD128:
1300 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001301 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001302 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001303
1304 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1305 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1306 cc_s390 = newVRegI(env);
1307
1308 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1309 f12 = make_fpr(12);
1310 f13 = make_fpr(13);
1311 f14 = make_fpr(14);
1312 f15 = make_fpr(15);
1313
1314 /* 1st operand --> (f12, f14) */
1315 addInstr(env, s390_insn_move(8, f12, op1_hi));
1316 addInstr(env, s390_insn_move(8, f14, op1_lo));
1317
1318 /* 2nd operand --> (f13, f15) */
1319 addInstr(env, s390_insn_move(8, f13, op2_hi));
1320 addInstr(env, s390_insn_move(8, f15, op2_lo));
1321
florian20c6bca2012-12-26 17:47:19 +00001322 switch(expr->Iex.Binop.op) {
1323 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1324 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1325 default: goto irreducible;
1326 }
1327 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1328 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001329
florian2d3d87f2012-12-21 21:05:17 +00001330 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001331 }
1332
sewardj2019a972011-03-07 16:04:07 +00001333 case Iop_Add8:
1334 case Iop_Add16:
1335 case Iop_Add32:
1336 case Iop_Add64:
1337 opkind = S390_ALU_ADD;
1338 break;
1339
1340 case Iop_Sub8:
1341 case Iop_Sub16:
1342 case Iop_Sub32:
1343 case Iop_Sub64:
1344 opkind = S390_ALU_SUB;
1345 is_commutative = False;
1346 break;
1347
1348 case Iop_And8:
1349 case Iop_And16:
1350 case Iop_And32:
1351 case Iop_And64:
1352 opkind = S390_ALU_AND;
1353 break;
1354
1355 case Iop_Or8:
1356 case Iop_Or16:
1357 case Iop_Or32:
1358 case Iop_Or64:
1359 opkind = S390_ALU_OR;
1360 break;
1361
1362 case Iop_Xor8:
1363 case Iop_Xor16:
1364 case Iop_Xor32:
1365 case Iop_Xor64:
1366 opkind = S390_ALU_XOR;
1367 break;
1368
1369 case Iop_Shl8:
1370 case Iop_Shl16:
1371 case Iop_Shl32:
1372 case Iop_Shl64:
1373 opkind = S390_ALU_LSH;
1374 is_commutative = False;
1375 break;
1376
1377 case Iop_Shr8:
1378 case Iop_Shr16:
1379 case Iop_Shr32:
1380 case Iop_Shr64:
1381 opkind = S390_ALU_RSH;
1382 is_commutative = False;
1383 break;
1384
1385 case Iop_Sar8:
1386 case Iop_Sar16:
1387 case Iop_Sar32:
1388 case Iop_Sar64:
1389 opkind = S390_ALU_RSHA;
1390 is_commutative = False;
1391 break;
1392
1393 default:
1394 goto irreducible;
1395 }
1396
1397 /* Pattern match: 0 - arg1 --> -arg1 */
1398 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1399 res = newVRegI(env);
1400 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1401 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1402 addInstr(env, insn);
1403
1404 return res;
1405 }
1406
1407 if (is_commutative) {
1408 order_commutative_operands(arg1, arg2);
1409 }
1410
1411 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1412 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1413 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001414
1415 /* As right shifts of one/two byte opreands are implemented using a
1416 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1417 switch (expr->Iex.Binop.op) {
1418 case Iop_Shr8:
1419 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1420 break;
1421 case Iop_Shr16:
1422 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1423 break;
1424 case Iop_Sar8:
1425 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1426 break;
1427 case Iop_Sar16:
1428 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1429 break;
1430 default:
1431 insn = s390_insn_move(size, res, h1);
1432 break;
1433 }
1434 addInstr(env, insn);
1435
sewardj2019a972011-03-07 16:04:07 +00001436 insn = s390_insn_alu(size, opkind, res, op2);
1437
1438 addInstr(env, insn);
1439
1440 return res;
1441 }
1442
1443 /* --------- UNARY OP --------- */
1444 case Iex_Unop: {
1445 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1446 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1447 s390_opnd_RMI opnd;
1448 s390_insn *insn;
1449 IRExpr *arg;
1450 HReg dst, h1;
1451 IROp unop, binop;
1452
1453 arg = expr->Iex.Unop.arg;
1454
1455 /* Special cases are handled here */
1456
1457 /* 32-bit multiply with 32-bit result or
1458 64-bit multiply with 64-bit result */
1459 unop = expr->Iex.Unop.op;
1460 binop = arg->Iex.Binop.op;
1461
1462 if ((arg->tag == Iex_Binop &&
1463 ((unop == Iop_64to32 &&
1464 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1465 (unop == Iop_128to64 &&
1466 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1467 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1468 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1469 dst = newVRegI(env); /* Result goes into a new register */
1470 addInstr(env, s390_insn_move(size, dst, h1));
1471 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1472
1473 return dst;
1474 }
1475
florian4d71a082011-12-18 00:08:17 +00001476 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001477 dst = newVRegI(env);
1478 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1479 addInstr(env, s390_insn_move(size, dst, h1));
1480
1481 return dst;
1482 }
1483
floriane38f6412012-12-21 17:32:12 +00001484 if (unop == Iop_ReinterpD64asI64) {
1485 dst = newVRegI(env);
1486 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1487 addInstr(env, s390_insn_move(size, dst, h1));
1488
1489 return dst;
1490 }
1491
floriance9e3db2012-12-27 20:14:03 +00001492 if (unop == Iop_ExtractSigD64) {
1493 dst = newVRegI(env);
1494 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1495 addInstr(env,
1496 s390_insn_dfp_unop(size, S390_DFP_EXTRACT_SIG_D64, dst, h1));
1497 return dst;
1498 }
1499
1500 if (unop == Iop_ExtractSigD128) {
1501 HReg op_hi, op_lo, f13, f15;
1502 dst = newVRegI(env);
1503 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1504
1505 /* We use non-virtual registers r13 and r15 as pair */
1506 f13 = make_fpr(13);
1507 f15 = make_fpr(15);
1508
1509 /* operand --> (f13, f15) */
1510 addInstr(env, s390_insn_move(8, f13, op_hi));
1511 addInstr(env, s390_insn_move(8, f15, op_lo));
1512
1513 addInstr(env, s390_insn_dfp128_unop(size, S390_DFP_EXTRACT_SIG_D128,
1514 dst, f13, f15));
1515 return dst;
1516 }
1517
sewardj2019a972011-03-07 16:04:07 +00001518 /* Expressions whose argument is 1-bit wide */
1519 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1520 s390_cc_t cond = s390_isel_cc(env, arg);
1521 dst = newVRegI(env); /* Result goes into a new register */
1522 addInstr(env, s390_insn_cc2bool(dst, cond));
1523
1524 switch (unop) {
1525 case Iop_1Uto8:
1526 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001527 /* Zero extend */
1528 mask.variant.imm = 1;
1529 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1530 break;
1531
sewardj2019a972011-03-07 16:04:07 +00001532 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001533 /* Zero extend */
1534 mask.variant.imm = 1;
1535 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001536 break;
1537
1538 case Iop_1Sto8:
1539 case Iop_1Sto16:
1540 case Iop_1Sto32:
1541 shift.variant.imm = 31;
1542 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1543 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1544 break;
1545
1546 case Iop_1Sto64:
1547 shift.variant.imm = 63;
1548 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1549 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1550 break;
1551
1552 default:
1553 goto irreducible;
1554 }
1555
1556 return dst;
1557 }
1558
1559 /* Regular processing */
1560
1561 if (unop == Iop_128to64) {
1562 HReg dst_hi, dst_lo;
1563
1564 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1565 return dst_lo;
1566 }
1567
1568 if (unop == Iop_128HIto64) {
1569 HReg dst_hi, dst_lo;
1570
1571 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1572 return dst_hi;
1573 }
1574
1575 dst = newVRegI(env); /* Result goes into a new register */
1576 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1577
1578 switch (unop) {
1579 case Iop_8Uto16:
1580 case Iop_8Uto32:
1581 case Iop_8Uto64:
1582 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1583 break;
1584
1585 case Iop_16Uto32:
1586 case Iop_16Uto64:
1587 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1588 break;
1589
1590 case Iop_32Uto64:
1591 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1592 break;
1593
1594 case Iop_8Sto16:
1595 case Iop_8Sto32:
1596 case Iop_8Sto64:
1597 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1598 break;
1599
1600 case Iop_16Sto32:
1601 case Iop_16Sto64:
1602 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1603 break;
1604
1605 case Iop_32Sto64:
1606 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1607 break;
1608
1609 case Iop_64to8:
1610 case Iop_64to16:
1611 case Iop_64to32:
1612 case Iop_32to8:
1613 case Iop_32to16:
1614 case Iop_16to8:
1615 /* Down-casts are no-ops. Upstream operations will only look at
1616 the bytes that make up the result of the down-cast. So there
1617 is no point setting the other bytes to 0. */
1618 insn = s390_opnd_copy(8, dst, opnd);
1619 break;
1620
1621 case Iop_64HIto32:
1622 addInstr(env, s390_opnd_copy(8, dst, opnd));
1623 shift.variant.imm = 32;
1624 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1625 break;
1626
1627 case Iop_32HIto16:
1628 addInstr(env, s390_opnd_copy(4, dst, opnd));
1629 shift.variant.imm = 16;
1630 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1631 break;
1632
1633 case Iop_16HIto8:
1634 addInstr(env, s390_opnd_copy(2, dst, opnd));
1635 shift.variant.imm = 8;
1636 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1637 break;
1638
1639 case Iop_Not8:
1640 case Iop_Not16:
1641 case Iop_Not32:
1642 case Iop_Not64:
1643 /* XOR with ffff... */
1644 mask.variant.imm = ~(ULong)0;
1645 addInstr(env, s390_opnd_copy(size, dst, opnd));
1646 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1647 break;
1648
1649 case Iop_Left8:
1650 case Iop_Left16:
1651 case Iop_Left32:
1652 case Iop_Left64:
1653 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1654 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1655 break;
1656
1657 case Iop_CmpwNEZ32:
1658 case Iop_CmpwNEZ64: {
1659 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1660 or -X will have a 1 in the MSB. */
1661 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1662 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1663 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1664 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1665 return dst;
1666 }
1667
1668 case Iop_Clz64: {
1669 HReg r10, r11;
1670
sewardj611b06e2011-03-24 08:57:29 +00001671 /* This will be implemented using FLOGR, if possible. So we need to
1672 set aside a pair of non-virtual registers. The result (number of
1673 left-most zero bits) will be in r10. The value in r11 is unspecified
1674 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001675 r10 = make_gpr(10);
1676 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001677
sewardj611b06e2011-03-24 08:57:29 +00001678 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001679 addInstr(env, s390_insn_move(8, dst, r10));
1680 return dst;
1681 }
1682
1683 default:
1684 goto irreducible;
1685 }
1686
1687 addInstr(env, insn);
1688
1689 return dst;
1690 }
1691
1692 /* --------- GET --------- */
1693 case Iex_Get: {
1694 HReg dst = newVRegI(env);
1695 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1696
1697 /* We never load more than 8 bytes from the guest state, because the
1698 floating point register pair is not contiguous. */
1699 vassert(size <= 8);
1700
1701 addInstr(env, s390_insn_load(size, dst, am));
1702
1703 return dst;
1704 }
1705
1706 case Iex_GetI:
1707 /* not needed */
1708 break;
1709
1710 /* --------- CCALL --------- */
1711 case Iex_CCall: {
1712 HReg dst = newVRegI(env);
1713
1714 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001715 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001716 return dst;
1717 }
1718
1719 /* --------- LITERAL --------- */
1720
1721 /* Load a literal into a register. Create a "load immediate"
1722 v-insn and return the register. */
1723 case Iex_Const: {
1724 ULong value;
1725 HReg dst = newVRegI(env);
1726 const IRConst *con = expr->Iex.Const.con;
1727
1728 /* Bitwise copy of the value. No sign/zero-extension */
1729 switch (con->tag) {
1730 case Ico_U64: value = con->Ico.U64; break;
1731 case Ico_U32: value = con->Ico.U32; break;
1732 case Ico_U16: value = con->Ico.U16; break;
1733 case Ico_U8: value = con->Ico.U8; break;
1734 default: vpanic("s390_isel_int_expr: invalid constant");
1735 }
1736
1737 addInstr(env, s390_insn_load_immediate(size, dst, value));
1738
1739 return dst;
1740 }
1741
1742 /* --------- MULTIPLEX --------- */
1743 case Iex_Mux0X: {
1744 IRExpr *cond_expr;
1745 HReg dst, tmp, rX;
1746 s390_opnd_RMI cond, r0, zero;
1747
1748 cond_expr = expr->Iex.Mux0X.cond;
1749
1750 dst = newVRegI(env);
1751 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1752 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1753 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1754
1755 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1756 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1757
1758 addInstr(env, s390_insn_move(size, dst, rX));
1759 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1760 return dst;
1761 }
1762
1763 /* Assume the condition is true and move rX to the destination reg. */
1764 addInstr(env, s390_insn_move(size, dst, rX));
1765
1766 /* Compute the condition ... */
1767 cond = s390_isel_int_expr_RMI(env, cond_expr);
1768
1769 /* tmp = cond & 0xFF */
1770 tmp = newVRegI(env);
1771 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1772 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1773
1774 /* ... and compare it with zero */
1775 zero = s390_opnd_imm(0);
1776 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1777
1778 /* ... and if it compared equal move r0 to the destination reg. */
1779 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1780 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1781
1782 return dst;
1783 }
1784
1785 default:
1786 break;
1787 }
1788
1789 /* We get here if no pattern matched. */
1790 irreducible:
1791 ppIRExpr(expr);
1792 vpanic("s390_isel_int_expr: cannot reduce tree");
1793}
1794
1795
1796static HReg
1797s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1798{
1799 HReg dst = s390_isel_int_expr_wrk(env, expr);
1800
1801 /* Sanity checks ... */
1802 vassert(hregClass(dst) == HRcInt64);
1803 vassert(hregIsVirtual(dst));
1804
1805 return dst;
1806}
1807
1808
1809static s390_opnd_RMI
1810s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1811{
1812 IRType ty = typeOfIRExpr(env->type_env, expr);
1813 s390_opnd_RMI dst;
1814
1815 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1816 ty == Ity_I64);
1817
1818 if (expr->tag == Iex_Load) {
1819 dst.tag = S390_OPND_AMODE;
1820 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1821 } else if (expr->tag == Iex_Get) {
1822 dst.tag = S390_OPND_AMODE;
1823 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1824 } else if (expr->tag == Iex_Const) {
1825 ULong value;
1826
1827 /* The bit pattern for the value will be stored as is in the least
1828 significant bits of VALUE. */
1829 switch (expr->Iex.Const.con->tag) {
1830 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1831 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1832 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1833 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1834 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1835 default:
1836 vpanic("s390_isel_int_expr_RMI");
1837 }
1838
1839 dst.tag = S390_OPND_IMMEDIATE;
1840 dst.variant.imm = value;
1841 } else {
1842 dst.tag = S390_OPND_REG;
1843 dst.variant.reg = s390_isel_int_expr(env, expr);
1844 }
1845
1846 return dst;
1847}
1848
1849
1850/*---------------------------------------------------------*/
1851/*--- ISEL: Floating point expressions (128 bit) ---*/
1852/*---------------------------------------------------------*/
1853static void
1854s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1855 IRExpr *expr)
1856{
1857 IRType ty = typeOfIRExpr(env->type_env, expr);
1858
1859 vassert(ty == Ity_F128);
1860
sewardj2019a972011-03-07 16:04:07 +00001861 switch (expr->tag) {
1862 case Iex_RdTmp:
1863 /* Return the virtual registers that hold the temporary. */
1864 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1865 return;
1866
1867 /* --------- LOAD --------- */
1868 case Iex_Load: {
1869 IRExpr *addr_hi, *addr_lo;
1870 s390_amode *am_hi, *am_lo;
1871
1872 if (expr->Iex.Load.end != Iend_BE)
1873 goto irreducible;
1874
1875 addr_hi = expr->Iex.Load.addr;
1876 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1877
1878 am_hi = s390_isel_amode(env, addr_hi);
1879 am_lo = s390_isel_amode(env, addr_lo);
1880
1881 *dst_hi = newVRegF(env);
1882 *dst_lo = newVRegF(env);
1883 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1884 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1885 return;
1886 }
1887
1888
1889 /* --------- GET --------- */
1890 case Iex_Get:
1891 /* This is not supported because loading 128-bit from the guest
1892 state is almost certainly wrong. Use get_fpr_pair instead. */
1893 vpanic("Iex_Get with F128 data");
1894
1895 /* --------- 4-ary OP --------- */
1896 case Iex_Qop:
1897 vpanic("Iex_Qop with F128 data");
1898
1899 /* --------- TERNARY OP --------- */
1900 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001901 IRTriop *triop = expr->Iex.Triop.details;
1902 IROp op = triop->op;
1903 IRExpr *left = triop->arg2;
1904 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001905 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001906 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1907
1908 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1909 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1910
1911 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1912 f12 = make_fpr(12);
1913 f13 = make_fpr(13);
1914 f14 = make_fpr(14);
1915 f15 = make_fpr(15);
1916
1917 /* 1st operand --> (f12, f14) */
1918 addInstr(env, s390_insn_move(8, f12, op1_hi));
1919 addInstr(env, s390_insn_move(8, f14, op1_lo));
1920
1921 /* 2nd operand --> (f13, f15) */
1922 addInstr(env, s390_insn_move(8, f13, op2_hi));
1923 addInstr(env, s390_insn_move(8, f15, op2_lo));
1924
1925 switch (op) {
1926 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1927 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1928 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1929 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1930 default:
1931 goto irreducible;
1932 }
1933
florian2c74d242012-09-12 19:38:42 +00001934 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1935 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001936
1937 /* Move result to virtual destination register */
1938 *dst_hi = newVRegF(env);
1939 *dst_lo = newVRegF(env);
1940 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1941 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1942
1943 return;
1944 }
1945
1946 /* --------- BINARY OP --------- */
1947 case Iex_Binop: {
1948 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001949
1950 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1951 f12 = make_fpr(12);
1952 f13 = make_fpr(13);
1953 f14 = make_fpr(14);
1954 f15 = make_fpr(15);
1955
1956 switch (expr->Iex.Binop.op) {
1957 case Iop_SqrtF128:
1958 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1959
1960 /* operand --> (f13, f15) */
1961 addInstr(env, s390_insn_move(8, f13, op_hi));
1962 addInstr(env, s390_insn_move(8, f15, op_lo));
1963
florian2c74d242012-09-12 19:38:42 +00001964 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1965 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1966 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001967
1968 /* Move result to virtual destination registers */
1969 *dst_hi = newVRegF(env);
1970 *dst_lo = newVRegF(env);
1971 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1972 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1973 return;
1974
1975 case Iop_F64HLtoF128:
1976 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1977 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1978 return;
1979
1980 default:
1981 goto irreducible;
1982 }
1983 }
1984
1985 /* --------- UNARY OP --------- */
1986 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001987 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001988 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00001989 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001990 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1991
1992 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1993 f12 = make_fpr(12);
1994 f13 = make_fpr(13);
1995 f14 = make_fpr(14);
1996 f15 = make_fpr(15);
1997
florian66e596d2012-09-07 15:00:53 +00001998 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001999 case Iop_NegF128:
2000 if (left->tag == Iex_Unop &&
2001 (left->Iex.Unop.op == Iop_AbsF32 ||
2002 left->Iex.Unop.op == Iop_AbsF64))
2003 bfpop = S390_BFP_NABS;
2004 else
2005 bfpop = S390_BFP_NEG;
2006 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00002007 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2008 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2009 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2010 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2011 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2012 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2013 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00002014 default:
2015 goto irreducible;
2016 }
2017
2018 float128_opnd:
2019 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2020
2021 /* operand --> (f13, f15) */
2022 addInstr(env, s390_insn_move(8, f13, op_hi));
2023 addInstr(env, s390_insn_move(8, f15, op_lo));
2024
florian2c74d242012-09-12 19:38:42 +00002025 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002026 goto move_dst;
2027
2028 convert_float:
2029 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002030 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002031 goto move_dst;
2032
2033 convert_int:
2034 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002035 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002036 goto move_dst;
2037
2038 move_dst:
2039 /* Move result to virtual destination registers */
2040 *dst_hi = newVRegF(env);
2041 *dst_lo = newVRegF(env);
2042 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2043 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2044 return;
2045 }
2046
2047 default:
2048 goto irreducible;
2049 }
2050
2051 /* We get here if no pattern matched. */
2052 irreducible:
2053 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002054 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002055}
2056
2057/* Compute a 128-bit value into two 64-bit registers. These may be either
2058 real or virtual regs; in any case they must not be changed by subsequent
2059 code emitted by the caller. */
2060static void
2061s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2062{
2063 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2064
2065 /* Sanity checks ... */
2066 vassert(hregIsVirtual(*dst_hi));
2067 vassert(hregIsVirtual(*dst_lo));
2068 vassert(hregClass(*dst_hi) == HRcFlt64);
2069 vassert(hregClass(*dst_lo) == HRcFlt64);
2070}
2071
2072
2073/*---------------------------------------------------------*/
2074/*--- ISEL: Floating point expressions (64 bit) ---*/
2075/*---------------------------------------------------------*/
2076
2077static HReg
2078s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2079{
2080 IRType ty = typeOfIRExpr(env->type_env, expr);
2081 UChar size;
2082
2083 vassert(ty == Ity_F32 || ty == Ity_F64);
2084
2085 size = sizeofIRType(ty);
2086
2087 switch (expr->tag) {
2088 case Iex_RdTmp:
2089 /* Return the virtual register that holds the temporary. */
2090 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2091
2092 /* --------- LOAD --------- */
2093 case Iex_Load: {
2094 HReg dst = newVRegF(env);
2095 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2096
2097 if (expr->Iex.Load.end != Iend_BE)
2098 goto irreducible;
2099
2100 addInstr(env, s390_insn_load(size, dst, am));
2101
2102 return dst;
2103 }
2104
2105 /* --------- GET --------- */
2106 case Iex_Get: {
2107 HReg dst = newVRegF(env);
2108 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2109
2110 addInstr(env, s390_insn_load(size, dst, am));
2111
2112 return dst;
2113 }
2114
2115 /* --------- LITERAL --------- */
2116
2117 /* Load a literal into a register. Create a "load immediate"
2118 v-insn and return the register. */
2119 case Iex_Const: {
2120 ULong value;
2121 HReg dst = newVRegF(env);
2122 const IRConst *con = expr->Iex.Const.con;
2123
2124 /* Bitwise copy of the value. No sign/zero-extension */
2125 switch (con->tag) {
2126 case Ico_F32i: value = con->Ico.F32i; break;
2127 case Ico_F64i: value = con->Ico.F64i; break;
2128 default: vpanic("s390_isel_float_expr: invalid constant");
2129 }
2130
2131 if (value != 0) vpanic("cannot load immediate floating point constant");
2132
2133 addInstr(env, s390_insn_load_immediate(size, dst, value));
2134
2135 return dst;
2136 }
2137
2138 /* --------- 4-ary OP --------- */
2139 case Iex_Qop: {
2140 HReg op1, op2, op3, dst;
2141 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002142
florian5906a6b2012-10-16 02:53:33 +00002143 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002144 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002145 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002146 dst = newVRegF(env);
2147 addInstr(env, s390_insn_move(size, dst, op1));
2148
florian96d7cc32012-06-01 20:41:24 +00002149 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002150 case Iop_MAddF32:
2151 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2152 case Iop_MSubF32:
2153 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2154
2155 default:
2156 goto irreducible;
2157 }
2158
florian2c74d242012-09-12 19:38:42 +00002159 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2160 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002161 return dst;
2162 }
2163
2164 /* --------- TERNARY OP --------- */
2165 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002166 IRTriop *triop = expr->Iex.Triop.details;
2167 IROp op = triop->op;
2168 IRExpr *left = triop->arg2;
2169 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002170 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002171 HReg h1, op2, dst;
2172
2173 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2174 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2175 dst = newVRegF(env);
2176 addInstr(env, s390_insn_move(size, dst, h1));
2177 switch (op) {
2178 case Iop_AddF32:
2179 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2180 case Iop_SubF32:
2181 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2182 case Iop_MulF32:
2183 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2184 case Iop_DivF32:
2185 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2186
2187 default:
2188 goto irreducible;
2189 }
2190
florian2c74d242012-09-12 19:38:42 +00002191 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2192 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002193 return dst;
2194 }
2195
2196 /* --------- BINARY OP --------- */
2197 case Iex_Binop: {
2198 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002199 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002200 IRExpr *left = expr->Iex.Binop.arg2;
2201 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002202 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002203
2204 switch (op) {
2205 case Iop_SqrtF32:
2206 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002207 h1 = s390_isel_float_expr(env, left);
2208 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002209 set_bfp_rounding_mode_in_fpc(env, irrm);
2210 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002211 return dst;
sewardj2019a972011-03-07 16:04:07 +00002212
florian9fcff4c2012-09-10 03:09:04 +00002213 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2214 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2215 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2216 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2217 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2218 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2219 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002220
florian9fcff4c2012-09-10 03:09:04 +00002221 convert_float:
2222 h1 = s390_isel_float_expr(env, left);
2223 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002224
florian9fcff4c2012-09-10 03:09:04 +00002225 convert_int:
2226 h1 = s390_isel_int_expr(env, left);
2227 goto convert;
2228
florian2c74d242012-09-12 19:38:42 +00002229 convert: {
florian125e20d2012-10-07 15:42:37 +00002230 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002231 /* convert-from-fixed and load-rounded have a rounding mode field
2232 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002233 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002234 if (s390_host_has_fpext) {
2235 rounding_mode = get_bfp_rounding_mode(env, irrm);
2236 } else {
2237 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002238 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002239 }
florian9fcff4c2012-09-10 03:09:04 +00002240 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2241 rounding_mode));
2242 return dst;
florian2c74d242012-09-12 19:38:42 +00002243 }
florian9fcff4c2012-09-10 03:09:04 +00002244
sewardj2019a972011-03-07 16:04:07 +00002245 default:
2246 goto irreducible;
2247
2248 case Iop_F128toF64:
2249 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002250 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002251 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002252
florian9fcff4c2012-09-10 03:09:04 +00002253 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2254 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002255
florian9fcff4c2012-09-10 03:09:04 +00002256 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002257
florian9fcff4c2012-09-10 03:09:04 +00002258 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002259 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002260 f15 = make_fpr(15);
2261
2262 /* operand --> (f13, f15) */
2263 addInstr(env, s390_insn_move(8, f13, op_hi));
2264 addInstr(env, s390_insn_move(8, f15, op_lo));
2265
2266 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002267 /* load-rounded has a rounding mode field when the floating point
2268 extension facility is installed. */
2269 if (s390_host_has_fpext) {
2270 rounding_mode = get_bfp_rounding_mode(env, irrm);
2271 } else {
2272 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002273 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002274 }
floriancc491a62012-09-10 23:44:37 +00002275 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002276 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002277 return dst;
2278 }
2279 }
sewardj2019a972011-03-07 16:04:07 +00002280 }
2281
2282 /* --------- UNARY OP --------- */
2283 case Iex_Unop: {
2284 IROp op = expr->Iex.Unop.op;
2285 IRExpr *left = expr->Iex.Unop.arg;
2286 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002287 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002288 HReg h1, dst;
2289
2290 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2291 HReg dst_hi, dst_lo;
2292
2293 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2294 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2295 }
2296
florian4d71a082011-12-18 00:08:17 +00002297 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002298 dst = newVRegF(env);
2299 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2300 addInstr(env, s390_insn_move(size, dst, h1));
2301
2302 return dst;
2303 }
2304
2305 switch (op) {
2306 case Iop_NegF32:
2307 case Iop_NegF64:
2308 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002309 (left->Iex.Unop.op == Iop_AbsF32 ||
2310 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002311 bfpop = S390_BFP_NABS;
2312 else
2313 bfpop = S390_BFP_NEG;
2314 break;
2315
2316 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002317 case Iop_AbsF64:
2318 bfpop = S390_BFP_ABS;
2319 break;
2320
2321 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2322 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2323 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2324
2325 convert_float1:
2326 h1 = s390_isel_float_expr(env, left);
2327 goto convert1;
2328
2329 convert_int1:
2330 h1 = s390_isel_int_expr(env, left);
2331 goto convert1;
2332
2333 convert1:
2334 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002335 /* No rounding mode is needed for these conversions. Just stick
2336 one in. It won't be used later on. */
2337 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002338 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002339 return dst;
2340
sewardj2019a972011-03-07 16:04:07 +00002341 default:
2342 goto irreducible;
2343 }
2344
2345 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002346 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002347 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002348 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002349 return dst;
2350 }
2351
2352 default:
2353 goto irreducible;
2354 }
2355
2356 /* We get here if no pattern matched. */
2357 irreducible:
2358 ppIRExpr(expr);
2359 vpanic("s390_isel_float_expr: cannot reduce tree");
2360}
2361
2362
2363static HReg
2364s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2365{
2366 HReg dst = s390_isel_float_expr_wrk(env, expr);
2367
2368 /* Sanity checks ... */
2369 vassert(hregClass(dst) == HRcFlt64);
2370 vassert(hregIsVirtual(dst));
2371
2372 return dst;
2373}
2374
2375
2376/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002377/*--- ISEL: Decimal point expressions (128 bit) ---*/
2378/*---------------------------------------------------------*/
2379static void
2380s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2381 IRExpr *expr)
2382{
2383 IRType ty = typeOfIRExpr(env->type_env, expr);
2384
2385 vassert(ty == Ity_D128);
2386
2387 switch (expr->tag) {
2388 case Iex_RdTmp:
2389 /* Return the virtual registers that hold the temporary. */
2390 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2391 return;
2392
2393 /* --------- LOAD --------- */
2394 case Iex_Load: {
2395 IRExpr *addr_hi, *addr_lo;
2396 s390_amode *am_hi, *am_lo;
2397
2398 if (expr->Iex.Load.end != Iend_BE)
2399 goto irreducible;
2400
2401 addr_hi = expr->Iex.Load.addr;
2402 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2403
2404 am_hi = s390_isel_amode(env, addr_hi);
2405 am_lo = s390_isel_amode(env, addr_lo);
2406
2407 *dst_hi = newVRegF(env);
2408 *dst_lo = newVRegF(env);
2409 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2410 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2411 return;
2412 }
2413
2414 /* --------- GET --------- */
2415 case Iex_Get:
2416 /* This is not supported because loading 128-bit from the guest
2417 state is almost certainly wrong. Use get_dpr_pair instead. */
2418 vpanic("Iex_Get with D128 data");
2419
2420 /* --------- 4-ary OP --------- */
2421 case Iex_Qop:
2422 vpanic("Iex_Qop with D128 data");
2423
2424 /* --------- TERNARY OP --------- */
2425 case Iex_Triop: {
2426 IRTriop *triop = expr->Iex.Triop.details;
2427 IROp op = triop->op;
2428 IRExpr *irrm = triop->arg1;
2429 IRExpr *left = triop->arg2;
2430 IRExpr *right = triop->arg3;
2431 s390_dfp_round_t rounding_mode;
2432 s390_dfp_binop_t dfpop;
2433 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2434
2435 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2436 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2437
2438 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2439 (f12, f14) as op2 and (f13, f15) as destination) */
2440 f9 = make_fpr(9);
2441 f11 = make_fpr(11);
2442 f12 = make_fpr(12);
2443 f13 = make_fpr(13);
2444 f14 = make_fpr(14);
2445 f15 = make_fpr(15);
2446
2447 /* 1st operand --> (f9, f11) */
2448 addInstr(env, s390_insn_move(8, f9, op1_hi));
2449 addInstr(env, s390_insn_move(8, f11, op1_lo));
2450
2451 /* 2nd operand --> (f12, f14) */
2452 addInstr(env, s390_insn_move(8, f12, op2_hi));
2453 addInstr(env, s390_insn_move(8, f14, op2_lo));
2454
2455 switch (op) {
2456 case Iop_AddD128: dfpop = S390_DFP_ADD; break;
2457 case Iop_SubD128: dfpop = S390_DFP_SUB; break;
2458 case Iop_MulD128: dfpop = S390_DFP_MUL; break;
2459 case Iop_DivD128: dfpop = S390_DFP_DIV; break;
2460 default:
2461 goto irreducible;
2462 }
2463
2464 /* DFP binary ops have insns with rounding mode field
2465 when the floating point extension facility is installed. */
2466 if (s390_host_has_fpext) {
2467 rounding_mode = get_dfp_rounding_mode(env, irrm);
2468 } else {
2469 set_dfp_rounding_mode_in_fpc(env, irrm);
2470 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2471 }
2472
2473 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2474 f12, f14, rounding_mode));
2475
2476 /* Move result to virtual destination register */
2477 *dst_hi = newVRegF(env);
2478 *dst_lo = newVRegF(env);
2479 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2480 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2481
2482 return;
2483 }
2484
2485 /* --------- BINARY OP --------- */
2486 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002487
floriane38f6412012-12-21 17:32:12 +00002488 switch (expr->Iex.Binop.op) {
2489 case Iop_D64HLtoD128:
2490 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2491 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2492 return;
2493
florian1b901d42013-01-01 22:19:24 +00002494 case Iop_ShlD128:
2495 case Iop_ShrD128: {
2496 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2497 s390_dfp_intop_t intop;
2498 IRExpr *left = expr->Iex.Binop.arg1;
2499 IRExpr *right = expr->Iex.Binop.arg2;
2500
2501 switch (expr->Iex.Binop.op) {
2502 case Iop_ShlD128: intop = S390_DFP_SHIFT_LEFT; break;
2503 case Iop_ShrD128: intop = S390_DFP_SHIFT_RIGHT; break;
2504 default: goto irreducible;
2505 }
2506
2507 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2508 f9 = make_fpr(9); /* 128 bit dfp operand */
2509 f11 = make_fpr(11);
2510
2511 f13 = make_fpr(13); /* 128 bit dfp destination */
2512 f15 = make_fpr(15);
2513
2514 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* dfp operand */
2515 addInstr(env, s390_insn_move(8, f9, op1_hi));
2516 addInstr(env, s390_insn_move(8, f11, op1_lo));
2517
2518 op2 = s390_isel_int_expr(env, right); /* int operand */
2519
2520 addInstr(env,
2521 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2522
2523 /* Move result to virtual destination register */
2524 *dst_hi = newVRegF(env);
2525 *dst_lo = newVRegF(env);
2526 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2527 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2528 return;
2529 }
2530
floriane38f6412012-12-21 17:32:12 +00002531 default:
2532 goto irreducible;
2533 }
2534 }
2535
2536 /* --------- UNARY OP --------- */
2537 case Iex_Unop: {
2538 IRExpr *left = expr->Iex.Unop.arg;
2539 s390_dfp_conv_t conv;
2540 // HReg op, f12, f13, f14, f15;
2541 HReg op, f12, f14;
2542
2543 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2544 f12 = make_fpr(12);
2545 // f13 = make_fpr(13);
2546 f14 = make_fpr(14);
2547 // f15 = make_fpr(15);
2548
2549 switch (expr->Iex.Unop.op) {
2550 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002551 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
2552 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2553 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002554 default:
2555 goto irreducible;
2556 }
2557
2558 convert_dfp:
2559 op = s390_isel_dfp_expr(env, left);
2560 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2561 goto move_dst;
2562
florian5f034622013-01-13 02:29:05 +00002563 convert_int:
2564 op = s390_isel_int_expr(env, left);
2565 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2566 goto move_dst;
2567
floriane38f6412012-12-21 17:32:12 +00002568 move_dst:
2569 /* Move result to virtual destination registers */
2570 *dst_hi = newVRegF(env);
2571 *dst_lo = newVRegF(env);
2572 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2573 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2574 return;
2575 }
2576
2577 default:
2578 goto irreducible;
2579 }
2580
2581 /* We get here if no pattern matched. */
2582 irreducible:
2583 ppIRExpr(expr);
2584 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2585
2586}
2587
2588
2589/* Compute a 128-bit value into two 64-bit registers. These may be either
2590 real or virtual regs; in any case they must not be changed by subsequent
2591 code emitted by the caller. */
2592static void
2593s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2594{
2595 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2596
2597 /* Sanity checks ... */
2598 vassert(hregIsVirtual(*dst_hi));
2599 vassert(hregIsVirtual(*dst_lo));
2600 vassert(hregClass(*dst_hi) == HRcFlt64);
2601 vassert(hregClass(*dst_lo) == HRcFlt64);
2602}
2603
2604
2605/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002606/*--- ISEL: Decimal point expressions (64 bit) ---*/
2607/*---------------------------------------------------------*/
2608
2609static HReg
2610s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2611{
2612 IRType ty = typeOfIRExpr(env->type_env, expr);
2613 UChar size;
2614
floriane38f6412012-12-21 17:32:12 +00002615 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002616
2617 size = sizeofIRType(ty);
2618
2619 switch (expr->tag) {
2620 case Iex_RdTmp:
2621 /* Return the virtual register that holds the temporary. */
2622 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2623
2624 /* --------- LOAD --------- */
2625 case Iex_Load: {
2626 HReg dst = newVRegF(env);
2627 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2628
2629 if (expr->Iex.Load.end != Iend_BE)
2630 goto irreducible;
2631
2632 addInstr(env, s390_insn_load(size, dst, am));
2633
2634 return dst;
2635 }
2636
2637 /* --------- GET --------- */
2638 case Iex_Get: {
2639 HReg dst = newVRegF(env);
2640 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2641
2642 addInstr(env, s390_insn_load(size, dst, am));
2643
2644 return dst;
2645 }
2646
floriane38f6412012-12-21 17:32:12 +00002647 /* --------- BINARY OP --------- */
2648 case Iex_Binop: {
2649 IROp op = expr->Iex.Binop.op;
2650 IRExpr *irrm = expr->Iex.Binop.arg1;
2651 IRExpr *left = expr->Iex.Binop.arg2;
2652 HReg h1, dst;
2653 s390_dfp_conv_t conv;
2654
2655 switch (op) {
2656 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002657 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002658
2659 convert_dfp:
2660 h1 = s390_isel_dfp_expr(env, left);
2661 goto convert;
2662
florian5f034622013-01-13 02:29:05 +00002663 convert_int:
2664 h1 = s390_isel_int_expr(env, left);
2665 goto convert;
2666
floriane38f6412012-12-21 17:32:12 +00002667 convert: {
2668 s390_dfp_round_t rounding_mode;
2669 /* convert-from-fixed and load-rounded have a rounding mode field
2670 when the floating point extension facility is installed. */
2671 dst = newVRegF(env);
2672 if (s390_host_has_fpext) {
2673 rounding_mode = get_dfp_rounding_mode(env, irrm);
2674 } else {
2675 set_dfp_rounding_mode_in_fpc(env, irrm);
2676 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2677 }
2678 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2679 rounding_mode));
2680 return dst;
2681 }
floriane38f6412012-12-21 17:32:12 +00002682
2683 case Iop_D128toD64: {
2684 HReg op_hi, op_lo, f13, f15;
2685 s390_dfp_round_t rounding_mode;
2686
2687 conv = S390_DFP_D128_TO_D64;
2688
2689 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2690
2691 /* We use non-virtual registers as pairs (f13, f15) */
2692 f13 = make_fpr(13);
2693 f15 = make_fpr(15);
2694
2695 /* operand --> (f13, f15) */
2696 addInstr(env, s390_insn_move(8, f13, op_hi));
2697 addInstr(env, s390_insn_move(8, f15, op_lo));
2698
2699 dst = newVRegF(env);
2700 /* load-rounded has a rounding mode field when the floating point
2701 extension facility is installed. */
2702 if (s390_host_has_fpext) {
2703 rounding_mode = get_dfp_rounding_mode(env, irrm);
2704 } else {
2705 set_dfp_rounding_mode_in_fpc(env, irrm);
2706 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2707 }
2708 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2709 rounding_mode));
2710 return dst;
2711 }
2712
florian1b901d42013-01-01 22:19:24 +00002713 case Iop_ShlD64:
2714 case Iop_ShrD64: {
2715 HReg op2;
2716 HReg op3;
2717 s390_dfp_intop_t intop;
2718 IRExpr *op1 = expr->Iex.Binop.arg1;
2719 IRExpr *shift = expr->Iex.Binop.arg2;
2720
2721 switch (expr->Iex.Binop.op) {
2722 case Iop_ShlD64: intop = S390_DFP_SHIFT_LEFT; break;
2723 case Iop_ShrD64: intop = S390_DFP_SHIFT_RIGHT; break;
2724 default: goto irreducible;
2725 }
2726
2727 op2 = s390_isel_int_expr(env, shift);
2728 op3 = s390_isel_dfp_expr(env, op1);
2729 dst = newVRegF(env);
2730
2731 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
2732 return dst;
2733 }
2734
2735 default:
2736 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00002737 }
2738 }
2739
2740 /* --------- UNARY OP --------- */
2741 case Iex_Unop: {
2742 IROp op = expr->Iex.Unop.op;
2743 IRExpr *left = expr->Iex.Unop.arg;
2744 s390_dfp_conv_t conv;
2745 HReg h1, dst;
2746
2747 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2748 HReg dst_hi, dst_lo;
2749
2750 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2751 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2752 }
2753
2754 if (op == Iop_ReinterpI64asD64) {
2755 dst = newVRegF(env);
2756 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2757 addInstr(env, s390_insn_move(size, dst, h1));
2758
2759 return dst;
2760 }
2761
2762 switch (op) {
2763 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00002764 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
2765 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00002766
2767 convert_dfp1:
2768 h1 = s390_isel_dfp_expr(env, left);
2769 goto convert1;
2770
florian5f034622013-01-13 02:29:05 +00002771 convert_int1:
2772 h1 = s390_isel_int_expr(env, left);
2773 goto convert1;
2774
floriane38f6412012-12-21 17:32:12 +00002775 convert1:
2776 dst = newVRegF(env);
2777 /* No rounding mode is needed for these conversions. Just stick
2778 one in. It won't be used later on. */
2779 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2780 S390_DFP_ROUND_NEAREST_EVEN_4));
2781 return dst;
2782
2783 default:
2784 goto irreducible;
2785 }
2786 }
2787
florian12390202012-11-10 22:34:14 +00002788 /* --------- TERNARY OP --------- */
2789 case Iex_Triop: {
2790 IRTriop *triop = expr->Iex.Triop.details;
2791 IROp op = triop->op;
2792 IRExpr *irrm = triop->arg1;
2793 IRExpr *left = triop->arg2;
2794 IRExpr *right = triop->arg3;
2795 s390_dfp_round_t rounding_mode;
2796 s390_dfp_binop_t dfpop;
2797 HReg op2, op3, dst;
2798
2799 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2800 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2801 dst = newVRegF(env);
2802 switch (op) {
2803 case Iop_AddD64: dfpop = S390_DFP_ADD; break;
2804 case Iop_SubD64: dfpop = S390_DFP_SUB; break;
2805 case Iop_MulD64: dfpop = S390_DFP_MUL; break;
2806 case Iop_DivD64: dfpop = S390_DFP_DIV; break;
2807 default:
2808 goto irreducible;
2809 }
2810 /* DFP binary ops have insns with rounding mode field
2811 when the floating point extension facility is installed. */
2812 if (s390_host_has_fpext) {
2813 rounding_mode = get_dfp_rounding_mode(env, irrm);
2814 } else {
2815 set_dfp_rounding_mode_in_fpc(env, irrm);
2816 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2817 }
2818
2819 addInstr(env,
2820 s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
2821 return dst;
2822 }
2823
2824 default:
2825 goto irreducible;
2826 }
2827
2828 /* We get here if no pattern matched. */
2829 irreducible:
2830 ppIRExpr(expr);
2831 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2832}
2833
2834static HReg
2835s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2836{
2837 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2838
2839 /* Sanity checks ... */
2840 vassert(hregClass(dst) == HRcFlt64);
2841 vassert(hregIsVirtual(dst));
2842
2843 return dst;
2844}
2845
2846
2847/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002848/*--- ISEL: Condition Code ---*/
2849/*---------------------------------------------------------*/
2850
2851/* This function handles all operators that produce a 1-bit result */
2852static s390_cc_t
2853s390_isel_cc(ISelEnv *env, IRExpr *cond)
2854{
2855 UChar size;
2856
2857 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2858
2859 /* Constant: either 1 or 0 */
2860 if (cond->tag == Iex_Const) {
2861 vassert(cond->Iex.Const.con->tag == Ico_U1);
2862 vassert(cond->Iex.Const.con->Ico.U1 == True
2863 || cond->Iex.Const.con->Ico.U1 == False);
2864
2865 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2866 }
2867
2868 /* Variable: values are 1 or 0 */
2869 if (cond->tag == Iex_RdTmp) {
2870 IRTemp tmp = cond->Iex.RdTmp.tmp;
2871 HReg reg = lookupIRTemp(env, tmp);
2872
2873 /* Load-and-test does not modify REG; so this is OK. */
2874 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2875 size = 4;
2876 else
2877 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2878 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2879 return S390_CC_NE;
2880 }
2881
2882 /* Unary operators */
2883 if (cond->tag == Iex_Unop) {
2884 IRExpr *arg = cond->Iex.Unop.arg;
2885
2886 switch (cond->Iex.Unop.op) {
2887 case Iop_Not1: /* Not1(cond) */
2888 /* Generate code for EXPR, and negate the test condition */
2889 return s390_cc_invert(s390_isel_cc(env, arg));
2890
2891 /* Iop_32/64to1 select the LSB from their operand */
2892 case Iop_32to1:
2893 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002894 HReg dst = newVRegI(env);
2895 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002896
2897 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2898
florianf366a802012-08-03 00:42:18 +00002899 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002900 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2901 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2902 return S390_CC_NE;
2903 }
2904
2905 case Iop_CmpNEZ8:
2906 case Iop_CmpNEZ16: {
2907 s390_opnd_RMI src;
2908 s390_unop_t op;
2909 HReg dst;
2910
2911 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2912 : S390_ZERO_EXTEND_16;
2913 dst = newVRegI(env);
2914 src = s390_isel_int_expr_RMI(env, arg);
2915 addInstr(env, s390_insn_unop(4, op, dst, src));
2916 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2917 return S390_CC_NE;
2918 }
2919
2920 case Iop_CmpNEZ32:
2921 case Iop_CmpNEZ64: {
2922 s390_opnd_RMI src;
2923
2924 src = s390_isel_int_expr_RMI(env, arg);
2925 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2926 addInstr(env, s390_insn_test(size, src));
2927 return S390_CC_NE;
2928 }
2929
2930 default:
2931 goto fail;
2932 }
2933 }
2934
2935 /* Binary operators */
2936 if (cond->tag == Iex_Binop) {
2937 IRExpr *arg1 = cond->Iex.Binop.arg1;
2938 IRExpr *arg2 = cond->Iex.Binop.arg2;
2939 HReg reg1, reg2;
2940
2941 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2942
2943 switch (cond->Iex.Binop.op) {
2944 s390_unop_t op;
2945 s390_cc_t result;
2946
2947 case Iop_CmpEQ8:
2948 case Iop_CasCmpEQ8:
2949 op = S390_ZERO_EXTEND_8;
2950 result = S390_CC_E;
2951 goto do_compare_ze;
2952
2953 case Iop_CmpNE8:
2954 case Iop_CasCmpNE8:
2955 op = S390_ZERO_EXTEND_8;
2956 result = S390_CC_NE;
2957 goto do_compare_ze;
2958
2959 case Iop_CmpEQ16:
2960 case Iop_CasCmpEQ16:
2961 op = S390_ZERO_EXTEND_16;
2962 result = S390_CC_E;
2963 goto do_compare_ze;
2964
2965 case Iop_CmpNE16:
2966 case Iop_CasCmpNE16:
2967 op = S390_ZERO_EXTEND_16;
2968 result = S390_CC_NE;
2969 goto do_compare_ze;
2970
2971 do_compare_ze: {
2972 s390_opnd_RMI op1, op2;
2973
2974 op1 = s390_isel_int_expr_RMI(env, arg1);
2975 reg1 = newVRegI(env);
2976 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2977
2978 op2 = s390_isel_int_expr_RMI(env, arg2);
2979 reg2 = newVRegI(env);
2980 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2981
2982 op2 = s390_opnd_reg(reg2);
2983 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2984
2985 return result;
2986 }
2987
2988 case Iop_CmpEQ32:
2989 case Iop_CmpEQ64:
2990 case Iop_CasCmpEQ32:
2991 case Iop_CasCmpEQ64:
2992 result = S390_CC_E;
2993 goto do_compare;
2994
2995 case Iop_CmpNE32:
2996 case Iop_CmpNE64:
2997 case Iop_CasCmpNE32:
2998 case Iop_CasCmpNE64:
2999 result = S390_CC_NE;
3000 goto do_compare;
3001
3002 do_compare: {
3003 HReg op1;
3004 s390_opnd_RMI op2;
3005
3006 order_commutative_operands(arg1, arg2);
3007
3008 op1 = s390_isel_int_expr(env, arg1);
3009 op2 = s390_isel_int_expr_RMI(env, arg2);
3010
3011 addInstr(env, s390_insn_compare(size, op1, op2, False));
3012
3013 return result;
3014 }
3015
3016 case Iop_CmpLT32S:
3017 case Iop_CmpLE32S:
3018 case Iop_CmpLT64S:
3019 case Iop_CmpLE64S: {
3020 HReg op1;
3021 s390_opnd_RMI op2;
3022
3023 op1 = s390_isel_int_expr(env, arg1);
3024 op2 = s390_isel_int_expr_RMI(env, arg2);
3025
3026 addInstr(env, s390_insn_compare(size, op1, op2, True));
3027
3028 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3029 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3030 }
3031
3032 case Iop_CmpLT32U:
3033 case Iop_CmpLE32U:
3034 case Iop_CmpLT64U:
3035 case Iop_CmpLE64U: {
3036 HReg op1;
3037 s390_opnd_RMI op2;
3038
3039 op1 = s390_isel_int_expr(env, arg1);
3040 op2 = s390_isel_int_expr_RMI(env, arg2);
3041
3042 addInstr(env, s390_insn_compare(size, op1, op2, False));
3043
3044 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3045 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3046 }
3047
3048 default:
3049 goto fail;
3050 }
3051 }
3052
3053 fail:
3054 ppIRExpr(cond);
3055 vpanic("s390_isel_cc: unexpected operator");
3056}
3057
3058
3059/*---------------------------------------------------------*/
3060/*--- ISEL: Statements ---*/
3061/*---------------------------------------------------------*/
3062
3063static void
3064s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3065{
3066 if (vex_traceflags & VEX_TRACE_VCODE) {
3067 vex_printf("\n -- ");
3068 ppIRStmt(stmt);
3069 vex_printf("\n");
3070 }
3071
3072 switch (stmt->tag) {
3073
3074 /* --------- STORE --------- */
3075 case Ist_Store: {
3076 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3077 s390_amode *am;
3078 HReg src;
3079
3080 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3081
3082 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3083
3084 switch (tyd) {
3085 case Ity_I8:
3086 case Ity_I16:
3087 case Ity_I32:
3088 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003089 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003090 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003091 stmt->Ist.Store.data->tag == Iex_Const) {
3092 ULong value =
3093 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3094 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003095 return;
3096 }
sewardj2019a972011-03-07 16:04:07 +00003097 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3098 break;
3099
3100 case Ity_F32:
3101 case Ity_F64:
3102 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3103 break;
3104
florianeb981ae2012-12-21 18:55:03 +00003105 case Ity_D32:
3106 case Ity_D64:
3107 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3108 break;
3109
sewardj2019a972011-03-07 16:04:07 +00003110 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003111 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003112 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003113 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003114
3115 default:
3116 goto stmt_fail;
3117 }
3118
3119 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3120 return;
3121 }
3122
3123 /* --------- PUT --------- */
3124 case Ist_Put: {
3125 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3126 HReg src;
3127 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003128 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003129
florianad43b3a2012-02-20 15:01:14 +00003130 /* Detect updates to certain guest registers. We track the contents
3131 of those registers as long as they contain constants. If the new
3132 constant is either zero or in the 8-bit neighbourhood of the
3133 current value we can use a memory-to-memory insn to do the update. */
3134
3135 Int offset = stmt->Ist.Put.offset;
3136
3137 /* Check necessary conditions:
3138 (1) must be one of the registers we care about
3139 (2) assigned value must be a constant */
3140 Int guest_reg = get_guest_reg(offset);
3141
3142 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3143
florianad43b3a2012-02-20 15:01:14 +00003144 if (stmt->Ist.Put.data->tag != Iex_Const) {
3145 /* Invalidate guest register contents */
3146 env->old_value_valid[guest_reg] = False;
3147 goto not_special;
3148 }
3149
cborntraaf7ad282012-08-08 14:11:33 +00003150 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3151 if (tyd != Ity_I64)
3152 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003153
cborntraaf7ad282012-08-08 14:11:33 +00003154 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003155
3156 old_value = env->old_value[guest_reg];
3157 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3158 env->old_value[guest_reg] = new_value;
3159
3160 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3161 env->old_value_valid[guest_reg] = True;
3162
3163 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003164 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003165 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003166 return;
florianad43b3a2012-02-20 15:01:14 +00003167 }
3168
florianad43b3a2012-02-20 15:01:14 +00003169 if (old_value_is_valid == False) goto not_special;
3170
3171 /* If the new value is in the neighbourhood of the old value
3172 we can use a memory-to-memory insn */
3173 difference = new_value - old_value;
3174
3175 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003176 am = s390_amode_for_guest_state(offset);
3177 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003178 (difference & 0xFF), new_value));
3179 return;
3180 }
3181
florianb93348d2012-12-27 00:59:43 +00003182 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003183 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003184 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003185 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003186 return;
3187 }
3188
3189 /* No special case applies... fall through */
3190
3191 not_special:
florianb93348d2012-12-27 00:59:43 +00003192 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003193
3194 switch (tyd) {
3195 case Ity_I8:
3196 case Ity_I16:
3197 case Ity_I32:
3198 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003199 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003200 stmt->Ist.Put.data->tag == Iex_Const) {
3201 ULong value =
3202 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3203 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003204 return;
3205 }
sewardj2019a972011-03-07 16:04:07 +00003206 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3207 break;
3208
3209 case Ity_F32:
3210 case Ity_F64:
3211 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3212 break;
3213
3214 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003215 case Ity_D128:
3216 /* Does not occur. See function put_(f|d)pr_pair. */
3217 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003218
floriane38f6412012-12-21 17:32:12 +00003219 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003220 case Ity_D64:
3221 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3222 break;
3223
sewardj2019a972011-03-07 16:04:07 +00003224 default:
3225 goto stmt_fail;
3226 }
3227
3228 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3229 return;
3230 }
3231
3232 /* --------- TMP --------- */
3233 case Ist_WrTmp: {
3234 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3235 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3236 HReg src, dst;
3237
3238 switch (tyd) {
3239 case Ity_I128: {
3240 HReg dst_hi, dst_lo, res_hi, res_lo;
3241
3242 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3243 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3244
3245 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3246 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3247 return;
3248 }
3249
3250 case Ity_I8:
3251 case Ity_I16:
3252 case Ity_I32:
3253 case Ity_I64:
3254 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3255 dst = lookupIRTemp(env, tmp);
3256 break;
3257
3258 case Ity_I1: {
3259 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3260 dst = lookupIRTemp(env, tmp);
3261 addInstr(env, s390_insn_cc2bool(dst, cond));
3262 return;
3263 }
3264
3265 case Ity_F32:
3266 case Ity_F64:
3267 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3268 dst = lookupIRTemp(env, tmp);
3269 break;
3270
3271 case Ity_F128: {
3272 HReg dst_hi, dst_lo, res_hi, res_lo;
3273
3274 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3275 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3276
3277 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3278 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3279 return;
3280 }
3281
floriane38f6412012-12-21 17:32:12 +00003282 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003283 case Ity_D64:
3284 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3285 dst = lookupIRTemp(env, tmp);
3286 break;
3287
floriane38f6412012-12-21 17:32:12 +00003288 case Ity_D128: {
3289 HReg dst_hi, dst_lo, res_hi, res_lo;
3290
3291 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3292 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3293
3294 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3295 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3296 return;
3297 }
3298
sewardj2019a972011-03-07 16:04:07 +00003299 default:
3300 goto stmt_fail;
3301 }
3302
3303 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3304 return;
3305 }
3306
3307 /* --------- Call to DIRTY helper --------- */
3308 case Ist_Dirty: {
3309 IRType retty;
3310 IRDirty* d = stmt->Ist.Dirty.details;
3311 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003312 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003313 Int i;
3314
3315 /* Invalidate tracked values of those guest state registers that are
3316 modified by this helper. */
3317 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003318 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3319 descriptors in guest state effect descriptions. Hence: */
3320 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003321 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3322 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3323 if (guest_reg != GUEST_UNKNOWN)
3324 env->old_value_valid[guest_reg] = False;
3325 }
3326 }
sewardj2019a972011-03-07 16:04:07 +00003327
3328 if (d->nFxState == 0)
3329 vassert(!d->needsBBP);
3330
3331 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3332
florian01ed6e72012-05-27 16:52:43 +00003333 if (d->tmp == IRTemp_INVALID) {
3334 /* No return value. */
3335 dst = INVALID_HREG;
3336 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003337 return;
florian01ed6e72012-05-27 16:52:43 +00003338 }
sewardj2019a972011-03-07 16:04:07 +00003339
3340 retty = typeOfIRTemp(env->type_env, d->tmp);
3341 if (retty == Ity_I64 || retty == Ity_I32
3342 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003343 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003344 dst = lookupIRTemp(env, d->tmp);
3345 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003346 return;
3347 }
3348 break;
3349 }
3350
3351 case Ist_CAS:
3352 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3353 IRCAS *cas = stmt->Ist.CAS.details;
3354 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3355 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3356 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3357 HReg old = lookupIRTemp(env, cas->oldLo);
3358
3359 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3360 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3361 } else {
3362 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3363 }
3364 return;
3365 } else {
florian448cbba2012-06-06 02:26:01 +00003366 IRCAS *cas = stmt->Ist.CAS.details;
3367 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3368 HReg r8, r9, r10, r11, r1;
3369 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3370 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3371 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3372 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3373 HReg old_low = lookupIRTemp(env, cas->oldLo);
3374 HReg old_high = lookupIRTemp(env, cas->oldHi);
3375
3376 /* Use non-virtual registers r8 and r9 as pair for op1
3377 and move op1 there */
3378 r8 = make_gpr(8);
3379 r9 = make_gpr(9);
3380 addInstr(env, s390_insn_move(8, r8, op1_high));
3381 addInstr(env, s390_insn_move(8, r9, op1_low));
3382
3383 /* Use non-virtual registers r10 and r11 as pair for op3
3384 and move op3 there */
3385 r10 = make_gpr(10);
3386 r11 = make_gpr(11);
3387 addInstr(env, s390_insn_move(8, r10, op3_high));
3388 addInstr(env, s390_insn_move(8, r11, op3_low));
3389
3390 /* Register r1 is used as a scratch register */
3391 r1 = make_gpr(1);
3392
3393 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3394 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3395 old_high, old_low, r1));
3396 } else {
3397 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3398 old_high, old_low, r1));
3399 }
3400 addInstr(env, s390_insn_move(8, op1_high, r8));
3401 addInstr(env, s390_insn_move(8, op1_low, r9));
3402 addInstr(env, s390_insn_move(8, op3_high, r10));
3403 addInstr(env, s390_insn_move(8, op3_low, r11));
3404 return;
sewardj2019a972011-03-07 16:04:07 +00003405 }
3406 break;
3407
3408 /* --------- EXIT --------- */
3409 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003410 s390_cc_t cond;
3411 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3412
3413 if (tag != Ico_U64)
3414 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3415
florian8844a632012-04-13 04:04:06 +00003416 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003417 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003418
3419 /* Case: boring transfer to known address */
3420 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3421 if (env->chaining_allowed) {
3422 /* .. almost always true .. */
3423 /* Skip the event check at the dst if this is a forwards
3424 edge. */
3425 Bool to_fast_entry
3426 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3427 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3428 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3429 guest_IA, to_fast_entry));
3430 } else {
3431 /* .. very occasionally .. */
3432 /* We can't use chaining, so ask for an assisted transfer,
3433 as that's the only alternative that is allowable. */
3434 HReg dst = s390_isel_int_expr(env,
3435 IRExpr_Const(stmt->Ist.Exit.dst));
3436 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3437 }
3438 return;
3439 }
3440
3441 /* Case: assisted transfer to arbitrary address */
3442 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003443 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003444 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003445 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003446 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003447 case Ijk_Sys_syscall:
3448 case Ijk_ClientReq:
3449 case Ijk_NoRedir:
3450 case Ijk_Yield:
3451 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003452 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3453 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3454 stmt->Ist.Exit.jk));
3455 return;
3456 }
3457 default:
3458 break;
3459 }
3460
3461 /* Do we ever expect to see any other kind? */
3462 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003463 }
3464
3465 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003466 case Ist_MBE:
3467 switch (stmt->Ist.MBE.event) {
3468 case Imbe_Fence:
3469 addInstr(env, s390_insn_mfence());
3470 return;
3471 default:
3472 break;
3473 }
sewardj2019a972011-03-07 16:04:07 +00003474 break;
3475
3476 /* --------- Miscellaneous --------- */
3477
3478 case Ist_PutI: /* Not needed */
3479 case Ist_IMark: /* Doesn't generate any executable code */
3480 case Ist_NoOp: /* Doesn't generate any executable code */
3481 case Ist_AbiHint: /* Meaningless in IR */
3482 return;
3483
3484 default:
3485 break;
3486 }
3487
3488 stmt_fail:
3489 ppIRStmt(stmt);
3490 vpanic("s390_isel_stmt");
3491}
3492
3493
3494/*---------------------------------------------------------*/
3495/*--- ISEL: Basic block terminators (Nexts) ---*/
3496/*---------------------------------------------------------*/
3497
3498static void
florianffbd84d2012-12-09 02:06:29 +00003499iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003500{
sewardj2019a972011-03-07 16:04:07 +00003501 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003502 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003503 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003504 vex_printf("; exit-");
3505 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003506 vex_printf("\n");
3507 }
3508
florian8844a632012-04-13 04:04:06 +00003509 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3510
3511 /* Case: boring transfer to known address */
3512 if (next->tag == Iex_Const) {
3513 IRConst *cdst = next->Iex.Const.con;
3514 vassert(cdst->tag == Ico_U64);
3515 if (jk == Ijk_Boring || jk == Ijk_Call) {
3516 /* Boring transfer to known address */
3517 if (env->chaining_allowed) {
3518 /* .. almost always true .. */
3519 /* Skip the event check at the dst if this is a forwards
3520 edge. */
3521 Bool to_fast_entry
3522 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3523 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3524 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3525 guest_IA, to_fast_entry));
3526 } else {
3527 /* .. very occasionally .. */
3528 /* We can't use chaining, so ask for an indirect transfer,
3529 as that's the cheapest alternative that is allowable. */
3530 HReg dst = s390_isel_int_expr(env, next);
3531 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3532 Ijk_Boring));
3533 }
3534 return;
3535 }
3536 }
3537
3538 /* Case: call/return (==boring) transfer to any address */
3539 switch (jk) {
3540 case Ijk_Boring:
3541 case Ijk_Ret:
3542 case Ijk_Call: {
3543 HReg dst = s390_isel_int_expr(env, next);
3544 if (env->chaining_allowed) {
3545 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3546 } else {
3547 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3548 Ijk_Boring));
3549 }
3550 return;
3551 }
3552 default:
3553 break;
3554 }
3555
3556 /* Case: some other kind of transfer to any address */
3557 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003558 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003559 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003560 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003561 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003562 case Ijk_Sys_syscall:
3563 case Ijk_ClientReq:
3564 case Ijk_NoRedir:
3565 case Ijk_Yield:
3566 case Ijk_SigTRAP: {
3567 HReg dst = s390_isel_int_expr(env, next);
3568 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3569 return;
3570 }
3571 default:
3572 break;
3573 }
3574
3575 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003576}
3577
3578
3579/*---------------------------------------------------------*/
3580/*--- Insn selector top-level ---*/
3581/*---------------------------------------------------------*/
3582
florianf26994a2012-04-21 03:34:54 +00003583/* Translate an entire SB to s390 code.
3584 Note: archinfo_host is a pointer to a stack-allocated variable.
3585 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003586
3587HInstrArray *
3588iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003589 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3590 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3591 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003592{
3593 UInt i, j;
3594 HReg hreg, hregHI;
3595 ISelEnv *env;
3596 UInt hwcaps_host = archinfo_host->hwcaps;
3597
florianf26994a2012-04-21 03:34:54 +00003598 /* KLUDGE: export hwcaps. */
3599 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003600
sewardj2019a972011-03-07 16:04:07 +00003601 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003602 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003603
3604 /* Make up an initial environment to use. */
3605 env = LibVEX_Alloc(sizeof(ISelEnv));
3606 env->vreg_ctr = 0;
3607
3608 /* Set up output code array. */
3609 env->code = newHInstrArray();
3610
3611 /* Copy BB's type env. */
3612 env->type_env = bb->tyenv;
3613
florianad43b3a2012-02-20 15:01:14 +00003614 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00003615 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3616 env->old_value[i] = 0; /* just something to have a defined value */
3617 env->old_value_valid[i] = False;
3618 }
3619
sewardj2019a972011-03-07 16:04:07 +00003620 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3621 change as we go along. For some reason types_used has Int type -- but
3622 it should be unsigned. Internally we use an unsigned type; so we
3623 assert it here. */
3624 vassert(bb->tyenv->types_used >= 0);
3625
3626 env->n_vregmap = bb->tyenv->types_used;
3627 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3628 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3629
florian2c74d242012-09-12 19:38:42 +00003630 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003631 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003632
sewardj2019a972011-03-07 16:04:07 +00003633 /* and finally ... */
3634 env->hwcaps = hwcaps_host;
3635
florian8844a632012-04-13 04:04:06 +00003636 env->max_ga = max_ga;
3637 env->chaining_allowed = chaining_allowed;
3638
sewardj2019a972011-03-07 16:04:07 +00003639 /* For each IR temporary, allocate a suitably-kinded virtual
3640 register. */
3641 j = 0;
3642 for (i = 0; i < env->n_vregmap; i++) {
3643 hregHI = hreg = INVALID_HREG;
3644 switch (bb->tyenv->types[i]) {
3645 case Ity_I1:
3646 case Ity_I8:
3647 case Ity_I16:
3648 case Ity_I32:
3649 hreg = mkHReg(j++, HRcInt64, True);
3650 break;
3651
3652 case Ity_I64:
3653 hreg = mkHReg(j++, HRcInt64, True);
3654 break;
3655
3656 case Ity_I128:
3657 hreg = mkHReg(j++, HRcInt64, True);
3658 hregHI = mkHReg(j++, HRcInt64, True);
3659 break;
3660
3661 case Ity_F32:
3662 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003663 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003664 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003665 hreg = mkHReg(j++, HRcFlt64, True);
3666 break;
3667
3668 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003669 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003670 hreg = mkHReg(j++, HRcFlt64, True);
3671 hregHI = mkHReg(j++, HRcFlt64, True);
3672 break;
3673
3674 case Ity_V128: /* fall through */
3675 default:
3676 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003677 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003678 }
3679
3680 env->vregmap[i] = hreg;
3681 env->vregmapHI[i] = hregHI;
3682 }
3683 env->vreg_ctr = j;
3684
florian8844a632012-04-13 04:04:06 +00003685 /* The very first instruction must be an event check. */
3686 s390_amode *counter, *fail_addr;
3687 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3688 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3689 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3690
3691 /* Possibly a block counter increment (for profiling). At this
3692 point we don't know the address of the counter, so just pretend
3693 it is zero. It will have to be patched later, but before this
3694 translation is used, by a call to LibVEX_patchProfInc. */
3695 if (add_profinc) {
3696 addInstr(env, s390_insn_profinc());
3697 }
3698
sewardj2019a972011-03-07 16:04:07 +00003699 /* Ok, finally we can iterate over the statements. */
3700 for (i = 0; i < bb->stmts_used; i++)
3701 if (bb->stmts[i])
3702 s390_isel_stmt(env, bb->stmts[i]);
3703
florian8844a632012-04-13 04:04:06 +00003704 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003705
3706 /* Record the number of vregs we used. */
3707 env->code->n_vregs = env->vreg_ctr;
3708
3709 return env->code;
3710}
3711
3712/*---------------------------------------------------------------*/
3713/*--- end host_s390_isel.c ---*/
3714/*---------------------------------------------------------------*/