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