blob: 040abaaf3b4efdf24f709a0098d453b1a15e08a3 [file] [log] [blame]
sewardj2019a972011-03-07 16:04:07 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
2
3/*---------------------------------------------------------------*/
4/*--- begin host_s390_isel.c ---*/
5/*---------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
florian61f23c12012-08-06 18:33:21 +000011 Copyright IBM Corp. 2010-2012
florian2c74d242012-09-12 19:38:42 +000012 Copyright (C) 2012-2012 Florian Krohm (britzel@acm.org)
sewardj2019a972011-03-07 16:04:07 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
32/* Contributed by Florian Krohm */
33
34#include "libvex_basictypes.h"
35#include "libvex_ir.h"
36#include "libvex.h"
37#include "libvex_s390x_common.h"
38
sewardj2019a972011-03-07 16:04:07 +000039#include "main_util.h"
40#include "main_globals.h"
florianad43b3a2012-02-20 15:01:14 +000041#include "guest_s390_defs.h" /* guest_s390x_state_requires_precise_mem_exns */
sewardj2019a972011-03-07 16:04:07 +000042#include "host_generic_regs.h"
43#include "host_s390_defs.h"
44
45/*---------------------------------------------------------*/
46/*--- ISelEnv ---*/
47/*---------------------------------------------------------*/
48
49/* This carries around:
50
51 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
52 might encounter. This is computed before insn selection starts,
53 and does not change.
54
55 - A mapping from IRTemp to HReg. This tells the insn selector
56 which virtual register(s) are associated with each IRTemp
57 temporary. This is computed before insn selection starts, and
58 does not change. We expect this mapping to map precisely the
59 same set of IRTemps as the type mapping does.
60
61 - vregmap holds the primary register for the IRTemp.
62 - vregmapHI holds the secondary register for the IRTemp,
63 if any is needed. That's only for Ity_I64 temps
64 in 32 bit mode or Ity_I128 temps in 64-bit mode.
65
66 - The code array, that is, the insns selected so far.
67
68 - A counter, for generating new virtual registers.
69
70 - The host subarchitecture we are selecting insns for.
71 This is set at the start and does not change.
florianad43b3a2012-02-20 15:01:14 +000072
florian8844a632012-04-13 04:04:06 +000073 - A Bool for indicating whether we may generate chain-me
74 instructions for control flow transfers, or whether we must use
75 XAssisted.
76
77 - The maximum guest address of any guest insn in this block.
78 Actually, the address of the highest-addressed byte from any insn
79 in this block. Is set at the start and does not change. This is
80 used for detecting jumps which are definitely forward-edges from
81 this block, and therefore can be made (chained) to the fast entry
82 point of the destination, thereby avoiding the destination's
83 event check.
84
florianad43b3a2012-02-20 15:01:14 +000085 - A flag to indicate whether the guest IA has been assigned to.
86
87 - Values of certain guest registers which are often assigned constants.
sewardj2019a972011-03-07 16:04:07 +000088*/
89
florianad43b3a2012-02-20 15:01:14 +000090/* Symbolic names for guest registers whose value we're tracking */
91enum {
92 GUEST_IA,
93 GUEST_CC_OP,
94 GUEST_CC_DEP1,
95 GUEST_CC_DEP2,
96 GUEST_CC_NDEP,
97 GUEST_SYSNO,
florian7d117ba2012-05-06 03:34:55 +000098 GUEST_COUNTER,
florianad43b3a2012-02-20 15:01:14 +000099 GUEST_UNKNOWN /* must be the last entry */
100};
101
102/* Number of registers we're tracking. */
103#define NUM_TRACKED_REGS GUEST_UNKNOWN
104
105
sewardj2019a972011-03-07 16:04:07 +0000106typedef struct {
107 IRTypeEnv *type_env;
108
florian8844a632012-04-13 04:04:06 +0000109 HInstrArray *code;
sewardj2019a972011-03-07 16:04:07 +0000110 HReg *vregmap;
111 HReg *vregmapHI;
112 UInt n_vregmap;
florian8844a632012-04-13 04:04:06 +0000113 UInt vreg_ctr;
114 UInt hwcaps;
sewardj2019a972011-03-07 16:04:07 +0000115
florian2c74d242012-09-12 19:38:42 +0000116 IRExpr *previous_bfp_rounding_mode;
florianc8e4f562012-10-27 16:19:31 +0000117 IRExpr *previous_dfp_rounding_mode;
florian2c74d242012-09-12 19:38:42 +0000118
florianad43b3a2012-02-20 15:01:14 +0000119 ULong old_value[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000120
florian8844a632012-04-13 04:04:06 +0000121 /* The next two are for translation chaining */
122 Addr64 max_ga;
123 Bool chaining_allowed;
124
florianad43b3a2012-02-20 15:01:14 +0000125 Bool first_IA_assignment;
126 Bool old_value_valid[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000127} ISelEnv;
128
129
130/* Forward declarations */
131static HReg s390_isel_int_expr(ISelEnv *, IRExpr *);
132static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *);
133static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
134static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
135static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
136static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
137static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
florian12390202012-11-10 22:34:14 +0000138static HReg s390_isel_dfp_expr(ISelEnv *, IRExpr *);
sewardj2019a972011-03-07 16:04:07 +0000139
140
florianad43b3a2012-02-20 15:01:14 +0000141static Int
142get_guest_reg(Int offset)
143{
144 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000145 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
146 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
147 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
148 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
149 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
150 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000151 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000152
153 /* Also make sure there is never a partial write to one of
154 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000155 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
156 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
157 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
158 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
159 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000160 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
161 /* counter is used both as 4-byte and as 8-byte entity */
162 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
163 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianaf50a192012-07-13 14:13:06 +0000164 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000165 break;
166
167 default: break;
168 }
169
170 return GUEST_UNKNOWN;
171}
172
sewardj2019a972011-03-07 16:04:07 +0000173/* Add an instruction */
174static void
175addInstr(ISelEnv *env, s390_insn *insn)
176{
177 addHInstr(env->code, insn);
178
179 if (vex_traceflags & VEX_TRACE_VCODE) {
180 vex_printf("%s\n", s390_insn_as_string(insn));
181 }
182}
183
184
185static __inline__ IRExpr *
186mkU64(ULong value)
187{
188 return IRExpr_Const(IRConst_U64(value));
189}
190
191
192/*---------------------------------------------------------*/
193/*--- Registers ---*/
194/*---------------------------------------------------------*/
195
196/* Return the virtual register to which a given IRTemp is mapped. */
197static HReg
198lookupIRTemp(ISelEnv *env, IRTemp tmp)
199{
200 vassert(tmp < env->n_vregmap);
201 vassert(env->vregmap[tmp] != INVALID_HREG);
202
203 return env->vregmap[tmp];
204}
205
206
207/* Return the two virtual registers to which the IRTemp is mapped. */
208static void
209lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
210{
211 vassert(tmp < env->n_vregmap);
212 vassert(env->vregmapHI[tmp] != INVALID_HREG);
213
214 *lo = env->vregmap[tmp];
215 *hi = env->vregmapHI[tmp];
216}
217
218
219/* Allocate a new integer register */
220static HReg
221newVRegI(ISelEnv *env)
222{
223 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
224 env->vreg_ctr++;
225
226 return reg;
227}
228
229
230/* Allocate a new floating point register */
231static HReg
232newVRegF(ISelEnv *env)
233{
234 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
235
236 env->vreg_ctr++;
237
238 return reg;
239}
240
241
242/* Construct a non-virtual general purpose register */
243static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000244make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000245{
246 return mkHReg(regno, HRcInt64, False /* virtual */ );
247}
248
249
250/* Construct a non-virtual floating point register */
251static __inline__ HReg
252make_fpr(UInt regno)
253{
254 return mkHReg(regno, HRcFlt64, False /* virtual */ );
255}
256
257
258/*---------------------------------------------------------*/
259/*--- Amode ---*/
260/*---------------------------------------------------------*/
261
262static __inline__ Bool
263ulong_fits_unsigned_12bit(ULong val)
264{
265 return (val & 0xFFFu) == val;
266}
267
268
269static __inline__ Bool
270ulong_fits_signed_20bit(ULong val)
271{
272 Long v = val & 0xFFFFFu;
273
274 v = (v << 44) >> 44; /* sign extend */
275
276 return val == (ULong)v;
277}
278
279
florianad43b3a2012-02-20 15:01:14 +0000280static __inline__ Bool
281ulong_fits_signed_8bit(ULong val)
282{
283 Long v = val & 0xFFu;
284
285 v = (v << 56) >> 56; /* sign extend */
286
287 return val == (ULong)v;
288}
289
sewardj2019a972011-03-07 16:04:07 +0000290/* EXPR is an expression that is used as an address. Return an s390_amode
291 for it. */
292static s390_amode *
293s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
294{
295 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
296 IRExpr *arg1 = expr->Iex.Binop.arg1;
297 IRExpr *arg2 = expr->Iex.Binop.arg2;
298
299 /* Move constant into right subtree */
300 if (arg1->tag == Iex_Const) {
301 IRExpr *tmp;
302 tmp = arg1;
303 arg1 = arg2;
304 arg2 = tmp;
305 }
306
307 /* r + constant: Check for b12 first, then b20 */
308 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
309 ULong value = arg2->Iex.Const.con->Ico.U64;
310
311 if (ulong_fits_unsigned_12bit(value)) {
312 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
313 }
sewardj652b56a2011-04-13 15:38:17 +0000314 /* If long-displacement is not available, do not construct B20 or
315 BX20 amodes because code generation cannot handle them. */
316 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000317 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
318 }
319 }
320 }
321
322 /* Doesn't match anything in particular. Generate it into
323 a register and use that. */
324 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
325}
326
327
328static s390_amode *
329s390_isel_amode(ISelEnv *env, IRExpr *expr)
330{
florian35da8612011-06-25 02:25:41 +0000331 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000332
333 /* Address computation should yield a 64-bit value */
334 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
335
336 am = s390_isel_amode_wrk(env, expr);
337
338 /* Check post-condition */
339 vassert(s390_amode_is_sane(am));
340
341 return am;
342}
343
344
345/*---------------------------------------------------------*/
346/*--- Helper functions ---*/
347/*---------------------------------------------------------*/
348
349/* Constants and memory accesses should be right operands */
350#define order_commutative_operands(left, right) \
351 do { \
352 if (left->tag == Iex_Const || left->tag == Iex_Load || \
353 left->tag == Iex_Get) { \
354 IRExpr *tmp; \
355 tmp = left; \
356 left = right; \
357 right = tmp; \
358 } \
359 } while (0)
360
361
362/* Copy an RMI operand to the DST register */
363static s390_insn *
364s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
365{
366 switch (opnd.tag) {
367 case S390_OPND_AMODE:
368 return s390_insn_load(size, dst, opnd.variant.am);
369
370 case S390_OPND_REG:
371 return s390_insn_move(size, dst, opnd.variant.reg);
372
373 case S390_OPND_IMMEDIATE:
374 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
375
376 default:
377 vpanic("s390_opnd_copy");
378 }
379}
380
381
382/* Construct a RMI operand for a register */
383static __inline__ s390_opnd_RMI
384s390_opnd_reg(HReg reg)
385{
386 s390_opnd_RMI opnd;
387
388 opnd.tag = S390_OPND_REG;
389 opnd.variant.reg = reg;
390
391 return opnd;
392}
393
394
395/* Construct a RMI operand for an immediate constant */
396static __inline__ s390_opnd_RMI
397s390_opnd_imm(ULong value)
398{
399 s390_opnd_RMI opnd;
400
401 opnd.tag = S390_OPND_IMMEDIATE;
402 opnd.variant.imm = value;
403
404 return opnd;
405}
406
407
florianffbd84d2012-12-09 02:06:29 +0000408/* Return 1, if EXPR represents the constant 0 */
409static Bool
sewardj2019a972011-03-07 16:04:07 +0000410s390_expr_is_const_zero(IRExpr *expr)
411{
412 ULong value;
413
414 if (expr->tag == Iex_Const) {
415 switch (expr->Iex.Const.con->tag) {
416 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
417 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
418 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
419 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
420 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
421 default:
422 vpanic("s390_expr_is_const_zero");
423 }
424 return value == 0;
425 }
426
427 return 0;
428}
429
430
431/* Call a helper (clean or dirty)
432 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000433
sewardj2019a972011-03-07 16:04:07 +0000434 (a) they are expressions yielding an integer result
435 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000436
437 guard is a Ity_Bit expression indicating whether or not the
438 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000439
440 Calling the helper function proceeds as follows:
441
442 (1) The helper arguments are evaluated and their value stored in
443 virtual registers.
444 (2) The condition code is evaluated
445 (3) The argument values are copied from the virtual registers to the
446 registers mandated by the ABI.
447 (4) Call the helper function.
448
449 This is not the most efficient way as step 3 generates register-to-register
450 moves. But it is the least fragile way as the only hidden dependency here
451 is that register-to-register moves (step 3) must not clobber the condition
452 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
453 to-register add more such dependencies. Not good. Besides, it's the job
454 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000455*/
456static void
457doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000458 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000459{
florian52af7bc2012-05-12 03:44:49 +0000460 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000461 ULong target;
462 HReg tmpregs[S390_NUM_GPRPARMS];
463 s390_cc_t cc;
464
465 n_args = 0;
466 for (i = 0; args[i]; i++)
467 ++n_args;
468
469 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
470 vpanic("doHelperCall: too many arguments");
471 }
472
florian11b8ee82012-08-06 13:35:33 +0000473 /* All arguments must have Ity_I64. For two reasons:
474 (1) We do not handle floating point arguments.
475 (2) The ABI requires that integer values are sign- or zero-extended
476 to 64 bit.
477 */
478 Int arg_errors = 0;
479 for (i = 0; i < n_args; ++i) {
480 IRType type = typeOfIRExpr(env->type_env, args[i]);
481 if (type != Ity_I64) {
482 ++arg_errors;
483 vex_printf("calling %s: argument #%d has type ", callee->name, i);
484 ppIRType(type);
485 vex_printf("; Ity_I64 is required\n");
486 }
487 }
488
489 if (arg_errors)
490 vpanic("cannot continue due to errors in argument passing");
491
florian52af7bc2012-05-12 03:44:49 +0000492 argreg = 0;
493
494 /* If we need the guest state pointer put it in a temporary arg reg */
495 if (passBBP) {
496 tmpregs[argreg] = newVRegI(env);
497 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
498 s390_hreg_guest_state_pointer()));
499 argreg++;
500 }
501
502 /* Compute the function arguments into a temporary register each */
503 for (i = 0; i < n_args; i++) {
504 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
505 argreg++;
506 }
507
sewardj2019a972011-03-07 16:04:07 +0000508 /* Compute the condition */
509 cc = S390_CC_ALWAYS;
510 if (guard) {
511 if (guard->tag == Iex_Const
512 && guard->Iex.Const.con->tag == Ico_U1
513 && guard->Iex.Const.con->Ico.U1 == True) {
514 /* unconditional -- do nothing */
515 } else {
516 cc = s390_isel_cc(env, guard);
517 }
518 }
519
florian52af7bc2012-05-12 03:44:49 +0000520 /* Move the args to the final register. It is paramount, that the
521 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000522 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000523 HReg finalreg;
524
525 finalreg = make_gpr(s390_gprno_from_arg_index(i));
526 size = sizeofIRType(Ity_I64);
527 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000528 }
529
530 target = Ptr_to_ULong(callee->addr);
531
532 /* Finally, the call itself. */
533 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000534 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000535}
536
537
florian2c74d242012-09-12 19:38:42 +0000538/*---------------------------------------------------------*/
539/*--- BFP helper functions ---*/
540/*---------------------------------------------------------*/
541
542/* Set the BFP rounding mode in the FPC. This function is called for
543 all non-conversion BFP instructions as those will always get the
544 rounding mode from the FPC. */
545static void
546set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000547{
florian2c74d242012-09-12 19:38:42 +0000548 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
549
550 /* Do we need to do anything? */
551 if (env->previous_bfp_rounding_mode &&
552 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
553 irrm->tag == Iex_RdTmp &&
554 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
555 /* No - new mode is identical to previous mode. */
556 return;
557 }
558
559 /* No luck - we better set it, and remember what we set it to. */
560 env->previous_bfp_rounding_mode = irrm;
561
562 /* The incoming rounding mode is in VEX IR encoding. Need to change
563 to s390.
564
565 rounding mode | s390 | IR
566 -------------------------
567 to nearest | 00 | 00
568 to zero | 01 | 11
569 to +infinity | 10 | 10
570 to -infinity | 11 | 01
571
572 So: s390 = (4 - IR) & 3
573 */
574 HReg ir = s390_isel_int_expr(env, irrm);
575
576 HReg mode = newVRegI(env);
577
578 addInstr(env, s390_insn_load_immediate(4, mode, 4));
579 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
580 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
581
florian125e20d2012-10-07 15:42:37 +0000582 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000583}
584
585
586/* This function is invoked for insns that support a specification of
587 a rounding mode in the insn itself. In that case there is no need to
588 stick the rounding mode into the FPC -- a good thing. However, the
589 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000590static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000591get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
592{
593 if (irrm->tag == Iex_Const) { /* rounding mode is known */
594 vassert(irrm->Iex.Const.con->tag == Ico_U32);
595 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000596
597 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000598 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
599 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
600 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
601 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000602 default:
603 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000604 }
605 }
606
florian2c74d242012-09-12 19:38:42 +0000607 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000608 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000609}
610
611
florianc8e4f562012-10-27 16:19:31 +0000612/*---------------------------------------------------------*/
613/*--- DFP helper functions ---*/
614/*---------------------------------------------------------*/
615
616/* Set the DFP rounding mode in the FPC. This function is called for
617 all non-conversion DFP instructions as those will always get the
618 rounding mode from the FPC. */
florianc8e4f562012-10-27 16:19:31 +0000619static void
620set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
621{
622 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
623
624 /* Do we need to do anything? */
625 if (env->previous_dfp_rounding_mode &&
626 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
627 irrm->tag == Iex_RdTmp &&
628 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
629 /* No - new mode is identical to previous mode. */
630 return;
631 }
632
633 /* No luck - we better set it, and remember what we set it to. */
634 env->previous_dfp_rounding_mode = irrm;
635
636 /* The incoming rounding mode is in VEX IR encoding. Need to change
637 to s390.
638
639 rounding mode | S390 | IR
640 -----------------------------------------------
641 to nearest, ties to even | 000 | 000
642 to zero | 001 | 011
643 to +infinity | 010 | 010
644 to -infinity | 011 | 001
645 to nearest, ties away from 0 | 100 | 100
646 to nearest, ties toward 0 | 101 | 111
647 to away from 0 | 110 | 110
648 to prepare for shorter precision | 111 | 101
649
650 So: s390 = (IR ^ ((IR << 1) & 2))
651 */
652 HReg ir = s390_isel_int_expr(env, irrm);
653
654 HReg mode = newVRegI(env);
655
656 addInstr(env, s390_insn_move(4, mode, ir));
657 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
658 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
659 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
660
661 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
662}
663
664
665/* This function is invoked for insns that support a specification of
666 a rounding mode in the insn itself. In that case there is no need to
667 stick the rounding mode into the FPC -- a good thing. However, the
668 rounding mode must be known.
669 The IR to s390 encoding is chosen in the range 0:7 except
670 S390_DFP_ROUND_NEAREST_TIE_TOWARD_0 and
671 S390_DFP_ROUND_AWAY_0 which have no choice within the range.
672 Since the s390 dfp rounding mode encoding in 8:15 is not used, the
673 quantum excpetion is not suppressed and this is fine as valgrind does
674 not model this exception.
675
676 Translation table of
677 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
678
679 s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
680 --------------------------------------------------------------------
681 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_1
682 NEAREST_TIE_AWAY_0_12 | " | "
683 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_3
684 PREPARE_SHORT_15 | " | "
685 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_4
686 NEAREST_EVEN_8 | " | "
687 ZERO_5 | ZERO | ZERO_5
688 ZERO_9 | " | "
689 POSINF_6 | PosINF | POSINF_6
690 POSINF_10 | " | "
691 NEGINF_7 | NegINF | NEGINF_7
692 NEGINF_11 | " | "
693 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
694 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
695*/
696static s390_dfp_round_t
697get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
698{
699 if (irrm->tag == Iex_Const) { /* rounding mode is known */
700 vassert(irrm->Iex.Const.con->tag == Ico_U32);
florian3d6a4222012-11-19 16:29:31 +0000701 IRRoundingModeDFP mode = irrm->Iex.Const.con->Ico.U32;
florianc8e4f562012-10-27 16:19:31 +0000702
703 switch (mode) {
704 case Irrm_DFP_NEAREST:
705 return S390_DFP_ROUND_NEAREST_EVEN_4;
706 case Irrm_DFP_NegINF:
707 return S390_DFP_ROUND_NEGINF_7;
708 case Irrm_DFP_PosINF:
709 return S390_DFP_ROUND_POSINF_6;
710 case Irrm_DFP_ZERO:
711 return S390_DFP_ROUND_ZERO_5;
712 case Irrm_DFP_NEAREST_TIE_AWAY_0:
713 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1;
714 case Irrm_DFP_PREPARE_SHORTER:
715 return S390_DFP_ROUND_PREPARE_SHORT_3;
716 case Irrm_DFP_AWAY_FROM_ZERO:
717 return S390_DFP_ROUND_AWAY_0;
718 case Irrm_DFP_NEAREST_TIE_TOWARD_0:
719 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
720 default:
721 vpanic("get_dfp_rounding_mode");
722 }
723 }
724
725 set_dfp_rounding_mode_in_fpc(env, irrm);
726 return S390_DFP_ROUND_PER_FPC_0;
727}
florianc8e4f562012-10-27 16:19:31 +0000728
sewardj2019a972011-03-07 16:04:07 +0000729/* CC_S390 holds the condition code in s390 encoding. Convert it to
730 VEX encoding
731
732 s390 VEX b6 b2 b0 cc.1 cc.0
733 0 0x40 EQ 1 0 0 0 0
734 1 0x01 LT 0 0 1 0 1
735 2 0x00 GT 0 0 0 1 0
736 3 0x45 Unordered 1 1 1 1 1
737
738 b0 = cc.0
739 b2 = cc.0 & cc.1
740 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
741
742 VEX = b0 | (b2 << 2) | (b6 << 6);
743*/
744static HReg
745convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390)
746{
747 HReg cc0, cc1, b2, b6, cc_vex;
748
749 cc0 = newVRegI(env);
750 addInstr(env, s390_insn_move(4, cc0, cc_s390));
751 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
752
753 cc1 = newVRegI(env);
754 addInstr(env, s390_insn_move(4, cc1, cc_s390));
755 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
756
757 b2 = newVRegI(env);
758 addInstr(env, s390_insn_move(4, b2, cc0));
759 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
760 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
761
762 b6 = newVRegI(env);
763 addInstr(env, s390_insn_move(4, b6, cc0));
764 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
765 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
766 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
767 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
768
769 cc_vex = newVRegI(env);
770 addInstr(env, s390_insn_move(4, cc_vex, cc0));
771 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
772 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
773
774 return cc_vex;
775}
776
777
778/*---------------------------------------------------------*/
779/*--- ISEL: Integer expressions (128 bit) ---*/
780/*---------------------------------------------------------*/
781static void
782s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
783 IRExpr *expr)
784{
785 IRType ty = typeOfIRExpr(env->type_env, expr);
786
787 vassert(ty == Ity_I128);
788
789 /* No need to consider the following
790 - 128-bit constants (they do not exist in VEX)
791 - 128-bit loads from memory (will not be generated)
792 */
793
794 /* Read 128-bit IRTemp */
795 if (expr->tag == Iex_RdTmp) {
796 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
797 return;
798 }
799
800 if (expr->tag == Iex_Binop) {
801 IRExpr *arg1 = expr->Iex.Binop.arg1;
802 IRExpr *arg2 = expr->Iex.Binop.arg2;
803 Bool is_signed_multiply, is_signed_divide;
804
805 switch (expr->Iex.Binop.op) {
806 case Iop_MullU64:
807 is_signed_multiply = False;
808 goto do_multiply64;
809
810 case Iop_MullS64:
811 is_signed_multiply = True;
812 goto do_multiply64;
813
814 case Iop_DivModU128to64:
815 is_signed_divide = False;
816 goto do_divide64;
817
818 case Iop_DivModS128to64:
819 is_signed_divide = True;
820 goto do_divide64;
821
822 case Iop_64HLto128:
823 *dst_hi = s390_isel_int_expr(env, arg1);
824 *dst_lo = s390_isel_int_expr(env, arg2);
825 return;
826
827 case Iop_DivModS64to64: {
828 HReg r10, r11, h1;
829 s390_opnd_RMI op2;
830
831 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
832 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
833
834 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000835 r10 = make_gpr(10);
836 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000837
838 /* Move 1st operand into r11 and */
839 addInstr(env, s390_insn_move(8, r11, h1));
840
841 /* Divide */
842 addInstr(env, s390_insn_divs(8, r10, r11, op2));
843
844 /* The result is in registers r10 (remainder) and r11 (quotient).
845 Move the result into the reg pair that is being returned such
846 such that the low 64 bits are the quotient and the upper 64 bits
847 are the remainder. (see libvex_ir.h). */
848 *dst_hi = newVRegI(env);
849 *dst_lo = newVRegI(env);
850 addInstr(env, s390_insn_move(8, *dst_hi, r10));
851 addInstr(env, s390_insn_move(8, *dst_lo, r11));
852 return;
853 }
854
855 default:
856 break;
857
858 do_multiply64: {
859 HReg r10, r11, h1;
860 s390_opnd_RMI op2;
861
862 order_commutative_operands(arg1, arg2);
863
864 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
865 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
866
867 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000868 r10 = make_gpr(10);
869 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000870
871 /* Move the first operand to r11 */
872 addInstr(env, s390_insn_move(8, r11, h1));
873
874 /* Multiply */
875 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
876
877 /* The result is in registers r10 and r11. Assign to two virtual regs
878 and return. */
879 *dst_hi = newVRegI(env);
880 *dst_lo = newVRegI(env);
881 addInstr(env, s390_insn_move(8, *dst_hi, r10));
882 addInstr(env, s390_insn_move(8, *dst_lo, r11));
883 return;
884 }
885
886 do_divide64: {
887 HReg r10, r11, hi, lo;
888 s390_opnd_RMI op2;
889
890 s390_isel_int128_expr(&hi, &lo, env, arg1);
891 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
892
893 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000894 r10 = make_gpr(10);
895 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000896
897 /* Move high 64 bits of the 1st operand into r10 and
898 the low 64 bits into r11. */
899 addInstr(env, s390_insn_move(8, r10, hi));
900 addInstr(env, s390_insn_move(8, r11, lo));
901
902 /* Divide */
903 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
904
905 /* The result is in registers r10 (remainder) and r11 (quotient).
906 Move the result into the reg pair that is being returned such
907 such that the low 64 bits are the quotient and the upper 64 bits
908 are the remainder. (see libvex_ir.h). */
909 *dst_hi = newVRegI(env);
910 *dst_lo = newVRegI(env);
911 addInstr(env, s390_insn_move(8, *dst_hi, r10));
912 addInstr(env, s390_insn_move(8, *dst_lo, r11));
913 return;
914 }
915 }
916 }
917
918 vpanic("s390_isel_int128_expr");
919}
920
921
922/* Compute a 128-bit value into two 64-bit registers. These may be either
923 real or virtual regs; in any case they must not be changed by subsequent
924 code emitted by the caller. */
925static void
926s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
927{
928 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
929
930 /* Sanity checks ... */
931 vassert(hregIsVirtual(*dst_hi));
932 vassert(hregIsVirtual(*dst_lo));
933 vassert(hregClass(*dst_hi) == HRcInt64);
934 vassert(hregClass(*dst_lo) == HRcInt64);
935}
936
937
938/*---------------------------------------------------------*/
939/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
940/*---------------------------------------------------------*/
941
942/* Select insns for an integer-typed expression, and add them to the
943 code list. Return a reg holding the result. This reg will be a
944 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
945 want to modify it, ask for a new vreg, copy it in there, and modify
946 the copy. The register allocator will do its best to map both
947 vregs to the same real register, so the copies will often disappear
948 later in the game.
949
950 This should handle expressions of 64, 32, 16 and 8-bit type.
951 All results are returned in a 64bit register.
952 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
953 are arbitrary, so you should mask or sign extend partial values
954 if necessary.
955*/
956
957/* DO NOT CALL THIS DIRECTLY ! */
958static HReg
959s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
960{
961 IRType ty = typeOfIRExpr(env->type_env, expr);
962 UChar size;
florian9fcff4c2012-09-10 03:09:04 +0000963 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +0000964
965 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
966
967 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
968
969 switch (expr->tag) {
970
971 /* --------- TEMP --------- */
972 case Iex_RdTmp:
973 /* Return the virtual register that holds the temporary. */
974 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
975
976 /* --------- LOAD --------- */
977 case Iex_Load: {
978 HReg dst = newVRegI(env);
979 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
980
981 if (expr->Iex.Load.end != Iend_BE)
982 goto irreducible;
983
984 addInstr(env, s390_insn_load(size, dst, am));
985
986 return dst;
987 }
988
989 /* --------- BINARY OP --------- */
990 case Iex_Binop: {
991 IRExpr *arg1 = expr->Iex.Binop.arg1;
992 IRExpr *arg2 = expr->Iex.Binop.arg2;
993 HReg h1, res;
994 s390_alu_t opkind;
995 s390_opnd_RMI op2, value, opnd;
996 s390_insn *insn;
997 Bool is_commutative, is_signed_multiply, is_signed_divide;
998
999 is_commutative = True;
1000
1001 switch (expr->Iex.Binop.op) {
1002 case Iop_MullU8:
1003 case Iop_MullU16:
1004 case Iop_MullU32:
1005 is_signed_multiply = False;
1006 goto do_multiply;
1007
1008 case Iop_MullS8:
1009 case Iop_MullS16:
1010 case Iop_MullS32:
1011 is_signed_multiply = True;
1012 goto do_multiply;
1013
1014 do_multiply: {
1015 HReg r10, r11;
1016 UInt arg_size = size / 2;
1017
1018 order_commutative_operands(arg1, arg2);
1019
1020 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1021 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1022
1023 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001024 r10 = make_gpr(10);
1025 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001026
1027 /* Move the first operand to r11 */
1028 addInstr(env, s390_insn_move(arg_size, r11, h1));
1029
1030 /* Multiply */
1031 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1032
1033 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1034 value into the destination register. */
1035 res = newVRegI(env);
1036 addInstr(env, s390_insn_move(arg_size, res, r10));
1037 value = s390_opnd_imm(arg_size * 8);
1038 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1039 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1040 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1041 opnd = s390_opnd_reg(r11);
1042 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1043 return res;
1044 }
1045
1046 case Iop_DivModS64to32:
1047 is_signed_divide = True;
1048 goto do_divide;
1049
1050 case Iop_DivModU64to32:
1051 is_signed_divide = False;
1052 goto do_divide;
1053
1054 do_divide: {
1055 HReg r10, r11;
1056
1057 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1058 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1059
1060 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001061 r10 = make_gpr(10);
1062 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001063
1064 /* Split the first operand and put the high 32 bits into r10 and
1065 the low 32 bits into r11. */
1066 addInstr(env, s390_insn_move(8, r10, h1));
1067 addInstr(env, s390_insn_move(8, r11, h1));
1068 value = s390_opnd_imm(32);
1069 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1070
1071 /* Divide */
1072 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1073
1074 /* The result is in registers r10 (remainder) and r11 (quotient).
1075 Combine them into a 64-bit value such that the low 32 bits are
1076 the quotient and the upper 32 bits are the remainder. (see
1077 libvex_ir.h). */
1078 res = newVRegI(env);
1079 addInstr(env, s390_insn_move(8, res, r10));
1080 value = s390_opnd_imm(32);
1081 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1082 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1083 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1084 opnd = s390_opnd_reg(r11);
1085 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1086 return res;
1087 }
1088
florian9fcff4c2012-09-10 03:09:04 +00001089 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1090 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1091 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1092 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1093 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1094 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1095 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1096 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1097 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1098 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1099 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1100 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
sewardj2019a972011-03-07 16:04:07 +00001101
1102 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001103 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001104
1105 res = newVRegI(env);
1106 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1107
florian2c74d242012-09-12 19:38:42 +00001108 rounding_mode = get_bfp_rounding_mode(env, arg1);
1109 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1110 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001111 return res;
1112 }
1113
1114 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001115 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001116 HReg op_hi, op_lo, f13, f15;
1117
1118 res = newVRegI(env);
1119 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1120
1121 /* We use non-virtual registers r13 and r15 as pair */
1122 f13 = make_fpr(13);
1123 f15 = make_fpr(15);
1124
1125 /* operand --> (f13, f15) */
1126 addInstr(env, s390_insn_move(8, f13, op_hi));
1127 addInstr(env, s390_insn_move(8, f15, op_lo));
1128
florian2c74d242012-09-12 19:38:42 +00001129 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001130 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001131 rounding_mode));
1132 return res;
1133 }
1134
1135 case Iop_8HLto16:
1136 case Iop_16HLto32:
1137 case Iop_32HLto64: {
1138 HReg h2;
1139 UInt arg_size = size / 2;
1140
1141 res = newVRegI(env);
1142 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1143 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1144
1145 addInstr(env, s390_insn_move(arg_size, res, h1));
1146 value = s390_opnd_imm(arg_size * 8);
1147 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1148 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1149 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1150 opnd = s390_opnd_reg(h2);
1151 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1152 return res;
1153 }
1154
1155 case Iop_Max32U: {
1156 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1157 res = newVRegI(env);
1158 h1 = s390_isel_int_expr(env, arg1);
1159 op2 = s390_isel_int_expr_RMI(env, arg2);
1160
1161 addInstr(env, s390_insn_move(size, res, h1));
1162 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1163 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1164 return res;
1165 }
1166
1167 case Iop_CmpF32:
1168 case Iop_CmpF64: {
1169 HReg cc_s390, h2;
1170
1171 h1 = s390_isel_float_expr(env, arg1);
1172 h2 = s390_isel_float_expr(env, arg2);
1173 cc_s390 = newVRegI(env);
1174
1175 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1176
1177 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1178
1179 return convert_s390_fpcc_to_vex(env, cc_s390);
1180 }
1181
1182 case Iop_CmpF128: {
1183 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1184
1185 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1186 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1187 cc_s390 = newVRegI(env);
1188
1189 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1190 f12 = make_fpr(12);
1191 f13 = make_fpr(13);
1192 f14 = make_fpr(14);
1193 f15 = make_fpr(15);
1194
1195 /* 1st operand --> (f12, f14) */
1196 addInstr(env, s390_insn_move(8, f12, op1_hi));
1197 addInstr(env, s390_insn_move(8, f14, op1_lo));
1198
1199 /* 2nd operand --> (f13, f15) */
1200 addInstr(env, s390_insn_move(8, f13, op2_hi));
1201 addInstr(env, s390_insn_move(8, f15, op2_lo));
1202
1203 res = newVRegI(env);
1204 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1205
1206 return convert_s390_fpcc_to_vex(env, cc_s390);
1207 }
1208
1209 case Iop_Add8:
1210 case Iop_Add16:
1211 case Iop_Add32:
1212 case Iop_Add64:
1213 opkind = S390_ALU_ADD;
1214 break;
1215
1216 case Iop_Sub8:
1217 case Iop_Sub16:
1218 case Iop_Sub32:
1219 case Iop_Sub64:
1220 opkind = S390_ALU_SUB;
1221 is_commutative = False;
1222 break;
1223
1224 case Iop_And8:
1225 case Iop_And16:
1226 case Iop_And32:
1227 case Iop_And64:
1228 opkind = S390_ALU_AND;
1229 break;
1230
1231 case Iop_Or8:
1232 case Iop_Or16:
1233 case Iop_Or32:
1234 case Iop_Or64:
1235 opkind = S390_ALU_OR;
1236 break;
1237
1238 case Iop_Xor8:
1239 case Iop_Xor16:
1240 case Iop_Xor32:
1241 case Iop_Xor64:
1242 opkind = S390_ALU_XOR;
1243 break;
1244
1245 case Iop_Shl8:
1246 case Iop_Shl16:
1247 case Iop_Shl32:
1248 case Iop_Shl64:
1249 opkind = S390_ALU_LSH;
1250 is_commutative = False;
1251 break;
1252
1253 case Iop_Shr8:
1254 case Iop_Shr16:
1255 case Iop_Shr32:
1256 case Iop_Shr64:
1257 opkind = S390_ALU_RSH;
1258 is_commutative = False;
1259 break;
1260
1261 case Iop_Sar8:
1262 case Iop_Sar16:
1263 case Iop_Sar32:
1264 case Iop_Sar64:
1265 opkind = S390_ALU_RSHA;
1266 is_commutative = False;
1267 break;
1268
1269 default:
1270 goto irreducible;
1271 }
1272
1273 /* Pattern match: 0 - arg1 --> -arg1 */
1274 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1275 res = newVRegI(env);
1276 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1277 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1278 addInstr(env, insn);
1279
1280 return res;
1281 }
1282
1283 if (is_commutative) {
1284 order_commutative_operands(arg1, arg2);
1285 }
1286
1287 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1288 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1289 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001290
1291 /* As right shifts of one/two byte opreands are implemented using a
1292 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1293 switch (expr->Iex.Binop.op) {
1294 case Iop_Shr8:
1295 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1296 break;
1297 case Iop_Shr16:
1298 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1299 break;
1300 case Iop_Sar8:
1301 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1302 break;
1303 case Iop_Sar16:
1304 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1305 break;
1306 default:
1307 insn = s390_insn_move(size, res, h1);
1308 break;
1309 }
1310 addInstr(env, insn);
1311
sewardj2019a972011-03-07 16:04:07 +00001312 insn = s390_insn_alu(size, opkind, res, op2);
1313
1314 addInstr(env, insn);
1315
1316 return res;
1317 }
1318
1319 /* --------- UNARY OP --------- */
1320 case Iex_Unop: {
1321 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1322 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1323 s390_opnd_RMI opnd;
1324 s390_insn *insn;
1325 IRExpr *arg;
1326 HReg dst, h1;
1327 IROp unop, binop;
1328
1329 arg = expr->Iex.Unop.arg;
1330
1331 /* Special cases are handled here */
1332
1333 /* 32-bit multiply with 32-bit result or
1334 64-bit multiply with 64-bit result */
1335 unop = expr->Iex.Unop.op;
1336 binop = arg->Iex.Binop.op;
1337
1338 if ((arg->tag == Iex_Binop &&
1339 ((unop == Iop_64to32 &&
1340 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1341 (unop == Iop_128to64 &&
1342 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1343 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1344 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1345 dst = newVRegI(env); /* Result goes into a new register */
1346 addInstr(env, s390_insn_move(size, dst, h1));
1347 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1348
1349 return dst;
1350 }
1351
florian4d71a082011-12-18 00:08:17 +00001352 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001353 dst = newVRegI(env);
1354 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1355 addInstr(env, s390_insn_move(size, dst, h1));
1356
1357 return dst;
1358 }
1359
1360 /* Expressions whose argument is 1-bit wide */
1361 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1362 s390_cc_t cond = s390_isel_cc(env, arg);
1363 dst = newVRegI(env); /* Result goes into a new register */
1364 addInstr(env, s390_insn_cc2bool(dst, cond));
1365
1366 switch (unop) {
1367 case Iop_1Uto8:
1368 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001369 /* Zero extend */
1370 mask.variant.imm = 1;
1371 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1372 break;
1373
sewardj2019a972011-03-07 16:04:07 +00001374 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001375 /* Zero extend */
1376 mask.variant.imm = 1;
1377 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001378 break;
1379
1380 case Iop_1Sto8:
1381 case Iop_1Sto16:
1382 case Iop_1Sto32:
1383 shift.variant.imm = 31;
1384 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1385 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1386 break;
1387
1388 case Iop_1Sto64:
1389 shift.variant.imm = 63;
1390 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1391 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1392 break;
1393
1394 default:
1395 goto irreducible;
1396 }
1397
1398 return dst;
1399 }
1400
1401 /* Regular processing */
1402
1403 if (unop == Iop_128to64) {
1404 HReg dst_hi, dst_lo;
1405
1406 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1407 return dst_lo;
1408 }
1409
1410 if (unop == Iop_128HIto64) {
1411 HReg dst_hi, dst_lo;
1412
1413 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1414 return dst_hi;
1415 }
1416
1417 dst = newVRegI(env); /* Result goes into a new register */
1418 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1419
1420 switch (unop) {
1421 case Iop_8Uto16:
1422 case Iop_8Uto32:
1423 case Iop_8Uto64:
1424 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1425 break;
1426
1427 case Iop_16Uto32:
1428 case Iop_16Uto64:
1429 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1430 break;
1431
1432 case Iop_32Uto64:
1433 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1434 break;
1435
1436 case Iop_8Sto16:
1437 case Iop_8Sto32:
1438 case Iop_8Sto64:
1439 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1440 break;
1441
1442 case Iop_16Sto32:
1443 case Iop_16Sto64:
1444 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1445 break;
1446
1447 case Iop_32Sto64:
1448 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1449 break;
1450
1451 case Iop_64to8:
1452 case Iop_64to16:
1453 case Iop_64to32:
1454 case Iop_32to8:
1455 case Iop_32to16:
1456 case Iop_16to8:
1457 /* Down-casts are no-ops. Upstream operations will only look at
1458 the bytes that make up the result of the down-cast. So there
1459 is no point setting the other bytes to 0. */
1460 insn = s390_opnd_copy(8, dst, opnd);
1461 break;
1462
1463 case Iop_64HIto32:
1464 addInstr(env, s390_opnd_copy(8, dst, opnd));
1465 shift.variant.imm = 32;
1466 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1467 break;
1468
1469 case Iop_32HIto16:
1470 addInstr(env, s390_opnd_copy(4, dst, opnd));
1471 shift.variant.imm = 16;
1472 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1473 break;
1474
1475 case Iop_16HIto8:
1476 addInstr(env, s390_opnd_copy(2, dst, opnd));
1477 shift.variant.imm = 8;
1478 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1479 break;
1480
1481 case Iop_Not8:
1482 case Iop_Not16:
1483 case Iop_Not32:
1484 case Iop_Not64:
1485 /* XOR with ffff... */
1486 mask.variant.imm = ~(ULong)0;
1487 addInstr(env, s390_opnd_copy(size, dst, opnd));
1488 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1489 break;
1490
1491 case Iop_Left8:
1492 case Iop_Left16:
1493 case Iop_Left32:
1494 case Iop_Left64:
1495 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1496 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1497 break;
1498
1499 case Iop_CmpwNEZ32:
1500 case Iop_CmpwNEZ64: {
1501 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1502 or -X will have a 1 in the MSB. */
1503 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1504 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1505 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1506 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1507 return dst;
1508 }
1509
1510 case Iop_Clz64: {
1511 HReg r10, r11;
1512
sewardj611b06e2011-03-24 08:57:29 +00001513 /* This will be implemented using FLOGR, if possible. So we need to
1514 set aside a pair of non-virtual registers. The result (number of
1515 left-most zero bits) will be in r10. The value in r11 is unspecified
1516 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001517 r10 = make_gpr(10);
1518 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001519
sewardj611b06e2011-03-24 08:57:29 +00001520 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001521 addInstr(env, s390_insn_move(8, dst, r10));
1522 return dst;
1523 }
1524
1525 default:
1526 goto irreducible;
1527 }
1528
1529 addInstr(env, insn);
1530
1531 return dst;
1532 }
1533
1534 /* --------- GET --------- */
1535 case Iex_Get: {
1536 HReg dst = newVRegI(env);
1537 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1538
1539 /* We never load more than 8 bytes from the guest state, because the
1540 floating point register pair is not contiguous. */
1541 vassert(size <= 8);
1542
1543 addInstr(env, s390_insn_load(size, dst, am));
1544
1545 return dst;
1546 }
1547
1548 case Iex_GetI:
1549 /* not needed */
1550 break;
1551
1552 /* --------- CCALL --------- */
1553 case Iex_CCall: {
1554 HReg dst = newVRegI(env);
1555
1556 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001557 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001558 return dst;
1559 }
1560
1561 /* --------- LITERAL --------- */
1562
1563 /* Load a literal into a register. Create a "load immediate"
1564 v-insn and return the register. */
1565 case Iex_Const: {
1566 ULong value;
1567 HReg dst = newVRegI(env);
1568 const IRConst *con = expr->Iex.Const.con;
1569
1570 /* Bitwise copy of the value. No sign/zero-extension */
1571 switch (con->tag) {
1572 case Ico_U64: value = con->Ico.U64; break;
1573 case Ico_U32: value = con->Ico.U32; break;
1574 case Ico_U16: value = con->Ico.U16; break;
1575 case Ico_U8: value = con->Ico.U8; break;
1576 default: vpanic("s390_isel_int_expr: invalid constant");
1577 }
1578
1579 addInstr(env, s390_insn_load_immediate(size, dst, value));
1580
1581 return dst;
1582 }
1583
1584 /* --------- MULTIPLEX --------- */
1585 case Iex_Mux0X: {
1586 IRExpr *cond_expr;
1587 HReg dst, tmp, rX;
1588 s390_opnd_RMI cond, r0, zero;
1589
1590 cond_expr = expr->Iex.Mux0X.cond;
1591
1592 dst = newVRegI(env);
1593 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1594 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1595 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1596
1597 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1598 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1599
1600 addInstr(env, s390_insn_move(size, dst, rX));
1601 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1602 return dst;
1603 }
1604
1605 /* Assume the condition is true and move rX to the destination reg. */
1606 addInstr(env, s390_insn_move(size, dst, rX));
1607
1608 /* Compute the condition ... */
1609 cond = s390_isel_int_expr_RMI(env, cond_expr);
1610
1611 /* tmp = cond & 0xFF */
1612 tmp = newVRegI(env);
1613 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1614 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1615
1616 /* ... and compare it with zero */
1617 zero = s390_opnd_imm(0);
1618 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1619
1620 /* ... and if it compared equal move r0 to the destination reg. */
1621 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1622 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1623
1624 return dst;
1625 }
1626
1627 default:
1628 break;
1629 }
1630
1631 /* We get here if no pattern matched. */
1632 irreducible:
1633 ppIRExpr(expr);
1634 vpanic("s390_isel_int_expr: cannot reduce tree");
1635}
1636
1637
1638static HReg
1639s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1640{
1641 HReg dst = s390_isel_int_expr_wrk(env, expr);
1642
1643 /* Sanity checks ... */
1644 vassert(hregClass(dst) == HRcInt64);
1645 vassert(hregIsVirtual(dst));
1646
1647 return dst;
1648}
1649
1650
1651static s390_opnd_RMI
1652s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1653{
1654 IRType ty = typeOfIRExpr(env->type_env, expr);
1655 s390_opnd_RMI dst;
1656
1657 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1658 ty == Ity_I64);
1659
1660 if (expr->tag == Iex_Load) {
1661 dst.tag = S390_OPND_AMODE;
1662 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1663 } else if (expr->tag == Iex_Get) {
1664 dst.tag = S390_OPND_AMODE;
1665 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1666 } else if (expr->tag == Iex_Const) {
1667 ULong value;
1668
1669 /* The bit pattern for the value will be stored as is in the least
1670 significant bits of VALUE. */
1671 switch (expr->Iex.Const.con->tag) {
1672 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1673 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1674 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1675 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1676 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1677 default:
1678 vpanic("s390_isel_int_expr_RMI");
1679 }
1680
1681 dst.tag = S390_OPND_IMMEDIATE;
1682 dst.variant.imm = value;
1683 } else {
1684 dst.tag = S390_OPND_REG;
1685 dst.variant.reg = s390_isel_int_expr(env, expr);
1686 }
1687
1688 return dst;
1689}
1690
1691
1692/*---------------------------------------------------------*/
1693/*--- ISEL: Floating point expressions (128 bit) ---*/
1694/*---------------------------------------------------------*/
1695static void
1696s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1697 IRExpr *expr)
1698{
1699 IRType ty = typeOfIRExpr(env->type_env, expr);
1700
1701 vassert(ty == Ity_F128);
1702
1703 /* Read 128-bit IRTemp */
1704 if (expr->tag == Iex_RdTmp) {
1705 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1706 return;
1707 }
1708
1709 switch (expr->tag) {
1710 case Iex_RdTmp:
1711 /* Return the virtual registers that hold the temporary. */
1712 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1713 return;
1714
1715 /* --------- LOAD --------- */
1716 case Iex_Load: {
1717 IRExpr *addr_hi, *addr_lo;
1718 s390_amode *am_hi, *am_lo;
1719
1720 if (expr->Iex.Load.end != Iend_BE)
1721 goto irreducible;
1722
1723 addr_hi = expr->Iex.Load.addr;
1724 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1725
1726 am_hi = s390_isel_amode(env, addr_hi);
1727 am_lo = s390_isel_amode(env, addr_lo);
1728
1729 *dst_hi = newVRegF(env);
1730 *dst_lo = newVRegF(env);
1731 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1732 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1733 return;
1734 }
1735
1736
1737 /* --------- GET --------- */
1738 case Iex_Get:
1739 /* This is not supported because loading 128-bit from the guest
1740 state is almost certainly wrong. Use get_fpr_pair instead. */
1741 vpanic("Iex_Get with F128 data");
1742
1743 /* --------- 4-ary OP --------- */
1744 case Iex_Qop:
1745 vpanic("Iex_Qop with F128 data");
1746
1747 /* --------- TERNARY OP --------- */
1748 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001749 IRTriop *triop = expr->Iex.Triop.details;
1750 IROp op = triop->op;
1751 IRExpr *left = triop->arg2;
1752 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001753 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001754 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1755
1756 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1757 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1758
1759 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1760 f12 = make_fpr(12);
1761 f13 = make_fpr(13);
1762 f14 = make_fpr(14);
1763 f15 = make_fpr(15);
1764
1765 /* 1st operand --> (f12, f14) */
1766 addInstr(env, s390_insn_move(8, f12, op1_hi));
1767 addInstr(env, s390_insn_move(8, f14, op1_lo));
1768
1769 /* 2nd operand --> (f13, f15) */
1770 addInstr(env, s390_insn_move(8, f13, op2_hi));
1771 addInstr(env, s390_insn_move(8, f15, op2_lo));
1772
1773 switch (op) {
1774 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1775 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1776 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1777 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1778 default:
1779 goto irreducible;
1780 }
1781
florian2c74d242012-09-12 19:38:42 +00001782 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1783 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001784
1785 /* Move result to virtual destination register */
1786 *dst_hi = newVRegF(env);
1787 *dst_lo = newVRegF(env);
1788 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1789 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1790
1791 return;
1792 }
1793
1794 /* --------- BINARY OP --------- */
1795 case Iex_Binop: {
1796 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001797
1798 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1799 f12 = make_fpr(12);
1800 f13 = make_fpr(13);
1801 f14 = make_fpr(14);
1802 f15 = make_fpr(15);
1803
1804 switch (expr->Iex.Binop.op) {
1805 case Iop_SqrtF128:
1806 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1807
1808 /* operand --> (f13, f15) */
1809 addInstr(env, s390_insn_move(8, f13, op_hi));
1810 addInstr(env, s390_insn_move(8, f15, op_lo));
1811
florian2c74d242012-09-12 19:38:42 +00001812 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1813 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1814 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001815
1816 /* Move result to virtual destination registers */
1817 *dst_hi = newVRegF(env);
1818 *dst_lo = newVRegF(env);
1819 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1820 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1821 return;
1822
1823 case Iop_F64HLtoF128:
1824 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1825 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1826 return;
1827
1828 default:
1829 goto irreducible;
1830 }
1831 }
1832
1833 /* --------- UNARY OP --------- */
1834 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001835 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001836 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00001837 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001838 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1839
1840 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1841 f12 = make_fpr(12);
1842 f13 = make_fpr(13);
1843 f14 = make_fpr(14);
1844 f15 = make_fpr(15);
1845
florian66e596d2012-09-07 15:00:53 +00001846 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001847 case Iop_NegF128:
1848 if (left->tag == Iex_Unop &&
1849 (left->Iex.Unop.op == Iop_AbsF32 ||
1850 left->Iex.Unop.op == Iop_AbsF64))
1851 bfpop = S390_BFP_NABS;
1852 else
1853 bfpop = S390_BFP_NEG;
1854 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00001855 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1856 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1857 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1858 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1859 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1860 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1861 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001862 default:
1863 goto irreducible;
1864 }
1865
1866 float128_opnd:
1867 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1868
1869 /* operand --> (f13, f15) */
1870 addInstr(env, s390_insn_move(8, f13, op_hi));
1871 addInstr(env, s390_insn_move(8, f15, op_lo));
1872
florian2c74d242012-09-12 19:38:42 +00001873 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001874 goto move_dst;
1875
1876 convert_float:
1877 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001878 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001879 goto move_dst;
1880
1881 convert_int:
1882 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001883 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001884 goto move_dst;
1885
1886 move_dst:
1887 /* Move result to virtual destination registers */
1888 *dst_hi = newVRegF(env);
1889 *dst_lo = newVRegF(env);
1890 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1891 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1892 return;
1893 }
1894
1895 default:
1896 goto irreducible;
1897 }
1898
1899 /* We get here if no pattern matched. */
1900 irreducible:
1901 ppIRExpr(expr);
florian4ebaa772012-12-20 19:44:18 +00001902 vpanic("s390_isel_float128_expr: cannot reduce tree");
sewardj2019a972011-03-07 16:04:07 +00001903}
1904
1905/* Compute a 128-bit value into two 64-bit registers. These may be either
1906 real or virtual regs; in any case they must not be changed by subsequent
1907 code emitted by the caller. */
1908static void
1909s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1910{
1911 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1912
1913 /* Sanity checks ... */
1914 vassert(hregIsVirtual(*dst_hi));
1915 vassert(hregIsVirtual(*dst_lo));
1916 vassert(hregClass(*dst_hi) == HRcFlt64);
1917 vassert(hregClass(*dst_lo) == HRcFlt64);
1918}
1919
1920
1921/*---------------------------------------------------------*/
1922/*--- ISEL: Floating point expressions (64 bit) ---*/
1923/*---------------------------------------------------------*/
1924
1925static HReg
1926s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1927{
1928 IRType ty = typeOfIRExpr(env->type_env, expr);
1929 UChar size;
1930
1931 vassert(ty == Ity_F32 || ty == Ity_F64);
1932
1933 size = sizeofIRType(ty);
1934
1935 switch (expr->tag) {
1936 case Iex_RdTmp:
1937 /* Return the virtual register that holds the temporary. */
1938 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1939
1940 /* --------- LOAD --------- */
1941 case Iex_Load: {
1942 HReg dst = newVRegF(env);
1943 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1944
1945 if (expr->Iex.Load.end != Iend_BE)
1946 goto irreducible;
1947
1948 addInstr(env, s390_insn_load(size, dst, am));
1949
1950 return dst;
1951 }
1952
1953 /* --------- GET --------- */
1954 case Iex_Get: {
1955 HReg dst = newVRegF(env);
1956 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1957
1958 addInstr(env, s390_insn_load(size, dst, am));
1959
1960 return dst;
1961 }
1962
1963 /* --------- LITERAL --------- */
1964
1965 /* Load a literal into a register. Create a "load immediate"
1966 v-insn and return the register. */
1967 case Iex_Const: {
1968 ULong value;
1969 HReg dst = newVRegF(env);
1970 const IRConst *con = expr->Iex.Const.con;
1971
1972 /* Bitwise copy of the value. No sign/zero-extension */
1973 switch (con->tag) {
1974 case Ico_F32i: value = con->Ico.F32i; break;
1975 case Ico_F64i: value = con->Ico.F64i; break;
1976 default: vpanic("s390_isel_float_expr: invalid constant");
1977 }
1978
1979 if (value != 0) vpanic("cannot load immediate floating point constant");
1980
1981 addInstr(env, s390_insn_load_immediate(size, dst, value));
1982
1983 return dst;
1984 }
1985
1986 /* --------- 4-ary OP --------- */
1987 case Iex_Qop: {
1988 HReg op1, op2, op3, dst;
1989 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001990
florian5906a6b2012-10-16 02:53:33 +00001991 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00001992 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00001993 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00001994 dst = newVRegF(env);
1995 addInstr(env, s390_insn_move(size, dst, op1));
1996
florian96d7cc32012-06-01 20:41:24 +00001997 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00001998 case Iop_MAddF32:
1999 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2000 case Iop_MSubF32:
2001 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2002
2003 default:
2004 goto irreducible;
2005 }
2006
florian2c74d242012-09-12 19:38:42 +00002007 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2008 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002009 return dst;
2010 }
2011
2012 /* --------- TERNARY OP --------- */
2013 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002014 IRTriop *triop = expr->Iex.Triop.details;
2015 IROp op = triop->op;
2016 IRExpr *left = triop->arg2;
2017 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002018 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002019 HReg h1, op2, dst;
2020
2021 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2022 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2023 dst = newVRegF(env);
2024 addInstr(env, s390_insn_move(size, dst, h1));
2025 switch (op) {
2026 case Iop_AddF32:
2027 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2028 case Iop_SubF32:
2029 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2030 case Iop_MulF32:
2031 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2032 case Iop_DivF32:
2033 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2034
2035 default:
2036 goto irreducible;
2037 }
2038
florian2c74d242012-09-12 19:38:42 +00002039 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2040 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002041 return dst;
2042 }
2043
2044 /* --------- BINARY OP --------- */
2045 case Iex_Binop: {
2046 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002047 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002048 IRExpr *left = expr->Iex.Binop.arg2;
2049 HReg h1, dst;
florian9fcff4c2012-09-10 03:09:04 +00002050 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002051
2052 switch (op) {
2053 case Iop_SqrtF32:
2054 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002055 h1 = s390_isel_float_expr(env, left);
2056 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002057 set_bfp_rounding_mode_in_fpc(env, irrm);
2058 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002059 return dst;
sewardj2019a972011-03-07 16:04:07 +00002060
florian9fcff4c2012-09-10 03:09:04 +00002061 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2062 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2063 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2064 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2065 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2066 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2067 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002068
florian9fcff4c2012-09-10 03:09:04 +00002069 convert_float:
2070 h1 = s390_isel_float_expr(env, left);
2071 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002072
florian9fcff4c2012-09-10 03:09:04 +00002073 convert_int:
2074 h1 = s390_isel_int_expr(env, left);
2075 goto convert;
2076
florian2c74d242012-09-12 19:38:42 +00002077 convert: {
florian125e20d2012-10-07 15:42:37 +00002078 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002079 /* convert-from-fixed and load-rounded have a rounding mode field
2080 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002081 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002082 if (s390_host_has_fpext) {
2083 rounding_mode = get_bfp_rounding_mode(env, irrm);
2084 } else {
2085 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002086 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002087 }
florian9fcff4c2012-09-10 03:09:04 +00002088 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2089 rounding_mode));
2090 return dst;
florian2c74d242012-09-12 19:38:42 +00002091 }
florian9fcff4c2012-09-10 03:09:04 +00002092
sewardj2019a972011-03-07 16:04:07 +00002093 default:
2094 goto irreducible;
2095
2096 case Iop_F128toF64:
2097 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002098 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002099 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002100
florian9fcff4c2012-09-10 03:09:04 +00002101 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2102 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002103
florian9fcff4c2012-09-10 03:09:04 +00002104 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002105
florian9fcff4c2012-09-10 03:09:04 +00002106 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002107 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002108 f15 = make_fpr(15);
2109
2110 /* operand --> (f13, f15) */
2111 addInstr(env, s390_insn_move(8, f13, op_hi));
2112 addInstr(env, s390_insn_move(8, f15, op_lo));
2113
2114 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002115 /* load-rounded has a rounding mode field when the floating point
2116 extension facility is installed. */
2117 if (s390_host_has_fpext) {
2118 rounding_mode = get_bfp_rounding_mode(env, irrm);
2119 } else {
2120 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002121 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002122 }
floriancc491a62012-09-10 23:44:37 +00002123 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002124 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002125 return dst;
2126 }
2127 }
sewardj2019a972011-03-07 16:04:07 +00002128 }
2129
2130 /* --------- UNARY OP --------- */
2131 case Iex_Unop: {
2132 IROp op = expr->Iex.Unop.op;
2133 IRExpr *left = expr->Iex.Unop.arg;
2134 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00002135 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002136 HReg h1, dst;
2137
2138 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2139 HReg dst_hi, dst_lo;
2140
2141 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2142 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2143 }
2144
florian4d71a082011-12-18 00:08:17 +00002145 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002146 dst = newVRegF(env);
2147 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2148 addInstr(env, s390_insn_move(size, dst, h1));
2149
2150 return dst;
2151 }
2152
2153 switch (op) {
2154 case Iop_NegF32:
2155 case Iop_NegF64:
2156 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002157 (left->Iex.Unop.op == Iop_AbsF32 ||
2158 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002159 bfpop = S390_BFP_NABS;
2160 else
2161 bfpop = S390_BFP_NEG;
2162 break;
2163
2164 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002165 case Iop_AbsF64:
2166 bfpop = S390_BFP_ABS;
2167 break;
2168
2169 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2170 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2171 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2172
2173 convert_float1:
2174 h1 = s390_isel_float_expr(env, left);
2175 goto convert1;
2176
2177 convert_int1:
2178 h1 = s390_isel_int_expr(env, left);
2179 goto convert1;
2180
2181 convert1:
2182 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002183 /* No rounding mode is needed for these conversions. Just stick
2184 one in. It won't be used later on. */
2185 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002186 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002187 return dst;
2188
sewardj2019a972011-03-07 16:04:07 +00002189 default:
2190 goto irreducible;
2191 }
2192
2193 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002194 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002195 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002196 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002197 return dst;
2198 }
2199
2200 default:
2201 goto irreducible;
2202 }
2203
2204 /* We get here if no pattern matched. */
2205 irreducible:
2206 ppIRExpr(expr);
2207 vpanic("s390_isel_float_expr: cannot reduce tree");
2208}
2209
2210
2211static HReg
2212s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2213{
2214 HReg dst = s390_isel_float_expr_wrk(env, expr);
2215
2216 /* Sanity checks ... */
2217 vassert(hregClass(dst) == HRcFlt64);
2218 vassert(hregIsVirtual(dst));
2219
2220 return dst;
2221}
2222
2223
2224/*---------------------------------------------------------*/
florian12390202012-11-10 22:34:14 +00002225/*--- ISEL: Decimal point expressions (64 bit) ---*/
2226/*---------------------------------------------------------*/
2227
2228static HReg
2229s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
2230{
2231 IRType ty = typeOfIRExpr(env->type_env, expr);
2232 UChar size;
2233
2234 vassert(ty == Ity_D64);
2235
2236 size = sizeofIRType(ty);
2237
2238 switch (expr->tag) {
2239 case Iex_RdTmp:
2240 /* Return the virtual register that holds the temporary. */
2241 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
2242
2243 /* --------- LOAD --------- */
2244 case Iex_Load: {
2245 HReg dst = newVRegF(env);
2246 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
2247
2248 if (expr->Iex.Load.end != Iend_BE)
2249 goto irreducible;
2250
2251 addInstr(env, s390_insn_load(size, dst, am));
2252
2253 return dst;
2254 }
2255
2256 /* --------- GET --------- */
2257 case Iex_Get: {
2258 HReg dst = newVRegF(env);
2259 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
2260
2261 addInstr(env, s390_insn_load(size, dst, am));
2262
2263 return dst;
2264 }
2265
2266 /* --------- TERNARY OP --------- */
2267 case Iex_Triop: {
2268 IRTriop *triop = expr->Iex.Triop.details;
2269 IROp op = triop->op;
2270 IRExpr *irrm = triop->arg1;
2271 IRExpr *left = triop->arg2;
2272 IRExpr *right = triop->arg3;
2273 s390_dfp_round_t rounding_mode;
2274 s390_dfp_binop_t dfpop;
2275 HReg op2, op3, dst;
2276
2277 op2 = s390_isel_dfp_expr(env, left); /* Process 1st operand */
2278 op3 = s390_isel_dfp_expr(env, right); /* Process 2nd operand */
2279 dst = newVRegF(env);
2280 switch (op) {
2281 case Iop_AddD64: dfpop = S390_DFP_ADD; break;
2282 case Iop_SubD64: dfpop = S390_DFP_SUB; break;
2283 case Iop_MulD64: dfpop = S390_DFP_MUL; break;
2284 case Iop_DivD64: dfpop = S390_DFP_DIV; break;
2285 default:
2286 goto irreducible;
2287 }
2288 /* DFP binary ops have insns with rounding mode field
2289 when the floating point extension facility is installed. */
2290 if (s390_host_has_fpext) {
2291 rounding_mode = get_dfp_rounding_mode(env, irrm);
2292 } else {
2293 set_dfp_rounding_mode_in_fpc(env, irrm);
2294 rounding_mode = S390_DFP_ROUND_PER_FPC_0;
2295 }
2296
2297 addInstr(env,
2298 s390_insn_dfp_binop(size, dfpop, dst, op2, op3, rounding_mode));
2299 return dst;
2300 }
2301
2302 default:
2303 goto irreducible;
2304 }
2305
2306 /* We get here if no pattern matched. */
2307 irreducible:
2308 ppIRExpr(expr);
2309 vpanic("s390_isel_dfp_expr: cannot reduce tree");
2310}
2311
2312static HReg
2313s390_isel_dfp_expr(ISelEnv *env, IRExpr *expr)
2314{
2315 HReg dst = s390_isel_dfp_expr_wrk(env, expr);
2316
2317 /* Sanity checks ... */
2318 vassert(hregClass(dst) == HRcFlt64);
2319 vassert(hregIsVirtual(dst));
2320
2321 return dst;
2322}
2323
2324
2325/*---------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +00002326/*--- ISEL: Condition Code ---*/
2327/*---------------------------------------------------------*/
2328
2329/* This function handles all operators that produce a 1-bit result */
2330static s390_cc_t
2331s390_isel_cc(ISelEnv *env, IRExpr *cond)
2332{
2333 UChar size;
2334
2335 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2336
2337 /* Constant: either 1 or 0 */
2338 if (cond->tag == Iex_Const) {
2339 vassert(cond->Iex.Const.con->tag == Ico_U1);
2340 vassert(cond->Iex.Const.con->Ico.U1 == True
2341 || cond->Iex.Const.con->Ico.U1 == False);
2342
2343 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2344 }
2345
2346 /* Variable: values are 1 or 0 */
2347 if (cond->tag == Iex_RdTmp) {
2348 IRTemp tmp = cond->Iex.RdTmp.tmp;
2349 HReg reg = lookupIRTemp(env, tmp);
2350
2351 /* Load-and-test does not modify REG; so this is OK. */
2352 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2353 size = 4;
2354 else
2355 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2356 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2357 return S390_CC_NE;
2358 }
2359
2360 /* Unary operators */
2361 if (cond->tag == Iex_Unop) {
2362 IRExpr *arg = cond->Iex.Unop.arg;
2363
2364 switch (cond->Iex.Unop.op) {
2365 case Iop_Not1: /* Not1(cond) */
2366 /* Generate code for EXPR, and negate the test condition */
2367 return s390_cc_invert(s390_isel_cc(env, arg));
2368
2369 /* Iop_32/64to1 select the LSB from their operand */
2370 case Iop_32to1:
2371 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002372 HReg dst = newVRegI(env);
2373 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002374
2375 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2376
florianf366a802012-08-03 00:42:18 +00002377 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002378 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2379 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2380 return S390_CC_NE;
2381 }
2382
2383 case Iop_CmpNEZ8:
2384 case Iop_CmpNEZ16: {
2385 s390_opnd_RMI src;
2386 s390_unop_t op;
2387 HReg dst;
2388
2389 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2390 : S390_ZERO_EXTEND_16;
2391 dst = newVRegI(env);
2392 src = s390_isel_int_expr_RMI(env, arg);
2393 addInstr(env, s390_insn_unop(4, op, dst, src));
2394 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2395 return S390_CC_NE;
2396 }
2397
2398 case Iop_CmpNEZ32:
2399 case Iop_CmpNEZ64: {
2400 s390_opnd_RMI src;
2401
2402 src = s390_isel_int_expr_RMI(env, arg);
2403 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2404 addInstr(env, s390_insn_test(size, src));
2405 return S390_CC_NE;
2406 }
2407
2408 default:
2409 goto fail;
2410 }
2411 }
2412
2413 /* Binary operators */
2414 if (cond->tag == Iex_Binop) {
2415 IRExpr *arg1 = cond->Iex.Binop.arg1;
2416 IRExpr *arg2 = cond->Iex.Binop.arg2;
2417 HReg reg1, reg2;
2418
2419 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2420
2421 switch (cond->Iex.Binop.op) {
2422 s390_unop_t op;
2423 s390_cc_t result;
2424
2425 case Iop_CmpEQ8:
2426 case Iop_CasCmpEQ8:
2427 op = S390_ZERO_EXTEND_8;
2428 result = S390_CC_E;
2429 goto do_compare_ze;
2430
2431 case Iop_CmpNE8:
2432 case Iop_CasCmpNE8:
2433 op = S390_ZERO_EXTEND_8;
2434 result = S390_CC_NE;
2435 goto do_compare_ze;
2436
2437 case Iop_CmpEQ16:
2438 case Iop_CasCmpEQ16:
2439 op = S390_ZERO_EXTEND_16;
2440 result = S390_CC_E;
2441 goto do_compare_ze;
2442
2443 case Iop_CmpNE16:
2444 case Iop_CasCmpNE16:
2445 op = S390_ZERO_EXTEND_16;
2446 result = S390_CC_NE;
2447 goto do_compare_ze;
2448
2449 do_compare_ze: {
2450 s390_opnd_RMI op1, op2;
2451
2452 op1 = s390_isel_int_expr_RMI(env, arg1);
2453 reg1 = newVRegI(env);
2454 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2455
2456 op2 = s390_isel_int_expr_RMI(env, arg2);
2457 reg2 = newVRegI(env);
2458 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2459
2460 op2 = s390_opnd_reg(reg2);
2461 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2462
2463 return result;
2464 }
2465
2466 case Iop_CmpEQ32:
2467 case Iop_CmpEQ64:
2468 case Iop_CasCmpEQ32:
2469 case Iop_CasCmpEQ64:
2470 result = S390_CC_E;
2471 goto do_compare;
2472
2473 case Iop_CmpNE32:
2474 case Iop_CmpNE64:
2475 case Iop_CasCmpNE32:
2476 case Iop_CasCmpNE64:
2477 result = S390_CC_NE;
2478 goto do_compare;
2479
2480 do_compare: {
2481 HReg op1;
2482 s390_opnd_RMI op2;
2483
2484 order_commutative_operands(arg1, arg2);
2485
2486 op1 = s390_isel_int_expr(env, arg1);
2487 op2 = s390_isel_int_expr_RMI(env, arg2);
2488
2489 addInstr(env, s390_insn_compare(size, op1, op2, False));
2490
2491 return result;
2492 }
2493
2494 case Iop_CmpLT32S:
2495 case Iop_CmpLE32S:
2496 case Iop_CmpLT64S:
2497 case Iop_CmpLE64S: {
2498 HReg op1;
2499 s390_opnd_RMI op2;
2500
2501 op1 = s390_isel_int_expr(env, arg1);
2502 op2 = s390_isel_int_expr_RMI(env, arg2);
2503
2504 addInstr(env, s390_insn_compare(size, op1, op2, True));
2505
2506 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2507 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2508 }
2509
2510 case Iop_CmpLT32U:
2511 case Iop_CmpLE32U:
2512 case Iop_CmpLT64U:
2513 case Iop_CmpLE64U: {
2514 HReg op1;
2515 s390_opnd_RMI op2;
2516
2517 op1 = s390_isel_int_expr(env, arg1);
2518 op2 = s390_isel_int_expr_RMI(env, arg2);
2519
2520 addInstr(env, s390_insn_compare(size, op1, op2, False));
2521
2522 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2523 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2524 }
2525
2526 default:
2527 goto fail;
2528 }
2529 }
2530
2531 fail:
2532 ppIRExpr(cond);
2533 vpanic("s390_isel_cc: unexpected operator");
2534}
2535
2536
2537/*---------------------------------------------------------*/
2538/*--- ISEL: Statements ---*/
2539/*---------------------------------------------------------*/
2540
2541static void
2542s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2543{
2544 if (vex_traceflags & VEX_TRACE_VCODE) {
2545 vex_printf("\n -- ");
2546 ppIRStmt(stmt);
2547 vex_printf("\n");
2548 }
2549
2550 switch (stmt->tag) {
2551
2552 /* --------- STORE --------- */
2553 case Ist_Store: {
2554 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2555 s390_amode *am;
2556 HReg src;
2557
2558 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2559
2560 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2561
2562 switch (tyd) {
2563 case Ity_I8:
2564 case Ity_I16:
2565 case Ity_I32:
2566 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00002567 if (am->tag == S390_AMODE_B12 &&
2568 s390_expr_is_const_zero(stmt->Ist.Store.data)) {
2569 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
2570 return;
2571 }
sewardj2019a972011-03-07 16:04:07 +00002572 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2573 break;
2574
2575 case Ity_F32:
2576 case Ity_F64:
2577 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2578 break;
2579
2580 case Ity_F128:
2581 /* Cannot occur. No such instruction */
2582 vpanic("Ist_Store with F128 data");
2583
2584 default:
2585 goto stmt_fail;
2586 }
2587
2588 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2589 return;
2590 }
2591
2592 /* --------- PUT --------- */
2593 case Ist_Put: {
2594 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2595 HReg src;
2596 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002597 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002598
florianad43b3a2012-02-20 15:01:14 +00002599 /* Detect updates to certain guest registers. We track the contents
2600 of those registers as long as they contain constants. If the new
2601 constant is either zero or in the 8-bit neighbourhood of the
2602 current value we can use a memory-to-memory insn to do the update. */
2603
2604 Int offset = stmt->Ist.Put.offset;
2605
2606 /* Check necessary conditions:
2607 (1) must be one of the registers we care about
2608 (2) assigned value must be a constant */
2609 Int guest_reg = get_guest_reg(offset);
2610
2611 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2612
2613 if (guest_reg == GUEST_IA) {
2614 /* If this is the first assignment to the IA reg, don't special case
2615 it. We need to do a full 8-byte assignment here. The reason is
2616 that in case of a redirected translation the guest IA does not
2617 contain the redirected-to address. Instead it contains the
2618 redirected-from address and those can be far apart. So in order to
2619 do incremnetal updates if the IA in the future we need to get the
2620 initial address of the super block correct. */
2621 if (env->first_IA_assignment) {
2622 env->first_IA_assignment = False;
2623 goto not_special;
2624 }
2625 }
2626
2627 if (stmt->Ist.Put.data->tag != Iex_Const) {
2628 /* Invalidate guest register contents */
2629 env->old_value_valid[guest_reg] = False;
2630 goto not_special;
2631 }
2632
cborntraaf7ad282012-08-08 14:11:33 +00002633 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2634 if (tyd != Ity_I64)
2635 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002636
cborntraaf7ad282012-08-08 14:11:33 +00002637 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002638
2639 old_value = env->old_value[guest_reg];
2640 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2641 env->old_value[guest_reg] = new_value;
2642
2643 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2644 env->old_value_valid[guest_reg] = True;
2645
2646 /* If the register already contains the new value, there is nothing
2647 to do here. Unless the guest register requires precise memory
2648 exceptions. */
2649 if (old_value_is_valid && new_value == old_value) {
2650 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2651 return;
2652 }
2653 }
2654
2655 /* guest register = 0 */
2656 if (new_value == 0) {
florian09bbba82012-12-11 04:09:43 +00002657 am = s390_amode_for_guest_state(offset);
2658 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
florianad43b3a2012-02-20 15:01:14 +00002659 return;
2660 }
2661
2662 if (old_value_is_valid == False) goto not_special;
2663
2664 /* If the new value is in the neighbourhood of the old value
2665 we can use a memory-to-memory insn */
2666 difference = new_value - old_value;
2667
2668 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2669 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2670 (difference & 0xFF), new_value));
2671 return;
2672 }
2673
2674 /* If the high word is the same it is sufficient to load the low word.
2675 Use R0 as a scratch reg. */
2676 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002677 HReg r0 = make_gpr(0);
2678 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002679 s390_amode *gam;
2680
2681 gam = s390_amode_b12(offset + 4, gsp);
2682 addInstr(env, s390_insn_load_immediate(4, r0,
2683 new_value & 0xFFFFFFFF));
2684 addInstr(env, s390_insn_store(4, gam, r0));
2685 return;
2686 }
2687
2688 /* No special case applies... fall through */
2689
2690 not_special:
sewardj2019a972011-03-07 16:04:07 +00002691 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2692
2693 switch (tyd) {
2694 case Ity_I8:
2695 case Ity_I16:
2696 case Ity_I32:
2697 case Ity_I64:
florian09bbba82012-12-11 04:09:43 +00002698 if (am->tag == S390_AMODE_B12 &&
2699 s390_expr_is_const_zero(stmt->Ist.Put.data)) {
2700 addInstr(env, s390_insn_mzero(sizeofIRType(tyd), am));
2701 return;
2702 }
sewardj2019a972011-03-07 16:04:07 +00002703 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2704 break;
2705
2706 case Ity_F32:
2707 case Ity_F64:
2708 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2709 break;
2710
2711 case Ity_F128:
2712 /* Does not occur. See function put_fpr_pair. */
2713 vpanic("Ist_Put with F128 data");
2714
florian12390202012-11-10 22:34:14 +00002715 case Ity_D64:
2716 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
2717 break;
2718
sewardj2019a972011-03-07 16:04:07 +00002719 default:
2720 goto stmt_fail;
2721 }
2722
2723 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2724 return;
2725 }
2726
2727 /* --------- TMP --------- */
2728 case Ist_WrTmp: {
2729 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2730 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2731 HReg src, dst;
2732
2733 switch (tyd) {
2734 case Ity_I128: {
2735 HReg dst_hi, dst_lo, res_hi, res_lo;
2736
2737 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2738 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2739
2740 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2741 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2742 return;
2743 }
2744
2745 case Ity_I8:
2746 case Ity_I16:
2747 case Ity_I32:
2748 case Ity_I64:
2749 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2750 dst = lookupIRTemp(env, tmp);
2751 break;
2752
2753 case Ity_I1: {
2754 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2755 dst = lookupIRTemp(env, tmp);
2756 addInstr(env, s390_insn_cc2bool(dst, cond));
2757 return;
2758 }
2759
2760 case Ity_F32:
2761 case Ity_F64:
2762 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2763 dst = lookupIRTemp(env, tmp);
2764 break;
2765
2766 case Ity_F128: {
2767 HReg dst_hi, dst_lo, res_hi, res_lo;
2768
2769 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2770 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2771
2772 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2773 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2774 return;
2775 }
2776
florian12390202012-11-10 22:34:14 +00002777 case Ity_D64:
2778 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
2779 dst = lookupIRTemp(env, tmp);
2780 break;
2781
sewardj2019a972011-03-07 16:04:07 +00002782 default:
2783 goto stmt_fail;
2784 }
2785
2786 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2787 return;
2788 }
2789
2790 /* --------- Call to DIRTY helper --------- */
2791 case Ist_Dirty: {
2792 IRType retty;
2793 IRDirty* d = stmt->Ist.Dirty.details;
2794 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002795 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002796 Int i;
2797
2798 /* Invalidate tracked values of those guest state registers that are
2799 modified by this helper. */
2800 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002801 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2802 descriptors in guest state effect descriptions. Hence: */
2803 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002804 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2805 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2806 if (guest_reg != GUEST_UNKNOWN)
2807 env->old_value_valid[guest_reg] = False;
2808 }
2809 }
sewardj2019a972011-03-07 16:04:07 +00002810
2811 if (d->nFxState == 0)
2812 vassert(!d->needsBBP);
2813
2814 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2815
florian01ed6e72012-05-27 16:52:43 +00002816 if (d->tmp == IRTemp_INVALID) {
2817 /* No return value. */
2818 dst = INVALID_HREG;
2819 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002820 return;
florian01ed6e72012-05-27 16:52:43 +00002821 }
sewardj2019a972011-03-07 16:04:07 +00002822
2823 retty = typeOfIRTemp(env->type_env, d->tmp);
2824 if (retty == Ity_I64 || retty == Ity_I32
2825 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002826 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002827 dst = lookupIRTemp(env, d->tmp);
2828 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002829 return;
2830 }
2831 break;
2832 }
2833
2834 case Ist_CAS:
2835 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2836 IRCAS *cas = stmt->Ist.CAS.details;
2837 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2838 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2839 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2840 HReg old = lookupIRTemp(env, cas->oldLo);
2841
2842 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2843 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2844 } else {
2845 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2846 }
2847 return;
2848 } else {
florian448cbba2012-06-06 02:26:01 +00002849 IRCAS *cas = stmt->Ist.CAS.details;
2850 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2851 HReg r8, r9, r10, r11, r1;
2852 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2853 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2854 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2855 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2856 HReg old_low = lookupIRTemp(env, cas->oldLo);
2857 HReg old_high = lookupIRTemp(env, cas->oldHi);
2858
2859 /* Use non-virtual registers r8 and r9 as pair for op1
2860 and move op1 there */
2861 r8 = make_gpr(8);
2862 r9 = make_gpr(9);
2863 addInstr(env, s390_insn_move(8, r8, op1_high));
2864 addInstr(env, s390_insn_move(8, r9, op1_low));
2865
2866 /* Use non-virtual registers r10 and r11 as pair for op3
2867 and move op3 there */
2868 r10 = make_gpr(10);
2869 r11 = make_gpr(11);
2870 addInstr(env, s390_insn_move(8, r10, op3_high));
2871 addInstr(env, s390_insn_move(8, r11, op3_low));
2872
2873 /* Register r1 is used as a scratch register */
2874 r1 = make_gpr(1);
2875
2876 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2877 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2878 old_high, old_low, r1));
2879 } else {
2880 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2881 old_high, old_low, r1));
2882 }
2883 addInstr(env, s390_insn_move(8, op1_high, r8));
2884 addInstr(env, s390_insn_move(8, op1_low, r9));
2885 addInstr(env, s390_insn_move(8, op3_high, r10));
2886 addInstr(env, s390_insn_move(8, op3_low, r11));
2887 return;
sewardj2019a972011-03-07 16:04:07 +00002888 }
2889 break;
2890
2891 /* --------- EXIT --------- */
2892 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002893 s390_cc_t cond;
2894 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2895
2896 if (tag != Ico_U64)
2897 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2898
florian8844a632012-04-13 04:04:06 +00002899 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002900 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002901
2902 /* Case: boring transfer to known address */
2903 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2904 if (env->chaining_allowed) {
2905 /* .. almost always true .. */
2906 /* Skip the event check at the dst if this is a forwards
2907 edge. */
2908 Bool to_fast_entry
2909 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2910 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2911 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2912 guest_IA, to_fast_entry));
2913 } else {
2914 /* .. very occasionally .. */
2915 /* We can't use chaining, so ask for an assisted transfer,
2916 as that's the only alternative that is allowable. */
2917 HReg dst = s390_isel_int_expr(env,
2918 IRExpr_Const(stmt->Ist.Exit.dst));
2919 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2920 }
2921 return;
2922 }
2923
2924 /* Case: assisted transfer to arbitrary address */
2925 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00002926 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002927 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002928 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002929 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002930 case Ijk_Sys_syscall:
2931 case Ijk_ClientReq:
2932 case Ijk_NoRedir:
2933 case Ijk_Yield:
2934 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002935 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2936 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2937 stmt->Ist.Exit.jk));
2938 return;
2939 }
2940 default:
2941 break;
2942 }
2943
2944 /* Do we ever expect to see any other kind? */
2945 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002946 }
2947
2948 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002949 case Ist_MBE:
2950 switch (stmt->Ist.MBE.event) {
2951 case Imbe_Fence:
2952 addInstr(env, s390_insn_mfence());
2953 return;
2954 default:
2955 break;
2956 }
sewardj2019a972011-03-07 16:04:07 +00002957 break;
2958
2959 /* --------- Miscellaneous --------- */
2960
2961 case Ist_PutI: /* Not needed */
2962 case Ist_IMark: /* Doesn't generate any executable code */
2963 case Ist_NoOp: /* Doesn't generate any executable code */
2964 case Ist_AbiHint: /* Meaningless in IR */
2965 return;
2966
2967 default:
2968 break;
2969 }
2970
2971 stmt_fail:
2972 ppIRStmt(stmt);
2973 vpanic("s390_isel_stmt");
2974}
2975
2976
2977/*---------------------------------------------------------*/
2978/*--- ISEL: Basic block terminators (Nexts) ---*/
2979/*---------------------------------------------------------*/
2980
2981static void
florianffbd84d2012-12-09 02:06:29 +00002982iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, Int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002983{
sewardj2019a972011-03-07 16:04:07 +00002984 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002985 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002986 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002987 vex_printf("; exit-");
2988 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002989 vex_printf("\n");
2990 }
2991
florian8844a632012-04-13 04:04:06 +00002992 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2993
2994 /* Case: boring transfer to known address */
2995 if (next->tag == Iex_Const) {
2996 IRConst *cdst = next->Iex.Const.con;
2997 vassert(cdst->tag == Ico_U64);
2998 if (jk == Ijk_Boring || jk == Ijk_Call) {
2999 /* Boring transfer to known address */
3000 if (env->chaining_allowed) {
3001 /* .. almost always true .. */
3002 /* Skip the event check at the dst if this is a forwards
3003 edge. */
3004 Bool to_fast_entry
3005 = ((Addr64)cdst->Ico.U64) > env->max_ga;
3006 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
3007 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
3008 guest_IA, to_fast_entry));
3009 } else {
3010 /* .. very occasionally .. */
3011 /* We can't use chaining, so ask for an indirect transfer,
3012 as that's the cheapest alternative that is allowable. */
3013 HReg dst = s390_isel_int_expr(env, next);
3014 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3015 Ijk_Boring));
3016 }
3017 return;
3018 }
3019 }
3020
3021 /* Case: call/return (==boring) transfer to any address */
3022 switch (jk) {
3023 case Ijk_Boring:
3024 case Ijk_Ret:
3025 case Ijk_Call: {
3026 HReg dst = s390_isel_int_expr(env, next);
3027 if (env->chaining_allowed) {
3028 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3029 } else {
3030 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3031 Ijk_Boring));
3032 }
3033 return;
3034 }
3035 default:
3036 break;
3037 }
3038
3039 /* Case: some other kind of transfer to any address */
3040 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003041 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003042 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003043 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003044 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003045 case Ijk_Sys_syscall:
3046 case Ijk_ClientReq:
3047 case Ijk_NoRedir:
3048 case Ijk_Yield:
3049 case Ijk_SigTRAP: {
3050 HReg dst = s390_isel_int_expr(env, next);
3051 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3052 return;
3053 }
3054 default:
3055 break;
3056 }
3057
3058 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003059}
3060
3061
3062/*---------------------------------------------------------*/
3063/*--- Insn selector top-level ---*/
3064/*---------------------------------------------------------*/
3065
florianf26994a2012-04-21 03:34:54 +00003066/* Translate an entire SB to s390 code.
3067 Note: archinfo_host is a pointer to a stack-allocated variable.
3068 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003069
3070HInstrArray *
3071iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003072 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3073 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3074 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003075{
3076 UInt i, j;
3077 HReg hreg, hregHI;
3078 ISelEnv *env;
3079 UInt hwcaps_host = archinfo_host->hwcaps;
3080
florianf26994a2012-04-21 03:34:54 +00003081 /* KLUDGE: export hwcaps. */
3082 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003083
sewardj2019a972011-03-07 16:04:07 +00003084 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003085 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003086
3087 /* Make up an initial environment to use. */
3088 env = LibVEX_Alloc(sizeof(ISelEnv));
3089 env->vreg_ctr = 0;
3090
3091 /* Set up output code array. */
3092 env->code = newHInstrArray();
3093
3094 /* Copy BB's type env. */
3095 env->type_env = bb->tyenv;
3096
florianad43b3a2012-02-20 15:01:14 +00003097 /* Set up data structures for tracking guest register values. */
3098 env->first_IA_assignment = True;
3099 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3100 env->old_value[i] = 0; /* just something to have a defined value */
3101 env->old_value_valid[i] = False;
3102 }
3103
sewardj2019a972011-03-07 16:04:07 +00003104 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3105 change as we go along. For some reason types_used has Int type -- but
3106 it should be unsigned. Internally we use an unsigned type; so we
3107 assert it here. */
3108 vassert(bb->tyenv->types_used >= 0);
3109
3110 env->n_vregmap = bb->tyenv->types_used;
3111 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3112 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3113
florian2c74d242012-09-12 19:38:42 +00003114 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003115 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003116
sewardj2019a972011-03-07 16:04:07 +00003117 /* and finally ... */
3118 env->hwcaps = hwcaps_host;
3119
florian8844a632012-04-13 04:04:06 +00003120 env->max_ga = max_ga;
3121 env->chaining_allowed = chaining_allowed;
3122
sewardj2019a972011-03-07 16:04:07 +00003123 /* For each IR temporary, allocate a suitably-kinded virtual
3124 register. */
3125 j = 0;
3126 for (i = 0; i < env->n_vregmap; i++) {
3127 hregHI = hreg = INVALID_HREG;
3128 switch (bb->tyenv->types[i]) {
3129 case Ity_I1:
3130 case Ity_I8:
3131 case Ity_I16:
3132 case Ity_I32:
3133 hreg = mkHReg(j++, HRcInt64, True);
3134 break;
3135
3136 case Ity_I64:
3137 hreg = mkHReg(j++, HRcInt64, True);
3138 break;
3139
3140 case Ity_I128:
3141 hreg = mkHReg(j++, HRcInt64, True);
3142 hregHI = mkHReg(j++, HRcInt64, True);
3143 break;
3144
3145 case Ity_F32:
3146 case Ity_F64:
florian12390202012-11-10 22:34:14 +00003147 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003148 hreg = mkHReg(j++, HRcFlt64, True);
3149 break;
3150
3151 case Ity_F128:
3152 hreg = mkHReg(j++, HRcFlt64, True);
3153 hregHI = mkHReg(j++, HRcFlt64, True);
3154 break;
3155
3156 case Ity_V128: /* fall through */
3157 default:
3158 ppIRType(bb->tyenv->types[i]);
florian4ebaa772012-12-20 19:44:18 +00003159 vpanic("iselSB_S390: IRTemp type");
sewardj2019a972011-03-07 16:04:07 +00003160 }
3161
3162 env->vregmap[i] = hreg;
3163 env->vregmapHI[i] = hregHI;
3164 }
3165 env->vreg_ctr = j;
3166
florian8844a632012-04-13 04:04:06 +00003167 /* The very first instruction must be an event check. */
3168 s390_amode *counter, *fail_addr;
3169 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3170 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3171 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3172
3173 /* Possibly a block counter increment (for profiling). At this
3174 point we don't know the address of the counter, so just pretend
3175 it is zero. It will have to be patched later, but before this
3176 translation is used, by a call to LibVEX_patchProfInc. */
3177 if (add_profinc) {
3178 addInstr(env, s390_insn_profinc());
3179 }
3180
sewardj2019a972011-03-07 16:04:07 +00003181 /* Ok, finally we can iterate over the statements. */
3182 for (i = 0; i < bb->stmts_used; i++)
3183 if (bb->stmts[i])
3184 s390_isel_stmt(env, bb->stmts[i]);
3185
florian8844a632012-04-13 04:04:06 +00003186 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003187
3188 /* Record the number of vregs we used. */
3189 env->code->n_vregs = env->vreg_ctr;
3190
3191 return env->code;
3192}
3193
3194/*---------------------------------------------------------------*/
3195/*--- end host_s390_isel.c ---*/
3196/*---------------------------------------------------------------*/