blob: 1203459920a417b072b1eac873aeaa8b8866be11 [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);
florian79efdc62013-02-11 00:47:35 +0000199 vassert(! hregIsInvalid(env->vregmap[tmp]));
sewardj2019a972011-03-07 16:04:07 +0000200
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);
florian79efdc62013-02-11 00:47:35 +0000210 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardj2019a972011-03-07 16:04:07 +0000211
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
florianb93348d2012-12-27 00:59:43 +0000429/* Return the value of CON as a sign-exteded ULong value */
430static ULong
431get_const_value_as_ulong(const IRConst *con)
432{
433 Long value;
434
435 switch (con->tag) {
436 case Ico_U1: value = con->Ico.U1; return (ULong) ((value << 63) >> 63);
437 case Ico_U8: value = con->Ico.U8; return (ULong) ((value << 56) >> 56);
438 case Ico_U16: value = con->Ico.U16; return (ULong) ((value << 48) >> 48);
439 case Ico_U32: value = con->Ico.U32; return (ULong) ((value << 32) >> 32);
440 case Ico_U64: return con->Ico.U64;
441 default:
442 vpanic("get_const_value_as_ulong");
443 }
444}
445
446
sewardj2019a972011-03-07 16:04:07 +0000447/* Call a helper (clean or dirty)
448 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000449
sewardj2019a972011-03-07 16:04:07 +0000450 (a) they are expressions yielding an integer result
451 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000452
453 guard is a Ity_Bit expression indicating whether or not the
454 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000455
456 Calling the helper function proceeds as follows:
457
458 (1) The helper arguments are evaluated and their value stored in
459 virtual registers.
460 (2) The condition code is evaluated
461 (3) The argument values are copied from the virtual registers to the
462 registers mandated by the ABI.
463 (4) Call the helper function.
464
465 This is not the most efficient way as step 3 generates register-to-register
466 moves. But it is the least fragile way as the only hidden dependency here
467 is that register-to-register moves (step 3) must not clobber the condition
468 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
469 to-register add more such dependencies. Not good. Besides, it's the job
470 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000471*/
472static void
473doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000474 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000475{
florian52af7bc2012-05-12 03:44:49 +0000476 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000477 ULong target;
478 HReg tmpregs[S390_NUM_GPRPARMS];
479 s390_cc_t cc;
480
481 n_args = 0;
482 for (i = 0; args[i]; i++)
483 ++n_args;
484
485 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
486 vpanic("doHelperCall: too many arguments");
487 }
488
florian11b8ee82012-08-06 13:35:33 +0000489 /* All arguments must have Ity_I64. For two reasons:
490 (1) We do not handle floating point arguments.
491 (2) The ABI requires that integer values are sign- or zero-extended
492 to 64 bit.
493 */
494 Int arg_errors = 0;
495 for (i = 0; i < n_args; ++i) {
496 IRType type = typeOfIRExpr(env->type_env, args[i]);
497 if (type != Ity_I64) {
498 ++arg_errors;
499 vex_printf("calling %s: argument #%d has type ", callee->name, i);
500 ppIRType(type);
501 vex_printf("; Ity_I64 is required\n");
502 }
503 }
504
505 if (arg_errors)
506 vpanic("cannot continue due to errors in argument passing");
507
florian52af7bc2012-05-12 03:44:49 +0000508 argreg = 0;
509
510 /* If we need the guest state pointer put it in a temporary arg reg */
511 if (passBBP) {
512 tmpregs[argreg] = newVRegI(env);
513 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
514 s390_hreg_guest_state_pointer()));
515 argreg++;
516 }
517
518 /* Compute the function arguments into a temporary register each */
519 for (i = 0; i < n_args; i++) {
520 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
521 argreg++;
522 }
523
sewardj2019a972011-03-07 16:04:07 +0000524 /* Compute the condition */
525 cc = S390_CC_ALWAYS;
526 if (guard) {
527 if (guard->tag == Iex_Const
528 && guard->Iex.Const.con->tag == Ico_U1
529 && guard->Iex.Const.con->Ico.U1 == True) {
530 /* unconditional -- do nothing */
531 } else {
532 cc = s390_isel_cc(env, guard);
533 }
534 }
535
florian52af7bc2012-05-12 03:44:49 +0000536 /* Move the args to the final register. It is paramount, that the
537 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000538 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000539 HReg finalreg;
540
541 finalreg = make_gpr(s390_gprno_from_arg_index(i));
542 size = sizeofIRType(Ity_I64);
543 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000544 }
545
546 target = Ptr_to_ULong(callee->addr);
547
548 /* Finally, the call itself. */
549 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000550 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000551}
552
553
florian2c74d242012-09-12 19:38:42 +0000554/*---------------------------------------------------------*/
555/*--- BFP helper functions ---*/
556/*---------------------------------------------------------*/
557
558/* Set the BFP rounding mode in the FPC. This function is called for
559 all non-conversion BFP instructions as those will always get the
560 rounding mode from the FPC. */
561static void
562set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000563{
florian2c74d242012-09-12 19:38:42 +0000564 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
565
566 /* Do we need to do anything? */
567 if (env->previous_bfp_rounding_mode &&
568 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
569 irrm->tag == Iex_RdTmp &&
570 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
571 /* No - new mode is identical to previous mode. */
572 return;
573 }
574
575 /* No luck - we better set it, and remember what we set it to. */
576 env->previous_bfp_rounding_mode = irrm;
577
578 /* The incoming rounding mode is in VEX IR encoding. Need to change
579 to s390.
580
581 rounding mode | s390 | IR
582 -------------------------
583 to nearest | 00 | 00
584 to zero | 01 | 11
585 to +infinity | 10 | 10
586 to -infinity | 11 | 01
587
588 So: s390 = (4 - IR) & 3
589 */
590 HReg ir = s390_isel_int_expr(env, irrm);
591
592 HReg mode = newVRegI(env);
593
594 addInstr(env, s390_insn_load_immediate(4, mode, 4));
595 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
596 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
597
florian125e20d2012-10-07 15:42:37 +0000598 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000599}
600
601
602/* This function is invoked for insns that support a specification of
603 a rounding mode in the insn itself. In that case there is no need to
604 stick the rounding mode into the FPC -- a good thing. However, the
605 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000606static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000607get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
608{
609 if (irrm->tag == Iex_Const) { /* rounding mode is known */
610 vassert(irrm->Iex.Const.con->tag == Ico_U32);
611 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000612
613 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000614 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
615 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
616 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
617 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000618 default:
619 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000620 }
621 }
622
florian2c74d242012-09-12 19:38:42 +0000623 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000624 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000625}
626
627
florianc8e4f562012-10-27 16:19:31 +0000628/*---------------------------------------------------------*/
629/*--- DFP helper functions ---*/
630/*---------------------------------------------------------*/
631
632/* Set the DFP rounding mode in the FPC. This function is called for
633 all non-conversion DFP instructions as those will always get the
634 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000635static void
636set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
637{
638 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
639
640 /* Do we need to do anything? */
641 if (env->previous_dfp_rounding_mode &&
642 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
643 irrm->tag == Iex_RdTmp &&
644 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
645 /* No - new mode is identical to previous mode. */
646 return;
647 }
648
649 /* No luck - we better set it, and remember what we set it to. */
650 env->previous_dfp_rounding_mode = irrm;
651
652 /* The incoming rounding mode is in VEX IR encoding. Need to change
653 to s390.
654
655 rounding mode | S390 | IR
656 -----------------------------------------------
657 to nearest, ties to even | 000 | 000
658 to zero | 001 | 011
659 to +infinity | 010 | 010
660 to -infinity | 011 | 001
661 to nearest, ties away from 0 | 100 | 100
662 to nearest, ties toward 0 | 101 | 111
663 to away from 0 | 110 | 110
664 to prepare for shorter precision | 111 | 101
665
666 So: s390 = (IR ^ ((IR << 1) & 2))
667 */
668 HReg ir = s390_isel_int_expr(env, irrm);
669
670 HReg mode = newVRegI(env);
671
672 addInstr(env, s390_insn_move(4, mode, ir));
673 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
674 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
675 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
676
677 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
678}
679
680
681/* This function is invoked for insns that support a specification of
682 a rounding mode in the insn itself. In that case there is no need to
683 stick the rounding mode into the FPC -- a good thing. However, the
684 rounding mode must be known.
florianff9000d2013-02-08 20:22:03 +0000685
686 When mapping an Irrm_DFP_ value to an S390_DFP_ROUND_ value there is
687 often a choice. For instance, Irrm_DFP_ZERO could be mapped to either
688 S390_DFP_ROUND_ZERO_5 or S390_DFP_ROUND_ZERO_9. The difference between
689 those two is that with S390_DFP_ROUND_ZERO_9 the recognition of the
690 quantum exception is suppressed whereas with S390_DFP_ROUND_ZERO_5 it
691 is not. As the quantum exception is not modelled we can choose either
692 value. The choice is to use S390_DFP_ROUND_.. values in the range [8:15],
693 because values in the range [1:7] have unpredictable rounding behaviour
694 when the floating point exception facility is not installed.
florianc8e4f562012-10-27 16:19:31 +0000695
696 Translation table of
697 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
698
699 s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
700 --------------------------------------------------------------------
florianff9000d2013-02-08 20:22:03 +0000701 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_12
florianc8e4f562012-10-27 16:19:31 +0000702 NEAREST_TIE_AWAY_0_12 | " | "
florianff9000d2013-02-08 20:22:03 +0000703 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_15
florianc8e4f562012-10-27 16:19:31 +0000704 PREPARE_SHORT_15 | " | "
florianff9000d2013-02-08 20:22:03 +0000705 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_8
florianc8e4f562012-10-27 16:19:31 +0000706 NEAREST_EVEN_8 | " | "
florianff9000d2013-02-08 20:22:03 +0000707 ZERO_5 | ZERO | ZERO_9
florianc8e4f562012-10-27 16:19:31 +0000708 ZERO_9 | " | "
florianff9000d2013-02-08 20:22:03 +0000709 POSINF_6 | PosINF | POSINF_10
florianc8e4f562012-10-27 16:19:31 +0000710 POSINF_10 | " | "
florianff9000d2013-02-08 20:22:03 +0000711 NEGINF_7 | NegINF | NEGINF_11
florianc8e4f562012-10-27 16:19:31 +0000712 NEGINF_11 | " | "
713 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
714 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
715*/
716static s390_dfp_round_t
717get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
718{
719 if (irrm->tag == Iex_Const) { /* rounding mode is known */
720 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian3d6a4222012-11-19 16:29:31 +0000721 IRRoundingModeDFP mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000722
723 switch (mode) {
724 case Irrm_DFP_NEAREST:
florianff9000d2013-02-08 20:22:03 +0000725 return S390_DFP_ROUND_NEAREST_EVEN_8;
florianc8e4f562012-10-27 16:19:31 +0000726 case Irrm_DFP_NegINF:
florianff9000d2013-02-08 20:22:03 +0000727 return S390_DFP_ROUND_NEGINF_11;
florianc8e4f562012-10-27 16:19:31 +0000728 case Irrm_DFP_PosINF:
florianff9000d2013-02-08 20:22:03 +0000729 return S390_DFP_ROUND_POSINF_10;
florianc8e4f562012-10-27 16:19:31 +0000730 case Irrm_DFP_ZERO:
florianff9000d2013-02-08 20:22:03 +0000731 return S390_DFP_ROUND_ZERO_9;
florianc8e4f562012-10-27 16:19:31 +0000732 case Irrm_DFP_NEAREST_TIE_AWAY_0:
florianff9000d2013-02-08 20:22:03 +0000733 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12;
florianc8e4f562012-10-27 16:19:31 +0000734 case Irrm_DFP_PREPARE_SHORTER:
florianff9000d2013-02-08 20:22:03 +0000735 return S390_DFP_ROUND_PREPARE_SHORT_15;
florianc8e4f562012-10-27 16:19:31 +0000736 case Irrm_DFP_AWAY_FROM_ZERO:
737 return S390_DFP_ROUND_AWAY_0;
738 case Irrm_DFP_NEAREST_TIE_TOWARD_0:
739 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
740 default:
741 vpanic("get_dfp_rounding_mode");
742 }
743 }
744
745 set_dfp_rounding_mode_in_fpc(env, irrm);
746 return S390_DFP_ROUND_PER_FPC_0;
747}
florianc8e4f562012-10-27 16:19:31 +0000748
florian2d3d87f2012-12-21 21:05:17 +0000749
750/*---------------------------------------------------------*/
751/*--- Condition code helper functions ---*/
752/*---------------------------------------------------------*/
753
sewardj2019a972011-03-07 16:04:07 +0000754/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000755 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000756
757 s390 VEX b6 b2 b0 cc.1 cc.0
758 0 0x40 EQ 1 0 0 0 0
759 1 0x01 LT 0 0 1 0 1
760 2 0x00 GT 0 0 0 1 0
761 3 0x45 Unordered 1 1 1 1 1
762
763 b0 = cc.0
764 b2 = cc.0 & cc.1
765 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
766
767 VEX = b0 | (b2 << 2) | (b6 << 6);
768*/
769static HReg
florian2d3d87f2012-12-21 21:05:17 +0000770convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000771{
772 HReg cc0, cc1, b2, b6, cc_vex;
773
774 cc0 = newVRegI(env);
775 addInstr(env, s390_insn_move(4, cc0, cc_s390));
776 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
777
778 cc1 = newVRegI(env);
779 addInstr(env, s390_insn_move(4, cc1, cc_s390));
780 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
781
782 b2 = newVRegI(env);
783 addInstr(env, s390_insn_move(4, b2, cc0));
784 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
785 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
786
787 b6 = newVRegI(env);
788 addInstr(env, s390_insn_move(4, b6, cc0));
789 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
790 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
791 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
792 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
793
794 cc_vex = newVRegI(env);
795 addInstr(env, s390_insn_move(4, cc_vex, cc0));
796 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
797 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
798
799 return cc_vex;
800}
801
florian2d3d87f2012-12-21 21:05:17 +0000802/* CC_S390 holds the condition code in s390 encoding. Convert it to
803 VEX encoding (IRCmpDResult) */
804static HReg
805convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
806{
807 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
808 return convert_s390_to_vex_bfpcc(env, cc_s390);
809}
810
sewardj2019a972011-03-07 16:04:07 +0000811
812/*---------------------------------------------------------*/
813/*--- ISEL: Integer expressions (128 bit) ---*/
814/*---------------------------------------------------------*/
815static void
816s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
817 IRExpr *expr)
818{
819 IRType ty = typeOfIRExpr(env->type_env, expr);
820
821 vassert(ty == Ity_I128);
822
823 /* No need to consider the following
824 - 128-bit constants (they do not exist in VEX)
825 - 128-bit loads from memory (will not be generated)
826 */
827
828 /* Read 128-bit IRTemp */
829 if (expr->tag == Iex_RdTmp) {
830 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
831 return;
832 }
833
834 if (expr->tag == Iex_Binop) {
835 IRExpr *arg1 = expr->Iex.Binop.arg1;
836 IRExpr *arg2 = expr->Iex.Binop.arg2;
837 Bool is_signed_multiply, is_signed_divide;
838
839 switch (expr->Iex.Binop.op) {
840 case Iop_MullU64:
841 is_signed_multiply = False;
842 goto do_multiply64;
843
844 case Iop_MullS64:
845 is_signed_multiply = True;
846 goto do_multiply64;
847
848 case Iop_DivModU128to64:
849 is_signed_divide = False;
850 goto do_divide64;
851
852 case Iop_DivModS128to64:
853 is_signed_divide = True;
854 goto do_divide64;
855
856 case Iop_64HLto128:
857 *dst_hi = s390_isel_int_expr(env, arg1);
858 *dst_lo = s390_isel_int_expr(env, arg2);
859 return;
860
861 case Iop_DivModS64to64: {
862 HReg r10, r11, h1;
863 s390_opnd_RMI op2;
864
865 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
866 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
867
868 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000869 r10 = make_gpr(10);
870 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000871
872 /* Move 1st operand into r11 and */
873 addInstr(env, s390_insn_move(8, r11, h1));
874
875 /* Divide */
876 addInstr(env, s390_insn_divs(8, r10, r11, op2));
877
878 /* The result is in registers r10 (remainder) and r11 (quotient).
879 Move the result into the reg pair that is being returned such
880 such that the low 64 bits are the quotient and the upper 64 bits
881 are the remainder. (see libvex_ir.h). */
882 *dst_hi = newVRegI(env);
883 *dst_lo = newVRegI(env);
884 addInstr(env, s390_insn_move(8, *dst_hi, r10));
885 addInstr(env, s390_insn_move(8, *dst_lo, r11));
886 return;
887 }
888
889 default:
890 break;
891
892 do_multiply64: {
893 HReg r10, r11, h1;
894 s390_opnd_RMI op2;
895
896 order_commutative_operands(arg1, arg2);
897
898 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
899 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
900
901 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000902 r10 = make_gpr(10);
903 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000904
905 /* Move the first operand to r11 */
906 addInstr(env, s390_insn_move(8, r11, h1));
907
908 /* Multiply */
909 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
910
911 /* The result is in registers r10 and r11. Assign to two virtual regs
912 and return. */
913 *dst_hi = newVRegI(env);
914 *dst_lo = newVRegI(env);
915 addInstr(env, s390_insn_move(8, *dst_hi, r10));
916 addInstr(env, s390_insn_move(8, *dst_lo, r11));
917 return;
918 }
919
920 do_divide64: {
921 HReg r10, r11, hi, lo;
922 s390_opnd_RMI op2;
923
924 s390_isel_int128_expr(&hi, &lo, env, arg1);
925 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
926
927 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000928 r10 = make_gpr(10);
929 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000930
931 /* Move high 64 bits of the 1st operand into r10 and
932 the low 64 bits into r11. */
933 addInstr(env, s390_insn_move(8, r10, hi));
934 addInstr(env, s390_insn_move(8, r11, lo));
935
936 /* Divide */
937 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
938
939 /* The result is in registers r10 (remainder) and r11 (quotient).
940 Move the result into the reg pair that is being returned such
941 such that the low 64 bits are the quotient and the upper 64 bits
942 are the remainder. (see libvex_ir.h). */
943 *dst_hi = newVRegI(env);
944 *dst_lo = newVRegI(env);
945 addInstr(env, s390_insn_move(8, *dst_hi, r10));
946 addInstr(env, s390_insn_move(8, *dst_lo, r11));
947 return;
948 }
949 }
950 }
951
952 vpanic("s390_isel_int128_expr");
953}
954
955
956/* Compute a 128-bit value into two 64-bit registers. These may be either
957 real or virtual regs; in any case they must not be changed by subsequent
958 code emitted by the caller. */
959static void
960s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
961{
962 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
963
964 /* Sanity checks ... */
965 vassert(hregIsVirtual(*dst_hi));
966 vassert(hregIsVirtual(*dst_lo));
967 vassert(hregClass(*dst_hi) == HRcInt64);
968 vassert(hregClass(*dst_lo) == HRcInt64);
969}
970
971
972/*---------------------------------------------------------*/
973/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
974/*---------------------------------------------------------*/
975
976/* Select insns for an integer-typed expression, and add them to the
977 code list. Return a reg holding the result. This reg will be a
978 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
979 want to modify it, ask for a new vreg, copy it in there, and modify
980 the copy. The register allocator will do its best to map both
981 vregs to the same real register, so the copies will often disappear
982 later in the game.
983
984 This should handle expressions of 64, 32, 16 and 8-bit type.
985 All results are returned in a 64bit register.
986 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
987 are arbitrary, so you should mask or sign extend partial values
988 if necessary.
989*/
990
991/* DO NOT CALL THIS DIRECTLY ! */
992static HReg
993s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
994{
995 IRType ty = typeOfIRExpr(env->type_env, expr);
996 UChar size;
florian6dc90242012-12-21 21:43:00 +0000997 s390_bfp_conv_t conv;
florian67a171c2013-01-20 03:08:04 +0000998 s390_dfp_conv_t dconv;
sewardj2019a972011-03-07 16:04:07 +0000999
1000 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
1001
1002 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
1003
1004 switch (expr->tag) {
1005
1006 /* --------- TEMP --------- */
1007 case Iex_RdTmp:
1008 /* Return the virtual register that holds the temporary. */
1009 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1010
1011 /* --------- LOAD --------- */
1012 case Iex_Load: {
1013 HReg dst = newVRegI(env);
1014 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1015
1016 if (expr->Iex.Load.end != Iend_BE)
1017 goto irreducible;
1018
1019 addInstr(env, s390_insn_load(size, dst, am));
1020
1021 return dst;
1022 }
1023
1024 /* --------- BINARY OP --------- */
1025 case Iex_Binop: {
1026 IRExpr *arg1 = expr->Iex.Binop.arg1;
1027 IRExpr *arg2 = expr->Iex.Binop.arg2;
1028 HReg h1, res;
1029 s390_alu_t opkind;
1030 s390_opnd_RMI op2, value, opnd;
1031 s390_insn *insn;
1032 Bool is_commutative, is_signed_multiply, is_signed_divide;
1033
1034 is_commutative = True;
1035
1036 switch (expr->Iex.Binop.op) {
1037 case Iop_MullU8:
1038 case Iop_MullU16:
1039 case Iop_MullU32:
1040 is_signed_multiply = False;
1041 goto do_multiply;
1042
1043 case Iop_MullS8:
1044 case Iop_MullS16:
1045 case Iop_MullS32:
1046 is_signed_multiply = True;
1047 goto do_multiply;
1048
1049 do_multiply: {
1050 HReg r10, r11;
1051 UInt arg_size = size / 2;
1052
1053 order_commutative_operands(arg1, arg2);
1054
1055 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1056 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1057
1058 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001059 r10 = make_gpr(10);
1060 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001061
1062 /* Move the first operand to r11 */
1063 addInstr(env, s390_insn_move(arg_size, r11, h1));
1064
1065 /* Multiply */
1066 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1067
1068 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1069 value into the destination register. */
1070 res = newVRegI(env);
1071 addInstr(env, s390_insn_move(arg_size, res, r10));
1072 value = s390_opnd_imm(arg_size * 8);
1073 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1074 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1075 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1076 opnd = s390_opnd_reg(r11);
1077 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1078 return res;
1079 }
1080
1081 case Iop_DivModS64to32:
1082 is_signed_divide = True;
1083 goto do_divide;
1084
1085 case Iop_DivModU64to32:
1086 is_signed_divide = False;
1087 goto do_divide;
1088
1089 do_divide: {
1090 HReg r10, r11;
1091
1092 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1093 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1094
1095 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001096 r10 = make_gpr(10);
1097 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001098
1099 /* Split the first operand and put the high 32 bits into r10 and
1100 the low 32 bits into r11. */
1101 addInstr(env, s390_insn_move(8, r10, h1));
1102 addInstr(env, s390_insn_move(8, r11, h1));
1103 value = s390_opnd_imm(32);
1104 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1105
1106 /* Divide */
1107 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1108
1109 /* The result is in registers r10 (remainder) and r11 (quotient).
1110 Combine them into a 64-bit value such that the low 32 bits are
1111 the quotient and the upper 32 bits are the remainder. (see
1112 libvex_ir.h). */
1113 res = newVRegI(env);
1114 addInstr(env, s390_insn_move(8, res, r10));
1115 value = s390_opnd_imm(32);
1116 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1117 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1118 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1119 opnd = s390_opnd_reg(r11);
1120 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1121 return res;
1122 }
1123
florian9fcff4c2012-09-10 03:09:04 +00001124 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1125 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1126 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1127 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1128 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1129 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1130 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1131 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1132 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1133 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1134 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1135 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
florian67a171c2013-01-20 03:08:04 +00001136
1137 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
floriana887acd2013-02-08 23:32:54 +00001138 case Iop_D64toI64S: dconv = S390_DFP_D64_TO_I64; goto do_convert_dfp;
florian67a171c2013-01-20 03:08:04 +00001139 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1140 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1141 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
floriana887acd2013-02-08 23:32:54 +00001142 case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128;
florian67a171c2013-01-20 03:08:04 +00001143 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1144 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00001145
1146 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001147 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001148
1149 res = newVRegI(env);
1150 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1151
florian2c74d242012-09-12 19:38:42 +00001152 rounding_mode = get_bfp_rounding_mode(env, arg1);
1153 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1154 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001155 return res;
1156 }
1157
1158 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001159 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001160 HReg op_hi, op_lo, f13, f15;
1161
1162 res = newVRegI(env);
1163 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1164
1165 /* We use non-virtual registers r13 and r15 as pair */
1166 f13 = make_fpr(13);
1167 f15 = make_fpr(15);
1168
1169 /* operand --> (f13, f15) */
1170 addInstr(env, s390_insn_move(8, f13, op_hi));
1171 addInstr(env, s390_insn_move(8, f15, op_lo));
1172
florian2c74d242012-09-12 19:38:42 +00001173 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001174 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001175 rounding_mode));
1176 return res;
1177 }
1178
florian5f034622013-01-13 02:29:05 +00001179 do_convert_dfp: {
1180 s390_dfp_round_t rounding_mode;
1181
1182 res = newVRegI(env);
1183 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1184
1185 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001186 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
florian5f034622013-01-13 02:29:05 +00001187 rounding_mode));
1188 return res;
1189 }
1190
1191 do_convert_dfp128: {
1192 s390_dfp_round_t rounding_mode;
1193 HReg op_hi, op_lo, f13, f15;
1194
1195 res = newVRegI(env);
1196 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1197
1198 /* We use non-virtual registers r13 and r15 as pair */
1199 f13 = make_fpr(13);
1200 f15 = make_fpr(15);
1201
1202 /* operand --> (f13, f15) */
1203 addInstr(env, s390_insn_move(8, f13, op_hi));
1204 addInstr(env, s390_insn_move(8, f15, op_lo));
1205
1206 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001207 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res, f13,
florian5f034622013-01-13 02:29:05 +00001208 f15, rounding_mode));
1209 return res;
1210 }
1211
sewardj2019a972011-03-07 16:04:07 +00001212 case Iop_8HLto16:
1213 case Iop_16HLto32:
1214 case Iop_32HLto64: {
1215 HReg h2;
1216 UInt arg_size = size / 2;
1217
1218 res = newVRegI(env);
1219 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1220 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1221
1222 addInstr(env, s390_insn_move(arg_size, res, h1));
1223 value = s390_opnd_imm(arg_size * 8);
1224 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1225 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1226 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1227 opnd = s390_opnd_reg(h2);
1228 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1229 return res;
1230 }
1231
1232 case Iop_Max32U: {
1233 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1234 res = newVRegI(env);
1235 h1 = s390_isel_int_expr(env, arg1);
1236 op2 = s390_isel_int_expr_RMI(env, arg2);
1237
1238 addInstr(env, s390_insn_move(size, res, h1));
1239 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1240 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1241 return res;
1242 }
1243
1244 case Iop_CmpF32:
1245 case Iop_CmpF64: {
1246 HReg cc_s390, h2;
1247
1248 h1 = s390_isel_float_expr(env, arg1);
1249 h2 = s390_isel_float_expr(env, arg2);
1250 cc_s390 = newVRegI(env);
1251
1252 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1253
1254 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1255
florian2d3d87f2012-12-21 21:05:17 +00001256 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001257 }
1258
1259 case Iop_CmpF128: {
1260 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1261
1262 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1263 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1264 cc_s390 = newVRegI(env);
1265
1266 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1267 f12 = make_fpr(12);
1268 f13 = make_fpr(13);
1269 f14 = make_fpr(14);
1270 f15 = make_fpr(15);
1271
1272 /* 1st operand --> (f12, f14) */
1273 addInstr(env, s390_insn_move(8, f12, op1_hi));
1274 addInstr(env, s390_insn_move(8, f14, op1_lo));
1275
1276 /* 2nd operand --> (f13, f15) */
1277 addInstr(env, s390_insn_move(8, f13, op2_hi));
1278 addInstr(env, s390_insn_move(8, f15, op2_lo));
1279
1280 res = newVRegI(env);
1281 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1282
florian2d3d87f2012-12-21 21:05:17 +00001283 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001284 }
1285
florian20c6bca2012-12-26 17:47:19 +00001286 case Iop_CmpD64:
1287 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001288 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001289 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001290
1291 h1 = s390_isel_dfp_expr(env, arg1);
1292 h2 = s390_isel_dfp_expr(env, arg2);
1293 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001294
florian20c6bca2012-12-26 17:47:19 +00001295 switch(expr->Iex.Binop.op) {
1296 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1297 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1298 default: goto irreducible;
1299 }
1300 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001301
florian2d3d87f2012-12-21 21:05:17 +00001302 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001303 }
1304
florian20c6bca2012-12-26 17:47:19 +00001305 case Iop_CmpD128:
1306 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001307 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001308 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001309
1310 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1311 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1312 cc_s390 = newVRegI(env);
1313
1314 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1315 f12 = make_fpr(12);
1316 f13 = make_fpr(13);
1317 f14 = make_fpr(14);
1318 f15 = make_fpr(15);
1319
1320 /* 1st operand --> (f12, f14) */
1321 addInstr(env, s390_insn_move(8, f12, op1_hi));
1322 addInstr(env, s390_insn_move(8, f14, op1_lo));
1323
1324 /* 2nd operand --> (f13, f15) */
1325 addInstr(env, s390_insn_move(8, f13, op2_hi));
1326 addInstr(env, s390_insn_move(8, f15, op2_lo));
1327
florian20c6bca2012-12-26 17:47:19 +00001328 switch(expr->Iex.Binop.op) {
1329 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1330 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1331 default: goto irreducible;
1332 }
1333 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1334 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001335
florian2d3d87f2012-12-21 21:05:17 +00001336 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001337 }
1338
sewardj2019a972011-03-07 16:04:07 +00001339 case Iop_Add8:
1340 case Iop_Add16:
1341 case Iop_Add32:
1342 case Iop_Add64:
1343 opkind = S390_ALU_ADD;
1344 break;
1345
1346 case Iop_Sub8:
1347 case Iop_Sub16:
1348 case Iop_Sub32:
1349 case Iop_Sub64:
1350 opkind = S390_ALU_SUB;
1351 is_commutative = False;
1352 break;
1353
1354 case Iop_And8:
1355 case Iop_And16:
1356 case Iop_And32:
1357 case Iop_And64:
1358 opkind = S390_ALU_AND;
1359 break;
1360
1361 case Iop_Or8:
1362 case Iop_Or16:
1363 case Iop_Or32:
1364 case Iop_Or64:
1365 opkind = S390_ALU_OR;
1366 break;
1367
1368 case Iop_Xor8:
1369 case Iop_Xor16:
1370 case Iop_Xor32:
1371 case Iop_Xor64:
1372 opkind = S390_ALU_XOR;
1373 break;
1374
1375 case Iop_Shl8:
1376 case Iop_Shl16:
1377 case Iop_Shl32:
1378 case Iop_Shl64:
1379 opkind = S390_ALU_LSH;
1380 is_commutative = False;
1381 break;
1382
1383 case Iop_Shr8:
1384 case Iop_Shr16:
1385 case Iop_Shr32:
1386 case Iop_Shr64:
1387 opkind = S390_ALU_RSH;
1388 is_commutative = False;
1389 break;
1390
1391 case Iop_Sar8:
1392 case Iop_Sar16:
1393 case Iop_Sar32:
1394 case Iop_Sar64:
1395 opkind = S390_ALU_RSHA;
1396 is_commutative = False;
1397 break;
1398
1399 default:
1400 goto irreducible;
1401 }
1402
1403 /* Pattern match: 0 - arg1 --> -arg1 */
1404 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1405 res = newVRegI(env);
1406 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1407 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1408 addInstr(env, insn);
1409
1410 return res;
1411 }
1412
1413 if (is_commutative) {
1414 order_commutative_operands(arg1, arg2);
1415 }
1416
1417 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1418 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1419 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001420
1421 /* As right shifts of one/two byte opreands are implemented using a
1422 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1423 switch (expr->Iex.Binop.op) {
1424 case Iop_Shr8:
1425 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1426 break;
1427 case Iop_Shr16:
1428 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1429 break;
1430 case Iop_Sar8:
1431 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1432 break;
1433 case Iop_Sar16:
1434 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1435 break;
1436 default:
1437 insn = s390_insn_move(size, res, h1);
1438 break;
1439 }
1440 addInstr(env, insn);
1441
sewardj2019a972011-03-07 16:04:07 +00001442 insn = s390_insn_alu(size, opkind, res, op2);
1443
1444 addInstr(env, insn);
1445
1446 return res;
1447 }
1448
1449 /* --------- UNARY OP --------- */
1450 case Iex_Unop: {
1451 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1452 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1453 s390_opnd_RMI opnd;
1454 s390_insn *insn;
1455 IRExpr *arg;
1456 HReg dst, h1;
1457 IROp unop, binop;
1458
1459 arg = expr->Iex.Unop.arg;
1460
1461 /* Special cases are handled here */
1462
1463 /* 32-bit multiply with 32-bit result or
1464 64-bit multiply with 64-bit result */
1465 unop = expr->Iex.Unop.op;
1466 binop = arg->Iex.Binop.op;
1467
1468 if ((arg->tag == Iex_Binop &&
1469 ((unop == Iop_64to32 &&
1470 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1471 (unop == Iop_128to64 &&
1472 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1473 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1474 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1475 dst = newVRegI(env); /* Result goes into a new register */
1476 addInstr(env, s390_insn_move(size, dst, h1));
1477 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1478
1479 return dst;
1480 }
1481
florian4d71a082011-12-18 00:08:17 +00001482 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001483 dst = newVRegI(env);
1484 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1485 addInstr(env, s390_insn_move(size, dst, h1));
1486
1487 return dst;
1488 }
1489
floriane38f6412012-12-21 17:32:12 +00001490 if (unop == Iop_ReinterpD64asI64) {
1491 dst = newVRegI(env);
1492 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1493 addInstr(env, s390_insn_move(size, dst, h1));
1494
1495 return dst;
1496 }
1497
floriance9e3db2012-12-27 20:14:03 +00001498 if (unop == Iop_ExtractSigD64) {
1499 dst = newVRegI(env);
1500 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1501 addInstr(env,
1502 s390_insn_dfp_unop(size, S390_DFP_EXTRACT_SIG_D64, dst, h1));
1503 return dst;
1504 }
1505
1506 if (unop == Iop_ExtractSigD128) {
1507 HReg op_hi, op_lo, f13, f15;
1508 dst = newVRegI(env);
1509 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1510
1511 /* We use non-virtual registers r13 and r15 as pair */
1512 f13 = make_fpr(13);
1513 f15 = make_fpr(15);
1514
1515 /* operand --> (f13, f15) */
1516 addInstr(env, s390_insn_move(8, f13, op_hi));
1517 addInstr(env, s390_insn_move(8, f15, op_lo));
1518
1519 addInstr(env, s390_insn_dfp128_unop(size, S390_DFP_EXTRACT_SIG_D128,
1520 dst, f13, f15));
1521 return dst;
1522 }
1523
sewardj2019a972011-03-07 16:04:07 +00001524 /* Expressions whose argument is 1-bit wide */
1525 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1526 s390_cc_t cond = s390_isel_cc(env, arg);
1527 dst = newVRegI(env); /* Result goes into a new register */
1528 addInstr(env, s390_insn_cc2bool(dst, cond));
1529
1530 switch (unop) {
1531 case Iop_1Uto8:
1532 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001533 /* Zero extend */
1534 mask.variant.imm = 1;
1535 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1536 break;
1537
sewardj2019a972011-03-07 16:04:07 +00001538 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001539 /* Zero extend */
1540 mask.variant.imm = 1;
1541 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001542 break;
1543
1544 case Iop_1Sto8:
1545 case Iop_1Sto16:
1546 case Iop_1Sto32:
1547 shift.variant.imm = 31;
1548 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1549 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1550 break;
1551
1552 case Iop_1Sto64:
1553 shift.variant.imm = 63;
1554 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1555 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1556 break;
1557
1558 default:
1559 goto irreducible;
1560 }
1561
1562 return dst;
1563 }
1564
1565 /* Regular processing */
1566
1567 if (unop == Iop_128to64) {
1568 HReg dst_hi, dst_lo;
1569
1570 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1571 return dst_lo;
1572 }
1573
1574 if (unop == Iop_128HIto64) {
1575 HReg dst_hi, dst_lo;
1576
1577 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1578 return dst_hi;
1579 }
1580
1581 dst = newVRegI(env); /* Result goes into a new register */
1582 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1583
1584 switch (unop) {
1585 case Iop_8Uto16:
1586 case Iop_8Uto32:
1587 case Iop_8Uto64:
1588 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1589 break;
1590
1591 case Iop_16Uto32:
1592 case Iop_16Uto64:
1593 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1594 break;
1595
1596 case Iop_32Uto64:
1597 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1598 break;
1599
1600 case Iop_8Sto16:
1601 case Iop_8Sto32:
1602 case Iop_8Sto64:
1603 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1604 break;
1605
1606 case Iop_16Sto32:
1607 case Iop_16Sto64:
1608 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1609 break;
1610
1611 case Iop_32Sto64:
1612 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1613 break;
1614
1615 case Iop_64to8:
1616 case Iop_64to16:
1617 case Iop_64to32:
1618 case Iop_32to8:
1619 case Iop_32to16:
1620 case Iop_16to8:
1621 /* Down-casts are no-ops. Upstream operations will only look at
1622 the bytes that make up the result of the down-cast. So there
1623 is no point setting the other bytes to 0. */
1624 insn = s390_opnd_copy(8, dst, opnd);
1625 break;
1626
1627 case Iop_64HIto32:
1628 addInstr(env, s390_opnd_copy(8, dst, opnd));
1629 shift.variant.imm = 32;
1630 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1631 break;
1632
1633 case Iop_32HIto16:
1634 addInstr(env, s390_opnd_copy(4, dst, opnd));
1635 shift.variant.imm = 16;
1636 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1637 break;
1638
1639 case Iop_16HIto8:
1640 addInstr(env, s390_opnd_copy(2, dst, opnd));
1641 shift.variant.imm = 8;
1642 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1643 break;
1644
1645 case Iop_Not8:
1646 case Iop_Not16:
1647 case Iop_Not32:
1648 case Iop_Not64:
1649 /* XOR with ffff... */
1650 mask.variant.imm = ~(ULong)0;
1651 addInstr(env, s390_opnd_copy(size, dst, opnd));
1652 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1653 break;
1654
1655 case Iop_Left8:
1656 case Iop_Left16:
1657 case Iop_Left32:
1658 case Iop_Left64:
1659 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1660 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1661 break;
1662
1663 case Iop_CmpwNEZ32:
1664 case Iop_CmpwNEZ64: {
1665 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1666 or -X will have a 1 in the MSB. */
1667 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1668 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1669 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1670 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1671 return dst;
1672 }
1673
1674 case Iop_Clz64: {
1675 HReg r10, r11;
1676
sewardj611b06e2011-03-24 08:57:29 +00001677 /* This will be implemented using FLOGR, if possible. So we need to
1678 set aside a pair of non-virtual registers. The result (number of
1679 left-most zero bits) will be in r10. The value in r11 is unspecified
1680 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001681 r10 = make_gpr(10);
1682 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001683
sewardj611b06e2011-03-24 08:57:29 +00001684 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001685 addInstr(env, s390_insn_move(8, dst, r10));
1686 return dst;
1687 }
1688
1689 default:
1690 goto irreducible;
1691 }
1692
1693 addInstr(env, insn);
1694
1695 return dst;
1696 }
1697
1698 /* --------- GET --------- */
1699 case Iex_Get: {
1700 HReg dst = newVRegI(env);
1701 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1702
1703 /* We never load more than 8 bytes from the guest state, because the
1704 floating point register pair is not contiguous. */
1705 vassert(size <= 8);
1706
1707 addInstr(env, s390_insn_load(size, dst, am));
1708
1709 return dst;
1710 }
1711
1712 case Iex_GetI:
1713 /* not needed */
1714 break;
1715
1716 /* --------- CCALL --------- */
1717 case Iex_CCall: {
1718 HReg dst = newVRegI(env);
1719
1720 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001721 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001722 return dst;
1723 }
1724
1725 /* --------- LITERAL --------- */
1726
1727 /* Load a literal into a register. Create a "load immediate"
1728 v-insn and return the register. */
1729 case Iex_Const: {
1730 ULong value;
1731 HReg dst = newVRegI(env);
1732 const IRConst *con = expr->Iex.Const.con;
1733
1734 /* Bitwise copy of the value. No sign/zero-extension */
1735 switch (con->tag) {
1736 case Ico_U64: value = con->Ico.U64; break;
1737 case Ico_U32: value = con->Ico.U32; break;
1738 case Ico_U16: value = con->Ico.U16; break;
1739 case Ico_U8: value = con->Ico.U8; break;
1740 default: vpanic("s390_isel_int_expr: invalid constant");
1741 }
1742
1743 addInstr(env, s390_insn_load_immediate(size, dst, value));
1744
1745 return dst;
1746 }
1747
1748 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00001749 case Iex_ITE: {
sewardj2019a972011-03-07 16:04:07 +00001750 IRExpr *cond_expr;
florian99dd03e2013-01-29 03:56:06 +00001751 HReg dst, r1;
sewardj009230b2013-01-26 11:47:55 +00001752 s390_opnd_RMI r0;
sewardj2019a972011-03-07 16:04:07 +00001753
florian99dd03e2013-01-29 03:56:06 +00001754 cond_expr = expr->Iex.ITE.cond;
sewardj2019a972011-03-07 16:04:07 +00001755
sewardj009230b2013-01-26 11:47:55 +00001756 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
1757
sewardj2019a972011-03-07 16:04:07 +00001758 dst = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00001759 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
1760 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
1761 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
sewardj2019a972011-03-07 16:04:07 +00001762
sewardj009230b2013-01-26 11:47:55 +00001763 s390_cc_t cc = s390_isel_cc(env, cond_expr);
sewardj2019a972011-03-07 16:04:07 +00001764
florian99dd03e2013-01-29 03:56:06 +00001765 addInstr(env, s390_insn_move(size, dst, r1));
sewardj009230b2013-01-26 11:47:55 +00001766 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
sewardj2019a972011-03-07 16:04:07 +00001767 return dst;
1768 }
1769
1770 default:
1771 break;
1772 }
1773
1774 /* We get here if no pattern matched. */
1775 irreducible:
1776 ppIRExpr(expr);
1777 vpanic("s390_isel_int_expr: cannot reduce tree");
1778}
1779
1780
1781static HReg
1782s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1783{
1784 HReg dst = s390_isel_int_expr_wrk(env, expr);
1785
1786 /* Sanity checks ... */
1787 vassert(hregClass(dst) == HRcInt64);
1788 vassert(hregIsVirtual(dst));
1789
1790 return dst;
1791}
1792
1793
1794static s390_opnd_RMI
1795s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1796{
1797 IRType ty = typeOfIRExpr(env->type_env, expr);
1798 s390_opnd_RMI dst;
1799
1800 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1801 ty == Ity_I64);
1802
1803 if (expr->tag == Iex_Load) {
1804 dst.tag = S390_OPND_AMODE;
1805 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1806 } else if (expr->tag == Iex_Get) {
1807 dst.tag = S390_OPND_AMODE;
1808 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1809 } else if (expr->tag == Iex_Const) {
1810 ULong value;
1811
1812 /* The bit pattern for the value will be stored as is in the least
1813 significant bits of VALUE. */
1814 switch (expr->Iex.Const.con->tag) {
1815 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1816 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1817 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1818 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1819 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1820 default:
1821 vpanic("s390_isel_int_expr_RMI");
1822 }
1823
1824 dst.tag = S390_OPND_IMMEDIATE;
1825 dst.variant.imm = value;
1826 } else {
1827 dst.tag = S390_OPND_REG;
1828 dst.variant.reg = s390_isel_int_expr(env, expr);
1829 }
1830
1831 return dst;
1832}
1833
1834
1835/*---------------------------------------------------------*/
1836/*--- ISEL: Floating point expressions (128 bit) ---*/
1837/*---------------------------------------------------------*/
1838static void
1839s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1840 IRExpr *expr)
1841{
1842 IRType ty = typeOfIRExpr(env->type_env, expr);
1843
1844 vassert(ty == Ity_F128);
1845
sewardj2019a972011-03-07 16:04:07 +00001846 switch (expr->tag) {
1847 case Iex_RdTmp:
1848 /* Return the virtual registers that hold the temporary. */
1849 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1850 return;
1851
1852 /* --------- LOAD --------- */
1853 case Iex_Load: {
1854 IRExpr *addr_hi, *addr_lo;
1855 s390_amode *am_hi, *am_lo;
1856
1857 if (expr->Iex.Load.end != Iend_BE)
1858 goto irreducible;
1859
1860 addr_hi = expr->Iex.Load.addr;
1861 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1862
1863 am_hi = s390_isel_amode(env, addr_hi);
1864 am_lo = s390_isel_amode(env, addr_lo);
1865
1866 *dst_hi = newVRegF(env);
1867 *dst_lo = newVRegF(env);
1868 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1869 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1870 return;
1871 }
1872
1873
1874 /* --------- GET --------- */
1875 case Iex_Get:
1876 /* This is not supported because loading 128-bit from the guest
1877 state is almost certainly wrong. Use get_fpr_pair instead. */
1878 vpanic("Iex_Get with F128 data");
1879
1880 /* --------- 4-ary OP --------- */
1881 case Iex_Qop:
1882 vpanic("Iex_Qop with F128 data");
1883
1884 /* --------- TERNARY OP --------- */
1885 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001886 IRTriop *triop = expr->Iex.Triop.details;
1887 IROp op = triop->op;
1888 IRExpr *left = triop->arg2;
1889 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001890 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001891 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1892
1893 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1894 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1895
1896 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1897 f12 = make_fpr(12);
1898 f13 = make_fpr(13);
1899 f14 = make_fpr(14);
1900 f15 = make_fpr(15);
1901
1902 /* 1st operand --> (f12, f14) */
1903 addInstr(env, s390_insn_move(8, f12, op1_hi));
1904 addInstr(env, s390_insn_move(8, f14, op1_lo));
1905
1906 /* 2nd operand --> (f13, f15) */
1907 addInstr(env, s390_insn_move(8, f13, op2_hi));
1908 addInstr(env, s390_insn_move(8, f15, op2_lo));
1909
1910 switch (op) {
1911 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1912 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1913 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1914 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1915 default:
1916 goto irreducible;
1917 }
1918
florian2c74d242012-09-12 19:38:42 +00001919 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1920 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001921
1922 /* Move result to virtual destination register */
1923 *dst_hi = newVRegF(env);
1924 *dst_lo = newVRegF(env);
1925 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1926 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1927
1928 return;
1929 }
1930
1931 /* --------- BINARY OP --------- */
1932 case Iex_Binop: {
1933 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001934
1935 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1936 f12 = make_fpr(12);
1937 f13 = make_fpr(13);
1938 f14 = make_fpr(14);
1939 f15 = make_fpr(15);
1940
1941 switch (expr->Iex.Binop.op) {
1942 case Iop_SqrtF128:
1943 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1944
1945 /* operand --> (f13, f15) */
1946 addInstr(env, s390_insn_move(8, f13, op_hi));
1947 addInstr(env, s390_insn_move(8, f15, op_lo));
1948
florian2c74d242012-09-12 19:38:42 +00001949 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1950 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1951 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001952
1953 /* Move result to virtual destination registers */
1954 *dst_hi = newVRegF(env);
1955 *dst_lo = newVRegF(env);
1956 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1957 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1958 return;
1959
1960 case Iop_F64HLtoF128:
1961 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1962 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1963 return;
1964
1965 default:
1966 goto irreducible;
1967 }
1968 }
1969
1970 /* --------- UNARY OP --------- */
1971 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001972 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001973 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00001974 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001975 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1976
1977 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1978 f12 = make_fpr(12);
1979 f13 = make_fpr(13);
1980 f14 = make_fpr(14);
1981 f15 = make_fpr(15);
1982
florian66e596d2012-09-07 15:00:53 +00001983 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001984 case Iop_NegF128:
1985 if (left->tag == Iex_Unop &&
1986 (left->Iex.Unop.op == Iop_AbsF32 ||
1987 left->Iex.Unop.op == Iop_AbsF64))
1988 bfpop = S390_BFP_NABS;
1989 else
1990 bfpop = S390_BFP_NEG;
1991 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00001992 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1993 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1994 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1995 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1996 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1997 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1998 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001999 default:
2000 goto irreducible;
2001 }
2002
2003 float128_opnd:
2004 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2005
2006 /* operand --> (f13, f15) */
2007 addInstr(env, s390_insn_move(8, f13, op_hi));
2008 addInstr(env, s390_insn_move(8, f15, op_lo));
2009
florian2c74d242012-09-12 19:38:42 +00002010 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002011 goto move_dst;
2012
2013 convert_float:
2014 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002015 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002016 goto move_dst;
2017
2018 convert_int:
2019 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002020 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002021 goto move_dst;
2022
2023 move_dst:
2024 /* Move result to virtual destination registers */
2025 *dst_hi = newVRegF(env);
2026 *dst_lo = newVRegF(env);
2027 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2028 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2029 return;
2030 }
2031
2032 default:
2033 goto irreducible;
2034 }
2035
2036 /* We get here if no pattern matched. */
2037 irreducible:
2038 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002039 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002040}
2041
2042/* Compute a 128-bit value into two 64-bit registers. These may be either
2043 real or virtual regs; in any case they must not be changed by subsequent
2044 code emitted by the caller. */
2045static void
2046s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2047{
2048 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2049
2050 /* Sanity checks ... */
2051 vassert(hregIsVirtual(*dst_hi));
2052 vassert(hregIsVirtual(*dst_lo));
2053 vassert(hregClass(*dst_hi) == HRcFlt64);
2054 vassert(hregClass(*dst_lo) == HRcFlt64);
2055}
2056
2057
2058/*---------------------------------------------------------*/
2059/*--- ISEL: Floating point expressions (64 bit) ---*/
2060/*---------------------------------------------------------*/
2061
2062static HReg
2063s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2064{
2065 IRType ty = typeOfIRExpr(env->type_env, expr);
2066 UChar size;
2067
2068 vassert(ty == Ity_F32 || ty == Ity_F64);
2069
2070 size = sizeofIRType(ty);
2071
2072 switch (expr->tag) {
2073 case Iex_RdTmp:
2074 /* Return the virtual register that holds the temporary. */
2075 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2076
2077 /* --------- LOAD --------- */
2078 case Iex_Load: {
2079 HReg dst = newVRegF(env);
2080 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2081
2082 if (expr->Iex.Load.end != Iend_BE)
2083 goto irreducible;
2084
2085 addInstr(env, s390_insn_load(size, dst, am));
2086
2087 return dst;
2088 }
2089
2090 /* --------- GET --------- */
2091 case Iex_Get: {
2092 HReg dst = newVRegF(env);
2093 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2094
2095 addInstr(env, s390_insn_load(size, dst, am));
2096
2097 return dst;
2098 }
2099
2100 /* --------- LITERAL --------- */
2101
2102 /* Load a literal into a register. Create a "load immediate"
2103 v-insn and return the register. */
2104 case Iex_Const: {
2105 ULong value;
2106 HReg dst = newVRegF(env);
2107 const IRConst *con = expr->Iex.Const.con;
2108
2109 /* Bitwise copy of the value. No sign/zero-extension */
2110 switch (con->tag) {
2111 case Ico_F32i: value = con->Ico.F32i; break;
2112 case Ico_F64i: value = con->Ico.F64i; break;
2113 default: vpanic("s390_isel_float_expr: invalid constant");
2114 }
2115
2116 if (value != 0) vpanic("cannot load immediate floating point constant");
2117
2118 addInstr(env, s390_insn_load_immediate(size, dst, value));
2119
2120 return dst;
2121 }
2122
2123 /* --------- 4-ary OP --------- */
2124 case Iex_Qop: {
2125 HReg op1, op2, op3, dst;
2126 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002127
florian5906a6b2012-10-16 02:53:33 +00002128 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002129 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002130 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002131 dst = newVRegF(env);
2132 addInstr(env, s390_insn_move(size, dst, op1));
2133
florian96d7cc32012-06-01 20:41:24 +00002134 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002135 case Iop_MAddF32:
2136 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2137 case Iop_MSubF32:
2138 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2139
2140 default:
2141 goto irreducible;
2142 }
2143
florian2c74d242012-09-12 19:38:42 +00002144 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2145 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002146 return dst;
2147 }
2148
2149 /* --------- TERNARY OP --------- */
2150 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002151 IRTriop *triop = expr->Iex.Triop.details;
2152 IROp op = triop->op;
2153 IRExpr *left = triop->arg2;
2154 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002155 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002156 HReg h1, op2, dst;
2157
2158 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2159 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2160 dst = newVRegF(env);
2161 addInstr(env, s390_insn_move(size, dst, h1));
2162 switch (op) {
2163 case Iop_AddF32:
2164 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2165 case Iop_SubF32:
2166 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2167 case Iop_MulF32:
2168 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2169 case Iop_DivF32:
2170 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2171
2172 default:
2173 goto irreducible;
2174 }
2175
florian2c74d242012-09-12 19:38:42 +00002176 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2177 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002178 return dst;
2179 }
2180
2181 /* --------- BINARY OP --------- */
2182 case Iex_Binop: {
2183 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002184 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002185 IRExpr *left = expr->Iex.Binop.arg2;
2186 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002187 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002188
2189 switch (op) {
2190 case Iop_SqrtF32:
2191 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002192 h1 = s390_isel_float_expr(env, left);
2193 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002194 set_bfp_rounding_mode_in_fpc(env, irrm);
2195 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002196 return dst;
sewardj2019a972011-03-07 16:04:07 +00002197
florian9fcff4c2012-09-10 03:09:04 +00002198 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2199 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2200 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2201 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2202 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2203 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2204 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002205
florian9fcff4c2012-09-10 03:09:04 +00002206 convert_float:
2207 h1 = s390_isel_float_expr(env, left);
2208 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002209
florian9fcff4c2012-09-10 03:09:04 +00002210 convert_int:
2211 h1 = s390_isel_int_expr(env, left);
2212 goto convert;
2213
florian2c74d242012-09-12 19:38:42 +00002214 convert: {
florian125e20d2012-10-07 15:42:37 +00002215 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002216 /* convert-from-fixed and load-rounded have a rounding mode field
2217 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002218 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002219 if (s390_host_has_fpext) {
2220 rounding_mode = get_bfp_rounding_mode(env, irrm);
2221 } else {
2222 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002223 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002224 }
florian9fcff4c2012-09-10 03:09:04 +00002225 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2226 rounding_mode));
2227 return dst;
florian2c74d242012-09-12 19:38:42 +00002228 }
florian9fcff4c2012-09-10 03:09:04 +00002229
sewardj2019a972011-03-07 16:04:07 +00002230 default:
2231 goto irreducible;
2232
2233 case Iop_F128toF64:
2234 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002235 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002236 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002237
florian9fcff4c2012-09-10 03:09:04 +00002238 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2239 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002240
florian9fcff4c2012-09-10 03:09:04 +00002241 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002242
florian9fcff4c2012-09-10 03:09:04 +00002243 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002244 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002245 f15 = make_fpr(15);
2246
2247 /* operand --> (f13, f15) */
2248 addInstr(env, s390_insn_move(8, f13, op_hi));
2249 addInstr(env, s390_insn_move(8, f15, op_lo));
2250
2251 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002252 /* load-rounded has a rounding mode field when the floating point
2253 extension facility is installed. */
2254 if (s390_host_has_fpext) {
2255 rounding_mode = get_bfp_rounding_mode(env, irrm);
2256 } else {
2257 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002258 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002259 }
floriancc491a62012-09-10 23:44:37 +00002260 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002261 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002262 return dst;
2263 }
2264 }
sewardj2019a972011-03-07 16:04:07 +00002265 }
2266
2267 /* --------- UNARY OP --------- */
2268 case Iex_Unop: {
2269 IROp op = expr->Iex.Unop.op;
2270 IRExpr *left = expr->Iex.Unop.arg;
2271 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002272 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002273 HReg h1, dst;
2274
2275 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2276 HReg dst_hi, dst_lo;
2277
2278 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2279 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2280 }
2281
florian4d71a082011-12-18 00:08:17 +00002282 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002283 dst = newVRegF(env);
2284 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2285 addInstr(env, s390_insn_move(size, dst, h1));
2286
2287 return dst;
2288 }
2289
2290 switch (op) {
2291 case Iop_NegF32:
2292 case Iop_NegF64:
2293 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002294 (left->Iex.Unop.op == Iop_AbsF32 ||
2295 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002296 bfpop = S390_BFP_NABS;
2297 else
2298 bfpop = S390_BFP_NEG;
2299 break;
2300
2301 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002302 case Iop_AbsF64:
2303 bfpop = S390_BFP_ABS;
2304 break;
2305
2306 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2307 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2308 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2309
2310 convert_float1:
2311 h1 = s390_isel_float_expr(env, left);
2312 goto convert1;
2313
2314 convert_int1:
2315 h1 = s390_isel_int_expr(env, left);
2316 goto convert1;
2317
2318 convert1:
2319 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002320 /* No rounding mode is needed for these conversions. Just stick
2321 one in. It won't be used later on. */
2322 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002323 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002324 return dst;
2325
sewardj2019a972011-03-07 16:04:07 +00002326 default:
2327 goto irreducible;
2328 }
2329
2330 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002331 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002332 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002333 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002334 return dst;
2335 }
2336
2337 default:
2338 goto irreducible;
2339 }
2340
2341 /* We get here if no pattern matched. */
2342 irreducible:
2343 ppIRExpr(expr);
2344 vpanic("s390_isel_float_expr: cannot reduce tree");
2345}
2346
2347
2348static HReg
2349s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2350{
2351 HReg dst = s390_isel_float_expr_wrk(env, expr);
2352
2353 /* Sanity checks ... */
2354 vassert(hregClass(dst) == HRcFlt64);
2355 vassert(hregIsVirtual(dst));
2356
2357 return dst;
2358}
2359
2360
2361/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002362/*--- ISEL: Decimal point expressions (128 bit) ---*/
2363/*---------------------------------------------------------*/
2364static void
2365s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2366 IRExpr *expr)
2367{
2368 IRType ty = typeOfIRExpr(env->type_env, expr);
2369
2370 vassert(ty == Ity_D128);
2371
2372 switch (expr->tag) {
2373 case Iex_RdTmp:
2374 /* Return the virtual registers that hold the temporary. */
2375 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2376 return;
2377
2378 /* --------- LOAD --------- */
2379 case Iex_Load: {
2380 IRExpr *addr_hi, *addr_lo;
2381 s390_amode *am_hi, *am_lo;
2382
2383 if (expr->Iex.Load.end != Iend_BE)
2384 goto irreducible;
2385
2386 addr_hi = expr->Iex.Load.addr;
2387 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2388
2389 am_hi = s390_isel_amode(env, addr_hi);
2390 am_lo = s390_isel_amode(env, addr_lo);
2391
2392 *dst_hi = newVRegF(env);
2393 *dst_lo = newVRegF(env);
2394 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2395 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2396 return;
2397 }
2398
2399 /* --------- GET --------- */
2400 case Iex_Get:
2401 /* This is not supported because loading 128-bit from the guest
2402 state is almost certainly wrong. Use get_dpr_pair instead. */
2403 vpanic("Iex_Get with D128 data");
2404
2405 /* --------- 4-ary OP --------- */
2406 case Iex_Qop:
2407 vpanic("Iex_Qop with D128 data");
2408
2409 /* --------- TERNARY OP --------- */
2410 case Iex_Triop: {
2411 IRTriop *triop = expr->Iex.Triop.details;
2412 IROp op = triop->op;
2413 IRExpr *irrm = triop->arg1;
2414 IRExpr *left = triop->arg2;
2415 IRExpr *right = triop->arg3;
2416 s390_dfp_round_t rounding_mode;
2417 s390_dfp_binop_t dfpop;
2418 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2419
2420 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2421 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2422
2423 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2424 (f12, f14) as op2 and (f13, f15) as destination) */
2425 f9 = make_fpr(9);
2426 f11 = make_fpr(11);
2427 f12 = make_fpr(12);
2428 f13 = make_fpr(13);
2429 f14 = make_fpr(14);
2430 f15 = make_fpr(15);
2431
2432 /* 1st operand --> (f9, f11) */
2433 addInstr(env, s390_insn_move(8, f9, op1_hi));
2434 addInstr(env, s390_insn_move(8, f11, op1_lo));
2435
2436 /* 2nd operand --> (f12, f14) */
2437 addInstr(env, s390_insn_move(8, f12, op2_hi));
2438 addInstr(env, s390_insn_move(8, f14, op2_lo));
2439
2440 switch (op) {
2441 case Iop_AddD128: dfpop = S390_DFP_ADD; break;
2442 case Iop_SubD128: dfpop = S390_DFP_SUB; break;
2443 case Iop_MulD128: dfpop = S390_DFP_MUL; break;
2444 case Iop_DivD128: dfpop = S390_DFP_DIV; break;
2445 default:
2446 goto irreducible;
2447 }
2448
2449 /* DFP binary ops have insns with rounding mode field
2450 when the floating point extension facility is installed. */
2451 if (s390_host_has_fpext) {
2452 rounding_mode = get_dfp_rounding_mode(env, irrm);
2453 } else {
2454 set_dfp_rounding_mode_in_fpc(env, irrm);
2455 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2456 }
2457
2458 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2459 f12, f14, rounding_mode));
2460
2461 /* Move result to virtual destination register */
2462 *dst_hi = newVRegF(env);
2463 *dst_lo = newVRegF(env);
2464 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2465 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2466
2467 return;
2468 }
2469
2470 /* --------- BINARY OP --------- */
2471 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002472
floriane38f6412012-12-21 17:32:12 +00002473 switch (expr->Iex.Binop.op) {
2474 case Iop_D64HLtoD128:
2475 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2476 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2477 return;
2478
florian1b901d42013-01-01 22:19:24 +00002479 case Iop_ShlD128:
2480 case Iop_ShrD128: {
2481 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2482 s390_dfp_intop_t intop;
2483 IRExpr *left = expr->Iex.Binop.arg1;
2484 IRExpr *right = expr->Iex.Binop.arg2;
2485
2486 switch (expr->Iex.Binop.op) {
2487 case Iop_ShlD128: intop = S390_DFP_SHIFT_LEFT; break;
2488 case Iop_ShrD128: intop = S390_DFP_SHIFT_RIGHT; break;
2489 default: goto irreducible;
2490 }
2491
2492 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2493 f9 = make_fpr(9); /* 128 bit dfp operand */
2494 f11 = make_fpr(11);
2495
2496 f13 = make_fpr(13); /* 128 bit dfp destination */
2497 f15 = make_fpr(15);
2498
2499 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left); /* dfp operand */
2500 addInstr(env, s390_insn_move(8, f9, op1_hi));
2501 addInstr(env, s390_insn_move(8, f11, op1_lo));
2502
2503 op2 = s390_isel_int_expr(env, right); /* int operand */
2504
2505 addInstr(env,
2506 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2507
2508 /* Move result to virtual destination register */
2509 *dst_hi = newVRegF(env);
2510 *dst_lo = newVRegF(env);
2511 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2512 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2513 return;
2514 }
2515
floriane38f6412012-12-21 17:32:12 +00002516 default:
2517 goto irreducible;
2518 }
2519 }
2520
2521 /* --------- UNARY OP --------- */
2522 case Iex_Unop: {
2523 IRExpr *left = expr->Iex.Unop.arg;
2524 s390_dfp_conv_t conv;
floriane38f6412012-12-21 17:32:12 +00002525 HReg op, f12, f14;
2526
floriana887acd2013-02-08 23:32:54 +00002527 /* We use non-virtual registers as pairs (f12, f14)) */
floriane38f6412012-12-21 17:32:12 +00002528 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00002529 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00002530
2531 switch (expr->Iex.Unop.op) {
2532 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002533 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
floriana887acd2013-02-08 23:32:54 +00002534 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002535 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2536 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002537 default:
2538 goto irreducible;
2539 }
2540
2541 convert_dfp:
2542 op = s390_isel_dfp_expr(env, left);
2543 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2544 goto move_dst;
2545
florian5f034622013-01-13 02:29:05 +00002546 convert_int:
2547 op = s390_isel_int_expr(env, left);
2548 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2549 goto move_dst;
2550
floriane38f6412012-12-21 17:32:12 +00002551 move_dst:
2552 /* Move result to virtual destination registers */
2553 *dst_hi = newVRegF(env);
2554 *dst_lo = newVRegF(env);
2555 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2556 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2557 return;
2558 }
2559
2560 default:
2561 goto irreducible;
2562 }
2563
2564 /* We get here if no pattern matched. */
2565 irreducible:
2566 ppIRExpr(expr);
2567 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2568
2569}
2570
2571
2572/* Compute a 128-bit value into two 64-bit registers. These may be either
2573 real or virtual regs; in any case they must not be changed by subsequent
2574 code emitted by the caller. */
2575static void
2576s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2577{
2578 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2579
2580 /* Sanity checks ... */
2581 vassert(hregIsVirtual(*dst_hi));
2582 vassert(hregIsVirtual(*dst_lo));
2583 vassert(hregClass(*dst_hi) == HRcFlt64);
2584 vassert(hregClass(*dst_lo) == HRcFlt64);
2585}
2586
2587
2588/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002589/*--- ISEL: Decimal point expressions (64 bit) ---*/
2590/*---------------------------------------------------------*/
2591
2592static HReg
2593s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2594{
2595 IRType ty = typeOfIRExpr(env->type_env, expr);
2596 UChar size;
2597
floriane38f6412012-12-21 17:32:12 +00002598 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002599
2600 size = sizeofIRType(ty);
2601
2602 switch (expr->tag) {
2603 case Iex_RdTmp:
2604 /* Return the virtual register that holds the temporary. */
2605 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2606
2607 /* --------- LOAD --------- */
2608 case Iex_Load: {
2609 HReg dst = newVRegF(env);
2610 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2611
2612 if (expr->Iex.Load.end != Iend_BE)
2613 goto irreducible;
2614
2615 addInstr(env, s390_insn_load(size, dst, am));
2616
2617 return dst;
2618 }
2619
2620 /* --------- GET --------- */
2621 case Iex_Get: {
2622 HReg dst = newVRegF(env);
2623 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2624
2625 addInstr(env, s390_insn_load(size, dst, am));
2626
2627 return dst;
2628 }
2629
floriane38f6412012-12-21 17:32:12 +00002630 /* --------- BINARY OP --------- */
2631 case Iex_Binop: {
2632 IROp op = expr->Iex.Binop.op;
2633 IRExpr *irrm = expr->Iex.Binop.arg1;
2634 IRExpr *left = expr->Iex.Binop.arg2;
2635 HReg h1, dst;
2636 s390_dfp_conv_t conv;
2637
2638 switch (op) {
2639 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
floriana887acd2013-02-08 23:32:54 +00002640 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002641 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002642
2643 convert_dfp:
2644 h1 = s390_isel_dfp_expr(env, left);
2645 goto convert;
2646
florian5f034622013-01-13 02:29:05 +00002647 convert_int:
2648 h1 = s390_isel_int_expr(env, left);
2649 goto convert;
2650
floriane38f6412012-12-21 17:32:12 +00002651 convert: {
2652 s390_dfp_round_t rounding_mode;
2653 /* convert-from-fixed and load-rounded have a rounding mode field
2654 when the floating point extension facility is installed. */
2655 dst = newVRegF(env);
2656 if (s390_host_has_fpext) {
2657 rounding_mode = get_dfp_rounding_mode(env, irrm);
2658 } else {
2659 set_dfp_rounding_mode_in_fpc(env, irrm);
2660 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2661 }
2662 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2663 rounding_mode));
2664 return dst;
2665 }
floriane38f6412012-12-21 17:32:12 +00002666
2667 case Iop_D128toD64: {
2668 HReg op_hi, op_lo, f13, f15;
2669 s390_dfp_round_t rounding_mode;
2670
2671 conv = S390_DFP_D128_TO_D64;
2672
2673 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2674
2675 /* We use non-virtual registers as pairs (f13, f15) */
2676 f13 = make_fpr(13);
2677 f15 = make_fpr(15);
2678
2679 /* operand --> (f13, f15) */
2680 addInstr(env, s390_insn_move(8, f13, op_hi));
2681 addInstr(env, s390_insn_move(8, f15, op_lo));
2682
2683 dst = newVRegF(env);
2684 /* load-rounded has a rounding mode field when the floating point
2685 extension facility is installed. */
2686 if (s390_host_has_fpext) {
2687 rounding_mode = get_dfp_rounding_mode(env, irrm);
2688 } else {
2689 set_dfp_rounding_mode_in_fpc(env, irrm);
2690 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2691 }
2692 addInstr(env, s390_insn_dfp128_convert_from(size, conv, dst, f13, f15,
2693 rounding_mode));
2694 return dst;
2695 }
2696
florian1b901d42013-01-01 22:19:24 +00002697 case Iop_ShlD64:
2698 case Iop_ShrD64: {
2699 HReg op2;
2700 HReg op3;
2701 s390_dfp_intop_t intop;
2702 IRExpr *op1 = expr->Iex.Binop.arg1;
2703 IRExpr *shift = expr->Iex.Binop.arg2;
2704
2705 switch (expr->Iex.Binop.op) {
2706 case Iop_ShlD64: intop = S390_DFP_SHIFT_LEFT; break;
2707 case Iop_ShrD64: intop = S390_DFP_SHIFT_RIGHT; break;
2708 default: goto irreducible;
2709 }
2710
2711 op2 = s390_isel_int_expr(env, shift);
2712 op3 = s390_isel_dfp_expr(env, op1);
2713 dst = newVRegF(env);
2714
2715 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
2716 return dst;
2717 }
2718
2719 default:
2720 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00002721 }
2722 }
2723
2724 /* --------- UNARY OP --------- */
2725 case Iex_Unop: {
2726 IROp op = expr->Iex.Unop.op;
2727 IRExpr *left = expr->Iex.Unop.arg;
2728 s390_dfp_conv_t conv;
2729 HReg h1, dst;
2730
2731 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
2732 HReg dst_hi, dst_lo;
2733
2734 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
2735 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
2736 }
2737
2738 if (op == Iop_ReinterpI64asD64) {
2739 dst = newVRegF(env);
2740 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2741 addInstr(env, s390_insn_move(size, dst, h1));
2742
2743 return dst;
2744 }
2745
2746 switch (op) {
2747 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00002748 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
2749 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00002750
2751 convert_dfp1:
2752 h1 = s390_isel_dfp_expr(env, left);
2753 goto convert1;
2754
florian5f034622013-01-13 02:29:05 +00002755 convert_int1:
2756 h1 = s390_isel_int_expr(env, left);
2757 goto convert1;
2758
floriane38f6412012-12-21 17:32:12 +00002759 convert1:
2760 dst = newVRegF(env);
2761 /* No rounding mode is needed for these conversions. Just stick
2762 one in. It won't be used later on. */
2763 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
2764 S390_DFP_ROUND_NEAREST_EVEN_4));
2765 return dst;
2766
2767 default:
2768 goto irreducible;
2769 }
2770 }
2771
florian12390202012-11-10 22:34:14 +00002772 /* --------- TERNARY OP --------- */
2773 case Iex_Triop: {
2774 IRTriop *triop = expr->Iex.Triop.details;
2775 IROp op = triop->op;
2776 IRExpr *irrm = triop->arg1;
2777 IRExpr *left = triop->arg2;
2778 IRExpr *right = triop->arg3;
2779 s390_dfp_round_t rounding_mode;
2780 s390_dfp_binop_t dfpop;
2781 HReg op2, op3, dst;
2782
2783 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2784 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2785 dst = newVRegF(env);
2786 switch (op) {
2787 case Iop_AddD64: dfpop = S390_DFP_ADD; break;
2788 case Iop_SubD64: dfpop = S390_DFP_SUB; break;
2789 case Iop_MulD64: dfpop = S390_DFP_MUL; break;
2790 case Iop_DivD64: dfpop = S390_DFP_DIV; break;
2791 default:
2792 goto irreducible;
2793 }
2794 /* DFP binary ops have insns with rounding mode field
2795 when the floating point extension facility is installed. */
2796 if (s390_host_has_fpext) {
2797 rounding_mode = get_dfp_rounding_mode(env, irrm);
2798 } else {
2799 set_dfp_rounding_mode_in_fpc(env, irrm);
2800 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2801 }
2802
2803 addInstr(env,
2804 s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
2805 return dst;
2806 }
2807
2808 default:
2809 goto irreducible;
2810 }
2811
2812 /* We get here if no pattern matched. */
2813 irreducible:
2814 ppIRExpr(expr);
2815 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2816}
2817
2818static HReg
2819s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2820{
2821 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2822
2823 /* Sanity checks ... */
2824 vassert(hregClass(dst) == HRcFlt64);
2825 vassert(hregIsVirtual(dst));
2826
2827 return dst;
2828}
2829
2830
2831/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002832/*--- ISEL: Condition Code ---*/
2833/*---------------------------------------------------------*/
2834
2835/* This function handles all operators that produce a 1-bit result */
2836static s390_cc_t
2837s390_isel_cc(ISelEnv *env, IRExpr *cond)
2838{
2839 UChar size;
2840
2841 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2842
2843 /* Constant: either 1 or 0 */
2844 if (cond->tag == Iex_Const) {
2845 vassert(cond->Iex.Const.con->tag == Ico_U1);
2846 vassert(cond->Iex.Const.con->Ico.U1 == True
2847 || cond->Iex.Const.con->Ico.U1 == False);
2848
2849 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2850 }
2851
2852 /* Variable: values are 1 or 0 */
2853 if (cond->tag == Iex_RdTmp) {
2854 IRTemp tmp = cond->Iex.RdTmp.tmp;
2855 HReg reg = lookupIRTemp(env, tmp);
2856
2857 /* Load-and-test does not modify REG; so this is OK. */
2858 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2859 size = 4;
2860 else
2861 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2862 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2863 return S390_CC_NE;
2864 }
2865
2866 /* Unary operators */
2867 if (cond->tag == Iex_Unop) {
2868 IRExpr *arg = cond->Iex.Unop.arg;
2869
2870 switch (cond->Iex.Unop.op) {
2871 case Iop_Not1: /* Not1(cond) */
2872 /* Generate code for EXPR, and negate the test condition */
2873 return s390_cc_invert(s390_isel_cc(env, arg));
2874
2875 /* Iop_32/64to1 select the LSB from their operand */
2876 case Iop_32to1:
2877 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002878 HReg dst = newVRegI(env);
2879 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002880
2881 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2882
florianf366a802012-08-03 00:42:18 +00002883 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002884 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2885 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2886 return S390_CC_NE;
2887 }
2888
2889 case Iop_CmpNEZ8:
2890 case Iop_CmpNEZ16: {
2891 s390_opnd_RMI src;
2892 s390_unop_t op;
2893 HReg dst;
2894
2895 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2896 : S390_ZERO_EXTEND_16;
2897 dst = newVRegI(env);
2898 src = s390_isel_int_expr_RMI(env, arg);
2899 addInstr(env, s390_insn_unop(4, op, dst, src));
2900 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2901 return S390_CC_NE;
2902 }
2903
2904 case Iop_CmpNEZ32:
2905 case Iop_CmpNEZ64: {
2906 s390_opnd_RMI src;
2907
2908 src = s390_isel_int_expr_RMI(env, arg);
2909 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2910 addInstr(env, s390_insn_test(size, src));
2911 return S390_CC_NE;
2912 }
2913
2914 default:
2915 goto fail;
2916 }
2917 }
2918
2919 /* Binary operators */
2920 if (cond->tag == Iex_Binop) {
2921 IRExpr *arg1 = cond->Iex.Binop.arg1;
2922 IRExpr *arg2 = cond->Iex.Binop.arg2;
2923 HReg reg1, reg2;
2924
2925 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2926
2927 switch (cond->Iex.Binop.op) {
2928 s390_unop_t op;
2929 s390_cc_t result;
2930
2931 case Iop_CmpEQ8:
2932 case Iop_CasCmpEQ8:
2933 op = S390_ZERO_EXTEND_8;
2934 result = S390_CC_E;
2935 goto do_compare_ze;
2936
2937 case Iop_CmpNE8:
2938 case Iop_CasCmpNE8:
2939 op = S390_ZERO_EXTEND_8;
2940 result = S390_CC_NE;
2941 goto do_compare_ze;
2942
2943 case Iop_CmpEQ16:
2944 case Iop_CasCmpEQ16:
2945 op = S390_ZERO_EXTEND_16;
2946 result = S390_CC_E;
2947 goto do_compare_ze;
2948
2949 case Iop_CmpNE16:
2950 case Iop_CasCmpNE16:
2951 op = S390_ZERO_EXTEND_16;
2952 result = S390_CC_NE;
2953 goto do_compare_ze;
2954
2955 do_compare_ze: {
2956 s390_opnd_RMI op1, op2;
2957
2958 op1 = s390_isel_int_expr_RMI(env, arg1);
2959 reg1 = newVRegI(env);
2960 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2961
2962 op2 = s390_isel_int_expr_RMI(env, arg2);
2963 reg2 = newVRegI(env);
2964 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2965
2966 op2 = s390_opnd_reg(reg2);
2967 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2968
2969 return result;
2970 }
2971
2972 case Iop_CmpEQ32:
2973 case Iop_CmpEQ64:
2974 case Iop_CasCmpEQ32:
2975 case Iop_CasCmpEQ64:
2976 result = S390_CC_E;
2977 goto do_compare;
2978
2979 case Iop_CmpNE32:
2980 case Iop_CmpNE64:
2981 case Iop_CasCmpNE32:
2982 case Iop_CasCmpNE64:
2983 result = S390_CC_NE;
2984 goto do_compare;
2985
2986 do_compare: {
2987 HReg op1;
2988 s390_opnd_RMI op2;
2989
2990 order_commutative_operands(arg1, arg2);
2991
2992 op1 = s390_isel_int_expr(env, arg1);
2993 op2 = s390_isel_int_expr_RMI(env, arg2);
2994
2995 addInstr(env, s390_insn_compare(size, op1, op2, False));
2996
2997 return result;
2998 }
2999
3000 case Iop_CmpLT32S:
3001 case Iop_CmpLE32S:
3002 case Iop_CmpLT64S:
3003 case Iop_CmpLE64S: {
3004 HReg op1;
3005 s390_opnd_RMI op2;
3006
3007 op1 = s390_isel_int_expr(env, arg1);
3008 op2 = s390_isel_int_expr_RMI(env, arg2);
3009
3010 addInstr(env, s390_insn_compare(size, op1, op2, True));
3011
3012 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3013 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3014 }
3015
3016 case Iop_CmpLT32U:
3017 case Iop_CmpLE32U:
3018 case Iop_CmpLT64U:
3019 case Iop_CmpLE64U: {
3020 HReg op1;
3021 s390_opnd_RMI op2;
3022
3023 op1 = s390_isel_int_expr(env, arg1);
3024 op2 = s390_isel_int_expr_RMI(env, arg2);
3025
3026 addInstr(env, s390_insn_compare(size, op1, op2, False));
3027
3028 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3029 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3030 }
3031
3032 default:
3033 goto fail;
3034 }
3035 }
3036
3037 fail:
3038 ppIRExpr(cond);
3039 vpanic("s390_isel_cc: unexpected operator");
3040}
3041
3042
3043/*---------------------------------------------------------*/
3044/*--- ISEL: Statements ---*/
3045/*---------------------------------------------------------*/
3046
3047static void
3048s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3049{
3050 if (vex_traceflags & VEX_TRACE_VCODE) {
3051 vex_printf("\n -- ");
3052 ppIRStmt(stmt);
3053 vex_printf("\n");
3054 }
3055
3056 switch (stmt->tag) {
3057
3058 /* --------- STORE --------- */
3059 case Ist_Store: {
3060 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3061 s390_amode *am;
3062 HReg src;
3063
3064 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3065
3066 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3067
3068 switch (tyd) {
3069 case Ity_I8:
3070 case Ity_I16:
3071 case Ity_I32:
3072 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003073 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003074 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003075 stmt->Ist.Store.data->tag == Iex_Const) {
3076 ULong value =
3077 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3078 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003079 return;
3080 }
floriancec3a8a2013-02-02 00:16:58 +00003081 /* Check whether we can use a memcpy here. Currently, the restriction
3082 is that both amodes need to be B12, so MVC can be emitted.
3083 We do not consider a store whose data expression is a load because
3084 we don't want to deal with overlapping locations. */
3085 /* store(get) never overlaps*/
3086 if (am->tag == S390_AMODE_B12 &&
3087 stmt->Ist.Store.data->tag == Iex_Get) {
3088 UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
3089 s390_amode *from = s390_amode_for_guest_state(offset);
3090 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
3091 return;
3092 }
3093 /* General case: compile data into a register */
sewardj2019a972011-03-07 16:04:07 +00003094 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3095 break;
3096
3097 case Ity_F32:
3098 case Ity_F64:
3099 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3100 break;
3101
florianeb981ae2012-12-21 18:55:03 +00003102 case Ity_D32:
3103 case Ity_D64:
3104 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3105 break;
3106
sewardj2019a972011-03-07 16:04:07 +00003107 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003108 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003109 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003110 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003111
3112 default:
3113 goto stmt_fail;
3114 }
3115
3116 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3117 return;
3118 }
3119
3120 /* --------- PUT --------- */
3121 case Ist_Put: {
3122 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3123 HReg src;
3124 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003125 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003126
florianad43b3a2012-02-20 15:01:14 +00003127 /* Detect updates to certain guest registers. We track the contents
3128 of those registers as long as they contain constants. If the new
3129 constant is either zero or in the 8-bit neighbourhood of the
3130 current value we can use a memory-to-memory insn to do the update. */
3131
3132 Int offset = stmt->Ist.Put.offset;
3133
3134 /* Check necessary conditions:
3135 (1) must be one of the registers we care about
3136 (2) assigned value must be a constant */
3137 Int guest_reg = get_guest_reg(offset);
3138
3139 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3140
florianad43b3a2012-02-20 15:01:14 +00003141 if (stmt->Ist.Put.data->tag != Iex_Const) {
3142 /* Invalidate guest register contents */
3143 env->old_value_valid[guest_reg] = False;
3144 goto not_special;
3145 }
3146
cborntraaf7ad282012-08-08 14:11:33 +00003147 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3148 if (tyd != Ity_I64)
3149 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003150
cborntraaf7ad282012-08-08 14:11:33 +00003151 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003152
3153 old_value = env->old_value[guest_reg];
3154 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3155 env->old_value[guest_reg] = new_value;
3156
3157 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3158 env->old_value_valid[guest_reg] = True;
3159
3160 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003161 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003162 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003163 return;
florianad43b3a2012-02-20 15:01:14 +00003164 }
3165
florianad43b3a2012-02-20 15:01:14 +00003166 if (old_value_is_valid == False) goto not_special;
3167
3168 /* If the new value is in the neighbourhood of the old value
3169 we can use a memory-to-memory insn */
3170 difference = new_value - old_value;
3171
3172 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003173 am = s390_amode_for_guest_state(offset);
3174 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003175 (difference & 0xFF), new_value));
3176 return;
3177 }
3178
florianb93348d2012-12-27 00:59:43 +00003179 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003180 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003181 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003182 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003183 return;
3184 }
3185
3186 /* No special case applies... fall through */
3187
3188 not_special:
florianb93348d2012-12-27 00:59:43 +00003189 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003190
3191 switch (tyd) {
3192 case Ity_I8:
3193 case Ity_I16:
3194 case Ity_I32:
3195 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003196 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003197 stmt->Ist.Put.data->tag == Iex_Const) {
3198 ULong value =
3199 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3200 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003201 return;
3202 }
floriancec3a8a2013-02-02 00:16:58 +00003203 /* Check whether we can use a memcpy here. Currently, the restriction
3204 is that both amodes need to be B12, so MVC can be emitted. */
3205 /* put(load) never overlaps */
3206 if (am->tag == S390_AMODE_B12 &&
3207 stmt->Ist.Put.data->tag == Iex_Load) {
3208 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
3209 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
3210 s390_amode *from = s390_isel_amode(env, data);
3211 UInt size = sizeofIRType(tyd);
3212
3213 if (from->tag == S390_AMODE_B12) {
3214 /* Source can be compiled into a B12 amode. */
3215 addInstr(env, s390_insn_memcpy(size, am, from));
3216 return;
3217 }
3218
3219 src = newVRegI(env);
3220 addInstr(env, s390_insn_load(size, src, from));
3221 break;
3222 }
3223 /* put(get) */
3224 if (am->tag == S390_AMODE_B12 &&
3225 stmt->Ist.Put.data->tag == Iex_Get) {
3226 UInt put_offset = am->d;
3227 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
3228 UInt size = sizeofIRType(tyd);
3229 /* don't memcpy in case of overlap */
3230 if (put_offset + size <= get_offset ||
3231 get_offset + size <= put_offset) {
3232 s390_amode *from = s390_amode_for_guest_state(get_offset);
3233 addInstr(env, s390_insn_memcpy(size, am, from));
3234 return;
3235 }
3236 goto no_memcpy_put;
3237 }
3238 /* General case: compile data into a register */
3239no_memcpy_put:
sewardj2019a972011-03-07 16:04:07 +00003240 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3241 break;
3242
3243 case Ity_F32:
3244 case Ity_F64:
3245 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3246 break;
3247
3248 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003249 case Ity_D128:
3250 /* Does not occur. See function put_(f|d)pr_pair. */
3251 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003252
floriane38f6412012-12-21 17:32:12 +00003253 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003254 case Ity_D64:
3255 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3256 break;
3257
sewardj2019a972011-03-07 16:04:07 +00003258 default:
3259 goto stmt_fail;
3260 }
3261
3262 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3263 return;
3264 }
3265
3266 /* --------- TMP --------- */
3267 case Ist_WrTmp: {
3268 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3269 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3270 HReg src, dst;
3271
3272 switch (tyd) {
3273 case Ity_I128: {
3274 HReg dst_hi, dst_lo, res_hi, res_lo;
3275
3276 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3277 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3278
3279 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3280 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3281 return;
3282 }
3283
3284 case Ity_I8:
3285 case Ity_I16:
3286 case Ity_I32:
3287 case Ity_I64:
3288 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3289 dst = lookupIRTemp(env, tmp);
3290 break;
3291
3292 case Ity_I1: {
3293 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3294 dst = lookupIRTemp(env, tmp);
3295 addInstr(env, s390_insn_cc2bool(dst, cond));
3296 return;
3297 }
3298
3299 case Ity_F32:
3300 case Ity_F64:
3301 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3302 dst = lookupIRTemp(env, tmp);
3303 break;
3304
3305 case Ity_F128: {
3306 HReg dst_hi, dst_lo, res_hi, res_lo;
3307
3308 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3309 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3310
3311 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3312 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3313 return;
3314 }
3315
floriane38f6412012-12-21 17:32:12 +00003316 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003317 case Ity_D64:
3318 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3319 dst = lookupIRTemp(env, tmp);
3320 break;
3321
floriane38f6412012-12-21 17:32:12 +00003322 case Ity_D128: {
3323 HReg dst_hi, dst_lo, res_hi, res_lo;
3324
3325 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3326 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3327
3328 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3329 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3330 return;
3331 }
3332
sewardj2019a972011-03-07 16:04:07 +00003333 default:
3334 goto stmt_fail;
3335 }
3336
3337 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3338 return;
3339 }
3340
3341 /* --------- Call to DIRTY helper --------- */
3342 case Ist_Dirty: {
3343 IRType retty;
3344 IRDirty* d = stmt->Ist.Dirty.details;
3345 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00003346 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00003347 Int i;
3348
3349 /* Invalidate tracked values of those guest state registers that are
3350 modified by this helper. */
3351 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003352 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3353 descriptors in guest state effect descriptions. Hence: */
3354 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003355 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3356 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3357 if (guest_reg != GUEST_UNKNOWN)
3358 env->old_value_valid[guest_reg] = False;
3359 }
3360 }
sewardj2019a972011-03-07 16:04:07 +00003361
3362 if (d->nFxState == 0)
3363 vassert(!d->needsBBP);
3364
3365 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
3366
florian01ed6e72012-05-27 16:52:43 +00003367 if (d->tmp == IRTemp_INVALID) {
3368 /* No return value. */
3369 dst = INVALID_HREG;
3370 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003371 return;
florian01ed6e72012-05-27 16:52:43 +00003372 }
sewardj2019a972011-03-07 16:04:07 +00003373
3374 retty = typeOfIRTemp(env->type_env, d->tmp);
3375 if (retty == Ity_I64 || retty == Ity_I32
3376 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003377 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00003378 dst = lookupIRTemp(env, d->tmp);
3379 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00003380 return;
3381 }
3382 break;
3383 }
3384
3385 case Ist_CAS:
3386 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3387 IRCAS *cas = stmt->Ist.CAS.details;
3388 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3389 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3390 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3391 HReg old = lookupIRTemp(env, cas->oldLo);
3392
3393 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3394 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3395 } else {
3396 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3397 }
3398 return;
3399 } else {
florian448cbba2012-06-06 02:26:01 +00003400 IRCAS *cas = stmt->Ist.CAS.details;
3401 s390_amode *op2 = s390_isel_amode(env, cas->addr);
3402 HReg r8, r9, r10, r11, r1;
3403 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3404 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3405 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3406 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3407 HReg old_low = lookupIRTemp(env, cas->oldLo);
3408 HReg old_high = lookupIRTemp(env, cas->oldHi);
3409
3410 /* Use non-virtual registers r8 and r9 as pair for op1
3411 and move op1 there */
3412 r8 = make_gpr(8);
3413 r9 = make_gpr(9);
3414 addInstr(env, s390_insn_move(8, r8, op1_high));
3415 addInstr(env, s390_insn_move(8, r9, op1_low));
3416
3417 /* Use non-virtual registers r10 and r11 as pair for op3
3418 and move op3 there */
3419 r10 = make_gpr(10);
3420 r11 = make_gpr(11);
3421 addInstr(env, s390_insn_move(8, r10, op3_high));
3422 addInstr(env, s390_insn_move(8, r11, op3_low));
3423
3424 /* Register r1 is used as a scratch register */
3425 r1 = make_gpr(1);
3426
3427 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3428 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3429 old_high, old_low, r1));
3430 } else {
3431 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3432 old_high, old_low, r1));
3433 }
3434 addInstr(env, s390_insn_move(8, op1_high, r8));
3435 addInstr(env, s390_insn_move(8, op1_low, r9));
3436 addInstr(env, s390_insn_move(8, op3_high, r10));
3437 addInstr(env, s390_insn_move(8, op3_low, r11));
3438 return;
sewardj2019a972011-03-07 16:04:07 +00003439 }
3440 break;
3441
3442 /* --------- EXIT --------- */
3443 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003444 s390_cc_t cond;
3445 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3446
3447 if (tag != Ico_U64)
3448 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3449
florian8844a632012-04-13 04:04:06 +00003450 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003451 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003452
3453 /* Case: boring transfer to known address */
3454 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3455 if (env->chaining_allowed) {
3456 /* .. almost always true .. */
3457 /* Skip the event check at the dst if this is a forwards
3458 edge. */
3459 Bool to_fast_entry
3460 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3461 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3462 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3463 guest_IA, to_fast_entry));
3464 } else {
3465 /* .. very occasionally .. */
3466 /* We can't use chaining, so ask for an assisted transfer,
3467 as that's the only alternative that is allowable. */
3468 HReg dst = s390_isel_int_expr(env,
3469 IRExpr_Const(stmt->Ist.Exit.dst));
3470 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3471 }
3472 return;
3473 }
3474
3475 /* Case: assisted transfer to arbitrary address */
3476 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003477 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003478 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003479 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00003480 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00003481 case Ijk_Sys_syscall:
3482 case Ijk_ClientReq:
3483 case Ijk_NoRedir:
3484 case Ijk_Yield:
3485 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003486 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3487 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3488 stmt->Ist.Exit.jk));
3489 return;
3490 }
3491 default:
3492 break;
3493 }
3494
3495 /* Do we ever expect to see any other kind? */
3496 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003497 }
3498
3499 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003500 case Ist_MBE:
3501 switch (stmt->Ist.MBE.event) {
3502 case Imbe_Fence:
3503 addInstr(env, s390_insn_mfence());
3504 return;
3505 default:
3506 break;
3507 }
sewardj2019a972011-03-07 16:04:07 +00003508 break;
3509
3510 /* --------- Miscellaneous --------- */
3511
3512 case Ist_PutI: /* Not needed */
3513 case Ist_IMark: /* Doesn't generate any executable code */
3514 case Ist_NoOp: /* Doesn't generate any executable code */
3515 case Ist_AbiHint: /* Meaningless in IR */
3516 return;
3517
3518 default:
3519 break;
3520 }
3521
3522 stmt_fail:
3523 ppIRStmt(stmt);
3524 vpanic("s390_isel_stmt");
3525}
3526
3527
3528/*---------------------------------------------------------*/
3529/*--- ISEL: Basic block terminators (Nexts) ---*/
3530/*---------------------------------------------------------*/
3531
3532static void
florianffbd84d2012-12-09 02:06:29 +00003533iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003534{
sewardj2019a972011-03-07 16:04:07 +00003535 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003536 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003537 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003538 vex_printf("; exit-");
3539 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003540 vex_printf("\n");
3541 }
3542
florian8844a632012-04-13 04:04:06 +00003543 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3544
3545 /* Case: boring transfer to known address */
3546 if (next->tag == Iex_Const) {
3547 IRConst *cdst = next->Iex.Const.con;
3548 vassert(cdst->tag == Ico_U64);
3549 if (jk == Ijk_Boring || jk == Ijk_Call) {
3550 /* Boring transfer to known address */
3551 if (env->chaining_allowed) {
3552 /* .. almost always true .. */
3553 /* Skip the event check at the dst if this is a forwards
3554 edge. */
3555 Bool to_fast_entry
3556 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3557 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3558 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3559 guest_IA, to_fast_entry));
3560 } else {
3561 /* .. very occasionally .. */
3562 /* We can't use chaining, so ask for an indirect transfer,
3563 as that's the cheapest alternative that is allowable. */
3564 HReg dst = s390_isel_int_expr(env, next);
3565 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3566 Ijk_Boring));
3567 }
3568 return;
3569 }
3570 }
3571
3572 /* Case: call/return (==boring) transfer to any address */
3573 switch (jk) {
3574 case Ijk_Boring:
3575 case Ijk_Ret:
3576 case Ijk_Call: {
3577 HReg dst = s390_isel_int_expr(env, next);
3578 if (env->chaining_allowed) {
3579 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3580 } else {
3581 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3582 Ijk_Boring));
3583 }
3584 return;
3585 }
3586 default:
3587 break;
3588 }
3589
3590 /* Case: some other kind of transfer to any address */
3591 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003592 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003593 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003594 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003595 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003596 case Ijk_Sys_syscall:
3597 case Ijk_ClientReq:
3598 case Ijk_NoRedir:
3599 case Ijk_Yield:
3600 case Ijk_SigTRAP: {
3601 HReg dst = s390_isel_int_expr(env, next);
3602 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3603 return;
3604 }
3605 default:
3606 break;
3607 }
3608
3609 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003610}
3611
3612
3613/*---------------------------------------------------------*/
3614/*--- Insn selector top-level ---*/
3615/*---------------------------------------------------------*/
3616
florianf26994a2012-04-21 03:34:54 +00003617/* Translate an entire SB to s390 code.
3618 Note: archinfo_host is a pointer to a stack-allocated variable.
3619 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003620
3621HInstrArray *
3622iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003623 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3624 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3625 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003626{
3627 UInt i, j;
3628 HReg hreg, hregHI;
3629 ISelEnv *env;
3630 UInt hwcaps_host = archinfo_host->hwcaps;
3631
florianf26994a2012-04-21 03:34:54 +00003632 /* KLUDGE: export hwcaps. */
3633 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003634
sewardj2019a972011-03-07 16:04:07 +00003635 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003636 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003637
3638 /* Make up an initial environment to use. */
3639 env = LibVEX_Alloc(sizeof(ISelEnv));
3640 env->vreg_ctr = 0;
3641
3642 /* Set up output code array. */
3643 env->code = newHInstrArray();
3644
3645 /* Copy BB's type env. */
3646 env->type_env = bb->tyenv;
3647
florianad43b3a2012-02-20 15:01:14 +00003648 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00003649 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3650 env->old_value[i] = 0; /* just something to have a defined value */
3651 env->old_value_valid[i] = False;
3652 }
3653
sewardj2019a972011-03-07 16:04:07 +00003654 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3655 change as we go along. For some reason types_used has Int type -- but
3656 it should be unsigned. Internally we use an unsigned type; so we
3657 assert it here. */
3658 vassert(bb->tyenv->types_used >= 0);
3659
3660 env->n_vregmap = bb->tyenv->types_used;
3661 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3662 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3663
florian2c74d242012-09-12 19:38:42 +00003664 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003665 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003666
sewardj2019a972011-03-07 16:04:07 +00003667 /* and finally ... */
3668 env->hwcaps = hwcaps_host;
3669
florian8844a632012-04-13 04:04:06 +00003670 env->max_ga = max_ga;
3671 env->chaining_allowed = chaining_allowed;
3672
sewardj2019a972011-03-07 16:04:07 +00003673 /* For each IR temporary, allocate a suitably-kinded virtual
3674 register. */
3675 j = 0;
3676 for (i = 0; i < env->n_vregmap; i++) {
3677 hregHI = hreg = INVALID_HREG;
3678 switch (bb->tyenv->types[i]) {
3679 case Ity_I1:
3680 case Ity_I8:
3681 case Ity_I16:
3682 case Ity_I32:
3683 hreg = mkHReg(j++, HRcInt64, True);
3684 break;
3685
3686 case Ity_I64:
3687 hreg = mkHReg(j++, HRcInt64, True);
3688 break;
3689
3690 case Ity_I128:
3691 hreg = mkHReg(j++, HRcInt64, True);
3692 hregHI = mkHReg(j++, HRcInt64, True);
3693 break;
3694
3695 case Ity_F32:
3696 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00003697 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003698 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003699 hreg = mkHReg(j++, HRcFlt64, True);
3700 break;
3701
3702 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003703 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003704 hreg = mkHReg(j++, HRcFlt64, True);
3705 hregHI = mkHReg(j++, HRcFlt64, True);
3706 break;
3707
3708 case Ity_V128: /* fall through */
3709 default:
3710 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003711 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003712 }
3713
3714 env->vregmap[i] = hreg;
3715 env->vregmapHI[i] = hregHI;
3716 }
3717 env->vreg_ctr = j;
3718
florian8844a632012-04-13 04:04:06 +00003719 /* The very first instruction must be an event check. */
3720 s390_amode *counter, *fail_addr;
3721 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3722 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3723 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3724
3725 /* Possibly a block counter increment (for profiling). At this
3726 point we don't know the address of the counter, so just pretend
3727 it is zero. It will have to be patched later, but before this
3728 translation is used, by a call to LibVEX_patchProfInc. */
3729 if (add_profinc) {
3730 addInstr(env, s390_insn_profinc());
3731 }
3732
sewardj2019a972011-03-07 16:04:07 +00003733 /* Ok, finally we can iterate over the statements. */
3734 for (i = 0; i < bb->stmts_used; i++)
3735 if (bb->stmts[i])
3736 s390_isel_stmt(env, bb->stmts[i]);
3737
florian8844a632012-04-13 04:04:06 +00003738 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003739
3740 /* Record the number of vregs we used. */
3741 env->code->n_vregs = env->vreg_ctr;
3742
3743 return env->code;
3744}
3745
3746/*---------------------------------------------------------------*/
3747/*--- end host_s390_isel.c ---*/
3748/*---------------------------------------------------------------*/