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