blob: e54dd21e5e5c4ef4f5a0b4481d6d36860cb6af92 [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:
florianaf50a192012-07-13 14:13:06 +0000159 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000160 break;
161
162 default: break;
163 }
164
165 return GUEST_UNKNOWN;
166}
167
sewardj2019a972011-03-07 16:04:07 +0000168/* Add an instruction */
169static void
170addInstr(ISelEnv *env, s390_insn *insn)
171{
172 addHInstr(env->code, insn);
173
174 if (vex_traceflags & VEX_TRACE_VCODE) {
175 vex_printf("%s\n", s390_insn_as_string(insn));
176 }
177}
178
179
180static __inline__ IRExpr *
181mkU64(ULong value)
182{
183 return IRExpr_Const(IRConst_U64(value));
184}
185
186
187/*---------------------------------------------------------*/
188/*--- Registers ---*/
189/*---------------------------------------------------------*/
190
191/* Return the virtual register to which a given IRTemp is mapped. */
192static HReg
193lookupIRTemp(ISelEnv *env, IRTemp tmp)
194{
195 vassert(tmp < env->n_vregmap);
196 vassert(env->vregmap[tmp] != INVALID_HREG);
197
198 return env->vregmap[tmp];
199}
200
201
202/* Return the two virtual registers to which the IRTemp is mapped. */
203static void
204lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
205{
206 vassert(tmp < env->n_vregmap);
207 vassert(env->vregmapHI[tmp] != INVALID_HREG);
208
209 *lo = env->vregmap[tmp];
210 *hi = env->vregmapHI[tmp];
211}
212
213
214/* Allocate a new integer register */
215static HReg
216newVRegI(ISelEnv *env)
217{
218 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
219 env->vreg_ctr++;
220
221 return reg;
222}
223
224
225/* Allocate a new floating point register */
226static HReg
227newVRegF(ISelEnv *env)
228{
229 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
230
231 env->vreg_ctr++;
232
233 return reg;
234}
235
236
237/* Construct a non-virtual general purpose register */
238static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000239make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000240{
241 return mkHReg(regno, HRcInt64, False /* virtual */ );
242}
243
244
245/* Construct a non-virtual floating point register */
246static __inline__ HReg
247make_fpr(UInt regno)
248{
249 return mkHReg(regno, HRcFlt64, False /* virtual */ );
250}
251
252
253/*---------------------------------------------------------*/
254/*--- Amode ---*/
255/*---------------------------------------------------------*/
256
257static __inline__ Bool
258ulong_fits_unsigned_12bit(ULong val)
259{
260 return (val & 0xFFFu) == val;
261}
262
263
264static __inline__ Bool
265ulong_fits_signed_20bit(ULong val)
266{
267 Long v = val & 0xFFFFFu;
268
269 v = (v << 44) >> 44; /* sign extend */
270
271 return val == (ULong)v;
272}
273
274
florianad43b3a2012-02-20 15:01:14 +0000275static __inline__ Bool
276ulong_fits_signed_8bit(ULong val)
277{
278 Long v = val & 0xFFu;
279
280 v = (v << 56) >> 56; /* sign extend */
281
282 return val == (ULong)v;
283}
284
sewardj2019a972011-03-07 16:04:07 +0000285/* EXPR is an expression that is used as an address. Return an s390_amode
286 for it. */
287static s390_amode *
288s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
289{
290 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
291 IRExpr *arg1 = expr->Iex.Binop.arg1;
292 IRExpr *arg2 = expr->Iex.Binop.arg2;
293
294 /* Move constant into right subtree */
295 if (arg1->tag == Iex_Const) {
296 IRExpr *tmp;
297 tmp = arg1;
298 arg1 = arg2;
299 arg2 = tmp;
300 }
301
302 /* r + constant: Check for b12 first, then b20 */
303 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
304 ULong value = arg2->Iex.Const.con->Ico.U64;
305
306 if (ulong_fits_unsigned_12bit(value)) {
307 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
308 }
sewardj652b56a2011-04-13 15:38:17 +0000309 /* If long-displacement is not available, do not construct B20 or
310 BX20 amodes because code generation cannot handle them. */
311 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000312 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
313 }
314 }
315 }
316
317 /* Doesn't match anything in particular. Generate it into
318 a register and use that. */
319 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
320}
321
322
323static s390_amode *
324s390_isel_amode(ISelEnv *env, IRExpr *expr)
325{
florian35da8612011-06-25 02:25:41 +0000326 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000327
328 /* Address computation should yield a 64-bit value */
329 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
330
331 am = s390_isel_amode_wrk(env, expr);
332
333 /* Check post-condition */
334 vassert(s390_amode_is_sane(am));
335
336 return am;
337}
338
339
340/*---------------------------------------------------------*/
341/*--- Helper functions ---*/
342/*---------------------------------------------------------*/
343
344/* Constants and memory accesses should be right operands */
345#define order_commutative_operands(left, right) \
346 do { \
347 if (left->tag == Iex_Const || left->tag == Iex_Load || \
348 left->tag == Iex_Get) { \
349 IRExpr *tmp; \
350 tmp = left; \
351 left = right; \
352 right = tmp; \
353 } \
354 } while (0)
355
356
357/* Copy an RMI operand to the DST register */
358static s390_insn *
359s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
360{
361 switch (opnd.tag) {
362 case S390_OPND_AMODE:
363 return s390_insn_load(size, dst, opnd.variant.am);
364
365 case S390_OPND_REG:
366 return s390_insn_move(size, dst, opnd.variant.reg);
367
368 case S390_OPND_IMMEDIATE:
369 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
370
371 default:
372 vpanic("s390_opnd_copy");
373 }
374}
375
376
377/* Construct a RMI operand for a register */
378static __inline__ s390_opnd_RMI
379s390_opnd_reg(HReg reg)
380{
381 s390_opnd_RMI opnd;
382
383 opnd.tag = S390_OPND_REG;
384 opnd.variant.reg = reg;
385
386 return opnd;
387}
388
389
390/* Construct a RMI operand for an immediate constant */
391static __inline__ s390_opnd_RMI
392s390_opnd_imm(ULong value)
393{
394 s390_opnd_RMI opnd;
395
396 opnd.tag = S390_OPND_IMMEDIATE;
397 opnd.variant.imm = value;
398
399 return opnd;
400}
401
402
403/* Return 1, if EXPR represents the cosntant 0 */
404static int
405s390_expr_is_const_zero(IRExpr *expr)
406{
407 ULong value;
408
409 if (expr->tag == Iex_Const) {
410 switch (expr->Iex.Const.con->tag) {
411 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
412 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
413 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
414 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
415 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
416 default:
417 vpanic("s390_expr_is_const_zero");
418 }
419 return value == 0;
420 }
421
422 return 0;
423}
424
425
426/* Call a helper (clean or dirty)
427 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000428
sewardj2019a972011-03-07 16:04:07 +0000429 (a) they are expressions yielding an integer result
430 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000431
432 guard is a Ity_Bit expression indicating whether or not the
433 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000434
435 Calling the helper function proceeds as follows:
436
437 (1) The helper arguments are evaluated and their value stored in
438 virtual registers.
439 (2) The condition code is evaluated
440 (3) The argument values are copied from the virtual registers to the
441 registers mandated by the ABI.
442 (4) Call the helper function.
443
444 This is not the most efficient way as step 3 generates register-to-register
445 moves. But it is the least fragile way as the only hidden dependency here
446 is that register-to-register moves (step 3) must not clobber the condition
447 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
448 to-register add more such dependencies. Not good. Besides, it's the job
449 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000450*/
451static void
452doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000453 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000454{
florian52af7bc2012-05-12 03:44:49 +0000455 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000456 ULong target;
457 HReg tmpregs[S390_NUM_GPRPARMS];
458 s390_cc_t cc;
459
460 n_args = 0;
461 for (i = 0; args[i]; i++)
462 ++n_args;
463
464 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
465 vpanic("doHelperCall: too many arguments");
466 }
467
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: {
florianf366a802012-08-03 00:42:18 +00002018 HReg dst = newVRegI(env);
2019 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002020
2021 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2022
florianf366a802012-08-03 00:42:18 +00002023 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002024 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2025 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2026 return S390_CC_NE;
2027 }
2028
2029 case Iop_CmpNEZ8:
2030 case Iop_CmpNEZ16: {
2031 s390_opnd_RMI src;
2032 s390_unop_t op;
2033 HReg dst;
2034
2035 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2036 : S390_ZERO_EXTEND_16;
2037 dst = newVRegI(env);
2038 src = s390_isel_int_expr_RMI(env, arg);
2039 addInstr(env, s390_insn_unop(4, op, dst, src));
2040 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2041 return S390_CC_NE;
2042 }
2043
2044 case Iop_CmpNEZ32:
2045 case Iop_CmpNEZ64: {
2046 s390_opnd_RMI src;
2047
2048 src = s390_isel_int_expr_RMI(env, arg);
2049 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2050 addInstr(env, s390_insn_test(size, src));
2051 return S390_CC_NE;
2052 }
2053
2054 default:
2055 goto fail;
2056 }
2057 }
2058
2059 /* Binary operators */
2060 if (cond->tag == Iex_Binop) {
2061 IRExpr *arg1 = cond->Iex.Binop.arg1;
2062 IRExpr *arg2 = cond->Iex.Binop.arg2;
2063 HReg reg1, reg2;
2064
2065 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2066
2067 switch (cond->Iex.Binop.op) {
2068 s390_unop_t op;
2069 s390_cc_t result;
2070
2071 case Iop_CmpEQ8:
2072 case Iop_CasCmpEQ8:
2073 op = S390_ZERO_EXTEND_8;
2074 result = S390_CC_E;
2075 goto do_compare_ze;
2076
2077 case Iop_CmpNE8:
2078 case Iop_CasCmpNE8:
2079 op = S390_ZERO_EXTEND_8;
2080 result = S390_CC_NE;
2081 goto do_compare_ze;
2082
2083 case Iop_CmpEQ16:
2084 case Iop_CasCmpEQ16:
2085 op = S390_ZERO_EXTEND_16;
2086 result = S390_CC_E;
2087 goto do_compare_ze;
2088
2089 case Iop_CmpNE16:
2090 case Iop_CasCmpNE16:
2091 op = S390_ZERO_EXTEND_16;
2092 result = S390_CC_NE;
2093 goto do_compare_ze;
2094
2095 do_compare_ze: {
2096 s390_opnd_RMI op1, op2;
2097
2098 op1 = s390_isel_int_expr_RMI(env, arg1);
2099 reg1 = newVRegI(env);
2100 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2101
2102 op2 = s390_isel_int_expr_RMI(env, arg2);
2103 reg2 = newVRegI(env);
2104 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2105
2106 op2 = s390_opnd_reg(reg2);
2107 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2108
2109 return result;
2110 }
2111
2112 case Iop_CmpEQ32:
2113 case Iop_CmpEQ64:
2114 case Iop_CasCmpEQ32:
2115 case Iop_CasCmpEQ64:
2116 result = S390_CC_E;
2117 goto do_compare;
2118
2119 case Iop_CmpNE32:
2120 case Iop_CmpNE64:
2121 case Iop_CasCmpNE32:
2122 case Iop_CasCmpNE64:
2123 result = S390_CC_NE;
2124 goto do_compare;
2125
2126 do_compare: {
2127 HReg op1;
2128 s390_opnd_RMI op2;
2129
2130 order_commutative_operands(arg1, arg2);
2131
2132 op1 = s390_isel_int_expr(env, arg1);
2133 op2 = s390_isel_int_expr_RMI(env, arg2);
2134
2135 addInstr(env, s390_insn_compare(size, op1, op2, False));
2136
2137 return result;
2138 }
2139
2140 case Iop_CmpLT32S:
2141 case Iop_CmpLE32S:
2142 case Iop_CmpLT64S:
2143 case Iop_CmpLE64S: {
2144 HReg op1;
2145 s390_opnd_RMI op2;
2146
2147 op1 = s390_isel_int_expr(env, arg1);
2148 op2 = s390_isel_int_expr_RMI(env, arg2);
2149
2150 addInstr(env, s390_insn_compare(size, op1, op2, True));
2151
2152 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2153 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2154 }
2155
2156 case Iop_CmpLT32U:
2157 case Iop_CmpLE32U:
2158 case Iop_CmpLT64U:
2159 case Iop_CmpLE64U: {
2160 HReg op1;
2161 s390_opnd_RMI op2;
2162
2163 op1 = s390_isel_int_expr(env, arg1);
2164 op2 = s390_isel_int_expr_RMI(env, arg2);
2165
2166 addInstr(env, s390_insn_compare(size, op1, op2, False));
2167
2168 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2169 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2170 }
2171
2172 default:
2173 goto fail;
2174 }
2175 }
2176
2177 fail:
2178 ppIRExpr(cond);
2179 vpanic("s390_isel_cc: unexpected operator");
2180}
2181
2182
2183/*---------------------------------------------------------*/
2184/*--- ISEL: Statements ---*/
2185/*---------------------------------------------------------*/
2186
2187static void
2188s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2189{
2190 if (vex_traceflags & VEX_TRACE_VCODE) {
2191 vex_printf("\n -- ");
2192 ppIRStmt(stmt);
2193 vex_printf("\n");
2194 }
2195
2196 switch (stmt->tag) {
2197
2198 /* --------- STORE --------- */
2199 case Ist_Store: {
2200 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2201 s390_amode *am;
2202 HReg src;
2203
2204 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2205
2206 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2207
2208 switch (tyd) {
2209 case Ity_I8:
2210 case Ity_I16:
2211 case Ity_I32:
2212 case Ity_I64:
2213 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2214 break;
2215
2216 case Ity_F32:
2217 case Ity_F64:
2218 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2219 break;
2220
2221 case Ity_F128:
2222 /* Cannot occur. No such instruction */
2223 vpanic("Ist_Store with F128 data");
2224
2225 default:
2226 goto stmt_fail;
2227 }
2228
2229 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2230 return;
2231 }
2232
2233 /* --------- PUT --------- */
2234 case Ist_Put: {
2235 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2236 HReg src;
2237 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002238 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002239
florianad43b3a2012-02-20 15:01:14 +00002240 /* Detect updates to certain guest registers. We track the contents
2241 of those registers as long as they contain constants. If the new
2242 constant is either zero or in the 8-bit neighbourhood of the
2243 current value we can use a memory-to-memory insn to do the update. */
2244
2245 Int offset = stmt->Ist.Put.offset;
2246
2247 /* Check necessary conditions:
2248 (1) must be one of the registers we care about
2249 (2) assigned value must be a constant */
2250 Int guest_reg = get_guest_reg(offset);
2251
2252 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2253
2254 if (guest_reg == GUEST_IA) {
2255 /* If this is the first assignment to the IA reg, don't special case
2256 it. We need to do a full 8-byte assignment here. The reason is
2257 that in case of a redirected translation the guest IA does not
2258 contain the redirected-to address. Instead it contains the
2259 redirected-from address and those can be far apart. So in order to
2260 do incremnetal updates if the IA in the future we need to get the
2261 initial address of the super block correct. */
2262 if (env->first_IA_assignment) {
2263 env->first_IA_assignment = False;
2264 goto not_special;
2265 }
2266 }
2267
2268 if (stmt->Ist.Put.data->tag != Iex_Const) {
2269 /* Invalidate guest register contents */
2270 env->old_value_valid[guest_reg] = False;
2271 goto not_special;
2272 }
2273
2274 /* OK. Necessary conditions are satisfied. */
2275
2276 /* Get the old value and update it */
2277 vassert(tyd == Ity_I64);
2278
2279 old_value = env->old_value[guest_reg];
2280 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2281 env->old_value[guest_reg] = new_value;
2282
2283 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2284 env->old_value_valid[guest_reg] = True;
2285
2286 /* If the register already contains the new value, there is nothing
2287 to do here. Unless the guest register requires precise memory
2288 exceptions. */
2289 if (old_value_is_valid && new_value == old_value) {
2290 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2291 return;
2292 }
2293 }
2294
2295 /* guest register = 0 */
2296 if (new_value == 0) {
2297 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2298 return;
2299 }
2300
2301 if (old_value_is_valid == False) goto not_special;
2302
2303 /* If the new value is in the neighbourhood of the old value
2304 we can use a memory-to-memory insn */
2305 difference = new_value - old_value;
2306
2307 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2308 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2309 (difference & 0xFF), new_value));
2310 return;
2311 }
2312
2313 /* If the high word is the same it is sufficient to load the low word.
2314 Use R0 as a scratch reg. */
2315 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002316 HReg r0 = make_gpr(0);
2317 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002318 s390_amode *gam;
2319
2320 gam = s390_amode_b12(offset + 4, gsp);
2321 addInstr(env, s390_insn_load_immediate(4, r0,
2322 new_value & 0xFFFFFFFF));
2323 addInstr(env, s390_insn_store(4, gam, r0));
2324 return;
2325 }
2326
2327 /* No special case applies... fall through */
2328
2329 not_special:
sewardj2019a972011-03-07 16:04:07 +00002330 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2331
2332 switch (tyd) {
2333 case Ity_I8:
2334 case Ity_I16:
2335 case Ity_I32:
2336 case Ity_I64:
2337 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2338 break;
2339
2340 case Ity_F32:
2341 case Ity_F64:
2342 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2343 break;
2344
2345 case Ity_F128:
2346 /* Does not occur. See function put_fpr_pair. */
2347 vpanic("Ist_Put with F128 data");
2348
2349 default:
2350 goto stmt_fail;
2351 }
2352
2353 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2354 return;
2355 }
2356
2357 /* --------- TMP --------- */
2358 case Ist_WrTmp: {
2359 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2360 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2361 HReg src, dst;
2362
2363 switch (tyd) {
2364 case Ity_I128: {
2365 HReg dst_hi, dst_lo, res_hi, res_lo;
2366
2367 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2368 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2369
2370 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2371 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2372 return;
2373 }
2374
2375 case Ity_I8:
2376 case Ity_I16:
2377 case Ity_I32:
2378 case Ity_I64:
2379 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2380 dst = lookupIRTemp(env, tmp);
2381 break;
2382
2383 case Ity_I1: {
2384 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2385 dst = lookupIRTemp(env, tmp);
2386 addInstr(env, s390_insn_cc2bool(dst, cond));
2387 return;
2388 }
2389
2390 case Ity_F32:
2391 case Ity_F64:
2392 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2393 dst = lookupIRTemp(env, tmp);
2394 break;
2395
2396 case Ity_F128: {
2397 HReg dst_hi, dst_lo, res_hi, res_lo;
2398
2399 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2400 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2401
2402 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2403 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2404 return;
2405 }
2406
2407 default:
2408 goto stmt_fail;
2409 }
2410
2411 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2412 return;
2413 }
2414
2415 /* --------- Call to DIRTY helper --------- */
2416 case Ist_Dirty: {
2417 IRType retty;
2418 IRDirty* d = stmt->Ist.Dirty.details;
2419 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002420 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002421 Int i;
2422
2423 /* Invalidate tracked values of those guest state registers that are
2424 modified by this helper. */
2425 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002426 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2427 descriptors in guest state effect descriptions. Hence: */
2428 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002429 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2430 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2431 if (guest_reg != GUEST_UNKNOWN)
2432 env->old_value_valid[guest_reg] = False;
2433 }
2434 }
sewardj2019a972011-03-07 16:04:07 +00002435
2436 if (d->nFxState == 0)
2437 vassert(!d->needsBBP);
2438
2439 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2440
florian01ed6e72012-05-27 16:52:43 +00002441 if (d->tmp == IRTemp_INVALID) {
2442 /* No return value. */
2443 dst = INVALID_HREG;
2444 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002445 return;
florian01ed6e72012-05-27 16:52:43 +00002446 }
sewardj2019a972011-03-07 16:04:07 +00002447
2448 retty = typeOfIRTemp(env->type_env, d->tmp);
2449 if (retty == Ity_I64 || retty == Ity_I32
2450 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002451 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002452 dst = lookupIRTemp(env, d->tmp);
2453 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002454 return;
2455 }
2456 break;
2457 }
2458
2459 case Ist_CAS:
2460 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2461 IRCAS *cas = stmt->Ist.CAS.details;
2462 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2463 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2464 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2465 HReg old = lookupIRTemp(env, cas->oldLo);
2466
2467 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2468 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2469 } else {
2470 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2471 }
2472 return;
2473 } else {
florian448cbba2012-06-06 02:26:01 +00002474 IRCAS *cas = stmt->Ist.CAS.details;
2475 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2476 HReg r8, r9, r10, r11, r1;
2477 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2478 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2479 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2480 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2481 HReg old_low = lookupIRTemp(env, cas->oldLo);
2482 HReg old_high = lookupIRTemp(env, cas->oldHi);
2483
2484 /* Use non-virtual registers r8 and r9 as pair for op1
2485 and move op1 there */
2486 r8 = make_gpr(8);
2487 r9 = make_gpr(9);
2488 addInstr(env, s390_insn_move(8, r8, op1_high));
2489 addInstr(env, s390_insn_move(8, r9, op1_low));
2490
2491 /* Use non-virtual registers r10 and r11 as pair for op3
2492 and move op3 there */
2493 r10 = make_gpr(10);
2494 r11 = make_gpr(11);
2495 addInstr(env, s390_insn_move(8, r10, op3_high));
2496 addInstr(env, s390_insn_move(8, r11, op3_low));
2497
2498 /* Register r1 is used as a scratch register */
2499 r1 = make_gpr(1);
2500
2501 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2502 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2503 old_high, old_low, r1));
2504 } else {
2505 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2506 old_high, old_low, r1));
2507 }
2508 addInstr(env, s390_insn_move(8, op1_high, r8));
2509 addInstr(env, s390_insn_move(8, op1_low, r9));
2510 addInstr(env, s390_insn_move(8, op3_high, r10));
2511 addInstr(env, s390_insn_move(8, op3_low, r11));
2512 return;
sewardj2019a972011-03-07 16:04:07 +00002513 }
2514 break;
2515
2516 /* --------- EXIT --------- */
2517 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002518 s390_cc_t cond;
2519 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2520
2521 if (tag != Ico_U64)
2522 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2523
florian8844a632012-04-13 04:04:06 +00002524 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002525 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002526
2527 /* Case: boring transfer to known address */
2528 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2529 if (env->chaining_allowed) {
2530 /* .. almost always true .. */
2531 /* Skip the event check at the dst if this is a forwards
2532 edge. */
2533 Bool to_fast_entry
2534 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2535 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2536 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2537 guest_IA, to_fast_entry));
2538 } else {
2539 /* .. very occasionally .. */
2540 /* We can't use chaining, so ask for an assisted transfer,
2541 as that's the only alternative that is allowable. */
2542 HReg dst = s390_isel_int_expr(env,
2543 IRExpr_Const(stmt->Ist.Exit.dst));
2544 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2545 }
2546 return;
2547 }
2548
2549 /* Case: assisted transfer to arbitrary address */
2550 switch (stmt->Ist.Exit.jk) {
florian65b5b3f2012-04-22 02:51:27 +00002551 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002552 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002553 case Ijk_Sys_syscall:
2554 case Ijk_ClientReq:
2555 case Ijk_NoRedir:
2556 case Ijk_Yield:
2557 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002558 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2559 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2560 stmt->Ist.Exit.jk));
2561 return;
2562 }
2563 default:
2564 break;
2565 }
2566
2567 /* Do we ever expect to see any other kind? */
2568 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002569 }
2570
2571 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002572 case Ist_MBE:
2573 switch (stmt->Ist.MBE.event) {
2574 case Imbe_Fence:
2575 addInstr(env, s390_insn_mfence());
2576 return;
2577 default:
2578 break;
2579 }
sewardj2019a972011-03-07 16:04:07 +00002580 break;
2581
2582 /* --------- Miscellaneous --------- */
2583
2584 case Ist_PutI: /* Not needed */
2585 case Ist_IMark: /* Doesn't generate any executable code */
2586 case Ist_NoOp: /* Doesn't generate any executable code */
2587 case Ist_AbiHint: /* Meaningless in IR */
2588 return;
2589
2590 default:
2591 break;
2592 }
2593
2594 stmt_fail:
2595 ppIRStmt(stmt);
2596 vpanic("s390_isel_stmt");
2597}
2598
2599
2600/*---------------------------------------------------------*/
2601/*--- ISEL: Basic block terminators (Nexts) ---*/
2602/*---------------------------------------------------------*/
2603
2604static void
florian8844a632012-04-13 04:04:06 +00002605iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002606{
sewardj2019a972011-03-07 16:04:07 +00002607 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002608 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002609 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002610 vex_printf("; exit-");
2611 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002612 vex_printf("\n");
2613 }
2614
florian8844a632012-04-13 04:04:06 +00002615 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2616
2617 /* Case: boring transfer to known address */
2618 if (next->tag == Iex_Const) {
2619 IRConst *cdst = next->Iex.Const.con;
2620 vassert(cdst->tag == Ico_U64);
2621 if (jk == Ijk_Boring || jk == Ijk_Call) {
2622 /* Boring transfer to known address */
2623 if (env->chaining_allowed) {
2624 /* .. almost always true .. */
2625 /* Skip the event check at the dst if this is a forwards
2626 edge. */
2627 Bool to_fast_entry
2628 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2629 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2630 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2631 guest_IA, to_fast_entry));
2632 } else {
2633 /* .. very occasionally .. */
2634 /* We can't use chaining, so ask for an indirect transfer,
2635 as that's the cheapest alternative that is allowable. */
2636 HReg dst = s390_isel_int_expr(env, next);
2637 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2638 Ijk_Boring));
2639 }
2640 return;
2641 }
2642 }
2643
2644 /* Case: call/return (==boring) transfer to any address */
2645 switch (jk) {
2646 case Ijk_Boring:
2647 case Ijk_Ret:
2648 case Ijk_Call: {
2649 HReg dst = s390_isel_int_expr(env, next);
2650 if (env->chaining_allowed) {
2651 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2652 } else {
2653 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2654 Ijk_Boring));
2655 }
2656 return;
2657 }
2658 default:
2659 break;
2660 }
2661
2662 /* Case: some other kind of transfer to any address */
2663 switch (jk) {
florian65b5b3f2012-04-22 02:51:27 +00002664 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002665 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002666 case Ijk_Sys_syscall:
2667 case Ijk_ClientReq:
2668 case Ijk_NoRedir:
2669 case Ijk_Yield:
2670 case Ijk_SigTRAP: {
2671 HReg dst = s390_isel_int_expr(env, next);
2672 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2673 return;
2674 }
2675 default:
2676 break;
2677 }
2678
2679 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002680}
2681
2682
2683/*---------------------------------------------------------*/
2684/*--- Insn selector top-level ---*/
2685/*---------------------------------------------------------*/
2686
florianf26994a2012-04-21 03:34:54 +00002687/* Translate an entire SB to s390 code.
2688 Note: archinfo_host is a pointer to a stack-allocated variable.
2689 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002690
2691HInstrArray *
2692iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002693 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2694 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2695 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002696{
2697 UInt i, j;
2698 HReg hreg, hregHI;
2699 ISelEnv *env;
2700 UInt hwcaps_host = archinfo_host->hwcaps;
2701
florianf26994a2012-04-21 03:34:54 +00002702 /* KLUDGE: export hwcaps. */
2703 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002704
sewardj2019a972011-03-07 16:04:07 +00002705 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002706 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002707
2708 /* Make up an initial environment to use. */
2709 env = LibVEX_Alloc(sizeof(ISelEnv));
2710 env->vreg_ctr = 0;
2711
2712 /* Set up output code array. */
2713 env->code = newHInstrArray();
2714
2715 /* Copy BB's type env. */
2716 env->type_env = bb->tyenv;
2717
florianad43b3a2012-02-20 15:01:14 +00002718 /* Set up data structures for tracking guest register values. */
2719 env->first_IA_assignment = True;
2720 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2721 env->old_value[i] = 0; /* just something to have a defined value */
2722 env->old_value_valid[i] = False;
2723 }
2724
sewardj2019a972011-03-07 16:04:07 +00002725 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2726 change as we go along. For some reason types_used has Int type -- but
2727 it should be unsigned. Internally we use an unsigned type; so we
2728 assert it here. */
2729 vassert(bb->tyenv->types_used >= 0);
2730
2731 env->n_vregmap = bb->tyenv->types_used;
2732 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2733 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2734
2735 /* and finally ... */
2736 env->hwcaps = hwcaps_host;
2737
florian8844a632012-04-13 04:04:06 +00002738 env->max_ga = max_ga;
2739 env->chaining_allowed = chaining_allowed;
2740
sewardj2019a972011-03-07 16:04:07 +00002741 /* For each IR temporary, allocate a suitably-kinded virtual
2742 register. */
2743 j = 0;
2744 for (i = 0; i < env->n_vregmap; i++) {
2745 hregHI = hreg = INVALID_HREG;
2746 switch (bb->tyenv->types[i]) {
2747 case Ity_I1:
2748 case Ity_I8:
2749 case Ity_I16:
2750 case Ity_I32:
2751 hreg = mkHReg(j++, HRcInt64, True);
2752 break;
2753
2754 case Ity_I64:
2755 hreg = mkHReg(j++, HRcInt64, True);
2756 break;
2757
2758 case Ity_I128:
2759 hreg = mkHReg(j++, HRcInt64, True);
2760 hregHI = mkHReg(j++, HRcInt64, True);
2761 break;
2762
2763 case Ity_F32:
2764 case Ity_F64:
2765 hreg = mkHReg(j++, HRcFlt64, True);
2766 break;
2767
2768 case Ity_F128:
2769 hreg = mkHReg(j++, HRcFlt64, True);
2770 hregHI = mkHReg(j++, HRcFlt64, True);
2771 break;
2772
2773 case Ity_V128: /* fall through */
2774 default:
2775 ppIRType(bb->tyenv->types[i]);
2776 vpanic("s390_isel_sb: IRTemp type");
2777 }
2778
2779 env->vregmap[i] = hreg;
2780 env->vregmapHI[i] = hregHI;
2781 }
2782 env->vreg_ctr = j;
2783
florian8844a632012-04-13 04:04:06 +00002784 /* The very first instruction must be an event check. */
2785 s390_amode *counter, *fail_addr;
2786 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2787 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2788 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2789
2790 /* Possibly a block counter increment (for profiling). At this
2791 point we don't know the address of the counter, so just pretend
2792 it is zero. It will have to be patched later, but before this
2793 translation is used, by a call to LibVEX_patchProfInc. */
2794 if (add_profinc) {
2795 addInstr(env, s390_insn_profinc());
2796 }
2797
sewardj2019a972011-03-07 16:04:07 +00002798 /* Ok, finally we can iterate over the statements. */
2799 for (i = 0; i < bb->stmts_used; i++)
2800 if (bb->stmts[i])
2801 s390_isel_stmt(env, bb->stmts[i]);
2802
florian8844a632012-04-13 04:04:06 +00002803 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002804
2805 /* Record the number of vregs we used. */
2806 env->code->n_vregs = env->vreg_ctr;
2807
2808 return env->code;
2809}
2810
2811/*---------------------------------------------------------------*/
2812/*--- end host_s390_isel.c ---*/
2813/*---------------------------------------------------------------*/