blob: 1d0ea6f669179f1c57933cd0c5bbbaa9b2837ca9 [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
408/* Return 1, if EXPR represents the cosntant 0 */
409static int
410s390_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);
701 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
702
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);
1902 vpanic("s390_isel_int_expr: cannot reduce tree");
1903}
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:
2567 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2568 break;
2569
2570 case Ity_F32:
2571 case Ity_F64:
2572 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2573 break;
2574
2575 case Ity_F128:
2576 /* Cannot occur. No such instruction */
2577 vpanic("Ist_Store with F128 data");
2578
2579 default:
2580 goto stmt_fail;
2581 }
2582
2583 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2584 return;
2585 }
2586
2587 /* --------- PUT --------- */
2588 case Ist_Put: {
2589 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2590 HReg src;
2591 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002592 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002593
florianad43b3a2012-02-20 15:01:14 +00002594 /* Detect updates to certain guest registers. We track the contents
2595 of those registers as long as they contain constants. If the new
2596 constant is either zero or in the 8-bit neighbourhood of the
2597 current value we can use a memory-to-memory insn to do the update. */
2598
2599 Int offset = stmt->Ist.Put.offset;
2600
2601 /* Check necessary conditions:
2602 (1) must be one of the registers we care about
2603 (2) assigned value must be a constant */
2604 Int guest_reg = get_guest_reg(offset);
2605
2606 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2607
2608 if (guest_reg == GUEST_IA) {
2609 /* If this is the first assignment to the IA reg, don't special case
2610 it. We need to do a full 8-byte assignment here. The reason is
2611 that in case of a redirected translation the guest IA does not
2612 contain the redirected-to address. Instead it contains the
2613 redirected-from address and those can be far apart. So in order to
2614 do incremnetal updates if the IA in the future we need to get the
2615 initial address of the super block correct. */
2616 if (env->first_IA_assignment) {
2617 env->first_IA_assignment = False;
2618 goto not_special;
2619 }
2620 }
2621
2622 if (stmt->Ist.Put.data->tag != Iex_Const) {
2623 /* Invalidate guest register contents */
2624 env->old_value_valid[guest_reg] = False;
2625 goto not_special;
2626 }
2627
cborntraaf7ad282012-08-08 14:11:33 +00002628 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2629 if (tyd != Ity_I64)
2630 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002631
cborntraaf7ad282012-08-08 14:11:33 +00002632 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002633
2634 old_value = env->old_value[guest_reg];
2635 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2636 env->old_value[guest_reg] = new_value;
2637
2638 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2639 env->old_value_valid[guest_reg] = True;
2640
2641 /* If the register already contains the new value, there is nothing
2642 to do here. Unless the guest register requires precise memory
2643 exceptions. */
2644 if (old_value_is_valid && new_value == old_value) {
2645 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2646 return;
2647 }
2648 }
2649
2650 /* guest register = 0 */
2651 if (new_value == 0) {
2652 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2653 return;
2654 }
2655
2656 if (old_value_is_valid == False) goto not_special;
2657
2658 /* If the new value is in the neighbourhood of the old value
2659 we can use a memory-to-memory insn */
2660 difference = new_value - old_value;
2661
2662 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2663 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2664 (difference & 0xFF), new_value));
2665 return;
2666 }
2667
2668 /* If the high word is the same it is sufficient to load the low word.
2669 Use R0 as a scratch reg. */
2670 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002671 HReg r0 = make_gpr(0);
2672 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002673 s390_amode *gam;
2674
2675 gam = s390_amode_b12(offset + 4, gsp);
2676 addInstr(env, s390_insn_load_immediate(4, r0,
2677 new_value & 0xFFFFFFFF));
2678 addInstr(env, s390_insn_store(4, gam, r0));
2679 return;
2680 }
2681
2682 /* No special case applies... fall through */
2683
2684 not_special:
sewardj2019a972011-03-07 16:04:07 +00002685 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2686
2687 switch (tyd) {
2688 case Ity_I8:
2689 case Ity_I16:
2690 case Ity_I32:
2691 case Ity_I64:
2692 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2693 break;
2694
2695 case Ity_F32:
2696 case Ity_F64:
2697 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2698 break;
2699
2700 case Ity_F128:
2701 /* Does not occur. See function put_fpr_pair. */
2702 vpanic("Ist_Put with F128 data");
2703
florian12390202012-11-10 22:34:14 +00002704 case Ity_D64:
2705 src = s390_isel_dfp_expr(env, stmt->Ist.Put.data);
2706 break;
2707
sewardj2019a972011-03-07 16:04:07 +00002708 default:
2709 goto stmt_fail;
2710 }
2711
2712 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2713 return;
2714 }
2715
2716 /* --------- TMP --------- */
2717 case Ist_WrTmp: {
2718 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2719 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2720 HReg src, dst;
2721
2722 switch (tyd) {
2723 case Ity_I128: {
2724 HReg dst_hi, dst_lo, res_hi, res_lo;
2725
2726 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2727 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2728
2729 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2730 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2731 return;
2732 }
2733
2734 case Ity_I8:
2735 case Ity_I16:
2736 case Ity_I32:
2737 case Ity_I64:
2738 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2739 dst = lookupIRTemp(env, tmp);
2740 break;
2741
2742 case Ity_I1: {
2743 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2744 dst = lookupIRTemp(env, tmp);
2745 addInstr(env, s390_insn_cc2bool(dst, cond));
2746 return;
2747 }
2748
2749 case Ity_F32:
2750 case Ity_F64:
2751 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2752 dst = lookupIRTemp(env, tmp);
2753 break;
2754
2755 case Ity_F128: {
2756 HReg dst_hi, dst_lo, res_hi, res_lo;
2757
2758 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2759 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2760
2761 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2762 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2763 return;
2764 }
2765
florian12390202012-11-10 22:34:14 +00002766 case Ity_D64:
2767 src = s390_isel_dfp_expr(env, stmt->Ist.WrTmp.data);
2768 dst = lookupIRTemp(env, tmp);
2769 break;
2770
sewardj2019a972011-03-07 16:04:07 +00002771 default:
2772 goto stmt_fail;
2773 }
2774
2775 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2776 return;
2777 }
2778
2779 /* --------- Call to DIRTY helper --------- */
2780 case Ist_Dirty: {
2781 IRType retty;
2782 IRDirty* d = stmt->Ist.Dirty.details;
2783 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002784 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002785 Int i;
2786
2787 /* Invalidate tracked values of those guest state registers that are
2788 modified by this helper. */
2789 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002790 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2791 descriptors in guest state effect descriptions. Hence: */
2792 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002793 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2794 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2795 if (guest_reg != GUEST_UNKNOWN)
2796 env->old_value_valid[guest_reg] = False;
2797 }
2798 }
sewardj2019a972011-03-07 16:04:07 +00002799
2800 if (d->nFxState == 0)
2801 vassert(!d->needsBBP);
2802
2803 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2804
florian01ed6e72012-05-27 16:52:43 +00002805 if (d->tmp == IRTemp_INVALID) {
2806 /* No return value. */
2807 dst = INVALID_HREG;
2808 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002809 return;
florian01ed6e72012-05-27 16:52:43 +00002810 }
sewardj2019a972011-03-07 16:04:07 +00002811
2812 retty = typeOfIRTemp(env->type_env, d->tmp);
2813 if (retty == Ity_I64 || retty == Ity_I32
2814 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002815 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002816 dst = lookupIRTemp(env, d->tmp);
2817 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002818 return;
2819 }
2820 break;
2821 }
2822
2823 case Ist_CAS:
2824 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2825 IRCAS *cas = stmt->Ist.CAS.details;
2826 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2827 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2828 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2829 HReg old = lookupIRTemp(env, cas->oldLo);
2830
2831 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2832 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2833 } else {
2834 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2835 }
2836 return;
2837 } else {
florian448cbba2012-06-06 02:26:01 +00002838 IRCAS *cas = stmt->Ist.CAS.details;
2839 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2840 HReg r8, r9, r10, r11, r1;
2841 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2842 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2843 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2844 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2845 HReg old_low = lookupIRTemp(env, cas->oldLo);
2846 HReg old_high = lookupIRTemp(env, cas->oldHi);
2847
2848 /* Use non-virtual registers r8 and r9 as pair for op1
2849 and move op1 there */
2850 r8 = make_gpr(8);
2851 r9 = make_gpr(9);
2852 addInstr(env, s390_insn_move(8, r8, op1_high));
2853 addInstr(env, s390_insn_move(8, r9, op1_low));
2854
2855 /* Use non-virtual registers r10 and r11 as pair for op3
2856 and move op3 there */
2857 r10 = make_gpr(10);
2858 r11 = make_gpr(11);
2859 addInstr(env, s390_insn_move(8, r10, op3_high));
2860 addInstr(env, s390_insn_move(8, r11, op3_low));
2861
2862 /* Register r1 is used as a scratch register */
2863 r1 = make_gpr(1);
2864
2865 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2866 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2867 old_high, old_low, r1));
2868 } else {
2869 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2870 old_high, old_low, r1));
2871 }
2872 addInstr(env, s390_insn_move(8, op1_high, r8));
2873 addInstr(env, s390_insn_move(8, op1_low, r9));
2874 addInstr(env, s390_insn_move(8, op3_high, r10));
2875 addInstr(env, s390_insn_move(8, op3_low, r11));
2876 return;
sewardj2019a972011-03-07 16:04:07 +00002877 }
2878 break;
2879
2880 /* --------- EXIT --------- */
2881 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002882 s390_cc_t cond;
2883 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2884
2885 if (tag != Ico_U64)
2886 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2887
florian8844a632012-04-13 04:04:06 +00002888 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002889 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002890
2891 /* Case: boring transfer to known address */
2892 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2893 if (env->chaining_allowed) {
2894 /* .. almost always true .. */
2895 /* Skip the event check at the dst if this is a forwards
2896 edge. */
2897 Bool to_fast_entry
2898 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2899 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2900 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2901 guest_IA, to_fast_entry));
2902 } else {
2903 /* .. very occasionally .. */
2904 /* We can't use chaining, so ask for an assisted transfer,
2905 as that's the only alternative that is allowable. */
2906 HReg dst = s390_isel_int_expr(env,
2907 IRExpr_Const(stmt->Ist.Exit.dst));
2908 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2909 }
2910 return;
2911 }
2912
2913 /* Case: assisted transfer to arbitrary address */
2914 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00002915 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002916 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002917 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002918 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002919 case Ijk_Sys_syscall:
2920 case Ijk_ClientReq:
2921 case Ijk_NoRedir:
2922 case Ijk_Yield:
2923 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002924 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2925 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2926 stmt->Ist.Exit.jk));
2927 return;
2928 }
2929 default:
2930 break;
2931 }
2932
2933 /* Do we ever expect to see any other kind? */
2934 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002935 }
2936
2937 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002938 case Ist_MBE:
2939 switch (stmt->Ist.MBE.event) {
2940 case Imbe_Fence:
2941 addInstr(env, s390_insn_mfence());
2942 return;
2943 default:
2944 break;
2945 }
sewardj2019a972011-03-07 16:04:07 +00002946 break;
2947
2948 /* --------- Miscellaneous --------- */
2949
2950 case Ist_PutI: /* Not needed */
2951 case Ist_IMark: /* Doesn't generate any executable code */
2952 case Ist_NoOp: /* Doesn't generate any executable code */
2953 case Ist_AbiHint: /* Meaningless in IR */
2954 return;
2955
2956 default:
2957 break;
2958 }
2959
2960 stmt_fail:
2961 ppIRStmt(stmt);
2962 vpanic("s390_isel_stmt");
2963}
2964
2965
2966/*---------------------------------------------------------*/
2967/*--- ISEL: Basic block terminators (Nexts) ---*/
2968/*---------------------------------------------------------*/
2969
2970static void
florian8844a632012-04-13 04:04:06 +00002971iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002972{
sewardj2019a972011-03-07 16:04:07 +00002973 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002974 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002975 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002976 vex_printf("; exit-");
2977 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002978 vex_printf("\n");
2979 }
2980
florian8844a632012-04-13 04:04:06 +00002981 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2982
2983 /* Case: boring transfer to known address */
2984 if (next->tag == Iex_Const) {
2985 IRConst *cdst = next->Iex.Const.con;
2986 vassert(cdst->tag == Ico_U64);
2987 if (jk == Ijk_Boring || jk == Ijk_Call) {
2988 /* Boring transfer to known address */
2989 if (env->chaining_allowed) {
2990 /* .. almost always true .. */
2991 /* Skip the event check at the dst if this is a forwards
2992 edge. */
2993 Bool to_fast_entry
2994 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2995 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2996 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2997 guest_IA, to_fast_entry));
2998 } else {
2999 /* .. very occasionally .. */
3000 /* We can't use chaining, so ask for an indirect transfer,
3001 as that's the cheapest alternative that is allowable. */
3002 HReg dst = s390_isel_int_expr(env, next);
3003 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3004 Ijk_Boring));
3005 }
3006 return;
3007 }
3008 }
3009
3010 /* Case: call/return (==boring) transfer to any address */
3011 switch (jk) {
3012 case Ijk_Boring:
3013 case Ijk_Ret:
3014 case Ijk_Call: {
3015 HReg dst = s390_isel_int_expr(env, next);
3016 if (env->chaining_allowed) {
3017 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
3018 } else {
3019 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
3020 Ijk_Boring));
3021 }
3022 return;
3023 }
3024 default:
3025 break;
3026 }
3027
3028 /* Case: some other kind of transfer to any address */
3029 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00003030 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00003031 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00003032 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00003033 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00003034 case Ijk_Sys_syscall:
3035 case Ijk_ClientReq:
3036 case Ijk_NoRedir:
3037 case Ijk_Yield:
3038 case Ijk_SigTRAP: {
3039 HReg dst = s390_isel_int_expr(env, next);
3040 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
3041 return;
3042 }
3043 default:
3044 break;
3045 }
3046
3047 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00003048}
3049
3050
3051/*---------------------------------------------------------*/
3052/*--- Insn selector top-level ---*/
3053/*---------------------------------------------------------*/
3054
florianf26994a2012-04-21 03:34:54 +00003055/* Translate an entire SB to s390 code.
3056 Note: archinfo_host is a pointer to a stack-allocated variable.
3057 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00003058
3059HInstrArray *
3060iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00003061 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
3062 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
3063 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00003064{
3065 UInt i, j;
3066 HReg hreg, hregHI;
3067 ISelEnv *env;
3068 UInt hwcaps_host = archinfo_host->hwcaps;
3069
florianf26994a2012-04-21 03:34:54 +00003070 /* KLUDGE: export hwcaps. */
3071 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00003072
sewardj2019a972011-03-07 16:04:07 +00003073 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00003074 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00003075
3076 /* Make up an initial environment to use. */
3077 env = LibVEX_Alloc(sizeof(ISelEnv));
3078 env->vreg_ctr = 0;
3079
3080 /* Set up output code array. */
3081 env->code = newHInstrArray();
3082
3083 /* Copy BB's type env. */
3084 env->type_env = bb->tyenv;
3085
florianad43b3a2012-02-20 15:01:14 +00003086 /* Set up data structures for tracking guest register values. */
3087 env->first_IA_assignment = True;
3088 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
3089 env->old_value[i] = 0; /* just something to have a defined value */
3090 env->old_value_valid[i] = False;
3091 }
3092
sewardj2019a972011-03-07 16:04:07 +00003093 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
3094 change as we go along. For some reason types_used has Int type -- but
3095 it should be unsigned. Internally we use an unsigned type; so we
3096 assert it here. */
3097 vassert(bb->tyenv->types_used >= 0);
3098
3099 env->n_vregmap = bb->tyenv->types_used;
3100 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3101 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3102
florian2c74d242012-09-12 19:38:42 +00003103 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00003104 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00003105
sewardj2019a972011-03-07 16:04:07 +00003106 /* and finally ... */
3107 env->hwcaps = hwcaps_host;
3108
florian8844a632012-04-13 04:04:06 +00003109 env->max_ga = max_ga;
3110 env->chaining_allowed = chaining_allowed;
3111
sewardj2019a972011-03-07 16:04:07 +00003112 /* For each IR temporary, allocate a suitably-kinded virtual
3113 register. */
3114 j = 0;
3115 for (i = 0; i < env->n_vregmap; i++) {
3116 hregHI = hreg = INVALID_HREG;
3117 switch (bb->tyenv->types[i]) {
3118 case Ity_I1:
3119 case Ity_I8:
3120 case Ity_I16:
3121 case Ity_I32:
3122 hreg = mkHReg(j++, HRcInt64, True);
3123 break;
3124
3125 case Ity_I64:
3126 hreg = mkHReg(j++, HRcInt64, True);
3127 break;
3128
3129 case Ity_I128:
3130 hreg = mkHReg(j++, HRcInt64, True);
3131 hregHI = mkHReg(j++, HRcInt64, True);
3132 break;
3133
3134 case Ity_F32:
3135 case Ity_F64:
florian12390202012-11-10 22:34:14 +00003136 case Ity_D64:
sewardj2019a972011-03-07 16:04:07 +00003137 hreg = mkHReg(j++, HRcFlt64, True);
3138 break;
3139
3140 case Ity_F128:
3141 hreg = mkHReg(j++, HRcFlt64, True);
3142 hregHI = mkHReg(j++, HRcFlt64, True);
3143 break;
3144
3145 case Ity_V128: /* fall through */
3146 default:
3147 ppIRType(bb->tyenv->types[i]);
3148 vpanic("s390_isel_sb: IRTemp type");
3149 }
3150
3151 env->vregmap[i] = hreg;
3152 env->vregmapHI[i] = hregHI;
3153 }
3154 env->vreg_ctr = j;
3155
florian8844a632012-04-13 04:04:06 +00003156 /* The very first instruction must be an event check. */
3157 s390_amode *counter, *fail_addr;
3158 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3159 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3160 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3161
3162 /* Possibly a block counter increment (for profiling). At this
3163 point we don't know the address of the counter, so just pretend
3164 it is zero. It will have to be patched later, but before this
3165 translation is used, by a call to LibVEX_patchProfInc. */
3166 if (add_profinc) {
3167 addInstr(env, s390_insn_profinc());
3168 }
3169
sewardj2019a972011-03-07 16:04:07 +00003170 /* Ok, finally we can iterate over the statements. */
3171 for (i = 0; i < bb->stmts_used; i++)
3172 if (bb->stmts[i])
3173 s390_isel_stmt(env, bb->stmts[i]);
3174
florian8844a632012-04-13 04:04:06 +00003175 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003176
3177 /* Record the number of vregs we used. */
3178 env->code->n_vregs = env->vreg_ctr;
3179
3180 return env->code;
3181}
3182
3183/*---------------------------------------------------------------*/
3184/*--- end host_s390_isel.c ---*/
3185/*---------------------------------------------------------------*/