blob: d42a3ab55c5436edcc53d7aa7eb85c67348ade96 [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
florian2c74d242012-09-12 19:38:42 +000012 Copyright (C) 2012-2012 Florian Krohm (britzel@acm.org)
sewardj2019a972011-03-07 16:04:07 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
32/* Contributed by Florian Krohm */
33
34#include "libvex_basictypes.h"
35#include "libvex_ir.h"
36#include "libvex.h"
37#include "libvex_s390x_common.h"
38
sewardj2019a972011-03-07 16:04:07 +000039#include "main_util.h"
40#include "main_globals.h"
florianad43b3a2012-02-20 15:01:14 +000041#include "guest_s390_defs.h" /* guest_s390x_state_requires_precise_mem_exns */
sewardj2019a972011-03-07 16:04:07 +000042#include "host_generic_regs.h"
43#include "host_s390_defs.h"
44
45/*---------------------------------------------------------*/
46/*--- ISelEnv ---*/
47/*---------------------------------------------------------*/
48
49/* This carries around:
50
51 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
52 might encounter. This is computed before insn selection starts,
53 and does not change.
54
55 - A mapping from IRTemp to HReg. This tells the insn selector
56 which virtual register(s) are associated with each IRTemp
57 temporary. This is computed before insn selection starts, and
58 does not change. We expect this mapping to map precisely the
59 same set of IRTemps as the type mapping does.
60
61 - vregmap holds the primary register for the IRTemp.
62 - vregmapHI holds the secondary register for the IRTemp,
63 if any is needed. That's only for Ity_I64 temps
64 in 32 bit mode or Ity_I128 temps in 64-bit mode.
65
66 - The code array, that is, the insns selected so far.
67
68 - A counter, for generating new virtual registers.
69
70 - The host subarchitecture we are selecting insns for.
71 This is set at the start and does not change.
florianad43b3a2012-02-20 15:01:14 +000072
florian8844a632012-04-13 04:04:06 +000073 - A Bool for indicating whether we may generate chain-me
74 instructions for control flow transfers, or whether we must use
75 XAssisted.
76
77 - The maximum guest address of any guest insn in this block.
78 Actually, the address of the highest-addressed byte from any insn
79 in this block. Is set at the start and does not change. This is
80 used for detecting jumps which are definitely forward-edges from
81 this block, and therefore can be made (chained) to the fast entry
82 point of the destination, thereby avoiding the destination's
83 event check.
84
florianad43b3a2012-02-20 15:01:14 +000085 - A flag to indicate whether the guest IA has been assigned to.
86
87 - Values of certain guest registers which are often assigned constants.
sewardj2019a972011-03-07 16:04:07 +000088*/
89
florianad43b3a2012-02-20 15:01:14 +000090/* Symbolic names for guest registers whose value we're tracking */
91enum {
92 GUEST_IA,
93 GUEST_CC_OP,
94 GUEST_CC_DEP1,
95 GUEST_CC_DEP2,
96 GUEST_CC_NDEP,
97 GUEST_SYSNO,
florian7d117ba2012-05-06 03:34:55 +000098 GUEST_COUNTER,
florianad43b3a2012-02-20 15:01:14 +000099 GUEST_UNKNOWN /* must be the last entry */
100};
101
102/* Number of registers we're tracking. */
103#define NUM_TRACKED_REGS GUEST_UNKNOWN
104
105
sewardj2019a972011-03-07 16:04:07 +0000106typedef struct {
107 IRTypeEnv *type_env;
108
florian8844a632012-04-13 04:04:06 +0000109 HInstrArray *code;
sewardj2019a972011-03-07 16:04:07 +0000110 HReg *vregmap;
111 HReg *vregmapHI;
112 UInt n_vregmap;
florian8844a632012-04-13 04:04:06 +0000113 UInt vreg_ctr;
114 UInt hwcaps;
sewardj2019a972011-03-07 16:04:07 +0000115
florian2c74d242012-09-12 19:38:42 +0000116 IRExpr *previous_bfp_rounding_mode;
117
florianad43b3a2012-02-20 15:01:14 +0000118 ULong old_value[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000119
florian8844a632012-04-13 04:04:06 +0000120 /* The next two are for translation chaining */
121 Addr64 max_ga;
122 Bool chaining_allowed;
123
florianad43b3a2012-02-20 15:01:14 +0000124 Bool first_IA_assignment;
125 Bool old_value_valid[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000126} ISelEnv;
127
128
129/* Forward declarations */
130static HReg s390_isel_int_expr(ISelEnv *, IRExpr *);
131static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *);
132static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
133static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
134static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
135static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
136static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
137
138
florianad43b3a2012-02-20 15:01:14 +0000139static Int
140get_guest_reg(Int offset)
141{
142 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000143 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
144 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
145 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
146 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
147 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
148 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000149 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000150
151 /* Also make sure there is never a partial write to one of
152 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000153 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
154 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
155 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
156 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
157 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000158 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
159 /* counter is used both as 4-byte and as 8-byte entity */
160 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
161 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianaf50a192012-07-13 14:13:06 +0000162 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000163 break;
164
165 default: break;
166 }
167
168 return GUEST_UNKNOWN;
169}
170
sewardj2019a972011-03-07 16:04:07 +0000171/* Add an instruction */
172static void
173addInstr(ISelEnv *env, s390_insn *insn)
174{
175 addHInstr(env->code, insn);
176
177 if (vex_traceflags & VEX_TRACE_VCODE) {
178 vex_printf("%s\n", s390_insn_as_string(insn));
179 }
180}
181
182
183static __inline__ IRExpr *
184mkU64(ULong value)
185{
186 return IRExpr_Const(IRConst_U64(value));
187}
188
189
190/*---------------------------------------------------------*/
191/*--- Registers ---*/
192/*---------------------------------------------------------*/
193
194/* Return the virtual register to which a given IRTemp is mapped. */
195static HReg
196lookupIRTemp(ISelEnv *env, IRTemp tmp)
197{
198 vassert(tmp < env->n_vregmap);
199 vassert(env->vregmap[tmp] != INVALID_HREG);
200
201 return env->vregmap[tmp];
202}
203
204
205/* Return the two virtual registers to which the IRTemp is mapped. */
206static void
207lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
208{
209 vassert(tmp < env->n_vregmap);
210 vassert(env->vregmapHI[tmp] != INVALID_HREG);
211
212 *lo = env->vregmap[tmp];
213 *hi = env->vregmapHI[tmp];
214}
215
216
217/* Allocate a new integer register */
218static HReg
219newVRegI(ISelEnv *env)
220{
221 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
222 env->vreg_ctr++;
223
224 return reg;
225}
226
227
228/* Allocate a new floating point register */
229static HReg
230newVRegF(ISelEnv *env)
231{
232 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
233
234 env->vreg_ctr++;
235
236 return reg;
237}
238
239
240/* Construct a non-virtual general purpose register */
241static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000242make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000243{
244 return mkHReg(regno, HRcInt64, False /* virtual */ );
245}
246
247
248/* Construct a non-virtual floating point register */
249static __inline__ HReg
250make_fpr(UInt regno)
251{
252 return mkHReg(regno, HRcFlt64, False /* virtual */ );
253}
254
255
256/*---------------------------------------------------------*/
257/*--- Amode ---*/
258/*---------------------------------------------------------*/
259
260static __inline__ Bool
261ulong_fits_unsigned_12bit(ULong val)
262{
263 return (val & 0xFFFu) == val;
264}
265
266
267static __inline__ Bool
268ulong_fits_signed_20bit(ULong val)
269{
270 Long v = val & 0xFFFFFu;
271
272 v = (v << 44) >> 44; /* sign extend */
273
274 return val == (ULong)v;
275}
276
277
florianad43b3a2012-02-20 15:01:14 +0000278static __inline__ Bool
279ulong_fits_signed_8bit(ULong val)
280{
281 Long v = val & 0xFFu;
282
283 v = (v << 56) >> 56; /* sign extend */
284
285 return val == (ULong)v;
286}
287
sewardj2019a972011-03-07 16:04:07 +0000288/* EXPR is an expression that is used as an address. Return an s390_amode
289 for it. */
290static s390_amode *
291s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
292{
293 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
294 IRExpr *arg1 = expr->Iex.Binop.arg1;
295 IRExpr *arg2 = expr->Iex.Binop.arg2;
296
297 /* Move constant into right subtree */
298 if (arg1->tag == Iex_Const) {
299 IRExpr *tmp;
300 tmp = arg1;
301 arg1 = arg2;
302 arg2 = tmp;
303 }
304
305 /* r + constant: Check for b12 first, then b20 */
306 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
307 ULong value = arg2->Iex.Const.con->Ico.U64;
308
309 if (ulong_fits_unsigned_12bit(value)) {
310 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
311 }
sewardj652b56a2011-04-13 15:38:17 +0000312 /* If long-displacement is not available, do not construct B20 or
313 BX20 amodes because code generation cannot handle them. */
314 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000315 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
316 }
317 }
318 }
319
320 /* Doesn't match anything in particular. Generate it into
321 a register and use that. */
322 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
323}
324
325
326static s390_amode *
327s390_isel_amode(ISelEnv *env, IRExpr *expr)
328{
florian35da8612011-06-25 02:25:41 +0000329 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000330
331 /* Address computation should yield a 64-bit value */
332 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
333
334 am = s390_isel_amode_wrk(env, expr);
335
336 /* Check post-condition */
337 vassert(s390_amode_is_sane(am));
338
339 return am;
340}
341
342
343/*---------------------------------------------------------*/
344/*--- Helper functions ---*/
345/*---------------------------------------------------------*/
346
347/* Constants and memory accesses should be right operands */
348#define order_commutative_operands(left, right) \
349 do { \
350 if (left->tag == Iex_Const || left->tag == Iex_Load || \
351 left->tag == Iex_Get) { \
352 IRExpr *tmp; \
353 tmp = left; \
354 left = right; \
355 right = tmp; \
356 } \
357 } while (0)
358
359
360/* Copy an RMI operand to the DST register */
361static s390_insn *
362s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
363{
364 switch (opnd.tag) {
365 case S390_OPND_AMODE:
366 return s390_insn_load(size, dst, opnd.variant.am);
367
368 case S390_OPND_REG:
369 return s390_insn_move(size, dst, opnd.variant.reg);
370
371 case S390_OPND_IMMEDIATE:
372 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
373
374 default:
375 vpanic("s390_opnd_copy");
376 }
377}
378
379
380/* Construct a RMI operand for a register */
381static __inline__ s390_opnd_RMI
382s390_opnd_reg(HReg reg)
383{
384 s390_opnd_RMI opnd;
385
386 opnd.tag = S390_OPND_REG;
387 opnd.variant.reg = reg;
388
389 return opnd;
390}
391
392
393/* Construct a RMI operand for an immediate constant */
394static __inline__ s390_opnd_RMI
395s390_opnd_imm(ULong value)
396{
397 s390_opnd_RMI opnd;
398
399 opnd.tag = S390_OPND_IMMEDIATE;
400 opnd.variant.imm = value;
401
402 return opnd;
403}
404
405
406/* Return 1, if EXPR represents the cosntant 0 */
407static int
408s390_expr_is_const_zero(IRExpr *expr)
409{
410 ULong value;
411
412 if (expr->tag == Iex_Const) {
413 switch (expr->Iex.Const.con->tag) {
414 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
415 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
416 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
417 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
418 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
419 default:
420 vpanic("s390_expr_is_const_zero");
421 }
422 return value == 0;
423 }
424
425 return 0;
426}
427
428
429/* Call a helper (clean or dirty)
430 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000431
sewardj2019a972011-03-07 16:04:07 +0000432 (a) they are expressions yielding an integer result
433 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000434
435 guard is a Ity_Bit expression indicating whether or not the
436 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000437
438 Calling the helper function proceeds as follows:
439
440 (1) The helper arguments are evaluated and their value stored in
441 virtual registers.
442 (2) The condition code is evaluated
443 (3) The argument values are copied from the virtual registers to the
444 registers mandated by the ABI.
445 (4) Call the helper function.
446
447 This is not the most efficient way as step 3 generates register-to-register
448 moves. But it is the least fragile way as the only hidden dependency here
449 is that register-to-register moves (step 3) must not clobber the condition
450 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
451 to-register add more such dependencies. Not good. Besides, it's the job
452 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000453*/
454static void
455doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000456 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000457{
florian52af7bc2012-05-12 03:44:49 +0000458 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000459 ULong target;
460 HReg tmpregs[S390_NUM_GPRPARMS];
461 s390_cc_t cc;
462
463 n_args = 0;
464 for (i = 0; args[i]; i++)
465 ++n_args;
466
467 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
468 vpanic("doHelperCall: too many arguments");
469 }
470
florian11b8ee82012-08-06 13:35:33 +0000471 /* All arguments must have Ity_I64. For two reasons:
472 (1) We do not handle floating point arguments.
473 (2) The ABI requires that integer values are sign- or zero-extended
474 to 64 bit.
475 */
476 Int arg_errors = 0;
477 for (i = 0; i < n_args; ++i) {
478 IRType type = typeOfIRExpr(env->type_env, args[i]);
479 if (type != Ity_I64) {
480 ++arg_errors;
481 vex_printf("calling %s: argument #%d has type ", callee->name, i);
482 ppIRType(type);
483 vex_printf("; Ity_I64 is required\n");
484 }
485 }
486
487 if (arg_errors)
488 vpanic("cannot continue due to errors in argument passing");
489
florian52af7bc2012-05-12 03:44:49 +0000490 argreg = 0;
491
492 /* If we need the guest state pointer put it in a temporary arg reg */
493 if (passBBP) {
494 tmpregs[argreg] = newVRegI(env);
495 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
496 s390_hreg_guest_state_pointer()));
497 argreg++;
498 }
499
500 /* Compute the function arguments into a temporary register each */
501 for (i = 0; i < n_args; i++) {
502 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
503 argreg++;
504 }
505
sewardj2019a972011-03-07 16:04:07 +0000506 /* Compute the condition */
507 cc = S390_CC_ALWAYS;
508 if (guard) {
509 if (guard->tag == Iex_Const
510 && guard->Iex.Const.con->tag == Ico_U1
511 && guard->Iex.Const.con->Ico.U1 == True) {
512 /* unconditional -- do nothing */
513 } else {
514 cc = s390_isel_cc(env, guard);
515 }
516 }
517
florian52af7bc2012-05-12 03:44:49 +0000518 /* Move the args to the final register. It is paramount, that the
519 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000520 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000521 HReg finalreg;
522
523 finalreg = make_gpr(s390_gprno_from_arg_index(i));
524 size = sizeofIRType(Ity_I64);
525 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000526 }
527
528 target = Ptr_to_ULong(callee->addr);
529
530 /* Finally, the call itself. */
531 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000532 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000533}
534
535
florian2c74d242012-09-12 19:38:42 +0000536/*---------------------------------------------------------*/
537/*--- BFP helper functions ---*/
538/*---------------------------------------------------------*/
539
540/* Set the BFP rounding mode in the FPC. This function is called for
541 all non-conversion BFP instructions as those will always get the
542 rounding mode from the FPC. */
543static void
544set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000545{
florian2c74d242012-09-12 19:38:42 +0000546 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
547
548 /* Do we need to do anything? */
549 if (env->previous_bfp_rounding_mode &&
550 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
551 irrm->tag == Iex_RdTmp &&
552 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
553 /* No - new mode is identical to previous mode. */
554 return;
555 }
556
557 /* No luck - we better set it, and remember what we set it to. */
558 env->previous_bfp_rounding_mode = irrm;
559
560 /* The incoming rounding mode is in VEX IR encoding. Need to change
561 to s390.
562
563 rounding mode | s390 | IR
564 -------------------------
565 to nearest | 00 | 00
566 to zero | 01 | 11
567 to +infinity | 10 | 10
568 to -infinity | 11 | 01
569
570 So: s390 = (4 - IR) & 3
571 */
572 HReg ir = s390_isel_int_expr(env, irrm);
573
574 HReg mode = newVRegI(env);
575
576 addInstr(env, s390_insn_load_immediate(4, mode, 4));
577 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
578 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
579
florian125e20d2012-10-07 15:42:37 +0000580 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000581}
582
583
584/* This function is invoked for insns that support a specification of
585 a rounding mode in the insn itself. In that case there is no need to
586 stick the rounding mode into the FPC -- a good thing. However, the
587 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000588static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000589get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
590{
591 if (irrm->tag == Iex_Const) { /* rounding mode is known */
592 vassert(irrm->Iex.Const.con->tag == Ico_U32);
593 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000594
595 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000596 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
597 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
598 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
599 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000600 default:
601 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000602 }
603 }
604
florian2c74d242012-09-12 19:38:42 +0000605 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000606 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000607}
608
609
610/* CC_S390 holds the condition code in s390 encoding. Convert it to
611 VEX encoding
612
613 s390 VEX b6 b2 b0 cc.1 cc.0
614 0 0x40 EQ 1 0 0 0 0
615 1 0x01 LT 0 0 1 0 1
616 2 0x00 GT 0 0 0 1 0
617 3 0x45 Unordered 1 1 1 1 1
618
619 b0 = cc.0
620 b2 = cc.0 & cc.1
621 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
622
623 VEX = b0 | (b2 << 2) | (b6 << 6);
624*/
625static HReg
626convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390)
627{
628 HReg cc0, cc1, b2, b6, cc_vex;
629
630 cc0 = newVRegI(env);
631 addInstr(env, s390_insn_move(4, cc0, cc_s390));
632 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
633
634 cc1 = newVRegI(env);
635 addInstr(env, s390_insn_move(4, cc1, cc_s390));
636 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
637
638 b2 = newVRegI(env);
639 addInstr(env, s390_insn_move(4, b2, cc0));
640 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
641 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
642
643 b6 = newVRegI(env);
644 addInstr(env, s390_insn_move(4, b6, cc0));
645 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
646 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
647 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
648 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
649
650 cc_vex = newVRegI(env);
651 addInstr(env, s390_insn_move(4, cc_vex, cc0));
652 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
653 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
654
655 return cc_vex;
656}
657
658
659/*---------------------------------------------------------*/
660/*--- ISEL: Integer expressions (128 bit) ---*/
661/*---------------------------------------------------------*/
662static void
663s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
664 IRExpr *expr)
665{
666 IRType ty = typeOfIRExpr(env->type_env, expr);
667
668 vassert(ty == Ity_I128);
669
670 /* No need to consider the following
671 - 128-bit constants (they do not exist in VEX)
672 - 128-bit loads from memory (will not be generated)
673 */
674
675 /* Read 128-bit IRTemp */
676 if (expr->tag == Iex_RdTmp) {
677 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
678 return;
679 }
680
681 if (expr->tag == Iex_Binop) {
682 IRExpr *arg1 = expr->Iex.Binop.arg1;
683 IRExpr *arg2 = expr->Iex.Binop.arg2;
684 Bool is_signed_multiply, is_signed_divide;
685
686 switch (expr->Iex.Binop.op) {
687 case Iop_MullU64:
688 is_signed_multiply = False;
689 goto do_multiply64;
690
691 case Iop_MullS64:
692 is_signed_multiply = True;
693 goto do_multiply64;
694
695 case Iop_DivModU128to64:
696 is_signed_divide = False;
697 goto do_divide64;
698
699 case Iop_DivModS128to64:
700 is_signed_divide = True;
701 goto do_divide64;
702
703 case Iop_64HLto128:
704 *dst_hi = s390_isel_int_expr(env, arg1);
705 *dst_lo = s390_isel_int_expr(env, arg2);
706 return;
707
708 case Iop_DivModS64to64: {
709 HReg r10, r11, h1;
710 s390_opnd_RMI op2;
711
712 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
713 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
714
715 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000716 r10 = make_gpr(10);
717 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000718
719 /* Move 1st operand into r11 and */
720 addInstr(env, s390_insn_move(8, r11, h1));
721
722 /* Divide */
723 addInstr(env, s390_insn_divs(8, r10, r11, op2));
724
725 /* The result is in registers r10 (remainder) and r11 (quotient).
726 Move the result into the reg pair that is being returned such
727 such that the low 64 bits are the quotient and the upper 64 bits
728 are the remainder. (see libvex_ir.h). */
729 *dst_hi = newVRegI(env);
730 *dst_lo = newVRegI(env);
731 addInstr(env, s390_insn_move(8, *dst_hi, r10));
732 addInstr(env, s390_insn_move(8, *dst_lo, r11));
733 return;
734 }
735
736 default:
737 break;
738
739 do_multiply64: {
740 HReg r10, r11, h1;
741 s390_opnd_RMI op2;
742
743 order_commutative_operands(arg1, arg2);
744
745 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
746 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
747
748 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000749 r10 = make_gpr(10);
750 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000751
752 /* Move the first operand to r11 */
753 addInstr(env, s390_insn_move(8, r11, h1));
754
755 /* Multiply */
756 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
757
758 /* The result is in registers r10 and r11. Assign to two virtual regs
759 and return. */
760 *dst_hi = newVRegI(env);
761 *dst_lo = newVRegI(env);
762 addInstr(env, s390_insn_move(8, *dst_hi, r10));
763 addInstr(env, s390_insn_move(8, *dst_lo, r11));
764 return;
765 }
766
767 do_divide64: {
768 HReg r10, r11, hi, lo;
769 s390_opnd_RMI op2;
770
771 s390_isel_int128_expr(&hi, &lo, env, arg1);
772 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
773
774 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000775 r10 = make_gpr(10);
776 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000777
778 /* Move high 64 bits of the 1st operand into r10 and
779 the low 64 bits into r11. */
780 addInstr(env, s390_insn_move(8, r10, hi));
781 addInstr(env, s390_insn_move(8, r11, lo));
782
783 /* Divide */
784 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
785
786 /* The result is in registers r10 (remainder) and r11 (quotient).
787 Move the result into the reg pair that is being returned such
788 such that the low 64 bits are the quotient and the upper 64 bits
789 are the remainder. (see libvex_ir.h). */
790 *dst_hi = newVRegI(env);
791 *dst_lo = newVRegI(env);
792 addInstr(env, s390_insn_move(8, *dst_hi, r10));
793 addInstr(env, s390_insn_move(8, *dst_lo, r11));
794 return;
795 }
796 }
797 }
798
799 vpanic("s390_isel_int128_expr");
800}
801
802
803/* Compute a 128-bit value into two 64-bit registers. These may be either
804 real or virtual regs; in any case they must not be changed by subsequent
805 code emitted by the caller. */
806static void
807s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
808{
809 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
810
811 /* Sanity checks ... */
812 vassert(hregIsVirtual(*dst_hi));
813 vassert(hregIsVirtual(*dst_lo));
814 vassert(hregClass(*dst_hi) == HRcInt64);
815 vassert(hregClass(*dst_lo) == HRcInt64);
816}
817
818
819/*---------------------------------------------------------*/
820/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
821/*---------------------------------------------------------*/
822
823/* Select insns for an integer-typed expression, and add them to the
824 code list. Return a reg holding the result. This reg will be a
825 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
826 want to modify it, ask for a new vreg, copy it in there, and modify
827 the copy. The register allocator will do its best to map both
828 vregs to the same real register, so the copies will often disappear
829 later in the game.
830
831 This should handle expressions of 64, 32, 16 and 8-bit type.
832 All results are returned in a 64bit register.
833 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
834 are arbitrary, so you should mask or sign extend partial values
835 if necessary.
836*/
837
838/* DO NOT CALL THIS DIRECTLY ! */
839static HReg
840s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
841{
842 IRType ty = typeOfIRExpr(env->type_env, expr);
843 UChar size;
florian9fcff4c2012-09-10 03:09:04 +0000844 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +0000845
846 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
847
848 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
849
850 switch (expr->tag) {
851
852 /* --------- TEMP --------- */
853 case Iex_RdTmp:
854 /* Return the virtual register that holds the temporary. */
855 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
856
857 /* --------- LOAD --------- */
858 case Iex_Load: {
859 HReg dst = newVRegI(env);
860 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
861
862 if (expr->Iex.Load.end != Iend_BE)
863 goto irreducible;
864
865 addInstr(env, s390_insn_load(size, dst, am));
866
867 return dst;
868 }
869
870 /* --------- BINARY OP --------- */
871 case Iex_Binop: {
872 IRExpr *arg1 = expr->Iex.Binop.arg1;
873 IRExpr *arg2 = expr->Iex.Binop.arg2;
874 HReg h1, res;
875 s390_alu_t opkind;
876 s390_opnd_RMI op2, value, opnd;
877 s390_insn *insn;
878 Bool is_commutative, is_signed_multiply, is_signed_divide;
879
880 is_commutative = True;
881
882 switch (expr->Iex.Binop.op) {
883 case Iop_MullU8:
884 case Iop_MullU16:
885 case Iop_MullU32:
886 is_signed_multiply = False;
887 goto do_multiply;
888
889 case Iop_MullS8:
890 case Iop_MullS16:
891 case Iop_MullS32:
892 is_signed_multiply = True;
893 goto do_multiply;
894
895 do_multiply: {
896 HReg r10, r11;
897 UInt arg_size = size / 2;
898
899 order_commutative_operands(arg1, arg2);
900
901 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
902 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
903
904 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000905 r10 = make_gpr(10);
906 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000907
908 /* Move the first operand to r11 */
909 addInstr(env, s390_insn_move(arg_size, r11, h1));
910
911 /* Multiply */
912 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
913
914 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
915 value into the destination register. */
916 res = newVRegI(env);
917 addInstr(env, s390_insn_move(arg_size, res, r10));
918 value = s390_opnd_imm(arg_size * 8);
919 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
920 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
921 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
922 opnd = s390_opnd_reg(r11);
923 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
924 return res;
925 }
926
927 case Iop_DivModS64to32:
928 is_signed_divide = True;
929 goto do_divide;
930
931 case Iop_DivModU64to32:
932 is_signed_divide = False;
933 goto do_divide;
934
935 do_divide: {
936 HReg r10, r11;
937
938 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
939 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
940
941 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000942 r10 = make_gpr(10);
943 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000944
945 /* Split the first operand and put the high 32 bits into r10 and
946 the low 32 bits into r11. */
947 addInstr(env, s390_insn_move(8, r10, h1));
948 addInstr(env, s390_insn_move(8, r11, h1));
949 value = s390_opnd_imm(32);
950 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
951
952 /* Divide */
953 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
954
955 /* The result is in registers r10 (remainder) and r11 (quotient).
956 Combine them into a 64-bit value such that the low 32 bits are
957 the quotient and the upper 32 bits are the remainder. (see
958 libvex_ir.h). */
959 res = newVRegI(env);
960 addInstr(env, s390_insn_move(8, res, r10));
961 value = s390_opnd_imm(32);
962 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
963 value = s390_opnd_imm((((ULong)1) << 32) - 1);
964 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
965 opnd = s390_opnd_reg(r11);
966 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
967 return res;
968 }
969
florian9fcff4c2012-09-10 03:09:04 +0000970 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
971 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
972 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
973 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
974 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
975 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
976 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
977 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
978 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
979 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
980 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
981 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
sewardj2019a972011-03-07 16:04:07 +0000982
983 do_convert: {
florian125e20d2012-10-07 15:42:37 +0000984 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +0000985
986 res = newVRegI(env);
987 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
988
florian2c74d242012-09-12 19:38:42 +0000989 rounding_mode = get_bfp_rounding_mode(env, arg1);
990 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
991 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +0000992 return res;
993 }
994
995 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +0000996 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +0000997 HReg op_hi, op_lo, f13, f15;
998
999 res = newVRegI(env);
1000 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1001
1002 /* We use non-virtual registers r13 and r15 as pair */
1003 f13 = make_fpr(13);
1004 f15 = make_fpr(15);
1005
1006 /* operand --> (f13, f15) */
1007 addInstr(env, s390_insn_move(8, f13, op_hi));
1008 addInstr(env, s390_insn_move(8, f15, op_lo));
1009
florian2c74d242012-09-12 19:38:42 +00001010 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001011 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001012 rounding_mode));
1013 return res;
1014 }
1015
1016 case Iop_8HLto16:
1017 case Iop_16HLto32:
1018 case Iop_32HLto64: {
1019 HReg h2;
1020 UInt arg_size = size / 2;
1021
1022 res = newVRegI(env);
1023 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1024 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1025
1026 addInstr(env, s390_insn_move(arg_size, res, h1));
1027 value = s390_opnd_imm(arg_size * 8);
1028 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1029 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1030 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1031 opnd = s390_opnd_reg(h2);
1032 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1033 return res;
1034 }
1035
1036 case Iop_Max32U: {
1037 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1038 res = newVRegI(env);
1039 h1 = s390_isel_int_expr(env, arg1);
1040 op2 = s390_isel_int_expr_RMI(env, arg2);
1041
1042 addInstr(env, s390_insn_move(size, res, h1));
1043 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1044 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1045 return res;
1046 }
1047
1048 case Iop_CmpF32:
1049 case Iop_CmpF64: {
1050 HReg cc_s390, h2;
1051
1052 h1 = s390_isel_float_expr(env, arg1);
1053 h2 = s390_isel_float_expr(env, arg2);
1054 cc_s390 = newVRegI(env);
1055
1056 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1057
1058 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1059
1060 return convert_s390_fpcc_to_vex(env, cc_s390);
1061 }
1062
1063 case Iop_CmpF128: {
1064 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1065
1066 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1067 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1068 cc_s390 = newVRegI(env);
1069
1070 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1071 f12 = make_fpr(12);
1072 f13 = make_fpr(13);
1073 f14 = make_fpr(14);
1074 f15 = make_fpr(15);
1075
1076 /* 1st operand --> (f12, f14) */
1077 addInstr(env, s390_insn_move(8, f12, op1_hi));
1078 addInstr(env, s390_insn_move(8, f14, op1_lo));
1079
1080 /* 2nd operand --> (f13, f15) */
1081 addInstr(env, s390_insn_move(8, f13, op2_hi));
1082 addInstr(env, s390_insn_move(8, f15, op2_lo));
1083
1084 res = newVRegI(env);
1085 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1086
1087 return convert_s390_fpcc_to_vex(env, cc_s390);
1088 }
1089
1090 case Iop_Add8:
1091 case Iop_Add16:
1092 case Iop_Add32:
1093 case Iop_Add64:
1094 opkind = S390_ALU_ADD;
1095 break;
1096
1097 case Iop_Sub8:
1098 case Iop_Sub16:
1099 case Iop_Sub32:
1100 case Iop_Sub64:
1101 opkind = S390_ALU_SUB;
1102 is_commutative = False;
1103 break;
1104
1105 case Iop_And8:
1106 case Iop_And16:
1107 case Iop_And32:
1108 case Iop_And64:
1109 opkind = S390_ALU_AND;
1110 break;
1111
1112 case Iop_Or8:
1113 case Iop_Or16:
1114 case Iop_Or32:
1115 case Iop_Or64:
1116 opkind = S390_ALU_OR;
1117 break;
1118
1119 case Iop_Xor8:
1120 case Iop_Xor16:
1121 case Iop_Xor32:
1122 case Iop_Xor64:
1123 opkind = S390_ALU_XOR;
1124 break;
1125
1126 case Iop_Shl8:
1127 case Iop_Shl16:
1128 case Iop_Shl32:
1129 case Iop_Shl64:
1130 opkind = S390_ALU_LSH;
1131 is_commutative = False;
1132 break;
1133
1134 case Iop_Shr8:
1135 case Iop_Shr16:
1136 case Iop_Shr32:
1137 case Iop_Shr64:
1138 opkind = S390_ALU_RSH;
1139 is_commutative = False;
1140 break;
1141
1142 case Iop_Sar8:
1143 case Iop_Sar16:
1144 case Iop_Sar32:
1145 case Iop_Sar64:
1146 opkind = S390_ALU_RSHA;
1147 is_commutative = False;
1148 break;
1149
1150 default:
1151 goto irreducible;
1152 }
1153
1154 /* Pattern match: 0 - arg1 --> -arg1 */
1155 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1156 res = newVRegI(env);
1157 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1158 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1159 addInstr(env, insn);
1160
1161 return res;
1162 }
1163
1164 if (is_commutative) {
1165 order_commutative_operands(arg1, arg2);
1166 }
1167
1168 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1169 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1170 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001171
1172 /* As right shifts of one/two byte opreands are implemented using a
1173 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1174 switch (expr->Iex.Binop.op) {
1175 case Iop_Shr8:
1176 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1177 break;
1178 case Iop_Shr16:
1179 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1180 break;
1181 case Iop_Sar8:
1182 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1183 break;
1184 case Iop_Sar16:
1185 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1186 break;
1187 default:
1188 insn = s390_insn_move(size, res, h1);
1189 break;
1190 }
1191 addInstr(env, insn);
1192
sewardj2019a972011-03-07 16:04:07 +00001193 insn = s390_insn_alu(size, opkind, res, op2);
1194
1195 addInstr(env, insn);
1196
1197 return res;
1198 }
1199
1200 /* --------- UNARY OP --------- */
1201 case Iex_Unop: {
1202 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1203 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1204 s390_opnd_RMI opnd;
1205 s390_insn *insn;
1206 IRExpr *arg;
1207 HReg dst, h1;
1208 IROp unop, binop;
1209
1210 arg = expr->Iex.Unop.arg;
1211
1212 /* Special cases are handled here */
1213
1214 /* 32-bit multiply with 32-bit result or
1215 64-bit multiply with 64-bit result */
1216 unop = expr->Iex.Unop.op;
1217 binop = arg->Iex.Binop.op;
1218
1219 if ((arg->tag == Iex_Binop &&
1220 ((unop == Iop_64to32 &&
1221 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1222 (unop == Iop_128to64 &&
1223 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1224 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1225 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1226 dst = newVRegI(env); /* Result goes into a new register */
1227 addInstr(env, s390_insn_move(size, dst, h1));
1228 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1229
1230 return dst;
1231 }
1232
florian4d71a082011-12-18 00:08:17 +00001233 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001234 dst = newVRegI(env);
1235 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1236 addInstr(env, s390_insn_move(size, dst, h1));
1237
1238 return dst;
1239 }
1240
1241 /* Expressions whose argument is 1-bit wide */
1242 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1243 s390_cc_t cond = s390_isel_cc(env, arg);
1244 dst = newVRegI(env); /* Result goes into a new register */
1245 addInstr(env, s390_insn_cc2bool(dst, cond));
1246
1247 switch (unop) {
1248 case Iop_1Uto8:
1249 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001250 /* Zero extend */
1251 mask.variant.imm = 1;
1252 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1253 break;
1254
sewardj2019a972011-03-07 16:04:07 +00001255 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001256 /* Zero extend */
1257 mask.variant.imm = 1;
1258 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001259 break;
1260
1261 case Iop_1Sto8:
1262 case Iop_1Sto16:
1263 case Iop_1Sto32:
1264 shift.variant.imm = 31;
1265 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1266 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1267 break;
1268
1269 case Iop_1Sto64:
1270 shift.variant.imm = 63;
1271 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1272 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1273 break;
1274
1275 default:
1276 goto irreducible;
1277 }
1278
1279 return dst;
1280 }
1281
1282 /* Regular processing */
1283
1284 if (unop == Iop_128to64) {
1285 HReg dst_hi, dst_lo;
1286
1287 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1288 return dst_lo;
1289 }
1290
1291 if (unop == Iop_128HIto64) {
1292 HReg dst_hi, dst_lo;
1293
1294 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1295 return dst_hi;
1296 }
1297
1298 dst = newVRegI(env); /* Result goes into a new register */
1299 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1300
1301 switch (unop) {
1302 case Iop_8Uto16:
1303 case Iop_8Uto32:
1304 case Iop_8Uto64:
1305 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1306 break;
1307
1308 case Iop_16Uto32:
1309 case Iop_16Uto64:
1310 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1311 break;
1312
1313 case Iop_32Uto64:
1314 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1315 break;
1316
1317 case Iop_8Sto16:
1318 case Iop_8Sto32:
1319 case Iop_8Sto64:
1320 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1321 break;
1322
1323 case Iop_16Sto32:
1324 case Iop_16Sto64:
1325 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1326 break;
1327
1328 case Iop_32Sto64:
1329 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1330 break;
1331
1332 case Iop_64to8:
1333 case Iop_64to16:
1334 case Iop_64to32:
1335 case Iop_32to8:
1336 case Iop_32to16:
1337 case Iop_16to8:
1338 /* Down-casts are no-ops. Upstream operations will only look at
1339 the bytes that make up the result of the down-cast. So there
1340 is no point setting the other bytes to 0. */
1341 insn = s390_opnd_copy(8, dst, opnd);
1342 break;
1343
1344 case Iop_64HIto32:
1345 addInstr(env, s390_opnd_copy(8, dst, opnd));
1346 shift.variant.imm = 32;
1347 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1348 break;
1349
1350 case Iop_32HIto16:
1351 addInstr(env, s390_opnd_copy(4, dst, opnd));
1352 shift.variant.imm = 16;
1353 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1354 break;
1355
1356 case Iop_16HIto8:
1357 addInstr(env, s390_opnd_copy(2, dst, opnd));
1358 shift.variant.imm = 8;
1359 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1360 break;
1361
1362 case Iop_Not8:
1363 case Iop_Not16:
1364 case Iop_Not32:
1365 case Iop_Not64:
1366 /* XOR with ffff... */
1367 mask.variant.imm = ~(ULong)0;
1368 addInstr(env, s390_opnd_copy(size, dst, opnd));
1369 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1370 break;
1371
1372 case Iop_Left8:
1373 case Iop_Left16:
1374 case Iop_Left32:
1375 case Iop_Left64:
1376 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1377 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1378 break;
1379
1380 case Iop_CmpwNEZ32:
1381 case Iop_CmpwNEZ64: {
1382 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1383 or -X will have a 1 in the MSB. */
1384 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1385 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1386 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1387 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1388 return dst;
1389 }
1390
1391 case Iop_Clz64: {
1392 HReg r10, r11;
1393
sewardj611b06e2011-03-24 08:57:29 +00001394 /* This will be implemented using FLOGR, if possible. So we need to
1395 set aside a pair of non-virtual registers. The result (number of
1396 left-most zero bits) will be in r10. The value in r11 is unspecified
1397 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001398 r10 = make_gpr(10);
1399 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001400
sewardj611b06e2011-03-24 08:57:29 +00001401 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001402 addInstr(env, s390_insn_move(8, dst, r10));
1403 return dst;
1404 }
1405
1406 default:
1407 goto irreducible;
1408 }
1409
1410 addInstr(env, insn);
1411
1412 return dst;
1413 }
1414
1415 /* --------- GET --------- */
1416 case Iex_Get: {
1417 HReg dst = newVRegI(env);
1418 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1419
1420 /* We never load more than 8 bytes from the guest state, because the
1421 floating point register pair is not contiguous. */
1422 vassert(size <= 8);
1423
1424 addInstr(env, s390_insn_load(size, dst, am));
1425
1426 return dst;
1427 }
1428
1429 case Iex_GetI:
1430 /* not needed */
1431 break;
1432
1433 /* --------- CCALL --------- */
1434 case Iex_CCall: {
1435 HReg dst = newVRegI(env);
1436
1437 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001438 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001439 return dst;
1440 }
1441
1442 /* --------- LITERAL --------- */
1443
1444 /* Load a literal into a register. Create a "load immediate"
1445 v-insn and return the register. */
1446 case Iex_Const: {
1447 ULong value;
1448 HReg dst = newVRegI(env);
1449 const IRConst *con = expr->Iex.Const.con;
1450
1451 /* Bitwise copy of the value. No sign/zero-extension */
1452 switch (con->tag) {
1453 case Ico_U64: value = con->Ico.U64; break;
1454 case Ico_U32: value = con->Ico.U32; break;
1455 case Ico_U16: value = con->Ico.U16; break;
1456 case Ico_U8: value = con->Ico.U8; break;
1457 default: vpanic("s390_isel_int_expr: invalid constant");
1458 }
1459
1460 addInstr(env, s390_insn_load_immediate(size, dst, value));
1461
1462 return dst;
1463 }
1464
1465 /* --------- MULTIPLEX --------- */
1466 case Iex_Mux0X: {
1467 IRExpr *cond_expr;
1468 HReg dst, tmp, rX;
1469 s390_opnd_RMI cond, r0, zero;
1470
1471 cond_expr = expr->Iex.Mux0X.cond;
1472
1473 dst = newVRegI(env);
1474 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1475 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1476 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1477
1478 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1479 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1480
1481 addInstr(env, s390_insn_move(size, dst, rX));
1482 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1483 return dst;
1484 }
1485
1486 /* Assume the condition is true and move rX to the destination reg. */
1487 addInstr(env, s390_insn_move(size, dst, rX));
1488
1489 /* Compute the condition ... */
1490 cond = s390_isel_int_expr_RMI(env, cond_expr);
1491
1492 /* tmp = cond & 0xFF */
1493 tmp = newVRegI(env);
1494 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1495 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1496
1497 /* ... and compare it with zero */
1498 zero = s390_opnd_imm(0);
1499 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1500
1501 /* ... and if it compared equal move r0 to the destination reg. */
1502 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1503 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1504
1505 return dst;
1506 }
1507
1508 default:
1509 break;
1510 }
1511
1512 /* We get here if no pattern matched. */
1513 irreducible:
1514 ppIRExpr(expr);
1515 vpanic("s390_isel_int_expr: cannot reduce tree");
1516}
1517
1518
1519static HReg
1520s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1521{
1522 HReg dst = s390_isel_int_expr_wrk(env, expr);
1523
1524 /* Sanity checks ... */
1525 vassert(hregClass(dst) == HRcInt64);
1526 vassert(hregIsVirtual(dst));
1527
1528 return dst;
1529}
1530
1531
1532static s390_opnd_RMI
1533s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1534{
1535 IRType ty = typeOfIRExpr(env->type_env, expr);
1536 s390_opnd_RMI dst;
1537
1538 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1539 ty == Ity_I64);
1540
1541 if (expr->tag == Iex_Load) {
1542 dst.tag = S390_OPND_AMODE;
1543 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1544 } else if (expr->tag == Iex_Get) {
1545 dst.tag = S390_OPND_AMODE;
1546 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1547 } else if (expr->tag == Iex_Const) {
1548 ULong value;
1549
1550 /* The bit pattern for the value will be stored as is in the least
1551 significant bits of VALUE. */
1552 switch (expr->Iex.Const.con->tag) {
1553 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1554 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1555 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1556 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1557 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1558 default:
1559 vpanic("s390_isel_int_expr_RMI");
1560 }
1561
1562 dst.tag = S390_OPND_IMMEDIATE;
1563 dst.variant.imm = value;
1564 } else {
1565 dst.tag = S390_OPND_REG;
1566 dst.variant.reg = s390_isel_int_expr(env, expr);
1567 }
1568
1569 return dst;
1570}
1571
1572
1573/*---------------------------------------------------------*/
1574/*--- ISEL: Floating point expressions (128 bit) ---*/
1575/*---------------------------------------------------------*/
1576static void
1577s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1578 IRExpr *expr)
1579{
1580 IRType ty = typeOfIRExpr(env->type_env, expr);
1581
1582 vassert(ty == Ity_F128);
1583
1584 /* Read 128-bit IRTemp */
1585 if (expr->tag == Iex_RdTmp) {
1586 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1587 return;
1588 }
1589
1590 switch (expr->tag) {
1591 case Iex_RdTmp:
1592 /* Return the virtual registers that hold the temporary. */
1593 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1594 return;
1595
1596 /* --------- LOAD --------- */
1597 case Iex_Load: {
1598 IRExpr *addr_hi, *addr_lo;
1599 s390_amode *am_hi, *am_lo;
1600
1601 if (expr->Iex.Load.end != Iend_BE)
1602 goto irreducible;
1603
1604 addr_hi = expr->Iex.Load.addr;
1605 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1606
1607 am_hi = s390_isel_amode(env, addr_hi);
1608 am_lo = s390_isel_amode(env, addr_lo);
1609
1610 *dst_hi = newVRegF(env);
1611 *dst_lo = newVRegF(env);
1612 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1613 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1614 return;
1615 }
1616
1617
1618 /* --------- GET --------- */
1619 case Iex_Get:
1620 /* This is not supported because loading 128-bit from the guest
1621 state is almost certainly wrong. Use get_fpr_pair instead. */
1622 vpanic("Iex_Get with F128 data");
1623
1624 /* --------- 4-ary OP --------- */
1625 case Iex_Qop:
1626 vpanic("Iex_Qop with F128 data");
1627
1628 /* --------- TERNARY OP --------- */
1629 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001630 IRTriop *triop = expr->Iex.Triop.details;
1631 IROp op = triop->op;
1632 IRExpr *left = triop->arg2;
1633 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001634 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001635 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1636
1637 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1638 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1639
1640 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1641 f12 = make_fpr(12);
1642 f13 = make_fpr(13);
1643 f14 = make_fpr(14);
1644 f15 = make_fpr(15);
1645
1646 /* 1st operand --> (f12, f14) */
1647 addInstr(env, s390_insn_move(8, f12, op1_hi));
1648 addInstr(env, s390_insn_move(8, f14, op1_lo));
1649
1650 /* 2nd operand --> (f13, f15) */
1651 addInstr(env, s390_insn_move(8, f13, op2_hi));
1652 addInstr(env, s390_insn_move(8, f15, op2_lo));
1653
1654 switch (op) {
1655 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1656 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1657 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1658 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1659 default:
1660 goto irreducible;
1661 }
1662
florian2c74d242012-09-12 19:38:42 +00001663 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1664 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001665
1666 /* Move result to virtual destination register */
1667 *dst_hi = newVRegF(env);
1668 *dst_lo = newVRegF(env);
1669 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1670 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1671
1672 return;
1673 }
1674
1675 /* --------- BINARY OP --------- */
1676 case Iex_Binop: {
1677 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001678
1679 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1680 f12 = make_fpr(12);
1681 f13 = make_fpr(13);
1682 f14 = make_fpr(14);
1683 f15 = make_fpr(15);
1684
1685 switch (expr->Iex.Binop.op) {
1686 case Iop_SqrtF128:
1687 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1688
1689 /* operand --> (f13, f15) */
1690 addInstr(env, s390_insn_move(8, f13, op_hi));
1691 addInstr(env, s390_insn_move(8, f15, op_lo));
1692
florian2c74d242012-09-12 19:38:42 +00001693 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1694 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1695 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001696
1697 /* Move result to virtual destination registers */
1698 *dst_hi = newVRegF(env);
1699 *dst_lo = newVRegF(env);
1700 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1701 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1702 return;
1703
1704 case Iop_F64HLtoF128:
1705 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1706 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1707 return;
1708
1709 default:
1710 goto irreducible;
1711 }
1712 }
1713
1714 /* --------- UNARY OP --------- */
1715 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001716 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001717 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00001718 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001719 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1720
1721 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1722 f12 = make_fpr(12);
1723 f13 = make_fpr(13);
1724 f14 = make_fpr(14);
1725 f15 = make_fpr(15);
1726
florian66e596d2012-09-07 15:00:53 +00001727 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001728 case Iop_NegF128:
1729 if (left->tag == Iex_Unop &&
1730 (left->Iex.Unop.op == Iop_AbsF32 ||
1731 left->Iex.Unop.op == Iop_AbsF64))
1732 bfpop = S390_BFP_NABS;
1733 else
1734 bfpop = S390_BFP_NEG;
1735 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00001736 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1737 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1738 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1739 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1740 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1741 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1742 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001743 default:
1744 goto irreducible;
1745 }
1746
1747 float128_opnd:
1748 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1749
1750 /* operand --> (f13, f15) */
1751 addInstr(env, s390_insn_move(8, f13, op_hi));
1752 addInstr(env, s390_insn_move(8, f15, op_lo));
1753
florian2c74d242012-09-12 19:38:42 +00001754 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001755 goto move_dst;
1756
1757 convert_float:
1758 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001759 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001760 goto move_dst;
1761
1762 convert_int:
1763 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001764 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001765 goto move_dst;
1766
1767 move_dst:
1768 /* Move result to virtual destination registers */
1769 *dst_hi = newVRegF(env);
1770 *dst_lo = newVRegF(env);
1771 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1772 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1773 return;
1774 }
1775
1776 default:
1777 goto irreducible;
1778 }
1779
1780 /* We get here if no pattern matched. */
1781 irreducible:
1782 ppIRExpr(expr);
1783 vpanic("s390_isel_int_expr: cannot reduce tree");
1784}
1785
1786/* Compute a 128-bit value into two 64-bit registers. These may be either
1787 real or virtual regs; in any case they must not be changed by subsequent
1788 code emitted by the caller. */
1789static void
1790s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1791{
1792 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1793
1794 /* Sanity checks ... */
1795 vassert(hregIsVirtual(*dst_hi));
1796 vassert(hregIsVirtual(*dst_lo));
1797 vassert(hregClass(*dst_hi) == HRcFlt64);
1798 vassert(hregClass(*dst_lo) == HRcFlt64);
1799}
1800
1801
1802/*---------------------------------------------------------*/
1803/*--- ISEL: Floating point expressions (64 bit) ---*/
1804/*---------------------------------------------------------*/
1805
1806static HReg
1807s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1808{
1809 IRType ty = typeOfIRExpr(env->type_env, expr);
1810 UChar size;
1811
1812 vassert(ty == Ity_F32 || ty == Ity_F64);
1813
1814 size = sizeofIRType(ty);
1815
1816 switch (expr->tag) {
1817 case Iex_RdTmp:
1818 /* Return the virtual register that holds the temporary. */
1819 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1820
1821 /* --------- LOAD --------- */
1822 case Iex_Load: {
1823 HReg dst = newVRegF(env);
1824 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1825
1826 if (expr->Iex.Load.end != Iend_BE)
1827 goto irreducible;
1828
1829 addInstr(env, s390_insn_load(size, dst, am));
1830
1831 return dst;
1832 }
1833
1834 /* --------- GET --------- */
1835 case Iex_Get: {
1836 HReg dst = newVRegF(env);
1837 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1838
1839 addInstr(env, s390_insn_load(size, dst, am));
1840
1841 return dst;
1842 }
1843
1844 /* --------- LITERAL --------- */
1845
1846 /* Load a literal into a register. Create a "load immediate"
1847 v-insn and return the register. */
1848 case Iex_Const: {
1849 ULong value;
1850 HReg dst = newVRegF(env);
1851 const IRConst *con = expr->Iex.Const.con;
1852
1853 /* Bitwise copy of the value. No sign/zero-extension */
1854 switch (con->tag) {
1855 case Ico_F32i: value = con->Ico.F32i; break;
1856 case Ico_F64i: value = con->Ico.F64i; break;
1857 default: vpanic("s390_isel_float_expr: invalid constant");
1858 }
1859
1860 if (value != 0) vpanic("cannot load immediate floating point constant");
1861
1862 addInstr(env, s390_insn_load_immediate(size, dst, value));
1863
1864 return dst;
1865 }
1866
1867 /* --------- 4-ary OP --------- */
1868 case Iex_Qop: {
1869 HReg op1, op2, op3, dst;
1870 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001871
florian5906a6b2012-10-16 02:53:33 +00001872 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00001873 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00001874 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00001875 dst = newVRegF(env);
1876 addInstr(env, s390_insn_move(size, dst, op1));
1877
florian96d7cc32012-06-01 20:41:24 +00001878 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00001879 case Iop_MAddF32:
1880 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1881 case Iop_MSubF32:
1882 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1883
1884 default:
1885 goto irreducible;
1886 }
1887
florian2c74d242012-09-12 19:38:42 +00001888 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
1889 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00001890 return dst;
1891 }
1892
1893 /* --------- TERNARY OP --------- */
1894 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001895 IRTriop *triop = expr->Iex.Triop.details;
1896 IROp op = triop->op;
1897 IRExpr *left = triop->arg2;
1898 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001899 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001900 HReg h1, op2, dst;
1901
1902 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1903 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1904 dst = newVRegF(env);
1905 addInstr(env, s390_insn_move(size, dst, h1));
1906 switch (op) {
1907 case Iop_AddF32:
1908 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1909 case Iop_SubF32:
1910 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1911 case Iop_MulF32:
1912 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1913 case Iop_DivF32:
1914 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1915
1916 default:
1917 goto irreducible;
1918 }
1919
florian2c74d242012-09-12 19:38:42 +00001920 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1921 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00001922 return dst;
1923 }
1924
1925 /* --------- BINARY OP --------- */
1926 case Iex_Binop: {
1927 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00001928 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00001929 IRExpr *left = expr->Iex.Binop.arg2;
1930 HReg h1, dst;
florian9fcff4c2012-09-10 03:09:04 +00001931 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001932
1933 switch (op) {
1934 case Iop_SqrtF32:
1935 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00001936 h1 = s390_isel_float_expr(env, left);
1937 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00001938 set_bfp_rounding_mode_in_fpc(env, irrm);
1939 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00001940 return dst;
sewardj2019a972011-03-07 16:04:07 +00001941
florian9fcff4c2012-09-10 03:09:04 +00001942 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
1943 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
1944 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
1945 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
1946 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
1947 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
1948 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00001949
florian9fcff4c2012-09-10 03:09:04 +00001950 convert_float:
1951 h1 = s390_isel_float_expr(env, left);
1952 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00001953
florian9fcff4c2012-09-10 03:09:04 +00001954 convert_int:
1955 h1 = s390_isel_int_expr(env, left);
1956 goto convert;
1957
florian2c74d242012-09-12 19:38:42 +00001958 convert: {
florian125e20d2012-10-07 15:42:37 +00001959 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00001960 /* convert-from-fixed and load-rounded have a rounding mode field
1961 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00001962 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00001963 if (s390_host_has_fpext) {
1964 rounding_mode = get_bfp_rounding_mode(env, irrm);
1965 } else {
1966 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00001967 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00001968 }
florian9fcff4c2012-09-10 03:09:04 +00001969 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
1970 rounding_mode));
1971 return dst;
florian2c74d242012-09-12 19:38:42 +00001972 }
florian9fcff4c2012-09-10 03:09:04 +00001973
sewardj2019a972011-03-07 16:04:07 +00001974 default:
1975 goto irreducible;
1976
1977 case Iop_F128toF64:
1978 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00001979 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00001980 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001981
florian9fcff4c2012-09-10 03:09:04 +00001982 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1983 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00001984
florian9fcff4c2012-09-10 03:09:04 +00001985 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00001986
florian9fcff4c2012-09-10 03:09:04 +00001987 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00001988 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00001989 f15 = make_fpr(15);
1990
1991 /* operand --> (f13, f15) */
1992 addInstr(env, s390_insn_move(8, f13, op_hi));
1993 addInstr(env, s390_insn_move(8, f15, op_lo));
1994
1995 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00001996 /* load-rounded has a rounding mode field when the floating point
1997 extension facility is installed. */
1998 if (s390_host_has_fpext) {
1999 rounding_mode = get_bfp_rounding_mode(env, irrm);
2000 } else {
2001 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002002 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002003 }
floriancc491a62012-09-10 23:44:37 +00002004 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002005 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002006 return dst;
2007 }
2008 }
sewardj2019a972011-03-07 16:04:07 +00002009 }
2010
2011 /* --------- UNARY OP --------- */
2012 case Iex_Unop: {
2013 IROp op = expr->Iex.Unop.op;
2014 IRExpr *left = expr->Iex.Unop.arg;
2015 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00002016 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002017 HReg h1, dst;
2018
2019 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2020 HReg dst_hi, dst_lo;
2021
2022 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2023 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2024 }
2025
florian4d71a082011-12-18 00:08:17 +00002026 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002027 dst = newVRegF(env);
2028 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2029 addInstr(env, s390_insn_move(size, dst, h1));
2030
2031 return dst;
2032 }
2033
2034 switch (op) {
2035 case Iop_NegF32:
2036 case Iop_NegF64:
2037 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002038 (left->Iex.Unop.op == Iop_AbsF32 ||
2039 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002040 bfpop = S390_BFP_NABS;
2041 else
2042 bfpop = S390_BFP_NEG;
2043 break;
2044
2045 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002046 case Iop_AbsF64:
2047 bfpop = S390_BFP_ABS;
2048 break;
2049
2050 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2051 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2052 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2053
2054 convert_float1:
2055 h1 = s390_isel_float_expr(env, left);
2056 goto convert1;
2057
2058 convert_int1:
2059 h1 = s390_isel_int_expr(env, left);
2060 goto convert1;
2061
2062 convert1:
2063 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002064 /* No rounding mode is needed for these conversions. Just stick
2065 one in. It won't be used later on. */
2066 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002067 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002068 return dst;
2069
sewardj2019a972011-03-07 16:04:07 +00002070 default:
2071 goto irreducible;
2072 }
2073
2074 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002075 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002076 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002077 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002078 return dst;
2079 }
2080
2081 default:
2082 goto irreducible;
2083 }
2084
2085 /* We get here if no pattern matched. */
2086 irreducible:
2087 ppIRExpr(expr);
2088 vpanic("s390_isel_float_expr: cannot reduce tree");
2089}
2090
2091
2092static HReg
2093s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2094{
2095 HReg dst = s390_isel_float_expr_wrk(env, expr);
2096
2097 /* Sanity checks ... */
2098 vassert(hregClass(dst) == HRcFlt64);
2099 vassert(hregIsVirtual(dst));
2100
2101 return dst;
2102}
2103
2104
2105/*---------------------------------------------------------*/
2106/*--- ISEL: Condition Code ---*/
2107/*---------------------------------------------------------*/
2108
2109/* This function handles all operators that produce a 1-bit result */
2110static s390_cc_t
2111s390_isel_cc(ISelEnv *env, IRExpr *cond)
2112{
2113 UChar size;
2114
2115 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2116
2117 /* Constant: either 1 or 0 */
2118 if (cond->tag == Iex_Const) {
2119 vassert(cond->Iex.Const.con->tag == Ico_U1);
2120 vassert(cond->Iex.Const.con->Ico.U1 == True
2121 || cond->Iex.Const.con->Ico.U1 == False);
2122
2123 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2124 }
2125
2126 /* Variable: values are 1 or 0 */
2127 if (cond->tag == Iex_RdTmp) {
2128 IRTemp tmp = cond->Iex.RdTmp.tmp;
2129 HReg reg = lookupIRTemp(env, tmp);
2130
2131 /* Load-and-test does not modify REG; so this is OK. */
2132 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2133 size = 4;
2134 else
2135 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2136 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2137 return S390_CC_NE;
2138 }
2139
2140 /* Unary operators */
2141 if (cond->tag == Iex_Unop) {
2142 IRExpr *arg = cond->Iex.Unop.arg;
2143
2144 switch (cond->Iex.Unop.op) {
2145 case Iop_Not1: /* Not1(cond) */
2146 /* Generate code for EXPR, and negate the test condition */
2147 return s390_cc_invert(s390_isel_cc(env, arg));
2148
2149 /* Iop_32/64to1 select the LSB from their operand */
2150 case Iop_32to1:
2151 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002152 HReg dst = newVRegI(env);
2153 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002154
2155 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2156
florianf366a802012-08-03 00:42:18 +00002157 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002158 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2159 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2160 return S390_CC_NE;
2161 }
2162
2163 case Iop_CmpNEZ8:
2164 case Iop_CmpNEZ16: {
2165 s390_opnd_RMI src;
2166 s390_unop_t op;
2167 HReg dst;
2168
2169 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2170 : S390_ZERO_EXTEND_16;
2171 dst = newVRegI(env);
2172 src = s390_isel_int_expr_RMI(env, arg);
2173 addInstr(env, s390_insn_unop(4, op, dst, src));
2174 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2175 return S390_CC_NE;
2176 }
2177
2178 case Iop_CmpNEZ32:
2179 case Iop_CmpNEZ64: {
2180 s390_opnd_RMI src;
2181
2182 src = s390_isel_int_expr_RMI(env, arg);
2183 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2184 addInstr(env, s390_insn_test(size, src));
2185 return S390_CC_NE;
2186 }
2187
2188 default:
2189 goto fail;
2190 }
2191 }
2192
2193 /* Binary operators */
2194 if (cond->tag == Iex_Binop) {
2195 IRExpr *arg1 = cond->Iex.Binop.arg1;
2196 IRExpr *arg2 = cond->Iex.Binop.arg2;
2197 HReg reg1, reg2;
2198
2199 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2200
2201 switch (cond->Iex.Binop.op) {
2202 s390_unop_t op;
2203 s390_cc_t result;
2204
2205 case Iop_CmpEQ8:
2206 case Iop_CasCmpEQ8:
2207 op = S390_ZERO_EXTEND_8;
2208 result = S390_CC_E;
2209 goto do_compare_ze;
2210
2211 case Iop_CmpNE8:
2212 case Iop_CasCmpNE8:
2213 op = S390_ZERO_EXTEND_8;
2214 result = S390_CC_NE;
2215 goto do_compare_ze;
2216
2217 case Iop_CmpEQ16:
2218 case Iop_CasCmpEQ16:
2219 op = S390_ZERO_EXTEND_16;
2220 result = S390_CC_E;
2221 goto do_compare_ze;
2222
2223 case Iop_CmpNE16:
2224 case Iop_CasCmpNE16:
2225 op = S390_ZERO_EXTEND_16;
2226 result = S390_CC_NE;
2227 goto do_compare_ze;
2228
2229 do_compare_ze: {
2230 s390_opnd_RMI op1, op2;
2231
2232 op1 = s390_isel_int_expr_RMI(env, arg1);
2233 reg1 = newVRegI(env);
2234 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2235
2236 op2 = s390_isel_int_expr_RMI(env, arg2);
2237 reg2 = newVRegI(env);
2238 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2239
2240 op2 = s390_opnd_reg(reg2);
2241 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2242
2243 return result;
2244 }
2245
2246 case Iop_CmpEQ32:
2247 case Iop_CmpEQ64:
2248 case Iop_CasCmpEQ32:
2249 case Iop_CasCmpEQ64:
2250 result = S390_CC_E;
2251 goto do_compare;
2252
2253 case Iop_CmpNE32:
2254 case Iop_CmpNE64:
2255 case Iop_CasCmpNE32:
2256 case Iop_CasCmpNE64:
2257 result = S390_CC_NE;
2258 goto do_compare;
2259
2260 do_compare: {
2261 HReg op1;
2262 s390_opnd_RMI op2;
2263
2264 order_commutative_operands(arg1, arg2);
2265
2266 op1 = s390_isel_int_expr(env, arg1);
2267 op2 = s390_isel_int_expr_RMI(env, arg2);
2268
2269 addInstr(env, s390_insn_compare(size, op1, op2, False));
2270
2271 return result;
2272 }
2273
2274 case Iop_CmpLT32S:
2275 case Iop_CmpLE32S:
2276 case Iop_CmpLT64S:
2277 case Iop_CmpLE64S: {
2278 HReg op1;
2279 s390_opnd_RMI op2;
2280
2281 op1 = s390_isel_int_expr(env, arg1);
2282 op2 = s390_isel_int_expr_RMI(env, arg2);
2283
2284 addInstr(env, s390_insn_compare(size, op1, op2, True));
2285
2286 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2287 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2288 }
2289
2290 case Iop_CmpLT32U:
2291 case Iop_CmpLE32U:
2292 case Iop_CmpLT64U:
2293 case Iop_CmpLE64U: {
2294 HReg op1;
2295 s390_opnd_RMI op2;
2296
2297 op1 = s390_isel_int_expr(env, arg1);
2298 op2 = s390_isel_int_expr_RMI(env, arg2);
2299
2300 addInstr(env, s390_insn_compare(size, op1, op2, False));
2301
2302 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2303 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2304 }
2305
2306 default:
2307 goto fail;
2308 }
2309 }
2310
2311 fail:
2312 ppIRExpr(cond);
2313 vpanic("s390_isel_cc: unexpected operator");
2314}
2315
2316
2317/*---------------------------------------------------------*/
2318/*--- ISEL: Statements ---*/
2319/*---------------------------------------------------------*/
2320
2321static void
2322s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2323{
2324 if (vex_traceflags & VEX_TRACE_VCODE) {
2325 vex_printf("\n -- ");
2326 ppIRStmt(stmt);
2327 vex_printf("\n");
2328 }
2329
2330 switch (stmt->tag) {
2331
2332 /* --------- STORE --------- */
2333 case Ist_Store: {
2334 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2335 s390_amode *am;
2336 HReg src;
2337
2338 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2339
2340 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2341
2342 switch (tyd) {
2343 case Ity_I8:
2344 case Ity_I16:
2345 case Ity_I32:
2346 case Ity_I64:
2347 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2348 break;
2349
2350 case Ity_F32:
2351 case Ity_F64:
2352 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2353 break;
2354
2355 case Ity_F128:
2356 /* Cannot occur. No such instruction */
2357 vpanic("Ist_Store with F128 data");
2358
2359 default:
2360 goto stmt_fail;
2361 }
2362
2363 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2364 return;
2365 }
2366
2367 /* --------- PUT --------- */
2368 case Ist_Put: {
2369 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2370 HReg src;
2371 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002372 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002373
florianad43b3a2012-02-20 15:01:14 +00002374 /* Detect updates to certain guest registers. We track the contents
2375 of those registers as long as they contain constants. If the new
2376 constant is either zero or in the 8-bit neighbourhood of the
2377 current value we can use a memory-to-memory insn to do the update. */
2378
2379 Int offset = stmt->Ist.Put.offset;
2380
2381 /* Check necessary conditions:
2382 (1) must be one of the registers we care about
2383 (2) assigned value must be a constant */
2384 Int guest_reg = get_guest_reg(offset);
2385
2386 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2387
2388 if (guest_reg == GUEST_IA) {
2389 /* If this is the first assignment to the IA reg, don't special case
2390 it. We need to do a full 8-byte assignment here. The reason is
2391 that in case of a redirected translation the guest IA does not
2392 contain the redirected-to address. Instead it contains the
2393 redirected-from address and those can be far apart. So in order to
2394 do incremnetal updates if the IA in the future we need to get the
2395 initial address of the super block correct. */
2396 if (env->first_IA_assignment) {
2397 env->first_IA_assignment = False;
2398 goto not_special;
2399 }
2400 }
2401
2402 if (stmt->Ist.Put.data->tag != Iex_Const) {
2403 /* Invalidate guest register contents */
2404 env->old_value_valid[guest_reg] = False;
2405 goto not_special;
2406 }
2407
cborntraaf7ad282012-08-08 14:11:33 +00002408 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2409 if (tyd != Ity_I64)
2410 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002411
cborntraaf7ad282012-08-08 14:11:33 +00002412 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002413
2414 old_value = env->old_value[guest_reg];
2415 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2416 env->old_value[guest_reg] = new_value;
2417
2418 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2419 env->old_value_valid[guest_reg] = True;
2420
2421 /* If the register already contains the new value, there is nothing
2422 to do here. Unless the guest register requires precise memory
2423 exceptions. */
2424 if (old_value_is_valid && new_value == old_value) {
2425 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2426 return;
2427 }
2428 }
2429
2430 /* guest register = 0 */
2431 if (new_value == 0) {
2432 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2433 return;
2434 }
2435
2436 if (old_value_is_valid == False) goto not_special;
2437
2438 /* If the new value is in the neighbourhood of the old value
2439 we can use a memory-to-memory insn */
2440 difference = new_value - old_value;
2441
2442 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2443 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2444 (difference & 0xFF), new_value));
2445 return;
2446 }
2447
2448 /* If the high word is the same it is sufficient to load the low word.
2449 Use R0 as a scratch reg. */
2450 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002451 HReg r0 = make_gpr(0);
2452 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002453 s390_amode *gam;
2454
2455 gam = s390_amode_b12(offset + 4, gsp);
2456 addInstr(env, s390_insn_load_immediate(4, r0,
2457 new_value & 0xFFFFFFFF));
2458 addInstr(env, s390_insn_store(4, gam, r0));
2459 return;
2460 }
2461
2462 /* No special case applies... fall through */
2463
2464 not_special:
sewardj2019a972011-03-07 16:04:07 +00002465 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2466
2467 switch (tyd) {
2468 case Ity_I8:
2469 case Ity_I16:
2470 case Ity_I32:
2471 case Ity_I64:
2472 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2473 break;
2474
2475 case Ity_F32:
2476 case Ity_F64:
2477 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2478 break;
2479
2480 case Ity_F128:
2481 /* Does not occur. See function put_fpr_pair. */
2482 vpanic("Ist_Put with F128 data");
2483
2484 default:
2485 goto stmt_fail;
2486 }
2487
2488 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2489 return;
2490 }
2491
2492 /* --------- TMP --------- */
2493 case Ist_WrTmp: {
2494 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2495 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2496 HReg src, dst;
2497
2498 switch (tyd) {
2499 case Ity_I128: {
2500 HReg dst_hi, dst_lo, res_hi, res_lo;
2501
2502 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2503 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2504
2505 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2506 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2507 return;
2508 }
2509
2510 case Ity_I8:
2511 case Ity_I16:
2512 case Ity_I32:
2513 case Ity_I64:
2514 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2515 dst = lookupIRTemp(env, tmp);
2516 break;
2517
2518 case Ity_I1: {
2519 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2520 dst = lookupIRTemp(env, tmp);
2521 addInstr(env, s390_insn_cc2bool(dst, cond));
2522 return;
2523 }
2524
2525 case Ity_F32:
2526 case Ity_F64:
2527 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2528 dst = lookupIRTemp(env, tmp);
2529 break;
2530
2531 case Ity_F128: {
2532 HReg dst_hi, dst_lo, res_hi, res_lo;
2533
2534 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2535 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2536
2537 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2538 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2539 return;
2540 }
2541
2542 default:
2543 goto stmt_fail;
2544 }
2545
2546 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2547 return;
2548 }
2549
2550 /* --------- Call to DIRTY helper --------- */
2551 case Ist_Dirty: {
2552 IRType retty;
2553 IRDirty* d = stmt->Ist.Dirty.details;
2554 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002555 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002556 Int i;
2557
2558 /* Invalidate tracked values of those guest state registers that are
2559 modified by this helper. */
2560 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002561 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2562 descriptors in guest state effect descriptions. Hence: */
2563 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002564 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2565 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2566 if (guest_reg != GUEST_UNKNOWN)
2567 env->old_value_valid[guest_reg] = False;
2568 }
2569 }
sewardj2019a972011-03-07 16:04:07 +00002570
2571 if (d->nFxState == 0)
2572 vassert(!d->needsBBP);
2573
2574 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2575
florian01ed6e72012-05-27 16:52:43 +00002576 if (d->tmp == IRTemp_INVALID) {
2577 /* No return value. */
2578 dst = INVALID_HREG;
2579 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002580 return;
florian01ed6e72012-05-27 16:52:43 +00002581 }
sewardj2019a972011-03-07 16:04:07 +00002582
2583 retty = typeOfIRTemp(env->type_env, d->tmp);
2584 if (retty == Ity_I64 || retty == Ity_I32
2585 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002586 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002587 dst = lookupIRTemp(env, d->tmp);
2588 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002589 return;
2590 }
2591 break;
2592 }
2593
2594 case Ist_CAS:
2595 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2596 IRCAS *cas = stmt->Ist.CAS.details;
2597 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2598 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2599 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2600 HReg old = lookupIRTemp(env, cas->oldLo);
2601
2602 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2603 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2604 } else {
2605 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2606 }
2607 return;
2608 } else {
florian448cbba2012-06-06 02:26:01 +00002609 IRCAS *cas = stmt->Ist.CAS.details;
2610 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2611 HReg r8, r9, r10, r11, r1;
2612 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2613 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2614 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2615 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2616 HReg old_low = lookupIRTemp(env, cas->oldLo);
2617 HReg old_high = lookupIRTemp(env, cas->oldHi);
2618
2619 /* Use non-virtual registers r8 and r9 as pair for op1
2620 and move op1 there */
2621 r8 = make_gpr(8);
2622 r9 = make_gpr(9);
2623 addInstr(env, s390_insn_move(8, r8, op1_high));
2624 addInstr(env, s390_insn_move(8, r9, op1_low));
2625
2626 /* Use non-virtual registers r10 and r11 as pair for op3
2627 and move op3 there */
2628 r10 = make_gpr(10);
2629 r11 = make_gpr(11);
2630 addInstr(env, s390_insn_move(8, r10, op3_high));
2631 addInstr(env, s390_insn_move(8, r11, op3_low));
2632
2633 /* Register r1 is used as a scratch register */
2634 r1 = make_gpr(1);
2635
2636 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2637 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2638 old_high, old_low, r1));
2639 } else {
2640 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2641 old_high, old_low, r1));
2642 }
2643 addInstr(env, s390_insn_move(8, op1_high, r8));
2644 addInstr(env, s390_insn_move(8, op1_low, r9));
2645 addInstr(env, s390_insn_move(8, op3_high, r10));
2646 addInstr(env, s390_insn_move(8, op3_low, r11));
2647 return;
sewardj2019a972011-03-07 16:04:07 +00002648 }
2649 break;
2650
2651 /* --------- EXIT --------- */
2652 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002653 s390_cc_t cond;
2654 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2655
2656 if (tag != Ico_U64)
2657 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2658
florian8844a632012-04-13 04:04:06 +00002659 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002660 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002661
2662 /* Case: boring transfer to known address */
2663 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2664 if (env->chaining_allowed) {
2665 /* .. almost always true .. */
2666 /* Skip the event check at the dst if this is a forwards
2667 edge. */
2668 Bool to_fast_entry
2669 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2670 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2671 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2672 guest_IA, to_fast_entry));
2673 } else {
2674 /* .. very occasionally .. */
2675 /* We can't use chaining, so ask for an assisted transfer,
2676 as that's the only alternative that is allowable. */
2677 HReg dst = s390_isel_int_expr(env,
2678 IRExpr_Const(stmt->Ist.Exit.dst));
2679 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2680 }
2681 return;
2682 }
2683
2684 /* Case: assisted transfer to arbitrary address */
2685 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00002686 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002687 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002688 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002689 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002690 case Ijk_Sys_syscall:
2691 case Ijk_ClientReq:
2692 case Ijk_NoRedir:
2693 case Ijk_Yield:
2694 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002695 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2696 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2697 stmt->Ist.Exit.jk));
2698 return;
2699 }
2700 default:
2701 break;
2702 }
2703
2704 /* Do we ever expect to see any other kind? */
2705 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002706 }
2707
2708 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002709 case Ist_MBE:
2710 switch (stmt->Ist.MBE.event) {
2711 case Imbe_Fence:
2712 addInstr(env, s390_insn_mfence());
2713 return;
2714 default:
2715 break;
2716 }
sewardj2019a972011-03-07 16:04:07 +00002717 break;
2718
2719 /* --------- Miscellaneous --------- */
2720
2721 case Ist_PutI: /* Not needed */
2722 case Ist_IMark: /* Doesn't generate any executable code */
2723 case Ist_NoOp: /* Doesn't generate any executable code */
2724 case Ist_AbiHint: /* Meaningless in IR */
2725 return;
2726
2727 default:
2728 break;
2729 }
2730
2731 stmt_fail:
2732 ppIRStmt(stmt);
2733 vpanic("s390_isel_stmt");
2734}
2735
2736
2737/*---------------------------------------------------------*/
2738/*--- ISEL: Basic block terminators (Nexts) ---*/
2739/*---------------------------------------------------------*/
2740
2741static void
florian8844a632012-04-13 04:04:06 +00002742iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002743{
sewardj2019a972011-03-07 16:04:07 +00002744 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002745 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002746 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002747 vex_printf("; exit-");
2748 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002749 vex_printf("\n");
2750 }
2751
florian8844a632012-04-13 04:04:06 +00002752 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2753
2754 /* Case: boring transfer to known address */
2755 if (next->tag == Iex_Const) {
2756 IRConst *cdst = next->Iex.Const.con;
2757 vassert(cdst->tag == Ico_U64);
2758 if (jk == Ijk_Boring || jk == Ijk_Call) {
2759 /* Boring transfer to known address */
2760 if (env->chaining_allowed) {
2761 /* .. almost always true .. */
2762 /* Skip the event check at the dst if this is a forwards
2763 edge. */
2764 Bool to_fast_entry
2765 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2766 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2767 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2768 guest_IA, to_fast_entry));
2769 } else {
2770 /* .. very occasionally .. */
2771 /* We can't use chaining, so ask for an indirect transfer,
2772 as that's the cheapest alternative that is allowable. */
2773 HReg dst = s390_isel_int_expr(env, next);
2774 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2775 Ijk_Boring));
2776 }
2777 return;
2778 }
2779 }
2780
2781 /* Case: call/return (==boring) transfer to any address */
2782 switch (jk) {
2783 case Ijk_Boring:
2784 case Ijk_Ret:
2785 case Ijk_Call: {
2786 HReg dst = s390_isel_int_expr(env, next);
2787 if (env->chaining_allowed) {
2788 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2789 } else {
2790 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2791 Ijk_Boring));
2792 }
2793 return;
2794 }
2795 default:
2796 break;
2797 }
2798
2799 /* Case: some other kind of transfer to any address */
2800 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00002801 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002802 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002803 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002804 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002805 case Ijk_Sys_syscall:
2806 case Ijk_ClientReq:
2807 case Ijk_NoRedir:
2808 case Ijk_Yield:
2809 case Ijk_SigTRAP: {
2810 HReg dst = s390_isel_int_expr(env, next);
2811 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2812 return;
2813 }
2814 default:
2815 break;
2816 }
2817
2818 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002819}
2820
2821
2822/*---------------------------------------------------------*/
2823/*--- Insn selector top-level ---*/
2824/*---------------------------------------------------------*/
2825
florianf26994a2012-04-21 03:34:54 +00002826/* Translate an entire SB to s390 code.
2827 Note: archinfo_host is a pointer to a stack-allocated variable.
2828 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002829
2830HInstrArray *
2831iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002832 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2833 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2834 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002835{
2836 UInt i, j;
2837 HReg hreg, hregHI;
2838 ISelEnv *env;
2839 UInt hwcaps_host = archinfo_host->hwcaps;
2840
florianf26994a2012-04-21 03:34:54 +00002841 /* KLUDGE: export hwcaps. */
2842 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002843
sewardj2019a972011-03-07 16:04:07 +00002844 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002845 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002846
2847 /* Make up an initial environment to use. */
2848 env = LibVEX_Alloc(sizeof(ISelEnv));
2849 env->vreg_ctr = 0;
2850
2851 /* Set up output code array. */
2852 env->code = newHInstrArray();
2853
2854 /* Copy BB's type env. */
2855 env->type_env = bb->tyenv;
2856
florianad43b3a2012-02-20 15:01:14 +00002857 /* Set up data structures for tracking guest register values. */
2858 env->first_IA_assignment = True;
2859 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2860 env->old_value[i] = 0; /* just something to have a defined value */
2861 env->old_value_valid[i] = False;
2862 }
2863
sewardj2019a972011-03-07 16:04:07 +00002864 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2865 change as we go along. For some reason types_used has Int type -- but
2866 it should be unsigned. Internally we use an unsigned type; so we
2867 assert it here. */
2868 vassert(bb->tyenv->types_used >= 0);
2869
2870 env->n_vregmap = bb->tyenv->types_used;
2871 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2872 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2873
florian2c74d242012-09-12 19:38:42 +00002874 env->previous_bfp_rounding_mode = NULL;
2875
sewardj2019a972011-03-07 16:04:07 +00002876 /* and finally ... */
2877 env->hwcaps = hwcaps_host;
2878
florian8844a632012-04-13 04:04:06 +00002879 env->max_ga = max_ga;
2880 env->chaining_allowed = chaining_allowed;
2881
sewardj2019a972011-03-07 16:04:07 +00002882 /* For each IR temporary, allocate a suitably-kinded virtual
2883 register. */
2884 j = 0;
2885 for (i = 0; i < env->n_vregmap; i++) {
2886 hregHI = hreg = INVALID_HREG;
2887 switch (bb->tyenv->types[i]) {
2888 case Ity_I1:
2889 case Ity_I8:
2890 case Ity_I16:
2891 case Ity_I32:
2892 hreg = mkHReg(j++, HRcInt64, True);
2893 break;
2894
2895 case Ity_I64:
2896 hreg = mkHReg(j++, HRcInt64, True);
2897 break;
2898
2899 case Ity_I128:
2900 hreg = mkHReg(j++, HRcInt64, True);
2901 hregHI = mkHReg(j++, HRcInt64, True);
2902 break;
2903
2904 case Ity_F32:
2905 case Ity_F64:
2906 hreg = mkHReg(j++, HRcFlt64, True);
2907 break;
2908
2909 case Ity_F128:
2910 hreg = mkHReg(j++, HRcFlt64, True);
2911 hregHI = mkHReg(j++, HRcFlt64, True);
2912 break;
2913
2914 case Ity_V128: /* fall through */
2915 default:
2916 ppIRType(bb->tyenv->types[i]);
2917 vpanic("s390_isel_sb: IRTemp type");
2918 }
2919
2920 env->vregmap[i] = hreg;
2921 env->vregmapHI[i] = hregHI;
2922 }
2923 env->vreg_ctr = j;
2924
florian8844a632012-04-13 04:04:06 +00002925 /* The very first instruction must be an event check. */
2926 s390_amode *counter, *fail_addr;
2927 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2928 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2929 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2930
2931 /* Possibly a block counter increment (for profiling). At this
2932 point we don't know the address of the counter, so just pretend
2933 it is zero. It will have to be patched later, but before this
2934 translation is used, by a call to LibVEX_patchProfInc. */
2935 if (add_profinc) {
2936 addInstr(env, s390_insn_profinc());
2937 }
2938
sewardj2019a972011-03-07 16:04:07 +00002939 /* Ok, finally we can iterate over the statements. */
2940 for (i = 0; i < bb->stmts_used; i++)
2941 if (bb->stmts[i])
2942 s390_isel_stmt(env, bb->stmts[i]);
2943
florian8844a632012-04-13 04:04:06 +00002944 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002945
2946 /* Record the number of vregs we used. */
2947 env->code->n_vregs = env->vreg_ctr;
2948
2949 return env->code;
2950}
2951
2952/*---------------------------------------------------------------*/
2953/*--- end host_s390_isel.c ---*/
2954/*---------------------------------------------------------------*/