blob: abfd2a6f7c2a555cbe80ec15e5cddbc4e2c35303 [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
florian61f23c12012-08-06 18:33:21 +000011 Copyright IBM Corp. 2010-2012
sewardj2019a972011-03-07 16:04:07 +000012
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;
florian1c8f7ff2012-09-01 00:12:11 +0000916 case Iop_F32toI32U: bfpop = S390_BFP_F32_TO_U32; goto do_convert;
917 case Iop_F32toI64U: bfpop = S390_BFP_F32_TO_U64; goto do_convert;
sewardj2019a972011-03-07 16:04:07 +0000918 case Iop_F64toI32S: bfpop = S390_BFP_F64_TO_I32; goto do_convert;
919 case Iop_F64toI64S: bfpop = S390_BFP_F64_TO_I64; goto do_convert;
florian1c8f7ff2012-09-01 00:12:11 +0000920 case Iop_F64toI32U: bfpop = S390_BFP_F64_TO_U32; goto do_convert;
921 case Iop_F64toI64U: bfpop = S390_BFP_F64_TO_U64; goto do_convert;
sewardj2019a972011-03-07 16:04:07 +0000922 case Iop_F128toI32S: bfpop = S390_BFP_F128_TO_I32; goto do_convert_128;
923 case Iop_F128toI64S: bfpop = S390_BFP_F128_TO_I64; goto do_convert_128;
florian1c8f7ff2012-09-01 00:12:11 +0000924 case Iop_F128toI32U: bfpop = S390_BFP_F128_TO_U32; goto do_convert_128;
925 case Iop_F128toI64U: bfpop = S390_BFP_F128_TO_U64; goto do_convert_128;
sewardj2019a972011-03-07 16:04:07 +0000926
927 do_convert: {
928 s390_round_t rounding_mode;
929
930 res = newVRegI(env);
931 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
932
933 rounding_mode = decode_rounding_mode(arg1);
934 addInstr(env, s390_insn_bfp_unop(size, bfpop, res, h1, rounding_mode));
935 return res;
936 }
937
938 do_convert_128: {
939 s390_round_t rounding_mode;
940 HReg op_hi, op_lo, f13, f15;
941
942 res = newVRegI(env);
943 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
944
945 /* We use non-virtual registers r13 and r15 as pair */
946 f13 = make_fpr(13);
947 f15 = make_fpr(15);
948
949 /* operand --> (f13, f15) */
950 addInstr(env, s390_insn_move(8, f13, op_hi));
951 addInstr(env, s390_insn_move(8, f15, op_lo));
952
953 rounding_mode = decode_rounding_mode(arg1);
954 addInstr(env, s390_insn_bfp128_convert_from(size, bfpop, res, f13, f15,
955 rounding_mode));
956 return res;
957 }
958
959 case Iop_8HLto16:
960 case Iop_16HLto32:
961 case Iop_32HLto64: {
962 HReg h2;
963 UInt arg_size = size / 2;
964
965 res = newVRegI(env);
966 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
967 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
968
969 addInstr(env, s390_insn_move(arg_size, res, h1));
970 value = s390_opnd_imm(arg_size * 8);
971 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
972 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
973 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
974 opnd = s390_opnd_reg(h2);
975 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
976 return res;
977 }
978
979 case Iop_Max32U: {
980 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
981 res = newVRegI(env);
982 h1 = s390_isel_int_expr(env, arg1);
983 op2 = s390_isel_int_expr_RMI(env, arg2);
984
985 addInstr(env, s390_insn_move(size, res, h1));
986 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
987 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
988 return res;
989 }
990
991 case Iop_CmpF32:
992 case Iop_CmpF64: {
993 HReg cc_s390, h2;
994
995 h1 = s390_isel_float_expr(env, arg1);
996 h2 = s390_isel_float_expr(env, arg2);
997 cc_s390 = newVRegI(env);
998
999 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1000
1001 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1002
1003 return convert_s390_fpcc_to_vex(env, cc_s390);
1004 }
1005
1006 case Iop_CmpF128: {
1007 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1008
1009 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1010 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1011 cc_s390 = newVRegI(env);
1012
1013 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1014 f12 = make_fpr(12);
1015 f13 = make_fpr(13);
1016 f14 = make_fpr(14);
1017 f15 = make_fpr(15);
1018
1019 /* 1st operand --> (f12, f14) */
1020 addInstr(env, s390_insn_move(8, f12, op1_hi));
1021 addInstr(env, s390_insn_move(8, f14, op1_lo));
1022
1023 /* 2nd operand --> (f13, f15) */
1024 addInstr(env, s390_insn_move(8, f13, op2_hi));
1025 addInstr(env, s390_insn_move(8, f15, op2_lo));
1026
1027 res = newVRegI(env);
1028 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1029
1030 return convert_s390_fpcc_to_vex(env, cc_s390);
1031 }
1032
1033 case Iop_Add8:
1034 case Iop_Add16:
1035 case Iop_Add32:
1036 case Iop_Add64:
1037 opkind = S390_ALU_ADD;
1038 break;
1039
1040 case Iop_Sub8:
1041 case Iop_Sub16:
1042 case Iop_Sub32:
1043 case Iop_Sub64:
1044 opkind = S390_ALU_SUB;
1045 is_commutative = False;
1046 break;
1047
1048 case Iop_And8:
1049 case Iop_And16:
1050 case Iop_And32:
1051 case Iop_And64:
1052 opkind = S390_ALU_AND;
1053 break;
1054
1055 case Iop_Or8:
1056 case Iop_Or16:
1057 case Iop_Or32:
1058 case Iop_Or64:
1059 opkind = S390_ALU_OR;
1060 break;
1061
1062 case Iop_Xor8:
1063 case Iop_Xor16:
1064 case Iop_Xor32:
1065 case Iop_Xor64:
1066 opkind = S390_ALU_XOR;
1067 break;
1068
1069 case Iop_Shl8:
1070 case Iop_Shl16:
1071 case Iop_Shl32:
1072 case Iop_Shl64:
1073 opkind = S390_ALU_LSH;
1074 is_commutative = False;
1075 break;
1076
1077 case Iop_Shr8:
1078 case Iop_Shr16:
1079 case Iop_Shr32:
1080 case Iop_Shr64:
1081 opkind = S390_ALU_RSH;
1082 is_commutative = False;
1083 break;
1084
1085 case Iop_Sar8:
1086 case Iop_Sar16:
1087 case Iop_Sar32:
1088 case Iop_Sar64:
1089 opkind = S390_ALU_RSHA;
1090 is_commutative = False;
1091 break;
1092
1093 default:
1094 goto irreducible;
1095 }
1096
1097 /* Pattern match: 0 - arg1 --> -arg1 */
1098 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1099 res = newVRegI(env);
1100 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1101 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1102 addInstr(env, insn);
1103
1104 return res;
1105 }
1106
1107 if (is_commutative) {
1108 order_commutative_operands(arg1, arg2);
1109 }
1110
1111 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1112 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1113 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001114
1115 /* As right shifts of one/two byte opreands are implemented using a
1116 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1117 switch (expr->Iex.Binop.op) {
1118 case Iop_Shr8:
1119 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1120 break;
1121 case Iop_Shr16:
1122 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1123 break;
1124 case Iop_Sar8:
1125 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1126 break;
1127 case Iop_Sar16:
1128 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1129 break;
1130 default:
1131 insn = s390_insn_move(size, res, h1);
1132 break;
1133 }
1134 addInstr(env, insn);
1135
sewardj2019a972011-03-07 16:04:07 +00001136 insn = s390_insn_alu(size, opkind, res, op2);
1137
1138 addInstr(env, insn);
1139
1140 return res;
1141 }
1142
1143 /* --------- UNARY OP --------- */
1144 case Iex_Unop: {
1145 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1146 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1147 s390_opnd_RMI opnd;
1148 s390_insn *insn;
1149 IRExpr *arg;
1150 HReg dst, h1;
1151 IROp unop, binop;
1152
1153 arg = expr->Iex.Unop.arg;
1154
1155 /* Special cases are handled here */
1156
1157 /* 32-bit multiply with 32-bit result or
1158 64-bit multiply with 64-bit result */
1159 unop = expr->Iex.Unop.op;
1160 binop = arg->Iex.Binop.op;
1161
1162 if ((arg->tag == Iex_Binop &&
1163 ((unop == Iop_64to32 &&
1164 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1165 (unop == Iop_128to64 &&
1166 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1167 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1168 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1169 dst = newVRegI(env); /* Result goes into a new register */
1170 addInstr(env, s390_insn_move(size, dst, h1));
1171 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1172
1173 return dst;
1174 }
1175
florian4d71a082011-12-18 00:08:17 +00001176 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001177 dst = newVRegI(env);
1178 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1179 addInstr(env, s390_insn_move(size, dst, h1));
1180
1181 return dst;
1182 }
1183
1184 /* Expressions whose argument is 1-bit wide */
1185 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1186 s390_cc_t cond = s390_isel_cc(env, arg);
1187 dst = newVRegI(env); /* Result goes into a new register */
1188 addInstr(env, s390_insn_cc2bool(dst, cond));
1189
1190 switch (unop) {
1191 case Iop_1Uto8:
1192 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001193 /* Zero extend */
1194 mask.variant.imm = 1;
1195 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1196 break;
1197
sewardj2019a972011-03-07 16:04:07 +00001198 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001199 /* Zero extend */
1200 mask.variant.imm = 1;
1201 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001202 break;
1203
1204 case Iop_1Sto8:
1205 case Iop_1Sto16:
1206 case Iop_1Sto32:
1207 shift.variant.imm = 31;
1208 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1209 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1210 break;
1211
1212 case Iop_1Sto64:
1213 shift.variant.imm = 63;
1214 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1215 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1216 break;
1217
1218 default:
1219 goto irreducible;
1220 }
1221
1222 return dst;
1223 }
1224
1225 /* Regular processing */
1226
1227 if (unop == Iop_128to64) {
1228 HReg dst_hi, dst_lo;
1229
1230 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1231 return dst_lo;
1232 }
1233
1234 if (unop == Iop_128HIto64) {
1235 HReg dst_hi, dst_lo;
1236
1237 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1238 return dst_hi;
1239 }
1240
1241 dst = newVRegI(env); /* Result goes into a new register */
1242 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1243
1244 switch (unop) {
1245 case Iop_8Uto16:
1246 case Iop_8Uto32:
1247 case Iop_8Uto64:
1248 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1249 break;
1250
1251 case Iop_16Uto32:
1252 case Iop_16Uto64:
1253 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1254 break;
1255
1256 case Iop_32Uto64:
1257 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1258 break;
1259
1260 case Iop_8Sto16:
1261 case Iop_8Sto32:
1262 case Iop_8Sto64:
1263 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1264 break;
1265
1266 case Iop_16Sto32:
1267 case Iop_16Sto64:
1268 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1269 break;
1270
1271 case Iop_32Sto64:
1272 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1273 break;
1274
1275 case Iop_64to8:
1276 case Iop_64to16:
1277 case Iop_64to32:
1278 case Iop_32to8:
1279 case Iop_32to16:
1280 case Iop_16to8:
1281 /* Down-casts are no-ops. Upstream operations will only look at
1282 the bytes that make up the result of the down-cast. So there
1283 is no point setting the other bytes to 0. */
1284 insn = s390_opnd_copy(8, dst, opnd);
1285 break;
1286
1287 case Iop_64HIto32:
1288 addInstr(env, s390_opnd_copy(8, dst, opnd));
1289 shift.variant.imm = 32;
1290 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1291 break;
1292
1293 case Iop_32HIto16:
1294 addInstr(env, s390_opnd_copy(4, dst, opnd));
1295 shift.variant.imm = 16;
1296 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1297 break;
1298
1299 case Iop_16HIto8:
1300 addInstr(env, s390_opnd_copy(2, dst, opnd));
1301 shift.variant.imm = 8;
1302 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1303 break;
1304
1305 case Iop_Not8:
1306 case Iop_Not16:
1307 case Iop_Not32:
1308 case Iop_Not64:
1309 /* XOR with ffff... */
1310 mask.variant.imm = ~(ULong)0;
1311 addInstr(env, s390_opnd_copy(size, dst, opnd));
1312 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1313 break;
1314
1315 case Iop_Left8:
1316 case Iop_Left16:
1317 case Iop_Left32:
1318 case Iop_Left64:
1319 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1320 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1321 break;
1322
1323 case Iop_CmpwNEZ32:
1324 case Iop_CmpwNEZ64: {
1325 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1326 or -X will have a 1 in the MSB. */
1327 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1328 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1329 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1330 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1331 return dst;
1332 }
1333
1334 case Iop_Clz64: {
1335 HReg r10, r11;
1336
sewardj611b06e2011-03-24 08:57:29 +00001337 /* This will be implemented using FLOGR, if possible. So we need to
1338 set aside a pair of non-virtual registers. The result (number of
1339 left-most zero bits) will be in r10. The value in r11 is unspecified
1340 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001341 r10 = make_gpr(10);
1342 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001343
sewardj611b06e2011-03-24 08:57:29 +00001344 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001345 addInstr(env, s390_insn_move(8, dst, r10));
1346 return dst;
1347 }
1348
1349 default:
1350 goto irreducible;
1351 }
1352
1353 addInstr(env, insn);
1354
1355 return dst;
1356 }
1357
1358 /* --------- GET --------- */
1359 case Iex_Get: {
1360 HReg dst = newVRegI(env);
1361 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1362
1363 /* We never load more than 8 bytes from the guest state, because the
1364 floating point register pair is not contiguous. */
1365 vassert(size <= 8);
1366
1367 addInstr(env, s390_insn_load(size, dst, am));
1368
1369 return dst;
1370 }
1371
1372 case Iex_GetI:
1373 /* not needed */
1374 break;
1375
1376 /* --------- CCALL --------- */
1377 case Iex_CCall: {
1378 HReg dst = newVRegI(env);
1379
1380 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001381 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001382 return dst;
1383 }
1384
1385 /* --------- LITERAL --------- */
1386
1387 /* Load a literal into a register. Create a "load immediate"
1388 v-insn and return the register. */
1389 case Iex_Const: {
1390 ULong value;
1391 HReg dst = newVRegI(env);
1392 const IRConst *con = expr->Iex.Const.con;
1393
1394 /* Bitwise copy of the value. No sign/zero-extension */
1395 switch (con->tag) {
1396 case Ico_U64: value = con->Ico.U64; break;
1397 case Ico_U32: value = con->Ico.U32; break;
1398 case Ico_U16: value = con->Ico.U16; break;
1399 case Ico_U8: value = con->Ico.U8; break;
1400 default: vpanic("s390_isel_int_expr: invalid constant");
1401 }
1402
1403 addInstr(env, s390_insn_load_immediate(size, dst, value));
1404
1405 return dst;
1406 }
1407
1408 /* --------- MULTIPLEX --------- */
1409 case Iex_Mux0X: {
1410 IRExpr *cond_expr;
1411 HReg dst, tmp, rX;
1412 s390_opnd_RMI cond, r0, zero;
1413
1414 cond_expr = expr->Iex.Mux0X.cond;
1415
1416 dst = newVRegI(env);
1417 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1418 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1419 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1420
1421 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1422 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1423
1424 addInstr(env, s390_insn_move(size, dst, rX));
1425 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1426 return dst;
1427 }
1428
1429 /* Assume the condition is true and move rX to the destination reg. */
1430 addInstr(env, s390_insn_move(size, dst, rX));
1431
1432 /* Compute the condition ... */
1433 cond = s390_isel_int_expr_RMI(env, cond_expr);
1434
1435 /* tmp = cond & 0xFF */
1436 tmp = newVRegI(env);
1437 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1438 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1439
1440 /* ... and compare it with zero */
1441 zero = s390_opnd_imm(0);
1442 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1443
1444 /* ... and if it compared equal move r0 to the destination reg. */
1445 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1446 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1447
1448 return dst;
1449 }
1450
1451 default:
1452 break;
1453 }
1454
1455 /* We get here if no pattern matched. */
1456 irreducible:
1457 ppIRExpr(expr);
1458 vpanic("s390_isel_int_expr: cannot reduce tree");
1459}
1460
1461
1462static HReg
1463s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1464{
1465 HReg dst = s390_isel_int_expr_wrk(env, expr);
1466
1467 /* Sanity checks ... */
1468 vassert(hregClass(dst) == HRcInt64);
1469 vassert(hregIsVirtual(dst));
1470
1471 return dst;
1472}
1473
1474
1475static s390_opnd_RMI
1476s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1477{
1478 IRType ty = typeOfIRExpr(env->type_env, expr);
1479 s390_opnd_RMI dst;
1480
1481 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1482 ty == Ity_I64);
1483
1484 if (expr->tag == Iex_Load) {
1485 dst.tag = S390_OPND_AMODE;
1486 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1487 } else if (expr->tag == Iex_Get) {
1488 dst.tag = S390_OPND_AMODE;
1489 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1490 } else if (expr->tag == Iex_Const) {
1491 ULong value;
1492
1493 /* The bit pattern for the value will be stored as is in the least
1494 significant bits of VALUE. */
1495 switch (expr->Iex.Const.con->tag) {
1496 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1497 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1498 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1499 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1500 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1501 default:
1502 vpanic("s390_isel_int_expr_RMI");
1503 }
1504
1505 dst.tag = S390_OPND_IMMEDIATE;
1506 dst.variant.imm = value;
1507 } else {
1508 dst.tag = S390_OPND_REG;
1509 dst.variant.reg = s390_isel_int_expr(env, expr);
1510 }
1511
1512 return dst;
1513}
1514
1515
1516/*---------------------------------------------------------*/
1517/*--- ISEL: Floating point expressions (128 bit) ---*/
1518/*---------------------------------------------------------*/
1519static void
1520s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1521 IRExpr *expr)
1522{
1523 IRType ty = typeOfIRExpr(env->type_env, expr);
1524
1525 vassert(ty == Ity_F128);
1526
1527 /* Read 128-bit IRTemp */
1528 if (expr->tag == Iex_RdTmp) {
1529 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1530 return;
1531 }
1532
1533 switch (expr->tag) {
1534 case Iex_RdTmp:
1535 /* Return the virtual registers that hold the temporary. */
1536 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1537 return;
1538
1539 /* --------- LOAD --------- */
1540 case Iex_Load: {
1541 IRExpr *addr_hi, *addr_lo;
1542 s390_amode *am_hi, *am_lo;
1543
1544 if (expr->Iex.Load.end != Iend_BE)
1545 goto irreducible;
1546
1547 addr_hi = expr->Iex.Load.addr;
1548 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1549
1550 am_hi = s390_isel_amode(env, addr_hi);
1551 am_lo = s390_isel_amode(env, addr_lo);
1552
1553 *dst_hi = newVRegF(env);
1554 *dst_lo = newVRegF(env);
1555 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1556 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1557 return;
1558 }
1559
1560
1561 /* --------- GET --------- */
1562 case Iex_Get:
1563 /* This is not supported because loading 128-bit from the guest
1564 state is almost certainly wrong. Use get_fpr_pair instead. */
1565 vpanic("Iex_Get with F128 data");
1566
1567 /* --------- 4-ary OP --------- */
1568 case Iex_Qop:
1569 vpanic("Iex_Qop with F128 data");
1570
1571 /* --------- TERNARY OP --------- */
1572 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001573 IRTriop *triop = expr->Iex.Triop.details;
1574 IROp op = triop->op;
1575 IRExpr *left = triop->arg2;
1576 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001577 s390_bfp_binop_t bfpop;
1578 s390_round_t rounding_mode;
1579 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1580
1581 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1582 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1583
1584 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1585 f12 = make_fpr(12);
1586 f13 = make_fpr(13);
1587 f14 = make_fpr(14);
1588 f15 = make_fpr(15);
1589
1590 /* 1st operand --> (f12, f14) */
1591 addInstr(env, s390_insn_move(8, f12, op1_hi));
1592 addInstr(env, s390_insn_move(8, f14, op1_lo));
1593
1594 /* 2nd operand --> (f13, f15) */
1595 addInstr(env, s390_insn_move(8, f13, op2_hi));
1596 addInstr(env, s390_insn_move(8, f15, op2_lo));
1597
1598 switch (op) {
1599 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1600 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1601 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1602 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1603 default:
1604 goto irreducible;
1605 }
1606
florian420bfa92012-06-02 20:29:22 +00001607 rounding_mode = decode_rounding_mode(triop->arg1);
sewardj2019a972011-03-07 16:04:07 +00001608 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1609 f15, rounding_mode));
1610
1611 /* Move result to virtual destination register */
1612 *dst_hi = newVRegF(env);
1613 *dst_lo = newVRegF(env);
1614 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1615 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1616
1617 return;
1618 }
1619
1620 /* --------- BINARY OP --------- */
1621 case Iex_Binop: {
1622 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardja970c402011-04-28 18:38:42 +00001623 s390_bfp_unop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001624 s390_round_t rounding_mode;
1625
1626 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1627 f12 = make_fpr(12);
1628 f13 = make_fpr(13);
1629 f14 = make_fpr(14);
1630 f15 = make_fpr(15);
1631
1632 switch (expr->Iex.Binop.op) {
1633 case Iop_SqrtF128:
1634 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1635
1636 /* operand --> (f13, f15) */
1637 addInstr(env, s390_insn_move(8, f13, op_hi));
1638 addInstr(env, s390_insn_move(8, f15, op_lo));
1639
1640 bfpop = S390_BFP_SQRT;
1641 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1642
1643 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1644 rounding_mode));
1645
1646 /* Move result to virtual destination registers */
1647 *dst_hi = newVRegF(env);
1648 *dst_lo = newVRegF(env);
1649 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1650 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1651 return;
1652
1653 case Iop_F64HLtoF128:
1654 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1655 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1656 return;
1657
1658 default:
1659 goto irreducible;
1660 }
1661 }
1662
1663 /* --------- UNARY OP --------- */
1664 case Iex_Unop: {
1665 IRExpr *left = expr->Iex.Binop.arg1;
1666 s390_bfp_unop_t bfpop;
1667 s390_round_t rounding_mode;
1668 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1669
1670 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1671 f12 = make_fpr(12);
1672 f13 = make_fpr(13);
1673 f14 = make_fpr(14);
1674 f15 = make_fpr(15);
1675
1676 switch (expr->Iex.Binop.op) {
1677 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1678 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1679 case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int;
1680 case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int;
florian1c8f7ff2012-09-01 00:12:11 +00001681 case Iop_I32UtoF128: bfpop = S390_BFP_U32_TO_F128; goto convert_int;
1682 case Iop_I64UtoF128: bfpop = S390_BFP_U64_TO_F128; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00001683 case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float;
1684 case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float;
1685 default:
1686 goto irreducible;
1687 }
1688
1689 float128_opnd:
1690 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1691
1692 /* operand --> (f13, f15) */
1693 addInstr(env, s390_insn_move(8, f13, op_hi));
1694 addInstr(env, s390_insn_move(8, f15, op_lo));
1695
1696 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1697 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1698 rounding_mode));
1699 goto move_dst;
1700
1701 convert_float:
1702 op = s390_isel_float_expr(env, left);
1703 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1704 op));
1705 goto move_dst;
1706
1707 convert_int:
1708 op = s390_isel_int_expr(env, left);
1709 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1710 op));
1711 goto move_dst;
1712
1713 move_dst:
1714 /* Move result to virtual destination registers */
1715 *dst_hi = newVRegF(env);
1716 *dst_lo = newVRegF(env);
1717 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1718 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1719 return;
1720 }
1721
1722 default:
1723 goto irreducible;
1724 }
1725
1726 /* We get here if no pattern matched. */
1727 irreducible:
1728 ppIRExpr(expr);
1729 vpanic("s390_isel_int_expr: cannot reduce tree");
1730}
1731
1732/* Compute a 128-bit value into two 64-bit registers. These may be either
1733 real or virtual regs; in any case they must not be changed by subsequent
1734 code emitted by the caller. */
1735static void
1736s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1737{
1738 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1739
1740 /* Sanity checks ... */
1741 vassert(hregIsVirtual(*dst_hi));
1742 vassert(hregIsVirtual(*dst_lo));
1743 vassert(hregClass(*dst_hi) == HRcFlt64);
1744 vassert(hregClass(*dst_lo) == HRcFlt64);
1745}
1746
1747
1748/*---------------------------------------------------------*/
1749/*--- ISEL: Floating point expressions (64 bit) ---*/
1750/*---------------------------------------------------------*/
1751
1752static HReg
1753s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1754{
1755 IRType ty = typeOfIRExpr(env->type_env, expr);
1756 UChar size;
1757
1758 vassert(ty == Ity_F32 || ty == Ity_F64);
1759
1760 size = sizeofIRType(ty);
1761
1762 switch (expr->tag) {
1763 case Iex_RdTmp:
1764 /* Return the virtual register that holds the temporary. */
1765 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1766
1767 /* --------- LOAD --------- */
1768 case Iex_Load: {
1769 HReg dst = newVRegF(env);
1770 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1771
1772 if (expr->Iex.Load.end != Iend_BE)
1773 goto irreducible;
1774
1775 addInstr(env, s390_insn_load(size, dst, am));
1776
1777 return dst;
1778 }
1779
1780 /* --------- GET --------- */
1781 case Iex_Get: {
1782 HReg dst = newVRegF(env);
1783 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1784
1785 addInstr(env, s390_insn_load(size, dst, am));
1786
1787 return dst;
1788 }
1789
1790 /* --------- LITERAL --------- */
1791
1792 /* Load a literal into a register. Create a "load immediate"
1793 v-insn and return the register. */
1794 case Iex_Const: {
1795 ULong value;
1796 HReg dst = newVRegF(env);
1797 const IRConst *con = expr->Iex.Const.con;
1798
1799 /* Bitwise copy of the value. No sign/zero-extension */
1800 switch (con->tag) {
1801 case Ico_F32i: value = con->Ico.F32i; break;
1802 case Ico_F64i: value = con->Ico.F64i; break;
1803 default: vpanic("s390_isel_float_expr: invalid constant");
1804 }
1805
1806 if (value != 0) vpanic("cannot load immediate floating point constant");
1807
1808 addInstr(env, s390_insn_load_immediate(size, dst, value));
1809
1810 return dst;
1811 }
1812
1813 /* --------- 4-ary OP --------- */
1814 case Iex_Qop: {
1815 HReg op1, op2, op3, dst;
1816 s390_bfp_triop_t bfpop;
1817 s390_round_t rounding_mode;
1818
florian96d7cc32012-06-01 20:41:24 +00001819 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
1820 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
1821 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00001822 dst = newVRegF(env);
1823 addInstr(env, s390_insn_move(size, dst, op1));
1824
florian96d7cc32012-06-01 20:41:24 +00001825 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00001826 case Iop_MAddF32:
1827 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1828 case Iop_MSubF32:
1829 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1830
1831 default:
1832 goto irreducible;
1833 }
1834
florian96d7cc32012-06-01 20:41:24 +00001835 rounding_mode = decode_rounding_mode(expr->Iex.Qop.details->arg1);
sewardj2019a972011-03-07 16:04:07 +00001836 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1837 rounding_mode));
1838 return dst;
1839 }
1840
1841 /* --------- TERNARY OP --------- */
1842 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001843 IRTriop *triop = expr->Iex.Triop.details;
1844 IROp op = triop->op;
1845 IRExpr *left = triop->arg2;
1846 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001847 s390_bfp_binop_t bfpop;
1848 s390_round_t rounding_mode;
1849 HReg h1, op2, dst;
1850
1851 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1852 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1853 dst = newVRegF(env);
1854 addInstr(env, s390_insn_move(size, dst, h1));
1855 switch (op) {
1856 case Iop_AddF32:
1857 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1858 case Iop_SubF32:
1859 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1860 case Iop_MulF32:
1861 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1862 case Iop_DivF32:
1863 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1864
1865 default:
1866 goto irreducible;
1867 }
1868
florian420bfa92012-06-02 20:29:22 +00001869 rounding_mode = decode_rounding_mode(triop->arg1);
sewardj2019a972011-03-07 16:04:07 +00001870 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1871 return dst;
1872 }
1873
1874 /* --------- BINARY OP --------- */
1875 case Iex_Binop: {
1876 IROp op = expr->Iex.Binop.op;
1877 IRExpr *left = expr->Iex.Binop.arg2;
1878 HReg h1, dst;
1879 s390_bfp_unop_t bfpop;
1880 s390_round_t rounding_mode;
1881 Int integer_operand;
1882
1883 integer_operand = 1;
1884
1885 switch (op) {
1886 case Iop_SqrtF32:
1887 case Iop_SqrtF64:
1888 bfpop = S390_BFP_SQRT;
1889 integer_operand = 0;
1890 break;
1891
1892 case Iop_F64toF32:
1893 bfpop = S390_BFP_F64_TO_F32;
1894 integer_operand = 0;
1895 break;
1896
1897 case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break;
florian1c8f7ff2012-09-01 00:12:11 +00001898 case Iop_I32UtoF32: bfpop = S390_BFP_U32_TO_F32; break;
sewardj2019a972011-03-07 16:04:07 +00001899 case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break;
1900 case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break;
florian1c8f7ff2012-09-01 00:12:11 +00001901 case Iop_I64UtoF32: bfpop = S390_BFP_U64_TO_F32; break;
1902 case Iop_I64UtoF64: bfpop = S390_BFP_U64_TO_F64; break;
1903
sewardj2019a972011-03-07 16:04:07 +00001904 default:
1905 goto irreducible;
1906
1907 case Iop_F128toF64:
1908 case Iop_F128toF32: {
1909 HReg op_hi, op_lo, f12, f13, f14, f15;
1910
1911 bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1912 : S390_BFP_F128_TO_F64;
1913
1914 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1915
1916 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1917
1918 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1919 f12 = make_fpr(12);
1920 f13 = make_fpr(13);
1921 f14 = make_fpr(14);
1922 f15 = make_fpr(15);
1923
1924 /* operand --> (f13, f15) */
1925 addInstr(env, s390_insn_move(8, f13, op_hi));
1926 addInstr(env, s390_insn_move(8, f15, op_lo));
1927
1928 dst = newVRegF(env);
1929 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1930 rounding_mode));
1931
1932 /* Move result to virtual destination registers */
1933 addInstr(env, s390_insn_move(8, dst, f12));
1934 return dst;
1935 }
1936 }
1937
1938 /* Process operand */
1939 if (integer_operand) {
1940 h1 = s390_isel_int_expr(env, left);
1941 } else {
1942 h1 = s390_isel_float_expr(env, left);
1943 }
1944
1945 dst = newVRegF(env);
1946 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1947 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1948 return dst;
1949 }
1950
1951 /* --------- UNARY OP --------- */
1952 case Iex_Unop: {
1953 IROp op = expr->Iex.Unop.op;
1954 IRExpr *left = expr->Iex.Unop.arg;
1955 s390_bfp_unop_t bfpop;
1956 s390_round_t rounding_mode;
1957 HReg h1, dst;
1958
1959 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1960 HReg dst_hi, dst_lo;
1961
1962 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1963 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1964 }
1965
florian4d71a082011-12-18 00:08:17 +00001966 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00001967 dst = newVRegF(env);
1968 h1 = s390_isel_int_expr(env, left); /* Process the operand */
1969 addInstr(env, s390_insn_move(size, dst, h1));
1970
1971 return dst;
1972 }
1973
1974 switch (op) {
1975 case Iop_NegF32:
1976 case Iop_NegF64:
1977 if (left->tag == Iex_Unop &&
1978 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1979 bfpop = S390_BFP_NABS;
1980 else
1981 bfpop = S390_BFP_NEG;
1982 break;
1983
1984 case Iop_AbsF32:
1985 case Iop_AbsF64: bfpop = S390_BFP_ABS; break;
1986 case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break;
florian1c8f7ff2012-09-01 00:12:11 +00001987 case Iop_I32UtoF64: bfpop = S390_BFP_U32_TO_F64; break;
sewardj2019a972011-03-07 16:04:07 +00001988 case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break;
1989 default:
1990 goto irreducible;
1991 }
1992
1993 /* Process operand */
florian1c8f7ff2012-09-01 00:12:11 +00001994 if (op == Iop_I32StoF64 || op == Iop_I32UtoF64)
sewardj2019a972011-03-07 16:04:07 +00001995 h1 = s390_isel_int_expr(env, left);
1996 else if (bfpop == S390_BFP_NABS)
1997 h1 = s390_isel_float_expr(env, left->Iex.Unop.arg);
1998 else
1999 h1 = s390_isel_float_expr(env, left);
2000
2001 dst = newVRegF(env);
2002 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
2003 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
2004 return dst;
2005 }
2006
2007 default:
2008 goto irreducible;
2009 }
2010
2011 /* We get here if no pattern matched. */
2012 irreducible:
2013 ppIRExpr(expr);
2014 vpanic("s390_isel_float_expr: cannot reduce tree");
2015}
2016
2017
2018static HReg
2019s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2020{
2021 HReg dst = s390_isel_float_expr_wrk(env, expr);
2022
2023 /* Sanity checks ... */
2024 vassert(hregClass(dst) == HRcFlt64);
2025 vassert(hregIsVirtual(dst));
2026
2027 return dst;
2028}
2029
2030
2031/*---------------------------------------------------------*/
2032/*--- ISEL: Condition Code ---*/
2033/*---------------------------------------------------------*/
2034
2035/* This function handles all operators that produce a 1-bit result */
2036static s390_cc_t
2037s390_isel_cc(ISelEnv *env, IRExpr *cond)
2038{
2039 UChar size;
2040
2041 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2042
2043 /* Constant: either 1 or 0 */
2044 if (cond->tag == Iex_Const) {
2045 vassert(cond->Iex.Const.con->tag == Ico_U1);
2046 vassert(cond->Iex.Const.con->Ico.U1 == True
2047 || cond->Iex.Const.con->Ico.U1 == False);
2048
2049 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2050 }
2051
2052 /* Variable: values are 1 or 0 */
2053 if (cond->tag == Iex_RdTmp) {
2054 IRTemp tmp = cond->Iex.RdTmp.tmp;
2055 HReg reg = lookupIRTemp(env, tmp);
2056
2057 /* Load-and-test does not modify REG; so this is OK. */
2058 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2059 size = 4;
2060 else
2061 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2062 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2063 return S390_CC_NE;
2064 }
2065
2066 /* Unary operators */
2067 if (cond->tag == Iex_Unop) {
2068 IRExpr *arg = cond->Iex.Unop.arg;
2069
2070 switch (cond->Iex.Unop.op) {
2071 case Iop_Not1: /* Not1(cond) */
2072 /* Generate code for EXPR, and negate the test condition */
2073 return s390_cc_invert(s390_isel_cc(env, arg));
2074
2075 /* Iop_32/64to1 select the LSB from their operand */
2076 case Iop_32to1:
2077 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002078 HReg dst = newVRegI(env);
2079 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002080
2081 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2082
florianf366a802012-08-03 00:42:18 +00002083 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002084 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2085 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2086 return S390_CC_NE;
2087 }
2088
2089 case Iop_CmpNEZ8:
2090 case Iop_CmpNEZ16: {
2091 s390_opnd_RMI src;
2092 s390_unop_t op;
2093 HReg dst;
2094
2095 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2096 : S390_ZERO_EXTEND_16;
2097 dst = newVRegI(env);
2098 src = s390_isel_int_expr_RMI(env, arg);
2099 addInstr(env, s390_insn_unop(4, op, dst, src));
2100 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2101 return S390_CC_NE;
2102 }
2103
2104 case Iop_CmpNEZ32:
2105 case Iop_CmpNEZ64: {
2106 s390_opnd_RMI src;
2107
2108 src = s390_isel_int_expr_RMI(env, arg);
2109 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2110 addInstr(env, s390_insn_test(size, src));
2111 return S390_CC_NE;
2112 }
2113
2114 default:
2115 goto fail;
2116 }
2117 }
2118
2119 /* Binary operators */
2120 if (cond->tag == Iex_Binop) {
2121 IRExpr *arg1 = cond->Iex.Binop.arg1;
2122 IRExpr *arg2 = cond->Iex.Binop.arg2;
2123 HReg reg1, reg2;
2124
2125 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2126
2127 switch (cond->Iex.Binop.op) {
2128 s390_unop_t op;
2129 s390_cc_t result;
2130
2131 case Iop_CmpEQ8:
2132 case Iop_CasCmpEQ8:
2133 op = S390_ZERO_EXTEND_8;
2134 result = S390_CC_E;
2135 goto do_compare_ze;
2136
2137 case Iop_CmpNE8:
2138 case Iop_CasCmpNE8:
2139 op = S390_ZERO_EXTEND_8;
2140 result = S390_CC_NE;
2141 goto do_compare_ze;
2142
2143 case Iop_CmpEQ16:
2144 case Iop_CasCmpEQ16:
2145 op = S390_ZERO_EXTEND_16;
2146 result = S390_CC_E;
2147 goto do_compare_ze;
2148
2149 case Iop_CmpNE16:
2150 case Iop_CasCmpNE16:
2151 op = S390_ZERO_EXTEND_16;
2152 result = S390_CC_NE;
2153 goto do_compare_ze;
2154
2155 do_compare_ze: {
2156 s390_opnd_RMI op1, op2;
2157
2158 op1 = s390_isel_int_expr_RMI(env, arg1);
2159 reg1 = newVRegI(env);
2160 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2161
2162 op2 = s390_isel_int_expr_RMI(env, arg2);
2163 reg2 = newVRegI(env);
2164 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2165
2166 op2 = s390_opnd_reg(reg2);
2167 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2168
2169 return result;
2170 }
2171
2172 case Iop_CmpEQ32:
2173 case Iop_CmpEQ64:
2174 case Iop_CasCmpEQ32:
2175 case Iop_CasCmpEQ64:
2176 result = S390_CC_E;
2177 goto do_compare;
2178
2179 case Iop_CmpNE32:
2180 case Iop_CmpNE64:
2181 case Iop_CasCmpNE32:
2182 case Iop_CasCmpNE64:
2183 result = S390_CC_NE;
2184 goto do_compare;
2185
2186 do_compare: {
2187 HReg op1;
2188 s390_opnd_RMI op2;
2189
2190 order_commutative_operands(arg1, arg2);
2191
2192 op1 = s390_isel_int_expr(env, arg1);
2193 op2 = s390_isel_int_expr_RMI(env, arg2);
2194
2195 addInstr(env, s390_insn_compare(size, op1, op2, False));
2196
2197 return result;
2198 }
2199
2200 case Iop_CmpLT32S:
2201 case Iop_CmpLE32S:
2202 case Iop_CmpLT64S:
2203 case Iop_CmpLE64S: {
2204 HReg op1;
2205 s390_opnd_RMI op2;
2206
2207 op1 = s390_isel_int_expr(env, arg1);
2208 op2 = s390_isel_int_expr_RMI(env, arg2);
2209
2210 addInstr(env, s390_insn_compare(size, op1, op2, True));
2211
2212 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2213 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2214 }
2215
2216 case Iop_CmpLT32U:
2217 case Iop_CmpLE32U:
2218 case Iop_CmpLT64U:
2219 case Iop_CmpLE64U: {
2220 HReg op1;
2221 s390_opnd_RMI op2;
2222
2223 op1 = s390_isel_int_expr(env, arg1);
2224 op2 = s390_isel_int_expr_RMI(env, arg2);
2225
2226 addInstr(env, s390_insn_compare(size, op1, op2, False));
2227
2228 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2229 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2230 }
2231
2232 default:
2233 goto fail;
2234 }
2235 }
2236
2237 fail:
2238 ppIRExpr(cond);
2239 vpanic("s390_isel_cc: unexpected operator");
2240}
2241
2242
2243/*---------------------------------------------------------*/
2244/*--- ISEL: Statements ---*/
2245/*---------------------------------------------------------*/
2246
2247static void
2248s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2249{
2250 if (vex_traceflags & VEX_TRACE_VCODE) {
2251 vex_printf("\n -- ");
2252 ppIRStmt(stmt);
2253 vex_printf("\n");
2254 }
2255
2256 switch (stmt->tag) {
2257
2258 /* --------- STORE --------- */
2259 case Ist_Store: {
2260 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2261 s390_amode *am;
2262 HReg src;
2263
2264 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2265
2266 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2267
2268 switch (tyd) {
2269 case Ity_I8:
2270 case Ity_I16:
2271 case Ity_I32:
2272 case Ity_I64:
2273 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2274 break;
2275
2276 case Ity_F32:
2277 case Ity_F64:
2278 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2279 break;
2280
2281 case Ity_F128:
2282 /* Cannot occur. No such instruction */
2283 vpanic("Ist_Store with F128 data");
2284
2285 default:
2286 goto stmt_fail;
2287 }
2288
2289 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2290 return;
2291 }
2292
2293 /* --------- PUT --------- */
2294 case Ist_Put: {
2295 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2296 HReg src;
2297 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002298 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002299
florianad43b3a2012-02-20 15:01:14 +00002300 /* Detect updates to certain guest registers. We track the contents
2301 of those registers as long as they contain constants. If the new
2302 constant is either zero or in the 8-bit neighbourhood of the
2303 current value we can use a memory-to-memory insn to do the update. */
2304
2305 Int offset = stmt->Ist.Put.offset;
2306
2307 /* Check necessary conditions:
2308 (1) must be one of the registers we care about
2309 (2) assigned value must be a constant */
2310 Int guest_reg = get_guest_reg(offset);
2311
2312 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2313
2314 if (guest_reg == GUEST_IA) {
2315 /* If this is the first assignment to the IA reg, don't special case
2316 it. We need to do a full 8-byte assignment here. The reason is
2317 that in case of a redirected translation the guest IA does not
2318 contain the redirected-to address. Instead it contains the
2319 redirected-from address and those can be far apart. So in order to
2320 do incremnetal updates if the IA in the future we need to get the
2321 initial address of the super block correct. */
2322 if (env->first_IA_assignment) {
2323 env->first_IA_assignment = False;
2324 goto not_special;
2325 }
2326 }
2327
2328 if (stmt->Ist.Put.data->tag != Iex_Const) {
2329 /* Invalidate guest register contents */
2330 env->old_value_valid[guest_reg] = False;
2331 goto not_special;
2332 }
2333
cborntraaf7ad282012-08-08 14:11:33 +00002334 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2335 if (tyd != Ity_I64)
2336 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002337
cborntraaf7ad282012-08-08 14:11:33 +00002338 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002339
2340 old_value = env->old_value[guest_reg];
2341 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2342 env->old_value[guest_reg] = new_value;
2343
2344 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2345 env->old_value_valid[guest_reg] = True;
2346
2347 /* If the register already contains the new value, there is nothing
2348 to do here. Unless the guest register requires precise memory
2349 exceptions. */
2350 if (old_value_is_valid && new_value == old_value) {
2351 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2352 return;
2353 }
2354 }
2355
2356 /* guest register = 0 */
2357 if (new_value == 0) {
2358 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2359 return;
2360 }
2361
2362 if (old_value_is_valid == False) goto not_special;
2363
2364 /* If the new value is in the neighbourhood of the old value
2365 we can use a memory-to-memory insn */
2366 difference = new_value - old_value;
2367
2368 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2369 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2370 (difference & 0xFF), new_value));
2371 return;
2372 }
2373
2374 /* If the high word is the same it is sufficient to load the low word.
2375 Use R0 as a scratch reg. */
2376 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002377 HReg r0 = make_gpr(0);
2378 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002379 s390_amode *gam;
2380
2381 gam = s390_amode_b12(offset + 4, gsp);
2382 addInstr(env, s390_insn_load_immediate(4, r0,
2383 new_value & 0xFFFFFFFF));
2384 addInstr(env, s390_insn_store(4, gam, r0));
2385 return;
2386 }
2387
2388 /* No special case applies... fall through */
2389
2390 not_special:
sewardj2019a972011-03-07 16:04:07 +00002391 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2392
2393 switch (tyd) {
2394 case Ity_I8:
2395 case Ity_I16:
2396 case Ity_I32:
2397 case Ity_I64:
2398 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2399 break;
2400
2401 case Ity_F32:
2402 case Ity_F64:
2403 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2404 break;
2405
2406 case Ity_F128:
2407 /* Does not occur. See function put_fpr_pair. */
2408 vpanic("Ist_Put with F128 data");
2409
2410 default:
2411 goto stmt_fail;
2412 }
2413
2414 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2415 return;
2416 }
2417
2418 /* --------- TMP --------- */
2419 case Ist_WrTmp: {
2420 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2421 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2422 HReg src, dst;
2423
2424 switch (tyd) {
2425 case Ity_I128: {
2426 HReg dst_hi, dst_lo, res_hi, res_lo;
2427
2428 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2429 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2430
2431 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2432 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2433 return;
2434 }
2435
2436 case Ity_I8:
2437 case Ity_I16:
2438 case Ity_I32:
2439 case Ity_I64:
2440 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2441 dst = lookupIRTemp(env, tmp);
2442 break;
2443
2444 case Ity_I1: {
2445 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2446 dst = lookupIRTemp(env, tmp);
2447 addInstr(env, s390_insn_cc2bool(dst, cond));
2448 return;
2449 }
2450
2451 case Ity_F32:
2452 case Ity_F64:
2453 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2454 dst = lookupIRTemp(env, tmp);
2455 break;
2456
2457 case Ity_F128: {
2458 HReg dst_hi, dst_lo, res_hi, res_lo;
2459
2460 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2461 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2462
2463 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2464 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2465 return;
2466 }
2467
2468 default:
2469 goto stmt_fail;
2470 }
2471
2472 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2473 return;
2474 }
2475
2476 /* --------- Call to DIRTY helper --------- */
2477 case Ist_Dirty: {
2478 IRType retty;
2479 IRDirty* d = stmt->Ist.Dirty.details;
2480 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002481 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002482 Int i;
2483
2484 /* Invalidate tracked values of those guest state registers that are
2485 modified by this helper. */
2486 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002487 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2488 descriptors in guest state effect descriptions. Hence: */
2489 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002490 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2491 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2492 if (guest_reg != GUEST_UNKNOWN)
2493 env->old_value_valid[guest_reg] = False;
2494 }
2495 }
sewardj2019a972011-03-07 16:04:07 +00002496
2497 if (d->nFxState == 0)
2498 vassert(!d->needsBBP);
2499
2500 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2501
florian01ed6e72012-05-27 16:52:43 +00002502 if (d->tmp == IRTemp_INVALID) {
2503 /* No return value. */
2504 dst = INVALID_HREG;
2505 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002506 return;
florian01ed6e72012-05-27 16:52:43 +00002507 }
sewardj2019a972011-03-07 16:04:07 +00002508
2509 retty = typeOfIRTemp(env->type_env, d->tmp);
2510 if (retty == Ity_I64 || retty == Ity_I32
2511 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002512 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002513 dst = lookupIRTemp(env, d->tmp);
2514 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002515 return;
2516 }
2517 break;
2518 }
2519
2520 case Ist_CAS:
2521 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2522 IRCAS *cas = stmt->Ist.CAS.details;
2523 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2524 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2525 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2526 HReg old = lookupIRTemp(env, cas->oldLo);
2527
2528 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2529 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2530 } else {
2531 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2532 }
2533 return;
2534 } else {
florian448cbba2012-06-06 02:26:01 +00002535 IRCAS *cas = stmt->Ist.CAS.details;
2536 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2537 HReg r8, r9, r10, r11, r1;
2538 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2539 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2540 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2541 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2542 HReg old_low = lookupIRTemp(env, cas->oldLo);
2543 HReg old_high = lookupIRTemp(env, cas->oldHi);
2544
2545 /* Use non-virtual registers r8 and r9 as pair for op1
2546 and move op1 there */
2547 r8 = make_gpr(8);
2548 r9 = make_gpr(9);
2549 addInstr(env, s390_insn_move(8, r8, op1_high));
2550 addInstr(env, s390_insn_move(8, r9, op1_low));
2551
2552 /* Use non-virtual registers r10 and r11 as pair for op3
2553 and move op3 there */
2554 r10 = make_gpr(10);
2555 r11 = make_gpr(11);
2556 addInstr(env, s390_insn_move(8, r10, op3_high));
2557 addInstr(env, s390_insn_move(8, r11, op3_low));
2558
2559 /* Register r1 is used as a scratch register */
2560 r1 = make_gpr(1);
2561
2562 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2563 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2564 old_high, old_low, r1));
2565 } else {
2566 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2567 old_high, old_low, r1));
2568 }
2569 addInstr(env, s390_insn_move(8, op1_high, r8));
2570 addInstr(env, s390_insn_move(8, op1_low, r9));
2571 addInstr(env, s390_insn_move(8, op3_high, r10));
2572 addInstr(env, s390_insn_move(8, op3_low, r11));
2573 return;
sewardj2019a972011-03-07 16:04:07 +00002574 }
2575 break;
2576
2577 /* --------- EXIT --------- */
2578 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002579 s390_cc_t cond;
2580 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2581
2582 if (tag != Ico_U64)
2583 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2584
florian8844a632012-04-13 04:04:06 +00002585 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002586 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002587
2588 /* Case: boring transfer to known address */
2589 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2590 if (env->chaining_allowed) {
2591 /* .. almost always true .. */
2592 /* Skip the event check at the dst if this is a forwards
2593 edge. */
2594 Bool to_fast_entry
2595 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2596 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2597 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2598 guest_IA, to_fast_entry));
2599 } else {
2600 /* .. very occasionally .. */
2601 /* We can't use chaining, so ask for an assisted transfer,
2602 as that's the only alternative that is allowable. */
2603 HReg dst = s390_isel_int_expr(env,
2604 IRExpr_Const(stmt->Ist.Exit.dst));
2605 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2606 }
2607 return;
2608 }
2609
2610 /* Case: assisted transfer to arbitrary address */
2611 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00002612 case Ijk_EmFail:
florian65b5b3f2012-04-22 02:51:27 +00002613 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002614 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002615 case Ijk_Sys_syscall:
2616 case Ijk_ClientReq:
2617 case Ijk_NoRedir:
2618 case Ijk_Yield:
2619 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002620 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2621 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2622 stmt->Ist.Exit.jk));
2623 return;
2624 }
2625 default:
2626 break;
2627 }
2628
2629 /* Do we ever expect to see any other kind? */
2630 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002631 }
2632
2633 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002634 case Ist_MBE:
2635 switch (stmt->Ist.MBE.event) {
2636 case Imbe_Fence:
2637 addInstr(env, s390_insn_mfence());
2638 return;
2639 default:
2640 break;
2641 }
sewardj2019a972011-03-07 16:04:07 +00002642 break;
2643
2644 /* --------- Miscellaneous --------- */
2645
2646 case Ist_PutI: /* Not needed */
2647 case Ist_IMark: /* Doesn't generate any executable code */
2648 case Ist_NoOp: /* Doesn't generate any executable code */
2649 case Ist_AbiHint: /* Meaningless in IR */
2650 return;
2651
2652 default:
2653 break;
2654 }
2655
2656 stmt_fail:
2657 ppIRStmt(stmt);
2658 vpanic("s390_isel_stmt");
2659}
2660
2661
2662/*---------------------------------------------------------*/
2663/*--- ISEL: Basic block terminators (Nexts) ---*/
2664/*---------------------------------------------------------*/
2665
2666static void
florian8844a632012-04-13 04:04:06 +00002667iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002668{
sewardj2019a972011-03-07 16:04:07 +00002669 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002670 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002671 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002672 vex_printf("; exit-");
2673 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002674 vex_printf("\n");
2675 }
2676
florian8844a632012-04-13 04:04:06 +00002677 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2678
2679 /* Case: boring transfer to known address */
2680 if (next->tag == Iex_Const) {
2681 IRConst *cdst = next->Iex.Const.con;
2682 vassert(cdst->tag == Ico_U64);
2683 if (jk == Ijk_Boring || jk == Ijk_Call) {
2684 /* Boring transfer to known address */
2685 if (env->chaining_allowed) {
2686 /* .. almost always true .. */
2687 /* Skip the event check at the dst if this is a forwards
2688 edge. */
2689 Bool to_fast_entry
2690 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2691 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2692 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2693 guest_IA, to_fast_entry));
2694 } else {
2695 /* .. very occasionally .. */
2696 /* We can't use chaining, so ask for an indirect transfer,
2697 as that's the cheapest alternative that is allowable. */
2698 HReg dst = s390_isel_int_expr(env, next);
2699 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2700 Ijk_Boring));
2701 }
2702 return;
2703 }
2704 }
2705
2706 /* Case: call/return (==boring) transfer to any address */
2707 switch (jk) {
2708 case Ijk_Boring:
2709 case Ijk_Ret:
2710 case Ijk_Call: {
2711 HReg dst = s390_isel_int_expr(env, next);
2712 if (env->chaining_allowed) {
2713 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2714 } else {
2715 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2716 Ijk_Boring));
2717 }
2718 return;
2719 }
2720 default:
2721 break;
2722 }
2723
2724 /* Case: some other kind of transfer to any address */
2725 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00002726 case Ijk_EmFail:
florian65b5b3f2012-04-22 02:51:27 +00002727 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002728 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002729 case Ijk_Sys_syscall:
2730 case Ijk_ClientReq:
2731 case Ijk_NoRedir:
2732 case Ijk_Yield:
2733 case Ijk_SigTRAP: {
2734 HReg dst = s390_isel_int_expr(env, next);
2735 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2736 return;
2737 }
2738 default:
2739 break;
2740 }
2741
2742 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002743}
2744
2745
2746/*---------------------------------------------------------*/
2747/*--- Insn selector top-level ---*/
2748/*---------------------------------------------------------*/
2749
florianf26994a2012-04-21 03:34:54 +00002750/* Translate an entire SB to s390 code.
2751 Note: archinfo_host is a pointer to a stack-allocated variable.
2752 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002753
2754HInstrArray *
2755iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002756 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2757 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2758 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002759{
2760 UInt i, j;
2761 HReg hreg, hregHI;
2762 ISelEnv *env;
2763 UInt hwcaps_host = archinfo_host->hwcaps;
2764
florianf26994a2012-04-21 03:34:54 +00002765 /* KLUDGE: export hwcaps. */
2766 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002767
sewardj2019a972011-03-07 16:04:07 +00002768 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002769 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002770
2771 /* Make up an initial environment to use. */
2772 env = LibVEX_Alloc(sizeof(ISelEnv));
2773 env->vreg_ctr = 0;
2774
2775 /* Set up output code array. */
2776 env->code = newHInstrArray();
2777
2778 /* Copy BB's type env. */
2779 env->type_env = bb->tyenv;
2780
florianad43b3a2012-02-20 15:01:14 +00002781 /* Set up data structures for tracking guest register values. */
2782 env->first_IA_assignment = True;
2783 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2784 env->old_value[i] = 0; /* just something to have a defined value */
2785 env->old_value_valid[i] = False;
2786 }
2787
sewardj2019a972011-03-07 16:04:07 +00002788 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2789 change as we go along. For some reason types_used has Int type -- but
2790 it should be unsigned. Internally we use an unsigned type; so we
2791 assert it here. */
2792 vassert(bb->tyenv->types_used >= 0);
2793
2794 env->n_vregmap = bb->tyenv->types_used;
2795 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2796 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2797
2798 /* and finally ... */
2799 env->hwcaps = hwcaps_host;
2800
florian8844a632012-04-13 04:04:06 +00002801 env->max_ga = max_ga;
2802 env->chaining_allowed = chaining_allowed;
2803
sewardj2019a972011-03-07 16:04:07 +00002804 /* For each IR temporary, allocate a suitably-kinded virtual
2805 register. */
2806 j = 0;
2807 for (i = 0; i < env->n_vregmap; i++) {
2808 hregHI = hreg = INVALID_HREG;
2809 switch (bb->tyenv->types[i]) {
2810 case Ity_I1:
2811 case Ity_I8:
2812 case Ity_I16:
2813 case Ity_I32:
2814 hreg = mkHReg(j++, HRcInt64, True);
2815 break;
2816
2817 case Ity_I64:
2818 hreg = mkHReg(j++, HRcInt64, True);
2819 break;
2820
2821 case Ity_I128:
2822 hreg = mkHReg(j++, HRcInt64, True);
2823 hregHI = mkHReg(j++, HRcInt64, True);
2824 break;
2825
2826 case Ity_F32:
2827 case Ity_F64:
2828 hreg = mkHReg(j++, HRcFlt64, True);
2829 break;
2830
2831 case Ity_F128:
2832 hreg = mkHReg(j++, HRcFlt64, True);
2833 hregHI = mkHReg(j++, HRcFlt64, True);
2834 break;
2835
2836 case Ity_V128: /* fall through */
2837 default:
2838 ppIRType(bb->tyenv->types[i]);
2839 vpanic("s390_isel_sb: IRTemp type");
2840 }
2841
2842 env->vregmap[i] = hreg;
2843 env->vregmapHI[i] = hregHI;
2844 }
2845 env->vreg_ctr = j;
2846
florian8844a632012-04-13 04:04:06 +00002847 /* The very first instruction must be an event check. */
2848 s390_amode *counter, *fail_addr;
2849 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2850 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2851 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2852
2853 /* Possibly a block counter increment (for profiling). At this
2854 point we don't know the address of the counter, so just pretend
2855 it is zero. It will have to be patched later, but before this
2856 translation is used, by a call to LibVEX_patchProfInc. */
2857 if (add_profinc) {
2858 addInstr(env, s390_insn_profinc());
2859 }
2860
sewardj2019a972011-03-07 16:04:07 +00002861 /* Ok, finally we can iterate over the statements. */
2862 for (i = 0; i < bb->stmts_used; i++)
2863 if (bb->stmts[i])
2864 s390_isel_stmt(env, bb->stmts[i]);
2865
florian8844a632012-04-13 04:04:06 +00002866 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002867
2868 /* Record the number of vregs we used. */
2869 env->code->n_vregs = env->vreg_ctr;
2870
2871 return env->code;
2872}
2873
2874/*---------------------------------------------------------------*/
2875/*--- end host_s390_isel.c ---*/
2876/*---------------------------------------------------------------*/