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