blob: 0acf262c815a5472d7dc7d5659a0b8d18f16a9a6 [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
580 addInstr(env, s390_insn_set_fpcrm(4, mode));
581}
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. */
588static s390_round_t
589get_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) {
florian2c74d242012-09-12 19:38:42 +0000596 case Irrm_NEAREST: return S390_ROUND_NEAREST_EVEN;
597 case Irrm_ZERO: return S390_ROUND_ZERO;
598 case Irrm_PosINF: return S390_ROUND_POSINF;
599 case Irrm_NegINF: return S390_ROUND_NEGINF;
600 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);
606 return S390_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: {
984 s390_round_t rounding_mode;
985
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: {
996 s390_round_t rounding_mode;
997 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) {
florian9fcff4c2012-09-10 03:09:04 +00001728 case Iop_NegF128: bfpop = S390_BFP_NEG; goto float128_opnd;
1729 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1730 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1731 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1732 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1733 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1734 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1735 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001736 default:
1737 goto irreducible;
1738 }
1739
1740 float128_opnd:
1741 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1742
1743 /* operand --> (f13, f15) */
1744 addInstr(env, s390_insn_move(8, f13, op_hi));
1745 addInstr(env, s390_insn_move(8, f15, op_lo));
1746
florian2c74d242012-09-12 19:38:42 +00001747 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001748 goto move_dst;
1749
1750 convert_float:
1751 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001752 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001753 goto move_dst;
1754
1755 convert_int:
1756 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001757 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001758 goto move_dst;
1759
1760 move_dst:
1761 /* Move result to virtual destination registers */
1762 *dst_hi = newVRegF(env);
1763 *dst_lo = newVRegF(env);
1764 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1765 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1766 return;
1767 }
1768
1769 default:
1770 goto irreducible;
1771 }
1772
1773 /* We get here if no pattern matched. */
1774 irreducible:
1775 ppIRExpr(expr);
1776 vpanic("s390_isel_int_expr: cannot reduce tree");
1777}
1778
1779/* Compute a 128-bit value into two 64-bit registers. These may be either
1780 real or virtual regs; in any case they must not be changed by subsequent
1781 code emitted by the caller. */
1782static void
1783s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1784{
1785 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1786
1787 /* Sanity checks ... */
1788 vassert(hregIsVirtual(*dst_hi));
1789 vassert(hregIsVirtual(*dst_lo));
1790 vassert(hregClass(*dst_hi) == HRcFlt64);
1791 vassert(hregClass(*dst_lo) == HRcFlt64);
1792}
1793
1794
1795/*---------------------------------------------------------*/
1796/*--- ISEL: Floating point expressions (64 bit) ---*/
1797/*---------------------------------------------------------*/
1798
1799static HReg
1800s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1801{
1802 IRType ty = typeOfIRExpr(env->type_env, expr);
1803 UChar size;
1804
1805 vassert(ty == Ity_F32 || ty == Ity_F64);
1806
1807 size = sizeofIRType(ty);
1808
1809 switch (expr->tag) {
1810 case Iex_RdTmp:
1811 /* Return the virtual register that holds the temporary. */
1812 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1813
1814 /* --------- LOAD --------- */
1815 case Iex_Load: {
1816 HReg dst = newVRegF(env);
1817 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1818
1819 if (expr->Iex.Load.end != Iend_BE)
1820 goto irreducible;
1821
1822 addInstr(env, s390_insn_load(size, dst, am));
1823
1824 return dst;
1825 }
1826
1827 /* --------- GET --------- */
1828 case Iex_Get: {
1829 HReg dst = newVRegF(env);
1830 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1831
1832 addInstr(env, s390_insn_load(size, dst, am));
1833
1834 return dst;
1835 }
1836
1837 /* --------- LITERAL --------- */
1838
1839 /* Load a literal into a register. Create a "load immediate"
1840 v-insn and return the register. */
1841 case Iex_Const: {
1842 ULong value;
1843 HReg dst = newVRegF(env);
1844 const IRConst *con = expr->Iex.Const.con;
1845
1846 /* Bitwise copy of the value. No sign/zero-extension */
1847 switch (con->tag) {
1848 case Ico_F32i: value = con->Ico.F32i; break;
1849 case Ico_F64i: value = con->Ico.F64i; break;
1850 default: vpanic("s390_isel_float_expr: invalid constant");
1851 }
1852
1853 if (value != 0) vpanic("cannot load immediate floating point constant");
1854
1855 addInstr(env, s390_insn_load_immediate(size, dst, value));
1856
1857 return dst;
1858 }
1859
1860 /* --------- 4-ary OP --------- */
1861 case Iex_Qop: {
1862 HReg op1, op2, op3, dst;
1863 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001864
florian96d7cc32012-06-01 20:41:24 +00001865 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
1866 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
1867 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00001868 dst = newVRegF(env);
1869 addInstr(env, s390_insn_move(size, dst, op1));
1870
florian96d7cc32012-06-01 20:41:24 +00001871 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00001872 case Iop_MAddF32:
1873 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
1874 case Iop_MSubF32:
1875 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
1876
1877 default:
1878 goto irreducible;
1879 }
1880
florian2c74d242012-09-12 19:38:42 +00001881 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
1882 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00001883 return dst;
1884 }
1885
1886 /* --------- TERNARY OP --------- */
1887 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001888 IRTriop *triop = expr->Iex.Triop.details;
1889 IROp op = triop->op;
1890 IRExpr *left = triop->arg2;
1891 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001892 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001893 HReg h1, op2, dst;
1894
1895 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
1896 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
1897 dst = newVRegF(env);
1898 addInstr(env, s390_insn_move(size, dst, h1));
1899 switch (op) {
1900 case Iop_AddF32:
1901 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
1902 case Iop_SubF32:
1903 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
1904 case Iop_MulF32:
1905 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
1906 case Iop_DivF32:
1907 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
1908
1909 default:
1910 goto irreducible;
1911 }
1912
florian2c74d242012-09-12 19:38:42 +00001913 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1914 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00001915 return dst;
1916 }
1917
1918 /* --------- BINARY OP --------- */
1919 case Iex_Binop: {
1920 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00001921 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00001922 IRExpr *left = expr->Iex.Binop.arg2;
1923 HReg h1, dst;
florian9fcff4c2012-09-10 03:09:04 +00001924 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001925
1926 switch (op) {
1927 case Iop_SqrtF32:
1928 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00001929 h1 = s390_isel_float_expr(env, left);
1930 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00001931 set_bfp_rounding_mode_in_fpc(env, irrm);
1932 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00001933 return dst;
sewardj2019a972011-03-07 16:04:07 +00001934
florian9fcff4c2012-09-10 03:09:04 +00001935 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
1936 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
1937 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
1938 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
1939 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
1940 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
1941 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00001942
florian9fcff4c2012-09-10 03:09:04 +00001943 convert_float:
1944 h1 = s390_isel_float_expr(env, left);
1945 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00001946
florian9fcff4c2012-09-10 03:09:04 +00001947 convert_int:
1948 h1 = s390_isel_int_expr(env, left);
1949 goto convert;
1950
florian2c74d242012-09-12 19:38:42 +00001951 convert: {
1952 s390_round_t rounding_mode;
1953 /* convert-from-fixed and load-rounded have a rounding mode field
1954 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00001955 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00001956 if (s390_host_has_fpext) {
1957 rounding_mode = get_bfp_rounding_mode(env, irrm);
1958 } else {
1959 set_bfp_rounding_mode_in_fpc(env, irrm);
1960 rounding_mode = S390_ROUND_PER_FPC;
1961 }
florian9fcff4c2012-09-10 03:09:04 +00001962 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
1963 rounding_mode));
1964 return dst;
florian2c74d242012-09-12 19:38:42 +00001965 }
florian9fcff4c2012-09-10 03:09:04 +00001966
sewardj2019a972011-03-07 16:04:07 +00001967 default:
1968 goto irreducible;
1969
1970 case Iop_F128toF64:
1971 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00001972 HReg op_hi, op_lo, f13, f15;
florian2c74d242012-09-12 19:38:42 +00001973 s390_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001974
florian9fcff4c2012-09-10 03:09:04 +00001975 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
1976 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00001977
florian9fcff4c2012-09-10 03:09:04 +00001978 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00001979
florian9fcff4c2012-09-10 03:09:04 +00001980 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00001981 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00001982 f15 = make_fpr(15);
1983
1984 /* operand --> (f13, f15) */
1985 addInstr(env, s390_insn_move(8, f13, op_hi));
1986 addInstr(env, s390_insn_move(8, f15, op_lo));
1987
1988 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00001989 /* load-rounded has a rounding mode field when the floating point
1990 extension facility is installed. */
1991 if (s390_host_has_fpext) {
1992 rounding_mode = get_bfp_rounding_mode(env, irrm);
1993 } else {
1994 set_bfp_rounding_mode_in_fpc(env, irrm);
1995 rounding_mode = S390_ROUND_PER_FPC;
1996 }
floriancc491a62012-09-10 23:44:37 +00001997 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00001998 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001999 return dst;
2000 }
2001 }
sewardj2019a972011-03-07 16:04:07 +00002002 }
2003
2004 /* --------- UNARY OP --------- */
2005 case Iex_Unop: {
2006 IROp op = expr->Iex.Unop.op;
2007 IRExpr *left = expr->Iex.Unop.arg;
2008 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00002009 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002010 HReg h1, dst;
2011
2012 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2013 HReg dst_hi, dst_lo;
2014
2015 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2016 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2017 }
2018
florian4d71a082011-12-18 00:08:17 +00002019 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002020 dst = newVRegF(env);
2021 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2022 addInstr(env, s390_insn_move(size, dst, h1));
2023
2024 return dst;
2025 }
2026
2027 switch (op) {
2028 case Iop_NegF32:
2029 case Iop_NegF64:
2030 if (left->tag == Iex_Unop &&
2031 (left->Iex.Unop.op == Iop_AbsF32 || left->Iex.Unop.op == Iop_AbsF64))
2032 bfpop = S390_BFP_NABS;
2033 else
2034 bfpop = S390_BFP_NEG;
2035 break;
2036
2037 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002038 case Iop_AbsF64:
2039 bfpop = S390_BFP_ABS;
2040 break;
2041
2042 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2043 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2044 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2045
2046 convert_float1:
2047 h1 = s390_isel_float_expr(env, left);
2048 goto convert1;
2049
2050 convert_int1:
2051 h1 = s390_isel_int_expr(env, left);
2052 goto convert1;
2053
2054 convert1:
2055 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002056 /* No rounding mode is needed for these conversions. Just stick
2057 one in. It won't be used later on. */
2058 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2059 S390_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002060 return dst;
2061
sewardj2019a972011-03-07 16:04:07 +00002062 default:
2063 goto irreducible;
2064 }
2065
2066 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002067 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002068 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002069 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002070 return dst;
2071 }
2072
2073 default:
2074 goto irreducible;
2075 }
2076
2077 /* We get here if no pattern matched. */
2078 irreducible:
2079 ppIRExpr(expr);
2080 vpanic("s390_isel_float_expr: cannot reduce tree");
2081}
2082
2083
2084static HReg
2085s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2086{
2087 HReg dst = s390_isel_float_expr_wrk(env, expr);
2088
2089 /* Sanity checks ... */
2090 vassert(hregClass(dst) == HRcFlt64);
2091 vassert(hregIsVirtual(dst));
2092
2093 return dst;
2094}
2095
2096
2097/*---------------------------------------------------------*/
2098/*--- ISEL: Condition Code ---*/
2099/*---------------------------------------------------------*/
2100
2101/* This function handles all operators that produce a 1-bit result */
2102static s390_cc_t
2103s390_isel_cc(ISelEnv *env, IRExpr *cond)
2104{
2105 UChar size;
2106
2107 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2108
2109 /* Constant: either 1 or 0 */
2110 if (cond->tag == Iex_Const) {
2111 vassert(cond->Iex.Const.con->tag == Ico_U1);
2112 vassert(cond->Iex.Const.con->Ico.U1 == True
2113 || cond->Iex.Const.con->Ico.U1 == False);
2114
2115 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2116 }
2117
2118 /* Variable: values are 1 or 0 */
2119 if (cond->tag == Iex_RdTmp) {
2120 IRTemp tmp = cond->Iex.RdTmp.tmp;
2121 HReg reg = lookupIRTemp(env, tmp);
2122
2123 /* Load-and-test does not modify REG; so this is OK. */
2124 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2125 size = 4;
2126 else
2127 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2128 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2129 return S390_CC_NE;
2130 }
2131
2132 /* Unary operators */
2133 if (cond->tag == Iex_Unop) {
2134 IRExpr *arg = cond->Iex.Unop.arg;
2135
2136 switch (cond->Iex.Unop.op) {
2137 case Iop_Not1: /* Not1(cond) */
2138 /* Generate code for EXPR, and negate the test condition */
2139 return s390_cc_invert(s390_isel_cc(env, arg));
2140
2141 /* Iop_32/64to1 select the LSB from their operand */
2142 case Iop_32to1:
2143 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002144 HReg dst = newVRegI(env);
2145 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002146
2147 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2148
florianf366a802012-08-03 00:42:18 +00002149 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002150 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2151 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2152 return S390_CC_NE;
2153 }
2154
2155 case Iop_CmpNEZ8:
2156 case Iop_CmpNEZ16: {
2157 s390_opnd_RMI src;
2158 s390_unop_t op;
2159 HReg dst;
2160
2161 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2162 : S390_ZERO_EXTEND_16;
2163 dst = newVRegI(env);
2164 src = s390_isel_int_expr_RMI(env, arg);
2165 addInstr(env, s390_insn_unop(4, op, dst, src));
2166 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2167 return S390_CC_NE;
2168 }
2169
2170 case Iop_CmpNEZ32:
2171 case Iop_CmpNEZ64: {
2172 s390_opnd_RMI src;
2173
2174 src = s390_isel_int_expr_RMI(env, arg);
2175 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2176 addInstr(env, s390_insn_test(size, src));
2177 return S390_CC_NE;
2178 }
2179
2180 default:
2181 goto fail;
2182 }
2183 }
2184
2185 /* Binary operators */
2186 if (cond->tag == Iex_Binop) {
2187 IRExpr *arg1 = cond->Iex.Binop.arg1;
2188 IRExpr *arg2 = cond->Iex.Binop.arg2;
2189 HReg reg1, reg2;
2190
2191 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2192
2193 switch (cond->Iex.Binop.op) {
2194 s390_unop_t op;
2195 s390_cc_t result;
2196
2197 case Iop_CmpEQ8:
2198 case Iop_CasCmpEQ8:
2199 op = S390_ZERO_EXTEND_8;
2200 result = S390_CC_E;
2201 goto do_compare_ze;
2202
2203 case Iop_CmpNE8:
2204 case Iop_CasCmpNE8:
2205 op = S390_ZERO_EXTEND_8;
2206 result = S390_CC_NE;
2207 goto do_compare_ze;
2208
2209 case Iop_CmpEQ16:
2210 case Iop_CasCmpEQ16:
2211 op = S390_ZERO_EXTEND_16;
2212 result = S390_CC_E;
2213 goto do_compare_ze;
2214
2215 case Iop_CmpNE16:
2216 case Iop_CasCmpNE16:
2217 op = S390_ZERO_EXTEND_16;
2218 result = S390_CC_NE;
2219 goto do_compare_ze;
2220
2221 do_compare_ze: {
2222 s390_opnd_RMI op1, op2;
2223
2224 op1 = s390_isel_int_expr_RMI(env, arg1);
2225 reg1 = newVRegI(env);
2226 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2227
2228 op2 = s390_isel_int_expr_RMI(env, arg2);
2229 reg2 = newVRegI(env);
2230 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2231
2232 op2 = s390_opnd_reg(reg2);
2233 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2234
2235 return result;
2236 }
2237
2238 case Iop_CmpEQ32:
2239 case Iop_CmpEQ64:
2240 case Iop_CasCmpEQ32:
2241 case Iop_CasCmpEQ64:
2242 result = S390_CC_E;
2243 goto do_compare;
2244
2245 case Iop_CmpNE32:
2246 case Iop_CmpNE64:
2247 case Iop_CasCmpNE32:
2248 case Iop_CasCmpNE64:
2249 result = S390_CC_NE;
2250 goto do_compare;
2251
2252 do_compare: {
2253 HReg op1;
2254 s390_opnd_RMI op2;
2255
2256 order_commutative_operands(arg1, arg2);
2257
2258 op1 = s390_isel_int_expr(env, arg1);
2259 op2 = s390_isel_int_expr_RMI(env, arg2);
2260
2261 addInstr(env, s390_insn_compare(size, op1, op2, False));
2262
2263 return result;
2264 }
2265
2266 case Iop_CmpLT32S:
2267 case Iop_CmpLE32S:
2268 case Iop_CmpLT64S:
2269 case Iop_CmpLE64S: {
2270 HReg op1;
2271 s390_opnd_RMI op2;
2272
2273 op1 = s390_isel_int_expr(env, arg1);
2274 op2 = s390_isel_int_expr_RMI(env, arg2);
2275
2276 addInstr(env, s390_insn_compare(size, op1, op2, True));
2277
2278 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2279 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2280 }
2281
2282 case Iop_CmpLT32U:
2283 case Iop_CmpLE32U:
2284 case Iop_CmpLT64U:
2285 case Iop_CmpLE64U: {
2286 HReg op1;
2287 s390_opnd_RMI op2;
2288
2289 op1 = s390_isel_int_expr(env, arg1);
2290 op2 = s390_isel_int_expr_RMI(env, arg2);
2291
2292 addInstr(env, s390_insn_compare(size, op1, op2, False));
2293
2294 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2295 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2296 }
2297
2298 default:
2299 goto fail;
2300 }
2301 }
2302
2303 fail:
2304 ppIRExpr(cond);
2305 vpanic("s390_isel_cc: unexpected operator");
2306}
2307
2308
2309/*---------------------------------------------------------*/
2310/*--- ISEL: Statements ---*/
2311/*---------------------------------------------------------*/
2312
2313static void
2314s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2315{
2316 if (vex_traceflags & VEX_TRACE_VCODE) {
2317 vex_printf("\n -- ");
2318 ppIRStmt(stmt);
2319 vex_printf("\n");
2320 }
2321
2322 switch (stmt->tag) {
2323
2324 /* --------- STORE --------- */
2325 case Ist_Store: {
2326 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2327 s390_amode *am;
2328 HReg src;
2329
2330 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2331
2332 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2333
2334 switch (tyd) {
2335 case Ity_I8:
2336 case Ity_I16:
2337 case Ity_I32:
2338 case Ity_I64:
2339 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2340 break;
2341
2342 case Ity_F32:
2343 case Ity_F64:
2344 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2345 break;
2346
2347 case Ity_F128:
2348 /* Cannot occur. No such instruction */
2349 vpanic("Ist_Store with F128 data");
2350
2351 default:
2352 goto stmt_fail;
2353 }
2354
2355 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2356 return;
2357 }
2358
2359 /* --------- PUT --------- */
2360 case Ist_Put: {
2361 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2362 HReg src;
2363 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002364 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002365
florianad43b3a2012-02-20 15:01:14 +00002366 /* Detect updates to certain guest registers. We track the contents
2367 of those registers as long as they contain constants. If the new
2368 constant is either zero or in the 8-bit neighbourhood of the
2369 current value we can use a memory-to-memory insn to do the update. */
2370
2371 Int offset = stmt->Ist.Put.offset;
2372
2373 /* Check necessary conditions:
2374 (1) must be one of the registers we care about
2375 (2) assigned value must be a constant */
2376 Int guest_reg = get_guest_reg(offset);
2377
2378 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2379
2380 if (guest_reg == GUEST_IA) {
2381 /* If this is the first assignment to the IA reg, don't special case
2382 it. We need to do a full 8-byte assignment here. The reason is
2383 that in case of a redirected translation the guest IA does not
2384 contain the redirected-to address. Instead it contains the
2385 redirected-from address and those can be far apart. So in order to
2386 do incremnetal updates if the IA in the future we need to get the
2387 initial address of the super block correct. */
2388 if (env->first_IA_assignment) {
2389 env->first_IA_assignment = False;
2390 goto not_special;
2391 }
2392 }
2393
2394 if (stmt->Ist.Put.data->tag != Iex_Const) {
2395 /* Invalidate guest register contents */
2396 env->old_value_valid[guest_reg] = False;
2397 goto not_special;
2398 }
2399
cborntraaf7ad282012-08-08 14:11:33 +00002400 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2401 if (tyd != Ity_I64)
2402 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002403
cborntraaf7ad282012-08-08 14:11:33 +00002404 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002405
2406 old_value = env->old_value[guest_reg];
2407 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2408 env->old_value[guest_reg] = new_value;
2409
2410 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2411 env->old_value_valid[guest_reg] = True;
2412
2413 /* If the register already contains the new value, there is nothing
2414 to do here. Unless the guest register requires precise memory
2415 exceptions. */
2416 if (old_value_is_valid && new_value == old_value) {
2417 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2418 return;
2419 }
2420 }
2421
2422 /* guest register = 0 */
2423 if (new_value == 0) {
2424 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2425 return;
2426 }
2427
2428 if (old_value_is_valid == False) goto not_special;
2429
2430 /* If the new value is in the neighbourhood of the old value
2431 we can use a memory-to-memory insn */
2432 difference = new_value - old_value;
2433
2434 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2435 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2436 (difference & 0xFF), new_value));
2437 return;
2438 }
2439
2440 /* If the high word is the same it is sufficient to load the low word.
2441 Use R0 as a scratch reg. */
2442 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002443 HReg r0 = make_gpr(0);
2444 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002445 s390_amode *gam;
2446
2447 gam = s390_amode_b12(offset + 4, gsp);
2448 addInstr(env, s390_insn_load_immediate(4, r0,
2449 new_value & 0xFFFFFFFF));
2450 addInstr(env, s390_insn_store(4, gam, r0));
2451 return;
2452 }
2453
2454 /* No special case applies... fall through */
2455
2456 not_special:
sewardj2019a972011-03-07 16:04:07 +00002457 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2458
2459 switch (tyd) {
2460 case Ity_I8:
2461 case Ity_I16:
2462 case Ity_I32:
2463 case Ity_I64:
2464 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2465 break;
2466
2467 case Ity_F32:
2468 case Ity_F64:
2469 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2470 break;
2471
2472 case Ity_F128:
2473 /* Does not occur. See function put_fpr_pair. */
2474 vpanic("Ist_Put with F128 data");
2475
2476 default:
2477 goto stmt_fail;
2478 }
2479
2480 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2481 return;
2482 }
2483
2484 /* --------- TMP --------- */
2485 case Ist_WrTmp: {
2486 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2487 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2488 HReg src, dst;
2489
2490 switch (tyd) {
2491 case Ity_I128: {
2492 HReg dst_hi, dst_lo, res_hi, res_lo;
2493
2494 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2495 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2496
2497 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2498 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2499 return;
2500 }
2501
2502 case Ity_I8:
2503 case Ity_I16:
2504 case Ity_I32:
2505 case Ity_I64:
2506 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2507 dst = lookupIRTemp(env, tmp);
2508 break;
2509
2510 case Ity_I1: {
2511 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2512 dst = lookupIRTemp(env, tmp);
2513 addInstr(env, s390_insn_cc2bool(dst, cond));
2514 return;
2515 }
2516
2517 case Ity_F32:
2518 case Ity_F64:
2519 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2520 dst = lookupIRTemp(env, tmp);
2521 break;
2522
2523 case Ity_F128: {
2524 HReg dst_hi, dst_lo, res_hi, res_lo;
2525
2526 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2527 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2528
2529 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2530 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2531 return;
2532 }
2533
2534 default:
2535 goto stmt_fail;
2536 }
2537
2538 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2539 return;
2540 }
2541
2542 /* --------- Call to DIRTY helper --------- */
2543 case Ist_Dirty: {
2544 IRType retty;
2545 IRDirty* d = stmt->Ist.Dirty.details;
2546 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002547 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002548 Int i;
2549
2550 /* Invalidate tracked values of those guest state registers that are
2551 modified by this helper. */
2552 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002553 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2554 descriptors in guest state effect descriptions. Hence: */
2555 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002556 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2557 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2558 if (guest_reg != GUEST_UNKNOWN)
2559 env->old_value_valid[guest_reg] = False;
2560 }
2561 }
sewardj2019a972011-03-07 16:04:07 +00002562
2563 if (d->nFxState == 0)
2564 vassert(!d->needsBBP);
2565
2566 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2567
florian01ed6e72012-05-27 16:52:43 +00002568 if (d->tmp == IRTemp_INVALID) {
2569 /* No return value. */
2570 dst = INVALID_HREG;
2571 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002572 return;
florian01ed6e72012-05-27 16:52:43 +00002573 }
sewardj2019a972011-03-07 16:04:07 +00002574
2575 retty = typeOfIRTemp(env->type_env, d->tmp);
2576 if (retty == Ity_I64 || retty == Ity_I32
2577 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002578 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002579 dst = lookupIRTemp(env, d->tmp);
2580 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002581 return;
2582 }
2583 break;
2584 }
2585
2586 case Ist_CAS:
2587 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2588 IRCAS *cas = stmt->Ist.CAS.details;
2589 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2590 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2591 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2592 HReg old = lookupIRTemp(env, cas->oldLo);
2593
2594 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2595 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2596 } else {
2597 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2598 }
2599 return;
2600 } else {
florian448cbba2012-06-06 02:26:01 +00002601 IRCAS *cas = stmt->Ist.CAS.details;
2602 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2603 HReg r8, r9, r10, r11, r1;
2604 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2605 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2606 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2607 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2608 HReg old_low = lookupIRTemp(env, cas->oldLo);
2609 HReg old_high = lookupIRTemp(env, cas->oldHi);
2610
2611 /* Use non-virtual registers r8 and r9 as pair for op1
2612 and move op1 there */
2613 r8 = make_gpr(8);
2614 r9 = make_gpr(9);
2615 addInstr(env, s390_insn_move(8, r8, op1_high));
2616 addInstr(env, s390_insn_move(8, r9, op1_low));
2617
2618 /* Use non-virtual registers r10 and r11 as pair for op3
2619 and move op3 there */
2620 r10 = make_gpr(10);
2621 r11 = make_gpr(11);
2622 addInstr(env, s390_insn_move(8, r10, op3_high));
2623 addInstr(env, s390_insn_move(8, r11, op3_low));
2624
2625 /* Register r1 is used as a scratch register */
2626 r1 = make_gpr(1);
2627
2628 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2629 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2630 old_high, old_low, r1));
2631 } else {
2632 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2633 old_high, old_low, r1));
2634 }
2635 addInstr(env, s390_insn_move(8, op1_high, r8));
2636 addInstr(env, s390_insn_move(8, op1_low, r9));
2637 addInstr(env, s390_insn_move(8, op3_high, r10));
2638 addInstr(env, s390_insn_move(8, op3_low, r11));
2639 return;
sewardj2019a972011-03-07 16:04:07 +00002640 }
2641 break;
2642
2643 /* --------- EXIT --------- */
2644 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002645 s390_cc_t cond;
2646 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2647
2648 if (tag != Ico_U64)
2649 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2650
florian8844a632012-04-13 04:04:06 +00002651 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002652 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002653
2654 /* Case: boring transfer to known address */
2655 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2656 if (env->chaining_allowed) {
2657 /* .. almost always true .. */
2658 /* Skip the event check at the dst if this is a forwards
2659 edge. */
2660 Bool to_fast_entry
2661 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2662 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2663 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2664 guest_IA, to_fast_entry));
2665 } else {
2666 /* .. very occasionally .. */
2667 /* We can't use chaining, so ask for an assisted transfer,
2668 as that's the only alternative that is allowable. */
2669 HReg dst = s390_isel_int_expr(env,
2670 IRExpr_Const(stmt->Ist.Exit.dst));
2671 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2672 }
2673 return;
2674 }
2675
2676 /* Case: assisted transfer to arbitrary address */
2677 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00002678 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002679 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002680 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002681 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002682 case Ijk_Sys_syscall:
2683 case Ijk_ClientReq:
2684 case Ijk_NoRedir:
2685 case Ijk_Yield:
2686 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002687 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2688 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2689 stmt->Ist.Exit.jk));
2690 return;
2691 }
2692 default:
2693 break;
2694 }
2695
2696 /* Do we ever expect to see any other kind? */
2697 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002698 }
2699
2700 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002701 case Ist_MBE:
2702 switch (stmt->Ist.MBE.event) {
2703 case Imbe_Fence:
2704 addInstr(env, s390_insn_mfence());
2705 return;
2706 default:
2707 break;
2708 }
sewardj2019a972011-03-07 16:04:07 +00002709 break;
2710
2711 /* --------- Miscellaneous --------- */
2712
2713 case Ist_PutI: /* Not needed */
2714 case Ist_IMark: /* Doesn't generate any executable code */
2715 case Ist_NoOp: /* Doesn't generate any executable code */
2716 case Ist_AbiHint: /* Meaningless in IR */
2717 return;
2718
2719 default:
2720 break;
2721 }
2722
2723 stmt_fail:
2724 ppIRStmt(stmt);
2725 vpanic("s390_isel_stmt");
2726}
2727
2728
2729/*---------------------------------------------------------*/
2730/*--- ISEL: Basic block terminators (Nexts) ---*/
2731/*---------------------------------------------------------*/
2732
2733static void
florian8844a632012-04-13 04:04:06 +00002734iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002735{
sewardj2019a972011-03-07 16:04:07 +00002736 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002737 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002738 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002739 vex_printf("; exit-");
2740 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002741 vex_printf("\n");
2742 }
2743
florian8844a632012-04-13 04:04:06 +00002744 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2745
2746 /* Case: boring transfer to known address */
2747 if (next->tag == Iex_Const) {
2748 IRConst *cdst = next->Iex.Const.con;
2749 vassert(cdst->tag == Ico_U64);
2750 if (jk == Ijk_Boring || jk == Ijk_Call) {
2751 /* Boring transfer to known address */
2752 if (env->chaining_allowed) {
2753 /* .. almost always true .. */
2754 /* Skip the event check at the dst if this is a forwards
2755 edge. */
2756 Bool to_fast_entry
2757 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2758 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2759 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2760 guest_IA, to_fast_entry));
2761 } else {
2762 /* .. very occasionally .. */
2763 /* We can't use chaining, so ask for an indirect transfer,
2764 as that's the cheapest alternative that is allowable. */
2765 HReg dst = s390_isel_int_expr(env, next);
2766 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2767 Ijk_Boring));
2768 }
2769 return;
2770 }
2771 }
2772
2773 /* Case: call/return (==boring) transfer to any address */
2774 switch (jk) {
2775 case Ijk_Boring:
2776 case Ijk_Ret:
2777 case Ijk_Call: {
2778 HReg dst = s390_isel_int_expr(env, next);
2779 if (env->chaining_allowed) {
2780 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2781 } else {
2782 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2783 Ijk_Boring));
2784 }
2785 return;
2786 }
2787 default:
2788 break;
2789 }
2790
2791 /* Case: some other kind of transfer to any address */
2792 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00002793 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002794 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002795 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002796 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002797 case Ijk_Sys_syscall:
2798 case Ijk_ClientReq:
2799 case Ijk_NoRedir:
2800 case Ijk_Yield:
2801 case Ijk_SigTRAP: {
2802 HReg dst = s390_isel_int_expr(env, next);
2803 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2804 return;
2805 }
2806 default:
2807 break;
2808 }
2809
2810 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002811}
2812
2813
2814/*---------------------------------------------------------*/
2815/*--- Insn selector top-level ---*/
2816/*---------------------------------------------------------*/
2817
florianf26994a2012-04-21 03:34:54 +00002818/* Translate an entire SB to s390 code.
2819 Note: archinfo_host is a pointer to a stack-allocated variable.
2820 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002821
2822HInstrArray *
2823iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002824 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2825 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2826 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002827{
2828 UInt i, j;
2829 HReg hreg, hregHI;
2830 ISelEnv *env;
2831 UInt hwcaps_host = archinfo_host->hwcaps;
2832
florianf26994a2012-04-21 03:34:54 +00002833 /* KLUDGE: export hwcaps. */
2834 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002835
sewardj2019a972011-03-07 16:04:07 +00002836 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002837 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002838
2839 /* Make up an initial environment to use. */
2840 env = LibVEX_Alloc(sizeof(ISelEnv));
2841 env->vreg_ctr = 0;
2842
2843 /* Set up output code array. */
2844 env->code = newHInstrArray();
2845
2846 /* Copy BB's type env. */
2847 env->type_env = bb->tyenv;
2848
florianad43b3a2012-02-20 15:01:14 +00002849 /* Set up data structures for tracking guest register values. */
2850 env->first_IA_assignment = True;
2851 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2852 env->old_value[i] = 0; /* just something to have a defined value */
2853 env->old_value_valid[i] = False;
2854 }
2855
sewardj2019a972011-03-07 16:04:07 +00002856 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2857 change as we go along. For some reason types_used has Int type -- but
2858 it should be unsigned. Internally we use an unsigned type; so we
2859 assert it here. */
2860 vassert(bb->tyenv->types_used >= 0);
2861
2862 env->n_vregmap = bb->tyenv->types_used;
2863 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2864 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2865
florian2c74d242012-09-12 19:38:42 +00002866 env->previous_bfp_rounding_mode = NULL;
2867
sewardj2019a972011-03-07 16:04:07 +00002868 /* and finally ... */
2869 env->hwcaps = hwcaps_host;
2870
florian8844a632012-04-13 04:04:06 +00002871 env->max_ga = max_ga;
2872 env->chaining_allowed = chaining_allowed;
2873
sewardj2019a972011-03-07 16:04:07 +00002874 /* For each IR temporary, allocate a suitably-kinded virtual
2875 register. */
2876 j = 0;
2877 for (i = 0; i < env->n_vregmap; i++) {
2878 hregHI = hreg = INVALID_HREG;
2879 switch (bb->tyenv->types[i]) {
2880 case Ity_I1:
2881 case Ity_I8:
2882 case Ity_I16:
2883 case Ity_I32:
2884 hreg = mkHReg(j++, HRcInt64, True);
2885 break;
2886
2887 case Ity_I64:
2888 hreg = mkHReg(j++, HRcInt64, True);
2889 break;
2890
2891 case Ity_I128:
2892 hreg = mkHReg(j++, HRcInt64, True);
2893 hregHI = mkHReg(j++, HRcInt64, True);
2894 break;
2895
2896 case Ity_F32:
2897 case Ity_F64:
2898 hreg = mkHReg(j++, HRcFlt64, True);
2899 break;
2900
2901 case Ity_F128:
2902 hreg = mkHReg(j++, HRcFlt64, True);
2903 hregHI = mkHReg(j++, HRcFlt64, True);
2904 break;
2905
2906 case Ity_V128: /* fall through */
2907 default:
2908 ppIRType(bb->tyenv->types[i]);
2909 vpanic("s390_isel_sb: IRTemp type");
2910 }
2911
2912 env->vregmap[i] = hreg;
2913 env->vregmapHI[i] = hregHI;
2914 }
2915 env->vreg_ctr = j;
2916
florian8844a632012-04-13 04:04:06 +00002917 /* The very first instruction must be an event check. */
2918 s390_amode *counter, *fail_addr;
2919 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
2920 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
2921 addInstr(env, s390_insn_evcheck(counter, fail_addr));
2922
2923 /* Possibly a block counter increment (for profiling). At this
2924 point we don't know the address of the counter, so just pretend
2925 it is zero. It will have to be patched later, but before this
2926 translation is used, by a call to LibVEX_patchProfInc. */
2927 if (add_profinc) {
2928 addInstr(env, s390_insn_profinc());
2929 }
2930
sewardj2019a972011-03-07 16:04:07 +00002931 /* Ok, finally we can iterate over the statements. */
2932 for (i = 0; i < bb->stmts_used; i++)
2933 if (bb->stmts[i])
2934 s390_isel_stmt(env, bb->stmts[i]);
2935
florian8844a632012-04-13 04:04:06 +00002936 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00002937
2938 /* Record the number of vregs we used. */
2939 env->code->n_vregs = env->vreg_ctr;
2940
2941 return env->code;
2942}
2943
2944/*---------------------------------------------------------------*/
2945/*--- end host_s390_isel.c ---*/
2946/*---------------------------------------------------------------*/