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