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