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