blob: 565111ab3cba401a39bb631c3d7b9e3bed92ca1e [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:
florian5f27dcf2012-08-04 04:25:30 +00001147 /* Zero extend */
1148 mask.variant.imm = 1;
1149 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1150 break;
1151
sewardj2019a972011-03-07 16:04:07 +00001152 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001153 /* Zero extend */
1154 mask.variant.imm = 1;
1155 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001156 break;
1157
1158 case Iop_1Sto8:
1159 case Iop_1Sto16:
1160 case Iop_1Sto32:
1161 shift.variant.imm = 31;
1162 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1163 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1164 break;
1165
1166 case Iop_1Sto64:
1167 shift.variant.imm = 63;
1168 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1169 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1170 break;
1171
1172 default:
1173 goto irreducible;
1174 }
1175
1176 return dst;
1177 }
1178
1179 /* Regular processing */
1180
1181 if (unop == Iop_128to64) {
1182 HReg dst_hi, dst_lo;
1183
1184 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1185 return dst_lo;
1186 }
1187
1188 if (unop == Iop_128HIto64) {
1189 HReg dst_hi, dst_lo;
1190
1191 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1192 return dst_hi;
1193 }
1194
1195 dst = newVRegI(env); /* Result goes into a new register */
1196 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1197
1198 switch (unop) {
1199 case Iop_8Uto16:
1200 case Iop_8Uto32:
1201 case Iop_8Uto64:
1202 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1203 break;
1204
1205 case Iop_16Uto32:
1206 case Iop_16Uto64:
1207 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1208 break;
1209
1210 case Iop_32Uto64:
1211 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1212 break;
1213
1214 case Iop_8Sto16:
1215 case Iop_8Sto32:
1216 case Iop_8Sto64:
1217 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1218 break;
1219
1220 case Iop_16Sto32:
1221 case Iop_16Sto64:
1222 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1223 break;
1224
1225 case Iop_32Sto64:
1226 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1227 break;
1228
1229 case Iop_64to8:
1230 case Iop_64to16:
1231 case Iop_64to32:
1232 case Iop_32to8:
1233 case Iop_32to16:
1234 case Iop_16to8:
1235 /* Down-casts are no-ops. Upstream operations will only look at
1236 the bytes that make up the result of the down-cast. So there
1237 is no point setting the other bytes to 0. */
1238 insn = s390_opnd_copy(8, dst, opnd);
1239 break;
1240
1241 case Iop_64HIto32:
1242 addInstr(env, s390_opnd_copy(8, dst, opnd));
1243 shift.variant.imm = 32;
1244 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1245 break;
1246
1247 case Iop_32HIto16:
1248 addInstr(env, s390_opnd_copy(4, dst, opnd));
1249 shift.variant.imm = 16;
1250 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1251 break;
1252
1253 case Iop_16HIto8:
1254 addInstr(env, s390_opnd_copy(2, dst, opnd));
1255 shift.variant.imm = 8;
1256 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1257 break;
1258
1259 case Iop_Not8:
1260 case Iop_Not16:
1261 case Iop_Not32:
1262 case Iop_Not64:
1263 /* XOR with ffff... */
1264 mask.variant.imm = ~(ULong)0;
1265 addInstr(env, s390_opnd_copy(size, dst, opnd));
1266 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1267 break;
1268
1269 case Iop_Left8:
1270 case Iop_Left16:
1271 case Iop_Left32:
1272 case Iop_Left64:
1273 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1274 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1275 break;
1276
1277 case Iop_CmpwNEZ32:
1278 case Iop_CmpwNEZ64: {
1279 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1280 or -X will have a 1 in the MSB. */
1281 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1282 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1283 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1284 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1285 return dst;
1286 }
1287
1288 case Iop_Clz64: {
1289 HReg r10, r11;
1290
sewardj611b06e2011-03-24 08:57:29 +00001291 /* This will be implemented using FLOGR, if possible. So we need to
1292 set aside a pair of non-virtual registers. The result (number of
1293 left-most zero bits) will be in r10. The value in r11 is unspecified
1294 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001295 r10 = make_gpr(10);
1296 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001297
sewardj611b06e2011-03-24 08:57:29 +00001298 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001299 addInstr(env, s390_insn_move(8, dst, r10));
1300 return dst;
1301 }
1302
1303 default:
1304 goto irreducible;
1305 }
1306
1307 addInstr(env, insn);
1308
1309 return dst;
1310 }
1311
1312 /* --------- GET --------- */
1313 case Iex_Get: {
1314 HReg dst = newVRegI(env);
1315 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1316
1317 /* We never load more than 8 bytes from the guest state, because the
1318 floating point register pair is not contiguous. */
1319 vassert(size <= 8);
1320
1321 addInstr(env, s390_insn_load(size, dst, am));
1322
1323 return dst;
1324 }
1325
1326 case Iex_GetI:
1327 /* not needed */
1328 break;
1329
1330 /* --------- CCALL --------- */
1331 case Iex_CCall: {
1332 HReg dst = newVRegI(env);
1333
1334 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001335 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001336 return dst;
1337 }
1338
1339 /* --------- LITERAL --------- */
1340
1341 /* Load a literal into a register. Create a "load immediate"
1342 v-insn and return the register. */
1343 case Iex_Const: {
1344 ULong value;
1345 HReg dst = newVRegI(env);
1346 const IRConst *con = expr->Iex.Const.con;
1347
1348 /* Bitwise copy of the value. No sign/zero-extension */
1349 switch (con->tag) {
1350 case Ico_U64: value = con->Ico.U64; break;
1351 case Ico_U32: value = con->Ico.U32; break;
1352 case Ico_U16: value = con->Ico.U16; break;
1353 case Ico_U8: value = con->Ico.U8; break;
1354 default: vpanic("s390_isel_int_expr: invalid constant");
1355 }
1356
1357 addInstr(env, s390_insn_load_immediate(size, dst, value));
1358
1359 return dst;
1360 }
1361
1362 /* --------- MULTIPLEX --------- */
1363 case Iex_Mux0X: {
1364 IRExpr *cond_expr;
1365 HReg dst, tmp, rX;
1366 s390_opnd_RMI cond, r0, zero;
1367
1368 cond_expr = expr->Iex.Mux0X.cond;
1369
1370 dst = newVRegI(env);
1371 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1372 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1373 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1374
1375 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1376 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1377
1378 addInstr(env, s390_insn_move(size, dst, rX));
1379 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1380 return dst;
1381 }
1382
1383 /* Assume the condition is true and move rX to the destination reg. */
1384 addInstr(env, s390_insn_move(size, dst, rX));
1385
1386 /* Compute the condition ... */
1387 cond = s390_isel_int_expr_RMI(env, cond_expr);
1388
1389 /* tmp = cond & 0xFF */
1390 tmp = newVRegI(env);
1391 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1392 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1393
1394 /* ... and compare it with zero */
1395 zero = s390_opnd_imm(0);
1396 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1397
1398 /* ... and if it compared equal move r0 to the destination reg. */
1399 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1400 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1401
1402 return dst;
1403 }
1404
1405 default:
1406 break;
1407 }
1408
1409 /* We get here if no pattern matched. */
1410 irreducible:
1411 ppIRExpr(expr);
1412 vpanic("s390_isel_int_expr: cannot reduce tree");
1413}
1414
1415
1416static HReg
1417s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1418{
1419 HReg dst = s390_isel_int_expr_wrk(env, expr);
1420
1421 /* Sanity checks ... */
1422 vassert(hregClass(dst) == HRcInt64);
1423 vassert(hregIsVirtual(dst));
1424
1425 return dst;
1426}
1427
1428
1429static s390_opnd_RMI
1430s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1431{
1432 IRType ty = typeOfIRExpr(env->type_env, expr);
1433 s390_opnd_RMI dst;
1434
1435 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1436 ty == Ity_I64);
1437
1438 if (expr->tag == Iex_Load) {
1439 dst.tag = S390_OPND_AMODE;
1440 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1441 } else if (expr->tag == Iex_Get) {
1442 dst.tag = S390_OPND_AMODE;
1443 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1444 } else if (expr->tag == Iex_Const) {
1445 ULong value;
1446
1447 /* The bit pattern for the value will be stored as is in the least
1448 significant bits of VALUE. */
1449 switch (expr->Iex.Const.con->tag) {
1450 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1451 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1452 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1453 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1454 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1455 default:
1456 vpanic("s390_isel_int_expr_RMI");
1457 }
1458
1459 dst.tag = S390_OPND_IMMEDIATE;
1460 dst.variant.imm = value;
1461 } else {
1462 dst.tag = S390_OPND_REG;
1463 dst.variant.reg = s390_isel_int_expr(env, expr);
1464 }
1465
1466 return dst;
1467}
1468
1469
1470/*---------------------------------------------------------*/
1471/*--- ISEL: Floating point expressions (128 bit) ---*/
1472/*---------------------------------------------------------*/
1473static void
1474s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1475 IRExpr *expr)
1476{
1477 IRType ty = typeOfIRExpr(env->type_env, expr);
1478
1479 vassert(ty == Ity_F128);
1480
1481 /* Read 128-bit IRTemp */
1482 if (expr->tag == Iex_RdTmp) {
1483 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1484 return;
1485 }
1486
1487 switch (expr->tag) {
1488 case Iex_RdTmp:
1489 /* Return the virtual registers that hold the temporary. */
1490 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1491 return;
1492
1493 /* --------- LOAD --------- */
1494 case Iex_Load: {
1495 IRExpr *addr_hi, *addr_lo;
1496 s390_amode *am_hi, *am_lo;
1497
1498 if (expr->Iex.Load.end != Iend_BE)
1499 goto irreducible;
1500
1501 addr_hi = expr->Iex.Load.addr;
1502 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1503
1504 am_hi = s390_isel_amode(env, addr_hi);
1505 am_lo = s390_isel_amode(env, addr_lo);
1506
1507 *dst_hi = newVRegF(env);
1508 *dst_lo = newVRegF(env);
1509 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1510 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1511 return;
1512 }
1513
1514
1515 /* --------- GET --------- */
1516 case Iex_Get:
1517 /* This is not supported because loading 128-bit from the guest
1518 state is almost certainly wrong. Use get_fpr_pair instead. */
1519 vpanic("Iex_Get with F128 data");
1520
1521 /* --------- 4-ary OP --------- */
1522 case Iex_Qop:
1523 vpanic("Iex_Qop with F128 data");
1524
1525 /* --------- TERNARY OP --------- */
1526 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001527 IRTriop *triop = expr->Iex.Triop.details;
1528 IROp op = triop->op;
1529 IRExpr *left = triop->arg2;
1530 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001531 s390_bfp_binop_t bfpop;
1532 s390_round_t rounding_mode;
1533 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1534
1535 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1536 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1537
1538 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1539 f12 = make_fpr(12);
1540 f13 = make_fpr(13);
1541 f14 = make_fpr(14);
1542 f15 = make_fpr(15);
1543
1544 /* 1st operand --> (f12, f14) */
1545 addInstr(env, s390_insn_move(8, f12, op1_hi));
1546 addInstr(env, s390_insn_move(8, f14, op1_lo));
1547
1548 /* 2nd operand --> (f13, f15) */
1549 addInstr(env, s390_insn_move(8, f13, op2_hi));
1550 addInstr(env, s390_insn_move(8, f15, op2_lo));
1551
1552 switch (op) {
1553 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1554 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1555 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1556 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1557 default:
1558 goto irreducible;
1559 }
1560
florian420bfa92012-06-02 20:29:22 +00001561 rounding_mode = decode_rounding_mode(triop->arg1);
sewardj2019a972011-03-07 16:04:07 +00001562 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1563 f15, rounding_mode));
1564
1565 /* Move result to virtual destination register */
1566 *dst_hi = newVRegF(env);
1567 *dst_lo = newVRegF(env);
1568 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1569 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1570
1571 return;
1572 }
1573
1574 /* --------- BINARY OP --------- */
1575 case Iex_Binop: {
1576 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardja970c402011-04-28 18:38:42 +00001577 s390_bfp_unop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001578 s390_round_t rounding_mode;
1579
1580 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1581 f12 = make_fpr(12);
1582 f13 = make_fpr(13);
1583 f14 = make_fpr(14);
1584 f15 = make_fpr(15);
1585
1586 switch (expr->Iex.Binop.op) {
1587 case Iop_SqrtF128:
1588 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1589
1590 /* operand --> (f13, f15) */
1591 addInstr(env, s390_insn_move(8, f13, op_hi));
1592 addInstr(env, s390_insn_move(8, f15, op_lo));
1593
1594 bfpop = S390_BFP_SQRT;
1595 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1596
1597 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1598 rounding_mode));
1599
1600 /* Move result to virtual destination registers */
1601 *dst_hi = newVRegF(env);
1602 *dst_lo = newVRegF(env);
1603 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1604 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1605 return;
1606
1607 case Iop_F64HLtoF128:
1608 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1609 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1610 return;
1611
1612 default:
1613 goto irreducible;
1614 }
1615 }
1616
1617 /* --------- UNARY OP --------- */
1618 case Iex_Unop: {
1619 IRExpr *left = expr->Iex.Binop.arg1;
1620 s390_bfp_unop_t bfpop;
1621 s390_round_t rounding_mode;
1622 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1623
1624 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1625 f12 = make_fpr(12);
1626 f13 = make_fpr(13);
1627 f14 = make_fpr(14);
1628 f15 = make_fpr(15);
1629
1630 switch (expr->Iex.Binop.op) {
1631 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1632 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1633 case Iop_I32StoF128: bfpop = S390_BFP_I32_TO_F128; goto convert_int;
1634 case Iop_I64StoF128: bfpop = S390_BFP_I64_TO_F128; goto convert_int;
1635 case Iop_F32toF128: bfpop = S390_BFP_F32_TO_F128; goto convert_float;
1636 case Iop_F64toF128: bfpop = S390_BFP_F64_TO_F128; goto convert_float;
1637 default:
1638 goto irreducible;
1639 }
1640
1641 float128_opnd:
1642 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1643
1644 /* operand --> (f13, f15) */
1645 addInstr(env, s390_insn_move(8, f13, op_hi));
1646 addInstr(env, s390_insn_move(8, f15, op_lo));
1647
1648 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1649 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1650 rounding_mode));
1651 goto move_dst;
1652
1653 convert_float:
1654 op = s390_isel_float_expr(env, left);
1655 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1656 op));
1657 goto move_dst;
1658
1659 convert_int:
1660 op = s390_isel_int_expr(env, left);
1661 addInstr(env, s390_insn_bfp128_convert_to(16, bfpop, f12, f14,
1662 op));
1663 goto move_dst;
1664
1665 move_dst:
1666 /* Move result to virtual destination registers */
1667 *dst_hi = newVRegF(env);
1668 *dst_lo = newVRegF(env);
1669 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1670 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1671 return;
1672 }
1673
1674 default:
1675 goto irreducible;
1676 }
1677
1678 /* We get here if no pattern matched. */
1679 irreducible:
1680 ppIRExpr(expr);
1681 vpanic("s390_isel_int_expr: cannot reduce tree");
1682}
1683
1684/* Compute a 128-bit value into two 64-bit registers. These may be either
1685 real or virtual regs; in any case they must not be changed by subsequent
1686 code emitted by the caller. */
1687static void
1688s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1689{
1690 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1691
1692 /* Sanity checks ... */
1693 vassert(hregIsVirtual(*dst_hi));
1694 vassert(hregIsVirtual(*dst_lo));
1695 vassert(hregClass(*dst_hi) == HRcFlt64);
1696 vassert(hregClass(*dst_lo) == HRcFlt64);
1697}
1698
1699
1700/*---------------------------------------------------------*/
1701/*--- ISEL: Floating point expressions (64 bit) ---*/
1702/*---------------------------------------------------------*/
1703
1704static HReg
1705s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1706{
1707 IRType ty = typeOfIRExpr(env->type_env, expr);
1708 UChar size;
1709
1710 vassert(ty == Ity_F32 || ty == Ity_F64);
1711
1712 size = sizeofIRType(ty);
1713
1714 switch (expr->tag) {
1715 case Iex_RdTmp:
1716 /* Return the virtual register that holds the temporary. */
1717 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1718
1719 /* --------- LOAD --------- */
1720 case Iex_Load: {
1721 HReg dst = newVRegF(env);
1722 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1723
1724 if (expr->Iex.Load.end != Iend_BE)
1725 goto irreducible;
1726
1727 addInstr(env, s390_insn_load(size, dst, am));
1728
1729 return dst;
1730 }
1731
1732 /* --------- GET --------- */
1733 case Iex_Get: {
1734 HReg dst = newVRegF(env);
1735 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1736
1737 addInstr(env, s390_insn_load(size, dst, am));
1738
1739 return dst;
1740 }
1741
1742 /* --------- LITERAL --------- */
1743
1744 /* Load a literal into a register. Create a "load immediate"
1745 v-insn and return the register. */
1746 case Iex_Const: {
1747 ULong value;
1748 HReg dst = newVRegF(env);
1749 const IRConst *con = expr->Iex.Const.con;
1750
1751 /* Bitwise copy of the value. No sign/zero-extension */
1752 switch (con->tag) {
1753 case Ico_F32i: value = con->Ico.F32i; break;
1754 case Ico_F64i: value = con->Ico.F64i; break;
1755 default: vpanic("s390_isel_float_expr: invalid constant");
1756 }
1757
1758 if (value != 0) vpanic("cannot load immediate floating point constant");
1759
1760 addInstr(env, s390_insn_load_immediate(size, dst, value));
1761
1762 return dst;
1763 }
1764
1765 /* --------- 4-ary OP --------- */
1766 case Iex_Qop: {
1767 HReg op1, op2, op3, dst;
1768 s390_bfp_triop_t bfpop;
1769 s390_round_t rounding_mode;
1770
florian96d7cc32012-06-01 20:41:24 +00001771 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
1772 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
1773 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00001774 dst = newVRegF(env);
1775 addInstr(env, s390_insn_move(size, dst, op1));
1776
florian96d7cc32012-06-01 20:41:24 +00001777 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00001778 case Iop_MAddF32:
1779 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1780 case Iop_MSubF32:
1781 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1782
1783 default:
1784 goto irreducible;
1785 }
1786
florian96d7cc32012-06-01 20:41:24 +00001787 rounding_mode = decode_rounding_mode(expr->Iex.Qop.details->arg1);
sewardj2019a972011-03-07 16:04:07 +00001788 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1789 rounding_mode));
1790 return dst;
1791 }
1792
1793 /* --------- TERNARY OP --------- */
1794 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001795 IRTriop *triop = expr->Iex.Triop.details;
1796 IROp op = triop->op;
1797 IRExpr *left = triop->arg2;
1798 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001799 s390_bfp_binop_t bfpop;
1800 s390_round_t rounding_mode;
1801 HReg h1, op2, dst;
1802
1803 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1804 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1805 dst = newVRegF(env);
1806 addInstr(env, s390_insn_move(size, dst, h1));
1807 switch (op) {
1808 case Iop_AddF32:
1809 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1810 case Iop_SubF32:
1811 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1812 case Iop_MulF32:
1813 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1814 case Iop_DivF32:
1815 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1816
1817 default:
1818 goto irreducible;
1819 }
1820
florian420bfa92012-06-02 20:29:22 +00001821 rounding_mode = decode_rounding_mode(triop->arg1);
sewardj2019a972011-03-07 16:04:07 +00001822 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1823 return dst;
1824 }
1825
1826 /* --------- BINARY OP --------- */
1827 case Iex_Binop: {
1828 IROp op = expr->Iex.Binop.op;
1829 IRExpr *left = expr->Iex.Binop.arg2;
1830 HReg h1, dst;
1831 s390_bfp_unop_t bfpop;
1832 s390_round_t rounding_mode;
1833 Int integer_operand;
1834
1835 integer_operand = 1;
1836
1837 switch (op) {
1838 case Iop_SqrtF32:
1839 case Iop_SqrtF64:
1840 bfpop = S390_BFP_SQRT;
1841 integer_operand = 0;
1842 break;
1843
1844 case Iop_F64toF32:
1845 bfpop = S390_BFP_F64_TO_F32;
1846 integer_operand = 0;
1847 break;
1848
1849 case Iop_I32StoF32: bfpop = S390_BFP_I32_TO_F32; break;
1850 case Iop_I64StoF32: bfpop = S390_BFP_I64_TO_F32; break;
1851 case Iop_I64StoF64: bfpop = S390_BFP_I64_TO_F64; break;
1852 default:
1853 goto irreducible;
1854
1855 case Iop_F128toF64:
1856 case Iop_F128toF32: {
1857 HReg op_hi, op_lo, f12, f13, f14, f15;
1858
1859 bfpop = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1860 : S390_BFP_F128_TO_F64;
1861
1862 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1863
1864 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1865
1866 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1867 f12 = make_fpr(12);
1868 f13 = make_fpr(13);
1869 f14 = make_fpr(14);
1870 f15 = make_fpr(15);
1871
1872 /* operand --> (f13, f15) */
1873 addInstr(env, s390_insn_move(8, f13, op_hi));
1874 addInstr(env, s390_insn_move(8, f15, op_lo));
1875
1876 dst = newVRegF(env);
1877 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1878 rounding_mode));
1879
1880 /* Move result to virtual destination registers */
1881 addInstr(env, s390_insn_move(8, dst, f12));
1882 return dst;
1883 }
1884 }
1885
1886 /* Process operand */
1887 if (integer_operand) {
1888 h1 = s390_isel_int_expr(env, left);
1889 } else {
1890 h1 = s390_isel_float_expr(env, left);
1891 }
1892
1893 dst = newVRegF(env);
1894 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1895 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1896 return dst;
1897 }
1898
1899 /* --------- UNARY OP --------- */
1900 case Iex_Unop: {
1901 IROp op = expr->Iex.Unop.op;
1902 IRExpr *left = expr->Iex.Unop.arg;
1903 s390_bfp_unop_t bfpop;
1904 s390_round_t rounding_mode;
1905 HReg h1, dst;
1906
1907 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1908 HReg dst_hi, dst_lo;
1909
1910 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1911 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1912 }
1913
florian4d71a082011-12-18 00:08:17 +00001914 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00001915 dst = newVRegF(env);
1916 h1 = s390_isel_int_expr(env, left); /* Process the operand */
1917 addInstr(env, s390_insn_move(size, dst, h1));
1918
1919 return dst;
1920 }
1921
1922 switch (op) {
1923 case Iop_NegF32:
1924 case Iop_NegF64:
1925 if (left->tag == Iex_Unop &&
1926 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1927 bfpop = S390_BFP_NABS;
1928 else
1929 bfpop = S390_BFP_NEG;
1930 break;
1931
1932 case Iop_AbsF32:
1933 case Iop_AbsF64: bfpop = S390_BFP_ABS; break;
1934 case Iop_I32StoF64: bfpop = S390_BFP_I32_TO_F64; break;
1935 case Iop_F32toF64: bfpop = S390_BFP_F32_TO_F64; break;
1936 default:
1937 goto irreducible;
1938 }
1939
1940 /* Process operand */
1941 if (op == Iop_I32StoF64)
1942 h1 = s390_isel_int_expr(env, left);
1943 else if (bfpop == S390_BFP_NABS)
1944 h1 = s390_isel_float_expr(env, left->Iex.Unop.arg);
1945 else
1946 h1 = s390_isel_float_expr(env, left);
1947
1948 dst = newVRegF(env);
1949 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1950 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
1951 return dst;
1952 }
1953
1954 default:
1955 goto irreducible;
1956 }
1957
1958 /* We get here if no pattern matched. */
1959 irreducible:
1960 ppIRExpr(expr);
1961 vpanic("s390_isel_float_expr: cannot reduce tree");
1962}
1963
1964
1965static HReg
1966s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
1967{
1968 HReg dst = s390_isel_float_expr_wrk(env, expr);
1969
1970 /* Sanity checks ... */
1971 vassert(hregClass(dst) == HRcFlt64);
1972 vassert(hregIsVirtual(dst));
1973
1974 return dst;
1975}
1976
1977
1978/*---------------------------------------------------------*/
1979/*--- ISEL: Condition Code ---*/
1980/*---------------------------------------------------------*/
1981
1982/* This function handles all operators that produce a 1-bit result */
1983static s390_cc_t
1984s390_isel_cc(ISelEnv *env, IRExpr *cond)
1985{
1986 UChar size;
1987
1988 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
1989
1990 /* Constant: either 1 or 0 */
1991 if (cond->tag == Iex_Const) {
1992 vassert(cond->Iex.Const.con->tag == Ico_U1);
1993 vassert(cond->Iex.Const.con->Ico.U1 == True
1994 || cond->Iex.Const.con->Ico.U1 == False);
1995
1996 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
1997 }
1998
1999 /* Variable: values are 1 or 0 */
2000 if (cond->tag == Iex_RdTmp) {
2001 IRTemp tmp = cond->Iex.RdTmp.tmp;
2002 HReg reg = lookupIRTemp(env, tmp);
2003
2004 /* Load-and-test does not modify REG; so this is OK. */
2005 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2006 size = 4;
2007 else
2008 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2009 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2010 return S390_CC_NE;
2011 }
2012
2013 /* Unary operators */
2014 if (cond->tag == Iex_Unop) {
2015 IRExpr *arg = cond->Iex.Unop.arg;
2016
2017 switch (cond->Iex.Unop.op) {
2018 case Iop_Not1: /* Not1(cond) */
2019 /* Generate code for EXPR, and negate the test condition */
2020 return s390_cc_invert(s390_isel_cc(env, arg));
2021
2022 /* Iop_32/64to1 select the LSB from their operand */
2023 case Iop_32to1:
2024 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002025 HReg dst = newVRegI(env);
2026 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002027
2028 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2029
florianf366a802012-08-03 00:42:18 +00002030 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002031 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2032 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2033 return S390_CC_NE;
2034 }
2035
2036 case Iop_CmpNEZ8:
2037 case Iop_CmpNEZ16: {
2038 s390_opnd_RMI src;
2039 s390_unop_t op;
2040 HReg dst;
2041
2042 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2043 : S390_ZERO_EXTEND_16;
2044 dst = newVRegI(env);
2045 src = s390_isel_int_expr_RMI(env, arg);
2046 addInstr(env, s390_insn_unop(4, op, dst, src));
2047 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2048 return S390_CC_NE;
2049 }
2050
2051 case Iop_CmpNEZ32:
2052 case Iop_CmpNEZ64: {
2053 s390_opnd_RMI src;
2054
2055 src = s390_isel_int_expr_RMI(env, arg);
2056 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2057 addInstr(env, s390_insn_test(size, src));
2058 return S390_CC_NE;
2059 }
2060
2061 default:
2062 goto fail;
2063 }
2064 }
2065
2066 /* Binary operators */
2067 if (cond->tag == Iex_Binop) {
2068 IRExpr *arg1 = cond->Iex.Binop.arg1;
2069 IRExpr *arg2 = cond->Iex.Binop.arg2;
2070 HReg reg1, reg2;
2071
2072 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2073
2074 switch (cond->Iex.Binop.op) {
2075 s390_unop_t op;
2076 s390_cc_t result;
2077
2078 case Iop_CmpEQ8:
2079 case Iop_CasCmpEQ8:
2080 op = S390_ZERO_EXTEND_8;
2081 result = S390_CC_E;
2082 goto do_compare_ze;
2083
2084 case Iop_CmpNE8:
2085 case Iop_CasCmpNE8:
2086 op = S390_ZERO_EXTEND_8;
2087 result = S390_CC_NE;
2088 goto do_compare_ze;
2089
2090 case Iop_CmpEQ16:
2091 case Iop_CasCmpEQ16:
2092 op = S390_ZERO_EXTEND_16;
2093 result = S390_CC_E;
2094 goto do_compare_ze;
2095
2096 case Iop_CmpNE16:
2097 case Iop_CasCmpNE16:
2098 op = S390_ZERO_EXTEND_16;
2099 result = S390_CC_NE;
2100 goto do_compare_ze;
2101
2102 do_compare_ze: {
2103 s390_opnd_RMI op1, op2;
2104
2105 op1 = s390_isel_int_expr_RMI(env, arg1);
2106 reg1 = newVRegI(env);
2107 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2108
2109 op2 = s390_isel_int_expr_RMI(env, arg2);
2110 reg2 = newVRegI(env);
2111 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2112
2113 op2 = s390_opnd_reg(reg2);
2114 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2115
2116 return result;
2117 }
2118
2119 case Iop_CmpEQ32:
2120 case Iop_CmpEQ64:
2121 case Iop_CasCmpEQ32:
2122 case Iop_CasCmpEQ64:
2123 result = S390_CC_E;
2124 goto do_compare;
2125
2126 case Iop_CmpNE32:
2127 case Iop_CmpNE64:
2128 case Iop_CasCmpNE32:
2129 case Iop_CasCmpNE64:
2130 result = S390_CC_NE;
2131 goto do_compare;
2132
2133 do_compare: {
2134 HReg op1;
2135 s390_opnd_RMI op2;
2136
2137 order_commutative_operands(arg1, arg2);
2138
2139 op1 = s390_isel_int_expr(env, arg1);
2140 op2 = s390_isel_int_expr_RMI(env, arg2);
2141
2142 addInstr(env, s390_insn_compare(size, op1, op2, False));
2143
2144 return result;
2145 }
2146
2147 case Iop_CmpLT32S:
2148 case Iop_CmpLE32S:
2149 case Iop_CmpLT64S:
2150 case Iop_CmpLE64S: {
2151 HReg op1;
2152 s390_opnd_RMI op2;
2153
2154 op1 = s390_isel_int_expr(env, arg1);
2155 op2 = s390_isel_int_expr_RMI(env, arg2);
2156
2157 addInstr(env, s390_insn_compare(size, op1, op2, True));
2158
2159 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2160 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2161 }
2162
2163 case Iop_CmpLT32U:
2164 case Iop_CmpLE32U:
2165 case Iop_CmpLT64U:
2166 case Iop_CmpLE64U: {
2167 HReg op1;
2168 s390_opnd_RMI op2;
2169
2170 op1 = s390_isel_int_expr(env, arg1);
2171 op2 = s390_isel_int_expr_RMI(env, arg2);
2172
2173 addInstr(env, s390_insn_compare(size, op1, op2, False));
2174
2175 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2176 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2177 }
2178
2179 default:
2180 goto fail;
2181 }
2182 }
2183
2184 fail:
2185 ppIRExpr(cond);
2186 vpanic("s390_isel_cc: unexpected operator");
2187}
2188
2189
2190/*---------------------------------------------------------*/
2191/*--- ISEL: Statements ---*/
2192/*---------------------------------------------------------*/
2193
2194static void
2195s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2196{
2197 if (vex_traceflags & VEX_TRACE_VCODE) {
2198 vex_printf("\n -- ");
2199 ppIRStmt(stmt);
2200 vex_printf("\n");
2201 }
2202
2203 switch (stmt->tag) {
2204
2205 /* --------- STORE --------- */
2206 case Ist_Store: {
2207 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2208 s390_amode *am;
2209 HReg src;
2210
2211 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2212
2213 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2214
2215 switch (tyd) {
2216 case Ity_I8:
2217 case Ity_I16:
2218 case Ity_I32:
2219 case Ity_I64:
2220 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2221 break;
2222
2223 case Ity_F32:
2224 case Ity_F64:
2225 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2226 break;
2227
2228 case Ity_F128:
2229 /* Cannot occur. No such instruction */
2230 vpanic("Ist_Store with F128 data");
2231
2232 default:
2233 goto stmt_fail;
2234 }
2235
2236 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2237 return;
2238 }
2239
2240 /* --------- PUT --------- */
2241 case Ist_Put: {
2242 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2243 HReg src;
2244 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002245 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002246
florianad43b3a2012-02-20 15:01:14 +00002247 /* Detect updates to certain guest registers. We track the contents
2248 of those registers as long as they contain constants. If the new
2249 constant is either zero or in the 8-bit neighbourhood of the
2250 current value we can use a memory-to-memory insn to do the update. */
2251
2252 Int offset = stmt->Ist.Put.offset;
2253
2254 /* Check necessary conditions:
2255 (1) must be one of the registers we care about
2256 (2) assigned value must be a constant */
2257 Int guest_reg = get_guest_reg(offset);
2258
2259 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2260
2261 if (guest_reg == GUEST_IA) {
2262 /* If this is the first assignment to the IA reg, don't special case
2263 it. We need to do a full 8-byte assignment here. The reason is
2264 that in case of a redirected translation the guest IA does not
2265 contain the redirected-to address. Instead it contains the
2266 redirected-from address and those can be far apart. So in order to
2267 do incremnetal updates if the IA in the future we need to get the
2268 initial address of the super block correct. */
2269 if (env->first_IA_assignment) {
2270 env->first_IA_assignment = False;
2271 goto not_special;
2272 }
2273 }
2274
2275 if (stmt->Ist.Put.data->tag != Iex_Const) {
2276 /* Invalidate guest register contents */
2277 env->old_value_valid[guest_reg] = False;
2278 goto not_special;
2279 }
2280
2281 /* OK. Necessary conditions are satisfied. */
2282
2283 /* Get the old value and update it */
2284 vassert(tyd == Ity_I64);
2285
2286 old_value = env->old_value[guest_reg];
2287 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2288 env->old_value[guest_reg] = new_value;
2289
2290 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2291 env->old_value_valid[guest_reg] = True;
2292
2293 /* If the register already contains the new value, there is nothing
2294 to do here. Unless the guest register requires precise memory
2295 exceptions. */
2296 if (old_value_is_valid && new_value == old_value) {
2297 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2298 return;
2299 }
2300 }
2301
2302 /* guest register = 0 */
2303 if (new_value == 0) {
2304 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2305 return;
2306 }
2307
2308 if (old_value_is_valid == False) goto not_special;
2309
2310 /* If the new value is in the neighbourhood of the old value
2311 we can use a memory-to-memory insn */
2312 difference = new_value - old_value;
2313
2314 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2315 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2316 (difference & 0xFF), new_value));
2317 return;
2318 }
2319
2320 /* If the high word is the same it is sufficient to load the low word.
2321 Use R0 as a scratch reg. */
2322 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002323 HReg r0 = make_gpr(0);
2324 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002325 s390_amode *gam;
2326
2327 gam = s390_amode_b12(offset + 4, gsp);
2328 addInstr(env, s390_insn_load_immediate(4, r0,
2329 new_value & 0xFFFFFFFF));
2330 addInstr(env, s390_insn_store(4, gam, r0));
2331 return;
2332 }
2333
2334 /* No special case applies... fall through */
2335
2336 not_special:
sewardj2019a972011-03-07 16:04:07 +00002337 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2338
2339 switch (tyd) {
2340 case Ity_I8:
2341 case Ity_I16:
2342 case Ity_I32:
2343 case Ity_I64:
2344 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2345 break;
2346
2347 case Ity_F32:
2348 case Ity_F64:
2349 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2350 break;
2351
2352 case Ity_F128:
2353 /* Does not occur. See function put_fpr_pair. */
2354 vpanic("Ist_Put with F128 data");
2355
2356 default:
2357 goto stmt_fail;
2358 }
2359
2360 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2361 return;
2362 }
2363
2364 /* --------- TMP --------- */
2365 case Ist_WrTmp: {
2366 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2367 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2368 HReg src, dst;
2369
2370 switch (tyd) {
2371 case Ity_I128: {
2372 HReg dst_hi, dst_lo, res_hi, res_lo;
2373
2374 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2375 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2376
2377 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2378 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2379 return;
2380 }
2381
2382 case Ity_I8:
2383 case Ity_I16:
2384 case Ity_I32:
2385 case Ity_I64:
2386 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2387 dst = lookupIRTemp(env, tmp);
2388 break;
2389
2390 case Ity_I1: {
2391 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2392 dst = lookupIRTemp(env, tmp);
2393 addInstr(env, s390_insn_cc2bool(dst, cond));
2394 return;
2395 }
2396
2397 case Ity_F32:
2398 case Ity_F64:
2399 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2400 dst = lookupIRTemp(env, tmp);
2401 break;
2402
2403 case Ity_F128: {
2404 HReg dst_hi, dst_lo, res_hi, res_lo;
2405
2406 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2407 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2408
2409 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2410 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2411 return;
2412 }
2413
2414 default:
2415 goto stmt_fail;
2416 }
2417
2418 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2419 return;
2420 }
2421
2422 /* --------- Call to DIRTY helper --------- */
2423 case Ist_Dirty: {
2424 IRType retty;
2425 IRDirty* d = stmt->Ist.Dirty.details;
2426 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002427 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002428 Int i;
2429
2430 /* Invalidate tracked values of those guest state registers that are
2431 modified by this helper. */
2432 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002433 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2434 descriptors in guest state effect descriptions. Hence: */
2435 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002436 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2437 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2438 if (guest_reg != GUEST_UNKNOWN)
2439 env->old_value_valid[guest_reg] = False;
2440 }
2441 }
sewardj2019a972011-03-07 16:04:07 +00002442
2443 if (d->nFxState == 0)
2444 vassert(!d->needsBBP);
2445
2446 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2447
florian01ed6e72012-05-27 16:52:43 +00002448 if (d->tmp == IRTemp_INVALID) {
2449 /* No return value. */
2450 dst = INVALID_HREG;
2451 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002452 return;
florian01ed6e72012-05-27 16:52:43 +00002453 }
sewardj2019a972011-03-07 16:04:07 +00002454
2455 retty = typeOfIRTemp(env->type_env, d->tmp);
2456 if (retty == Ity_I64 || retty == Ity_I32
2457 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002458 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002459 dst = lookupIRTemp(env, d->tmp);
2460 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002461 return;
2462 }
2463 break;
2464 }
2465
2466 case Ist_CAS:
2467 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2468 IRCAS *cas = stmt->Ist.CAS.details;
2469 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2470 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2471 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2472 HReg old = lookupIRTemp(env, cas->oldLo);
2473
2474 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2475 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2476 } else {
2477 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2478 }
2479 return;
2480 } else {
florian448cbba2012-06-06 02:26:01 +00002481 IRCAS *cas = stmt->Ist.CAS.details;
2482 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2483 HReg r8, r9, r10, r11, r1;
2484 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2485 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2486 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2487 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2488 HReg old_low = lookupIRTemp(env, cas->oldLo);
2489 HReg old_high = lookupIRTemp(env, cas->oldHi);
2490
2491 /* Use non-virtual registers r8 and r9 as pair for op1
2492 and move op1 there */
2493 r8 = make_gpr(8);
2494 r9 = make_gpr(9);
2495 addInstr(env, s390_insn_move(8, r8, op1_high));
2496 addInstr(env, s390_insn_move(8, r9, op1_low));
2497
2498 /* Use non-virtual registers r10 and r11 as pair for op3
2499 and move op3 there */
2500 r10 = make_gpr(10);
2501 r11 = make_gpr(11);
2502 addInstr(env, s390_insn_move(8, r10, op3_high));
2503 addInstr(env, s390_insn_move(8, r11, op3_low));
2504
2505 /* Register r1 is used as a scratch register */
2506 r1 = make_gpr(1);
2507
2508 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2509 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2510 old_high, old_low, r1));
2511 } else {
2512 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2513 old_high, old_low, r1));
2514 }
2515 addInstr(env, s390_insn_move(8, op1_high, r8));
2516 addInstr(env, s390_insn_move(8, op1_low, r9));
2517 addInstr(env, s390_insn_move(8, op3_high, r10));
2518 addInstr(env, s390_insn_move(8, op3_low, r11));
2519 return;
sewardj2019a972011-03-07 16:04:07 +00002520 }
2521 break;
2522
2523 /* --------- EXIT --------- */
2524 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002525 s390_cc_t cond;
2526 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2527
2528 if (tag != Ico_U64)
2529 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2530
florian8844a632012-04-13 04:04:06 +00002531 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002532 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002533
2534 /* Case: boring transfer to known address */
2535 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2536 if (env->chaining_allowed) {
2537 /* .. almost always true .. */
2538 /* Skip the event check at the dst if this is a forwards
2539 edge. */
2540 Bool to_fast_entry
2541 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2542 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2543 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2544 guest_IA, to_fast_entry));
2545 } else {
2546 /* .. very occasionally .. */
2547 /* We can't use chaining, so ask for an assisted transfer,
2548 as that's the only alternative that is allowable. */
2549 HReg dst = s390_isel_int_expr(env,
2550 IRExpr_Const(stmt->Ist.Exit.dst));
2551 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2552 }
2553 return;
2554 }
2555
2556 /* Case: assisted transfer to arbitrary address */
2557 switch (stmt->Ist.Exit.jk) {
florian65b5b3f2012-04-22 02:51:27 +00002558 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002559 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002560 case Ijk_Sys_syscall:
2561 case Ijk_ClientReq:
2562 case Ijk_NoRedir:
2563 case Ijk_Yield:
2564 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002565 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2566 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2567 stmt->Ist.Exit.jk));
2568 return;
2569 }
2570 default:
2571 break;
2572 }
2573
2574 /* Do we ever expect to see any other kind? */
2575 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002576 }
2577
2578 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002579 case Ist_MBE:
2580 switch (stmt->Ist.MBE.event) {
2581 case Imbe_Fence:
2582 addInstr(env, s390_insn_mfence());
2583 return;
2584 default:
2585 break;
2586 }
sewardj2019a972011-03-07 16:04:07 +00002587 break;
2588
2589 /* --------- Miscellaneous --------- */
2590
2591 case Ist_PutI: /* Not needed */
2592 case Ist_IMark: /* Doesn't generate any executable code */
2593 case Ist_NoOp: /* Doesn't generate any executable code */
2594 case Ist_AbiHint: /* Meaningless in IR */
2595 return;
2596
2597 default:
2598 break;
2599 }
2600
2601 stmt_fail:
2602 ppIRStmt(stmt);
2603 vpanic("s390_isel_stmt");
2604}
2605
2606
2607/*---------------------------------------------------------*/
2608/*--- ISEL: Basic block terminators (Nexts) ---*/
2609/*---------------------------------------------------------*/
2610
2611static void
florian8844a632012-04-13 04:04:06 +00002612iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002613{
sewardj2019a972011-03-07 16:04:07 +00002614 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002615 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002616 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002617 vex_printf("; exit-");
2618 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002619 vex_printf("\n");
2620 }
2621
florian8844a632012-04-13 04:04:06 +00002622 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2623
2624 /* Case: boring transfer to known address */
2625 if (next->tag == Iex_Const) {
2626 IRConst *cdst = next->Iex.Const.con;
2627 vassert(cdst->tag == Ico_U64);
2628 if (jk == Ijk_Boring || jk == Ijk_Call) {
2629 /* Boring transfer to known address */
2630 if (env->chaining_allowed) {
2631 /* .. almost always true .. */
2632 /* Skip the event check at the dst if this is a forwards
2633 edge. */
2634 Bool to_fast_entry
2635 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2636 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2637 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2638 guest_IA, to_fast_entry));
2639 } else {
2640 /* .. very occasionally .. */
2641 /* We can't use chaining, so ask for an indirect transfer,
2642 as that's the cheapest alternative that is allowable. */
2643 HReg dst = s390_isel_int_expr(env, next);
2644 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2645 Ijk_Boring));
2646 }
2647 return;
2648 }
2649 }
2650
2651 /* Case: call/return (==boring) transfer to any address */
2652 switch (jk) {
2653 case Ijk_Boring:
2654 case Ijk_Ret:
2655 case Ijk_Call: {
2656 HReg dst = s390_isel_int_expr(env, next);
2657 if (env->chaining_allowed) {
2658 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2659 } else {
2660 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2661 Ijk_Boring));
2662 }
2663 return;
2664 }
2665 default:
2666 break;
2667 }
2668
2669 /* Case: some other kind of transfer to any address */
2670 switch (jk) {
florian65b5b3f2012-04-22 02:51:27 +00002671 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002672 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002673 case Ijk_Sys_syscall:
2674 case Ijk_ClientReq:
2675 case Ijk_NoRedir:
2676 case Ijk_Yield:
2677 case Ijk_SigTRAP: {
2678 HReg dst = s390_isel_int_expr(env, next);
2679 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2680 return;
2681 }
2682 default:
2683 break;
2684 }
2685
2686 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002687}
2688
2689
2690/*---------------------------------------------------------*/
2691/*--- Insn selector top-level ---*/
2692/*---------------------------------------------------------*/
2693
florianf26994a2012-04-21 03:34:54 +00002694/* Translate an entire SB to s390 code.
2695 Note: archinfo_host is a pointer to a stack-allocated variable.
2696 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002697
2698HInstrArray *
2699iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002700 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2701 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2702 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002703{
2704 UInt i, j;
2705 HReg hreg, hregHI;
2706 ISelEnv *env;
2707 UInt hwcaps_host = archinfo_host->hwcaps;
2708
florianf26994a2012-04-21 03:34:54 +00002709 /* KLUDGE: export hwcaps. */
2710 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002711
sewardj2019a972011-03-07 16:04:07 +00002712 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002713 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002714
2715 /* Make up an initial environment to use. */
2716 env = LibVEX_Alloc(sizeof(ISelEnv));
2717 env->vreg_ctr = 0;
2718
2719 /* Set up output code array. */
2720 env->code = newHInstrArray();
2721
2722 /* Copy BB's type env. */
2723 env->type_env = bb->tyenv;
2724
florianad43b3a2012-02-20 15:01:14 +00002725 /* Set up data structures for tracking guest register values. */
2726 env->first_IA_assignment = True;
2727 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2728 env->old_value[i] = 0; /* just something to have a defined value */
2729 env->old_value_valid[i] = False;
2730 }
2731
sewardj2019a972011-03-07 16:04:07 +00002732 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2733 change as we go along. For some reason types_used has Int type -- but
2734 it should be unsigned. Internally we use an unsigned type; so we
2735 assert it here. */
2736 vassert(bb->tyenv->types_used >= 0);
2737
2738 env->n_vregmap = bb->tyenv->types_used;
2739 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2740 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2741
2742 /* and finally ... */
2743 env->hwcaps = hwcaps_host;
2744
florian8844a632012-04-13 04:04:06 +00002745 env->max_ga = max_ga;
2746 env->chaining_allowed = chaining_allowed;
2747
sewardj2019a972011-03-07 16:04:07 +00002748 /* For each IR temporary, allocate a suitably-kinded virtual
2749 register. */
2750 j = 0;
2751 for (i = 0; i < env->n_vregmap; i++) {
2752 hregHI = hreg = INVALID_HREG;
2753 switch (bb->tyenv->types[i]) {
2754 case Ity_I1:
2755 case Ity_I8:
2756 case Ity_I16:
2757 case Ity_I32:
2758 hreg = mkHReg(j++, HRcInt64, True);
2759 break;
2760
2761 case Ity_I64:
2762 hreg = mkHReg(j++, HRcInt64, True);
2763 break;
2764
2765 case Ity_I128:
2766 hreg = mkHReg(j++, HRcInt64, True);
2767 hregHI = mkHReg(j++, HRcInt64, True);
2768 break;
2769
2770 case Ity_F32:
2771 case Ity_F64:
2772 hreg = mkHReg(j++, HRcFlt64, True);
2773 break;
2774
2775 case Ity_F128:
2776 hreg = mkHReg(j++, HRcFlt64, True);
2777 hregHI = mkHReg(j++, HRcFlt64, True);
2778 break;
2779
2780 case Ity_V128: /* fall through */
2781 default:
2782 ppIRType(bb->tyenv->types[i]);
2783 vpanic("s390_isel_sb: IRTemp type");
2784 }
2785
2786 env->vregmap[i] = hreg;
2787 env->vregmapHI[i] = hregHI;
2788 }
2789 env->vreg_ctr = j;
2790
florian8844a632012-04-13 04:04:06 +00002791 /* The very first instruction must be an event check. */
2792 s390_amode *counter, *fail_addr;
2793 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2794 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2795 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2796
2797 /* Possibly a block counter increment (for profiling). At this
2798 point we don't know the address of the counter, so just pretend
2799 it is zero. It will have to be patched later, but before this
2800 translation is used, by a call to LibVEX_patchProfInc. */
2801 if (add_profinc) {
2802 addInstr(env, s390_insn_profinc());
2803 }
2804
sewardj2019a972011-03-07 16:04:07 +00002805 /* Ok, finally we can iterate over the statements. */
2806 for (i = 0; i < bb->stmts_used; i++)
2807 if (bb->stmts[i])
2808 s390_isel_stmt(env, bb->stmts[i]);
2809
florian8844a632012-04-13 04:04:06 +00002810 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002811
2812 /* Record the number of vregs we used. */
2813 env->code->n_vregs = env->vreg_ctr;
2814
2815 return env->code;
2816}
2817
2818/*---------------------------------------------------------------*/
2819/*--- end host_s390_isel.c ---*/
2820/*---------------------------------------------------------------*/