blob: 9aca09f6c4f52f743e6bd4f13ff6aae06c2d860d [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"
florianad43b3a2012-02-20 15:01:14 +000041#include "guest_s390_defs.h" /* guest_s390x_state_requires_precise_mem_exns */
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 - A flag to indicate whether the guest IA has been assigned to.
86
87 - Values of certain guest registers which are often assigned constants.
sewardj2019a972011-03-07 16:04:07 +000088*/
89
florianad43b3a2012-02-20 15:01:14 +000090/* Symbolic names for guest registers whose value we're tracking */
91enum {
92 GUEST_IA,
93 GUEST_CC_OP,
94 GUEST_CC_DEP1,
95 GUEST_CC_DEP2,
96 GUEST_CC_NDEP,
97 GUEST_SYSNO,
florian7d117ba2012-05-06 03:34:55 +000098 GUEST_COUNTER,
florianad43b3a2012-02-20 15:01:14 +000099 GUEST_UNKNOWN /* must be the last entry */
100};
101
102/* Number of registers we're tracking. */
103#define NUM_TRACKED_REGS GUEST_UNKNOWN
104
105
sewardj2019a972011-03-07 16:04:07 +0000106typedef struct {
107 IRTypeEnv *type_env;
108
florian8844a632012-04-13 04:04:06 +0000109 HInstrArray *code;
sewardj2019a972011-03-07 16:04:07 +0000110 HReg *vregmap;
111 HReg *vregmapHI;
112 UInt n_vregmap;
florian8844a632012-04-13 04:04:06 +0000113 UInt vreg_ctr;
114 UInt hwcaps;
sewardj2019a972011-03-07 16:04:07 +0000115
florian2c74d242012-09-12 19:38:42 +0000116 IRExpr *previous_bfp_rounding_mode;
florianc8e4f562012-10-27 16:19:31 +0000117 IRExpr *previous_dfp_rounding_mode;
florian2c74d242012-09-12 19:38:42 +0000118
florianad43b3a2012-02-20 15:01:14 +0000119 ULong old_value[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000120
florian8844a632012-04-13 04:04:06 +0000121 /* The next two are for translation chaining */
122 Addr64 max_ga;
123 Bool chaining_allowed;
124
florianad43b3a2012-02-20 15:01:14 +0000125 Bool first_IA_assignment;
126 Bool old_value_valid[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000127} ISelEnv;
128
129
130/* Forward declarations */
131static HReg s390_isel_int_expr(ISelEnv *, IRExpr *);
132static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *);
133static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
134static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
135static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
136static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
137static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
florian12390202012-11-10 22:34:14 +0000138static HReg s390_isel_dfp_expr(ISelEnv *, IRExpr *);
floriane38f6412012-12-21 17:32:12 +0000139static void s390_isel_dfp128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
sewardj2019a972011-03-07 16:04:07 +0000140
141
florianad43b3a2012-02-20 15:01:14 +0000142static Int
143get_guest_reg(Int offset)
144{
145 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000146 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
147 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
148 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
149 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
150 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
151 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000152 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000153
154 /* Also make sure there is never a partial write to one of
155 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000156 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
157 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
158 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
159 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
160 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000161 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
162 /* counter is used both as 4-byte and as 8-byte entity */
163 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
164 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianaf50a192012-07-13 14:13:06 +0000165 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000166 break;
167
168 default: break;
169 }
170
171 return GUEST_UNKNOWN;
172}
173
sewardj2019a972011-03-07 16:04:07 +0000174/* Add an instruction */
175static void
176addInstr(ISelEnv *env, s390_insn *insn)
177{
178 addHInstr(env->code, insn);
179
180 if (vex_traceflags & VEX_TRACE_VCODE) {
181 vex_printf("%s\n", s390_insn_as_string(insn));
182 }
183}
184
185
186static __inline__ IRExpr *
187mkU64(ULong value)
188{
189 return IRExpr_Const(IRConst_U64(value));
190}
191
192
193/*---------------------------------------------------------*/
194/*--- Registers ---*/
195/*---------------------------------------------------------*/
196
197/* Return the virtual register to which a given IRTemp is mapped. */
198static HReg
199lookupIRTemp(ISelEnv *env, IRTemp tmp)
200{
201 vassert(tmp < env->n_vregmap);
202 vassert(env->vregmap[tmp] != INVALID_HREG);
203
204 return env->vregmap[tmp];
205}
206
207
208/* Return the two virtual registers to which the IRTemp is mapped. */
209static void
210lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
211{
212 vassert(tmp < env->n_vregmap);
213 vassert(env->vregmapHI[tmp] != INVALID_HREG);
214
215 *lo = env->vregmap[tmp];
216 *hi = env->vregmapHI[tmp];
217}
218
219
220/* Allocate a new integer register */
221static HReg
222newVRegI(ISelEnv *env)
223{
224 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
225 env->vreg_ctr++;
226
227 return reg;
228}
229
230
231/* Allocate a new floating point register */
232static HReg
233newVRegF(ISelEnv *env)
234{
235 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
236
237 env->vreg_ctr++;
238
239 return reg;
240}
241
242
243/* Construct a non-virtual general purpose register */
244static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000245make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000246{
247 return mkHReg(regno, HRcInt64, False /* virtual */ );
248}
249
250
251/* Construct a non-virtual floating point register */
252static __inline__ HReg
253make_fpr(UInt regno)
254{
255 return mkHReg(regno, HRcFlt64, False /* virtual */ );
256}
257
258
259/*---------------------------------------------------------*/
260/*--- Amode ---*/
261/*---------------------------------------------------------*/
262
263static __inline__ Bool
264ulong_fits_unsigned_12bit(ULong val)
265{
266 return (val & 0xFFFu) == val;
267}
268
269
270static __inline__ Bool
271ulong_fits_signed_20bit(ULong val)
272{
273 Long v = val & 0xFFFFFu;
274
275 v = (v << 44) >> 44; /* sign extend */
276
277 return val == (ULong)v;
278}
279
280
florianad43b3a2012-02-20 15:01:14 +0000281static __inline__ Bool
282ulong_fits_signed_8bit(ULong val)
283{
284 Long v = val & 0xFFu;
285
286 v = (v << 56) >> 56; /* sign extend */
287
288 return val == (ULong)v;
289}
290
sewardj2019a972011-03-07 16:04:07 +0000291/* EXPR is an expression that is used as an address. Return an s390_amode
292 for it. */
293static s390_amode *
294s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
295{
296 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
297 IRExpr *arg1 = expr->Iex.Binop.arg1;
298 IRExpr *arg2 = expr->Iex.Binop.arg2;
299
300 /* Move constant into right subtree */
301 if (arg1->tag == Iex_Const) {
302 IRExpr *tmp;
303 tmp = arg1;
304 arg1 = arg2;
305 arg2 = tmp;
306 }
307
308 /* r + constant: Check for b12 first, then b20 */
309 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
310 ULong value = arg2->Iex.Const.con->Ico.U64;
311
312 if (ulong_fits_unsigned_12bit(value)) {
313 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
314 }
sewardj652b56a2011-04-13 15:38:17 +0000315 /* If long-displacement is not available, do not construct B20 or
316 BX20 amodes because code generation cannot handle them. */
317 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000318 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
319 }
320 }
321 }
322
323 /* Doesn't match anything in particular. Generate it into
324 a register and use that. */
325 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
326}
327
328
329static s390_amode *
330s390_isel_amode(ISelEnv *env, IRExpr *expr)
331{
florian35da8612011-06-25 02:25:41 +0000332 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000333
334 /* Address computation should yield a 64-bit value */
335 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
336
337 am = s390_isel_amode_wrk(env, expr);
338
339 /* Check post-condition */
340 vassert(s390_amode_is_sane(am));
341
342 return am;
343}
344
345
346/*---------------------------------------------------------*/
347/*--- Helper functions ---*/
348/*---------------------------------------------------------*/
349
350/* Constants and memory accesses should be right operands */
351#define order_commutative_operands(left, right) \
352 do { \
353 if (left->tag == Iex_Const || left->tag == Iex_Load || \
354 left->tag == Iex_Get) { \
355 IRExpr *tmp; \
356 tmp = left; \
357 left = right; \
358 right = tmp; \
359 } \
360 } while (0)
361
362
363/* Copy an RMI operand to the DST register */
364static s390_insn *
365s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
366{
367 switch (opnd.tag) {
368 case S390_OPND_AMODE:
369 return s390_insn_load(size, dst, opnd.variant.am);
370
371 case S390_OPND_REG:
372 return s390_insn_move(size, dst, opnd.variant.reg);
373
374 case S390_OPND_IMMEDIATE:
375 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
376
377 default:
378 vpanic("s390_opnd_copy");
379 }
380}
381
382
383/* Construct a RMI operand for a register */
384static __inline__ s390_opnd_RMI
385s390_opnd_reg(HReg reg)
386{
387 s390_opnd_RMI opnd;
388
389 opnd.tag = S390_OPND_REG;
390 opnd.variant.reg = reg;
391
392 return opnd;
393}
394
395
396/* Construct a RMI operand for an immediate constant */
397static __inline__ s390_opnd_RMI
398s390_opnd_imm(ULong value)
399{
400 s390_opnd_RMI opnd;
401
402 opnd.tag = S390_OPND_IMMEDIATE;
403 opnd.variant.imm = value;
404
405 return opnd;
406}
407
408
florianffbd84d2012-12-09 02:06:29 +0000409/* Return 1, if EXPR represents the constant 0 */
410static Bool
sewardj2019a972011-03-07 16:04:07 +0000411s390_expr_is_const_zero(IRExpr *expr)
412{
413 ULong value;
414
415 if (expr->tag == Iex_Const) {
416 switch (expr->Iex.Const.con->tag) {
417 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
418 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
419 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
420 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
421 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
422 default:
423 vpanic("s390_expr_is_const_zero");
424 }
425 return value == 0;
426 }
427
428 return 0;
429}
430
431
432/* Call a helper (clean or dirty)
433 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000434
sewardj2019a972011-03-07 16:04:07 +0000435 (a) they are expressions yielding an integer result
436 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000437
438 guard is a Ity_Bit expression indicating whether or not the
439 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000440
441 Calling the helper function proceeds as follows:
442
443 (1) The helper arguments are evaluated and their value stored in
444 virtual registers.
445 (2) The condition code is evaluated
446 (3) The argument values are copied from the virtual registers to the
447 registers mandated by the ABI.
448 (4) Call the helper function.
449
450 This is not the most efficient way as step 3 generates register-to-register
451 moves. But it is the least fragile way as the only hidden dependency here
452 is that register-to-register moves (step 3) must not clobber the condition
453 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
454 to-register add more such dependencies. Not good. Besides, it's the job
455 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000456*/
457static void
458doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000459 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000460{
florian52af7bc2012-05-12 03:44:49 +0000461 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000462 ULong target;
463 HReg tmpregs[S390_NUM_GPRPARMS];
464 s390_cc_t cc;
465
466 n_args = 0;
467 for (i = 0; args[i]; i++)
468 ++n_args;
469
470 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
471 vpanic("doHelperCall: too many arguments");
472 }
473
florian11b8ee82012-08-06 13:35:33 +0000474 /* All arguments must have Ity_I64. For two reasons:
475 (1) We do not handle floating point arguments.
476 (2) The ABI requires that integer values are sign- or zero-extended
477 to 64 bit.
478 */
479 Int arg_errors = 0;
480 for (i = 0; i < n_args; ++i) {
481 IRType type = typeOfIRExpr(env->type_env, args[i]);
482 if (type != Ity_I64) {
483 ++arg_errors;
484 vex_printf("calling %s: argument #%d has type ", callee->name, i);
485 ppIRType(type);
486 vex_printf("; Ity_I64 is required\n");
487 }
488 }
489
490 if (arg_errors)
491 vpanic("cannot continue due to errors in argument passing");
492
florian52af7bc2012-05-12 03:44:49 +0000493 argreg = 0;
494
495 /* If we need the guest state pointer put it in a temporary arg reg */
496 if (passBBP) {
497 tmpregs[argreg] = newVRegI(env);
498 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
499 s390_hreg_guest_state_pointer()));
500 argreg++;
501 }
502
503 /* Compute the function arguments into a temporary register each */
504 for (i = 0; i < n_args; i++) {
505 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
506 argreg++;
507 }
508
sewardj2019a972011-03-07 16:04:07 +0000509 /* Compute the condition */
510 cc = S390_CC_ALWAYS;
511 if (guard) {
512 if (guard->tag == Iex_Const
513 && guard->Iex.Const.con->tag == Ico_U1
514 && guard->Iex.Const.con->Ico.U1 == True) {
515 /* unconditional -- do nothing */
516 } else {
517 cc = s390_isel_cc(env, guard);
518 }
519 }
520
florian52af7bc2012-05-12 03:44:49 +0000521 /* Move the args to the final register. It is paramount, that the
522 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000523 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000524 HReg finalreg;
525
526 finalreg = make_gpr(s390_gprno_from_arg_index(i));
527 size = sizeofIRType(Ity_I64);
528 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000529 }
530
531 target = Ptr_to_ULong(callee->addr);
532
533 /* Finally, the call itself. */
534 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000535 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000536}
537
538
florian2c74d242012-09-12 19:38:42 +0000539/*---------------------------------------------------------*/
540/*--- BFP helper functions ---*/
541/*---------------------------------------------------------*/
542
543/* Set the BFP rounding mode in the FPC. This function is called for
544 all non-conversion BFP instructions as those will always get the
545 rounding mode from the FPC. */
546static void
547set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000548{
florian2c74d242012-09-12 19:38:42 +0000549 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
550
551 /* Do we need to do anything? */
552 if (env->previous_bfp_rounding_mode &&
553 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
554 irrm->tag == Iex_RdTmp &&
555 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
556 /* No - new mode is identical to previous mode. */
557 return;
558 }
559
560 /* No luck - we better set it, and remember what we set it to. */
561 env->previous_bfp_rounding_mode = irrm;
562
563 /* The incoming rounding mode is in VEX IR encoding. Need to change
564 to s390.
565
566 rounding mode | s390 | IR
567 -------------------------
568 to nearest | 00 | 00
569 to zero | 01 | 11
570 to +infinity | 10 | 10
571 to -infinity | 11 | 01
572
573 So: s390 = (4 - IR) & 3
574 */
575 HReg ir = s390_isel_int_expr(env, irrm);
576
577 HReg mode = newVRegI(env);
578
579 addInstr(env, s390_insn_load_immediate(4, mode, 4));
580 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
581 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
582
florian125e20d2012-10-07 15:42:37 +0000583 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000584}
585
586
587/* This function is invoked for insns that support a specification of
588 a rounding mode in the insn itself. In that case there is no need to
589 stick the rounding mode into the FPC -- a good thing. However, the
590 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000591static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000592get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
593{
594 if (irrm->tag == Iex_Const) { /* rounding mode is known */
595 vassert(irrm->Iex.Const.con->tag == Ico_U32);
596 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000597
598 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000599 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
600 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
601 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
602 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000603 default:
604 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000605 }
606 }
607
florian2c74d242012-09-12 19:38:42 +0000608 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000609 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000610}
611
612
florianc8e4f562012-10-27 16:19:31 +0000613/*---------------------------------------------------------*/
614/*--- DFP helper functions ---*/
615/*---------------------------------------------------------*/
616
617/* Set the DFP rounding mode in the FPC. This function is called for
618 all non-conversion DFP instructions as those will always get the
619 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000620static void
621set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
622{
623 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
624
625 /* Do we need to do anything? */
626 if (env->previous_dfp_rounding_mode &&
627 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
628 irrm->tag == Iex_RdTmp &&
629 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
630 /* No - new mode is identical to previous mode. */
631 return;
632 }
633
634 /* No luck - we better set it, and remember what we set it to. */
635 env->previous_dfp_rounding_mode = irrm;
636
637 /* The incoming rounding mode is in VEX IR encoding. Need to change
638 to s390.
639
640 rounding mode | S390 | IR
641 -----------------------------------------------
642 to nearest, ties to even | 000 | 000
643 to zero | 001 | 011
644 to +infinity | 010 | 010
645 to -infinity | 011 | 001
646 to nearest, ties away from 0 | 100 | 100
647 to nearest, ties toward 0 | 101 | 111
648 to away from 0 | 110 | 110
649 to prepare for shorter precision | 111 | 101
650
651 So: s390 = (IR ^ ((IR << 1) & 2))
652 */
653 HReg ir = s390_isel_int_expr(env, irrm);
654
655 HReg mode = newVRegI(env);
656
657 addInstr(env, s390_insn_move(4, mode, ir));
658 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
659 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
660 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
661
662 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
663}
664
665
666/* This function is invoked for insns that support a specification of
667 a rounding mode in the insn itself. In that case there is no need to
668 stick the rounding mode into the FPC -- a good thing. However, the
669 rounding mode must be known.
670 The IR to s390 encoding is chosen in the range 0:7 except
671 S390_DFP_ROUND_NEAREST_TIE_TOWARD_0 and
672 S390_DFP_ROUND_AWAY_0 which have no choice within the range.
673 Since the s390 dfp rounding mode encoding in 8:15 is not used, the
674 quantum excpetion is not suppressed and this is fine as valgrind does
675 not model this exception.
676
677 Translation table of
678 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
679
680 s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
681 --------------------------------------------------------------------
682 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_1
683 NEAREST_TIE_AWAY_0_12 | " | "
684 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_3
685 PREPARE_SHORT_15 | " | "
686 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_4
687 NEAREST_EVEN_8 | " | "
688 ZERO_5 | ZERO | ZERO_5
689 ZERO_9 | " | "
690 POSINF_6 | PosINF | POSINF_6
691 POSINF_10 | " | "
692 NEGINF_7 | NegINF | NEGINF_7
693 NEGINF_11 | " | "
694 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
695 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
696*/
697static s390_dfp_round_t
698get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
699{
700 if (irrm->tag == Iex_Const) { /* rounding mode is known */
701 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian3d6a4222012-11-19 16:29:31 +0000702 IRRoundingModeDFP mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000703
704 switch (mode) {
705 case Irrm_DFP_NEAREST:
706 return S390_DFP_ROUND_NEAREST_EVEN_4;
707 case Irrm_DFP_NegINF:
708 return S390_DFP_ROUND_NEGINF_7;
709 case Irrm_DFP_PosINF:
710 return S390_DFP_ROUND_POSINF_6;
711 case Irrm_DFP_ZERO:
712 return S390_DFP_ROUND_ZERO_5;
713 case Irrm_DFP_NEAREST_TIE_AWAY_0:
714 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1;
715 case Irrm_DFP_PREPARE_SHORTER:
716 return S390_DFP_ROUND_PREPARE_SHORT_3;
717 case Irrm_DFP_AWAY_FROM_ZERO:
718 return S390_DFP_ROUND_AWAY_0;
719 case Irrm_DFP_NEAREST_TIE_TOWARD_0:
720 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
721 default:
722 vpanic("get_dfp_rounding_mode");
723 }
724 }
725
726 set_dfp_rounding_mode_in_fpc(env, irrm);
727 return S390_DFP_ROUND_PER_FPC_0;
728}
florianc8e4f562012-10-27 16:19:31 +0000729
florian2d3d87f2012-12-21 21:05:17 +0000730
731/*---------------------------------------------------------*/
732/*--- Condition code helper functions ---*/
733/*---------------------------------------------------------*/
734
sewardj2019a972011-03-07 16:04:07 +0000735/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000736 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000737
738 s390 VEX b6 b2 b0 cc.1 cc.0
739 0 0x40 EQ 1 0 0 0 0
740 1 0x01 LT 0 0 1 0 1
741 2 0x00 GT 0 0 0 1 0
742 3 0x45 Unordered 1 1 1 1 1
743
744 b0 = cc.0
745 b2 = cc.0 & cc.1
746 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
747
748 VEX = b0 | (b2 << 2) | (b6 << 6);
749*/
750static HReg
florian2d3d87f2012-12-21 21:05:17 +0000751convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000752{
753 HReg cc0, cc1, b2, b6, cc_vex;
754
755 cc0 = newVRegI(env);
756 addInstr(env, s390_insn_move(4, cc0, cc_s390));
757 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
758
759 cc1 = newVRegI(env);
760 addInstr(env, s390_insn_move(4, cc1, cc_s390));
761 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
762
763 b2 = newVRegI(env);
764 addInstr(env, s390_insn_move(4, b2, cc0));
765 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
766 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
767
768 b6 = newVRegI(env);
769 addInstr(env, s390_insn_move(4, b6, cc0));
770 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
771 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
772 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
773 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
774
775 cc_vex = newVRegI(env);
776 addInstr(env, s390_insn_move(4, cc_vex, cc0));
777 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
778 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
779
780 return cc_vex;
781}
782
florian2d3d87f2012-12-21 21:05:17 +0000783/* CC_S390 holds the condition code in s390 encoding. Convert it to
784 VEX encoding (IRCmpDResult) */
785static HReg
786convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
787{
788 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
789 return convert_s390_to_vex_bfpcc(env, cc_s390);
790}
791
sewardj2019a972011-03-07 16:04:07 +0000792
793/*---------------------------------------------------------*/
794/*--- ISEL: Integer expressions (128 bit) ---*/
795/*---------------------------------------------------------*/
796static void
797s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
798 IRExpr *expr)
799{
800 IRType ty = typeOfIRExpr(env->type_env, expr);
801
802 vassert(ty == Ity_I128);
803
804 /* No need to consider the following
805 - 128-bit constants (they do not exist in VEX)
806 - 128-bit loads from memory (will not be generated)
807 */
808
809 /* Read 128-bit IRTemp */
810 if (expr->tag == Iex_RdTmp) {
811 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
812 return;
813 }
814
815 if (expr->tag == Iex_Binop) {
816 IRExpr *arg1 = expr->Iex.Binop.arg1;
817 IRExpr *arg2 = expr->Iex.Binop.arg2;
818 Bool is_signed_multiply, is_signed_divide;
819
820 switch (expr->Iex.Binop.op) {
821 case Iop_MullU64:
822 is_signed_multiply = False;
823 goto do_multiply64;
824
825 case Iop_MullS64:
826 is_signed_multiply = True;
827 goto do_multiply64;
828
829 case Iop_DivModU128to64:
830 is_signed_divide = False;
831 goto do_divide64;
832
833 case Iop_DivModS128to64:
834 is_signed_divide = True;
835 goto do_divide64;
836
837 case Iop_64HLto128:
838 *dst_hi = s390_isel_int_expr(env, arg1);
839 *dst_lo = s390_isel_int_expr(env, arg2);
840 return;
841
842 case Iop_DivModS64to64: {
843 HReg r10, r11, h1;
844 s390_opnd_RMI op2;
845
846 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
847 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
848
849 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000850 r10 = make_gpr(10);
851 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000852
853 /* Move 1st operand into r11 and */
854 addInstr(env, s390_insn_move(8, r11, h1));
855
856 /* Divide */
857 addInstr(env, s390_insn_divs(8, r10, r11, op2));
858
859 /* The result is in registers r10 (remainder) and r11 (quotient).
860 Move the result into the reg pair that is being returned such
861 such that the low 64 bits are the quotient and the upper 64 bits
862 are the remainder. (see libvex_ir.h). */
863 *dst_hi = newVRegI(env);
864 *dst_lo = newVRegI(env);
865 addInstr(env, s390_insn_move(8, *dst_hi, r10));
866 addInstr(env, s390_insn_move(8, *dst_lo, r11));
867 return;
868 }
869
870 default:
871 break;
872
873 do_multiply64: {
874 HReg r10, r11, h1;
875 s390_opnd_RMI op2;
876
877 order_commutative_operands(arg1, arg2);
878
879 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
880 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
881
882 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000883 r10 = make_gpr(10);
884 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000885
886 /* Move the first operand to r11 */
887 addInstr(env, s390_insn_move(8, r11, h1));
888
889 /* Multiply */
890 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
891
892 /* The result is in registers r10 and r11. Assign to two virtual regs
893 and return. */
894 *dst_hi = newVRegI(env);
895 *dst_lo = newVRegI(env);
896 addInstr(env, s390_insn_move(8, *dst_hi, r10));
897 addInstr(env, s390_insn_move(8, *dst_lo, r11));
898 return;
899 }
900
901 do_divide64: {
902 HReg r10, r11, hi, lo;
903 s390_opnd_RMI op2;
904
905 s390_isel_int128_expr(&hi, &lo, env, arg1);
906 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
907
908 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000909 r10 = make_gpr(10);
910 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000911
912 /* Move high 64 bits of the 1st operand into r10 and
913 the low 64 bits into r11. */
914 addInstr(env, s390_insn_move(8, r10, hi));
915 addInstr(env, s390_insn_move(8, r11, lo));
916
917 /* Divide */
918 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
919
920 /* The result is in registers r10 (remainder) and r11 (quotient).
921 Move the result into the reg pair that is being returned such
922 such that the low 64 bits are the quotient and the upper 64 bits
923 are the remainder. (see libvex_ir.h). */
924 *dst_hi = newVRegI(env);
925 *dst_lo = newVRegI(env);
926 addInstr(env, s390_insn_move(8, *dst_hi, r10));
927 addInstr(env, s390_insn_move(8, *dst_lo, r11));
928 return;
929 }
930 }
931 }
932
933 vpanic("s390_isel_int128_expr");
934}
935
936
937/* Compute a 128-bit value into two 64-bit registers. These may be either
938 real or virtual regs; in any case they must not be changed by subsequent
939 code emitted by the caller. */
940static void
941s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
942{
943 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
944
945 /* Sanity checks ... */
946 vassert(hregIsVirtual(*dst_hi));
947 vassert(hregIsVirtual(*dst_lo));
948 vassert(hregClass(*dst_hi) == HRcInt64);
949 vassert(hregClass(*dst_lo) == HRcInt64);
950}
951
952
953/*---------------------------------------------------------*/
954/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
955/*---------------------------------------------------------*/
956
957/* Select insns for an integer-typed expression, and add them to the
958 code list. Return a reg holding the result. This reg will be a
959 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
960 want to modify it, ask for a new vreg, copy it in there, and modify
961 the copy. The register allocator will do its best to map both
962 vregs to the same real register, so the copies will often disappear
963 later in the game.
964
965 This should handle expressions of 64, 32, 16 and 8-bit type.
966 All results are returned in a 64bit register.
967 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
968 are arbitrary, so you should mask or sign extend partial values
969 if necessary.
970*/
971
972/* DO NOT CALL THIS DIRECTLY ! */
973static HReg
974s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
975{
976 IRType ty = typeOfIRExpr(env->type_env, expr);
977 UChar size;
florian6dc90242012-12-21 21:43:00 +0000978 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +0000979
980 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
981
982 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
983
984 switch (expr->tag) {
985
986 /* --------- TEMP --------- */
987 case Iex_RdTmp:
988 /* Return the virtual register that holds the temporary. */
989 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
990
991 /* --------- LOAD --------- */
992 case Iex_Load: {
993 HReg dst = newVRegI(env);
994 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
995
996 if (expr->Iex.Load.end != Iend_BE)
997 goto irreducible;
998
999 addInstr(env, s390_insn_load(size, dst, am));
1000
1001 return dst;
1002 }
1003
1004 /* --------- BINARY OP --------- */
1005 case Iex_Binop: {
1006 IRExpr *arg1 = expr->Iex.Binop.arg1;
1007 IRExpr *arg2 = expr->Iex.Binop.arg2;
1008 HReg h1, res;
1009 s390_alu_t opkind;
1010 s390_opnd_RMI op2, value, opnd;
1011 s390_insn *insn;
1012 Bool is_commutative, is_signed_multiply, is_signed_divide;
1013
1014 is_commutative = True;
1015
1016 switch (expr->Iex.Binop.op) {
1017 case Iop_MullU8:
1018 case Iop_MullU16:
1019 case Iop_MullU32:
1020 is_signed_multiply = False;
1021 goto do_multiply;
1022
1023 case Iop_MullS8:
1024 case Iop_MullS16:
1025 case Iop_MullS32:
1026 is_signed_multiply = True;
1027 goto do_multiply;
1028
1029 do_multiply: {
1030 HReg r10, r11;
1031 UInt arg_size = size / 2;
1032
1033 order_commutative_operands(arg1, arg2);
1034
1035 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1036 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1037
1038 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001039 r10 = make_gpr(10);
1040 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001041
1042 /* Move the first operand to r11 */
1043 addInstr(env, s390_insn_move(arg_size, r11, h1));
1044
1045 /* Multiply */
1046 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1047
1048 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1049 value into the destination register. */
1050 res = newVRegI(env);
1051 addInstr(env, s390_insn_move(arg_size, res, r10));
1052 value = s390_opnd_imm(arg_size * 8);
1053 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1054 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1055 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1056 opnd = s390_opnd_reg(r11);
1057 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1058 return res;
1059 }
1060
1061 case Iop_DivModS64to32:
1062 is_signed_divide = True;
1063 goto do_divide;
1064
1065 case Iop_DivModU64to32:
1066 is_signed_divide = False;
1067 goto do_divide;
1068
1069 do_divide: {
1070 HReg r10, r11;
1071
1072 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1073 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1074
1075 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001076 r10 = make_gpr(10);
1077 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001078
1079 /* Split the first operand and put the high 32 bits into r10 and
1080 the low 32 bits into r11. */
1081 addInstr(env, s390_insn_move(8, r10, h1));
1082 addInstr(env, s390_insn_move(8, r11, h1));
1083 value = s390_opnd_imm(32);
1084 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1085
1086 /* Divide */
1087 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1088
1089 /* The result is in registers r10 (remainder) and r11 (quotient).
1090 Combine them into a 64-bit value such that the low 32 bits are
1091 the quotient and the upper 32 bits are the remainder. (see
1092 libvex_ir.h). */
1093 res = newVRegI(env);
1094 addInstr(env, s390_insn_move(8, res, r10));
1095 value = s390_opnd_imm(32);
1096 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1097 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1098 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1099 opnd = s390_opnd_reg(r11);
1100 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1101 return res;
1102 }
1103
florian9fcff4c2012-09-10 03:09:04 +00001104 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1105 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1106 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1107 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1108 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1109 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1110 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1111 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1112 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1113 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1114 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1115 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
sewardj2019a972011-03-07 16:04:07 +00001116
1117 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001118 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001119
1120 res = newVRegI(env);
1121 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1122
florian2c74d242012-09-12 19:38:42 +00001123 rounding_mode = get_bfp_rounding_mode(env, arg1);
1124 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1125 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001126 return res;
1127 }
1128
1129 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001130 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001131 HReg op_hi, op_lo, f13, f15;
1132
1133 res = newVRegI(env);
1134 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1135
1136 /* We use non-virtual registers r13 and r15 as pair */
1137 f13 = make_fpr(13);
1138 f15 = make_fpr(15);
1139
1140 /* operand --> (f13, f15) */
1141 addInstr(env, s390_insn_move(8, f13, op_hi));
1142 addInstr(env, s390_insn_move(8, f15, op_lo));
1143
florian2c74d242012-09-12 19:38:42 +00001144 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001145 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001146 rounding_mode));
1147 return res;
1148 }
1149
1150 case Iop_8HLto16:
1151 case Iop_16HLto32:
1152 case Iop_32HLto64: {
1153 HReg h2;
1154 UInt arg_size = size / 2;
1155
1156 res = newVRegI(env);
1157 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1158 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1159
1160 addInstr(env, s390_insn_move(arg_size, res, h1));
1161 value = s390_opnd_imm(arg_size * 8);
1162 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1163 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1164 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1165 opnd = s390_opnd_reg(h2);
1166 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1167 return res;
1168 }
1169
1170 case Iop_Max32U: {
1171 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1172 res = newVRegI(env);
1173 h1 = s390_isel_int_expr(env, arg1);
1174 op2 = s390_isel_int_expr_RMI(env, arg2);
1175
1176 addInstr(env, s390_insn_move(size, res, h1));
1177 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1178 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1179 return res;
1180 }
1181
1182 case Iop_CmpF32:
1183 case Iop_CmpF64: {
1184 HReg cc_s390, h2;
1185
1186 h1 = s390_isel_float_expr(env, arg1);
1187 h2 = s390_isel_float_expr(env, arg2);
1188 cc_s390 = newVRegI(env);
1189
1190 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1191
1192 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1193
florian2d3d87f2012-12-21 21:05:17 +00001194 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001195 }
1196
1197 case Iop_CmpF128: {
1198 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1199
1200 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1201 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1202 cc_s390 = newVRegI(env);
1203
1204 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1205 f12 = make_fpr(12);
1206 f13 = make_fpr(13);
1207 f14 = make_fpr(14);
1208 f15 = make_fpr(15);
1209
1210 /* 1st operand --> (f12, f14) */
1211 addInstr(env, s390_insn_move(8, f12, op1_hi));
1212 addInstr(env, s390_insn_move(8, f14, op1_lo));
1213
1214 /* 2nd operand --> (f13, f15) */
1215 addInstr(env, s390_insn_move(8, f13, op2_hi));
1216 addInstr(env, s390_insn_move(8, f15, op2_lo));
1217
1218 res = newVRegI(env);
1219 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1220
florian2d3d87f2012-12-21 21:05:17 +00001221 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001222 }
1223
floriane38f6412012-12-21 17:32:12 +00001224 case Iop_CmpD64: {
1225 HReg cc_s390, h2;
1226
1227 h1 = s390_isel_dfp_expr(env, arg1);
1228 h2 = s390_isel_dfp_expr(env, arg2);
1229 cc_s390 = newVRegI(env);
1230 size = 8;
1231
1232 addInstr(env, s390_insn_dfp_compare(size, cc_s390, h1, h2));
1233
florian2d3d87f2012-12-21 21:05:17 +00001234 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001235 }
1236
1237 case Iop_CmpD128: {
1238 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1239
1240 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1241 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1242 cc_s390 = newVRegI(env);
1243
1244 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1245 f12 = make_fpr(12);
1246 f13 = make_fpr(13);
1247 f14 = make_fpr(14);
1248 f15 = make_fpr(15);
1249
1250 /* 1st operand --> (f12, f14) */
1251 addInstr(env, s390_insn_move(8, f12, op1_hi));
1252 addInstr(env, s390_insn_move(8, f14, op1_lo));
1253
1254 /* 2nd operand --> (f13, f15) */
1255 addInstr(env, s390_insn_move(8, f13, op2_hi));
1256 addInstr(env, s390_insn_move(8, f15, op2_lo));
1257
1258 res = newVRegI(env);
1259 addInstr(env, s390_insn_dfp128_compare(16, cc_s390, f12, f14, f13, f15));
1260
florian2d3d87f2012-12-21 21:05:17 +00001261 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001262 }
1263
sewardj2019a972011-03-07 16:04:07 +00001264 case Iop_Add8:
1265 case Iop_Add16:
1266 case Iop_Add32:
1267 case Iop_Add64:
1268 opkind = S390_ALU_ADD;
1269 break;
1270
1271 case Iop_Sub8:
1272 case Iop_Sub16:
1273 case Iop_Sub32:
1274 case Iop_Sub64:
1275 opkind = S390_ALU_SUB;
1276 is_commutative = False;
1277 break;
1278
1279 case Iop_And8:
1280 case Iop_And16:
1281 case Iop_And32:
1282 case Iop_And64:
1283 opkind = S390_ALU_AND;
1284 break;
1285
1286 case Iop_Or8:
1287 case Iop_Or16:
1288 case Iop_Or32:
1289 case Iop_Or64:
1290 opkind = S390_ALU_OR;
1291 break;
1292
1293 case Iop_Xor8:
1294 case Iop_Xor16:
1295 case Iop_Xor32:
1296 case Iop_Xor64:
1297 opkind = S390_ALU_XOR;
1298 break;
1299
1300 case Iop_Shl8:
1301 case Iop_Shl16:
1302 case Iop_Shl32:
1303 case Iop_Shl64:
1304 opkind = S390_ALU_LSH;
1305 is_commutative = False;
1306 break;
1307
1308 case Iop_Shr8:
1309 case Iop_Shr16:
1310 case Iop_Shr32:
1311 case Iop_Shr64:
1312 opkind = S390_ALU_RSH;
1313 is_commutative = False;
1314 break;
1315
1316 case Iop_Sar8:
1317 case Iop_Sar16:
1318 case Iop_Sar32:
1319 case Iop_Sar64:
1320 opkind = S390_ALU_RSHA;
1321 is_commutative = False;
1322 break;
1323
1324 default:
1325 goto irreducible;
1326 }
1327
1328 /* Pattern match: 0 - arg1 --> -arg1 */
1329 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1330 res = newVRegI(env);
1331 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1332 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1333 addInstr(env, insn);
1334
1335 return res;
1336 }
1337
1338 if (is_commutative) {
1339 order_commutative_operands(arg1, arg2);
1340 }
1341
1342 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1343 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1344 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001345
1346 /* As right shifts of one/two byte opreands are implemented using a
1347 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1348 switch (expr->Iex.Binop.op) {
1349 case Iop_Shr8:
1350 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1351 break;
1352 case Iop_Shr16:
1353 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1354 break;
1355 case Iop_Sar8:
1356 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1357 break;
1358 case Iop_Sar16:
1359 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1360 break;
1361 default:
1362 insn = s390_insn_move(size, res, h1);
1363 break;
1364 }
1365 addInstr(env, insn);
1366
sewardj2019a972011-03-07 16:04:07 +00001367 insn = s390_insn_alu(size, opkind, res, op2);
1368
1369 addInstr(env, insn);
1370
1371 return res;
1372 }
1373
1374 /* --------- UNARY OP --------- */
1375 case Iex_Unop: {
1376 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1377 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1378 s390_opnd_RMI opnd;
1379 s390_insn *insn;
1380 IRExpr *arg;
1381 HReg dst, h1;
1382 IROp unop, binop;
1383
1384 arg = expr->Iex.Unop.arg;
1385
1386 /* Special cases are handled here */
1387
1388 /* 32-bit multiply with 32-bit result or
1389 64-bit multiply with 64-bit result */
1390 unop = expr->Iex.Unop.op;
1391 binop = arg->Iex.Binop.op;
1392
1393 if ((arg->tag == Iex_Binop &&
1394 ((unop == Iop_64to32 &&
1395 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1396 (unop == Iop_128to64 &&
1397 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1398 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1399 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1400 dst = newVRegI(env); /* Result goes into a new register */
1401 addInstr(env, s390_insn_move(size, dst, h1));
1402 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1403
1404 return dst;
1405 }
1406
florian4d71a082011-12-18 00:08:17 +00001407 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001408 dst = newVRegI(env);
1409 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1410 addInstr(env, s390_insn_move(size, dst, h1));
1411
1412 return dst;
1413 }
1414
floriane38f6412012-12-21 17:32:12 +00001415 if (unop == Iop_ReinterpD64asI64) {
1416 dst = newVRegI(env);
1417 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1418 addInstr(env, s390_insn_move(size, dst, h1));
1419
1420 return dst;
1421 }
1422
sewardj2019a972011-03-07 16:04:07 +00001423 /* Expressions whose argument is 1-bit wide */
1424 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1425 s390_cc_t cond = s390_isel_cc(env, arg);
1426 dst = newVRegI(env); /* Result goes into a new register */
1427 addInstr(env, s390_insn_cc2bool(dst, cond));
1428
1429 switch (unop) {
1430 case Iop_1Uto8:
1431 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001432 /* Zero extend */
1433 mask.variant.imm = 1;
1434 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1435 break;
1436
sewardj2019a972011-03-07 16:04:07 +00001437 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001438 /* Zero extend */
1439 mask.variant.imm = 1;
1440 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001441 break;
1442
1443 case Iop_1Sto8:
1444 case Iop_1Sto16:
1445 case Iop_1Sto32:
1446 shift.variant.imm = 31;
1447 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1448 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1449 break;
1450
1451 case Iop_1Sto64:
1452 shift.variant.imm = 63;
1453 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1454 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1455 break;
1456
1457 default:
1458 goto irreducible;
1459 }
1460
1461 return dst;
1462 }
1463
1464 /* Regular processing */
1465
1466 if (unop == Iop_128to64) {
1467 HReg dst_hi, dst_lo;
1468
1469 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1470 return dst_lo;
1471 }
1472
1473 if (unop == Iop_128HIto64) {
1474 HReg dst_hi, dst_lo;
1475
1476 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1477 return dst_hi;
1478 }
1479
1480 dst = newVRegI(env); /* Result goes into a new register */
1481 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1482
1483 switch (unop) {
1484 case Iop_8Uto16:
1485 case Iop_8Uto32:
1486 case Iop_8Uto64:
1487 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1488 break;
1489
1490 case Iop_16Uto32:
1491 case Iop_16Uto64:
1492 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1493 break;
1494
1495 case Iop_32Uto64:
1496 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1497 break;
1498
1499 case Iop_8Sto16:
1500 case Iop_8Sto32:
1501 case Iop_8Sto64:
1502 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1503 break;
1504
1505 case Iop_16Sto32:
1506 case Iop_16Sto64:
1507 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1508 break;
1509
1510 case Iop_32Sto64:
1511 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1512 break;
1513
1514 case Iop_64to8:
1515 case Iop_64to16:
1516 case Iop_64to32:
1517 case Iop_32to8:
1518 case Iop_32to16:
1519 case Iop_16to8:
1520 /* Down-casts are no-ops. Upstream operations will only look at
1521 the bytes that make up the result of the down-cast. So there
1522 is no point setting the other bytes to 0. */
1523 insn = s390_opnd_copy(8, dst, opnd);
1524 break;
1525
1526 case Iop_64HIto32:
1527 addInstr(env, s390_opnd_copy(8, dst, opnd));
1528 shift.variant.imm = 32;
1529 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1530 break;
1531
1532 case Iop_32HIto16:
1533 addInstr(env, s390_opnd_copy(4, dst, opnd));
1534 shift.variant.imm = 16;
1535 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1536 break;
1537
1538 case Iop_16HIto8:
1539 addInstr(env, s390_opnd_copy(2, dst, opnd));
1540 shift.variant.imm = 8;
1541 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1542 break;
1543
1544 case Iop_Not8:
1545 case Iop_Not16:
1546 case Iop_Not32:
1547 case Iop_Not64:
1548 /* XOR with ffff... */
1549 mask.variant.imm = ~(ULong)0;
1550 addInstr(env, s390_opnd_copy(size, dst, opnd));
1551 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1552 break;
1553
1554 case Iop_Left8:
1555 case Iop_Left16:
1556 case Iop_Left32:
1557 case Iop_Left64:
1558 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1559 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1560 break;
1561
1562 case Iop_CmpwNEZ32:
1563 case Iop_CmpwNEZ64: {
1564 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1565 or -X will have a 1 in the MSB. */
1566 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1567 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1568 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1569 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1570 return dst;
1571 }
1572
1573 case Iop_Clz64: {
1574 HReg r10, r11;
1575
sewardj611b06e2011-03-24 08:57:29 +00001576 /* This will be implemented using FLOGR, if possible. So we need to
1577 set aside a pair of non-virtual registers. The result (number of
1578 left-most zero bits) will be in r10. The value in r11 is unspecified
1579 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001580 r10 = make_gpr(10);
1581 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001582
sewardj611b06e2011-03-24 08:57:29 +00001583 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001584 addInstr(env, s390_insn_move(8, dst, r10));
1585 return dst;
1586 }
1587
1588 default:
1589 goto irreducible;
1590 }
1591
1592 addInstr(env, insn);
1593
1594 return dst;
1595 }
1596
1597 /* --------- GET --------- */
1598 case Iex_Get: {
1599 HReg dst = newVRegI(env);
1600 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1601
1602 /* We never load more than 8 bytes from the guest state, because the
1603 floating point register pair is not contiguous. */
1604 vassert(size <= 8);
1605
1606 addInstr(env, s390_insn_load(size, dst, am));
1607
1608 return dst;
1609 }
1610
1611 case Iex_GetI:
1612 /* not needed */
1613 break;
1614
1615 /* --------- CCALL --------- */
1616 case Iex_CCall: {
1617 HReg dst = newVRegI(env);
1618
1619 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001620 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001621 return dst;
1622 }
1623
1624 /* --------- LITERAL --------- */
1625
1626 /* Load a literal into a register. Create a "load immediate"
1627 v-insn and return the register. */
1628 case Iex_Const: {
1629 ULong value;
1630 HReg dst = newVRegI(env);
1631 const IRConst *con = expr->Iex.Const.con;
1632
1633 /* Bitwise copy of the value. No sign/zero-extension */
1634 switch (con->tag) {
1635 case Ico_U64: value = con->Ico.U64; break;
1636 case Ico_U32: value = con->Ico.U32; break;
1637 case Ico_U16: value = con->Ico.U16; break;
1638 case Ico_U8: value = con->Ico.U8; break;
1639 default: vpanic("s390_isel_int_expr: invalid constant");
1640 }
1641
1642 addInstr(env, s390_insn_load_immediate(size, dst, value));
1643
1644 return dst;
1645 }
1646
1647 /* --------- MULTIPLEX --------- */
1648 case Iex_Mux0X: {
1649 IRExpr *cond_expr;
1650 HReg dst, tmp, rX;
1651 s390_opnd_RMI cond, r0, zero;
1652
1653 cond_expr = expr->Iex.Mux0X.cond;
1654
1655 dst = newVRegI(env);
1656 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1657 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1658 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1659
1660 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1661 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1662
1663 addInstr(env, s390_insn_move(size, dst, rX));
1664 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1665 return dst;
1666 }
1667
1668 /* Assume the condition is true and move rX to the destination reg. */
1669 addInstr(env, s390_insn_move(size, dst, rX));
1670
1671 /* Compute the condition ... */
1672 cond = s390_isel_int_expr_RMI(env, cond_expr);
1673
1674 /* tmp = cond & 0xFF */
1675 tmp = newVRegI(env);
1676 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1677 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1678
1679 /* ... and compare it with zero */
1680 zero = s390_opnd_imm(0);
1681 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1682
1683 /* ... and if it compared equal move r0 to the destination reg. */
1684 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1685 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1686
1687 return dst;
1688 }
1689
1690 default:
1691 break;
1692 }
1693
1694 /* We get here if no pattern matched. */
1695 irreducible:
1696 ppIRExpr(expr);
1697 vpanic("s390_isel_int_expr: cannot reduce tree");
1698}
1699
1700
1701static HReg
1702s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1703{
1704 HReg dst = s390_isel_int_expr_wrk(env, expr);
1705
1706 /* Sanity checks ... */
1707 vassert(hregClass(dst) == HRcInt64);
1708 vassert(hregIsVirtual(dst));
1709
1710 return dst;
1711}
1712
1713
1714static s390_opnd_RMI
1715s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1716{
1717 IRType ty = typeOfIRExpr(env->type_env, expr);
1718 s390_opnd_RMI dst;
1719
1720 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1721 ty == Ity_I64);
1722
1723 if (expr->tag == Iex_Load) {
1724 dst.tag = S390_OPND_AMODE;
1725 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1726 } else if (expr->tag == Iex_Get) {
1727 dst.tag = S390_OPND_AMODE;
1728 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1729 } else if (expr->tag == Iex_Const) {
1730 ULong value;
1731
1732 /* The bit pattern for the value will be stored as is in the least
1733 significant bits of VALUE. */
1734 switch (expr->Iex.Const.con->tag) {
1735 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1736 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1737 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1738 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1739 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1740 default:
1741 vpanic("s390_isel_int_expr_RMI");
1742 }
1743
1744 dst.tag = S390_OPND_IMMEDIATE;
1745 dst.variant.imm = value;
1746 } else {
1747 dst.tag = S390_OPND_REG;
1748 dst.variant.reg = s390_isel_int_expr(env, expr);
1749 }
1750
1751 return dst;
1752}
1753
1754
1755/*---------------------------------------------------------*/
1756/*--- ISEL: Floating point expressions (128 bit) ---*/
1757/*---------------------------------------------------------*/
1758static void
1759s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1760 IRExpr *expr)
1761{
1762 IRType ty = typeOfIRExpr(env->type_env, expr);
1763
1764 vassert(ty == Ity_F128);
1765
sewardj2019a972011-03-07 16:04:07 +00001766 switch (expr->tag) {
1767 case Iex_RdTmp:
1768 /* Return the virtual registers that hold the temporary. */
1769 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1770 return;
1771
1772 /* --------- LOAD --------- */
1773 case Iex_Load: {
1774 IRExpr *addr_hi, *addr_lo;
1775 s390_amode *am_hi, *am_lo;
1776
1777 if (expr->Iex.Load.end != Iend_BE)
1778 goto irreducible;
1779
1780 addr_hi = expr->Iex.Load.addr;
1781 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1782
1783 am_hi = s390_isel_amode(env, addr_hi);
1784 am_lo = s390_isel_amode(env, addr_lo);
1785
1786 *dst_hi = newVRegF(env);
1787 *dst_lo = newVRegF(env);
1788 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1789 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1790 return;
1791 }
1792
1793
1794 /* --------- GET --------- */
1795 case Iex_Get:
1796 /* This is not supported because loading 128-bit from the guest
1797 state is almost certainly wrong. Use get_fpr_pair instead. */
1798 vpanic("Iex_Get with F128 data");
1799
1800 /* --------- 4-ary OP --------- */
1801 case Iex_Qop:
1802 vpanic("Iex_Qop with F128 data");
1803
1804 /* --------- TERNARY OP --------- */
1805 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001806 IRTriop *triop = expr->Iex.Triop.details;
1807 IROp op = triop->op;
1808 IRExpr *left = triop->arg2;
1809 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001810 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001811 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1812
1813 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1814 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1815
1816 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1817 f12 = make_fpr(12);
1818 f13 = make_fpr(13);
1819 f14 = make_fpr(14);
1820 f15 = make_fpr(15);
1821
1822 /* 1st operand --> (f12, f14) */
1823 addInstr(env, s390_insn_move(8, f12, op1_hi));
1824 addInstr(env, s390_insn_move(8, f14, op1_lo));
1825
1826 /* 2nd operand --> (f13, f15) */
1827 addInstr(env, s390_insn_move(8, f13, op2_hi));
1828 addInstr(env, s390_insn_move(8, f15, op2_lo));
1829
1830 switch (op) {
1831 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1832 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1833 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1834 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1835 default:
1836 goto irreducible;
1837 }
1838
florian2c74d242012-09-12 19:38:42 +00001839 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1840 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001841
1842 /* Move result to virtual destination register */
1843 *dst_hi = newVRegF(env);
1844 *dst_lo = newVRegF(env);
1845 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1846 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1847
1848 return;
1849 }
1850
1851 /* --------- BINARY OP --------- */
1852 case Iex_Binop: {
1853 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001854
1855 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1856 f12 = make_fpr(12);
1857 f13 = make_fpr(13);
1858 f14 = make_fpr(14);
1859 f15 = make_fpr(15);
1860
1861 switch (expr->Iex.Binop.op) {
1862 case Iop_SqrtF128:
1863 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1864
1865 /* operand --> (f13, f15) */
1866 addInstr(env, s390_insn_move(8, f13, op_hi));
1867 addInstr(env, s390_insn_move(8, f15, op_lo));
1868
florian2c74d242012-09-12 19:38:42 +00001869 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1870 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1871 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001872
1873 /* Move result to virtual destination registers */
1874 *dst_hi = newVRegF(env);
1875 *dst_lo = newVRegF(env);
1876 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1877 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1878 return;
1879
1880 case Iop_F64HLtoF128:
1881 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1882 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1883 return;
1884
1885 default:
1886 goto irreducible;
1887 }
1888 }
1889
1890 /* --------- UNARY OP --------- */
1891 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001892 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001893 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00001894 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001895 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1896
1897 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1898 f12 = make_fpr(12);
1899 f13 = make_fpr(13);
1900 f14 = make_fpr(14);
1901 f15 = make_fpr(15);
1902
florian66e596d2012-09-07 15:00:53 +00001903 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001904 case Iop_NegF128:
1905 if (left->tag == Iex_Unop &&
1906 (left->Iex.Unop.op == Iop_AbsF32 ||
1907 left->Iex.Unop.op == Iop_AbsF64))
1908 bfpop = S390_BFP_NABS;
1909 else
1910 bfpop = S390_BFP_NEG;
1911 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00001912 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1913 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1914 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1915 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1916 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1917 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1918 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001919 default:
1920 goto irreducible;
1921 }
1922
1923 float128_opnd:
1924 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1925
1926 /* operand --> (f13, f15) */
1927 addInstr(env, s390_insn_move(8, f13, op_hi));
1928 addInstr(env, s390_insn_move(8, f15, op_lo));
1929
florian2c74d242012-09-12 19:38:42 +00001930 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001931 goto move_dst;
1932
1933 convert_float:
1934 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001935 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001936 goto move_dst;
1937
1938 convert_int:
1939 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001940 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001941 goto move_dst;
1942
1943 move_dst:
1944 /* Move result to virtual destination registers */
1945 *dst_hi = newVRegF(env);
1946 *dst_lo = newVRegF(env);
1947 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1948 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1949 return;
1950 }
1951
1952 default:
1953 goto irreducible;
1954 }
1955
1956 /* We get here if no pattern matched. */
1957 irreducible:
1958 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00001959 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00001960}
1961
1962/* Compute a 128-bit value into two 64-bit registers. These may be either
1963 real or virtual regs; in any case they must not be changed by subsequent
1964 code emitted by the caller. */
1965static void
1966s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1967{
1968 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1969
1970 /* Sanity checks ... */
1971 vassert(hregIsVirtual(*dst_hi));
1972 vassert(hregIsVirtual(*dst_lo));
1973 vassert(hregClass(*dst_hi) == HRcFlt64);
1974 vassert(hregClass(*dst_lo) == HRcFlt64);
1975}
1976
1977
1978/*---------------------------------------------------------*/
1979/*--- ISEL: Floating point expressions (64 bit) ---*/
1980/*---------------------------------------------------------*/
1981
1982static HReg
1983s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1984{
1985 IRType ty = typeOfIRExpr(env->type_env, expr);
1986 UChar size;
1987
1988 vassert(ty == Ity_F32 || ty == Ity_F64);
1989
1990 size = sizeofIRType(ty);
1991
1992 switch (expr->tag) {
1993 case Iex_RdTmp:
1994 /* Return the virtual register that holds the temporary. */
1995 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1996
1997 /* --------- LOAD --------- */
1998 case Iex_Load: {
1999 HReg dst = newVRegF(env);
2000 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2001
2002 if (expr->Iex.Load.end != Iend_BE)
2003 goto irreducible;
2004
2005 addInstr(env, s390_insn_load(size, dst, am));
2006
2007 return dst;
2008 }
2009
2010 /* --------- GET --------- */
2011 case Iex_Get: {
2012 HReg dst = newVRegF(env);
2013 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2014
2015 addInstr(env, s390_insn_load(size, dst, am));
2016
2017 return dst;
2018 }
2019
2020 /* --------- LITERAL --------- */
2021
2022 /* Load a literal into a register. Create a "load immediate"
2023 v-insn and return the register. */
2024 case Iex_Const: {
2025 ULong value;
2026 HReg dst = newVRegF(env);
2027 const IRConst *con = expr->Iex.Const.con;
2028
2029 /* Bitwise copy of the value. No sign/zero-extension */
2030 switch (con->tag) {
2031 case Ico_F32i: value = con->Ico.F32i; break;
2032 case Ico_F64i: value = con->Ico.F64i; break;
2033 default: vpanic("s390_isel_float_expr: invalid constant");
2034 }
2035
2036 if (value != 0) vpanic("cannot load immediate floating point constant");
2037
2038 addInstr(env, s390_insn_load_immediate(size, dst, value));
2039
2040 return dst;
2041 }
2042
2043 /* --------- 4-ary OP --------- */
2044 case Iex_Qop: {
2045 HReg op1, op2, op3, dst;
2046 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002047
florian5906a6b2012-10-16 02:53:33 +00002048 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002049 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002050 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002051 dst = newVRegF(env);
2052 addInstr(env, s390_insn_move(size, dst, op1));
2053
florian96d7cc32012-06-01 20:41:24 +00002054 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002055 case Iop_MAddF32:
2056 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2057 case Iop_MSubF32:
2058 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2059
2060 default:
2061 goto irreducible;
2062 }
2063
florian2c74d242012-09-12 19:38:42 +00002064 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2065 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002066 return dst;
2067 }
2068
2069 /* --------- TERNARY OP --------- */
2070 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002071 IRTriop *triop = expr->Iex.Triop.details;
2072 IROp op = triop->op;
2073 IRExpr *left = triop->arg2;
2074 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002075 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002076 HReg h1, op2, dst;
2077
2078 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2079 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2080 dst = newVRegF(env);
2081 addInstr(env, s390_insn_move(size, dst, h1));
2082 switch (op) {
2083 case Iop_AddF32:
2084 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2085 case Iop_SubF32:
2086 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2087 case Iop_MulF32:
2088 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2089 case Iop_DivF32:
2090 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2091
2092 default:
2093 goto irreducible;
2094 }
2095
florian2c74d242012-09-12 19:38:42 +00002096 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2097 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002098 return dst;
2099 }
2100
2101 /* --------- BINARY OP --------- */
2102 case Iex_Binop: {
2103 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002104 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002105 IRExpr *left = expr->Iex.Binop.arg2;
2106 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002107 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002108
2109 switch (op) {
2110 case Iop_SqrtF32:
2111 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002112 h1 = s390_isel_float_expr(env, left);
2113 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002114 set_bfp_rounding_mode_in_fpc(env, irrm);
2115 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002116 return dst;
sewardj2019a972011-03-07 16:04:07 +00002117
florian9fcff4c2012-09-10 03:09:04 +00002118 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2119 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2120 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2121 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2122 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2123 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2124 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002125
florian9fcff4c2012-09-10 03:09:04 +00002126 convert_float:
2127 h1 = s390_isel_float_expr(env, left);
2128 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002129
florian9fcff4c2012-09-10 03:09:04 +00002130 convert_int:
2131 h1 = s390_isel_int_expr(env, left);
2132 goto convert;
2133
florian2c74d242012-09-12 19:38:42 +00002134 convert: {
florian125e20d2012-10-07 15:42:37 +00002135 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002136 /* convert-from-fixed and load-rounded have a rounding mode field
2137 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002138 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002139 if (s390_host_has_fpext) {
2140 rounding_mode = get_bfp_rounding_mode(env, irrm);
2141 } else {
2142 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002143 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002144 }
florian9fcff4c2012-09-10 03:09:04 +00002145 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2146 rounding_mode));
2147 return dst;
florian2c74d242012-09-12 19:38:42 +00002148 }
florian9fcff4c2012-09-10 03:09:04 +00002149
sewardj2019a972011-03-07 16:04:07 +00002150 default:
2151 goto irreducible;
2152
2153 case Iop_F128toF64:
2154 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002155 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002156 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002157
florian9fcff4c2012-09-10 03:09:04 +00002158 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2159 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002160
florian9fcff4c2012-09-10 03:09:04 +00002161 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002162
florian9fcff4c2012-09-10 03:09:04 +00002163 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002164 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002165 f15 = make_fpr(15);
2166
2167 /* operand --> (f13, f15) */
2168 addInstr(env, s390_insn_move(8, f13, op_hi));
2169 addInstr(env, s390_insn_move(8, f15, op_lo));
2170
2171 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002172 /* load-rounded has a rounding mode field when the floating point
2173 extension facility is installed. */
2174 if (s390_host_has_fpext) {
2175 rounding_mode = get_bfp_rounding_mode(env, irrm);
2176 } else {
2177 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002178 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002179 }
floriancc491a62012-09-10 23:44:37 +00002180 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002181 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002182 return dst;
2183 }
2184 }
sewardj2019a972011-03-07 16:04:07 +00002185 }
2186
2187 /* --------- UNARY OP --------- */
2188 case Iex_Unop: {
2189 IROp op = expr->Iex.Unop.op;
2190 IRExpr *left = expr->Iex.Unop.arg;
2191 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002192 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002193 HReg h1, dst;
2194
2195 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2196 HReg dst_hi, dst_lo;
2197
2198 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2199 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2200 }
2201
florian4d71a082011-12-18 00:08:17 +00002202 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002203 dst = newVRegF(env);
2204 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2205 addInstr(env, s390_insn_move(size, dst, h1));
2206
2207 return dst;
2208 }
2209
2210 switch (op) {
2211 case Iop_NegF32:
2212 case Iop_NegF64:
2213 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002214 (left->Iex.Unop.op == Iop_AbsF32 ||
2215 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002216 bfpop = S390_BFP_NABS;
2217 else
2218 bfpop = S390_BFP_NEG;
2219 break;
2220
2221 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002222 case Iop_AbsF64:
2223 bfpop = S390_BFP_ABS;
2224 break;
2225
2226 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2227 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2228 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2229
2230 convert_float1:
2231 h1 = s390_isel_float_expr(env, left);
2232 goto convert1;
2233
2234 convert_int1:
2235 h1 = s390_isel_int_expr(env, left);
2236 goto convert1;
2237
2238 convert1:
2239 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002240 /* No rounding mode is needed for these conversions. Just stick
2241 one in. It won't be used later on. */
2242 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002243 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002244 return dst;
2245
sewardj2019a972011-03-07 16:04:07 +00002246 default:
2247 goto irreducible;
2248 }
2249
2250 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002251 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002252 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002253 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002254 return dst;
2255 }
2256
2257 default:
2258 goto irreducible;
2259 }
2260
2261 /* We get here if no pattern matched. */
2262 irreducible:
2263 ppIRExpr(expr);
2264 vpanic("s390_isel_float_expr: cannot reduce tree");
2265}
2266
2267
2268static HReg
2269s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2270{
2271 HReg dst = s390_isel_float_expr_wrk(env, expr);
2272
2273 /* Sanity checks ... */
2274 vassert(hregClass(dst) == HRcFlt64);
2275 vassert(hregIsVirtual(dst));
2276
2277 return dst;
2278}
2279
2280
2281/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002282/*--- ISEL: Decimal point expressions (128 bit) ---*/
2283/*---------------------------------------------------------*/
2284static void
2285s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2286 IRExpr *expr)
2287{
2288 IRType ty = typeOfIRExpr(env->type_env, expr);
2289
2290 vassert(ty == Ity_D128);
2291
2292 switch (expr->tag) {
2293 case Iex_RdTmp:
2294 /* Return the virtual registers that hold the temporary. */
2295 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2296 return;
2297
2298 /* --------- LOAD --------- */
2299 case Iex_Load: {
2300 IRExpr *addr_hi, *addr_lo;
2301 s390_amode *am_hi, *am_lo;
2302
2303 if (expr->Iex.Load.end != Iend_BE)
2304 goto irreducible;
2305
2306 addr_hi = expr->Iex.Load.addr;
2307 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2308
2309 am_hi = s390_isel_amode(env, addr_hi);
2310 am_lo = s390_isel_amode(env, addr_lo);
2311
2312 *dst_hi = newVRegF(env);
2313 *dst_lo = newVRegF(env);
2314 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2315 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2316 return;
2317 }
2318
2319 /* --------- GET --------- */
2320 case Iex_Get:
2321 /* This is not supported because loading 128-bit from the guest
2322 state is almost certainly wrong. Use get_dpr_pair instead. */
2323 vpanic("Iex_Get with D128 data");
2324
2325 /* --------- 4-ary OP --------- */
2326 case Iex_Qop:
2327 vpanic("Iex_Qop with D128 data");
2328
2329 /* --------- TERNARY OP --------- */
2330 case Iex_Triop: {
2331 IRTriop *triop = expr->Iex.Triop.details;
2332 IROp op = triop->op;
2333 IRExpr *irrm = triop->arg1;
2334 IRExpr *left = triop->arg2;
2335 IRExpr *right = triop->arg3;
2336 s390_dfp_round_t rounding_mode;
2337 s390_dfp_binop_t dfpop;
2338 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2339
2340 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2341 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2342
2343 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2344 (f12, f14) as op2 and (f13, f15) as destination) */
2345 f9 = make_fpr(9);
2346 f11 = make_fpr(11);
2347 f12 = make_fpr(12);
2348 f13 = make_fpr(13);
2349 f14 = make_fpr(14);
2350 f15 = make_fpr(15);
2351
2352 /* 1st operand --> (f9, f11) */
2353 addInstr(env, s390_insn_move(8, f9, op1_hi));
2354 addInstr(env, s390_insn_move(8, f11, op1_lo));
2355
2356 /* 2nd operand --> (f12, f14) */
2357 addInstr(env, s390_insn_move(8, f12, op2_hi));
2358 addInstr(env, s390_insn_move(8, f14, op2_lo));
2359
2360 switch (op) {
2361 case Iop_AddD128: dfpop = S390_DFP_ADD; break;
2362 case Iop_SubD128: dfpop = S390_DFP_SUB; break;
2363 case Iop_MulD128: dfpop = S390_DFP_MUL; break;
2364 case Iop_DivD128: dfpop = S390_DFP_DIV; break;
2365 default:
2366 goto irreducible;
2367 }
2368
2369 /* DFP binary ops have insns with rounding mode field
2370 when the floating point extension facility is installed. */
2371 if (s390_host_has_fpext) {
2372 rounding_mode = get_dfp_rounding_mode(env, irrm);
2373 } else {
2374 set_dfp_rounding_mode_in_fpc(env, irrm);
2375 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2376 }
2377
2378 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2379 f12, f14, rounding_mode));
2380
2381 /* Move result to virtual destination register */
2382 *dst_hi = newVRegF(env);
2383 *dst_lo = newVRegF(env);
2384 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2385 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2386
2387 return;
2388 }
2389
2390 /* --------- BINARY OP --------- */
2391 case Iex_Binop: {
2392 switch (expr->Iex.Binop.op) {
2393 case Iop_D64HLtoD128:
2394 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2395 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2396 return;
2397
2398 default:
2399 goto irreducible;
2400 }
2401 }
2402
2403 /* --------- UNARY OP --------- */
2404 case Iex_Unop: {
2405 IRExpr *left = expr->Iex.Unop.arg;
2406 s390_dfp_conv_t conv;
2407 // HReg op, f12, f13, f14, f15;
2408 HReg op, f12, f14;
2409
2410 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2411 f12 = make_fpr(12);
2412 // f13 = make_fpr(13);
2413 f14 = make_fpr(14);
2414 // f15 = make_fpr(15);
2415
2416 switch (expr->Iex.Unop.op) {
2417 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
2418 default:
2419 goto irreducible;
2420 }
2421
2422 convert_dfp:
2423 op = s390_isel_dfp_expr(env, left);
2424 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2425 goto move_dst;
2426
2427 move_dst:
2428 /* Move result to virtual destination registers */
2429 *dst_hi = newVRegF(env);
2430 *dst_lo = newVRegF(env);
2431 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2432 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2433 return;
2434 }
2435
2436 default:
2437 goto irreducible;
2438 }
2439
2440 /* We get here if no pattern matched. */
2441 irreducible:
2442 ppIRExpr(expr);
2443 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2444
2445}
2446
2447
2448/* Compute a 128-bit value into two 64-bit registers. These may be either
2449 real or virtual regs; in any case they must not be changed by subsequent
2450 code emitted by the caller. */
2451static void
2452s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2453{
2454 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2455
2456 /* Sanity checks ... */
2457 vassert(hregIsVirtual(*dst_hi));
2458 vassert(hregIsVirtual(*dst_lo));
2459 vassert(hregClass(*dst_hi) == HRcFlt64);
2460 vassert(hregClass(*dst_lo) == HRcFlt64);
2461}
2462
2463
2464/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002465/*--- ISEL: Decimal point expressions (64 bit) ---*/
2466/*---------------------------------------------------------*/
2467
2468static HReg
2469s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2470{
2471 IRType ty = typeOfIRExpr(env->type_env, expr);
2472 UChar size;
2473
floriane38f6412012-12-21 17:32:12 +00002474 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002475
2476 size = sizeofIRType(ty);
2477
2478 switch (expr->tag) {
2479 case Iex_RdTmp:
2480 /* Return the virtual register that holds the temporary. */
2481 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2482
2483 /* --------- LOAD --------- */
2484 case Iex_Load: {
2485 HReg dst = newVRegF(env);
2486 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2487
2488 if (expr->Iex.Load.end != Iend_BE)
2489 goto irreducible;
2490
2491 addInstr(env, s390_insn_load(size, dst, am));
2492
2493 return dst;
2494 }
2495
2496 /* --------- GET --------- */
2497 case Iex_Get: {
2498 HReg dst = newVRegF(env);
2499 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2500
2501 addInstr(env, s390_insn_load(size, dst, am));
2502
2503 return dst;
2504 }
2505
floriane38f6412012-12-21 17:32:12 +00002506 /* --------- BINARY OP --------- */
2507 case Iex_Binop: {
2508 IROp op = expr->Iex.Binop.op;
2509 IRExpr *irrm = expr->Iex.Binop.arg1;
2510 IRExpr *left = expr->Iex.Binop.arg2;
2511 HReg h1, dst;
2512 s390_dfp_conv_t conv;
2513
2514 switch (op) {
2515 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
2516
2517 convert_dfp:
2518 h1 = s390_isel_dfp_expr(env, left);
2519 goto convert;
2520
2521 convert: {
2522 s390_dfp_round_t rounding_mode;
2523 /* convert-from-fixed and load-rounded have a rounding mode field
2524 when the floating point extension facility is installed. */
2525 dst = newVRegF(env);
2526 if (s390_host_has_fpext) {
2527 rounding_mode = get_dfp_rounding_mode(env, irrm);
2528 } else {
2529 set_dfp_rounding_mode_in_fpc(env, irrm);
2530 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2531 }
2532 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2533 rounding_mode));
2534 return dst;
2535 }
2536 default:
2537 goto irreducible;
2538
2539 case Iop_D128toD64: {
2540 HReg op_hi, op_lo, f13, f15;
2541 s390_dfp_round_t rounding_mode;
2542
2543 conv = S390_DFP_D128_TO_D64;
2544
2545 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2546
2547 /* We use non-virtual registers as pairs (f13, f15) */
2548 f13 = make_fpr(13);
2549 f15 = make_fpr(15);
2550
2551 /* operand --> (f13, f15) */
2552 addInstr(env, s390_insn_move(8, f13, op_hi));
2553 addInstr(env, s390_insn_move(8, f15, op_lo));
2554
2555 dst = newVRegF(env);
2556 /* load-rounded has a rounding mode field when the floating point
2557 extension facility is installed. */
2558 if (s390_host_has_fpext) {
2559 rounding_mode = get_dfp_rounding_mode(env, irrm);
2560 } else {
2561 set_dfp_rounding_mode_in_fpc(env, irrm);
2562 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2563 }
2564 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2565 rounding_mode));
2566 return dst;
2567 }
2568
2569 }
2570 }
2571
2572 /* --------- UNARY OP --------- */
2573 case Iex_Unop: {
2574 IROp op = expr->Iex.Unop.op;
2575 IRExpr *left = expr->Iex.Unop.arg;
2576 s390_dfp_conv_t conv;
2577 HReg h1, dst;
2578
2579 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2580 HReg dst_hi, dst_lo;
2581
2582 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2583 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2584 }
2585
2586 if (op == Iop_ReinterpI64asD64) {
2587 dst = newVRegF(env);
2588 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2589 addInstr(env, s390_insn_move(size, dst, h1));
2590
2591 return dst;
2592 }
2593
2594 switch (op) {
2595 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
2596
2597 convert_dfp1:
2598 h1 = s390_isel_dfp_expr(env, left);
2599 goto convert1;
2600
2601 convert1:
2602 dst = newVRegF(env);
2603 /* No rounding mode is needed for these conversions. Just stick
2604 one in. It won't be used later on. */
2605 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2606 S390_DFP_ROUND_NEAREST_EVEN_4));
2607 return dst;
2608
2609 default:
2610 goto irreducible;
2611 }
2612 }
2613
florian12390202012-11-10 22:34:14 +00002614 /* --------- TERNARY OP --------- */
2615 case Iex_Triop: {
2616 IRTriop *triop = expr->Iex.Triop.details;
2617 IROp op = triop->op;
2618 IRExpr *irrm = triop->arg1;
2619 IRExpr *left = triop->arg2;
2620 IRExpr *right = triop->arg3;
2621 s390_dfp_round_t rounding_mode;
2622 s390_dfp_binop_t dfpop;
2623 HReg op2, op3, dst;
2624
2625 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2626 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2627 dst = newVRegF(env);
2628 switch (op) {
2629 case Iop_AddD64: dfpop = S390_DFP_ADD; break;
2630 case Iop_SubD64: dfpop = S390_DFP_SUB; break;
2631 case Iop_MulD64: dfpop = S390_DFP_MUL; break;
2632 case Iop_DivD64: dfpop = S390_DFP_DIV; break;
2633 default:
2634 goto irreducible;
2635 }
2636 /* DFP binary ops have insns with rounding mode field
2637 when the floating point extension facility is installed. */
2638 if (s390_host_has_fpext) {
2639 rounding_mode = get_dfp_rounding_mode(env, irrm);
2640 } else {
2641 set_dfp_rounding_mode_in_fpc(env, irrm);
2642 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2643 }
2644
2645 addInstr(env,
2646 s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
2647 return dst;
2648 }
2649
2650 default:
2651 goto irreducible;
2652 }
2653
2654 /* We get here if no pattern matched. */
2655 irreducible:
2656 ppIRExpr(expr);
2657 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2658}
2659
2660static HReg
2661s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2662{
2663 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2664
2665 /* Sanity checks ... */
2666 vassert(hregClass(dst) == HRcFlt64);
2667 vassert(hregIsVirtual(dst));
2668
2669 return dst;
2670}
2671
2672
2673/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002674/*--- ISEL: Condition Code ---*/
2675/*---------------------------------------------------------*/
2676
2677/* This function handles all operators that produce a 1-bit result */
2678static s390_cc_t
2679s390_isel_cc(ISelEnv *env, IRExpr *cond)
2680{
2681 UChar size;
2682
2683 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2684
2685 /* Constant: either 1 or 0 */
2686 if (cond->tag == Iex_Const) {
2687 vassert(cond->Iex.Const.con->tag == Ico_U1);
2688 vassert(cond->Iex.Const.con->Ico.U1 == True
2689 || cond->Iex.Const.con->Ico.U1 == False);
2690
2691 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2692 }
2693
2694 /* Variable: values are 1 or 0 */
2695 if (cond->tag == Iex_RdTmp) {
2696 IRTemp tmp = cond->Iex.RdTmp.tmp;
2697 HReg reg = lookupIRTemp(env, tmp);
2698
2699 /* Load-and-test does not modify REG; so this is OK. */
2700 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2701 size = 4;
2702 else
2703 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2704 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2705 return S390_CC_NE;
2706 }
2707
2708 /* Unary operators */
2709 if (cond->tag == Iex_Unop) {
2710 IRExpr *arg = cond->Iex.Unop.arg;
2711
2712 switch (cond->Iex.Unop.op) {
2713 case Iop_Not1: /* Not1(cond) */
2714 /* Generate code for EXPR, and negate the test condition */
2715 return s390_cc_invert(s390_isel_cc(env, arg));
2716
2717 /* Iop_32/64to1 select the LSB from their operand */
2718 case Iop_32to1:
2719 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002720 HReg dst = newVRegI(env);
2721 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002722
2723 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2724
florianf366a802012-08-03 00:42:18 +00002725 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002726 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2727 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2728 return S390_CC_NE;
2729 }
2730
2731 case Iop_CmpNEZ8:
2732 case Iop_CmpNEZ16: {
2733 s390_opnd_RMI src;
2734 s390_unop_t op;
2735 HReg dst;
2736
2737 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2738 : S390_ZERO_EXTEND_16;
2739 dst = newVRegI(env);
2740 src = s390_isel_int_expr_RMI(env, arg);
2741 addInstr(env, s390_insn_unop(4, op, dst, src));
2742 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2743 return S390_CC_NE;
2744 }
2745
2746 case Iop_CmpNEZ32:
2747 case Iop_CmpNEZ64: {
2748 s390_opnd_RMI src;
2749
2750 src = s390_isel_int_expr_RMI(env, arg);
2751 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2752 addInstr(env, s390_insn_test(size, src));
2753 return S390_CC_NE;
2754 }
2755
2756 default:
2757 goto fail;
2758 }
2759 }
2760
2761 /* Binary operators */
2762 if (cond->tag == Iex_Binop) {
2763 IRExpr *arg1 = cond->Iex.Binop.arg1;
2764 IRExpr *arg2 = cond->Iex.Binop.arg2;
2765 HReg reg1, reg2;
2766
2767 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2768
2769 switch (cond->Iex.Binop.op) {
2770 s390_unop_t op;
2771 s390_cc_t result;
2772
2773 case Iop_CmpEQ8:
2774 case Iop_CasCmpEQ8:
2775 op = S390_ZERO_EXTEND_8;
2776 result = S390_CC_E;
2777 goto do_compare_ze;
2778
2779 case Iop_CmpNE8:
2780 case Iop_CasCmpNE8:
2781 op = S390_ZERO_EXTEND_8;
2782 result = S390_CC_NE;
2783 goto do_compare_ze;
2784
2785 case Iop_CmpEQ16:
2786 case Iop_CasCmpEQ16:
2787 op = S390_ZERO_EXTEND_16;
2788 result = S390_CC_E;
2789 goto do_compare_ze;
2790
2791 case Iop_CmpNE16:
2792 case Iop_CasCmpNE16:
2793 op = S390_ZERO_EXTEND_16;
2794 result = S390_CC_NE;
2795 goto do_compare_ze;
2796
2797 do_compare_ze: {
2798 s390_opnd_RMI op1, op2;
2799
2800 op1 = s390_isel_int_expr_RMI(env, arg1);
2801 reg1 = newVRegI(env);
2802 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2803
2804 op2 = s390_isel_int_expr_RMI(env, arg2);
2805 reg2 = newVRegI(env);
2806 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2807
2808 op2 = s390_opnd_reg(reg2);
2809 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2810
2811 return result;
2812 }
2813
2814 case Iop_CmpEQ32:
2815 case Iop_CmpEQ64:
2816 case Iop_CasCmpEQ32:
2817 case Iop_CasCmpEQ64:
2818 result = S390_CC_E;
2819 goto do_compare;
2820
2821 case Iop_CmpNE32:
2822 case Iop_CmpNE64:
2823 case Iop_CasCmpNE32:
2824 case Iop_CasCmpNE64:
2825 result = S390_CC_NE;
2826 goto do_compare;
2827
2828 do_compare: {
2829 HReg op1;
2830 s390_opnd_RMI op2;
2831
2832 order_commutative_operands(arg1, arg2);
2833
2834 op1 = s390_isel_int_expr(env, arg1);
2835 op2 = s390_isel_int_expr_RMI(env, arg2);
2836
2837 addInstr(env, s390_insn_compare(size, op1, op2, False));
2838
2839 return result;
2840 }
2841
2842 case Iop_CmpLT32S:
2843 case Iop_CmpLE32S:
2844 case Iop_CmpLT64S:
2845 case Iop_CmpLE64S: {
2846 HReg op1;
2847 s390_opnd_RMI op2;
2848
2849 op1 = s390_isel_int_expr(env, arg1);
2850 op2 = s390_isel_int_expr_RMI(env, arg2);
2851
2852 addInstr(env, s390_insn_compare(size, op1, op2, True));
2853
2854 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2855 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2856 }
2857
2858 case Iop_CmpLT32U:
2859 case Iop_CmpLE32U:
2860 case Iop_CmpLT64U:
2861 case Iop_CmpLE64U: {
2862 HReg op1;
2863 s390_opnd_RMI op2;
2864
2865 op1 = s390_isel_int_expr(env, arg1);
2866 op2 = s390_isel_int_expr_RMI(env, arg2);
2867
2868 addInstr(env, s390_insn_compare(size, op1, op2, False));
2869
2870 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2871 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2872 }
2873
2874 default:
2875 goto fail;
2876 }
2877 }
2878
2879 fail:
2880 ppIRExpr(cond);
2881 vpanic("s390_isel_cc: unexpected operator");
2882}
2883
2884
2885/*---------------------------------------------------------*/
2886/*--- ISEL: Statements ---*/
2887/*---------------------------------------------------------*/
2888
2889static void
2890s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2891{
2892 if (vex_traceflags & VEX_TRACE_VCODE) {
2893 vex_printf("\n -- ");
2894 ppIRStmt(stmt);
2895 vex_printf("\n");
2896 }
2897
2898 switch (stmt->tag) {
2899
2900 /* --------- STORE --------- */
2901 case Ist_Store: {
2902 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2903 s390_amode *am;
2904 HReg src;
2905
2906 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2907
2908 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2909
2910 switch (tyd) {
2911 case Ity_I8:
2912 case Ity_I16:
2913 case Ity_I32:
2914 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00002915 if (am->tag == S390_AMODE_B12 &&
2916 s390_expr_is_const_zero(stmt->Ist.Store.data)) {
2917 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
2918 return;
2919 }
sewardj2019a972011-03-07 16:04:07 +00002920 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2921 break;
2922
2923 case Ity_F32:
2924 case Ity_F64:
2925 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2926 break;
2927
florianeb981ae2012-12-21 18:55:03 +00002928 case Ity_D32:
2929 case Ity_D64:
2930 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
2931 break;
2932
sewardj2019a972011-03-07 16:04:07 +00002933 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00002934 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00002935 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00002936 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00002937
2938 default:
2939 goto stmt_fail;
2940 }
2941
2942 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2943 return;
2944 }
2945
2946 /* --------- PUT --------- */
2947 case Ist_Put: {
2948 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2949 HReg src;
2950 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002951 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002952
florianad43b3a2012-02-20 15:01:14 +00002953 /* Detect updates to certain guest registers. We track the contents
2954 of those registers as long as they contain constants. If the new
2955 constant is either zero or in the 8-bit neighbourhood of the
2956 current value we can use a memory-to-memory insn to do the update. */
2957
2958 Int offset = stmt->Ist.Put.offset;
2959
2960 /* Check necessary conditions:
2961 (1) must be one of the registers we care about
2962 (2) assigned value must be a constant */
2963 Int guest_reg = get_guest_reg(offset);
2964
2965 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2966
2967 if (guest_reg == GUEST_IA) {
2968 /* If this is the first assignment to the IA reg, don't special case
2969 it. We need to do a full 8-byte assignment here. The reason is
2970 that in case of a redirected translation the guest IA does not
2971 contain the redirected-to address. Instead it contains the
2972 redirected-from address and those can be far apart. So in order to
2973 do incremnetal updates if the IA in the future we need to get the
2974 initial address of the super block correct. */
2975 if (env->first_IA_assignment) {
2976 env->first_IA_assignment = False;
2977 goto not_special;
2978 }
2979 }
2980
2981 if (stmt->Ist.Put.data->tag != Iex_Const) {
2982 /* Invalidate guest register contents */
2983 env->old_value_valid[guest_reg] = False;
2984 goto not_special;
2985 }
2986
cborntraaf7ad282012-08-08 14:11:33 +00002987 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2988 if (tyd != Ity_I64)
2989 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002990
cborntraaf7ad282012-08-08 14:11:33 +00002991 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002992
2993 old_value = env->old_value[guest_reg];
2994 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2995 env->old_value[guest_reg] = new_value;
2996
2997 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2998 env->old_value_valid[guest_reg] = True;
2999
3000 /* If the register already contains the new value, there is nothing
3001 to do here. Unless the guest register requires precise memory
3002 exceptions. */
3003 if (old_value_is_valid && new_value == old_value) {
3004 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
3005 return;
3006 }
3007 }
3008
3009 /* guest register = 0 */
3010 if (new_value == 0) {
florian09bbba82012-12-11 04:09:43 +00003011 am = s390_amode_for_guest_state(offset);
3012 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
florianad43b3a2012-02-20 15:01:14 +00003013 return;
3014 }
3015
3016 if (old_value_is_valid == False) goto not_special;
3017
3018 /* If the new value is in the neighbourhood of the old value
3019 we can use a memory-to-memory insn */
3020 difference = new_value - old_value;
3021
3022 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
3023 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
3024 (difference & 0xFF), new_value));
3025 return;
3026 }
3027
3028 /* If the high word is the same it is sufficient to load the low word.
3029 Use R0 as a scratch reg. */
3030 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00003031 HReg r0 = make_gpr(0);
3032 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00003033 s390_amode *gam;
3034
3035 gam = s390_amode_b12(offset + 4, gsp);
3036 addInstr(env, s390_insn_load_immediate(4, r0,
3037 new_value & 0xFFFFFFFF));
3038 addInstr(env, s390_insn_store(4, gam, r0));
3039 return;
3040 }
3041
3042 /* No special case applies... fall through */
3043
3044 not_special:
sewardj2019a972011-03-07 16:04:07 +00003045 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
3046
3047 switch (tyd) {
3048 case Ity_I8:
3049 case Ity_I16:
3050 case Ity_I32:
3051 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003052 if (am->tag == S390_AMODE_B12 &&
3053 s390_expr_is_const_zero(stmt->Ist.Put.data)) {
3054 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
3055 return;
3056 }
sewardj2019a972011-03-07 16:04:07 +00003057 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3058 break;
3059
3060 case Ity_F32:
3061 case Ity_F64:
3062 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3063 break;
3064
3065 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003066 case Ity_D128:
3067 /* Does not occur. See function put_(f|d)pr_pair. */
3068 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003069
floriane38f6412012-12-21 17:32:12 +00003070 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003071 case Ity_D64:
3072 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3073 break;
3074
sewardj2019a972011-03-07 16:04:07 +00003075 default:
3076 goto stmt_fail;
3077 }
3078
3079 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3080 return;
3081 }
3082
3083 /* --------- TMP --------- */
3084 case Ist_WrTmp: {
3085 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3086 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3087 HReg src, dst;
3088
3089 switch (tyd) {
3090 case Ity_I128: {
3091 HReg dst_hi, dst_lo, res_hi, res_lo;
3092
3093 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3094 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3095
3096 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3097 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3098 return;
3099 }
3100
3101 case Ity_I8:
3102 case Ity_I16:
3103 case Ity_I32:
3104 case Ity_I64:
3105 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3106 dst = lookupIRTemp(env, tmp);
3107 break;
3108
3109 case Ity_I1: {
3110 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3111 dst = lookupIRTemp(env, tmp);
3112 addInstr(env, s390_insn_cc2bool(dst, cond));
3113 return;
3114 }
3115
3116 case Ity_F32:
3117 case Ity_F64:
3118 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3119 dst = lookupIRTemp(env, tmp);
3120 break;
3121
3122 case Ity_F128: {
3123 HReg dst_hi, dst_lo, res_hi, res_lo;
3124
3125 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3126 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3127
3128 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3129 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3130 return;
3131 }
3132
floriane38f6412012-12-21 17:32:12 +00003133 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003134 case Ity_D64:
3135 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3136 dst = lookupIRTemp(env, tmp);
3137 break;
3138
floriane38f6412012-12-21 17:32:12 +00003139 case Ity_D128: {
3140 HReg dst_hi, dst_lo, res_hi, res_lo;
3141
3142 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3143 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3144
3145 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3146 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3147 return;
3148 }
3149
sewardj2019a972011-03-07 16:04:07 +00003150 default:
3151 goto stmt_fail;
3152 }
3153
3154 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3155 return;
3156 }
3157
3158 /* --------- Call to DIRTY helper --------- */
3159 case Ist_Dirty: {
3160 IRType retty;
3161 IRDirty* d = stmt->Ist.Dirty.details;
3162 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003163 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003164 Int i;
3165
3166 /* Invalidate tracked values of those guest state registers that are
3167 modified by this helper. */
3168 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003169 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3170 descriptors in guest state effect descriptions. Hence: */
3171 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003172 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3173 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3174 if (guest_reg != GUEST_UNKNOWN)
3175 env->old_value_valid[guest_reg] = False;
3176 }
3177 }
sewardj2019a972011-03-07 16:04:07 +00003178
3179 if (d->nFxState == 0)
3180 vassert(!d->needsBBP);
3181
3182 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3183
florian01ed6e72012-05-27 16:52:43 +00003184 if (d->tmp == IRTemp_INVALID) {
3185 /* No return value. */
3186 dst = INVALID_HREG;
3187 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003188 return;
florian01ed6e72012-05-27 16:52:43 +00003189 }
sewardj2019a972011-03-07 16:04:07 +00003190
3191 retty = typeOfIRTemp(env->type_env, d->tmp);
3192 if (retty == Ity_I64 || retty == Ity_I32
3193 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003194 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003195 dst = lookupIRTemp(env, d->tmp);
3196 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003197 return;
3198 }
3199 break;
3200 }
3201
3202 case Ist_CAS:
3203 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3204 IRCAS *cas = stmt->Ist.CAS.details;
3205 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3206 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3207 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3208 HReg old = lookupIRTemp(env, cas->oldLo);
3209
3210 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3211 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3212 } else {
3213 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3214 }
3215 return;
3216 } else {
florian448cbba2012-06-06 02:26:01 +00003217 IRCAS *cas = stmt->Ist.CAS.details;
3218 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3219 HReg r8, r9, r10, r11, r1;
3220 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3221 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3222 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3223 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3224 HReg old_low = lookupIRTemp(env, cas->oldLo);
3225 HReg old_high = lookupIRTemp(env, cas->oldHi);
3226
3227 /* Use non-virtual registers r8 and r9 as pair for op1
3228 and move op1 there */
3229 r8 = make_gpr(8);
3230 r9 = make_gpr(9);
3231 addInstr(env, s390_insn_move(8, r8, op1_high));
3232 addInstr(env, s390_insn_move(8, r9, op1_low));
3233
3234 /* Use non-virtual registers r10 and r11 as pair for op3
3235 and move op3 there */
3236 r10 = make_gpr(10);
3237 r11 = make_gpr(11);
3238 addInstr(env, s390_insn_move(8, r10, op3_high));
3239 addInstr(env, s390_insn_move(8, r11, op3_low));
3240
3241 /* Register r1 is used as a scratch register */
3242 r1 = make_gpr(1);
3243
3244 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3245 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3246 old_high, old_low, r1));
3247 } else {
3248 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3249 old_high, old_low, r1));
3250 }
3251 addInstr(env, s390_insn_move(8, op1_high, r8));
3252 addInstr(env, s390_insn_move(8, op1_low, r9));
3253 addInstr(env, s390_insn_move(8, op3_high, r10));
3254 addInstr(env, s390_insn_move(8, op3_low, r11));
3255 return;
sewardj2019a972011-03-07 16:04:07 +00003256 }
3257 break;
3258
3259 /* --------- EXIT --------- */
3260 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003261 s390_cc_t cond;
3262 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3263
3264 if (tag != Ico_U64)
3265 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3266
florian8844a632012-04-13 04:04:06 +00003267 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003268 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003269
3270 /* Case: boring transfer to known address */
3271 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3272 if (env->chaining_allowed) {
3273 /* .. almost always true .. */
3274 /* Skip the event check at the dst if this is a forwards
3275 edge. */
3276 Bool to_fast_entry
3277 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3278 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3279 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3280 guest_IA, to_fast_entry));
3281 } else {
3282 /* .. very occasionally .. */
3283 /* We can't use chaining, so ask for an assisted transfer,
3284 as that's the only alternative that is allowable. */
3285 HReg dst = s390_isel_int_expr(env,
3286 IRExpr_Const(stmt->Ist.Exit.dst));
3287 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3288 }
3289 return;
3290 }
3291
3292 /* Case: assisted transfer to arbitrary address */
3293 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003294 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003295 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003296 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003297 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003298 case Ijk_Sys_syscall:
3299 case Ijk_ClientReq:
3300 case Ijk_NoRedir:
3301 case Ijk_Yield:
3302 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003303 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3304 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3305 stmt->Ist.Exit.jk));
3306 return;
3307 }
3308 default:
3309 break;
3310 }
3311
3312 /* Do we ever expect to see any other kind? */
3313 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003314 }
3315
3316 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003317 case Ist_MBE:
3318 switch (stmt->Ist.MBE.event) {
3319 case Imbe_Fence:
3320 addInstr(env, s390_insn_mfence());
3321 return;
3322 default:
3323 break;
3324 }
sewardj2019a972011-03-07 16:04:07 +00003325 break;
3326
3327 /* --------- Miscellaneous --------- */
3328
3329 case Ist_PutI: /* Not needed */
3330 case Ist_IMark: /* Doesn't generate any executable code */
3331 case Ist_NoOp: /* Doesn't generate any executable code */
3332 case Ist_AbiHint: /* Meaningless in IR */
3333 return;
3334
3335 default:
3336 break;
3337 }
3338
3339 stmt_fail:
3340 ppIRStmt(stmt);
3341 vpanic("s390_isel_stmt");
3342}
3343
3344
3345/*---------------------------------------------------------*/
3346/*--- ISEL: Basic block terminators (Nexts) ---*/
3347/*---------------------------------------------------------*/
3348
3349static void
florianffbd84d2012-12-09 02:06:29 +00003350iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003351{
sewardj2019a972011-03-07 16:04:07 +00003352 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003353 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003354 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003355 vex_printf("; exit-");
3356 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003357 vex_printf("\n");
3358 }
3359
florian8844a632012-04-13 04:04:06 +00003360 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3361
3362 /* Case: boring transfer to known address */
3363 if (next->tag == Iex_Const) {
3364 IRConst *cdst = next->Iex.Const.con;
3365 vassert(cdst->tag == Ico_U64);
3366 if (jk == Ijk_Boring || jk == Ijk_Call) {
3367 /* Boring transfer to known address */
3368 if (env->chaining_allowed) {
3369 /* .. almost always true .. */
3370 /* Skip the event check at the dst if this is a forwards
3371 edge. */
3372 Bool to_fast_entry
3373 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3374 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3375 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3376 guest_IA, to_fast_entry));
3377 } else {
3378 /* .. very occasionally .. */
3379 /* We can't use chaining, so ask for an indirect transfer,
3380 as that's the cheapest alternative that is allowable. */
3381 HReg dst = s390_isel_int_expr(env, next);
3382 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3383 Ijk_Boring));
3384 }
3385 return;
3386 }
3387 }
3388
3389 /* Case: call/return (==boring) transfer to any address */
3390 switch (jk) {
3391 case Ijk_Boring:
3392 case Ijk_Ret:
3393 case Ijk_Call: {
3394 HReg dst = s390_isel_int_expr(env, next);
3395 if (env->chaining_allowed) {
3396 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3397 } else {
3398 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3399 Ijk_Boring));
3400 }
3401 return;
3402 }
3403 default:
3404 break;
3405 }
3406
3407 /* Case: some other kind of transfer to any address */
3408 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003409 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003410 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003411 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003412 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003413 case Ijk_Sys_syscall:
3414 case Ijk_ClientReq:
3415 case Ijk_NoRedir:
3416 case Ijk_Yield:
3417 case Ijk_SigTRAP: {
3418 HReg dst = s390_isel_int_expr(env, next);
3419 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3420 return;
3421 }
3422 default:
3423 break;
3424 }
3425
3426 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003427}
3428
3429
3430/*---------------------------------------------------------*/
3431/*--- Insn selector top-level ---*/
3432/*---------------------------------------------------------*/
3433
florianf26994a2012-04-21 03:34:54 +00003434/* Translate an entire SB to s390 code.
3435 Note: archinfo_host is a pointer to a stack-allocated variable.
3436 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003437
3438HInstrArray *
3439iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003440 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3441 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3442 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003443{
3444 UInt i, j;
3445 HReg hreg, hregHI;
3446 ISelEnv *env;
3447 UInt hwcaps_host = archinfo_host->hwcaps;
3448
florianf26994a2012-04-21 03:34:54 +00003449 /* KLUDGE: export hwcaps. */
3450 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003451
sewardj2019a972011-03-07 16:04:07 +00003452 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003453 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003454
3455 /* Make up an initial environment to use. */
3456 env = LibVEX_Alloc(sizeof(ISelEnv));
3457 env->vreg_ctr = 0;
3458
3459 /* Set up output code array. */
3460 env->code = newHInstrArray();
3461
3462 /* Copy BB's type env. */
3463 env->type_env = bb->tyenv;
3464
florianad43b3a2012-02-20 15:01:14 +00003465 /* Set up data structures for tracking guest register values. */
3466 env->first_IA_assignment = True;
3467 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3468 env->old_value[i] = 0; /* just something to have a defined value */
3469 env->old_value_valid[i] = False;
3470 }
3471
sewardj2019a972011-03-07 16:04:07 +00003472 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3473 change as we go along. For some reason types_used has Int type -- but
3474 it should be unsigned. Internally we use an unsigned type; so we
3475 assert it here. */
3476 vassert(bb->tyenv->types_used >= 0);
3477
3478 env->n_vregmap = bb->tyenv->types_used;
3479 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3480 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3481
florian2c74d242012-09-12 19:38:42 +00003482 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003483 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003484
sewardj2019a972011-03-07 16:04:07 +00003485 /* and finally ... */
3486 env->hwcaps = hwcaps_host;
3487
florian8844a632012-04-13 04:04:06 +00003488 env->max_ga = max_ga;
3489 env->chaining_allowed = chaining_allowed;
3490
sewardj2019a972011-03-07 16:04:07 +00003491 /* For each IR temporary, allocate a suitably-kinded virtual
3492 register. */
3493 j = 0;
3494 for (i = 0; i < env->n_vregmap; i++) {
3495 hregHI = hreg = INVALID_HREG;
3496 switch (bb->tyenv->types[i]) {
3497 case Ity_I1:
3498 case Ity_I8:
3499 case Ity_I16:
3500 case Ity_I32:
3501 hreg = mkHReg(j++, HRcInt64, True);
3502 break;
3503
3504 case Ity_I64:
3505 hreg = mkHReg(j++, HRcInt64, True);
3506 break;
3507
3508 case Ity_I128:
3509 hreg = mkHReg(j++, HRcInt64, True);
3510 hregHI = mkHReg(j++, HRcInt64, True);
3511 break;
3512
3513 case Ity_F32:
3514 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003515 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003516 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003517 hreg = mkHReg(j++, HRcFlt64, True);
3518 break;
3519
3520 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003521 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003522 hreg = mkHReg(j++, HRcFlt64, True);
3523 hregHI = mkHReg(j++, HRcFlt64, True);
3524 break;
3525
3526 case Ity_V128: /* fall through */
3527 default:
3528 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003529 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003530 }
3531
3532 env->vregmap[i] = hreg;
3533 env->vregmapHI[i] = hregHI;
3534 }
3535 env->vreg_ctr = j;
3536
florian8844a632012-04-13 04:04:06 +00003537 /* The very first instruction must be an event check. */
3538 s390_amode *counter, *fail_addr;
3539 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3540 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3541 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3542
3543 /* Possibly a block counter increment (for profiling). At this
3544 point we don't know the address of the counter, so just pretend
3545 it is zero. It will have to be patched later, but before this
3546 translation is used, by a call to LibVEX_patchProfInc. */
3547 if (add_profinc) {
3548 addInstr(env, s390_insn_profinc());
3549 }
3550
sewardj2019a972011-03-07 16:04:07 +00003551 /* Ok, finally we can iterate over the statements. */
3552 for (i = 0; i < bb->stmts_used; i++)
3553 if (bb->stmts[i])
3554 s390_isel_stmt(env, bb->stmts[i]);
3555
florian8844a632012-04-13 04:04:06 +00003556 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003557
3558 /* Record the number of vregs we used. */
3559 env->code->n_vregs = env->vreg_ctr;
3560
3561 return env->code;
3562}
3563
3564/*---------------------------------------------------------------*/
3565/*--- end host_s390_isel.c ---*/
3566/*---------------------------------------------------------------*/