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