blob: 095221f15df653d2ee8461310a81478dcca2f73d [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
1185 /* We use non-virtual registers r10 and r11 as pair for the two
1186 output values */
1187 r10 = make_gpr(env, 10);
1188 r11 = make_gpr(env, 11);
1189
1190 /* flogr */
1191 addInstr(env, s390_insn_flogr(8, r10, r11, opnd));
1192
1193 /* The result is in registers r10 (bit position) and r11 (modified
1194 input value). The value in r11 is not needed and will be
1195 discarded. */
1196 addInstr(env, s390_insn_move(8, dst, r10));
1197 return dst;
1198 }
1199
1200 default:
1201 goto irreducible;
1202 }
1203
1204 addInstr(env, insn);
1205
1206 return dst;
1207 }
1208
1209 /* --------- GET --------- */
1210 case Iex_Get: {
1211 HReg dst = newVRegI(env);
1212 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1213
1214 /* We never load more than 8 bytes from the guest state, because the
1215 floating point register pair is not contiguous. */
1216 vassert(size <= 8);
1217
1218 addInstr(env, s390_insn_load(size, dst, am));
1219
1220 return dst;
1221 }
1222
1223 case Iex_GetI:
1224 /* not needed */
1225 break;
1226
1227 /* --------- CCALL --------- */
1228 case Iex_CCall: {
1229 HReg dst = newVRegI(env);
1230
1231 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
1232 expr->Iex.CCall.args);
1233
1234 /* Move the returned value into the return register */
1235 addInstr(env, s390_insn_move(sizeofIRType(expr->Iex.CCall.retty), dst,
1236 mkHReg(S390_REGNO_RETURN_VALUE,
1237 HRcInt64, False)));
1238 return dst;
1239 }
1240
1241 /* --------- LITERAL --------- */
1242
1243 /* Load a literal into a register. Create a "load immediate"
1244 v-insn and return the register. */
1245 case Iex_Const: {
1246 ULong value;
1247 HReg dst = newVRegI(env);
1248 const IRConst *con = expr->Iex.Const.con;
1249
1250 /* Bitwise copy of the value. No sign/zero-extension */
1251 switch (con->tag) {
1252 case Ico_U64: value = con->Ico.U64; break;
1253 case Ico_U32: value = con->Ico.U32; break;
1254 case Ico_U16: value = con->Ico.U16; break;
1255 case Ico_U8: value = con->Ico.U8; break;
1256 default: vpanic("s390_isel_int_expr: invalid constant");
1257 }
1258
1259 addInstr(env, s390_insn_load_immediate(size, dst, value));
1260
1261 return dst;
1262 }
1263
1264 /* --------- MULTIPLEX --------- */
1265 case Iex_Mux0X: {
1266 IRExpr *cond_expr;
1267 HReg dst, tmp, rX;
1268 s390_opnd_RMI cond, r0, zero;
1269
1270 cond_expr = expr->Iex.Mux0X.cond;
1271
1272 dst = newVRegI(env);
1273 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1274 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1275 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1276
1277 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1278 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1279
1280 addInstr(env, s390_insn_move(size, dst, rX));
1281 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1282 return dst;
1283 }
1284
1285 /* Assume the condition is true and move rX to the destination reg. */
1286 addInstr(env, s390_insn_move(size, dst, rX));
1287
1288 /* Compute the condition ... */
1289 cond = s390_isel_int_expr_RMI(env, cond_expr);
1290
1291 /* tmp = cond & 0xFF */
1292 tmp = newVRegI(env);
1293 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1294 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1295
1296 /* ... and compare it with zero */
1297 zero = s390_opnd_imm(0);
1298 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1299
1300 /* ... and if it compared equal move r0 to the destination reg. */
1301 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1302 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1303
1304 return dst;
1305 }
1306
1307 default:
1308 break;
1309 }
1310
1311 /* We get here if no pattern matched. */
1312 irreducible:
1313 ppIRExpr(expr);
1314 vpanic("s390_isel_int_expr: cannot reduce tree");
1315}
1316
1317
1318static HReg
1319s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1320{
1321 HReg dst = s390_isel_int_expr_wrk(env, expr);
1322
1323 /* Sanity checks ... */
1324 vassert(hregClass(dst) == HRcInt64);
1325 vassert(hregIsVirtual(dst));
1326
1327 return dst;
1328}
1329
1330
1331static s390_opnd_RMI
1332s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1333{
1334 IRType ty = typeOfIRExpr(env->type_env, expr);
1335 s390_opnd_RMI dst;
1336
1337 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1338 ty == Ity_I64);
1339
1340 if (expr->tag == Iex_Load) {
1341 dst.tag = S390_OPND_AMODE;
1342 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1343 } else if (expr->tag == Iex_Get) {
1344 dst.tag = S390_OPND_AMODE;
1345 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1346 } else if (expr->tag == Iex_Const) {
1347 ULong value;
1348
1349 /* The bit pattern for the value will be stored as is in the least
1350 significant bits of VALUE. */
1351 switch (expr->Iex.Const.con->tag) {
1352 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1353 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1354 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1355 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1356 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1357 default:
1358 vpanic("s390_isel_int_expr_RMI");
1359 }
1360
1361 dst.tag = S390_OPND_IMMEDIATE;
1362 dst.variant.imm = value;
1363 } else {
1364 dst.tag = S390_OPND_REG;
1365 dst.variant.reg = s390_isel_int_expr(env, expr);
1366 }
1367
1368 return dst;
1369}
1370
1371
1372/*---------------------------------------------------------*/
1373/*--- ISEL: Floating point expressions (128 bit) ---*/
1374/*---------------------------------------------------------*/
1375static void
1376s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1377 IRExpr *expr)
1378{
1379 IRType ty = typeOfIRExpr(env->type_env, expr);
1380
1381 vassert(ty == Ity_F128);
1382
1383 /* Read 128-bit IRTemp */
1384 if (expr->tag == Iex_RdTmp) {
1385 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1386 return;
1387 }
1388
1389 switch (expr->tag) {
1390 case Iex_RdTmp:
1391 /* Return the virtual registers that hold the temporary. */
1392 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1393 return;
1394
1395 /* --------- LOAD --------- */
1396 case Iex_Load: {
1397 IRExpr *addr_hi, *addr_lo;
1398 s390_amode *am_hi, *am_lo;
1399
1400 if (expr->Iex.Load.end != Iend_BE)
1401 goto irreducible;
1402
1403 addr_hi = expr->Iex.Load.addr;
1404 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1405
1406 am_hi = s390_isel_amode(env, addr_hi);
1407 am_lo = s390_isel_amode(env, addr_lo);
1408
1409 *dst_hi = newVRegF(env);
1410 *dst_lo = newVRegF(env);
1411 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1412 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1413 return;
1414 }
1415
1416
1417 /* --------- GET --------- */
1418 case Iex_Get:
1419 /* This is not supported because loading 128-bit from the guest
1420 state is almost certainly wrong. Use get_fpr_pair instead. */
1421 vpanic("Iex_Get with F128 data");
1422
1423 /* --------- 4-ary OP --------- */
1424 case Iex_Qop:
1425 vpanic("Iex_Qop with F128 data");
1426
1427 /* --------- TERNARY OP --------- */
1428 case Iex_Triop: {
1429 IROp op = expr->Iex.Triop.op;
1430 IRExpr *left = expr->Iex.Triop.arg2;
1431 IRExpr *right = expr->Iex.Triop.arg3;
1432 s390_bfp_binop_t bfpop;
1433 s390_round_t rounding_mode;
1434 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1435
1436 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1437 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1438
1439 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1440 f12 = make_fpr(12);
1441 f13 = make_fpr(13);
1442 f14 = make_fpr(14);
1443 f15 = make_fpr(15);
1444
1445 /* 1st operand --> (f12, f14) */
1446 addInstr(env, s390_insn_move(8, f12, op1_hi));
1447 addInstr(env, s390_insn_move(8, f14, op1_lo));
1448
1449 /* 2nd operand --> (f13, f15) */
1450 addInstr(env, s390_insn_move(8, f13, op2_hi));
1451 addInstr(env, s390_insn_move(8, f15, op2_lo));
1452
1453 switch (op) {
1454 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1455 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1456 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1457 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1458 default:
1459 goto irreducible;
1460 }
1461
1462 rounding_mode = decode_rounding_mode(expr->Iex.Triop.arg1);
1463 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1464 f15, rounding_mode));
1465
1466 /* Move result to virtual destination register */
1467 *dst_hi = newVRegF(env);
1468 *dst_lo = newVRegF(env);
1469 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1470 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1471
1472 return;
1473 }
1474
1475 /* --------- BINARY OP --------- */
1476 case Iex_Binop: {
1477 HReg op_hi, op_lo, f12, f13, f14, f15;
1478 s390_bfp_binop_t bfpop;
1479 s390_round_t rounding_mode;
1480
1481 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1482 f12 = make_fpr(12);
1483 f13 = make_fpr(13);
1484 f14 = make_fpr(14);
1485 f15 = make_fpr(15);
1486
1487 switch (expr->Iex.Binop.op) {
1488 case Iop_SqrtF128:
1489 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1490
1491 /* operand --> (f13, f15) */
1492 addInstr(env, s390_insn_move(8, f13, op_hi));
1493 addInstr(env, s390_insn_move(8, f15, op_lo));
1494
1495 bfpop = S390_BFP_SQRT;
1496 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1497
1498 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1499 rounding_mode));
1500
1501 /* Move result to virtual destination registers */
1502 *dst_hi = newVRegF(env);
1503 *dst_lo = newVRegF(env);
1504 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1505 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1506 return;
1507
1508 case Iop_F64HLtoF128:
1509 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1510 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1511 return;
1512
1513 default:
1514 goto irreducible;
1515 }
1516 }
1517
1518 /* --------- UNARY OP --------- */
1519 case Iex_Unop: {
1520 IRExpr *left = expr->Iex.Binop.arg1;
1521 s390_bfp_unop_t bfpop;
1522 s390_round_t rounding_mode;
1523 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1524
1525 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1526 f12 = make_fpr(12);
1527 f13 = make_fpr(13);
1528 f14 = make_fpr(14);
1529 f15 = make_fpr(15);
1530
1531 switch (expr->Iex.Binop.op) {
1532 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1533 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1534 case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int;
1535 case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int;
1536 case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float;
1537 case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float;
1538 default:
1539 goto irreducible;
1540 }
1541
1542 float128_opnd:
1543 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1544
1545 /* operand --> (f13, f15) */
1546 addInstr(env, s390_insn_move(8, f13, op_hi));
1547 addInstr(env, s390_insn_move(8, f15, op_lo));
1548
1549 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1550 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1551 rounding_mode));
1552 goto move_dst;
1553
1554 convert_float:
1555 op = s390_isel_float_expr(env, left);
1556 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1557 op));
1558 goto move_dst;
1559
1560 convert_int:
1561 op = s390_isel_int_expr(env, left);
1562 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1563 op));
1564 goto move_dst;
1565
1566 move_dst:
1567 /* Move result to virtual destination registers */
1568 *dst_hi = newVRegF(env);
1569 *dst_lo = newVRegF(env);
1570 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1571 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1572 return;
1573 }
1574
1575 default:
1576 goto irreducible;
1577 }
1578
1579 /* We get here if no pattern matched. */
1580 irreducible:
1581 ppIRExpr(expr);
1582 vpanic("s390_isel_int_expr: cannot reduce tree");
1583}
1584
1585/* Compute a 128-bit value into two 64-bit registers. These may be either
1586 real or virtual regs; in any case they must not be changed by subsequent
1587 code emitted by the caller. */
1588static void
1589s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1590{
1591 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1592
1593 /* Sanity checks ... */
1594 vassert(hregIsVirtual(*dst_hi));
1595 vassert(hregIsVirtual(*dst_lo));
1596 vassert(hregClass(*dst_hi) == HRcFlt64);
1597 vassert(hregClass(*dst_lo) == HRcFlt64);
1598}
1599
1600
1601/*---------------------------------------------------------*/
1602/*--- ISEL: Floating point expressions (64 bit) ---*/
1603/*---------------------------------------------------------*/
1604
1605static HReg
1606s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1607{
1608 IRType ty = typeOfIRExpr(env->type_env, expr);
1609 UChar size;
1610
1611 vassert(ty == Ity_F32 || ty == Ity_F64);
1612
1613 size = sizeofIRType(ty);
1614
1615 switch (expr->tag) {
1616 case Iex_RdTmp:
1617 /* Return the virtual register that holds the temporary. */
1618 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1619
1620 /* --------- LOAD --------- */
1621 case Iex_Load: {
1622 HReg dst = newVRegF(env);
1623 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1624
1625 if (expr->Iex.Load.end != Iend_BE)
1626 goto irreducible;
1627
1628 addInstr(env, s390_insn_load(size, dst, am));
1629
1630 return dst;
1631 }
1632
1633 /* --------- GET --------- */
1634 case Iex_Get: {
1635 HReg dst = newVRegF(env);
1636 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1637
1638 addInstr(env, s390_insn_load(size, dst, am));
1639
1640 return dst;
1641 }
1642
1643 /* --------- LITERAL --------- */
1644
1645 /* Load a literal into a register. Create a "load immediate"
1646 v-insn and return the register. */
1647 case Iex_Const: {
1648 ULong value;
1649 HReg dst = newVRegF(env);
1650 const IRConst *con = expr->Iex.Const.con;
1651
1652 /* Bitwise copy of the value. No sign/zero-extension */
1653 switch (con->tag) {
1654 case Ico_F32i: value = con->Ico.F32i; break;
1655 case Ico_F64i: value = con->Ico.F64i; break;
1656 default: vpanic("s390_isel_float_expr: invalid constant");
1657 }
1658
1659 if (value != 0) vpanic("cannot load immediate floating point constant");
1660
1661 addInstr(env, s390_insn_load_immediate(size, dst, value));
1662
1663 return dst;
1664 }
1665
1666 /* --------- 4-ary OP --------- */
1667 case Iex_Qop: {
1668 HReg op1, op2, op3, dst;
1669 s390_bfp_triop_t bfpop;
1670 s390_round_t rounding_mode;
1671
1672 op1 = s390_isel_float_expr(env, expr->Iex.Qop.arg2);
1673 op2 = s390_isel_float_expr(env, expr->Iex.Qop.arg3);
1674 op3 = s390_isel_float_expr(env, expr->Iex.Qop.arg4);
1675 dst = newVRegF(env);
1676 addInstr(env, s390_insn_move(size, dst, op1));
1677
1678 switch (expr->Iex.Qop.op) {
1679 case Iop_MAddF32:
1680 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1681 case Iop_MSubF32:
1682 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1683
1684 default:
1685 goto irreducible;
1686 }
1687
1688 rounding_mode = decode_rounding_mode(expr->Iex.Qop.arg1);
1689 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1690 rounding_mode));
1691 return dst;
1692 }
1693
1694 /* --------- TERNARY OP --------- */
1695 case Iex_Triop: {
1696 IROp op = expr->Iex.Triop.op;
1697 IRExpr *left = expr->Iex.Triop.arg2;
1698 IRExpr *right = expr->Iex.Triop.arg3;
1699 s390_bfp_binop_t bfpop;
1700 s390_round_t rounding_mode;
1701 HReg h1, op2, dst;
1702
1703 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1704 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1705 dst = newVRegF(env);
1706 addInstr(env, s390_insn_move(size, dst, h1));
1707 switch (op) {
1708 case Iop_AddF32:
1709 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1710 case Iop_SubF32:
1711 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1712 case Iop_MulF32:
1713 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1714 case Iop_DivF32:
1715 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1716
1717 default:
1718 goto irreducible;
1719 }
1720
1721 rounding_mode = decode_rounding_mode(expr->Iex.Triop.arg1);
1722 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1723 return dst;
1724 }
1725
1726 /* --------- BINARY OP --------- */
1727 case Iex_Binop: {
1728 IROp op = expr->Iex.Binop.op;
1729 IRExpr *left = expr->Iex.Binop.arg2;
1730 HReg h1, dst;
1731 s390_bfp_unop_t bfpop;
1732 s390_round_t rounding_mode;
1733 Int integer_operand;
1734
1735 integer_operand = 1;
1736
1737 switch (op) {
1738 case Iop_SqrtF32:
1739 case Iop_SqrtF64:
1740 bfpop = S390_BFP_SQRT;
1741 integer_operand = 0;
1742 break;
1743
1744 case Iop_F64toF32:
1745 bfpop = S390_BFP_F64_TO_F32;
1746 integer_operand = 0;
1747 break;
1748
1749 case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break;
1750 case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break;
1751 case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break;
1752 default:
1753 goto irreducible;
1754
1755 case Iop_F128toF64:
1756 case Iop_F128toF32: {
1757 HReg op_hi, op_lo, f12, f13, f14, f15;
1758
1759 bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1760 : S390_BFP_F128_TO_F64;
1761
1762 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1763
1764 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1765
1766 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1767 f12 = make_fpr(12);
1768 f13 = make_fpr(13);
1769 f14 = make_fpr(14);
1770 f15 = make_fpr(15);
1771
1772 /* operand --> (f13, f15) */
1773 addInstr(env, s390_insn_move(8, f13, op_hi));
1774 addInstr(env, s390_insn_move(8, f15, op_lo));
1775
1776 dst = newVRegF(env);
1777 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1778 rounding_mode));
1779
1780 /* Move result to virtual destination registers */
1781 addInstr(env, s390_insn_move(8, dst, f12));
1782 return dst;
1783 }
1784 }
1785
1786 /* Process operand */
1787 if (integer_operand) {
1788 h1 = s390_isel_int_expr(env, left);
1789 } else {
1790 h1 = s390_isel_float_expr(env, left);
1791 }
1792
1793 dst = newVRegF(env);
1794 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1795 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1796 return dst;
1797 }
1798
1799 /* --------- UNARY OP --------- */
1800 case Iex_Unop: {
1801 IROp op = expr->Iex.Unop.op;
1802 IRExpr *left = expr->Iex.Unop.arg;
1803 s390_bfp_unop_t bfpop;
1804 s390_round_t rounding_mode;
1805 HReg h1, dst;
1806
1807 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1808 HReg dst_hi, dst_lo;
1809
1810 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1811 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1812 }
1813
1814 if (op == Iop_ReinterpI64asF64) {
1815 dst = newVRegF(env);
1816 h1 = s390_isel_int_expr(env, left); /* Process the operand */
1817 addInstr(env, s390_insn_move(size, dst, h1));
1818
1819 return dst;
1820 }
1821
1822 switch (op) {
1823 case Iop_NegF32:
1824 case Iop_NegF64:
1825 if (left->tag == Iex_Unop &&
1826 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1827 bfpop = S390_BFP_NABS;
1828 else
1829 bfpop = S390_BFP_NEG;
1830 break;
1831
1832 case Iop_AbsF32:
1833 case Iop_AbsF64: bfpop = S390_BFP_ABS; break;
1834 case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break;
1835 case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break;
1836 default:
1837 goto irreducible;
1838 }
1839
1840 /* Process operand */
1841 if (op == Iop_I32StoF64)
1842 h1 = s390_isel_int_expr(env, left);
1843 else if (bfpop == S390_BFP_NABS)
1844 h1 = s390_isel_float_expr(env, left->Iex.Unop.arg);
1845 else
1846 h1 = s390_isel_float_expr(env, left);
1847
1848 dst = newVRegF(env);
1849 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1850 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1851 return dst;
1852 }
1853
1854 default:
1855 goto irreducible;
1856 }
1857
1858 /* We get here if no pattern matched. */
1859 irreducible:
1860 ppIRExpr(expr);
1861 vpanic("s390_isel_float_expr: cannot reduce tree");
1862}
1863
1864
1865static HReg
1866s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
1867{
1868 HReg dst = s390_isel_float_expr_wrk(env, expr);
1869
1870 /* Sanity checks ... */
1871 vassert(hregClass(dst) == HRcFlt64);
1872 vassert(hregIsVirtual(dst));
1873
1874 return dst;
1875}
1876
1877
1878/*---------------------------------------------------------*/
1879/*--- ISEL: Condition Code ---*/
1880/*---------------------------------------------------------*/
1881
1882/* This function handles all operators that produce a 1-bit result */
1883static s390_cc_t
1884s390_isel_cc(ISelEnv *env, IRExpr *cond)
1885{
1886 UChar size;
1887
1888 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
1889
1890 /* Constant: either 1 or 0 */
1891 if (cond->tag == Iex_Const) {
1892 vassert(cond->Iex.Const.con->tag == Ico_U1);
1893 vassert(cond->Iex.Const.con->Ico.U1 == True
1894 || cond->Iex.Const.con->Ico.U1 == False);
1895
1896 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
1897 }
1898
1899 /* Variable: values are 1 or 0 */
1900 if (cond->tag == Iex_RdTmp) {
1901 IRTemp tmp = cond->Iex.RdTmp.tmp;
1902 HReg reg = lookupIRTemp(env, tmp);
1903
1904 /* Load-and-test does not modify REG; so this is OK. */
1905 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
1906 size = 4;
1907 else
1908 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
1909 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
1910 return S390_CC_NE;
1911 }
1912
1913 /* Unary operators */
1914 if (cond->tag == Iex_Unop) {
1915 IRExpr *arg = cond->Iex.Unop.arg;
1916
1917 switch (cond->Iex.Unop.op) {
1918 case Iop_Not1: /* Not1(cond) */
1919 /* Generate code for EXPR, and negate the test condition */
1920 return s390_cc_invert(s390_isel_cc(env, arg));
1921
1922 /* Iop_32/64to1 select the LSB from their operand */
1923 case Iop_32to1:
1924 case Iop_64to1: {
1925 HReg dst = s390_isel_int_expr(env, arg);
1926
1927 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
1928
1929 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
1930 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
1931 return S390_CC_NE;
1932 }
1933
1934 case Iop_CmpNEZ8:
1935 case Iop_CmpNEZ16: {
1936 s390_opnd_RMI src;
1937 s390_unop_t op;
1938 HReg dst;
1939
1940 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
1941 : S390_ZERO_EXTEND_16;
1942 dst = newVRegI(env);
1943 src = s390_isel_int_expr_RMI(env, arg);
1944 addInstr(env, s390_insn_unop(4, op, dst, src));
1945 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
1946 return S390_CC_NE;
1947 }
1948
1949 case Iop_CmpNEZ32:
1950 case Iop_CmpNEZ64: {
1951 s390_opnd_RMI src;
1952
1953 src = s390_isel_int_expr_RMI(env, arg);
1954 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
1955 addInstr(env, s390_insn_test(size, src));
1956 return S390_CC_NE;
1957 }
1958
1959 default:
1960 goto fail;
1961 }
1962 }
1963
1964 /* Binary operators */
1965 if (cond->tag == Iex_Binop) {
1966 IRExpr *arg1 = cond->Iex.Binop.arg1;
1967 IRExpr *arg2 = cond->Iex.Binop.arg2;
1968 HReg reg1, reg2;
1969
1970 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
1971
1972 switch (cond->Iex.Binop.op) {
1973 s390_unop_t op;
1974 s390_cc_t result;
1975
1976 case Iop_CmpEQ8:
1977 case Iop_CasCmpEQ8:
1978 op = S390_ZERO_EXTEND_8;
1979 result = S390_CC_E;
1980 goto do_compare_ze;
1981
1982 case Iop_CmpNE8:
1983 case Iop_CasCmpNE8:
1984 op = S390_ZERO_EXTEND_8;
1985 result = S390_CC_NE;
1986 goto do_compare_ze;
1987
1988 case Iop_CmpEQ16:
1989 case Iop_CasCmpEQ16:
1990 op = S390_ZERO_EXTEND_16;
1991 result = S390_CC_E;
1992 goto do_compare_ze;
1993
1994 case Iop_CmpNE16:
1995 case Iop_CasCmpNE16:
1996 op = S390_ZERO_EXTEND_16;
1997 result = S390_CC_NE;
1998 goto do_compare_ze;
1999
2000 do_compare_ze: {
2001 s390_opnd_RMI op1, op2;
2002
2003 op1 = s390_isel_int_expr_RMI(env, arg1);
2004 reg1 = newVRegI(env);
2005 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2006
2007 op2 = s390_isel_int_expr_RMI(env, arg2);
2008 reg2 = newVRegI(env);
2009 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2010
2011 op2 = s390_opnd_reg(reg2);
2012 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2013
2014 return result;
2015 }
2016
2017 case Iop_CmpEQ32:
2018 case Iop_CmpEQ64:
2019 case Iop_CasCmpEQ32:
2020 case Iop_CasCmpEQ64:
2021 result = S390_CC_E;
2022 goto do_compare;
2023
2024 case Iop_CmpNE32:
2025 case Iop_CmpNE64:
2026 case Iop_CasCmpNE32:
2027 case Iop_CasCmpNE64:
2028 result = S390_CC_NE;
2029 goto do_compare;
2030
2031 do_compare: {
2032 HReg op1;
2033 s390_opnd_RMI op2;
2034
2035 order_commutative_operands(arg1, arg2);
2036
2037 op1 = s390_isel_int_expr(env, arg1);
2038 op2 = s390_isel_int_expr_RMI(env, arg2);
2039
2040 addInstr(env, s390_insn_compare(size, op1, op2, False));
2041
2042 return result;
2043 }
2044
2045 case Iop_CmpLT32S:
2046 case Iop_CmpLE32S:
2047 case Iop_CmpLT64S:
2048 case Iop_CmpLE64S: {
2049 HReg op1;
2050 s390_opnd_RMI op2;
2051
2052 op1 = s390_isel_int_expr(env, arg1);
2053 op2 = s390_isel_int_expr_RMI(env, arg2);
2054
2055 addInstr(env, s390_insn_compare(size, op1, op2, True));
2056
2057 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2058 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2059 }
2060
2061 case Iop_CmpLT32U:
2062 case Iop_CmpLE32U:
2063 case Iop_CmpLT64U:
2064 case Iop_CmpLE64U: {
2065 HReg op1;
2066 s390_opnd_RMI op2;
2067
2068 op1 = s390_isel_int_expr(env, arg1);
2069 op2 = s390_isel_int_expr_RMI(env, arg2);
2070
2071 addInstr(env, s390_insn_compare(size, op1, op2, False));
2072
2073 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2074 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2075 }
2076
2077 default:
2078 goto fail;
2079 }
2080 }
2081
2082 fail:
2083 ppIRExpr(cond);
2084 vpanic("s390_isel_cc: unexpected operator");
2085}
2086
2087
2088/*---------------------------------------------------------*/
2089/*--- ISEL: Statements ---*/
2090/*---------------------------------------------------------*/
2091
2092static void
2093s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2094{
2095 if (vex_traceflags & VEX_TRACE_VCODE) {
2096 vex_printf("\n -- ");
2097 ppIRStmt(stmt);
2098 vex_printf("\n");
2099 }
2100
2101 switch (stmt->tag) {
2102
2103 /* --------- STORE --------- */
2104 case Ist_Store: {
2105 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2106 s390_amode *am;
2107 HReg src;
2108
2109 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2110
2111 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2112
2113 switch (tyd) {
2114 case Ity_I8:
2115 case Ity_I16:
2116 case Ity_I32:
2117 case Ity_I64:
2118 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2119 break;
2120
2121 case Ity_F32:
2122 case Ity_F64:
2123 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2124 break;
2125
2126 case Ity_F128:
2127 /* Cannot occur. No such instruction */
2128 vpanic("Ist_Store with F128 data");
2129
2130 default:
2131 goto stmt_fail;
2132 }
2133
2134 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2135 return;
2136 }
2137
2138 /* --------- PUT --------- */
2139 case Ist_Put: {
2140 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2141 HReg src;
2142 s390_amode *am;
2143
2144 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2145
2146 switch (tyd) {
2147 case Ity_I8:
2148 case Ity_I16:
2149 case Ity_I32:
2150 case Ity_I64:
2151 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2152 break;
2153
2154 case Ity_F32:
2155 case Ity_F64:
2156 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2157 break;
2158
2159 case Ity_F128:
2160 /* Does not occur. See function put_fpr_pair. */
2161 vpanic("Ist_Put with F128 data");
2162
2163 default:
2164 goto stmt_fail;
2165 }
2166
2167 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2168 return;
2169 }
2170
2171 /* --------- TMP --------- */
2172 case Ist_WrTmp: {
2173 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2174 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2175 HReg src, dst;
2176
2177 switch (tyd) {
2178 case Ity_I128: {
2179 HReg dst_hi, dst_lo, res_hi, res_lo;
2180
2181 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2182 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2183
2184 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2185 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2186 return;
2187 }
2188
2189 case Ity_I8:
2190 case Ity_I16:
2191 case Ity_I32:
2192 case Ity_I64:
2193 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2194 dst = lookupIRTemp(env, tmp);
2195 break;
2196
2197 case Ity_I1: {
2198 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2199 dst = lookupIRTemp(env, tmp);
2200 addInstr(env, s390_insn_cc2bool(dst, cond));
2201 return;
2202 }
2203
2204 case Ity_F32:
2205 case Ity_F64:
2206 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2207 dst = lookupIRTemp(env, tmp);
2208 break;
2209
2210 case Ity_F128: {
2211 HReg dst_hi, dst_lo, res_hi, res_lo;
2212
2213 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2214 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2215
2216 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2217 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2218 return;
2219 }
2220
2221 default:
2222 goto stmt_fail;
2223 }
2224
2225 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2226 return;
2227 }
2228
2229 /* --------- Call to DIRTY helper --------- */
2230 case Ist_Dirty: {
2231 IRType retty;
2232 IRDirty* d = stmt->Ist.Dirty.details;
2233 Bool passBBP;
2234
2235 if (d->nFxState == 0)
2236 vassert(!d->needsBBP);
2237
2238 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2239
2240 doHelperCall(env, passBBP, d->guard, d->cee, d->args);
2241
2242 /* Now figure out what to do with the returned value, if any. */
2243 if (d->tmp == IRTemp_INVALID)
2244 /* No return value. Nothing to do. */
2245 return;
2246
2247 retty = typeOfIRTemp(env->type_env, d->tmp);
2248 if (retty == Ity_I64 || retty == Ity_I32
2249 || retty == Ity_I16 || retty == Ity_I8) {
2250 /* Move the returned value into the return register */
2251 HReg dst = lookupIRTemp(env, d->tmp);
2252 addInstr(env, s390_insn_move(sizeofIRType(retty), dst,
2253 mkHReg(S390_REGNO_RETURN_VALUE,
2254 HRcInt64, False)));
2255 return;
2256 }
2257 break;
2258 }
2259
2260 case Ist_CAS:
2261 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2262 IRCAS *cas = stmt->Ist.CAS.details;
2263 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2264 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2265 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2266 HReg old = lookupIRTemp(env, cas->oldLo);
2267
2268 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2269 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2270 } else {
2271 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2272 }
2273 return;
2274 } else {
2275 vpanic("compare double and swap not implemented\n");
2276 }
2277 break;
2278
2279 /* --------- EXIT --------- */
2280 case Ist_Exit: {
2281 s390_opnd_RMI dst;
2282 s390_cc_t cond;
2283 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2284
2285 if (tag != Ico_U64)
2286 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2287
2288 dst = s390_isel_int_expr_RMI(env, IRExpr_Const(stmt->Ist.Exit.dst));
2289 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
2290 addInstr(env, s390_insn_branch(stmt->Ist.Exit.jk, cond, dst));
2291 return;
2292 }
2293
2294 /* --------- MEM FENCE --------- */
2295 case Ist_MBE: /* fixs390 later */
2296 break;
2297
2298 /* --------- Miscellaneous --------- */
2299
2300 case Ist_PutI: /* Not needed */
2301 case Ist_IMark: /* Doesn't generate any executable code */
2302 case Ist_NoOp: /* Doesn't generate any executable code */
2303 case Ist_AbiHint: /* Meaningless in IR */
2304 return;
2305
2306 default:
2307 break;
2308 }
2309
2310 stmt_fail:
2311 ppIRStmt(stmt);
2312 vpanic("s390_isel_stmt");
2313}
2314
2315
2316/*---------------------------------------------------------*/
2317/*--- ISEL: Basic block terminators (Nexts) ---*/
2318/*---------------------------------------------------------*/
2319
2320static void
2321iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk)
2322{
2323 s390_opnd_RMI dst;
2324
2325 if (vex_traceflags & VEX_TRACE_VCODE) {
2326 vex_printf("\n-- goto {");
2327 ppIRJumpKind(jk);
2328 vex_printf("} ");
2329 ppIRExpr(next);
2330 vex_printf("\n");
2331 }
2332
2333 dst = s390_isel_int_expr_RMI(env, next);
2334 addInstr(env, s390_insn_branch(jk, S390_CC_ALWAYS, dst));
2335}
2336
2337
2338/*---------------------------------------------------------*/
2339/*--- Insn selector top-level ---*/
2340/*---------------------------------------------------------*/
2341
2342/* Translate an entire SB to s390 code. */
2343
2344HInstrArray *
2345iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
2346 VexAbiInfo *vbi)
2347{
2348 UInt i, j;
2349 HReg hreg, hregHI;
2350 ISelEnv *env;
2351 UInt hwcaps_host = archinfo_host->hwcaps;
2352
2353 /* KLUDGE: export archinfo_host. */
2354 s390_archinfo_host = archinfo_host;
2355
2356
2357 /* Do some sanity checks */
2358 vassert((hwcaps_host & ~(VEX_HWCAPS_S390X_ALL)) == 0);
2359
2360 /* Make up an initial environment to use. */
2361 env = LibVEX_Alloc(sizeof(ISelEnv));
2362 env->vreg_ctr = 0;
2363
2364 /* Set up output code array. */
2365 env->code = newHInstrArray();
2366
2367 /* Copy BB's type env. */
2368 env->type_env = bb->tyenv;
2369
2370 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2371 change as we go along. For some reason types_used has Int type -- but
2372 it should be unsigned. Internally we use an unsigned type; so we
2373 assert it here. */
2374 vassert(bb->tyenv->types_used >= 0);
2375
2376 env->n_vregmap = bb->tyenv->types_used;
2377 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2378 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2379
2380 /* and finally ... */
2381 env->hwcaps = hwcaps_host;
2382
2383 /* For each IR temporary, allocate a suitably-kinded virtual
2384 register. */
2385 j = 0;
2386 for (i = 0; i < env->n_vregmap; i++) {
2387 hregHI = hreg = INVALID_HREG;
2388 switch (bb->tyenv->types[i]) {
2389 case Ity_I1:
2390 case Ity_I8:
2391 case Ity_I16:
2392 case Ity_I32:
2393 hreg = mkHReg(j++, HRcInt64, True);
2394 break;
2395
2396 case Ity_I64:
2397 hreg = mkHReg(j++, HRcInt64, True);
2398 break;
2399
2400 case Ity_I128:
2401 hreg = mkHReg(j++, HRcInt64, True);
2402 hregHI = mkHReg(j++, HRcInt64, True);
2403 break;
2404
2405 case Ity_F32:
2406 case Ity_F64:
2407 hreg = mkHReg(j++, HRcFlt64, True);
2408 break;
2409
2410 case Ity_F128:
2411 hreg = mkHReg(j++, HRcFlt64, True);
2412 hregHI = mkHReg(j++, HRcFlt64, True);
2413 break;
2414
2415 case Ity_V128: /* fall through */
2416 default:
2417 ppIRType(bb->tyenv->types[i]);
2418 vpanic("s390_isel_sb: IRTemp type");
2419 }
2420
2421 env->vregmap[i] = hreg;
2422 env->vregmapHI[i] = hregHI;
2423 }
2424 env->vreg_ctr = j;
2425
2426 /* Ok, finally we can iterate over the statements. */
2427 for (i = 0; i < bb->stmts_used; i++)
2428 if (bb->stmts[i])
2429 s390_isel_stmt(env, bb->stmts[i]);
2430
2431 iselNext(env, bb->next, bb->jumpkind);
2432
2433 /* Record the number of vregs we used. */
2434 env->code->n_vregs = env->vreg_ctr;
2435
2436 return env->code;
2437}
2438
2439/*---------------------------------------------------------------*/
2440/*--- end host_s390_isel.c ---*/
2441/*---------------------------------------------------------------*/