blob: 8ac425a38e270e6160708aef76e974f50eb93f3e [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:
florianaf50a192012-07-13 14:13:06 +0000159 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000160 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:
floriane0654362012-05-09 13:31:09 +0000428
sewardj2019a972011-03-07 16:04:07 +0000429 (a) they are expressions yielding an integer result
430 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000431
432 guard is a Ity_Bit expression indicating whether or not the
433 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000434
435 Calling the helper function proceeds as follows:
436
437 (1) The helper arguments are evaluated and their value stored in
438 virtual registers.
439 (2) The condition code is evaluated
440 (3) The argument values are copied from the virtual registers to the
441 registers mandated by the ABI.
442 (4) Call the helper function.
443
444 This is not the most efficient way as step 3 generates register-to-register
445 moves. But it is the least fragile way as the only hidden dependency here
446 is that register-to-register moves (step 3) must not clobber the condition
447 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
448 to-register add more such dependencies. Not good. Besides, it's the job
449 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000450*/
451static void
452doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000453 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000454{
florian52af7bc2012-05-12 03:44:49 +0000455 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000456 ULong target;
457 HReg tmpregs[S390_NUM_GPRPARMS];
458 s390_cc_t cc;
459
460 n_args = 0;
461 for (i = 0; args[i]; i++)
462 ++n_args;
463
464 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
465 vpanic("doHelperCall: too many arguments");
466 }
467
florian11b8ee82012-08-06 13:35:33 +0000468 /* All arguments must have Ity_I64. For two reasons:
469 (1) We do not handle floating point arguments.
470 (2) The ABI requires that integer values are sign- or zero-extended
471 to 64 bit.
472 */
473 Int arg_errors = 0;
474 for (i = 0; i < n_args; ++i) {
475 IRType type = typeOfIRExpr(env->type_env, args[i]);
476 if (type != Ity_I64) {
477 ++arg_errors;
478 vex_printf("calling %s: argument #%d has type ", callee->name, i);
479 ppIRType(type);
480 vex_printf("; Ity_I64 is required\n");
481 }
482 }
483
484 if (arg_errors)
485 vpanic("cannot continue due to errors in argument passing");
486
florian52af7bc2012-05-12 03:44:49 +0000487 argreg = 0;
488
489 /* If we need the guest state pointer put it in a temporary arg reg */
490 if (passBBP) {
491 tmpregs[argreg] = newVRegI(env);
492 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
493 s390_hreg_guest_state_pointer()));
494 argreg++;
495 }
496
497 /* Compute the function arguments into a temporary register each */
498 for (i = 0; i < n_args; i++) {
499 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
500 argreg++;
501 }
502
sewardj2019a972011-03-07 16:04:07 +0000503 /* Compute the condition */
504 cc = S390_CC_ALWAYS;
505 if (guard) {
506 if (guard->tag == Iex_Const
507 && guard->Iex.Const.con->tag == Ico_U1
508 && guard->Iex.Const.con->Ico.U1 == True) {
509 /* unconditional -- do nothing */
510 } else {
511 cc = s390_isel_cc(env, guard);
512 }
513 }
514
florian52af7bc2012-05-12 03:44:49 +0000515 /* Move the args to the final register. It is paramount, that the
516 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000517 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000518 HReg finalreg;
519
520 finalreg = make_gpr(s390_gprno_from_arg_index(i));
521 size = sizeofIRType(Ity_I64);
522 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000523 }
524
525 target = Ptr_to_ULong(callee->addr);
526
527 /* Finally, the call itself. */
528 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000529 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000530}
531
532
533/* Given an expression representing a rounding mode using IRRoundingMode
534 encoding convert it to an s390_round_t value. */
535static s390_round_t
536decode_rounding_mode(IRExpr *rounding_expr)
537{
538 if (rounding_expr->tag == Iex_Const &&
539 rounding_expr->Iex.Const.con->tag == Ico_U32) {
540 IRRoundingMode mode = rounding_expr->Iex.Const.con->Ico.U32;
541
542 switch (mode) {
543 case Irrm_NEAREST: return S390_ROUND_NEAREST_EVEN;
544 case Irrm_ZERO: return S390_ROUND_ZERO;
545 case Irrm_PosINF: return S390_ROUND_POSINF;
546 case Irrm_NegINF: return S390_ROUND_NEGINF;
547 }
548 }
549
550 vpanic("decode_rounding_mode");
551}
552
553
554/* CC_S390 holds the condition code in s390 encoding. Convert it to
555 VEX encoding
556
557 s390 VEX b6 b2 b0 cc.1 cc.0
558 0 0x40 EQ 1 0 0 0 0
559 1 0x01 LT 0 0 1 0 1
560 2 0x00 GT 0 0 0 1 0
561 3 0x45 Unordered 1 1 1 1 1
562
563 b0 = cc.0
564 b2 = cc.0 & cc.1
565 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
566
567 VEX = b0 | (b2 << 2) | (b6 << 6);
568*/
569static HReg
570convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390)
571{
572 HReg cc0, cc1, b2, b6, cc_vex;
573
574 cc0 = newVRegI(env);
575 addInstr(env, s390_insn_move(4, cc0, cc_s390));
576 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
577
578 cc1 = newVRegI(env);
579 addInstr(env, s390_insn_move(4, cc1, cc_s390));
580 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
581
582 b2 = newVRegI(env);
583 addInstr(env, s390_insn_move(4, b2, cc0));
584 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
585 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
586
587 b6 = newVRegI(env);
588 addInstr(env, s390_insn_move(4, b6, cc0));
589 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
590 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
591 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
592 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
593
594 cc_vex = newVRegI(env);
595 addInstr(env, s390_insn_move(4, cc_vex, cc0));
596 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
597 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
598
599 return cc_vex;
600}
601
602
603/*---------------------------------------------------------*/
604/*--- ISEL: Integer expressions (128 bit) ---*/
605/*---------------------------------------------------------*/
606static void
607s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
608 IRExpr *expr)
609{
610 IRType ty = typeOfIRExpr(env->type_env, expr);
611
612 vassert(ty == Ity_I128);
613
614 /* No need to consider the following
615 - 128-bit constants (they do not exist in VEX)
616 - 128-bit loads from memory (will not be generated)
617 */
618
619 /* Read 128-bit IRTemp */
620 if (expr->tag == Iex_RdTmp) {
621 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
622 return;
623 }
624
625 if (expr->tag == Iex_Binop) {
626 IRExpr *arg1 = expr->Iex.Binop.arg1;
627 IRExpr *arg2 = expr->Iex.Binop.arg2;
628 Bool is_signed_multiply, is_signed_divide;
629
630 switch (expr->Iex.Binop.op) {
631 case Iop_MullU64:
632 is_signed_multiply = False;
633 goto do_multiply64;
634
635 case Iop_MullS64:
636 is_signed_multiply = True;
637 goto do_multiply64;
638
639 case Iop_DivModU128to64:
640 is_signed_divide = False;
641 goto do_divide64;
642
643 case Iop_DivModS128to64:
644 is_signed_divide = True;
645 goto do_divide64;
646
647 case Iop_64HLto128:
648 *dst_hi = s390_isel_int_expr(env, arg1);
649 *dst_lo = s390_isel_int_expr(env, arg2);
650 return;
651
652 case Iop_DivModS64to64: {
653 HReg r10, r11, h1;
654 s390_opnd_RMI op2;
655
656 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
657 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
658
659 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000660 r10 = make_gpr(10);
661 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000662
663 /* Move 1st operand into r11 and */
664 addInstr(env, s390_insn_move(8, r11, h1));
665
666 /* Divide */
667 addInstr(env, s390_insn_divs(8, r10, r11, op2));
668
669 /* The result is in registers r10 (remainder) and r11 (quotient).
670 Move the result into the reg pair that is being returned such
671 such that the low 64 bits are the quotient and the upper 64 bits
672 are the remainder. (see libvex_ir.h). */
673 *dst_hi = newVRegI(env);
674 *dst_lo = newVRegI(env);
675 addInstr(env, s390_insn_move(8, *dst_hi, r10));
676 addInstr(env, s390_insn_move(8, *dst_lo, r11));
677 return;
678 }
679
680 default:
681 break;
682
683 do_multiply64: {
684 HReg r10, r11, h1;
685 s390_opnd_RMI op2;
686
687 order_commutative_operands(arg1, arg2);
688
689 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
690 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
691
692 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000693 r10 = make_gpr(10);
694 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000695
696 /* Move the first operand to r11 */
697 addInstr(env, s390_insn_move(8, r11, h1));
698
699 /* Multiply */
700 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
701
702 /* The result is in registers r10 and r11. Assign to two virtual regs
703 and return. */
704 *dst_hi = newVRegI(env);
705 *dst_lo = newVRegI(env);
706 addInstr(env, s390_insn_move(8, *dst_hi, r10));
707 addInstr(env, s390_insn_move(8, *dst_lo, r11));
708 return;
709 }
710
711 do_divide64: {
712 HReg r10, r11, hi, lo;
713 s390_opnd_RMI op2;
714
715 s390_isel_int128_expr(&hi, &lo, env, arg1);
716 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
717
718 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000719 r10 = make_gpr(10);
720 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000721
722 /* Move high 64 bits of the 1st operand into r10 and
723 the low 64 bits into r11. */
724 addInstr(env, s390_insn_move(8, r10, hi));
725 addInstr(env, s390_insn_move(8, r11, lo));
726
727 /* Divide */
728 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
729
730 /* The result is in registers r10 (remainder) and r11 (quotient).
731 Move the result into the reg pair that is being returned such
732 such that the low 64 bits are the quotient and the upper 64 bits
733 are the remainder. (see libvex_ir.h). */
734 *dst_hi = newVRegI(env);
735 *dst_lo = newVRegI(env);
736 addInstr(env, s390_insn_move(8, *dst_hi, r10));
737 addInstr(env, s390_insn_move(8, *dst_lo, r11));
738 return;
739 }
740 }
741 }
742
743 vpanic("s390_isel_int128_expr");
744}
745
746
747/* Compute a 128-bit value into two 64-bit registers. These may be either
748 real or virtual regs; in any case they must not be changed by subsequent
749 code emitted by the caller. */
750static void
751s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
752{
753 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
754
755 /* Sanity checks ... */
756 vassert(hregIsVirtual(*dst_hi));
757 vassert(hregIsVirtual(*dst_lo));
758 vassert(hregClass(*dst_hi) == HRcInt64);
759 vassert(hregClass(*dst_lo) == HRcInt64);
760}
761
762
763/*---------------------------------------------------------*/
764/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
765/*---------------------------------------------------------*/
766
767/* Select insns for an integer-typed expression, and add them to the
768 code list. Return a reg holding the result. This reg will be a
769 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
770 want to modify it, ask for a new vreg, copy it in there, and modify
771 the copy. The register allocator will do its best to map both
772 vregs to the same real register, so the copies will often disappear
773 later in the game.
774
775 This should handle expressions of 64, 32, 16 and 8-bit type.
776 All results are returned in a 64bit register.
777 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
778 are arbitrary, so you should mask or sign extend partial values
779 if necessary.
780*/
781
782/* DO NOT CALL THIS DIRECTLY ! */
783static HReg
784s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
785{
786 IRType ty = typeOfIRExpr(env->type_env, expr);
787 UChar size;
788 s390_bfp_unop_t bfpop;
789
790 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
791
792 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
793
794 switch (expr->tag) {
795
796 /* --------- TEMP --------- */
797 case Iex_RdTmp:
798 /* Return the virtual register that holds the temporary. */
799 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
800
801 /* --------- LOAD --------- */
802 case Iex_Load: {
803 HReg dst = newVRegI(env);
804 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
805
806 if (expr->Iex.Load.end != Iend_BE)
807 goto irreducible;
808
809 addInstr(env, s390_insn_load(size, dst, am));
810
811 return dst;
812 }
813
814 /* --------- BINARY OP --------- */
815 case Iex_Binop: {
816 IRExpr *arg1 = expr->Iex.Binop.arg1;
817 IRExpr *arg2 = expr->Iex.Binop.arg2;
818 HReg h1, res;
819 s390_alu_t opkind;
820 s390_opnd_RMI op2, value, opnd;
821 s390_insn *insn;
822 Bool is_commutative, is_signed_multiply, is_signed_divide;
823
824 is_commutative = True;
825
826 switch (expr->Iex.Binop.op) {
827 case Iop_MullU8:
828 case Iop_MullU16:
829 case Iop_MullU32:
830 is_signed_multiply = False;
831 goto do_multiply;
832
833 case Iop_MullS8:
834 case Iop_MullS16:
835 case Iop_MullS32:
836 is_signed_multiply = True;
837 goto do_multiply;
838
839 do_multiply: {
840 HReg r10, r11;
841 UInt arg_size = size / 2;
842
843 order_commutative_operands(arg1, arg2);
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 /* Move the first operand to r11 */
853 addInstr(env, s390_insn_move(arg_size, r11, h1));
854
855 /* Multiply */
856 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
857
858 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
859 value into the destination register. */
860 res = newVRegI(env);
861 addInstr(env, s390_insn_move(arg_size, res, r10));
862 value = s390_opnd_imm(arg_size * 8);
863 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
864 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
865 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
866 opnd = s390_opnd_reg(r11);
867 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
868 return res;
869 }
870
871 case Iop_DivModS64to32:
872 is_signed_divide = True;
873 goto do_divide;
874
875 case Iop_DivModU64to32:
876 is_signed_divide = False;
877 goto do_divide;
878
879 do_divide: {
880 HReg r10, r11;
881
882 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
883 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
884
885 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000886 r10 = make_gpr(10);
887 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000888
889 /* Split the first operand and put the high 32 bits into r10 and
890 the low 32 bits into r11. */
891 addInstr(env, s390_insn_move(8, r10, h1));
892 addInstr(env, s390_insn_move(8, r11, h1));
893 value = s390_opnd_imm(32);
894 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
895
896 /* Divide */
897 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
898
899 /* The result is in registers r10 (remainder) and r11 (quotient).
900 Combine them into a 64-bit value such that the low 32 bits are
901 the quotient and the upper 32 bits are the remainder. (see
902 libvex_ir.h). */
903 res = newVRegI(env);
904 addInstr(env, s390_insn_move(8, res, r10));
905 value = s390_opnd_imm(32);
906 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
907 value = s390_opnd_imm((((ULong)1) << 32) - 1);
908 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
909 opnd = s390_opnd_reg(r11);
910 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
911 return res;
912 }
913
914 case Iop_F32toI32S: bfpop = S390_BFP_F32_TO_I32; goto do_convert;
915 case Iop_F32toI64S: bfpop = S390_BFP_F32_TO_I64; goto do_convert;
916 case Iop_F64toI32S: bfpop = S390_BFP_F64_TO_I32; goto do_convert;
917 case Iop_F64toI64S: bfpop = S390_BFP_F64_TO_I64; goto do_convert;
918 case Iop_F128toI32S: bfpop = S390_BFP_F128_TO_I32; goto do_convert_128;
919 case Iop_F128toI64S: bfpop = S390_BFP_F128_TO_I64; goto do_convert_128;
920
921 do_convert: {
922 s390_round_t rounding_mode;
923
924 res = newVRegI(env);
925 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
926
927 rounding_mode = decode_rounding_mode(arg1);
928 addInstr(env, s390_insn_bfp_unop(size, bfpop, res, h1, rounding_mode));
929 return res;
930 }
931
932 do_convert_128: {
933 s390_round_t rounding_mode;
934 HReg op_hi, op_lo, f13, f15;
935
936 res = newVRegI(env);
937 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
938
939 /* We use non-virtual registers r13 and r15 as pair */
940 f13 = make_fpr(13);
941 f15 = make_fpr(15);
942
943 /* operand --> (f13, f15) */
944 addInstr(env, s390_insn_move(8, f13, op_hi));
945 addInstr(env, s390_insn_move(8, f15, op_lo));
946
947 rounding_mode = decode_rounding_mode(arg1);
948 addInstr(env, s390_insn_bfp128_convert_from(size, bfpop, res, f13, f15,
949 rounding_mode));
950 return res;
951 }
952
953 case Iop_8HLto16:
954 case Iop_16HLto32:
955 case Iop_32HLto64: {
956 HReg h2;
957 UInt arg_size = size / 2;
958
959 res = newVRegI(env);
960 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
961 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
962
963 addInstr(env, s390_insn_move(arg_size, res, h1));
964 value = s390_opnd_imm(arg_size * 8);
965 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
966 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
967 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
968 opnd = s390_opnd_reg(h2);
969 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
970 return res;
971 }
972
973 case Iop_Max32U: {
974 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
975 res = newVRegI(env);
976 h1 = s390_isel_int_expr(env, arg1);
977 op2 = s390_isel_int_expr_RMI(env, arg2);
978
979 addInstr(env, s390_insn_move(size, res, h1));
980 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
981 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
982 return res;
983 }
984
985 case Iop_CmpF32:
986 case Iop_CmpF64: {
987 HReg cc_s390, h2;
988
989 h1 = s390_isel_float_expr(env, arg1);
990 h2 = s390_isel_float_expr(env, arg2);
991 cc_s390 = newVRegI(env);
992
993 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
994
995 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
996
997 return convert_s390_fpcc_to_vex(env, cc_s390);
998 }
999
1000 case Iop_CmpF128: {
1001 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1002
1003 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1004 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1005 cc_s390 = newVRegI(env);
1006
1007 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1008 f12 = make_fpr(12);
1009 f13 = make_fpr(13);
1010 f14 = make_fpr(14);
1011 f15 = make_fpr(15);
1012
1013 /* 1st operand --> (f12, f14) */
1014 addInstr(env, s390_insn_move(8, f12, op1_hi));
1015 addInstr(env, s390_insn_move(8, f14, op1_lo));
1016
1017 /* 2nd operand --> (f13, f15) */
1018 addInstr(env, s390_insn_move(8, f13, op2_hi));
1019 addInstr(env, s390_insn_move(8, f15, op2_lo));
1020
1021 res = newVRegI(env);
1022 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1023
1024 return convert_s390_fpcc_to_vex(env, cc_s390);
1025 }
1026
1027 case Iop_Add8:
1028 case Iop_Add16:
1029 case Iop_Add32:
1030 case Iop_Add64:
1031 opkind = S390_ALU_ADD;
1032 break;
1033
1034 case Iop_Sub8:
1035 case Iop_Sub16:
1036 case Iop_Sub32:
1037 case Iop_Sub64:
1038 opkind = S390_ALU_SUB;
1039 is_commutative = False;
1040 break;
1041
1042 case Iop_And8:
1043 case Iop_And16:
1044 case Iop_And32:
1045 case Iop_And64:
1046 opkind = S390_ALU_AND;
1047 break;
1048
1049 case Iop_Or8:
1050 case Iop_Or16:
1051 case Iop_Or32:
1052 case Iop_Or64:
1053 opkind = S390_ALU_OR;
1054 break;
1055
1056 case Iop_Xor8:
1057 case Iop_Xor16:
1058 case Iop_Xor32:
1059 case Iop_Xor64:
1060 opkind = S390_ALU_XOR;
1061 break;
1062
1063 case Iop_Shl8:
1064 case Iop_Shl16:
1065 case Iop_Shl32:
1066 case Iop_Shl64:
1067 opkind = S390_ALU_LSH;
1068 is_commutative = False;
1069 break;
1070
1071 case Iop_Shr8:
1072 case Iop_Shr16:
1073 case Iop_Shr32:
1074 case Iop_Shr64:
1075 opkind = S390_ALU_RSH;
1076 is_commutative = False;
1077 break;
1078
1079 case Iop_Sar8:
1080 case Iop_Sar16:
1081 case Iop_Sar32:
1082 case Iop_Sar64:
1083 opkind = S390_ALU_RSHA;
1084 is_commutative = False;
1085 break;
1086
1087 default:
1088 goto irreducible;
1089 }
1090
1091 /* Pattern match: 0 - arg1 --> -arg1 */
1092 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1093 res = newVRegI(env);
1094 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1095 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1096 addInstr(env, insn);
1097
1098 return res;
1099 }
1100
1101 if (is_commutative) {
1102 order_commutative_operands(arg1, arg2);
1103 }
1104
1105 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1106 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1107 res = newVRegI(env);
1108 addInstr(env, s390_insn_move(size, res, h1));
1109 insn = s390_insn_alu(size, opkind, res, op2);
1110
1111 addInstr(env, insn);
1112
1113 return res;
1114 }
1115
1116 /* --------- UNARY OP --------- */
1117 case Iex_Unop: {
1118 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1119 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1120 s390_opnd_RMI opnd;
1121 s390_insn *insn;
1122 IRExpr *arg;
1123 HReg dst, h1;
1124 IROp unop, binop;
1125
1126 arg = expr->Iex.Unop.arg;
1127
1128 /* Special cases are handled here */
1129
1130 /* 32-bit multiply with 32-bit result or
1131 64-bit multiply with 64-bit result */
1132 unop = expr->Iex.Unop.op;
1133 binop = arg->Iex.Binop.op;
1134
1135 if ((arg->tag == Iex_Binop &&
1136 ((unop == Iop_64to32 &&
1137 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1138 (unop == Iop_128to64 &&
1139 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1140 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1141 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1142 dst = newVRegI(env); /* Result goes into a new register */
1143 addInstr(env, s390_insn_move(size, dst, h1));
1144 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1145
1146 return dst;
1147 }
1148
florian4d71a082011-12-18 00:08:17 +00001149 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001150 dst = newVRegI(env);
1151 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1152 addInstr(env, s390_insn_move(size, dst, h1));
1153
1154 return dst;
1155 }
1156
1157 /* Expressions whose argument is 1-bit wide */
1158 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1159 s390_cc_t cond = s390_isel_cc(env, arg);
1160 dst = newVRegI(env); /* Result goes into a new register */
1161 addInstr(env, s390_insn_cc2bool(dst, cond));
1162
1163 switch (unop) {
1164 case Iop_1Uto8:
1165 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001166 /* Zero extend */
1167 mask.variant.imm = 1;
1168 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1169 break;
1170
sewardj2019a972011-03-07 16:04:07 +00001171 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001172 /* Zero extend */
1173 mask.variant.imm = 1;
1174 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001175 break;
1176
1177 case Iop_1Sto8:
1178 case Iop_1Sto16:
1179 case Iop_1Sto32:
1180 shift.variant.imm = 31;
1181 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1182 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1183 break;
1184
1185 case Iop_1Sto64:
1186 shift.variant.imm = 63;
1187 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1188 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1189 break;
1190
1191 default:
1192 goto irreducible;
1193 }
1194
1195 return dst;
1196 }
1197
1198 /* Regular processing */
1199
1200 if (unop == Iop_128to64) {
1201 HReg dst_hi, dst_lo;
1202
1203 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1204 return dst_lo;
1205 }
1206
1207 if (unop == Iop_128HIto64) {
1208 HReg dst_hi, dst_lo;
1209
1210 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1211 return dst_hi;
1212 }
1213
1214 dst = newVRegI(env); /* Result goes into a new register */
1215 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1216
1217 switch (unop) {
1218 case Iop_8Uto16:
1219 case Iop_8Uto32:
1220 case Iop_8Uto64:
1221 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1222 break;
1223
1224 case Iop_16Uto32:
1225 case Iop_16Uto64:
1226 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1227 break;
1228
1229 case Iop_32Uto64:
1230 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1231 break;
1232
1233 case Iop_8Sto16:
1234 case Iop_8Sto32:
1235 case Iop_8Sto64:
1236 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1237 break;
1238
1239 case Iop_16Sto32:
1240 case Iop_16Sto64:
1241 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1242 break;
1243
1244 case Iop_32Sto64:
1245 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1246 break;
1247
1248 case Iop_64to8:
1249 case Iop_64to16:
1250 case Iop_64to32:
1251 case Iop_32to8:
1252 case Iop_32to16:
1253 case Iop_16to8:
1254 /* Down-casts are no-ops. Upstream operations will only look at
1255 the bytes that make up the result of the down-cast. So there
1256 is no point setting the other bytes to 0. */
1257 insn = s390_opnd_copy(8, dst, opnd);
1258 break;
1259
1260 case Iop_64HIto32:
1261 addInstr(env, s390_opnd_copy(8, dst, opnd));
1262 shift.variant.imm = 32;
1263 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1264 break;
1265
1266 case Iop_32HIto16:
1267 addInstr(env, s390_opnd_copy(4, dst, opnd));
1268 shift.variant.imm = 16;
1269 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1270 break;
1271
1272 case Iop_16HIto8:
1273 addInstr(env, s390_opnd_copy(2, dst, opnd));
1274 shift.variant.imm = 8;
1275 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1276 break;
1277
1278 case Iop_Not8:
1279 case Iop_Not16:
1280 case Iop_Not32:
1281 case Iop_Not64:
1282 /* XOR with ffff... */
1283 mask.variant.imm = ~(ULong)0;
1284 addInstr(env, s390_opnd_copy(size, dst, opnd));
1285 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1286 break;
1287
1288 case Iop_Left8:
1289 case Iop_Left16:
1290 case Iop_Left32:
1291 case Iop_Left64:
1292 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1293 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1294 break;
1295
1296 case Iop_CmpwNEZ32:
1297 case Iop_CmpwNEZ64: {
1298 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1299 or -X will have a 1 in the MSB. */
1300 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1301 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1302 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1303 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1304 return dst;
1305 }
1306
1307 case Iop_Clz64: {
1308 HReg r10, r11;
1309
sewardj611b06e2011-03-24 08:57:29 +00001310 /* This will be implemented using FLOGR, if possible. So we need to
1311 set aside a pair of non-virtual registers. The result (number of
1312 left-most zero bits) will be in r10. The value in r11 is unspecified
1313 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001314 r10 = make_gpr(10);
1315 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001316
sewardj611b06e2011-03-24 08:57:29 +00001317 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001318 addInstr(env, s390_insn_move(8, dst, r10));
1319 return dst;
1320 }
1321
1322 default:
1323 goto irreducible;
1324 }
1325
1326 addInstr(env, insn);
1327
1328 return dst;
1329 }
1330
1331 /* --------- GET --------- */
1332 case Iex_Get: {
1333 HReg dst = newVRegI(env);
1334 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1335
1336 /* We never load more than 8 bytes from the guest state, because the
1337 floating point register pair is not contiguous. */
1338 vassert(size <= 8);
1339
1340 addInstr(env, s390_insn_load(size, dst, am));
1341
1342 return dst;
1343 }
1344
1345 case Iex_GetI:
1346 /* not needed */
1347 break;
1348
1349 /* --------- CCALL --------- */
1350 case Iex_CCall: {
1351 HReg dst = newVRegI(env);
1352
1353 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001354 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001355 return dst;
1356 }
1357
1358 /* --------- LITERAL --------- */
1359
1360 /* Load a literal into a register. Create a "load immediate"
1361 v-insn and return the register. */
1362 case Iex_Const: {
1363 ULong value;
1364 HReg dst = newVRegI(env);
1365 const IRConst *con = expr->Iex.Const.con;
1366
1367 /* Bitwise copy of the value. No sign/zero-extension */
1368 switch (con->tag) {
1369 case Ico_U64: value = con->Ico.U64; break;
1370 case Ico_U32: value = con->Ico.U32; break;
1371 case Ico_U16: value = con->Ico.U16; break;
1372 case Ico_U8: value = con->Ico.U8; break;
1373 default: vpanic("s390_isel_int_expr: invalid constant");
1374 }
1375
1376 addInstr(env, s390_insn_load_immediate(size, dst, value));
1377
1378 return dst;
1379 }
1380
1381 /* --------- MULTIPLEX --------- */
1382 case Iex_Mux0X: {
1383 IRExpr *cond_expr;
1384 HReg dst, tmp, rX;
1385 s390_opnd_RMI cond, r0, zero;
1386
1387 cond_expr = expr->Iex.Mux0X.cond;
1388
1389 dst = newVRegI(env);
1390 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1391 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1392 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1393
1394 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1395 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1396
1397 addInstr(env, s390_insn_move(size, dst, rX));
1398 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1399 return dst;
1400 }
1401
1402 /* Assume the condition is true and move rX to the destination reg. */
1403 addInstr(env, s390_insn_move(size, dst, rX));
1404
1405 /* Compute the condition ... */
1406 cond = s390_isel_int_expr_RMI(env, cond_expr);
1407
1408 /* tmp = cond & 0xFF */
1409 tmp = newVRegI(env);
1410 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1411 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1412
1413 /* ... and compare it with zero */
1414 zero = s390_opnd_imm(0);
1415 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1416
1417 /* ... and if it compared equal move r0 to the destination reg. */
1418 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1419 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1420
1421 return dst;
1422 }
1423
1424 default:
1425 break;
1426 }
1427
1428 /* We get here if no pattern matched. */
1429 irreducible:
1430 ppIRExpr(expr);
1431 vpanic("s390_isel_int_expr: cannot reduce tree");
1432}
1433
1434
1435static HReg
1436s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1437{
1438 HReg dst = s390_isel_int_expr_wrk(env, expr);
1439
1440 /* Sanity checks ... */
1441 vassert(hregClass(dst) == HRcInt64);
1442 vassert(hregIsVirtual(dst));
1443
1444 return dst;
1445}
1446
1447
1448static s390_opnd_RMI
1449s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1450{
1451 IRType ty = typeOfIRExpr(env->type_env, expr);
1452 s390_opnd_RMI dst;
1453
1454 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1455 ty == Ity_I64);
1456
1457 if (expr->tag == Iex_Load) {
1458 dst.tag = S390_OPND_AMODE;
1459 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1460 } else if (expr->tag == Iex_Get) {
1461 dst.tag = S390_OPND_AMODE;
1462 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1463 } else if (expr->tag == Iex_Const) {
1464 ULong value;
1465
1466 /* The bit pattern for the value will be stored as is in the least
1467 significant bits of VALUE. */
1468 switch (expr->Iex.Const.con->tag) {
1469 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1470 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1471 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1472 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1473 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1474 default:
1475 vpanic("s390_isel_int_expr_RMI");
1476 }
1477
1478 dst.tag = S390_OPND_IMMEDIATE;
1479 dst.variant.imm = value;
1480 } else {
1481 dst.tag = S390_OPND_REG;
1482 dst.variant.reg = s390_isel_int_expr(env, expr);
1483 }
1484
1485 return dst;
1486}
1487
1488
1489/*---------------------------------------------------------*/
1490/*--- ISEL: Floating point expressions (128 bit) ---*/
1491/*---------------------------------------------------------*/
1492static void
1493s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1494 IRExpr *expr)
1495{
1496 IRType ty = typeOfIRExpr(env->type_env, expr);
1497
1498 vassert(ty == Ity_F128);
1499
1500 /* Read 128-bit IRTemp */
1501 if (expr->tag == Iex_RdTmp) {
1502 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1503 return;
1504 }
1505
1506 switch (expr->tag) {
1507 case Iex_RdTmp:
1508 /* Return the virtual registers that hold the temporary. */
1509 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1510 return;
1511
1512 /* --------- LOAD --------- */
1513 case Iex_Load: {
1514 IRExpr *addr_hi, *addr_lo;
1515 s390_amode *am_hi, *am_lo;
1516
1517 if (expr->Iex.Load.end != Iend_BE)
1518 goto irreducible;
1519
1520 addr_hi = expr->Iex.Load.addr;
1521 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1522
1523 am_hi = s390_isel_amode(env, addr_hi);
1524 am_lo = s390_isel_amode(env, addr_lo);
1525
1526 *dst_hi = newVRegF(env);
1527 *dst_lo = newVRegF(env);
1528 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1529 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1530 return;
1531 }
1532
1533
1534 /* --------- GET --------- */
1535 case Iex_Get:
1536 /* This is not supported because loading 128-bit from the guest
1537 state is almost certainly wrong. Use get_fpr_pair instead. */
1538 vpanic("Iex_Get with F128 data");
1539
1540 /* --------- 4-ary OP --------- */
1541 case Iex_Qop:
1542 vpanic("Iex_Qop with F128 data");
1543
1544 /* --------- TERNARY OP --------- */
1545 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001546 IRTriop *triop = expr->Iex.Triop.details;
1547 IROp op = triop->op;
1548 IRExpr *left = triop->arg2;
1549 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001550 s390_bfp_binop_t bfpop;
1551 s390_round_t rounding_mode;
1552 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1553
1554 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1555 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1556
1557 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1558 f12 = make_fpr(12);
1559 f13 = make_fpr(13);
1560 f14 = make_fpr(14);
1561 f15 = make_fpr(15);
1562
1563 /* 1st operand --> (f12, f14) */
1564 addInstr(env, s390_insn_move(8, f12, op1_hi));
1565 addInstr(env, s390_insn_move(8, f14, op1_lo));
1566
1567 /* 2nd operand --> (f13, f15) */
1568 addInstr(env, s390_insn_move(8, f13, op2_hi));
1569 addInstr(env, s390_insn_move(8, f15, op2_lo));
1570
1571 switch (op) {
1572 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1573 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1574 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1575 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1576 default:
1577 goto irreducible;
1578 }
1579
florian420bfa92012-06-02 20:29:22 +00001580 rounding_mode = decode_rounding_mode(triop->arg1);
sewardj2019a972011-03-07 16:04:07 +00001581 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1582 f15, rounding_mode));
1583
1584 /* Move result to virtual destination register */
1585 *dst_hi = newVRegF(env);
1586 *dst_lo = newVRegF(env);
1587 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1588 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1589
1590 return;
1591 }
1592
1593 /* --------- BINARY OP --------- */
1594 case Iex_Binop: {
1595 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardja970c402011-04-28 18:38:42 +00001596 s390_bfp_unop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001597 s390_round_t rounding_mode;
1598
1599 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1600 f12 = make_fpr(12);
1601 f13 = make_fpr(13);
1602 f14 = make_fpr(14);
1603 f15 = make_fpr(15);
1604
1605 switch (expr->Iex.Binop.op) {
1606 case Iop_SqrtF128:
1607 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1608
1609 /* operand --> (f13, f15) */
1610 addInstr(env, s390_insn_move(8, f13, op_hi));
1611 addInstr(env, s390_insn_move(8, f15, op_lo));
1612
1613 bfpop = S390_BFP_SQRT;
1614 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1615
1616 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1617 rounding_mode));
1618
1619 /* Move result to virtual destination registers */
1620 *dst_hi = newVRegF(env);
1621 *dst_lo = newVRegF(env);
1622 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1623 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1624 return;
1625
1626 case Iop_F64HLtoF128:
1627 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1628 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1629 return;
1630
1631 default:
1632 goto irreducible;
1633 }
1634 }
1635
1636 /* --------- UNARY OP --------- */
1637 case Iex_Unop: {
1638 IRExpr *left = expr->Iex.Binop.arg1;
1639 s390_bfp_unop_t bfpop;
1640 s390_round_t rounding_mode;
1641 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1642
1643 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1644 f12 = make_fpr(12);
1645 f13 = make_fpr(13);
1646 f14 = make_fpr(14);
1647 f15 = make_fpr(15);
1648
1649 switch (expr->Iex.Binop.op) {
1650 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1651 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1652 case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int;
1653 case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int;
1654 case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float;
1655 case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float;
1656 default:
1657 goto irreducible;
1658 }
1659
1660 float128_opnd:
1661 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1662
1663 /* operand --> (f13, f15) */
1664 addInstr(env, s390_insn_move(8, f13, op_hi));
1665 addInstr(env, s390_insn_move(8, f15, op_lo));
1666
1667 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1668 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1669 rounding_mode));
1670 goto move_dst;
1671
1672 convert_float:
1673 op = s390_isel_float_expr(env, left);
1674 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1675 op));
1676 goto move_dst;
1677
1678 convert_int:
1679 op = s390_isel_int_expr(env, left);
1680 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1681 op));
1682 goto move_dst;
1683
1684 move_dst:
1685 /* Move result to virtual destination registers */
1686 *dst_hi = newVRegF(env);
1687 *dst_lo = newVRegF(env);
1688 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1689 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1690 return;
1691 }
1692
1693 default:
1694 goto irreducible;
1695 }
1696
1697 /* We get here if no pattern matched. */
1698 irreducible:
1699 ppIRExpr(expr);
1700 vpanic("s390_isel_int_expr: cannot reduce tree");
1701}
1702
1703/* Compute a 128-bit value into two 64-bit registers. These may be either
1704 real or virtual regs; in any case they must not be changed by subsequent
1705 code emitted by the caller. */
1706static void
1707s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1708{
1709 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1710
1711 /* Sanity checks ... */
1712 vassert(hregIsVirtual(*dst_hi));
1713 vassert(hregIsVirtual(*dst_lo));
1714 vassert(hregClass(*dst_hi) == HRcFlt64);
1715 vassert(hregClass(*dst_lo) == HRcFlt64);
1716}
1717
1718
1719/*---------------------------------------------------------*/
1720/*--- ISEL: Floating point expressions (64 bit) ---*/
1721/*---------------------------------------------------------*/
1722
1723static HReg
1724s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1725{
1726 IRType ty = typeOfIRExpr(env->type_env, expr);
1727 UChar size;
1728
1729 vassert(ty == Ity_F32 || ty == Ity_F64);
1730
1731 size = sizeofIRType(ty);
1732
1733 switch (expr->tag) {
1734 case Iex_RdTmp:
1735 /* Return the virtual register that holds the temporary. */
1736 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1737
1738 /* --------- LOAD --------- */
1739 case Iex_Load: {
1740 HReg dst = newVRegF(env);
1741 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1742
1743 if (expr->Iex.Load.end != Iend_BE)
1744 goto irreducible;
1745
1746 addInstr(env, s390_insn_load(size, dst, am));
1747
1748 return dst;
1749 }
1750
1751 /* --------- GET --------- */
1752 case Iex_Get: {
1753 HReg dst = newVRegF(env);
1754 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1755
1756 addInstr(env, s390_insn_load(size, dst, am));
1757
1758 return dst;
1759 }
1760
1761 /* --------- LITERAL --------- */
1762
1763 /* Load a literal into a register. Create a "load immediate"
1764 v-insn and return the register. */
1765 case Iex_Const: {
1766 ULong value;
1767 HReg dst = newVRegF(env);
1768 const IRConst *con = expr->Iex.Const.con;
1769
1770 /* Bitwise copy of the value. No sign/zero-extension */
1771 switch (con->tag) {
1772 case Ico_F32i: value = con->Ico.F32i; break;
1773 case Ico_F64i: value = con->Ico.F64i; break;
1774 default: vpanic("s390_isel_float_expr: invalid constant");
1775 }
1776
1777 if (value != 0) vpanic("cannot load immediate floating point constant");
1778
1779 addInstr(env, s390_insn_load_immediate(size, dst, value));
1780
1781 return dst;
1782 }
1783
1784 /* --------- 4-ary OP --------- */
1785 case Iex_Qop: {
1786 HReg op1, op2, op3, dst;
1787 s390_bfp_triop_t bfpop;
1788 s390_round_t rounding_mode;
1789
florian96d7cc32012-06-01 20:41:24 +00001790 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
1791 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
1792 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00001793 dst = newVRegF(env);
1794 addInstr(env, s390_insn_move(size, dst, op1));
1795
florian96d7cc32012-06-01 20:41:24 +00001796 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00001797 case Iop_MAddF32:
1798 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1799 case Iop_MSubF32:
1800 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1801
1802 default:
1803 goto irreducible;
1804 }
1805
florian96d7cc32012-06-01 20:41:24 +00001806 rounding_mode = decode_rounding_mode(expr->Iex.Qop.details->arg1);
sewardj2019a972011-03-07 16:04:07 +00001807 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1808 rounding_mode));
1809 return dst;
1810 }
1811
1812 /* --------- TERNARY OP --------- */
1813 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001814 IRTriop *triop = expr->Iex.Triop.details;
1815 IROp op = triop->op;
1816 IRExpr *left = triop->arg2;
1817 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001818 s390_bfp_binop_t bfpop;
1819 s390_round_t rounding_mode;
1820 HReg h1, op2, dst;
1821
1822 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1823 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1824 dst = newVRegF(env);
1825 addInstr(env, s390_insn_move(size, dst, h1));
1826 switch (op) {
1827 case Iop_AddF32:
1828 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1829 case Iop_SubF32:
1830 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1831 case Iop_MulF32:
1832 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1833 case Iop_DivF32:
1834 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1835
1836 default:
1837 goto irreducible;
1838 }
1839
florian420bfa92012-06-02 20:29:22 +00001840 rounding_mode = decode_rounding_mode(triop->arg1);
sewardj2019a972011-03-07 16:04:07 +00001841 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1842 return dst;
1843 }
1844
1845 /* --------- BINARY OP --------- */
1846 case Iex_Binop: {
1847 IROp op = expr->Iex.Binop.op;
1848 IRExpr *left = expr->Iex.Binop.arg2;
1849 HReg h1, dst;
1850 s390_bfp_unop_t bfpop;
1851 s390_round_t rounding_mode;
1852 Int integer_operand;
1853
1854 integer_operand = 1;
1855
1856 switch (op) {
1857 case Iop_SqrtF32:
1858 case Iop_SqrtF64:
1859 bfpop = S390_BFP_SQRT;
1860 integer_operand = 0;
1861 break;
1862
1863 case Iop_F64toF32:
1864 bfpop = S390_BFP_F64_TO_F32;
1865 integer_operand = 0;
1866 break;
1867
1868 case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break;
1869 case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break;
1870 case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break;
1871 default:
1872 goto irreducible;
1873
1874 case Iop_F128toF64:
1875 case Iop_F128toF32: {
1876 HReg op_hi, op_lo, f12, f13, f14, f15;
1877
1878 bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1879 : S390_BFP_F128_TO_F64;
1880
1881 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1882
1883 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1884
1885 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1886 f12 = make_fpr(12);
1887 f13 = make_fpr(13);
1888 f14 = make_fpr(14);
1889 f15 = make_fpr(15);
1890
1891 /* operand --> (f13, f15) */
1892 addInstr(env, s390_insn_move(8, f13, op_hi));
1893 addInstr(env, s390_insn_move(8, f15, op_lo));
1894
1895 dst = newVRegF(env);
1896 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1897 rounding_mode));
1898
1899 /* Move result to virtual destination registers */
1900 addInstr(env, s390_insn_move(8, dst, f12));
1901 return dst;
1902 }
1903 }
1904
1905 /* Process operand */
1906 if (integer_operand) {
1907 h1 = s390_isel_int_expr(env, left);
1908 } else {
1909 h1 = s390_isel_float_expr(env, left);
1910 }
1911
1912 dst = newVRegF(env);
1913 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1914 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1915 return dst;
1916 }
1917
1918 /* --------- UNARY OP --------- */
1919 case Iex_Unop: {
1920 IROp op = expr->Iex.Unop.op;
1921 IRExpr *left = expr->Iex.Unop.arg;
1922 s390_bfp_unop_t bfpop;
1923 s390_round_t rounding_mode;
1924 HReg h1, dst;
1925
1926 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1927 HReg dst_hi, dst_lo;
1928
1929 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1930 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1931 }
1932
florian4d71a082011-12-18 00:08:17 +00001933 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00001934 dst = newVRegF(env);
1935 h1 = s390_isel_int_expr(env, left); /* Process the operand */
1936 addInstr(env, s390_insn_move(size, dst, h1));
1937
1938 return dst;
1939 }
1940
1941 switch (op) {
1942 case Iop_NegF32:
1943 case Iop_NegF64:
1944 if (left->tag == Iex_Unop &&
1945 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1946 bfpop = S390_BFP_NABS;
1947 else
1948 bfpop = S390_BFP_NEG;
1949 break;
1950
1951 case Iop_AbsF32:
1952 case Iop_AbsF64: bfpop = S390_BFP_ABS; break;
1953 case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break;
1954 case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break;
1955 default:
1956 goto irreducible;
1957 }
1958
1959 /* Process operand */
1960 if (op == Iop_I32StoF64)
1961 h1 = s390_isel_int_expr(env, left);
1962 else if (bfpop == S390_BFP_NABS)
1963 h1 = s390_isel_float_expr(env, left->Iex.Unop.arg);
1964 else
1965 h1 = s390_isel_float_expr(env, left);
1966
1967 dst = newVRegF(env);
1968 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1969 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1970 return dst;
1971 }
1972
1973 default:
1974 goto irreducible;
1975 }
1976
1977 /* We get here if no pattern matched. */
1978 irreducible:
1979 ppIRExpr(expr);
1980 vpanic("s390_isel_float_expr: cannot reduce tree");
1981}
1982
1983
1984static HReg
1985s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
1986{
1987 HReg dst = s390_isel_float_expr_wrk(env, expr);
1988
1989 /* Sanity checks ... */
1990 vassert(hregClass(dst) == HRcFlt64);
1991 vassert(hregIsVirtual(dst));
1992
1993 return dst;
1994}
1995
1996
1997/*---------------------------------------------------------*/
1998/*--- ISEL: Condition Code ---*/
1999/*---------------------------------------------------------*/
2000
2001/* This function handles all operators that produce a 1-bit result */
2002static s390_cc_t
2003s390_isel_cc(ISelEnv *env, IRExpr *cond)
2004{
2005 UChar size;
2006
2007 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2008
2009 /* Constant: either 1 or 0 */
2010 if (cond->tag == Iex_Const) {
2011 vassert(cond->Iex.Const.con->tag == Ico_U1);
2012 vassert(cond->Iex.Const.con->Ico.U1 == True
2013 || cond->Iex.Const.con->Ico.U1 == False);
2014
2015 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2016 }
2017
2018 /* Variable: values are 1 or 0 */
2019 if (cond->tag == Iex_RdTmp) {
2020 IRTemp tmp = cond->Iex.RdTmp.tmp;
2021 HReg reg = lookupIRTemp(env, tmp);
2022
2023 /* Load-and-test does not modify REG; so this is OK. */
2024 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2025 size = 4;
2026 else
2027 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2028 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2029 return S390_CC_NE;
2030 }
2031
2032 /* Unary operators */
2033 if (cond->tag == Iex_Unop) {
2034 IRExpr *arg = cond->Iex.Unop.arg;
2035
2036 switch (cond->Iex.Unop.op) {
2037 case Iop_Not1: /* Not1(cond) */
2038 /* Generate code for EXPR, and negate the test condition */
2039 return s390_cc_invert(s390_isel_cc(env, arg));
2040
2041 /* Iop_32/64to1 select the LSB from their operand */
2042 case Iop_32to1:
2043 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002044 HReg dst = newVRegI(env);
2045 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002046
2047 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2048
florianf366a802012-08-03 00:42:18 +00002049 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002050 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2051 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2052 return S390_CC_NE;
2053 }
2054
2055 case Iop_CmpNEZ8:
2056 case Iop_CmpNEZ16: {
2057 s390_opnd_RMI src;
2058 s390_unop_t op;
2059 HReg dst;
2060
2061 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2062 : S390_ZERO_EXTEND_16;
2063 dst = newVRegI(env);
2064 src = s390_isel_int_expr_RMI(env, arg);
2065 addInstr(env, s390_insn_unop(4, op, dst, src));
2066 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2067 return S390_CC_NE;
2068 }
2069
2070 case Iop_CmpNEZ32:
2071 case Iop_CmpNEZ64: {
2072 s390_opnd_RMI src;
2073
2074 src = s390_isel_int_expr_RMI(env, arg);
2075 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2076 addInstr(env, s390_insn_test(size, src));
2077 return S390_CC_NE;
2078 }
2079
2080 default:
2081 goto fail;
2082 }
2083 }
2084
2085 /* Binary operators */
2086 if (cond->tag == Iex_Binop) {
2087 IRExpr *arg1 = cond->Iex.Binop.arg1;
2088 IRExpr *arg2 = cond->Iex.Binop.arg2;
2089 HReg reg1, reg2;
2090
2091 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2092
2093 switch (cond->Iex.Binop.op) {
2094 s390_unop_t op;
2095 s390_cc_t result;
2096
2097 case Iop_CmpEQ8:
2098 case Iop_CasCmpEQ8:
2099 op = S390_ZERO_EXTEND_8;
2100 result = S390_CC_E;
2101 goto do_compare_ze;
2102
2103 case Iop_CmpNE8:
2104 case Iop_CasCmpNE8:
2105 op = S390_ZERO_EXTEND_8;
2106 result = S390_CC_NE;
2107 goto do_compare_ze;
2108
2109 case Iop_CmpEQ16:
2110 case Iop_CasCmpEQ16:
2111 op = S390_ZERO_EXTEND_16;
2112 result = S390_CC_E;
2113 goto do_compare_ze;
2114
2115 case Iop_CmpNE16:
2116 case Iop_CasCmpNE16:
2117 op = S390_ZERO_EXTEND_16;
2118 result = S390_CC_NE;
2119 goto do_compare_ze;
2120
2121 do_compare_ze: {
2122 s390_opnd_RMI op1, op2;
2123
2124 op1 = s390_isel_int_expr_RMI(env, arg1);
2125 reg1 = newVRegI(env);
2126 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2127
2128 op2 = s390_isel_int_expr_RMI(env, arg2);
2129 reg2 = newVRegI(env);
2130 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2131
2132 op2 = s390_opnd_reg(reg2);
2133 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2134
2135 return result;
2136 }
2137
2138 case Iop_CmpEQ32:
2139 case Iop_CmpEQ64:
2140 case Iop_CasCmpEQ32:
2141 case Iop_CasCmpEQ64:
2142 result = S390_CC_E;
2143 goto do_compare;
2144
2145 case Iop_CmpNE32:
2146 case Iop_CmpNE64:
2147 case Iop_CasCmpNE32:
2148 case Iop_CasCmpNE64:
2149 result = S390_CC_NE;
2150 goto do_compare;
2151
2152 do_compare: {
2153 HReg op1;
2154 s390_opnd_RMI op2;
2155
2156 order_commutative_operands(arg1, arg2);
2157
2158 op1 = s390_isel_int_expr(env, arg1);
2159 op2 = s390_isel_int_expr_RMI(env, arg2);
2160
2161 addInstr(env, s390_insn_compare(size, op1, op2, False));
2162
2163 return result;
2164 }
2165
2166 case Iop_CmpLT32S:
2167 case Iop_CmpLE32S:
2168 case Iop_CmpLT64S:
2169 case Iop_CmpLE64S: {
2170 HReg op1;
2171 s390_opnd_RMI op2;
2172
2173 op1 = s390_isel_int_expr(env, arg1);
2174 op2 = s390_isel_int_expr_RMI(env, arg2);
2175
2176 addInstr(env, s390_insn_compare(size, op1, op2, True));
2177
2178 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2179 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2180 }
2181
2182 case Iop_CmpLT32U:
2183 case Iop_CmpLE32U:
2184 case Iop_CmpLT64U:
2185 case Iop_CmpLE64U: {
2186 HReg op1;
2187 s390_opnd_RMI op2;
2188
2189 op1 = s390_isel_int_expr(env, arg1);
2190 op2 = s390_isel_int_expr_RMI(env, arg2);
2191
2192 addInstr(env, s390_insn_compare(size, op1, op2, False));
2193
2194 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2195 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2196 }
2197
2198 default:
2199 goto fail;
2200 }
2201 }
2202
2203 fail:
2204 ppIRExpr(cond);
2205 vpanic("s390_isel_cc: unexpected operator");
2206}
2207
2208
2209/*---------------------------------------------------------*/
2210/*--- ISEL: Statements ---*/
2211/*---------------------------------------------------------*/
2212
2213static void
2214s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2215{
2216 if (vex_traceflags & VEX_TRACE_VCODE) {
2217 vex_printf("\n -- ");
2218 ppIRStmt(stmt);
2219 vex_printf("\n");
2220 }
2221
2222 switch (stmt->tag) {
2223
2224 /* --------- STORE --------- */
2225 case Ist_Store: {
2226 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2227 s390_amode *am;
2228 HReg src;
2229
2230 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2231
2232 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2233
2234 switch (tyd) {
2235 case Ity_I8:
2236 case Ity_I16:
2237 case Ity_I32:
2238 case Ity_I64:
2239 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2240 break;
2241
2242 case Ity_F32:
2243 case Ity_F64:
2244 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2245 break;
2246
2247 case Ity_F128:
2248 /* Cannot occur. No such instruction */
2249 vpanic("Ist_Store with F128 data");
2250
2251 default:
2252 goto stmt_fail;
2253 }
2254
2255 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2256 return;
2257 }
2258
2259 /* --------- PUT --------- */
2260 case Ist_Put: {
2261 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2262 HReg src;
2263 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002264 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002265
florianad43b3a2012-02-20 15:01:14 +00002266 /* Detect updates to certain guest registers. We track the contents
2267 of those registers as long as they contain constants. If the new
2268 constant is either zero or in the 8-bit neighbourhood of the
2269 current value we can use a memory-to-memory insn to do the update. */
2270
2271 Int offset = stmt->Ist.Put.offset;
2272
2273 /* Check necessary conditions:
2274 (1) must be one of the registers we care about
2275 (2) assigned value must be a constant */
2276 Int guest_reg = get_guest_reg(offset);
2277
2278 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2279
2280 if (guest_reg == GUEST_IA) {
2281 /* If this is the first assignment to the IA reg, don't special case
2282 it. We need to do a full 8-byte assignment here. The reason is
2283 that in case of a redirected translation the guest IA does not
2284 contain the redirected-to address. Instead it contains the
2285 redirected-from address and those can be far apart. So in order to
2286 do incremnetal updates if the IA in the future we need to get the
2287 initial address of the super block correct. */
2288 if (env->first_IA_assignment) {
2289 env->first_IA_assignment = False;
2290 goto not_special;
2291 }
2292 }
2293
2294 if (stmt->Ist.Put.data->tag != Iex_Const) {
2295 /* Invalidate guest register contents */
2296 env->old_value_valid[guest_reg] = False;
2297 goto not_special;
2298 }
2299
2300 /* OK. Necessary conditions are satisfied. */
2301
2302 /* Get the old value and update it */
2303 vassert(tyd == Ity_I64);
2304
2305 old_value = env->old_value[guest_reg];
2306 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2307 env->old_value[guest_reg] = new_value;
2308
2309 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2310 env->old_value_valid[guest_reg] = True;
2311
2312 /* If the register already contains the new value, there is nothing
2313 to do here. Unless the guest register requires precise memory
2314 exceptions. */
2315 if (old_value_is_valid && new_value == old_value) {
2316 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2317 return;
2318 }
2319 }
2320
2321 /* guest register = 0 */
2322 if (new_value == 0) {
2323 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2324 return;
2325 }
2326
2327 if (old_value_is_valid == False) goto not_special;
2328
2329 /* If the new value is in the neighbourhood of the old value
2330 we can use a memory-to-memory insn */
2331 difference = new_value - old_value;
2332
2333 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2334 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2335 (difference & 0xFF), new_value));
2336 return;
2337 }
2338
2339 /* If the high word is the same it is sufficient to load the low word.
2340 Use R0 as a scratch reg. */
2341 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002342 HReg r0 = make_gpr(0);
2343 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002344 s390_amode *gam;
2345
2346 gam = s390_amode_b12(offset + 4, gsp);
2347 addInstr(env, s390_insn_load_immediate(4, r0,
2348 new_value & 0xFFFFFFFF));
2349 addInstr(env, s390_insn_store(4, gam, r0));
2350 return;
2351 }
2352
2353 /* No special case applies... fall through */
2354
2355 not_special:
sewardj2019a972011-03-07 16:04:07 +00002356 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2357
2358 switch (tyd) {
2359 case Ity_I8:
2360 case Ity_I16:
2361 case Ity_I32:
2362 case Ity_I64:
2363 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2364 break;
2365
2366 case Ity_F32:
2367 case Ity_F64:
2368 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2369 break;
2370
2371 case Ity_F128:
2372 /* Does not occur. See function put_fpr_pair. */
2373 vpanic("Ist_Put with F128 data");
2374
2375 default:
2376 goto stmt_fail;
2377 }
2378
2379 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2380 return;
2381 }
2382
2383 /* --------- TMP --------- */
2384 case Ist_WrTmp: {
2385 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2386 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2387 HReg src, dst;
2388
2389 switch (tyd) {
2390 case Ity_I128: {
2391 HReg dst_hi, dst_lo, res_hi, res_lo;
2392
2393 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2394 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2395
2396 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2397 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2398 return;
2399 }
2400
2401 case Ity_I8:
2402 case Ity_I16:
2403 case Ity_I32:
2404 case Ity_I64:
2405 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2406 dst = lookupIRTemp(env, tmp);
2407 break;
2408
2409 case Ity_I1: {
2410 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2411 dst = lookupIRTemp(env, tmp);
2412 addInstr(env, s390_insn_cc2bool(dst, cond));
2413 return;
2414 }
2415
2416 case Ity_F32:
2417 case Ity_F64:
2418 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2419 dst = lookupIRTemp(env, tmp);
2420 break;
2421
2422 case Ity_F128: {
2423 HReg dst_hi, dst_lo, res_hi, res_lo;
2424
2425 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2426 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2427
2428 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2429 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2430 return;
2431 }
2432
2433 default:
2434 goto stmt_fail;
2435 }
2436
2437 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2438 return;
2439 }
2440
2441 /* --------- Call to DIRTY helper --------- */
2442 case Ist_Dirty: {
2443 IRType retty;
2444 IRDirty* d = stmt->Ist.Dirty.details;
2445 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002446 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002447 Int i;
2448
2449 /* Invalidate tracked values of those guest state registers that are
2450 modified by this helper. */
2451 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002452 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2453 descriptors in guest state effect descriptions. Hence: */
2454 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002455 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2456 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2457 if (guest_reg != GUEST_UNKNOWN)
2458 env->old_value_valid[guest_reg] = False;
2459 }
2460 }
sewardj2019a972011-03-07 16:04:07 +00002461
2462 if (d->nFxState == 0)
2463 vassert(!d->needsBBP);
2464
2465 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2466
florian01ed6e72012-05-27 16:52:43 +00002467 if (d->tmp == IRTemp_INVALID) {
2468 /* No return value. */
2469 dst = INVALID_HREG;
2470 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002471 return;
florian01ed6e72012-05-27 16:52:43 +00002472 }
sewardj2019a972011-03-07 16:04:07 +00002473
2474 retty = typeOfIRTemp(env->type_env, d->tmp);
2475 if (retty == Ity_I64 || retty == Ity_I32
2476 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002477 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002478 dst = lookupIRTemp(env, d->tmp);
2479 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002480 return;
2481 }
2482 break;
2483 }
2484
2485 case Ist_CAS:
2486 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2487 IRCAS *cas = stmt->Ist.CAS.details;
2488 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2489 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2490 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2491 HReg old = lookupIRTemp(env, cas->oldLo);
2492
2493 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2494 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2495 } else {
2496 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2497 }
2498 return;
2499 } else {
florian448cbba2012-06-06 02:26:01 +00002500 IRCAS *cas = stmt->Ist.CAS.details;
2501 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2502 HReg r8, r9, r10, r11, r1;
2503 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2504 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2505 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2506 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2507 HReg old_low = lookupIRTemp(env, cas->oldLo);
2508 HReg old_high = lookupIRTemp(env, cas->oldHi);
2509
2510 /* Use non-virtual registers r8 and r9 as pair for op1
2511 and move op1 there */
2512 r8 = make_gpr(8);
2513 r9 = make_gpr(9);
2514 addInstr(env, s390_insn_move(8, r8, op1_high));
2515 addInstr(env, s390_insn_move(8, r9, op1_low));
2516
2517 /* Use non-virtual registers r10 and r11 as pair for op3
2518 and move op3 there */
2519 r10 = make_gpr(10);
2520 r11 = make_gpr(11);
2521 addInstr(env, s390_insn_move(8, r10, op3_high));
2522 addInstr(env, s390_insn_move(8, r11, op3_low));
2523
2524 /* Register r1 is used as a scratch register */
2525 r1 = make_gpr(1);
2526
2527 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2528 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2529 old_high, old_low, r1));
2530 } else {
2531 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2532 old_high, old_low, r1));
2533 }
2534 addInstr(env, s390_insn_move(8, op1_high, r8));
2535 addInstr(env, s390_insn_move(8, op1_low, r9));
2536 addInstr(env, s390_insn_move(8, op3_high, r10));
2537 addInstr(env, s390_insn_move(8, op3_low, r11));
2538 return;
sewardj2019a972011-03-07 16:04:07 +00002539 }
2540 break;
2541
2542 /* --------- EXIT --------- */
2543 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002544 s390_cc_t cond;
2545 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2546
2547 if (tag != Ico_U64)
2548 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2549
florian8844a632012-04-13 04:04:06 +00002550 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002551 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002552
2553 /* Case: boring transfer to known address */
2554 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2555 if (env->chaining_allowed) {
2556 /* .. almost always true .. */
2557 /* Skip the event check at the dst if this is a forwards
2558 edge. */
2559 Bool to_fast_entry
2560 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2561 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2562 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2563 guest_IA, to_fast_entry));
2564 } else {
2565 /* .. very occasionally .. */
2566 /* We can't use chaining, so ask for an assisted transfer,
2567 as that's the only alternative that is allowable. */
2568 HReg dst = s390_isel_int_expr(env,
2569 IRExpr_Const(stmt->Ist.Exit.dst));
2570 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2571 }
2572 return;
2573 }
2574
2575 /* Case: assisted transfer to arbitrary address */
2576 switch (stmt->Ist.Exit.jk) {
florian65b5b3f2012-04-22 02:51:27 +00002577 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002578 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002579 case Ijk_Sys_syscall:
2580 case Ijk_ClientReq:
2581 case Ijk_NoRedir:
2582 case Ijk_Yield:
2583 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002584 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2585 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2586 stmt->Ist.Exit.jk));
2587 return;
2588 }
2589 default:
2590 break;
2591 }
2592
2593 /* Do we ever expect to see any other kind? */
2594 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002595 }
2596
2597 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002598 case Ist_MBE:
2599 switch (stmt->Ist.MBE.event) {
2600 case Imbe_Fence:
2601 addInstr(env, s390_insn_mfence());
2602 return;
2603 default:
2604 break;
2605 }
sewardj2019a972011-03-07 16:04:07 +00002606 break;
2607
2608 /* --------- Miscellaneous --------- */
2609
2610 case Ist_PutI: /* Not needed */
2611 case Ist_IMark: /* Doesn't generate any executable code */
2612 case Ist_NoOp: /* Doesn't generate any executable code */
2613 case Ist_AbiHint: /* Meaningless in IR */
2614 return;
2615
2616 default:
2617 break;
2618 }
2619
2620 stmt_fail:
2621 ppIRStmt(stmt);
2622 vpanic("s390_isel_stmt");
2623}
2624
2625
2626/*---------------------------------------------------------*/
2627/*--- ISEL: Basic block terminators (Nexts) ---*/
2628/*---------------------------------------------------------*/
2629
2630static void
florian8844a632012-04-13 04:04:06 +00002631iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002632{
sewardj2019a972011-03-07 16:04:07 +00002633 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002634 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002635 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002636 vex_printf("; exit-");
2637 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002638 vex_printf("\n");
2639 }
2640
florian8844a632012-04-13 04:04:06 +00002641 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2642
2643 /* Case: boring transfer to known address */
2644 if (next->tag == Iex_Const) {
2645 IRConst *cdst = next->Iex.Const.con;
2646 vassert(cdst->tag == Ico_U64);
2647 if (jk == Ijk_Boring || jk == Ijk_Call) {
2648 /* Boring transfer to known address */
2649 if (env->chaining_allowed) {
2650 /* .. almost always true .. */
2651 /* Skip the event check at the dst if this is a forwards
2652 edge. */
2653 Bool to_fast_entry
2654 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2655 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2656 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2657 guest_IA, to_fast_entry));
2658 } else {
2659 /* .. very occasionally .. */
2660 /* We can't use chaining, so ask for an indirect transfer,
2661 as that's the cheapest alternative that is allowable. */
2662 HReg dst = s390_isel_int_expr(env, next);
2663 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2664 Ijk_Boring));
2665 }
2666 return;
2667 }
2668 }
2669
2670 /* Case: call/return (==boring) transfer to any address */
2671 switch (jk) {
2672 case Ijk_Boring:
2673 case Ijk_Ret:
2674 case Ijk_Call: {
2675 HReg dst = s390_isel_int_expr(env, next);
2676 if (env->chaining_allowed) {
2677 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2678 } else {
2679 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2680 Ijk_Boring));
2681 }
2682 return;
2683 }
2684 default:
2685 break;
2686 }
2687
2688 /* Case: some other kind of transfer to any address */
2689 switch (jk) {
florian65b5b3f2012-04-22 02:51:27 +00002690 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002691 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002692 case Ijk_Sys_syscall:
2693 case Ijk_ClientReq:
2694 case Ijk_NoRedir:
2695 case Ijk_Yield:
2696 case Ijk_SigTRAP: {
2697 HReg dst = s390_isel_int_expr(env, next);
2698 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2699 return;
2700 }
2701 default:
2702 break;
2703 }
2704
2705 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002706}
2707
2708
2709/*---------------------------------------------------------*/
2710/*--- Insn selector top-level ---*/
2711/*---------------------------------------------------------*/
2712
florianf26994a2012-04-21 03:34:54 +00002713/* Translate an entire SB to s390 code.
2714 Note: archinfo_host is a pointer to a stack-allocated variable.
2715 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002716
2717HInstrArray *
2718iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002719 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2720 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2721 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002722{
2723 UInt i, j;
2724 HReg hreg, hregHI;
2725 ISelEnv *env;
2726 UInt hwcaps_host = archinfo_host->hwcaps;
2727
florianf26994a2012-04-21 03:34:54 +00002728 /* KLUDGE: export hwcaps. */
2729 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002730
sewardj2019a972011-03-07 16:04:07 +00002731 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002732 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002733
2734 /* Make up an initial environment to use. */
2735 env = LibVEX_Alloc(sizeof(ISelEnv));
2736 env->vreg_ctr = 0;
2737
2738 /* Set up output code array. */
2739 env->code = newHInstrArray();
2740
2741 /* Copy BB's type env. */
2742 env->type_env = bb->tyenv;
2743
florianad43b3a2012-02-20 15:01:14 +00002744 /* Set up data structures for tracking guest register values. */
2745 env->first_IA_assignment = True;
2746 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2747 env->old_value[i] = 0; /* just something to have a defined value */
2748 env->old_value_valid[i] = False;
2749 }
2750
sewardj2019a972011-03-07 16:04:07 +00002751 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2752 change as we go along. For some reason types_used has Int type -- but
2753 it should be unsigned. Internally we use an unsigned type; so we
2754 assert it here. */
2755 vassert(bb->tyenv->types_used >= 0);
2756
2757 env->n_vregmap = bb->tyenv->types_used;
2758 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2759 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2760
2761 /* and finally ... */
2762 env->hwcaps = hwcaps_host;
2763
florian8844a632012-04-13 04:04:06 +00002764 env->max_ga = max_ga;
2765 env->chaining_allowed = chaining_allowed;
2766
sewardj2019a972011-03-07 16:04:07 +00002767 /* For each IR temporary, allocate a suitably-kinded virtual
2768 register. */
2769 j = 0;
2770 for (i = 0; i < env->n_vregmap; i++) {
2771 hregHI = hreg = INVALID_HREG;
2772 switch (bb->tyenv->types[i]) {
2773 case Ity_I1:
2774 case Ity_I8:
2775 case Ity_I16:
2776 case Ity_I32:
2777 hreg = mkHReg(j++, HRcInt64, True);
2778 break;
2779
2780 case Ity_I64:
2781 hreg = mkHReg(j++, HRcInt64, True);
2782 break;
2783
2784 case Ity_I128:
2785 hreg = mkHReg(j++, HRcInt64, True);
2786 hregHI = mkHReg(j++, HRcInt64, True);
2787 break;
2788
2789 case Ity_F32:
2790 case Ity_F64:
2791 hreg = mkHReg(j++, HRcFlt64, True);
2792 break;
2793
2794 case Ity_F128:
2795 hreg = mkHReg(j++, HRcFlt64, True);
2796 hregHI = mkHReg(j++, HRcFlt64, True);
2797 break;
2798
2799 case Ity_V128: /* fall through */
2800 default:
2801 ppIRType(bb->tyenv->types[i]);
2802 vpanic("s390_isel_sb: IRTemp type");
2803 }
2804
2805 env->vregmap[i] = hreg;
2806 env->vregmapHI[i] = hregHI;
2807 }
2808 env->vreg_ctr = j;
2809
florian8844a632012-04-13 04:04:06 +00002810 /* The very first instruction must be an event check. */
2811 s390_amode *counter, *fail_addr;
2812 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2813 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2814 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2815
2816 /* Possibly a block counter increment (for profiling). At this
2817 point we don't know the address of the counter, so just pretend
2818 it is zero. It will have to be patched later, but before this
2819 translation is used, by a call to LibVEX_patchProfInc. */
2820 if (add_profinc) {
2821 addInstr(env, s390_insn_profinc());
2822 }
2823
sewardj2019a972011-03-07 16:04:07 +00002824 /* Ok, finally we can iterate over the statements. */
2825 for (i = 0; i < bb->stmts_used; i++)
2826 if (bb->stmts[i])
2827 s390_isel_stmt(env, bb->stmts[i]);
2828
florian8844a632012-04-13 04:04:06 +00002829 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002830
2831 /* Record the number of vregs we used. */
2832 env->code->n_vregs = env->vreg_ctr;
2833
2834 return env->code;
2835}
2836
2837/*---------------------------------------------------------------*/
2838/*--- end host_s390_isel.c ---*/
2839/*---------------------------------------------------------------*/