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