blob: 6916731bc3a48e1f3a273571c0f3b2109c5b85ff [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
2914 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00002915 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00002916 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00002917 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00002918
2919 default:
2920 goto stmt_fail;
2921 }
2922
2923 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2924 return;
2925 }
2926
2927 /* --------- PUT --------- */
2928 case Ist_Put: {
2929 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2930 HReg src;
2931 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002932 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002933
florianad43b3a2012-02-20 15:01:14 +00002934 /* Detect updates to certain guest registers. We track the contents
2935 of those registers as long as they contain constants. If the new
2936 constant is either zero or in the 8-bit neighbourhood of the
2937 current value we can use a memory-to-memory insn to do the update. */
2938
2939 Int offset = stmt->Ist.Put.offset;
2940
2941 /* Check necessary conditions:
2942 (1) must be one of the registers we care about
2943 (2) assigned value must be a constant */
2944 Int guest_reg = get_guest_reg(offset);
2945
2946 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2947
2948 if (guest_reg == GUEST_IA) {
2949 /* If this is the first assignment to the IA reg, don't special case
2950 it. We need to do a full 8-byte assignment here. The reason is
2951 that in case of a redirected translation the guest IA does not
2952 contain the redirected-to address. Instead it contains the
2953 redirected-from address and those can be far apart. So in order to
2954 do incremnetal updates if the IA in the future we need to get the
2955 initial address of the super block correct. */
2956 if (env->first_IA_assignment) {
2957 env->first_IA_assignment = False;
2958 goto not_special;
2959 }
2960 }
2961
2962 if (stmt->Ist.Put.data->tag != Iex_Const) {
2963 /* Invalidate guest register contents */
2964 env->old_value_valid[guest_reg] = False;
2965 goto not_special;
2966 }
2967
cborntraaf7ad282012-08-08 14:11:33 +00002968 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2969 if (tyd != Ity_I64)
2970 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002971
cborntraaf7ad282012-08-08 14:11:33 +00002972 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002973
2974 old_value = env->old_value[guest_reg];
2975 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2976 env->old_value[guest_reg] = new_value;
2977
2978 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2979 env->old_value_valid[guest_reg] = True;
2980
2981 /* If the register already contains the new value, there is nothing
2982 to do here. Unless the guest register requires precise memory
2983 exceptions. */
2984 if (old_value_is_valid && new_value == old_value) {
2985 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2986 return;
2987 }
2988 }
2989
2990 /* guest register = 0 */
2991 if (new_value == 0) {
florian09bbba82012-12-11 04:09:43 +00002992 am = s390_amode_for_guest_state(offset);
2993 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
florianad43b3a2012-02-20 15:01:14 +00002994 return;
2995 }
2996
2997 if (old_value_is_valid == False) goto not_special;
2998
2999 /* If the new value is in the neighbourhood of the old value
3000 we can use a memory-to-memory insn */
3001 difference = new_value - old_value;
3002
3003 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
3004 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
3005 (difference & 0xFF), new_value));
3006 return;
3007 }
3008
3009 /* If the high word is the same it is sufficient to load the low word.
3010 Use R0 as a scratch reg. */
3011 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00003012 HReg r0 = make_gpr(0);
3013 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00003014 s390_amode *gam;
3015
3016 gam = s390_amode_b12(offset + 4, gsp);
3017 addInstr(env, s390_insn_load_immediate(4, r0,
3018 new_value & 0xFFFFFFFF));
3019 addInstr(env, s390_insn_store(4, gam, r0));
3020 return;
3021 }
3022
3023 /* No special case applies... fall through */
3024
3025 not_special:
sewardj2019a972011-03-07 16:04:07 +00003026 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
3027
3028 switch (tyd) {
3029 case Ity_I8:
3030 case Ity_I16:
3031 case Ity_I32:
3032 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003033 if (am->tag == S390_AMODE_B12 &&
3034 s390_expr_is_const_zero(stmt->Ist.Put.data)) {
3035 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
3036 return;
3037 }
sewardj2019a972011-03-07 16:04:07 +00003038 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3039 break;
3040
3041 case Ity_F32:
3042 case Ity_F64:
3043 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3044 break;
3045
3046 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003047 case Ity_D128:
3048 /* Does not occur. See function put_(f|d)pr_pair. */
3049 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003050
floriane38f6412012-12-21 17:32:12 +00003051 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003052 case Ity_D64:
3053 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3054 break;
3055
sewardj2019a972011-03-07 16:04:07 +00003056 default:
3057 goto stmt_fail;
3058 }
3059
3060 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3061 return;
3062 }
3063
3064 /* --------- TMP --------- */
3065 case Ist_WrTmp: {
3066 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3067 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3068 HReg src, dst;
3069
3070 switch (tyd) {
3071 case Ity_I128: {
3072 HReg dst_hi, dst_lo, res_hi, res_lo;
3073
3074 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3075 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3076
3077 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3078 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3079 return;
3080 }
3081
3082 case Ity_I8:
3083 case Ity_I16:
3084 case Ity_I32:
3085 case Ity_I64:
3086 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3087 dst = lookupIRTemp(env, tmp);
3088 break;
3089
3090 case Ity_I1: {
3091 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3092 dst = lookupIRTemp(env, tmp);
3093 addInstr(env, s390_insn_cc2bool(dst, cond));
3094 return;
3095 }
3096
3097 case Ity_F32:
3098 case Ity_F64:
3099 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3100 dst = lookupIRTemp(env, tmp);
3101 break;
3102
3103 case Ity_F128: {
3104 HReg dst_hi, dst_lo, res_hi, res_lo;
3105
3106 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3107 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3108
3109 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3110 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3111 return;
3112 }
3113
floriane38f6412012-12-21 17:32:12 +00003114 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003115 case Ity_D64:
3116 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3117 dst = lookupIRTemp(env, tmp);
3118 break;
3119
floriane38f6412012-12-21 17:32:12 +00003120 case Ity_D128: {
3121 HReg dst_hi, dst_lo, res_hi, res_lo;
3122
3123 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3124 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3125
3126 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3127 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3128 return;
3129 }
3130
sewardj2019a972011-03-07 16:04:07 +00003131 default:
3132 goto stmt_fail;
3133 }
3134
3135 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3136 return;
3137 }
3138
3139 /* --------- Call to DIRTY helper --------- */
3140 case Ist_Dirty: {
3141 IRType retty;
3142 IRDirty* d = stmt->Ist.Dirty.details;
3143 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003144 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003145 Int i;
3146
3147 /* Invalidate tracked values of those guest state registers that are
3148 modified by this helper. */
3149 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003150 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3151 descriptors in guest state effect descriptions. Hence: */
3152 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003153 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3154 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3155 if (guest_reg != GUEST_UNKNOWN)
3156 env->old_value_valid[guest_reg] = False;
3157 }
3158 }
sewardj2019a972011-03-07 16:04:07 +00003159
3160 if (d->nFxState == 0)
3161 vassert(!d->needsBBP);
3162
3163 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3164
florian01ed6e72012-05-27 16:52:43 +00003165 if (d->tmp == IRTemp_INVALID) {
3166 /* No return value. */
3167 dst = INVALID_HREG;
3168 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003169 return;
florian01ed6e72012-05-27 16:52:43 +00003170 }
sewardj2019a972011-03-07 16:04:07 +00003171
3172 retty = typeOfIRTemp(env->type_env, d->tmp);
3173 if (retty == Ity_I64 || retty == Ity_I32
3174 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003175 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003176 dst = lookupIRTemp(env, d->tmp);
3177 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003178 return;
3179 }
3180 break;
3181 }
3182
3183 case Ist_CAS:
3184 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3185 IRCAS *cas = stmt->Ist.CAS.details;
3186 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3187 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3188 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3189 HReg old = lookupIRTemp(env, cas->oldLo);
3190
3191 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3192 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3193 } else {
3194 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3195 }
3196 return;
3197 } else {
florian448cbba2012-06-06 02:26:01 +00003198 IRCAS *cas = stmt->Ist.CAS.details;
3199 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3200 HReg r8, r9, r10, r11, r1;
3201 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3202 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3203 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3204 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3205 HReg old_low = lookupIRTemp(env, cas->oldLo);
3206 HReg old_high = lookupIRTemp(env, cas->oldHi);
3207
3208 /* Use non-virtual registers r8 and r9 as pair for op1
3209 and move op1 there */
3210 r8 = make_gpr(8);
3211 r9 = make_gpr(9);
3212 addInstr(env, s390_insn_move(8, r8, op1_high));
3213 addInstr(env, s390_insn_move(8, r9, op1_low));
3214
3215 /* Use non-virtual registers r10 and r11 as pair for op3
3216 and move op3 there */
3217 r10 = make_gpr(10);
3218 r11 = make_gpr(11);
3219 addInstr(env, s390_insn_move(8, r10, op3_high));
3220 addInstr(env, s390_insn_move(8, r11, op3_low));
3221
3222 /* Register r1 is used as a scratch register */
3223 r1 = make_gpr(1);
3224
3225 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3226 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3227 old_high, old_low, r1));
3228 } else {
3229 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3230 old_high, old_low, r1));
3231 }
3232 addInstr(env, s390_insn_move(8, op1_high, r8));
3233 addInstr(env, s390_insn_move(8, op1_low, r9));
3234 addInstr(env, s390_insn_move(8, op3_high, r10));
3235 addInstr(env, s390_insn_move(8, op3_low, r11));
3236 return;
sewardj2019a972011-03-07 16:04:07 +00003237 }
3238 break;
3239
3240 /* --------- EXIT --------- */
3241 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003242 s390_cc_t cond;
3243 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3244
3245 if (tag != Ico_U64)
3246 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3247
florian8844a632012-04-13 04:04:06 +00003248 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003249 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003250
3251 /* Case: boring transfer to known address */
3252 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3253 if (env->chaining_allowed) {
3254 /* .. almost always true .. */
3255 /* Skip the event check at the dst if this is a forwards
3256 edge. */
3257 Bool to_fast_entry
3258 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3259 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3260 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3261 guest_IA, to_fast_entry));
3262 } else {
3263 /* .. very occasionally .. */
3264 /* We can't use chaining, so ask for an assisted transfer,
3265 as that's the only alternative that is allowable. */
3266 HReg dst = s390_isel_int_expr(env,
3267 IRExpr_Const(stmt->Ist.Exit.dst));
3268 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3269 }
3270 return;
3271 }
3272
3273 /* Case: assisted transfer to arbitrary address */
3274 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003275 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003276 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003277 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003278 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003279 case Ijk_Sys_syscall:
3280 case Ijk_ClientReq:
3281 case Ijk_NoRedir:
3282 case Ijk_Yield:
3283 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003284 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3285 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3286 stmt->Ist.Exit.jk));
3287 return;
3288 }
3289 default:
3290 break;
3291 }
3292
3293 /* Do we ever expect to see any other kind? */
3294 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003295 }
3296
3297 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003298 case Ist_MBE:
3299 switch (stmt->Ist.MBE.event) {
3300 case Imbe_Fence:
3301 addInstr(env, s390_insn_mfence());
3302 return;
3303 default:
3304 break;
3305 }
sewardj2019a972011-03-07 16:04:07 +00003306 break;
3307
3308 /* --------- Miscellaneous --------- */
3309
3310 case Ist_PutI: /* Not needed */
3311 case Ist_IMark: /* Doesn't generate any executable code */
3312 case Ist_NoOp: /* Doesn't generate any executable code */
3313 case Ist_AbiHint: /* Meaningless in IR */
3314 return;
3315
3316 default:
3317 break;
3318 }
3319
3320 stmt_fail:
3321 ppIRStmt(stmt);
3322 vpanic("s390_isel_stmt");
3323}
3324
3325
3326/*---------------------------------------------------------*/
3327/*--- ISEL: Basic block terminators (Nexts) ---*/
3328/*---------------------------------------------------------*/
3329
3330static void
florianffbd84d2012-12-09 02:06:29 +00003331iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003332{
sewardj2019a972011-03-07 16:04:07 +00003333 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003334 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003335 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003336 vex_printf("; exit-");
3337 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003338 vex_printf("\n");
3339 }
3340
florian8844a632012-04-13 04:04:06 +00003341 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3342
3343 /* Case: boring transfer to known address */
3344 if (next->tag == Iex_Const) {
3345 IRConst *cdst = next->Iex.Const.con;
3346 vassert(cdst->tag == Ico_U64);
3347 if (jk == Ijk_Boring || jk == Ijk_Call) {
3348 /* Boring transfer to known address */
3349 if (env->chaining_allowed) {
3350 /* .. almost always true .. */
3351 /* Skip the event check at the dst if this is a forwards
3352 edge. */
3353 Bool to_fast_entry
3354 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3355 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3356 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3357 guest_IA, to_fast_entry));
3358 } else {
3359 /* .. very occasionally .. */
3360 /* We can't use chaining, so ask for an indirect transfer,
3361 as that's the cheapest alternative that is allowable. */
3362 HReg dst = s390_isel_int_expr(env, next);
3363 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3364 Ijk_Boring));
3365 }
3366 return;
3367 }
3368 }
3369
3370 /* Case: call/return (==boring) transfer to any address */
3371 switch (jk) {
3372 case Ijk_Boring:
3373 case Ijk_Ret:
3374 case Ijk_Call: {
3375 HReg dst = s390_isel_int_expr(env, next);
3376 if (env->chaining_allowed) {
3377 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3378 } else {
3379 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3380 Ijk_Boring));
3381 }
3382 return;
3383 }
3384 default:
3385 break;
3386 }
3387
3388 /* Case: some other kind of transfer to any address */
3389 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003390 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003391 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003392 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003393 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003394 case Ijk_Sys_syscall:
3395 case Ijk_ClientReq:
3396 case Ijk_NoRedir:
3397 case Ijk_Yield:
3398 case Ijk_SigTRAP: {
3399 HReg dst = s390_isel_int_expr(env, next);
3400 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3401 return;
3402 }
3403 default:
3404 break;
3405 }
3406
3407 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003408}
3409
3410
3411/*---------------------------------------------------------*/
3412/*--- Insn selector top-level ---*/
3413/*---------------------------------------------------------*/
3414
florianf26994a2012-04-21 03:34:54 +00003415/* Translate an entire SB to s390 code.
3416 Note: archinfo_host is a pointer to a stack-allocated variable.
3417 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003418
3419HInstrArray *
3420iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003421 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3422 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3423 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003424{
3425 UInt i, j;
3426 HReg hreg, hregHI;
3427 ISelEnv *env;
3428 UInt hwcaps_host = archinfo_host->hwcaps;
3429
florianf26994a2012-04-21 03:34:54 +00003430 /* KLUDGE: export hwcaps. */
3431 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003432
sewardj2019a972011-03-07 16:04:07 +00003433 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003434 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003435
3436 /* Make up an initial environment to use. */
3437 env = LibVEX_Alloc(sizeof(ISelEnv));
3438 env->vreg_ctr = 0;
3439
3440 /* Set up output code array. */
3441 env->code = newHInstrArray();
3442
3443 /* Copy BB's type env. */
3444 env->type_env = bb->tyenv;
3445
florianad43b3a2012-02-20 15:01:14 +00003446 /* Set up data structures for tracking guest register values. */
3447 env->first_IA_assignment = True;
3448 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3449 env->old_value[i] = 0; /* just something to have a defined value */
3450 env->old_value_valid[i] = False;
3451 }
3452
sewardj2019a972011-03-07 16:04:07 +00003453 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3454 change as we go along. For some reason types_used has Int type -- but
3455 it should be unsigned. Internally we use an unsigned type; so we
3456 assert it here. */
3457 vassert(bb->tyenv->types_used >= 0);
3458
3459 env->n_vregmap = bb->tyenv->types_used;
3460 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3461 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3462
florian2c74d242012-09-12 19:38:42 +00003463 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003464 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003465
sewardj2019a972011-03-07 16:04:07 +00003466 /* and finally ... */
3467 env->hwcaps = hwcaps_host;
3468
florian8844a632012-04-13 04:04:06 +00003469 env->max_ga = max_ga;
3470 env->chaining_allowed = chaining_allowed;
3471
sewardj2019a972011-03-07 16:04:07 +00003472 /* For each IR temporary, allocate a suitably-kinded virtual
3473 register. */
3474 j = 0;
3475 for (i = 0; i < env->n_vregmap; i++) {
3476 hregHI = hreg = INVALID_HREG;
3477 switch (bb->tyenv->types[i]) {
3478 case Ity_I1:
3479 case Ity_I8:
3480 case Ity_I16:
3481 case Ity_I32:
3482 hreg = mkHReg(j++, HRcInt64, True);
3483 break;
3484
3485 case Ity_I64:
3486 hreg = mkHReg(j++, HRcInt64, True);
3487 break;
3488
3489 case Ity_I128:
3490 hreg = mkHReg(j++, HRcInt64, True);
3491 hregHI = mkHReg(j++, HRcInt64, True);
3492 break;
3493
3494 case Ity_F32:
3495 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003496 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003497 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003498 hreg = mkHReg(j++, HRcFlt64, True);
3499 break;
3500
3501 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003502 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003503 hreg = mkHReg(j++, HRcFlt64, True);
3504 hregHI = mkHReg(j++, HRcFlt64, True);
3505 break;
3506
3507 case Ity_V128: /* fall through */
3508 default:
3509 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003510 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003511 }
3512
3513 env->vregmap[i] = hreg;
3514 env->vregmapHI[i] = hregHI;
3515 }
3516 env->vreg_ctr = j;
3517
florian8844a632012-04-13 04:04:06 +00003518 /* The very first instruction must be an event check. */
3519 s390_amode *counter, *fail_addr;
3520 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3521 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3522 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3523
3524 /* Possibly a block counter increment (for profiling). At this
3525 point we don't know the address of the counter, so just pretend
3526 it is zero. It will have to be patched later, but before this
3527 translation is used, by a call to LibVEX_patchProfInc. */
3528 if (add_profinc) {
3529 addInstr(env, s390_insn_profinc());
3530 }
3531
sewardj2019a972011-03-07 16:04:07 +00003532 /* Ok, finally we can iterate over the statements. */
3533 for (i = 0; i < bb->stmts_used; i++)
3534 if (bb->stmts[i])
3535 s390_isel_stmt(env, bb->stmts[i]);
3536
florian8844a632012-04-13 04:04:06 +00003537 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003538
3539 /* Record the number of vregs we used. */
3540 env->code->n_vregs = env->vreg_ctr;
3541
3542 return env->code;
3543}
3544
3545/*---------------------------------------------------------------*/
3546/*--- end host_s390_isel.c ---*/
3547/*---------------------------------------------------------------*/