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