blob: fc320144e1077f53b3f86ab61e31547429576d46 [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
sewardj89ae8472013-10-18 14:12:58 +000011 Copyright IBM Corp. 2010-2013
12 Copyright (C) 2012-2013 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 *);
florian406ac942014-11-22 20:10:21 +0000130static s390_amode *s390_isel_amode_b12_b20(ISelEnv *, IRExpr *);
sewardj2019a972011-03-07 16:04:07 +0000131static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
132static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
133static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
134static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
135static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
florian12390202012-11-10 22:34:14 +0000136static HReg s390_isel_dfp_expr(ISelEnv *, IRExpr *);
floriane38f6412012-12-21 17:32:12 +0000137static void s390_isel_dfp128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
sewardj2019a972011-03-07 16:04:07 +0000138
139
florianad43b3a2012-02-20 15:01:14 +0000140static Int
141get_guest_reg(Int offset)
142{
143 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000144 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
145 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
146 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
147 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
148 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
149 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000150 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000151
152 /* Also make sure there is never a partial write to one of
153 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000154 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
155 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
156 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
157 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
158 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000159 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
160 /* counter is used both as 4-byte and as 8-byte entity */
161 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
162 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianaf50a192012-07-13 14:13:06 +0000163 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000164 break;
165
166 default: break;
167 }
168
169 return GUEST_UNKNOWN;
170}
171
sewardj2019a972011-03-07 16:04:07 +0000172/* Add an instruction */
173static void
174addInstr(ISelEnv *env, s390_insn *insn)
175{
176 addHInstr(env->code, insn);
177
178 if (vex_traceflags & VEX_TRACE_VCODE) {
179 vex_printf("%s\n", s390_insn_as_string(insn));
180 }
181}
182
183
184static __inline__ IRExpr *
185mkU64(ULong value)
186{
187 return IRExpr_Const(IRConst_U64(value));
188}
189
190
191/*---------------------------------------------------------*/
192/*--- Registers ---*/
193/*---------------------------------------------------------*/
194
195/* Return the virtual register to which a given IRTemp is mapped. */
196static HReg
197lookupIRTemp(ISelEnv *env, IRTemp tmp)
198{
199 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000200 vassert(! hregIsInvalid(env->vregmap[tmp]));
sewardj2019a972011-03-07 16:04:07 +0000201
202 return env->vregmap[tmp];
203}
204
205
206/* Return the two virtual registers to which the IRTemp is mapped. */
207static void
208lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
209{
210 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000211 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardj2019a972011-03-07 16:04:07 +0000212
213 *lo = env->vregmap[tmp];
214 *hi = env->vregmapHI[tmp];
215}
216
217
218/* Allocate a new integer register */
219static HReg
220newVRegI(ISelEnv *env)
221{
222 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
223 env->vreg_ctr++;
224
225 return reg;
226}
227
228
229/* Allocate a new floating point register */
230static HReg
231newVRegF(ISelEnv *env)
232{
233 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
234
235 env->vreg_ctr++;
236
237 return reg;
238}
239
240
241/* Construct a non-virtual general purpose register */
242static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000243make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000244{
245 return mkHReg(regno, HRcInt64, False /* virtual */ );
246}
247
248
249/* Construct a non-virtual floating point register */
250static __inline__ HReg
251make_fpr(UInt regno)
252{
253 return mkHReg(regno, HRcFlt64, False /* virtual */ );
254}
255
256
257/*---------------------------------------------------------*/
258/*--- Amode ---*/
259/*---------------------------------------------------------*/
260
261static __inline__ Bool
262ulong_fits_unsigned_12bit(ULong val)
263{
264 return (val & 0xFFFu) == val;
265}
266
267
268static __inline__ Bool
269ulong_fits_signed_20bit(ULong val)
270{
271 Long v = val & 0xFFFFFu;
272
273 v = (v << 44) >> 44; /* sign extend */
274
275 return val == (ULong)v;
276}
277
278
florianad43b3a2012-02-20 15:01:14 +0000279static __inline__ Bool
280ulong_fits_signed_8bit(ULong val)
281{
282 Long v = val & 0xFFu;
283
284 v = (v << 56) >> 56; /* sign extend */
285
286 return val == (ULong)v;
287}
288
sewardj2019a972011-03-07 16:04:07 +0000289/* EXPR is an expression that is used as an address. Return an s390_amode
florian406ac942014-11-22 20:10:21 +0000290 for it. If select_b12_b20_only is true the returned amode must be either
291 S390_AMODE_B12 or S390_AMODE_B20. */
sewardj2019a972011-03-07 16:04:07 +0000292static s390_amode *
florian406ac942014-11-22 20:10:21 +0000293s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr,
294 Bool select_b12_b20_only __attribute__((unused)))
sewardj2019a972011-03-07 16:04:07 +0000295{
296 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
297 IRExpr *arg1 = expr->Iex.Binop.arg1;
298 IRExpr *arg2 = expr->Iex.Binop.arg2;
299
300 /* Move constant into right subtree */
301 if (arg1->tag == Iex_Const) {
302 IRExpr *tmp;
303 tmp = arg1;
304 arg1 = arg2;
305 arg2 = tmp;
306 }
307
308 /* r + constant: Check for b12 first, then b20 */
309 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
310 ULong value = arg2->Iex.Const.con->Ico.U64;
311
312 if (ulong_fits_unsigned_12bit(value)) {
313 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
314 }
sewardj652b56a2011-04-13 15:38:17 +0000315 /* If long-displacement is not available, do not construct B20 or
316 BX20 amodes because code generation cannot handle them. */
317 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000318 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
319 }
320 }
321 }
322
323 /* Doesn't match anything in particular. Generate it into
324 a register and use that. */
325 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
326}
327
328
329static s390_amode *
330s390_isel_amode(ISelEnv *env, IRExpr *expr)
331{
florian35da8612011-06-25 02:25:41 +0000332 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000333
334 /* Address computation should yield a 64-bit value */
335 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
336
florian406ac942014-11-22 20:10:21 +0000337 am = s390_isel_amode_wrk(env, expr, /* B12, B20 only */ False);
sewardj2019a972011-03-07 16:04:07 +0000338
339 /* Check post-condition */
340 vassert(s390_amode_is_sane(am));
341
342 return am;
343}
344
345
florian406ac942014-11-22 20:10:21 +0000346/* Sometimes we must compile an expression into an amode that is either
347 S390_AMODE_B12 or S390_AMODE_B20. An example is the compare-and-swap
348 opcode. These opcodes do not have a variant hat accepts an addressing
349 mode with an index register.
350 Now, in theory we could, when emitting the compare-and-swap insn,
351 hack a, say, BX12 amode into a B12 amode like so:
352
353 r0 = b # save away base register
354 b = b + x # add index register to base register
355 cas(b,d,...) # emit compare-and-swap using b12 amode
356 b = r0 # restore base register
357
358 Unfortunately, emitting the compare-and-swap insn already utilises r0
359 under the covers, so the trick above is off limits, sadly. */
360static s390_amode *
361s390_isel_amode_b12_b20(ISelEnv *env, IRExpr *expr)
362{
363 s390_amode *am;
364
365 /* Address computation should yield a 64-bit value */
366 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
367
368 am = s390_isel_amode_wrk(env, expr, /* B12, B20 only */ True);
369
370 /* Check post-condition */
371 vassert(s390_amode_is_sane(am) &&
372 (am->tag == S390_AMODE_B12 || am->tag == S390_AMODE_B20));
373
374 return am;
375}
376
377
sewardj2019a972011-03-07 16:04:07 +0000378/*---------------------------------------------------------*/
379/*--- Helper functions ---*/
380/*---------------------------------------------------------*/
381
382/* Constants and memory accesses should be right operands */
383#define order_commutative_operands(left, right) \
384 do { \
385 if (left->tag == Iex_Const || left->tag == Iex_Load || \
386 left->tag == Iex_Get) { \
387 IRExpr *tmp; \
388 tmp = left; \
389 left = right; \
390 right = tmp; \
391 } \
392 } while (0)
393
394
395/* Copy an RMI operand to the DST register */
396static s390_insn *
397s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
398{
399 switch (opnd.tag) {
400 case S390_OPND_AMODE:
401 return s390_insn_load(size, dst, opnd.variant.am);
402
403 case S390_OPND_REG:
404 return s390_insn_move(size, dst, opnd.variant.reg);
405
406 case S390_OPND_IMMEDIATE:
407 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
408
409 default:
410 vpanic("s390_opnd_copy");
411 }
412}
413
414
415/* Construct a RMI operand for a register */
416static __inline__ s390_opnd_RMI
417s390_opnd_reg(HReg reg)
418{
419 s390_opnd_RMI opnd;
420
421 opnd.tag = S390_OPND_REG;
422 opnd.variant.reg = reg;
423
424 return opnd;
425}
426
427
428/* Construct a RMI operand for an immediate constant */
429static __inline__ s390_opnd_RMI
430s390_opnd_imm(ULong value)
431{
432 s390_opnd_RMI opnd;
433
434 opnd.tag = S390_OPND_IMMEDIATE;
435 opnd.variant.imm = value;
436
437 return opnd;
438}
439
440
florianffbd84d2012-12-09 02:06:29 +0000441/* Return 1, if EXPR represents the constant 0 */
442static Bool
sewardj2019a972011-03-07 16:04:07 +0000443s390_expr_is_const_zero(IRExpr *expr)
444{
445 ULong value;
446
447 if (expr->tag == Iex_Const) {
448 switch (expr->Iex.Const.con->tag) {
449 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
450 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
451 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
452 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
453 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
454 default:
455 vpanic("s390_expr_is_const_zero");
456 }
457 return value == 0;
458 }
459
460 return 0;
461}
462
463
florianb93348d2012-12-27 00:59:43 +0000464/* Return the value of CON as a sign-exteded ULong value */
465static ULong
466get_const_value_as_ulong(const IRConst *con)
467{
468 Long value;
469
470 switch (con->tag) {
471 case Ico_U1: value = con->Ico.U1; return (ULong) ((value << 63) >> 63);
472 case Ico_U8: value = con->Ico.U8; return (ULong) ((value << 56) >> 56);
473 case Ico_U16: value = con->Ico.U16; return (ULong) ((value << 48) >> 48);
474 case Ico_U32: value = con->Ico.U32; return (ULong) ((value << 32) >> 32);
475 case Ico_U64: return con->Ico.U64;
476 default:
477 vpanic("get_const_value_as_ulong");
478 }
479}
480
481
sewardj2019a972011-03-07 16:04:07 +0000482/* Call a helper (clean or dirty)
483 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000484
sewardj2019a972011-03-07 16:04:07 +0000485 (a) they are expressions yielding an integer result
486 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000487
488 guard is a Ity_Bit expression indicating whether or not the
489 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000490
491 Calling the helper function proceeds as follows:
492
493 (1) The helper arguments are evaluated and their value stored in
494 virtual registers.
495 (2) The condition code is evaluated
496 (3) The argument values are copied from the virtual registers to the
497 registers mandated by the ABI.
498 (4) Call the helper function.
499
500 This is not the most efficient way as step 3 generates register-to-register
501 moves. But it is the least fragile way as the only hidden dependency here
502 is that register-to-register moves (step 3) must not clobber the condition
503 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
504 to-register add more such dependencies. Not good. Besides, it's the job
505 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000506*/
507static void
sewardj74142b82013-08-08 10:28:59 +0000508doHelperCall(/*OUT*/UInt *stackAdjustAfterCall,
509 /*OUT*/RetLoc *retloc,
510 ISelEnv *env, IRExpr *guard,
511 IRCallee *callee, IRType retTy, IRExpr **args)
sewardj2019a972011-03-07 16:04:07 +0000512{
florian52af7bc2012-05-12 03:44:49 +0000513 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000514 ULong target;
515 HReg tmpregs[S390_NUM_GPRPARMS];
516 s390_cc_t cc;
517
sewardj74142b82013-08-08 10:28:59 +0000518 /* Set default returns. We'll update them later if needed. */
519 *stackAdjustAfterCall = 0;
520 *retloc = mk_RetLoc_INVALID();
521
522 /* The return type can be I{64,32,16,8} or V{128,256}. In the
523 latter two cases, it is expected that |args| will contain the
florian608e5602014-11-21 21:40:45 +0000524 special node IRExpr_VECRET(). For s390, however, V128 and V256 return
525 values do not occur as we generally do not support vector types.
sewardj74142b82013-08-08 10:28:59 +0000526
florian90419562013-08-15 20:54:52 +0000527 |args| may also contain IRExpr_BBPTR(), in which case the value
sewardj74142b82013-08-08 10:28:59 +0000528 in the guest state pointer register is passed as the
529 corresponding argument.
530
531 These are used for cross-checking that IR-level constraints on
florian90419562013-08-15 20:54:52 +0000532 the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */
sewardj74142b82013-08-08 10:28:59 +0000533 UInt nVECRETs = 0;
534 UInt nBBPTRs = 0;
535
sewardj2019a972011-03-07 16:04:07 +0000536 n_args = 0;
537 for (i = 0; args[i]; i++)
538 ++n_args;
539
sewardj74142b82013-08-08 10:28:59 +0000540 if (n_args > S390_NUM_GPRPARMS) {
sewardj2019a972011-03-07 16:04:07 +0000541 vpanic("doHelperCall: too many arguments");
542 }
543
florian11b8ee82012-08-06 13:35:33 +0000544 /* All arguments must have Ity_I64. For two reasons:
545 (1) We do not handle floating point arguments.
546 (2) The ABI requires that integer values are sign- or zero-extended
547 to 64 bit.
548 */
549 Int arg_errors = 0;
550 for (i = 0; i < n_args; ++i) {
florian90419562013-08-15 20:54:52 +0000551 if (UNLIKELY(args[i]->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000552 nVECRETs++;
florian90419562013-08-15 20:54:52 +0000553 } else if (UNLIKELY(args[i]->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000554 nBBPTRs++;
555 } else {
556 IRType type = typeOfIRExpr(env->type_env, args[i]);
557 if (type != Ity_I64) {
558 ++arg_errors;
559 vex_printf("calling %s: argument #%d has type ", callee->name, i);
560 ppIRType(type);
561 vex_printf("; Ity_I64 is required\n");
562 }
florian11b8ee82012-08-06 13:35:33 +0000563 }
564 }
565
566 if (arg_errors)
567 vpanic("cannot continue due to errors in argument passing");
568
florian608e5602014-11-21 21:40:45 +0000569 /* If these fail, the IR is ill-formed */
sewardj74142b82013-08-08 10:28:59 +0000570 vassert(nBBPTRs == 0 || nBBPTRs == 1);
florian608e5602014-11-21 21:40:45 +0000571 vassert(nVECRETs == 0);
florian52af7bc2012-05-12 03:44:49 +0000572
sewardj74142b82013-08-08 10:28:59 +0000573 argreg = 0;
574
florian52af7bc2012-05-12 03:44:49 +0000575 /* Compute the function arguments into a temporary register each */
576 for (i = 0; i < n_args; i++) {
sewardj74142b82013-08-08 10:28:59 +0000577 IRExpr *arg = args[i];
florian608e5602014-11-21 21:40:45 +0000578 if (UNLIKELY(arg->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000579 /* If we need the guest state pointer put it in a temporary arg reg */
580 tmpregs[argreg] = newVRegI(env);
581 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
582 s390_hreg_guest_state_pointer()));
583 } else {
584 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
585 }
florian52af7bc2012-05-12 03:44:49 +0000586 argreg++;
587 }
588
sewardj2019a972011-03-07 16:04:07 +0000589 /* Compute the condition */
590 cc = S390_CC_ALWAYS;
591 if (guard) {
592 if (guard->tag == Iex_Const
593 && guard->Iex.Const.con->tag == Ico_U1
594 && guard->Iex.Const.con->Ico.U1 == True) {
595 /* unconditional -- do nothing */
596 } else {
597 cc = s390_isel_cc(env, guard);
598 }
599 }
600
florian52af7bc2012-05-12 03:44:49 +0000601 /* Move the args to the final register. It is paramount, that the
602 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000603 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000604 HReg finalreg;
605
606 finalreg = make_gpr(s390_gprno_from_arg_index(i));
607 size = sizeofIRType(Ity_I64);
608 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000609 }
610
611 target = Ptr_to_ULong(callee->addr);
612
sewardj74142b82013-08-08 10:28:59 +0000613 /* Do final checks, set the return values, and generate the call
614 instruction proper. */
615 vassert(*stackAdjustAfterCall == 0);
616 vassert(is_RetLoc_INVALID(*retloc));
617 switch (retTy) {
618 case Ity_INVALID:
619 /* Function doesn't return a value. */
620 *retloc = mk_RetLoc_simple(RLPri_None);
621 break;
622 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
623 *retloc = mk_RetLoc_simple(RLPri_Int);
624 break;
sewardj74142b82013-08-08 10:28:59 +0000625 default:
626 /* IR can denote other possible return types, but we don't
627 handle those here. */
florian608e5602014-11-21 21:40:45 +0000628 vex_printf("calling %s: return type is ", callee->name);
629 ppIRType(retTy);
630 vex_printf("; an integer type is required\n");
sewardj74142b82013-08-08 10:28:59 +0000631 vassert(0);
632 }
633
sewardj2019a972011-03-07 16:04:07 +0000634 /* Finally, the call itself. */
635 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
sewardj74142b82013-08-08 10:28:59 +0000636 callee->name, *retloc));
sewardj2019a972011-03-07 16:04:07 +0000637}
638
639
florian2c74d242012-09-12 19:38:42 +0000640/*---------------------------------------------------------*/
641/*--- BFP helper functions ---*/
642/*---------------------------------------------------------*/
643
644/* Set the BFP rounding mode in the FPC. This function is called for
645 all non-conversion BFP instructions as those will always get the
646 rounding mode from the FPC. */
647static void
648set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000649{
florian2c74d242012-09-12 19:38:42 +0000650 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
651
652 /* Do we need to do anything? */
653 if (env->previous_bfp_rounding_mode &&
654 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
655 irrm->tag == Iex_RdTmp &&
656 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
657 /* No - new mode is identical to previous mode. */
658 return;
659 }
660
661 /* No luck - we better set it, and remember what we set it to. */
662 env->previous_bfp_rounding_mode = irrm;
663
664 /* The incoming rounding mode is in VEX IR encoding. Need to change
665 to s390.
666
667 rounding mode | s390 | IR
668 -------------------------
669 to nearest | 00 | 00
670 to zero | 01 | 11
671 to +infinity | 10 | 10
672 to -infinity | 11 | 01
673
674 So: s390 = (4 - IR) & 3
675 */
676 HReg ir = s390_isel_int_expr(env, irrm);
677
678 HReg mode = newVRegI(env);
679
680 addInstr(env, s390_insn_load_immediate(4, mode, 4));
681 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
682 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
683
florian125e20d2012-10-07 15:42:37 +0000684 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000685}
686
687
688/* This function is invoked for insns that support a specification of
689 a rounding mode in the insn itself. In that case there is no need to
690 stick the rounding mode into the FPC -- a good thing. However, the
691 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000692static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000693get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
694{
695 if (irrm->tag == Iex_Const) { /* rounding mode is known */
696 vassert(irrm->Iex.Const.con->tag == Ico_U32);
697 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000698
699 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000700 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
701 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
702 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
703 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000704 default:
705 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000706 }
707 }
708
florian2c74d242012-09-12 19:38:42 +0000709 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000710 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000711}
712
713
florianc8e4f562012-10-27 16:19:31 +0000714/*---------------------------------------------------------*/
715/*--- DFP helper functions ---*/
716/*---------------------------------------------------------*/
717
718/* Set the DFP rounding mode in the FPC. This function is called for
719 all non-conversion DFP instructions as those will always get the
720 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000721static void
722set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
723{
724 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
725
726 /* Do we need to do anything? */
727 if (env->previous_dfp_rounding_mode &&
728 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
729 irrm->tag == Iex_RdTmp &&
730 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
731 /* No - new mode is identical to previous mode. */
732 return;
733 }
734
735 /* No luck - we better set it, and remember what we set it to. */
736 env->previous_dfp_rounding_mode = irrm;
737
738 /* The incoming rounding mode is in VEX IR encoding. Need to change
739 to s390.
740
741 rounding mode | S390 | IR
742 -----------------------------------------------
743 to nearest, ties to even | 000 | 000
744 to zero | 001 | 011
745 to +infinity | 010 | 010
746 to -infinity | 011 | 001
747 to nearest, ties away from 0 | 100 | 100
748 to nearest, ties toward 0 | 101 | 111
749 to away from 0 | 110 | 110
750 to prepare for shorter precision | 111 | 101
751
752 So: s390 = (IR ^ ((IR << 1) & 2))
753 */
754 HReg ir = s390_isel_int_expr(env, irrm);
755
756 HReg mode = newVRegI(env);
757
758 addInstr(env, s390_insn_move(4, mode, ir));
759 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
760 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
761 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
762
763 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
764}
765
766
767/* This function is invoked for insns that support a specification of
768 a rounding mode in the insn itself. In that case there is no need to
769 stick the rounding mode into the FPC -- a good thing. However, the
770 rounding mode must be known.
florianff9000d2013-02-08 20:22:03 +0000771
florian79e5a482013-06-06 19:12:46 +0000772 When mapping an Irrm_XYZ value to an S390_DFP_ROUND_ value there is
773 often a choice. For instance, Irrm_ZERO could be mapped to either
florianff9000d2013-02-08 20:22:03 +0000774 S390_DFP_ROUND_ZERO_5 or S390_DFP_ROUND_ZERO_9. The difference between
775 those two is that with S390_DFP_ROUND_ZERO_9 the recognition of the
776 quantum exception is suppressed whereas with S390_DFP_ROUND_ZERO_5 it
777 is not. As the quantum exception is not modelled we can choose either
778 value. The choice is to use S390_DFP_ROUND_.. values in the range [8:15],
779 because values in the range [1:7] have unpredictable rounding behaviour
780 when the floating point exception facility is not installed.
florianc8e4f562012-10-27 16:19:31 +0000781
782 Translation table of
783 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
784
florian79e5a482013-06-06 19:12:46 +0000785 s390(S390_DFP_ROUND_) | IR(Irrm_) | s390(S390_DFP_ROUND_)
florianc8e4f562012-10-27 16:19:31 +0000786 --------------------------------------------------------------------
florianff9000d2013-02-08 20:22:03 +0000787 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_12
florianc8e4f562012-10-27 16:19:31 +0000788 NEAREST_TIE_AWAY_0_12 | " | "
florianff9000d2013-02-08 20:22:03 +0000789 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_15
florianc8e4f562012-10-27 16:19:31 +0000790 PREPARE_SHORT_15 | " | "
florianff9000d2013-02-08 20:22:03 +0000791 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_8
florianc8e4f562012-10-27 16:19:31 +0000792 NEAREST_EVEN_8 | " | "
florianff9000d2013-02-08 20:22:03 +0000793 ZERO_5 | ZERO | ZERO_9
florianc8e4f562012-10-27 16:19:31 +0000794 ZERO_9 | " | "
florianff9000d2013-02-08 20:22:03 +0000795 POSINF_6 | PosINF | POSINF_10
florianc8e4f562012-10-27 16:19:31 +0000796 POSINF_10 | " | "
florianff9000d2013-02-08 20:22:03 +0000797 NEGINF_7 | NegINF | NEGINF_11
florianc8e4f562012-10-27 16:19:31 +0000798 NEGINF_11 | " | "
799 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
800 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
801*/
802static s390_dfp_round_t
803get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
804{
805 if (irrm->tag == Iex_Const) { /* rounding mode is known */
806 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian79e5a482013-06-06 19:12:46 +0000807 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000808
809 switch (mode) {
florian79e5a482013-06-06 19:12:46 +0000810 case Irrm_NEAREST:
florianff9000d2013-02-08 20:22:03 +0000811 return S390_DFP_ROUND_NEAREST_EVEN_8;
florian79e5a482013-06-06 19:12:46 +0000812 case Irrm_NegINF:
florianff9000d2013-02-08 20:22:03 +0000813 return S390_DFP_ROUND_NEGINF_11;
florian79e5a482013-06-06 19:12:46 +0000814 case Irrm_PosINF:
florianff9000d2013-02-08 20:22:03 +0000815 return S390_DFP_ROUND_POSINF_10;
florian79e5a482013-06-06 19:12:46 +0000816 case Irrm_ZERO:
florianff9000d2013-02-08 20:22:03 +0000817 return S390_DFP_ROUND_ZERO_9;
florian79e5a482013-06-06 19:12:46 +0000818 case Irrm_NEAREST_TIE_AWAY_0:
florianff9000d2013-02-08 20:22:03 +0000819 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12;
florian79e5a482013-06-06 19:12:46 +0000820 case Irrm_PREPARE_SHORTER:
florianff9000d2013-02-08 20:22:03 +0000821 return S390_DFP_ROUND_PREPARE_SHORT_15;
florian79e5a482013-06-06 19:12:46 +0000822 case Irrm_AWAY_FROM_ZERO:
florianc8e4f562012-10-27 16:19:31 +0000823 return S390_DFP_ROUND_AWAY_0;
florian79e5a482013-06-06 19:12:46 +0000824 case Irrm_NEAREST_TIE_TOWARD_0:
florianc8e4f562012-10-27 16:19:31 +0000825 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
826 default:
827 vpanic("get_dfp_rounding_mode");
828 }
829 }
830
831 set_dfp_rounding_mode_in_fpc(env, irrm);
832 return S390_DFP_ROUND_PER_FPC_0;
833}
florianc8e4f562012-10-27 16:19:31 +0000834
florian2d3d87f2012-12-21 21:05:17 +0000835
836/*---------------------------------------------------------*/
837/*--- Condition code helper functions ---*/
838/*---------------------------------------------------------*/
839
sewardj2019a972011-03-07 16:04:07 +0000840/* CC_S390 holds the condition code in s390 encoding. Convert it to
florian2d3d87f2012-12-21 21:05:17 +0000841 VEX encoding (IRCmpFResult)
sewardj2019a972011-03-07 16:04:07 +0000842
843 s390 VEX b6 b2 b0 cc.1 cc.0
844 0 0x40 EQ 1 0 0 0 0
845 1 0x01 LT 0 0 1 0 1
846 2 0x00 GT 0 0 0 1 0
847 3 0x45 Unordered 1 1 1 1 1
848
849 b0 = cc.0
850 b2 = cc.0 & cc.1
851 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
852
853 VEX = b0 | (b2 << 2) | (b6 << 6);
854*/
855static HReg
florian2d3d87f2012-12-21 21:05:17 +0000856convert_s390_to_vex_bfpcc(ISelEnv *env, HReg cc_s390)
sewardj2019a972011-03-07 16:04:07 +0000857{
858 HReg cc0, cc1, b2, b6, cc_vex;
859
860 cc0 = newVRegI(env);
861 addInstr(env, s390_insn_move(4, cc0, cc_s390));
862 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
863
864 cc1 = newVRegI(env);
865 addInstr(env, s390_insn_move(4, cc1, cc_s390));
866 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
867
868 b2 = newVRegI(env);
869 addInstr(env, s390_insn_move(4, b2, cc0));
870 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
871 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
872
873 b6 = newVRegI(env);
874 addInstr(env, s390_insn_move(4, b6, cc0));
875 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
876 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
877 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
878 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
879
880 cc_vex = newVRegI(env);
881 addInstr(env, s390_insn_move(4, cc_vex, cc0));
882 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
883 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
884
885 return cc_vex;
886}
887
florian2d3d87f2012-12-21 21:05:17 +0000888/* CC_S390 holds the condition code in s390 encoding. Convert it to
889 VEX encoding (IRCmpDResult) */
890static HReg
891convert_s390_to_vex_dfpcc(ISelEnv *env, HReg cc_s390)
892{
893 /* The encodings for IRCmpFResult and IRCmpDResult are the same/ */
894 return convert_s390_to_vex_bfpcc(env, cc_s390);
895}
896
sewardj2019a972011-03-07 16:04:07 +0000897
898/*---------------------------------------------------------*/
899/*--- ISEL: Integer expressions (128 bit) ---*/
900/*---------------------------------------------------------*/
901static void
902s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
903 IRExpr *expr)
904{
905 IRType ty = typeOfIRExpr(env->type_env, expr);
906
907 vassert(ty == Ity_I128);
908
909 /* No need to consider the following
910 - 128-bit constants (they do not exist in VEX)
911 - 128-bit loads from memory (will not be generated)
912 */
913
914 /* Read 128-bit IRTemp */
915 if (expr->tag == Iex_RdTmp) {
916 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
917 return;
918 }
919
920 if (expr->tag == Iex_Binop) {
921 IRExpr *arg1 = expr->Iex.Binop.arg1;
922 IRExpr *arg2 = expr->Iex.Binop.arg2;
923 Bool is_signed_multiply, is_signed_divide;
924
925 switch (expr->Iex.Binop.op) {
926 case Iop_MullU64:
927 is_signed_multiply = False;
928 goto do_multiply64;
929
930 case Iop_MullS64:
931 is_signed_multiply = True;
932 goto do_multiply64;
933
934 case Iop_DivModU128to64:
935 is_signed_divide = False;
936 goto do_divide64;
937
938 case Iop_DivModS128to64:
939 is_signed_divide = True;
940 goto do_divide64;
941
942 case Iop_64HLto128:
943 *dst_hi = s390_isel_int_expr(env, arg1);
944 *dst_lo = s390_isel_int_expr(env, arg2);
945 return;
946
947 case Iop_DivModS64to64: {
948 HReg r10, r11, h1;
949 s390_opnd_RMI op2;
950
951 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
952 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
953
954 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000955 r10 = make_gpr(10);
956 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000957
958 /* Move 1st operand into r11 and */
959 addInstr(env, s390_insn_move(8, r11, h1));
960
961 /* Divide */
962 addInstr(env, s390_insn_divs(8, r10, r11, op2));
963
964 /* The result is in registers r10 (remainder) and r11 (quotient).
965 Move the result into the reg pair that is being returned such
966 such that the low 64 bits are the quotient and the upper 64 bits
967 are the remainder. (see libvex_ir.h). */
968 *dst_hi = newVRegI(env);
969 *dst_lo = newVRegI(env);
970 addInstr(env, s390_insn_move(8, *dst_hi, r10));
971 addInstr(env, s390_insn_move(8, *dst_lo, r11));
972 return;
973 }
974
975 default:
976 break;
977
978 do_multiply64: {
979 HReg r10, r11, h1;
980 s390_opnd_RMI op2;
981
982 order_commutative_operands(arg1, arg2);
983
984 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
985 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
986
987 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000988 r10 = make_gpr(10);
989 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000990
991 /* Move the first operand to r11 */
992 addInstr(env, s390_insn_move(8, r11, h1));
993
994 /* Multiply */
995 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
996
997 /* The result is in registers r10 and r11. Assign to two virtual regs
998 and return. */
999 *dst_hi = newVRegI(env);
1000 *dst_lo = newVRegI(env);
1001 addInstr(env, s390_insn_move(8, *dst_hi, r10));
1002 addInstr(env, s390_insn_move(8, *dst_lo, r11));
1003 return;
1004 }
1005
1006 do_divide64: {
1007 HReg r10, r11, hi, lo;
1008 s390_opnd_RMI op2;
1009
1010 s390_isel_int128_expr(&hi, &lo, env, arg1);
1011 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1012
1013 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001014 r10 = make_gpr(10);
1015 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001016
1017 /* Move high 64 bits of the 1st operand into r10 and
1018 the low 64 bits into r11. */
1019 addInstr(env, s390_insn_move(8, r10, hi));
1020 addInstr(env, s390_insn_move(8, r11, lo));
1021
1022 /* Divide */
1023 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
1024
1025 /* The result is in registers r10 (remainder) and r11 (quotient).
1026 Move the result into the reg pair that is being returned such
1027 such that the low 64 bits are the quotient and the upper 64 bits
1028 are the remainder. (see libvex_ir.h). */
1029 *dst_hi = newVRegI(env);
1030 *dst_lo = newVRegI(env);
1031 addInstr(env, s390_insn_move(8, *dst_hi, r10));
1032 addInstr(env, s390_insn_move(8, *dst_lo, r11));
1033 return;
1034 }
1035 }
1036 }
1037
1038 vpanic("s390_isel_int128_expr");
1039}
1040
1041
1042/* Compute a 128-bit value into two 64-bit registers. These may be either
1043 real or virtual regs; in any case they must not be changed by subsequent
1044 code emitted by the caller. */
1045static void
1046s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1047{
1048 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
1049
1050 /* Sanity checks ... */
1051 vassert(hregIsVirtual(*dst_hi));
1052 vassert(hregIsVirtual(*dst_lo));
1053 vassert(hregClass(*dst_hi) == HRcInt64);
1054 vassert(hregClass(*dst_lo) == HRcInt64);
1055}
1056
1057
1058/*---------------------------------------------------------*/
1059/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
1060/*---------------------------------------------------------*/
1061
1062/* Select insns for an integer-typed expression, and add them to the
1063 code list. Return a reg holding the result. This reg will be a
1064 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
1065 want to modify it, ask for a new vreg, copy it in there, and modify
1066 the copy. The register allocator will do its best to map both
1067 vregs to the same real register, so the copies will often disappear
1068 later in the game.
1069
1070 This should handle expressions of 64, 32, 16 and 8-bit type.
1071 All results are returned in a 64bit register.
1072 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1073 are arbitrary, so you should mask or sign extend partial values
1074 if necessary.
1075*/
1076
1077/* DO NOT CALL THIS DIRECTLY ! */
1078static HReg
1079s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
1080{
1081 IRType ty = typeOfIRExpr(env->type_env, expr);
1082 UChar size;
florian6dc90242012-12-21 21:43:00 +00001083 s390_bfp_conv_t conv;
florian67a171c2013-01-20 03:08:04 +00001084 s390_dfp_conv_t dconv;
sewardj2019a972011-03-07 16:04:07 +00001085
1086 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
1087
1088 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
1089
1090 switch (expr->tag) {
1091
1092 /* --------- TEMP --------- */
1093 case Iex_RdTmp:
1094 /* Return the virtual register that holds the temporary. */
1095 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1096
1097 /* --------- LOAD --------- */
1098 case Iex_Load: {
1099 HReg dst = newVRegI(env);
1100 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1101
1102 if (expr->Iex.Load.end != Iend_BE)
1103 goto irreducible;
1104
1105 addInstr(env, s390_insn_load(size, dst, am));
1106
1107 return dst;
1108 }
1109
1110 /* --------- BINARY OP --------- */
1111 case Iex_Binop: {
1112 IRExpr *arg1 = expr->Iex.Binop.arg1;
1113 IRExpr *arg2 = expr->Iex.Binop.arg2;
1114 HReg h1, res;
1115 s390_alu_t opkind;
1116 s390_opnd_RMI op2, value, opnd;
1117 s390_insn *insn;
1118 Bool is_commutative, is_signed_multiply, is_signed_divide;
1119
1120 is_commutative = True;
1121
1122 switch (expr->Iex.Binop.op) {
1123 case Iop_MullU8:
1124 case Iop_MullU16:
1125 case Iop_MullU32:
1126 is_signed_multiply = False;
1127 goto do_multiply;
1128
1129 case Iop_MullS8:
1130 case Iop_MullS16:
1131 case Iop_MullS32:
1132 is_signed_multiply = True;
1133 goto do_multiply;
1134
1135 do_multiply: {
1136 HReg r10, r11;
1137 UInt arg_size = size / 2;
1138
1139 order_commutative_operands(arg1, arg2);
1140
1141 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1142 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1143
1144 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001145 r10 = make_gpr(10);
1146 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001147
1148 /* Move the first operand to r11 */
1149 addInstr(env, s390_insn_move(arg_size, r11, h1));
1150
1151 /* Multiply */
1152 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1153
1154 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1155 value into the destination register. */
1156 res = newVRegI(env);
1157 addInstr(env, s390_insn_move(arg_size, res, r10));
1158 value = s390_opnd_imm(arg_size * 8);
1159 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1160 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1161 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1162 opnd = s390_opnd_reg(r11);
1163 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1164 return res;
1165 }
1166
1167 case Iop_DivModS64to32:
1168 is_signed_divide = True;
1169 goto do_divide;
1170
1171 case Iop_DivModU64to32:
1172 is_signed_divide = False;
1173 goto do_divide;
1174
1175 do_divide: {
1176 HReg r10, r11;
1177
1178 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1179 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1180
1181 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001182 r10 = make_gpr(10);
1183 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001184
1185 /* Split the first operand and put the high 32 bits into r10 and
1186 the low 32 bits into r11. */
1187 addInstr(env, s390_insn_move(8, r10, h1));
1188 addInstr(env, s390_insn_move(8, r11, h1));
1189 value = s390_opnd_imm(32);
1190 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1191
1192 /* Divide */
1193 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1194
1195 /* The result is in registers r10 (remainder) and r11 (quotient).
1196 Combine them into a 64-bit value such that the low 32 bits are
1197 the quotient and the upper 32 bits are the remainder. (see
1198 libvex_ir.h). */
1199 res = newVRegI(env);
1200 addInstr(env, s390_insn_move(8, res, r10));
1201 value = s390_opnd_imm(32);
1202 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1203 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1204 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1205 opnd = s390_opnd_reg(r11);
1206 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1207 return res;
1208 }
1209
florian9fcff4c2012-09-10 03:09:04 +00001210 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1211 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1212 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1213 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1214 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1215 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1216 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1217 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1218 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1219 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1220 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1221 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
florian67a171c2013-01-20 03:08:04 +00001222
1223 case Iop_D64toI32S: dconv = S390_DFP_D64_TO_I32; goto do_convert_dfp;
floriana887acd2013-02-08 23:32:54 +00001224 case Iop_D64toI64S: dconv = S390_DFP_D64_TO_I64; goto do_convert_dfp;
florian67a171c2013-01-20 03:08:04 +00001225 case Iop_D64toI32U: dconv = S390_DFP_D64_TO_U32; goto do_convert_dfp;
1226 case Iop_D64toI64U: dconv = S390_DFP_D64_TO_U64; goto do_convert_dfp;
1227 case Iop_D128toI32S: dconv = S390_DFP_D128_TO_I32; goto do_convert_dfp128;
floriana887acd2013-02-08 23:32:54 +00001228 case Iop_D128toI64S: dconv = S390_DFP_D128_TO_I64; goto do_convert_dfp128;
florian67a171c2013-01-20 03:08:04 +00001229 case Iop_D128toI32U: dconv = S390_DFP_D128_TO_U32; goto do_convert_dfp128;
1230 case Iop_D128toI64U: dconv = S390_DFP_D128_TO_U64; goto do_convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00001231
1232 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001233 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001234
1235 res = newVRegI(env);
1236 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1237
florian2c74d242012-09-12 19:38:42 +00001238 rounding_mode = get_bfp_rounding_mode(env, arg1);
1239 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1240 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001241 return res;
1242 }
1243
1244 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001245 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001246 HReg op_hi, op_lo, f13, f15;
1247
1248 res = newVRegI(env);
1249 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1250
1251 /* We use non-virtual registers r13 and r15 as pair */
1252 f13 = make_fpr(13);
1253 f15 = make_fpr(15);
1254
1255 /* operand --> (f13, f15) */
1256 addInstr(env, s390_insn_move(8, f13, op_hi));
1257 addInstr(env, s390_insn_move(8, f15, op_lo));
1258
florian2c74d242012-09-12 19:38:42 +00001259 rounding_mode = get_bfp_rounding_mode(env, arg1);
floriana2039c52013-12-10 16:51:15 +00001260 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res,
1261 INVALID_HREG, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001262 rounding_mode));
1263 return res;
1264 }
1265
florian5f034622013-01-13 02:29:05 +00001266 do_convert_dfp: {
1267 s390_dfp_round_t rounding_mode;
1268
1269 res = newVRegI(env);
1270 h1 = s390_isel_dfp_expr(env, arg2); /* Process operand */
1271
1272 rounding_mode = get_dfp_rounding_mode(env, arg1);
florian67a171c2013-01-20 03:08:04 +00001273 addInstr(env, s390_insn_dfp_convert(size, dconv, res, h1,
florian5f034622013-01-13 02:29:05 +00001274 rounding_mode));
1275 return res;
1276 }
1277
1278 do_convert_dfp128: {
1279 s390_dfp_round_t rounding_mode;
1280 HReg op_hi, op_lo, f13, f15;
1281
1282 res = newVRegI(env);
1283 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1284
1285 /* We use non-virtual registers r13 and r15 as pair */
1286 f13 = make_fpr(13);
1287 f15 = make_fpr(15);
1288
1289 /* operand --> (f13, f15) */
1290 addInstr(env, s390_insn_move(8, f13, op_hi));
1291 addInstr(env, s390_insn_move(8, f15, op_lo));
1292
1293 rounding_mode = get_dfp_rounding_mode(env, arg1);
floriana2039c52013-12-10 16:51:15 +00001294 addInstr(env, s390_insn_dfp128_convert_from(size, dconv, res,
1295 INVALID_HREG, f13,
florian5f034622013-01-13 02:29:05 +00001296 f15, rounding_mode));
1297 return res;
1298 }
1299
sewardj2019a972011-03-07 16:04:07 +00001300 case Iop_8HLto16:
1301 case Iop_16HLto32:
1302 case Iop_32HLto64: {
1303 HReg h2;
1304 UInt arg_size = size / 2;
1305
1306 res = newVRegI(env);
1307 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1308 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1309
1310 addInstr(env, s390_insn_move(arg_size, res, h1));
1311 value = s390_opnd_imm(arg_size * 8);
1312 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1313 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1314 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1315 opnd = s390_opnd_reg(h2);
1316 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1317 return res;
1318 }
1319
1320 case Iop_Max32U: {
1321 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1322 res = newVRegI(env);
1323 h1 = s390_isel_int_expr(env, arg1);
1324 op2 = s390_isel_int_expr_RMI(env, arg2);
1325
1326 addInstr(env, s390_insn_move(size, res, h1));
1327 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1328 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1329 return res;
1330 }
1331
1332 case Iop_CmpF32:
1333 case Iop_CmpF64: {
1334 HReg cc_s390, h2;
1335
1336 h1 = s390_isel_float_expr(env, arg1);
1337 h2 = s390_isel_float_expr(env, arg2);
1338 cc_s390 = newVRegI(env);
1339
1340 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1341
1342 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1343
florian2d3d87f2012-12-21 21:05:17 +00001344 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001345 }
1346
1347 case Iop_CmpF128: {
1348 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1349
1350 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1351 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1352 cc_s390 = newVRegI(env);
1353
1354 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1355 f12 = make_fpr(12);
1356 f13 = make_fpr(13);
1357 f14 = make_fpr(14);
1358 f15 = make_fpr(15);
1359
1360 /* 1st operand --> (f12, f14) */
1361 addInstr(env, s390_insn_move(8, f12, op1_hi));
1362 addInstr(env, s390_insn_move(8, f14, op1_lo));
1363
1364 /* 2nd operand --> (f13, f15) */
1365 addInstr(env, s390_insn_move(8, f13, op2_hi));
1366 addInstr(env, s390_insn_move(8, f15, op2_lo));
1367
1368 res = newVRegI(env);
1369 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1370
florian2d3d87f2012-12-21 21:05:17 +00001371 return convert_s390_to_vex_bfpcc(env, cc_s390);
sewardj2019a972011-03-07 16:04:07 +00001372 }
1373
florian20c6bca2012-12-26 17:47:19 +00001374 case Iop_CmpD64:
1375 case Iop_CmpExpD64: {
floriane38f6412012-12-21 17:32:12 +00001376 HReg cc_s390, h2;
florian20c6bca2012-12-26 17:47:19 +00001377 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001378
1379 h1 = s390_isel_dfp_expr(env, arg1);
1380 h2 = s390_isel_dfp_expr(env, arg2);
1381 cc_s390 = newVRegI(env);
floriane38f6412012-12-21 17:32:12 +00001382
florian20c6bca2012-12-26 17:47:19 +00001383 switch(expr->Iex.Binop.op) {
1384 case Iop_CmpD64: cmp = S390_DFP_COMPARE; break;
1385 case Iop_CmpExpD64: cmp = S390_DFP_COMPARE_EXP; break;
1386 default: goto irreducible;
1387 }
1388 addInstr(env, s390_insn_dfp_compare(8, cmp, cc_s390, h1, h2));
floriane38f6412012-12-21 17:32:12 +00001389
florian2d3d87f2012-12-21 21:05:17 +00001390 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001391 }
1392
florian20c6bca2012-12-26 17:47:19 +00001393 case Iop_CmpD128:
1394 case Iop_CmpExpD128: {
floriane38f6412012-12-21 17:32:12 +00001395 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
florian20c6bca2012-12-26 17:47:19 +00001396 s390_dfp_cmp_t cmp;
floriane38f6412012-12-21 17:32:12 +00001397
1398 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1399 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1400 cc_s390 = newVRegI(env);
1401
1402 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1403 f12 = make_fpr(12);
1404 f13 = make_fpr(13);
1405 f14 = make_fpr(14);
1406 f15 = make_fpr(15);
1407
1408 /* 1st operand --> (f12, f14) */
1409 addInstr(env, s390_insn_move(8, f12, op1_hi));
1410 addInstr(env, s390_insn_move(8, f14, op1_lo));
1411
1412 /* 2nd operand --> (f13, f15) */
1413 addInstr(env, s390_insn_move(8, f13, op2_hi));
1414 addInstr(env, s390_insn_move(8, f15, op2_lo));
1415
florian20c6bca2012-12-26 17:47:19 +00001416 switch(expr->Iex.Binop.op) {
1417 case Iop_CmpD128: cmp = S390_DFP_COMPARE; break;
1418 case Iop_CmpExpD128: cmp = S390_DFP_COMPARE_EXP; break;
1419 default: goto irreducible;
1420 }
1421 addInstr(env, s390_insn_dfp128_compare(16, cmp, cc_s390, f12, f14,
1422 f13, f15));
floriane38f6412012-12-21 17:32:12 +00001423
florian2d3d87f2012-12-21 21:05:17 +00001424 return convert_s390_to_vex_dfpcc(env, cc_s390);
floriane38f6412012-12-21 17:32:12 +00001425 }
1426
sewardj2019a972011-03-07 16:04:07 +00001427 case Iop_Add8:
1428 case Iop_Add16:
1429 case Iop_Add32:
1430 case Iop_Add64:
1431 opkind = S390_ALU_ADD;
1432 break;
1433
1434 case Iop_Sub8:
1435 case Iop_Sub16:
1436 case Iop_Sub32:
1437 case Iop_Sub64:
1438 opkind = S390_ALU_SUB;
1439 is_commutative = False;
1440 break;
1441
1442 case Iop_And8:
1443 case Iop_And16:
1444 case Iop_And32:
1445 case Iop_And64:
1446 opkind = S390_ALU_AND;
1447 break;
1448
1449 case Iop_Or8:
1450 case Iop_Or16:
1451 case Iop_Or32:
1452 case Iop_Or64:
1453 opkind = S390_ALU_OR;
1454 break;
1455
1456 case Iop_Xor8:
1457 case Iop_Xor16:
1458 case Iop_Xor32:
1459 case Iop_Xor64:
1460 opkind = S390_ALU_XOR;
1461 break;
1462
1463 case Iop_Shl8:
1464 case Iop_Shl16:
1465 case Iop_Shl32:
1466 case Iop_Shl64:
1467 opkind = S390_ALU_LSH;
1468 is_commutative = False;
1469 break;
1470
1471 case Iop_Shr8:
1472 case Iop_Shr16:
1473 case Iop_Shr32:
1474 case Iop_Shr64:
1475 opkind = S390_ALU_RSH;
1476 is_commutative = False;
1477 break;
1478
1479 case Iop_Sar8:
1480 case Iop_Sar16:
1481 case Iop_Sar32:
1482 case Iop_Sar64:
1483 opkind = S390_ALU_RSHA;
1484 is_commutative = False;
1485 break;
1486
1487 default:
1488 goto irreducible;
1489 }
1490
1491 /* Pattern match: 0 - arg1 --> -arg1 */
1492 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1493 res = newVRegI(env);
1494 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1495 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1496 addInstr(env, insn);
1497
1498 return res;
1499 }
1500
1501 if (is_commutative) {
1502 order_commutative_operands(arg1, arg2);
1503 }
1504
1505 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1506 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1507 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001508
1509 /* As right shifts of one/two byte opreands are implemented using a
1510 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1511 switch (expr->Iex.Binop.op) {
1512 case Iop_Shr8:
1513 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1514 break;
1515 case Iop_Shr16:
1516 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1517 break;
1518 case Iop_Sar8:
1519 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1520 break;
1521 case Iop_Sar16:
1522 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1523 break;
1524 default:
1525 insn = s390_insn_move(size, res, h1);
1526 break;
1527 }
1528 addInstr(env, insn);
1529
sewardj2019a972011-03-07 16:04:07 +00001530 insn = s390_insn_alu(size, opkind, res, op2);
1531
1532 addInstr(env, insn);
1533
1534 return res;
1535 }
1536
1537 /* --------- UNARY OP --------- */
1538 case Iex_Unop: {
1539 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1540 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1541 s390_opnd_RMI opnd;
1542 s390_insn *insn;
1543 IRExpr *arg;
1544 HReg dst, h1;
1545 IROp unop, binop;
1546
1547 arg = expr->Iex.Unop.arg;
1548
1549 /* Special cases are handled here */
1550
1551 /* 32-bit multiply with 32-bit result or
1552 64-bit multiply with 64-bit result */
1553 unop = expr->Iex.Unop.op;
1554 binop = arg->Iex.Binop.op;
1555
1556 if ((arg->tag == Iex_Binop &&
1557 ((unop == Iop_64to32 &&
1558 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1559 (unop == Iop_128to64 &&
1560 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1561 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1562 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1563 dst = newVRegI(env); /* Result goes into a new register */
1564 addInstr(env, s390_insn_move(size, dst, h1));
1565 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1566
1567 return dst;
1568 }
1569
florian4d71a082011-12-18 00:08:17 +00001570 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001571 dst = newVRegI(env);
1572 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1573 addInstr(env, s390_insn_move(size, dst, h1));
1574
1575 return dst;
1576 }
1577
floriane38f6412012-12-21 17:32:12 +00001578 if (unop == Iop_ReinterpD64asI64) {
1579 dst = newVRegI(env);
1580 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
1581 addInstr(env, s390_insn_move(size, dst, h1));
1582
1583 return dst;
1584 }
1585
florian5c539732013-02-14 14:27:12 +00001586 if (unop == Iop_ExtractExpD64 || unop == Iop_ExtractSigD64) {
1587 s390_dfp_unop_t dfpop;
1588 switch(unop) {
1589 case Iop_ExtractExpD64: dfpop = S390_DFP_EXTRACT_EXP_D64; break;
1590 case Iop_ExtractSigD64: dfpop = S390_DFP_EXTRACT_SIG_D64; break;
1591 default: goto irreducible;
1592 }
floriance9e3db2012-12-27 20:14:03 +00001593 dst = newVRegI(env);
1594 h1 = s390_isel_dfp_expr(env, arg); /* Process the operand */
florian5c539732013-02-14 14:27:12 +00001595 addInstr(env, s390_insn_dfp_unop(size, dfpop, dst, h1));
floriance9e3db2012-12-27 20:14:03 +00001596 return dst;
1597 }
1598
florian5c539732013-02-14 14:27:12 +00001599 if (unop == Iop_ExtractExpD128 || unop == Iop_ExtractSigD128) {
1600 s390_dfp_unop_t dfpop;
floriance9e3db2012-12-27 20:14:03 +00001601 HReg op_hi, op_lo, f13, f15;
florian5c539732013-02-14 14:27:12 +00001602
1603 switch(unop) {
1604 case Iop_ExtractExpD128: dfpop = S390_DFP_EXTRACT_EXP_D128; break;
1605 case Iop_ExtractSigD128: dfpop = S390_DFP_EXTRACT_SIG_D128; break;
1606 default: goto irreducible;
1607 }
floriance9e3db2012-12-27 20:14:03 +00001608 dst = newVRegI(env);
1609 s390_isel_dfp128_expr(&op_hi, &op_lo, env, arg); /* Process operand */
1610
1611 /* We use non-virtual registers r13 and r15 as pair */
1612 f13 = make_fpr(13);
1613 f15 = make_fpr(15);
1614
1615 /* operand --> (f13, f15) */
1616 addInstr(env, s390_insn_move(8, f13, op_hi));
1617 addInstr(env, s390_insn_move(8, f15, op_lo));
1618
florian5c539732013-02-14 14:27:12 +00001619 addInstr(env, s390_insn_dfp128_unop(size, dfpop, dst, f13, f15));
floriance9e3db2012-12-27 20:14:03 +00001620 return dst;
1621 }
1622
sewardj2019a972011-03-07 16:04:07 +00001623 /* Expressions whose argument is 1-bit wide */
1624 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1625 s390_cc_t cond = s390_isel_cc(env, arg);
1626 dst = newVRegI(env); /* Result goes into a new register */
1627 addInstr(env, s390_insn_cc2bool(dst, cond));
1628
1629 switch (unop) {
1630 case Iop_1Uto8:
1631 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001632 /* Zero extend */
1633 mask.variant.imm = 1;
1634 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1635 break;
1636
sewardj2019a972011-03-07 16:04:07 +00001637 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001638 /* Zero extend */
1639 mask.variant.imm = 1;
1640 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001641 break;
1642
1643 case Iop_1Sto8:
1644 case Iop_1Sto16:
1645 case Iop_1Sto32:
1646 shift.variant.imm = 31;
1647 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1648 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1649 break;
1650
1651 case Iop_1Sto64:
1652 shift.variant.imm = 63;
1653 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1654 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1655 break;
1656
1657 default:
1658 goto irreducible;
1659 }
1660
1661 return dst;
1662 }
1663
1664 /* Regular processing */
1665
1666 if (unop == Iop_128to64) {
1667 HReg dst_hi, dst_lo;
1668
1669 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1670 return dst_lo;
1671 }
1672
1673 if (unop == Iop_128HIto64) {
1674 HReg dst_hi, dst_lo;
1675
1676 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1677 return dst_hi;
1678 }
1679
1680 dst = newVRegI(env); /* Result goes into a new register */
1681 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1682
1683 switch (unop) {
1684 case Iop_8Uto16:
1685 case Iop_8Uto32:
1686 case Iop_8Uto64:
1687 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1688 break;
1689
1690 case Iop_16Uto32:
1691 case Iop_16Uto64:
1692 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1693 break;
1694
1695 case Iop_32Uto64:
1696 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1697 break;
1698
1699 case Iop_8Sto16:
1700 case Iop_8Sto32:
1701 case Iop_8Sto64:
1702 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1703 break;
1704
1705 case Iop_16Sto32:
1706 case Iop_16Sto64:
1707 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1708 break;
1709
1710 case Iop_32Sto64:
1711 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1712 break;
1713
1714 case Iop_64to8:
1715 case Iop_64to16:
1716 case Iop_64to32:
1717 case Iop_32to8:
1718 case Iop_32to16:
1719 case Iop_16to8:
1720 /* Down-casts are no-ops. Upstream operations will only look at
1721 the bytes that make up the result of the down-cast. So there
1722 is no point setting the other bytes to 0. */
1723 insn = s390_opnd_copy(8, dst, opnd);
1724 break;
1725
1726 case Iop_64HIto32:
1727 addInstr(env, s390_opnd_copy(8, dst, opnd));
1728 shift.variant.imm = 32;
1729 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1730 break;
1731
1732 case Iop_32HIto16:
1733 addInstr(env, s390_opnd_copy(4, dst, opnd));
1734 shift.variant.imm = 16;
1735 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1736 break;
1737
1738 case Iop_16HIto8:
1739 addInstr(env, s390_opnd_copy(2, dst, opnd));
1740 shift.variant.imm = 8;
1741 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1742 break;
1743
1744 case Iop_Not8:
1745 case Iop_Not16:
1746 case Iop_Not32:
1747 case Iop_Not64:
1748 /* XOR with ffff... */
1749 mask.variant.imm = ~(ULong)0;
1750 addInstr(env, s390_opnd_copy(size, dst, opnd));
1751 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1752 break;
1753
1754 case Iop_Left8:
1755 case Iop_Left16:
1756 case Iop_Left32:
1757 case Iop_Left64:
1758 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1759 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1760 break;
1761
1762 case Iop_CmpwNEZ32:
1763 case Iop_CmpwNEZ64: {
1764 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1765 or -X will have a 1 in the MSB. */
1766 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1767 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1768 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1769 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1770 return dst;
1771 }
1772
1773 case Iop_Clz64: {
1774 HReg r10, r11;
1775
sewardj611b06e2011-03-24 08:57:29 +00001776 /* This will be implemented using FLOGR, if possible. So we need to
1777 set aside a pair of non-virtual registers. The result (number of
1778 left-most zero bits) will be in r10. The value in r11 is unspecified
1779 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001780 r10 = make_gpr(10);
1781 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001782
sewardj611b06e2011-03-24 08:57:29 +00001783 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001784 addInstr(env, s390_insn_move(8, dst, r10));
1785 return dst;
1786 }
1787
1788 default:
1789 goto irreducible;
1790 }
1791
1792 addInstr(env, insn);
1793
1794 return dst;
1795 }
1796
1797 /* --------- GET --------- */
1798 case Iex_Get: {
1799 HReg dst = newVRegI(env);
1800 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1801
1802 /* We never load more than 8 bytes from the guest state, because the
1803 floating point register pair is not contiguous. */
1804 vassert(size <= 8);
1805
1806 addInstr(env, s390_insn_load(size, dst, am));
1807
1808 return dst;
1809 }
1810
1811 case Iex_GetI:
1812 /* not needed */
1813 break;
1814
1815 /* --------- CCALL --------- */
1816 case Iex_CCall: {
1817 HReg dst = newVRegI(env);
sewardj74142b82013-08-08 10:28:59 +00001818 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
1819 UInt addToSp = 0;
1820 RetLoc rloc = mk_RetLoc_INVALID();
sewardj2019a972011-03-07 16:04:07 +00001821
sewardj74142b82013-08-08 10:28:59 +00001822 doHelperCall(&addToSp, &rloc, env, NULL, expr->Iex.CCall.cee,
1823 expr->Iex.CCall.retty, expr->Iex.CCall.args);
1824 vassert(is_sane_RetLoc(rloc));
1825 vassert(rloc.pri == RLPri_Int);
1826 vassert(addToSp == 0);
1827 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
1828
sewardj2019a972011-03-07 16:04:07 +00001829 return dst;
1830 }
1831
1832 /* --------- LITERAL --------- */
1833
1834 /* Load a literal into a register. Create a "load immediate"
1835 v-insn and return the register. */
1836 case Iex_Const: {
1837 ULong value;
1838 HReg dst = newVRegI(env);
1839 const IRConst *con = expr->Iex.Const.con;
1840
1841 /* Bitwise copy of the value. No sign/zero-extension */
1842 switch (con->tag) {
1843 case Ico_U64: value = con->Ico.U64; break;
1844 case Ico_U32: value = con->Ico.U32; break;
1845 case Ico_U16: value = con->Ico.U16; break;
1846 case Ico_U8: value = con->Ico.U8; break;
1847 default: vpanic("s390_isel_int_expr: invalid constant");
1848 }
1849
1850 addInstr(env, s390_insn_load_immediate(size, dst, value));
1851
1852 return dst;
1853 }
1854
1855 /* --------- MULTIPLEX --------- */
florian99dd03e2013-01-29 03:56:06 +00001856 case Iex_ITE: {
sewardj2019a972011-03-07 16:04:07 +00001857 IRExpr *cond_expr;
florian99dd03e2013-01-29 03:56:06 +00001858 HReg dst, r1;
sewardj009230b2013-01-26 11:47:55 +00001859 s390_opnd_RMI r0;
sewardj2019a972011-03-07 16:04:07 +00001860
florian99dd03e2013-01-29 03:56:06 +00001861 cond_expr = expr->Iex.ITE.cond;
sewardj2019a972011-03-07 16:04:07 +00001862
sewardj009230b2013-01-26 11:47:55 +00001863 vassert(typeOfIRExpr(env->type_env, cond_expr) == Ity_I1);
1864
sewardj2019a972011-03-07 16:04:07 +00001865 dst = newVRegI(env);
florian99dd03e2013-01-29 03:56:06 +00001866 r0 = s390_isel_int_expr_RMI(env, expr->Iex.ITE.iffalse);
1867 r1 = s390_isel_int_expr(env, expr->Iex.ITE.iftrue);
1868 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.ITE.iftrue));
sewardj2019a972011-03-07 16:04:07 +00001869
sewardj009230b2013-01-26 11:47:55 +00001870 s390_cc_t cc = s390_isel_cc(env, cond_expr);
sewardj2019a972011-03-07 16:04:07 +00001871
florian99dd03e2013-01-29 03:56:06 +00001872 addInstr(env, s390_insn_move(size, dst, r1));
sewardj009230b2013-01-26 11:47:55 +00001873 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
sewardj2019a972011-03-07 16:04:07 +00001874 return dst;
1875 }
1876
1877 default:
1878 break;
1879 }
1880
1881 /* We get here if no pattern matched. */
1882 irreducible:
1883 ppIRExpr(expr);
1884 vpanic("s390_isel_int_expr: cannot reduce tree");
1885}
1886
1887
1888static HReg
1889s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1890{
1891 HReg dst = s390_isel_int_expr_wrk(env, expr);
1892
1893 /* Sanity checks ... */
1894 vassert(hregClass(dst) == HRcInt64);
1895 vassert(hregIsVirtual(dst));
1896
1897 return dst;
1898}
1899
1900
1901static s390_opnd_RMI
1902s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1903{
1904 IRType ty = typeOfIRExpr(env->type_env, expr);
1905 s390_opnd_RMI dst;
1906
1907 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1908 ty == Ity_I64);
1909
1910 if (expr->tag == Iex_Load) {
1911 dst.tag = S390_OPND_AMODE;
1912 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1913 } else if (expr->tag == Iex_Get) {
1914 dst.tag = S390_OPND_AMODE;
1915 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1916 } else if (expr->tag == Iex_Const) {
1917 ULong value;
1918
1919 /* The bit pattern for the value will be stored as is in the least
1920 significant bits of VALUE. */
1921 switch (expr->Iex.Const.con->tag) {
1922 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1923 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1924 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1925 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1926 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1927 default:
1928 vpanic("s390_isel_int_expr_RMI");
1929 }
1930
1931 dst.tag = S390_OPND_IMMEDIATE;
1932 dst.variant.imm = value;
1933 } else {
1934 dst.tag = S390_OPND_REG;
1935 dst.variant.reg = s390_isel_int_expr(env, expr);
1936 }
1937
1938 return dst;
1939}
1940
1941
1942/*---------------------------------------------------------*/
1943/*--- ISEL: Floating point expressions (128 bit) ---*/
1944/*---------------------------------------------------------*/
1945static void
1946s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1947 IRExpr *expr)
1948{
1949 IRType ty = typeOfIRExpr(env->type_env, expr);
1950
1951 vassert(ty == Ity_F128);
1952
sewardj2019a972011-03-07 16:04:07 +00001953 switch (expr->tag) {
1954 case Iex_RdTmp:
1955 /* Return the virtual registers that hold the temporary. */
1956 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1957 return;
1958
1959 /* --------- LOAD --------- */
1960 case Iex_Load: {
1961 IRExpr *addr_hi, *addr_lo;
1962 s390_amode *am_hi, *am_lo;
1963
1964 if (expr->Iex.Load.end != Iend_BE)
1965 goto irreducible;
1966
1967 addr_hi = expr->Iex.Load.addr;
1968 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1969
1970 am_hi = s390_isel_amode(env, addr_hi);
1971 am_lo = s390_isel_amode(env, addr_lo);
1972
1973 *dst_hi = newVRegF(env);
1974 *dst_lo = newVRegF(env);
1975 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1976 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1977 return;
1978 }
1979
1980
1981 /* --------- GET --------- */
1982 case Iex_Get:
1983 /* This is not supported because loading 128-bit from the guest
1984 state is almost certainly wrong. Use get_fpr_pair instead. */
1985 vpanic("Iex_Get with F128 data");
1986
1987 /* --------- 4-ary OP --------- */
1988 case Iex_Qop:
1989 vpanic("Iex_Qop with F128 data");
1990
1991 /* --------- TERNARY OP --------- */
1992 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001993 IRTriop *triop = expr->Iex.Triop.details;
1994 IROp op = triop->op;
1995 IRExpr *left = triop->arg2;
1996 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001997 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001998 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1999
2000 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
2001 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
2002
2003 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2004 f12 = make_fpr(12);
2005 f13 = make_fpr(13);
2006 f14 = make_fpr(14);
2007 f15 = make_fpr(15);
2008
2009 /* 1st operand --> (f12, f14) */
2010 addInstr(env, s390_insn_move(8, f12, op1_hi));
2011 addInstr(env, s390_insn_move(8, f14, op1_lo));
2012
2013 /* 2nd operand --> (f13, f15) */
2014 addInstr(env, s390_insn_move(8, f13, op2_hi));
2015 addInstr(env, s390_insn_move(8, f15, op2_lo));
2016
2017 switch (op) {
2018 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
2019 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
2020 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
2021 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
2022 default:
2023 goto irreducible;
2024 }
2025
florian2c74d242012-09-12 19:38:42 +00002026 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2027 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002028
2029 /* Move result to virtual destination register */
2030 *dst_hi = newVRegF(env);
2031 *dst_lo = newVRegF(env);
2032 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2033 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2034
2035 return;
2036 }
2037
2038 /* --------- BINARY OP --------- */
2039 case Iex_Binop: {
sewardj2019a972011-03-07 16:04:07 +00002040 switch (expr->Iex.Binop.op) {
florian78d5ef72013-05-11 15:02:58 +00002041 case Iop_SqrtF128: {
2042 HReg op_hi, op_lo, f12, f13, f14, f15;
2043
2044 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2045 f12 = make_fpr(12);
2046 f13 = make_fpr(13);
2047 f14 = make_fpr(14);
2048 f15 = make_fpr(15);
2049
sewardj2019a972011-03-07 16:04:07 +00002050 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
2051
2052 /* operand --> (f13, f15) */
2053 addInstr(env, s390_insn_move(8, f13, op_hi));
2054 addInstr(env, s390_insn_move(8, f15, op_lo));
2055
florian2c74d242012-09-12 19:38:42 +00002056 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
2057 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
2058 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002059
2060 /* Move result to virtual destination registers */
2061 *dst_hi = newVRegF(env);
2062 *dst_lo = newVRegF(env);
2063 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2064 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2065 return;
florian78d5ef72013-05-11 15:02:58 +00002066 }
sewardj2019a972011-03-07 16:04:07 +00002067
2068 case Iop_F64HLtoF128:
2069 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
2070 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
2071 return;
2072
florian7ab421d2013-06-17 21:03:56 +00002073 case Iop_D32toF128:
2074 case Iop_D64toF128: {
2075 IRExpr *irrm;
2076 IRExpr *left;
2077 s390_dfp_round_t rm;
2078 HReg h1; /* virtual reg. to hold source */
2079 HReg f0, f2, f4, r1; /* real registers used by PFPO */
2080 s390_fp_conv_t fpconv;
2081
2082 switch (expr->Iex.Binop.op) {
2083 case Iop_D32toF128:
2084 fpconv = S390_FP_D32_TO_F128;
2085 break;
2086 case Iop_D64toF128:
2087 fpconv = S390_FP_D64_TO_F128;
2088 break;
2089 default: goto irreducible;
2090 }
2091
2092 f4 = make_fpr(4); /* source */
2093 f0 = make_fpr(0); /* destination */
2094 f2 = make_fpr(2); /* destination */
2095 r1 = make_gpr(1); /* GPR #1 clobbered */
2096 irrm = expr->Iex.Binop.arg1;
2097 left = expr->Iex.Binop.arg2;
2098 rm = get_dfp_rounding_mode(env, irrm);
2099 h1 = s390_isel_dfp_expr(env, left);
2100 addInstr(env, s390_insn_move(8, f4, h1));
2101 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
2102 f4, INVALID_HREG, r1, rm));
2103 /* (f0, f2) --> destination */
2104 *dst_hi = newVRegF(env);
2105 *dst_lo = newVRegF(env);
2106 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2107 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2108
2109 return;
2110 }
2111
florian78d5ef72013-05-11 15:02:58 +00002112 case Iop_D128toF128: {
2113 IRExpr *irrm;
2114 IRExpr *left;
2115 s390_dfp_round_t rm;
2116 HReg op_hi, op_lo;
2117 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2118
2119 f4 = make_fpr(4); /* source */
2120 f6 = make_fpr(6); /* source */
2121 f0 = make_fpr(0); /* destination */
2122 f2 = make_fpr(2); /* destination */
2123 r1 = make_gpr(1); /* GPR #1 clobbered */
2124
2125 irrm = expr->Iex.Binop.arg1;
2126 left = expr->Iex.Binop.arg2;
2127 rm = get_dfp_rounding_mode(env, irrm);
2128 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2129 /* operand --> (f4, f6) */
2130 addInstr(env, s390_insn_move(8, f4, op_hi));
2131 addInstr(env, s390_insn_move(8, f6, op_lo));
2132 addInstr(env, s390_insn_fp128_convert(16, S390_FP_D128_TO_F128, f0, f2,
2133 f4, f6, r1, rm));
2134 /* (f0, f2) --> destination */
2135 *dst_hi = newVRegF(env);
2136 *dst_lo = newVRegF(env);
2137 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2138 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2139
2140 return;
2141 }
2142
sewardj2019a972011-03-07 16:04:07 +00002143 default:
2144 goto irreducible;
2145 }
2146 }
2147
2148 /* --------- UNARY OP --------- */
2149 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00002150 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00002151 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002152 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002153 HReg op_hi, op_lo, op, f12, f13, f14, f15;
2154
2155 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2156 f12 = make_fpr(12);
2157 f13 = make_fpr(13);
2158 f14 = make_fpr(14);
2159 f15 = make_fpr(15);
2160
florian66e596d2012-09-07 15:00:53 +00002161 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00002162 case Iop_NegF128:
2163 if (left->tag == Iex_Unop &&
2164 (left->Iex.Unop.op == Iop_AbsF32 ||
2165 left->Iex.Unop.op == Iop_AbsF64))
2166 bfpop = S390_BFP_NABS;
2167 else
2168 bfpop = S390_BFP_NEG;
2169 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00002170 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
2171 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
2172 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
2173 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
2174 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
2175 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
2176 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00002177 default:
2178 goto irreducible;
2179 }
2180
2181 float128_opnd:
2182 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2183
2184 /* operand --> (f13, f15) */
2185 addInstr(env, s390_insn_move(8, f13, op_hi));
2186 addInstr(env, s390_insn_move(8, f15, op_lo));
2187
florian2c74d242012-09-12 19:38:42 +00002188 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00002189 goto move_dst;
2190
2191 convert_float:
2192 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002193 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002194 goto move_dst;
2195
2196 convert_int:
2197 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00002198 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00002199 goto move_dst;
2200
2201 move_dst:
2202 /* Move result to virtual destination registers */
2203 *dst_hi = newVRegF(env);
2204 *dst_lo = newVRegF(env);
2205 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2206 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2207 return;
2208 }
2209
2210 default:
2211 goto irreducible;
2212 }
2213
2214 /* We get here if no pattern matched. */
2215 irreducible:
2216 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00002217 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00002218}
2219
2220/* Compute a 128-bit value into two 64-bit registers. These may be either
2221 real or virtual regs; in any case they must not be changed by subsequent
2222 code emitted by the caller. */
2223static void
2224s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2225{
2226 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
2227
2228 /* Sanity checks ... */
2229 vassert(hregIsVirtual(*dst_hi));
2230 vassert(hregIsVirtual(*dst_lo));
2231 vassert(hregClass(*dst_hi) == HRcFlt64);
2232 vassert(hregClass(*dst_lo) == HRcFlt64);
2233}
2234
2235
2236/*---------------------------------------------------------*/
2237/*--- ISEL: Floating point expressions (64 bit) ---*/
2238/*---------------------------------------------------------*/
2239
2240static HReg
2241s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
2242{
2243 IRType ty = typeOfIRExpr(env->type_env, expr);
2244 UChar size;
2245
2246 vassert(ty == Ity_F32 || ty == Ity_F64);
2247
2248 size = sizeofIRType(ty);
2249
2250 switch (expr->tag) {
2251 case Iex_RdTmp:
2252 /* Return the virtual register that holds the temporary. */
2253 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2254
2255 /* --------- LOAD --------- */
2256 case Iex_Load: {
2257 HReg dst = newVRegF(env);
2258 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2259
2260 if (expr->Iex.Load.end != Iend_BE)
2261 goto irreducible;
2262
2263 addInstr(env, s390_insn_load(size, dst, am));
2264
2265 return dst;
2266 }
2267
2268 /* --------- GET --------- */
2269 case Iex_Get: {
2270 HReg dst = newVRegF(env);
2271 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2272
2273 addInstr(env, s390_insn_load(size, dst, am));
2274
2275 return dst;
2276 }
2277
2278 /* --------- LITERAL --------- */
2279
2280 /* Load a literal into a register. Create a "load immediate"
2281 v-insn and return the register. */
2282 case Iex_Const: {
2283 ULong value;
2284 HReg dst = newVRegF(env);
2285 const IRConst *con = expr->Iex.Const.con;
2286
2287 /* Bitwise copy of the value. No sign/zero-extension */
2288 switch (con->tag) {
2289 case Ico_F32i: value = con->Ico.F32i; break;
2290 case Ico_F64i: value = con->Ico.F64i; break;
2291 default: vpanic("s390_isel_float_expr: invalid constant");
2292 }
2293
2294 if (value != 0) vpanic("cannot load immediate floating point constant");
2295
2296 addInstr(env, s390_insn_load_immediate(size, dst, value));
2297
2298 return dst;
2299 }
2300
2301 /* --------- 4-ary OP --------- */
2302 case Iex_Qop: {
2303 HReg op1, op2, op3, dst;
2304 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002305
florian5906a6b2012-10-16 02:53:33 +00002306 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00002307 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00002308 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00002309 dst = newVRegF(env);
2310 addInstr(env, s390_insn_move(size, dst, op1));
2311
florian96d7cc32012-06-01 20:41:24 +00002312 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00002313 case Iop_MAddF32:
2314 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2315 case Iop_MSubF32:
2316 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2317
2318 default:
2319 goto irreducible;
2320 }
2321
florian2c74d242012-09-12 19:38:42 +00002322 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2323 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002324 return dst;
2325 }
2326
2327 /* --------- TERNARY OP --------- */
2328 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002329 IRTriop *triop = expr->Iex.Triop.details;
2330 IROp op = triop->op;
2331 IRExpr *left = triop->arg2;
2332 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002333 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002334 HReg h1, op2, dst;
2335
2336 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2337 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2338 dst = newVRegF(env);
2339 addInstr(env, s390_insn_move(size, dst, h1));
2340 switch (op) {
2341 case Iop_AddF32:
2342 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2343 case Iop_SubF32:
2344 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2345 case Iop_MulF32:
2346 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2347 case Iop_DivF32:
2348 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2349
2350 default:
2351 goto irreducible;
2352 }
2353
florian2c74d242012-09-12 19:38:42 +00002354 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2355 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002356 return dst;
2357 }
2358
2359 /* --------- BINARY OP --------- */
2360 case Iex_Binop: {
2361 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002362 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002363 IRExpr *left = expr->Iex.Binop.arg2;
2364 HReg h1, dst;
florian6dc90242012-12-21 21:43:00 +00002365 s390_bfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002366 s390_fp_conv_t fpconv;
sewardj2019a972011-03-07 16:04:07 +00002367
2368 switch (op) {
2369 case Iop_SqrtF32:
2370 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002371 h1 = s390_isel_float_expr(env, left);
2372 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002373 set_bfp_rounding_mode_in_fpc(env, irrm);
2374 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002375 return dst;
sewardj2019a972011-03-07 16:04:07 +00002376
florian9fcff4c2012-09-10 03:09:04 +00002377 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2378 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2379 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2380 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2381 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2382 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2383 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
florian7ab421d2013-06-17 21:03:56 +00002384 case Iop_D32toF32: fpconv = S390_FP_D32_TO_F32; goto convert_dfp;
2385 case Iop_D32toF64: fpconv = S390_FP_D32_TO_F64; goto convert_dfp;
2386 case Iop_D64toF32: fpconv = S390_FP_D64_TO_F32; goto convert_dfp;
florian78d5ef72013-05-11 15:02:58 +00002387 case Iop_D64toF64: fpconv = S390_FP_D64_TO_F64; goto convert_dfp;
florian7ab421d2013-06-17 21:03:56 +00002388 case Iop_D128toF32: fpconv = S390_FP_D128_TO_F32; goto convert_dfp128;
florian78d5ef72013-05-11 15:02:58 +00002389 case Iop_D128toF64: fpconv = S390_FP_D128_TO_F64; goto convert_dfp128;
sewardj2019a972011-03-07 16:04:07 +00002390
florian9fcff4c2012-09-10 03:09:04 +00002391 convert_float:
2392 h1 = s390_isel_float_expr(env, left);
2393 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002394
florian9fcff4c2012-09-10 03:09:04 +00002395 convert_int:
2396 h1 = s390_isel_int_expr(env, left);
2397 goto convert;
2398
florian2c74d242012-09-12 19:38:42 +00002399 convert: {
florian125e20d2012-10-07 15:42:37 +00002400 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002401 /* convert-from-fixed and load-rounded have a rounding mode field
2402 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002403 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002404 if (s390_host_has_fpext) {
2405 rounding_mode = get_bfp_rounding_mode(env, irrm);
2406 } else {
2407 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002408 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002409 }
florian9fcff4c2012-09-10 03:09:04 +00002410 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2411 rounding_mode));
2412 return dst;
florian2c74d242012-09-12 19:38:42 +00002413 }
florian78d5ef72013-05-11 15:02:58 +00002414
2415 convert_dfp: {
2416 s390_dfp_round_t rm;
2417 HReg f0, f4, r1; /* real registers used by PFPO */
2418
2419 f4 = make_fpr(4); /* source */
2420 f0 = make_fpr(0); /* destination */
2421 r1 = make_gpr(1); /* GPR #1 clobbered */
2422 h1 = s390_isel_dfp_expr(env, left);
2423 dst = newVRegF(env);
2424 rm = get_dfp_rounding_mode(env, irrm);
2425 /* operand --> f4 */
2426 addInstr(env, s390_insn_move(8, f4, h1));
2427 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
2428 /* f0 --> destination */
2429 addInstr(env, s390_insn_move(8, dst, f0));
2430 return dst;
2431 }
2432
2433 convert_dfp128: {
2434 s390_dfp_round_t rm;
2435 HReg op_hi, op_lo;
2436 HReg f0, f4, f6, r1; /* real registers used by PFPO */
2437
2438 f4 = make_fpr(4); /* source */
2439 f6 = make_fpr(6); /* source */
2440 f0 = make_fpr(0); /* destination */
2441 r1 = make_gpr(1); /* GPR #1 clobbered */
2442 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
2443 dst = newVRegF(env);
2444 rm = get_dfp_rounding_mode(env, irrm);
2445 /* operand --> (f4, f6) */
2446 addInstr(env, s390_insn_move(8, f4, op_hi));
2447 addInstr(env, s390_insn_move(8, f6, op_lo));
2448 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
2449 f4, f6, r1, rm));
2450 /* f0 --> destination */
2451 addInstr(env, s390_insn_move(8, dst, f0));
2452 return dst;
2453 }
2454
sewardj2019a972011-03-07 16:04:07 +00002455 default:
2456 goto irreducible;
2457
2458 case Iop_F128toF64:
2459 case Iop_F128toF32: {
floriana2039c52013-12-10 16:51:15 +00002460 HReg op_hi, op_lo, f12, f13, f14, f15;
florian125e20d2012-10-07 15:42:37 +00002461 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002462
florian9fcff4c2012-09-10 03:09:04 +00002463 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2464 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002465
florian9fcff4c2012-09-10 03:09:04 +00002466 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002467
floriana2039c52013-12-10 16:51:15 +00002468 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
2469 f12 = make_fpr(12);
sewardj2019a972011-03-07 16:04:07 +00002470 f13 = make_fpr(13);
floriana2039c52013-12-10 16:51:15 +00002471 f14 = make_fpr(14);
sewardj2019a972011-03-07 16:04:07 +00002472 f15 = make_fpr(15);
2473
2474 /* operand --> (f13, f15) */
2475 addInstr(env, s390_insn_move(8, f13, op_hi));
2476 addInstr(env, s390_insn_move(8, f15, op_lo));
2477
floriana2039c52013-12-10 16:51:15 +00002478 /* result --> (f12, f14) */
2479
florian2c74d242012-09-12 19:38:42 +00002480 /* load-rounded has a rounding mode field when the floating point
2481 extension facility is installed. */
2482 if (s390_host_has_fpext) {
2483 rounding_mode = get_bfp_rounding_mode(env, irrm);
2484 } else {
2485 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002486 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002487 }
floriana2039c52013-12-10 16:51:15 +00002488
2489 addInstr(env, s390_insn_bfp128_convert_from(size, conv, f12, f14,
2490 f13, f15, rounding_mode));
2491 dst = newVRegF(env);
2492 addInstr(env, s390_insn_move(8, dst, f12));
2493
sewardj2019a972011-03-07 16:04:07 +00002494 return dst;
2495 }
2496 }
sewardj2019a972011-03-07 16:04:07 +00002497 }
2498
2499 /* --------- UNARY OP --------- */
2500 case Iex_Unop: {
2501 IROp op = expr->Iex.Unop.op;
2502 IRExpr *left = expr->Iex.Unop.arg;
2503 s390_bfp_unop_t bfpop;
florian6dc90242012-12-21 21:43:00 +00002504 s390_bfp_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002505 HReg h1, dst;
2506
2507 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2508 HReg dst_hi, dst_lo;
2509
2510 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2511 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2512 }
2513
florian4d71a082011-12-18 00:08:17 +00002514 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002515 dst = newVRegF(env);
2516 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2517 addInstr(env, s390_insn_move(size, dst, h1));
2518
2519 return dst;
2520 }
2521
2522 switch (op) {
2523 case Iop_NegF32:
2524 case Iop_NegF64:
2525 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002526 (left->Iex.Unop.op == Iop_AbsF32 ||
2527 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002528 bfpop = S390_BFP_NABS;
2529 else
2530 bfpop = S390_BFP_NEG;
2531 break;
2532
2533 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002534 case Iop_AbsF64:
2535 bfpop = S390_BFP_ABS;
2536 break;
2537
2538 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2539 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2540 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2541
2542 convert_float1:
2543 h1 = s390_isel_float_expr(env, left);
2544 goto convert1;
2545
2546 convert_int1:
2547 h1 = s390_isel_int_expr(env, left);
2548 goto convert1;
2549
2550 convert1:
2551 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002552 /* No rounding mode is needed for these conversions. Just stick
2553 one in. It won't be used later on. */
2554 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002555 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002556 return dst;
2557
sewardj2019a972011-03-07 16:04:07 +00002558 default:
2559 goto irreducible;
2560 }
2561
2562 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002563 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002564 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002565 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002566 return dst;
2567 }
2568
2569 default:
2570 goto irreducible;
2571 }
2572
2573 /* We get here if no pattern matched. */
2574 irreducible:
2575 ppIRExpr(expr);
2576 vpanic("s390_isel_float_expr: cannot reduce tree");
2577}
2578
2579
2580static HReg
2581s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2582{
2583 HReg dst = s390_isel_float_expr_wrk(env, expr);
2584
2585 /* Sanity checks ... */
2586 vassert(hregClass(dst) == HRcFlt64);
2587 vassert(hregIsVirtual(dst));
2588
2589 return dst;
2590}
2591
2592
2593/*---------------------------------------------------------*/
floriane38f6412012-12-21 17:32:12 +00002594/*--- ISEL: Decimal point expressions (128 bit) ---*/
2595/*---------------------------------------------------------*/
2596static void
2597s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
2598 IRExpr *expr)
2599{
2600 IRType ty = typeOfIRExpr(env->type_env, expr);
2601
2602 vassert(ty == Ity_D128);
2603
2604 switch (expr->tag) {
2605 case Iex_RdTmp:
2606 /* Return the virtual registers that hold the temporary. */
2607 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
2608 return;
2609
2610 /* --------- LOAD --------- */
2611 case Iex_Load: {
2612 IRExpr *addr_hi, *addr_lo;
2613 s390_amode *am_hi, *am_lo;
2614
2615 if (expr->Iex.Load.end != Iend_BE)
2616 goto irreducible;
2617
2618 addr_hi = expr->Iex.Load.addr;
2619 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
2620
2621 am_hi = s390_isel_amode(env, addr_hi);
2622 am_lo = s390_isel_amode(env, addr_lo);
2623
2624 *dst_hi = newVRegF(env);
2625 *dst_lo = newVRegF(env);
2626 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
2627 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
2628 return;
2629 }
2630
2631 /* --------- GET --------- */
2632 case Iex_Get:
2633 /* This is not supported because loading 128-bit from the guest
2634 state is almost certainly wrong. Use get_dpr_pair instead. */
2635 vpanic("Iex_Get with D128 data");
2636
2637 /* --------- 4-ary OP --------- */
2638 case Iex_Qop:
2639 vpanic("Iex_Qop with D128 data");
2640
2641 /* --------- TERNARY OP --------- */
2642 case Iex_Triop: {
2643 IRTriop *triop = expr->Iex.Triop.details;
2644 IROp op = triop->op;
2645 IRExpr *irrm = triop->arg1;
2646 IRExpr *left = triop->arg2;
2647 IRExpr *right = triop->arg3;
2648 s390_dfp_round_t rounding_mode;
2649 s390_dfp_binop_t dfpop;
2650 HReg op1_hi, op1_lo, op2_hi, op2_lo, f9, f11, f12, f13, f14, f15;
2651
floriane38f6412012-12-21 17:32:12 +00002652 /* We use non-virtual registers as pairs with (f9, f11) as op1,
2653 (f12, f14) as op2 and (f13, f15) as destination) */
2654 f9 = make_fpr(9);
2655 f11 = make_fpr(11);
2656 f12 = make_fpr(12);
2657 f13 = make_fpr(13);
2658 f14 = make_fpr(14);
2659 f15 = make_fpr(15);
2660
floriane38f6412012-12-21 17:32:12 +00002661 switch (op) {
florian5c539732013-02-14 14:27:12 +00002662 case Iop_AddD128: dfpop = S390_DFP_ADD; goto evaluate_dfp128;
2663 case Iop_SubD128: dfpop = S390_DFP_SUB; goto evaluate_dfp128;
2664 case Iop_MulD128: dfpop = S390_DFP_MUL; goto evaluate_dfp128;
2665 case Iop_DivD128: dfpop = S390_DFP_DIV; goto evaluate_dfp128;
2666 case Iop_QuantizeD128: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp128;
2667
2668 evaluate_dfp128: {
2669 /* Process 1st operand */
2670 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);
2671 /* 1st operand --> (f9, f11) */
2672 addInstr(env, s390_insn_move(8, f9, op1_hi));
2673 addInstr(env, s390_insn_move(8, f11, op1_lo));
2674
2675 /* Process 2nd operand */
2676 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2677 /* 2nd operand --> (f12, f14) */
2678 addInstr(env, s390_insn_move(8, f12, op2_hi));
2679 addInstr(env, s390_insn_move(8, f14, op2_lo));
2680
2681 /* DFP arithmetic ops take rounding mode only when fpext is
2682 installed. But, DFP quantize operation takes rm irrespective
2683 of fpext facility . */
floriand18287d2013-02-21 03:03:05 +00002684 if (s390_host_has_fpext || op == Iop_QuantizeD128) {
florian5c539732013-02-14 14:27:12 +00002685 rounding_mode = get_dfp_rounding_mode(env, irrm);
2686 } else {
2687 set_dfp_rounding_mode_in_fpc(env, irrm);
2688 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2689 }
2690 addInstr(env, s390_insn_dfp128_binop(16, dfpop, f13, f15, f9, f11,
2691 f12, f14, rounding_mode));
2692 /* Move result to virtual destination register */
2693 *dst_hi = newVRegF(env);
2694 *dst_lo = newVRegF(env);
2695 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2696 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2697 return;
2698 }
2699
2700 case Iop_SignificanceRoundD128: {
2701 /* Process 1st operand */
2702 HReg op1 = s390_isel_int_expr(env, left);
2703 /* Process 2nd operand */
2704 s390_isel_dfp128_expr(&op2_hi, &op2_lo, env, right);
2705 /* 2nd operand --> (f12, f14) */
2706 addInstr(env, s390_insn_move(8, f12, op2_hi));
2707 addInstr(env, s390_insn_move(8, f14, op2_lo));
2708
2709 rounding_mode = get_dfp_rounding_mode(env, irrm);
2710 addInstr(env, s390_insn_dfp128_reround(16, f13, f15, op1, f12, f14,
2711 rounding_mode));
2712 /* Move result to virtual destination register */
2713 *dst_hi = newVRegF(env);
2714 *dst_lo = newVRegF(env);
2715 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2716 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2717 return;
2718 }
2719
floriane38f6412012-12-21 17:32:12 +00002720 default:
2721 goto irreducible;
2722 }
floriane38f6412012-12-21 17:32:12 +00002723 }
2724
2725 /* --------- BINARY OP --------- */
2726 case Iex_Binop: {
florian1b901d42013-01-01 22:19:24 +00002727
floriane38f6412012-12-21 17:32:12 +00002728 switch (expr->Iex.Binop.op) {
2729 case Iop_D64HLtoD128:
2730 *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
2731 *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
2732 return;
2733
florian1b901d42013-01-01 22:19:24 +00002734 case Iop_ShlD128:
florian5c539732013-02-14 14:27:12 +00002735 case Iop_ShrD128:
2736 case Iop_InsertExpD128: {
florian1b901d42013-01-01 22:19:24 +00002737 HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
2738 s390_dfp_intop_t intop;
florian5c539732013-02-14 14:27:12 +00002739 IRExpr *dfp_op;
2740 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00002741
2742 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00002743 case Iop_ShlD128: /* (D128, I64) -> D128 */
2744 intop = S390_DFP_SHIFT_LEFT;
2745 dfp_op = expr->Iex.Binop.arg1;
2746 int_op = expr->Iex.Binop.arg2;
2747 break;
2748 case Iop_ShrD128: /* (D128, I64) -> D128 */
2749 intop = S390_DFP_SHIFT_RIGHT;
2750 dfp_op = expr->Iex.Binop.arg1;
2751 int_op = expr->Iex.Binop.arg2;
2752 break;
2753 case Iop_InsertExpD128: /* (I64, D128) -> D128 */
2754 intop = S390_DFP_INSERT_EXP;
2755 int_op = expr->Iex.Binop.arg1;
2756 dfp_op = expr->Iex.Binop.arg2;
2757 break;
florian1b901d42013-01-01 22:19:24 +00002758 default: goto irreducible;
2759 }
2760
2761 /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
2762 f9 = make_fpr(9); /* 128 bit dfp operand */
2763 f11 = make_fpr(11);
2764
2765 f13 = make_fpr(13); /* 128 bit dfp destination */
2766 f15 = make_fpr(15);
2767
florian5c539732013-02-14 14:27:12 +00002768 /* Process dfp operand */
2769 s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, dfp_op);
2770 /* op1 -> (f9,f11) */
florian1b901d42013-01-01 22:19:24 +00002771 addInstr(env, s390_insn_move(8, f9, op1_hi));
2772 addInstr(env, s390_insn_move(8, f11, op1_lo));
2773
florian5c539732013-02-14 14:27:12 +00002774 op2 = s390_isel_int_expr(env, int_op); /* int operand */
florian1b901d42013-01-01 22:19:24 +00002775
2776 addInstr(env,
2777 s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
2778
2779 /* Move result to virtual destination register */
2780 *dst_hi = newVRegF(env);
2781 *dst_lo = newVRegF(env);
2782 addInstr(env, s390_insn_move(8, *dst_hi, f13));
2783 addInstr(env, s390_insn_move(8, *dst_lo, f15));
2784 return;
2785 }
2786
florian7ab421d2013-06-17 21:03:56 +00002787 case Iop_F32toD128:
florian78d5ef72013-05-11 15:02:58 +00002788 case Iop_F64toD128: {
2789 IRExpr *irrm;
2790 IRExpr *left;
2791 s390_dfp_round_t rm;
2792 HReg h1; /* virtual reg. to hold source */
2793 HReg f0, f2, f4, r1; /* real registers used by PFPO */
florian7ab421d2013-06-17 21:03:56 +00002794 s390_fp_conv_t fpconv;
2795
2796 switch (expr->Iex.Binop.op) {
2797 case Iop_F32toD128: /* (D128, I64) -> D128 */
2798 fpconv = S390_FP_F32_TO_D128;
2799 break;
2800 case Iop_F64toD128: /* (D128, I64) -> D128 */
2801 fpconv = S390_FP_F64_TO_D128;
2802 break;
2803 default: goto irreducible;
2804 }
florian78d5ef72013-05-11 15:02:58 +00002805
2806 f4 = make_fpr(4); /* source */
2807 f0 = make_fpr(0); /* destination */
2808 f2 = make_fpr(2); /* destination */
2809 r1 = make_gpr(1); /* GPR #1 clobbered */
2810 irrm = expr->Iex.Binop.arg1;
2811 left = expr->Iex.Binop.arg2;
2812 rm = get_dfp_rounding_mode(env, irrm);
2813 h1 = s390_isel_float_expr(env, left);
2814 addInstr(env, s390_insn_move(8, f4, h1));
florian7ab421d2013-06-17 21:03:56 +00002815 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, f2,
florian78d5ef72013-05-11 15:02:58 +00002816 f4, INVALID_HREG, r1, rm));
2817 /* (f0, f2) --> destination */
2818 *dst_hi = newVRegF(env);
2819 *dst_lo = newVRegF(env);
2820 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2821 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2822
2823 return;
2824 }
2825
2826 case Iop_F128toD128: {
2827 IRExpr *irrm;
2828 IRExpr *left;
2829 s390_dfp_round_t rm;
2830 HReg op_hi, op_lo;
2831 HReg f0, f2, f4, f6, r1; /* real registers used by PFPO */
2832
2833 f4 = make_fpr(4); /* source */
2834 f6 = make_fpr(6); /* source */
2835 f0 = make_fpr(0); /* destination */
2836 f2 = make_fpr(2); /* destination */
2837 r1 = make_gpr(1); /* GPR #1 clobbered */
2838
2839 irrm = expr->Iex.Binop.arg1;
2840 left = expr->Iex.Binop.arg2;
2841 rm = get_dfp_rounding_mode(env, irrm);
2842 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
2843 /* operand --> (f4, f6) */
2844 addInstr(env, s390_insn_move(8, f4, op_hi));
2845 addInstr(env, s390_insn_move(8, f6, op_lo));
2846 addInstr(env, s390_insn_fp128_convert(16, S390_FP_F128_TO_D128, f0, f2,
2847 f4, f6, r1, rm));
2848 /* (f0, f2) --> destination */
2849 *dst_hi = newVRegF(env);
2850 *dst_lo = newVRegF(env);
2851 addInstr(env, s390_insn_move(8, *dst_hi, f0));
2852 addInstr(env, s390_insn_move(8, *dst_lo, f2));
2853
2854 return;
2855 }
2856
floriane38f6412012-12-21 17:32:12 +00002857 default:
2858 goto irreducible;
2859 }
2860 }
2861
2862 /* --------- UNARY OP --------- */
2863 case Iex_Unop: {
2864 IRExpr *left = expr->Iex.Unop.arg;
2865 s390_dfp_conv_t conv;
floriane38f6412012-12-21 17:32:12 +00002866 HReg op, f12, f14;
2867
floriana887acd2013-02-08 23:32:54 +00002868 /* We use non-virtual registers as pairs (f12, f14)) */
floriane38f6412012-12-21 17:32:12 +00002869 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00002870 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00002871
2872 switch (expr->Iex.Unop.op) {
2873 case Iop_D64toD128: conv = S390_DFP_D64_TO_D128; goto convert_dfp;
florian5f034622013-01-13 02:29:05 +00002874 case Iop_I32StoD128: conv = S390_DFP_I32_TO_D128; goto convert_int;
floriana887acd2013-02-08 23:32:54 +00002875 case Iop_I64StoD128: conv = S390_DFP_I64_TO_D128; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002876 case Iop_I32UtoD128: conv = S390_DFP_U32_TO_D128; goto convert_int;
2877 case Iop_I64UtoD128: conv = S390_DFP_U64_TO_D128; goto convert_int;
floriane38f6412012-12-21 17:32:12 +00002878 default:
2879 goto irreducible;
2880 }
2881
2882 convert_dfp:
2883 op = s390_isel_dfp_expr(env, left);
2884 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2885 goto move_dst;
2886
florian5f034622013-01-13 02:29:05 +00002887 convert_int:
2888 op = s390_isel_int_expr(env, left);
2889 addInstr(env, s390_insn_dfp128_convert_to(16, conv, f12, f14, op));
2890 goto move_dst;
2891
floriane38f6412012-12-21 17:32:12 +00002892 move_dst:
2893 /* Move result to virtual destination registers */
2894 *dst_hi = newVRegF(env);
2895 *dst_lo = newVRegF(env);
2896 addInstr(env, s390_insn_move(8, *dst_hi, f12));
2897 addInstr(env, s390_insn_move(8, *dst_lo, f14));
2898 return;
2899 }
2900
2901 default:
2902 goto irreducible;
2903 }
2904
2905 /* We get here if no pattern matched. */
2906 irreducible:
2907 ppIRExpr(expr);
2908 vpanic("s390_isel_dfp128_expr_wrk: cannot reduce tree");
2909
2910}
2911
2912
2913/* Compute a 128-bit value into two 64-bit registers. These may be either
2914 real or virtual regs; in any case they must not be changed by subsequent
2915 code emitted by the caller. */
2916static void
2917s390_isel_dfp128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
2918{
2919 s390_isel_dfp128_expr_wrk(dst_hi, dst_lo, env, expr);
2920
2921 /* Sanity checks ... */
2922 vassert(hregIsVirtual(*dst_hi));
2923 vassert(hregIsVirtual(*dst_lo));
2924 vassert(hregClass(*dst_hi) == HRcFlt64);
2925 vassert(hregClass(*dst_lo) == HRcFlt64);
2926}
2927
2928
2929/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002930/*--- ISEL: Decimal point expressions (64 bit) ---*/
2931/*---------------------------------------------------------*/
2932
2933static HReg
2934s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2935{
2936 IRType ty = typeOfIRExpr(env->type_env, expr);
2937 UChar size;
2938
floriane38f6412012-12-21 17:32:12 +00002939 vassert(ty == Ity_D64 || ty == Ity_D32);
florian12390202012-11-10 22:34:14 +00002940
2941 size = sizeofIRType(ty);
2942
2943 switch (expr->tag) {
2944 case Iex_RdTmp:
2945 /* Return the virtual register that holds the temporary. */
2946 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2947
2948 /* --------- LOAD --------- */
2949 case Iex_Load: {
2950 HReg dst = newVRegF(env);
2951 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2952
2953 if (expr->Iex.Load.end != Iend_BE)
2954 goto irreducible;
2955
2956 addInstr(env, s390_insn_load(size, dst, am));
2957
2958 return dst;
2959 }
2960
2961 /* --------- GET --------- */
2962 case Iex_Get: {
2963 HReg dst = newVRegF(env);
2964 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2965
2966 addInstr(env, s390_insn_load(size, dst, am));
2967
2968 return dst;
2969 }
2970
floriane38f6412012-12-21 17:32:12 +00002971 /* --------- BINARY OP --------- */
2972 case Iex_Binop: {
2973 IROp op = expr->Iex.Binop.op;
2974 IRExpr *irrm = expr->Iex.Binop.arg1;
2975 IRExpr *left = expr->Iex.Binop.arg2;
2976 HReg h1, dst;
2977 s390_dfp_conv_t conv;
florian78d5ef72013-05-11 15:02:58 +00002978 s390_fp_conv_t fpconv;
floriane38f6412012-12-21 17:32:12 +00002979
2980 switch (op) {
2981 case Iop_D64toD32: conv = S390_DFP_D64_TO_D32; goto convert_dfp;
floriana887acd2013-02-08 23:32:54 +00002982 case Iop_I64StoD64: conv = S390_DFP_I64_TO_D64; goto convert_int;
florian5f034622013-01-13 02:29:05 +00002983 case Iop_I64UtoD64: conv = S390_DFP_U64_TO_D64; goto convert_int;
florian7ab421d2013-06-17 21:03:56 +00002984 case Iop_F32toD32: fpconv = S390_FP_F32_TO_D32; goto convert_bfp;
2985 case Iop_F32toD64: fpconv = S390_FP_F32_TO_D64; goto convert_bfp;
2986 case Iop_F64toD32: fpconv = S390_FP_F64_TO_D32; goto convert_bfp;
florian78d5ef72013-05-11 15:02:58 +00002987 case Iop_F64toD64: fpconv = S390_FP_F64_TO_D64; goto convert_bfp;
florian7ab421d2013-06-17 21:03:56 +00002988 case Iop_F128toD32: fpconv = S390_FP_F128_TO_D32; goto convert_bfp128;
2989 case Iop_F128toD64: fpconv = S390_FP_F128_TO_D64; goto convert_bfp128;
floriane38f6412012-12-21 17:32:12 +00002990
2991 convert_dfp:
2992 h1 = s390_isel_dfp_expr(env, left);
2993 goto convert;
2994
florian5f034622013-01-13 02:29:05 +00002995 convert_int:
2996 h1 = s390_isel_int_expr(env, left);
2997 goto convert;
2998
floriane38f6412012-12-21 17:32:12 +00002999 convert: {
3000 s390_dfp_round_t rounding_mode;
3001 /* convert-from-fixed and load-rounded have a rounding mode field
3002 when the floating point extension facility is installed. */
3003 dst = newVRegF(env);
3004 if (s390_host_has_fpext) {
3005 rounding_mode = get_dfp_rounding_mode(env, irrm);
3006 } else {
3007 set_dfp_rounding_mode_in_fpc(env, irrm);
3008 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3009 }
3010 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3011 rounding_mode));
3012 return dst;
3013 }
floriane38f6412012-12-21 17:32:12 +00003014
florian78d5ef72013-05-11 15:02:58 +00003015 convert_bfp: {
3016 s390_dfp_round_t rm;
3017 HReg f0, f4, r1; /* real registers used by PFPO */
3018
3019 f4 = make_fpr(4); /* source */
3020 f0 = make_fpr(0); /* destination */
3021 r1 = make_gpr(1); /* GPR #1 clobbered */
3022 h1 = s390_isel_float_expr(env, left);
3023 dst = newVRegF(env);
3024 rm = get_dfp_rounding_mode(env, irrm);
3025 /* operand --> f4 */
3026 addInstr(env, s390_insn_move(8, f4, h1));
3027 addInstr(env, s390_insn_fp_convert(size, fpconv, f0, f4, r1, rm));
3028 /* f0 --> destination */
3029 addInstr(env, s390_insn_move(8, dst, f0));
3030 return dst;
3031 }
3032
florian7ab421d2013-06-17 21:03:56 +00003033 convert_bfp128: {
3034 s390_dfp_round_t rm;
3035 HReg op_hi, op_lo;
3036 HReg f0, f4, f6, r1; /* real registers used by PFPO */
3037
3038 f4 = make_fpr(4); /* source */
3039 f6 = make_fpr(6); /* source */
3040 f0 = make_fpr(0); /* destination */
3041 r1 = make_gpr(1); /* GPR #1 clobbered */
3042 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
3043 dst = newVRegF(env);
3044 rm = get_dfp_rounding_mode(env, irrm);
3045 /* operand --> (f4, f6) */
3046 addInstr(env, s390_insn_move(8, f4, op_hi));
3047 addInstr(env, s390_insn_move(8, f6, op_lo));
3048 addInstr(env, s390_insn_fp128_convert(16, fpconv, f0, INVALID_HREG,
3049 f4, f6, r1, rm));
3050 /* f0 --> destination */
3051 addInstr(env, s390_insn_move(8, dst, f0));
3052 return dst;
3053 }
3054
floriane38f6412012-12-21 17:32:12 +00003055 case Iop_D128toD64: {
floriana2039c52013-12-10 16:51:15 +00003056 HReg op_hi, op_lo, f12, f13, f14, f15;
floriane38f6412012-12-21 17:32:12 +00003057 s390_dfp_round_t rounding_mode;
3058
3059 conv = S390_DFP_D128_TO_D64;
3060
3061 s390_isel_dfp128_expr(&op_hi, &op_lo, env, left);
3062
floriana2039c52013-12-10 16:51:15 +00003063 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14) */
3064 f12 = make_fpr(12);
floriane38f6412012-12-21 17:32:12 +00003065 f13 = make_fpr(13);
floriana2039c52013-12-10 16:51:15 +00003066 f14 = make_fpr(14);
floriane38f6412012-12-21 17:32:12 +00003067 f15 = make_fpr(15);
3068
3069 /* operand --> (f13, f15) */
3070 addInstr(env, s390_insn_move(8, f13, op_hi));
3071 addInstr(env, s390_insn_move(8, f15, op_lo));
3072
floriana2039c52013-12-10 16:51:15 +00003073 /* result --> (f12, f14) */
3074
floriane38f6412012-12-21 17:32:12 +00003075 /* load-rounded has a rounding mode field when the floating point
3076 extension facility is installed. */
3077 if (s390_host_has_fpext) {
3078 rounding_mode = get_dfp_rounding_mode(env, irrm);
3079 } else {
3080 set_dfp_rounding_mode_in_fpc(env, irrm);
3081 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3082 }
floriana2039c52013-12-10 16:51:15 +00003083 addInstr(env, s390_insn_dfp128_convert_from(size, conv, f12, f14,
3084 f13, f15, rounding_mode));
3085 dst = newVRegF(env);
3086 addInstr(env, s390_insn_move(8, dst, f12));
3087
floriane38f6412012-12-21 17:32:12 +00003088 return dst;
3089 }
3090
florian1b901d42013-01-01 22:19:24 +00003091 case Iop_ShlD64:
florian5c539732013-02-14 14:27:12 +00003092 case Iop_ShrD64:
3093 case Iop_InsertExpD64: {
florian1b901d42013-01-01 22:19:24 +00003094 HReg op2;
3095 HReg op3;
florian5c539732013-02-14 14:27:12 +00003096 IRExpr *dfp_op;
3097 IRExpr *int_op;
florian1b901d42013-01-01 22:19:24 +00003098 s390_dfp_intop_t intop;
florian1b901d42013-01-01 22:19:24 +00003099
3100 switch (expr->Iex.Binop.op) {
florian5c539732013-02-14 14:27:12 +00003101 case Iop_ShlD64: /* (D64, I64) -> D64 */
3102 intop = S390_DFP_SHIFT_LEFT;
3103 dfp_op = expr->Iex.Binop.arg1;
3104 int_op = expr->Iex.Binop.arg2;
3105 break;
3106 case Iop_ShrD64: /* (D64, I64) -> D64 */
3107 intop = S390_DFP_SHIFT_RIGHT;
3108 dfp_op = expr->Iex.Binop.arg1;
3109 int_op = expr->Iex.Binop.arg2;
3110 break;
3111 case Iop_InsertExpD64: /* (I64, D64) -> D64 */
3112 intop = S390_DFP_INSERT_EXP;
3113 int_op = expr->Iex.Binop.arg1;
3114 dfp_op = expr->Iex.Binop.arg2;
3115 break;
florian1b901d42013-01-01 22:19:24 +00003116 default: goto irreducible;
3117 }
3118
florian5c539732013-02-14 14:27:12 +00003119 op2 = s390_isel_int_expr(env, int_op);
3120 op3 = s390_isel_dfp_expr(env, dfp_op);
florian1b901d42013-01-01 22:19:24 +00003121 dst = newVRegF(env);
3122
3123 addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
3124 return dst;
3125 }
3126
3127 default:
3128 goto irreducible;
floriane38f6412012-12-21 17:32:12 +00003129 }
3130 }
3131
3132 /* --------- UNARY OP --------- */
3133 case Iex_Unop: {
3134 IROp op = expr->Iex.Unop.op;
3135 IRExpr *left = expr->Iex.Unop.arg;
3136 s390_dfp_conv_t conv;
3137 HReg h1, dst;
3138
3139 if (op == Iop_D128HItoD64 || op == Iop_D128LOtoD64) {
3140 HReg dst_hi, dst_lo;
3141
3142 s390_isel_dfp128_expr(&dst_hi, &dst_lo, env, left);
3143 return op == Iop_D128LOtoD64 ? dst_lo : dst_hi;
3144 }
3145
3146 if (op == Iop_ReinterpI64asD64) {
3147 dst = newVRegF(env);
3148 h1 = s390_isel_int_expr(env, left); /* Process the operand */
3149 addInstr(env, s390_insn_move(size, dst, h1));
3150
3151 return dst;
3152 }
3153
3154 switch (op) {
3155 case Iop_D32toD64: conv = S390_DFP_D32_TO_D64; goto convert_dfp1;
florian5f034622013-01-13 02:29:05 +00003156 case Iop_I32StoD64: conv = S390_DFP_I32_TO_D64; goto convert_int1;
3157 case Iop_I32UtoD64: conv = S390_DFP_U32_TO_D64; goto convert_int1;
floriane38f6412012-12-21 17:32:12 +00003158
3159 convert_dfp1:
3160 h1 = s390_isel_dfp_expr(env, left);
3161 goto convert1;
3162
florian5f034622013-01-13 02:29:05 +00003163 convert_int1:
3164 h1 = s390_isel_int_expr(env, left);
3165 goto convert1;
3166
floriane38f6412012-12-21 17:32:12 +00003167 convert1:
3168 dst = newVRegF(env);
3169 /* No rounding mode is needed for these conversions. Just stick
3170 one in. It won't be used later on. */
3171 addInstr(env, s390_insn_dfp_convert(size, conv, dst, h1,
3172 S390_DFP_ROUND_NEAREST_EVEN_4));
3173 return dst;
3174
3175 default:
3176 goto irreducible;
3177 }
3178 }
3179
florian12390202012-11-10 22:34:14 +00003180 /* --------- TERNARY OP --------- */
3181 case Iex_Triop: {
3182 IRTriop *triop = expr->Iex.Triop.details;
3183 IROp op = triop->op;
3184 IRExpr *irrm = triop->arg1;
3185 IRExpr *left = triop->arg2;
3186 IRExpr *right = triop->arg3;
3187 s390_dfp_round_t rounding_mode;
3188 s390_dfp_binop_t dfpop;
3189 HReg op2, op3, dst;
3190
florian12390202012-11-10 22:34:14 +00003191 switch (op) {
florian5c539732013-02-14 14:27:12 +00003192 case Iop_AddD64: dfpop = S390_DFP_ADD; goto evaluate_dfp;
3193 case Iop_SubD64: dfpop = S390_DFP_SUB; goto evaluate_dfp;
3194 case Iop_MulD64: dfpop = S390_DFP_MUL; goto evaluate_dfp;
3195 case Iop_DivD64: dfpop = S390_DFP_DIV; goto evaluate_dfp;
3196 case Iop_QuantizeD64: dfpop = S390_DFP_QUANTIZE; goto evaluate_dfp;
3197
3198 evaluate_dfp: {
3199 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
3200 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3201 dst = newVRegF(env);
3202 /* DFP arithmetic ops take rounding mode only when fpext is
3203 installed. But, DFP quantize operation takes rm irrespective
3204 of fpext facility . */
3205 if (s390_host_has_fpext || dfpop == S390_DFP_QUANTIZE) {
3206 rounding_mode = get_dfp_rounding_mode(env, irrm);
3207 } else {
3208 set_dfp_rounding_mode_in_fpc(env, irrm);
3209 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
3210 }
3211 addInstr(env, s390_insn_dfp_binop(size, dfpop, dst, op2, op3,
3212 rounding_mode));
3213 return dst;
3214 }
3215
3216 case Iop_SignificanceRoundD64:
3217 op2 = s390_isel_int_expr(env, left); /* Process 1st operand */
3218 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
3219 dst = newVRegF(env);
3220 rounding_mode = get_dfp_rounding_mode(env, irrm);
3221 addInstr(env, s390_insn_dfp_reround(size, dst, op2, op3,
3222 rounding_mode));
3223 return dst;
3224
florian12390202012-11-10 22:34:14 +00003225 default:
3226 goto irreducible;
3227 }
florian12390202012-11-10 22:34:14 +00003228 }
3229
3230 default:
3231 goto irreducible;
3232 }
3233
3234 /* We get here if no pattern matched. */
3235 irreducible:
3236 ppIRExpr(expr);
3237 vpanic("s390_isel_dfp_expr: cannot reduce tree");
3238}
3239
3240static HReg
3241s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
3242{
3243 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
3244
3245 /* Sanity checks ... */
3246 vassert(hregClass(dst) == HRcFlt64);
3247 vassert(hregIsVirtual(dst));
3248
3249 return dst;
3250}
3251
3252
3253/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00003254/*--- ISEL: Condition Code ---*/
3255/*---------------------------------------------------------*/
3256
3257/* This function handles all operators that produce a 1-bit result */
3258static s390_cc_t
3259s390_isel_cc(ISelEnv *env, IRExpr *cond)
3260{
3261 UChar size;
3262
3263 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
3264
3265 /* Constant: either 1 or 0 */
3266 if (cond->tag == Iex_Const) {
3267 vassert(cond->Iex.Const.con->tag == Ico_U1);
3268 vassert(cond->Iex.Const.con->Ico.U1 == True
3269 || cond->Iex.Const.con->Ico.U1 == False);
3270
3271 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
3272 }
3273
3274 /* Variable: values are 1 or 0 */
3275 if (cond->tag == Iex_RdTmp) {
3276 IRTemp tmp = cond->Iex.RdTmp.tmp;
3277 HReg reg = lookupIRTemp(env, tmp);
3278
3279 /* Load-and-test does not modify REG; so this is OK. */
3280 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
3281 size = 4;
3282 else
3283 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
3284 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
3285 return S390_CC_NE;
3286 }
3287
3288 /* Unary operators */
3289 if (cond->tag == Iex_Unop) {
3290 IRExpr *arg = cond->Iex.Unop.arg;
3291
3292 switch (cond->Iex.Unop.op) {
3293 case Iop_Not1: /* Not1(cond) */
3294 /* Generate code for EXPR, and negate the test condition */
3295 return s390_cc_invert(s390_isel_cc(env, arg));
3296
3297 /* Iop_32/64to1 select the LSB from their operand */
3298 case Iop_32to1:
3299 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00003300 HReg dst = newVRegI(env);
3301 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00003302
3303 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3304
florianf366a802012-08-03 00:42:18 +00003305 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00003306 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
3307 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
3308 return S390_CC_NE;
3309 }
3310
3311 case Iop_CmpNEZ8:
3312 case Iop_CmpNEZ16: {
3313 s390_opnd_RMI src;
3314 s390_unop_t op;
3315 HReg dst;
3316
3317 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
3318 : S390_ZERO_EXTEND_16;
3319 dst = newVRegI(env);
3320 src = s390_isel_int_expr_RMI(env, arg);
3321 addInstr(env, s390_insn_unop(4, op, dst, src));
3322 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
3323 return S390_CC_NE;
3324 }
3325
3326 case Iop_CmpNEZ32:
3327 case Iop_CmpNEZ64: {
3328 s390_opnd_RMI src;
3329
3330 src = s390_isel_int_expr_RMI(env, arg);
3331 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
3332 addInstr(env, s390_insn_test(size, src));
3333 return S390_CC_NE;
3334 }
3335
3336 default:
3337 goto fail;
3338 }
3339 }
3340
3341 /* Binary operators */
3342 if (cond->tag == Iex_Binop) {
3343 IRExpr *arg1 = cond->Iex.Binop.arg1;
3344 IRExpr *arg2 = cond->Iex.Binop.arg2;
3345 HReg reg1, reg2;
3346
3347 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
3348
3349 switch (cond->Iex.Binop.op) {
3350 s390_unop_t op;
3351 s390_cc_t result;
3352
3353 case Iop_CmpEQ8:
3354 case Iop_CasCmpEQ8:
3355 op = S390_ZERO_EXTEND_8;
3356 result = S390_CC_E;
3357 goto do_compare_ze;
3358
3359 case Iop_CmpNE8:
3360 case Iop_CasCmpNE8:
3361 op = S390_ZERO_EXTEND_8;
3362 result = S390_CC_NE;
3363 goto do_compare_ze;
3364
3365 case Iop_CmpEQ16:
3366 case Iop_CasCmpEQ16:
3367 op = S390_ZERO_EXTEND_16;
3368 result = S390_CC_E;
3369 goto do_compare_ze;
3370
3371 case Iop_CmpNE16:
3372 case Iop_CasCmpNE16:
3373 op = S390_ZERO_EXTEND_16;
3374 result = S390_CC_NE;
3375 goto do_compare_ze;
3376
3377 do_compare_ze: {
3378 s390_opnd_RMI op1, op2;
3379
3380 op1 = s390_isel_int_expr_RMI(env, arg1);
3381 reg1 = newVRegI(env);
3382 addInstr(env, s390_insn_unop(4, op, reg1, op1));
3383
3384 op2 = s390_isel_int_expr_RMI(env, arg2);
3385 reg2 = newVRegI(env);
3386 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
3387
3388 op2 = s390_opnd_reg(reg2);
3389 addInstr(env, s390_insn_compare(4, reg1, op2, False));
3390
3391 return result;
3392 }
3393
3394 case Iop_CmpEQ32:
3395 case Iop_CmpEQ64:
3396 case Iop_CasCmpEQ32:
3397 case Iop_CasCmpEQ64:
3398 result = S390_CC_E;
3399 goto do_compare;
3400
3401 case Iop_CmpNE32:
3402 case Iop_CmpNE64:
3403 case Iop_CasCmpNE32:
3404 case Iop_CasCmpNE64:
3405 result = S390_CC_NE;
3406 goto do_compare;
3407
3408 do_compare: {
3409 HReg op1;
3410 s390_opnd_RMI op2;
3411
3412 order_commutative_operands(arg1, arg2);
3413
3414 op1 = s390_isel_int_expr(env, arg1);
3415 op2 = s390_isel_int_expr_RMI(env, arg2);
3416
3417 addInstr(env, s390_insn_compare(size, op1, op2, False));
3418
3419 return result;
3420 }
3421
3422 case Iop_CmpLT32S:
3423 case Iop_CmpLE32S:
3424 case Iop_CmpLT64S:
3425 case Iop_CmpLE64S: {
3426 HReg op1;
3427 s390_opnd_RMI op2;
3428
3429 op1 = s390_isel_int_expr(env, arg1);
3430 op2 = s390_isel_int_expr_RMI(env, arg2);
3431
3432 addInstr(env, s390_insn_compare(size, op1, op2, True));
3433
3434 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
3435 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
3436 }
3437
3438 case Iop_CmpLT32U:
3439 case Iop_CmpLE32U:
3440 case Iop_CmpLT64U:
3441 case Iop_CmpLE64U: {
3442 HReg op1;
3443 s390_opnd_RMI op2;
3444
3445 op1 = s390_isel_int_expr(env, arg1);
3446 op2 = s390_isel_int_expr_RMI(env, arg2);
3447
3448 addInstr(env, s390_insn_compare(size, op1, op2, False));
3449
3450 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
3451 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
3452 }
3453
3454 default:
3455 goto fail;
3456 }
3457 }
3458
3459 fail:
3460 ppIRExpr(cond);
3461 vpanic("s390_isel_cc: unexpected operator");
3462}
3463
3464
3465/*---------------------------------------------------------*/
3466/*--- ISEL: Statements ---*/
3467/*---------------------------------------------------------*/
3468
3469static void
3470s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
3471{
3472 if (vex_traceflags & VEX_TRACE_VCODE) {
3473 vex_printf("\n -- ");
3474 ppIRStmt(stmt);
3475 vex_printf("\n");
3476 }
3477
3478 switch (stmt->tag) {
3479
3480 /* --------- STORE --------- */
3481 case Ist_Store: {
3482 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3483 s390_amode *am;
3484 HReg src;
3485
3486 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
3487
3488 am = s390_isel_amode(env, stmt->Ist.Store.addr);
3489
3490 switch (tyd) {
3491 case Ity_I8:
3492 case Ity_I16:
3493 case Ity_I32:
3494 case Ity_I64:
florianf85fe3e2012-12-22 02:28:25 +00003495 /* fixs390: We could check for INSN_MADD here. */
florian09bbba82012-12-11 04:09:43 +00003496 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003497 stmt->Ist.Store.data->tag == Iex_Const) {
3498 ULong value =
3499 get_const_value_as_ulong(stmt->Ist.Store.data->Iex.Const.con);
3500 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003501 return;
3502 }
floriancec3a8a2013-02-02 00:16:58 +00003503 /* Check whether we can use a memcpy here. Currently, the restriction
3504 is that both amodes need to be B12, so MVC can be emitted.
3505 We do not consider a store whose data expression is a load because
3506 we don't want to deal with overlapping locations. */
3507 /* store(get) never overlaps*/
3508 if (am->tag == S390_AMODE_B12 &&
3509 stmt->Ist.Store.data->tag == Iex_Get) {
3510 UInt offset = stmt->Ist.Store.data->Iex.Get.offset;
3511 s390_amode *from = s390_amode_for_guest_state(offset);
3512 addInstr(env, s390_insn_memcpy(sizeofIRType(tyd), am, from));
3513 return;
3514 }
3515 /* General case: compile data into a register */
sewardj2019a972011-03-07 16:04:07 +00003516 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
3517 break;
3518
3519 case Ity_F32:
3520 case Ity_F64:
3521 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
3522 break;
3523
florianeb981ae2012-12-21 18:55:03 +00003524 case Ity_D32:
3525 case Ity_D64:
3526 src = s390_isel_dfp_expr(env, stmt->Ist.Store.data);
3527 break;
3528
sewardj2019a972011-03-07 16:04:07 +00003529 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003530 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00003531 /* Cannot occur. No such instruction */
floriane38f6412012-12-21 17:32:12 +00003532 vpanic("Ist_Store with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003533
3534 default:
3535 goto stmt_fail;
3536 }
3537
3538 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3539 return;
3540 }
3541
3542 /* --------- PUT --------- */
3543 case Ist_Put: {
3544 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3545 HReg src;
3546 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00003547 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00003548
florianad43b3a2012-02-20 15:01:14 +00003549 /* Detect updates to certain guest registers. We track the contents
3550 of those registers as long as they contain constants. If the new
3551 constant is either zero or in the 8-bit neighbourhood of the
3552 current value we can use a memory-to-memory insn to do the update. */
3553
3554 Int offset = stmt->Ist.Put.offset;
3555
3556 /* Check necessary conditions:
3557 (1) must be one of the registers we care about
3558 (2) assigned value must be a constant */
3559 Int guest_reg = get_guest_reg(offset);
3560
3561 if (guest_reg == GUEST_UNKNOWN) goto not_special;
3562
florianad43b3a2012-02-20 15:01:14 +00003563 if (stmt->Ist.Put.data->tag != Iex_Const) {
3564 /* Invalidate guest register contents */
3565 env->old_value_valid[guest_reg] = False;
3566 goto not_special;
3567 }
3568
cborntraaf7ad282012-08-08 14:11:33 +00003569 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
3570 if (tyd != Ity_I64)
3571 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00003572
cborntraaf7ad282012-08-08 14:11:33 +00003573 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00003574
3575 old_value = env->old_value[guest_reg];
3576 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
3577 env->old_value[guest_reg] = new_value;
3578
3579 Bool old_value_is_valid = env->old_value_valid[guest_reg];
3580 env->old_value_valid[guest_reg] = True;
3581
3582 /* If the register already contains the new value, there is nothing
florian9f42ab42012-12-23 01:09:16 +00003583 to do here. */
florianad43b3a2012-02-20 15:01:14 +00003584 if (old_value_is_valid && new_value == old_value) {
florian9f42ab42012-12-23 01:09:16 +00003585 return;
florianad43b3a2012-02-20 15:01:14 +00003586 }
3587
florianad43b3a2012-02-20 15:01:14 +00003588 if (old_value_is_valid == False) goto not_special;
3589
3590 /* If the new value is in the neighbourhood of the old value
3591 we can use a memory-to-memory insn */
3592 difference = new_value - old_value;
3593
3594 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
florianf85fe3e2012-12-22 02:28:25 +00003595 am = s390_amode_for_guest_state(offset);
3596 addInstr(env, s390_insn_madd(sizeofIRType(tyd), am,
florianad43b3a2012-02-20 15:01:14 +00003597 (difference & 0xFF), new_value));
3598 return;
3599 }
3600
florianb93348d2012-12-27 00:59:43 +00003601 /* If the high word is the same it is sufficient to load the low word. */
florianad43b3a2012-02-20 15:01:14 +00003602 if ((old_value >> 32) == (new_value >> 32)) {
florianf85fe3e2012-12-22 02:28:25 +00003603 am = s390_amode_for_guest_state(offset + 4);
florianb93348d2012-12-27 00:59:43 +00003604 addInstr(env, s390_insn_mimm(4, am, new_value & 0xFFFFFFFF));
florianad43b3a2012-02-20 15:01:14 +00003605 return;
3606 }
3607
3608 /* No special case applies... fall through */
3609
3610 not_special:
florianb93348d2012-12-27 00:59:43 +00003611 am = s390_amode_for_guest_state(offset);
sewardj2019a972011-03-07 16:04:07 +00003612
3613 switch (tyd) {
3614 case Ity_I8:
3615 case Ity_I16:
3616 case Ity_I32:
3617 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00003618 if (am->tag == S390_AMODE_B12 &&
florianb93348d2012-12-27 00:59:43 +00003619 stmt->Ist.Put.data->tag == Iex_Const) {
3620 ULong value =
3621 get_const_value_as_ulong(stmt->Ist.Put.data->Iex.Const.con);
3622 addInstr(env, s390_insn_mimm(sizeofIRType(tyd), am, value));
florian09bbba82012-12-11 04:09:43 +00003623 return;
3624 }
floriancec3a8a2013-02-02 00:16:58 +00003625 /* Check whether we can use a memcpy here. Currently, the restriction
3626 is that both amodes need to be B12, so MVC can be emitted. */
3627 /* put(load) never overlaps */
3628 if (am->tag == S390_AMODE_B12 &&
3629 stmt->Ist.Put.data->tag == Iex_Load) {
3630 if (stmt->Ist.Put.data->Iex.Load.end != Iend_BE) goto stmt_fail;
3631 IRExpr *data = stmt->Ist.Put.data->Iex.Load.addr;
3632 s390_amode *from = s390_isel_amode(env, data);
3633 UInt size = sizeofIRType(tyd);
3634
3635 if (from->tag == S390_AMODE_B12) {
3636 /* Source can be compiled into a B12 amode. */
3637 addInstr(env, s390_insn_memcpy(size, am, from));
3638 return;
3639 }
3640
3641 src = newVRegI(env);
3642 addInstr(env, s390_insn_load(size, src, from));
3643 break;
3644 }
3645 /* put(get) */
3646 if (am->tag == S390_AMODE_B12 &&
3647 stmt->Ist.Put.data->tag == Iex_Get) {
3648 UInt put_offset = am->d;
3649 UInt get_offset = stmt->Ist.Put.data->Iex.Get.offset;
3650 UInt size = sizeofIRType(tyd);
3651 /* don't memcpy in case of overlap */
3652 if (put_offset + size <= get_offset ||
3653 get_offset + size <= put_offset) {
3654 s390_amode *from = s390_amode_for_guest_state(get_offset);
3655 addInstr(env, s390_insn_memcpy(size, am, from));
3656 return;
3657 }
3658 goto no_memcpy_put;
3659 }
3660 /* General case: compile data into a register */
3661no_memcpy_put:
sewardj2019a972011-03-07 16:04:07 +00003662 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
3663 break;
3664
3665 case Ity_F32:
3666 case Ity_F64:
3667 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
3668 break;
3669
3670 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00003671 case Ity_D128:
3672 /* Does not occur. See function put_(f|d)pr_pair. */
3673 vpanic("Ist_Put with 128-bit floating point data");
sewardj2019a972011-03-07 16:04:07 +00003674
floriane38f6412012-12-21 17:32:12 +00003675 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003676 case Ity_D64:
3677 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
3678 break;
3679
sewardj2019a972011-03-07 16:04:07 +00003680 default:
3681 goto stmt_fail;
3682 }
3683
3684 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
3685 return;
3686 }
3687
3688 /* --------- TMP --------- */
3689 case Ist_WrTmp: {
3690 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3691 IRType tyd = typeOfIRTemp(env->type_env, tmp);
3692 HReg src, dst;
3693
3694 switch (tyd) {
3695 case Ity_I128: {
3696 HReg dst_hi, dst_lo, res_hi, res_lo;
3697
3698 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3699 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3700
3701 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3702 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3703 return;
3704 }
3705
3706 case Ity_I8:
3707 case Ity_I16:
3708 case Ity_I32:
3709 case Ity_I64:
3710 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
3711 dst = lookupIRTemp(env, tmp);
3712 break;
3713
3714 case Ity_I1: {
3715 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
3716 dst = lookupIRTemp(env, tmp);
3717 addInstr(env, s390_insn_cc2bool(dst, cond));
3718 return;
3719 }
3720
3721 case Ity_F32:
3722 case Ity_F64:
3723 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
3724 dst = lookupIRTemp(env, tmp);
3725 break;
3726
3727 case Ity_F128: {
3728 HReg dst_hi, dst_lo, res_hi, res_lo;
3729
3730 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3731 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3732
3733 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3734 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3735 return;
3736 }
3737
floriane38f6412012-12-21 17:32:12 +00003738 case Ity_D32:
florian12390202012-11-10 22:34:14 +00003739 case Ity_D64:
3740 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
3741 dst = lookupIRTemp(env, tmp);
3742 break;
3743
floriane38f6412012-12-21 17:32:12 +00003744 case Ity_D128: {
3745 HReg dst_hi, dst_lo, res_hi, res_lo;
3746
3747 s390_isel_dfp128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
3748 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
3749
3750 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
3751 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
3752 return;
3753 }
3754
sewardj2019a972011-03-07 16:04:07 +00003755 default:
3756 goto stmt_fail;
3757 }
3758
3759 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
3760 return;
3761 }
3762
3763 /* --------- Call to DIRTY helper --------- */
3764 case Ist_Dirty: {
3765 IRType retty;
3766 IRDirty* d = stmt->Ist.Dirty.details;
florian01ed6e72012-05-27 16:52:43 +00003767 HReg dst;
sewardj74142b82013-08-08 10:28:59 +00003768 RetLoc rloc = mk_RetLoc_INVALID();
3769 UInt addToSp = 0;
florianad43b3a2012-02-20 15:01:14 +00003770 Int i;
3771
3772 /* Invalidate tracked values of those guest state registers that are
3773 modified by this helper. */
3774 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00003775 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
3776 descriptors in guest state effect descriptions. Hence: */
3777 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00003778 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
3779 Int guest_reg = get_guest_reg(d->fxState[i].offset);
3780 if (guest_reg != GUEST_UNKNOWN)
3781 env->old_value_valid[guest_reg] = False;
3782 }
3783 }
sewardj2019a972011-03-07 16:04:07 +00003784
florian01ed6e72012-05-27 16:52:43 +00003785 if (d->tmp == IRTemp_INVALID) {
3786 /* No return value. */
sewardj74142b82013-08-08 10:28:59 +00003787 retty = Ity_INVALID;
3788 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3789 d->args);
3790 vassert(is_sane_RetLoc(rloc));
3791 vassert(rloc.pri == RLPri_None);
3792 vassert(addToSp == 0);
3793
sewardj2019a972011-03-07 16:04:07 +00003794 return;
florian01ed6e72012-05-27 16:52:43 +00003795 }
sewardj2019a972011-03-07 16:04:07 +00003796
3797 retty = typeOfIRTemp(env->type_env, d->tmp);
3798 if (retty == Ity_I64 || retty == Ity_I32
3799 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00003800 /* Move the returned value to the destination register */
sewardj74142b82013-08-08 10:28:59 +00003801 HReg ret = make_gpr(S390_REGNO_RETURN_VALUE);
3802
florian01ed6e72012-05-27 16:52:43 +00003803 dst = lookupIRTemp(env, d->tmp);
sewardj74142b82013-08-08 10:28:59 +00003804 doHelperCall(&addToSp, &rloc, env, d->guard, d->cee, retty,
3805 d->args);
3806 vassert(is_sane_RetLoc(rloc));
3807 vassert(rloc.pri == RLPri_Int);
3808 vassert(addToSp == 0);
3809 addInstr(env, s390_insn_move(sizeof(ULong), dst, ret));
3810
sewardj2019a972011-03-07 16:04:07 +00003811 return;
3812 }
3813 break;
3814 }
3815
3816 case Ist_CAS:
3817 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3818 IRCAS *cas = stmt->Ist.CAS.details;
florian406ac942014-11-22 20:10:21 +00003819 s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr);
sewardj2019a972011-03-07 16:04:07 +00003820 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
3821 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3822 HReg old = lookupIRTemp(env, cas->oldLo);
3823
3824 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3825 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
3826 } else {
3827 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
3828 }
3829 return;
3830 } else {
florian448cbba2012-06-06 02:26:01 +00003831 IRCAS *cas = stmt->Ist.CAS.details;
florian406ac942014-11-22 20:10:21 +00003832 s390_amode *op2 = s390_isel_amode_b12_b20(env, cas->addr);
florian448cbba2012-06-06 02:26:01 +00003833 HReg r8, r9, r10, r11, r1;
3834 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
3835 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
3836 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
3837 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
3838 HReg old_low = lookupIRTemp(env, cas->oldLo);
3839 HReg old_high = lookupIRTemp(env, cas->oldHi);
3840
3841 /* Use non-virtual registers r8 and r9 as pair for op1
3842 and move op1 there */
3843 r8 = make_gpr(8);
3844 r9 = make_gpr(9);
3845 addInstr(env, s390_insn_move(8, r8, op1_high));
3846 addInstr(env, s390_insn_move(8, r9, op1_low));
3847
3848 /* Use non-virtual registers r10 and r11 as pair for op3
3849 and move op3 there */
3850 r10 = make_gpr(10);
3851 r11 = make_gpr(11);
3852 addInstr(env, s390_insn_move(8, r10, op3_high));
3853 addInstr(env, s390_insn_move(8, r11, op3_low));
3854
3855 /* Register r1 is used as a scratch register */
3856 r1 = make_gpr(1);
3857
3858 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3859 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
3860 old_high, old_low, r1));
3861 } else {
3862 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
3863 old_high, old_low, r1));
3864 }
3865 addInstr(env, s390_insn_move(8, op1_high, r8));
3866 addInstr(env, s390_insn_move(8, op1_low, r9));
3867 addInstr(env, s390_insn_move(8, op3_high, r10));
3868 addInstr(env, s390_insn_move(8, op3_low, r11));
3869 return;
sewardj2019a972011-03-07 16:04:07 +00003870 }
3871 break;
3872
3873 /* --------- EXIT --------- */
3874 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00003875 s390_cc_t cond;
3876 IRConstTag tag = stmt->Ist.Exit.dst->tag;
3877
3878 if (tag != Ico_U64)
3879 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
3880
florian8844a632012-04-13 04:04:06 +00003881 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00003882 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00003883
3884 /* Case: boring transfer to known address */
3885 if (stmt->Ist.Exit.jk == Ijk_Boring) {
3886 if (env->chaining_allowed) {
3887 /* .. almost always true .. */
3888 /* Skip the event check at the dst if this is a forwards
3889 edge. */
3890 Bool to_fast_entry
3891 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
3892 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
3893 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
3894 guest_IA, to_fast_entry));
3895 } else {
3896 /* .. very occasionally .. */
3897 /* We can't use chaining, so ask for an assisted transfer,
3898 as that's the only alternative that is allowable. */
3899 HReg dst = s390_isel_int_expr(env,
3900 IRExpr_Const(stmt->Ist.Exit.dst));
3901 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
3902 }
3903 return;
3904 }
3905
3906 /* Case: assisted transfer to arbitrary address */
3907 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00003908 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003909 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003910 case Ijk_NoDecode:
sewardj05f5e012014-05-04 10:52:11 +00003911 case Ijk_InvalICache:
florian2d98d892012-04-14 20:35:17 +00003912 case Ijk_Sys_syscall:
3913 case Ijk_ClientReq:
3914 case Ijk_NoRedir:
3915 case Ijk_Yield:
3916 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00003917 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
3918 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
3919 stmt->Ist.Exit.jk));
3920 return;
3921 }
3922 default:
3923 break;
3924 }
3925
3926 /* Do we ever expect to see any other kind? */
3927 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00003928 }
3929
3930 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00003931 case Ist_MBE:
3932 switch (stmt->Ist.MBE.event) {
3933 case Imbe_Fence:
3934 addInstr(env, s390_insn_mfence());
3935 return;
3936 default:
3937 break;
3938 }
sewardj2019a972011-03-07 16:04:07 +00003939 break;
3940
3941 /* --------- Miscellaneous --------- */
3942
3943 case Ist_PutI: /* Not needed */
3944 case Ist_IMark: /* Doesn't generate any executable code */
3945 case Ist_NoOp: /* Doesn't generate any executable code */
3946 case Ist_AbiHint: /* Meaningless in IR */
3947 return;
3948
3949 default:
3950 break;
3951 }
3952
3953 stmt_fail:
3954 ppIRStmt(stmt);
3955 vpanic("s390_isel_stmt");
3956}
3957
3958
3959/*---------------------------------------------------------*/
3960/*--- ISEL: Basic block terminators (Nexts) ---*/
3961/*---------------------------------------------------------*/
3962
3963static void
florianffbd84d2012-12-09 02:06:29 +00003964iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00003965{
sewardj2019a972011-03-07 16:04:07 +00003966 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00003967 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00003968 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00003969 vex_printf("; exit-");
3970 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00003971 vex_printf("\n");
3972 }
3973
florian8844a632012-04-13 04:04:06 +00003974 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
3975
3976 /* Case: boring transfer to known address */
3977 if (next->tag == Iex_Const) {
3978 IRConst *cdst = next->Iex.Const.con;
3979 vassert(cdst->tag == Ico_U64);
3980 if (jk == Ijk_Boring || jk == Ijk_Call) {
3981 /* Boring transfer to known address */
3982 if (env->chaining_allowed) {
3983 /* .. almost always true .. */
3984 /* Skip the event check at the dst if this is a forwards
3985 edge. */
3986 Bool to_fast_entry
3987 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3988 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3989 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3990 guest_IA, to_fast_entry));
3991 } else {
3992 /* .. very occasionally .. */
3993 /* We can't use chaining, so ask for an indirect transfer,
3994 as that's the cheapest alternative that is allowable. */
3995 HReg dst = s390_isel_int_expr(env, next);
3996 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3997 Ijk_Boring));
3998 }
3999 return;
4000 }
4001 }
4002
4003 /* Case: call/return (==boring) transfer to any address */
4004 switch (jk) {
4005 case Ijk_Boring:
4006 case Ijk_Ret:
4007 case Ijk_Call: {
4008 HReg dst = s390_isel_int_expr(env, next);
4009 if (env->chaining_allowed) {
4010 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
4011 } else {
4012 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
4013 Ijk_Boring));
4014 }
4015 return;
4016 }
4017 default:
4018 break;
4019 }
4020
4021 /* Case: some other kind of transfer to any address */
4022 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00004023 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00004024 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00004025 case Ijk_NoDecode:
sewardj05f5e012014-05-04 10:52:11 +00004026 case Ijk_InvalICache:
florian8844a632012-04-13 04:04:06 +00004027 case Ijk_Sys_syscall:
4028 case Ijk_ClientReq:
4029 case Ijk_NoRedir:
4030 case Ijk_Yield:
4031 case Ijk_SigTRAP: {
4032 HReg dst = s390_isel_int_expr(env, next);
4033 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
4034 return;
4035 }
4036 default:
4037 break;
4038 }
4039
4040 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00004041}
4042
4043
4044/*---------------------------------------------------------*/
4045/*--- Insn selector top-level ---*/
4046/*---------------------------------------------------------*/
4047
florianf26994a2012-04-21 03:34:54 +00004048/* Translate an entire SB to s390 code.
4049 Note: archinfo_host is a pointer to a stack-allocated variable.
4050 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00004051
4052HInstrArray *
floriand8c64e02014-10-08 08:54:44 +00004053iselSB_S390(IRSB *bb, VexArch arch_host, const VexArchInfo *archinfo_host,
4054 const VexAbiInfo *vbi, Int offset_host_evcheck_counter,
florian8844a632012-04-13 04:04:06 +00004055 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
4056 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00004057{
4058 UInt i, j;
4059 HReg hreg, hregHI;
4060 ISelEnv *env;
4061 UInt hwcaps_host = archinfo_host->hwcaps;
4062
florianf26994a2012-04-21 03:34:54 +00004063 /* KLUDGE: export hwcaps. */
4064 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00004065
sewardj2019a972011-03-07 16:04:07 +00004066 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00004067 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00004068
sewardj9b769162014-07-24 12:42:03 +00004069 /* Check that the host's endianness is as expected. */
4070 vassert(archinfo_host->endness == VexEndnessBE);
4071
sewardj2019a972011-03-07 16:04:07 +00004072 /* Make up an initial environment to use. */
4073 env = LibVEX_Alloc(sizeof(ISelEnv));
4074 env->vreg_ctr = 0;
4075
4076 /* Set up output code array. */
4077 env->code = newHInstrArray();
4078
4079 /* Copy BB's type env. */
4080 env->type_env = bb->tyenv;
4081
florianad43b3a2012-02-20 15:01:14 +00004082 /* Set up data structures for tracking guest register values. */
florianad43b3a2012-02-20 15:01:14 +00004083 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
4084 env->old_value[i] = 0; /* just something to have a defined value */
4085 env->old_value_valid[i] = False;
4086 }
4087
sewardj2019a972011-03-07 16:04:07 +00004088 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
4089 change as we go along. For some reason types_used has Int type -- but
4090 it should be unsigned. Internally we use an unsigned type; so we
4091 assert it here. */
4092 vassert(bb->tyenv->types_used >= 0);
4093
4094 env->n_vregmap = bb->tyenv->types_used;
4095 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4096 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4097
florian2c74d242012-09-12 19:38:42 +00004098 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00004099 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00004100
sewardj2019a972011-03-07 16:04:07 +00004101 /* and finally ... */
4102 env->hwcaps = hwcaps_host;
4103
florian8844a632012-04-13 04:04:06 +00004104 env->max_ga = max_ga;
4105 env->chaining_allowed = chaining_allowed;
4106
sewardj2019a972011-03-07 16:04:07 +00004107 /* For each IR temporary, allocate a suitably-kinded virtual
4108 register. */
4109 j = 0;
4110 for (i = 0; i < env->n_vregmap; i++) {
4111 hregHI = hreg = INVALID_HREG;
4112 switch (bb->tyenv->types[i]) {
4113 case Ity_I1:
4114 case Ity_I8:
4115 case Ity_I16:
4116 case Ity_I32:
4117 hreg = mkHReg(j++, HRcInt64, True);
4118 break;
4119
4120 case Ity_I64:
4121 hreg = mkHReg(j++, HRcInt64, True);
4122 break;
4123
4124 case Ity_I128:
4125 hreg = mkHReg(j++, HRcInt64, True);
4126 hregHI = mkHReg(j++, HRcInt64, True);
4127 break;
4128
4129 case Ity_F32:
4130 case Ity_F64:
floriane38f6412012-12-21 17:32:12 +00004131 case Ity_D32:
florian12390202012-11-10 22:34:14 +00004132 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00004133 hreg = mkHReg(j++, HRcFlt64, True);
4134 break;
4135
4136 case Ity_F128:
floriane38f6412012-12-21 17:32:12 +00004137 case Ity_D128:
sewardj2019a972011-03-07 16:04:07 +00004138 hreg = mkHReg(j++, HRcFlt64, True);
4139 hregHI = mkHReg(j++, HRcFlt64, True);
4140 break;
4141
4142 case Ity_V128: /* fall through */
4143 default:
4144 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00004145 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00004146 }
4147
4148 env->vregmap[i] = hreg;
4149 env->vregmapHI[i] = hregHI;
4150 }
4151 env->vreg_ctr = j;
4152
florian8844a632012-04-13 04:04:06 +00004153 /* The very first instruction must be an event check. */
4154 s390_amode *counter, *fail_addr;
4155 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
4156 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
4157 addInstr(env, s390_insn_evcheck(counter, fail_addr));
4158
4159 /* Possibly a block counter increment (for profiling). At this
4160 point we don't know the address of the counter, so just pretend
4161 it is zero. It will have to be patched later, but before this
4162 translation is used, by a call to LibVEX_patchProfInc. */
4163 if (add_profinc) {
4164 addInstr(env, s390_insn_profinc());
4165 }
4166
sewardj2019a972011-03-07 16:04:07 +00004167 /* Ok, finally we can iterate over the statements. */
4168 for (i = 0; i < bb->stmts_used; i++)
4169 if (bb->stmts[i])
4170 s390_isel_stmt(env, bb->stmts[i]);
4171
florian8844a632012-04-13 04:04:06 +00004172 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00004173
4174 /* Record the number of vregs we used. */
4175 env->code->n_vregs = env->vreg_ctr;
4176
4177 return env->code;
4178}
4179
4180/*---------------------------------------------------------------*/
4181/*--- end host_s390_isel.c ---*/
4182/*---------------------------------------------------------------*/