blob: 4d85a0ffb3f06f58f4219f551249bbad57b87110 [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
11 Copyright IBM Corp. 2010-2011
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 02110-1301, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
31/* Contributed by Florian Krohm */
32
33#include "libvex_basictypes.h"
34#include "libvex_ir.h"
35#include "libvex.h"
36#include "libvex_s390x_common.h"
37
sewardj2019a972011-03-07 16:04:07 +000038#include "main_util.h"
39#include "main_globals.h"
florianad43b3a2012-02-20 15:01:14 +000040#include "guest_s390_defs.h" /* guest_s390x_state_requires_precise_mem_exns */
sewardj2019a972011-03-07 16:04:07 +000041#include "host_generic_regs.h"
42#include "host_s390_defs.h"
43
44/*---------------------------------------------------------*/
45/*--- ISelEnv ---*/
46/*---------------------------------------------------------*/
47
48/* This carries around:
49
50 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
51 might encounter. This is computed before insn selection starts,
52 and does not change.
53
54 - A mapping from IRTemp to HReg. This tells the insn selector
55 which virtual register(s) are associated with each IRTemp
56 temporary. This is computed before insn selection starts, and
57 does not change. We expect this mapping to map precisely the
58 same set of IRTemps as the type mapping does.
59
60 - vregmap holds the primary register for the IRTemp.
61 - vregmapHI holds the secondary register for the IRTemp,
62 if any is needed. That's only for Ity_I64 temps
63 in 32 bit mode or Ity_I128 temps in 64-bit mode.
64
65 - The code array, that is, the insns selected so far.
66
67 - A counter, for generating new virtual registers.
68
69 - The host subarchitecture we are selecting insns for.
70 This is set at the start and does not change.
florianad43b3a2012-02-20 15:01:14 +000071
florian8844a632012-04-13 04:04:06 +000072 - A Bool for indicating whether we may generate chain-me
73 instructions for control flow transfers, or whether we must use
74 XAssisted.
75
76 - The maximum guest address of any guest insn in this block.
77 Actually, the address of the highest-addressed byte from any insn
78 in this block. Is set at the start and does not change. This is
79 used for detecting jumps which are definitely forward-edges from
80 this block, and therefore can be made (chained) to the fast entry
81 point of the destination, thereby avoiding the destination's
82 event check.
83
florianad43b3a2012-02-20 15:01:14 +000084 - A flag to indicate whether the guest IA has been assigned to.
85
86 - Values of certain guest registers which are often assigned constants.
sewardj2019a972011-03-07 16:04:07 +000087*/
88
florianad43b3a2012-02-20 15:01:14 +000089/* Symbolic names for guest registers whose value we're tracking */
90enum {
91 GUEST_IA,
92 GUEST_CC_OP,
93 GUEST_CC_DEP1,
94 GUEST_CC_DEP2,
95 GUEST_CC_NDEP,
96 GUEST_SYSNO,
florian7d117ba2012-05-06 03:34:55 +000097 GUEST_COUNTER,
florianad43b3a2012-02-20 15:01:14 +000098 GUEST_UNKNOWN /* must be the last entry */
99};
100
101/* Number of registers we're tracking. */
102#define NUM_TRACKED_REGS GUEST_UNKNOWN
103
104
sewardj2019a972011-03-07 16:04:07 +0000105typedef struct {
106 IRTypeEnv *type_env;
107
florian8844a632012-04-13 04:04:06 +0000108 HInstrArray *code;
sewardj2019a972011-03-07 16:04:07 +0000109 HReg *vregmap;
110 HReg *vregmapHI;
111 UInt n_vregmap;
florian8844a632012-04-13 04:04:06 +0000112 UInt vreg_ctr;
113 UInt hwcaps;
sewardj2019a972011-03-07 16:04:07 +0000114
florianad43b3a2012-02-20 15:01:14 +0000115 ULong old_value[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000116
florian8844a632012-04-13 04:04:06 +0000117 /* The next two are for translation chaining */
118 Addr64 max_ga;
119 Bool chaining_allowed;
120
florianad43b3a2012-02-20 15:01:14 +0000121 Bool first_IA_assignment;
122 Bool old_value_valid[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000123} ISelEnv;
124
125
126/* Forward declarations */
127static HReg s390_isel_int_expr(ISelEnv *, IRExpr *);
128static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *);
129static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
130static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
131static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
132static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
133static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
134
135
florianad43b3a2012-02-20 15:01:14 +0000136static Int
137get_guest_reg(Int offset)
138{
139 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000140 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
141 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
142 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
143 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
144 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
145 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000146 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000147
148 /* Also make sure there is never a partial write to one of
149 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000150 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
151 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
152 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
153 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
154 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000155 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
156 /* counter is used both as 4-byte and as 8-byte entity */
157 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
158 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianad43b3a2012-02-20 15:01:14 +0000159 vassert("partial update of this guest state register is not allowed");
160 break;
161
162 default: break;
163 }
164
165 return GUEST_UNKNOWN;
166}
167
sewardj2019a972011-03-07 16:04:07 +0000168/* Add an instruction */
169static void
170addInstr(ISelEnv *env, s390_insn *insn)
171{
172 addHInstr(env->code, insn);
173
174 if (vex_traceflags & VEX_TRACE_VCODE) {
175 vex_printf("%s\n", s390_insn_as_string(insn));
176 }
177}
178
179
180static __inline__ IRExpr *
181mkU64(ULong value)
182{
183 return IRExpr_Const(IRConst_U64(value));
184}
185
186
187/*---------------------------------------------------------*/
188/*--- Registers ---*/
189/*---------------------------------------------------------*/
190
191/* Return the virtual register to which a given IRTemp is mapped. */
192static HReg
193lookupIRTemp(ISelEnv *env, IRTemp tmp)
194{
195 vassert(tmp < env->n_vregmap);
196 vassert(env->vregmap[tmp] != INVALID_HREG);
197
198 return env->vregmap[tmp];
199}
200
201
202/* Return the two virtual registers to which the IRTemp is mapped. */
203static void
204lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
205{
206 vassert(tmp < env->n_vregmap);
207 vassert(env->vregmapHI[tmp] != INVALID_HREG);
208
209 *lo = env->vregmap[tmp];
210 *hi = env->vregmapHI[tmp];
211}
212
213
214/* Allocate a new integer register */
215static HReg
216newVRegI(ISelEnv *env)
217{
218 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
219 env->vreg_ctr++;
220
221 return reg;
222}
223
224
225/* Allocate a new floating point register */
226static HReg
227newVRegF(ISelEnv *env)
228{
229 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
230
231 env->vreg_ctr++;
232
233 return reg;
234}
235
236
237/* Construct a non-virtual general purpose register */
238static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000239make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000240{
241 return mkHReg(regno, HRcInt64, False /* virtual */ );
242}
243
244
245/* Construct a non-virtual floating point register */
246static __inline__ HReg
247make_fpr(UInt regno)
248{
249 return mkHReg(regno, HRcFlt64, False /* virtual */ );
250}
251
252
253/*---------------------------------------------------------*/
254/*--- Amode ---*/
255/*---------------------------------------------------------*/
256
257static __inline__ Bool
258ulong_fits_unsigned_12bit(ULong val)
259{
260 return (val & 0xFFFu) == val;
261}
262
263
264static __inline__ Bool
265ulong_fits_signed_20bit(ULong val)
266{
267 Long v = val & 0xFFFFFu;
268
269 v = (v << 44) >> 44; /* sign extend */
270
271 return val == (ULong)v;
272}
273
274
florianad43b3a2012-02-20 15:01:14 +0000275static __inline__ Bool
276ulong_fits_signed_8bit(ULong val)
277{
278 Long v = val & 0xFFu;
279
280 v = (v << 56) >> 56; /* sign extend */
281
282 return val == (ULong)v;
283}
284
sewardj2019a972011-03-07 16:04:07 +0000285/* EXPR is an expression that is used as an address. Return an s390_amode
286 for it. */
287static s390_amode *
288s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
289{
290 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
291 IRExpr *arg1 = expr->Iex.Binop.arg1;
292 IRExpr *arg2 = expr->Iex.Binop.arg2;
293
294 /* Move constant into right subtree */
295 if (arg1->tag == Iex_Const) {
296 IRExpr *tmp;
297 tmp = arg1;
298 arg1 = arg2;
299 arg2 = tmp;
300 }
301
302 /* r + constant: Check for b12 first, then b20 */
303 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
304 ULong value = arg2->Iex.Const.con->Ico.U64;
305
306 if (ulong_fits_unsigned_12bit(value)) {
307 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
308 }
sewardj652b56a2011-04-13 15:38:17 +0000309 /* If long-displacement is not available, do not construct B20 or
310 BX20 amodes because code generation cannot handle them. */
311 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000312 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
313 }
314 }
315 }
316
317 /* Doesn't match anything in particular. Generate it into
318 a register and use that. */
319 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
320}
321
322
323static s390_amode *
324s390_isel_amode(ISelEnv *env, IRExpr *expr)
325{
florian35da8612011-06-25 02:25:41 +0000326 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000327
328 /* Address computation should yield a 64-bit value */
329 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
330
331 am = s390_isel_amode_wrk(env, expr);
332
333 /* Check post-condition */
334 vassert(s390_amode_is_sane(am));
335
336 return am;
337}
338
339
340/*---------------------------------------------------------*/
341/*--- Helper functions ---*/
342/*---------------------------------------------------------*/
343
344/* Constants and memory accesses should be right operands */
345#define order_commutative_operands(left, right) \
346 do { \
347 if (left->tag == Iex_Const || left->tag == Iex_Load || \
348 left->tag == Iex_Get) { \
349 IRExpr *tmp; \
350 tmp = left; \
351 left = right; \
352 right = tmp; \
353 } \
354 } while (0)
355
356
357/* Copy an RMI operand to the DST register */
358static s390_insn *
359s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
360{
361 switch (opnd.tag) {
362 case S390_OPND_AMODE:
363 return s390_insn_load(size, dst, opnd.variant.am);
364
365 case S390_OPND_REG:
366 return s390_insn_move(size, dst, opnd.variant.reg);
367
368 case S390_OPND_IMMEDIATE:
369 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
370
371 default:
372 vpanic("s390_opnd_copy");
373 }
374}
375
376
377/* Construct a RMI operand for a register */
378static __inline__ s390_opnd_RMI
379s390_opnd_reg(HReg reg)
380{
381 s390_opnd_RMI opnd;
382
383 opnd.tag = S390_OPND_REG;
384 opnd.variant.reg = reg;
385
386 return opnd;
387}
388
389
390/* Construct a RMI operand for an immediate constant */
391static __inline__ s390_opnd_RMI
392s390_opnd_imm(ULong value)
393{
394 s390_opnd_RMI opnd;
395
396 opnd.tag = S390_OPND_IMMEDIATE;
397 opnd.variant.imm = value;
398
399 return opnd;
400}
401
402
403/* Return 1, if EXPR represents the cosntant 0 */
404static int
405s390_expr_is_const_zero(IRExpr *expr)
406{
407 ULong value;
408
409 if (expr->tag == Iex_Const) {
410 switch (expr->Iex.Const.con->tag) {
411 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
412 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
413 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
414 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
415 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
416 default:
417 vpanic("s390_expr_is_const_zero");
418 }
419 return value == 0;
420 }
421
422 return 0;
423}
424
425
floriane0654362012-05-09 13:31:09 +0000426/* If EXPR can be evaluated with a single s390_insn, do so and assign the
427 value to register DST. If not, return NULL. */
428static s390_insn *
429s390_isel_single_insn_for_int_expr(ISelEnv *env, HReg dst, IRExpr *expr)
430{
431 switch (expr->tag) {
432 case Iex_Const: {
433 ULong value;
434 const IRConst *con = expr->Iex.Const.con;
435
436 /* Bitwise copy of the value. No sign/zero-extension */
437 switch (con->tag) {
438 case Ico_U64: value = con->Ico.U64; break;
439 case Ico_U32: value = con->Ico.U32; break;
440 case Ico_U16: value = con->Ico.U16; break;
441 case Ico_U8: value = con->Ico.U8; break;
442 default: vpanic("s390_isel_single_insn_for_int_expr: invalid constant");
443 }
444
445 return s390_insn_load_immediate(8, dst, value);
446 }
447
448 case Iex_RdTmp: {
449 HReg src = lookupIRTemp(env, expr->Iex.RdTmp.tmp);
450 return s390_insn_move(8, dst, src);
451 }
452
453 case Iex_Get: {
454 UInt size = sizeofIRType(typeOfIRExpr(env->type_env, expr));
455 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
456
457 return s390_insn_load(size, dst, am);
458 }
459
460 case Iex_Load: {
461 UInt size = sizeofIRType(typeOfIRExpr(env->type_env, expr));
462 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
463
464 vassert(expr->Iex.Load.end == Iend_BE);
465
466 return s390_insn_load(size, dst, am);
467 }
468
469 default:
470 /* too complex */
471 return NULL;
472 }
473}
474
475
sewardj2019a972011-03-07 16:04:07 +0000476/* Call a helper (clean or dirty)
477 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000478
sewardj2019a972011-03-07 16:04:07 +0000479 (a) they are expressions yielding an integer result
480 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000481
482 guard is a Ity_Bit expression indicating whether or not the
483 call happens. If guard == NULL, the call is unconditional.
sewardj2019a972011-03-07 16:04:07 +0000484*/
485static void
486doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
487 IRCallee *callee, IRExpr **args)
488{
floriane0654362012-05-09 13:31:09 +0000489 UInt n_args, i, argreg;
sewardj2019a972011-03-07 16:04:07 +0000490 ULong target;
floriane0654362012-05-09 13:31:09 +0000491 s390_insn *insn_for_arg[S390_NUM_GPRPARMS];
sewardj2019a972011-03-07 16:04:07 +0000492 HReg tmpregs[S390_NUM_GPRPARMS];
493 s390_cc_t cc;
494
495 n_args = 0;
496 for (i = 0; args[i]; i++)
497 ++n_args;
498
499 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
500 vpanic("doHelperCall: too many arguments");
501 }
502
sewardj2019a972011-03-07 16:04:07 +0000503 /* Compute the condition */
504 cc = S390_CC_ALWAYS;
505 if (guard) {
506 if (guard->tag == Iex_Const
507 && guard->Iex.Const.con->tag == Ico_U1
508 && guard->Iex.Const.con->Ico.U1 == True) {
509 /* unconditional -- do nothing */
510 } else {
511 cc = s390_isel_cc(env, guard);
512 }
513 }
514
floriane0654362012-05-09 13:31:09 +0000515 /* Evaluate the function arguments for the helper call.
516 First, as the helper function is written in C, we are free to evaluate
517 argumeqnts in any order we like, as the evaluation order is unspecified
518 by the C standard.
sewardj2019a972011-03-07 16:04:07 +0000519
floriane0654362012-05-09 13:31:09 +0000520 Secondly, if possible, we want to evaluate the arguments such that its
521 value ends up in the register that is mandated by the ABI for this
522 argument. The idea is to avoid an additional move insn from a virtual
523 to a real register. Currently, the register allocator is not very good
524 at eliminating those.
525
526 The complication is that we need to make sure that real registers do not
527 get overwritten while evaluating the arguments. Consider a helper call
528 with two arguments. The first argument is an integer constant and the
529 second argument is a complex expression. If we evaluate the 1st argument
530 and load the constant into r2 (as mandated by ABI) and the 2nd argument
531 expression contains a helper call with arguments, then evaluation of the
532 2nd argument will overwrite the contents of r2. Not so good. Therefore,
533 we first evaluate all those arguments which are complex and assign their
534 value to a virtual register. Then in a second pass we evaluate those
535 arguments where the value can be assigned to the ABI destination register
536 directly. There is no danger now that those can be overwritten. This is
537 what happens conceptually. The implementation is slightly different. */
538
539 argreg = 0;
540
541 /* If we need the guest state pointer put it into the correct register */
542 if (passBBP) {
543 insn_for_arg[argreg] =
544 s390_insn_move(sizeof(ULong),
545 make_gpr(s390_gprno_from_arg_index(argreg)),
546 s390_hreg_guest_state_pointer());
547 argreg++;
548 }
549
550 /* Compute the function arguments. Issue insns for complex arguments.
551 Store their value in a temporary register each. For arguments that
552 can be evaluated in their ABI destination register, generate the
553 insn but do not issue it yet. */
554 for (i = 0; i < n_args; i++) {
555 HReg dst = make_gpr(s390_gprno_from_arg_index(argreg));
556
557 insn_for_arg[argreg] =
558 s390_isel_single_insn_for_int_expr(env, dst, args[i]);
559
560 if (insn_for_arg[argreg] == NULL) {
561 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
562 }
563 argreg++;
564 }
565
566 /* Assign values to ABI registers */
567 for (i = 0; i < argreg; i++) {
568 if (insn_for_arg[i]) {
569 addInstr(env, insn_for_arg[i]); /* issue insn */
570 } else {
571 /* Move value to ABI register */
572 HReg finalreg = make_gpr(s390_gprno_from_arg_index(i));
573 addInstr(env, s390_insn_move(8, finalreg, tmpregs[i]));
574 }
sewardj2019a972011-03-07 16:04:07 +0000575 }
576
577 target = Ptr_to_ULong(callee->addr);
578
579 /* Finally, the call itself. */
580 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
581 callee->name));
582}
583
584
585/* Given an expression representing a rounding mode using IRRoundingMode
586 encoding convert it to an s390_round_t value. */
587static s390_round_t
588decode_rounding_mode(IRExpr *rounding_expr)
589{
590 if (rounding_expr->tag == Iex_Const &&
591 rounding_expr->Iex.Const.con->tag == Ico_U32) {
592 IRRoundingMode mode = rounding_expr->Iex.Const.con->Ico.U32;
593
594 switch (mode) {
595 case Irrm_NEAREST: return S390_ROUND_NEAREST_EVEN;
596 case Irrm_ZERO: return S390_ROUND_ZERO;
597 case Irrm_PosINF: return S390_ROUND_POSINF;
598 case Irrm_NegINF: return S390_ROUND_NEGINF;
599 }
600 }
601
602 vpanic("decode_rounding_mode");
603}
604
605
606/* CC_S390 holds the condition code in s390 encoding. Convert it to
607 VEX encoding
608
609 s390 VEX b6 b2 b0 cc.1 cc.0
610 0 0x40 EQ 1 0 0 0 0
611 1 0x01 LT 0 0 1 0 1
612 2 0x00 GT 0 0 0 1 0
613 3 0x45 Unordered 1 1 1 1 1
614
615 b0 = cc.0
616 b2 = cc.0 & cc.1
617 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
618
619 VEX = b0 | (b2 << 2) | (b6 << 6);
620*/
621static HReg
622convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390)
623{
624 HReg cc0, cc1, b2, b6, cc_vex;
625
626 cc0 = newVRegI(env);
627 addInstr(env, s390_insn_move(4, cc0, cc_s390));
628 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
629
630 cc1 = newVRegI(env);
631 addInstr(env, s390_insn_move(4, cc1, cc_s390));
632 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
633
634 b2 = newVRegI(env);
635 addInstr(env, s390_insn_move(4, b2, cc0));
636 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
637 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
638
639 b6 = newVRegI(env);
640 addInstr(env, s390_insn_move(4, b6, cc0));
641 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
642 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
643 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
644 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
645
646 cc_vex = newVRegI(env);
647 addInstr(env, s390_insn_move(4, cc_vex, cc0));
648 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
649 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
650
651 return cc_vex;
652}
653
654
655/*---------------------------------------------------------*/
656/*--- ISEL: Integer expressions (128 bit) ---*/
657/*---------------------------------------------------------*/
658static void
659s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
660 IRExpr *expr)
661{
662 IRType ty = typeOfIRExpr(env->type_env, expr);
663
664 vassert(ty == Ity_I128);
665
666 /* No need to consider the following
667 - 128-bit constants (they do not exist in VEX)
668 - 128-bit loads from memory (will not be generated)
669 */
670
671 /* Read 128-bit IRTemp */
672 if (expr->tag == Iex_RdTmp) {
673 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
674 return;
675 }
676
677 if (expr->tag == Iex_Binop) {
678 IRExpr *arg1 = expr->Iex.Binop.arg1;
679 IRExpr *arg2 = expr->Iex.Binop.arg2;
680 Bool is_signed_multiply, is_signed_divide;
681
682 switch (expr->Iex.Binop.op) {
683 case Iop_MullU64:
684 is_signed_multiply = False;
685 goto do_multiply64;
686
687 case Iop_MullS64:
688 is_signed_multiply = True;
689 goto do_multiply64;
690
691 case Iop_DivModU128to64:
692 is_signed_divide = False;
693 goto do_divide64;
694
695 case Iop_DivModS128to64:
696 is_signed_divide = True;
697 goto do_divide64;
698
699 case Iop_64HLto128:
700 *dst_hi = s390_isel_int_expr(env, arg1);
701 *dst_lo = s390_isel_int_expr(env, arg2);
702 return;
703
704 case Iop_DivModS64to64: {
705 HReg r10, r11, h1;
706 s390_opnd_RMI op2;
707
708 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
709 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
710
711 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000712 r10 = make_gpr(10);
713 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000714
715 /* Move 1st operand into r11 and */
716 addInstr(env, s390_insn_move(8, r11, h1));
717
718 /* Divide */
719 addInstr(env, s390_insn_divs(8, r10, r11, op2));
720
721 /* The result is in registers r10 (remainder) and r11 (quotient).
722 Move the result into the reg pair that is being returned such
723 such that the low 64 bits are the quotient and the upper 64 bits
724 are the remainder. (see libvex_ir.h). */
725 *dst_hi = newVRegI(env);
726 *dst_lo = newVRegI(env);
727 addInstr(env, s390_insn_move(8, *dst_hi, r10));
728 addInstr(env, s390_insn_move(8, *dst_lo, r11));
729 return;
730 }
731
732 default:
733 break;
734
735 do_multiply64: {
736 HReg r10, r11, h1;
737 s390_opnd_RMI op2;
738
739 order_commutative_operands(arg1, arg2);
740
741 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
742 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
743
744 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000745 r10 = make_gpr(10);
746 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000747
748 /* Move the first operand to r11 */
749 addInstr(env, s390_insn_move(8, r11, h1));
750
751 /* Multiply */
752 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
753
754 /* The result is in registers r10 and r11. Assign to two virtual regs
755 and return. */
756 *dst_hi = newVRegI(env);
757 *dst_lo = newVRegI(env);
758 addInstr(env, s390_insn_move(8, *dst_hi, r10));
759 addInstr(env, s390_insn_move(8, *dst_lo, r11));
760 return;
761 }
762
763 do_divide64: {
764 HReg r10, r11, hi, lo;
765 s390_opnd_RMI op2;
766
767 s390_isel_int128_expr(&hi, &lo, env, arg1);
768 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
769
770 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000771 r10 = make_gpr(10);
772 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000773
774 /* Move high 64 bits of the 1st operand into r10 and
775 the low 64 bits into r11. */
776 addInstr(env, s390_insn_move(8, r10, hi));
777 addInstr(env, s390_insn_move(8, r11, lo));
778
779 /* Divide */
780 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
781
782 /* The result is in registers r10 (remainder) and r11 (quotient).
783 Move the result into the reg pair that is being returned such
784 such that the low 64 bits are the quotient and the upper 64 bits
785 are the remainder. (see libvex_ir.h). */
786 *dst_hi = newVRegI(env);
787 *dst_lo = newVRegI(env);
788 addInstr(env, s390_insn_move(8, *dst_hi, r10));
789 addInstr(env, s390_insn_move(8, *dst_lo, r11));
790 return;
791 }
792 }
793 }
794
795 vpanic("s390_isel_int128_expr");
796}
797
798
799/* Compute a 128-bit value into two 64-bit registers. These may be either
800 real or virtual regs; in any case they must not be changed by subsequent
801 code emitted by the caller. */
802static void
803s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
804{
805 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
806
807 /* Sanity checks ... */
808 vassert(hregIsVirtual(*dst_hi));
809 vassert(hregIsVirtual(*dst_lo));
810 vassert(hregClass(*dst_hi) == HRcInt64);
811 vassert(hregClass(*dst_lo) == HRcInt64);
812}
813
814
815/*---------------------------------------------------------*/
816/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
817/*---------------------------------------------------------*/
818
819/* Select insns for an integer-typed expression, and add them to the
820 code list. Return a reg holding the result. This reg will be a
821 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
822 want to modify it, ask for a new vreg, copy it in there, and modify
823 the copy. The register allocator will do its best to map both
824 vregs to the same real register, so the copies will often disappear
825 later in the game.
826
827 This should handle expressions of 64, 32, 16 and 8-bit type.
828 All results are returned in a 64bit register.
829 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
830 are arbitrary, so you should mask or sign extend partial values
831 if necessary.
832*/
833
834/* DO NOT CALL THIS DIRECTLY ! */
835static HReg
836s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
837{
838 IRType ty = typeOfIRExpr(env->type_env, expr);
839 UChar size;
840 s390_bfp_unop_t bfpop;
841
842 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
843
844 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
845
846 switch (expr->tag) {
847
848 /* --------- TEMP --------- */
849 case Iex_RdTmp:
850 /* Return the virtual register that holds the temporary. */
851 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
852
853 /* --------- LOAD --------- */
854 case Iex_Load: {
855 HReg dst = newVRegI(env);
856 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
857
858 if (expr->Iex.Load.end != Iend_BE)
859 goto irreducible;
860
861 addInstr(env, s390_insn_load(size, dst, am));
862
863 return dst;
864 }
865
866 /* --------- BINARY OP --------- */
867 case Iex_Binop: {
868 IRExpr *arg1 = expr->Iex.Binop.arg1;
869 IRExpr *arg2 = expr->Iex.Binop.arg2;
870 HReg h1, res;
871 s390_alu_t opkind;
872 s390_opnd_RMI op2, value, opnd;
873 s390_insn *insn;
874 Bool is_commutative, is_signed_multiply, is_signed_divide;
875
876 is_commutative = True;
877
878 switch (expr->Iex.Binop.op) {
879 case Iop_MullU8:
880 case Iop_MullU16:
881 case Iop_MullU32:
882 is_signed_multiply = False;
883 goto do_multiply;
884
885 case Iop_MullS8:
886 case Iop_MullS16:
887 case Iop_MullS32:
888 is_signed_multiply = True;
889 goto do_multiply;
890
891 do_multiply: {
892 HReg r10, r11;
893 UInt arg_size = size / 2;
894
895 order_commutative_operands(arg1, arg2);
896
897 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
898 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
899
900 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000901 r10 = make_gpr(10);
902 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000903
904 /* Move the first operand to r11 */
905 addInstr(env, s390_insn_move(arg_size, r11, h1));
906
907 /* Multiply */
908 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
909
910 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
911 value into the destination register. */
912 res = newVRegI(env);
913 addInstr(env, s390_insn_move(arg_size, res, r10));
914 value = s390_opnd_imm(arg_size * 8);
915 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
916 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
917 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
918 opnd = s390_opnd_reg(r11);
919 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
920 return res;
921 }
922
923 case Iop_DivModS64to32:
924 is_signed_divide = True;
925 goto do_divide;
926
927 case Iop_DivModU64to32:
928 is_signed_divide = False;
929 goto do_divide;
930
931 do_divide: {
932 HReg r10, r11;
933
934 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
935 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
936
937 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000938 r10 = make_gpr(10);
939 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000940
941 /* Split the first operand and put the high 32 bits into r10 and
942 the low 32 bits into r11. */
943 addInstr(env, s390_insn_move(8, r10, h1));
944 addInstr(env, s390_insn_move(8, r11, h1));
945 value = s390_opnd_imm(32);
946 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
947
948 /* Divide */
949 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
950
951 /* The result is in registers r10 (remainder) and r11 (quotient).
952 Combine them into a 64-bit value such that the low 32 bits are
953 the quotient and the upper 32 bits are the remainder. (see
954 libvex_ir.h). */
955 res = newVRegI(env);
956 addInstr(env, s390_insn_move(8, res, r10));
957 value = s390_opnd_imm(32);
958 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
959 value = s390_opnd_imm((((ULong)1) << 32) - 1);
960 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
961 opnd = s390_opnd_reg(r11);
962 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
963 return res;
964 }
965
966 case Iop_F32toI32S: bfpop = S390_BFP_F32_TO_I32; goto do_convert;
967 case Iop_F32toI64S: bfpop = S390_BFP_F32_TO_I64; goto do_convert;
968 case Iop_F64toI32S: bfpop = S390_BFP_F64_TO_I32; goto do_convert;
969 case Iop_F64toI64S: bfpop = S390_BFP_F64_TO_I64; goto do_convert;
970 case Iop_F128toI32S: bfpop = S390_BFP_F128_TO_I32; goto do_convert_128;
971 case Iop_F128toI64S: bfpop = S390_BFP_F128_TO_I64; goto do_convert_128;
972
973 do_convert: {
974 s390_round_t rounding_mode;
975
976 res = newVRegI(env);
977 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
978
979 rounding_mode = decode_rounding_mode(arg1);
980 addInstr(env, s390_insn_bfp_unop(size, bfpop, res, h1, rounding_mode));
981 return res;
982 }
983
984 do_convert_128: {
985 s390_round_t rounding_mode;
986 HReg op_hi, op_lo, f13, f15;
987
988 res = newVRegI(env);
989 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
990
991 /* We use non-virtual registers r13 and r15 as pair */
992 f13 = make_fpr(13);
993 f15 = make_fpr(15);
994
995 /* operand --> (f13, f15) */
996 addInstr(env, s390_insn_move(8, f13, op_hi));
997 addInstr(env, s390_insn_move(8, f15, op_lo));
998
999 rounding_mode = decode_rounding_mode(arg1);
1000 addInstr(env, s390_insn_bfp128_convert_from(size, bfpop, res, f13, f15,
1001 rounding_mode));
1002 return res;
1003 }
1004
1005 case Iop_8HLto16:
1006 case Iop_16HLto32:
1007 case Iop_32HLto64: {
1008 HReg h2;
1009 UInt arg_size = size / 2;
1010
1011 res = newVRegI(env);
1012 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1013 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1014
1015 addInstr(env, s390_insn_move(arg_size, res, h1));
1016 value = s390_opnd_imm(arg_size * 8);
1017 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1018 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1019 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1020 opnd = s390_opnd_reg(h2);
1021 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1022 return res;
1023 }
1024
1025 case Iop_Max32U: {
1026 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1027 res = newVRegI(env);
1028 h1 = s390_isel_int_expr(env, arg1);
1029 op2 = s390_isel_int_expr_RMI(env, arg2);
1030
1031 addInstr(env, s390_insn_move(size, res, h1));
1032 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1033 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1034 return res;
1035 }
1036
1037 case Iop_CmpF32:
1038 case Iop_CmpF64: {
1039 HReg cc_s390, h2;
1040
1041 h1 = s390_isel_float_expr(env, arg1);
1042 h2 = s390_isel_float_expr(env, arg2);
1043 cc_s390 = newVRegI(env);
1044
1045 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1046
1047 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1048
1049 return convert_s390_fpcc_to_vex(env, cc_s390);
1050 }
1051
1052 case Iop_CmpF128: {
1053 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1054
1055 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1056 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1057 cc_s390 = newVRegI(env);
1058
1059 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1060 f12 = make_fpr(12);
1061 f13 = make_fpr(13);
1062 f14 = make_fpr(14);
1063 f15 = make_fpr(15);
1064
1065 /* 1st operand --> (f12, f14) */
1066 addInstr(env, s390_insn_move(8, f12, op1_hi));
1067 addInstr(env, s390_insn_move(8, f14, op1_lo));
1068
1069 /* 2nd operand --> (f13, f15) */
1070 addInstr(env, s390_insn_move(8, f13, op2_hi));
1071 addInstr(env, s390_insn_move(8, f15, op2_lo));
1072
1073 res = newVRegI(env);
1074 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1075
1076 return convert_s390_fpcc_to_vex(env, cc_s390);
1077 }
1078
1079 case Iop_Add8:
1080 case Iop_Add16:
1081 case Iop_Add32:
1082 case Iop_Add64:
1083 opkind = S390_ALU_ADD;
1084 break;
1085
1086 case Iop_Sub8:
1087 case Iop_Sub16:
1088 case Iop_Sub32:
1089 case Iop_Sub64:
1090 opkind = S390_ALU_SUB;
1091 is_commutative = False;
1092 break;
1093
1094 case Iop_And8:
1095 case Iop_And16:
1096 case Iop_And32:
1097 case Iop_And64:
1098 opkind = S390_ALU_AND;
1099 break;
1100
1101 case Iop_Or8:
1102 case Iop_Or16:
1103 case Iop_Or32:
1104 case Iop_Or64:
1105 opkind = S390_ALU_OR;
1106 break;
1107
1108 case Iop_Xor8:
1109 case Iop_Xor16:
1110 case Iop_Xor32:
1111 case Iop_Xor64:
1112 opkind = S390_ALU_XOR;
1113 break;
1114
1115 case Iop_Shl8:
1116 case Iop_Shl16:
1117 case Iop_Shl32:
1118 case Iop_Shl64:
1119 opkind = S390_ALU_LSH;
1120 is_commutative = False;
1121 break;
1122
1123 case Iop_Shr8:
1124 case Iop_Shr16:
1125 case Iop_Shr32:
1126 case Iop_Shr64:
1127 opkind = S390_ALU_RSH;
1128 is_commutative = False;
1129 break;
1130
1131 case Iop_Sar8:
1132 case Iop_Sar16:
1133 case Iop_Sar32:
1134 case Iop_Sar64:
1135 opkind = S390_ALU_RSHA;
1136 is_commutative = False;
1137 break;
1138
1139 default:
1140 goto irreducible;
1141 }
1142
1143 /* Pattern match: 0 - arg1 --> -arg1 */
1144 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1145 res = newVRegI(env);
1146 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1147 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1148 addInstr(env, insn);
1149
1150 return res;
1151 }
1152
1153 if (is_commutative) {
1154 order_commutative_operands(arg1, arg2);
1155 }
1156
1157 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1158 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1159 res = newVRegI(env);
1160 addInstr(env, s390_insn_move(size, res, h1));
1161 insn = s390_insn_alu(size, opkind, res, op2);
1162
1163 addInstr(env, insn);
1164
1165 return res;
1166 }
1167
1168 /* --------- UNARY OP --------- */
1169 case Iex_Unop: {
1170 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1171 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1172 s390_opnd_RMI opnd;
1173 s390_insn *insn;
1174 IRExpr *arg;
1175 HReg dst, h1;
1176 IROp unop, binop;
1177
1178 arg = expr->Iex.Unop.arg;
1179
1180 /* Special cases are handled here */
1181
1182 /* 32-bit multiply with 32-bit result or
1183 64-bit multiply with 64-bit result */
1184 unop = expr->Iex.Unop.op;
1185 binop = arg->Iex.Binop.op;
1186
1187 if ((arg->tag == Iex_Binop &&
1188 ((unop == Iop_64to32 &&
1189 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1190 (unop == Iop_128to64 &&
1191 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1192 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1193 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1194 dst = newVRegI(env); /* Result goes into a new register */
1195 addInstr(env, s390_insn_move(size, dst, h1));
1196 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1197
1198 return dst;
1199 }
1200
florian4d71a082011-12-18 00:08:17 +00001201 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001202 dst = newVRegI(env);
1203 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1204 addInstr(env, s390_insn_move(size, dst, h1));
1205
1206 return dst;
1207 }
1208
1209 /* Expressions whose argument is 1-bit wide */
1210 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1211 s390_cc_t cond = s390_isel_cc(env, arg);
1212 dst = newVRegI(env); /* Result goes into a new register */
1213 addInstr(env, s390_insn_cc2bool(dst, cond));
1214
1215 switch (unop) {
1216 case Iop_1Uto8:
1217 case Iop_1Uto32:
1218 case Iop_1Uto64:
1219 /* Nothing to do */
1220 break;
1221
1222 case Iop_1Sto8:
1223 case Iop_1Sto16:
1224 case Iop_1Sto32:
1225 shift.variant.imm = 31;
1226 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1227 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1228 break;
1229
1230 case Iop_1Sto64:
1231 shift.variant.imm = 63;
1232 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1233 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1234 break;
1235
1236 default:
1237 goto irreducible;
1238 }
1239
1240 return dst;
1241 }
1242
1243 /* Regular processing */
1244
1245 if (unop == Iop_128to64) {
1246 HReg dst_hi, dst_lo;
1247
1248 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1249 return dst_lo;
1250 }
1251
1252 if (unop == Iop_128HIto64) {
1253 HReg dst_hi, dst_lo;
1254
1255 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1256 return dst_hi;
1257 }
1258
1259 dst = newVRegI(env); /* Result goes into a new register */
1260 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1261
1262 switch (unop) {
1263 case Iop_8Uto16:
1264 case Iop_8Uto32:
1265 case Iop_8Uto64:
1266 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1267 break;
1268
1269 case Iop_16Uto32:
1270 case Iop_16Uto64:
1271 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1272 break;
1273
1274 case Iop_32Uto64:
1275 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1276 break;
1277
1278 case Iop_8Sto16:
1279 case Iop_8Sto32:
1280 case Iop_8Sto64:
1281 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1282 break;
1283
1284 case Iop_16Sto32:
1285 case Iop_16Sto64:
1286 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1287 break;
1288
1289 case Iop_32Sto64:
1290 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1291 break;
1292
1293 case Iop_64to8:
1294 case Iop_64to16:
1295 case Iop_64to32:
1296 case Iop_32to8:
1297 case Iop_32to16:
1298 case Iop_16to8:
1299 /* Down-casts are no-ops. Upstream operations will only look at
1300 the bytes that make up the result of the down-cast. So there
1301 is no point setting the other bytes to 0. */
1302 insn = s390_opnd_copy(8, dst, opnd);
1303 break;
1304
1305 case Iop_64HIto32:
1306 addInstr(env, s390_opnd_copy(8, dst, opnd));
1307 shift.variant.imm = 32;
1308 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1309 break;
1310
1311 case Iop_32HIto16:
1312 addInstr(env, s390_opnd_copy(4, dst, opnd));
1313 shift.variant.imm = 16;
1314 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1315 break;
1316
1317 case Iop_16HIto8:
1318 addInstr(env, s390_opnd_copy(2, dst, opnd));
1319 shift.variant.imm = 8;
1320 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1321 break;
1322
1323 case Iop_Not8:
1324 case Iop_Not16:
1325 case Iop_Not32:
1326 case Iop_Not64:
1327 /* XOR with ffff... */
1328 mask.variant.imm = ~(ULong)0;
1329 addInstr(env, s390_opnd_copy(size, dst, opnd));
1330 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1331 break;
1332
1333 case Iop_Left8:
1334 case Iop_Left16:
1335 case Iop_Left32:
1336 case Iop_Left64:
1337 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1338 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1339 break;
1340
1341 case Iop_CmpwNEZ32:
1342 case Iop_CmpwNEZ64: {
1343 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1344 or -X will have a 1 in the MSB. */
1345 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1346 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1347 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1348 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1349 return dst;
1350 }
1351
1352 case Iop_Clz64: {
1353 HReg r10, r11;
1354
sewardj611b06e2011-03-24 08:57:29 +00001355 /* This will be implemented using FLOGR, if possible. So we need to
1356 set aside a pair of non-virtual registers. The result (number of
1357 left-most zero bits) will be in r10. The value in r11 is unspecified
1358 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001359 r10 = make_gpr(10);
1360 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001361
sewardj611b06e2011-03-24 08:57:29 +00001362 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001363 addInstr(env, s390_insn_move(8, dst, r10));
1364 return dst;
1365 }
1366
1367 default:
1368 goto irreducible;
1369 }
1370
1371 addInstr(env, insn);
1372
1373 return dst;
1374 }
1375
1376 /* --------- GET --------- */
1377 case Iex_Get: {
1378 HReg dst = newVRegI(env);
1379 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1380
1381 /* We never load more than 8 bytes from the guest state, because the
1382 floating point register pair is not contiguous. */
1383 vassert(size <= 8);
1384
1385 addInstr(env, s390_insn_load(size, dst, am));
1386
1387 return dst;
1388 }
1389
1390 case Iex_GetI:
1391 /* not needed */
1392 break;
1393
1394 /* --------- CCALL --------- */
1395 case Iex_CCall: {
1396 HReg dst = newVRegI(env);
1397
1398 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
1399 expr->Iex.CCall.args);
1400
1401 /* Move the returned value into the return register */
1402 addInstr(env, s390_insn_move(sizeofIRType(expr->Iex.CCall.retty), dst,
florian297b6062012-05-08 20:16:17 +00001403 make_gpr(S390_REGNO_RETURN_VALUE)));
sewardj2019a972011-03-07 16:04:07 +00001404 return dst;
1405 }
1406
1407 /* --------- LITERAL --------- */
1408
1409 /* Load a literal into a register. Create a "load immediate"
1410 v-insn and return the register. */
1411 case Iex_Const: {
1412 ULong value;
1413 HReg dst = newVRegI(env);
1414 const IRConst *con = expr->Iex.Const.con;
1415
1416 /* Bitwise copy of the value. No sign/zero-extension */
1417 switch (con->tag) {
1418 case Ico_U64: value = con->Ico.U64; break;
1419 case Ico_U32: value = con->Ico.U32; break;
1420 case Ico_U16: value = con->Ico.U16; break;
1421 case Ico_U8: value = con->Ico.U8; break;
1422 default: vpanic("s390_isel_int_expr: invalid constant");
1423 }
1424
1425 addInstr(env, s390_insn_load_immediate(size, dst, value));
1426
1427 return dst;
1428 }
1429
1430 /* --------- MULTIPLEX --------- */
1431 case Iex_Mux0X: {
1432 IRExpr *cond_expr;
1433 HReg dst, tmp, rX;
1434 s390_opnd_RMI cond, r0, zero;
1435
1436 cond_expr = expr->Iex.Mux0X.cond;
1437
1438 dst = newVRegI(env);
1439 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1440 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1441 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1442
1443 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1444 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1445
1446 addInstr(env, s390_insn_move(size, dst, rX));
1447 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1448 return dst;
1449 }
1450
1451 /* Assume the condition is true and move rX to the destination reg. */
1452 addInstr(env, s390_insn_move(size, dst, rX));
1453
1454 /* Compute the condition ... */
1455 cond = s390_isel_int_expr_RMI(env, cond_expr);
1456
1457 /* tmp = cond & 0xFF */
1458 tmp = newVRegI(env);
1459 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1460 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1461
1462 /* ... and compare it with zero */
1463 zero = s390_opnd_imm(0);
1464 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1465
1466 /* ... and if it compared equal move r0 to the destination reg. */
1467 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1468 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1469
1470 return dst;
1471 }
1472
1473 default:
1474 break;
1475 }
1476
1477 /* We get here if no pattern matched. */
1478 irreducible:
1479 ppIRExpr(expr);
1480 vpanic("s390_isel_int_expr: cannot reduce tree");
1481}
1482
1483
1484static HReg
1485s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1486{
1487 HReg dst = s390_isel_int_expr_wrk(env, expr);
1488
1489 /* Sanity checks ... */
1490 vassert(hregClass(dst) == HRcInt64);
1491 vassert(hregIsVirtual(dst));
1492
1493 return dst;
1494}
1495
1496
1497static s390_opnd_RMI
1498s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1499{
1500 IRType ty = typeOfIRExpr(env->type_env, expr);
1501 s390_opnd_RMI dst;
1502
1503 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1504 ty == Ity_I64);
1505
1506 if (expr->tag == Iex_Load) {
1507 dst.tag = S390_OPND_AMODE;
1508 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1509 } else if (expr->tag == Iex_Get) {
1510 dst.tag = S390_OPND_AMODE;
1511 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1512 } else if (expr->tag == Iex_Const) {
1513 ULong value;
1514
1515 /* The bit pattern for the value will be stored as is in the least
1516 significant bits of VALUE. */
1517 switch (expr->Iex.Const.con->tag) {
1518 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1519 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1520 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1521 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1522 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1523 default:
1524 vpanic("s390_isel_int_expr_RMI");
1525 }
1526
1527 dst.tag = S390_OPND_IMMEDIATE;
1528 dst.variant.imm = value;
1529 } else {
1530 dst.tag = S390_OPND_REG;
1531 dst.variant.reg = s390_isel_int_expr(env, expr);
1532 }
1533
1534 return dst;
1535}
1536
1537
1538/*---------------------------------------------------------*/
1539/*--- ISEL: Floating point expressions (128 bit) ---*/
1540/*---------------------------------------------------------*/
1541static void
1542s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1543 IRExpr *expr)
1544{
1545 IRType ty = typeOfIRExpr(env->type_env, expr);
1546
1547 vassert(ty == Ity_F128);
1548
1549 /* Read 128-bit IRTemp */
1550 if (expr->tag == Iex_RdTmp) {
1551 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1552 return;
1553 }
1554
1555 switch (expr->tag) {
1556 case Iex_RdTmp:
1557 /* Return the virtual registers that hold the temporary. */
1558 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1559 return;
1560
1561 /* --------- LOAD --------- */
1562 case Iex_Load: {
1563 IRExpr *addr_hi, *addr_lo;
1564 s390_amode *am_hi, *am_lo;
1565
1566 if (expr->Iex.Load.end != Iend_BE)
1567 goto irreducible;
1568
1569 addr_hi = expr->Iex.Load.addr;
1570 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1571
1572 am_hi = s390_isel_amode(env, addr_hi);
1573 am_lo = s390_isel_amode(env, addr_lo);
1574
1575 *dst_hi = newVRegF(env);
1576 *dst_lo = newVRegF(env);
1577 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1578 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1579 return;
1580 }
1581
1582
1583 /* --------- GET --------- */
1584 case Iex_Get:
1585 /* This is not supported because loading 128-bit from the guest
1586 state is almost certainly wrong. Use get_fpr_pair instead. */
1587 vpanic("Iex_Get with F128 data");
1588
1589 /* --------- 4-ary OP --------- */
1590 case Iex_Qop:
1591 vpanic("Iex_Qop with F128 data");
1592
1593 /* --------- TERNARY OP --------- */
1594 case Iex_Triop: {
1595 IROp op = expr->Iex.Triop.op;
1596 IRExpr *left = expr->Iex.Triop.arg2;
1597 IRExpr *right = expr->Iex.Triop.arg3;
1598 s390_bfp_binop_t bfpop;
1599 s390_round_t rounding_mode;
1600 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1601
1602 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1603 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1604
1605 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1606 f12 = make_fpr(12);
1607 f13 = make_fpr(13);
1608 f14 = make_fpr(14);
1609 f15 = make_fpr(15);
1610
1611 /* 1st operand --> (f12, f14) */
1612 addInstr(env, s390_insn_move(8, f12, op1_hi));
1613 addInstr(env, s390_insn_move(8, f14, op1_lo));
1614
1615 /* 2nd operand --> (f13, f15) */
1616 addInstr(env, s390_insn_move(8, f13, op2_hi));
1617 addInstr(env, s390_insn_move(8, f15, op2_lo));
1618
1619 switch (op) {
1620 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1621 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1622 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1623 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1624 default:
1625 goto irreducible;
1626 }
1627
1628 rounding_mode = decode_rounding_mode(expr->Iex.Triop.arg1);
1629 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1630 f15, rounding_mode));
1631
1632 /* Move result to virtual destination register */
1633 *dst_hi = newVRegF(env);
1634 *dst_lo = newVRegF(env);
1635 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1636 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1637
1638 return;
1639 }
1640
1641 /* --------- BINARY OP --------- */
1642 case Iex_Binop: {
1643 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardja970c402011-04-28 18:38:42 +00001644 s390_bfp_unop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001645 s390_round_t rounding_mode;
1646
1647 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1648 f12 = make_fpr(12);
1649 f13 = make_fpr(13);
1650 f14 = make_fpr(14);
1651 f15 = make_fpr(15);
1652
1653 switch (expr->Iex.Binop.op) {
1654 case Iop_SqrtF128:
1655 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1656
1657 /* operand --> (f13, f15) */
1658 addInstr(env, s390_insn_move(8, f13, op_hi));
1659 addInstr(env, s390_insn_move(8, f15, op_lo));
1660
1661 bfpop = S390_BFP_SQRT;
1662 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1663
1664 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1665 rounding_mode));
1666
1667 /* Move result to virtual destination registers */
1668 *dst_hi = newVRegF(env);
1669 *dst_lo = newVRegF(env);
1670 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1671 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1672 return;
1673
1674 case Iop_F64HLtoF128:
1675 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1676 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1677 return;
1678
1679 default:
1680 goto irreducible;
1681 }
1682 }
1683
1684 /* --------- UNARY OP --------- */
1685 case Iex_Unop: {
1686 IRExpr *left = expr->Iex.Binop.arg1;
1687 s390_bfp_unop_t bfpop;
1688 s390_round_t rounding_mode;
1689 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1690
1691 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1692 f12 = make_fpr(12);
1693 f13 = make_fpr(13);
1694 f14 = make_fpr(14);
1695 f15 = make_fpr(15);
1696
1697 switch (expr->Iex.Binop.op) {
1698 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1699 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1700 case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int;
1701 case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int;
1702 case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float;
1703 case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float;
1704 default:
1705 goto irreducible;
1706 }
1707
1708 float128_opnd:
1709 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1710
1711 /* operand --> (f13, f15) */
1712 addInstr(env, s390_insn_move(8, f13, op_hi));
1713 addInstr(env, s390_insn_move(8, f15, op_lo));
1714
1715 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1716 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1717 rounding_mode));
1718 goto move_dst;
1719
1720 convert_float:
1721 op = s390_isel_float_expr(env, left);
1722 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1723 op));
1724 goto move_dst;
1725
1726 convert_int:
1727 op = s390_isel_int_expr(env, left);
1728 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1729 op));
1730 goto move_dst;
1731
1732 move_dst:
1733 /* Move result to virtual destination registers */
1734 *dst_hi = newVRegF(env);
1735 *dst_lo = newVRegF(env);
1736 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1737 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1738 return;
1739 }
1740
1741 default:
1742 goto irreducible;
1743 }
1744
1745 /* We get here if no pattern matched. */
1746 irreducible:
1747 ppIRExpr(expr);
1748 vpanic("s390_isel_int_expr: cannot reduce tree");
1749}
1750
1751/* Compute a 128-bit value into two 64-bit registers. These may be either
1752 real or virtual regs; in any case they must not be changed by subsequent
1753 code emitted by the caller. */
1754static void
1755s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1756{
1757 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1758
1759 /* Sanity checks ... */
1760 vassert(hregIsVirtual(*dst_hi));
1761 vassert(hregIsVirtual(*dst_lo));
1762 vassert(hregClass(*dst_hi) == HRcFlt64);
1763 vassert(hregClass(*dst_lo) == HRcFlt64);
1764}
1765
1766
1767/*---------------------------------------------------------*/
1768/*--- ISEL: Floating point expressions (64 bit) ---*/
1769/*---------------------------------------------------------*/
1770
1771static HReg
1772s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1773{
1774 IRType ty = typeOfIRExpr(env->type_env, expr);
1775 UChar size;
1776
1777 vassert(ty == Ity_F32 || ty == Ity_F64);
1778
1779 size = sizeofIRType(ty);
1780
1781 switch (expr->tag) {
1782 case Iex_RdTmp:
1783 /* Return the virtual register that holds the temporary. */
1784 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1785
1786 /* --------- LOAD --------- */
1787 case Iex_Load: {
1788 HReg dst = newVRegF(env);
1789 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1790
1791 if (expr->Iex.Load.end != Iend_BE)
1792 goto irreducible;
1793
1794 addInstr(env, s390_insn_load(size, dst, am));
1795
1796 return dst;
1797 }
1798
1799 /* --------- GET --------- */
1800 case Iex_Get: {
1801 HReg dst = newVRegF(env);
1802 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1803
1804 addInstr(env, s390_insn_load(size, dst, am));
1805
1806 return dst;
1807 }
1808
1809 /* --------- LITERAL --------- */
1810
1811 /* Load a literal into a register. Create a "load immediate"
1812 v-insn and return the register. */
1813 case Iex_Const: {
1814 ULong value;
1815 HReg dst = newVRegF(env);
1816 const IRConst *con = expr->Iex.Const.con;
1817
1818 /* Bitwise copy of the value. No sign/zero-extension */
1819 switch (con->tag) {
1820 case Ico_F32i: value = con->Ico.F32i; break;
1821 case Ico_F64i: value = con->Ico.F64i; break;
1822 default: vpanic("s390_isel_float_expr: invalid constant");
1823 }
1824
1825 if (value != 0) vpanic("cannot load immediate floating point constant");
1826
1827 addInstr(env, s390_insn_load_immediate(size, dst, value));
1828
1829 return dst;
1830 }
1831
1832 /* --------- 4-ary OP --------- */
1833 case Iex_Qop: {
1834 HReg op1, op2, op3, dst;
1835 s390_bfp_triop_t bfpop;
1836 s390_round_t rounding_mode;
1837
1838 op1 = s390_isel_float_expr(env, expr->Iex.Qop.arg2);
1839 op2 = s390_isel_float_expr(env, expr->Iex.Qop.arg3);
1840 op3 = s390_isel_float_expr(env, expr->Iex.Qop.arg4);
1841 dst = newVRegF(env);
1842 addInstr(env, s390_insn_move(size, dst, op1));
1843
1844 switch (expr->Iex.Qop.op) {
1845 case Iop_MAddF32:
1846 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1847 case Iop_MSubF32:
1848 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1849
1850 default:
1851 goto irreducible;
1852 }
1853
1854 rounding_mode = decode_rounding_mode(expr->Iex.Qop.arg1);
1855 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1856 rounding_mode));
1857 return dst;
1858 }
1859
1860 /* --------- TERNARY OP --------- */
1861 case Iex_Triop: {
1862 IROp op = expr->Iex.Triop.op;
1863 IRExpr *left = expr->Iex.Triop.arg2;
1864 IRExpr *right = expr->Iex.Triop.arg3;
1865 s390_bfp_binop_t bfpop;
1866 s390_round_t rounding_mode;
1867 HReg h1, op2, dst;
1868
1869 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1870 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1871 dst = newVRegF(env);
1872 addInstr(env, s390_insn_move(size, dst, h1));
1873 switch (op) {
1874 case Iop_AddF32:
1875 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1876 case Iop_SubF32:
1877 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1878 case Iop_MulF32:
1879 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1880 case Iop_DivF32:
1881 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1882
1883 default:
1884 goto irreducible;
1885 }
1886
1887 rounding_mode = decode_rounding_mode(expr->Iex.Triop.arg1);
1888 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1889 return dst;
1890 }
1891
1892 /* --------- BINARY OP --------- */
1893 case Iex_Binop: {
1894 IROp op = expr->Iex.Binop.op;
1895 IRExpr *left = expr->Iex.Binop.arg2;
1896 HReg h1, dst;
1897 s390_bfp_unop_t bfpop;
1898 s390_round_t rounding_mode;
1899 Int integer_operand;
1900
1901 integer_operand = 1;
1902
1903 switch (op) {
1904 case Iop_SqrtF32:
1905 case Iop_SqrtF64:
1906 bfpop = S390_BFP_SQRT;
1907 integer_operand = 0;
1908 break;
1909
1910 case Iop_F64toF32:
1911 bfpop = S390_BFP_F64_TO_F32;
1912 integer_operand = 0;
1913 break;
1914
1915 case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break;
1916 case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break;
1917 case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break;
1918 default:
1919 goto irreducible;
1920
1921 case Iop_F128toF64:
1922 case Iop_F128toF32: {
1923 HReg op_hi, op_lo, f12, f13, f14, f15;
1924
1925 bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1926 : S390_BFP_F128_TO_F64;
1927
1928 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1929
1930 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1931
1932 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1933 f12 = make_fpr(12);
1934 f13 = make_fpr(13);
1935 f14 = make_fpr(14);
1936 f15 = make_fpr(15);
1937
1938 /* operand --> (f13, f15) */
1939 addInstr(env, s390_insn_move(8, f13, op_hi));
1940 addInstr(env, s390_insn_move(8, f15, op_lo));
1941
1942 dst = newVRegF(env);
1943 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1944 rounding_mode));
1945
1946 /* Move result to virtual destination registers */
1947 addInstr(env, s390_insn_move(8, dst, f12));
1948 return dst;
1949 }
1950 }
1951
1952 /* Process operand */
1953 if (integer_operand) {
1954 h1 = s390_isel_int_expr(env, left);
1955 } else {
1956 h1 = s390_isel_float_expr(env, left);
1957 }
1958
1959 dst = newVRegF(env);
1960 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1961 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1962 return dst;
1963 }
1964
1965 /* --------- UNARY OP --------- */
1966 case Iex_Unop: {
1967 IROp op = expr->Iex.Unop.op;
1968 IRExpr *left = expr->Iex.Unop.arg;
1969 s390_bfp_unop_t bfpop;
1970 s390_round_t rounding_mode;
1971 HReg h1, dst;
1972
1973 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1974 HReg dst_hi, dst_lo;
1975
1976 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1977 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1978 }
1979
florian4d71a082011-12-18 00:08:17 +00001980 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00001981 dst = newVRegF(env);
1982 h1 = s390_isel_int_expr(env, left); /* Process the operand */
1983 addInstr(env, s390_insn_move(size, dst, h1));
1984
1985 return dst;
1986 }
1987
1988 switch (op) {
1989 case Iop_NegF32:
1990 case Iop_NegF64:
1991 if (left->tag == Iex_Unop &&
1992 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1993 bfpop = S390_BFP_NABS;
1994 else
1995 bfpop = S390_BFP_NEG;
1996 break;
1997
1998 case Iop_AbsF32:
1999 case Iop_AbsF64: bfpop = S390_BFP_ABS; break;
2000 case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break;
2001 case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break;
2002 default:
2003 goto irreducible;
2004 }
2005
2006 /* Process operand */
2007 if (op == Iop_I32StoF64)
2008 h1 = s390_isel_int_expr(env, left);
2009 else if (bfpop == S390_BFP_NABS)
2010 h1 = s390_isel_float_expr(env, left->Iex.Unop.arg);
2011 else
2012 h1 = s390_isel_float_expr(env, left);
2013
2014 dst = newVRegF(env);
2015 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
2016 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
2017 return dst;
2018 }
2019
2020 default:
2021 goto irreducible;
2022 }
2023
2024 /* We get here if no pattern matched. */
2025 irreducible:
2026 ppIRExpr(expr);
2027 vpanic("s390_isel_float_expr: cannot reduce tree");
2028}
2029
2030
2031static HReg
2032s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2033{
2034 HReg dst = s390_isel_float_expr_wrk(env, expr);
2035
2036 /* Sanity checks ... */
2037 vassert(hregClass(dst) == HRcFlt64);
2038 vassert(hregIsVirtual(dst));
2039
2040 return dst;
2041}
2042
2043
2044/*---------------------------------------------------------*/
2045/*--- ISEL: Condition Code ---*/
2046/*---------------------------------------------------------*/
2047
2048/* This function handles all operators that produce a 1-bit result */
2049static s390_cc_t
2050s390_isel_cc(ISelEnv *env, IRExpr *cond)
2051{
2052 UChar size;
2053
2054 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2055
2056 /* Constant: either 1 or 0 */
2057 if (cond->tag == Iex_Const) {
2058 vassert(cond->Iex.Const.con->tag == Ico_U1);
2059 vassert(cond->Iex.Const.con->Ico.U1 == True
2060 || cond->Iex.Const.con->Ico.U1 == False);
2061
2062 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2063 }
2064
2065 /* Variable: values are 1 or 0 */
2066 if (cond->tag == Iex_RdTmp) {
2067 IRTemp tmp = cond->Iex.RdTmp.tmp;
2068 HReg reg = lookupIRTemp(env, tmp);
2069
2070 /* Load-and-test does not modify REG; so this is OK. */
2071 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2072 size = 4;
2073 else
2074 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2075 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2076 return S390_CC_NE;
2077 }
2078
2079 /* Unary operators */
2080 if (cond->tag == Iex_Unop) {
2081 IRExpr *arg = cond->Iex.Unop.arg;
2082
2083 switch (cond->Iex.Unop.op) {
2084 case Iop_Not1: /* Not1(cond) */
2085 /* Generate code for EXPR, and negate the test condition */
2086 return s390_cc_invert(s390_isel_cc(env, arg));
2087
2088 /* Iop_32/64to1 select the LSB from their operand */
2089 case Iop_32to1:
2090 case Iop_64to1: {
2091 HReg dst = s390_isel_int_expr(env, arg);
2092
2093 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2094
2095 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2096 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2097 return S390_CC_NE;
2098 }
2099
2100 case Iop_CmpNEZ8:
2101 case Iop_CmpNEZ16: {
2102 s390_opnd_RMI src;
2103 s390_unop_t op;
2104 HReg dst;
2105
2106 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2107 : S390_ZERO_EXTEND_16;
2108 dst = newVRegI(env);
2109 src = s390_isel_int_expr_RMI(env, arg);
2110 addInstr(env, s390_insn_unop(4, op, dst, src));
2111 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2112 return S390_CC_NE;
2113 }
2114
2115 case Iop_CmpNEZ32:
2116 case Iop_CmpNEZ64: {
2117 s390_opnd_RMI src;
2118
2119 src = s390_isel_int_expr_RMI(env, arg);
2120 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2121 addInstr(env, s390_insn_test(size, src));
2122 return S390_CC_NE;
2123 }
2124
2125 default:
2126 goto fail;
2127 }
2128 }
2129
2130 /* Binary operators */
2131 if (cond->tag == Iex_Binop) {
2132 IRExpr *arg1 = cond->Iex.Binop.arg1;
2133 IRExpr *arg2 = cond->Iex.Binop.arg2;
2134 HReg reg1, reg2;
2135
2136 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2137
2138 switch (cond->Iex.Binop.op) {
2139 s390_unop_t op;
2140 s390_cc_t result;
2141
2142 case Iop_CmpEQ8:
2143 case Iop_CasCmpEQ8:
2144 op = S390_ZERO_EXTEND_8;
2145 result = S390_CC_E;
2146 goto do_compare_ze;
2147
2148 case Iop_CmpNE8:
2149 case Iop_CasCmpNE8:
2150 op = S390_ZERO_EXTEND_8;
2151 result = S390_CC_NE;
2152 goto do_compare_ze;
2153
2154 case Iop_CmpEQ16:
2155 case Iop_CasCmpEQ16:
2156 op = S390_ZERO_EXTEND_16;
2157 result = S390_CC_E;
2158 goto do_compare_ze;
2159
2160 case Iop_CmpNE16:
2161 case Iop_CasCmpNE16:
2162 op = S390_ZERO_EXTEND_16;
2163 result = S390_CC_NE;
2164 goto do_compare_ze;
2165
2166 do_compare_ze: {
2167 s390_opnd_RMI op1, op2;
2168
2169 op1 = s390_isel_int_expr_RMI(env, arg1);
2170 reg1 = newVRegI(env);
2171 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2172
2173 op2 = s390_isel_int_expr_RMI(env, arg2);
2174 reg2 = newVRegI(env);
2175 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2176
2177 op2 = s390_opnd_reg(reg2);
2178 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2179
2180 return result;
2181 }
2182
2183 case Iop_CmpEQ32:
2184 case Iop_CmpEQ64:
2185 case Iop_CasCmpEQ32:
2186 case Iop_CasCmpEQ64:
2187 result = S390_CC_E;
2188 goto do_compare;
2189
2190 case Iop_CmpNE32:
2191 case Iop_CmpNE64:
2192 case Iop_CasCmpNE32:
2193 case Iop_CasCmpNE64:
2194 result = S390_CC_NE;
2195 goto do_compare;
2196
2197 do_compare: {
2198 HReg op1;
2199 s390_opnd_RMI op2;
2200
2201 order_commutative_operands(arg1, arg2);
2202
2203 op1 = s390_isel_int_expr(env, arg1);
2204 op2 = s390_isel_int_expr_RMI(env, arg2);
2205
2206 addInstr(env, s390_insn_compare(size, op1, op2, False));
2207
2208 return result;
2209 }
2210
2211 case Iop_CmpLT32S:
2212 case Iop_CmpLE32S:
2213 case Iop_CmpLT64S:
2214 case Iop_CmpLE64S: {
2215 HReg op1;
2216 s390_opnd_RMI op2;
2217
2218 op1 = s390_isel_int_expr(env, arg1);
2219 op2 = s390_isel_int_expr_RMI(env, arg2);
2220
2221 addInstr(env, s390_insn_compare(size, op1, op2, True));
2222
2223 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2224 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2225 }
2226
2227 case Iop_CmpLT32U:
2228 case Iop_CmpLE32U:
2229 case Iop_CmpLT64U:
2230 case Iop_CmpLE64U: {
2231 HReg op1;
2232 s390_opnd_RMI op2;
2233
2234 op1 = s390_isel_int_expr(env, arg1);
2235 op2 = s390_isel_int_expr_RMI(env, arg2);
2236
2237 addInstr(env, s390_insn_compare(size, op1, op2, False));
2238
2239 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2240 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2241 }
2242
2243 default:
2244 goto fail;
2245 }
2246 }
2247
2248 fail:
2249 ppIRExpr(cond);
2250 vpanic("s390_isel_cc: unexpected operator");
2251}
2252
2253
2254/*---------------------------------------------------------*/
2255/*--- ISEL: Statements ---*/
2256/*---------------------------------------------------------*/
2257
2258static void
2259s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2260{
2261 if (vex_traceflags & VEX_TRACE_VCODE) {
2262 vex_printf("\n -- ");
2263 ppIRStmt(stmt);
2264 vex_printf("\n");
2265 }
2266
2267 switch (stmt->tag) {
2268
2269 /* --------- STORE --------- */
2270 case Ist_Store: {
2271 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2272 s390_amode *am;
2273 HReg src;
2274
2275 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2276
2277 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2278
2279 switch (tyd) {
2280 case Ity_I8:
2281 case Ity_I16:
2282 case Ity_I32:
2283 case Ity_I64:
2284 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2285 break;
2286
2287 case Ity_F32:
2288 case Ity_F64:
2289 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2290 break;
2291
2292 case Ity_F128:
2293 /* Cannot occur. No such instruction */
2294 vpanic("Ist_Store with F128 data");
2295
2296 default:
2297 goto stmt_fail;
2298 }
2299
2300 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2301 return;
2302 }
2303
2304 /* --------- PUT --------- */
2305 case Ist_Put: {
2306 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2307 HReg src;
2308 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002309 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002310
florianad43b3a2012-02-20 15:01:14 +00002311 /* Detect updates to certain guest registers. We track the contents
2312 of those registers as long as they contain constants. If the new
2313 constant is either zero or in the 8-bit neighbourhood of the
2314 current value we can use a memory-to-memory insn to do the update. */
2315
2316 Int offset = stmt->Ist.Put.offset;
2317
2318 /* Check necessary conditions:
2319 (1) must be one of the registers we care about
2320 (2) assigned value must be a constant */
2321 Int guest_reg = get_guest_reg(offset);
2322
2323 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2324
2325 if (guest_reg == GUEST_IA) {
2326 /* If this is the first assignment to the IA reg, don't special case
2327 it. We need to do a full 8-byte assignment here. The reason is
2328 that in case of a redirected translation the guest IA does not
2329 contain the redirected-to address. Instead it contains the
2330 redirected-from address and those can be far apart. So in order to
2331 do incremnetal updates if the IA in the future we need to get the
2332 initial address of the super block correct. */
2333 if (env->first_IA_assignment) {
2334 env->first_IA_assignment = False;
2335 goto not_special;
2336 }
2337 }
2338
2339 if (stmt->Ist.Put.data->tag != Iex_Const) {
2340 /* Invalidate guest register contents */
2341 env->old_value_valid[guest_reg] = False;
2342 goto not_special;
2343 }
2344
2345 /* OK. Necessary conditions are satisfied. */
2346
2347 /* Get the old value and update it */
2348 vassert(tyd == Ity_I64);
2349
2350 old_value = env->old_value[guest_reg];
2351 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2352 env->old_value[guest_reg] = new_value;
2353
2354 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2355 env->old_value_valid[guest_reg] = True;
2356
2357 /* If the register already contains the new value, there is nothing
2358 to do here. Unless the guest register requires precise memory
2359 exceptions. */
2360 if (old_value_is_valid && new_value == old_value) {
2361 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2362 return;
2363 }
2364 }
2365
2366 /* guest register = 0 */
2367 if (new_value == 0) {
2368 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2369 return;
2370 }
2371
2372 if (old_value_is_valid == False) goto not_special;
2373
2374 /* If the new value is in the neighbourhood of the old value
2375 we can use a memory-to-memory insn */
2376 difference = new_value - old_value;
2377
2378 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2379 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2380 (difference & 0xFF), new_value));
2381 return;
2382 }
2383
2384 /* If the high word is the same it is sufficient to load the low word.
2385 Use R0 as a scratch reg. */
2386 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002387 HReg r0 = make_gpr(0);
2388 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002389 s390_amode *gam;
2390
2391 gam = s390_amode_b12(offset + 4, gsp);
2392 addInstr(env, s390_insn_load_immediate(4, r0,
2393 new_value & 0xFFFFFFFF));
2394 addInstr(env, s390_insn_store(4, gam, r0));
2395 return;
2396 }
2397
2398 /* No special case applies... fall through */
2399
2400 not_special:
sewardj2019a972011-03-07 16:04:07 +00002401 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2402
2403 switch (tyd) {
2404 case Ity_I8:
2405 case Ity_I16:
2406 case Ity_I32:
2407 case Ity_I64:
2408 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2409 break;
2410
2411 case Ity_F32:
2412 case Ity_F64:
2413 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2414 break;
2415
2416 case Ity_F128:
2417 /* Does not occur. See function put_fpr_pair. */
2418 vpanic("Ist_Put with F128 data");
2419
2420 default:
2421 goto stmt_fail;
2422 }
2423
2424 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2425 return;
2426 }
2427
2428 /* --------- TMP --------- */
2429 case Ist_WrTmp: {
2430 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2431 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2432 HReg src, dst;
2433
2434 switch (tyd) {
2435 case Ity_I128: {
2436 HReg dst_hi, dst_lo, res_hi, res_lo;
2437
2438 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2439 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2440
2441 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2442 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2443 return;
2444 }
2445
2446 case Ity_I8:
2447 case Ity_I16:
2448 case Ity_I32:
2449 case Ity_I64:
2450 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2451 dst = lookupIRTemp(env, tmp);
2452 break;
2453
2454 case Ity_I1: {
2455 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2456 dst = lookupIRTemp(env, tmp);
2457 addInstr(env, s390_insn_cc2bool(dst, cond));
2458 return;
2459 }
2460
2461 case Ity_F32:
2462 case Ity_F64:
2463 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2464 dst = lookupIRTemp(env, tmp);
2465 break;
2466
2467 case Ity_F128: {
2468 HReg dst_hi, dst_lo, res_hi, res_lo;
2469
2470 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2471 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2472
2473 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2474 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2475 return;
2476 }
2477
2478 default:
2479 goto stmt_fail;
2480 }
2481
2482 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2483 return;
2484 }
2485
2486 /* --------- Call to DIRTY helper --------- */
2487 case Ist_Dirty: {
2488 IRType retty;
2489 IRDirty* d = stmt->Ist.Dirty.details;
2490 Bool passBBP;
florianad43b3a2012-02-20 15:01:14 +00002491 Int i;
2492
2493 /* Invalidate tracked values of those guest state registers that are
2494 modified by this helper. */
2495 for (i = 0; i < d->nFxState; ++i) {
2496 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2497 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2498 if (guest_reg != GUEST_UNKNOWN)
2499 env->old_value_valid[guest_reg] = False;
2500 }
2501 }
sewardj2019a972011-03-07 16:04:07 +00002502
2503 if (d->nFxState == 0)
2504 vassert(!d->needsBBP);
2505
2506 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2507
2508 doHelperCall(env, passBBP, d->guard, d->cee, d->args);
2509
2510 /* Now figure out what to do with the returned value, if any. */
2511 if (d->tmp == IRTemp_INVALID)
2512 /* No return value. Nothing to do. */
2513 return;
2514
2515 retty = typeOfIRTemp(env->type_env, d->tmp);
2516 if (retty == Ity_I64 || retty == Ity_I32
2517 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002518 /* Move the returned value to the destination register */
sewardj2019a972011-03-07 16:04:07 +00002519 HReg dst = lookupIRTemp(env, d->tmp);
2520 addInstr(env, s390_insn_move(sizeofIRType(retty), dst,
florian297b6062012-05-08 20:16:17 +00002521 make_gpr(S390_REGNO_RETURN_VALUE)));
sewardj2019a972011-03-07 16:04:07 +00002522 return;
2523 }
2524 break;
2525 }
2526
2527 case Ist_CAS:
2528 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2529 IRCAS *cas = stmt->Ist.CAS.details;
2530 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2531 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2532 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2533 HReg old = lookupIRTemp(env, cas->oldLo);
2534
2535 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2536 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2537 } else {
2538 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2539 }
2540 return;
2541 } else {
2542 vpanic("compare double and swap not implemented\n");
2543 }
2544 break;
2545
2546 /* --------- EXIT --------- */
2547 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002548 s390_cc_t cond;
2549 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2550
2551 if (tag != Ico_U64)
2552 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2553
florian8844a632012-04-13 04:04:06 +00002554 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002555 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002556
2557 /* Case: boring transfer to known address */
2558 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2559 if (env->chaining_allowed) {
2560 /* .. almost always true .. */
2561 /* Skip the event check at the dst if this is a forwards
2562 edge. */
2563 Bool to_fast_entry
2564 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2565 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2566 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2567 guest_IA, to_fast_entry));
2568 } else {
2569 /* .. very occasionally .. */
2570 /* We can't use chaining, so ask for an assisted transfer,
2571 as that's the only alternative that is allowable. */
2572 HReg dst = s390_isel_int_expr(env,
2573 IRExpr_Const(stmt->Ist.Exit.dst));
2574 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2575 }
2576 return;
2577 }
2578
2579 /* Case: assisted transfer to arbitrary address */
2580 switch (stmt->Ist.Exit.jk) {
florian65b5b3f2012-04-22 02:51:27 +00002581 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002582 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002583 case Ijk_Sys_syscall:
2584 case Ijk_ClientReq:
2585 case Ijk_NoRedir:
2586 case Ijk_Yield:
2587 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002588 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2589 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2590 stmt->Ist.Exit.jk));
2591 return;
2592 }
2593 default:
2594 break;
2595 }
2596
2597 /* Do we ever expect to see any other kind? */
2598 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002599 }
2600
2601 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002602 case Ist_MBE:
2603 switch (stmt->Ist.MBE.event) {
2604 case Imbe_Fence:
2605 addInstr(env, s390_insn_mfence());
2606 return;
2607 default:
2608 break;
2609 }
sewardj2019a972011-03-07 16:04:07 +00002610 break;
2611
2612 /* --------- Miscellaneous --------- */
2613
2614 case Ist_PutI: /* Not needed */
2615 case Ist_IMark: /* Doesn't generate any executable code */
2616 case Ist_NoOp: /* Doesn't generate any executable code */
2617 case Ist_AbiHint: /* Meaningless in IR */
2618 return;
2619
2620 default:
2621 break;
2622 }
2623
2624 stmt_fail:
2625 ppIRStmt(stmt);
2626 vpanic("s390_isel_stmt");
2627}
2628
2629
2630/*---------------------------------------------------------*/
2631/*--- ISEL: Basic block terminators (Nexts) ---*/
2632/*---------------------------------------------------------*/
2633
2634static void
florian8844a632012-04-13 04:04:06 +00002635iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002636{
sewardj2019a972011-03-07 16:04:07 +00002637 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002638 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002639 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002640 vex_printf("; exit-");
2641 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002642 vex_printf("\n");
2643 }
2644
florian8844a632012-04-13 04:04:06 +00002645 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2646
2647 /* Case: boring transfer to known address */
2648 if (next->tag == Iex_Const) {
2649 IRConst *cdst = next->Iex.Const.con;
2650 vassert(cdst->tag == Ico_U64);
2651 if (jk == Ijk_Boring || jk == Ijk_Call) {
2652 /* Boring transfer to known address */
2653 if (env->chaining_allowed) {
2654 /* .. almost always true .. */
2655 /* Skip the event check at the dst if this is a forwards
2656 edge. */
2657 Bool to_fast_entry
2658 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2659 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2660 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2661 guest_IA, to_fast_entry));
2662 } else {
2663 /* .. very occasionally .. */
2664 /* We can't use chaining, so ask for an indirect transfer,
2665 as that's the cheapest alternative that is allowable. */
2666 HReg dst = s390_isel_int_expr(env, next);
2667 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2668 Ijk_Boring));
2669 }
2670 return;
2671 }
2672 }
2673
2674 /* Case: call/return (==boring) transfer to any address */
2675 switch (jk) {
2676 case Ijk_Boring:
2677 case Ijk_Ret:
2678 case Ijk_Call: {
2679 HReg dst = s390_isel_int_expr(env, next);
2680 if (env->chaining_allowed) {
2681 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2682 } else {
2683 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2684 Ijk_Boring));
2685 }
2686 return;
2687 }
2688 default:
2689 break;
2690 }
2691
2692 /* Case: some other kind of transfer to any address */
2693 switch (jk) {
florian65b5b3f2012-04-22 02:51:27 +00002694 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002695 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002696 case Ijk_Sys_syscall:
2697 case Ijk_ClientReq:
2698 case Ijk_NoRedir:
2699 case Ijk_Yield:
2700 case Ijk_SigTRAP: {
2701 HReg dst = s390_isel_int_expr(env, next);
2702 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2703 return;
2704 }
2705 default:
2706 break;
2707 }
2708
2709 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002710}
2711
2712
2713/*---------------------------------------------------------*/
2714/*--- Insn selector top-level ---*/
2715/*---------------------------------------------------------*/
2716
florianf26994a2012-04-21 03:34:54 +00002717/* Translate an entire SB to s390 code.
2718 Note: archinfo_host is a pointer to a stack-allocated variable.
2719 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002720
2721HInstrArray *
2722iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002723 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2724 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2725 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002726{
2727 UInt i, j;
2728 HReg hreg, hregHI;
2729 ISelEnv *env;
2730 UInt hwcaps_host = archinfo_host->hwcaps;
2731
florianf26994a2012-04-21 03:34:54 +00002732 /* KLUDGE: export hwcaps. */
2733 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002734
sewardj2019a972011-03-07 16:04:07 +00002735 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002736 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002737
2738 /* Make up an initial environment to use. */
2739 env = LibVEX_Alloc(sizeof(ISelEnv));
2740 env->vreg_ctr = 0;
2741
2742 /* Set up output code array. */
2743 env->code = newHInstrArray();
2744
2745 /* Copy BB's type env. */
2746 env->type_env = bb->tyenv;
2747
florianad43b3a2012-02-20 15:01:14 +00002748 /* Set up data structures for tracking guest register values. */
2749 env->first_IA_assignment = True;
2750 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2751 env->old_value[i] = 0; /* just something to have a defined value */
2752 env->old_value_valid[i] = False;
2753 }
2754
sewardj2019a972011-03-07 16:04:07 +00002755 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2756 change as we go along. For some reason types_used has Int type -- but
2757 it should be unsigned. Internally we use an unsigned type; so we
2758 assert it here. */
2759 vassert(bb->tyenv->types_used >= 0);
2760
2761 env->n_vregmap = bb->tyenv->types_used;
2762 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2763 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2764
2765 /* and finally ... */
2766 env->hwcaps = hwcaps_host;
2767
florian8844a632012-04-13 04:04:06 +00002768 env->max_ga = max_ga;
2769 env->chaining_allowed = chaining_allowed;
2770
sewardj2019a972011-03-07 16:04:07 +00002771 /* For each IR temporary, allocate a suitably-kinded virtual
2772 register. */
2773 j = 0;
2774 for (i = 0; i < env->n_vregmap; i++) {
2775 hregHI = hreg = INVALID_HREG;
2776 switch (bb->tyenv->types[i]) {
2777 case Ity_I1:
2778 case Ity_I8:
2779 case Ity_I16:
2780 case Ity_I32:
2781 hreg = mkHReg(j++, HRcInt64, True);
2782 break;
2783
2784 case Ity_I64:
2785 hreg = mkHReg(j++, HRcInt64, True);
2786 break;
2787
2788 case Ity_I128:
2789 hreg = mkHReg(j++, HRcInt64, True);
2790 hregHI = mkHReg(j++, HRcInt64, True);
2791 break;
2792
2793 case Ity_F32:
2794 case Ity_F64:
2795 hreg = mkHReg(j++, HRcFlt64, True);
2796 break;
2797
2798 case Ity_F128:
2799 hreg = mkHReg(j++, HRcFlt64, True);
2800 hregHI = mkHReg(j++, HRcFlt64, True);
2801 break;
2802
2803 case Ity_V128: /* fall through */
2804 default:
2805 ppIRType(bb->tyenv->types[i]);
2806 vpanic("s390_isel_sb: IRTemp type");
2807 }
2808
2809 env->vregmap[i] = hreg;
2810 env->vregmapHI[i] = hregHI;
2811 }
2812 env->vreg_ctr = j;
2813
florian8844a632012-04-13 04:04:06 +00002814 /* The very first instruction must be an event check. */
2815 s390_amode *counter, *fail_addr;
2816 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2817 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2818 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2819
2820 /* Possibly a block counter increment (for profiling). At this
2821 point we don't know the address of the counter, so just pretend
2822 it is zero. It will have to be patched later, but before this
2823 translation is used, by a call to LibVEX_patchProfInc. */
2824 if (add_profinc) {
2825 addInstr(env, s390_insn_profinc());
2826 }
2827
sewardj2019a972011-03-07 16:04:07 +00002828 /* Ok, finally we can iterate over the statements. */
2829 for (i = 0; i < bb->stmts_used; i++)
2830 if (bb->stmts[i])
2831 s390_isel_stmt(env, bb->stmts[i]);
2832
florian8844a632012-04-13 04:04:06 +00002833 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002834
2835 /* Record the number of vregs we used. */
2836 env->code->n_vregs = env->vreg_ctr;
2837
2838 return env->code;
2839}
2840
2841/*---------------------------------------------------------------*/
2842/*--- end host_s390_isel.c ---*/
2843/*---------------------------------------------------------------*/