blob: 3027045049418493b38d03b865b6dfc2de6f97d2 [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
florian20c6bca2012-12-26 17:47:19 +00001221 case Iop_CmpD64:
1222 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001223 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001224 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001225
1226 h1 = s390_isel_dfp_expr(env, arg1);
1227 h2 = s390_isel_dfp_expr(env, arg2);
1228 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001229
florian20c6bca2012-12-26 17:47:19 +00001230 switch(expr->Iex.Binop.op) {
1231 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1232 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1233 default: goto irreducible;
1234 }
1235 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001236
florian2d3d87f2012-12-21 21:05:17 +00001237 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001238 }
1239
florian20c6bca2012-12-26 17:47:19 +00001240 case Iop_CmpD128:
1241 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001242 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001243 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001244
1245 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1246 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1247 cc_s390 = newVRegI(env);
1248
1249 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1250 f12 = make_fpr(12);
1251 f13 = make_fpr(13);
1252 f14 = make_fpr(14);
1253 f15 = make_fpr(15);
1254
1255 /* 1st operand --> (f12, f14) */
1256 addInstr(env, s390_insn_move(8, f12, op1_hi));
1257 addInstr(env, s390_insn_move(8, f14, op1_lo));
1258
1259 /* 2nd operand --> (f13, f15) */
1260 addInstr(env, s390_insn_move(8, f13, op2_hi));
1261 addInstr(env, s390_insn_move(8, f15, op2_lo));
1262
florian20c6bca2012-12-26 17:47:19 +00001263 switch(expr->Iex.Binop.op) {
1264 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1265 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1266 default: goto irreducible;
1267 }
1268 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1269 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001270
florian2d3d87f2012-12-21 21:05:17 +00001271 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001272 }
1273
sewardj2019a972011-03-07 16:04:07 +00001274 case Iop_Add8:
1275 case Iop_Add16:
1276 case Iop_Add32:
1277 case Iop_Add64:
1278 opkind = S390_ALU_ADD;
1279 break;
1280
1281 case Iop_Sub8:
1282 case Iop_Sub16:
1283 case Iop_Sub32:
1284 case Iop_Sub64:
1285 opkind = S390_ALU_SUB;
1286 is_commutative = False;
1287 break;
1288
1289 case Iop_And8:
1290 case Iop_And16:
1291 case Iop_And32:
1292 case Iop_And64:
1293 opkind = S390_ALU_AND;
1294 break;
1295
1296 case Iop_Or8:
1297 case Iop_Or16:
1298 case Iop_Or32:
1299 case Iop_Or64:
1300 opkind = S390_ALU_OR;
1301 break;
1302
1303 case Iop_Xor8:
1304 case Iop_Xor16:
1305 case Iop_Xor32:
1306 case Iop_Xor64:
1307 opkind = S390_ALU_XOR;
1308 break;
1309
1310 case Iop_Shl8:
1311 case Iop_Shl16:
1312 case Iop_Shl32:
1313 case Iop_Shl64:
1314 opkind = S390_ALU_LSH;
1315 is_commutative = False;
1316 break;
1317
1318 case Iop_Shr8:
1319 case Iop_Shr16:
1320 case Iop_Shr32:
1321 case Iop_Shr64:
1322 opkind = S390_ALU_RSH;
1323 is_commutative = False;
1324 break;
1325
1326 case Iop_Sar8:
1327 case Iop_Sar16:
1328 case Iop_Sar32:
1329 case Iop_Sar64:
1330 opkind = S390_ALU_RSHA;
1331 is_commutative = False;
1332 break;
1333
1334 default:
1335 goto irreducible;
1336 }
1337
1338 /* Pattern match: 0 - arg1 --> -arg1 */
1339 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1340 res = newVRegI(env);
1341 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1342 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1343 addInstr(env, insn);
1344
1345 return res;
1346 }
1347
1348 if (is_commutative) {
1349 order_commutative_operands(arg1, arg2);
1350 }
1351
1352 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1353 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1354 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001355
1356 /* As right shifts of one/two byte opreands are implemented using a
1357 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1358 switch (expr->Iex.Binop.op) {
1359 case Iop_Shr8:
1360 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1361 break;
1362 case Iop_Shr16:
1363 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1364 break;
1365 case Iop_Sar8:
1366 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1367 break;
1368 case Iop_Sar16:
1369 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1370 break;
1371 default:
1372 insn = s390_insn_move(size, res, h1);
1373 break;
1374 }
1375 addInstr(env, insn);
1376
sewardj2019a972011-03-07 16:04:07 +00001377 insn = s390_insn_alu(size, opkind, res, op2);
1378
1379 addInstr(env, insn);
1380
1381 return res;
1382 }
1383
1384 /* --------- UNARY OP --------- */
1385 case Iex_Unop: {
1386 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1387 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1388 s390_opnd_RMI opnd;
1389 s390_insn *insn;
1390 IRExpr *arg;
1391 HReg dst, h1;
1392 IROp unop, binop;
1393
1394 arg = expr->Iex.Unop.arg;
1395
1396 /* Special cases are handled here */
1397
1398 /* 32-bit multiply with 32-bit result or
1399 64-bit multiply with 64-bit result */
1400 unop = expr->Iex.Unop.op;
1401 binop = arg->Iex.Binop.op;
1402
1403 if ((arg->tag == Iex_Binop &&
1404 ((unop == Iop_64to32 &&
1405 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1406 (unop == Iop_128to64 &&
1407 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1408 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1409 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1410 dst = newVRegI(env); /* Result goes into a new register */
1411 addInstr(env, s390_insn_move(size, dst, h1));
1412 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1413
1414 return dst;
1415 }
1416
florian4d71a082011-12-18 00:08:17 +00001417 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001418 dst = newVRegI(env);
1419 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1420 addInstr(env, s390_insn_move(size, dst, h1));
1421
1422 return dst;
1423 }
1424
floriane38f6412012-12-21 17:32:12 +00001425 if (unop == Iop_ReinterpD64asI64) {
1426 dst = newVRegI(env);
1427 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1428 addInstr(env, s390_insn_move(size, dst, h1));
1429
1430 return dst;
1431 }
1432
sewardj2019a972011-03-07 16:04:07 +00001433 /* Expressions whose argument is 1-bit wide */
1434 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1435 s390_cc_t cond = s390_isel_cc(env, arg);
1436 dst = newVRegI(env); /* Result goes into a new register */
1437 addInstr(env, s390_insn_cc2bool(dst, cond));
1438
1439 switch (unop) {
1440 case Iop_1Uto8:
1441 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001442 /* Zero extend */
1443 mask.variant.imm = 1;
1444 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1445 break;
1446
sewardj2019a972011-03-07 16:04:07 +00001447 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001448 /* Zero extend */
1449 mask.variant.imm = 1;
1450 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001451 break;
1452
1453 case Iop_1Sto8:
1454 case Iop_1Sto16:
1455 case Iop_1Sto32:
1456 shift.variant.imm = 31;
1457 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1458 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1459 break;
1460
1461 case Iop_1Sto64:
1462 shift.variant.imm = 63;
1463 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1464 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1465 break;
1466
1467 default:
1468 goto irreducible;
1469 }
1470
1471 return dst;
1472 }
1473
1474 /* Regular processing */
1475
1476 if (unop == Iop_128to64) {
1477 HReg dst_hi, dst_lo;
1478
1479 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1480 return dst_lo;
1481 }
1482
1483 if (unop == Iop_128HIto64) {
1484 HReg dst_hi, dst_lo;
1485
1486 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1487 return dst_hi;
1488 }
1489
1490 dst = newVRegI(env); /* Result goes into a new register */
1491 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1492
1493 switch (unop) {
1494 case Iop_8Uto16:
1495 case Iop_8Uto32:
1496 case Iop_8Uto64:
1497 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1498 break;
1499
1500 case Iop_16Uto32:
1501 case Iop_16Uto64:
1502 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1503 break;
1504
1505 case Iop_32Uto64:
1506 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1507 break;
1508
1509 case Iop_8Sto16:
1510 case Iop_8Sto32:
1511 case Iop_8Sto64:
1512 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1513 break;
1514
1515 case Iop_16Sto32:
1516 case Iop_16Sto64:
1517 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1518 break;
1519
1520 case Iop_32Sto64:
1521 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1522 break;
1523
1524 case Iop_64to8:
1525 case Iop_64to16:
1526 case Iop_64to32:
1527 case Iop_32to8:
1528 case Iop_32to16:
1529 case Iop_16to8:
1530 /* Down-casts are no-ops. Upstream operations will only look at
1531 the bytes that make up the result of the down-cast. So there
1532 is no point setting the other bytes to 0. */
1533 insn = s390_opnd_copy(8, dst, opnd);
1534 break;
1535
1536 case Iop_64HIto32:
1537 addInstr(env, s390_opnd_copy(8, dst, opnd));
1538 shift.variant.imm = 32;
1539 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1540 break;
1541
1542 case Iop_32HIto16:
1543 addInstr(env, s390_opnd_copy(4, dst, opnd));
1544 shift.variant.imm = 16;
1545 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1546 break;
1547
1548 case Iop_16HIto8:
1549 addInstr(env, s390_opnd_copy(2, dst, opnd));
1550 shift.variant.imm = 8;
1551 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1552 break;
1553
1554 case Iop_Not8:
1555 case Iop_Not16:
1556 case Iop_Not32:
1557 case Iop_Not64:
1558 /* XOR with ffff... */
1559 mask.variant.imm = ~(ULong)0;
1560 addInstr(env, s390_opnd_copy(size, dst, opnd));
1561 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1562 break;
1563
1564 case Iop_Left8:
1565 case Iop_Left16:
1566 case Iop_Left32:
1567 case Iop_Left64:
1568 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1569 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1570 break;
1571
1572 case Iop_CmpwNEZ32:
1573 case Iop_CmpwNEZ64: {
1574 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1575 or -X will have a 1 in the MSB. */
1576 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1577 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1578 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1579 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1580 return dst;
1581 }
1582
1583 case Iop_Clz64: {
1584 HReg r10, r11;
1585
sewardj611b06e2011-03-24 08:57:29 +00001586 /* This will be implemented using FLOGR, if possible. So we need to
1587 set aside a pair of non-virtual registers. The result (number of
1588 left-most zero bits) will be in r10. The value in r11 is unspecified
1589 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001590 r10 = make_gpr(10);
1591 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001592
sewardj611b06e2011-03-24 08:57:29 +00001593 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001594 addInstr(env, s390_insn_move(8, dst, r10));
1595 return dst;
1596 }
1597
1598 default:
1599 goto irreducible;
1600 }
1601
1602 addInstr(env, insn);
1603
1604 return dst;
1605 }
1606
1607 /* --------- GET --------- */
1608 case Iex_Get: {
1609 HReg dst = newVRegI(env);
1610 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1611
1612 /* We never load more than 8 bytes from the guest state, because the
1613 floating point register pair is not contiguous. */
1614 vassert(size <= 8);
1615
1616 addInstr(env, s390_insn_load(size, dst, am));
1617
1618 return dst;
1619 }
1620
1621 case Iex_GetI:
1622 /* not needed */
1623 break;
1624
1625 /* --------- CCALL --------- */
1626 case Iex_CCall: {
1627 HReg dst = newVRegI(env);
1628
1629 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001630 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001631 return dst;
1632 }
1633
1634 /* --------- LITERAL --------- */
1635
1636 /* Load a literal into a register. Create a "load immediate"
1637 v-insn and return the register. */
1638 case Iex_Const: {
1639 ULong value;
1640 HReg dst = newVRegI(env);
1641 const IRConst *con = expr->Iex.Const.con;
1642
1643 /* Bitwise copy of the value. No sign/zero-extension */
1644 switch (con->tag) {
1645 case Ico_U64: value = con->Ico.U64; break;
1646 case Ico_U32: value = con->Ico.U32; break;
1647 case Ico_U16: value = con->Ico.U16; break;
1648 case Ico_U8: value = con->Ico.U8; break;
1649 default: vpanic("s390_isel_int_expr: invalid constant");
1650 }
1651
1652 addInstr(env, s390_insn_load_immediate(size, dst, value));
1653
1654 return dst;
1655 }
1656
1657 /* --------- MULTIPLEX --------- */
1658 case Iex_Mux0X: {
1659 IRExpr *cond_expr;
1660 HReg dst, tmp, rX;
1661 s390_opnd_RMI cond, r0, zero;
1662
1663 cond_expr = expr->Iex.Mux0X.cond;
1664
1665 dst = newVRegI(env);
1666 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1667 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1668 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1669
1670 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1671 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1672
1673 addInstr(env, s390_insn_move(size, dst, rX));
1674 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1675 return dst;
1676 }
1677
1678 /* Assume the condition is true and move rX to the destination reg. */
1679 addInstr(env, s390_insn_move(size, dst, rX));
1680
1681 /* Compute the condition ... */
1682 cond = s390_isel_int_expr_RMI(env, cond_expr);
1683
1684 /* tmp = cond & 0xFF */
1685 tmp = newVRegI(env);
1686 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1687 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1688
1689 /* ... and compare it with zero */
1690 zero = s390_opnd_imm(0);
1691 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1692
1693 /* ... and if it compared equal move r0 to the destination reg. */
1694 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1695 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1696
1697 return dst;
1698 }
1699
1700 default:
1701 break;
1702 }
1703
1704 /* We get here if no pattern matched. */
1705 irreducible:
1706 ppIRExpr(expr);
1707 vpanic("s390_isel_int_expr: cannot reduce tree");
1708}
1709
1710
1711static HReg
1712s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1713{
1714 HReg dst = s390_isel_int_expr_wrk(env, expr);
1715
1716 /* Sanity checks ... */
1717 vassert(hregClass(dst) == HRcInt64);
1718 vassert(hregIsVirtual(dst));
1719
1720 return dst;
1721}
1722
1723
1724static s390_opnd_RMI
1725s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1726{
1727 IRType ty = typeOfIRExpr(env->type_env, expr);
1728 s390_opnd_RMI dst;
1729
1730 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1731 ty == Ity_I64);
1732
1733 if (expr->tag == Iex_Load) {
1734 dst.tag = S390_OPND_AMODE;
1735 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1736 } else if (expr->tag == Iex_Get) {
1737 dst.tag = S390_OPND_AMODE;
1738 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1739 } else if (expr->tag == Iex_Const) {
1740 ULong value;
1741
1742 /* The bit pattern for the value will be stored as is in the least
1743 significant bits of VALUE. */
1744 switch (expr->Iex.Const.con->tag) {
1745 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1746 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1747 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1748 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1749 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1750 default:
1751 vpanic("s390_isel_int_expr_RMI");
1752 }
1753
1754 dst.tag = S390_OPND_IMMEDIATE;
1755 dst.variant.imm = value;
1756 } else {
1757 dst.tag = S390_OPND_REG;
1758 dst.variant.reg = s390_isel_int_expr(env, expr);
1759 }
1760
1761 return dst;
1762}
1763
1764
1765/*---------------------------------------------------------*/
1766/*--- ISEL: Floating point expressions (128 bit) ---*/
1767/*---------------------------------------------------------*/
1768static void
1769s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1770 IRExpr *expr)
1771{
1772 IRType ty = typeOfIRExpr(env->type_env, expr);
1773
1774 vassert(ty == Ity_F128);
1775
sewardj2019a972011-03-07 16:04:07 +00001776 switch (expr->tag) {
1777 case Iex_RdTmp:
1778 /* Return the virtual registers that hold the temporary. */
1779 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1780 return;
1781
1782 /* --------- LOAD --------- */
1783 case Iex_Load: {
1784 IRExpr *addr_hi, *addr_lo;
1785 s390_amode *am_hi, *am_lo;
1786
1787 if (expr->Iex.Load.end != Iend_BE)
1788 goto irreducible;
1789
1790 addr_hi = expr->Iex.Load.addr;
1791 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1792
1793 am_hi = s390_isel_amode(env, addr_hi);
1794 am_lo = s390_isel_amode(env, addr_lo);
1795
1796 *dst_hi = newVRegF(env);
1797 *dst_lo = newVRegF(env);
1798 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1799 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1800 return;
1801 }
1802
1803
1804 /* --------- GET --------- */
1805 case Iex_Get:
1806 /* This is not supported because loading 128-bit from the guest
1807 state is almost certainly wrong. Use get_fpr_pair instead. */
1808 vpanic("Iex_Get with F128 data");
1809
1810 /* --------- 4-ary OP --------- */
1811 case Iex_Qop:
1812 vpanic("Iex_Qop with F128 data");
1813
1814 /* --------- TERNARY OP --------- */
1815 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001816 IRTriop *triop = expr->Iex.Triop.details;
1817 IROp op = triop->op;
1818 IRExpr *left = triop->arg2;
1819 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001820 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001821 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1822
1823 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1824 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1825
1826 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1827 f12 = make_fpr(12);
1828 f13 = make_fpr(13);
1829 f14 = make_fpr(14);
1830 f15 = make_fpr(15);
1831
1832 /* 1st operand --> (f12, f14) */
1833 addInstr(env, s390_insn_move(8, f12, op1_hi));
1834 addInstr(env, s390_insn_move(8, f14, op1_lo));
1835
1836 /* 2nd operand --> (f13, f15) */
1837 addInstr(env, s390_insn_move(8, f13, op2_hi));
1838 addInstr(env, s390_insn_move(8, f15, op2_lo));
1839
1840 switch (op) {
1841 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1842 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1843 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1844 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1845 default:
1846 goto irreducible;
1847 }
1848
florian2c74d242012-09-12 19:38:42 +00001849 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1850 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001851
1852 /* Move result to virtual destination register */
1853 *dst_hi = newVRegF(env);
1854 *dst_lo = newVRegF(env);
1855 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1856 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1857
1858 return;
1859 }
1860
1861 /* --------- BINARY OP --------- */
1862 case Iex_Binop: {
1863 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001864
1865 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1866 f12 = make_fpr(12);
1867 f13 = make_fpr(13);
1868 f14 = make_fpr(14);
1869 f15 = make_fpr(15);
1870
1871 switch (expr->Iex.Binop.op) {
1872 case Iop_SqrtF128:
1873 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1874
1875 /* operand --> (f13, f15) */
1876 addInstr(env, s390_insn_move(8, f13, op_hi));
1877 addInstr(env, s390_insn_move(8, f15, op_lo));
1878
florian2c74d242012-09-12 19:38:42 +00001879 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1880 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1881 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001882
1883 /* Move result to virtual destination registers */
1884 *dst_hi = newVRegF(env);
1885 *dst_lo = newVRegF(env);
1886 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1887 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1888 return;
1889
1890 case Iop_F64HLtoF128:
1891 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1892 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1893 return;
1894
1895 default:
1896 goto irreducible;
1897 }
1898 }
1899
1900 /* --------- UNARY OP --------- */
1901 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001902 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001903 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00001904 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001905 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1906
1907 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1908 f12 = make_fpr(12);
1909 f13 = make_fpr(13);
1910 f14 = make_fpr(14);
1911 f15 = make_fpr(15);
1912
florian66e596d2012-09-07 15:00:53 +00001913 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001914 case Iop_NegF128:
1915 if (left->tag == Iex_Unop &&
1916 (left->Iex.Unop.op == Iop_AbsF32 ||
1917 left->Iex.Unop.op == Iop_AbsF64))
1918 bfpop = S390_BFP_NABS;
1919 else
1920 bfpop = S390_BFP_NEG;
1921 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00001922 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1923 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1924 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1925 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1926 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1927 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1928 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001929 default:
1930 goto irreducible;
1931 }
1932
1933 float128_opnd:
1934 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1935
1936 /* operand --> (f13, f15) */
1937 addInstr(env, s390_insn_move(8, f13, op_hi));
1938 addInstr(env, s390_insn_move(8, f15, op_lo));
1939
florian2c74d242012-09-12 19:38:42 +00001940 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001941 goto move_dst;
1942
1943 convert_float:
1944 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001945 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001946 goto move_dst;
1947
1948 convert_int:
1949 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001950 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001951 goto move_dst;
1952
1953 move_dst:
1954 /* Move result to virtual destination registers */
1955 *dst_hi = newVRegF(env);
1956 *dst_lo = newVRegF(env);
1957 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1958 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1959 return;
1960 }
1961
1962 default:
1963 goto irreducible;
1964 }
1965
1966 /* We get here if no pattern matched. */
1967 irreducible:
1968 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00001969 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00001970}
1971
1972/* Compute a 128-bit value into two 64-bit registers. These may be either
1973 real or virtual regs; in any case they must not be changed by subsequent
1974 code emitted by the caller. */
1975static void
1976s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1977{
1978 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1979
1980 /* Sanity checks ... */
1981 vassert(hregIsVirtual(*dst_hi));
1982 vassert(hregIsVirtual(*dst_lo));
1983 vassert(hregClass(*dst_hi) == HRcFlt64);
1984 vassert(hregClass(*dst_lo) == HRcFlt64);
1985}
1986
1987
1988/*---------------------------------------------------------*/
1989/*--- ISEL: Floating point expressions (64 bit) ---*/
1990/*---------------------------------------------------------*/
1991
1992static HReg
1993s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1994{
1995 IRType ty = typeOfIRExpr(env->type_env, expr);
1996 UChar size;
1997
1998 vassert(ty == Ity_F32 || ty == Ity_F64);
1999
2000 size = sizeofIRType(ty);
2001
2002 switch (expr->tag) {
2003 case Iex_RdTmp:
2004 /* Return the virtual register that holds the temporary. */
2005 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2006
2007 /* --------- LOAD --------- */
2008 case Iex_Load: {
2009 HReg dst = newVRegF(env);
2010 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2011
2012 if (expr->Iex.Load.end != Iend_BE)
2013 goto irreducible;
2014
2015 addInstr(env, s390_insn_load(size, dst, am));
2016
2017 return dst;
2018 }
2019
2020 /* --------- GET --------- */
2021 case Iex_Get: {
2022 HReg dst = newVRegF(env);
2023 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2024
2025 addInstr(env, s390_insn_load(size, dst, am));
2026
2027 return dst;
2028 }
2029
2030 /* --------- LITERAL --------- */
2031
2032 /* Load a literal into a register. Create a "load immediate"
2033 v-insn and return the register. */
2034 case Iex_Const: {
2035 ULong value;
2036 HReg dst = newVRegF(env);
2037 const IRConst *con = expr->Iex.Const.con;
2038
2039 /* Bitwise copy of the value. No sign/zero-extension */
2040 switch (con->tag) {
2041 case Ico_F32i: value = con->Ico.F32i; break;
2042 case Ico_F64i: value = con->Ico.F64i; break;
2043 default: vpanic("s390_isel_float_expr: invalid constant");
2044 }
2045
2046 if (value != 0) vpanic("cannot load immediate floating point constant");
2047
2048 addInstr(env, s390_insn_load_immediate(size, dst, value));
2049
2050 return dst;
2051 }
2052
2053 /* --------- 4-ary OP --------- */
2054 case Iex_Qop: {
2055 HReg op1, op2, op3, dst;
2056 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002057
florian5906a6b2012-10-16 02:53:33 +00002058 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002059 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002060 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002061 dst = newVRegF(env);
2062 addInstr(env, s390_insn_move(size, dst, op1));
2063
florian96d7cc32012-06-01 20:41:24 +00002064 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002065 case Iop_MAddF32:
2066 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2067 case Iop_MSubF32:
2068 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2069
2070 default:
2071 goto irreducible;
2072 }
2073
florian2c74d242012-09-12 19:38:42 +00002074 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2075 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002076 return dst;
2077 }
2078
2079 /* --------- TERNARY OP --------- */
2080 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002081 IRTriop *triop = expr->Iex.Triop.details;
2082 IROp op = triop->op;
2083 IRExpr *left = triop->arg2;
2084 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002085 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002086 HReg h1, op2, dst;
2087
2088 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2089 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2090 dst = newVRegF(env);
2091 addInstr(env, s390_insn_move(size, dst, h1));
2092 switch (op) {
2093 case Iop_AddF32:
2094 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2095 case Iop_SubF32:
2096 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2097 case Iop_MulF32:
2098 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2099 case Iop_DivF32:
2100 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2101
2102 default:
2103 goto irreducible;
2104 }
2105
florian2c74d242012-09-12 19:38:42 +00002106 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2107 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002108 return dst;
2109 }
2110
2111 /* --------- BINARY OP --------- */
2112 case Iex_Binop: {
2113 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002114 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002115 IRExpr *left = expr->Iex.Binop.arg2;
2116 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002117 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002118
2119 switch (op) {
2120 case Iop_SqrtF32:
2121 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002122 h1 = s390_isel_float_expr(env, left);
2123 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002124 set_bfp_rounding_mode_in_fpc(env, irrm);
2125 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002126 return dst;
sewardj2019a972011-03-07 16:04:07 +00002127
florian9fcff4c2012-09-10 03:09:04 +00002128 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2129 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2130 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2131 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2132 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2133 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2134 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002135
florian9fcff4c2012-09-10 03:09:04 +00002136 convert_float:
2137 h1 = s390_isel_float_expr(env, left);
2138 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002139
florian9fcff4c2012-09-10 03:09:04 +00002140 convert_int:
2141 h1 = s390_isel_int_expr(env, left);
2142 goto convert;
2143
florian2c74d242012-09-12 19:38:42 +00002144 convert: {
florian125e20d2012-10-07 15:42:37 +00002145 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002146 /* convert-from-fixed and load-rounded have a rounding mode field
2147 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002148 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002149 if (s390_host_has_fpext) {
2150 rounding_mode = get_bfp_rounding_mode(env, irrm);
2151 } else {
2152 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002153 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002154 }
florian9fcff4c2012-09-10 03:09:04 +00002155 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2156 rounding_mode));
2157 return dst;
florian2c74d242012-09-12 19:38:42 +00002158 }
florian9fcff4c2012-09-10 03:09:04 +00002159
sewardj2019a972011-03-07 16:04:07 +00002160 default:
2161 goto irreducible;
2162
2163 case Iop_F128toF64:
2164 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002165 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002166 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002167
florian9fcff4c2012-09-10 03:09:04 +00002168 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2169 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002170
florian9fcff4c2012-09-10 03:09:04 +00002171 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002172
florian9fcff4c2012-09-10 03:09:04 +00002173 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002174 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002175 f15 = make_fpr(15);
2176
2177 /* operand --> (f13, f15) */
2178 addInstr(env, s390_insn_move(8, f13, op_hi));
2179 addInstr(env, s390_insn_move(8, f15, op_lo));
2180
2181 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002182 /* load-rounded has a rounding mode field when the floating point
2183 extension facility is installed. */
2184 if (s390_host_has_fpext) {
2185 rounding_mode = get_bfp_rounding_mode(env, irrm);
2186 } else {
2187 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002188 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002189 }
floriancc491a62012-09-10 23:44:37 +00002190 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002191 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002192 return dst;
2193 }
2194 }
sewardj2019a972011-03-07 16:04:07 +00002195 }
2196
2197 /* --------- UNARY OP --------- */
2198 case Iex_Unop: {
2199 IROp op = expr->Iex.Unop.op;
2200 IRExpr *left = expr->Iex.Unop.arg;
2201 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002202 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002203 HReg h1, dst;
2204
2205 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2206 HReg dst_hi, dst_lo;
2207
2208 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2209 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2210 }
2211
florian4d71a082011-12-18 00:08:17 +00002212 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002213 dst = newVRegF(env);
2214 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2215 addInstr(env, s390_insn_move(size, dst, h1));
2216
2217 return dst;
2218 }
2219
2220 switch (op) {
2221 case Iop_NegF32:
2222 case Iop_NegF64:
2223 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002224 (left->Iex.Unop.op == Iop_AbsF32 ||
2225 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002226 bfpop = S390_BFP_NABS;
2227 else
2228 bfpop = S390_BFP_NEG;
2229 break;
2230
2231 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002232 case Iop_AbsF64:
2233 bfpop = S390_BFP_ABS;
2234 break;
2235
2236 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2237 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2238 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2239
2240 convert_float1:
2241 h1 = s390_isel_float_expr(env, left);
2242 goto convert1;
2243
2244 convert_int1:
2245 h1 = s390_isel_int_expr(env, left);
2246 goto convert1;
2247
2248 convert1:
2249 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002250 /* No rounding mode is needed for these conversions. Just stick
2251 one in. It won't be used later on. */
2252 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002253 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002254 return dst;
2255
sewardj2019a972011-03-07 16:04:07 +00002256 default:
2257 goto irreducible;
2258 }
2259
2260 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002261 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002262 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002263 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002264 return dst;
2265 }
2266
2267 default:
2268 goto irreducible;
2269 }
2270
2271 /* We get here if no pattern matched. */
2272 irreducible:
2273 ppIRExpr(expr);
2274 vpanic("s390_isel_float_expr: cannot reduce tree");
2275}
2276
2277
2278static HReg
2279s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2280{
2281 HReg dst = s390_isel_float_expr_wrk(env, expr);
2282
2283 /* Sanity checks ... */
2284 vassert(hregClass(dst) == HRcFlt64);
2285 vassert(hregIsVirtual(dst));
2286
2287 return dst;
2288}
2289
2290
2291/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002292/*--- ISEL: Decimal point expressions (128 bit) ---*/
2293/*---------------------------------------------------------*/
2294static void
2295s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2296 IRExpr *expr)
2297{
2298 IRType ty = typeOfIRExpr(env->type_env, expr);
2299
2300 vassert(ty == Ity_D128);
2301
2302 switch (expr->tag) {
2303 case Iex_RdTmp:
2304 /* Return the virtual registers that hold the temporary. */
2305 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2306 return;
2307
2308 /* --------- LOAD --------- */
2309 case Iex_Load: {
2310 IRExpr *addr_hi, *addr_lo;
2311 s390_amode *am_hi, *am_lo;
2312
2313 if (expr->Iex.Load.end != Iend_BE)
2314 goto irreducible;
2315
2316 addr_hi = expr->Iex.Load.addr;
2317 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2318
2319 am_hi = s390_isel_amode(env, addr_hi);
2320 am_lo = s390_isel_amode(env, addr_lo);
2321
2322 *dst_hi = newVRegF(env);
2323 *dst_lo = newVRegF(env);
2324 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2325 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2326 return;
2327 }
2328
2329 /* --------- GET --------- */
2330 case Iex_Get:
2331 /* This is not supported because loading 128-bit from the guest
2332 state is almost certainly wrong. Use get_dpr_pair instead. */
2333 vpanic("Iex_Get with D128 data");
2334
2335 /* --------- 4-ary OP --------- */
2336 case Iex_Qop:
2337 vpanic("Iex_Qop with D128 data");
2338
2339 /* --------- TERNARY OP --------- */
2340 case Iex_Triop: {
2341 IRTriop *triop = expr->Iex.Triop.details;
2342 IROp op = triop->op;
2343 IRExpr *irrm = triop->arg1;
2344 IRExpr *left = triop->arg2;
2345 IRExpr *right = triop->arg3;
2346 s390_dfp_round_t rounding_mode;
2347 s390_dfp_binop_t dfpop;
2348 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2349
2350 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2351 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2352
2353 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2354 (f12, f14) as op2 and (f13, f15) as destination) */
2355 f9 = make_fpr(9);
2356 f11 = make_fpr(11);
2357 f12 = make_fpr(12);
2358 f13 = make_fpr(13);
2359 f14 = make_fpr(14);
2360 f15 = make_fpr(15);
2361
2362 /* 1st operand --> (f9, f11) */
2363 addInstr(env, s390_insn_move(8, f9, op1_hi));
2364 addInstr(env, s390_insn_move(8, f11, op1_lo));
2365
2366 /* 2nd operand --> (f12, f14) */
2367 addInstr(env, s390_insn_move(8, f12, op2_hi));
2368 addInstr(env, s390_insn_move(8, f14, op2_lo));
2369
2370 switch (op) {
2371 case Iop_AddD128: dfpop = S390_DFP_ADD; break;
2372 case Iop_SubD128: dfpop = S390_DFP_SUB; break;
2373 case Iop_MulD128: dfpop = S390_DFP_MUL; break;
2374 case Iop_DivD128: dfpop = S390_DFP_DIV; break;
2375 default:
2376 goto irreducible;
2377 }
2378
2379 /* DFP binary ops have insns with rounding mode field
2380 when the floating point extension facility is installed. */
2381 if (s390_host_has_fpext) {
2382 rounding_mode = get_dfp_rounding_mode(env, irrm);
2383 } else {
2384 set_dfp_rounding_mode_in_fpc(env, irrm);
2385 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2386 }
2387
2388 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2389 f12, f14, rounding_mode));
2390
2391 /* Move result to virtual destination register */
2392 *dst_hi = newVRegF(env);
2393 *dst_lo = newVRegF(env);
2394 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2395 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2396
2397 return;
2398 }
2399
2400 /* --------- BINARY OP --------- */
2401 case Iex_Binop: {
2402 switch (expr->Iex.Binop.op) {
2403 case Iop_D64HLtoD128:
2404 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2405 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2406 return;
2407
2408 default:
2409 goto irreducible;
2410 }
2411 }
2412
2413 /* --------- UNARY OP --------- */
2414 case Iex_Unop: {
2415 IRExpr *left = expr->Iex.Unop.arg;
2416 s390_dfp_conv_t conv;
2417 // HReg op, f12, f13, f14, f15;
2418 HReg op, f12, f14;
2419
2420 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2421 f12 = make_fpr(12);
2422 // f13 = make_fpr(13);
2423 f14 = make_fpr(14);
2424 // f15 = make_fpr(15);
2425
2426 switch (expr->Iex.Unop.op) {
2427 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
2428 default:
2429 goto irreducible;
2430 }
2431
2432 convert_dfp:
2433 op = s390_isel_dfp_expr(env, left);
2434 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2435 goto move_dst;
2436
2437 move_dst:
2438 /* Move result to virtual destination registers */
2439 *dst_hi = newVRegF(env);
2440 *dst_lo = newVRegF(env);
2441 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2442 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2443 return;
2444 }
2445
2446 default:
2447 goto irreducible;
2448 }
2449
2450 /* We get here if no pattern matched. */
2451 irreducible:
2452 ppIRExpr(expr);
2453 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2454
2455}
2456
2457
2458/* Compute a 128-bit value into two 64-bit registers. These may be either
2459 real or virtual regs; in any case they must not be changed by subsequent
2460 code emitted by the caller. */
2461static void
2462s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2463{
2464 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2465
2466 /* Sanity checks ... */
2467 vassert(hregIsVirtual(*dst_hi));
2468 vassert(hregIsVirtual(*dst_lo));
2469 vassert(hregClass(*dst_hi) == HRcFlt64);
2470 vassert(hregClass(*dst_lo) == HRcFlt64);
2471}
2472
2473
2474/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002475/*--- ISEL: Decimal point expressions (64 bit) ---*/
2476/*---------------------------------------------------------*/
2477
2478static HReg
2479s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2480{
2481 IRType ty = typeOfIRExpr(env->type_env, expr);
2482 UChar size;
2483
floriane38f6412012-12-21 17:32:12 +00002484 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002485
2486 size = sizeofIRType(ty);
2487
2488 switch (expr->tag) {
2489 case Iex_RdTmp:
2490 /* Return the virtual register that holds the temporary. */
2491 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2492
2493 /* --------- LOAD --------- */
2494 case Iex_Load: {
2495 HReg dst = newVRegF(env);
2496 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2497
2498 if (expr->Iex.Load.end != Iend_BE)
2499 goto irreducible;
2500
2501 addInstr(env, s390_insn_load(size, dst, am));
2502
2503 return dst;
2504 }
2505
2506 /* --------- GET --------- */
2507 case Iex_Get: {
2508 HReg dst = newVRegF(env);
2509 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2510
2511 addInstr(env, s390_insn_load(size, dst, am));
2512
2513 return dst;
2514 }
2515
floriane38f6412012-12-21 17:32:12 +00002516 /* --------- BINARY OP --------- */
2517 case Iex_Binop: {
2518 IROp op = expr->Iex.Binop.op;
2519 IRExpr *irrm = expr->Iex.Binop.arg1;
2520 IRExpr *left = expr->Iex.Binop.arg2;
2521 HReg h1, dst;
2522 s390_dfp_conv_t conv;
2523
2524 switch (op) {
2525 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
2526
2527 convert_dfp:
2528 h1 = s390_isel_dfp_expr(env, left);
2529 goto convert;
2530
2531 convert: {
2532 s390_dfp_round_t rounding_mode;
2533 /* convert-from-fixed and load-rounded have a rounding mode field
2534 when the floating point extension facility is installed. */
2535 dst = newVRegF(env);
2536 if (s390_host_has_fpext) {
2537 rounding_mode = get_dfp_rounding_mode(env, irrm);
2538 } else {
2539 set_dfp_rounding_mode_in_fpc(env, irrm);
2540 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2541 }
2542 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2543 rounding_mode));
2544 return dst;
2545 }
2546 default:
2547 goto irreducible;
2548
2549 case Iop_D128toD64: {
2550 HReg op_hi, op_lo, f13, f15;
2551 s390_dfp_round_t rounding_mode;
2552
2553 conv = S390_DFP_D128_TO_D64;
2554
2555 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2556
2557 /* We use non-virtual registers as pairs (f13, f15) */
2558 f13 = make_fpr(13);
2559 f15 = make_fpr(15);
2560
2561 /* operand --> (f13, f15) */
2562 addInstr(env, s390_insn_move(8, f13, op_hi));
2563 addInstr(env, s390_insn_move(8, f15, op_lo));
2564
2565 dst = newVRegF(env);
2566 /* load-rounded has a rounding mode field when the floating point
2567 extension facility is installed. */
2568 if (s390_host_has_fpext) {
2569 rounding_mode = get_dfp_rounding_mode(env, irrm);
2570 } else {
2571 set_dfp_rounding_mode_in_fpc(env, irrm);
2572 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2573 }
2574 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2575 rounding_mode));
2576 return dst;
2577 }
2578
2579 }
2580 }
2581
2582 /* --------- UNARY OP --------- */
2583 case Iex_Unop: {
2584 IROp op = expr->Iex.Unop.op;
2585 IRExpr *left = expr->Iex.Unop.arg;
2586 s390_dfp_conv_t conv;
2587 HReg h1, dst;
2588
2589 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2590 HReg dst_hi, dst_lo;
2591
2592 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2593 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2594 }
2595
2596 if (op == Iop_ReinterpI64asD64) {
2597 dst = newVRegF(env);
2598 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2599 addInstr(env, s390_insn_move(size, dst, h1));
2600
2601 return dst;
2602 }
2603
2604 switch (op) {
2605 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
2606
2607 convert_dfp1:
2608 h1 = s390_isel_dfp_expr(env, left);
2609 goto convert1;
2610
2611 convert1:
2612 dst = newVRegF(env);
2613 /* No rounding mode is needed for these conversions. Just stick
2614 one in. It won't be used later on. */
2615 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2616 S390_DFP_ROUND_NEAREST_EVEN_4));
2617 return dst;
2618
2619 default:
2620 goto irreducible;
2621 }
2622 }
2623
florian12390202012-11-10 22:34:14 +00002624 /* --------- TERNARY OP --------- */
2625 case Iex_Triop: {
2626 IRTriop *triop = expr->Iex.Triop.details;
2627 IROp op = triop->op;
2628 IRExpr *irrm = triop->arg1;
2629 IRExpr *left = triop->arg2;
2630 IRExpr *right = triop->arg3;
2631 s390_dfp_round_t rounding_mode;
2632 s390_dfp_binop_t dfpop;
2633 HReg op2, op3, dst;
2634
2635 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2636 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2637 dst = newVRegF(env);
2638 switch (op) {
2639 case Iop_AddD64: dfpop = S390_DFP_ADD; break;
2640 case Iop_SubD64: dfpop = S390_DFP_SUB; break;
2641 case Iop_MulD64: dfpop = S390_DFP_MUL; break;
2642 case Iop_DivD64: dfpop = S390_DFP_DIV; break;
2643 default:
2644 goto irreducible;
2645 }
2646 /* DFP binary ops have insns with rounding mode field
2647 when the floating point extension facility is installed. */
2648 if (s390_host_has_fpext) {
2649 rounding_mode = get_dfp_rounding_mode(env, irrm);
2650 } else {
2651 set_dfp_rounding_mode_in_fpc(env, irrm);
2652 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2653 }
2654
2655 addInstr(env,
2656 s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
2657 return dst;
2658 }
2659
2660 default:
2661 goto irreducible;
2662 }
2663
2664 /* We get here if no pattern matched. */
2665 irreducible:
2666 ppIRExpr(expr);
2667 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2668}
2669
2670static HReg
2671s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2672{
2673 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2674
2675 /* Sanity checks ... */
2676 vassert(hregClass(dst) == HRcFlt64);
2677 vassert(hregIsVirtual(dst));
2678
2679 return dst;
2680}
2681
2682
2683/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002684/*--- ISEL: Condition Code ---*/
2685/*---------------------------------------------------------*/
2686
2687/* This function handles all operators that produce a 1-bit result */
2688static s390_cc_t
2689s390_isel_cc(ISelEnv *env, IRExpr *cond)
2690{
2691 UChar size;
2692
2693 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2694
2695 /* Constant: either 1 or 0 */
2696 if (cond->tag == Iex_Const) {
2697 vassert(cond->Iex.Const.con->tag == Ico_U1);
2698 vassert(cond->Iex.Const.con->Ico.U1 == True
2699 || cond->Iex.Const.con->Ico.U1 == False);
2700
2701 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2702 }
2703
2704 /* Variable: values are 1 or 0 */
2705 if (cond->tag == Iex_RdTmp) {
2706 IRTemp tmp = cond->Iex.RdTmp.tmp;
2707 HReg reg = lookupIRTemp(env, tmp);
2708
2709 /* Load-and-test does not modify REG; so this is OK. */
2710 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2711 size = 4;
2712 else
2713 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2714 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2715 return S390_CC_NE;
2716 }
2717
2718 /* Unary operators */
2719 if (cond->tag == Iex_Unop) {
2720 IRExpr *arg = cond->Iex.Unop.arg;
2721
2722 switch (cond->Iex.Unop.op) {
2723 case Iop_Not1: /* Not1(cond) */
2724 /* Generate code for EXPR, and negate the test condition */
2725 return s390_cc_invert(s390_isel_cc(env, arg));
2726
2727 /* Iop_32/64to1 select the LSB from their operand */
2728 case Iop_32to1:
2729 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002730 HReg dst = newVRegI(env);
2731 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002732
2733 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2734
florianf366a802012-08-03 00:42:18 +00002735 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002736 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2737 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2738 return S390_CC_NE;
2739 }
2740
2741 case Iop_CmpNEZ8:
2742 case Iop_CmpNEZ16: {
2743 s390_opnd_RMI src;
2744 s390_unop_t op;
2745 HReg dst;
2746
2747 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2748 : S390_ZERO_EXTEND_16;
2749 dst = newVRegI(env);
2750 src = s390_isel_int_expr_RMI(env, arg);
2751 addInstr(env, s390_insn_unop(4, op, dst, src));
2752 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2753 return S390_CC_NE;
2754 }
2755
2756 case Iop_CmpNEZ32:
2757 case Iop_CmpNEZ64: {
2758 s390_opnd_RMI src;
2759
2760 src = s390_isel_int_expr_RMI(env, arg);
2761 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2762 addInstr(env, s390_insn_test(size, src));
2763 return S390_CC_NE;
2764 }
2765
2766 default:
2767 goto fail;
2768 }
2769 }
2770
2771 /* Binary operators */
2772 if (cond->tag == Iex_Binop) {
2773 IRExpr *arg1 = cond->Iex.Binop.arg1;
2774 IRExpr *arg2 = cond->Iex.Binop.arg2;
2775 HReg reg1, reg2;
2776
2777 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2778
2779 switch (cond->Iex.Binop.op) {
2780 s390_unop_t op;
2781 s390_cc_t result;
2782
2783 case Iop_CmpEQ8:
2784 case Iop_CasCmpEQ8:
2785 op = S390_ZERO_EXTEND_8;
2786 result = S390_CC_E;
2787 goto do_compare_ze;
2788
2789 case Iop_CmpNE8:
2790 case Iop_CasCmpNE8:
2791 op = S390_ZERO_EXTEND_8;
2792 result = S390_CC_NE;
2793 goto do_compare_ze;
2794
2795 case Iop_CmpEQ16:
2796 case Iop_CasCmpEQ16:
2797 op = S390_ZERO_EXTEND_16;
2798 result = S390_CC_E;
2799 goto do_compare_ze;
2800
2801 case Iop_CmpNE16:
2802 case Iop_CasCmpNE16:
2803 op = S390_ZERO_EXTEND_16;
2804 result = S390_CC_NE;
2805 goto do_compare_ze;
2806
2807 do_compare_ze: {
2808 s390_opnd_RMI op1, op2;
2809
2810 op1 = s390_isel_int_expr_RMI(env, arg1);
2811 reg1 = newVRegI(env);
2812 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2813
2814 op2 = s390_isel_int_expr_RMI(env, arg2);
2815 reg2 = newVRegI(env);
2816 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2817
2818 op2 = s390_opnd_reg(reg2);
2819 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2820
2821 return result;
2822 }
2823
2824 case Iop_CmpEQ32:
2825 case Iop_CmpEQ64:
2826 case Iop_CasCmpEQ32:
2827 case Iop_CasCmpEQ64:
2828 result = S390_CC_E;
2829 goto do_compare;
2830
2831 case Iop_CmpNE32:
2832 case Iop_CmpNE64:
2833 case Iop_CasCmpNE32:
2834 case Iop_CasCmpNE64:
2835 result = S390_CC_NE;
2836 goto do_compare;
2837
2838 do_compare: {
2839 HReg op1;
2840 s390_opnd_RMI op2;
2841
2842 order_commutative_operands(arg1, arg2);
2843
2844 op1 = s390_isel_int_expr(env, arg1);
2845 op2 = s390_isel_int_expr_RMI(env, arg2);
2846
2847 addInstr(env, s390_insn_compare(size, op1, op2, False));
2848
2849 return result;
2850 }
2851
2852 case Iop_CmpLT32S:
2853 case Iop_CmpLE32S:
2854 case Iop_CmpLT64S:
2855 case Iop_CmpLE64S: {
2856 HReg op1;
2857 s390_opnd_RMI op2;
2858
2859 op1 = s390_isel_int_expr(env, arg1);
2860 op2 = s390_isel_int_expr_RMI(env, arg2);
2861
2862 addInstr(env, s390_insn_compare(size, op1, op2, True));
2863
2864 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2865 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2866 }
2867
2868 case Iop_CmpLT32U:
2869 case Iop_CmpLE32U:
2870 case Iop_CmpLT64U:
2871 case Iop_CmpLE64U: {
2872 HReg op1;
2873 s390_opnd_RMI op2;
2874
2875 op1 = s390_isel_int_expr(env, arg1);
2876 op2 = s390_isel_int_expr_RMI(env, arg2);
2877
2878 addInstr(env, s390_insn_compare(size, op1, op2, False));
2879
2880 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2881 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2882 }
2883
2884 default:
2885 goto fail;
2886 }
2887 }
2888
2889 fail:
2890 ppIRExpr(cond);
2891 vpanic("s390_isel_cc: unexpected operator");
2892}
2893
2894
2895/*---------------------------------------------------------*/
2896/*--- ISEL: Statements ---*/
2897/*---------------------------------------------------------*/
2898
2899static void
2900s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2901{
2902 if (vex_traceflags & VEX_TRACE_VCODE) {
2903 vex_printf("\n -- ");
2904 ppIRStmt(stmt);
2905 vex_printf("\n");
2906 }
2907
2908 switch (stmt->tag) {
2909
2910 /* --------- STORE --------- */
2911 case Ist_Store: {
2912 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2913 s390_amode *am;
2914 HReg src;
2915
2916 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2917
2918 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2919
2920 switch (tyd) {
2921 case Ity_I8:
2922 case Ity_I16:
2923 case Ity_I32:
2924 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00002925 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00002926 if (am->tag == S390_AMODE_B12 &&
2927 s390_expr_is_const_zero(stmt->Ist.Store.data)) {
2928 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
2929 return;
2930 }
sewardj2019a972011-03-07 16:04:07 +00002931 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2932 break;
2933
2934 case Ity_F32:
2935 case Ity_F64:
2936 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2937 break;
2938
florianeb981ae2012-12-21 18:55:03 +00002939 case Ity_D32:
2940 case Ity_D64:
2941 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
2942 break;
2943
sewardj2019a972011-03-07 16:04:07 +00002944 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00002945 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00002946 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00002947 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00002948
2949 default:
2950 goto stmt_fail;
2951 }
2952
2953 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2954 return;
2955 }
2956
2957 /* --------- PUT --------- */
2958 case Ist_Put: {
2959 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2960 HReg src;
2961 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002962 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002963
florianad43b3a2012-02-20 15:01:14 +00002964 /* Detect updates to certain guest registers. We track the contents
2965 of those registers as long as they contain constants. If the new
2966 constant is either zero or in the 8-bit neighbourhood of the
2967 current value we can use a memory-to-memory insn to do the update. */
2968
2969 Int offset = stmt->Ist.Put.offset;
2970
2971 /* Check necessary conditions:
2972 (1) must be one of the registers we care about
2973 (2) assigned value must be a constant */
2974 Int guest_reg = get_guest_reg(offset);
2975
2976 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2977
florianad43b3a2012-02-20 15:01:14 +00002978 if (stmt->Ist.Put.data->tag != Iex_Const) {
2979 /* Invalidate guest register contents */
2980 env->old_value_valid[guest_reg] = False;
2981 goto not_special;
2982 }
2983
cborntraaf7ad282012-08-08 14:11:33 +00002984 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2985 if (tyd != Ity_I64)
2986 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002987
cborntraaf7ad282012-08-08 14:11:33 +00002988 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002989
2990 old_value = env->old_value[guest_reg];
2991 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2992 env->old_value[guest_reg] = new_value;
2993
2994 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2995 env->old_value_valid[guest_reg] = True;
2996
2997 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00002998 to do here. */
florianad43b3a2012-02-20 15:01:14 +00002999 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003000 return;
florianad43b3a2012-02-20 15:01:14 +00003001 }
3002
3003 /* guest register = 0 */
3004 if (new_value == 0) {
florian09bbba82012-12-11 04:09:43 +00003005 am = s390_amode_for_guest_state(offset);
3006 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
florianad43b3a2012-02-20 15:01:14 +00003007 return;
3008 }
3009
3010 if (old_value_is_valid == False) goto not_special;
3011
3012 /* If the new value is in the neighbourhood of the old value
3013 we can use a memory-to-memory insn */
3014 difference = new_value - old_value;
3015
3016 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003017 am = s390_amode_for_guest_state(offset);
3018 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003019 (difference & 0xFF), new_value));
3020 return;
3021 }
3022
3023 /* If the high word is the same it is sufficient to load the low word.
3024 Use R0 as a scratch reg. */
3025 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00003026 HReg r0 = make_gpr(0);
florianad43b3a2012-02-20 15:01:14 +00003027
florianf85fe3e2012-12-22 02:28:25 +00003028 am = s390_amode_for_guest_state(offset + 4);
florianad43b3a2012-02-20 15:01:14 +00003029 addInstr(env, s390_insn_load_immediate(4, r0,
3030 new_value & 0xFFFFFFFF));
florianf85fe3e2012-12-22 02:28:25 +00003031 addInstr(env, s390_insn_store(4, am, r0));
florianad43b3a2012-02-20 15:01:14 +00003032 return;
3033 }
3034
3035 /* No special case applies... fall through */
3036
3037 not_special:
sewardj2019a972011-03-07 16:04:07 +00003038 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
3039
3040 switch (tyd) {
3041 case Ity_I8:
3042 case Ity_I16:
3043 case Ity_I32:
3044 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003045 if (am->tag == S390_AMODE_B12 &&
3046 s390_expr_is_const_zero(stmt->Ist.Put.data)) {
3047 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
3048 return;
3049 }
sewardj2019a972011-03-07 16:04:07 +00003050 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3051 break;
3052
3053 case Ity_F32:
3054 case Ity_F64:
3055 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3056 break;
3057
3058 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003059 case Ity_D128:
3060 /* Does not occur. See function put_(f|d)pr_pair. */
3061 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003062
floriane38f6412012-12-21 17:32:12 +00003063 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003064 case Ity_D64:
3065 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3066 break;
3067
sewardj2019a972011-03-07 16:04:07 +00003068 default:
3069 goto stmt_fail;
3070 }
3071
3072 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3073 return;
3074 }
3075
3076 /* --------- TMP --------- */
3077 case Ist_WrTmp: {
3078 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3079 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3080 HReg src, dst;
3081
3082 switch (tyd) {
3083 case Ity_I128: {
3084 HReg dst_hi, dst_lo, res_hi, res_lo;
3085
3086 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3087 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3088
3089 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3090 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3091 return;
3092 }
3093
3094 case Ity_I8:
3095 case Ity_I16:
3096 case Ity_I32:
3097 case Ity_I64:
3098 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3099 dst = lookupIRTemp(env, tmp);
3100 break;
3101
3102 case Ity_I1: {
3103 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3104 dst = lookupIRTemp(env, tmp);
3105 addInstr(env, s390_insn_cc2bool(dst, cond));
3106 return;
3107 }
3108
3109 case Ity_F32:
3110 case Ity_F64:
3111 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3112 dst = lookupIRTemp(env, tmp);
3113 break;
3114
3115 case Ity_F128: {
3116 HReg dst_hi, dst_lo, res_hi, res_lo;
3117
3118 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3119 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3120
3121 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3122 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3123 return;
3124 }
3125
floriane38f6412012-12-21 17:32:12 +00003126 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003127 case Ity_D64:
3128 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3129 dst = lookupIRTemp(env, tmp);
3130 break;
3131
floriane38f6412012-12-21 17:32:12 +00003132 case Ity_D128: {
3133 HReg dst_hi, dst_lo, res_hi, res_lo;
3134
3135 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3136 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3137
3138 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3139 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3140 return;
3141 }
3142
sewardj2019a972011-03-07 16:04:07 +00003143 default:
3144 goto stmt_fail;
3145 }
3146
3147 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3148 return;
3149 }
3150
3151 /* --------- Call to DIRTY helper --------- */
3152 case Ist_Dirty: {
3153 IRType retty;
3154 IRDirty* d = stmt->Ist.Dirty.details;
3155 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003156 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003157 Int i;
3158
3159 /* Invalidate tracked values of those guest state registers that are
3160 modified by this helper. */
3161 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003162 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3163 descriptors in guest state effect descriptions. Hence: */
3164 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003165 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3166 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3167 if (guest_reg != GUEST_UNKNOWN)
3168 env->old_value_valid[guest_reg] = False;
3169 }
3170 }
sewardj2019a972011-03-07 16:04:07 +00003171
3172 if (d->nFxState == 0)
3173 vassert(!d->needsBBP);
3174
3175 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3176
florian01ed6e72012-05-27 16:52:43 +00003177 if (d->tmp == IRTemp_INVALID) {
3178 /* No return value. */
3179 dst = INVALID_HREG;
3180 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003181 return;
florian01ed6e72012-05-27 16:52:43 +00003182 }
sewardj2019a972011-03-07 16:04:07 +00003183
3184 retty = typeOfIRTemp(env->type_env, d->tmp);
3185 if (retty == Ity_I64 || retty == Ity_I32
3186 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003187 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003188 dst = lookupIRTemp(env, d->tmp);
3189 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003190 return;
3191 }
3192 break;
3193 }
3194
3195 case Ist_CAS:
3196 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3197 IRCAS *cas = stmt->Ist.CAS.details;
3198 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3199 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3200 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3201 HReg old = lookupIRTemp(env, cas->oldLo);
3202
3203 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3204 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3205 } else {
3206 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3207 }
3208 return;
3209 } else {
florian448cbba2012-06-06 02:26:01 +00003210 IRCAS *cas = stmt->Ist.CAS.details;
3211 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3212 HReg r8, r9, r10, r11, r1;
3213 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3214 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3215 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3216 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3217 HReg old_low = lookupIRTemp(env, cas->oldLo);
3218 HReg old_high = lookupIRTemp(env, cas->oldHi);
3219
3220 /* Use non-virtual registers r8 and r9 as pair for op1
3221 and move op1 there */
3222 r8 = make_gpr(8);
3223 r9 = make_gpr(9);
3224 addInstr(env, s390_insn_move(8, r8, op1_high));
3225 addInstr(env, s390_insn_move(8, r9, op1_low));
3226
3227 /* Use non-virtual registers r10 and r11 as pair for op3
3228 and move op3 there */
3229 r10 = make_gpr(10);
3230 r11 = make_gpr(11);
3231 addInstr(env, s390_insn_move(8, r10, op3_high));
3232 addInstr(env, s390_insn_move(8, r11, op3_low));
3233
3234 /* Register r1 is used as a scratch register */
3235 r1 = make_gpr(1);
3236
3237 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3238 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3239 old_high, old_low, r1));
3240 } else {
3241 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3242 old_high, old_low, r1));
3243 }
3244 addInstr(env, s390_insn_move(8, op1_high, r8));
3245 addInstr(env, s390_insn_move(8, op1_low, r9));
3246 addInstr(env, s390_insn_move(8, op3_high, r10));
3247 addInstr(env, s390_insn_move(8, op3_low, r11));
3248 return;
sewardj2019a972011-03-07 16:04:07 +00003249 }
3250 break;
3251
3252 /* --------- EXIT --------- */
3253 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003254 s390_cc_t cond;
3255 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3256
3257 if (tag != Ico_U64)
3258 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3259
florian8844a632012-04-13 04:04:06 +00003260 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003261 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003262
3263 /* Case: boring transfer to known address */
3264 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3265 if (env->chaining_allowed) {
3266 /* .. almost always true .. */
3267 /* Skip the event check at the dst if this is a forwards
3268 edge. */
3269 Bool to_fast_entry
3270 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3271 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3272 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3273 guest_IA, to_fast_entry));
3274 } else {
3275 /* .. very occasionally .. */
3276 /* We can't use chaining, so ask for an assisted transfer,
3277 as that's the only alternative that is allowable. */
3278 HReg dst = s390_isel_int_expr(env,
3279 IRExpr_Const(stmt->Ist.Exit.dst));
3280 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3281 }
3282 return;
3283 }
3284
3285 /* Case: assisted transfer to arbitrary address */
3286 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003287 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003288 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003289 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003290 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003291 case Ijk_Sys_syscall:
3292 case Ijk_ClientReq:
3293 case Ijk_NoRedir:
3294 case Ijk_Yield:
3295 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003296 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3297 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3298 stmt->Ist.Exit.jk));
3299 return;
3300 }
3301 default:
3302 break;
3303 }
3304
3305 /* Do we ever expect to see any other kind? */
3306 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003307 }
3308
3309 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003310 case Ist_MBE:
3311 switch (stmt->Ist.MBE.event) {
3312 case Imbe_Fence:
3313 addInstr(env, s390_insn_mfence());
3314 return;
3315 default:
3316 break;
3317 }
sewardj2019a972011-03-07 16:04:07 +00003318 break;
3319
3320 /* --------- Miscellaneous --------- */
3321
3322 case Ist_PutI: /* Not needed */
3323 case Ist_IMark: /* Doesn't generate any executable code */
3324 case Ist_NoOp: /* Doesn't generate any executable code */
3325 case Ist_AbiHint: /* Meaningless in IR */
3326 return;
3327
3328 default:
3329 break;
3330 }
3331
3332 stmt_fail:
3333 ppIRStmt(stmt);
3334 vpanic("s390_isel_stmt");
3335}
3336
3337
3338/*---------------------------------------------------------*/
3339/*--- ISEL: Basic block terminators (Nexts) ---*/
3340/*---------------------------------------------------------*/
3341
3342static void
florianffbd84d2012-12-09 02:06:29 +00003343iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003344{
sewardj2019a972011-03-07 16:04:07 +00003345 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003346 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003347 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003348 vex_printf("; exit-");
3349 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003350 vex_printf("\n");
3351 }
3352
florian8844a632012-04-13 04:04:06 +00003353 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3354
3355 /* Case: boring transfer to known address */
3356 if (next->tag == Iex_Const) {
3357 IRConst *cdst = next->Iex.Const.con;
3358 vassert(cdst->tag == Ico_U64);
3359 if (jk == Ijk_Boring || jk == Ijk_Call) {
3360 /* Boring transfer to known address */
3361 if (env->chaining_allowed) {
3362 /* .. almost always true .. */
3363 /* Skip the event check at the dst if this is a forwards
3364 edge. */
3365 Bool to_fast_entry
3366 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3367 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3368 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3369 guest_IA, to_fast_entry));
3370 } else {
3371 /* .. very occasionally .. */
3372 /* We can't use chaining, so ask for an indirect transfer,
3373 as that's the cheapest alternative that is allowable. */
3374 HReg dst = s390_isel_int_expr(env, next);
3375 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3376 Ijk_Boring));
3377 }
3378 return;
3379 }
3380 }
3381
3382 /* Case: call/return (==boring) transfer to any address */
3383 switch (jk) {
3384 case Ijk_Boring:
3385 case Ijk_Ret:
3386 case Ijk_Call: {
3387 HReg dst = s390_isel_int_expr(env, next);
3388 if (env->chaining_allowed) {
3389 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3390 } else {
3391 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3392 Ijk_Boring));
3393 }
3394 return;
3395 }
3396 default:
3397 break;
3398 }
3399
3400 /* Case: some other kind of transfer to any address */
3401 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003402 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003403 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003404 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003405 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003406 case Ijk_Sys_syscall:
3407 case Ijk_ClientReq:
3408 case Ijk_NoRedir:
3409 case Ijk_Yield:
3410 case Ijk_SigTRAP: {
3411 HReg dst = s390_isel_int_expr(env, next);
3412 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3413 return;
3414 }
3415 default:
3416 break;
3417 }
3418
3419 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003420}
3421
3422
3423/*---------------------------------------------------------*/
3424/*--- Insn selector top-level ---*/
3425/*---------------------------------------------------------*/
3426
florianf26994a2012-04-21 03:34:54 +00003427/* Translate an entire SB to s390 code.
3428 Note: archinfo_host is a pointer to a stack-allocated variable.
3429 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003430
3431HInstrArray *
3432iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003433 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3434 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3435 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003436{
3437 UInt i, j;
3438 HReg hreg, hregHI;
3439 ISelEnv *env;
3440 UInt hwcaps_host = archinfo_host->hwcaps;
3441
florianf26994a2012-04-21 03:34:54 +00003442 /* KLUDGE: export hwcaps. */
3443 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003444
sewardj2019a972011-03-07 16:04:07 +00003445 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003446 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003447
3448 /* Make up an initial environment to use. */
3449 env = LibVEX_Alloc(sizeof(ISelEnv));
3450 env->vreg_ctr = 0;
3451
3452 /* Set up output code array. */
3453 env->code = newHInstrArray();
3454
3455 /* Copy BB's type env. */
3456 env->type_env = bb->tyenv;
3457
florianad43b3a2012-02-20 15:01:14 +00003458 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00003459 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3460 env->old_value[i] = 0; /* just something to have a defined value */
3461 env->old_value_valid[i] = False;
3462 }
3463
sewardj2019a972011-03-07 16:04:07 +00003464 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3465 change as we go along. For some reason types_used has Int type -- but
3466 it should be unsigned. Internally we use an unsigned type; so we
3467 assert it here. */
3468 vassert(bb->tyenv->types_used >= 0);
3469
3470 env->n_vregmap = bb->tyenv->types_used;
3471 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3472 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3473
florian2c74d242012-09-12 19:38:42 +00003474 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003475 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003476
sewardj2019a972011-03-07 16:04:07 +00003477 /* and finally ... */
3478 env->hwcaps = hwcaps_host;
3479
florian8844a632012-04-13 04:04:06 +00003480 env->max_ga = max_ga;
3481 env->chaining_allowed = chaining_allowed;
3482
sewardj2019a972011-03-07 16:04:07 +00003483 /* For each IR temporary, allocate a suitably-kinded virtual
3484 register. */
3485 j = 0;
3486 for (i = 0; i < env->n_vregmap; i++) {
3487 hregHI = hreg = INVALID_HREG;
3488 switch (bb->tyenv->types[i]) {
3489 case Ity_I1:
3490 case Ity_I8:
3491 case Ity_I16:
3492 case Ity_I32:
3493 hreg = mkHReg(j++, HRcInt64, True);
3494 break;
3495
3496 case Ity_I64:
3497 hreg = mkHReg(j++, HRcInt64, True);
3498 break;
3499
3500 case Ity_I128:
3501 hreg = mkHReg(j++, HRcInt64, True);
3502 hregHI = mkHReg(j++, HRcInt64, True);
3503 break;
3504
3505 case Ity_F32:
3506 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003507 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003508 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003509 hreg = mkHReg(j++, HRcFlt64, True);
3510 break;
3511
3512 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003513 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003514 hreg = mkHReg(j++, HRcFlt64, True);
3515 hregHI = mkHReg(j++, HRcFlt64, True);
3516 break;
3517
3518 case Ity_V128: /* fall through */
3519 default:
3520 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003521 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003522 }
3523
3524 env->vregmap[i] = hreg;
3525 env->vregmapHI[i] = hregHI;
3526 }
3527 env->vreg_ctr = j;
3528
florian8844a632012-04-13 04:04:06 +00003529 /* The very first instruction must be an event check. */
3530 s390_amode *counter, *fail_addr;
3531 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3532 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3533 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3534
3535 /* Possibly a block counter increment (for profiling). At this
3536 point we don't know the address of the counter, so just pretend
3537 it is zero. It will have to be patched later, but before this
3538 translation is used, by a call to LibVEX_patchProfInc. */
3539 if (add_profinc) {
3540 addInstr(env, s390_insn_profinc());
3541 }
3542
sewardj2019a972011-03-07 16:04:07 +00003543 /* Ok, finally we can iterate over the statements. */
3544 for (i = 0; i < bb->stmts_used; i++)
3545 if (bb->stmts[i])
3546 s390_isel_stmt(env, bb->stmts[i]);
3547
florian8844a632012-04-13 04:04:06 +00003548 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003549
3550 /* Record the number of vregs we used. */
3551 env->code->n_vregs = env->vreg_ctr;
3552
3553 return env->code;
3554}
3555
3556/*---------------------------------------------------------------*/
3557/*--- end host_s390_isel.c ---*/
3558/*---------------------------------------------------------------*/