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