blob: e5851195b62201c8f8a78dd9bfe25d2d83655693 [file] [log] [blame]
sewardj2019a972011-03-07 16:04:07 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
2
3/*---------------------------------------------------------------*/
4/*--- begin host_s390_isel.c ---*/
5/*---------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
florian61f23c12012-08-06 18:33:21 +000011 Copyright IBM Corp. 2010-2012
florian2c74d242012-09-12 19:38:42 +000012 Copyright (C) 2012-2012 Florian Krohm (britzel@acm.org)
sewardj2019a972011-03-07 16:04:07 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
32/* Contributed by Florian Krohm */
33
34#include "libvex_basictypes.h"
35#include "libvex_ir.h"
36#include "libvex.h"
37#include "libvex_s390x_common.h"
38
sewardj2019a972011-03-07 16:04:07 +000039#include "main_util.h"
40#include "main_globals.h"
florian9f42ab42012-12-23 01:09:16 +000041#include "guest_s390_defs.h" /* S390X_GUEST_OFFSET */
sewardj2019a972011-03-07 16:04:07 +000042#include "host_generic_regs.h"
43#include "host_s390_defs.h"
44
45/*---------------------------------------------------------*/
46/*--- ISelEnv ---*/
47/*---------------------------------------------------------*/
48
49/* This carries around:
50
51 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
52 might encounter. This is computed before insn selection starts,
53 and does not change.
54
55 - A mapping from IRTemp to HReg. This tells the insn selector
56 which virtual register(s) are associated with each IRTemp
57 temporary. This is computed before insn selection starts, and
58 does not change. We expect this mapping to map precisely the
59 same set of IRTemps as the type mapping does.
60
61 - vregmap holds the primary register for the IRTemp.
62 - vregmapHI holds the secondary register for the IRTemp,
63 if any is needed. That's only for Ity_I64 temps
64 in 32 bit mode or Ity_I128 temps in 64-bit mode.
65
66 - The code array, that is, the insns selected so far.
67
68 - A counter, for generating new virtual registers.
69
70 - The host subarchitecture we are selecting insns for.
71 This is set at the start and does not change.
florianad43b3a2012-02-20 15:01:14 +000072
florian8844a632012-04-13 04:04:06 +000073 - A Bool for indicating whether we may generate chain-me
74 instructions for control flow transfers, or whether we must use
75 XAssisted.
76
77 - The maximum guest address of any guest insn in this block.
78 Actually, the address of the highest-addressed byte from any insn
79 in this block. Is set at the start and does not change. This is
80 used for detecting jumps which are definitely forward-edges from
81 this block, and therefore can be made (chained) to the fast entry
82 point of the destination, thereby avoiding the destination's
83 event check.
84
florianad43b3a2012-02-20 15:01:14 +000085 - Values of certain guest registers which are often assigned constants.
sewardj2019a972011-03-07 16:04:07 +000086*/
87
florianad43b3a2012-02-20 15:01:14 +000088/* Symbolic names for guest registers whose value we're tracking */
89enum {
90 GUEST_IA,
91 GUEST_CC_OP,
92 GUEST_CC_DEP1,
93 GUEST_CC_DEP2,
94 GUEST_CC_NDEP,
95 GUEST_SYSNO,
florian7d117ba2012-05-06 03:34:55 +000096 GUEST_COUNTER,
florianad43b3a2012-02-20 15:01:14 +000097 GUEST_UNKNOWN /* must be the last entry */
98};
99
100/* Number of registers we're tracking. */
101#define NUM_TRACKED_REGS GUEST_UNKNOWN
102
103
sewardj2019a972011-03-07 16:04:07 +0000104typedef struct {
105 IRTypeEnv *type_env;
106
florian8844a632012-04-13 04:04:06 +0000107 HInstrArray *code;
sewardj2019a972011-03-07 16:04:07 +0000108 HReg *vregmap;
109 HReg *vregmapHI;
110 UInt n_vregmap;
florian8844a632012-04-13 04:04:06 +0000111 UInt vreg_ctr;
112 UInt hwcaps;
sewardj2019a972011-03-07 16:04:07 +0000113
florian2c74d242012-09-12 19:38:42 +0000114 IRExpr *previous_bfp_rounding_mode;
florianc8e4f562012-10-27 16:19:31 +0000115 IRExpr *previous_dfp_rounding_mode;
florian2c74d242012-09-12 19:38:42 +0000116
florianad43b3a2012-02-20 15:01:14 +0000117 ULong old_value[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000118
florian8844a632012-04-13 04:04:06 +0000119 /* The next two are for translation chaining */
120 Addr64 max_ga;
121 Bool chaining_allowed;
122
florianad43b3a2012-02-20 15:01:14 +0000123 Bool old_value_valid[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000124} ISelEnv;
125
126
127/* Forward declarations */
128static HReg s390_isel_int_expr(ISelEnv *, IRExpr *);
129static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *);
130static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
131static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
132static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
133static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
134static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
florian12390202012-11-10 22:34:14 +0000135static HReg s390_isel_dfp_expr(ISelEnv *, IRExpr *);
floriane38f6412012-12-21 17:32:12 +0000136static void s390_isel_dfp128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
sewardj2019a972011-03-07 16:04:07 +0000137
138
florianad43b3a2012-02-20 15:01:14 +0000139static Int
140get_guest_reg(Int offset)
141{
142 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000143 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
144 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
145 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
146 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
147 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
148 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000149 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000150
151 /* Also make sure there is never a partial write to one of
152 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000153 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
154 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
155 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
156 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
157 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000158 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
159 /* counter is used both as 4-byte and as 8-byte entity */
160 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
161 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianaf50a192012-07-13 14:13:06 +0000162 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000163 break;
164
165 default: break;
166 }
167
168 return GUEST_UNKNOWN;
169}
170
sewardj2019a972011-03-07 16:04:07 +0000171/* Add an instruction */
172static void
173addInstr(ISelEnv *env, s390_insn *insn)
174{
175 addHInstr(env->code, insn);
176
177 if (vex_traceflags & VEX_TRACE_VCODE) {
178 vex_printf("%s\n", s390_insn_as_string(insn));
179 }
180}
181
182
183static __inline__ IRExpr *
184mkU64(ULong value)
185{
186 return IRExpr_Const(IRConst_U64(value));
187}
188
189
190/*---------------------------------------------------------*/
191/*--- Registers ---*/
192/*---------------------------------------------------------*/
193
194/* Return the virtual register to which a given IRTemp is mapped. */
195static HReg
196lookupIRTemp(ISelEnv *env, IRTemp tmp)
197{
198 vassert(tmp < env->n_vregmap);
199 vassert(env->vregmap[tmp] != INVALID_HREG);
200
201 return env->vregmap[tmp];
202}
203
204
205/* Return the two virtual registers to which the IRTemp is mapped. */
206static void
207lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
208{
209 vassert(tmp < env->n_vregmap);
210 vassert(env->vregmapHI[tmp] != INVALID_HREG);
211
212 *lo = env->vregmap[tmp];
213 *hi = env->vregmapHI[tmp];
214}
215
216
217/* Allocate a new integer register */
218static HReg
219newVRegI(ISelEnv *env)
220{
221 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
222 env->vreg_ctr++;
223
224 return reg;
225}
226
227
228/* Allocate a new floating point register */
229static HReg
230newVRegF(ISelEnv *env)
231{
232 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
233
234 env->vreg_ctr++;
235
236 return reg;
237}
238
239
240/* Construct a non-virtual general purpose register */
241static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000242make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000243{
244 return mkHReg(regno, HRcInt64, False /* virtual */ );
245}
246
247
248/* Construct a non-virtual floating point register */
249static __inline__ HReg
250make_fpr(UInt regno)
251{
252 return mkHReg(regno, HRcFlt64, False /* virtual */ );
253}
254
255
256/*---------------------------------------------------------*/
257/*--- Amode ---*/
258/*---------------------------------------------------------*/
259
260static __inline__ Bool
261ulong_fits_unsigned_12bit(ULong val)
262{
263 return (val & 0xFFFu) == val;
264}
265
266
267static __inline__ Bool
268ulong_fits_signed_20bit(ULong val)
269{
270 Long v = val & 0xFFFFFu;
271
272 v = (v << 44) >> 44; /* sign extend */
273
274 return val == (ULong)v;
275}
276
277
florianad43b3a2012-02-20 15:01:14 +0000278static __inline__ Bool
279ulong_fits_signed_8bit(ULong val)
280{
281 Long v = val & 0xFFu;
282
283 v = (v << 56) >> 56; /* sign extend */
284
285 return val == (ULong)v;
286}
287
sewardj2019a972011-03-07 16:04:07 +0000288/* EXPR is an expression that is used as an address. Return an s390_amode
289 for it. */
290static s390_amode *
291s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
292{
293 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
294 IRExpr *arg1 = expr->Iex.Binop.arg1;
295 IRExpr *arg2 = expr->Iex.Binop.arg2;
296
297 /* Move constant into right subtree */
298 if (arg1->tag == Iex_Const) {
299 IRExpr *tmp;
300 tmp = arg1;
301 arg1 = arg2;
302 arg2 = tmp;
303 }
304
305 /* r + constant: Check for b12 first, then b20 */
306 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
307 ULong value = arg2->Iex.Const.con->Ico.U64;
308
309 if (ulong_fits_unsigned_12bit(value)) {
310 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
311 }
sewardj652b56a2011-04-13 15:38:17 +0000312 /* If long-displacement is not available, do not construct B20 or
313 BX20 amodes because code generation cannot handle them. */
314 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000315 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
316 }
317 }
318 }
319
320 /* Doesn't match anything in particular. Generate it into
321 a register and use that. */
322 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
323}
324
325
326static s390_amode *
327s390_isel_amode(ISelEnv *env, IRExpr *expr)
328{
florian35da8612011-06-25 02:25:41 +0000329 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000330
331 /* Address computation should yield a 64-bit value */
332 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
333
334 am = s390_isel_amode_wrk(env, expr);
335
336 /* Check post-condition */
337 vassert(s390_amode_is_sane(am));
338
339 return am;
340}
341
342
343/*---------------------------------------------------------*/
344/*--- Helper functions ---*/
345/*---------------------------------------------------------*/
346
347/* Constants and memory accesses should be right operands */
348#define order_commutative_operands(left, right) \
349 do { \
350 if (left->tag == Iex_Const || left->tag == Iex_Load || \
351 left->tag == Iex_Get) { \
352 IRExpr *tmp; \
353 tmp = left; \
354 left = right; \
355 right = tmp; \
356 } \
357 } while (0)
358
359
360/* Copy an RMI operand to the DST register */
361static s390_insn *
362s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
363{
364 switch (opnd.tag) {
365 case S390_OPND_AMODE:
366 return s390_insn_load(size, dst, opnd.variant.am);
367
368 case S390_OPND_REG:
369 return s390_insn_move(size, dst, opnd.variant.reg);
370
371 case S390_OPND_IMMEDIATE:
372 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
373
374 default:
375 vpanic("s390_opnd_copy");
376 }
377}
378
379
380/* Construct a RMI operand for a register */
381static __inline__ s390_opnd_RMI
382s390_opnd_reg(HReg reg)
383{
384 s390_opnd_RMI opnd;
385
386 opnd.tag = S390_OPND_REG;
387 opnd.variant.reg = reg;
388
389 return opnd;
390}
391
392
393/* Construct a RMI operand for an immediate constant */
394static __inline__ s390_opnd_RMI
395s390_opnd_imm(ULong value)
396{
397 s390_opnd_RMI opnd;
398
399 opnd.tag = S390_OPND_IMMEDIATE;
400 opnd.variant.imm = value;
401
402 return opnd;
403}
404
405
florianffbd84d2012-12-09 02:06:29 +0000406/* Return 1, if EXPR represents the constant 0 */
407static Bool
sewardj2019a972011-03-07 16:04:07 +0000408s390_expr_is_const_zero(IRExpr *expr)
409{
410 ULong value;
411
412 if (expr->tag == Iex_Const) {
413 switch (expr->Iex.Const.con->tag) {
414 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
415 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
416 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
417 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
418 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
419 default:
420 vpanic("s390_expr_is_const_zero");
421 }
422 return value == 0;
423 }
424
425 return 0;
426}
427
428
florianb93348d2012-12-27 00:59:43 +0000429/* Return the value of CON as a sign-exteded ULong value */
430static ULong
431get_const_value_as_ulong(const IRConst *con)
432{
433 Long value;
434
435 switch (con->tag) {
436 case Ico_U1: value = con->Ico.U1; return (ULong) ((value << 63) >> 63);
437 case Ico_U8: value = con->Ico.U8; return (ULong) ((value << 56) >> 56);
438 case Ico_U16: value = con->Ico.U16; return (ULong) ((value << 48) >> 48);
439 case Ico_U32: value = con->Ico.U32; return (ULong) ((value << 32) >> 32);
440 case Ico_U64: return con->Ico.U64;
441 default:
442 vpanic("get_const_value_as_ulong");
443 }
444}
445
446
sewardj2019a972011-03-07 16:04:07 +0000447/* Call a helper (clean or dirty)
448 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000449
sewardj2019a972011-03-07 16:04:07 +0000450 (a) they are expressions yielding an integer result
451 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000452
453 guard is a Ity_Bit expression indicating whether or not the
454 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000455
456 Calling the helper function proceeds as follows:
457
458 (1) The helper arguments are evaluated and their value stored in
459 virtual registers.
460 (2) The condition code is evaluated
461 (3) The argument values are copied from the virtual registers to the
462 registers mandated by the ABI.
463 (4) Call the helper function.
464
465 This is not the most efficient way as step 3 generates register-to-register
466 moves. But it is the least fragile way as the only hidden dependency here
467 is that register-to-register moves (step 3) must not clobber the condition
468 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
469 to-register add more such dependencies. Not good. Besides, it's the job
470 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000471*/
472static void
473doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000474 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000475{
florian52af7bc2012-05-12 03:44:49 +0000476 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000477 ULong target;
478 HReg tmpregs[S390_NUM_GPRPARMS];
479 s390_cc_t cc;
480
481 n_args = 0;
482 for (i = 0; args[i]; i++)
483 ++n_args;
484
485 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
486 vpanic("doHelperCall: too many arguments");
487 }
488
florian11b8ee82012-08-06 13:35:33 +0000489 /* All arguments must have Ity_I64. For two reasons:
490 (1) We do not handle floating point arguments.
491 (2) The ABI requires that integer values are sign- or zero-extended
492 to 64 bit.
493 */
494 Int arg_errors = 0;
495 for (i = 0; i < n_args; ++i) {
496 IRType type = typeOfIRExpr(env->type_env, args[i]);
497 if (type != Ity_I64) {
498 ++arg_errors;
499 vex_printf("calling %s: argument #%d has type ", callee->name, i);
500 ppIRType(type);
501 vex_printf("; Ity_I64 is required\n");
502 }
503 }
504
505 if (arg_errors)
506 vpanic("cannot continue due to errors in argument passing");
507
florian52af7bc2012-05-12 03:44:49 +0000508 argreg = 0;
509
510 /* If we need the guest state pointer put it in a temporary arg reg */
511 if (passBBP) {
512 tmpregs[argreg] = newVRegI(env);
513 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
514 s390_hreg_guest_state_pointer()));
515 argreg++;
516 }
517
518 /* Compute the function arguments into a temporary register each */
519 for (i = 0; i < n_args; i++) {
520 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
521 argreg++;
522 }
523
sewardj2019a972011-03-07 16:04:07 +0000524 /* Compute the condition */
525 cc = S390_CC_ALWAYS;
526 if (guard) {
527 if (guard->tag == Iex_Const
528 && guard->Iex.Const.con->tag == Ico_U1
529 && guard->Iex.Const.con->Ico.U1 == True) {
530 /* unconditional -- do nothing */
531 } else {
532 cc = s390_isel_cc(env, guard);
533 }
534 }
535
florian52af7bc2012-05-12 03:44:49 +0000536 /* Move the args to the final register. It is paramount, that the
537 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000538 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000539 HReg finalreg;
540
541 finalreg = make_gpr(s390_gprno_from_arg_index(i));
542 size = sizeofIRType(Ity_I64);
543 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000544 }
545
546 target = Ptr_to_ULong(callee->addr);
547
548 /* Finally, the call itself. */
549 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000550 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000551}
552
553
florian2c74d242012-09-12 19:38:42 +0000554/*---------------------------------------------------------*/
555/*--- BFP helper functions ---*/
556/*---------------------------------------------------------*/
557
558/* Set the BFP rounding mode in the FPC. This function is called for
559 all non-conversion BFP instructions as those will always get the
560 rounding mode from the FPC. */
561static void
562set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000563{
florian2c74d242012-09-12 19:38:42 +0000564 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
565
566 /* Do we need to do anything? */
567 if (env->previous_bfp_rounding_mode &&
568 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
569 irrm->tag == Iex_RdTmp &&
570 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
571 /* No - new mode is identical to previous mode. */
572 return;
573 }
574
575 /* No luck - we better set it, and remember what we set it to. */
576 env->previous_bfp_rounding_mode = irrm;
577
578 /* The incoming rounding mode is in VEX IR encoding. Need to change
579 to s390.
580
581 rounding mode | s390 | IR
582 -------------------------
583 to nearest | 00 | 00
584 to zero | 01 | 11
585 to +infinity | 10 | 10
586 to -infinity | 11 | 01
587
588 So: s390 = (4 - IR) & 3
589 */
590 HReg ir = s390_isel_int_expr(env, irrm);
591
592 HReg mode = newVRegI(env);
593
594 addInstr(env, s390_insn_load_immediate(4, mode, 4));
595 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
596 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
597
florian125e20d2012-10-07 15:42:37 +0000598 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000599}
600
601
602/* This function is invoked for insns that support a specification of
603 a rounding mode in the insn itself. In that case there is no need to
604 stick the rounding mode into the FPC -- a good thing. However, the
605 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000606static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000607get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
608{
609 if (irrm->tag == Iex_Const) { /* rounding mode is known */
610 vassert(irrm->Iex.Const.con->tag == Ico_U32);
611 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000612
613 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000614 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
615 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
616 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
617 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000618 default:
619 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000620 }
621 }
622
florian2c74d242012-09-12 19:38:42 +0000623 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000624 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000625}
626
627
florianc8e4f562012-10-27 16:19:31 +0000628/*---------------------------------------------------------*/
629/*--- DFP helper functions ---*/
630/*---------------------------------------------------------*/
631
632/* Set the DFP rounding mode in the FPC. This function is called for
633 all non-conversion DFP instructions as those will always get the
634 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000635static void
636set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
637{
638 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
639
640 /* Do we need to do anything? */
641 if (env->previous_dfp_rounding_mode &&
642 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
643 irrm->tag == Iex_RdTmp &&
644 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
645 /* No - new mode is identical to previous mode. */
646 return;
647 }
648
649 /* No luck - we better set it, and remember what we set it to. */
650 env->previous_dfp_rounding_mode = irrm;
651
652 /* The incoming rounding mode is in VEX IR encoding. Need to change
653 to s390.
654
655 rounding mode | S390 | IR
656 -----------------------------------------------
657 to nearest, ties to even | 000 | 000
658 to zero | 001 | 011
659 to +infinity | 010 | 010
660 to -infinity | 011 | 001
661 to nearest, ties away from 0 | 100 | 100
662 to nearest, ties toward 0 | 101 | 111
663 to away from 0 | 110 | 110
664 to prepare for shorter precision | 111 | 101
665
666 So: s390 = (IR ^ ((IR << 1) & 2))
667 */
668 HReg ir = s390_isel_int_expr(env, irrm);
669
670 HReg mode = newVRegI(env);
671
672 addInstr(env, s390_insn_move(4, mode, ir));
673 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
674 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
675 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
676
677 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
678}
679
680
681/* This function is invoked for insns that support a specification of
682 a rounding mode in the insn itself. In that case there is no need to
683 stick the rounding mode into the FPC -- a good thing. However, the
684 rounding mode must be known.
685 The IR to s390 encoding is chosen in the range 0:7 except
686 S390_DFP_ROUND_NEAREST_TIE_TOWARD_0 and
687 S390_DFP_ROUND_AWAY_0 which have no choice within the range.
688 Since the s390 dfp rounding mode encoding in 8:15 is not used, the
689 quantum excpetion is not suppressed and this is fine as valgrind does
690 not model this exception.
691
692 Translation table of
693 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
694
695 s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
696 --------------------------------------------------------------------
697 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_1
698 NEAREST_TIE_AWAY_0_12 | " | "
699 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_3
700 PREPARE_SHORT_15 | " | "
701 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_4
702 NEAREST_EVEN_8 | " | "
703 ZERO_5 | ZERO | ZERO_5
704 ZERO_9 | " | "
705 POSINF_6 | PosINF | POSINF_6
706 POSINF_10 | " | "
707 NEGINF_7 | NegINF | NEGINF_7
708 NEGINF_11 | " | "
709 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
710 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
711*/
712static s390_dfp_round_t
713get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
714{
715 if (irrm->tag == Iex_Const) { /* rounding mode is known */
716 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian3d6a4222012-11-19 16:29:31 +0000717 IRRoundingModeDFP mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000718
719 switch (mode) {
720 case Irrm_DFP_NEAREST:
721 return S390_DFP_ROUND_NEAREST_EVEN_4;
722 case Irrm_DFP_NegINF:
723 return S390_DFP_ROUND_NEGINF_7;
724 case Irrm_DFP_PosINF:
725 return S390_DFP_ROUND_POSINF_6;
726 case Irrm_DFP_ZERO:
727 return S390_DFP_ROUND_ZERO_5;
728 case Irrm_DFP_NEAREST_TIE_AWAY_0:
729 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1;
730 case Irrm_DFP_PREPARE_SHORTER:
731 return S390_DFP_ROUND_PREPARE_SHORT_3;
732 case Irrm_DFP_AWAY_FROM_ZERO:
733 return S390_DFP_ROUND_AWAY_0;
734 case Irrm_DFP_NEAREST_TIE_TOWARD_0:
735 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
736 default:
737 vpanic("get_dfp_rounding_mode");
738 }
739 }
740
741 set_dfp_rounding_mode_in_fpc(env, irrm);
742 return S390_DFP_ROUND_PER_FPC_0;
743}
florianc8e4f562012-10-27 16:19:31 +0000744
florian2d3d87f2012-12-21 21:05:17 +0000745
746/*---------------------------------------------------------*/
747/*--- Condition code helper functions ---*/
748/*---------------------------------------------------------*/
749
sewardj2019a972011-03-07 16:04:07 +0000750/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000751 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000752
753 s390 VEX b6 b2 b0 cc.1 cc.0
754 0 0x40 EQ 1 0 0 0 0
755 1 0x01 LT 0 0 1 0 1
756 2 0x00 GT 0 0 0 1 0
757 3 0x45 Unordered 1 1 1 1 1
758
759 b0 = cc.0
760 b2 = cc.0 & cc.1
761 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
762
763 VEX = b0 | (b2 << 2) | (b6 << 6);
764*/
765static HReg
florian2d3d87f2012-12-21 21:05:17 +0000766convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000767{
768 HReg cc0, cc1, b2, b6, cc_vex;
769
770 cc0 = newVRegI(env);
771 addInstr(env, s390_insn_move(4, cc0, cc_s390));
772 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
773
774 cc1 = newVRegI(env);
775 addInstr(env, s390_insn_move(4, cc1, cc_s390));
776 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
777
778 b2 = newVRegI(env);
779 addInstr(env, s390_insn_move(4, b2, cc0));
780 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
781 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
782
783 b6 = newVRegI(env);
784 addInstr(env, s390_insn_move(4, b6, cc0));
785 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
786 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
787 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
788 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
789
790 cc_vex = newVRegI(env);
791 addInstr(env, s390_insn_move(4, cc_vex, cc0));
792 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
793 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
794
795 return cc_vex;
796}
797
florian2d3d87f2012-12-21 21:05:17 +0000798/* CC_S390 holds the condition code in s390 encoding. Convert it to
799 VEX encoding (IRCmpDResult) */
800static HReg
801convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
802{
803 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
804 return convert_s390_to_vex_bfpcc(env, cc_s390);
805}
806
sewardj2019a972011-03-07 16:04:07 +0000807
808/*---------------------------------------------------------*/
809/*--- ISEL: Integer expressions (128 bit) ---*/
810/*---------------------------------------------------------*/
811static void
812s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
813 IRExpr *expr)
814{
815 IRType ty = typeOfIRExpr(env->type_env, expr);
816
817 vassert(ty == Ity_I128);
818
819 /* No need to consider the following
820 - 128-bit constants (they do not exist in VEX)
821 - 128-bit loads from memory (will not be generated)
822 */
823
824 /* Read 128-bit IRTemp */
825 if (expr->tag == Iex_RdTmp) {
826 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
827 return;
828 }
829
830 if (expr->tag == Iex_Binop) {
831 IRExpr *arg1 = expr->Iex.Binop.arg1;
832 IRExpr *arg2 = expr->Iex.Binop.arg2;
833 Bool is_signed_multiply, is_signed_divide;
834
835 switch (expr->Iex.Binop.op) {
836 case Iop_MullU64:
837 is_signed_multiply = False;
838 goto do_multiply64;
839
840 case Iop_MullS64:
841 is_signed_multiply = True;
842 goto do_multiply64;
843
844 case Iop_DivModU128to64:
845 is_signed_divide = False;
846 goto do_divide64;
847
848 case Iop_DivModS128to64:
849 is_signed_divide = True;
850 goto do_divide64;
851
852 case Iop_64HLto128:
853 *dst_hi = s390_isel_int_expr(env, arg1);
854 *dst_lo = s390_isel_int_expr(env, arg2);
855 return;
856
857 case Iop_DivModS64to64: {
858 HReg r10, r11, h1;
859 s390_opnd_RMI op2;
860
861 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
862 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
863
864 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000865 r10 = make_gpr(10);
866 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000867
868 /* Move 1st operand into r11 and */
869 addInstr(env, s390_insn_move(8, r11, h1));
870
871 /* Divide */
872 addInstr(env, s390_insn_divs(8, r10, r11, op2));
873
874 /* The result is in registers r10 (remainder) and r11 (quotient).
875 Move the result into the reg pair that is being returned such
876 such that the low 64 bits are the quotient and the upper 64 bits
877 are the remainder. (see libvex_ir.h). */
878 *dst_hi = newVRegI(env);
879 *dst_lo = newVRegI(env);
880 addInstr(env, s390_insn_move(8, *dst_hi, r10));
881 addInstr(env, s390_insn_move(8, *dst_lo, r11));
882 return;
883 }
884
885 default:
886 break;
887
888 do_multiply64: {
889 HReg r10, r11, h1;
890 s390_opnd_RMI op2;
891
892 order_commutative_operands(arg1, arg2);
893
894 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
895 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
896
897 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000898 r10 = make_gpr(10);
899 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000900
901 /* Move the first operand to r11 */
902 addInstr(env, s390_insn_move(8, r11, h1));
903
904 /* Multiply */
905 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
906
907 /* The result is in registers r10 and r11. Assign to two virtual regs
908 and return. */
909 *dst_hi = newVRegI(env);
910 *dst_lo = newVRegI(env);
911 addInstr(env, s390_insn_move(8, *dst_hi, r10));
912 addInstr(env, s390_insn_move(8, *dst_lo, r11));
913 return;
914 }
915
916 do_divide64: {
917 HReg r10, r11, hi, lo;
918 s390_opnd_RMI op2;
919
920 s390_isel_int128_expr(&hi, &lo, env, arg1);
921 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
922
923 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000924 r10 = make_gpr(10);
925 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000926
927 /* Move high 64 bits of the 1st operand into r10 and
928 the low 64 bits into r11. */
929 addInstr(env, s390_insn_move(8, r10, hi));
930 addInstr(env, s390_insn_move(8, r11, lo));
931
932 /* Divide */
933 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
934
935 /* The result is in registers r10 (remainder) and r11 (quotient).
936 Move the result into the reg pair that is being returned such
937 such that the low 64 bits are the quotient and the upper 64 bits
938 are the remainder. (see libvex_ir.h). */
939 *dst_hi = newVRegI(env);
940 *dst_lo = newVRegI(env);
941 addInstr(env, s390_insn_move(8, *dst_hi, r10));
942 addInstr(env, s390_insn_move(8, *dst_lo, r11));
943 return;
944 }
945 }
946 }
947
948 vpanic("s390_isel_int128_expr");
949}
950
951
952/* Compute a 128-bit value into two 64-bit registers. These may be either
953 real or virtual regs; in any case they must not be changed by subsequent
954 code emitted by the caller. */
955static void
956s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
957{
958 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
959
960 /* Sanity checks ... */
961 vassert(hregIsVirtual(*dst_hi));
962 vassert(hregIsVirtual(*dst_lo));
963 vassert(hregClass(*dst_hi) == HRcInt64);
964 vassert(hregClass(*dst_lo) == HRcInt64);
965}
966
967
968/*---------------------------------------------------------*/
969/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
970/*---------------------------------------------------------*/
971
972/* Select insns for an integer-typed expression, and add them to the
973 code list. Return a reg holding the result. This reg will be a
974 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
975 want to modify it, ask for a new vreg, copy it in there, and modify
976 the copy. The register allocator will do its best to map both
977 vregs to the same real register, so the copies will often disappear
978 later in the game.
979
980 This should handle expressions of 64, 32, 16 and 8-bit type.
981 All results are returned in a 64bit register.
982 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
983 are arbitrary, so you should mask or sign extend partial values
984 if necessary.
985*/
986
987/* DO NOT CALL THIS DIRECTLY ! */
988static HReg
989s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
990{
991 IRType ty = typeOfIRExpr(env->type_env, expr);
992 UChar size;
florian6dc90242012-12-21 21:43:00 +0000993 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +0000994
995 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
996
997 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
998
999 switch (expr->tag) {
1000
1001 /* --------- TEMP --------- */
1002 case Iex_RdTmp:
1003 /* Return the virtual register that holds the temporary. */
1004 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1005
1006 /* --------- LOAD --------- */
1007 case Iex_Load: {
1008 HReg dst = newVRegI(env);
1009 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1010
1011 if (expr->Iex.Load.end != Iend_BE)
1012 goto irreducible;
1013
1014 addInstr(env, s390_insn_load(size, dst, am));
1015
1016 return dst;
1017 }
1018
1019 /* --------- BINARY OP --------- */
1020 case Iex_Binop: {
1021 IRExpr *arg1 = expr->Iex.Binop.arg1;
1022 IRExpr *arg2 = expr->Iex.Binop.arg2;
1023 HReg h1, res;
1024 s390_alu_t opkind;
1025 s390_opnd_RMI op2, value, opnd;
1026 s390_insn *insn;
1027 Bool is_commutative, is_signed_multiply, is_signed_divide;
1028
1029 is_commutative = True;
1030
1031 switch (expr->Iex.Binop.op) {
1032 case Iop_MullU8:
1033 case Iop_MullU16:
1034 case Iop_MullU32:
1035 is_signed_multiply = False;
1036 goto do_multiply;
1037
1038 case Iop_MullS8:
1039 case Iop_MullS16:
1040 case Iop_MullS32:
1041 is_signed_multiply = True;
1042 goto do_multiply;
1043
1044 do_multiply: {
1045 HReg r10, r11;
1046 UInt arg_size = size / 2;
1047
1048 order_commutative_operands(arg1, arg2);
1049
1050 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1051 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1052
1053 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001054 r10 = make_gpr(10);
1055 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001056
1057 /* Move the first operand to r11 */
1058 addInstr(env, s390_insn_move(arg_size, r11, h1));
1059
1060 /* Multiply */
1061 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1062
1063 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1064 value into the destination register. */
1065 res = newVRegI(env);
1066 addInstr(env, s390_insn_move(arg_size, res, r10));
1067 value = s390_opnd_imm(arg_size * 8);
1068 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1069 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1070 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1071 opnd = s390_opnd_reg(r11);
1072 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1073 return res;
1074 }
1075
1076 case Iop_DivModS64to32:
1077 is_signed_divide = True;
1078 goto do_divide;
1079
1080 case Iop_DivModU64to32:
1081 is_signed_divide = False;
1082 goto do_divide;
1083
1084 do_divide: {
1085 HReg r10, r11;
1086
1087 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1088 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1089
1090 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001091 r10 = make_gpr(10);
1092 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001093
1094 /* Split the first operand and put the high 32 bits into r10 and
1095 the low 32 bits into r11. */
1096 addInstr(env, s390_insn_move(8, r10, h1));
1097 addInstr(env, s390_insn_move(8, r11, h1));
1098 value = s390_opnd_imm(32);
1099 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1100
1101 /* Divide */
1102 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1103
1104 /* The result is in registers r10 (remainder) and r11 (quotient).
1105 Combine them into a 64-bit value such that the low 32 bits are
1106 the quotient and the upper 32 bits are the remainder. (see
1107 libvex_ir.h). */
1108 res = newVRegI(env);
1109 addInstr(env, s390_insn_move(8, res, r10));
1110 value = s390_opnd_imm(32);
1111 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1112 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1113 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1114 opnd = s390_opnd_reg(r11);
1115 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1116 return res;
1117 }
1118
florian9fcff4c2012-09-10 03:09:04 +00001119 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1120 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1121 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1122 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1123 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1124 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1125 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1126 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1127 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1128 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1129 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1130 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
sewardj2019a972011-03-07 16:04:07 +00001131
1132 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001133 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001134
1135 res = newVRegI(env);
1136 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1137
florian2c74d242012-09-12 19:38:42 +00001138 rounding_mode = get_bfp_rounding_mode(env, arg1);
1139 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1140 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001141 return res;
1142 }
1143
1144 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001145 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001146 HReg op_hi, op_lo, f13, f15;
1147
1148 res = newVRegI(env);
1149 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1150
1151 /* We use non-virtual registers r13 and r15 as pair */
1152 f13 = make_fpr(13);
1153 f15 = make_fpr(15);
1154
1155 /* operand --> (f13, f15) */
1156 addInstr(env, s390_insn_move(8, f13, op_hi));
1157 addInstr(env, s390_insn_move(8, f15, op_lo));
1158
florian2c74d242012-09-12 19:38:42 +00001159 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001160 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001161 rounding_mode));
1162 return res;
1163 }
1164
1165 case Iop_8HLto16:
1166 case Iop_16HLto32:
1167 case Iop_32HLto64: {
1168 HReg h2;
1169 UInt arg_size = size / 2;
1170
1171 res = newVRegI(env);
1172 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1173 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1174
1175 addInstr(env, s390_insn_move(arg_size, res, h1));
1176 value = s390_opnd_imm(arg_size * 8);
1177 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1178 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1179 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1180 opnd = s390_opnd_reg(h2);
1181 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1182 return res;
1183 }
1184
1185 case Iop_Max32U: {
1186 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1187 res = newVRegI(env);
1188 h1 = s390_isel_int_expr(env, arg1);
1189 op2 = s390_isel_int_expr_RMI(env, arg2);
1190
1191 addInstr(env, s390_insn_move(size, res, h1));
1192 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1193 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1194 return res;
1195 }
1196
1197 case Iop_CmpF32:
1198 case Iop_CmpF64: {
1199 HReg cc_s390, h2;
1200
1201 h1 = s390_isel_float_expr(env, arg1);
1202 h2 = s390_isel_float_expr(env, arg2);
1203 cc_s390 = newVRegI(env);
1204
1205 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1206
1207 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1208
florian2d3d87f2012-12-21 21:05:17 +00001209 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001210 }
1211
1212 case Iop_CmpF128: {
1213 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1214
1215 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1216 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1217 cc_s390 = newVRegI(env);
1218
1219 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1220 f12 = make_fpr(12);
1221 f13 = make_fpr(13);
1222 f14 = make_fpr(14);
1223 f15 = make_fpr(15);
1224
1225 /* 1st operand --> (f12, f14) */
1226 addInstr(env, s390_insn_move(8, f12, op1_hi));
1227 addInstr(env, s390_insn_move(8, f14, op1_lo));
1228
1229 /* 2nd operand --> (f13, f15) */
1230 addInstr(env, s390_insn_move(8, f13, op2_hi));
1231 addInstr(env, s390_insn_move(8, f15, op2_lo));
1232
1233 res = newVRegI(env);
1234 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1235
florian2d3d87f2012-12-21 21:05:17 +00001236 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001237 }
1238
florian20c6bca2012-12-26 17:47:19 +00001239 case Iop_CmpD64:
1240 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001241 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001242 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001243
1244 h1 = s390_isel_dfp_expr(env, arg1);
1245 h2 = s390_isel_dfp_expr(env, arg2);
1246 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001247
florian20c6bca2012-12-26 17:47:19 +00001248 switch(expr->Iex.Binop.op) {
1249 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1250 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1251 default: goto irreducible;
1252 }
1253 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001254
florian2d3d87f2012-12-21 21:05:17 +00001255 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001256 }
1257
florian20c6bca2012-12-26 17:47:19 +00001258 case Iop_CmpD128:
1259 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001260 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001261 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001262
1263 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1264 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1265 cc_s390 = newVRegI(env);
1266
1267 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1268 f12 = make_fpr(12);
1269 f13 = make_fpr(13);
1270 f14 = make_fpr(14);
1271 f15 = make_fpr(15);
1272
1273 /* 1st operand --> (f12, f14) */
1274 addInstr(env, s390_insn_move(8, f12, op1_hi));
1275 addInstr(env, s390_insn_move(8, f14, op1_lo));
1276
1277 /* 2nd operand --> (f13, f15) */
1278 addInstr(env, s390_insn_move(8, f13, op2_hi));
1279 addInstr(env, s390_insn_move(8, f15, op2_lo));
1280
florian20c6bca2012-12-26 17:47:19 +00001281 switch(expr->Iex.Binop.op) {
1282 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1283 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1284 default: goto irreducible;
1285 }
1286 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1287 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001288
florian2d3d87f2012-12-21 21:05:17 +00001289 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001290 }
1291
sewardj2019a972011-03-07 16:04:07 +00001292 case Iop_Add8:
1293 case Iop_Add16:
1294 case Iop_Add32:
1295 case Iop_Add64:
1296 opkind = S390_ALU_ADD;
1297 break;
1298
1299 case Iop_Sub8:
1300 case Iop_Sub16:
1301 case Iop_Sub32:
1302 case Iop_Sub64:
1303 opkind = S390_ALU_SUB;
1304 is_commutative = False;
1305 break;
1306
1307 case Iop_And8:
1308 case Iop_And16:
1309 case Iop_And32:
1310 case Iop_And64:
1311 opkind = S390_ALU_AND;
1312 break;
1313
1314 case Iop_Or8:
1315 case Iop_Or16:
1316 case Iop_Or32:
1317 case Iop_Or64:
1318 opkind = S390_ALU_OR;
1319 break;
1320
1321 case Iop_Xor8:
1322 case Iop_Xor16:
1323 case Iop_Xor32:
1324 case Iop_Xor64:
1325 opkind = S390_ALU_XOR;
1326 break;
1327
1328 case Iop_Shl8:
1329 case Iop_Shl16:
1330 case Iop_Shl32:
1331 case Iop_Shl64:
1332 opkind = S390_ALU_LSH;
1333 is_commutative = False;
1334 break;
1335
1336 case Iop_Shr8:
1337 case Iop_Shr16:
1338 case Iop_Shr32:
1339 case Iop_Shr64:
1340 opkind = S390_ALU_RSH;
1341 is_commutative = False;
1342 break;
1343
1344 case Iop_Sar8:
1345 case Iop_Sar16:
1346 case Iop_Sar32:
1347 case Iop_Sar64:
1348 opkind = S390_ALU_RSHA;
1349 is_commutative = False;
1350 break;
1351
1352 default:
1353 goto irreducible;
1354 }
1355
1356 /* Pattern match: 0 - arg1 --> -arg1 */
1357 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1358 res = newVRegI(env);
1359 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1360 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1361 addInstr(env, insn);
1362
1363 return res;
1364 }
1365
1366 if (is_commutative) {
1367 order_commutative_operands(arg1, arg2);
1368 }
1369
1370 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1371 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1372 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001373
1374 /* As right shifts of one/two byte opreands are implemented using a
1375 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1376 switch (expr->Iex.Binop.op) {
1377 case Iop_Shr8:
1378 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1379 break;
1380 case Iop_Shr16:
1381 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1382 break;
1383 case Iop_Sar8:
1384 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1385 break;
1386 case Iop_Sar16:
1387 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1388 break;
1389 default:
1390 insn = s390_insn_move(size, res, h1);
1391 break;
1392 }
1393 addInstr(env, insn);
1394
sewardj2019a972011-03-07 16:04:07 +00001395 insn = s390_insn_alu(size, opkind, res, op2);
1396
1397 addInstr(env, insn);
1398
1399 return res;
1400 }
1401
1402 /* --------- UNARY OP --------- */
1403 case Iex_Unop: {
1404 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1405 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1406 s390_opnd_RMI opnd;
1407 s390_insn *insn;
1408 IRExpr *arg;
1409 HReg dst, h1;
1410 IROp unop, binop;
1411
1412 arg = expr->Iex.Unop.arg;
1413
1414 /* Special cases are handled here */
1415
1416 /* 32-bit multiply with 32-bit result or
1417 64-bit multiply with 64-bit result */
1418 unop = expr->Iex.Unop.op;
1419 binop = arg->Iex.Binop.op;
1420
1421 if ((arg->tag == Iex_Binop &&
1422 ((unop == Iop_64to32 &&
1423 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1424 (unop == Iop_128to64 &&
1425 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1426 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1427 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1428 dst = newVRegI(env); /* Result goes into a new register */
1429 addInstr(env, s390_insn_move(size, dst, h1));
1430 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1431
1432 return dst;
1433 }
1434
florian4d71a082011-12-18 00:08:17 +00001435 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001436 dst = newVRegI(env);
1437 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1438 addInstr(env, s390_insn_move(size, dst, h1));
1439
1440 return dst;
1441 }
1442
floriane38f6412012-12-21 17:32:12 +00001443 if (unop == Iop_ReinterpD64asI64) {
1444 dst = newVRegI(env);
1445 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1446 addInstr(env, s390_insn_move(size, dst, h1));
1447
1448 return dst;
1449 }
1450
floriance9e3db2012-12-27 20:14:03 +00001451 if (unop == Iop_ExtractSigD64) {
1452 dst = newVRegI(env);
1453 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1454 addInstr(env,
1455 s390_insn_dfp_unop(size, S390_DFP_EXTRACT_SIG_D64, dst, h1));
1456 return dst;
1457 }
1458
1459 if (unop == Iop_ExtractSigD128) {
1460 HReg op_hi, op_lo, f13, f15;
1461 dst = newVRegI(env);
1462 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1463
1464 /* We use non-virtual registers r13 and r15 as pair */
1465 f13 = make_fpr(13);
1466 f15 = make_fpr(15);
1467
1468 /* operand --> (f13, f15) */
1469 addInstr(env, s390_insn_move(8, f13, op_hi));
1470 addInstr(env, s390_insn_move(8, f15, op_lo));
1471
1472 addInstr(env, s390_insn_dfp128_unop(size, S390_DFP_EXTRACT_SIG_D128,
1473 dst, f13, f15));
1474 return dst;
1475 }
1476
sewardj2019a972011-03-07 16:04:07 +00001477 /* Expressions whose argument is 1-bit wide */
1478 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1479 s390_cc_t cond = s390_isel_cc(env, arg);
1480 dst = newVRegI(env); /* Result goes into a new register */
1481 addInstr(env, s390_insn_cc2bool(dst, cond));
1482
1483 switch (unop) {
1484 case Iop_1Uto8:
1485 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001486 /* Zero extend */
1487 mask.variant.imm = 1;
1488 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1489 break;
1490
sewardj2019a972011-03-07 16:04:07 +00001491 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001492 /* Zero extend */
1493 mask.variant.imm = 1;
1494 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001495 break;
1496
1497 case Iop_1Sto8:
1498 case Iop_1Sto16:
1499 case Iop_1Sto32:
1500 shift.variant.imm = 31;
1501 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1502 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1503 break;
1504
1505 case Iop_1Sto64:
1506 shift.variant.imm = 63;
1507 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1508 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1509 break;
1510
1511 default:
1512 goto irreducible;
1513 }
1514
1515 return dst;
1516 }
1517
1518 /* Regular processing */
1519
1520 if (unop == Iop_128to64) {
1521 HReg dst_hi, dst_lo;
1522
1523 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1524 return dst_lo;
1525 }
1526
1527 if (unop == Iop_128HIto64) {
1528 HReg dst_hi, dst_lo;
1529
1530 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1531 return dst_hi;
1532 }
1533
1534 dst = newVRegI(env); /* Result goes into a new register */
1535 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1536
1537 switch (unop) {
1538 case Iop_8Uto16:
1539 case Iop_8Uto32:
1540 case Iop_8Uto64:
1541 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1542 break;
1543
1544 case Iop_16Uto32:
1545 case Iop_16Uto64:
1546 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1547 break;
1548
1549 case Iop_32Uto64:
1550 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1551 break;
1552
1553 case Iop_8Sto16:
1554 case Iop_8Sto32:
1555 case Iop_8Sto64:
1556 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1557 break;
1558
1559 case Iop_16Sto32:
1560 case Iop_16Sto64:
1561 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1562 break;
1563
1564 case Iop_32Sto64:
1565 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1566 break;
1567
1568 case Iop_64to8:
1569 case Iop_64to16:
1570 case Iop_64to32:
1571 case Iop_32to8:
1572 case Iop_32to16:
1573 case Iop_16to8:
1574 /* Down-casts are no-ops. Upstream operations will only look at
1575 the bytes that make up the result of the down-cast. So there
1576 is no point setting the other bytes to 0. */
1577 insn = s390_opnd_copy(8, dst, opnd);
1578 break;
1579
1580 case Iop_64HIto32:
1581 addInstr(env, s390_opnd_copy(8, dst, opnd));
1582 shift.variant.imm = 32;
1583 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1584 break;
1585
1586 case Iop_32HIto16:
1587 addInstr(env, s390_opnd_copy(4, dst, opnd));
1588 shift.variant.imm = 16;
1589 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1590 break;
1591
1592 case Iop_16HIto8:
1593 addInstr(env, s390_opnd_copy(2, dst, opnd));
1594 shift.variant.imm = 8;
1595 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1596 break;
1597
1598 case Iop_Not8:
1599 case Iop_Not16:
1600 case Iop_Not32:
1601 case Iop_Not64:
1602 /* XOR with ffff... */
1603 mask.variant.imm = ~(ULong)0;
1604 addInstr(env, s390_opnd_copy(size, dst, opnd));
1605 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1606 break;
1607
1608 case Iop_Left8:
1609 case Iop_Left16:
1610 case Iop_Left32:
1611 case Iop_Left64:
1612 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1613 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1614 break;
1615
1616 case Iop_CmpwNEZ32:
1617 case Iop_CmpwNEZ64: {
1618 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1619 or -X will have a 1 in the MSB. */
1620 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1621 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1622 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1623 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1624 return dst;
1625 }
1626
1627 case Iop_Clz64: {
1628 HReg r10, r11;
1629
sewardj611b06e2011-03-24 08:57:29 +00001630 /* This will be implemented using FLOGR, if possible. So we need to
1631 set aside a pair of non-virtual registers. The result (number of
1632 left-most zero bits) will be in r10. The value in r11 is unspecified
1633 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001634 r10 = make_gpr(10);
1635 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001636
sewardj611b06e2011-03-24 08:57:29 +00001637 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001638 addInstr(env, s390_insn_move(8, dst, r10));
1639 return dst;
1640 }
1641
1642 default:
1643 goto irreducible;
1644 }
1645
1646 addInstr(env, insn);
1647
1648 return dst;
1649 }
1650
1651 /* --------- GET --------- */
1652 case Iex_Get: {
1653 HReg dst = newVRegI(env);
1654 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1655
1656 /* We never load more than 8 bytes from the guest state, because the
1657 floating point register pair is not contiguous. */
1658 vassert(size <= 8);
1659
1660 addInstr(env, s390_insn_load(size, dst, am));
1661
1662 return dst;
1663 }
1664
1665 case Iex_GetI:
1666 /* not needed */
1667 break;
1668
1669 /* --------- CCALL --------- */
1670 case Iex_CCall: {
1671 HReg dst = newVRegI(env);
1672
1673 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001674 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001675 return dst;
1676 }
1677
1678 /* --------- LITERAL --------- */
1679
1680 /* Load a literal into a register. Create a "load immediate"
1681 v-insn and return the register. */
1682 case Iex_Const: {
1683 ULong value;
1684 HReg dst = newVRegI(env);
1685 const IRConst *con = expr->Iex.Const.con;
1686
1687 /* Bitwise copy of the value. No sign/zero-extension */
1688 switch (con->tag) {
1689 case Ico_U64: value = con->Ico.U64; break;
1690 case Ico_U32: value = con->Ico.U32; break;
1691 case Ico_U16: value = con->Ico.U16; break;
1692 case Ico_U8: value = con->Ico.U8; break;
1693 default: vpanic("s390_isel_int_expr: invalid constant");
1694 }
1695
1696 addInstr(env, s390_insn_load_immediate(size, dst, value));
1697
1698 return dst;
1699 }
1700
1701 /* --------- MULTIPLEX --------- */
1702 case Iex_Mux0X: {
1703 IRExpr *cond_expr;
1704 HReg dst, tmp, rX;
1705 s390_opnd_RMI cond, r0, zero;
1706
1707 cond_expr = expr->Iex.Mux0X.cond;
1708
1709 dst = newVRegI(env);
1710 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1711 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1712 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1713
1714 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1715 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1716
1717 addInstr(env, s390_insn_move(size, dst, rX));
1718 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1719 return dst;
1720 }
1721
1722 /* Assume the condition is true and move rX to the destination reg. */
1723 addInstr(env, s390_insn_move(size, dst, rX));
1724
1725 /* Compute the condition ... */
1726 cond = s390_isel_int_expr_RMI(env, cond_expr);
1727
1728 /* tmp = cond & 0xFF */
1729 tmp = newVRegI(env);
1730 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1731 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1732
1733 /* ... and compare it with zero */
1734 zero = s390_opnd_imm(0);
1735 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1736
1737 /* ... and if it compared equal move r0 to the destination reg. */
1738 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1739 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1740
1741 return dst;
1742 }
1743
1744 default:
1745 break;
1746 }
1747
1748 /* We get here if no pattern matched. */
1749 irreducible:
1750 ppIRExpr(expr);
1751 vpanic("s390_isel_int_expr: cannot reduce tree");
1752}
1753
1754
1755static HReg
1756s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1757{
1758 HReg dst = s390_isel_int_expr_wrk(env, expr);
1759
1760 /* Sanity checks ... */
1761 vassert(hregClass(dst) == HRcInt64);
1762 vassert(hregIsVirtual(dst));
1763
1764 return dst;
1765}
1766
1767
1768static s390_opnd_RMI
1769s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1770{
1771 IRType ty = typeOfIRExpr(env->type_env, expr);
1772 s390_opnd_RMI dst;
1773
1774 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1775 ty == Ity_I64);
1776
1777 if (expr->tag == Iex_Load) {
1778 dst.tag = S390_OPND_AMODE;
1779 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1780 } else if (expr->tag == Iex_Get) {
1781 dst.tag = S390_OPND_AMODE;
1782 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1783 } else if (expr->tag == Iex_Const) {
1784 ULong value;
1785
1786 /* The bit pattern for the value will be stored as is in the least
1787 significant bits of VALUE. */
1788 switch (expr->Iex.Const.con->tag) {
1789 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1790 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1791 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1792 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1793 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1794 default:
1795 vpanic("s390_isel_int_expr_RMI");
1796 }
1797
1798 dst.tag = S390_OPND_IMMEDIATE;
1799 dst.variant.imm = value;
1800 } else {
1801 dst.tag = S390_OPND_REG;
1802 dst.variant.reg = s390_isel_int_expr(env, expr);
1803 }
1804
1805 return dst;
1806}
1807
1808
1809/*---------------------------------------------------------*/
1810/*--- ISEL: Floating point expressions (128 bit) ---*/
1811/*---------------------------------------------------------*/
1812static void
1813s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1814 IRExpr *expr)
1815{
1816 IRType ty = typeOfIRExpr(env->type_env, expr);
1817
1818 vassert(ty == Ity_F128);
1819
sewardj2019a972011-03-07 16:04:07 +00001820 switch (expr->tag) {
1821 case Iex_RdTmp:
1822 /* Return the virtual registers that hold the temporary. */
1823 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1824 return;
1825
1826 /* --------- LOAD --------- */
1827 case Iex_Load: {
1828 IRExpr *addr_hi, *addr_lo;
1829 s390_amode *am_hi, *am_lo;
1830
1831 if (expr->Iex.Load.end != Iend_BE)
1832 goto irreducible;
1833
1834 addr_hi = expr->Iex.Load.addr;
1835 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1836
1837 am_hi = s390_isel_amode(env, addr_hi);
1838 am_lo = s390_isel_amode(env, addr_lo);
1839
1840 *dst_hi = newVRegF(env);
1841 *dst_lo = newVRegF(env);
1842 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1843 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1844 return;
1845 }
1846
1847
1848 /* --------- GET --------- */
1849 case Iex_Get:
1850 /* This is not supported because loading 128-bit from the guest
1851 state is almost certainly wrong. Use get_fpr_pair instead. */
1852 vpanic("Iex_Get with F128 data");
1853
1854 /* --------- 4-ary OP --------- */
1855 case Iex_Qop:
1856 vpanic("Iex_Qop with F128 data");
1857
1858 /* --------- TERNARY OP --------- */
1859 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001860 IRTriop *triop = expr->Iex.Triop.details;
1861 IROp op = triop->op;
1862 IRExpr *left = triop->arg2;
1863 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001864 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001865 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1866
1867 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1868 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1869
1870 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1871 f12 = make_fpr(12);
1872 f13 = make_fpr(13);
1873 f14 = make_fpr(14);
1874 f15 = make_fpr(15);
1875
1876 /* 1st operand --> (f12, f14) */
1877 addInstr(env, s390_insn_move(8, f12, op1_hi));
1878 addInstr(env, s390_insn_move(8, f14, op1_lo));
1879
1880 /* 2nd operand --> (f13, f15) */
1881 addInstr(env, s390_insn_move(8, f13, op2_hi));
1882 addInstr(env, s390_insn_move(8, f15, op2_lo));
1883
1884 switch (op) {
1885 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1886 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1887 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1888 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1889 default:
1890 goto irreducible;
1891 }
1892
florian2c74d242012-09-12 19:38:42 +00001893 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1894 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001895
1896 /* Move result to virtual destination register */
1897 *dst_hi = newVRegF(env);
1898 *dst_lo = newVRegF(env);
1899 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1900 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1901
1902 return;
1903 }
1904
1905 /* --------- BINARY OP --------- */
1906 case Iex_Binop: {
1907 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001908
1909 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1910 f12 = make_fpr(12);
1911 f13 = make_fpr(13);
1912 f14 = make_fpr(14);
1913 f15 = make_fpr(15);
1914
1915 switch (expr->Iex.Binop.op) {
1916 case Iop_SqrtF128:
1917 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1918
1919 /* operand --> (f13, f15) */
1920 addInstr(env, s390_insn_move(8, f13, op_hi));
1921 addInstr(env, s390_insn_move(8, f15, op_lo));
1922
florian2c74d242012-09-12 19:38:42 +00001923 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1924 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1925 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001926
1927 /* Move result to virtual destination registers */
1928 *dst_hi = newVRegF(env);
1929 *dst_lo = newVRegF(env);
1930 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1931 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1932 return;
1933
1934 case Iop_F64HLtoF128:
1935 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1936 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1937 return;
1938
1939 default:
1940 goto irreducible;
1941 }
1942 }
1943
1944 /* --------- UNARY OP --------- */
1945 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001946 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001947 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00001948 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001949 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1950
1951 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1952 f12 = make_fpr(12);
1953 f13 = make_fpr(13);
1954 f14 = make_fpr(14);
1955 f15 = make_fpr(15);
1956
florian66e596d2012-09-07 15:00:53 +00001957 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001958 case Iop_NegF128:
1959 if (left->tag == Iex_Unop &&
1960 (left->Iex.Unop.op == Iop_AbsF32 ||
1961 left->Iex.Unop.op == Iop_AbsF64))
1962 bfpop = S390_BFP_NABS;
1963 else
1964 bfpop = S390_BFP_NEG;
1965 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00001966 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1967 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1968 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1969 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1970 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1971 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1972 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001973 default:
1974 goto irreducible;
1975 }
1976
1977 float128_opnd:
1978 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1979
1980 /* operand --> (f13, f15) */
1981 addInstr(env, s390_insn_move(8, f13, op_hi));
1982 addInstr(env, s390_insn_move(8, f15, op_lo));
1983
florian2c74d242012-09-12 19:38:42 +00001984 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001985 goto move_dst;
1986
1987 convert_float:
1988 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001989 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001990 goto move_dst;
1991
1992 convert_int:
1993 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001994 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001995 goto move_dst;
1996
1997 move_dst:
1998 /* Move result to virtual destination registers */
1999 *dst_hi = newVRegF(env);
2000 *dst_lo = newVRegF(env);
2001 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2002 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2003 return;
2004 }
2005
2006 default:
2007 goto irreducible;
2008 }
2009
2010 /* We get here if no pattern matched. */
2011 irreducible:
2012 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002013 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002014}
2015
2016/* Compute a 128-bit value into two 64-bit registers. These may be either
2017 real or virtual regs; in any case they must not be changed by subsequent
2018 code emitted by the caller. */
2019static void
2020s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2021{
2022 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2023
2024 /* Sanity checks ... */
2025 vassert(hregIsVirtual(*dst_hi));
2026 vassert(hregIsVirtual(*dst_lo));
2027 vassert(hregClass(*dst_hi) == HRcFlt64);
2028 vassert(hregClass(*dst_lo) == HRcFlt64);
2029}
2030
2031
2032/*---------------------------------------------------------*/
2033/*--- ISEL: Floating point expressions (64 bit) ---*/
2034/*---------------------------------------------------------*/
2035
2036static HReg
2037s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2038{
2039 IRType ty = typeOfIRExpr(env->type_env, expr);
2040 UChar size;
2041
2042 vassert(ty == Ity_F32 || ty == Ity_F64);
2043
2044 size = sizeofIRType(ty);
2045
2046 switch (expr->tag) {
2047 case Iex_RdTmp:
2048 /* Return the virtual register that holds the temporary. */
2049 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2050
2051 /* --------- LOAD --------- */
2052 case Iex_Load: {
2053 HReg dst = newVRegF(env);
2054 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2055
2056 if (expr->Iex.Load.end != Iend_BE)
2057 goto irreducible;
2058
2059 addInstr(env, s390_insn_load(size, dst, am));
2060
2061 return dst;
2062 }
2063
2064 /* --------- GET --------- */
2065 case Iex_Get: {
2066 HReg dst = newVRegF(env);
2067 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2068
2069 addInstr(env, s390_insn_load(size, dst, am));
2070
2071 return dst;
2072 }
2073
2074 /* --------- LITERAL --------- */
2075
2076 /* Load a literal into a register. Create a "load immediate"
2077 v-insn and return the register. */
2078 case Iex_Const: {
2079 ULong value;
2080 HReg dst = newVRegF(env);
2081 const IRConst *con = expr->Iex.Const.con;
2082
2083 /* Bitwise copy of the value. No sign/zero-extension */
2084 switch (con->tag) {
2085 case Ico_F32i: value = con->Ico.F32i; break;
2086 case Ico_F64i: value = con->Ico.F64i; break;
2087 default: vpanic("s390_isel_float_expr: invalid constant");
2088 }
2089
2090 if (value != 0) vpanic("cannot load immediate floating point constant");
2091
2092 addInstr(env, s390_insn_load_immediate(size, dst, value));
2093
2094 return dst;
2095 }
2096
2097 /* --------- 4-ary OP --------- */
2098 case Iex_Qop: {
2099 HReg op1, op2, op3, dst;
2100 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002101
florian5906a6b2012-10-16 02:53:33 +00002102 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002103 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002104 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002105 dst = newVRegF(env);
2106 addInstr(env, s390_insn_move(size, dst, op1));
2107
florian96d7cc32012-06-01 20:41:24 +00002108 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002109 case Iop_MAddF32:
2110 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2111 case Iop_MSubF32:
2112 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2113
2114 default:
2115 goto irreducible;
2116 }
2117
florian2c74d242012-09-12 19:38:42 +00002118 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2119 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002120 return dst;
2121 }
2122
2123 /* --------- TERNARY OP --------- */
2124 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002125 IRTriop *triop = expr->Iex.Triop.details;
2126 IROp op = triop->op;
2127 IRExpr *left = triop->arg2;
2128 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002129 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002130 HReg h1, op2, dst;
2131
2132 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2133 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2134 dst = newVRegF(env);
2135 addInstr(env, s390_insn_move(size, dst, h1));
2136 switch (op) {
2137 case Iop_AddF32:
2138 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2139 case Iop_SubF32:
2140 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2141 case Iop_MulF32:
2142 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2143 case Iop_DivF32:
2144 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2145
2146 default:
2147 goto irreducible;
2148 }
2149
florian2c74d242012-09-12 19:38:42 +00002150 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2151 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002152 return dst;
2153 }
2154
2155 /* --------- BINARY OP --------- */
2156 case Iex_Binop: {
2157 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002158 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002159 IRExpr *left = expr->Iex.Binop.arg2;
2160 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002161 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002162
2163 switch (op) {
2164 case Iop_SqrtF32:
2165 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002166 h1 = s390_isel_float_expr(env, left);
2167 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002168 set_bfp_rounding_mode_in_fpc(env, irrm);
2169 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002170 return dst;
sewardj2019a972011-03-07 16:04:07 +00002171
florian9fcff4c2012-09-10 03:09:04 +00002172 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2173 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2174 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2175 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2176 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2177 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2178 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002179
florian9fcff4c2012-09-10 03:09:04 +00002180 convert_float:
2181 h1 = s390_isel_float_expr(env, left);
2182 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002183
florian9fcff4c2012-09-10 03:09:04 +00002184 convert_int:
2185 h1 = s390_isel_int_expr(env, left);
2186 goto convert;
2187
florian2c74d242012-09-12 19:38:42 +00002188 convert: {
florian125e20d2012-10-07 15:42:37 +00002189 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002190 /* convert-from-fixed and load-rounded have a rounding mode field
2191 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002192 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002193 if (s390_host_has_fpext) {
2194 rounding_mode = get_bfp_rounding_mode(env, irrm);
2195 } else {
2196 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002197 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002198 }
florian9fcff4c2012-09-10 03:09:04 +00002199 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2200 rounding_mode));
2201 return dst;
florian2c74d242012-09-12 19:38:42 +00002202 }
florian9fcff4c2012-09-10 03:09:04 +00002203
sewardj2019a972011-03-07 16:04:07 +00002204 default:
2205 goto irreducible;
2206
2207 case Iop_F128toF64:
2208 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002209 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002210 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002211
florian9fcff4c2012-09-10 03:09:04 +00002212 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2213 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002214
florian9fcff4c2012-09-10 03:09:04 +00002215 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002216
florian9fcff4c2012-09-10 03:09:04 +00002217 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002218 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002219 f15 = make_fpr(15);
2220
2221 /* operand --> (f13, f15) */
2222 addInstr(env, s390_insn_move(8, f13, op_hi));
2223 addInstr(env, s390_insn_move(8, f15, op_lo));
2224
2225 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002226 /* load-rounded has a rounding mode field when the floating point
2227 extension facility is installed. */
2228 if (s390_host_has_fpext) {
2229 rounding_mode = get_bfp_rounding_mode(env, irrm);
2230 } else {
2231 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002232 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002233 }
floriancc491a62012-09-10 23:44:37 +00002234 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002235 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002236 return dst;
2237 }
2238 }
sewardj2019a972011-03-07 16:04:07 +00002239 }
2240
2241 /* --------- UNARY OP --------- */
2242 case Iex_Unop: {
2243 IROp op = expr->Iex.Unop.op;
2244 IRExpr *left = expr->Iex.Unop.arg;
2245 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002246 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002247 HReg h1, dst;
2248
2249 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2250 HReg dst_hi, dst_lo;
2251
2252 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2253 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2254 }
2255
florian4d71a082011-12-18 00:08:17 +00002256 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002257 dst = newVRegF(env);
2258 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2259 addInstr(env, s390_insn_move(size, dst, h1));
2260
2261 return dst;
2262 }
2263
2264 switch (op) {
2265 case Iop_NegF32:
2266 case Iop_NegF64:
2267 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002268 (left->Iex.Unop.op == Iop_AbsF32 ||
2269 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002270 bfpop = S390_BFP_NABS;
2271 else
2272 bfpop = S390_BFP_NEG;
2273 break;
2274
2275 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002276 case Iop_AbsF64:
2277 bfpop = S390_BFP_ABS;
2278 break;
2279
2280 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2281 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2282 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2283
2284 convert_float1:
2285 h1 = s390_isel_float_expr(env, left);
2286 goto convert1;
2287
2288 convert_int1:
2289 h1 = s390_isel_int_expr(env, left);
2290 goto convert1;
2291
2292 convert1:
2293 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002294 /* No rounding mode is needed for these conversions. Just stick
2295 one in. It won't be used later on. */
2296 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002297 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002298 return dst;
2299
sewardj2019a972011-03-07 16:04:07 +00002300 default:
2301 goto irreducible;
2302 }
2303
2304 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002305 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002306 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002307 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002308 return dst;
2309 }
2310
2311 default:
2312 goto irreducible;
2313 }
2314
2315 /* We get here if no pattern matched. */
2316 irreducible:
2317 ppIRExpr(expr);
2318 vpanic("s390_isel_float_expr: cannot reduce tree");
2319}
2320
2321
2322static HReg
2323s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2324{
2325 HReg dst = s390_isel_float_expr_wrk(env, expr);
2326
2327 /* Sanity checks ... */
2328 vassert(hregClass(dst) == HRcFlt64);
2329 vassert(hregIsVirtual(dst));
2330
2331 return dst;
2332}
2333
2334
2335/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002336/*--- ISEL: Decimal point expressions (128 bit) ---*/
2337/*---------------------------------------------------------*/
2338static void
2339s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2340 IRExpr *expr)
2341{
2342 IRType ty = typeOfIRExpr(env->type_env, expr);
2343
2344 vassert(ty == Ity_D128);
2345
2346 switch (expr->tag) {
2347 case Iex_RdTmp:
2348 /* Return the virtual registers that hold the temporary. */
2349 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2350 return;
2351
2352 /* --------- LOAD --------- */
2353 case Iex_Load: {
2354 IRExpr *addr_hi, *addr_lo;
2355 s390_amode *am_hi, *am_lo;
2356
2357 if (expr->Iex.Load.end != Iend_BE)
2358 goto irreducible;
2359
2360 addr_hi = expr->Iex.Load.addr;
2361 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2362
2363 am_hi = s390_isel_amode(env, addr_hi);
2364 am_lo = s390_isel_amode(env, addr_lo);
2365
2366 *dst_hi = newVRegF(env);
2367 *dst_lo = newVRegF(env);
2368 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2369 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2370 return;
2371 }
2372
2373 /* --------- GET --------- */
2374 case Iex_Get:
2375 /* This is not supported because loading 128-bit from the guest
2376 state is almost certainly wrong. Use get_dpr_pair instead. */
2377 vpanic("Iex_Get with D128 data");
2378
2379 /* --------- 4-ary OP --------- */
2380 case Iex_Qop:
2381 vpanic("Iex_Qop with D128 data");
2382
2383 /* --------- TERNARY OP --------- */
2384 case Iex_Triop: {
2385 IRTriop *triop = expr->Iex.Triop.details;
2386 IROp op = triop->op;
2387 IRExpr *irrm = triop->arg1;
2388 IRExpr *left = triop->arg2;
2389 IRExpr *right = triop->arg3;
2390 s390_dfp_round_t rounding_mode;
2391 s390_dfp_binop_t dfpop;
2392 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2393
2394 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2395 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2396
2397 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2398 (f12, f14) as op2 and (f13, f15) as destination) */
2399 f9 = make_fpr(9);
2400 f11 = make_fpr(11);
2401 f12 = make_fpr(12);
2402 f13 = make_fpr(13);
2403 f14 = make_fpr(14);
2404 f15 = make_fpr(15);
2405
2406 /* 1st operand --> (f9, f11) */
2407 addInstr(env, s390_insn_move(8, f9, op1_hi));
2408 addInstr(env, s390_insn_move(8, f11, op1_lo));
2409
2410 /* 2nd operand --> (f12, f14) */
2411 addInstr(env, s390_insn_move(8, f12, op2_hi));
2412 addInstr(env, s390_insn_move(8, f14, op2_lo));
2413
2414 switch (op) {
2415 case Iop_AddD128: dfpop = S390_DFP_ADD; break;
2416 case Iop_SubD128: dfpop = S390_DFP_SUB; break;
2417 case Iop_MulD128: dfpop = S390_DFP_MUL; break;
2418 case Iop_DivD128: dfpop = S390_DFP_DIV; break;
2419 default:
2420 goto irreducible;
2421 }
2422
2423 /* DFP binary ops have insns with rounding mode field
2424 when the floating point extension facility is installed. */
2425 if (s390_host_has_fpext) {
2426 rounding_mode = get_dfp_rounding_mode(env, irrm);
2427 } else {
2428 set_dfp_rounding_mode_in_fpc(env, irrm);
2429 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2430 }
2431
2432 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2433 f12, f14, rounding_mode));
2434
2435 /* Move result to virtual destination register */
2436 *dst_hi = newVRegF(env);
2437 *dst_lo = newVRegF(env);
2438 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2439 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2440
2441 return;
2442 }
2443
2444 /* --------- BINARY OP --------- */
2445 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002446
floriane38f6412012-12-21 17:32:12 +00002447 switch (expr->Iex.Binop.op) {
2448 case Iop_D64HLtoD128:
2449 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2450 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2451 return;
2452
florian1b901d42013-01-01 22:19:24 +00002453 case Iop_ShlD128:
2454 case Iop_ShrD128: {
2455 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2456 s390_dfp_intop_t intop;
2457 IRExpr *left = expr->Iex.Binop.arg1;
2458 IRExpr *right = expr->Iex.Binop.arg2;
2459
2460 switch (expr->Iex.Binop.op) {
2461 case Iop_ShlD128: intop = S390_DFP_SHIFT_LEFT; break;
2462 case Iop_ShrD128: intop = S390_DFP_SHIFT_RIGHT; break;
2463 default: goto irreducible;
2464 }
2465
2466 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2467 f9 = make_fpr(9); /* 128 bit dfp operand */
2468 f11 = make_fpr(11);
2469
2470 f13 = make_fpr(13); /* 128 bit dfp destination */
2471 f15 = make_fpr(15);
2472
2473 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* dfp operand */
2474 addInstr(env, s390_insn_move(8, f9, op1_hi));
2475 addInstr(env, s390_insn_move(8, f11, op1_lo));
2476
2477 op2 = s390_isel_int_expr(env, right); /* int operand */
2478
2479 addInstr(env,
2480 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2481
2482 /* Move result to virtual destination register */
2483 *dst_hi = newVRegF(env);
2484 *dst_lo = newVRegF(env);
2485 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2486 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2487 return;
2488 }
2489
floriane38f6412012-12-21 17:32:12 +00002490 default:
2491 goto irreducible;
2492 }
2493 }
2494
2495 /* --------- UNARY OP --------- */
2496 case Iex_Unop: {
2497 IRExpr *left = expr->Iex.Unop.arg;
2498 s390_dfp_conv_t conv;
2499 // HReg op, f12, f13, f14, f15;
2500 HReg op, f12, f14;
2501
2502 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2503 f12 = make_fpr(12);
2504 // f13 = make_fpr(13);
2505 f14 = make_fpr(14);
2506 // f15 = make_fpr(15);
2507
2508 switch (expr->Iex.Unop.op) {
2509 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
2510 default:
2511 goto irreducible;
2512 }
2513
2514 convert_dfp:
2515 op = s390_isel_dfp_expr(env, left);
2516 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2517 goto move_dst;
2518
2519 move_dst:
2520 /* Move result to virtual destination registers */
2521 *dst_hi = newVRegF(env);
2522 *dst_lo = newVRegF(env);
2523 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2524 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2525 return;
2526 }
2527
2528 default:
2529 goto irreducible;
2530 }
2531
2532 /* We get here if no pattern matched. */
2533 irreducible:
2534 ppIRExpr(expr);
2535 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2536
2537}
2538
2539
2540/* Compute a 128-bit value into two 64-bit registers. These may be either
2541 real or virtual regs; in any case they must not be changed by subsequent
2542 code emitted by the caller. */
2543static void
2544s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2545{
2546 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2547
2548 /* Sanity checks ... */
2549 vassert(hregIsVirtual(*dst_hi));
2550 vassert(hregIsVirtual(*dst_lo));
2551 vassert(hregClass(*dst_hi) == HRcFlt64);
2552 vassert(hregClass(*dst_lo) == HRcFlt64);
2553}
2554
2555
2556/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002557/*--- ISEL: Decimal point expressions (64 bit) ---*/
2558/*---------------------------------------------------------*/
2559
2560static HReg
2561s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2562{
2563 IRType ty = typeOfIRExpr(env->type_env, expr);
2564 UChar size;
2565
floriane38f6412012-12-21 17:32:12 +00002566 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002567
2568 size = sizeofIRType(ty);
2569
2570 switch (expr->tag) {
2571 case Iex_RdTmp:
2572 /* Return the virtual register that holds the temporary. */
2573 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2574
2575 /* --------- LOAD --------- */
2576 case Iex_Load: {
2577 HReg dst = newVRegF(env);
2578 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2579
2580 if (expr->Iex.Load.end != Iend_BE)
2581 goto irreducible;
2582
2583 addInstr(env, s390_insn_load(size, dst, am));
2584
2585 return dst;
2586 }
2587
2588 /* --------- GET --------- */
2589 case Iex_Get: {
2590 HReg dst = newVRegF(env);
2591 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2592
2593 addInstr(env, s390_insn_load(size, dst, am));
2594
2595 return dst;
2596 }
2597
floriane38f6412012-12-21 17:32:12 +00002598 /* --------- BINARY OP --------- */
2599 case Iex_Binop: {
2600 IROp op = expr->Iex.Binop.op;
2601 IRExpr *irrm = expr->Iex.Binop.arg1;
2602 IRExpr *left = expr->Iex.Binop.arg2;
2603 HReg h1, dst;
2604 s390_dfp_conv_t conv;
2605
2606 switch (op) {
2607 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
2608
2609 convert_dfp:
2610 h1 = s390_isel_dfp_expr(env, left);
2611 goto convert;
2612
2613 convert: {
2614 s390_dfp_round_t rounding_mode;
2615 /* convert-from-fixed and load-rounded have a rounding mode field
2616 when the floating point extension facility is installed. */
2617 dst = newVRegF(env);
2618 if (s390_host_has_fpext) {
2619 rounding_mode = get_dfp_rounding_mode(env, irrm);
2620 } else {
2621 set_dfp_rounding_mode_in_fpc(env, irrm);
2622 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2623 }
2624 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2625 rounding_mode));
2626 return dst;
2627 }
floriane38f6412012-12-21 17:32:12 +00002628
2629 case Iop_D128toD64: {
2630 HReg op_hi, op_lo, f13, f15;
2631 s390_dfp_round_t rounding_mode;
2632
2633 conv = S390_DFP_D128_TO_D64;
2634
2635 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2636
2637 /* We use non-virtual registers as pairs (f13, f15) */
2638 f13 = make_fpr(13);
2639 f15 = make_fpr(15);
2640
2641 /* operand --> (f13, f15) */
2642 addInstr(env, s390_insn_move(8, f13, op_hi));
2643 addInstr(env, s390_insn_move(8, f15, op_lo));
2644
2645 dst = newVRegF(env);
2646 /* load-rounded has a rounding mode field when the floating point
2647 extension facility is installed. */
2648 if (s390_host_has_fpext) {
2649 rounding_mode = get_dfp_rounding_mode(env, irrm);
2650 } else {
2651 set_dfp_rounding_mode_in_fpc(env, irrm);
2652 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2653 }
2654 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2655 rounding_mode));
2656 return dst;
2657 }
2658
florian1b901d42013-01-01 22:19:24 +00002659 case Iop_ShlD64:
2660 case Iop_ShrD64: {
2661 HReg op2;
2662 HReg op3;
2663 s390_dfp_intop_t intop;
2664 IRExpr *op1 = expr->Iex.Binop.arg1;
2665 IRExpr *shift = expr->Iex.Binop.arg2;
2666
2667 switch (expr->Iex.Binop.op) {
2668 case Iop_ShlD64: intop = S390_DFP_SHIFT_LEFT; break;
2669 case Iop_ShrD64: intop = S390_DFP_SHIFT_RIGHT; break;
2670 default: goto irreducible;
2671 }
2672
2673 op2 = s390_isel_int_expr(env, shift);
2674 op3 = s390_isel_dfp_expr(env, op1);
2675 dst = newVRegF(env);
2676
2677 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
2678 return dst;
2679 }
2680
2681 default:
2682 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00002683 }
2684 }
2685
2686 /* --------- UNARY OP --------- */
2687 case Iex_Unop: {
2688 IROp op = expr->Iex.Unop.op;
2689 IRExpr *left = expr->Iex.Unop.arg;
2690 s390_dfp_conv_t conv;
2691 HReg h1, dst;
2692
2693 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2694 HReg dst_hi, dst_lo;
2695
2696 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2697 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2698 }
2699
2700 if (op == Iop_ReinterpI64asD64) {
2701 dst = newVRegF(env);
2702 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2703 addInstr(env, s390_insn_move(size, dst, h1));
2704
2705 return dst;
2706 }
2707
2708 switch (op) {
2709 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
2710
2711 convert_dfp1:
2712 h1 = s390_isel_dfp_expr(env, left);
2713 goto convert1;
2714
2715 convert1:
2716 dst = newVRegF(env);
2717 /* No rounding mode is needed for these conversions. Just stick
2718 one in. It won't be used later on. */
2719 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2720 S390_DFP_ROUND_NEAREST_EVEN_4));
2721 return dst;
2722
2723 default:
2724 goto irreducible;
2725 }
2726 }
2727
florian12390202012-11-10 22:34:14 +00002728 /* --------- TERNARY OP --------- */
2729 case Iex_Triop: {
2730 IRTriop *triop = expr->Iex.Triop.details;
2731 IROp op = triop->op;
2732 IRExpr *irrm = triop->arg1;
2733 IRExpr *left = triop->arg2;
2734 IRExpr *right = triop->arg3;
2735 s390_dfp_round_t rounding_mode;
2736 s390_dfp_binop_t dfpop;
2737 HReg op2, op3, dst;
2738
2739 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2740 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2741 dst = newVRegF(env);
2742 switch (op) {
2743 case Iop_AddD64: dfpop = S390_DFP_ADD; break;
2744 case Iop_SubD64: dfpop = S390_DFP_SUB; break;
2745 case Iop_MulD64: dfpop = S390_DFP_MUL; break;
2746 case Iop_DivD64: dfpop = S390_DFP_DIV; break;
2747 default:
2748 goto irreducible;
2749 }
2750 /* DFP binary ops have insns with rounding mode field
2751 when the floating point extension facility is installed. */
2752 if (s390_host_has_fpext) {
2753 rounding_mode = get_dfp_rounding_mode(env, irrm);
2754 } else {
2755 set_dfp_rounding_mode_in_fpc(env, irrm);
2756 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2757 }
2758
2759 addInstr(env,
2760 s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
2761 return dst;
2762 }
2763
2764 default:
2765 goto irreducible;
2766 }
2767
2768 /* We get here if no pattern matched. */
2769 irreducible:
2770 ppIRExpr(expr);
2771 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2772}
2773
2774static HReg
2775s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2776{
2777 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2778
2779 /* Sanity checks ... */
2780 vassert(hregClass(dst) == HRcFlt64);
2781 vassert(hregIsVirtual(dst));
2782
2783 return dst;
2784}
2785
2786
2787/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002788/*--- ISEL: Condition Code ---*/
2789/*---------------------------------------------------------*/
2790
2791/* This function handles all operators that produce a 1-bit result */
2792static s390_cc_t
2793s390_isel_cc(ISelEnv *env, IRExpr *cond)
2794{
2795 UChar size;
2796
2797 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2798
2799 /* Constant: either 1 or 0 */
2800 if (cond->tag == Iex_Const) {
2801 vassert(cond->Iex.Const.con->tag == Ico_U1);
2802 vassert(cond->Iex.Const.con->Ico.U1 == True
2803 || cond->Iex.Const.con->Ico.U1 == False);
2804
2805 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2806 }
2807
2808 /* Variable: values are 1 or 0 */
2809 if (cond->tag == Iex_RdTmp) {
2810 IRTemp tmp = cond->Iex.RdTmp.tmp;
2811 HReg reg = lookupIRTemp(env, tmp);
2812
2813 /* Load-and-test does not modify REG; so this is OK. */
2814 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2815 size = 4;
2816 else
2817 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2818 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2819 return S390_CC_NE;
2820 }
2821
2822 /* Unary operators */
2823 if (cond->tag == Iex_Unop) {
2824 IRExpr *arg = cond->Iex.Unop.arg;
2825
2826 switch (cond->Iex.Unop.op) {
2827 case Iop_Not1: /* Not1(cond) */
2828 /* Generate code for EXPR, and negate the test condition */
2829 return s390_cc_invert(s390_isel_cc(env, arg));
2830
2831 /* Iop_32/64to1 select the LSB from their operand */
2832 case Iop_32to1:
2833 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002834 HReg dst = newVRegI(env);
2835 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002836
2837 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2838
florianf366a802012-08-03 00:42:18 +00002839 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002840 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2841 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2842 return S390_CC_NE;
2843 }
2844
2845 case Iop_CmpNEZ8:
2846 case Iop_CmpNEZ16: {
2847 s390_opnd_RMI src;
2848 s390_unop_t op;
2849 HReg dst;
2850
2851 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2852 : S390_ZERO_EXTEND_16;
2853 dst = newVRegI(env);
2854 src = s390_isel_int_expr_RMI(env, arg);
2855 addInstr(env, s390_insn_unop(4, op, dst, src));
2856 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2857 return S390_CC_NE;
2858 }
2859
2860 case Iop_CmpNEZ32:
2861 case Iop_CmpNEZ64: {
2862 s390_opnd_RMI src;
2863
2864 src = s390_isel_int_expr_RMI(env, arg);
2865 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2866 addInstr(env, s390_insn_test(size, src));
2867 return S390_CC_NE;
2868 }
2869
2870 default:
2871 goto fail;
2872 }
2873 }
2874
2875 /* Binary operators */
2876 if (cond->tag == Iex_Binop) {
2877 IRExpr *arg1 = cond->Iex.Binop.arg1;
2878 IRExpr *arg2 = cond->Iex.Binop.arg2;
2879 HReg reg1, reg2;
2880
2881 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2882
2883 switch (cond->Iex.Binop.op) {
2884 s390_unop_t op;
2885 s390_cc_t result;
2886
2887 case Iop_CmpEQ8:
2888 case Iop_CasCmpEQ8:
2889 op = S390_ZERO_EXTEND_8;
2890 result = S390_CC_E;
2891 goto do_compare_ze;
2892
2893 case Iop_CmpNE8:
2894 case Iop_CasCmpNE8:
2895 op = S390_ZERO_EXTEND_8;
2896 result = S390_CC_NE;
2897 goto do_compare_ze;
2898
2899 case Iop_CmpEQ16:
2900 case Iop_CasCmpEQ16:
2901 op = S390_ZERO_EXTEND_16;
2902 result = S390_CC_E;
2903 goto do_compare_ze;
2904
2905 case Iop_CmpNE16:
2906 case Iop_CasCmpNE16:
2907 op = S390_ZERO_EXTEND_16;
2908 result = S390_CC_NE;
2909 goto do_compare_ze;
2910
2911 do_compare_ze: {
2912 s390_opnd_RMI op1, op2;
2913
2914 op1 = s390_isel_int_expr_RMI(env, arg1);
2915 reg1 = newVRegI(env);
2916 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2917
2918 op2 = s390_isel_int_expr_RMI(env, arg2);
2919 reg2 = newVRegI(env);
2920 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2921
2922 op2 = s390_opnd_reg(reg2);
2923 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2924
2925 return result;
2926 }
2927
2928 case Iop_CmpEQ32:
2929 case Iop_CmpEQ64:
2930 case Iop_CasCmpEQ32:
2931 case Iop_CasCmpEQ64:
2932 result = S390_CC_E;
2933 goto do_compare;
2934
2935 case Iop_CmpNE32:
2936 case Iop_CmpNE64:
2937 case Iop_CasCmpNE32:
2938 case Iop_CasCmpNE64:
2939 result = S390_CC_NE;
2940 goto do_compare;
2941
2942 do_compare: {
2943 HReg op1;
2944 s390_opnd_RMI op2;
2945
2946 order_commutative_operands(arg1, arg2);
2947
2948 op1 = s390_isel_int_expr(env, arg1);
2949 op2 = s390_isel_int_expr_RMI(env, arg2);
2950
2951 addInstr(env, s390_insn_compare(size, op1, op2, False));
2952
2953 return result;
2954 }
2955
2956 case Iop_CmpLT32S:
2957 case Iop_CmpLE32S:
2958 case Iop_CmpLT64S:
2959 case Iop_CmpLE64S: {
2960 HReg op1;
2961 s390_opnd_RMI op2;
2962
2963 op1 = s390_isel_int_expr(env, arg1);
2964 op2 = s390_isel_int_expr_RMI(env, arg2);
2965
2966 addInstr(env, s390_insn_compare(size, op1, op2, True));
2967
2968 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2969 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2970 }
2971
2972 case Iop_CmpLT32U:
2973 case Iop_CmpLE32U:
2974 case Iop_CmpLT64U:
2975 case Iop_CmpLE64U: {
2976 HReg op1;
2977 s390_opnd_RMI op2;
2978
2979 op1 = s390_isel_int_expr(env, arg1);
2980 op2 = s390_isel_int_expr_RMI(env, arg2);
2981
2982 addInstr(env, s390_insn_compare(size, op1, op2, False));
2983
2984 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2985 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2986 }
2987
2988 default:
2989 goto fail;
2990 }
2991 }
2992
2993 fail:
2994 ppIRExpr(cond);
2995 vpanic("s390_isel_cc: unexpected operator");
2996}
2997
2998
2999/*---------------------------------------------------------*/
3000/*--- ISEL: Statements ---*/
3001/*---------------------------------------------------------*/
3002
3003static void
3004s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3005{
3006 if (vex_traceflags & VEX_TRACE_VCODE) {
3007 vex_printf("\n -- ");
3008 ppIRStmt(stmt);
3009 vex_printf("\n");
3010 }
3011
3012 switch (stmt->tag) {
3013
3014 /* --------- STORE --------- */
3015 case Ist_Store: {
3016 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3017 s390_amode *am;
3018 HReg src;
3019
3020 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3021
3022 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3023
3024 switch (tyd) {
3025 case Ity_I8:
3026 case Ity_I16:
3027 case Ity_I32:
3028 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003029 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003030 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003031 stmt->Ist.Store.data->tag == Iex_Const) {
3032 ULong value =
3033 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3034 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003035 return;
3036 }
sewardj2019a972011-03-07 16:04:07 +00003037 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3038 break;
3039
3040 case Ity_F32:
3041 case Ity_F64:
3042 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3043 break;
3044
florianeb981ae2012-12-21 18:55:03 +00003045 case Ity_D32:
3046 case Ity_D64:
3047 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3048 break;
3049
sewardj2019a972011-03-07 16:04:07 +00003050 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003051 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003052 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003053 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003054
3055 default:
3056 goto stmt_fail;
3057 }
3058
3059 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3060 return;
3061 }
3062
3063 /* --------- PUT --------- */
3064 case Ist_Put: {
3065 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3066 HReg src;
3067 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003068 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003069
florianad43b3a2012-02-20 15:01:14 +00003070 /* Detect updates to certain guest registers. We track the contents
3071 of those registers as long as they contain constants. If the new
3072 constant is either zero or in the 8-bit neighbourhood of the
3073 current value we can use a memory-to-memory insn to do the update. */
3074
3075 Int offset = stmt->Ist.Put.offset;
3076
3077 /* Check necessary conditions:
3078 (1) must be one of the registers we care about
3079 (2) assigned value must be a constant */
3080 Int guest_reg = get_guest_reg(offset);
3081
3082 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3083
florianad43b3a2012-02-20 15:01:14 +00003084 if (stmt->Ist.Put.data->tag != Iex_Const) {
3085 /* Invalidate guest register contents */
3086 env->old_value_valid[guest_reg] = False;
3087 goto not_special;
3088 }
3089
cborntraaf7ad282012-08-08 14:11:33 +00003090 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3091 if (tyd != Ity_I64)
3092 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003093
cborntraaf7ad282012-08-08 14:11:33 +00003094 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003095
3096 old_value = env->old_value[guest_reg];
3097 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3098 env->old_value[guest_reg] = new_value;
3099
3100 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3101 env->old_value_valid[guest_reg] = True;
3102
3103 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003104 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003105 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003106 return;
florianad43b3a2012-02-20 15:01:14 +00003107 }
3108
florianad43b3a2012-02-20 15:01:14 +00003109 if (old_value_is_valid == False) goto not_special;
3110
3111 /* If the new value is in the neighbourhood of the old value
3112 we can use a memory-to-memory insn */
3113 difference = new_value - old_value;
3114
3115 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003116 am = s390_amode_for_guest_state(offset);
3117 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003118 (difference & 0xFF), new_value));
3119 return;
3120 }
3121
florianb93348d2012-12-27 00:59:43 +00003122 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003123 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003124 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003125 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003126 return;
3127 }
3128
3129 /* No special case applies... fall through */
3130
3131 not_special:
florianb93348d2012-12-27 00:59:43 +00003132 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003133
3134 switch (tyd) {
3135 case Ity_I8:
3136 case Ity_I16:
3137 case Ity_I32:
3138 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003139 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003140 stmt->Ist.Put.data->tag == Iex_Const) {
3141 ULong value =
3142 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3143 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003144 return;
3145 }
sewardj2019a972011-03-07 16:04:07 +00003146 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3147 break;
3148
3149 case Ity_F32:
3150 case Ity_F64:
3151 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3152 break;
3153
3154 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003155 case Ity_D128:
3156 /* Does not occur. See function put_(f|d)pr_pair. */
3157 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003158
floriane38f6412012-12-21 17:32:12 +00003159 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003160 case Ity_D64:
3161 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3162 break;
3163
sewardj2019a972011-03-07 16:04:07 +00003164 default:
3165 goto stmt_fail;
3166 }
3167
3168 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3169 return;
3170 }
3171
3172 /* --------- TMP --------- */
3173 case Ist_WrTmp: {
3174 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3175 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3176 HReg src, dst;
3177
3178 switch (tyd) {
3179 case Ity_I128: {
3180 HReg dst_hi, dst_lo, res_hi, res_lo;
3181
3182 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3183 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3184
3185 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3186 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3187 return;
3188 }
3189
3190 case Ity_I8:
3191 case Ity_I16:
3192 case Ity_I32:
3193 case Ity_I64:
3194 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3195 dst = lookupIRTemp(env, tmp);
3196 break;
3197
3198 case Ity_I1: {
3199 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3200 dst = lookupIRTemp(env, tmp);
3201 addInstr(env, s390_insn_cc2bool(dst, cond));
3202 return;
3203 }
3204
3205 case Ity_F32:
3206 case Ity_F64:
3207 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3208 dst = lookupIRTemp(env, tmp);
3209 break;
3210
3211 case Ity_F128: {
3212 HReg dst_hi, dst_lo, res_hi, res_lo;
3213
3214 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3215 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3216
3217 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3218 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3219 return;
3220 }
3221
floriane38f6412012-12-21 17:32:12 +00003222 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003223 case Ity_D64:
3224 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3225 dst = lookupIRTemp(env, tmp);
3226 break;
3227
floriane38f6412012-12-21 17:32:12 +00003228 case Ity_D128: {
3229 HReg dst_hi, dst_lo, res_hi, res_lo;
3230
3231 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3232 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3233
3234 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3235 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3236 return;
3237 }
3238
sewardj2019a972011-03-07 16:04:07 +00003239 default:
3240 goto stmt_fail;
3241 }
3242
3243 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3244 return;
3245 }
3246
3247 /* --------- Call to DIRTY helper --------- */
3248 case Ist_Dirty: {
3249 IRType retty;
3250 IRDirty* d = stmt->Ist.Dirty.details;
3251 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003252 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003253 Int i;
3254
3255 /* Invalidate tracked values of those guest state registers that are
3256 modified by this helper. */
3257 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003258 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3259 descriptors in guest state effect descriptions. Hence: */
3260 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003261 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3262 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3263 if (guest_reg != GUEST_UNKNOWN)
3264 env->old_value_valid[guest_reg] = False;
3265 }
3266 }
sewardj2019a972011-03-07 16:04:07 +00003267
3268 if (d->nFxState == 0)
3269 vassert(!d->needsBBP);
3270
3271 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3272
florian01ed6e72012-05-27 16:52:43 +00003273 if (d->tmp == IRTemp_INVALID) {
3274 /* No return value. */
3275 dst = INVALID_HREG;
3276 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003277 return;
florian01ed6e72012-05-27 16:52:43 +00003278 }
sewardj2019a972011-03-07 16:04:07 +00003279
3280 retty = typeOfIRTemp(env->type_env, d->tmp);
3281 if (retty == Ity_I64 || retty == Ity_I32
3282 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003283 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003284 dst = lookupIRTemp(env, d->tmp);
3285 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003286 return;
3287 }
3288 break;
3289 }
3290
3291 case Ist_CAS:
3292 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3293 IRCAS *cas = stmt->Ist.CAS.details;
3294 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3295 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3296 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3297 HReg old = lookupIRTemp(env, cas->oldLo);
3298
3299 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3300 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3301 } else {
3302 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3303 }
3304 return;
3305 } else {
florian448cbba2012-06-06 02:26:01 +00003306 IRCAS *cas = stmt->Ist.CAS.details;
3307 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3308 HReg r8, r9, r10, r11, r1;
3309 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3310 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3311 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3312 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3313 HReg old_low = lookupIRTemp(env, cas->oldLo);
3314 HReg old_high = lookupIRTemp(env, cas->oldHi);
3315
3316 /* Use non-virtual registers r8 and r9 as pair for op1
3317 and move op1 there */
3318 r8 = make_gpr(8);
3319 r9 = make_gpr(9);
3320 addInstr(env, s390_insn_move(8, r8, op1_high));
3321 addInstr(env, s390_insn_move(8, r9, op1_low));
3322
3323 /* Use non-virtual registers r10 and r11 as pair for op3
3324 and move op3 there */
3325 r10 = make_gpr(10);
3326 r11 = make_gpr(11);
3327 addInstr(env, s390_insn_move(8, r10, op3_high));
3328 addInstr(env, s390_insn_move(8, r11, op3_low));
3329
3330 /* Register r1 is used as a scratch register */
3331 r1 = make_gpr(1);
3332
3333 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3334 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3335 old_high, old_low, r1));
3336 } else {
3337 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3338 old_high, old_low, r1));
3339 }
3340 addInstr(env, s390_insn_move(8, op1_high, r8));
3341 addInstr(env, s390_insn_move(8, op1_low, r9));
3342 addInstr(env, s390_insn_move(8, op3_high, r10));
3343 addInstr(env, s390_insn_move(8, op3_low, r11));
3344 return;
sewardj2019a972011-03-07 16:04:07 +00003345 }
3346 break;
3347
3348 /* --------- EXIT --------- */
3349 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003350 s390_cc_t cond;
3351 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3352
3353 if (tag != Ico_U64)
3354 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3355
florian8844a632012-04-13 04:04:06 +00003356 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003357 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003358
3359 /* Case: boring transfer to known address */
3360 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3361 if (env->chaining_allowed) {
3362 /* .. almost always true .. */
3363 /* Skip the event check at the dst if this is a forwards
3364 edge. */
3365 Bool to_fast_entry
3366 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3367 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3368 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3369 guest_IA, to_fast_entry));
3370 } else {
3371 /* .. very occasionally .. */
3372 /* We can't use chaining, so ask for an assisted transfer,
3373 as that's the only alternative that is allowable. */
3374 HReg dst = s390_isel_int_expr(env,
3375 IRExpr_Const(stmt->Ist.Exit.dst));
3376 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3377 }
3378 return;
3379 }
3380
3381 /* Case: assisted transfer to arbitrary address */
3382 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003383 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003384 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003385 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003386 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003387 case Ijk_Sys_syscall:
3388 case Ijk_ClientReq:
3389 case Ijk_NoRedir:
3390 case Ijk_Yield:
3391 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003392 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3393 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3394 stmt->Ist.Exit.jk));
3395 return;
3396 }
3397 default:
3398 break;
3399 }
3400
3401 /* Do we ever expect to see any other kind? */
3402 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003403 }
3404
3405 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003406 case Ist_MBE:
3407 switch (stmt->Ist.MBE.event) {
3408 case Imbe_Fence:
3409 addInstr(env, s390_insn_mfence());
3410 return;
3411 default:
3412 break;
3413 }
sewardj2019a972011-03-07 16:04:07 +00003414 break;
3415
3416 /* --------- Miscellaneous --------- */
3417
3418 case Ist_PutI: /* Not needed */
3419 case Ist_IMark: /* Doesn't generate any executable code */
3420 case Ist_NoOp: /* Doesn't generate any executable code */
3421 case Ist_AbiHint: /* Meaningless in IR */
3422 return;
3423
3424 default:
3425 break;
3426 }
3427
3428 stmt_fail:
3429 ppIRStmt(stmt);
3430 vpanic("s390_isel_stmt");
3431}
3432
3433
3434/*---------------------------------------------------------*/
3435/*--- ISEL: Basic block terminators (Nexts) ---*/
3436/*---------------------------------------------------------*/
3437
3438static void
florianffbd84d2012-12-09 02:06:29 +00003439iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003440{
sewardj2019a972011-03-07 16:04:07 +00003441 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003442 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003443 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003444 vex_printf("; exit-");
3445 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003446 vex_printf("\n");
3447 }
3448
florian8844a632012-04-13 04:04:06 +00003449 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3450
3451 /* Case: boring transfer to known address */
3452 if (next->tag == Iex_Const) {
3453 IRConst *cdst = next->Iex.Const.con;
3454 vassert(cdst->tag == Ico_U64);
3455 if (jk == Ijk_Boring || jk == Ijk_Call) {
3456 /* Boring transfer to known address */
3457 if (env->chaining_allowed) {
3458 /* .. almost always true .. */
3459 /* Skip the event check at the dst if this is a forwards
3460 edge. */
3461 Bool to_fast_entry
3462 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3463 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3464 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3465 guest_IA, to_fast_entry));
3466 } else {
3467 /* .. very occasionally .. */
3468 /* We can't use chaining, so ask for an indirect transfer,
3469 as that's the cheapest alternative that is allowable. */
3470 HReg dst = s390_isel_int_expr(env, next);
3471 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3472 Ijk_Boring));
3473 }
3474 return;
3475 }
3476 }
3477
3478 /* Case: call/return (==boring) transfer to any address */
3479 switch (jk) {
3480 case Ijk_Boring:
3481 case Ijk_Ret:
3482 case Ijk_Call: {
3483 HReg dst = s390_isel_int_expr(env, next);
3484 if (env->chaining_allowed) {
3485 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3486 } else {
3487 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3488 Ijk_Boring));
3489 }
3490 return;
3491 }
3492 default:
3493 break;
3494 }
3495
3496 /* Case: some other kind of transfer to any address */
3497 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003498 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003499 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003500 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003501 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003502 case Ijk_Sys_syscall:
3503 case Ijk_ClientReq:
3504 case Ijk_NoRedir:
3505 case Ijk_Yield:
3506 case Ijk_SigTRAP: {
3507 HReg dst = s390_isel_int_expr(env, next);
3508 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3509 return;
3510 }
3511 default:
3512 break;
3513 }
3514
3515 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003516}
3517
3518
3519/*---------------------------------------------------------*/
3520/*--- Insn selector top-level ---*/
3521/*---------------------------------------------------------*/
3522
florianf26994a2012-04-21 03:34:54 +00003523/* Translate an entire SB to s390 code.
3524 Note: archinfo_host is a pointer to a stack-allocated variable.
3525 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003526
3527HInstrArray *
3528iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003529 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3530 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3531 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003532{
3533 UInt i, j;
3534 HReg hreg, hregHI;
3535 ISelEnv *env;
3536 UInt hwcaps_host = archinfo_host->hwcaps;
3537
florianf26994a2012-04-21 03:34:54 +00003538 /* KLUDGE: export hwcaps. */
3539 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003540
sewardj2019a972011-03-07 16:04:07 +00003541 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003542 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003543
3544 /* Make up an initial environment to use. */
3545 env = LibVEX_Alloc(sizeof(ISelEnv));
3546 env->vreg_ctr = 0;
3547
3548 /* Set up output code array. */
3549 env->code = newHInstrArray();
3550
3551 /* Copy BB's type env. */
3552 env->type_env = bb->tyenv;
3553
florianad43b3a2012-02-20 15:01:14 +00003554 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00003555 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3556 env->old_value[i] = 0; /* just something to have a defined value */
3557 env->old_value_valid[i] = False;
3558 }
3559
sewardj2019a972011-03-07 16:04:07 +00003560 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3561 change as we go along. For some reason types_used has Int type -- but
3562 it should be unsigned. Internally we use an unsigned type; so we
3563 assert it here. */
3564 vassert(bb->tyenv->types_used >= 0);
3565
3566 env->n_vregmap = bb->tyenv->types_used;
3567 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3568 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3569
florian2c74d242012-09-12 19:38:42 +00003570 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003571 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003572
sewardj2019a972011-03-07 16:04:07 +00003573 /* and finally ... */
3574 env->hwcaps = hwcaps_host;
3575
florian8844a632012-04-13 04:04:06 +00003576 env->max_ga = max_ga;
3577 env->chaining_allowed = chaining_allowed;
3578
sewardj2019a972011-03-07 16:04:07 +00003579 /* For each IR temporary, allocate a suitably-kinded virtual
3580 register. */
3581 j = 0;
3582 for (i = 0; i < env->n_vregmap; i++) {
3583 hregHI = hreg = INVALID_HREG;
3584 switch (bb->tyenv->types[i]) {
3585 case Ity_I1:
3586 case Ity_I8:
3587 case Ity_I16:
3588 case Ity_I32:
3589 hreg = mkHReg(j++, HRcInt64, True);
3590 break;
3591
3592 case Ity_I64:
3593 hreg = mkHReg(j++, HRcInt64, True);
3594 break;
3595
3596 case Ity_I128:
3597 hreg = mkHReg(j++, HRcInt64, True);
3598 hregHI = mkHReg(j++, HRcInt64, True);
3599 break;
3600
3601 case Ity_F32:
3602 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003603 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003604 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003605 hreg = mkHReg(j++, HRcFlt64, True);
3606 break;
3607
3608 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003609 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003610 hreg = mkHReg(j++, HRcFlt64, True);
3611 hregHI = mkHReg(j++, HRcFlt64, True);
3612 break;
3613
3614 case Ity_V128: /* fall through */
3615 default:
3616 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003617 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003618 }
3619
3620 env->vregmap[i] = hreg;
3621 env->vregmapHI[i] = hregHI;
3622 }
3623 env->vreg_ctr = j;
3624
florian8844a632012-04-13 04:04:06 +00003625 /* The very first instruction must be an event check. */
3626 s390_amode *counter, *fail_addr;
3627 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3628 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3629 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3630
3631 /* Possibly a block counter increment (for profiling). At this
3632 point we don't know the address of the counter, so just pretend
3633 it is zero. It will have to be patched later, but before this
3634 translation is used, by a call to LibVEX_patchProfInc. */
3635 if (add_profinc) {
3636 addInstr(env, s390_insn_profinc());
3637 }
3638
sewardj2019a972011-03-07 16:04:07 +00003639 /* Ok, finally we can iterate over the statements. */
3640 for (i = 0; i < bb->stmts_used; i++)
3641 if (bb->stmts[i])
3642 s390_isel_stmt(env, bb->stmts[i]);
3643
florian8844a632012-04-13 04:04:06 +00003644 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003645
3646 /* Record the number of vregs we used. */
3647 env->code->n_vregs = env->vreg_ctr;
3648
3649 return env->code;
3650}
3651
3652/*---------------------------------------------------------------*/
3653/*--- end host_s390_isel.c ---*/
3654/*---------------------------------------------------------------*/