blob: 21b8867a3281393ca416cbfc6a6f189068ab339b [file] [log] [blame]
sewardj2019a972011-03-07 16:04:07 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
2
3/*---------------------------------------------------------------*/
4/*--- begin host_s390_isel.c ---*/
5/*---------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
florian61f23c12012-08-06 18:33:21 +000011 Copyright IBM Corp. 2010-2012
florian2c74d242012-09-12 19:38:42 +000012 Copyright (C) 2012-2012 Florian Krohm (britzel@acm.org)
sewardj2019a972011-03-07 16:04:07 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
32/* Contributed by Florian Krohm */
33
34#include "libvex_basictypes.h"
35#include "libvex_ir.h"
36#include "libvex.h"
37#include "libvex_s390x_common.h"
38
sewardj2019a972011-03-07 16:04:07 +000039#include "main_util.h"
40#include "main_globals.h"
florian9f42ab42012-12-23 01:09:16 +000041#include "guest_s390_defs.h" /* S390X_GUEST_OFFSET */
sewardj2019a972011-03-07 16:04:07 +000042#include "host_generic_regs.h"
43#include "host_s390_defs.h"
44
45/*---------------------------------------------------------*/
46/*--- ISelEnv ---*/
47/*---------------------------------------------------------*/
48
49/* This carries around:
50
51 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
52 might encounter. This is computed before insn selection starts,
53 and does not change.
54
55 - A mapping from IRTemp to HReg. This tells the insn selector
56 which virtual register(s) are associated with each IRTemp
57 temporary. This is computed before insn selection starts, and
58 does not change. We expect this mapping to map precisely the
59 same set of IRTemps as the type mapping does.
60
61 - vregmap holds the primary register for the IRTemp.
62 - vregmapHI holds the secondary register for the IRTemp,
63 if any is needed. That's only for Ity_I64 temps
64 in 32 bit mode or Ity_I128 temps in 64-bit mode.
65
66 - The code array, that is, the insns selected so far.
67
68 - A counter, for generating new virtual registers.
69
70 - The host subarchitecture we are selecting insns for.
71 This is set at the start and does not change.
florianad43b3a2012-02-20 15:01:14 +000072
florian8844a632012-04-13 04:04:06 +000073 - A Bool for indicating whether we may generate chain-me
74 instructions for control flow transfers, or whether we must use
75 XAssisted.
76
77 - The maximum guest address of any guest insn in this block.
78 Actually, the address of the highest-addressed byte from any insn
79 in this block. Is set at the start and does not change. This is
80 used for detecting jumps which are definitely forward-edges from
81 this block, and therefore can be made (chained) to the fast entry
82 point of the destination, thereby avoiding the destination's
83 event check.
84
florianad43b3a2012-02-20 15:01:14 +000085 - Values of certain guest registers which are often assigned constants.
sewardj2019a972011-03-07 16:04:07 +000086*/
87
florianad43b3a2012-02-20 15:01:14 +000088/* Symbolic names for guest registers whose value we're tracking */
89enum {
90 GUEST_IA,
91 GUEST_CC_OP,
92 GUEST_CC_DEP1,
93 GUEST_CC_DEP2,
94 GUEST_CC_NDEP,
95 GUEST_SYSNO,
florian7d117ba2012-05-06 03:34:55 +000096 GUEST_COUNTER,
florianad43b3a2012-02-20 15:01:14 +000097 GUEST_UNKNOWN /* must be the last entry */
98};
99
100/* Number of registers we're tracking. */
101#define NUM_TRACKED_REGS GUEST_UNKNOWN
102
103
sewardj2019a972011-03-07 16:04:07 +0000104typedef struct {
105 IRTypeEnv *type_env;
106
florian8844a632012-04-13 04:04:06 +0000107 HInstrArray *code;
sewardj2019a972011-03-07 16:04:07 +0000108 HReg *vregmap;
109 HReg *vregmapHI;
110 UInt n_vregmap;
florian8844a632012-04-13 04:04:06 +0000111 UInt vreg_ctr;
112 UInt hwcaps;
sewardj2019a972011-03-07 16:04:07 +0000113
florian2c74d242012-09-12 19:38:42 +0000114 IRExpr *previous_bfp_rounding_mode;
florianc8e4f562012-10-27 16:19:31 +0000115 IRExpr *previous_dfp_rounding_mode;
florian2c74d242012-09-12 19:38:42 +0000116
florianad43b3a2012-02-20 15:01:14 +0000117 ULong old_value[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000118
florian8844a632012-04-13 04:04:06 +0000119 /* The next two are for translation chaining */
120 Addr64 max_ga;
121 Bool chaining_allowed;
122
florianad43b3a2012-02-20 15:01:14 +0000123 Bool old_value_valid[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000124} ISelEnv;
125
126
127/* Forward declarations */
128static HReg s390_isel_int_expr(ISelEnv *, IRExpr *);
129static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *);
130static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
131static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
132static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
133static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
134static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
florian12390202012-11-10 22:34:14 +0000135static HReg s390_isel_dfp_expr(ISelEnv *, IRExpr *);
floriane38f6412012-12-21 17:32:12 +0000136static void s390_isel_dfp128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
sewardj2019a972011-03-07 16:04:07 +0000137
138
florianad43b3a2012-02-20 15:01:14 +0000139static Int
140get_guest_reg(Int offset)
141{
142 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000143 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
144 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
145 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
146 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
147 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
148 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000149 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000150
151 /* Also make sure there is never a partial write to one of
152 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000153 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
154 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
155 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
156 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
157 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000158 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
159 /* counter is used both as 4-byte and as 8-byte entity */
160 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
161 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianaf50a192012-07-13 14:13:06 +0000162 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000163 break;
164
165 default: break;
166 }
167
168 return GUEST_UNKNOWN;
169}
170
sewardj2019a972011-03-07 16:04:07 +0000171/* Add an instruction */
172static void
173addInstr(ISelEnv *env, s390_insn *insn)
174{
175 addHInstr(env->code, insn);
176
177 if (vex_traceflags & VEX_TRACE_VCODE) {
178 vex_printf("%s\n", s390_insn_as_string(insn));
179 }
180}
181
182
183static __inline__ IRExpr *
184mkU64(ULong value)
185{
186 return IRExpr_Const(IRConst_U64(value));
187}
188
189
190/*---------------------------------------------------------*/
191/*--- Registers ---*/
192/*---------------------------------------------------------*/
193
194/* Return the virtual register to which a given IRTemp is mapped. */
195static HReg
196lookupIRTemp(ISelEnv *env, IRTemp tmp)
197{
198 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000199 vassert(! hregIsInvalid(env->vregmap[tmp]));
sewardj2019a972011-03-07 16:04:07 +0000200
201 return env->vregmap[tmp];
202}
203
204
205/* Return the two virtual registers to which the IRTemp is mapped. */
206static void
207lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
208{
209 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000210 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardj2019a972011-03-07 16:04:07 +0000211
212 *lo = env->vregmap[tmp];
213 *hi = env->vregmapHI[tmp];
214}
215
216
217/* Allocate a new integer register */
218static HReg
219newVRegI(ISelEnv *env)
220{
221 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
222 env->vreg_ctr++;
223
224 return reg;
225}
226
227
228/* Allocate a new floating point register */
229static HReg
230newVRegF(ISelEnv *env)
231{
232 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
233
234 env->vreg_ctr++;
235
236 return reg;
237}
238
239
240/* Construct a non-virtual general purpose register */
241static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000242make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000243{
244 return mkHReg(regno, HRcInt64, False /* virtual */ );
245}
246
247
248/* Construct a non-virtual floating point register */
249static __inline__ HReg
250make_fpr(UInt regno)
251{
252 return mkHReg(regno, HRcFlt64, False /* virtual */ );
253}
254
255
256/*---------------------------------------------------------*/
257/*--- Amode ---*/
258/*---------------------------------------------------------*/
259
260static __inline__ Bool
261ulong_fits_unsigned_12bit(ULong val)
262{
263 return (val & 0xFFFu) == val;
264}
265
266
267static __inline__ Bool
268ulong_fits_signed_20bit(ULong val)
269{
270 Long v = val & 0xFFFFFu;
271
272 v = (v << 44) >> 44; /* sign extend */
273
274 return val == (ULong)v;
275}
276
277
florianad43b3a2012-02-20 15:01:14 +0000278static __inline__ Bool
279ulong_fits_signed_8bit(ULong val)
280{
281 Long v = val & 0xFFu;
282
283 v = (v << 56) >> 56; /* sign extend */
284
285 return val == (ULong)v;
286}
287
sewardj2019a972011-03-07 16:04:07 +0000288/* EXPR is an expression that is used as an address. Return an s390_amode
289 for it. */
290static s390_amode *
291s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
292{
293 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
294 IRExpr *arg1 = expr->Iex.Binop.arg1;
295 IRExpr *arg2 = expr->Iex.Binop.arg2;
296
297 /* Move constant into right subtree */
298 if (arg1->tag == Iex_Const) {
299 IRExpr *tmp;
300 tmp = arg1;
301 arg1 = arg2;
302 arg2 = tmp;
303 }
304
305 /* r + constant: Check for b12 first, then b20 */
306 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
307 ULong value = arg2->Iex.Const.con->Ico.U64;
308
309 if (ulong_fits_unsigned_12bit(value)) {
310 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
311 }
sewardj652b56a2011-04-13 15:38:17 +0000312 /* If long-displacement is not available, do not construct B20 or
313 BX20 amodes because code generation cannot handle them. */
314 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000315 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
316 }
317 }
318 }
319
320 /* Doesn't match anything in particular. Generate it into
321 a register and use that. */
322 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
323}
324
325
326static s390_amode *
327s390_isel_amode(ISelEnv *env, IRExpr *expr)
328{
florian35da8612011-06-25 02:25:41 +0000329 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000330
331 /* Address computation should yield a 64-bit value */
332 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
333
334 am = s390_isel_amode_wrk(env, expr);
335
336 /* Check post-condition */
337 vassert(s390_amode_is_sane(am));
338
339 return am;
340}
341
342
343/*---------------------------------------------------------*/
344/*--- Helper functions ---*/
345/*---------------------------------------------------------*/
346
347/* Constants and memory accesses should be right operands */
348#define order_commutative_operands(left, right) \
349 do { \
350 if (left->tag == Iex_Const || left->tag == Iex_Load || \
351 left->tag == Iex_Get) { \
352 IRExpr *tmp; \
353 tmp = left; \
354 left = right; \
355 right = tmp; \
356 } \
357 } while (0)
358
359
360/* Copy an RMI operand to the DST register */
361static s390_insn *
362s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
363{
364 switch (opnd.tag) {
365 case S390_OPND_AMODE:
366 return s390_insn_load(size, dst, opnd.variant.am);
367
368 case S390_OPND_REG:
369 return s390_insn_move(size, dst, opnd.variant.reg);
370
371 case S390_OPND_IMMEDIATE:
372 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
373
374 default:
375 vpanic("s390_opnd_copy");
376 }
377}
378
379
380/* Construct a RMI operand for a register */
381static __inline__ s390_opnd_RMI
382s390_opnd_reg(HReg reg)
383{
384 s390_opnd_RMI opnd;
385
386 opnd.tag = S390_OPND_REG;
387 opnd.variant.reg = reg;
388
389 return opnd;
390}
391
392
393/* Construct a RMI operand for an immediate constant */
394static __inline__ s390_opnd_RMI
395s390_opnd_imm(ULong value)
396{
397 s390_opnd_RMI opnd;
398
399 opnd.tag = S390_OPND_IMMEDIATE;
400 opnd.variant.imm = value;
401
402 return opnd;
403}
404
405
florianffbd84d2012-12-09 02:06:29 +0000406/* Return 1, if EXPR represents the constant 0 */
407static Bool
sewardj2019a972011-03-07 16:04:07 +0000408s390_expr_is_const_zero(IRExpr *expr)
409{
410 ULong value;
411
412 if (expr->tag == Iex_Const) {
413 switch (expr->Iex.Const.con->tag) {
414 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
415 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
416 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
417 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
418 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
419 default:
420 vpanic("s390_expr_is_const_zero");
421 }
422 return value == 0;
423 }
424
425 return 0;
426}
427
428
florianb93348d2012-12-27 00:59:43 +0000429/* Return the value of CON as a sign-exteded ULong value */
430static ULong
431get_const_value_as_ulong(const IRConst *con)
432{
433 Long value;
434
435 switch (con->tag) {
436 case Ico_U1: value = con->Ico.U1; return (ULong) ((value << 63) >> 63);
437 case Ico_U8: value = con->Ico.U8; return (ULong) ((value << 56) >> 56);
438 case Ico_U16: value = con->Ico.U16; return (ULong) ((value << 48) >> 48);
439 case Ico_U32: value = con->Ico.U32; return (ULong) ((value << 32) >> 32);
440 case Ico_U64: return con->Ico.U64;
441 default:
442 vpanic("get_const_value_as_ulong");
443 }
444}
445
446
sewardj2019a972011-03-07 16:04:07 +0000447/* Call a helper (clean or dirty)
448 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000449
sewardj2019a972011-03-07 16:04:07 +0000450 (a) they are expressions yielding an integer result
451 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000452
453 guard is a Ity_Bit expression indicating whether or not the
454 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000455
456 Calling the helper function proceeds as follows:
457
458 (1) The helper arguments are evaluated and their value stored in
459 virtual registers.
460 (2) The condition code is evaluated
461 (3) The argument values are copied from the virtual registers to the
462 registers mandated by the ABI.
463 (4) Call the helper function.
464
465 This is not the most efficient way as step 3 generates register-to-register
466 moves. But it is the least fragile way as the only hidden dependency here
467 is that register-to-register moves (step 3) must not clobber the condition
468 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
469 to-register add more such dependencies. Not good. Besides, it's the job
470 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000471*/
472static void
473doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000474 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000475{
florian52af7bc2012-05-12 03:44:49 +0000476 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000477 ULong target;
478 HReg tmpregs[S390_NUM_GPRPARMS];
479 s390_cc_t cc;
480
481 n_args = 0;
482 for (i = 0; args[i]; i++)
483 ++n_args;
484
485 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
486 vpanic("doHelperCall: too many arguments");
487 }
488
florian11b8ee82012-08-06 13:35:33 +0000489 /* All arguments must have Ity_I64. For two reasons:
490 (1) We do not handle floating point arguments.
491 (2) The ABI requires that integer values are sign- or zero-extended
492 to 64 bit.
493 */
494 Int arg_errors = 0;
495 for (i = 0; i < n_args; ++i) {
496 IRType type = typeOfIRExpr(env->type_env, args[i]);
497 if (type != Ity_I64) {
498 ++arg_errors;
499 vex_printf("calling %s: argument #%d has type ", callee->name, i);
500 ppIRType(type);
501 vex_printf("; Ity_I64 is required\n");
502 }
503 }
504
505 if (arg_errors)
506 vpanic("cannot continue due to errors in argument passing");
507
florian52af7bc2012-05-12 03:44:49 +0000508 argreg = 0;
509
510 /* If we need the guest state pointer put it in a temporary arg reg */
511 if (passBBP) {
512 tmpregs[argreg] = newVRegI(env);
513 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
514 s390_hreg_guest_state_pointer()));
515 argreg++;
516 }
517
518 /* Compute the function arguments into a temporary register each */
519 for (i = 0; i < n_args; i++) {
520 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
521 argreg++;
522 }
523
sewardj2019a972011-03-07 16:04:07 +0000524 /* Compute the condition */
525 cc = S390_CC_ALWAYS;
526 if (guard) {
527 if (guard->tag == Iex_Const
528 && guard->Iex.Const.con->tag == Ico_U1
529 && guard->Iex.Const.con->Ico.U1 == True) {
530 /* unconditional -- do nothing */
531 } else {
532 cc = s390_isel_cc(env, guard);
533 }
534 }
535
florian52af7bc2012-05-12 03:44:49 +0000536 /* Move the args to the final register. It is paramount, that the
537 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000538 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000539 HReg finalreg;
540
541 finalreg = make_gpr(s390_gprno_from_arg_index(i));
542 size = sizeofIRType(Ity_I64);
543 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000544 }
545
546 target = Ptr_to_ULong(callee->addr);
547
548 /* Finally, the call itself. */
549 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000550 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000551}
552
553
florian2c74d242012-09-12 19:38:42 +0000554/*---------------------------------------------------------*/
555/*--- BFP helper functions ---*/
556/*---------------------------------------------------------*/
557
558/* Set the BFP rounding mode in the FPC. This function is called for
559 all non-conversion BFP instructions as those will always get the
560 rounding mode from the FPC. */
561static void
562set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000563{
florian2c74d242012-09-12 19:38:42 +0000564 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
565
566 /* Do we need to do anything? */
567 if (env->previous_bfp_rounding_mode &&
568 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
569 irrm->tag == Iex_RdTmp &&
570 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
571 /* No - new mode is identical to previous mode. */
572 return;
573 }
574
575 /* No luck - we better set it, and remember what we set it to. */
576 env->previous_bfp_rounding_mode = irrm;
577
578 /* The incoming rounding mode is in VEX IR encoding. Need to change
579 to s390.
580
581 rounding mode | s390 | IR
582 -------------------------
583 to nearest | 00 | 00
584 to zero | 01 | 11
585 to +infinity | 10 | 10
586 to -infinity | 11 | 01
587
588 So: s390 = (4 - IR) & 3
589 */
590 HReg ir = s390_isel_int_expr(env, irrm);
591
592 HReg mode = newVRegI(env);
593
594 addInstr(env, s390_insn_load_immediate(4, mode, 4));
595 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
596 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
597
florian125e20d2012-10-07 15:42:37 +0000598 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000599}
600
601
602/* This function is invoked for insns that support a specification of
603 a rounding mode in the insn itself. In that case there is no need to
604 stick the rounding mode into the FPC -- a good thing. However, the
605 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000606static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000607get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
608{
609 if (irrm->tag == Iex_Const) { /* rounding mode is known */
610 vassert(irrm->Iex.Const.con->tag == Ico_U32);
611 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000612
613 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000614 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
615 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
616 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
617 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000618 default:
619 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000620 }
621 }
622
florian2c74d242012-09-12 19:38:42 +0000623 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000624 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000625}
626
627
florianc8e4f562012-10-27 16:19:31 +0000628/*---------------------------------------------------------*/
629/*--- DFP helper functions ---*/
630/*---------------------------------------------------------*/
631
632/* Set the DFP rounding mode in the FPC. This function is called for
633 all non-conversion DFP instructions as those will always get the
634 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000635static void
636set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
637{
638 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
639
640 /* Do we need to do anything? */
641 if (env->previous_dfp_rounding_mode &&
642 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
643 irrm->tag == Iex_RdTmp &&
644 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
645 /* No - new mode is identical to previous mode. */
646 return;
647 }
648
649 /* No luck - we better set it, and remember what we set it to. */
650 env->previous_dfp_rounding_mode = irrm;
651
652 /* The incoming rounding mode is in VEX IR encoding. Need to change
653 to s390.
654
655 rounding mode | S390 | IR
656 -----------------------------------------------
657 to nearest, ties to even | 000 | 000
658 to zero | 001 | 011
659 to +infinity | 010 | 010
660 to -infinity | 011 | 001
661 to nearest, ties away from 0 | 100 | 100
662 to nearest, ties toward 0 | 101 | 111
663 to away from 0 | 110 | 110
664 to prepare for shorter precision | 111 | 101
665
666 So: s390 = (IR ^ ((IR << 1) & 2))
667 */
668 HReg ir = s390_isel_int_expr(env, irrm);
669
670 HReg mode = newVRegI(env);
671
672 addInstr(env, s390_insn_move(4, mode, ir));
673 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
674 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
675 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
676
677 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
678}
679
680
681/* This function is invoked for insns that support a specification of
682 a rounding mode in the insn itself. In that case there is no need to
683 stick the rounding mode into the FPC -- a good thing. However, the
684 rounding mode must be known.
florianff9000d2013-02-08 20:22:03 +0000685
686 When mapping an Irrm_DFP_ value to an S390_DFP_ROUND_ value there is
687 often a choice. For instance, Irrm_DFP_ZERO could be mapped to either
688 S390_DFP_ROUND_ZERO_5 or S390_DFP_ROUND_ZERO_9. The difference between
689 those two is that with S390_DFP_ROUND_ZERO_9 the recognition of the
690 quantum exception is suppressed whereas with S390_DFP_ROUND_ZERO_5 it
691 is not. As the quantum exception is not modelled we can choose either
692 value. The choice is to use S390_DFP_ROUND_.. values in the range [8:15],
693 because values in the range [1:7] have unpredictable rounding behaviour
694 when the floating point exception facility is not installed.
florianc8e4f562012-10-27 16:19:31 +0000695
696 Translation table of
697 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
698
699 s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
700 --------------------------------------------------------------------
florianff9000d2013-02-08 20:22:03 +0000701 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_12
florianc8e4f562012-10-27 16:19:31 +0000702 NEAREST_TIE_AWAY_0_12 | " | "
florianff9000d2013-02-08 20:22:03 +0000703 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_15
florianc8e4f562012-10-27 16:19:31 +0000704 PREPARE_SHORT_15 | " | "
florianff9000d2013-02-08 20:22:03 +0000705 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_8
florianc8e4f562012-10-27 16:19:31 +0000706 NEAREST_EVEN_8 | " | "
florianff9000d2013-02-08 20:22:03 +0000707 ZERO_5 | ZERO | ZERO_9
florianc8e4f562012-10-27 16:19:31 +0000708 ZERO_9 | " | "
florianff9000d2013-02-08 20:22:03 +0000709 POSINF_6 | PosINF | POSINF_10
florianc8e4f562012-10-27 16:19:31 +0000710 POSINF_10 | " | "
florianff9000d2013-02-08 20:22:03 +0000711 NEGINF_7 | NegINF | NEGINF_11
florianc8e4f562012-10-27 16:19:31 +0000712 NEGINF_11 | " | "
713 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
714 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
715*/
716static s390_dfp_round_t
717get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
718{
719 if (irrm->tag == Iex_Const) { /* rounding mode is known */
720 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian3d6a4222012-11-19 16:29:31 +0000721 IRRoundingModeDFP mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000722
723 switch (mode) {
724 case Irrm_DFP_NEAREST:
florianff9000d2013-02-08 20:22:03 +0000725 return S390_DFP_ROUND_NEAREST_EVEN_8;
florianc8e4f562012-10-27 16:19:31 +0000726 case Irrm_DFP_NegINF:
florianff9000d2013-02-08 20:22:03 +0000727 return S390_DFP_ROUND_NEGINF_11;
florianc8e4f562012-10-27 16:19:31 +0000728 case Irrm_DFP_PosINF:
florianff9000d2013-02-08 20:22:03 +0000729 return S390_DFP_ROUND_POSINF_10;
florianc8e4f562012-10-27 16:19:31 +0000730 case Irrm_DFP_ZERO:
florianff9000d2013-02-08 20:22:03 +0000731 return S390_DFP_ROUND_ZERO_9;
florianc8e4f562012-10-27 16:19:31 +0000732 case Irrm_DFP_NEAREST_TIE_AWAY_0:
florianff9000d2013-02-08 20:22:03 +0000733 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12;
florianc8e4f562012-10-27 16:19:31 +0000734 case Irrm_DFP_PREPARE_SHORTER:
florianff9000d2013-02-08 20:22:03 +0000735 return S390_DFP_ROUND_PREPARE_SHORT_15;
florianc8e4f562012-10-27 16:19:31 +0000736 case Irrm_DFP_AWAY_FROM_ZERO:
737 return S390_DFP_ROUND_AWAY_0;
738 case Irrm_DFP_NEAREST_TIE_TOWARD_0:
739 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
740 default:
741 vpanic("get_dfp_rounding_mode");
742 }
743 }
744
745 set_dfp_rounding_mode_in_fpc(env, irrm);
746 return S390_DFP_ROUND_PER_FPC_0;
747}
florianc8e4f562012-10-27 16:19:31 +0000748
florian2d3d87f2012-12-21 21:05:17 +0000749
750/*---------------------------------------------------------*/
751/*--- Condition code helper functions ---*/
752/*---------------------------------------------------------*/
753
sewardj2019a972011-03-07 16:04:07 +0000754/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000755 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000756
757 s390 VEX b6 b2 b0 cc.1 cc.0
758 0 0x40 EQ 1 0 0 0 0
759 1 0x01 LT 0 0 1 0 1
760 2 0x00 GT 0 0 0 1 0
761 3 0x45 Unordered 1 1 1 1 1
762
763 b0 = cc.0
764 b2 = cc.0 & cc.1
765 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
766
767 VEX = b0 | (b2 << 2) | (b6 << 6);
768*/
769static HReg
florian2d3d87f2012-12-21 21:05:17 +0000770convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000771{
772 HReg cc0, cc1, b2, b6, cc_vex;
773
774 cc0 = newVRegI(env);
775 addInstr(env, s390_insn_move(4, cc0, cc_s390));
776 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
777
778 cc1 = newVRegI(env);
779 addInstr(env, s390_insn_move(4, cc1, cc_s390));
780 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
781
782 b2 = newVRegI(env);
783 addInstr(env, s390_insn_move(4, b2, cc0));
784 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
785 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
786
787 b6 = newVRegI(env);
788 addInstr(env, s390_insn_move(4, b6, cc0));
789 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
790 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
791 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
792 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
793
794 cc_vex = newVRegI(env);
795 addInstr(env, s390_insn_move(4, cc_vex, cc0));
796 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
797 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
798
799 return cc_vex;
800}
801
florian2d3d87f2012-12-21 21:05:17 +0000802/* CC_S390 holds the condition code in s390 encoding. Convert it to
803 VEX encoding (IRCmpDResult) */
804static HReg
805convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
806{
807 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
808 return convert_s390_to_vex_bfpcc(env, cc_s390);
809}
810
sewardj2019a972011-03-07 16:04:07 +0000811
812/*---------------------------------------------------------*/
813/*--- ISEL: Integer expressions (128 bit) ---*/
814/*---------------------------------------------------------*/
815static void
816s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
817 IRExpr *expr)
818{
819 IRType ty = typeOfIRExpr(env->type_env, expr);
820
821 vassert(ty == Ity_I128);
822
823 /* No need to consider the following
824 - 128-bit constants (they do not exist in VEX)
825 - 128-bit loads from memory (will not be generated)
826 */
827
828 /* Read 128-bit IRTemp */
829 if (expr->tag == Iex_RdTmp) {
830 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
831 return;
832 }
833
834 if (expr->tag == Iex_Binop) {
835 IRExpr *arg1 = expr->Iex.Binop.arg1;
836 IRExpr *arg2 = expr->Iex.Binop.arg2;
837 Bool is_signed_multiply, is_signed_divide;
838
839 switch (expr->Iex.Binop.op) {
840 case Iop_MullU64:
841 is_signed_multiply = False;
842 goto do_multiply64;
843
844 case Iop_MullS64:
845 is_signed_multiply = True;
846 goto do_multiply64;
847
848 case Iop_DivModU128to64:
849 is_signed_divide = False;
850 goto do_divide64;
851
852 case Iop_DivModS128to64:
853 is_signed_divide = True;
854 goto do_divide64;
855
856 case Iop_64HLto128:
857 *dst_hi = s390_isel_int_expr(env, arg1);
858 *dst_lo = s390_isel_int_expr(env, arg2);
859 return;
860
861 case Iop_DivModS64to64: {
862 HReg r10, r11, h1;
863 s390_opnd_RMI op2;
864
865 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
866 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
867
868 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000869 r10 = make_gpr(10);
870 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000871
872 /* Move 1st operand into r11 and */
873 addInstr(env, s390_insn_move(8, r11, h1));
874
875 /* Divide */
876 addInstr(env, s390_insn_divs(8, r10, r11, op2));
877
878 /* The result is in registers r10 (remainder) and r11 (quotient).
879 Move the result into the reg pair that is being returned such
880 such that the low 64 bits are the quotient and the upper 64 bits
881 are the remainder. (see libvex_ir.h). */
882 *dst_hi = newVRegI(env);
883 *dst_lo = newVRegI(env);
884 addInstr(env, s390_insn_move(8, *dst_hi, r10));
885 addInstr(env, s390_insn_move(8, *dst_lo, r11));
886 return;
887 }
888
889 default:
890 break;
891
892 do_multiply64: {
893 HReg r10, r11, h1;
894 s390_opnd_RMI op2;
895
896 order_commutative_operands(arg1, arg2);
897
898 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
899 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
900
901 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000902 r10 = make_gpr(10);
903 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000904
905 /* Move the first operand to r11 */
906 addInstr(env, s390_insn_move(8, r11, h1));
907
908 /* Multiply */
909 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
910
911 /* The result is in registers r10 and r11. Assign to two virtual regs
912 and return. */
913 *dst_hi = newVRegI(env);
914 *dst_lo = newVRegI(env);
915 addInstr(env, s390_insn_move(8, *dst_hi, r10));
916 addInstr(env, s390_insn_move(8, *dst_lo, r11));
917 return;
918 }
919
920 do_divide64: {
921 HReg r10, r11, hi, lo;
922 s390_opnd_RMI op2;
923
924 s390_isel_int128_expr(&hi, &lo, env, arg1);
925 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
926
927 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000928 r10 = make_gpr(10);
929 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000930
931 /* Move high 64 bits of the 1st operand into r10 and
932 the low 64 bits into r11. */
933 addInstr(env, s390_insn_move(8, r10, hi));
934 addInstr(env, s390_insn_move(8, r11, lo));
935
936 /* Divide */
937 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
938
939 /* The result is in registers r10 (remainder) and r11 (quotient).
940 Move the result into the reg pair that is being returned such
941 such that the low 64 bits are the quotient and the upper 64 bits
942 are the remainder. (see libvex_ir.h). */
943 *dst_hi = newVRegI(env);
944 *dst_lo = newVRegI(env);
945 addInstr(env, s390_insn_move(8, *dst_hi, r10));
946 addInstr(env, s390_insn_move(8, *dst_lo, r11));
947 return;
948 }
949 }
950 }
951
952 vpanic("s390_isel_int128_expr");
953}
954
955
956/* Compute a 128-bit value into two 64-bit registers. These may be either
957 real or virtual regs; in any case they must not be changed by subsequent
958 code emitted by the caller. */
959static void
960s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
961{
962 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
963
964 /* Sanity checks ... */
965 vassert(hregIsVirtual(*dst_hi));
966 vassert(hregIsVirtual(*dst_lo));
967 vassert(hregClass(*dst_hi) == HRcInt64);
968 vassert(hregClass(*dst_lo) == HRcInt64);
969}
970
971
972/*---------------------------------------------------------*/
973/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
974/*---------------------------------------------------------*/
975
976/* Select insns for an integer-typed expression, and add them to the
977 code list. Return a reg holding the result. This reg will be a
978 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
979 want to modify it, ask for a new vreg, copy it in there, and modify
980 the copy. The register allocator will do its best to map both
981 vregs to the same real register, so the copies will often disappear
982 later in the game.
983
984 This should handle expressions of 64, 32, 16 and 8-bit type.
985 All results are returned in a 64bit register.
986 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
987 are arbitrary, so you should mask or sign extend partial values
988 if necessary.
989*/
990
991/* DO NOT CALL THIS DIRECTLY ! */
992static HReg
993s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
994{
995 IRType ty = typeOfIRExpr(env->type_env, expr);
996 UChar size;
florian6dc90242012-12-21 21:43:00 +0000997 s390_bfp_conv_t conv;
florian67a171c2013-01-20 03:08:04 +0000998 s390_dfp_conv_t dconv;
sewardj2019a972011-03-07 16:04:07 +0000999
1000 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
1001
1002 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
1003
1004 switch (expr->tag) {
1005
1006 /* --------- TEMP --------- */
1007 case Iex_RdTmp:
1008 /* Return the virtual register that holds the temporary. */
1009 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1010
1011 /* --------- LOAD --------- */
1012 case Iex_Load: {
1013 HReg dst = newVRegI(env);
1014 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1015
1016 if (expr->Iex.Load.end != Iend_BE)
1017 goto irreducible;
1018
1019 addInstr(env, s390_insn_load(size, dst, am));
1020
1021 return dst;
1022 }
1023
1024 /* --------- BINARY OP --------- */
1025 case Iex_Binop: {
1026 IRExpr *arg1 = expr->Iex.Binop.arg1;
1027 IRExpr *arg2 = expr->Iex.Binop.arg2;
1028 HReg h1, res;
1029 s390_alu_t opkind;
1030 s390_opnd_RMI op2, value, opnd;
1031 s390_insn *insn;
1032 Bool is_commutative, is_signed_multiply, is_signed_divide;
1033
1034 is_commutative = True;
1035
1036 switch (expr->Iex.Binop.op) {
1037 case Iop_MullU8:
1038 case Iop_MullU16:
1039 case Iop_MullU32:
1040 is_signed_multiply = False;
1041 goto do_multiply;
1042
1043 case Iop_MullS8:
1044 case Iop_MullS16:
1045 case Iop_MullS32:
1046 is_signed_multiply = True;
1047 goto do_multiply;
1048
1049 do_multiply: {
1050 HReg r10, r11;
1051 UInt arg_size = size / 2;
1052
1053 order_commutative_operands(arg1, arg2);
1054
1055 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1056 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1057
1058 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001059 r10 = make_gpr(10);
1060 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001061
1062 /* Move the first operand to r11 */
1063 addInstr(env, s390_insn_move(arg_size, r11, h1));
1064
1065 /* Multiply */
1066 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1067
1068 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1069 value into the destination register. */
1070 res = newVRegI(env);
1071 addInstr(env, s390_insn_move(arg_size, res, r10));
1072 value = s390_opnd_imm(arg_size * 8);
1073 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1074 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1075 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1076 opnd = s390_opnd_reg(r11);
1077 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1078 return res;
1079 }
1080
1081 case Iop_DivModS64to32:
1082 is_signed_divide = True;
1083 goto do_divide;
1084
1085 case Iop_DivModU64to32:
1086 is_signed_divide = False;
1087 goto do_divide;
1088
1089 do_divide: {
1090 HReg r10, r11;
1091
1092 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1093 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1094
1095 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001096 r10 = make_gpr(10);
1097 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001098
1099 /* Split the first operand and put the high 32 bits into r10 and
1100 the low 32 bits into r11. */
1101 addInstr(env, s390_insn_move(8, r10, h1));
1102 addInstr(env, s390_insn_move(8, r11, h1));
1103 value = s390_opnd_imm(32);
1104 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1105
1106 /* Divide */
1107 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1108
1109 /* The result is in registers r10 (remainder) and r11 (quotient).
1110 Combine them into a 64-bit value such that the low 32 bits are
1111 the quotient and the upper 32 bits are the remainder. (see
1112 libvex_ir.h). */
1113 res = newVRegI(env);
1114 addInstr(env, s390_insn_move(8, res, r10));
1115 value = s390_opnd_imm(32);
1116 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1117 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1118 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1119 opnd = s390_opnd_reg(r11);
1120 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1121 return res;
1122 }
1123
florian9fcff4c2012-09-10 03:09:04 +00001124 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1125 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1126 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1127 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1128 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1129 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1130 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1131 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1132 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1133 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1134 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1135 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
florian67a171c2013-01-20 03:08:04 +00001136
1137 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
floriana887acd2013-02-08 23:32:54 +00001138 case Iop_D64toI64S: dconv = S390_DFP_D64_TO_I64; goto do_convert_dfp;
florian67a171c2013-01-20 03:08:04 +00001139 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1140 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1141 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
floriana887acd2013-02-08 23:32:54 +00001142 case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128;
florian67a171c2013-01-20 03:08:04 +00001143 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1144 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00001145
1146 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001147 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001148
1149 res = newVRegI(env);
1150 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1151
florian2c74d242012-09-12 19:38:42 +00001152 rounding_mode = get_bfp_rounding_mode(env, arg1);
1153 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1154 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001155 return res;
1156 }
1157
1158 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001159 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001160 HReg op_hi, op_lo, f13, f15;
1161
1162 res = newVRegI(env);
1163 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1164
1165 /* We use non-virtual registers r13 and r15 as pair */
1166 f13 = make_fpr(13);
1167 f15 = make_fpr(15);
1168
1169 /* operand --> (f13, f15) */
1170 addInstr(env, s390_insn_move(8, f13, op_hi));
1171 addInstr(env, s390_insn_move(8, f15, op_lo));
1172
florian2c74d242012-09-12 19:38:42 +00001173 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001174 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001175 rounding_mode));
1176 return res;
1177 }
1178
florian5f034622013-01-13 02:29:05 +00001179 do_convert_dfp: {
1180 s390_dfp_round_t rounding_mode;
1181
1182 res = newVRegI(env);
1183 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1184
1185 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001186 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
florian5f034622013-01-13 02:29:05 +00001187 rounding_mode));
1188 return res;
1189 }
1190
1191 do_convert_dfp128: {
1192 s390_dfp_round_t rounding_mode;
1193 HReg op_hi, op_lo, f13, f15;
1194
1195 res = newVRegI(env);
1196 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1197
1198 /* We use non-virtual registers r13 and r15 as pair */
1199 f13 = make_fpr(13);
1200 f15 = make_fpr(15);
1201
1202 /* operand --> (f13, f15) */
1203 addInstr(env, s390_insn_move(8, f13, op_hi));
1204 addInstr(env, s390_insn_move(8, f15, op_lo));
1205
1206 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001207 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res, f13,
florian5f034622013-01-13 02:29:05 +00001208 f15, rounding_mode));
1209 return res;
1210 }
1211
sewardj2019a972011-03-07 16:04:07 +00001212 case Iop_8HLto16:
1213 case Iop_16HLto32:
1214 case Iop_32HLto64: {
1215 HReg h2;
1216 UInt arg_size = size / 2;
1217
1218 res = newVRegI(env);
1219 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1220 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1221
1222 addInstr(env, s390_insn_move(arg_size, res, h1));
1223 value = s390_opnd_imm(arg_size * 8);
1224 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1225 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1226 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1227 opnd = s390_opnd_reg(h2);
1228 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1229 return res;
1230 }
1231
1232 case Iop_Max32U: {
1233 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1234 res = newVRegI(env);
1235 h1 = s390_isel_int_expr(env, arg1);
1236 op2 = s390_isel_int_expr_RMI(env, arg2);
1237
1238 addInstr(env, s390_insn_move(size, res, h1));
1239 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1240 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1241 return res;
1242 }
1243
1244 case Iop_CmpF32:
1245 case Iop_CmpF64: {
1246 HReg cc_s390, h2;
1247
1248 h1 = s390_isel_float_expr(env, arg1);
1249 h2 = s390_isel_float_expr(env, arg2);
1250 cc_s390 = newVRegI(env);
1251
1252 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1253
1254 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1255
florian2d3d87f2012-12-21 21:05:17 +00001256 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001257 }
1258
1259 case Iop_CmpF128: {
1260 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1261
1262 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1263 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1264 cc_s390 = newVRegI(env);
1265
1266 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1267 f12 = make_fpr(12);
1268 f13 = make_fpr(13);
1269 f14 = make_fpr(14);
1270 f15 = make_fpr(15);
1271
1272 /* 1st operand --> (f12, f14) */
1273 addInstr(env, s390_insn_move(8, f12, op1_hi));
1274 addInstr(env, s390_insn_move(8, f14, op1_lo));
1275
1276 /* 2nd operand --> (f13, f15) */
1277 addInstr(env, s390_insn_move(8, f13, op2_hi));
1278 addInstr(env, s390_insn_move(8, f15, op2_lo));
1279
1280 res = newVRegI(env);
1281 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1282
florian2d3d87f2012-12-21 21:05:17 +00001283 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001284 }
1285
florian20c6bca2012-12-26 17:47:19 +00001286 case Iop_CmpD64:
1287 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001288 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001289 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001290
1291 h1 = s390_isel_dfp_expr(env, arg1);
1292 h2 = s390_isel_dfp_expr(env, arg2);
1293 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001294
florian20c6bca2012-12-26 17:47:19 +00001295 switch(expr->Iex.Binop.op) {
1296 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1297 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1298 default: goto irreducible;
1299 }
1300 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001301
florian2d3d87f2012-12-21 21:05:17 +00001302 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001303 }
1304
florian20c6bca2012-12-26 17:47:19 +00001305 case Iop_CmpD128:
1306 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001307 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001308 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001309
1310 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1311 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1312 cc_s390 = newVRegI(env);
1313
1314 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1315 f12 = make_fpr(12);
1316 f13 = make_fpr(13);
1317 f14 = make_fpr(14);
1318 f15 = make_fpr(15);
1319
1320 /* 1st operand --> (f12, f14) */
1321 addInstr(env, s390_insn_move(8, f12, op1_hi));
1322 addInstr(env, s390_insn_move(8, f14, op1_lo));
1323
1324 /* 2nd operand --> (f13, f15) */
1325 addInstr(env, s390_insn_move(8, f13, op2_hi));
1326 addInstr(env, s390_insn_move(8, f15, op2_lo));
1327
florian20c6bca2012-12-26 17:47:19 +00001328 switch(expr->Iex.Binop.op) {
1329 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1330 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1331 default: goto irreducible;
1332 }
1333 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1334 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001335
florian2d3d87f2012-12-21 21:05:17 +00001336 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001337 }
1338
sewardj2019a972011-03-07 16:04:07 +00001339 case Iop_Add8:
1340 case Iop_Add16:
1341 case Iop_Add32:
1342 case Iop_Add64:
1343 opkind = S390_ALU_ADD;
1344 break;
1345
1346 case Iop_Sub8:
1347 case Iop_Sub16:
1348 case Iop_Sub32:
1349 case Iop_Sub64:
1350 opkind = S390_ALU_SUB;
1351 is_commutative = False;
1352 break;
1353
1354 case Iop_And8:
1355 case Iop_And16:
1356 case Iop_And32:
1357 case Iop_And64:
1358 opkind = S390_ALU_AND;
1359 break;
1360
1361 case Iop_Or8:
1362 case Iop_Or16:
1363 case Iop_Or32:
1364 case Iop_Or64:
1365 opkind = S390_ALU_OR;
1366 break;
1367
1368 case Iop_Xor8:
1369 case Iop_Xor16:
1370 case Iop_Xor32:
1371 case Iop_Xor64:
1372 opkind = S390_ALU_XOR;
1373 break;
1374
1375 case Iop_Shl8:
1376 case Iop_Shl16:
1377 case Iop_Shl32:
1378 case Iop_Shl64:
1379 opkind = S390_ALU_LSH;
1380 is_commutative = False;
1381 break;
1382
1383 case Iop_Shr8:
1384 case Iop_Shr16:
1385 case Iop_Shr32:
1386 case Iop_Shr64:
1387 opkind = S390_ALU_RSH;
1388 is_commutative = False;
1389 break;
1390
1391 case Iop_Sar8:
1392 case Iop_Sar16:
1393 case Iop_Sar32:
1394 case Iop_Sar64:
1395 opkind = S390_ALU_RSHA;
1396 is_commutative = False;
1397 break;
1398
1399 default:
1400 goto irreducible;
1401 }
1402
1403 /* Pattern match: 0 - arg1 --> -arg1 */
1404 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1405 res = newVRegI(env);
1406 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1407 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1408 addInstr(env, insn);
1409
1410 return res;
1411 }
1412
1413 if (is_commutative) {
1414 order_commutative_operands(arg1, arg2);
1415 }
1416
1417 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1418 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1419 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001420
1421 /* As right shifts of one/two byte opreands are implemented using a
1422 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1423 switch (expr->Iex.Binop.op) {
1424 case Iop_Shr8:
1425 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1426 break;
1427 case Iop_Shr16:
1428 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1429 break;
1430 case Iop_Sar8:
1431 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1432 break;
1433 case Iop_Sar16:
1434 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1435 break;
1436 default:
1437 insn = s390_insn_move(size, res, h1);
1438 break;
1439 }
1440 addInstr(env, insn);
1441
sewardj2019a972011-03-07 16:04:07 +00001442 insn = s390_insn_alu(size, opkind, res, op2);
1443
1444 addInstr(env, insn);
1445
1446 return res;
1447 }
1448
1449 /* --------- UNARY OP --------- */
1450 case Iex_Unop: {
1451 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1452 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1453 s390_opnd_RMI opnd;
1454 s390_insn *insn;
1455 IRExpr *arg;
1456 HReg dst, h1;
1457 IROp unop, binop;
1458
1459 arg = expr->Iex.Unop.arg;
1460
1461 /* Special cases are handled here */
1462
1463 /* 32-bit multiply with 32-bit result or
1464 64-bit multiply with 64-bit result */
1465 unop = expr->Iex.Unop.op;
1466 binop = arg->Iex.Binop.op;
1467
1468 if ((arg->tag == Iex_Binop &&
1469 ((unop == Iop_64to32 &&
1470 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1471 (unop == Iop_128to64 &&
1472 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1473 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1474 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1475 dst = newVRegI(env); /* Result goes into a new register */
1476 addInstr(env, s390_insn_move(size, dst, h1));
1477 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1478
1479 return dst;
1480 }
1481
florian4d71a082011-12-18 00:08:17 +00001482 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001483 dst = newVRegI(env);
1484 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1485 addInstr(env, s390_insn_move(size, dst, h1));
1486
1487 return dst;
1488 }
1489
floriane38f6412012-12-21 17:32:12 +00001490 if (unop == Iop_ReinterpD64asI64) {
1491 dst = newVRegI(env);
1492 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1493 addInstr(env, s390_insn_move(size, dst, h1));
1494
1495 return dst;
1496 }
1497
florian5c539732013-02-14 14:27:12 +00001498 if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
1499 s390_dfp_unop_t dfpop;
1500 switch(unop) {
1501 case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
1502 case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
1503 default: goto irreducible;
1504 }
floriance9e3db2012-12-27 20:14:03 +00001505 dst = newVRegI(env);
1506 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
florian5c539732013-02-14 14:27:12 +00001507 addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
floriance9e3db2012-12-27 20:14:03 +00001508 return dst;
1509 }
1510
florian5c539732013-02-14 14:27:12 +00001511 if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
1512 s390_dfp_unop_t dfpop;
floriance9e3db2012-12-27 20:14:03 +00001513 HReg op_hi, op_lo, f13, f15;
florian5c539732013-02-14 14:27:12 +00001514
1515 switch(unop) {
1516 case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
1517 case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
1518 default: goto irreducible;
1519 }
floriance9e3db2012-12-27 20:14:03 +00001520 dst = newVRegI(env);
1521 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1522
1523 /* We use non-virtual registers r13 and r15 as pair */
1524 f13 = make_fpr(13);
1525 f15 = make_fpr(15);
1526
1527 /* operand --> (f13, f15) */
1528 addInstr(env, s390_insn_move(8, f13, op_hi));
1529 addInstr(env, s390_insn_move(8, f15, op_lo));
1530
florian5c539732013-02-14 14:27:12 +00001531 addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
floriance9e3db2012-12-27 20:14:03 +00001532 return dst;
1533 }
1534
sewardj2019a972011-03-07 16:04:07 +00001535 /* Expressions whose argument is 1-bit wide */
1536 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1537 s390_cc_t cond = s390_isel_cc(env, arg);
1538 dst = newVRegI(env); /* Result goes into a new register */
1539 addInstr(env, s390_insn_cc2bool(dst, cond));
1540
1541 switch (unop) {
1542 case Iop_1Uto8:
1543 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001544 /* Zero extend */
1545 mask.variant.imm = 1;
1546 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1547 break;
1548
sewardj2019a972011-03-07 16:04:07 +00001549 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001550 /* Zero extend */
1551 mask.variant.imm = 1;
1552 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001553 break;
1554
1555 case Iop_1Sto8:
1556 case Iop_1Sto16:
1557 case Iop_1Sto32:
1558 shift.variant.imm = 31;
1559 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1560 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1561 break;
1562
1563 case Iop_1Sto64:
1564 shift.variant.imm = 63;
1565 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1566 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1567 break;
1568
1569 default:
1570 goto irreducible;
1571 }
1572
1573 return dst;
1574 }
1575
1576 /* Regular processing */
1577
1578 if (unop == Iop_128to64) {
1579 HReg dst_hi, dst_lo;
1580
1581 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1582 return dst_lo;
1583 }
1584
1585 if (unop == Iop_128HIto64) {
1586 HReg dst_hi, dst_lo;
1587
1588 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1589 return dst_hi;
1590 }
1591
1592 dst = newVRegI(env); /* Result goes into a new register */
1593 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1594
1595 switch (unop) {
1596 case Iop_8Uto16:
1597 case Iop_8Uto32:
1598 case Iop_8Uto64:
1599 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1600 break;
1601
1602 case Iop_16Uto32:
1603 case Iop_16Uto64:
1604 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1605 break;
1606
1607 case Iop_32Uto64:
1608 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1609 break;
1610
1611 case Iop_8Sto16:
1612 case Iop_8Sto32:
1613 case Iop_8Sto64:
1614 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1615 break;
1616
1617 case Iop_16Sto32:
1618 case Iop_16Sto64:
1619 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1620 break;
1621
1622 case Iop_32Sto64:
1623 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1624 break;
1625
1626 case Iop_64to8:
1627 case Iop_64to16:
1628 case Iop_64to32:
1629 case Iop_32to8:
1630 case Iop_32to16:
1631 case Iop_16to8:
1632 /* Down-casts are no-ops. Upstream operations will only look at
1633 the bytes that make up the result of the down-cast. So there
1634 is no point setting the other bytes to 0. */
1635 insn = s390_opnd_copy(8, dst, opnd);
1636 break;
1637
1638 case Iop_64HIto32:
1639 addInstr(env, s390_opnd_copy(8, dst, opnd));
1640 shift.variant.imm = 32;
1641 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1642 break;
1643
1644 case Iop_32HIto16:
1645 addInstr(env, s390_opnd_copy(4, dst, opnd));
1646 shift.variant.imm = 16;
1647 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1648 break;
1649
1650 case Iop_16HIto8:
1651 addInstr(env, s390_opnd_copy(2, dst, opnd));
1652 shift.variant.imm = 8;
1653 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1654 break;
1655
1656 case Iop_Not8:
1657 case Iop_Not16:
1658 case Iop_Not32:
1659 case Iop_Not64:
1660 /* XOR with ffff... */
1661 mask.variant.imm = ~(ULong)0;
1662 addInstr(env, s390_opnd_copy(size, dst, opnd));
1663 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1664 break;
1665
1666 case Iop_Left8:
1667 case Iop_Left16:
1668 case Iop_Left32:
1669 case Iop_Left64:
1670 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1671 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1672 break;
1673
1674 case Iop_CmpwNEZ32:
1675 case Iop_CmpwNEZ64: {
1676 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1677 or -X will have a 1 in the MSB. */
1678 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1679 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1680 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1681 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1682 return dst;
1683 }
1684
1685 case Iop_Clz64: {
1686 HReg r10, r11;
1687
sewardj611b06e2011-03-24 08:57:29 +00001688 /* This will be implemented using FLOGR, if possible. So we need to
1689 set aside a pair of non-virtual registers. The result (number of
1690 left-most zero bits) will be in r10. The value in r11 is unspecified
1691 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001692 r10 = make_gpr(10);
1693 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001694
sewardj611b06e2011-03-24 08:57:29 +00001695 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001696 addInstr(env, s390_insn_move(8, dst, r10));
1697 return dst;
1698 }
1699
1700 default:
1701 goto irreducible;
1702 }
1703
1704 addInstr(env, insn);
1705
1706 return dst;
1707 }
1708
1709 /* --------- GET --------- */
1710 case Iex_Get: {
1711 HReg dst = newVRegI(env);
1712 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1713
1714 /* We never load more than 8 bytes from the guest state, because the
1715 floating point register pair is not contiguous. */
1716 vassert(size <= 8);
1717
1718 addInstr(env, s390_insn_load(size, dst, am));
1719
1720 return dst;
1721 }
1722
1723 case Iex_GetI:
1724 /* not needed */
1725 break;
1726
1727 /* --------- CCALL --------- */
1728 case Iex_CCall: {
1729 HReg dst = newVRegI(env);
1730
1731 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001732 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001733 return dst;
1734 }
1735
1736 /* --------- LITERAL --------- */
1737
1738 /* Load a literal into a register. Create a "load immediate"
1739 v-insn and return the register. */
1740 case Iex_Const: {
1741 ULong value;
1742 HReg dst = newVRegI(env);
1743 const IRConst *con = expr->Iex.Const.con;
1744
1745 /* Bitwise copy of the value. No sign/zero-extension */
1746 switch (con->tag) {
1747 case Ico_U64: value = con->Ico.U64; break;
1748 case Ico_U32: value = con->Ico.U32; break;
1749 case Ico_U16: value = con->Ico.U16; break;
1750 case Ico_U8: value = con->Ico.U8; break;
1751 default: vpanic("s390_isel_int_expr: invalid constant");
1752 }
1753
1754 addInstr(env, s390_insn_load_immediate(size, dst, value));
1755
1756 return dst;
1757 }
1758
1759 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00001760 case Iex_ITE: {
sewardj2019a972011-03-07 16:04:07 +00001761 IRExpr *cond_expr;
florian99dd03e2013-01-29 03:56:06 +00001762 HReg dst, r1;
sewardj009230b2013-01-26 11:47:55 +00001763 s390_opnd_RMI r0;
sewardj2019a972011-03-07 16:04:07 +00001764
florian99dd03e2013-01-29 03:56:06 +00001765 cond_expr = expr->Iex.ITE.cond;
sewardj2019a972011-03-07 16:04:07 +00001766
sewardj009230b2013-01-26 11:47:55 +00001767 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
1768
sewardj2019a972011-03-07 16:04:07 +00001769 dst = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00001770 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
1771 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
1772 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
sewardj2019a972011-03-07 16:04:07 +00001773
sewardj009230b2013-01-26 11:47:55 +00001774 s390_cc_t cc = s390_isel_cc(env, cond_expr);
sewardj2019a972011-03-07 16:04:07 +00001775
florian99dd03e2013-01-29 03:56:06 +00001776 addInstr(env, s390_insn_move(size, dst, r1));
sewardj009230b2013-01-26 11:47:55 +00001777 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
sewardj2019a972011-03-07 16:04:07 +00001778 return dst;
1779 }
1780
1781 default:
1782 break;
1783 }
1784
1785 /* We get here if no pattern matched. */
1786 irreducible:
1787 ppIRExpr(expr);
1788 vpanic("s390_isel_int_expr: cannot reduce tree");
1789}
1790
1791
1792static HReg
1793s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1794{
1795 HReg dst = s390_isel_int_expr_wrk(env, expr);
1796
1797 /* Sanity checks ... */
1798 vassert(hregClass(dst) == HRcInt64);
1799 vassert(hregIsVirtual(dst));
1800
1801 return dst;
1802}
1803
1804
1805static s390_opnd_RMI
1806s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1807{
1808 IRType ty = typeOfIRExpr(env->type_env, expr);
1809 s390_opnd_RMI dst;
1810
1811 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1812 ty == Ity_I64);
1813
1814 if (expr->tag == Iex_Load) {
1815 dst.tag = S390_OPND_AMODE;
1816 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1817 } else if (expr->tag == Iex_Get) {
1818 dst.tag = S390_OPND_AMODE;
1819 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1820 } else if (expr->tag == Iex_Const) {
1821 ULong value;
1822
1823 /* The bit pattern for the value will be stored as is in the least
1824 significant bits of VALUE. */
1825 switch (expr->Iex.Const.con->tag) {
1826 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1827 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1828 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1829 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1830 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1831 default:
1832 vpanic("s390_isel_int_expr_RMI");
1833 }
1834
1835 dst.tag = S390_OPND_IMMEDIATE;
1836 dst.variant.imm = value;
1837 } else {
1838 dst.tag = S390_OPND_REG;
1839 dst.variant.reg = s390_isel_int_expr(env, expr);
1840 }
1841
1842 return dst;
1843}
1844
1845
1846/*---------------------------------------------------------*/
1847/*--- ISEL: Floating point expressions (128 bit) ---*/
1848/*---------------------------------------------------------*/
1849static void
1850s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1851 IRExpr *expr)
1852{
1853 IRType ty = typeOfIRExpr(env->type_env, expr);
1854
1855 vassert(ty == Ity_F128);
1856
sewardj2019a972011-03-07 16:04:07 +00001857 switch (expr->tag) {
1858 case Iex_RdTmp:
1859 /* Return the virtual registers that hold the temporary. */
1860 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1861 return;
1862
1863 /* --------- LOAD --------- */
1864 case Iex_Load: {
1865 IRExpr *addr_hi, *addr_lo;
1866 s390_amode *am_hi, *am_lo;
1867
1868 if (expr->Iex.Load.end != Iend_BE)
1869 goto irreducible;
1870
1871 addr_hi = expr->Iex.Load.addr;
1872 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1873
1874 am_hi = s390_isel_amode(env, addr_hi);
1875 am_lo = s390_isel_amode(env, addr_lo);
1876
1877 *dst_hi = newVRegF(env);
1878 *dst_lo = newVRegF(env);
1879 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1880 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1881 return;
1882 }
1883
1884
1885 /* --------- GET --------- */
1886 case Iex_Get:
1887 /* This is not supported because loading 128-bit from the guest
1888 state is almost certainly wrong. Use get_fpr_pair instead. */
1889 vpanic("Iex_Get with F128 data");
1890
1891 /* --------- 4-ary OP --------- */
1892 case Iex_Qop:
1893 vpanic("Iex_Qop with F128 data");
1894
1895 /* --------- TERNARY OP --------- */
1896 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001897 IRTriop *triop = expr->Iex.Triop.details;
1898 IROp op = triop->op;
1899 IRExpr *left = triop->arg2;
1900 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001901 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001902 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1903
1904 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1905 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1906
1907 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1908 f12 = make_fpr(12);
1909 f13 = make_fpr(13);
1910 f14 = make_fpr(14);
1911 f15 = make_fpr(15);
1912
1913 /* 1st operand --> (f12, f14) */
1914 addInstr(env, s390_insn_move(8, f12, op1_hi));
1915 addInstr(env, s390_insn_move(8, f14, op1_lo));
1916
1917 /* 2nd operand --> (f13, f15) */
1918 addInstr(env, s390_insn_move(8, f13, op2_hi));
1919 addInstr(env, s390_insn_move(8, f15, op2_lo));
1920
1921 switch (op) {
1922 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1923 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1924 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1925 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1926 default:
1927 goto irreducible;
1928 }
1929
florian2c74d242012-09-12 19:38:42 +00001930 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1931 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001932
1933 /* Move result to virtual destination register */
1934 *dst_hi = newVRegF(env);
1935 *dst_lo = newVRegF(env);
1936 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1937 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1938
1939 return;
1940 }
1941
1942 /* --------- BINARY OP --------- */
1943 case Iex_Binop: {
1944 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001945
1946 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1947 f12 = make_fpr(12);
1948 f13 = make_fpr(13);
1949 f14 = make_fpr(14);
1950 f15 = make_fpr(15);
1951
1952 switch (expr->Iex.Binop.op) {
1953 case Iop_SqrtF128:
1954 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1955
1956 /* operand --> (f13, f15) */
1957 addInstr(env, s390_insn_move(8, f13, op_hi));
1958 addInstr(env, s390_insn_move(8, f15, op_lo));
1959
florian2c74d242012-09-12 19:38:42 +00001960 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1961 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1962 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001963
1964 /* Move result to virtual destination registers */
1965 *dst_hi = newVRegF(env);
1966 *dst_lo = newVRegF(env);
1967 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1968 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1969 return;
1970
1971 case Iop_F64HLtoF128:
1972 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1973 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1974 return;
1975
1976 default:
1977 goto irreducible;
1978 }
1979 }
1980
1981 /* --------- UNARY OP --------- */
1982 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001983 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001984 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00001985 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001986 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1987
1988 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1989 f12 = make_fpr(12);
1990 f13 = make_fpr(13);
1991 f14 = make_fpr(14);
1992 f15 = make_fpr(15);
1993
florian66e596d2012-09-07 15:00:53 +00001994 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001995 case Iop_NegF128:
1996 if (left->tag == Iex_Unop &&
1997 (left->Iex.Unop.op == Iop_AbsF32 ||
1998 left->Iex.Unop.op == Iop_AbsF64))
1999 bfpop = S390_BFP_NABS;
2000 else
2001 bfpop = S390_BFP_NEG;
2002 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00002003 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2004 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2005 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2006 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2007 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2008 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2009 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00002010 default:
2011 goto irreducible;
2012 }
2013
2014 float128_opnd:
2015 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2016
2017 /* operand --> (f13, f15) */
2018 addInstr(env, s390_insn_move(8, f13, op_hi));
2019 addInstr(env, s390_insn_move(8, f15, op_lo));
2020
florian2c74d242012-09-12 19:38:42 +00002021 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002022 goto move_dst;
2023
2024 convert_float:
2025 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002026 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002027 goto move_dst;
2028
2029 convert_int:
2030 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002031 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002032 goto move_dst;
2033
2034 move_dst:
2035 /* Move result to virtual destination registers */
2036 *dst_hi = newVRegF(env);
2037 *dst_lo = newVRegF(env);
2038 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2039 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2040 return;
2041 }
2042
2043 default:
2044 goto irreducible;
2045 }
2046
2047 /* We get here if no pattern matched. */
2048 irreducible:
2049 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002050 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002051}
2052
2053/* Compute a 128-bit value into two 64-bit registers. These may be either
2054 real or virtual regs; in any case they must not be changed by subsequent
2055 code emitted by the caller. */
2056static void
2057s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2058{
2059 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2060
2061 /* Sanity checks ... */
2062 vassert(hregIsVirtual(*dst_hi));
2063 vassert(hregIsVirtual(*dst_lo));
2064 vassert(hregClass(*dst_hi) == HRcFlt64);
2065 vassert(hregClass(*dst_lo) == HRcFlt64);
2066}
2067
2068
2069/*---------------------------------------------------------*/
2070/*--- ISEL: Floating point expressions (64 bit) ---*/
2071/*---------------------------------------------------------*/
2072
2073static HReg
2074s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2075{
2076 IRType ty = typeOfIRExpr(env->type_env, expr);
2077 UChar size;
2078
2079 vassert(ty == Ity_F32 || ty == Ity_F64);
2080
2081 size = sizeofIRType(ty);
2082
2083 switch (expr->tag) {
2084 case Iex_RdTmp:
2085 /* Return the virtual register that holds the temporary. */
2086 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2087
2088 /* --------- LOAD --------- */
2089 case Iex_Load: {
2090 HReg dst = newVRegF(env);
2091 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2092
2093 if (expr->Iex.Load.end != Iend_BE)
2094 goto irreducible;
2095
2096 addInstr(env, s390_insn_load(size, dst, am));
2097
2098 return dst;
2099 }
2100
2101 /* --------- GET --------- */
2102 case Iex_Get: {
2103 HReg dst = newVRegF(env);
2104 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2105
2106 addInstr(env, s390_insn_load(size, dst, am));
2107
2108 return dst;
2109 }
2110
2111 /* --------- LITERAL --------- */
2112
2113 /* Load a literal into a register. Create a "load immediate"
2114 v-insn and return the register. */
2115 case Iex_Const: {
2116 ULong value;
2117 HReg dst = newVRegF(env);
2118 const IRConst *con = expr->Iex.Const.con;
2119
2120 /* Bitwise copy of the value. No sign/zero-extension */
2121 switch (con->tag) {
2122 case Ico_F32i: value = con->Ico.F32i; break;
2123 case Ico_F64i: value = con->Ico.F64i; break;
2124 default: vpanic("s390_isel_float_expr: invalid constant");
2125 }
2126
2127 if (value != 0) vpanic("cannot load immediate floating point constant");
2128
2129 addInstr(env, s390_insn_load_immediate(size, dst, value));
2130
2131 return dst;
2132 }
2133
2134 /* --------- 4-ary OP --------- */
2135 case Iex_Qop: {
2136 HReg op1, op2, op3, dst;
2137 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002138
florian5906a6b2012-10-16 02:53:33 +00002139 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002140 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002141 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002142 dst = newVRegF(env);
2143 addInstr(env, s390_insn_move(size, dst, op1));
2144
florian96d7cc32012-06-01 20:41:24 +00002145 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002146 case Iop_MAddF32:
2147 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2148 case Iop_MSubF32:
2149 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2150
2151 default:
2152 goto irreducible;
2153 }
2154
florian2c74d242012-09-12 19:38:42 +00002155 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2156 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002157 return dst;
2158 }
2159
2160 /* --------- TERNARY OP --------- */
2161 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002162 IRTriop *triop = expr->Iex.Triop.details;
2163 IROp op = triop->op;
2164 IRExpr *left = triop->arg2;
2165 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002166 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002167 HReg h1, op2, dst;
2168
2169 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2170 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2171 dst = newVRegF(env);
2172 addInstr(env, s390_insn_move(size, dst, h1));
2173 switch (op) {
2174 case Iop_AddF32:
2175 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2176 case Iop_SubF32:
2177 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2178 case Iop_MulF32:
2179 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2180 case Iop_DivF32:
2181 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2182
2183 default:
2184 goto irreducible;
2185 }
2186
florian2c74d242012-09-12 19:38:42 +00002187 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2188 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002189 return dst;
2190 }
2191
2192 /* --------- BINARY OP --------- */
2193 case Iex_Binop: {
2194 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002195 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002196 IRExpr *left = expr->Iex.Binop.arg2;
2197 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002198 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002199
2200 switch (op) {
2201 case Iop_SqrtF32:
2202 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002203 h1 = s390_isel_float_expr(env, left);
2204 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002205 set_bfp_rounding_mode_in_fpc(env, irrm);
2206 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002207 return dst;
sewardj2019a972011-03-07 16:04:07 +00002208
florian9fcff4c2012-09-10 03:09:04 +00002209 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2210 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2211 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2212 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2213 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2214 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2215 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002216
florian9fcff4c2012-09-10 03:09:04 +00002217 convert_float:
2218 h1 = s390_isel_float_expr(env, left);
2219 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002220
florian9fcff4c2012-09-10 03:09:04 +00002221 convert_int:
2222 h1 = s390_isel_int_expr(env, left);
2223 goto convert;
2224
florian2c74d242012-09-12 19:38:42 +00002225 convert: {
florian125e20d2012-10-07 15:42:37 +00002226 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002227 /* convert-from-fixed and load-rounded have a rounding mode field
2228 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002229 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002230 if (s390_host_has_fpext) {
2231 rounding_mode = get_bfp_rounding_mode(env, irrm);
2232 } else {
2233 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002234 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002235 }
florian9fcff4c2012-09-10 03:09:04 +00002236 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2237 rounding_mode));
2238 return dst;
florian2c74d242012-09-12 19:38:42 +00002239 }
florian9fcff4c2012-09-10 03:09:04 +00002240
sewardj2019a972011-03-07 16:04:07 +00002241 default:
2242 goto irreducible;
2243
2244 case Iop_F128toF64:
2245 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002246 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002247 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002248
florian9fcff4c2012-09-10 03:09:04 +00002249 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2250 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002251
florian9fcff4c2012-09-10 03:09:04 +00002252 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002253
florian9fcff4c2012-09-10 03:09:04 +00002254 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002255 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002256 f15 = make_fpr(15);
2257
2258 /* operand --> (f13, f15) */
2259 addInstr(env, s390_insn_move(8, f13, op_hi));
2260 addInstr(env, s390_insn_move(8, f15, op_lo));
2261
2262 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002263 /* load-rounded has a rounding mode field when the floating point
2264 extension facility is installed. */
2265 if (s390_host_has_fpext) {
2266 rounding_mode = get_bfp_rounding_mode(env, irrm);
2267 } else {
2268 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002269 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002270 }
floriancc491a62012-09-10 23:44:37 +00002271 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002272 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002273 return dst;
2274 }
2275 }
sewardj2019a972011-03-07 16:04:07 +00002276 }
2277
2278 /* --------- UNARY OP --------- */
2279 case Iex_Unop: {
2280 IROp op = expr->Iex.Unop.op;
2281 IRExpr *left = expr->Iex.Unop.arg;
2282 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002283 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002284 HReg h1, dst;
2285
2286 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2287 HReg dst_hi, dst_lo;
2288
2289 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2290 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2291 }
2292
florian4d71a082011-12-18 00:08:17 +00002293 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002294 dst = newVRegF(env);
2295 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2296 addInstr(env, s390_insn_move(size, dst, h1));
2297
2298 return dst;
2299 }
2300
2301 switch (op) {
2302 case Iop_NegF32:
2303 case Iop_NegF64:
2304 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002305 (left->Iex.Unop.op == Iop_AbsF32 ||
2306 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002307 bfpop = S390_BFP_NABS;
2308 else
2309 bfpop = S390_BFP_NEG;
2310 break;
2311
2312 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002313 case Iop_AbsF64:
2314 bfpop = S390_BFP_ABS;
2315 break;
2316
2317 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2318 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2319 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2320
2321 convert_float1:
2322 h1 = s390_isel_float_expr(env, left);
2323 goto convert1;
2324
2325 convert_int1:
2326 h1 = s390_isel_int_expr(env, left);
2327 goto convert1;
2328
2329 convert1:
2330 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002331 /* No rounding mode is needed for these conversions. Just stick
2332 one in. It won't be used later on. */
2333 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002334 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002335 return dst;
2336
sewardj2019a972011-03-07 16:04:07 +00002337 default:
2338 goto irreducible;
2339 }
2340
2341 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002342 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002343 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002344 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002345 return dst;
2346 }
2347
2348 default:
2349 goto irreducible;
2350 }
2351
2352 /* We get here if no pattern matched. */
2353 irreducible:
2354 ppIRExpr(expr);
2355 vpanic("s390_isel_float_expr: cannot reduce tree");
2356}
2357
2358
2359static HReg
2360s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2361{
2362 HReg dst = s390_isel_float_expr_wrk(env, expr);
2363
2364 /* Sanity checks ... */
2365 vassert(hregClass(dst) == HRcFlt64);
2366 vassert(hregIsVirtual(dst));
2367
2368 return dst;
2369}
2370
2371
2372/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002373/*--- ISEL: Decimal point expressions (128 bit) ---*/
2374/*---------------------------------------------------------*/
2375static void
2376s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2377 IRExpr *expr)
2378{
2379 IRType ty = typeOfIRExpr(env->type_env, expr);
2380
2381 vassert(ty == Ity_D128);
2382
2383 switch (expr->tag) {
2384 case Iex_RdTmp:
2385 /* Return the virtual registers that hold the temporary. */
2386 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2387 return;
2388
2389 /* --------- LOAD --------- */
2390 case Iex_Load: {
2391 IRExpr *addr_hi, *addr_lo;
2392 s390_amode *am_hi, *am_lo;
2393
2394 if (expr->Iex.Load.end != Iend_BE)
2395 goto irreducible;
2396
2397 addr_hi = expr->Iex.Load.addr;
2398 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2399
2400 am_hi = s390_isel_amode(env, addr_hi);
2401 am_lo = s390_isel_amode(env, addr_lo);
2402
2403 *dst_hi = newVRegF(env);
2404 *dst_lo = newVRegF(env);
2405 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2406 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2407 return;
2408 }
2409
2410 /* --------- GET --------- */
2411 case Iex_Get:
2412 /* This is not supported because loading 128-bit from the guest
2413 state is almost certainly wrong. Use get_dpr_pair instead. */
2414 vpanic("Iex_Get with D128 data");
2415
2416 /* --------- 4-ary OP --------- */
2417 case Iex_Qop:
2418 vpanic("Iex_Qop with D128 data");
2419
2420 /* --------- TERNARY OP --------- */
2421 case Iex_Triop: {
2422 IRTriop *triop = expr->Iex.Triop.details;
2423 IROp op = triop->op;
2424 IRExpr *irrm = triop->arg1;
2425 IRExpr *left = triop->arg2;
2426 IRExpr *right = triop->arg3;
2427 s390_dfp_round_t rounding_mode;
2428 s390_dfp_binop_t dfpop;
2429 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2430
floriane38f6412012-12-21 17:32:12 +00002431 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2432 (f12, f14) as op2 and (f13, f15) as destination) */
2433 f9 = make_fpr(9);
2434 f11 = make_fpr(11);
2435 f12 = make_fpr(12);
2436 f13 = make_fpr(13);
2437 f14 = make_fpr(14);
2438 f15 = make_fpr(15);
2439
floriane38f6412012-12-21 17:32:12 +00002440 switch (op) {
florian5c539732013-02-14 14:27:12 +00002441 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128;
2442 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128;
2443 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128;
2444 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128;
2445 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
2446
2447 evaluate_dfp128: {
2448 /* Process 1st operand */
2449 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
2450 /* 1st operand --> (f9, f11) */
2451 addInstr(env, s390_insn_move(8, f9, op1_hi));
2452 addInstr(env, s390_insn_move(8, f11, op1_lo));
2453
2454 /* Process 2nd operand */
2455 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2456 /* 2nd operand --> (f12, f14) */
2457 addInstr(env, s390_insn_move(8, f12, op2_hi));
2458 addInstr(env, s390_insn_move(8, f14, op2_lo));
2459
2460 /* DFP arithmetic ops take rounding mode only when fpext is
2461 installed. But, DFP quantize operation takes rm irrespective
2462 of fpext facility . */
floriand18287d2013-02-21 03:03:05 +00002463 if (s390_host_has_fpext || op == Iop_QuantizeD128) {
florian5c539732013-02-14 14:27:12 +00002464 rounding_mode = get_dfp_rounding_mode(env, irrm);
2465 } else {
2466 set_dfp_rounding_mode_in_fpc(env, irrm);
2467 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2468 }
2469 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2470 f12, f14, rounding_mode));
2471 /* Move result to virtual destination register */
2472 *dst_hi = newVRegF(env);
2473 *dst_lo = newVRegF(env);
2474 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2475 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2476 return;
2477 }
2478
2479 case Iop_SignificanceRoundD128: {
2480 /* Process 1st operand */
2481 HReg op1 = s390_isel_int_expr(env, left);
2482 /* Process 2nd operand */
2483 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2484 /* 2nd operand --> (f12, f14) */
2485 addInstr(env, s390_insn_move(8, f12, op2_hi));
2486 addInstr(env, s390_insn_move(8, f14, op2_lo));
2487
2488 rounding_mode = get_dfp_rounding_mode(env, irrm);
2489 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14,
2490 rounding_mode));
2491 /* Move result to virtual destination register */
2492 *dst_hi = newVRegF(env);
2493 *dst_lo = newVRegF(env);
2494 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2495 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2496 return;
2497 }
2498
floriane38f6412012-12-21 17:32:12 +00002499 default:
2500 goto irreducible;
2501 }
floriane38f6412012-12-21 17:32:12 +00002502 }
2503
2504 /* --------- BINARY OP --------- */
2505 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002506
floriane38f6412012-12-21 17:32:12 +00002507 switch (expr->Iex.Binop.op) {
2508 case Iop_D64HLtoD128:
2509 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2510 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2511 return;
2512
florian1b901d42013-01-01 22:19:24 +00002513 case Iop_ShlD128:
florian5c539732013-02-14 14:27:12 +00002514 case Iop_ShrD128:
2515 case Iop_InsertExpD128: {
florian1b901d42013-01-01 22:19:24 +00002516 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2517 s390_dfp_intop_t intop;
florian5c539732013-02-14 14:27:12 +00002518 IRExpr *dfp_op;
2519 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00002520
2521 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00002522 case Iop_ShlD128: /* (D128, I64) -> D128 */
2523 intop = S390_DFP_SHIFT_LEFT;
2524 dfp_op = expr->Iex.Binop.arg1;
2525 int_op = expr->Iex.Binop.arg2;
2526 break;
2527 case Iop_ShrD128: /* (D128, I64) -> D128 */
2528 intop = S390_DFP_SHIFT_RIGHT;
2529 dfp_op = expr->Iex.Binop.arg1;
2530 int_op = expr->Iex.Binop.arg2;
2531 break;
2532 case Iop_InsertExpD128: /* (I64, D128) -> D128 */
2533 intop = S390_DFP_INSERT_EXP;
2534 int_op = expr->Iex.Binop.arg1;
2535 dfp_op = expr->Iex.Binop.arg2;
2536 break;
florian1b901d42013-01-01 22:19:24 +00002537 default: goto irreducible;
2538 }
2539
2540 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2541 f9 = make_fpr(9); /* 128 bit dfp operand */
2542 f11 = make_fpr(11);
2543
2544 f13 = make_fpr(13); /* 128 bit dfp destination */
2545 f15 = make_fpr(15);
2546
florian5c539732013-02-14 14:27:12 +00002547 /* Process dfp operand */
2548 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
2549 /* op1 -> (f9,f11) */
florian1b901d42013-01-01 22:19:24 +00002550 addInstr(env, s390_insn_move(8, f9, op1_hi));
2551 addInstr(env, s390_insn_move(8, f11, op1_lo));
2552
florian5c539732013-02-14 14:27:12 +00002553 op2 = s390_isel_int_expr(env, int_op); /* int operand */
florian1b901d42013-01-01 22:19:24 +00002554
2555 addInstr(env,
2556 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2557
2558 /* Move result to virtual destination register */
2559 *dst_hi = newVRegF(env);
2560 *dst_lo = newVRegF(env);
2561 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2562 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2563 return;
2564 }
2565
floriane38f6412012-12-21 17:32:12 +00002566 default:
2567 goto irreducible;
2568 }
2569 }
2570
2571 /* --------- UNARY OP --------- */
2572 case Iex_Unop: {
2573 IRExpr *left = expr->Iex.Unop.arg;
2574 s390_dfp_conv_t conv;
floriane38f6412012-12-21 17:32:12 +00002575 HReg op, f12, f14;
2576
floriana887acd2013-02-08 23:32:54 +00002577 /* We use non-virtual registers as pairs (f12, f14)) */
floriane38f6412012-12-21 17:32:12 +00002578 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00002579 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00002580
2581 switch (expr->Iex.Unop.op) {
2582 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002583 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
floriana887acd2013-02-08 23:32:54 +00002584 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002585 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2586 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002587 default:
2588 goto irreducible;
2589 }
2590
2591 convert_dfp:
2592 op = s390_isel_dfp_expr(env, left);
2593 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2594 goto move_dst;
2595
florian5f034622013-01-13 02:29:05 +00002596 convert_int:
2597 op = s390_isel_int_expr(env, left);
2598 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2599 goto move_dst;
2600
floriane38f6412012-12-21 17:32:12 +00002601 move_dst:
2602 /* Move result to virtual destination registers */
2603 *dst_hi = newVRegF(env);
2604 *dst_lo = newVRegF(env);
2605 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2606 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2607 return;
2608 }
2609
2610 default:
2611 goto irreducible;
2612 }
2613
2614 /* We get here if no pattern matched. */
2615 irreducible:
2616 ppIRExpr(expr);
2617 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2618
2619}
2620
2621
2622/* Compute a 128-bit value into two 64-bit registers. These may be either
2623 real or virtual regs; in any case they must not be changed by subsequent
2624 code emitted by the caller. */
2625static void
2626s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2627{
2628 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2629
2630 /* Sanity checks ... */
2631 vassert(hregIsVirtual(*dst_hi));
2632 vassert(hregIsVirtual(*dst_lo));
2633 vassert(hregClass(*dst_hi) == HRcFlt64);
2634 vassert(hregClass(*dst_lo) == HRcFlt64);
2635}
2636
2637
2638/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002639/*--- ISEL: Decimal point expressions (64 bit) ---*/
2640/*---------------------------------------------------------*/
2641
2642static HReg
2643s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2644{
2645 IRType ty = typeOfIRExpr(env->type_env, expr);
2646 UChar size;
2647
floriane38f6412012-12-21 17:32:12 +00002648 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002649
2650 size = sizeofIRType(ty);
2651
2652 switch (expr->tag) {
2653 case Iex_RdTmp:
2654 /* Return the virtual register that holds the temporary. */
2655 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2656
2657 /* --------- LOAD --------- */
2658 case Iex_Load: {
2659 HReg dst = newVRegF(env);
2660 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2661
2662 if (expr->Iex.Load.end != Iend_BE)
2663 goto irreducible;
2664
2665 addInstr(env, s390_insn_load(size, dst, am));
2666
2667 return dst;
2668 }
2669
2670 /* --------- GET --------- */
2671 case Iex_Get: {
2672 HReg dst = newVRegF(env);
2673 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2674
2675 addInstr(env, s390_insn_load(size, dst, am));
2676
2677 return dst;
2678 }
2679
floriane38f6412012-12-21 17:32:12 +00002680 /* --------- BINARY OP --------- */
2681 case Iex_Binop: {
2682 IROp op = expr->Iex.Binop.op;
2683 IRExpr *irrm = expr->Iex.Binop.arg1;
2684 IRExpr *left = expr->Iex.Binop.arg2;
2685 HReg h1, dst;
2686 s390_dfp_conv_t conv;
2687
2688 switch (op) {
2689 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
floriana887acd2013-02-08 23:32:54 +00002690 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002691 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002692
2693 convert_dfp:
2694 h1 = s390_isel_dfp_expr(env, left);
2695 goto convert;
2696
florian5f034622013-01-13 02:29:05 +00002697 convert_int:
2698 h1 = s390_isel_int_expr(env, left);
2699 goto convert;
2700
floriane38f6412012-12-21 17:32:12 +00002701 convert: {
2702 s390_dfp_round_t rounding_mode;
2703 /* convert-from-fixed and load-rounded have a rounding mode field
2704 when the floating point extension facility is installed. */
2705 dst = newVRegF(env);
2706 if (s390_host_has_fpext) {
2707 rounding_mode = get_dfp_rounding_mode(env, irrm);
2708 } else {
2709 set_dfp_rounding_mode_in_fpc(env, irrm);
2710 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2711 }
2712 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2713 rounding_mode));
2714 return dst;
2715 }
floriane38f6412012-12-21 17:32:12 +00002716
2717 case Iop_D128toD64: {
2718 HReg op_hi, op_lo, f13, f15;
2719 s390_dfp_round_t rounding_mode;
2720
2721 conv = S390_DFP_D128_TO_D64;
2722
2723 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2724
2725 /* We use non-virtual registers as pairs (f13, f15) */
2726 f13 = make_fpr(13);
2727 f15 = make_fpr(15);
2728
2729 /* operand --> (f13, f15) */
2730 addInstr(env, s390_insn_move(8, f13, op_hi));
2731 addInstr(env, s390_insn_move(8, f15, op_lo));
2732
2733 dst = newVRegF(env);
2734 /* load-rounded has a rounding mode field when the floating point
2735 extension facility is installed. */
2736 if (s390_host_has_fpext) {
2737 rounding_mode = get_dfp_rounding_mode(env, irrm);
2738 } else {
2739 set_dfp_rounding_mode_in_fpc(env, irrm);
2740 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2741 }
2742 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2743 rounding_mode));
2744 return dst;
2745 }
2746
florian1b901d42013-01-01 22:19:24 +00002747 case Iop_ShlD64:
florian5c539732013-02-14 14:27:12 +00002748 case Iop_ShrD64:
2749 case Iop_InsertExpD64: {
florian1b901d42013-01-01 22:19:24 +00002750 HReg op2;
2751 HReg op3;
florian5c539732013-02-14 14:27:12 +00002752 IRExpr *dfp_op;
2753 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00002754 s390_dfp_intop_t intop;
florian1b901d42013-01-01 22:19:24 +00002755
2756 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00002757 case Iop_ShlD64: /* (D64, I64) -> D64 */
2758 intop = S390_DFP_SHIFT_LEFT;
2759 dfp_op = expr->Iex.Binop.arg1;
2760 int_op = expr->Iex.Binop.arg2;
2761 break;
2762 case Iop_ShrD64: /* (D64, I64) -> D64 */
2763 intop = S390_DFP_SHIFT_RIGHT;
2764 dfp_op = expr->Iex.Binop.arg1;
2765 int_op = expr->Iex.Binop.arg2;
2766 break;
2767 case Iop_InsertExpD64: /* (I64, D64) -> D64 */
2768 intop = S390_DFP_INSERT_EXP;
2769 int_op = expr->Iex.Binop.arg1;
2770 dfp_op = expr->Iex.Binop.arg2;
2771 break;
florian1b901d42013-01-01 22:19:24 +00002772 default: goto irreducible;
2773 }
2774
florian5c539732013-02-14 14:27:12 +00002775 op2 = s390_isel_int_expr(env, int_op);
2776 op3 = s390_isel_dfp_expr(env, dfp_op);
florian1b901d42013-01-01 22:19:24 +00002777 dst = newVRegF(env);
2778
2779 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
2780 return dst;
2781 }
2782
2783 default:
2784 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00002785 }
2786 }
2787
2788 /* --------- UNARY OP --------- */
2789 case Iex_Unop: {
2790 IROp op = expr->Iex.Unop.op;
2791 IRExpr *left = expr->Iex.Unop.arg;
2792 s390_dfp_conv_t conv;
2793 HReg h1, dst;
2794
2795 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2796 HReg dst_hi, dst_lo;
2797
2798 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2799 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2800 }
2801
2802 if (op == Iop_ReinterpI64asD64) {
2803 dst = newVRegF(env);
2804 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2805 addInstr(env, s390_insn_move(size, dst, h1));
2806
2807 return dst;
2808 }
2809
2810 switch (op) {
2811 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00002812 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
2813 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00002814
2815 convert_dfp1:
2816 h1 = s390_isel_dfp_expr(env, left);
2817 goto convert1;
2818
florian5f034622013-01-13 02:29:05 +00002819 convert_int1:
2820 h1 = s390_isel_int_expr(env, left);
2821 goto convert1;
2822
floriane38f6412012-12-21 17:32:12 +00002823 convert1:
2824 dst = newVRegF(env);
2825 /* No rounding mode is needed for these conversions. Just stick
2826 one in. It won't be used later on. */
2827 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2828 S390_DFP_ROUND_NEAREST_EVEN_4));
2829 return dst;
2830
2831 default:
2832 goto irreducible;
2833 }
2834 }
2835
florian12390202012-11-10 22:34:14 +00002836 /* --------- TERNARY OP --------- */
2837 case Iex_Triop: {
2838 IRTriop *triop = expr->Iex.Triop.details;
2839 IROp op = triop->op;
2840 IRExpr *irrm = triop->arg1;
2841 IRExpr *left = triop->arg2;
2842 IRExpr *right = triop->arg3;
2843 s390_dfp_round_t rounding_mode;
2844 s390_dfp_binop_t dfpop;
2845 HReg op2, op3, dst;
2846
florian12390202012-11-10 22:34:14 +00002847 switch (op) {
florian5c539732013-02-14 14:27:12 +00002848 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp;
2849 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp;
2850 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp;
2851 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp;
2852 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
2853
2854 evaluate_dfp: {
2855 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2856 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2857 dst = newVRegF(env);
2858 /* DFP arithmetic ops take rounding mode only when fpext is
2859 installed. But, DFP quantize operation takes rm irrespective
2860 of fpext facility . */
2861 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
2862 rounding_mode = get_dfp_rounding_mode(env, irrm);
2863 } else {
2864 set_dfp_rounding_mode_in_fpc(env, irrm);
2865 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2866 }
2867 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3,
2868 rounding_mode));
2869 return dst;
2870 }
2871
2872 case Iop_SignificanceRoundD64:
2873 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */
2874 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2875 dst = newVRegF(env);
2876 rounding_mode = get_dfp_rounding_mode(env, irrm);
2877 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3,
2878 rounding_mode));
2879 return dst;
2880
florian12390202012-11-10 22:34:14 +00002881 default:
2882 goto irreducible;
2883 }
florian12390202012-11-10 22:34:14 +00002884 }
2885
2886 default:
2887 goto irreducible;
2888 }
2889
2890 /* We get here if no pattern matched. */
2891 irreducible:
2892 ppIRExpr(expr);
2893 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2894}
2895
2896static HReg
2897s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2898{
2899 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2900
2901 /* Sanity checks ... */
2902 vassert(hregClass(dst) == HRcFlt64);
2903 vassert(hregIsVirtual(dst));
2904
2905 return dst;
2906}
2907
2908
2909/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002910/*--- ISEL: Condition Code ---*/
2911/*---------------------------------------------------------*/
2912
2913/* This function handles all operators that produce a 1-bit result */
2914static s390_cc_t
2915s390_isel_cc(ISelEnv *env, IRExpr *cond)
2916{
2917 UChar size;
2918
2919 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2920
2921 /* Constant: either 1 or 0 */
2922 if (cond->tag == Iex_Const) {
2923 vassert(cond->Iex.Const.con->tag == Ico_U1);
2924 vassert(cond->Iex.Const.con->Ico.U1 == True
2925 || cond->Iex.Const.con->Ico.U1 == False);
2926
2927 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2928 }
2929
2930 /* Variable: values are 1 or 0 */
2931 if (cond->tag == Iex_RdTmp) {
2932 IRTemp tmp = cond->Iex.RdTmp.tmp;
2933 HReg reg = lookupIRTemp(env, tmp);
2934
2935 /* Load-and-test does not modify REG; so this is OK. */
2936 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2937 size = 4;
2938 else
2939 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2940 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2941 return S390_CC_NE;
2942 }
2943
2944 /* Unary operators */
2945 if (cond->tag == Iex_Unop) {
2946 IRExpr *arg = cond->Iex.Unop.arg;
2947
2948 switch (cond->Iex.Unop.op) {
2949 case Iop_Not1: /* Not1(cond) */
2950 /* Generate code for EXPR, and negate the test condition */
2951 return s390_cc_invert(s390_isel_cc(env, arg));
2952
2953 /* Iop_32/64to1 select the LSB from their operand */
2954 case Iop_32to1:
2955 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002956 HReg dst = newVRegI(env);
2957 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002958
2959 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2960
florianf366a802012-08-03 00:42:18 +00002961 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002962 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2963 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2964 return S390_CC_NE;
2965 }
2966
2967 case Iop_CmpNEZ8:
2968 case Iop_CmpNEZ16: {
2969 s390_opnd_RMI src;
2970 s390_unop_t op;
2971 HReg dst;
2972
2973 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2974 : S390_ZERO_EXTEND_16;
2975 dst = newVRegI(env);
2976 src = s390_isel_int_expr_RMI(env, arg);
2977 addInstr(env, s390_insn_unop(4, op, dst, src));
2978 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2979 return S390_CC_NE;
2980 }
2981
2982 case Iop_CmpNEZ32:
2983 case Iop_CmpNEZ64: {
2984 s390_opnd_RMI src;
2985
2986 src = s390_isel_int_expr_RMI(env, arg);
2987 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2988 addInstr(env, s390_insn_test(size, src));
2989 return S390_CC_NE;
2990 }
2991
2992 default:
2993 goto fail;
2994 }
2995 }
2996
2997 /* Binary operators */
2998 if (cond->tag == Iex_Binop) {
2999 IRExpr *arg1 = cond->Iex.Binop.arg1;
3000 IRExpr *arg2 = cond->Iex.Binop.arg2;
3001 HReg reg1, reg2;
3002
3003 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
3004
3005 switch (cond->Iex.Binop.op) {
3006 s390_unop_t op;
3007 s390_cc_t result;
3008
3009 case Iop_CmpEQ8:
3010 case Iop_CasCmpEQ8:
3011 op = S390_ZERO_EXTEND_8;
3012 result = S390_CC_E;
3013 goto do_compare_ze;
3014
3015 case Iop_CmpNE8:
3016 case Iop_CasCmpNE8:
3017 op = S390_ZERO_EXTEND_8;
3018 result = S390_CC_NE;
3019 goto do_compare_ze;
3020
3021 case Iop_CmpEQ16:
3022 case Iop_CasCmpEQ16:
3023 op = S390_ZERO_EXTEND_16;
3024 result = S390_CC_E;
3025 goto do_compare_ze;
3026
3027 case Iop_CmpNE16:
3028 case Iop_CasCmpNE16:
3029 op = S390_ZERO_EXTEND_16;
3030 result = S390_CC_NE;
3031 goto do_compare_ze;
3032
3033 do_compare_ze: {
3034 s390_opnd_RMI op1, op2;
3035
3036 op1 = s390_isel_int_expr_RMI(env, arg1);
3037 reg1 = newVRegI(env);
3038 addInstr(env, s390_insn_unop(4, op, reg1, op1));
3039
3040 op2 = s390_isel_int_expr_RMI(env, arg2);
3041 reg2 = newVRegI(env);
3042 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
3043
3044 op2 = s390_opnd_reg(reg2);
3045 addInstr(env, s390_insn_compare(4, reg1, op2, False));
3046
3047 return result;
3048 }
3049
3050 case Iop_CmpEQ32:
3051 case Iop_CmpEQ64:
3052 case Iop_CasCmpEQ32:
3053 case Iop_CasCmpEQ64:
3054 result = S390_CC_E;
3055 goto do_compare;
3056
3057 case Iop_CmpNE32:
3058 case Iop_CmpNE64:
3059 case Iop_CasCmpNE32:
3060 case Iop_CasCmpNE64:
3061 result = S390_CC_NE;
3062 goto do_compare;
3063
3064 do_compare: {
3065 HReg op1;
3066 s390_opnd_RMI op2;
3067
3068 order_commutative_operands(arg1, arg2);
3069
3070 op1 = s390_isel_int_expr(env, arg1);
3071 op2 = s390_isel_int_expr_RMI(env, arg2);
3072
3073 addInstr(env, s390_insn_compare(size, op1, op2, False));
3074
3075 return result;
3076 }
3077
3078 case Iop_CmpLT32S:
3079 case Iop_CmpLE32S:
3080 case Iop_CmpLT64S:
3081 case Iop_CmpLE64S: {
3082 HReg op1;
3083 s390_opnd_RMI op2;
3084
3085 op1 = s390_isel_int_expr(env, arg1);
3086 op2 = s390_isel_int_expr_RMI(env, arg2);
3087
3088 addInstr(env, s390_insn_compare(size, op1, op2, True));
3089
3090 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3091 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3092 }
3093
3094 case Iop_CmpLT32U:
3095 case Iop_CmpLE32U:
3096 case Iop_CmpLT64U:
3097 case Iop_CmpLE64U: {
3098 HReg op1;
3099 s390_opnd_RMI op2;
3100
3101 op1 = s390_isel_int_expr(env, arg1);
3102 op2 = s390_isel_int_expr_RMI(env, arg2);
3103
3104 addInstr(env, s390_insn_compare(size, op1, op2, False));
3105
3106 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3107 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3108 }
3109
3110 default:
3111 goto fail;
3112 }
3113 }
3114
3115 fail:
3116 ppIRExpr(cond);
3117 vpanic("s390_isel_cc: unexpected operator");
3118}
3119
3120
3121/*---------------------------------------------------------*/
3122/*--- ISEL: Statements ---*/
3123/*---------------------------------------------------------*/
3124
3125static void
3126s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3127{
3128 if (vex_traceflags & VEX_TRACE_VCODE) {
3129 vex_printf("\n -- ");
3130 ppIRStmt(stmt);
3131 vex_printf("\n");
3132 }
3133
3134 switch (stmt->tag) {
3135
3136 /* --------- STORE --------- */
3137 case Ist_Store: {
3138 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3139 s390_amode *am;
3140 HReg src;
3141
3142 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3143
3144 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3145
3146 switch (tyd) {
3147 case Ity_I8:
3148 case Ity_I16:
3149 case Ity_I32:
3150 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003151 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003152 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003153 stmt->Ist.Store.data->tag == Iex_Const) {
3154 ULong value =
3155 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3156 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003157 return;
3158 }
floriancec3a8a2013-02-02 00:16:58 +00003159 /* Check whether we can use a memcpy here. Currently, the restriction
3160 is that both amodes need to be B12, so MVC can be emitted.
3161 We do not consider a store whose data expression is a load because
3162 we don't want to deal with overlapping locations. */
3163 /* store(get) never overlaps*/
3164 if (am->tag == S390_AMODE_B12 &&
3165 stmt->Ist.Store.data->tag == Iex_Get) {
3166 UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
3167 s390_amode *from = s390_amode_for_guest_state(offset);
3168 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
3169 return;
3170 }
3171 /* General case: compile data into a register */
sewardj2019a972011-03-07 16:04:07 +00003172 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3173 break;
3174
3175 case Ity_F32:
3176 case Ity_F64:
3177 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3178 break;
3179
florianeb981ae2012-12-21 18:55:03 +00003180 case Ity_D32:
3181 case Ity_D64:
3182 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3183 break;
3184
sewardj2019a972011-03-07 16:04:07 +00003185 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003186 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003187 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003188 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003189
3190 default:
3191 goto stmt_fail;
3192 }
3193
3194 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3195 return;
3196 }
3197
3198 /* --------- PUT --------- */
3199 case Ist_Put: {
3200 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3201 HReg src;
3202 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003203 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003204
florianad43b3a2012-02-20 15:01:14 +00003205 /* Detect updates to certain guest registers. We track the contents
3206 of those registers as long as they contain constants. If the new
3207 constant is either zero or in the 8-bit neighbourhood of the
3208 current value we can use a memory-to-memory insn to do the update. */
3209
3210 Int offset = stmt->Ist.Put.offset;
3211
3212 /* Check necessary conditions:
3213 (1) must be one of the registers we care about
3214 (2) assigned value must be a constant */
3215 Int guest_reg = get_guest_reg(offset);
3216
3217 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3218
florianad43b3a2012-02-20 15:01:14 +00003219 if (stmt->Ist.Put.data->tag != Iex_Const) {
3220 /* Invalidate guest register contents */
3221 env->old_value_valid[guest_reg] = False;
3222 goto not_special;
3223 }
3224
cborntraaf7ad282012-08-08 14:11:33 +00003225 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3226 if (tyd != Ity_I64)
3227 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003228
cborntraaf7ad282012-08-08 14:11:33 +00003229 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003230
3231 old_value = env->old_value[guest_reg];
3232 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3233 env->old_value[guest_reg] = new_value;
3234
3235 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3236 env->old_value_valid[guest_reg] = True;
3237
3238 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003239 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003240 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003241 return;
florianad43b3a2012-02-20 15:01:14 +00003242 }
3243
florianad43b3a2012-02-20 15:01:14 +00003244 if (old_value_is_valid == False) goto not_special;
3245
3246 /* If the new value is in the neighbourhood of the old value
3247 we can use a memory-to-memory insn */
3248 difference = new_value - old_value;
3249
3250 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003251 am = s390_amode_for_guest_state(offset);
3252 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003253 (difference & 0xFF), new_value));
3254 return;
3255 }
3256
florianb93348d2012-12-27 00:59:43 +00003257 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003258 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003259 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003260 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003261 return;
3262 }
3263
3264 /* No special case applies... fall through */
3265
3266 not_special:
florianb93348d2012-12-27 00:59:43 +00003267 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003268
3269 switch (tyd) {
3270 case Ity_I8:
3271 case Ity_I16:
3272 case Ity_I32:
3273 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003274 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003275 stmt->Ist.Put.data->tag == Iex_Const) {
3276 ULong value =
3277 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3278 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003279 return;
3280 }
floriancec3a8a2013-02-02 00:16:58 +00003281 /* Check whether we can use a memcpy here. Currently, the restriction
3282 is that both amodes need to be B12, so MVC can be emitted. */
3283 /* put(load) never overlaps */
3284 if (am->tag == S390_AMODE_B12 &&
3285 stmt->Ist.Put.data->tag == Iex_Load) {
3286 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
3287 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
3288 s390_amode *from = s390_isel_amode(env, data);
3289 UInt size = sizeofIRType(tyd);
3290
3291 if (from->tag == S390_AMODE_B12) {
3292 /* Source can be compiled into a B12 amode. */
3293 addInstr(env, s390_insn_memcpy(size, am, from));
3294 return;
3295 }
3296
3297 src = newVRegI(env);
3298 addInstr(env, s390_insn_load(size, src, from));
3299 break;
3300 }
3301 /* put(get) */
3302 if (am->tag == S390_AMODE_B12 &&
3303 stmt->Ist.Put.data->tag == Iex_Get) {
3304 UInt put_offset = am->d;
3305 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
3306 UInt size = sizeofIRType(tyd);
3307 /* don't memcpy in case of overlap */
3308 if (put_offset + size <= get_offset ||
3309 get_offset + size <= put_offset) {
3310 s390_amode *from = s390_amode_for_guest_state(get_offset);
3311 addInstr(env, s390_insn_memcpy(size, am, from));
3312 return;
3313 }
3314 goto no_memcpy_put;
3315 }
3316 /* General case: compile data into a register */
3317no_memcpy_put:
sewardj2019a972011-03-07 16:04:07 +00003318 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3319 break;
3320
3321 case Ity_F32:
3322 case Ity_F64:
3323 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3324 break;
3325
3326 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003327 case Ity_D128:
3328 /* Does not occur. See function put_(f|d)pr_pair. */
3329 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003330
floriane38f6412012-12-21 17:32:12 +00003331 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003332 case Ity_D64:
3333 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3334 break;
3335
sewardj2019a972011-03-07 16:04:07 +00003336 default:
3337 goto stmt_fail;
3338 }
3339
3340 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3341 return;
3342 }
3343
3344 /* --------- TMP --------- */
3345 case Ist_WrTmp: {
3346 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3347 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3348 HReg src, dst;
3349
3350 switch (tyd) {
3351 case Ity_I128: {
3352 HReg dst_hi, dst_lo, res_hi, res_lo;
3353
3354 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3355 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3356
3357 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3358 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3359 return;
3360 }
3361
3362 case Ity_I8:
3363 case Ity_I16:
3364 case Ity_I32:
3365 case Ity_I64:
3366 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3367 dst = lookupIRTemp(env, tmp);
3368 break;
3369
3370 case Ity_I1: {
3371 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3372 dst = lookupIRTemp(env, tmp);
3373 addInstr(env, s390_insn_cc2bool(dst, cond));
3374 return;
3375 }
3376
3377 case Ity_F32:
3378 case Ity_F64:
3379 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3380 dst = lookupIRTemp(env, tmp);
3381 break;
3382
3383 case Ity_F128: {
3384 HReg dst_hi, dst_lo, res_hi, res_lo;
3385
3386 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3387 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3388
3389 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3390 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3391 return;
3392 }
3393
floriane38f6412012-12-21 17:32:12 +00003394 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003395 case Ity_D64:
3396 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3397 dst = lookupIRTemp(env, tmp);
3398 break;
3399
floriane38f6412012-12-21 17:32:12 +00003400 case Ity_D128: {
3401 HReg dst_hi, dst_lo, res_hi, res_lo;
3402
3403 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3404 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3405
3406 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3407 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3408 return;
3409 }
3410
sewardj2019a972011-03-07 16:04:07 +00003411 default:
3412 goto stmt_fail;
3413 }
3414
3415 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3416 return;
3417 }
3418
3419 /* --------- Call to DIRTY helper --------- */
3420 case Ist_Dirty: {
3421 IRType retty;
3422 IRDirty* d = stmt->Ist.Dirty.details;
3423 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003424 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003425 Int i;
3426
3427 /* Invalidate tracked values of those guest state registers that are
3428 modified by this helper. */
3429 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003430 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3431 descriptors in guest state effect descriptions. Hence: */
3432 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003433 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3434 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3435 if (guest_reg != GUEST_UNKNOWN)
3436 env->old_value_valid[guest_reg] = False;
3437 }
3438 }
sewardj2019a972011-03-07 16:04:07 +00003439
3440 if (d->nFxState == 0)
3441 vassert(!d->needsBBP);
3442
3443 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3444
florian01ed6e72012-05-27 16:52:43 +00003445 if (d->tmp == IRTemp_INVALID) {
3446 /* No return value. */
3447 dst = INVALID_HREG;
3448 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003449 return;
florian01ed6e72012-05-27 16:52:43 +00003450 }
sewardj2019a972011-03-07 16:04:07 +00003451
3452 retty = typeOfIRTemp(env->type_env, d->tmp);
3453 if (retty == Ity_I64 || retty == Ity_I32
3454 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003455 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003456 dst = lookupIRTemp(env, d->tmp);
3457 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003458 return;
3459 }
3460 break;
3461 }
3462
3463 case Ist_CAS:
3464 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3465 IRCAS *cas = stmt->Ist.CAS.details;
3466 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3467 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3468 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3469 HReg old = lookupIRTemp(env, cas->oldLo);
3470
3471 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3472 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3473 } else {
3474 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3475 }
3476 return;
3477 } else {
florian448cbba2012-06-06 02:26:01 +00003478 IRCAS *cas = stmt->Ist.CAS.details;
3479 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3480 HReg r8, r9, r10, r11, r1;
3481 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3482 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3483 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3484 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3485 HReg old_low = lookupIRTemp(env, cas->oldLo);
3486 HReg old_high = lookupIRTemp(env, cas->oldHi);
3487
3488 /* Use non-virtual registers r8 and r9 as pair for op1
3489 and move op1 there */
3490 r8 = make_gpr(8);
3491 r9 = make_gpr(9);
3492 addInstr(env, s390_insn_move(8, r8, op1_high));
3493 addInstr(env, s390_insn_move(8, r9, op1_low));
3494
3495 /* Use non-virtual registers r10 and r11 as pair for op3
3496 and move op3 there */
3497 r10 = make_gpr(10);
3498 r11 = make_gpr(11);
3499 addInstr(env, s390_insn_move(8, r10, op3_high));
3500 addInstr(env, s390_insn_move(8, r11, op3_low));
3501
3502 /* Register r1 is used as a scratch register */
3503 r1 = make_gpr(1);
3504
3505 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3506 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3507 old_high, old_low, r1));
3508 } else {
3509 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3510 old_high, old_low, r1));
3511 }
3512 addInstr(env, s390_insn_move(8, op1_high, r8));
3513 addInstr(env, s390_insn_move(8, op1_low, r9));
3514 addInstr(env, s390_insn_move(8, op3_high, r10));
3515 addInstr(env, s390_insn_move(8, op3_low, r11));
3516 return;
sewardj2019a972011-03-07 16:04:07 +00003517 }
3518 break;
3519
3520 /* --------- EXIT --------- */
3521 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003522 s390_cc_t cond;
3523 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3524
3525 if (tag != Ico_U64)
3526 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3527
florian8844a632012-04-13 04:04:06 +00003528 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003529 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003530
3531 /* Case: boring transfer to known address */
3532 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3533 if (env->chaining_allowed) {
3534 /* .. almost always true .. */
3535 /* Skip the event check at the dst if this is a forwards
3536 edge. */
3537 Bool to_fast_entry
3538 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3539 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3540 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3541 guest_IA, to_fast_entry));
3542 } else {
3543 /* .. very occasionally .. */
3544 /* We can't use chaining, so ask for an assisted transfer,
3545 as that's the only alternative that is allowable. */
3546 HReg dst = s390_isel_int_expr(env,
3547 IRExpr_Const(stmt->Ist.Exit.dst));
3548 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3549 }
3550 return;
3551 }
3552
3553 /* Case: assisted transfer to arbitrary address */
3554 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003555 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003556 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003557 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003558 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003559 case Ijk_Sys_syscall:
3560 case Ijk_ClientReq:
3561 case Ijk_NoRedir:
3562 case Ijk_Yield:
3563 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003564 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3565 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3566 stmt->Ist.Exit.jk));
3567 return;
3568 }
3569 default:
3570 break;
3571 }
3572
3573 /* Do we ever expect to see any other kind? */
3574 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003575 }
3576
3577 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003578 case Ist_MBE:
3579 switch (stmt->Ist.MBE.event) {
3580 case Imbe_Fence:
3581 addInstr(env, s390_insn_mfence());
3582 return;
3583 default:
3584 break;
3585 }
sewardj2019a972011-03-07 16:04:07 +00003586 break;
3587
3588 /* --------- Miscellaneous --------- */
3589
3590 case Ist_PutI: /* Not needed */
3591 case Ist_IMark: /* Doesn't generate any executable code */
3592 case Ist_NoOp: /* Doesn't generate any executable code */
3593 case Ist_AbiHint: /* Meaningless in IR */
3594 return;
3595
3596 default:
3597 break;
3598 }
3599
3600 stmt_fail:
3601 ppIRStmt(stmt);
3602 vpanic("s390_isel_stmt");
3603}
3604
3605
3606/*---------------------------------------------------------*/
3607/*--- ISEL: Basic block terminators (Nexts) ---*/
3608/*---------------------------------------------------------*/
3609
3610static void
florianffbd84d2012-12-09 02:06:29 +00003611iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003612{
sewardj2019a972011-03-07 16:04:07 +00003613 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003614 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003615 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003616 vex_printf("; exit-");
3617 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003618 vex_printf("\n");
3619 }
3620
florian8844a632012-04-13 04:04:06 +00003621 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3622
3623 /* Case: boring transfer to known address */
3624 if (next->tag == Iex_Const) {
3625 IRConst *cdst = next->Iex.Const.con;
3626 vassert(cdst->tag == Ico_U64);
3627 if (jk == Ijk_Boring || jk == Ijk_Call) {
3628 /* Boring transfer to known address */
3629 if (env->chaining_allowed) {
3630 /* .. almost always true .. */
3631 /* Skip the event check at the dst if this is a forwards
3632 edge. */
3633 Bool to_fast_entry
3634 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3635 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3636 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3637 guest_IA, to_fast_entry));
3638 } else {
3639 /* .. very occasionally .. */
3640 /* We can't use chaining, so ask for an indirect transfer,
3641 as that's the cheapest alternative that is allowable. */
3642 HReg dst = s390_isel_int_expr(env, next);
3643 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3644 Ijk_Boring));
3645 }
3646 return;
3647 }
3648 }
3649
3650 /* Case: call/return (==boring) transfer to any address */
3651 switch (jk) {
3652 case Ijk_Boring:
3653 case Ijk_Ret:
3654 case Ijk_Call: {
3655 HReg dst = s390_isel_int_expr(env, next);
3656 if (env->chaining_allowed) {
3657 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3658 } else {
3659 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3660 Ijk_Boring));
3661 }
3662 return;
3663 }
3664 default:
3665 break;
3666 }
3667
3668 /* Case: some other kind of transfer to any address */
3669 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003670 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003671 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003672 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003673 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003674 case Ijk_Sys_syscall:
3675 case Ijk_ClientReq:
3676 case Ijk_NoRedir:
3677 case Ijk_Yield:
3678 case Ijk_SigTRAP: {
3679 HReg dst = s390_isel_int_expr(env, next);
3680 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3681 return;
3682 }
3683 default:
3684 break;
3685 }
3686
3687 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003688}
3689
3690
3691/*---------------------------------------------------------*/
3692/*--- Insn selector top-level ---*/
3693/*---------------------------------------------------------*/
3694
florianf26994a2012-04-21 03:34:54 +00003695/* Translate an entire SB to s390 code.
3696 Note: archinfo_host is a pointer to a stack-allocated variable.
3697 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003698
3699HInstrArray *
3700iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003701 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3702 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3703 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003704{
3705 UInt i, j;
3706 HReg hreg, hregHI;
3707 ISelEnv *env;
3708 UInt hwcaps_host = archinfo_host->hwcaps;
3709
florianf26994a2012-04-21 03:34:54 +00003710 /* KLUDGE: export hwcaps. */
3711 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003712
sewardj2019a972011-03-07 16:04:07 +00003713 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003714 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003715
3716 /* Make up an initial environment to use. */
3717 env = LibVEX_Alloc(sizeof(ISelEnv));
3718 env->vreg_ctr = 0;
3719
3720 /* Set up output code array. */
3721 env->code = newHInstrArray();
3722
3723 /* Copy BB's type env. */
3724 env->type_env = bb->tyenv;
3725
florianad43b3a2012-02-20 15:01:14 +00003726 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00003727 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3728 env->old_value[i] = 0; /* just something to have a defined value */
3729 env->old_value_valid[i] = False;
3730 }
3731
sewardj2019a972011-03-07 16:04:07 +00003732 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3733 change as we go along. For some reason types_used has Int type -- but
3734 it should be unsigned. Internally we use an unsigned type; so we
3735 assert it here. */
3736 vassert(bb->tyenv->types_used >= 0);
3737
3738 env->n_vregmap = bb->tyenv->types_used;
3739 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3740 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3741
florian2c74d242012-09-12 19:38:42 +00003742 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003743 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003744
sewardj2019a972011-03-07 16:04:07 +00003745 /* and finally ... */
3746 env->hwcaps = hwcaps_host;
3747
florian8844a632012-04-13 04:04:06 +00003748 env->max_ga = max_ga;
3749 env->chaining_allowed = chaining_allowed;
3750
sewardj2019a972011-03-07 16:04:07 +00003751 /* For each IR temporary, allocate a suitably-kinded virtual
3752 register. */
3753 j = 0;
3754 for (i = 0; i < env->n_vregmap; i++) {
3755 hregHI = hreg = INVALID_HREG;
3756 switch (bb->tyenv->types[i]) {
3757 case Ity_I1:
3758 case Ity_I8:
3759 case Ity_I16:
3760 case Ity_I32:
3761 hreg = mkHReg(j++, HRcInt64, True);
3762 break;
3763
3764 case Ity_I64:
3765 hreg = mkHReg(j++, HRcInt64, True);
3766 break;
3767
3768 case Ity_I128:
3769 hreg = mkHReg(j++, HRcInt64, True);
3770 hregHI = mkHReg(j++, HRcInt64, True);
3771 break;
3772
3773 case Ity_F32:
3774 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003775 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003776 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003777 hreg = mkHReg(j++, HRcFlt64, True);
3778 break;
3779
3780 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003781 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003782 hreg = mkHReg(j++, HRcFlt64, True);
3783 hregHI = mkHReg(j++, HRcFlt64, True);
3784 break;
3785
3786 case Ity_V128: /* fall through */
3787 default:
3788 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003789 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003790 }
3791
3792 env->vregmap[i] = hreg;
3793 env->vregmapHI[i] = hregHI;
3794 }
3795 env->vreg_ctr = j;
3796
florian8844a632012-04-13 04:04:06 +00003797 /* The very first instruction must be an event check. */
3798 s390_amode *counter, *fail_addr;
3799 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3800 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3801 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3802
3803 /* Possibly a block counter increment (for profiling). At this
3804 point we don't know the address of the counter, so just pretend
3805 it is zero. It will have to be patched later, but before this
3806 translation is used, by a call to LibVEX_patchProfInc. */
3807 if (add_profinc) {
3808 addInstr(env, s390_insn_profinc());
3809 }
3810
sewardj2019a972011-03-07 16:04:07 +00003811 /* Ok, finally we can iterate over the statements. */
3812 for (i = 0; i < bb->stmts_used; i++)
3813 if (bb->stmts[i])
3814 s390_isel_stmt(env, bb->stmts[i]);
3815
florian8844a632012-04-13 04:04:06 +00003816 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003817
3818 /* Record the number of vregs we used. */
3819 env->code->n_vregs = env->vreg_ctr;
3820
3821 return env->code;
3822}
3823
3824/*---------------------------------------------------------------*/
3825/*--- end host_s390_isel.c ---*/
3826/*---------------------------------------------------------------*/