blob: 2567b208abd612b48fe32277b4a828f83a9b4334 [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
sewardj2019a972011-03-07 16:04:07 +0000730/* CC_S390 holds the condition code in s390 encoding. Convert it to
731 VEX encoding
732
733 s390 VEX b6 b2 b0 cc.1 cc.0
734 0 0x40 EQ 1 0 0 0 0
735 1 0x01 LT 0 0 1 0 1
736 2 0x00 GT 0 0 0 1 0
737 3 0x45 Unordered 1 1 1 1 1
738
739 b0 = cc.0
740 b2 = cc.0 & cc.1
741 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
742
743 VEX = b0 | (b2 << 2) | (b6 << 6);
744*/
745static HReg
746convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390)
747{
748 HReg cc0, cc1, b2, b6, cc_vex;
749
750 cc0 = newVRegI(env);
751 addInstr(env, s390_insn_move(4, cc0, cc_s390));
752 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
753
754 cc1 = newVRegI(env);
755 addInstr(env, s390_insn_move(4, cc1, cc_s390));
756 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
757
758 b2 = newVRegI(env);
759 addInstr(env, s390_insn_move(4, b2, cc0));
760 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
761 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
762
763 b6 = newVRegI(env);
764 addInstr(env, s390_insn_move(4, b6, cc0));
765 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
766 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
767 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
768 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
769
770 cc_vex = newVRegI(env);
771 addInstr(env, s390_insn_move(4, cc_vex, cc0));
772 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
773 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
774
775 return cc_vex;
776}
777
778
779/*---------------------------------------------------------*/
780/*--- ISEL: Integer expressions (128 bit) ---*/
781/*---------------------------------------------------------*/
782static void
783s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
784 IRExpr *expr)
785{
786 IRType ty = typeOfIRExpr(env->type_env, expr);
787
788 vassert(ty == Ity_I128);
789
790 /* No need to consider the following
791 - 128-bit constants (they do not exist in VEX)
792 - 128-bit loads from memory (will not be generated)
793 */
794
795 /* Read 128-bit IRTemp */
796 if (expr->tag == Iex_RdTmp) {
797 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
798 return;
799 }
800
801 if (expr->tag == Iex_Binop) {
802 IRExpr *arg1 = expr->Iex.Binop.arg1;
803 IRExpr *arg2 = expr->Iex.Binop.arg2;
804 Bool is_signed_multiply, is_signed_divide;
805
806 switch (expr->Iex.Binop.op) {
807 case Iop_MullU64:
808 is_signed_multiply = False;
809 goto do_multiply64;
810
811 case Iop_MullS64:
812 is_signed_multiply = True;
813 goto do_multiply64;
814
815 case Iop_DivModU128to64:
816 is_signed_divide = False;
817 goto do_divide64;
818
819 case Iop_DivModS128to64:
820 is_signed_divide = True;
821 goto do_divide64;
822
823 case Iop_64HLto128:
824 *dst_hi = s390_isel_int_expr(env, arg1);
825 *dst_lo = s390_isel_int_expr(env, arg2);
826 return;
827
828 case Iop_DivModS64to64: {
829 HReg r10, r11, h1;
830 s390_opnd_RMI op2;
831
832 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
833 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
834
835 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000836 r10 = make_gpr(10);
837 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000838
839 /* Move 1st operand into r11 and */
840 addInstr(env, s390_insn_move(8, r11, h1));
841
842 /* Divide */
843 addInstr(env, s390_insn_divs(8, r10, r11, op2));
844
845 /* The result is in registers r10 (remainder) and r11 (quotient).
846 Move the result into the reg pair that is being returned such
847 such that the low 64 bits are the quotient and the upper 64 bits
848 are the remainder. (see libvex_ir.h). */
849 *dst_hi = newVRegI(env);
850 *dst_lo = newVRegI(env);
851 addInstr(env, s390_insn_move(8, *dst_hi, r10));
852 addInstr(env, s390_insn_move(8, *dst_lo, r11));
853 return;
854 }
855
856 default:
857 break;
858
859 do_multiply64: {
860 HReg r10, r11, h1;
861 s390_opnd_RMI op2;
862
863 order_commutative_operands(arg1, arg2);
864
865 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
866 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
867
868 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000869 r10 = make_gpr(10);
870 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000871
872 /* Move the first operand to r11 */
873 addInstr(env, s390_insn_move(8, r11, h1));
874
875 /* Multiply */
876 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
877
878 /* The result is in registers r10 and r11. Assign to two virtual regs
879 and return. */
880 *dst_hi = newVRegI(env);
881 *dst_lo = newVRegI(env);
882 addInstr(env, s390_insn_move(8, *dst_hi, r10));
883 addInstr(env, s390_insn_move(8, *dst_lo, r11));
884 return;
885 }
886
887 do_divide64: {
888 HReg r10, r11, hi, lo;
889 s390_opnd_RMI op2;
890
891 s390_isel_int128_expr(&hi, &lo, env, arg1);
892 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
893
894 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000895 r10 = make_gpr(10);
896 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000897
898 /* Move high 64 bits of the 1st operand into r10 and
899 the low 64 bits into r11. */
900 addInstr(env, s390_insn_move(8, r10, hi));
901 addInstr(env, s390_insn_move(8, r11, lo));
902
903 /* Divide */
904 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
905
906 /* The result is in registers r10 (remainder) and r11 (quotient).
907 Move the result into the reg pair that is being returned such
908 such that the low 64 bits are the quotient and the upper 64 bits
909 are the remainder. (see libvex_ir.h). */
910 *dst_hi = newVRegI(env);
911 *dst_lo = newVRegI(env);
912 addInstr(env, s390_insn_move(8, *dst_hi, r10));
913 addInstr(env, s390_insn_move(8, *dst_lo, r11));
914 return;
915 }
916 }
917 }
918
919 vpanic("s390_isel_int128_expr");
920}
921
922
923/* Compute a 128-bit value into two 64-bit registers. These may be either
924 real or virtual regs; in any case they must not be changed by subsequent
925 code emitted by the caller. */
926static void
927s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
928{
929 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
930
931 /* Sanity checks ... */
932 vassert(hregIsVirtual(*dst_hi));
933 vassert(hregIsVirtual(*dst_lo));
934 vassert(hregClass(*dst_hi) == HRcInt64);
935 vassert(hregClass(*dst_lo) == HRcInt64);
936}
937
938
939/*---------------------------------------------------------*/
940/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
941/*---------------------------------------------------------*/
942
943/* Select insns for an integer-typed expression, and add them to the
944 code list. Return a reg holding the result. This reg will be a
945 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
946 want to modify it, ask for a new vreg, copy it in there, and modify
947 the copy. The register allocator will do its best to map both
948 vregs to the same real register, so the copies will often disappear
949 later in the game.
950
951 This should handle expressions of 64, 32, 16 and 8-bit type.
952 All results are returned in a 64bit register.
953 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
954 are arbitrary, so you should mask or sign extend partial values
955 if necessary.
956*/
957
958/* DO NOT CALL THIS DIRECTLY ! */
959static HReg
960s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
961{
962 IRType ty = typeOfIRExpr(env->type_env, expr);
963 UChar size;
florian9fcff4c2012-09-10 03:09:04 +0000964 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +0000965
966 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
967
968 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
969
970 switch (expr->tag) {
971
972 /* --------- TEMP --------- */
973 case Iex_RdTmp:
974 /* Return the virtual register that holds the temporary. */
975 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
976
977 /* --------- LOAD --------- */
978 case Iex_Load: {
979 HReg dst = newVRegI(env);
980 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
981
982 if (expr->Iex.Load.end != Iend_BE)
983 goto irreducible;
984
985 addInstr(env, s390_insn_load(size, dst, am));
986
987 return dst;
988 }
989
990 /* --------- BINARY OP --------- */
991 case Iex_Binop: {
992 IRExpr *arg1 = expr->Iex.Binop.arg1;
993 IRExpr *arg2 = expr->Iex.Binop.arg2;
994 HReg h1, res;
995 s390_alu_t opkind;
996 s390_opnd_RMI op2, value, opnd;
997 s390_insn *insn;
998 Bool is_commutative, is_signed_multiply, is_signed_divide;
999
1000 is_commutative = True;
1001
1002 switch (expr->Iex.Binop.op) {
1003 case Iop_MullU8:
1004 case Iop_MullU16:
1005 case Iop_MullU32:
1006 is_signed_multiply = False;
1007 goto do_multiply;
1008
1009 case Iop_MullS8:
1010 case Iop_MullS16:
1011 case Iop_MullS32:
1012 is_signed_multiply = True;
1013 goto do_multiply;
1014
1015 do_multiply: {
1016 HReg r10, r11;
1017 UInt arg_size = size / 2;
1018
1019 order_commutative_operands(arg1, arg2);
1020
1021 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1022 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1023
1024 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001025 r10 = make_gpr(10);
1026 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001027
1028 /* Move the first operand to r11 */
1029 addInstr(env, s390_insn_move(arg_size, r11, h1));
1030
1031 /* Multiply */
1032 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1033
1034 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1035 value into the destination register. */
1036 res = newVRegI(env);
1037 addInstr(env, s390_insn_move(arg_size, res, r10));
1038 value = s390_opnd_imm(arg_size * 8);
1039 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1040 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1041 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1042 opnd = s390_opnd_reg(r11);
1043 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1044 return res;
1045 }
1046
1047 case Iop_DivModS64to32:
1048 is_signed_divide = True;
1049 goto do_divide;
1050
1051 case Iop_DivModU64to32:
1052 is_signed_divide = False;
1053 goto do_divide;
1054
1055 do_divide: {
1056 HReg r10, r11;
1057
1058 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1059 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1060
1061 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001062 r10 = make_gpr(10);
1063 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001064
1065 /* Split the first operand and put the high 32 bits into r10 and
1066 the low 32 bits into r11. */
1067 addInstr(env, s390_insn_move(8, r10, h1));
1068 addInstr(env, s390_insn_move(8, r11, h1));
1069 value = s390_opnd_imm(32);
1070 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1071
1072 /* Divide */
1073 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1074
1075 /* The result is in registers r10 (remainder) and r11 (quotient).
1076 Combine them into a 64-bit value such that the low 32 bits are
1077 the quotient and the upper 32 bits are the remainder. (see
1078 libvex_ir.h). */
1079 res = newVRegI(env);
1080 addInstr(env, s390_insn_move(8, res, r10));
1081 value = s390_opnd_imm(32);
1082 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1083 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1084 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1085 opnd = s390_opnd_reg(r11);
1086 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1087 return res;
1088 }
1089
florian9fcff4c2012-09-10 03:09:04 +00001090 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1091 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1092 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1093 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1094 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1095 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1096 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1097 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1098 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1099 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1100 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1101 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
sewardj2019a972011-03-07 16:04:07 +00001102
1103 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001104 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001105
1106 res = newVRegI(env);
1107 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1108
florian2c74d242012-09-12 19:38:42 +00001109 rounding_mode = get_bfp_rounding_mode(env, arg1);
1110 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1111 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001112 return res;
1113 }
1114
1115 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001116 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001117 HReg op_hi, op_lo, f13, f15;
1118
1119 res = newVRegI(env);
1120 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1121
1122 /* We use non-virtual registers r13 and r15 as pair */
1123 f13 = make_fpr(13);
1124 f15 = make_fpr(15);
1125
1126 /* operand --> (f13, f15) */
1127 addInstr(env, s390_insn_move(8, f13, op_hi));
1128 addInstr(env, s390_insn_move(8, f15, op_lo));
1129
florian2c74d242012-09-12 19:38:42 +00001130 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001131 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001132 rounding_mode));
1133 return res;
1134 }
1135
1136 case Iop_8HLto16:
1137 case Iop_16HLto32:
1138 case Iop_32HLto64: {
1139 HReg h2;
1140 UInt arg_size = size / 2;
1141
1142 res = newVRegI(env);
1143 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1144 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1145
1146 addInstr(env, s390_insn_move(arg_size, res, h1));
1147 value = s390_opnd_imm(arg_size * 8);
1148 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1149 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1150 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1151 opnd = s390_opnd_reg(h2);
1152 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1153 return res;
1154 }
1155
1156 case Iop_Max32U: {
1157 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1158 res = newVRegI(env);
1159 h1 = s390_isel_int_expr(env, arg1);
1160 op2 = s390_isel_int_expr_RMI(env, arg2);
1161
1162 addInstr(env, s390_insn_move(size, res, h1));
1163 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1164 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1165 return res;
1166 }
1167
1168 case Iop_CmpF32:
1169 case Iop_CmpF64: {
1170 HReg cc_s390, h2;
1171
1172 h1 = s390_isel_float_expr(env, arg1);
1173 h2 = s390_isel_float_expr(env, arg2);
1174 cc_s390 = newVRegI(env);
1175
1176 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1177
1178 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1179
1180 return convert_s390_fpcc_to_vex(env, cc_s390);
1181 }
1182
1183 case Iop_CmpF128: {
1184 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1185
1186 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1187 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1188 cc_s390 = newVRegI(env);
1189
1190 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1191 f12 = make_fpr(12);
1192 f13 = make_fpr(13);
1193 f14 = make_fpr(14);
1194 f15 = make_fpr(15);
1195
1196 /* 1st operand --> (f12, f14) */
1197 addInstr(env, s390_insn_move(8, f12, op1_hi));
1198 addInstr(env, s390_insn_move(8, f14, op1_lo));
1199
1200 /* 2nd operand --> (f13, f15) */
1201 addInstr(env, s390_insn_move(8, f13, op2_hi));
1202 addInstr(env, s390_insn_move(8, f15, op2_lo));
1203
1204 res = newVRegI(env);
1205 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1206
1207 return convert_s390_fpcc_to_vex(env, cc_s390);
1208 }
1209
floriane38f6412012-12-21 17:32:12 +00001210 case Iop_CmpD64: {
1211 HReg cc_s390, h2;
1212
1213 h1 = s390_isel_dfp_expr(env, arg1);
1214 h2 = s390_isel_dfp_expr(env, arg2);
1215 cc_s390 = newVRegI(env);
1216 size = 8;
1217
1218 addInstr(env, s390_insn_dfp_compare(size, cc_s390, h1, h2));
1219
1220 return convert_s390_fpcc_to_vex(env, cc_s390);
1221 }
1222
1223 case Iop_CmpD128: {
1224 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1225
1226 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1227 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1228 cc_s390 = newVRegI(env);
1229
1230 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1231 f12 = make_fpr(12);
1232 f13 = make_fpr(13);
1233 f14 = make_fpr(14);
1234 f15 = make_fpr(15);
1235
1236 /* 1st operand --> (f12, f14) */
1237 addInstr(env, s390_insn_move(8, f12, op1_hi));
1238 addInstr(env, s390_insn_move(8, f14, op1_lo));
1239
1240 /* 2nd operand --> (f13, f15) */
1241 addInstr(env, s390_insn_move(8, f13, op2_hi));
1242 addInstr(env, s390_insn_move(8, f15, op2_lo));
1243
1244 res = newVRegI(env);
1245 addInstr(env, s390_insn_dfp128_compare(16, cc_s390, f12, f14, f13, f15));
1246
1247 return convert_s390_fpcc_to_vex(env, cc_s390);
1248 }
1249
sewardj2019a972011-03-07 16:04:07 +00001250 case Iop_Add8:
1251 case Iop_Add16:
1252 case Iop_Add32:
1253 case Iop_Add64:
1254 opkind = S390_ALU_ADD;
1255 break;
1256
1257 case Iop_Sub8:
1258 case Iop_Sub16:
1259 case Iop_Sub32:
1260 case Iop_Sub64:
1261 opkind = S390_ALU_SUB;
1262 is_commutative = False;
1263 break;
1264
1265 case Iop_And8:
1266 case Iop_And16:
1267 case Iop_And32:
1268 case Iop_And64:
1269 opkind = S390_ALU_AND;
1270 break;
1271
1272 case Iop_Or8:
1273 case Iop_Or16:
1274 case Iop_Or32:
1275 case Iop_Or64:
1276 opkind = S390_ALU_OR;
1277 break;
1278
1279 case Iop_Xor8:
1280 case Iop_Xor16:
1281 case Iop_Xor32:
1282 case Iop_Xor64:
1283 opkind = S390_ALU_XOR;
1284 break;
1285
1286 case Iop_Shl8:
1287 case Iop_Shl16:
1288 case Iop_Shl32:
1289 case Iop_Shl64:
1290 opkind = S390_ALU_LSH;
1291 is_commutative = False;
1292 break;
1293
1294 case Iop_Shr8:
1295 case Iop_Shr16:
1296 case Iop_Shr32:
1297 case Iop_Shr64:
1298 opkind = S390_ALU_RSH;
1299 is_commutative = False;
1300 break;
1301
1302 case Iop_Sar8:
1303 case Iop_Sar16:
1304 case Iop_Sar32:
1305 case Iop_Sar64:
1306 opkind = S390_ALU_RSHA;
1307 is_commutative = False;
1308 break;
1309
1310 default:
1311 goto irreducible;
1312 }
1313
1314 /* Pattern match: 0 - arg1 --> -arg1 */
1315 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1316 res = newVRegI(env);
1317 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1318 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1319 addInstr(env, insn);
1320
1321 return res;
1322 }
1323
1324 if (is_commutative) {
1325 order_commutative_operands(arg1, arg2);
1326 }
1327
1328 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1329 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1330 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001331
1332 /* As right shifts of one/two byte opreands are implemented using a
1333 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1334 switch (expr->Iex.Binop.op) {
1335 case Iop_Shr8:
1336 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1337 break;
1338 case Iop_Shr16:
1339 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1340 break;
1341 case Iop_Sar8:
1342 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1343 break;
1344 case Iop_Sar16:
1345 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1346 break;
1347 default:
1348 insn = s390_insn_move(size, res, h1);
1349 break;
1350 }
1351 addInstr(env, insn);
1352
sewardj2019a972011-03-07 16:04:07 +00001353 insn = s390_insn_alu(size, opkind, res, op2);
1354
1355 addInstr(env, insn);
1356
1357 return res;
1358 }
1359
1360 /* --------- UNARY OP --------- */
1361 case Iex_Unop: {
1362 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1363 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1364 s390_opnd_RMI opnd;
1365 s390_insn *insn;
1366 IRExpr *arg;
1367 HReg dst, h1;
1368 IROp unop, binop;
1369
1370 arg = expr->Iex.Unop.arg;
1371
1372 /* Special cases are handled here */
1373
1374 /* 32-bit multiply with 32-bit result or
1375 64-bit multiply with 64-bit result */
1376 unop = expr->Iex.Unop.op;
1377 binop = arg->Iex.Binop.op;
1378
1379 if ((arg->tag == Iex_Binop &&
1380 ((unop == Iop_64to32 &&
1381 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1382 (unop == Iop_128to64 &&
1383 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1384 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1385 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1386 dst = newVRegI(env); /* Result goes into a new register */
1387 addInstr(env, s390_insn_move(size, dst, h1));
1388 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1389
1390 return dst;
1391 }
1392
florian4d71a082011-12-18 00:08:17 +00001393 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001394 dst = newVRegI(env);
1395 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1396 addInstr(env, s390_insn_move(size, dst, h1));
1397
1398 return dst;
1399 }
1400
floriane38f6412012-12-21 17:32:12 +00001401 if (unop == Iop_ReinterpD64asI64) {
1402 dst = newVRegI(env);
1403 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1404 addInstr(env, s390_insn_move(size, dst, h1));
1405
1406 return dst;
1407 }
1408
sewardj2019a972011-03-07 16:04:07 +00001409 /* Expressions whose argument is 1-bit wide */
1410 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1411 s390_cc_t cond = s390_isel_cc(env, arg);
1412 dst = newVRegI(env); /* Result goes into a new register */
1413 addInstr(env, s390_insn_cc2bool(dst, cond));
1414
1415 switch (unop) {
1416 case Iop_1Uto8:
1417 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001418 /* Zero extend */
1419 mask.variant.imm = 1;
1420 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1421 break;
1422
sewardj2019a972011-03-07 16:04:07 +00001423 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001424 /* Zero extend */
1425 mask.variant.imm = 1;
1426 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001427 break;
1428
1429 case Iop_1Sto8:
1430 case Iop_1Sto16:
1431 case Iop_1Sto32:
1432 shift.variant.imm = 31;
1433 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1434 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1435 break;
1436
1437 case Iop_1Sto64:
1438 shift.variant.imm = 63;
1439 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1440 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1441 break;
1442
1443 default:
1444 goto irreducible;
1445 }
1446
1447 return dst;
1448 }
1449
1450 /* Regular processing */
1451
1452 if (unop == Iop_128to64) {
1453 HReg dst_hi, dst_lo;
1454
1455 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1456 return dst_lo;
1457 }
1458
1459 if (unop == Iop_128HIto64) {
1460 HReg dst_hi, dst_lo;
1461
1462 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1463 return dst_hi;
1464 }
1465
1466 dst = newVRegI(env); /* Result goes into a new register */
1467 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1468
1469 switch (unop) {
1470 case Iop_8Uto16:
1471 case Iop_8Uto32:
1472 case Iop_8Uto64:
1473 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1474 break;
1475
1476 case Iop_16Uto32:
1477 case Iop_16Uto64:
1478 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1479 break;
1480
1481 case Iop_32Uto64:
1482 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1483 break;
1484
1485 case Iop_8Sto16:
1486 case Iop_8Sto32:
1487 case Iop_8Sto64:
1488 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1489 break;
1490
1491 case Iop_16Sto32:
1492 case Iop_16Sto64:
1493 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1494 break;
1495
1496 case Iop_32Sto64:
1497 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1498 break;
1499
1500 case Iop_64to8:
1501 case Iop_64to16:
1502 case Iop_64to32:
1503 case Iop_32to8:
1504 case Iop_32to16:
1505 case Iop_16to8:
1506 /* Down-casts are no-ops. Upstream operations will only look at
1507 the bytes that make up the result of the down-cast. So there
1508 is no point setting the other bytes to 0. */
1509 insn = s390_opnd_copy(8, dst, opnd);
1510 break;
1511
1512 case Iop_64HIto32:
1513 addInstr(env, s390_opnd_copy(8, dst, opnd));
1514 shift.variant.imm = 32;
1515 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1516 break;
1517
1518 case Iop_32HIto16:
1519 addInstr(env, s390_opnd_copy(4, dst, opnd));
1520 shift.variant.imm = 16;
1521 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1522 break;
1523
1524 case Iop_16HIto8:
1525 addInstr(env, s390_opnd_copy(2, dst, opnd));
1526 shift.variant.imm = 8;
1527 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1528 break;
1529
1530 case Iop_Not8:
1531 case Iop_Not16:
1532 case Iop_Not32:
1533 case Iop_Not64:
1534 /* XOR with ffff... */
1535 mask.variant.imm = ~(ULong)0;
1536 addInstr(env, s390_opnd_copy(size, dst, opnd));
1537 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1538 break;
1539
1540 case Iop_Left8:
1541 case Iop_Left16:
1542 case Iop_Left32:
1543 case Iop_Left64:
1544 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1545 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1546 break;
1547
1548 case Iop_CmpwNEZ32:
1549 case Iop_CmpwNEZ64: {
1550 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1551 or -X will have a 1 in the MSB. */
1552 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1553 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1554 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1555 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1556 return dst;
1557 }
1558
1559 case Iop_Clz64: {
1560 HReg r10, r11;
1561
sewardj611b06e2011-03-24 08:57:29 +00001562 /* This will be implemented using FLOGR, if possible. So we need to
1563 set aside a pair of non-virtual registers. The result (number of
1564 left-most zero bits) will be in r10. The value in r11 is unspecified
1565 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001566 r10 = make_gpr(10);
1567 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001568
sewardj611b06e2011-03-24 08:57:29 +00001569 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001570 addInstr(env, s390_insn_move(8, dst, r10));
1571 return dst;
1572 }
1573
1574 default:
1575 goto irreducible;
1576 }
1577
1578 addInstr(env, insn);
1579
1580 return dst;
1581 }
1582
1583 /* --------- GET --------- */
1584 case Iex_Get: {
1585 HReg dst = newVRegI(env);
1586 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1587
1588 /* We never load more than 8 bytes from the guest state, because the
1589 floating point register pair is not contiguous. */
1590 vassert(size <= 8);
1591
1592 addInstr(env, s390_insn_load(size, dst, am));
1593
1594 return dst;
1595 }
1596
1597 case Iex_GetI:
1598 /* not needed */
1599 break;
1600
1601 /* --------- CCALL --------- */
1602 case Iex_CCall: {
1603 HReg dst = newVRegI(env);
1604
1605 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001606 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001607 return dst;
1608 }
1609
1610 /* --------- LITERAL --------- */
1611
1612 /* Load a literal into a register. Create a "load immediate"
1613 v-insn and return the register. */
1614 case Iex_Const: {
1615 ULong value;
1616 HReg dst = newVRegI(env);
1617 const IRConst *con = expr->Iex.Const.con;
1618
1619 /* Bitwise copy of the value. No sign/zero-extension */
1620 switch (con->tag) {
1621 case Ico_U64: value = con->Ico.U64; break;
1622 case Ico_U32: value = con->Ico.U32; break;
1623 case Ico_U16: value = con->Ico.U16; break;
1624 case Ico_U8: value = con->Ico.U8; break;
1625 default: vpanic("s390_isel_int_expr: invalid constant");
1626 }
1627
1628 addInstr(env, s390_insn_load_immediate(size, dst, value));
1629
1630 return dst;
1631 }
1632
1633 /* --------- MULTIPLEX --------- */
1634 case Iex_Mux0X: {
1635 IRExpr *cond_expr;
1636 HReg dst, tmp, rX;
1637 s390_opnd_RMI cond, r0, zero;
1638
1639 cond_expr = expr->Iex.Mux0X.cond;
1640
1641 dst = newVRegI(env);
1642 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1643 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1644 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1645
1646 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1647 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1648
1649 addInstr(env, s390_insn_move(size, dst, rX));
1650 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1651 return dst;
1652 }
1653
1654 /* Assume the condition is true and move rX to the destination reg. */
1655 addInstr(env, s390_insn_move(size, dst, rX));
1656
1657 /* Compute the condition ... */
1658 cond = s390_isel_int_expr_RMI(env, cond_expr);
1659
1660 /* tmp = cond & 0xFF */
1661 tmp = newVRegI(env);
1662 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1663 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1664
1665 /* ... and compare it with zero */
1666 zero = s390_opnd_imm(0);
1667 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1668
1669 /* ... and if it compared equal move r0 to the destination reg. */
1670 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1671 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1672
1673 return dst;
1674 }
1675
1676 default:
1677 break;
1678 }
1679
1680 /* We get here if no pattern matched. */
1681 irreducible:
1682 ppIRExpr(expr);
1683 vpanic("s390_isel_int_expr: cannot reduce tree");
1684}
1685
1686
1687static HReg
1688s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1689{
1690 HReg dst = s390_isel_int_expr_wrk(env, expr);
1691
1692 /* Sanity checks ... */
1693 vassert(hregClass(dst) == HRcInt64);
1694 vassert(hregIsVirtual(dst));
1695
1696 return dst;
1697}
1698
1699
1700static s390_opnd_RMI
1701s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1702{
1703 IRType ty = typeOfIRExpr(env->type_env, expr);
1704 s390_opnd_RMI dst;
1705
1706 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1707 ty == Ity_I64);
1708
1709 if (expr->tag == Iex_Load) {
1710 dst.tag = S390_OPND_AMODE;
1711 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1712 } else if (expr->tag == Iex_Get) {
1713 dst.tag = S390_OPND_AMODE;
1714 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1715 } else if (expr->tag == Iex_Const) {
1716 ULong value;
1717
1718 /* The bit pattern for the value will be stored as is in the least
1719 significant bits of VALUE. */
1720 switch (expr->Iex.Const.con->tag) {
1721 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1722 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1723 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1724 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1725 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1726 default:
1727 vpanic("s390_isel_int_expr_RMI");
1728 }
1729
1730 dst.tag = S390_OPND_IMMEDIATE;
1731 dst.variant.imm = value;
1732 } else {
1733 dst.tag = S390_OPND_REG;
1734 dst.variant.reg = s390_isel_int_expr(env, expr);
1735 }
1736
1737 return dst;
1738}
1739
1740
1741/*---------------------------------------------------------*/
1742/*--- ISEL: Floating point expressions (128 bit) ---*/
1743/*---------------------------------------------------------*/
1744static void
1745s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1746 IRExpr *expr)
1747{
1748 IRType ty = typeOfIRExpr(env->type_env, expr);
1749
1750 vassert(ty == Ity_F128);
1751
sewardj2019a972011-03-07 16:04:07 +00001752 switch (expr->tag) {
1753 case Iex_RdTmp:
1754 /* Return the virtual registers that hold the temporary. */
1755 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1756 return;
1757
1758 /* --------- LOAD --------- */
1759 case Iex_Load: {
1760 IRExpr *addr_hi, *addr_lo;
1761 s390_amode *am_hi, *am_lo;
1762
1763 if (expr->Iex.Load.end != Iend_BE)
1764 goto irreducible;
1765
1766 addr_hi = expr->Iex.Load.addr;
1767 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1768
1769 am_hi = s390_isel_amode(env, addr_hi);
1770 am_lo = s390_isel_amode(env, addr_lo);
1771
1772 *dst_hi = newVRegF(env);
1773 *dst_lo = newVRegF(env);
1774 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1775 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1776 return;
1777 }
1778
1779
1780 /* --------- GET --------- */
1781 case Iex_Get:
1782 /* This is not supported because loading 128-bit from the guest
1783 state is almost certainly wrong. Use get_fpr_pair instead. */
1784 vpanic("Iex_Get with F128 data");
1785
1786 /* --------- 4-ary OP --------- */
1787 case Iex_Qop:
1788 vpanic("Iex_Qop with F128 data");
1789
1790 /* --------- TERNARY OP --------- */
1791 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001792 IRTriop *triop = expr->Iex.Triop.details;
1793 IROp op = triop->op;
1794 IRExpr *left = triop->arg2;
1795 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001796 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001797 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1798
1799 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1800 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1801
1802 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1803 f12 = make_fpr(12);
1804 f13 = make_fpr(13);
1805 f14 = make_fpr(14);
1806 f15 = make_fpr(15);
1807
1808 /* 1st operand --> (f12, f14) */
1809 addInstr(env, s390_insn_move(8, f12, op1_hi));
1810 addInstr(env, s390_insn_move(8, f14, op1_lo));
1811
1812 /* 2nd operand --> (f13, f15) */
1813 addInstr(env, s390_insn_move(8, f13, op2_hi));
1814 addInstr(env, s390_insn_move(8, f15, op2_lo));
1815
1816 switch (op) {
1817 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1818 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1819 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1820 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1821 default:
1822 goto irreducible;
1823 }
1824
florian2c74d242012-09-12 19:38:42 +00001825 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1826 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001827
1828 /* Move result to virtual destination register */
1829 *dst_hi = newVRegF(env);
1830 *dst_lo = newVRegF(env);
1831 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1832 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1833
1834 return;
1835 }
1836
1837 /* --------- BINARY OP --------- */
1838 case Iex_Binop: {
1839 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001840
1841 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1842 f12 = make_fpr(12);
1843 f13 = make_fpr(13);
1844 f14 = make_fpr(14);
1845 f15 = make_fpr(15);
1846
1847 switch (expr->Iex.Binop.op) {
1848 case Iop_SqrtF128:
1849 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1850
1851 /* operand --> (f13, f15) */
1852 addInstr(env, s390_insn_move(8, f13, op_hi));
1853 addInstr(env, s390_insn_move(8, f15, op_lo));
1854
florian2c74d242012-09-12 19:38:42 +00001855 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1856 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1857 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001858
1859 /* Move result to virtual destination registers */
1860 *dst_hi = newVRegF(env);
1861 *dst_lo = newVRegF(env);
1862 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1863 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1864 return;
1865
1866 case Iop_F64HLtoF128:
1867 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1868 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1869 return;
1870
1871 default:
1872 goto irreducible;
1873 }
1874 }
1875
1876 /* --------- UNARY OP --------- */
1877 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001878 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001879 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00001880 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001881 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1882
1883 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1884 f12 = make_fpr(12);
1885 f13 = make_fpr(13);
1886 f14 = make_fpr(14);
1887 f15 = make_fpr(15);
1888
florian66e596d2012-09-07 15:00:53 +00001889 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001890 case Iop_NegF128:
1891 if (left->tag == Iex_Unop &&
1892 (left->Iex.Unop.op == Iop_AbsF32 ||
1893 left->Iex.Unop.op == Iop_AbsF64))
1894 bfpop = S390_BFP_NABS;
1895 else
1896 bfpop = S390_BFP_NEG;
1897 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00001898 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1899 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1900 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1901 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1902 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1903 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1904 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001905 default:
1906 goto irreducible;
1907 }
1908
1909 float128_opnd:
1910 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1911
1912 /* operand --> (f13, f15) */
1913 addInstr(env, s390_insn_move(8, f13, op_hi));
1914 addInstr(env, s390_insn_move(8, f15, op_lo));
1915
florian2c74d242012-09-12 19:38:42 +00001916 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001917 goto move_dst;
1918
1919 convert_float:
1920 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001921 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001922 goto move_dst;
1923
1924 convert_int:
1925 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001926 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001927 goto move_dst;
1928
1929 move_dst:
1930 /* Move result to virtual destination registers */
1931 *dst_hi = newVRegF(env);
1932 *dst_lo = newVRegF(env);
1933 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1934 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1935 return;
1936 }
1937
1938 default:
1939 goto irreducible;
1940 }
1941
1942 /* We get here if no pattern matched. */
1943 irreducible:
1944 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00001945 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00001946}
1947
1948/* Compute a 128-bit value into two 64-bit registers. These may be either
1949 real or virtual regs; in any case they must not be changed by subsequent
1950 code emitted by the caller. */
1951static void
1952s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1953{
1954 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1955
1956 /* Sanity checks ... */
1957 vassert(hregIsVirtual(*dst_hi));
1958 vassert(hregIsVirtual(*dst_lo));
1959 vassert(hregClass(*dst_hi) == HRcFlt64);
1960 vassert(hregClass(*dst_lo) == HRcFlt64);
1961}
1962
1963
1964/*---------------------------------------------------------*/
1965/*--- ISEL: Floating point expressions (64 bit) ---*/
1966/*---------------------------------------------------------*/
1967
1968static HReg
1969s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1970{
1971 IRType ty = typeOfIRExpr(env->type_env, expr);
1972 UChar size;
1973
1974 vassert(ty == Ity_F32 || ty == Ity_F64);
1975
1976 size = sizeofIRType(ty);
1977
1978 switch (expr->tag) {
1979 case Iex_RdTmp:
1980 /* Return the virtual register that holds the temporary. */
1981 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1982
1983 /* --------- LOAD --------- */
1984 case Iex_Load: {
1985 HReg dst = newVRegF(env);
1986 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1987
1988 if (expr->Iex.Load.end != Iend_BE)
1989 goto irreducible;
1990
1991 addInstr(env, s390_insn_load(size, dst, am));
1992
1993 return dst;
1994 }
1995
1996 /* --------- GET --------- */
1997 case Iex_Get: {
1998 HReg dst = newVRegF(env);
1999 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2000
2001 addInstr(env, s390_insn_load(size, dst, am));
2002
2003 return dst;
2004 }
2005
2006 /* --------- LITERAL --------- */
2007
2008 /* Load a literal into a register. Create a "load immediate"
2009 v-insn and return the register. */
2010 case Iex_Const: {
2011 ULong value;
2012 HReg dst = newVRegF(env);
2013 const IRConst *con = expr->Iex.Const.con;
2014
2015 /* Bitwise copy of the value. No sign/zero-extension */
2016 switch (con->tag) {
2017 case Ico_F32i: value = con->Ico.F32i; break;
2018 case Ico_F64i: value = con->Ico.F64i; break;
2019 default: vpanic("s390_isel_float_expr: invalid constant");
2020 }
2021
2022 if (value != 0) vpanic("cannot load immediate floating point constant");
2023
2024 addInstr(env, s390_insn_load_immediate(size, dst, value));
2025
2026 return dst;
2027 }
2028
2029 /* --------- 4-ary OP --------- */
2030 case Iex_Qop: {
2031 HReg op1, op2, op3, dst;
2032 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002033
florian5906a6b2012-10-16 02:53:33 +00002034 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002035 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002036 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002037 dst = newVRegF(env);
2038 addInstr(env, s390_insn_move(size, dst, op1));
2039
florian96d7cc32012-06-01 20:41:24 +00002040 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002041 case Iop_MAddF32:
2042 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2043 case Iop_MSubF32:
2044 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2045
2046 default:
2047 goto irreducible;
2048 }
2049
florian2c74d242012-09-12 19:38:42 +00002050 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2051 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002052 return dst;
2053 }
2054
2055 /* --------- TERNARY OP --------- */
2056 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002057 IRTriop *triop = expr->Iex.Triop.details;
2058 IROp op = triop->op;
2059 IRExpr *left = triop->arg2;
2060 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002061 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002062 HReg h1, op2, dst;
2063
2064 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2065 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2066 dst = newVRegF(env);
2067 addInstr(env, s390_insn_move(size, dst, h1));
2068 switch (op) {
2069 case Iop_AddF32:
2070 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2071 case Iop_SubF32:
2072 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2073 case Iop_MulF32:
2074 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2075 case Iop_DivF32:
2076 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2077
2078 default:
2079 goto irreducible;
2080 }
2081
florian2c74d242012-09-12 19:38:42 +00002082 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2083 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002084 return dst;
2085 }
2086
2087 /* --------- BINARY OP --------- */
2088 case Iex_Binop: {
2089 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002090 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002091 IRExpr *left = expr->Iex.Binop.arg2;
2092 HReg h1, dst;
florian9fcff4c2012-09-10 03:09:04 +00002093 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002094
2095 switch (op) {
2096 case Iop_SqrtF32:
2097 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002098 h1 = s390_isel_float_expr(env, left);
2099 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002100 set_bfp_rounding_mode_in_fpc(env, irrm);
2101 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002102 return dst;
sewardj2019a972011-03-07 16:04:07 +00002103
florian9fcff4c2012-09-10 03:09:04 +00002104 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2105 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2106 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2107 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2108 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2109 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2110 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002111
florian9fcff4c2012-09-10 03:09:04 +00002112 convert_float:
2113 h1 = s390_isel_float_expr(env, left);
2114 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002115
florian9fcff4c2012-09-10 03:09:04 +00002116 convert_int:
2117 h1 = s390_isel_int_expr(env, left);
2118 goto convert;
2119
florian2c74d242012-09-12 19:38:42 +00002120 convert: {
florian125e20d2012-10-07 15:42:37 +00002121 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002122 /* convert-from-fixed and load-rounded have a rounding mode field
2123 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002124 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002125 if (s390_host_has_fpext) {
2126 rounding_mode = get_bfp_rounding_mode(env, irrm);
2127 } else {
2128 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002129 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002130 }
florian9fcff4c2012-09-10 03:09:04 +00002131 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2132 rounding_mode));
2133 return dst;
florian2c74d242012-09-12 19:38:42 +00002134 }
florian9fcff4c2012-09-10 03:09:04 +00002135
sewardj2019a972011-03-07 16:04:07 +00002136 default:
2137 goto irreducible;
2138
2139 case Iop_F128toF64:
2140 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002141 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002142 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002143
florian9fcff4c2012-09-10 03:09:04 +00002144 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2145 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002146
florian9fcff4c2012-09-10 03:09:04 +00002147 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002148
florian9fcff4c2012-09-10 03:09:04 +00002149 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002150 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002151 f15 = make_fpr(15);
2152
2153 /* operand --> (f13, f15) */
2154 addInstr(env, s390_insn_move(8, f13, op_hi));
2155 addInstr(env, s390_insn_move(8, f15, op_lo));
2156
2157 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002158 /* load-rounded has a rounding mode field when the floating point
2159 extension facility is installed. */
2160 if (s390_host_has_fpext) {
2161 rounding_mode = get_bfp_rounding_mode(env, irrm);
2162 } else {
2163 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002164 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002165 }
floriancc491a62012-09-10 23:44:37 +00002166 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002167 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002168 return dst;
2169 }
2170 }
sewardj2019a972011-03-07 16:04:07 +00002171 }
2172
2173 /* --------- UNARY OP --------- */
2174 case Iex_Unop: {
2175 IROp op = expr->Iex.Unop.op;
2176 IRExpr *left = expr->Iex.Unop.arg;
2177 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00002178 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002179 HReg h1, dst;
2180
2181 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2182 HReg dst_hi, dst_lo;
2183
2184 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2185 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2186 }
2187
florian4d71a082011-12-18 00:08:17 +00002188 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002189 dst = newVRegF(env);
2190 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2191 addInstr(env, s390_insn_move(size, dst, h1));
2192
2193 return dst;
2194 }
2195
2196 switch (op) {
2197 case Iop_NegF32:
2198 case Iop_NegF64:
2199 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002200 (left->Iex.Unop.op == Iop_AbsF32 ||
2201 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002202 bfpop = S390_BFP_NABS;
2203 else
2204 bfpop = S390_BFP_NEG;
2205 break;
2206
2207 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002208 case Iop_AbsF64:
2209 bfpop = S390_BFP_ABS;
2210 break;
2211
2212 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2213 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2214 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2215
2216 convert_float1:
2217 h1 = s390_isel_float_expr(env, left);
2218 goto convert1;
2219
2220 convert_int1:
2221 h1 = s390_isel_int_expr(env, left);
2222 goto convert1;
2223
2224 convert1:
2225 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002226 /* No rounding mode is needed for these conversions. Just stick
2227 one in. It won't be used later on. */
2228 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002229 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002230 return dst;
2231
sewardj2019a972011-03-07 16:04:07 +00002232 default:
2233 goto irreducible;
2234 }
2235
2236 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002237 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002238 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002239 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002240 return dst;
2241 }
2242
2243 default:
2244 goto irreducible;
2245 }
2246
2247 /* We get here if no pattern matched. */
2248 irreducible:
2249 ppIRExpr(expr);
2250 vpanic("s390_isel_float_expr: cannot reduce tree");
2251}
2252
2253
2254static HReg
2255s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2256{
2257 HReg dst = s390_isel_float_expr_wrk(env, expr);
2258
2259 /* Sanity checks ... */
2260 vassert(hregClass(dst) == HRcFlt64);
2261 vassert(hregIsVirtual(dst));
2262
2263 return dst;
2264}
2265
2266
2267/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002268/*--- ISEL: Decimal point expressions (128 bit) ---*/
2269/*---------------------------------------------------------*/
2270static void
2271s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2272 IRExpr *expr)
2273{
2274 IRType ty = typeOfIRExpr(env->type_env, expr);
2275
2276 vassert(ty == Ity_D128);
2277
2278 switch (expr->tag) {
2279 case Iex_RdTmp:
2280 /* Return the virtual registers that hold the temporary. */
2281 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2282 return;
2283
2284 /* --------- LOAD --------- */
2285 case Iex_Load: {
2286 IRExpr *addr_hi, *addr_lo;
2287 s390_amode *am_hi, *am_lo;
2288
2289 if (expr->Iex.Load.end != Iend_BE)
2290 goto irreducible;
2291
2292 addr_hi = expr->Iex.Load.addr;
2293 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2294
2295 am_hi = s390_isel_amode(env, addr_hi);
2296 am_lo = s390_isel_amode(env, addr_lo);
2297
2298 *dst_hi = newVRegF(env);
2299 *dst_lo = newVRegF(env);
2300 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2301 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2302 return;
2303 }
2304
2305 /* --------- GET --------- */
2306 case Iex_Get:
2307 /* This is not supported because loading 128-bit from the guest
2308 state is almost certainly wrong. Use get_dpr_pair instead. */
2309 vpanic("Iex_Get with D128 data");
2310
2311 /* --------- 4-ary OP --------- */
2312 case Iex_Qop:
2313 vpanic("Iex_Qop with D128 data");
2314
2315 /* --------- TERNARY OP --------- */
2316 case Iex_Triop: {
2317 IRTriop *triop = expr->Iex.Triop.details;
2318 IROp op = triop->op;
2319 IRExpr *irrm = triop->arg1;
2320 IRExpr *left = triop->arg2;
2321 IRExpr *right = triop->arg3;
2322 s390_dfp_round_t rounding_mode;
2323 s390_dfp_binop_t dfpop;
2324 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2325
2326 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2327 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2328
2329 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2330 (f12, f14) as op2 and (f13, f15) as destination) */
2331 f9 = make_fpr(9);
2332 f11 = make_fpr(11);
2333 f12 = make_fpr(12);
2334 f13 = make_fpr(13);
2335 f14 = make_fpr(14);
2336 f15 = make_fpr(15);
2337
2338 /* 1st operand --> (f9, f11) */
2339 addInstr(env, s390_insn_move(8, f9, op1_hi));
2340 addInstr(env, s390_insn_move(8, f11, op1_lo));
2341
2342 /* 2nd operand --> (f12, f14) */
2343 addInstr(env, s390_insn_move(8, f12, op2_hi));
2344 addInstr(env, s390_insn_move(8, f14, op2_lo));
2345
2346 switch (op) {
2347 case Iop_AddD128: dfpop = S390_DFP_ADD; break;
2348 case Iop_SubD128: dfpop = S390_DFP_SUB; break;
2349 case Iop_MulD128: dfpop = S390_DFP_MUL; break;
2350 case Iop_DivD128: dfpop = S390_DFP_DIV; break;
2351 default:
2352 goto irreducible;
2353 }
2354
2355 /* DFP binary ops have insns with rounding mode field
2356 when the floating point extension facility is installed. */
2357 if (s390_host_has_fpext) {
2358 rounding_mode = get_dfp_rounding_mode(env, irrm);
2359 } else {
2360 set_dfp_rounding_mode_in_fpc(env, irrm);
2361 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2362 }
2363
2364 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2365 f12, f14, rounding_mode));
2366
2367 /* Move result to virtual destination register */
2368 *dst_hi = newVRegF(env);
2369 *dst_lo = newVRegF(env);
2370 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2371 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2372
2373 return;
2374 }
2375
2376 /* --------- BINARY OP --------- */
2377 case Iex_Binop: {
2378 switch (expr->Iex.Binop.op) {
2379 case Iop_D64HLtoD128:
2380 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2381 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2382 return;
2383
2384 default:
2385 goto irreducible;
2386 }
2387 }
2388
2389 /* --------- UNARY OP --------- */
2390 case Iex_Unop: {
2391 IRExpr *left = expr->Iex.Unop.arg;
2392 s390_dfp_conv_t conv;
2393 // HReg op, f12, f13, f14, f15;
2394 HReg op, f12, f14;
2395
2396 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2397 f12 = make_fpr(12);
2398 // f13 = make_fpr(13);
2399 f14 = make_fpr(14);
2400 // f15 = make_fpr(15);
2401
2402 switch (expr->Iex.Unop.op) {
2403 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
2404 default:
2405 goto irreducible;
2406 }
2407
2408 convert_dfp:
2409 op = s390_isel_dfp_expr(env, left);
2410 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2411 goto move_dst;
2412
2413 move_dst:
2414 /* Move result to virtual destination registers */
2415 *dst_hi = newVRegF(env);
2416 *dst_lo = newVRegF(env);
2417 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2418 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2419 return;
2420 }
2421
2422 default:
2423 goto irreducible;
2424 }
2425
2426 /* We get here if no pattern matched. */
2427 irreducible:
2428 ppIRExpr(expr);
2429 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2430
2431}
2432
2433
2434/* Compute a 128-bit value into two 64-bit registers. These may be either
2435 real or virtual regs; in any case they must not be changed by subsequent
2436 code emitted by the caller. */
2437static void
2438s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2439{
2440 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2441
2442 /* Sanity checks ... */
2443 vassert(hregIsVirtual(*dst_hi));
2444 vassert(hregIsVirtual(*dst_lo));
2445 vassert(hregClass(*dst_hi) == HRcFlt64);
2446 vassert(hregClass(*dst_lo) == HRcFlt64);
2447}
2448
2449
2450/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002451/*--- ISEL: Decimal point expressions (64 bit) ---*/
2452/*---------------------------------------------------------*/
2453
2454static HReg
2455s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2456{
2457 IRType ty = typeOfIRExpr(env->type_env, expr);
2458 UChar size;
2459
floriane38f6412012-12-21 17:32:12 +00002460 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002461
2462 size = sizeofIRType(ty);
2463
2464 switch (expr->tag) {
2465 case Iex_RdTmp:
2466 /* Return the virtual register that holds the temporary. */
2467 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2468
2469 /* --------- LOAD --------- */
2470 case Iex_Load: {
2471 HReg dst = newVRegF(env);
2472 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2473
2474 if (expr->Iex.Load.end != Iend_BE)
2475 goto irreducible;
2476
2477 addInstr(env, s390_insn_load(size, dst, am));
2478
2479 return dst;
2480 }
2481
2482 /* --------- GET --------- */
2483 case Iex_Get: {
2484 HReg dst = newVRegF(env);
2485 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2486
2487 addInstr(env, s390_insn_load(size, dst, am));
2488
2489 return dst;
2490 }
2491
floriane38f6412012-12-21 17:32:12 +00002492 /* --------- BINARY OP --------- */
2493 case Iex_Binop: {
2494 IROp op = expr->Iex.Binop.op;
2495 IRExpr *irrm = expr->Iex.Binop.arg1;
2496 IRExpr *left = expr->Iex.Binop.arg2;
2497 HReg h1, dst;
2498 s390_dfp_conv_t conv;
2499
2500 switch (op) {
2501 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
2502
2503 convert_dfp:
2504 h1 = s390_isel_dfp_expr(env, left);
2505 goto convert;
2506
2507 convert: {
2508 s390_dfp_round_t rounding_mode;
2509 /* convert-from-fixed and load-rounded have a rounding mode field
2510 when the floating point extension facility is installed. */
2511 dst = newVRegF(env);
2512 if (s390_host_has_fpext) {
2513 rounding_mode = get_dfp_rounding_mode(env, irrm);
2514 } else {
2515 set_dfp_rounding_mode_in_fpc(env, irrm);
2516 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2517 }
2518 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2519 rounding_mode));
2520 return dst;
2521 }
2522 default:
2523 goto irreducible;
2524
2525 case Iop_D128toD64: {
2526 HReg op_hi, op_lo, f13, f15;
2527 s390_dfp_round_t rounding_mode;
2528
2529 conv = S390_DFP_D128_TO_D64;
2530
2531 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2532
2533 /* We use non-virtual registers as pairs (f13, f15) */
2534 f13 = make_fpr(13);
2535 f15 = make_fpr(15);
2536
2537 /* operand --> (f13, f15) */
2538 addInstr(env, s390_insn_move(8, f13, op_hi));
2539 addInstr(env, s390_insn_move(8, f15, op_lo));
2540
2541 dst = newVRegF(env);
2542 /* load-rounded has a rounding mode field when the floating point
2543 extension facility is installed. */
2544 if (s390_host_has_fpext) {
2545 rounding_mode = get_dfp_rounding_mode(env, irrm);
2546 } else {
2547 set_dfp_rounding_mode_in_fpc(env, irrm);
2548 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2549 }
2550 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2551 rounding_mode));
2552 return dst;
2553 }
2554
2555 }
2556 }
2557
2558 /* --------- UNARY OP --------- */
2559 case Iex_Unop: {
2560 IROp op = expr->Iex.Unop.op;
2561 IRExpr *left = expr->Iex.Unop.arg;
2562 s390_dfp_conv_t conv;
2563 HReg h1, dst;
2564
2565 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2566 HReg dst_hi, dst_lo;
2567
2568 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2569 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2570 }
2571
2572 if (op == Iop_ReinterpI64asD64) {
2573 dst = newVRegF(env);
2574 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2575 addInstr(env, s390_insn_move(size, dst, h1));
2576
2577 return dst;
2578 }
2579
2580 switch (op) {
2581 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
2582
2583 convert_dfp1:
2584 h1 = s390_isel_dfp_expr(env, left);
2585 goto convert1;
2586
2587 convert1:
2588 dst = newVRegF(env);
2589 /* No rounding mode is needed for these conversions. Just stick
2590 one in. It won't be used later on. */
2591 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2592 S390_DFP_ROUND_NEAREST_EVEN_4));
2593 return dst;
2594
2595 default:
2596 goto irreducible;
2597 }
2598 }
2599
florian12390202012-11-10 22:34:14 +00002600 /* --------- TERNARY OP --------- */
2601 case Iex_Triop: {
2602 IRTriop *triop = expr->Iex.Triop.details;
2603 IROp op = triop->op;
2604 IRExpr *irrm = triop->arg1;
2605 IRExpr *left = triop->arg2;
2606 IRExpr *right = triop->arg3;
2607 s390_dfp_round_t rounding_mode;
2608 s390_dfp_binop_t dfpop;
2609 HReg op2, op3, dst;
2610
2611 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2612 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2613 dst = newVRegF(env);
2614 switch (op) {
2615 case Iop_AddD64: dfpop = S390_DFP_ADD; break;
2616 case Iop_SubD64: dfpop = S390_DFP_SUB; break;
2617 case Iop_MulD64: dfpop = S390_DFP_MUL; break;
2618 case Iop_DivD64: dfpop = S390_DFP_DIV; break;
2619 default:
2620 goto irreducible;
2621 }
2622 /* DFP binary ops have insns with rounding mode field
2623 when the floating point extension facility is installed. */
2624 if (s390_host_has_fpext) {
2625 rounding_mode = get_dfp_rounding_mode(env, irrm);
2626 } else {
2627 set_dfp_rounding_mode_in_fpc(env, irrm);
2628 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2629 }
2630
2631 addInstr(env,
2632 s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
2633 return dst;
2634 }
2635
2636 default:
2637 goto irreducible;
2638 }
2639
2640 /* We get here if no pattern matched. */
2641 irreducible:
2642 ppIRExpr(expr);
2643 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2644}
2645
2646static HReg
2647s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2648{
2649 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2650
2651 /* Sanity checks ... */
2652 vassert(hregClass(dst) == HRcFlt64);
2653 vassert(hregIsVirtual(dst));
2654
2655 return dst;
2656}
2657
2658
2659/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002660/*--- ISEL: Condition Code ---*/
2661/*---------------------------------------------------------*/
2662
2663/* This function handles all operators that produce a 1-bit result */
2664static s390_cc_t
2665s390_isel_cc(ISelEnv *env, IRExpr *cond)
2666{
2667 UChar size;
2668
2669 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2670
2671 /* Constant: either 1 or 0 */
2672 if (cond->tag == Iex_Const) {
2673 vassert(cond->Iex.Const.con->tag == Ico_U1);
2674 vassert(cond->Iex.Const.con->Ico.U1 == True
2675 || cond->Iex.Const.con->Ico.U1 == False);
2676
2677 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2678 }
2679
2680 /* Variable: values are 1 or 0 */
2681 if (cond->tag == Iex_RdTmp) {
2682 IRTemp tmp = cond->Iex.RdTmp.tmp;
2683 HReg reg = lookupIRTemp(env, tmp);
2684
2685 /* Load-and-test does not modify REG; so this is OK. */
2686 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2687 size = 4;
2688 else
2689 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2690 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2691 return S390_CC_NE;
2692 }
2693
2694 /* Unary operators */
2695 if (cond->tag == Iex_Unop) {
2696 IRExpr *arg = cond->Iex.Unop.arg;
2697
2698 switch (cond->Iex.Unop.op) {
2699 case Iop_Not1: /* Not1(cond) */
2700 /* Generate code for EXPR, and negate the test condition */
2701 return s390_cc_invert(s390_isel_cc(env, arg));
2702
2703 /* Iop_32/64to1 select the LSB from their operand */
2704 case Iop_32to1:
2705 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002706 HReg dst = newVRegI(env);
2707 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002708
2709 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2710
florianf366a802012-08-03 00:42:18 +00002711 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002712 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2713 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2714 return S390_CC_NE;
2715 }
2716
2717 case Iop_CmpNEZ8:
2718 case Iop_CmpNEZ16: {
2719 s390_opnd_RMI src;
2720 s390_unop_t op;
2721 HReg dst;
2722
2723 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2724 : S390_ZERO_EXTEND_16;
2725 dst = newVRegI(env);
2726 src = s390_isel_int_expr_RMI(env, arg);
2727 addInstr(env, s390_insn_unop(4, op, dst, src));
2728 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2729 return S390_CC_NE;
2730 }
2731
2732 case Iop_CmpNEZ32:
2733 case Iop_CmpNEZ64: {
2734 s390_opnd_RMI src;
2735
2736 src = s390_isel_int_expr_RMI(env, arg);
2737 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2738 addInstr(env, s390_insn_test(size, src));
2739 return S390_CC_NE;
2740 }
2741
2742 default:
2743 goto fail;
2744 }
2745 }
2746
2747 /* Binary operators */
2748 if (cond->tag == Iex_Binop) {
2749 IRExpr *arg1 = cond->Iex.Binop.arg1;
2750 IRExpr *arg2 = cond->Iex.Binop.arg2;
2751 HReg reg1, reg2;
2752
2753 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2754
2755 switch (cond->Iex.Binop.op) {
2756 s390_unop_t op;
2757 s390_cc_t result;
2758
2759 case Iop_CmpEQ8:
2760 case Iop_CasCmpEQ8:
2761 op = S390_ZERO_EXTEND_8;
2762 result = S390_CC_E;
2763 goto do_compare_ze;
2764
2765 case Iop_CmpNE8:
2766 case Iop_CasCmpNE8:
2767 op = S390_ZERO_EXTEND_8;
2768 result = S390_CC_NE;
2769 goto do_compare_ze;
2770
2771 case Iop_CmpEQ16:
2772 case Iop_CasCmpEQ16:
2773 op = S390_ZERO_EXTEND_16;
2774 result = S390_CC_E;
2775 goto do_compare_ze;
2776
2777 case Iop_CmpNE16:
2778 case Iop_CasCmpNE16:
2779 op = S390_ZERO_EXTEND_16;
2780 result = S390_CC_NE;
2781 goto do_compare_ze;
2782
2783 do_compare_ze: {
2784 s390_opnd_RMI op1, op2;
2785
2786 op1 = s390_isel_int_expr_RMI(env, arg1);
2787 reg1 = newVRegI(env);
2788 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2789
2790 op2 = s390_isel_int_expr_RMI(env, arg2);
2791 reg2 = newVRegI(env);
2792 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2793
2794 op2 = s390_opnd_reg(reg2);
2795 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2796
2797 return result;
2798 }
2799
2800 case Iop_CmpEQ32:
2801 case Iop_CmpEQ64:
2802 case Iop_CasCmpEQ32:
2803 case Iop_CasCmpEQ64:
2804 result = S390_CC_E;
2805 goto do_compare;
2806
2807 case Iop_CmpNE32:
2808 case Iop_CmpNE64:
2809 case Iop_CasCmpNE32:
2810 case Iop_CasCmpNE64:
2811 result = S390_CC_NE;
2812 goto do_compare;
2813
2814 do_compare: {
2815 HReg op1;
2816 s390_opnd_RMI op2;
2817
2818 order_commutative_operands(arg1, arg2);
2819
2820 op1 = s390_isel_int_expr(env, arg1);
2821 op2 = s390_isel_int_expr_RMI(env, arg2);
2822
2823 addInstr(env, s390_insn_compare(size, op1, op2, False));
2824
2825 return result;
2826 }
2827
2828 case Iop_CmpLT32S:
2829 case Iop_CmpLE32S:
2830 case Iop_CmpLT64S:
2831 case Iop_CmpLE64S: {
2832 HReg op1;
2833 s390_opnd_RMI op2;
2834
2835 op1 = s390_isel_int_expr(env, arg1);
2836 op2 = s390_isel_int_expr_RMI(env, arg2);
2837
2838 addInstr(env, s390_insn_compare(size, op1, op2, True));
2839
2840 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2841 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2842 }
2843
2844 case Iop_CmpLT32U:
2845 case Iop_CmpLE32U:
2846 case Iop_CmpLT64U:
2847 case Iop_CmpLE64U: {
2848 HReg op1;
2849 s390_opnd_RMI op2;
2850
2851 op1 = s390_isel_int_expr(env, arg1);
2852 op2 = s390_isel_int_expr_RMI(env, arg2);
2853
2854 addInstr(env, s390_insn_compare(size, op1, op2, False));
2855
2856 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2857 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2858 }
2859
2860 default:
2861 goto fail;
2862 }
2863 }
2864
2865 fail:
2866 ppIRExpr(cond);
2867 vpanic("s390_isel_cc: unexpected operator");
2868}
2869
2870
2871/*---------------------------------------------------------*/
2872/*--- ISEL: Statements ---*/
2873/*---------------------------------------------------------*/
2874
2875static void
2876s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2877{
2878 if (vex_traceflags & VEX_TRACE_VCODE) {
2879 vex_printf("\n -- ");
2880 ppIRStmt(stmt);
2881 vex_printf("\n");
2882 }
2883
2884 switch (stmt->tag) {
2885
2886 /* --------- STORE --------- */
2887 case Ist_Store: {
2888 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2889 s390_amode *am;
2890 HReg src;
2891
2892 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2893
2894 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2895
2896 switch (tyd) {
2897 case Ity_I8:
2898 case Ity_I16:
2899 case Ity_I32:
2900 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00002901 if (am->tag == S390_AMODE_B12 &&
2902 s390_expr_is_const_zero(stmt->Ist.Store.data)) {
2903 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
2904 return;
2905 }
sewardj2019a972011-03-07 16:04:07 +00002906 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2907 break;
2908
2909 case Ity_F32:
2910 case Ity_F64:
2911 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2912 break;
2913
florianeb981ae2012-12-21 18:55:03 +00002914 case Ity_D32:
2915 case Ity_D64:
2916 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
2917 break;
2918
sewardj2019a972011-03-07 16:04:07 +00002919 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00002920 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00002921 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00002922 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00002923
2924 default:
2925 goto stmt_fail;
2926 }
2927
2928 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2929 return;
2930 }
2931
2932 /* --------- PUT --------- */
2933 case Ist_Put: {
2934 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2935 HReg src;
2936 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002937 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002938
florianad43b3a2012-02-20 15:01:14 +00002939 /* Detect updates to certain guest registers. We track the contents
2940 of those registers as long as they contain constants. If the new
2941 constant is either zero or in the 8-bit neighbourhood of the
2942 current value we can use a memory-to-memory insn to do the update. */
2943
2944 Int offset = stmt->Ist.Put.offset;
2945
2946 /* Check necessary conditions:
2947 (1) must be one of the registers we care about
2948 (2) assigned value must be a constant */
2949 Int guest_reg = get_guest_reg(offset);
2950
2951 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2952
2953 if (guest_reg == GUEST_IA) {
2954 /* If this is the first assignment to the IA reg, don't special case
2955 it. We need to do a full 8-byte assignment here. The reason is
2956 that in case of a redirected translation the guest IA does not
2957 contain the redirected-to address. Instead it contains the
2958 redirected-from address and those can be far apart. So in order to
2959 do incremnetal updates if the IA in the future we need to get the
2960 initial address of the super block correct. */
2961 if (env->first_IA_assignment) {
2962 env->first_IA_assignment = False;
2963 goto not_special;
2964 }
2965 }
2966
2967 if (stmt->Ist.Put.data->tag != Iex_Const) {
2968 /* Invalidate guest register contents */
2969 env->old_value_valid[guest_reg] = False;
2970 goto not_special;
2971 }
2972
cborntraaf7ad282012-08-08 14:11:33 +00002973 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2974 if (tyd != Ity_I64)
2975 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002976
cborntraaf7ad282012-08-08 14:11:33 +00002977 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002978
2979 old_value = env->old_value[guest_reg];
2980 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2981 env->old_value[guest_reg] = new_value;
2982
2983 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2984 env->old_value_valid[guest_reg] = True;
2985
2986 /* If the register already contains the new value, there is nothing
2987 to do here. Unless the guest register requires precise memory
2988 exceptions. */
2989 if (old_value_is_valid && new_value == old_value) {
2990 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2991 return;
2992 }
2993 }
2994
2995 /* guest register = 0 */
2996 if (new_value == 0) {
florian09bbba82012-12-11 04:09:43 +00002997 am = s390_amode_for_guest_state(offset);
2998 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
florianad43b3a2012-02-20 15:01:14 +00002999 return;
3000 }
3001
3002 if (old_value_is_valid == False) goto not_special;
3003
3004 /* If the new value is in the neighbourhood of the old value
3005 we can use a memory-to-memory insn */
3006 difference = new_value - old_value;
3007
3008 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
3009 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
3010 (difference & 0xFF), new_value));
3011 return;
3012 }
3013
3014 /* If the high word is the same it is sufficient to load the low word.
3015 Use R0 as a scratch reg. */
3016 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00003017 HReg r0 = make_gpr(0);
3018 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00003019 s390_amode *gam;
3020
3021 gam = s390_amode_b12(offset + 4, gsp);
3022 addInstr(env, s390_insn_load_immediate(4, r0,
3023 new_value & 0xFFFFFFFF));
3024 addInstr(env, s390_insn_store(4, gam, r0));
3025 return;
3026 }
3027
3028 /* No special case applies... fall through */
3029
3030 not_special:
sewardj2019a972011-03-07 16:04:07 +00003031 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
3032
3033 switch (tyd) {
3034 case Ity_I8:
3035 case Ity_I16:
3036 case Ity_I32:
3037 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003038 if (am->tag == S390_AMODE_B12 &&
3039 s390_expr_is_const_zero(stmt->Ist.Put.data)) {
3040 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
3041 return;
3042 }
sewardj2019a972011-03-07 16:04:07 +00003043 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3044 break;
3045
3046 case Ity_F32:
3047 case Ity_F64:
3048 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3049 break;
3050
3051 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003052 case Ity_D128:
3053 /* Does not occur. See function put_(f|d)pr_pair. */
3054 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003055
floriane38f6412012-12-21 17:32:12 +00003056 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003057 case Ity_D64:
3058 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3059 break;
3060
sewardj2019a972011-03-07 16:04:07 +00003061 default:
3062 goto stmt_fail;
3063 }
3064
3065 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3066 return;
3067 }
3068
3069 /* --------- TMP --------- */
3070 case Ist_WrTmp: {
3071 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3072 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3073 HReg src, dst;
3074
3075 switch (tyd) {
3076 case Ity_I128: {
3077 HReg dst_hi, dst_lo, res_hi, res_lo;
3078
3079 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3080 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3081
3082 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3083 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3084 return;
3085 }
3086
3087 case Ity_I8:
3088 case Ity_I16:
3089 case Ity_I32:
3090 case Ity_I64:
3091 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3092 dst = lookupIRTemp(env, tmp);
3093 break;
3094
3095 case Ity_I1: {
3096 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3097 dst = lookupIRTemp(env, tmp);
3098 addInstr(env, s390_insn_cc2bool(dst, cond));
3099 return;
3100 }
3101
3102 case Ity_F32:
3103 case Ity_F64:
3104 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3105 dst = lookupIRTemp(env, tmp);
3106 break;
3107
3108 case Ity_F128: {
3109 HReg dst_hi, dst_lo, res_hi, res_lo;
3110
3111 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3112 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3113
3114 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3115 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3116 return;
3117 }
3118
floriane38f6412012-12-21 17:32:12 +00003119 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003120 case Ity_D64:
3121 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3122 dst = lookupIRTemp(env, tmp);
3123 break;
3124
floriane38f6412012-12-21 17:32:12 +00003125 case Ity_D128: {
3126 HReg dst_hi, dst_lo, res_hi, res_lo;
3127
3128 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3129 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3130
3131 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3132 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3133 return;
3134 }
3135
sewardj2019a972011-03-07 16:04:07 +00003136 default:
3137 goto stmt_fail;
3138 }
3139
3140 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3141 return;
3142 }
3143
3144 /* --------- Call to DIRTY helper --------- */
3145 case Ist_Dirty: {
3146 IRType retty;
3147 IRDirty* d = stmt->Ist.Dirty.details;
3148 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003149 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003150 Int i;
3151
3152 /* Invalidate tracked values of those guest state registers that are
3153 modified by this helper. */
3154 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003155 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3156 descriptors in guest state effect descriptions. Hence: */
3157 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003158 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3159 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3160 if (guest_reg != GUEST_UNKNOWN)
3161 env->old_value_valid[guest_reg] = False;
3162 }
3163 }
sewardj2019a972011-03-07 16:04:07 +00003164
3165 if (d->nFxState == 0)
3166 vassert(!d->needsBBP);
3167
3168 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3169
florian01ed6e72012-05-27 16:52:43 +00003170 if (d->tmp == IRTemp_INVALID) {
3171 /* No return value. */
3172 dst = INVALID_HREG;
3173 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003174 return;
florian01ed6e72012-05-27 16:52:43 +00003175 }
sewardj2019a972011-03-07 16:04:07 +00003176
3177 retty = typeOfIRTemp(env->type_env, d->tmp);
3178 if (retty == Ity_I64 || retty == Ity_I32
3179 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003180 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003181 dst = lookupIRTemp(env, d->tmp);
3182 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003183 return;
3184 }
3185 break;
3186 }
3187
3188 case Ist_CAS:
3189 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3190 IRCAS *cas = stmt->Ist.CAS.details;
3191 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3192 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3193 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3194 HReg old = lookupIRTemp(env, cas->oldLo);
3195
3196 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3197 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3198 } else {
3199 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3200 }
3201 return;
3202 } else {
florian448cbba2012-06-06 02:26:01 +00003203 IRCAS *cas = stmt->Ist.CAS.details;
3204 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3205 HReg r8, r9, r10, r11, r1;
3206 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3207 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3208 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3209 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3210 HReg old_low = lookupIRTemp(env, cas->oldLo);
3211 HReg old_high = lookupIRTemp(env, cas->oldHi);
3212
3213 /* Use non-virtual registers r8 and r9 as pair for op1
3214 and move op1 there */
3215 r8 = make_gpr(8);
3216 r9 = make_gpr(9);
3217 addInstr(env, s390_insn_move(8, r8, op1_high));
3218 addInstr(env, s390_insn_move(8, r9, op1_low));
3219
3220 /* Use non-virtual registers r10 and r11 as pair for op3
3221 and move op3 there */
3222 r10 = make_gpr(10);
3223 r11 = make_gpr(11);
3224 addInstr(env, s390_insn_move(8, r10, op3_high));
3225 addInstr(env, s390_insn_move(8, r11, op3_low));
3226
3227 /* Register r1 is used as a scratch register */
3228 r1 = make_gpr(1);
3229
3230 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3231 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3232 old_high, old_low, r1));
3233 } else {
3234 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3235 old_high, old_low, r1));
3236 }
3237 addInstr(env, s390_insn_move(8, op1_high, r8));
3238 addInstr(env, s390_insn_move(8, op1_low, r9));
3239 addInstr(env, s390_insn_move(8, op3_high, r10));
3240 addInstr(env, s390_insn_move(8, op3_low, r11));
3241 return;
sewardj2019a972011-03-07 16:04:07 +00003242 }
3243 break;
3244
3245 /* --------- EXIT --------- */
3246 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003247 s390_cc_t cond;
3248 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3249
3250 if (tag != Ico_U64)
3251 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3252
florian8844a632012-04-13 04:04:06 +00003253 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003254 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003255
3256 /* Case: boring transfer to known address */
3257 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3258 if (env->chaining_allowed) {
3259 /* .. almost always true .. */
3260 /* Skip the event check at the dst if this is a forwards
3261 edge. */
3262 Bool to_fast_entry
3263 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3264 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3265 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3266 guest_IA, to_fast_entry));
3267 } else {
3268 /* .. very occasionally .. */
3269 /* We can't use chaining, so ask for an assisted transfer,
3270 as that's the only alternative that is allowable. */
3271 HReg dst = s390_isel_int_expr(env,
3272 IRExpr_Const(stmt->Ist.Exit.dst));
3273 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3274 }
3275 return;
3276 }
3277
3278 /* Case: assisted transfer to arbitrary address */
3279 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003280 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003281 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003282 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003283 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003284 case Ijk_Sys_syscall:
3285 case Ijk_ClientReq:
3286 case Ijk_NoRedir:
3287 case Ijk_Yield:
3288 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003289 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3290 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3291 stmt->Ist.Exit.jk));
3292 return;
3293 }
3294 default:
3295 break;
3296 }
3297
3298 /* Do we ever expect to see any other kind? */
3299 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003300 }
3301
3302 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003303 case Ist_MBE:
3304 switch (stmt->Ist.MBE.event) {
3305 case Imbe_Fence:
3306 addInstr(env, s390_insn_mfence());
3307 return;
3308 default:
3309 break;
3310 }
sewardj2019a972011-03-07 16:04:07 +00003311 break;
3312
3313 /* --------- Miscellaneous --------- */
3314
3315 case Ist_PutI: /* Not needed */
3316 case Ist_IMark: /* Doesn't generate any executable code */
3317 case Ist_NoOp: /* Doesn't generate any executable code */
3318 case Ist_AbiHint: /* Meaningless in IR */
3319 return;
3320
3321 default:
3322 break;
3323 }
3324
3325 stmt_fail:
3326 ppIRStmt(stmt);
3327 vpanic("s390_isel_stmt");
3328}
3329
3330
3331/*---------------------------------------------------------*/
3332/*--- ISEL: Basic block terminators (Nexts) ---*/
3333/*---------------------------------------------------------*/
3334
3335static void
florianffbd84d2012-12-09 02:06:29 +00003336iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003337{
sewardj2019a972011-03-07 16:04:07 +00003338 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003339 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003340 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003341 vex_printf("; exit-");
3342 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003343 vex_printf("\n");
3344 }
3345
florian8844a632012-04-13 04:04:06 +00003346 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3347
3348 /* Case: boring transfer to known address */
3349 if (next->tag == Iex_Const) {
3350 IRConst *cdst = next->Iex.Const.con;
3351 vassert(cdst->tag == Ico_U64);
3352 if (jk == Ijk_Boring || jk == Ijk_Call) {
3353 /* Boring transfer to known address */
3354 if (env->chaining_allowed) {
3355 /* .. almost always true .. */
3356 /* Skip the event check at the dst if this is a forwards
3357 edge. */
3358 Bool to_fast_entry
3359 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3360 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3361 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3362 guest_IA, to_fast_entry));
3363 } else {
3364 /* .. very occasionally .. */
3365 /* We can't use chaining, so ask for an indirect transfer,
3366 as that's the cheapest alternative that is allowable. */
3367 HReg dst = s390_isel_int_expr(env, next);
3368 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3369 Ijk_Boring));
3370 }
3371 return;
3372 }
3373 }
3374
3375 /* Case: call/return (==boring) transfer to any address */
3376 switch (jk) {
3377 case Ijk_Boring:
3378 case Ijk_Ret:
3379 case Ijk_Call: {
3380 HReg dst = s390_isel_int_expr(env, next);
3381 if (env->chaining_allowed) {
3382 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3383 } else {
3384 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3385 Ijk_Boring));
3386 }
3387 return;
3388 }
3389 default:
3390 break;
3391 }
3392
3393 /* Case: some other kind of transfer to any address */
3394 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003395 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003396 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003397 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003398 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003399 case Ijk_Sys_syscall:
3400 case Ijk_ClientReq:
3401 case Ijk_NoRedir:
3402 case Ijk_Yield:
3403 case Ijk_SigTRAP: {
3404 HReg dst = s390_isel_int_expr(env, next);
3405 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3406 return;
3407 }
3408 default:
3409 break;
3410 }
3411
3412 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003413}
3414
3415
3416/*---------------------------------------------------------*/
3417/*--- Insn selector top-level ---*/
3418/*---------------------------------------------------------*/
3419
florianf26994a2012-04-21 03:34:54 +00003420/* Translate an entire SB to s390 code.
3421 Note: archinfo_host is a pointer to a stack-allocated variable.
3422 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003423
3424HInstrArray *
3425iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003426 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3427 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3428 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003429{
3430 UInt i, j;
3431 HReg hreg, hregHI;
3432 ISelEnv *env;
3433 UInt hwcaps_host = archinfo_host->hwcaps;
3434
florianf26994a2012-04-21 03:34:54 +00003435 /* KLUDGE: export hwcaps. */
3436 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003437
sewardj2019a972011-03-07 16:04:07 +00003438 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003439 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003440
3441 /* Make up an initial environment to use. */
3442 env = LibVEX_Alloc(sizeof(ISelEnv));
3443 env->vreg_ctr = 0;
3444
3445 /* Set up output code array. */
3446 env->code = newHInstrArray();
3447
3448 /* Copy BB's type env. */
3449 env->type_env = bb->tyenv;
3450
florianad43b3a2012-02-20 15:01:14 +00003451 /* Set up data structures for tracking guest register values. */
3452 env->first_IA_assignment = True;
3453 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3454 env->old_value[i] = 0; /* just something to have a defined value */
3455 env->old_value_valid[i] = False;
3456 }
3457
sewardj2019a972011-03-07 16:04:07 +00003458 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3459 change as we go along. For some reason types_used has Int type -- but
3460 it should be unsigned. Internally we use an unsigned type; so we
3461 assert it here. */
3462 vassert(bb->tyenv->types_used >= 0);
3463
3464 env->n_vregmap = bb->tyenv->types_used;
3465 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3466 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3467
florian2c74d242012-09-12 19:38:42 +00003468 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003469 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003470
sewardj2019a972011-03-07 16:04:07 +00003471 /* and finally ... */
3472 env->hwcaps = hwcaps_host;
3473
florian8844a632012-04-13 04:04:06 +00003474 env->max_ga = max_ga;
3475 env->chaining_allowed = chaining_allowed;
3476
sewardj2019a972011-03-07 16:04:07 +00003477 /* For each IR temporary, allocate a suitably-kinded virtual
3478 register. */
3479 j = 0;
3480 for (i = 0; i < env->n_vregmap; i++) {
3481 hregHI = hreg = INVALID_HREG;
3482 switch (bb->tyenv->types[i]) {
3483 case Ity_I1:
3484 case Ity_I8:
3485 case Ity_I16:
3486 case Ity_I32:
3487 hreg = mkHReg(j++, HRcInt64, True);
3488 break;
3489
3490 case Ity_I64:
3491 hreg = mkHReg(j++, HRcInt64, True);
3492 break;
3493
3494 case Ity_I128:
3495 hreg = mkHReg(j++, HRcInt64, True);
3496 hregHI = mkHReg(j++, HRcInt64, True);
3497 break;
3498
3499 case Ity_F32:
3500 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003501 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003502 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003503 hreg = mkHReg(j++, HRcFlt64, True);
3504 break;
3505
3506 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003507 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003508 hreg = mkHReg(j++, HRcFlt64, True);
3509 hregHI = mkHReg(j++, HRcFlt64, True);
3510 break;
3511
3512 case Ity_V128: /* fall through */
3513 default:
3514 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003515 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003516 }
3517
3518 env->vregmap[i] = hreg;
3519 env->vregmapHI[i] = hregHI;
3520 }
3521 env->vreg_ctr = j;
3522
florian8844a632012-04-13 04:04:06 +00003523 /* The very first instruction must be an event check. */
3524 s390_amode *counter, *fail_addr;
3525 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3526 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3527 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3528
3529 /* Possibly a block counter increment (for profiling). At this
3530 point we don't know the address of the counter, so just pretend
3531 it is zero. It will have to be patched later, but before this
3532 translation is used, by a call to LibVEX_patchProfInc. */
3533 if (add_profinc) {
3534 addInstr(env, s390_insn_profinc());
3535 }
3536
sewardj2019a972011-03-07 16:04:07 +00003537 /* Ok, finally we can iterate over the statements. */
3538 for (i = 0; i < bb->stmts_used; i++)
3539 if (bb->stmts[i])
3540 s390_isel_stmt(env, bb->stmts[i]);
3541
florian8844a632012-04-13 04:04:06 +00003542 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003543
3544 /* Record the number of vregs we used. */
3545 env->code->n_vregs = env->vreg_ctr;
3546
3547 return env->code;
3548}
3549
3550/*---------------------------------------------------------------*/
3551/*--- end host_s390_isel.c ---*/
3552/*---------------------------------------------------------------*/