blob: 76173d24055f08384a09c367de8ff733a543c0d0 [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: {
1520 IROp op = expr->Iex.Triop.op;
1521 IRExpr *left = expr->Iex.Triop.arg2;
1522 IRExpr *right = expr->Iex.Triop.arg3;
1523 s390_bfp_binop_t bfpop;
1524 s390_round_t rounding_mode;
1525 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1526
1527 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1528 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1529
1530 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1531 f12 = make_fpr(12);
1532 f13 = make_fpr(13);
1533 f14 = make_fpr(14);
1534 f15 = make_fpr(15);
1535
1536 /* 1st operand --> (f12, f14) */
1537 addInstr(env, s390_insn_move(8, f12, op1_hi));
1538 addInstr(env, s390_insn_move(8, f14, op1_lo));
1539
1540 /* 2nd operand --> (f13, f15) */
1541 addInstr(env, s390_insn_move(8, f13, op2_hi));
1542 addInstr(env, s390_insn_move(8, f15, op2_lo));
1543
1544 switch (op) {
1545 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1546 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1547 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1548 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1549 default:
1550 goto irreducible;
1551 }
1552
1553 rounding_mode = decode_rounding_mode(expr->Iex.Triop.arg1);
1554 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1555 f15, rounding_mode));
1556
1557 /* Move result to virtual destination register */
1558 *dst_hi = newVRegF(env);
1559 *dst_lo = newVRegF(env);
1560 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1561 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1562
1563 return;
1564 }
1565
1566 /* --------- BINARY OP --------- */
1567 case Iex_Binop: {
1568 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardja970c402011-04-28 18:38:42 +00001569 s390_bfp_unop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001570 s390_round_t rounding_mode;
1571
1572 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1573 f12 = make_fpr(12);
1574 f13 = make_fpr(13);
1575 f14 = make_fpr(14);
1576 f15 = make_fpr(15);
1577
1578 switch (expr->Iex.Binop.op) {
1579 case Iop_SqrtF128:
1580 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1581
1582 /* operand --> (f13, f15) */
1583 addInstr(env, s390_insn_move(8, f13, op_hi));
1584 addInstr(env, s390_insn_move(8, f15, op_lo));
1585
1586 bfpop = S390_BFP_SQRT;
1587 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1588
1589 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1590 rounding_mode));
1591
1592 /* Move result to virtual destination registers */
1593 *dst_hi = newVRegF(env);
1594 *dst_lo = newVRegF(env);
1595 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1596 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1597 return;
1598
1599 case Iop_F64HLtoF128:
1600 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1601 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1602 return;
1603
1604 default:
1605 goto irreducible;
1606 }
1607 }
1608
1609 /* --------- UNARY OP --------- */
1610 case Iex_Unop: {
1611 IRExpr *left = expr->Iex.Binop.arg1;
1612 s390_bfp_unop_t bfpop;
1613 s390_round_t rounding_mode;
1614 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1615
1616 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1617 f12 = make_fpr(12);
1618 f13 = make_fpr(13);
1619 f14 = make_fpr(14);
1620 f15 = make_fpr(15);
1621
1622 switch (expr->Iex.Binop.op) {
1623 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1624 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1625 case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int;
1626 case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int;
1627 case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float;
1628 case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float;
1629 default:
1630 goto irreducible;
1631 }
1632
1633 float128_opnd:
1634 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1635
1636 /* operand --> (f13, f15) */
1637 addInstr(env, s390_insn_move(8, f13, op_hi));
1638 addInstr(env, s390_insn_move(8, f15, op_lo));
1639
1640 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1641 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1642 rounding_mode));
1643 goto move_dst;
1644
1645 convert_float:
1646 op = s390_isel_float_expr(env, left);
1647 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1648 op));
1649 goto move_dst;
1650
1651 convert_int:
1652 op = s390_isel_int_expr(env, left);
1653 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1654 op));
1655 goto move_dst;
1656
1657 move_dst:
1658 /* Move result to virtual destination registers */
1659 *dst_hi = newVRegF(env);
1660 *dst_lo = newVRegF(env);
1661 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1662 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1663 return;
1664 }
1665
1666 default:
1667 goto irreducible;
1668 }
1669
1670 /* We get here if no pattern matched. */
1671 irreducible:
1672 ppIRExpr(expr);
1673 vpanic("s390_isel_int_expr: cannot reduce tree");
1674}
1675
1676/* Compute a 128-bit value into two 64-bit registers. These may be either
1677 real or virtual regs; in any case they must not be changed by subsequent
1678 code emitted by the caller. */
1679static void
1680s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1681{
1682 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1683
1684 /* Sanity checks ... */
1685 vassert(hregIsVirtual(*dst_hi));
1686 vassert(hregIsVirtual(*dst_lo));
1687 vassert(hregClass(*dst_hi) == HRcFlt64);
1688 vassert(hregClass(*dst_lo) == HRcFlt64);
1689}
1690
1691
1692/*---------------------------------------------------------*/
1693/*--- ISEL: Floating point expressions (64 bit) ---*/
1694/*---------------------------------------------------------*/
1695
1696static HReg
1697s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1698{
1699 IRType ty = typeOfIRExpr(env->type_env, expr);
1700 UChar size;
1701
1702 vassert(ty == Ity_F32 || ty == Ity_F64);
1703
1704 size = sizeofIRType(ty);
1705
1706 switch (expr->tag) {
1707 case Iex_RdTmp:
1708 /* Return the virtual register that holds the temporary. */
1709 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1710
1711 /* --------- LOAD --------- */
1712 case Iex_Load: {
1713 HReg dst = newVRegF(env);
1714 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1715
1716 if (expr->Iex.Load.end != Iend_BE)
1717 goto irreducible;
1718
1719 addInstr(env, s390_insn_load(size, dst, am));
1720
1721 return dst;
1722 }
1723
1724 /* --------- GET --------- */
1725 case Iex_Get: {
1726 HReg dst = newVRegF(env);
1727 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1728
1729 addInstr(env, s390_insn_load(size, dst, am));
1730
1731 return dst;
1732 }
1733
1734 /* --------- LITERAL --------- */
1735
1736 /* Load a literal into a register. Create a "load immediate"
1737 v-insn and return the register. */
1738 case Iex_Const: {
1739 ULong value;
1740 HReg dst = newVRegF(env);
1741 const IRConst *con = expr->Iex.Const.con;
1742
1743 /* Bitwise copy of the value. No sign/zero-extension */
1744 switch (con->tag) {
1745 case Ico_F32i: value = con->Ico.F32i; break;
1746 case Ico_F64i: value = con->Ico.F64i; break;
1747 default: vpanic("s390_isel_float_expr: invalid constant");
1748 }
1749
1750 if (value != 0) vpanic("cannot load immediate floating point constant");
1751
1752 addInstr(env, s390_insn_load_immediate(size, dst, value));
1753
1754 return dst;
1755 }
1756
1757 /* --------- 4-ary OP --------- */
1758 case Iex_Qop: {
1759 HReg op1, op2, op3, dst;
1760 s390_bfp_triop_t bfpop;
1761 s390_round_t rounding_mode;
1762
1763 op1 = s390_isel_float_expr(env, expr->Iex.Qop.arg2);
1764 op2 = s390_isel_float_expr(env, expr->Iex.Qop.arg3);
1765 op3 = s390_isel_float_expr(env, expr->Iex.Qop.arg4);
1766 dst = newVRegF(env);
1767 addInstr(env, s390_insn_move(size, dst, op1));
1768
1769 switch (expr->Iex.Qop.op) {
1770 case Iop_MAddF32:
1771 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1772 case Iop_MSubF32:
1773 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1774
1775 default:
1776 goto irreducible;
1777 }
1778
1779 rounding_mode = decode_rounding_mode(expr->Iex.Qop.arg1);
1780 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1781 rounding_mode));
1782 return dst;
1783 }
1784
1785 /* --------- TERNARY OP --------- */
1786 case Iex_Triop: {
1787 IROp op = expr->Iex.Triop.op;
1788 IRExpr *left = expr->Iex.Triop.arg2;
1789 IRExpr *right = expr->Iex.Triop.arg3;
1790 s390_bfp_binop_t bfpop;
1791 s390_round_t rounding_mode;
1792 HReg h1, op2, dst;
1793
1794 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1795 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1796 dst = newVRegF(env);
1797 addInstr(env, s390_insn_move(size, dst, h1));
1798 switch (op) {
1799 case Iop_AddF32:
1800 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1801 case Iop_SubF32:
1802 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1803 case Iop_MulF32:
1804 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1805 case Iop_DivF32:
1806 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1807
1808 default:
1809 goto irreducible;
1810 }
1811
1812 rounding_mode = decode_rounding_mode(expr->Iex.Triop.arg1);
1813 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1814 return dst;
1815 }
1816
1817 /* --------- BINARY OP --------- */
1818 case Iex_Binop: {
1819 IROp op = expr->Iex.Binop.op;
1820 IRExpr *left = expr->Iex.Binop.arg2;
1821 HReg h1, dst;
1822 s390_bfp_unop_t bfpop;
1823 s390_round_t rounding_mode;
1824 Int integer_operand;
1825
1826 integer_operand = 1;
1827
1828 switch (op) {
1829 case Iop_SqrtF32:
1830 case Iop_SqrtF64:
1831 bfpop = S390_BFP_SQRT;
1832 integer_operand = 0;
1833 break;
1834
1835 case Iop_F64toF32:
1836 bfpop = S390_BFP_F64_TO_F32;
1837 integer_operand = 0;
1838 break;
1839
1840 case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break;
1841 case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break;
1842 case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break;
1843 default:
1844 goto irreducible;
1845
1846 case Iop_F128toF64:
1847 case Iop_F128toF32: {
1848 HReg op_hi, op_lo, f12, f13, f14, f15;
1849
1850 bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1851 : S390_BFP_F128_TO_F64;
1852
1853 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1854
1855 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1856
1857 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1858 f12 = make_fpr(12);
1859 f13 = make_fpr(13);
1860 f14 = make_fpr(14);
1861 f15 = make_fpr(15);
1862
1863 /* operand --> (f13, f15) */
1864 addInstr(env, s390_insn_move(8, f13, op_hi));
1865 addInstr(env, s390_insn_move(8, f15, op_lo));
1866
1867 dst = newVRegF(env);
1868 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1869 rounding_mode));
1870
1871 /* Move result to virtual destination registers */
1872 addInstr(env, s390_insn_move(8, dst, f12));
1873 return dst;
1874 }
1875 }
1876
1877 /* Process operand */
1878 if (integer_operand) {
1879 h1 = s390_isel_int_expr(env, left);
1880 } else {
1881 h1 = s390_isel_float_expr(env, left);
1882 }
1883
1884 dst = newVRegF(env);
1885 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1886 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1887 return dst;
1888 }
1889
1890 /* --------- UNARY OP --------- */
1891 case Iex_Unop: {
1892 IROp op = expr->Iex.Unop.op;
1893 IRExpr *left = expr->Iex.Unop.arg;
1894 s390_bfp_unop_t bfpop;
1895 s390_round_t rounding_mode;
1896 HReg h1, dst;
1897
1898 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1899 HReg dst_hi, dst_lo;
1900
1901 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1902 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1903 }
1904
florian4d71a082011-12-18 00:08:17 +00001905 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00001906 dst = newVRegF(env);
1907 h1 = s390_isel_int_expr(env, left); /* Process the operand */
1908 addInstr(env, s390_insn_move(size, dst, h1));
1909
1910 return dst;
1911 }
1912
1913 switch (op) {
1914 case Iop_NegF32:
1915 case Iop_NegF64:
1916 if (left->tag == Iex_Unop &&
1917 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1918 bfpop = S390_BFP_NABS;
1919 else
1920 bfpop = S390_BFP_NEG;
1921 break;
1922
1923 case Iop_AbsF32:
1924 case Iop_AbsF64: bfpop = S390_BFP_ABS; break;
1925 case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break;
1926 case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break;
1927 default:
1928 goto irreducible;
1929 }
1930
1931 /* Process operand */
1932 if (op == Iop_I32StoF64)
1933 h1 = s390_isel_int_expr(env, left);
1934 else if (bfpop == S390_BFP_NABS)
1935 h1 = s390_isel_float_expr(env, left->Iex.Unop.arg);
1936 else
1937 h1 = s390_isel_float_expr(env, left);
1938
1939 dst = newVRegF(env);
1940 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1941 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1942 return dst;
1943 }
1944
1945 default:
1946 goto irreducible;
1947 }
1948
1949 /* We get here if no pattern matched. */
1950 irreducible:
1951 ppIRExpr(expr);
1952 vpanic("s390_isel_float_expr: cannot reduce tree");
1953}
1954
1955
1956static HReg
1957s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
1958{
1959 HReg dst = s390_isel_float_expr_wrk(env, expr);
1960
1961 /* Sanity checks ... */
1962 vassert(hregClass(dst) == HRcFlt64);
1963 vassert(hregIsVirtual(dst));
1964
1965 return dst;
1966}
1967
1968
1969/*---------------------------------------------------------*/
1970/*--- ISEL: Condition Code ---*/
1971/*---------------------------------------------------------*/
1972
1973/* This function handles all operators that produce a 1-bit result */
1974static s390_cc_t
1975s390_isel_cc(ISelEnv *env, IRExpr *cond)
1976{
1977 UChar size;
1978
1979 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
1980
1981 /* Constant: either 1 or 0 */
1982 if (cond->tag == Iex_Const) {
1983 vassert(cond->Iex.Const.con->tag == Ico_U1);
1984 vassert(cond->Iex.Const.con->Ico.U1 == True
1985 || cond->Iex.Const.con->Ico.U1 == False);
1986
1987 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
1988 }
1989
1990 /* Variable: values are 1 or 0 */
1991 if (cond->tag == Iex_RdTmp) {
1992 IRTemp tmp = cond->Iex.RdTmp.tmp;
1993 HReg reg = lookupIRTemp(env, tmp);
1994
1995 /* Load-and-test does not modify REG; so this is OK. */
1996 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
1997 size = 4;
1998 else
1999 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2000 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2001 return S390_CC_NE;
2002 }
2003
2004 /* Unary operators */
2005 if (cond->tag == Iex_Unop) {
2006 IRExpr *arg = cond->Iex.Unop.arg;
2007
2008 switch (cond->Iex.Unop.op) {
2009 case Iop_Not1: /* Not1(cond) */
2010 /* Generate code for EXPR, and negate the test condition */
2011 return s390_cc_invert(s390_isel_cc(env, arg));
2012
2013 /* Iop_32/64to1 select the LSB from their operand */
2014 case Iop_32to1:
2015 case Iop_64to1: {
2016 HReg dst = s390_isel_int_expr(env, arg);
2017
2018 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2019
2020 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2021 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2022 return S390_CC_NE;
2023 }
2024
2025 case Iop_CmpNEZ8:
2026 case Iop_CmpNEZ16: {
2027 s390_opnd_RMI src;
2028 s390_unop_t op;
2029 HReg dst;
2030
2031 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2032 : S390_ZERO_EXTEND_16;
2033 dst = newVRegI(env);
2034 src = s390_isel_int_expr_RMI(env, arg);
2035 addInstr(env, s390_insn_unop(4, op, dst, src));
2036 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2037 return S390_CC_NE;
2038 }
2039
2040 case Iop_CmpNEZ32:
2041 case Iop_CmpNEZ64: {
2042 s390_opnd_RMI src;
2043
2044 src = s390_isel_int_expr_RMI(env, arg);
2045 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2046 addInstr(env, s390_insn_test(size, src));
2047 return S390_CC_NE;
2048 }
2049
2050 default:
2051 goto fail;
2052 }
2053 }
2054
2055 /* Binary operators */
2056 if (cond->tag == Iex_Binop) {
2057 IRExpr *arg1 = cond->Iex.Binop.arg1;
2058 IRExpr *arg2 = cond->Iex.Binop.arg2;
2059 HReg reg1, reg2;
2060
2061 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2062
2063 switch (cond->Iex.Binop.op) {
2064 s390_unop_t op;
2065 s390_cc_t result;
2066
2067 case Iop_CmpEQ8:
2068 case Iop_CasCmpEQ8:
2069 op = S390_ZERO_EXTEND_8;
2070 result = S390_CC_E;
2071 goto do_compare_ze;
2072
2073 case Iop_CmpNE8:
2074 case Iop_CasCmpNE8:
2075 op = S390_ZERO_EXTEND_8;
2076 result = S390_CC_NE;
2077 goto do_compare_ze;
2078
2079 case Iop_CmpEQ16:
2080 case Iop_CasCmpEQ16:
2081 op = S390_ZERO_EXTEND_16;
2082 result = S390_CC_E;
2083 goto do_compare_ze;
2084
2085 case Iop_CmpNE16:
2086 case Iop_CasCmpNE16:
2087 op = S390_ZERO_EXTEND_16;
2088 result = S390_CC_NE;
2089 goto do_compare_ze;
2090
2091 do_compare_ze: {
2092 s390_opnd_RMI op1, op2;
2093
2094 op1 = s390_isel_int_expr_RMI(env, arg1);
2095 reg1 = newVRegI(env);
2096 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2097
2098 op2 = s390_isel_int_expr_RMI(env, arg2);
2099 reg2 = newVRegI(env);
2100 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2101
2102 op2 = s390_opnd_reg(reg2);
2103 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2104
2105 return result;
2106 }
2107
2108 case Iop_CmpEQ32:
2109 case Iop_CmpEQ64:
2110 case Iop_CasCmpEQ32:
2111 case Iop_CasCmpEQ64:
2112 result = S390_CC_E;
2113 goto do_compare;
2114
2115 case Iop_CmpNE32:
2116 case Iop_CmpNE64:
2117 case Iop_CasCmpNE32:
2118 case Iop_CasCmpNE64:
2119 result = S390_CC_NE;
2120 goto do_compare;
2121
2122 do_compare: {
2123 HReg op1;
2124 s390_opnd_RMI op2;
2125
2126 order_commutative_operands(arg1, arg2);
2127
2128 op1 = s390_isel_int_expr(env, arg1);
2129 op2 = s390_isel_int_expr_RMI(env, arg2);
2130
2131 addInstr(env, s390_insn_compare(size, op1, op2, False));
2132
2133 return result;
2134 }
2135
2136 case Iop_CmpLT32S:
2137 case Iop_CmpLE32S:
2138 case Iop_CmpLT64S:
2139 case Iop_CmpLE64S: {
2140 HReg op1;
2141 s390_opnd_RMI op2;
2142
2143 op1 = s390_isel_int_expr(env, arg1);
2144 op2 = s390_isel_int_expr_RMI(env, arg2);
2145
2146 addInstr(env, s390_insn_compare(size, op1, op2, True));
2147
2148 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2149 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2150 }
2151
2152 case Iop_CmpLT32U:
2153 case Iop_CmpLE32U:
2154 case Iop_CmpLT64U:
2155 case Iop_CmpLE64U: {
2156 HReg op1;
2157 s390_opnd_RMI op2;
2158
2159 op1 = s390_isel_int_expr(env, arg1);
2160 op2 = s390_isel_int_expr_RMI(env, arg2);
2161
2162 addInstr(env, s390_insn_compare(size, op1, op2, False));
2163
2164 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2165 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2166 }
2167
2168 default:
2169 goto fail;
2170 }
2171 }
2172
2173 fail:
2174 ppIRExpr(cond);
2175 vpanic("s390_isel_cc: unexpected operator");
2176}
2177
2178
2179/*---------------------------------------------------------*/
2180/*--- ISEL: Statements ---*/
2181/*---------------------------------------------------------*/
2182
2183static void
2184s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2185{
2186 if (vex_traceflags & VEX_TRACE_VCODE) {
2187 vex_printf("\n -- ");
2188 ppIRStmt(stmt);
2189 vex_printf("\n");
2190 }
2191
2192 switch (stmt->tag) {
2193
2194 /* --------- STORE --------- */
2195 case Ist_Store: {
2196 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2197 s390_amode *am;
2198 HReg src;
2199
2200 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2201
2202 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2203
2204 switch (tyd) {
2205 case Ity_I8:
2206 case Ity_I16:
2207 case Ity_I32:
2208 case Ity_I64:
2209 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2210 break;
2211
2212 case Ity_F32:
2213 case Ity_F64:
2214 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2215 break;
2216
2217 case Ity_F128:
2218 /* Cannot occur. No such instruction */
2219 vpanic("Ist_Store with F128 data");
2220
2221 default:
2222 goto stmt_fail;
2223 }
2224
2225 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2226 return;
2227 }
2228
2229 /* --------- PUT --------- */
2230 case Ist_Put: {
2231 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2232 HReg src;
2233 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002234 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002235
florianad43b3a2012-02-20 15:01:14 +00002236 /* Detect updates to certain guest registers. We track the contents
2237 of those registers as long as they contain constants. If the new
2238 constant is either zero or in the 8-bit neighbourhood of the
2239 current value we can use a memory-to-memory insn to do the update. */
2240
2241 Int offset = stmt->Ist.Put.offset;
2242
2243 /* Check necessary conditions:
2244 (1) must be one of the registers we care about
2245 (2) assigned value must be a constant */
2246 Int guest_reg = get_guest_reg(offset);
2247
2248 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2249
2250 if (guest_reg == GUEST_IA) {
2251 /* If this is the first assignment to the IA reg, don't special case
2252 it. We need to do a full 8-byte assignment here. The reason is
2253 that in case of a redirected translation the guest IA does not
2254 contain the redirected-to address. Instead it contains the
2255 redirected-from address and those can be far apart. So in order to
2256 do incremnetal updates if the IA in the future we need to get the
2257 initial address of the super block correct. */
2258 if (env->first_IA_assignment) {
2259 env->first_IA_assignment = False;
2260 goto not_special;
2261 }
2262 }
2263
2264 if (stmt->Ist.Put.data->tag != Iex_Const) {
2265 /* Invalidate guest register contents */
2266 env->old_value_valid[guest_reg] = False;
2267 goto not_special;
2268 }
2269
2270 /* OK. Necessary conditions are satisfied. */
2271
2272 /* Get the old value and update it */
2273 vassert(tyd == Ity_I64);
2274
2275 old_value = env->old_value[guest_reg];
2276 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2277 env->old_value[guest_reg] = new_value;
2278
2279 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2280 env->old_value_valid[guest_reg] = True;
2281
2282 /* If the register already contains the new value, there is nothing
2283 to do here. Unless the guest register requires precise memory
2284 exceptions. */
2285 if (old_value_is_valid && new_value == old_value) {
2286 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2287 return;
2288 }
2289 }
2290
2291 /* guest register = 0 */
2292 if (new_value == 0) {
2293 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2294 return;
2295 }
2296
2297 if (old_value_is_valid == False) goto not_special;
2298
2299 /* If the new value is in the neighbourhood of the old value
2300 we can use a memory-to-memory insn */
2301 difference = new_value - old_value;
2302
2303 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2304 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2305 (difference & 0xFF), new_value));
2306 return;
2307 }
2308
2309 /* If the high word is the same it is sufficient to load the low word.
2310 Use R0 as a scratch reg. */
2311 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002312 HReg r0 = make_gpr(0);
2313 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002314 s390_amode *gam;
2315
2316 gam = s390_amode_b12(offset + 4, gsp);
2317 addInstr(env, s390_insn_load_immediate(4, r0,
2318 new_value & 0xFFFFFFFF));
2319 addInstr(env, s390_insn_store(4, gam, r0));
2320 return;
2321 }
2322
2323 /* No special case applies... fall through */
2324
2325 not_special:
sewardj2019a972011-03-07 16:04:07 +00002326 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2327
2328 switch (tyd) {
2329 case Ity_I8:
2330 case Ity_I16:
2331 case Ity_I32:
2332 case Ity_I64:
2333 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2334 break;
2335
2336 case Ity_F32:
2337 case Ity_F64:
2338 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2339 break;
2340
2341 case Ity_F128:
2342 /* Does not occur. See function put_fpr_pair. */
2343 vpanic("Ist_Put with F128 data");
2344
2345 default:
2346 goto stmt_fail;
2347 }
2348
2349 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2350 return;
2351 }
2352
2353 /* --------- TMP --------- */
2354 case Ist_WrTmp: {
2355 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2356 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2357 HReg src, dst;
2358
2359 switch (tyd) {
2360 case Ity_I128: {
2361 HReg dst_hi, dst_lo, res_hi, res_lo;
2362
2363 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2364 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2365
2366 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2367 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2368 return;
2369 }
2370
2371 case Ity_I8:
2372 case Ity_I16:
2373 case Ity_I32:
2374 case Ity_I64:
2375 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2376 dst = lookupIRTemp(env, tmp);
2377 break;
2378
2379 case Ity_I1: {
2380 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2381 dst = lookupIRTemp(env, tmp);
2382 addInstr(env, s390_insn_cc2bool(dst, cond));
2383 return;
2384 }
2385
2386 case Ity_F32:
2387 case Ity_F64:
2388 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2389 dst = lookupIRTemp(env, tmp);
2390 break;
2391
2392 case Ity_F128: {
2393 HReg dst_hi, dst_lo, res_hi, res_lo;
2394
2395 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2396 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2397
2398 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2399 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2400 return;
2401 }
2402
2403 default:
2404 goto stmt_fail;
2405 }
2406
2407 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2408 return;
2409 }
2410
2411 /* --------- Call to DIRTY helper --------- */
2412 case Ist_Dirty: {
2413 IRType retty;
2414 IRDirty* d = stmt->Ist.Dirty.details;
2415 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002416 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002417 Int i;
2418
2419 /* Invalidate tracked values of those guest state registers that are
2420 modified by this helper. */
2421 for (i = 0; i < d->nFxState; ++i) {
2422 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2423 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2424 if (guest_reg != GUEST_UNKNOWN)
2425 env->old_value_valid[guest_reg] = False;
2426 }
2427 }
sewardj2019a972011-03-07 16:04:07 +00002428
2429 if (d->nFxState == 0)
2430 vassert(!d->needsBBP);
2431
2432 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2433
florian01ed6e72012-05-27 16:52:43 +00002434 if (d->tmp == IRTemp_INVALID) {
2435 /* No return value. */
2436 dst = INVALID_HREG;
2437 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002438 return;
florian01ed6e72012-05-27 16:52:43 +00002439 }
sewardj2019a972011-03-07 16:04:07 +00002440
2441 retty = typeOfIRTemp(env->type_env, d->tmp);
2442 if (retty == Ity_I64 || retty == Ity_I32
2443 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002444 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002445 dst = lookupIRTemp(env, d->tmp);
2446 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002447 return;
2448 }
2449 break;
2450 }
2451
2452 case Ist_CAS:
2453 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2454 IRCAS *cas = stmt->Ist.CAS.details;
2455 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2456 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2457 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2458 HReg old = lookupIRTemp(env, cas->oldLo);
2459
2460 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2461 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2462 } else {
2463 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2464 }
2465 return;
2466 } else {
2467 vpanic("compare double and swap not implemented\n");
2468 }
2469 break;
2470
2471 /* --------- EXIT --------- */
2472 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002473 s390_cc_t cond;
2474 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2475
2476 if (tag != Ico_U64)
2477 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2478
florian8844a632012-04-13 04:04:06 +00002479 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002480 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002481
2482 /* Case: boring transfer to known address */
2483 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2484 if (env->chaining_allowed) {
2485 /* .. almost always true .. */
2486 /* Skip the event check at the dst if this is a forwards
2487 edge. */
2488 Bool to_fast_entry
2489 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2490 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2491 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2492 guest_IA, to_fast_entry));
2493 } else {
2494 /* .. very occasionally .. */
2495 /* We can't use chaining, so ask for an assisted transfer,
2496 as that's the only alternative that is allowable. */
2497 HReg dst = s390_isel_int_expr(env,
2498 IRExpr_Const(stmt->Ist.Exit.dst));
2499 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2500 }
2501 return;
2502 }
2503
2504 /* Case: assisted transfer to arbitrary address */
2505 switch (stmt->Ist.Exit.jk) {
florian65b5b3f2012-04-22 02:51:27 +00002506 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002507 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002508 case Ijk_Sys_syscall:
2509 case Ijk_ClientReq:
2510 case Ijk_NoRedir:
2511 case Ijk_Yield:
2512 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002513 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2514 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2515 stmt->Ist.Exit.jk));
2516 return;
2517 }
2518 default:
2519 break;
2520 }
2521
2522 /* Do we ever expect to see any other kind? */
2523 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002524 }
2525
2526 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002527 case Ist_MBE:
2528 switch (stmt->Ist.MBE.event) {
2529 case Imbe_Fence:
2530 addInstr(env, s390_insn_mfence());
2531 return;
2532 default:
2533 break;
2534 }
sewardj2019a972011-03-07 16:04:07 +00002535 break;
2536
2537 /* --------- Miscellaneous --------- */
2538
2539 case Ist_PutI: /* Not needed */
2540 case Ist_IMark: /* Doesn't generate any executable code */
2541 case Ist_NoOp: /* Doesn't generate any executable code */
2542 case Ist_AbiHint: /* Meaningless in IR */
2543 return;
2544
2545 default:
2546 break;
2547 }
2548
2549 stmt_fail:
2550 ppIRStmt(stmt);
2551 vpanic("s390_isel_stmt");
2552}
2553
2554
2555/*---------------------------------------------------------*/
2556/*--- ISEL: Basic block terminators (Nexts) ---*/
2557/*---------------------------------------------------------*/
2558
2559static void
florian8844a632012-04-13 04:04:06 +00002560iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002561{
sewardj2019a972011-03-07 16:04:07 +00002562 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002563 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002564 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002565 vex_printf("; exit-");
2566 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002567 vex_printf("\n");
2568 }
2569
florian8844a632012-04-13 04:04:06 +00002570 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2571
2572 /* Case: boring transfer to known address */
2573 if (next->tag == Iex_Const) {
2574 IRConst *cdst = next->Iex.Const.con;
2575 vassert(cdst->tag == Ico_U64);
2576 if (jk == Ijk_Boring || jk == Ijk_Call) {
2577 /* Boring transfer to known address */
2578 if (env->chaining_allowed) {
2579 /* .. almost always true .. */
2580 /* Skip the event check at the dst if this is a forwards
2581 edge. */
2582 Bool to_fast_entry
2583 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2584 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2585 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2586 guest_IA, to_fast_entry));
2587 } else {
2588 /* .. very occasionally .. */
2589 /* We can't use chaining, so ask for an indirect transfer,
2590 as that's the cheapest alternative that is allowable. */
2591 HReg dst = s390_isel_int_expr(env, next);
2592 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2593 Ijk_Boring));
2594 }
2595 return;
2596 }
2597 }
2598
2599 /* Case: call/return (==boring) transfer to any address */
2600 switch (jk) {
2601 case Ijk_Boring:
2602 case Ijk_Ret:
2603 case Ijk_Call: {
2604 HReg dst = s390_isel_int_expr(env, next);
2605 if (env->chaining_allowed) {
2606 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2607 } else {
2608 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2609 Ijk_Boring));
2610 }
2611 return;
2612 }
2613 default:
2614 break;
2615 }
2616
2617 /* Case: some other kind of transfer to any address */
2618 switch (jk) {
florian65b5b3f2012-04-22 02:51:27 +00002619 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002620 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002621 case Ijk_Sys_syscall:
2622 case Ijk_ClientReq:
2623 case Ijk_NoRedir:
2624 case Ijk_Yield:
2625 case Ijk_SigTRAP: {
2626 HReg dst = s390_isel_int_expr(env, next);
2627 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2628 return;
2629 }
2630 default:
2631 break;
2632 }
2633
2634 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002635}
2636
2637
2638/*---------------------------------------------------------*/
2639/*--- Insn selector top-level ---*/
2640/*---------------------------------------------------------*/
2641
florianf26994a2012-04-21 03:34:54 +00002642/* Translate an entire SB to s390 code.
2643 Note: archinfo_host is a pointer to a stack-allocated variable.
2644 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002645
2646HInstrArray *
2647iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002648 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2649 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2650 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002651{
2652 UInt i, j;
2653 HReg hreg, hregHI;
2654 ISelEnv *env;
2655 UInt hwcaps_host = archinfo_host->hwcaps;
2656
florianf26994a2012-04-21 03:34:54 +00002657 /* KLUDGE: export hwcaps. */
2658 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002659
sewardj2019a972011-03-07 16:04:07 +00002660 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002661 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002662
2663 /* Make up an initial environment to use. */
2664 env = LibVEX_Alloc(sizeof(ISelEnv));
2665 env->vreg_ctr = 0;
2666
2667 /* Set up output code array. */
2668 env->code = newHInstrArray();
2669
2670 /* Copy BB's type env. */
2671 env->type_env = bb->tyenv;
2672
florianad43b3a2012-02-20 15:01:14 +00002673 /* Set up data structures for tracking guest register values. */
2674 env->first_IA_assignment = True;
2675 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2676 env->old_value[i] = 0; /* just something to have a defined value */
2677 env->old_value_valid[i] = False;
2678 }
2679
sewardj2019a972011-03-07 16:04:07 +00002680 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2681 change as we go along. For some reason types_used has Int type -- but
2682 it should be unsigned. Internally we use an unsigned type; so we
2683 assert it here. */
2684 vassert(bb->tyenv->types_used >= 0);
2685
2686 env->n_vregmap = bb->tyenv->types_used;
2687 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2688 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2689
2690 /* and finally ... */
2691 env->hwcaps = hwcaps_host;
2692
florian8844a632012-04-13 04:04:06 +00002693 env->max_ga = max_ga;
2694 env->chaining_allowed = chaining_allowed;
2695
sewardj2019a972011-03-07 16:04:07 +00002696 /* For each IR temporary, allocate a suitably-kinded virtual
2697 register. */
2698 j = 0;
2699 for (i = 0; i < env->n_vregmap; i++) {
2700 hregHI = hreg = INVALID_HREG;
2701 switch (bb->tyenv->types[i]) {
2702 case Ity_I1:
2703 case Ity_I8:
2704 case Ity_I16:
2705 case Ity_I32:
2706 hreg = mkHReg(j++, HRcInt64, True);
2707 break;
2708
2709 case Ity_I64:
2710 hreg = mkHReg(j++, HRcInt64, True);
2711 break;
2712
2713 case Ity_I128:
2714 hreg = mkHReg(j++, HRcInt64, True);
2715 hregHI = mkHReg(j++, HRcInt64, True);
2716 break;
2717
2718 case Ity_F32:
2719 case Ity_F64:
2720 hreg = mkHReg(j++, HRcFlt64, True);
2721 break;
2722
2723 case Ity_F128:
2724 hreg = mkHReg(j++, HRcFlt64, True);
2725 hregHI = mkHReg(j++, HRcFlt64, True);
2726 break;
2727
2728 case Ity_V128: /* fall through */
2729 default:
2730 ppIRType(bb->tyenv->types[i]);
2731 vpanic("s390_isel_sb: IRTemp type");
2732 }
2733
2734 env->vregmap[i] = hreg;
2735 env->vregmapHI[i] = hregHI;
2736 }
2737 env->vreg_ctr = j;
2738
florian8844a632012-04-13 04:04:06 +00002739 /* The very first instruction must be an event check. */
2740 s390_amode *counter, *fail_addr;
2741 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2742 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2743 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2744
2745 /* Possibly a block counter increment (for profiling). At this
2746 point we don't know the address of the counter, so just pretend
2747 it is zero. It will have to be patched later, but before this
2748 translation is used, by a call to LibVEX_patchProfInc. */
2749 if (add_profinc) {
2750 addInstr(env, s390_insn_profinc());
2751 }
2752
sewardj2019a972011-03-07 16:04:07 +00002753 /* Ok, finally we can iterate over the statements. */
2754 for (i = 0; i < bb->stmts_used; i++)
2755 if (bb->stmts[i])
2756 s390_isel_stmt(env, bb->stmts[i]);
2757
florian8844a632012-04-13 04:04:06 +00002758 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002759
2760 /* Record the number of vregs we used. */
2761 env->code->n_vregs = env->vreg_ctr;
2762
2763 return env->code;
2764}
2765
2766/*---------------------------------------------------------------*/
2767/*--- end host_s390_isel.c ---*/
2768/*---------------------------------------------------------------*/