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