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