blob: 42b92c8c62ad6b7b6abcb11d8dd25824aef1f02c [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
florian61f23c12012-08-06 18:33:21 +000011 Copyright IBM Corp. 2010-2012
sewardj2019a972011-03-07 16:04:07 +000012
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
florian11b8ee82012-08-06 13:35:33 +0000468 /* All arguments must have Ity_I64. For two reasons:
469 (1) We do not handle floating point arguments.
470 (2) The ABI requires that integer values are sign- or zero-extended
471 to 64 bit.
472 */
473 Int arg_errors = 0;
474 for (i = 0; i < n_args; ++i) {
475 IRType type = typeOfIRExpr(env->type_env, args[i]);
476 if (type != Ity_I64) {
477 ++arg_errors;
478 vex_printf("calling %s: argument #%d has type ", callee->name, i);
479 ppIRType(type);
480 vex_printf("; Ity_I64 is required\n");
481 }
482 }
483
484 if (arg_errors)
485 vpanic("cannot continue due to errors in argument passing");
486
florian52af7bc2012-05-12 03:44:49 +0000487 argreg = 0;
488
489 /* If we need the guest state pointer put it in a temporary arg reg */
490 if (passBBP) {
491 tmpregs[argreg] = newVRegI(env);
492 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
493 s390_hreg_guest_state_pointer()));
494 argreg++;
495 }
496
497 /* Compute the function arguments into a temporary register each */
498 for (i = 0; i < n_args; i++) {
499 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
500 argreg++;
501 }
502
sewardj2019a972011-03-07 16:04:07 +0000503 /* Compute the condition */
504 cc = S390_CC_ALWAYS;
505 if (guard) {
506 if (guard->tag == Iex_Const
507 && guard->Iex.Const.con->tag == Ico_U1
508 && guard->Iex.Const.con->Ico.U1 == True) {
509 /* unconditional -- do nothing */
510 } else {
511 cc = s390_isel_cc(env, guard);
512 }
513 }
514
florian52af7bc2012-05-12 03:44:49 +0000515 /* Move the args to the final register. It is paramount, that the
516 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000517 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000518 HReg finalreg;
519
520 finalreg = make_gpr(s390_gprno_from_arg_index(i));
521 size = sizeofIRType(Ity_I64);
522 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000523 }
524
525 target = Ptr_to_ULong(callee->addr);
526
527 /* Finally, the call itself. */
528 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000529 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000530}
531
532
533/* Given an expression representing a rounding mode using IRRoundingMode
534 encoding convert it to an s390_round_t value. */
535static s390_round_t
536decode_rounding_mode(IRExpr *rounding_expr)
537{
538 if (rounding_expr->tag == Iex_Const &&
539 rounding_expr->Iex.Const.con->tag == Ico_U32) {
540 IRRoundingMode mode = rounding_expr->Iex.Const.con->Ico.U32;
541
542 switch (mode) {
543 case Irrm_NEAREST: return S390_ROUND_NEAREST_EVEN;
544 case Irrm_ZERO: return S390_ROUND_ZERO;
545 case Irrm_PosINF: return S390_ROUND_POSINF;
546 case Irrm_NegINF: return S390_ROUND_NEGINF;
547 }
548 }
549
550 vpanic("decode_rounding_mode");
551}
552
553
554/* CC_S390 holds the condition code in s390 encoding. Convert it to
555 VEX encoding
556
557 s390 VEX b6 b2 b0 cc.1 cc.0
558 0 0x40 EQ 1 0 0 0 0
559 1 0x01 LT 0 0 1 0 1
560 2 0x00 GT 0 0 0 1 0
561 3 0x45 Unordered 1 1 1 1 1
562
563 b0 = cc.0
564 b2 = cc.0 & cc.1
565 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
566
567 VEX = b0 | (b2 << 2) | (b6 << 6);
568*/
569static HReg
570convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390)
571{
572 HReg cc0, cc1, b2, b6, cc_vex;
573
574 cc0 = newVRegI(env);
575 addInstr(env, s390_insn_move(4, cc0, cc_s390));
576 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
577
578 cc1 = newVRegI(env);
579 addInstr(env, s390_insn_move(4, cc1, cc_s390));
580 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
581
582 b2 = newVRegI(env);
583 addInstr(env, s390_insn_move(4, b2, cc0));
584 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
585 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
586
587 b6 = newVRegI(env);
588 addInstr(env, s390_insn_move(4, b6, cc0));
589 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
590 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
591 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
592 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
593
594 cc_vex = newVRegI(env);
595 addInstr(env, s390_insn_move(4, cc_vex, cc0));
596 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
597 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
598
599 return cc_vex;
600}
601
602
603/*---------------------------------------------------------*/
604/*--- ISEL: Integer expressions (128 bit) ---*/
605/*---------------------------------------------------------*/
606static void
607s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
608 IRExpr *expr)
609{
610 IRType ty = typeOfIRExpr(env->type_env, expr);
611
612 vassert(ty == Ity_I128);
613
614 /* No need to consider the following
615 - 128-bit constants (they do not exist in VEX)
616 - 128-bit loads from memory (will not be generated)
617 */
618
619 /* Read 128-bit IRTemp */
620 if (expr->tag == Iex_RdTmp) {
621 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
622 return;
623 }
624
625 if (expr->tag == Iex_Binop) {
626 IRExpr *arg1 = expr->Iex.Binop.arg1;
627 IRExpr *arg2 = expr->Iex.Binop.arg2;
628 Bool is_signed_multiply, is_signed_divide;
629
630 switch (expr->Iex.Binop.op) {
631 case Iop_MullU64:
632 is_signed_multiply = False;
633 goto do_multiply64;
634
635 case Iop_MullS64:
636 is_signed_multiply = True;
637 goto do_multiply64;
638
639 case Iop_DivModU128to64:
640 is_signed_divide = False;
641 goto do_divide64;
642
643 case Iop_DivModS128to64:
644 is_signed_divide = True;
645 goto do_divide64;
646
647 case Iop_64HLto128:
648 *dst_hi = s390_isel_int_expr(env, arg1);
649 *dst_lo = s390_isel_int_expr(env, arg2);
650 return;
651
652 case Iop_DivModS64to64: {
653 HReg r10, r11, h1;
654 s390_opnd_RMI op2;
655
656 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
657 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
658
659 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000660 r10 = make_gpr(10);
661 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000662
663 /* Move 1st operand into r11 and */
664 addInstr(env, s390_insn_move(8, r11, h1));
665
666 /* Divide */
667 addInstr(env, s390_insn_divs(8, r10, r11, op2));
668
669 /* The result is in registers r10 (remainder) and r11 (quotient).
670 Move the result into the reg pair that is being returned such
671 such that the low 64 bits are the quotient and the upper 64 bits
672 are the remainder. (see libvex_ir.h). */
673 *dst_hi = newVRegI(env);
674 *dst_lo = newVRegI(env);
675 addInstr(env, s390_insn_move(8, *dst_hi, r10));
676 addInstr(env, s390_insn_move(8, *dst_lo, r11));
677 return;
678 }
679
680 default:
681 break;
682
683 do_multiply64: {
684 HReg r10, r11, h1;
685 s390_opnd_RMI op2;
686
687 order_commutative_operands(arg1, arg2);
688
689 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
690 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
691
692 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000693 r10 = make_gpr(10);
694 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000695
696 /* Move the first operand to r11 */
697 addInstr(env, s390_insn_move(8, r11, h1));
698
699 /* Multiply */
700 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
701
702 /* The result is in registers r10 and r11. Assign to two virtual regs
703 and return. */
704 *dst_hi = newVRegI(env);
705 *dst_lo = newVRegI(env);
706 addInstr(env, s390_insn_move(8, *dst_hi, r10));
707 addInstr(env, s390_insn_move(8, *dst_lo, r11));
708 return;
709 }
710
711 do_divide64: {
712 HReg r10, r11, hi, lo;
713 s390_opnd_RMI op2;
714
715 s390_isel_int128_expr(&hi, &lo, env, arg1);
716 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
717
718 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000719 r10 = make_gpr(10);
720 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000721
722 /* Move high 64 bits of the 1st operand into r10 and
723 the low 64 bits into r11. */
724 addInstr(env, s390_insn_move(8, r10, hi));
725 addInstr(env, s390_insn_move(8, r11, lo));
726
727 /* Divide */
728 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
729
730 /* The result is in registers r10 (remainder) and r11 (quotient).
731 Move the result into the reg pair that is being returned such
732 such that the low 64 bits are the quotient and the upper 64 bits
733 are the remainder. (see libvex_ir.h). */
734 *dst_hi = newVRegI(env);
735 *dst_lo = newVRegI(env);
736 addInstr(env, s390_insn_move(8, *dst_hi, r10));
737 addInstr(env, s390_insn_move(8, *dst_lo, r11));
738 return;
739 }
740 }
741 }
742
743 vpanic("s390_isel_int128_expr");
744}
745
746
747/* Compute a 128-bit value into two 64-bit registers. These may be either
748 real or virtual regs; in any case they must not be changed by subsequent
749 code emitted by the caller. */
750static void
751s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
752{
753 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
754
755 /* Sanity checks ... */
756 vassert(hregIsVirtual(*dst_hi));
757 vassert(hregIsVirtual(*dst_lo));
758 vassert(hregClass(*dst_hi) == HRcInt64);
759 vassert(hregClass(*dst_lo) == HRcInt64);
760}
761
762
763/*---------------------------------------------------------*/
764/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
765/*---------------------------------------------------------*/
766
767/* Select insns for an integer-typed expression, and add them to the
768 code list. Return a reg holding the result. This reg will be a
769 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
770 want to modify it, ask for a new vreg, copy it in there, and modify
771 the copy. The register allocator will do its best to map both
772 vregs to the same real register, so the copies will often disappear
773 later in the game.
774
775 This should handle expressions of 64, 32, 16 and 8-bit type.
776 All results are returned in a 64bit register.
777 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
778 are arbitrary, so you should mask or sign extend partial values
779 if necessary.
780*/
781
782/* DO NOT CALL THIS DIRECTLY ! */
783static HReg
784s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
785{
786 IRType ty = typeOfIRExpr(env->type_env, expr);
787 UChar size;
florian9fcff4c2012-09-10 03:09:04 +0000788 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +0000789
790 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
791
792 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
793
794 switch (expr->tag) {
795
796 /* --------- TEMP --------- */
797 case Iex_RdTmp:
798 /* Return the virtual register that holds the temporary. */
799 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
800
801 /* --------- LOAD --------- */
802 case Iex_Load: {
803 HReg dst = newVRegI(env);
804 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
805
806 if (expr->Iex.Load.end != Iend_BE)
807 goto irreducible;
808
809 addInstr(env, s390_insn_load(size, dst, am));
810
811 return dst;
812 }
813
814 /* --------- BINARY OP --------- */
815 case Iex_Binop: {
816 IRExpr *arg1 = expr->Iex.Binop.arg1;
817 IRExpr *arg2 = expr->Iex.Binop.arg2;
818 HReg h1, res;
819 s390_alu_t opkind;
820 s390_opnd_RMI op2, value, opnd;
821 s390_insn *insn;
822 Bool is_commutative, is_signed_multiply, is_signed_divide;
823
824 is_commutative = True;
825
826 switch (expr->Iex.Binop.op) {
827 case Iop_MullU8:
828 case Iop_MullU16:
829 case Iop_MullU32:
830 is_signed_multiply = False;
831 goto do_multiply;
832
833 case Iop_MullS8:
834 case Iop_MullS16:
835 case Iop_MullS32:
836 is_signed_multiply = True;
837 goto do_multiply;
838
839 do_multiply: {
840 HReg r10, r11;
841 UInt arg_size = size / 2;
842
843 order_commutative_operands(arg1, arg2);
844
845 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
846 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
847
848 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000849 r10 = make_gpr(10);
850 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000851
852 /* Move the first operand to r11 */
853 addInstr(env, s390_insn_move(arg_size, r11, h1));
854
855 /* Multiply */
856 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
857
858 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
859 value into the destination register. */
860 res = newVRegI(env);
861 addInstr(env, s390_insn_move(arg_size, res, r10));
862 value = s390_opnd_imm(arg_size * 8);
863 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
864 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
865 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
866 opnd = s390_opnd_reg(r11);
867 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
868 return res;
869 }
870
871 case Iop_DivModS64to32:
872 is_signed_divide = True;
873 goto do_divide;
874
875 case Iop_DivModU64to32:
876 is_signed_divide = False;
877 goto do_divide;
878
879 do_divide: {
880 HReg r10, r11;
881
882 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
883 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
884
885 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000886 r10 = make_gpr(10);
887 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000888
889 /* Split the first operand and put the high 32 bits into r10 and
890 the low 32 bits into r11. */
891 addInstr(env, s390_insn_move(8, r10, h1));
892 addInstr(env, s390_insn_move(8, r11, h1));
893 value = s390_opnd_imm(32);
894 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
895
896 /* Divide */
897 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
898
899 /* The result is in registers r10 (remainder) and r11 (quotient).
900 Combine them into a 64-bit value such that the low 32 bits are
901 the quotient and the upper 32 bits are the remainder. (see
902 libvex_ir.h). */
903 res = newVRegI(env);
904 addInstr(env, s390_insn_move(8, res, r10));
905 value = s390_opnd_imm(32);
906 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
907 value = s390_opnd_imm((((ULong)1) << 32) - 1);
908 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
909 opnd = s390_opnd_reg(r11);
910 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
911 return res;
912 }
913
florian9fcff4c2012-09-10 03:09:04 +0000914 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
915 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
916 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
917 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
918 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
919 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
920 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
921 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
922 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
923 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
924 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
925 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
sewardj2019a972011-03-07 16:04:07 +0000926
927 do_convert: {
928 s390_round_t rounding_mode;
929
930 res = newVRegI(env);
931 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
932
933 rounding_mode = decode_rounding_mode(arg1);
florian9fcff4c2012-09-10 03:09:04 +0000934 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1, rounding_mode));
sewardj2019a972011-03-07 16:04:07 +0000935 return res;
936 }
937
938 do_convert_128: {
939 s390_round_t rounding_mode;
940 HReg op_hi, op_lo, f13, f15;
941
942 res = newVRegI(env);
943 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
944
945 /* We use non-virtual registers r13 and r15 as pair */
946 f13 = make_fpr(13);
947 f15 = make_fpr(15);
948
949 /* operand --> (f13, f15) */
950 addInstr(env, s390_insn_move(8, f13, op_hi));
951 addInstr(env, s390_insn_move(8, f15, op_lo));
952
953 rounding_mode = decode_rounding_mode(arg1);
florian9fcff4c2012-09-10 03:09:04 +0000954 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +0000955 rounding_mode));
956 return res;
957 }
958
959 case Iop_8HLto16:
960 case Iop_16HLto32:
961 case Iop_32HLto64: {
962 HReg h2;
963 UInt arg_size = size / 2;
964
965 res = newVRegI(env);
966 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
967 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
968
969 addInstr(env, s390_insn_move(arg_size, res, h1));
970 value = s390_opnd_imm(arg_size * 8);
971 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
972 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
973 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
974 opnd = s390_opnd_reg(h2);
975 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
976 return res;
977 }
978
979 case Iop_Max32U: {
980 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
981 res = newVRegI(env);
982 h1 = s390_isel_int_expr(env, arg1);
983 op2 = s390_isel_int_expr_RMI(env, arg2);
984
985 addInstr(env, s390_insn_move(size, res, h1));
986 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
987 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
988 return res;
989 }
990
991 case Iop_CmpF32:
992 case Iop_CmpF64: {
993 HReg cc_s390, h2;
994
995 h1 = s390_isel_float_expr(env, arg1);
996 h2 = s390_isel_float_expr(env, arg2);
997 cc_s390 = newVRegI(env);
998
999 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1000
1001 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1002
1003 return convert_s390_fpcc_to_vex(env, cc_s390);
1004 }
1005
1006 case Iop_CmpF128: {
1007 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1008
1009 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1010 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1011 cc_s390 = newVRegI(env);
1012
1013 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1014 f12 = make_fpr(12);
1015 f13 = make_fpr(13);
1016 f14 = make_fpr(14);
1017 f15 = make_fpr(15);
1018
1019 /* 1st operand --> (f12, f14) */
1020 addInstr(env, s390_insn_move(8, f12, op1_hi));
1021 addInstr(env, s390_insn_move(8, f14, op1_lo));
1022
1023 /* 2nd operand --> (f13, f15) */
1024 addInstr(env, s390_insn_move(8, f13, op2_hi));
1025 addInstr(env, s390_insn_move(8, f15, op2_lo));
1026
1027 res = newVRegI(env);
1028 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1029
1030 return convert_s390_fpcc_to_vex(env, cc_s390);
1031 }
1032
1033 case Iop_Add8:
1034 case Iop_Add16:
1035 case Iop_Add32:
1036 case Iop_Add64:
1037 opkind = S390_ALU_ADD;
1038 break;
1039
1040 case Iop_Sub8:
1041 case Iop_Sub16:
1042 case Iop_Sub32:
1043 case Iop_Sub64:
1044 opkind = S390_ALU_SUB;
1045 is_commutative = False;
1046 break;
1047
1048 case Iop_And8:
1049 case Iop_And16:
1050 case Iop_And32:
1051 case Iop_And64:
1052 opkind = S390_ALU_AND;
1053 break;
1054
1055 case Iop_Or8:
1056 case Iop_Or16:
1057 case Iop_Or32:
1058 case Iop_Or64:
1059 opkind = S390_ALU_OR;
1060 break;
1061
1062 case Iop_Xor8:
1063 case Iop_Xor16:
1064 case Iop_Xor32:
1065 case Iop_Xor64:
1066 opkind = S390_ALU_XOR;
1067 break;
1068
1069 case Iop_Shl8:
1070 case Iop_Shl16:
1071 case Iop_Shl32:
1072 case Iop_Shl64:
1073 opkind = S390_ALU_LSH;
1074 is_commutative = False;
1075 break;
1076
1077 case Iop_Shr8:
1078 case Iop_Shr16:
1079 case Iop_Shr32:
1080 case Iop_Shr64:
1081 opkind = S390_ALU_RSH;
1082 is_commutative = False;
1083 break;
1084
1085 case Iop_Sar8:
1086 case Iop_Sar16:
1087 case Iop_Sar32:
1088 case Iop_Sar64:
1089 opkind = S390_ALU_RSHA;
1090 is_commutative = False;
1091 break;
1092
1093 default:
1094 goto irreducible;
1095 }
1096
1097 /* Pattern match: 0 - arg1 --> -arg1 */
1098 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1099 res = newVRegI(env);
1100 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1101 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1102 addInstr(env, insn);
1103
1104 return res;
1105 }
1106
1107 if (is_commutative) {
1108 order_commutative_operands(arg1, arg2);
1109 }
1110
1111 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1112 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1113 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001114
1115 /* As right shifts of one/two byte opreands are implemented using a
1116 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1117 switch (expr->Iex.Binop.op) {
1118 case Iop_Shr8:
1119 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1120 break;
1121 case Iop_Shr16:
1122 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1123 break;
1124 case Iop_Sar8:
1125 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1126 break;
1127 case Iop_Sar16:
1128 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1129 break;
1130 default:
1131 insn = s390_insn_move(size, res, h1);
1132 break;
1133 }
1134 addInstr(env, insn);
1135
sewardj2019a972011-03-07 16:04:07 +00001136 insn = s390_insn_alu(size, opkind, res, op2);
1137
1138 addInstr(env, insn);
1139
1140 return res;
1141 }
1142
1143 /* --------- UNARY OP --------- */
1144 case Iex_Unop: {
1145 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1146 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1147 s390_opnd_RMI opnd;
1148 s390_insn *insn;
1149 IRExpr *arg;
1150 HReg dst, h1;
1151 IROp unop, binop;
1152
1153 arg = expr->Iex.Unop.arg;
1154
1155 /* Special cases are handled here */
1156
1157 /* 32-bit multiply with 32-bit result or
1158 64-bit multiply with 64-bit result */
1159 unop = expr->Iex.Unop.op;
1160 binop = arg->Iex.Binop.op;
1161
1162 if ((arg->tag == Iex_Binop &&
1163 ((unop == Iop_64to32 &&
1164 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1165 (unop == Iop_128to64 &&
1166 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1167 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1168 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1169 dst = newVRegI(env); /* Result goes into a new register */
1170 addInstr(env, s390_insn_move(size, dst, h1));
1171 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1172
1173 return dst;
1174 }
1175
florian4d71a082011-12-18 00:08:17 +00001176 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001177 dst = newVRegI(env);
1178 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1179 addInstr(env, s390_insn_move(size, dst, h1));
1180
1181 return dst;
1182 }
1183
1184 /* Expressions whose argument is 1-bit wide */
1185 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1186 s390_cc_t cond = s390_isel_cc(env, arg);
1187 dst = newVRegI(env); /* Result goes into a new register */
1188 addInstr(env, s390_insn_cc2bool(dst, cond));
1189
1190 switch (unop) {
1191 case Iop_1Uto8:
1192 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001193 /* Zero extend */
1194 mask.variant.imm = 1;
1195 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1196 break;
1197
sewardj2019a972011-03-07 16:04:07 +00001198 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001199 /* Zero extend */
1200 mask.variant.imm = 1;
1201 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001202 break;
1203
1204 case Iop_1Sto8:
1205 case Iop_1Sto16:
1206 case Iop_1Sto32:
1207 shift.variant.imm = 31;
1208 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1209 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1210 break;
1211
1212 case Iop_1Sto64:
1213 shift.variant.imm = 63;
1214 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1215 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1216 break;
1217
1218 default:
1219 goto irreducible;
1220 }
1221
1222 return dst;
1223 }
1224
1225 /* Regular processing */
1226
1227 if (unop == Iop_128to64) {
1228 HReg dst_hi, dst_lo;
1229
1230 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1231 return dst_lo;
1232 }
1233
1234 if (unop == Iop_128HIto64) {
1235 HReg dst_hi, dst_lo;
1236
1237 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1238 return dst_hi;
1239 }
1240
1241 dst = newVRegI(env); /* Result goes into a new register */
1242 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1243
1244 switch (unop) {
1245 case Iop_8Uto16:
1246 case Iop_8Uto32:
1247 case Iop_8Uto64:
1248 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1249 break;
1250
1251 case Iop_16Uto32:
1252 case Iop_16Uto64:
1253 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1254 break;
1255
1256 case Iop_32Uto64:
1257 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1258 break;
1259
1260 case Iop_8Sto16:
1261 case Iop_8Sto32:
1262 case Iop_8Sto64:
1263 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1264 break;
1265
1266 case Iop_16Sto32:
1267 case Iop_16Sto64:
1268 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1269 break;
1270
1271 case Iop_32Sto64:
1272 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1273 break;
1274
1275 case Iop_64to8:
1276 case Iop_64to16:
1277 case Iop_64to32:
1278 case Iop_32to8:
1279 case Iop_32to16:
1280 case Iop_16to8:
1281 /* Down-casts are no-ops. Upstream operations will only look at
1282 the bytes that make up the result of the down-cast. So there
1283 is no point setting the other bytes to 0. */
1284 insn = s390_opnd_copy(8, dst, opnd);
1285 break;
1286
1287 case Iop_64HIto32:
1288 addInstr(env, s390_opnd_copy(8, dst, opnd));
1289 shift.variant.imm = 32;
1290 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1291 break;
1292
1293 case Iop_32HIto16:
1294 addInstr(env, s390_opnd_copy(4, dst, opnd));
1295 shift.variant.imm = 16;
1296 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1297 break;
1298
1299 case Iop_16HIto8:
1300 addInstr(env, s390_opnd_copy(2, dst, opnd));
1301 shift.variant.imm = 8;
1302 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1303 break;
1304
1305 case Iop_Not8:
1306 case Iop_Not16:
1307 case Iop_Not32:
1308 case Iop_Not64:
1309 /* XOR with ffff... */
1310 mask.variant.imm = ~(ULong)0;
1311 addInstr(env, s390_opnd_copy(size, dst, opnd));
1312 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1313 break;
1314
1315 case Iop_Left8:
1316 case Iop_Left16:
1317 case Iop_Left32:
1318 case Iop_Left64:
1319 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1320 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1321 break;
1322
1323 case Iop_CmpwNEZ32:
1324 case Iop_CmpwNEZ64: {
1325 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1326 or -X will have a 1 in the MSB. */
1327 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1328 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1329 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1330 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1331 return dst;
1332 }
1333
1334 case Iop_Clz64: {
1335 HReg r10, r11;
1336
sewardj611b06e2011-03-24 08:57:29 +00001337 /* This will be implemented using FLOGR, if possible. So we need to
1338 set aside a pair of non-virtual registers. The result (number of
1339 left-most zero bits) will be in r10. The value in r11 is unspecified
1340 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001341 r10 = make_gpr(10);
1342 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001343
sewardj611b06e2011-03-24 08:57:29 +00001344 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001345 addInstr(env, s390_insn_move(8, dst, r10));
1346 return dst;
1347 }
1348
1349 default:
1350 goto irreducible;
1351 }
1352
1353 addInstr(env, insn);
1354
1355 return dst;
1356 }
1357
1358 /* --------- GET --------- */
1359 case Iex_Get: {
1360 HReg dst = newVRegI(env);
1361 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1362
1363 /* We never load more than 8 bytes from the guest state, because the
1364 floating point register pair is not contiguous. */
1365 vassert(size <= 8);
1366
1367 addInstr(env, s390_insn_load(size, dst, am));
1368
1369 return dst;
1370 }
1371
1372 case Iex_GetI:
1373 /* not needed */
1374 break;
1375
1376 /* --------- CCALL --------- */
1377 case Iex_CCall: {
1378 HReg dst = newVRegI(env);
1379
1380 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001381 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001382 return dst;
1383 }
1384
1385 /* --------- LITERAL --------- */
1386
1387 /* Load a literal into a register. Create a "load immediate"
1388 v-insn and return the register. */
1389 case Iex_Const: {
1390 ULong value;
1391 HReg dst = newVRegI(env);
1392 const IRConst *con = expr->Iex.Const.con;
1393
1394 /* Bitwise copy of the value. No sign/zero-extension */
1395 switch (con->tag) {
1396 case Ico_U64: value = con->Ico.U64; break;
1397 case Ico_U32: value = con->Ico.U32; break;
1398 case Ico_U16: value = con->Ico.U16; break;
1399 case Ico_U8: value = con->Ico.U8; break;
1400 default: vpanic("s390_isel_int_expr: invalid constant");
1401 }
1402
1403 addInstr(env, s390_insn_load_immediate(size, dst, value));
1404
1405 return dst;
1406 }
1407
1408 /* --------- MULTIPLEX --------- */
1409 case Iex_Mux0X: {
1410 IRExpr *cond_expr;
1411 HReg dst, tmp, rX;
1412 s390_opnd_RMI cond, r0, zero;
1413
1414 cond_expr = expr->Iex.Mux0X.cond;
1415
1416 dst = newVRegI(env);
1417 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1418 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1419 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1420
1421 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1422 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1423
1424 addInstr(env, s390_insn_move(size, dst, rX));
1425 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1426 return dst;
1427 }
1428
1429 /* Assume the condition is true and move rX to the destination reg. */
1430 addInstr(env, s390_insn_move(size, dst, rX));
1431
1432 /* Compute the condition ... */
1433 cond = s390_isel_int_expr_RMI(env, cond_expr);
1434
1435 /* tmp = cond & 0xFF */
1436 tmp = newVRegI(env);
1437 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1438 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1439
1440 /* ... and compare it with zero */
1441 zero = s390_opnd_imm(0);
1442 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1443
1444 /* ... and if it compared equal move r0 to the destination reg. */
1445 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1446 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1447
1448 return dst;
1449 }
1450
1451 default:
1452 break;
1453 }
1454
1455 /* We get here if no pattern matched. */
1456 irreducible:
1457 ppIRExpr(expr);
1458 vpanic("s390_isel_int_expr: cannot reduce tree");
1459}
1460
1461
1462static HReg
1463s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1464{
1465 HReg dst = s390_isel_int_expr_wrk(env, expr);
1466
1467 /* Sanity checks ... */
1468 vassert(hregClass(dst) == HRcInt64);
1469 vassert(hregIsVirtual(dst));
1470
1471 return dst;
1472}
1473
1474
1475static s390_opnd_RMI
1476s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1477{
1478 IRType ty = typeOfIRExpr(env->type_env, expr);
1479 s390_opnd_RMI dst;
1480
1481 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1482 ty == Ity_I64);
1483
1484 if (expr->tag == Iex_Load) {
1485 dst.tag = S390_OPND_AMODE;
1486 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1487 } else if (expr->tag == Iex_Get) {
1488 dst.tag = S390_OPND_AMODE;
1489 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1490 } else if (expr->tag == Iex_Const) {
1491 ULong value;
1492
1493 /* The bit pattern for the value will be stored as is in the least
1494 significant bits of VALUE. */
1495 switch (expr->Iex.Const.con->tag) {
1496 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1497 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1498 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1499 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1500 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1501 default:
1502 vpanic("s390_isel_int_expr_RMI");
1503 }
1504
1505 dst.tag = S390_OPND_IMMEDIATE;
1506 dst.variant.imm = value;
1507 } else {
1508 dst.tag = S390_OPND_REG;
1509 dst.variant.reg = s390_isel_int_expr(env, expr);
1510 }
1511
1512 return dst;
1513}
1514
1515
1516/*---------------------------------------------------------*/
1517/*--- ISEL: Floating point expressions (128 bit) ---*/
1518/*---------------------------------------------------------*/
1519static void
1520s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1521 IRExpr *expr)
1522{
1523 IRType ty = typeOfIRExpr(env->type_env, expr);
1524
1525 vassert(ty == Ity_F128);
1526
1527 /* Read 128-bit IRTemp */
1528 if (expr->tag == Iex_RdTmp) {
1529 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1530 return;
1531 }
1532
1533 switch (expr->tag) {
1534 case Iex_RdTmp:
1535 /* Return the virtual registers that hold the temporary. */
1536 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1537 return;
1538
1539 /* --------- LOAD --------- */
1540 case Iex_Load: {
1541 IRExpr *addr_hi, *addr_lo;
1542 s390_amode *am_hi, *am_lo;
1543
1544 if (expr->Iex.Load.end != Iend_BE)
1545 goto irreducible;
1546
1547 addr_hi = expr->Iex.Load.addr;
1548 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1549
1550 am_hi = s390_isel_amode(env, addr_hi);
1551 am_lo = s390_isel_amode(env, addr_lo);
1552
1553 *dst_hi = newVRegF(env);
1554 *dst_lo = newVRegF(env);
1555 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1556 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1557 return;
1558 }
1559
1560
1561 /* --------- GET --------- */
1562 case Iex_Get:
1563 /* This is not supported because loading 128-bit from the guest
1564 state is almost certainly wrong. Use get_fpr_pair instead. */
1565 vpanic("Iex_Get with F128 data");
1566
1567 /* --------- 4-ary OP --------- */
1568 case Iex_Qop:
1569 vpanic("Iex_Qop with F128 data");
1570
1571 /* --------- TERNARY OP --------- */
1572 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001573 IRTriop *triop = expr->Iex.Triop.details;
1574 IROp op = triop->op;
1575 IRExpr *left = triop->arg2;
1576 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001577 s390_bfp_binop_t bfpop;
1578 s390_round_t rounding_mode;
1579 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1580
1581 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1582 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1583
1584 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1585 f12 = make_fpr(12);
1586 f13 = make_fpr(13);
1587 f14 = make_fpr(14);
1588 f15 = make_fpr(15);
1589
1590 /* 1st operand --> (f12, f14) */
1591 addInstr(env, s390_insn_move(8, f12, op1_hi));
1592 addInstr(env, s390_insn_move(8, f14, op1_lo));
1593
1594 /* 2nd operand --> (f13, f15) */
1595 addInstr(env, s390_insn_move(8, f13, op2_hi));
1596 addInstr(env, s390_insn_move(8, f15, op2_lo));
1597
1598 switch (op) {
1599 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1600 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1601 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1602 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1603 default:
1604 goto irreducible;
1605 }
1606
florian420bfa92012-06-02 20:29:22 +00001607 rounding_mode = decode_rounding_mode(triop->arg1);
sewardj2019a972011-03-07 16:04:07 +00001608 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13,
1609 f15, rounding_mode));
1610
1611 /* Move result to virtual destination register */
1612 *dst_hi = newVRegF(env);
1613 *dst_lo = newVRegF(env);
1614 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1615 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1616
1617 return;
1618 }
1619
1620 /* --------- BINARY OP --------- */
1621 case Iex_Binop: {
1622 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardja970c402011-04-28 18:38:42 +00001623 s390_bfp_unop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001624 s390_round_t rounding_mode;
1625
1626 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1627 f12 = make_fpr(12);
1628 f13 = make_fpr(13);
1629 f14 = make_fpr(14);
1630 f15 = make_fpr(15);
1631
1632 switch (expr->Iex.Binop.op) {
1633 case Iop_SqrtF128:
1634 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1635
1636 /* operand --> (f13, f15) */
1637 addInstr(env, s390_insn_move(8, f13, op_hi));
1638 addInstr(env, s390_insn_move(8, f15, op_lo));
1639
1640 bfpop = S390_BFP_SQRT;
1641 rounding_mode = decode_rounding_mode(expr->Iex.Binop.arg1);
1642
1643 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1644 rounding_mode));
1645
1646 /* Move result to virtual destination registers */
1647 *dst_hi = newVRegF(env);
1648 *dst_lo = newVRegF(env);
1649 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1650 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1651 return;
1652
1653 case Iop_F64HLtoF128:
1654 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1655 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1656 return;
1657
1658 default:
1659 goto irreducible;
1660 }
1661 }
1662
1663 /* --------- UNARY OP --------- */
1664 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001665 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001666 s390_bfp_unop_t bfpop;
1667 s390_round_t rounding_mode;
florian9fcff4c2012-09-10 03:09:04 +00001668 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001669 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1670
1671 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1672 f12 = make_fpr(12);
1673 f13 = make_fpr(13);
1674 f14 = make_fpr(14);
1675 f15 = make_fpr(15);
1676
florian66e596d2012-09-07 15:00:53 +00001677 switch (expr->Iex.Unop.op) {
florian9fcff4c2012-09-10 03:09:04 +00001678 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1679 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1680 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1681 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1682 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1683 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1684 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1685 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001686 default:
1687 goto irreducible;
1688 }
1689
1690 float128_opnd:
1691 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1692
1693 /* operand --> (f13, f15) */
1694 addInstr(env, s390_insn_move(8, f13, op_hi));
1695 addInstr(env, s390_insn_move(8, f15, op_lo));
1696
1697 rounding_mode = S390_ROUND_NEAREST_EVEN; /* will not be used later on */
1698 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15,
1699 rounding_mode));
1700 goto move_dst;
1701
1702 convert_float:
1703 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001704 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001705 goto move_dst;
1706
1707 convert_int:
1708 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001709 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001710 goto move_dst;
1711
1712 move_dst:
1713 /* Move result to virtual destination registers */
1714 *dst_hi = newVRegF(env);
1715 *dst_lo = newVRegF(env);
1716 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1717 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1718 return;
1719 }
1720
1721 default:
1722 goto irreducible;
1723 }
1724
1725 /* We get here if no pattern matched. */
1726 irreducible:
1727 ppIRExpr(expr);
1728 vpanic("s390_isel_int_expr: cannot reduce tree");
1729}
1730
1731/* Compute a 128-bit value into two 64-bit registers. These may be either
1732 real or virtual regs; in any case they must not be changed by subsequent
1733 code emitted by the caller. */
1734static void
1735s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1736{
1737 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1738
1739 /* Sanity checks ... */
1740 vassert(hregIsVirtual(*dst_hi));
1741 vassert(hregIsVirtual(*dst_lo));
1742 vassert(hregClass(*dst_hi) == HRcFlt64);
1743 vassert(hregClass(*dst_lo) == HRcFlt64);
1744}
1745
1746
1747/*---------------------------------------------------------*/
1748/*--- ISEL: Floating point expressions (64 bit) ---*/
1749/*---------------------------------------------------------*/
1750
1751static HReg
1752s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1753{
1754 IRType ty = typeOfIRExpr(env->type_env, expr);
1755 UChar size;
1756
1757 vassert(ty == Ity_F32 || ty == Ity_F64);
1758
1759 size = sizeofIRType(ty);
1760
1761 switch (expr->tag) {
1762 case Iex_RdTmp:
1763 /* Return the virtual register that holds the temporary. */
1764 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1765
1766 /* --------- LOAD --------- */
1767 case Iex_Load: {
1768 HReg dst = newVRegF(env);
1769 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1770
1771 if (expr->Iex.Load.end != Iend_BE)
1772 goto irreducible;
1773
1774 addInstr(env, s390_insn_load(size, dst, am));
1775
1776 return dst;
1777 }
1778
1779 /* --------- GET --------- */
1780 case Iex_Get: {
1781 HReg dst = newVRegF(env);
1782 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1783
1784 addInstr(env, s390_insn_load(size, dst, am));
1785
1786 return dst;
1787 }
1788
1789 /* --------- LITERAL --------- */
1790
1791 /* Load a literal into a register. Create a "load immediate"
1792 v-insn and return the register. */
1793 case Iex_Const: {
1794 ULong value;
1795 HReg dst = newVRegF(env);
1796 const IRConst *con = expr->Iex.Const.con;
1797
1798 /* Bitwise copy of the value. No sign/zero-extension */
1799 switch (con->tag) {
1800 case Ico_F32i: value = con->Ico.F32i; break;
1801 case Ico_F64i: value = con->Ico.F64i; break;
1802 default: vpanic("s390_isel_float_expr: invalid constant");
1803 }
1804
1805 if (value != 0) vpanic("cannot load immediate floating point constant");
1806
1807 addInstr(env, s390_insn_load_immediate(size, dst, value));
1808
1809 return dst;
1810 }
1811
1812 /* --------- 4-ary OP --------- */
1813 case Iex_Qop: {
1814 HReg op1, op2, op3, dst;
1815 s390_bfp_triop_t bfpop;
1816 s390_round_t rounding_mode;
1817
florian96d7cc32012-06-01 20:41:24 +00001818 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
1819 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
1820 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00001821 dst = newVRegF(env);
1822 addInstr(env, s390_insn_move(size, dst, op1));
1823
florian96d7cc32012-06-01 20:41:24 +00001824 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00001825 case Iop_MAddF32:
1826 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1827 case Iop_MSubF32:
1828 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1829
1830 default:
1831 goto irreducible;
1832 }
1833
florian96d7cc32012-06-01 20:41:24 +00001834 rounding_mode = decode_rounding_mode(expr->Iex.Qop.details->arg1);
sewardj2019a972011-03-07 16:04:07 +00001835 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3,
1836 rounding_mode));
1837 return dst;
1838 }
1839
1840 /* --------- TERNARY OP --------- */
1841 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001842 IRTriop *triop = expr->Iex.Triop.details;
1843 IROp op = triop->op;
1844 IRExpr *left = triop->arg2;
1845 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001846 s390_bfp_binop_t bfpop;
1847 s390_round_t rounding_mode;
1848 HReg h1, op2, dst;
1849
1850 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1851 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1852 dst = newVRegF(env);
1853 addInstr(env, s390_insn_move(size, dst, h1));
1854 switch (op) {
1855 case Iop_AddF32:
1856 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1857 case Iop_SubF32:
1858 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1859 case Iop_MulF32:
1860 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1861 case Iop_DivF32:
1862 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1863
1864 default:
1865 goto irreducible;
1866 }
1867
florian420bfa92012-06-02 20:29:22 +00001868 rounding_mode = decode_rounding_mode(triop->arg1);
sewardj2019a972011-03-07 16:04:07 +00001869 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2, rounding_mode));
1870 return dst;
1871 }
1872
1873 /* --------- BINARY OP --------- */
1874 case Iex_Binop: {
1875 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00001876 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00001877 IRExpr *left = expr->Iex.Binop.arg2;
1878 HReg h1, dst;
sewardj2019a972011-03-07 16:04:07 +00001879 s390_round_t rounding_mode;
florian9fcff4c2012-09-10 03:09:04 +00001880 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001881
1882 switch (op) {
1883 case Iop_SqrtF32:
1884 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00001885 h1 = s390_isel_float_expr(env, left);
1886 dst = newVRegF(env);
1887 rounding_mode = decode_rounding_mode(irrm);
1888 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1,
1889 rounding_mode));
1890 return dst;
sewardj2019a972011-03-07 16:04:07 +00001891
florian9fcff4c2012-09-10 03:09:04 +00001892 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
1893 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
1894 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
1895 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
1896 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
1897 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
1898 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00001899
florian9fcff4c2012-09-10 03:09:04 +00001900 convert_float:
1901 h1 = s390_isel_float_expr(env, left);
1902 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00001903
florian9fcff4c2012-09-10 03:09:04 +00001904 convert_int:
1905 h1 = s390_isel_int_expr(env, left);
1906 goto convert;
1907
1908 convert:
1909 dst = newVRegF(env);
1910 rounding_mode = decode_rounding_mode(irrm);
1911 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
1912 rounding_mode));
1913 return dst;
1914
sewardj2019a972011-03-07 16:04:07 +00001915 default:
1916 goto irreducible;
1917
1918 case Iop_F128toF64:
1919 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00001920 HReg op_hi, op_lo, f13, f15;
sewardj2019a972011-03-07 16:04:07 +00001921
florian9fcff4c2012-09-10 03:09:04 +00001922 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1923 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00001924
florian9fcff4c2012-09-10 03:09:04 +00001925 rounding_mode = decode_rounding_mode(irrm);
sewardj2019a972011-03-07 16:04:07 +00001926
florian9fcff4c2012-09-10 03:09:04 +00001927 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00001928
florian9fcff4c2012-09-10 03:09:04 +00001929 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00001930 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00001931 f15 = make_fpr(15);
1932
1933 /* operand --> (f13, f15) */
1934 addInstr(env, s390_insn_move(8, f13, op_hi));
1935 addInstr(env, s390_insn_move(8, f15, op_lo));
1936
1937 dst = newVRegF(env);
florian9fcff4c2012-09-10 03:09:04 +00001938 addInstr(env, s390_insn_bfp128_convert_from(16, conv, dst, f13, f15,
1939 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001940 return dst;
1941 }
1942 }
sewardj2019a972011-03-07 16:04:07 +00001943 }
1944
1945 /* --------- UNARY OP --------- */
1946 case Iex_Unop: {
1947 IROp op = expr->Iex.Unop.op;
1948 IRExpr *left = expr->Iex.Unop.arg;
1949 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00001950 /* No rounding mode is needed for these conversions. Provide the
1951 default rounding mode. It will not be used. */
1952 s390_round_t rounding_mode = S390_ROUND_NEAREST_EVEN;
1953 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001954 HReg h1, dst;
1955
1956 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
1957 HReg dst_hi, dst_lo;
1958
1959 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
1960 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
1961 }
1962
florian4d71a082011-12-18 00:08:17 +00001963 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00001964 dst = newVRegF(env);
1965 h1 = s390_isel_int_expr(env, left); /* Process the operand */
1966 addInstr(env, s390_insn_move(size, dst, h1));
1967
1968 return dst;
1969 }
1970
1971 switch (op) {
1972 case Iop_NegF32:
1973 case Iop_NegF64:
1974 if (left->tag == Iex_Unop &&
1975 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
1976 bfpop = S390_BFP_NABS;
1977 else
1978 bfpop = S390_BFP_NEG;
1979 break;
1980
1981 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00001982 case Iop_AbsF64:
1983 bfpop = S390_BFP_ABS;
1984 break;
1985
1986 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
1987 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
1988 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
1989
1990 convert_float1:
1991 h1 = s390_isel_float_expr(env, left);
1992 goto convert1;
1993
1994 convert_int1:
1995 h1 = s390_isel_int_expr(env, left);
1996 goto convert1;
1997
1998 convert1:
1999 dst = newVRegF(env);
2000 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1, rounding_mode));
2001 return dst;
2002
sewardj2019a972011-03-07 16:04:07 +00002003 default:
2004 goto irreducible;
2005 }
2006
2007 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002008 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002009 dst = newVRegF(env);
sewardj2019a972011-03-07 16:04:07 +00002010 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1, rounding_mode));
2011 return dst;
2012 }
2013
2014 default:
2015 goto irreducible;
2016 }
2017
2018 /* We get here if no pattern matched. */
2019 irreducible:
2020 ppIRExpr(expr);
2021 vpanic("s390_isel_float_expr: cannot reduce tree");
2022}
2023
2024
2025static HReg
2026s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2027{
2028 HReg dst = s390_isel_float_expr_wrk(env, expr);
2029
2030 /* Sanity checks ... */
2031 vassert(hregClass(dst) == HRcFlt64);
2032 vassert(hregIsVirtual(dst));
2033
2034 return dst;
2035}
2036
2037
2038/*---------------------------------------------------------*/
2039/*--- ISEL: Condition Code ---*/
2040/*---------------------------------------------------------*/
2041
2042/* This function handles all operators that produce a 1-bit result */
2043static s390_cc_t
2044s390_isel_cc(ISelEnv *env, IRExpr *cond)
2045{
2046 UChar size;
2047
2048 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2049
2050 /* Constant: either 1 or 0 */
2051 if (cond->tag == Iex_Const) {
2052 vassert(cond->Iex.Const.con->tag == Ico_U1);
2053 vassert(cond->Iex.Const.con->Ico.U1 == True
2054 || cond->Iex.Const.con->Ico.U1 == False);
2055
2056 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2057 }
2058
2059 /* Variable: values are 1 or 0 */
2060 if (cond->tag == Iex_RdTmp) {
2061 IRTemp tmp = cond->Iex.RdTmp.tmp;
2062 HReg reg = lookupIRTemp(env, tmp);
2063
2064 /* Load-and-test does not modify REG; so this is OK. */
2065 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2066 size = 4;
2067 else
2068 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2069 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2070 return S390_CC_NE;
2071 }
2072
2073 /* Unary operators */
2074 if (cond->tag == Iex_Unop) {
2075 IRExpr *arg = cond->Iex.Unop.arg;
2076
2077 switch (cond->Iex.Unop.op) {
2078 case Iop_Not1: /* Not1(cond) */
2079 /* Generate code for EXPR, and negate the test condition */
2080 return s390_cc_invert(s390_isel_cc(env, arg));
2081
2082 /* Iop_32/64to1 select the LSB from their operand */
2083 case Iop_32to1:
2084 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002085 HReg dst = newVRegI(env);
2086 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002087
2088 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2089
florianf366a802012-08-03 00:42:18 +00002090 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002091 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2092 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2093 return S390_CC_NE;
2094 }
2095
2096 case Iop_CmpNEZ8:
2097 case Iop_CmpNEZ16: {
2098 s390_opnd_RMI src;
2099 s390_unop_t op;
2100 HReg dst;
2101
2102 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2103 : S390_ZERO_EXTEND_16;
2104 dst = newVRegI(env);
2105 src = s390_isel_int_expr_RMI(env, arg);
2106 addInstr(env, s390_insn_unop(4, op, dst, src));
2107 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2108 return S390_CC_NE;
2109 }
2110
2111 case Iop_CmpNEZ32:
2112 case Iop_CmpNEZ64: {
2113 s390_opnd_RMI src;
2114
2115 src = s390_isel_int_expr_RMI(env, arg);
2116 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2117 addInstr(env, s390_insn_test(size, src));
2118 return S390_CC_NE;
2119 }
2120
2121 default:
2122 goto fail;
2123 }
2124 }
2125
2126 /* Binary operators */
2127 if (cond->tag == Iex_Binop) {
2128 IRExpr *arg1 = cond->Iex.Binop.arg1;
2129 IRExpr *arg2 = cond->Iex.Binop.arg2;
2130 HReg reg1, reg2;
2131
2132 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2133
2134 switch (cond->Iex.Binop.op) {
2135 s390_unop_t op;
2136 s390_cc_t result;
2137
2138 case Iop_CmpEQ8:
2139 case Iop_CasCmpEQ8:
2140 op = S390_ZERO_EXTEND_8;
2141 result = S390_CC_E;
2142 goto do_compare_ze;
2143
2144 case Iop_CmpNE8:
2145 case Iop_CasCmpNE8:
2146 op = S390_ZERO_EXTEND_8;
2147 result = S390_CC_NE;
2148 goto do_compare_ze;
2149
2150 case Iop_CmpEQ16:
2151 case Iop_CasCmpEQ16:
2152 op = S390_ZERO_EXTEND_16;
2153 result = S390_CC_E;
2154 goto do_compare_ze;
2155
2156 case Iop_CmpNE16:
2157 case Iop_CasCmpNE16:
2158 op = S390_ZERO_EXTEND_16;
2159 result = S390_CC_NE;
2160 goto do_compare_ze;
2161
2162 do_compare_ze: {
2163 s390_opnd_RMI op1, op2;
2164
2165 op1 = s390_isel_int_expr_RMI(env, arg1);
2166 reg1 = newVRegI(env);
2167 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2168
2169 op2 = s390_isel_int_expr_RMI(env, arg2);
2170 reg2 = newVRegI(env);
2171 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2172
2173 op2 = s390_opnd_reg(reg2);
2174 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2175
2176 return result;
2177 }
2178
2179 case Iop_CmpEQ32:
2180 case Iop_CmpEQ64:
2181 case Iop_CasCmpEQ32:
2182 case Iop_CasCmpEQ64:
2183 result = S390_CC_E;
2184 goto do_compare;
2185
2186 case Iop_CmpNE32:
2187 case Iop_CmpNE64:
2188 case Iop_CasCmpNE32:
2189 case Iop_CasCmpNE64:
2190 result = S390_CC_NE;
2191 goto do_compare;
2192
2193 do_compare: {
2194 HReg op1;
2195 s390_opnd_RMI op2;
2196
2197 order_commutative_operands(arg1, arg2);
2198
2199 op1 = s390_isel_int_expr(env, arg1);
2200 op2 = s390_isel_int_expr_RMI(env, arg2);
2201
2202 addInstr(env, s390_insn_compare(size, op1, op2, False));
2203
2204 return result;
2205 }
2206
2207 case Iop_CmpLT32S:
2208 case Iop_CmpLE32S:
2209 case Iop_CmpLT64S:
2210 case Iop_CmpLE64S: {
2211 HReg op1;
2212 s390_opnd_RMI op2;
2213
2214 op1 = s390_isel_int_expr(env, arg1);
2215 op2 = s390_isel_int_expr_RMI(env, arg2);
2216
2217 addInstr(env, s390_insn_compare(size, op1, op2, True));
2218
2219 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2220 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2221 }
2222
2223 case Iop_CmpLT32U:
2224 case Iop_CmpLE32U:
2225 case Iop_CmpLT64U:
2226 case Iop_CmpLE64U: {
2227 HReg op1;
2228 s390_opnd_RMI op2;
2229
2230 op1 = s390_isel_int_expr(env, arg1);
2231 op2 = s390_isel_int_expr_RMI(env, arg2);
2232
2233 addInstr(env, s390_insn_compare(size, op1, op2, False));
2234
2235 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2236 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2237 }
2238
2239 default:
2240 goto fail;
2241 }
2242 }
2243
2244 fail:
2245 ppIRExpr(cond);
2246 vpanic("s390_isel_cc: unexpected operator");
2247}
2248
2249
2250/*---------------------------------------------------------*/
2251/*--- ISEL: Statements ---*/
2252/*---------------------------------------------------------*/
2253
2254static void
2255s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2256{
2257 if (vex_traceflags & VEX_TRACE_VCODE) {
2258 vex_printf("\n -- ");
2259 ppIRStmt(stmt);
2260 vex_printf("\n");
2261 }
2262
2263 switch (stmt->tag) {
2264
2265 /* --------- STORE --------- */
2266 case Ist_Store: {
2267 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2268 s390_amode *am;
2269 HReg src;
2270
2271 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2272
2273 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2274
2275 switch (tyd) {
2276 case Ity_I8:
2277 case Ity_I16:
2278 case Ity_I32:
2279 case Ity_I64:
2280 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2281 break;
2282
2283 case Ity_F32:
2284 case Ity_F64:
2285 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2286 break;
2287
2288 case Ity_F128:
2289 /* Cannot occur. No such instruction */
2290 vpanic("Ist_Store with F128 data");
2291
2292 default:
2293 goto stmt_fail;
2294 }
2295
2296 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2297 return;
2298 }
2299
2300 /* --------- PUT --------- */
2301 case Ist_Put: {
2302 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2303 HReg src;
2304 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002305 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002306
florianad43b3a2012-02-20 15:01:14 +00002307 /* Detect updates to certain guest registers. We track the contents
2308 of those registers as long as they contain constants. If the new
2309 constant is either zero or in the 8-bit neighbourhood of the
2310 current value we can use a memory-to-memory insn to do the update. */
2311
2312 Int offset = stmt->Ist.Put.offset;
2313
2314 /* Check necessary conditions:
2315 (1) must be one of the registers we care about
2316 (2) assigned value must be a constant */
2317 Int guest_reg = get_guest_reg(offset);
2318
2319 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2320
2321 if (guest_reg == GUEST_IA) {
2322 /* If this is the first assignment to the IA reg, don't special case
2323 it. We need to do a full 8-byte assignment here. The reason is
2324 that in case of a redirected translation the guest IA does not
2325 contain the redirected-to address. Instead it contains the
2326 redirected-from address and those can be far apart. So in order to
2327 do incremnetal updates if the IA in the future we need to get the
2328 initial address of the super block correct. */
2329 if (env->first_IA_assignment) {
2330 env->first_IA_assignment = False;
2331 goto not_special;
2332 }
2333 }
2334
2335 if (stmt->Ist.Put.data->tag != Iex_Const) {
2336 /* Invalidate guest register contents */
2337 env->old_value_valid[guest_reg] = False;
2338 goto not_special;
2339 }
2340
cborntraaf7ad282012-08-08 14:11:33 +00002341 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2342 if (tyd != Ity_I64)
2343 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002344
cborntraaf7ad282012-08-08 14:11:33 +00002345 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002346
2347 old_value = env->old_value[guest_reg];
2348 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2349 env->old_value[guest_reg] = new_value;
2350
2351 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2352 env->old_value_valid[guest_reg] = True;
2353
2354 /* If the register already contains the new value, there is nothing
2355 to do here. Unless the guest register requires precise memory
2356 exceptions. */
2357 if (old_value_is_valid && new_value == old_value) {
2358 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2359 return;
2360 }
2361 }
2362
2363 /* guest register = 0 */
2364 if (new_value == 0) {
2365 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2366 return;
2367 }
2368
2369 if (old_value_is_valid == False) goto not_special;
2370
2371 /* If the new value is in the neighbourhood of the old value
2372 we can use a memory-to-memory insn */
2373 difference = new_value - old_value;
2374
2375 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2376 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2377 (difference & 0xFF), new_value));
2378 return;
2379 }
2380
2381 /* If the high word is the same it is sufficient to load the low word.
2382 Use R0 as a scratch reg. */
2383 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002384 HReg r0 = make_gpr(0);
2385 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002386 s390_amode *gam;
2387
2388 gam = s390_amode_b12(offset + 4, gsp);
2389 addInstr(env, s390_insn_load_immediate(4, r0,
2390 new_value & 0xFFFFFFFF));
2391 addInstr(env, s390_insn_store(4, gam, r0));
2392 return;
2393 }
2394
2395 /* No special case applies... fall through */
2396
2397 not_special:
sewardj2019a972011-03-07 16:04:07 +00002398 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2399
2400 switch (tyd) {
2401 case Ity_I8:
2402 case Ity_I16:
2403 case Ity_I32:
2404 case Ity_I64:
2405 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2406 break;
2407
2408 case Ity_F32:
2409 case Ity_F64:
2410 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2411 break;
2412
2413 case Ity_F128:
2414 /* Does not occur. See function put_fpr_pair. */
2415 vpanic("Ist_Put with F128 data");
2416
2417 default:
2418 goto stmt_fail;
2419 }
2420
2421 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2422 return;
2423 }
2424
2425 /* --------- TMP --------- */
2426 case Ist_WrTmp: {
2427 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2428 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2429 HReg src, dst;
2430
2431 switch (tyd) {
2432 case Ity_I128: {
2433 HReg dst_hi, dst_lo, res_hi, res_lo;
2434
2435 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2436 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2437
2438 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2439 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2440 return;
2441 }
2442
2443 case Ity_I8:
2444 case Ity_I16:
2445 case Ity_I32:
2446 case Ity_I64:
2447 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2448 dst = lookupIRTemp(env, tmp);
2449 break;
2450
2451 case Ity_I1: {
2452 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2453 dst = lookupIRTemp(env, tmp);
2454 addInstr(env, s390_insn_cc2bool(dst, cond));
2455 return;
2456 }
2457
2458 case Ity_F32:
2459 case Ity_F64:
2460 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2461 dst = lookupIRTemp(env, tmp);
2462 break;
2463
2464 case Ity_F128: {
2465 HReg dst_hi, dst_lo, res_hi, res_lo;
2466
2467 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2468 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2469
2470 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2471 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2472 return;
2473 }
2474
2475 default:
2476 goto stmt_fail;
2477 }
2478
2479 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2480 return;
2481 }
2482
2483 /* --------- Call to DIRTY helper --------- */
2484 case Ist_Dirty: {
2485 IRType retty;
2486 IRDirty* d = stmt->Ist.Dirty.details;
2487 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002488 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002489 Int i;
2490
2491 /* Invalidate tracked values of those guest state registers that are
2492 modified by this helper. */
2493 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002494 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2495 descriptors in guest state effect descriptions. Hence: */
2496 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002497 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2498 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2499 if (guest_reg != GUEST_UNKNOWN)
2500 env->old_value_valid[guest_reg] = False;
2501 }
2502 }
sewardj2019a972011-03-07 16:04:07 +00002503
2504 if (d->nFxState == 0)
2505 vassert(!d->needsBBP);
2506
2507 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2508
florian01ed6e72012-05-27 16:52:43 +00002509 if (d->tmp == IRTemp_INVALID) {
2510 /* No return value. */
2511 dst = INVALID_HREG;
2512 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002513 return;
florian01ed6e72012-05-27 16:52:43 +00002514 }
sewardj2019a972011-03-07 16:04:07 +00002515
2516 retty = typeOfIRTemp(env->type_env, d->tmp);
2517 if (retty == Ity_I64 || retty == Ity_I32
2518 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002519 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002520 dst = lookupIRTemp(env, d->tmp);
2521 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002522 return;
2523 }
2524 break;
2525 }
2526
2527 case Ist_CAS:
2528 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2529 IRCAS *cas = stmt->Ist.CAS.details;
2530 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2531 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2532 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2533 HReg old = lookupIRTemp(env, cas->oldLo);
2534
2535 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2536 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2537 } else {
2538 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2539 }
2540 return;
2541 } else {
florian448cbba2012-06-06 02:26:01 +00002542 IRCAS *cas = stmt->Ist.CAS.details;
2543 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2544 HReg r8, r9, r10, r11, r1;
2545 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2546 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2547 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2548 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2549 HReg old_low = lookupIRTemp(env, cas->oldLo);
2550 HReg old_high = lookupIRTemp(env, cas->oldHi);
2551
2552 /* Use non-virtual registers r8 and r9 as pair for op1
2553 and move op1 there */
2554 r8 = make_gpr(8);
2555 r9 = make_gpr(9);
2556 addInstr(env, s390_insn_move(8, r8, op1_high));
2557 addInstr(env, s390_insn_move(8, r9, op1_low));
2558
2559 /* Use non-virtual registers r10 and r11 as pair for op3
2560 and move op3 there */
2561 r10 = make_gpr(10);
2562 r11 = make_gpr(11);
2563 addInstr(env, s390_insn_move(8, r10, op3_high));
2564 addInstr(env, s390_insn_move(8, r11, op3_low));
2565
2566 /* Register r1 is used as a scratch register */
2567 r1 = make_gpr(1);
2568
2569 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2570 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2571 old_high, old_low, r1));
2572 } else {
2573 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2574 old_high, old_low, r1));
2575 }
2576 addInstr(env, s390_insn_move(8, op1_high, r8));
2577 addInstr(env, s390_insn_move(8, op1_low, r9));
2578 addInstr(env, s390_insn_move(8, op3_high, r10));
2579 addInstr(env, s390_insn_move(8, op3_low, r11));
2580 return;
sewardj2019a972011-03-07 16:04:07 +00002581 }
2582 break;
2583
2584 /* --------- EXIT --------- */
2585 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002586 s390_cc_t cond;
2587 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2588
2589 if (tag != Ico_U64)
2590 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2591
florian8844a632012-04-13 04:04:06 +00002592 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002593 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002594
2595 /* Case: boring transfer to known address */
2596 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2597 if (env->chaining_allowed) {
2598 /* .. almost always true .. */
2599 /* Skip the event check at the dst if this is a forwards
2600 edge. */
2601 Bool to_fast_entry
2602 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2603 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2604 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2605 guest_IA, to_fast_entry));
2606 } else {
2607 /* .. very occasionally .. */
2608 /* We can't use chaining, so ask for an assisted transfer,
2609 as that's the only alternative that is allowable. */
2610 HReg dst = s390_isel_int_expr(env,
2611 IRExpr_Const(stmt->Ist.Exit.dst));
2612 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2613 }
2614 return;
2615 }
2616
2617 /* Case: assisted transfer to arbitrary address */
2618 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00002619 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002620 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002621 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002622 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002623 case Ijk_Sys_syscall:
2624 case Ijk_ClientReq:
2625 case Ijk_NoRedir:
2626 case Ijk_Yield:
2627 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002628 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2629 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2630 stmt->Ist.Exit.jk));
2631 return;
2632 }
2633 default:
2634 break;
2635 }
2636
2637 /* Do we ever expect to see any other kind? */
2638 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002639 }
2640
2641 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002642 case Ist_MBE:
2643 switch (stmt->Ist.MBE.event) {
2644 case Imbe_Fence:
2645 addInstr(env, s390_insn_mfence());
2646 return;
2647 default:
2648 break;
2649 }
sewardj2019a972011-03-07 16:04:07 +00002650 break;
2651
2652 /* --------- Miscellaneous --------- */
2653
2654 case Ist_PutI: /* Not needed */
2655 case Ist_IMark: /* Doesn't generate any executable code */
2656 case Ist_NoOp: /* Doesn't generate any executable code */
2657 case Ist_AbiHint: /* Meaningless in IR */
2658 return;
2659
2660 default:
2661 break;
2662 }
2663
2664 stmt_fail:
2665 ppIRStmt(stmt);
2666 vpanic("s390_isel_stmt");
2667}
2668
2669
2670/*---------------------------------------------------------*/
2671/*--- ISEL: Basic block terminators (Nexts) ---*/
2672/*---------------------------------------------------------*/
2673
2674static void
florian8844a632012-04-13 04:04:06 +00002675iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002676{
sewardj2019a972011-03-07 16:04:07 +00002677 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002678 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002679 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002680 vex_printf("; exit-");
2681 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002682 vex_printf("\n");
2683 }
2684
florian8844a632012-04-13 04:04:06 +00002685 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2686
2687 /* Case: boring transfer to known address */
2688 if (next->tag == Iex_Const) {
2689 IRConst *cdst = next->Iex.Const.con;
2690 vassert(cdst->tag == Ico_U64);
2691 if (jk == Ijk_Boring || jk == Ijk_Call) {
2692 /* Boring transfer to known address */
2693 if (env->chaining_allowed) {
2694 /* .. almost always true .. */
2695 /* Skip the event check at the dst if this is a forwards
2696 edge. */
2697 Bool to_fast_entry
2698 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2699 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2700 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2701 guest_IA, to_fast_entry));
2702 } else {
2703 /* .. very occasionally .. */
2704 /* We can't use chaining, so ask for an indirect transfer,
2705 as that's the cheapest alternative that is allowable. */
2706 HReg dst = s390_isel_int_expr(env, next);
2707 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2708 Ijk_Boring));
2709 }
2710 return;
2711 }
2712 }
2713
2714 /* Case: call/return (==boring) transfer to any address */
2715 switch (jk) {
2716 case Ijk_Boring:
2717 case Ijk_Ret:
2718 case Ijk_Call: {
2719 HReg dst = s390_isel_int_expr(env, next);
2720 if (env->chaining_allowed) {
2721 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2722 } else {
2723 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2724 Ijk_Boring));
2725 }
2726 return;
2727 }
2728 default:
2729 break;
2730 }
2731
2732 /* Case: some other kind of transfer to any address */
2733 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00002734 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002735 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002736 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002737 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002738 case Ijk_Sys_syscall:
2739 case Ijk_ClientReq:
2740 case Ijk_NoRedir:
2741 case Ijk_Yield:
2742 case Ijk_SigTRAP: {
2743 HReg dst = s390_isel_int_expr(env, next);
2744 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2745 return;
2746 }
2747 default:
2748 break;
2749 }
2750
2751 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002752}
2753
2754
2755/*---------------------------------------------------------*/
2756/*--- Insn selector top-level ---*/
2757/*---------------------------------------------------------*/
2758
florianf26994a2012-04-21 03:34:54 +00002759/* Translate an entire SB to s390 code.
2760 Note: archinfo_host is a pointer to a stack-allocated variable.
2761 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002762
2763HInstrArray *
2764iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002765 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2766 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2767 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002768{
2769 UInt i, j;
2770 HReg hreg, hregHI;
2771 ISelEnv *env;
2772 UInt hwcaps_host = archinfo_host->hwcaps;
2773
florianf26994a2012-04-21 03:34:54 +00002774 /* KLUDGE: export hwcaps. */
2775 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002776
sewardj2019a972011-03-07 16:04:07 +00002777 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002778 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002779
2780 /* Make up an initial environment to use. */
2781 env = LibVEX_Alloc(sizeof(ISelEnv));
2782 env->vreg_ctr = 0;
2783
2784 /* Set up output code array. */
2785 env->code = newHInstrArray();
2786
2787 /* Copy BB's type env. */
2788 env->type_env = bb->tyenv;
2789
florianad43b3a2012-02-20 15:01:14 +00002790 /* Set up data structures for tracking guest register values. */
2791 env->first_IA_assignment = True;
2792 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2793 env->old_value[i] = 0; /* just something to have a defined value */
2794 env->old_value_valid[i] = False;
2795 }
2796
sewardj2019a972011-03-07 16:04:07 +00002797 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2798 change as we go along. For some reason types_used has Int type -- but
2799 it should be unsigned. Internally we use an unsigned type; so we
2800 assert it here. */
2801 vassert(bb->tyenv->types_used >= 0);
2802
2803 env->n_vregmap = bb->tyenv->types_used;
2804 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2805 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2806
2807 /* and finally ... */
2808 env->hwcaps = hwcaps_host;
2809
florian8844a632012-04-13 04:04:06 +00002810 env->max_ga = max_ga;
2811 env->chaining_allowed = chaining_allowed;
2812
sewardj2019a972011-03-07 16:04:07 +00002813 /* For each IR temporary, allocate a suitably-kinded virtual
2814 register. */
2815 j = 0;
2816 for (i = 0; i < env->n_vregmap; i++) {
2817 hregHI = hreg = INVALID_HREG;
2818 switch (bb->tyenv->types[i]) {
2819 case Ity_I1:
2820 case Ity_I8:
2821 case Ity_I16:
2822 case Ity_I32:
2823 hreg = mkHReg(j++, HRcInt64, True);
2824 break;
2825
2826 case Ity_I64:
2827 hreg = mkHReg(j++, HRcInt64, True);
2828 break;
2829
2830 case Ity_I128:
2831 hreg = mkHReg(j++, HRcInt64, True);
2832 hregHI = mkHReg(j++, HRcInt64, True);
2833 break;
2834
2835 case Ity_F32:
2836 case Ity_F64:
2837 hreg = mkHReg(j++, HRcFlt64, True);
2838 break;
2839
2840 case Ity_F128:
2841 hreg = mkHReg(j++, HRcFlt64, True);
2842 hregHI = mkHReg(j++, HRcFlt64, True);
2843 break;
2844
2845 case Ity_V128: /* fall through */
2846 default:
2847 ppIRType(bb->tyenv->types[i]);
2848 vpanic("s390_isel_sb: IRTemp type");
2849 }
2850
2851 env->vregmap[i] = hreg;
2852 env->vregmapHI[i] = hregHI;
2853 }
2854 env->vreg_ctr = j;
2855
florian8844a632012-04-13 04:04:06 +00002856 /* The very first instruction must be an event check. */
2857 s390_amode *counter, *fail_addr;
2858 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2859 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2860 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2861
2862 /* Possibly a block counter increment (for profiling). At this
2863 point we don't know the address of the counter, so just pretend
2864 it is zero. It will have to be patched later, but before this
2865 translation is used, by a call to LibVEX_patchProfInc. */
2866 if (add_profinc) {
2867 addInstr(env, s390_insn_profinc());
2868 }
2869
sewardj2019a972011-03-07 16:04:07 +00002870 /* Ok, finally we can iterate over the statements. */
2871 for (i = 0; i < bb->stmts_used; i++)
2872 if (bb->stmts[i])
2873 s390_isel_stmt(env, bb->stmts[i]);
2874
florian8844a632012-04-13 04:04:06 +00002875 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002876
2877 /* Record the number of vregs we used. */
2878 env->code->n_vregs = env->vreg_ctr;
2879
2880 return env->code;
2881}
2882
2883/*---------------------------------------------------------------*/
2884/*--- end host_s390_isel.c ---*/
2885/*---------------------------------------------------------------*/