blob: 4add4c657c5d4ab1f9ae0e0c48a38992a96317f4 [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
florian297b6062012-05-08 20:16:17 +0000239make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000240{
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
florian297b6062012-05-08 20:16:17 +0000483 finalreg = make_gpr(s390_gprno_from_arg_index(i));
sewardj2019a972011-03-07 16:04:07 +0000484 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 */
florian297b6062012-05-08 20:16:17 +0000623 r10 = make_gpr(10);
624 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000625
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 */
florian297b6062012-05-08 20:16:17 +0000656 r10 = make_gpr(10);
657 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000658
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 */
florian297b6062012-05-08 20:16:17 +0000682 r10 = make_gpr(10);
683 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000684
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 */
florian297b6062012-05-08 20:16:17 +0000812 r10 = make_gpr(10);
813 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000814
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 */
florian297b6062012-05-08 20:16:17 +0000849 r10 = make_gpr(10);
850 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000851
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. */
florian297b6062012-05-08 20:16:17 +00001270 r10 = make_gpr(10);
1271 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001272
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,
florian297b6062012-05-08 20:16:17 +00001314 make_gpr(S390_REGNO_RETURN_VALUE)));
sewardj2019a972011-03-07 16:04:07 +00001315 return dst;
1316 }
1317
1318 /* --------- LITERAL --------- */
1319
1320 /* Load a literal into a register. Create a "load immediate"
1321 v-insn and return the register. */
1322 case Iex_Const: {
1323 ULong value;
1324 HReg dst = newVRegI(env);
1325 const IRConst *con = expr->Iex.Const.con;
1326
1327 /* Bitwise copy of the value. No sign/zero-extension */
1328 switch (con->tag) {
1329 case Ico_U64: value = con->Ico.U64; break;
1330 case Ico_U32: value = con->Ico.U32; break;
1331 case Ico_U16: value = con->Ico.U16; break;
1332 case Ico_U8: value = con->Ico.U8; break;
1333 default: vpanic("s390_isel_int_expr: invalid constant");
1334 }
1335
1336 addInstr(env, s390_insn_load_immediate(size, dst, value));
1337
1338 return dst;
1339 }
1340
1341 /* --------- MULTIPLEX --------- */
1342 case Iex_Mux0X: {
1343 IRExpr *cond_expr;
1344 HReg dst, tmp, rX;
1345 s390_opnd_RMI cond, r0, zero;
1346
1347 cond_expr = expr->Iex.Mux0X.cond;
1348
1349 dst = newVRegI(env);
1350 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1351 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1352 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1353
1354 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1355 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1356
1357 addInstr(env, s390_insn_move(size, dst, rX));
1358 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1359 return dst;
1360 }
1361
1362 /* Assume the condition is true and move rX to the destination reg. */
1363 addInstr(env, s390_insn_move(size, dst, rX));
1364
1365 /* Compute the condition ... */
1366 cond = s390_isel_int_expr_RMI(env, cond_expr);
1367
1368 /* tmp = cond & 0xFF */
1369 tmp = newVRegI(env);
1370 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1371 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1372
1373 /* ... and compare it with zero */
1374 zero = s390_opnd_imm(0);
1375 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1376
1377 /* ... and if it compared equal move r0 to the destination reg. */
1378 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1379 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1380
1381 return dst;
1382 }
1383
1384 default:
1385 break;
1386 }
1387
1388 /* We get here if no pattern matched. */
1389 irreducible:
1390 ppIRExpr(expr);
1391 vpanic("s390_isel_int_expr: cannot reduce tree");
1392}
1393
1394
1395static HReg
1396s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1397{
1398 HReg dst = s390_isel_int_expr_wrk(env, expr);
1399
1400 /* Sanity checks ... */
1401 vassert(hregClass(dst) == HRcInt64);
1402 vassert(hregIsVirtual(dst));
1403
1404 return dst;
1405}
1406
1407
1408static s390_opnd_RMI
1409s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1410{
1411 IRType ty = typeOfIRExpr(env->type_env, expr);
1412 s390_opnd_RMI dst;
1413
1414 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1415 ty == Ity_I64);
1416
1417 if (expr->tag == Iex_Load) {
1418 dst.tag = S390_OPND_AMODE;
1419 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1420 } else if (expr->tag == Iex_Get) {
1421 dst.tag = S390_OPND_AMODE;
1422 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1423 } else if (expr->tag == Iex_Const) {
1424 ULong value;
1425
1426 /* The bit pattern for the value will be stored as is in the least
1427 significant bits of VALUE. */
1428 switch (expr->Iex.Const.con->tag) {
1429 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1430 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1431 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1432 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1433 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1434 default:
1435 vpanic("s390_isel_int_expr_RMI");
1436 }
1437
1438 dst.tag = S390_OPND_IMMEDIATE;
1439 dst.variant.imm = value;
1440 } else {
1441 dst.tag = S390_OPND_REG;
1442 dst.variant.reg = s390_isel_int_expr(env, expr);
1443 }
1444
1445 return dst;
1446}
1447
1448
1449/*---------------------------------------------------------*/
1450/*--- ISEL: Floating point expressions (128 bit) ---*/
1451/*---------------------------------------------------------*/
1452static void
1453s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1454 IRExpr *expr)
1455{
1456 IRType ty = typeOfIRExpr(env->type_env, expr);
1457
1458 vassert(ty == Ity_F128);
1459
1460 /* Read 128-bit IRTemp */
1461 if (expr->tag == Iex_RdTmp) {
1462 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1463 return;
1464 }
1465
1466 switch (expr->tag) {
1467 case Iex_RdTmp:
1468 /* Return the virtual registers that hold the temporary. */
1469 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1470 return;
1471
1472 /* --------- LOAD --------- */
1473 case Iex_Load: {
1474 IRExpr *addr_hi, *addr_lo;
1475 s390_amode *am_hi, *am_lo;
1476
1477 if (expr->Iex.Load.end != Iend_BE)
1478 goto irreducible;
1479
1480 addr_hi = expr->Iex.Load.addr;
1481 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1482
1483 am_hi = s390_isel_amode(env, addr_hi);
1484 am_lo = s390_isel_amode(env, addr_lo);
1485
1486 *dst_hi = newVRegF(env);
1487 *dst_lo = newVRegF(env);
1488 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1489 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1490 return;
1491 }
1492
1493
1494 /* --------- GET --------- */
1495 case Iex_Get:
1496 /* This is not supported because loading 128-bit from the guest
1497 state is almost certainly wrong. Use get_fpr_pair instead. */
1498 vpanic("Iex_Get with F128 data");
1499
1500 /* --------- 4-ary OP --------- */
1501 case Iex_Qop:
1502 vpanic("Iex_Qop with F128 data");
1503
1504 /* --------- TERNARY OP --------- */
1505 case Iex_Triop: {
1506 IROp op = expr->Iex.Triop.op;
1507 IRExpr *left = expr->Iex.Triop.arg2;
1508 IRExpr *right = expr->Iex.Triop.arg3;
1509 s390_bfp_binop_t bfpop;
1510 s390_round_t rounding_mode;
1511 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1512
1513 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1514 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1515
1516 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1517 f12 = make_fpr(12);
1518 f13 = make_fpr(13);
1519 f14 = make_fpr(14);
1520 f15 = make_fpr(15);
1521
1522 /* 1st operand --> (f12, f14) */
1523 addInstr(env, s390_insn_move(8, f12, op1_hi));
1524 addInstr(env, s390_insn_move(8, f14, op1_lo));
1525
1526 /* 2nd operand --> (f13, f15) */
1527 addInstr(env, s390_insn_move(8, f13, op2_hi));
1528 addInstr(env, s390_insn_move(8, f15, op2_lo));
1529
1530 switch (op) {
1531 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1532 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1533 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1534 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1535 default:
1536 goto irreducible;
1537 }
1538
1539 rounding_mode = decode_rounding_mode(expr->Iex.Triop.arg1);
1540 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1541 f15, rounding_mode));
1542
1543 /* Move result to virtual destination register */
1544 *dst_hi = newVRegF(env);
1545 *dst_lo = newVRegF(env);
1546 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1547 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1548
1549 return;
1550 }
1551
1552 /* --------- BINARY OP --------- */
1553 case Iex_Binop: {
1554 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardja970c402011-04-28 18:38:42 +00001555 s390_bfp_unop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001556 s390_round_t rounding_mode;
1557
1558 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1559 f12 = make_fpr(12);
1560 f13 = make_fpr(13);
1561 f14 = make_fpr(14);
1562 f15 = make_fpr(15);
1563
1564 switch (expr->Iex.Binop.op) {
1565 case Iop_SqrtF128:
1566 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1567
1568 /* operand --> (f13, f15) */
1569 addInstr(env, s390_insn_move(8, f13, op_hi));
1570 addInstr(env, s390_insn_move(8, f15, op_lo));
1571
1572 bfpop = S390_BFP_SQRT;
1573 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1574
1575 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1576 rounding_mode));
1577
1578 /* Move result to virtual destination registers */
1579 *dst_hi = newVRegF(env);
1580 *dst_lo = newVRegF(env);
1581 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1582 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1583 return;
1584
1585 case Iop_F64HLtoF128:
1586 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1587 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1588 return;
1589
1590 default:
1591 goto irreducible;
1592 }
1593 }
1594
1595 /* --------- UNARY OP --------- */
1596 case Iex_Unop: {
1597 IRExpr *left = expr->Iex.Binop.arg1;
1598 s390_bfp_unop_t bfpop;
1599 s390_round_t rounding_mode;
1600 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1601
1602 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1603 f12 = make_fpr(12);
1604 f13 = make_fpr(13);
1605 f14 = make_fpr(14);
1606 f15 = make_fpr(15);
1607
1608 switch (expr->Iex.Binop.op) {
1609 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1610 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1611 case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int;
1612 case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int;
1613 case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float;
1614 case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float;
1615 default:
1616 goto irreducible;
1617 }
1618
1619 float128_opnd:
1620 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1621
1622 /* operand --> (f13, f15) */
1623 addInstr(env, s390_insn_move(8, f13, op_hi));
1624 addInstr(env, s390_insn_move(8, f15, op_lo));
1625
1626 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1627 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1628 rounding_mode));
1629 goto move_dst;
1630
1631 convert_float:
1632 op = s390_isel_float_expr(env, left);
1633 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1634 op));
1635 goto move_dst;
1636
1637 convert_int:
1638 op = s390_isel_int_expr(env, left);
1639 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1640 op));
1641 goto move_dst;
1642
1643 move_dst:
1644 /* Move result to virtual destination registers */
1645 *dst_hi = newVRegF(env);
1646 *dst_lo = newVRegF(env);
1647 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1648 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1649 return;
1650 }
1651
1652 default:
1653 goto irreducible;
1654 }
1655
1656 /* We get here if no pattern matched. */
1657 irreducible:
1658 ppIRExpr(expr);
1659 vpanic("s390_isel_int_expr: cannot reduce tree");
1660}
1661
1662/* Compute a 128-bit value into two 64-bit registers. These may be either
1663 real or virtual regs; in any case they must not be changed by subsequent
1664 code emitted by the caller. */
1665static void
1666s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1667{
1668 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1669
1670 /* Sanity checks ... */
1671 vassert(hregIsVirtual(*dst_hi));
1672 vassert(hregIsVirtual(*dst_lo));
1673 vassert(hregClass(*dst_hi) == HRcFlt64);
1674 vassert(hregClass(*dst_lo) == HRcFlt64);
1675}
1676
1677
1678/*---------------------------------------------------------*/
1679/*--- ISEL: Floating point expressions (64 bit) ---*/
1680/*---------------------------------------------------------*/
1681
1682static HReg
1683s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1684{
1685 IRType ty = typeOfIRExpr(env->type_env, expr);
1686 UChar size;
1687
1688 vassert(ty == Ity_F32 || ty == Ity_F64);
1689
1690 size = sizeofIRType(ty);
1691
1692 switch (expr->tag) {
1693 case Iex_RdTmp:
1694 /* Return the virtual register that holds the temporary. */
1695 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1696
1697 /* --------- LOAD --------- */
1698 case Iex_Load: {
1699 HReg dst = newVRegF(env);
1700 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1701
1702 if (expr->Iex.Load.end != Iend_BE)
1703 goto irreducible;
1704
1705 addInstr(env, s390_insn_load(size, dst, am));
1706
1707 return dst;
1708 }
1709
1710 /* --------- GET --------- */
1711 case Iex_Get: {
1712 HReg dst = newVRegF(env);
1713 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1714
1715 addInstr(env, s390_insn_load(size, dst, am));
1716
1717 return dst;
1718 }
1719
1720 /* --------- LITERAL --------- */
1721
1722 /* Load a literal into a register. Create a "load immediate"
1723 v-insn and return the register. */
1724 case Iex_Const: {
1725 ULong value;
1726 HReg dst = newVRegF(env);
1727 const IRConst *con = expr->Iex.Const.con;
1728
1729 /* Bitwise copy of the value. No sign/zero-extension */
1730 switch (con->tag) {
1731 case Ico_F32i: value = con->Ico.F32i; break;
1732 case Ico_F64i: value = con->Ico.F64i; break;
1733 default: vpanic("s390_isel_float_expr: invalid constant");
1734 }
1735
1736 if (value != 0) vpanic("cannot load immediate floating point constant");
1737
1738 addInstr(env, s390_insn_load_immediate(size, dst, value));
1739
1740 return dst;
1741 }
1742
1743 /* --------- 4-ary OP --------- */
1744 case Iex_Qop: {
1745 HReg op1, op2, op3, dst;
1746 s390_bfp_triop_t bfpop;
1747 s390_round_t rounding_mode;
1748
1749 op1 = s390_isel_float_expr(env, expr->Iex.Qop.arg2);
1750 op2 = s390_isel_float_expr(env, expr->Iex.Qop.arg3);
1751 op3 = s390_isel_float_expr(env, expr->Iex.Qop.arg4);
1752 dst = newVRegF(env);
1753 addInstr(env, s390_insn_move(size, dst, op1));
1754
1755 switch (expr->Iex.Qop.op) {
1756 case Iop_MAddF32:
1757 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1758 case Iop_MSubF32:
1759 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1760
1761 default:
1762 goto irreducible;
1763 }
1764
1765 rounding_mode = decode_rounding_mode(expr->Iex.Qop.arg1);
1766 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1767 rounding_mode));
1768 return dst;
1769 }
1770
1771 /* --------- TERNARY OP --------- */
1772 case Iex_Triop: {
1773 IROp op = expr->Iex.Triop.op;
1774 IRExpr *left = expr->Iex.Triop.arg2;
1775 IRExpr *right = expr->Iex.Triop.arg3;
1776 s390_bfp_binop_t bfpop;
1777 s390_round_t rounding_mode;
1778 HReg h1, op2, dst;
1779
1780 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1781 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1782 dst = newVRegF(env);
1783 addInstr(env, s390_insn_move(size, dst, h1));
1784 switch (op) {
1785 case Iop_AddF32:
1786 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1787 case Iop_SubF32:
1788 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1789 case Iop_MulF32:
1790 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1791 case Iop_DivF32:
1792 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1793
1794 default:
1795 goto irreducible;
1796 }
1797
1798 rounding_mode = decode_rounding_mode(expr->Iex.Triop.arg1);
1799 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1800 return dst;
1801 }
1802
1803 /* --------- BINARY OP --------- */
1804 case Iex_Binop: {
1805 IROp op = expr->Iex.Binop.op;
1806 IRExpr *left = expr->Iex.Binop.arg2;
1807 HReg h1, dst;
1808 s390_bfp_unop_t bfpop;
1809 s390_round_t rounding_mode;
1810 Int integer_operand;
1811
1812 integer_operand = 1;
1813
1814 switch (op) {
1815 case Iop_SqrtF32:
1816 case Iop_SqrtF64:
1817 bfpop = S390_BFP_SQRT;
1818 integer_operand = 0;
1819 break;
1820
1821 case Iop_F64toF32:
1822 bfpop = S390_BFP_F64_TO_F32;
1823 integer_operand = 0;
1824 break;
1825
1826 case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break;
1827 case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break;
1828 case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break;
1829 default:
1830 goto irreducible;
1831
1832 case Iop_F128toF64:
1833 case Iop_F128toF32: {
1834 HReg op_hi, op_lo, f12, f13, f14, f15;
1835
1836 bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1837 : S390_BFP_F128_TO_F64;
1838
1839 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1840
1841 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1842
1843 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1844 f12 = make_fpr(12);
1845 f13 = make_fpr(13);
1846 f14 = make_fpr(14);
1847 f15 = make_fpr(15);
1848
1849 /* operand --> (f13, f15) */
1850 addInstr(env, s390_insn_move(8, f13, op_hi));
1851 addInstr(env, s390_insn_move(8, f15, op_lo));
1852
1853 dst = newVRegF(env);
1854 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1855 rounding_mode));
1856
1857 /* Move result to virtual destination registers */
1858 addInstr(env, s390_insn_move(8, dst, f12));
1859 return dst;
1860 }
1861 }
1862
1863 /* Process operand */
1864 if (integer_operand) {
1865 h1 = s390_isel_int_expr(env, left);
1866 } else {
1867 h1 = s390_isel_float_expr(env, left);
1868 }
1869
1870 dst = newVRegF(env);
1871 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1872 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1873 return dst;
1874 }
1875
1876 /* --------- UNARY OP --------- */
1877 case Iex_Unop: {
1878 IROp op = expr->Iex.Unop.op;
1879 IRExpr *left = expr->Iex.Unop.arg;
1880 s390_bfp_unop_t bfpop;
1881 s390_round_t rounding_mode;
1882 HReg h1, dst;
1883
1884 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1885 HReg dst_hi, dst_lo;
1886
1887 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1888 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1889 }
1890
florian4d71a082011-12-18 00:08:17 +00001891 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00001892 dst = newVRegF(env);
1893 h1 = s390_isel_int_expr(env, left); /* Process the operand */
1894 addInstr(env, s390_insn_move(size, dst, h1));
1895
1896 return dst;
1897 }
1898
1899 switch (op) {
1900 case Iop_NegF32:
1901 case Iop_NegF64:
1902 if (left->tag == Iex_Unop &&
1903 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1904 bfpop = S390_BFP_NABS;
1905 else
1906 bfpop = S390_BFP_NEG;
1907 break;
1908
1909 case Iop_AbsF32:
1910 case Iop_AbsF64: bfpop = S390_BFP_ABS; break;
1911 case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break;
1912 case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break;
1913 default:
1914 goto irreducible;
1915 }
1916
1917 /* Process operand */
1918 if (op == Iop_I32StoF64)
1919 h1 = s390_isel_int_expr(env, left);
1920 else if (bfpop == S390_BFP_NABS)
1921 h1 = s390_isel_float_expr(env, left->Iex.Unop.arg);
1922 else
1923 h1 = s390_isel_float_expr(env, left);
1924
1925 dst = newVRegF(env);
1926 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1927 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1928 return dst;
1929 }
1930
1931 default:
1932 goto irreducible;
1933 }
1934
1935 /* We get here if no pattern matched. */
1936 irreducible:
1937 ppIRExpr(expr);
1938 vpanic("s390_isel_float_expr: cannot reduce tree");
1939}
1940
1941
1942static HReg
1943s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
1944{
1945 HReg dst = s390_isel_float_expr_wrk(env, expr);
1946
1947 /* Sanity checks ... */
1948 vassert(hregClass(dst) == HRcFlt64);
1949 vassert(hregIsVirtual(dst));
1950
1951 return dst;
1952}
1953
1954
1955/*---------------------------------------------------------*/
1956/*--- ISEL: Condition Code ---*/
1957/*---------------------------------------------------------*/
1958
1959/* This function handles all operators that produce a 1-bit result */
1960static s390_cc_t
1961s390_isel_cc(ISelEnv *env, IRExpr *cond)
1962{
1963 UChar size;
1964
1965 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
1966
1967 /* Constant: either 1 or 0 */
1968 if (cond->tag == Iex_Const) {
1969 vassert(cond->Iex.Const.con->tag == Ico_U1);
1970 vassert(cond->Iex.Const.con->Ico.U1 == True
1971 || cond->Iex.Const.con->Ico.U1 == False);
1972
1973 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
1974 }
1975
1976 /* Variable: values are 1 or 0 */
1977 if (cond->tag == Iex_RdTmp) {
1978 IRTemp tmp = cond->Iex.RdTmp.tmp;
1979 HReg reg = lookupIRTemp(env, tmp);
1980
1981 /* Load-and-test does not modify REG; so this is OK. */
1982 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
1983 size = 4;
1984 else
1985 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
1986 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
1987 return S390_CC_NE;
1988 }
1989
1990 /* Unary operators */
1991 if (cond->tag == Iex_Unop) {
1992 IRExpr *arg = cond->Iex.Unop.arg;
1993
1994 switch (cond->Iex.Unop.op) {
1995 case Iop_Not1: /* Not1(cond) */
1996 /* Generate code for EXPR, and negate the test condition */
1997 return s390_cc_invert(s390_isel_cc(env, arg));
1998
1999 /* Iop_32/64to1 select the LSB from their operand */
2000 case Iop_32to1:
2001 case Iop_64to1: {
2002 HReg dst = s390_isel_int_expr(env, arg);
2003
2004 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2005
2006 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2007 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2008 return S390_CC_NE;
2009 }
2010
2011 case Iop_CmpNEZ8:
2012 case Iop_CmpNEZ16: {
2013 s390_opnd_RMI src;
2014 s390_unop_t op;
2015 HReg dst;
2016
2017 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2018 : S390_ZERO_EXTEND_16;
2019 dst = newVRegI(env);
2020 src = s390_isel_int_expr_RMI(env, arg);
2021 addInstr(env, s390_insn_unop(4, op, dst, src));
2022 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2023 return S390_CC_NE;
2024 }
2025
2026 case Iop_CmpNEZ32:
2027 case Iop_CmpNEZ64: {
2028 s390_opnd_RMI src;
2029
2030 src = s390_isel_int_expr_RMI(env, arg);
2031 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2032 addInstr(env, s390_insn_test(size, src));
2033 return S390_CC_NE;
2034 }
2035
2036 default:
2037 goto fail;
2038 }
2039 }
2040
2041 /* Binary operators */
2042 if (cond->tag == Iex_Binop) {
2043 IRExpr *arg1 = cond->Iex.Binop.arg1;
2044 IRExpr *arg2 = cond->Iex.Binop.arg2;
2045 HReg reg1, reg2;
2046
2047 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2048
2049 switch (cond->Iex.Binop.op) {
2050 s390_unop_t op;
2051 s390_cc_t result;
2052
2053 case Iop_CmpEQ8:
2054 case Iop_CasCmpEQ8:
2055 op = S390_ZERO_EXTEND_8;
2056 result = S390_CC_E;
2057 goto do_compare_ze;
2058
2059 case Iop_CmpNE8:
2060 case Iop_CasCmpNE8:
2061 op = S390_ZERO_EXTEND_8;
2062 result = S390_CC_NE;
2063 goto do_compare_ze;
2064
2065 case Iop_CmpEQ16:
2066 case Iop_CasCmpEQ16:
2067 op = S390_ZERO_EXTEND_16;
2068 result = S390_CC_E;
2069 goto do_compare_ze;
2070
2071 case Iop_CmpNE16:
2072 case Iop_CasCmpNE16:
2073 op = S390_ZERO_EXTEND_16;
2074 result = S390_CC_NE;
2075 goto do_compare_ze;
2076
2077 do_compare_ze: {
2078 s390_opnd_RMI op1, op2;
2079
2080 op1 = s390_isel_int_expr_RMI(env, arg1);
2081 reg1 = newVRegI(env);
2082 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2083
2084 op2 = s390_isel_int_expr_RMI(env, arg2);
2085 reg2 = newVRegI(env);
2086 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2087
2088 op2 = s390_opnd_reg(reg2);
2089 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2090
2091 return result;
2092 }
2093
2094 case Iop_CmpEQ32:
2095 case Iop_CmpEQ64:
2096 case Iop_CasCmpEQ32:
2097 case Iop_CasCmpEQ64:
2098 result = S390_CC_E;
2099 goto do_compare;
2100
2101 case Iop_CmpNE32:
2102 case Iop_CmpNE64:
2103 case Iop_CasCmpNE32:
2104 case Iop_CasCmpNE64:
2105 result = S390_CC_NE;
2106 goto do_compare;
2107
2108 do_compare: {
2109 HReg op1;
2110 s390_opnd_RMI op2;
2111
2112 order_commutative_operands(arg1, arg2);
2113
2114 op1 = s390_isel_int_expr(env, arg1);
2115 op2 = s390_isel_int_expr_RMI(env, arg2);
2116
2117 addInstr(env, s390_insn_compare(size, op1, op2, False));
2118
2119 return result;
2120 }
2121
2122 case Iop_CmpLT32S:
2123 case Iop_CmpLE32S:
2124 case Iop_CmpLT64S:
2125 case Iop_CmpLE64S: {
2126 HReg op1;
2127 s390_opnd_RMI op2;
2128
2129 op1 = s390_isel_int_expr(env, arg1);
2130 op2 = s390_isel_int_expr_RMI(env, arg2);
2131
2132 addInstr(env, s390_insn_compare(size, op1, op2, True));
2133
2134 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2135 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2136 }
2137
2138 case Iop_CmpLT32U:
2139 case Iop_CmpLE32U:
2140 case Iop_CmpLT64U:
2141 case Iop_CmpLE64U: {
2142 HReg op1;
2143 s390_opnd_RMI op2;
2144
2145 op1 = s390_isel_int_expr(env, arg1);
2146 op2 = s390_isel_int_expr_RMI(env, arg2);
2147
2148 addInstr(env, s390_insn_compare(size, op1, op2, False));
2149
2150 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2151 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2152 }
2153
2154 default:
2155 goto fail;
2156 }
2157 }
2158
2159 fail:
2160 ppIRExpr(cond);
2161 vpanic("s390_isel_cc: unexpected operator");
2162}
2163
2164
2165/*---------------------------------------------------------*/
2166/*--- ISEL: Statements ---*/
2167/*---------------------------------------------------------*/
2168
2169static void
2170s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2171{
2172 if (vex_traceflags & VEX_TRACE_VCODE) {
2173 vex_printf("\n -- ");
2174 ppIRStmt(stmt);
2175 vex_printf("\n");
2176 }
2177
2178 switch (stmt->tag) {
2179
2180 /* --------- STORE --------- */
2181 case Ist_Store: {
2182 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2183 s390_amode *am;
2184 HReg src;
2185
2186 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2187
2188 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2189
2190 switch (tyd) {
2191 case Ity_I8:
2192 case Ity_I16:
2193 case Ity_I32:
2194 case Ity_I64:
2195 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2196 break;
2197
2198 case Ity_F32:
2199 case Ity_F64:
2200 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2201 break;
2202
2203 case Ity_F128:
2204 /* Cannot occur. No such instruction */
2205 vpanic("Ist_Store with F128 data");
2206
2207 default:
2208 goto stmt_fail;
2209 }
2210
2211 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2212 return;
2213 }
2214
2215 /* --------- PUT --------- */
2216 case Ist_Put: {
2217 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2218 HReg src;
2219 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002220 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002221
florianad43b3a2012-02-20 15:01:14 +00002222 /* Detect updates to certain guest registers. We track the contents
2223 of those registers as long as they contain constants. If the new
2224 constant is either zero or in the 8-bit neighbourhood of the
2225 current value we can use a memory-to-memory insn to do the update. */
2226
2227 Int offset = stmt->Ist.Put.offset;
2228
2229 /* Check necessary conditions:
2230 (1) must be one of the registers we care about
2231 (2) assigned value must be a constant */
2232 Int guest_reg = get_guest_reg(offset);
2233
2234 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2235
2236 if (guest_reg == GUEST_IA) {
2237 /* If this is the first assignment to the IA reg, don't special case
2238 it. We need to do a full 8-byte assignment here. The reason is
2239 that in case of a redirected translation the guest IA does not
2240 contain the redirected-to address. Instead it contains the
2241 redirected-from address and those can be far apart. So in order to
2242 do incremnetal updates if the IA in the future we need to get the
2243 initial address of the super block correct. */
2244 if (env->first_IA_assignment) {
2245 env->first_IA_assignment = False;
2246 goto not_special;
2247 }
2248 }
2249
2250 if (stmt->Ist.Put.data->tag != Iex_Const) {
2251 /* Invalidate guest register contents */
2252 env->old_value_valid[guest_reg] = False;
2253 goto not_special;
2254 }
2255
2256 /* OK. Necessary conditions are satisfied. */
2257
2258 /* Get the old value and update it */
2259 vassert(tyd == Ity_I64);
2260
2261 old_value = env->old_value[guest_reg];
2262 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2263 env->old_value[guest_reg] = new_value;
2264
2265 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2266 env->old_value_valid[guest_reg] = True;
2267
2268 /* If the register already contains the new value, there is nothing
2269 to do here. Unless the guest register requires precise memory
2270 exceptions. */
2271 if (old_value_is_valid && new_value == old_value) {
2272 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2273 return;
2274 }
2275 }
2276
2277 /* guest register = 0 */
2278 if (new_value == 0) {
2279 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2280 return;
2281 }
2282
2283 if (old_value_is_valid == False) goto not_special;
2284
2285 /* If the new value is in the neighbourhood of the old value
2286 we can use a memory-to-memory insn */
2287 difference = new_value - old_value;
2288
2289 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2290 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2291 (difference & 0xFF), new_value));
2292 return;
2293 }
2294
2295 /* If the high word is the same it is sufficient to load the low word.
2296 Use R0 as a scratch reg. */
2297 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002298 HReg r0 = make_gpr(0);
2299 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002300 s390_amode *gam;
2301
2302 gam = s390_amode_b12(offset + 4, gsp);
2303 addInstr(env, s390_insn_load_immediate(4, r0,
2304 new_value & 0xFFFFFFFF));
2305 addInstr(env, s390_insn_store(4, gam, r0));
2306 return;
2307 }
2308
2309 /* No special case applies... fall through */
2310
2311 not_special:
sewardj2019a972011-03-07 16:04:07 +00002312 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2313
2314 switch (tyd) {
2315 case Ity_I8:
2316 case Ity_I16:
2317 case Ity_I32:
2318 case Ity_I64:
2319 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2320 break;
2321
2322 case Ity_F32:
2323 case Ity_F64:
2324 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2325 break;
2326
2327 case Ity_F128:
2328 /* Does not occur. See function put_fpr_pair. */
2329 vpanic("Ist_Put with F128 data");
2330
2331 default:
2332 goto stmt_fail;
2333 }
2334
2335 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2336 return;
2337 }
2338
2339 /* --------- TMP --------- */
2340 case Ist_WrTmp: {
2341 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2342 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2343 HReg src, dst;
2344
2345 switch (tyd) {
2346 case Ity_I128: {
2347 HReg dst_hi, dst_lo, res_hi, res_lo;
2348
2349 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2350 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2351
2352 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2353 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2354 return;
2355 }
2356
2357 case Ity_I8:
2358 case Ity_I16:
2359 case Ity_I32:
2360 case Ity_I64:
2361 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2362 dst = lookupIRTemp(env, tmp);
2363 break;
2364
2365 case Ity_I1: {
2366 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2367 dst = lookupIRTemp(env, tmp);
2368 addInstr(env, s390_insn_cc2bool(dst, cond));
2369 return;
2370 }
2371
2372 case Ity_F32:
2373 case Ity_F64:
2374 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2375 dst = lookupIRTemp(env, tmp);
2376 break;
2377
2378 case Ity_F128: {
2379 HReg dst_hi, dst_lo, res_hi, res_lo;
2380
2381 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2382 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2383
2384 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2385 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2386 return;
2387 }
2388
2389 default:
2390 goto stmt_fail;
2391 }
2392
2393 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2394 return;
2395 }
2396
2397 /* --------- Call to DIRTY helper --------- */
2398 case Ist_Dirty: {
2399 IRType retty;
2400 IRDirty* d = stmt->Ist.Dirty.details;
2401 Bool passBBP;
florianad43b3a2012-02-20 15:01:14 +00002402 Int i;
2403
2404 /* Invalidate tracked values of those guest state registers that are
2405 modified by this helper. */
2406 for (i = 0; i < d->nFxState; ++i) {
2407 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2408 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2409 if (guest_reg != GUEST_UNKNOWN)
2410 env->old_value_valid[guest_reg] = False;
2411 }
2412 }
sewardj2019a972011-03-07 16:04:07 +00002413
2414 if (d->nFxState == 0)
2415 vassert(!d->needsBBP);
2416
2417 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2418
2419 doHelperCall(env, passBBP, d->guard, d->cee, d->args);
2420
2421 /* Now figure out what to do with the returned value, if any. */
2422 if (d->tmp == IRTemp_INVALID)
2423 /* No return value. Nothing to do. */
2424 return;
2425
2426 retty = typeOfIRTemp(env->type_env, d->tmp);
2427 if (retty == Ity_I64 || retty == Ity_I32
2428 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002429 /* Move the returned value to the destination register */
sewardj2019a972011-03-07 16:04:07 +00002430 HReg dst = lookupIRTemp(env, d->tmp);
2431 addInstr(env, s390_insn_move(sizeofIRType(retty), dst,
florian297b6062012-05-08 20:16:17 +00002432 make_gpr(S390_REGNO_RETURN_VALUE)));
sewardj2019a972011-03-07 16:04:07 +00002433 return;
2434 }
2435 break;
2436 }
2437
2438 case Ist_CAS:
2439 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2440 IRCAS *cas = stmt->Ist.CAS.details;
2441 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2442 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2443 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2444 HReg old = lookupIRTemp(env, cas->oldLo);
2445
2446 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2447 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2448 } else {
2449 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2450 }
2451 return;
2452 } else {
2453 vpanic("compare double and swap not implemented\n");
2454 }
2455 break;
2456
2457 /* --------- EXIT --------- */
2458 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002459 s390_cc_t cond;
2460 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2461
2462 if (tag != Ico_U64)
2463 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2464
florian8844a632012-04-13 04:04:06 +00002465 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002466 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002467
2468 /* Case: boring transfer to known address */
2469 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2470 if (env->chaining_allowed) {
2471 /* .. almost always true .. */
2472 /* Skip the event check at the dst if this is a forwards
2473 edge. */
2474 Bool to_fast_entry
2475 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2476 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2477 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2478 guest_IA, to_fast_entry));
2479 } else {
2480 /* .. very occasionally .. */
2481 /* We can't use chaining, so ask for an assisted transfer,
2482 as that's the only alternative that is allowable. */
2483 HReg dst = s390_isel_int_expr(env,
2484 IRExpr_Const(stmt->Ist.Exit.dst));
2485 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2486 }
2487 return;
2488 }
2489
2490 /* Case: assisted transfer to arbitrary address */
2491 switch (stmt->Ist.Exit.jk) {
florian65b5b3f2012-04-22 02:51:27 +00002492 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002493 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002494 case Ijk_Sys_syscall:
2495 case Ijk_ClientReq:
2496 case Ijk_NoRedir:
2497 case Ijk_Yield:
2498 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002499 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2500 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2501 stmt->Ist.Exit.jk));
2502 return;
2503 }
2504 default:
2505 break;
2506 }
2507
2508 /* Do we ever expect to see any other kind? */
2509 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002510 }
2511
2512 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002513 case Ist_MBE:
2514 switch (stmt->Ist.MBE.event) {
2515 case Imbe_Fence:
2516 addInstr(env, s390_insn_mfence());
2517 return;
2518 default:
2519 break;
2520 }
sewardj2019a972011-03-07 16:04:07 +00002521 break;
2522
2523 /* --------- Miscellaneous --------- */
2524
2525 case Ist_PutI: /* Not needed */
2526 case Ist_IMark: /* Doesn't generate any executable code */
2527 case Ist_NoOp: /* Doesn't generate any executable code */
2528 case Ist_AbiHint: /* Meaningless in IR */
2529 return;
2530
2531 default:
2532 break;
2533 }
2534
2535 stmt_fail:
2536 ppIRStmt(stmt);
2537 vpanic("s390_isel_stmt");
2538}
2539
2540
2541/*---------------------------------------------------------*/
2542/*--- ISEL: Basic block terminators (Nexts) ---*/
2543/*---------------------------------------------------------*/
2544
2545static void
florian8844a632012-04-13 04:04:06 +00002546iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002547{
sewardj2019a972011-03-07 16:04:07 +00002548 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002549 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002550 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002551 vex_printf("; exit-");
2552 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002553 vex_printf("\n");
2554 }
2555
florian8844a632012-04-13 04:04:06 +00002556 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2557
2558 /* Case: boring transfer to known address */
2559 if (next->tag == Iex_Const) {
2560 IRConst *cdst = next->Iex.Const.con;
2561 vassert(cdst->tag == Ico_U64);
2562 if (jk == Ijk_Boring || jk == Ijk_Call) {
2563 /* Boring transfer to known address */
2564 if (env->chaining_allowed) {
2565 /* .. almost always true .. */
2566 /* Skip the event check at the dst if this is a forwards
2567 edge. */
2568 Bool to_fast_entry
2569 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2570 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2571 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2572 guest_IA, to_fast_entry));
2573 } else {
2574 /* .. very occasionally .. */
2575 /* We can't use chaining, so ask for an indirect transfer,
2576 as that's the cheapest alternative that is allowable. */
2577 HReg dst = s390_isel_int_expr(env, next);
2578 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2579 Ijk_Boring));
2580 }
2581 return;
2582 }
2583 }
2584
2585 /* Case: call/return (==boring) transfer to any address */
2586 switch (jk) {
2587 case Ijk_Boring:
2588 case Ijk_Ret:
2589 case Ijk_Call: {
2590 HReg dst = s390_isel_int_expr(env, next);
2591 if (env->chaining_allowed) {
2592 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2593 } else {
2594 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2595 Ijk_Boring));
2596 }
2597 return;
2598 }
2599 default:
2600 break;
2601 }
2602
2603 /* Case: some other kind of transfer to any address */
2604 switch (jk) {
florian65b5b3f2012-04-22 02:51:27 +00002605 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002606 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002607 case Ijk_Sys_syscall:
2608 case Ijk_ClientReq:
2609 case Ijk_NoRedir:
2610 case Ijk_Yield:
2611 case Ijk_SigTRAP: {
2612 HReg dst = s390_isel_int_expr(env, next);
2613 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2614 return;
2615 }
2616 default:
2617 break;
2618 }
2619
2620 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002621}
2622
2623
2624/*---------------------------------------------------------*/
2625/*--- Insn selector top-level ---*/
2626/*---------------------------------------------------------*/
2627
florianf26994a2012-04-21 03:34:54 +00002628/* Translate an entire SB to s390 code.
2629 Note: archinfo_host is a pointer to a stack-allocated variable.
2630 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002631
2632HInstrArray *
2633iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002634 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2635 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2636 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002637{
2638 UInt i, j;
2639 HReg hreg, hregHI;
2640 ISelEnv *env;
2641 UInt hwcaps_host = archinfo_host->hwcaps;
2642
florianf26994a2012-04-21 03:34:54 +00002643 /* KLUDGE: export hwcaps. */
2644 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002645
sewardj2019a972011-03-07 16:04:07 +00002646 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002647 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002648
2649 /* Make up an initial environment to use. */
2650 env = LibVEX_Alloc(sizeof(ISelEnv));
2651 env->vreg_ctr = 0;
2652
2653 /* Set up output code array. */
2654 env->code = newHInstrArray();
2655
2656 /* Copy BB's type env. */
2657 env->type_env = bb->tyenv;
2658
florianad43b3a2012-02-20 15:01:14 +00002659 /* Set up data structures for tracking guest register values. */
2660 env->first_IA_assignment = True;
2661 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2662 env->old_value[i] = 0; /* just something to have a defined value */
2663 env->old_value_valid[i] = False;
2664 }
2665
sewardj2019a972011-03-07 16:04:07 +00002666 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2667 change as we go along. For some reason types_used has Int type -- but
2668 it should be unsigned. Internally we use an unsigned type; so we
2669 assert it here. */
2670 vassert(bb->tyenv->types_used >= 0);
2671
2672 env->n_vregmap = bb->tyenv->types_used;
2673 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2674 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2675
2676 /* and finally ... */
2677 env->hwcaps = hwcaps_host;
2678
florian8844a632012-04-13 04:04:06 +00002679 env->max_ga = max_ga;
2680 env->chaining_allowed = chaining_allowed;
2681
sewardj2019a972011-03-07 16:04:07 +00002682 /* For each IR temporary, allocate a suitably-kinded virtual
2683 register. */
2684 j = 0;
2685 for (i = 0; i < env->n_vregmap; i++) {
2686 hregHI = hreg = INVALID_HREG;
2687 switch (bb->tyenv->types[i]) {
2688 case Ity_I1:
2689 case Ity_I8:
2690 case Ity_I16:
2691 case Ity_I32:
2692 hreg = mkHReg(j++, HRcInt64, True);
2693 break;
2694
2695 case Ity_I64:
2696 hreg = mkHReg(j++, HRcInt64, True);
2697 break;
2698
2699 case Ity_I128:
2700 hreg = mkHReg(j++, HRcInt64, True);
2701 hregHI = mkHReg(j++, HRcInt64, True);
2702 break;
2703
2704 case Ity_F32:
2705 case Ity_F64:
2706 hreg = mkHReg(j++, HRcFlt64, True);
2707 break;
2708
2709 case Ity_F128:
2710 hreg = mkHReg(j++, HRcFlt64, True);
2711 hregHI = mkHReg(j++, HRcFlt64, True);
2712 break;
2713
2714 case Ity_V128: /* fall through */
2715 default:
2716 ppIRType(bb->tyenv->types[i]);
2717 vpanic("s390_isel_sb: IRTemp type");
2718 }
2719
2720 env->vregmap[i] = hreg;
2721 env->vregmapHI[i] = hregHI;
2722 }
2723 env->vreg_ctr = j;
2724
florian8844a632012-04-13 04:04:06 +00002725 /* The very first instruction must be an event check. */
2726 s390_amode *counter, *fail_addr;
2727 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2728 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2729 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2730
2731 /* Possibly a block counter increment (for profiling). At this
2732 point we don't know the address of the counter, so just pretend
2733 it is zero. It will have to be patched later, but before this
2734 translation is used, by a call to LibVEX_patchProfInc. */
2735 if (add_profinc) {
2736 addInstr(env, s390_insn_profinc());
2737 }
2738
sewardj2019a972011-03-07 16:04:07 +00002739 /* Ok, finally we can iterate over the statements. */
2740 for (i = 0; i < bb->stmts_used; i++)
2741 if (bb->stmts[i])
2742 s390_isel_stmt(env, bb->stmts[i]);
2743
florian8844a632012-04-13 04:04:06 +00002744 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002745
2746 /* Record the number of vregs we used. */
2747 env->code->n_vregs = env->vreg_ctr;
2748
2749 return env->code;
2750}
2751
2752/*---------------------------------------------------------------*/
2753/*--- end host_s390_isel.c ---*/
2754/*---------------------------------------------------------------*/