blob: 6a958d1431f4376c977e5ce89714b51fa5ba14ae [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;
florianc8e4f562012-10-27 16:19:31 +0000117 IRExpr *previous_dfp_rounding_mode;
florian2c74d242012-09-12 19:38:42 +0000118
florianad43b3a2012-02-20 15:01:14 +0000119 ULong old_value[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000120
florian8844a632012-04-13 04:04:06 +0000121 /* The next two are for translation chaining */
122 Addr64 max_ga;
123 Bool chaining_allowed;
124
florianad43b3a2012-02-20 15:01:14 +0000125 Bool first_IA_assignment;
126 Bool old_value_valid[NUM_TRACKED_REGS];
sewardj2019a972011-03-07 16:04:07 +0000127} ISelEnv;
128
129
130/* Forward declarations */
131static HReg s390_isel_int_expr(ISelEnv *, IRExpr *);
132static s390_amode *s390_isel_amode(ISelEnv *, IRExpr *);
133static s390_cc_t s390_isel_cc(ISelEnv *, IRExpr *);
134static s390_opnd_RMI s390_isel_int_expr_RMI(ISelEnv *, IRExpr *);
135static void s390_isel_int128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
136static HReg s390_isel_float_expr(ISelEnv *, IRExpr *);
137static void s390_isel_float128_expr(HReg *, HReg *, ISelEnv *, IRExpr *);
138
139
florianad43b3a2012-02-20 15:01:14 +0000140static Int
141get_guest_reg(Int offset)
142{
143 switch (offset) {
florian428dfdd2012-03-27 03:09:49 +0000144 case S390X_GUEST_OFFSET(guest_IA): return GUEST_IA;
145 case S390X_GUEST_OFFSET(guest_CC_OP): return GUEST_CC_OP;
146 case S390X_GUEST_OFFSET(guest_CC_DEP1): return GUEST_CC_DEP1;
147 case S390X_GUEST_OFFSET(guest_CC_DEP2): return GUEST_CC_DEP2;
148 case S390X_GUEST_OFFSET(guest_CC_NDEP): return GUEST_CC_NDEP;
149 case S390X_GUEST_OFFSET(guest_SYSNO): return GUEST_SYSNO;
florian7d117ba2012-05-06 03:34:55 +0000150 case S390X_GUEST_OFFSET(guest_counter): return GUEST_COUNTER;
florianad43b3a2012-02-20 15:01:14 +0000151
152 /* Also make sure there is never a partial write to one of
153 these registers. That would complicate matters. */
florian428dfdd2012-03-27 03:09:49 +0000154 case S390X_GUEST_OFFSET(guest_IA)+1 ... S390X_GUEST_OFFSET(guest_IA)+7:
155 case S390X_GUEST_OFFSET(guest_CC_OP)+1 ... S390X_GUEST_OFFSET(guest_CC_OP)+7:
156 case S390X_GUEST_OFFSET(guest_CC_DEP1)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP1)+7:
157 case S390X_GUEST_OFFSET(guest_CC_DEP2)+1 ... S390X_GUEST_OFFSET(guest_CC_DEP2)+7:
158 case S390X_GUEST_OFFSET(guest_CC_NDEP)+1 ... S390X_GUEST_OFFSET(guest_CC_NDEP)+7:
florian7d117ba2012-05-06 03:34:55 +0000159 case S390X_GUEST_OFFSET(guest_SYSNO)+1 ... S390X_GUEST_OFFSET(guest_SYSNO)+7:
160 /* counter is used both as 4-byte and as 8-byte entity */
161 case S390X_GUEST_OFFSET(guest_counter)+1 ... S390X_GUEST_OFFSET(guest_counter)+3:
162 case S390X_GUEST_OFFSET(guest_counter)+5 ... S390X_GUEST_OFFSET(guest_counter)+7:
florianaf50a192012-07-13 14:13:06 +0000163 vpanic("partial update of this guest state register is not allowed");
florianad43b3a2012-02-20 15:01:14 +0000164 break;
165
166 default: break;
167 }
168
169 return GUEST_UNKNOWN;
170}
171
sewardj2019a972011-03-07 16:04:07 +0000172/* Add an instruction */
173static void
174addInstr(ISelEnv *env, s390_insn *insn)
175{
176 addHInstr(env->code, insn);
177
178 if (vex_traceflags & VEX_TRACE_VCODE) {
179 vex_printf("%s\n", s390_insn_as_string(insn));
180 }
181}
182
183
184static __inline__ IRExpr *
185mkU64(ULong value)
186{
187 return IRExpr_Const(IRConst_U64(value));
188}
189
190
191/*---------------------------------------------------------*/
192/*--- Registers ---*/
193/*---------------------------------------------------------*/
194
195/* Return the virtual register to which a given IRTemp is mapped. */
196static HReg
197lookupIRTemp(ISelEnv *env, IRTemp tmp)
198{
199 vassert(tmp < env->n_vregmap);
200 vassert(env->vregmap[tmp] != INVALID_HREG);
201
202 return env->vregmap[tmp];
203}
204
205
206/* Return the two virtual registers to which the IRTemp is mapped. */
207static void
208lookupIRTemp128(HReg *hi, HReg *lo, ISelEnv *env, IRTemp tmp)
209{
210 vassert(tmp < env->n_vregmap);
211 vassert(env->vregmapHI[tmp] != INVALID_HREG);
212
213 *lo = env->vregmap[tmp];
214 *hi = env->vregmapHI[tmp];
215}
216
217
218/* Allocate a new integer register */
219static HReg
220newVRegI(ISelEnv *env)
221{
222 HReg reg = mkHReg(env->vreg_ctr, HRcInt64, True /* virtual */ );
223 env->vreg_ctr++;
224
225 return reg;
226}
227
228
229/* Allocate a new floating point register */
230static HReg
231newVRegF(ISelEnv *env)
232{
233 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /* virtual */ );
234
235 env->vreg_ctr++;
236
237 return reg;
238}
239
240
241/* Construct a non-virtual general purpose register */
242static __inline__ HReg
florian297b6062012-05-08 20:16:17 +0000243make_gpr(UInt regno)
sewardj2019a972011-03-07 16:04:07 +0000244{
245 return mkHReg(regno, HRcInt64, False /* virtual */ );
246}
247
248
249/* Construct a non-virtual floating point register */
250static __inline__ HReg
251make_fpr(UInt regno)
252{
253 return mkHReg(regno, HRcFlt64, False /* virtual */ );
254}
255
256
257/*---------------------------------------------------------*/
258/*--- Amode ---*/
259/*---------------------------------------------------------*/
260
261static __inline__ Bool
262ulong_fits_unsigned_12bit(ULong val)
263{
264 return (val & 0xFFFu) == val;
265}
266
267
268static __inline__ Bool
269ulong_fits_signed_20bit(ULong val)
270{
271 Long v = val & 0xFFFFFu;
272
273 v = (v << 44) >> 44; /* sign extend */
274
275 return val == (ULong)v;
276}
277
278
florianad43b3a2012-02-20 15:01:14 +0000279static __inline__ Bool
280ulong_fits_signed_8bit(ULong val)
281{
282 Long v = val & 0xFFu;
283
284 v = (v << 56) >> 56; /* sign extend */
285
286 return val == (ULong)v;
287}
288
sewardj2019a972011-03-07 16:04:07 +0000289/* EXPR is an expression that is used as an address. Return an s390_amode
290 for it. */
291static s390_amode *
292s390_isel_amode_wrk(ISelEnv *env, IRExpr *expr)
293{
294 if (expr->tag == Iex_Binop && expr->Iex.Binop.op == Iop_Add64) {
295 IRExpr *arg1 = expr->Iex.Binop.arg1;
296 IRExpr *arg2 = expr->Iex.Binop.arg2;
297
298 /* Move constant into right subtree */
299 if (arg1->tag == Iex_Const) {
300 IRExpr *tmp;
301 tmp = arg1;
302 arg1 = arg2;
303 arg2 = tmp;
304 }
305
306 /* r + constant: Check for b12 first, then b20 */
307 if (arg2->tag == Iex_Const && arg2->Iex.Const.con->tag == Ico_U64) {
308 ULong value = arg2->Iex.Const.con->Ico.U64;
309
310 if (ulong_fits_unsigned_12bit(value)) {
311 return s390_amode_b12((Int)value, s390_isel_int_expr(env, arg1));
312 }
sewardj652b56a2011-04-13 15:38:17 +0000313 /* If long-displacement is not available, do not construct B20 or
314 BX20 amodes because code generation cannot handle them. */
315 if (s390_host_has_ldisp && ulong_fits_signed_20bit(value)) {
sewardj2019a972011-03-07 16:04:07 +0000316 return s390_amode_b20((Int)value, s390_isel_int_expr(env, arg1));
317 }
318 }
319 }
320
321 /* Doesn't match anything in particular. Generate it into
322 a register and use that. */
323 return s390_amode_b12(0, s390_isel_int_expr(env, expr));
324}
325
326
327static s390_amode *
328s390_isel_amode(ISelEnv *env, IRExpr *expr)
329{
florian35da8612011-06-25 02:25:41 +0000330 s390_amode *am;
sewardj2019a972011-03-07 16:04:07 +0000331
332 /* Address computation should yield a 64-bit value */
333 vassert(typeOfIRExpr(env->type_env, expr) == Ity_I64);
334
335 am = s390_isel_amode_wrk(env, expr);
336
337 /* Check post-condition */
338 vassert(s390_amode_is_sane(am));
339
340 return am;
341}
342
343
344/*---------------------------------------------------------*/
345/*--- Helper functions ---*/
346/*---------------------------------------------------------*/
347
348/* Constants and memory accesses should be right operands */
349#define order_commutative_operands(left, right) \
350 do { \
351 if (left->tag == Iex_Const || left->tag == Iex_Load || \
352 left->tag == Iex_Get) { \
353 IRExpr *tmp; \
354 tmp = left; \
355 left = right; \
356 right = tmp; \
357 } \
358 } while (0)
359
360
361/* Copy an RMI operand to the DST register */
362static s390_insn *
363s390_opnd_copy(UChar size, HReg dst, s390_opnd_RMI opnd)
364{
365 switch (opnd.tag) {
366 case S390_OPND_AMODE:
367 return s390_insn_load(size, dst, opnd.variant.am);
368
369 case S390_OPND_REG:
370 return s390_insn_move(size, dst, opnd.variant.reg);
371
372 case S390_OPND_IMMEDIATE:
373 return s390_insn_load_immediate(size, dst, opnd.variant.imm);
374
375 default:
376 vpanic("s390_opnd_copy");
377 }
378}
379
380
381/* Construct a RMI operand for a register */
382static __inline__ s390_opnd_RMI
383s390_opnd_reg(HReg reg)
384{
385 s390_opnd_RMI opnd;
386
387 opnd.tag = S390_OPND_REG;
388 opnd.variant.reg = reg;
389
390 return opnd;
391}
392
393
394/* Construct a RMI operand for an immediate constant */
395static __inline__ s390_opnd_RMI
396s390_opnd_imm(ULong value)
397{
398 s390_opnd_RMI opnd;
399
400 opnd.tag = S390_OPND_IMMEDIATE;
401 opnd.variant.imm = value;
402
403 return opnd;
404}
405
406
407/* Return 1, if EXPR represents the cosntant 0 */
408static int
409s390_expr_is_const_zero(IRExpr *expr)
410{
411 ULong value;
412
413 if (expr->tag == Iex_Const) {
414 switch (expr->Iex.Const.con->tag) {
415 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
416 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
417 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
418 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
419 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
420 default:
421 vpanic("s390_expr_is_const_zero");
422 }
423 return value == 0;
424 }
425
426 return 0;
427}
428
429
430/* Call a helper (clean or dirty)
431 Arguments must satisfy the following conditions:
floriane0654362012-05-09 13:31:09 +0000432
sewardj2019a972011-03-07 16:04:07 +0000433 (a) they are expressions yielding an integer result
434 (b) there can be no more than S390_NUM_GPRPARMS arguments
floriane0654362012-05-09 13:31:09 +0000435
436 guard is a Ity_Bit expression indicating whether or not the
437 call happens. If guard == NULL, the call is unconditional.
florian52af7bc2012-05-12 03:44:49 +0000438
439 Calling the helper function proceeds as follows:
440
441 (1) The helper arguments are evaluated and their value stored in
442 virtual registers.
443 (2) The condition code is evaluated
444 (3) The argument values are copied from the virtual registers to the
445 registers mandated by the ABI.
446 (4) Call the helper function.
447
448 This is not the most efficient way as step 3 generates register-to-register
449 moves. But it is the least fragile way as the only hidden dependency here
450 is that register-to-register moves (step 3) must not clobber the condition
451 code. Other schemes (e.g. VEX r2326) that attempt to avoid the register-
452 to-register add more such dependencies. Not good. Besides, it's the job
453 of the register allocator to throw out those reg-to-reg moves.
sewardj2019a972011-03-07 16:04:07 +0000454*/
455static void
456doHelperCall(ISelEnv *env, Bool passBBP, IRExpr *guard,
florian01ed6e72012-05-27 16:52:43 +0000457 IRCallee *callee, IRExpr **args, HReg dst)
sewardj2019a972011-03-07 16:04:07 +0000458{
florian52af7bc2012-05-12 03:44:49 +0000459 UInt n_args, i, argreg, size;
sewardj2019a972011-03-07 16:04:07 +0000460 ULong target;
461 HReg tmpregs[S390_NUM_GPRPARMS];
462 s390_cc_t cc;
463
464 n_args = 0;
465 for (i = 0; args[i]; i++)
466 ++n_args;
467
468 if (n_args > (S390_NUM_GPRPARMS - (passBBP ? 1 : 0))) {
469 vpanic("doHelperCall: too many arguments");
470 }
471
florian11b8ee82012-08-06 13:35:33 +0000472 /* All arguments must have Ity_I64. For two reasons:
473 (1) We do not handle floating point arguments.
474 (2) The ABI requires that integer values are sign- or zero-extended
475 to 64 bit.
476 */
477 Int arg_errors = 0;
478 for (i = 0; i < n_args; ++i) {
479 IRType type = typeOfIRExpr(env->type_env, args[i]);
480 if (type != Ity_I64) {
481 ++arg_errors;
482 vex_printf("calling %s: argument #%d has type ", callee->name, i);
483 ppIRType(type);
484 vex_printf("; Ity_I64 is required\n");
485 }
486 }
487
488 if (arg_errors)
489 vpanic("cannot continue due to errors in argument passing");
490
florian52af7bc2012-05-12 03:44:49 +0000491 argreg = 0;
492
493 /* If we need the guest state pointer put it in a temporary arg reg */
494 if (passBBP) {
495 tmpregs[argreg] = newVRegI(env);
496 addInstr(env, s390_insn_move(sizeof(ULong), tmpregs[argreg],
497 s390_hreg_guest_state_pointer()));
498 argreg++;
499 }
500
501 /* Compute the function arguments into a temporary register each */
502 for (i = 0; i < n_args; i++) {
503 tmpregs[argreg] = s390_isel_int_expr(env, args[i]);
504 argreg++;
505 }
506
sewardj2019a972011-03-07 16:04:07 +0000507 /* Compute the condition */
508 cc = S390_CC_ALWAYS;
509 if (guard) {
510 if (guard->tag == Iex_Const
511 && guard->Iex.Const.con->tag == Ico_U1
512 && guard->Iex.Const.con->Ico.U1 == True) {
513 /* unconditional -- do nothing */
514 } else {
515 cc = s390_isel_cc(env, guard);
516 }
517 }
518
florian52af7bc2012-05-12 03:44:49 +0000519 /* Move the args to the final register. It is paramount, that the
520 code to move the registers does not clobber the condition code ! */
floriane0654362012-05-09 13:31:09 +0000521 for (i = 0; i < argreg; i++) {
florian52af7bc2012-05-12 03:44:49 +0000522 HReg finalreg;
523
524 finalreg = make_gpr(s390_gprno_from_arg_index(i));
525 size = sizeofIRType(Ity_I64);
526 addInstr(env, s390_insn_move(size, finalreg, tmpregs[i]));
sewardj2019a972011-03-07 16:04:07 +0000527 }
528
529 target = Ptr_to_ULong(callee->addr);
530
531 /* Finally, the call itself. */
532 addInstr(env, s390_insn_helper_call(cc, (Addr64)target, n_args,
florian01ed6e72012-05-27 16:52:43 +0000533 callee->name, dst));
sewardj2019a972011-03-07 16:04:07 +0000534}
535
536
florian2c74d242012-09-12 19:38:42 +0000537/*---------------------------------------------------------*/
538/*--- BFP helper functions ---*/
539/*---------------------------------------------------------*/
540
541/* Set the BFP rounding mode in the FPC. This function is called for
542 all non-conversion BFP instructions as those will always get the
543 rounding mode from the FPC. */
544static void
545set_bfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
sewardj2019a972011-03-07 16:04:07 +0000546{
florian2c74d242012-09-12 19:38:42 +0000547 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
548
549 /* Do we need to do anything? */
550 if (env->previous_bfp_rounding_mode &&
551 env->previous_bfp_rounding_mode->tag == Iex_RdTmp &&
552 irrm->tag == Iex_RdTmp &&
553 env->previous_bfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
554 /* No - new mode is identical to previous mode. */
555 return;
556 }
557
558 /* No luck - we better set it, and remember what we set it to. */
559 env->previous_bfp_rounding_mode = irrm;
560
561 /* The incoming rounding mode is in VEX IR encoding. Need to change
562 to s390.
563
564 rounding mode | s390 | IR
565 -------------------------
566 to nearest | 00 | 00
567 to zero | 01 | 11
568 to +infinity | 10 | 10
569 to -infinity | 11 | 01
570
571 So: s390 = (4 - IR) & 3
572 */
573 HReg ir = s390_isel_int_expr(env, irrm);
574
575 HReg mode = newVRegI(env);
576
577 addInstr(env, s390_insn_load_immediate(4, mode, 4));
578 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, mode, s390_opnd_reg(ir)));
579 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(3)));
580
florian125e20d2012-10-07 15:42:37 +0000581 addInstr(env, s390_insn_set_fpc_bfprm(4, mode));
florian2c74d242012-09-12 19:38:42 +0000582}
583
584
585/* This function is invoked for insns that support a specification of
586 a rounding mode in the insn itself. In that case there is no need to
587 stick the rounding mode into the FPC -- a good thing. However, the
588 rounding mode must be known. */
florian125e20d2012-10-07 15:42:37 +0000589static s390_bfp_round_t
florian2c74d242012-09-12 19:38:42 +0000590get_bfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
591{
592 if (irrm->tag == Iex_Const) { /* rounding mode is known */
593 vassert(irrm->Iex.Const.con->tag == Ico_U32);
594 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
sewardj2019a972011-03-07 16:04:07 +0000595
596 switch (mode) {
florian125e20d2012-10-07 15:42:37 +0000597 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
598 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
599 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
600 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
florian2c74d242012-09-12 19:38:42 +0000601 default:
602 vpanic("get_bfp_rounding_mode");
sewardj2019a972011-03-07 16:04:07 +0000603 }
604 }
605
florian2c74d242012-09-12 19:38:42 +0000606 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +0000607 return S390_BFP_ROUND_PER_FPC;
sewardj2019a972011-03-07 16:04:07 +0000608}
609
610
florianc8e4f562012-10-27 16:19:31 +0000611/*---------------------------------------------------------*/
612/*--- DFP helper functions ---*/
613/*---------------------------------------------------------*/
614
615/* Set the DFP rounding mode in the FPC. This function is called for
616 all non-conversion DFP instructions as those will always get the
617 rounding mode from the FPC. */
618#if 0 // fixs390: avoid compiler warnings about unused function
619static void
620set_dfp_rounding_mode_in_fpc(ISelEnv *env, IRExpr *irrm)
621{
622 vassert(typeOfIRExpr(env->type_env, irrm) == Ity_I32);
623
624 /* Do we need to do anything? */
625 if (env->previous_dfp_rounding_mode &&
626 env->previous_dfp_rounding_mode->tag == Iex_RdTmp &&
627 irrm->tag == Iex_RdTmp &&
628 env->previous_dfp_rounding_mode->Iex.RdTmp.tmp == irrm->Iex.RdTmp.tmp) {
629 /* No - new mode is identical to previous mode. */
630 return;
631 }
632
633 /* No luck - we better set it, and remember what we set it to. */
634 env->previous_dfp_rounding_mode = irrm;
635
636 /* The incoming rounding mode is in VEX IR encoding. Need to change
637 to s390.
638
639 rounding mode | S390 | IR
640 -----------------------------------------------
641 to nearest, ties to even | 000 | 000
642 to zero | 001 | 011
643 to +infinity | 010 | 010
644 to -infinity | 011 | 001
645 to nearest, ties away from 0 | 100 | 100
646 to nearest, ties toward 0 | 101 | 111
647 to away from 0 | 110 | 110
648 to prepare for shorter precision | 111 | 101
649
650 So: s390 = (IR ^ ((IR << 1) & 2))
651 */
652 HReg ir = s390_isel_int_expr(env, irrm);
653
654 HReg mode = newVRegI(env);
655
656 addInstr(env, s390_insn_move(4, mode, ir));
657 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, mode, s390_opnd_imm(1)));
658 addInstr(env, s390_insn_alu(4, S390_ALU_AND, mode, s390_opnd_imm(2)));
659 addInstr(env, s390_insn_alu(4, S390_ALU_XOR, mode, s390_opnd_reg(ir)));
660
661 addInstr(env, s390_insn_set_fpc_dfprm(4, mode));
662}
663
664
665/* This function is invoked for insns that support a specification of
666 a rounding mode in the insn itself. In that case there is no need to
667 stick the rounding mode into the FPC -- a good thing. However, the
668 rounding mode must be known.
669 The IR to s390 encoding is chosen in the range 0:7 except
670 S390_DFP_ROUND_NEAREST_TIE_TOWARD_0 and
671 S390_DFP_ROUND_AWAY_0 which have no choice within the range.
672 Since the s390 dfp rounding mode encoding in 8:15 is not used, the
673 quantum excpetion is not suppressed and this is fine as valgrind does
674 not model this exception.
675
676 Translation table of
677 s390 DFP rounding mode to IRRoundingMode to s390 DFP rounding mode
678
679 s390(S390_DFP_ROUND_) | IR(Irrm_DFP_) | s390(S390_DFP_ROUND_)
680 --------------------------------------------------------------------
681 NEAREST_TIE_AWAY_0_1 | NEAREST_TIE_AWAY_0 | NEAREST_TIE_AWAY_0_1
682 NEAREST_TIE_AWAY_0_12 | " | "
683 PREPARE_SHORT_3 | PREPARE_SHORTER | PREPARE_SHORT_3
684 PREPARE_SHORT_15 | " | "
685 NEAREST_EVEN_4 | NEAREST | NEAREST_EVEN_4
686 NEAREST_EVEN_8 | " | "
687 ZERO_5 | ZERO | ZERO_5
688 ZERO_9 | " | "
689 POSINF_6 | PosINF | POSINF_6
690 POSINF_10 | " | "
691 NEGINF_7 | NegINF | NEGINF_7
692 NEGINF_11 | " | "
693 NEAREST_TIE_TOWARD_0 | NEAREST_TIE_TOWARD_0| NEAREST_TIE_TOWARD_0
694 AWAY_0 | AWAY_FROM_ZERO | AWAY_0
695*/
696static s390_dfp_round_t
697get_dfp_rounding_mode(ISelEnv *env, IRExpr *irrm)
698{
699 if (irrm->tag == Iex_Const) { /* rounding mode is known */
700 vassert(irrm->Iex.Const.con->tag == Ico_U32);
701 IRRoundingMode mode = irrm->Iex.Const.con->Ico.U32;
702
703 switch (mode) {
704 case Irrm_DFP_NEAREST:
705 return S390_DFP_ROUND_NEAREST_EVEN_4;
706 case Irrm_DFP_NegINF:
707 return S390_DFP_ROUND_NEGINF_7;
708 case Irrm_DFP_PosINF:
709 return S390_DFP_ROUND_POSINF_6;
710 case Irrm_DFP_ZERO:
711 return S390_DFP_ROUND_ZERO_5;
712 case Irrm_DFP_NEAREST_TIE_AWAY_0:
713 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1;
714 case Irrm_DFP_PREPARE_SHORTER:
715 return S390_DFP_ROUND_PREPARE_SHORT_3;
716 case Irrm_DFP_AWAY_FROM_ZERO:
717 return S390_DFP_ROUND_AWAY_0;
718 case Irrm_DFP_NEAREST_TIE_TOWARD_0:
719 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
720 default:
721 vpanic("get_dfp_rounding_mode");
722 }
723 }
724
725 set_dfp_rounding_mode_in_fpc(env, irrm);
726 return S390_DFP_ROUND_PER_FPC_0;
727}
728#endif
729
sewardj2019a972011-03-07 16:04:07 +0000730/* CC_S390 holds the condition code in s390 encoding. Convert it to
731 VEX encoding
732
733 s390 VEX b6 b2 b0 cc.1 cc.0
734 0 0x40 EQ 1 0 0 0 0
735 1 0x01 LT 0 0 1 0 1
736 2 0x00 GT 0 0 0 1 0
737 3 0x45 Unordered 1 1 1 1 1
738
739 b0 = cc.0
740 b2 = cc.0 & cc.1
741 b6 = ~(cc.0 ^ cc.1) // ((cc.0 - cc.1) + 0x1 ) & 0x1
742
743 VEX = b0 | (b2 << 2) | (b6 << 6);
744*/
745static HReg
746convert_s390_fpcc_to_vex(ISelEnv *env, HReg cc_s390)
747{
748 HReg cc0, cc1, b2, b6, cc_vex;
749
750 cc0 = newVRegI(env);
751 addInstr(env, s390_insn_move(4, cc0, cc_s390));
752 addInstr(env, s390_insn_alu(4, S390_ALU_AND, cc0, s390_opnd_imm(1)));
753
754 cc1 = newVRegI(env);
755 addInstr(env, s390_insn_move(4, cc1, cc_s390));
756 addInstr(env, s390_insn_alu(4, S390_ALU_RSH, cc1, s390_opnd_imm(1)));
757
758 b2 = newVRegI(env);
759 addInstr(env, s390_insn_move(4, b2, cc0));
760 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b2, s390_opnd_reg(cc1)));
761 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b2, s390_opnd_imm(2)));
762
763 b6 = newVRegI(env);
764 addInstr(env, s390_insn_move(4, b6, cc0));
765 addInstr(env, s390_insn_alu(4, S390_ALU_SUB, b6, s390_opnd_reg(cc1)));
766 addInstr(env, s390_insn_alu(4, S390_ALU_ADD, b6, s390_opnd_imm(1)));
767 addInstr(env, s390_insn_alu(4, S390_ALU_AND, b6, s390_opnd_imm(1)));
768 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, b6, s390_opnd_imm(6)));
769
770 cc_vex = newVRegI(env);
771 addInstr(env, s390_insn_move(4, cc_vex, cc0));
772 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b2)));
773 addInstr(env, s390_insn_alu(4, S390_ALU_OR, cc_vex, s390_opnd_reg(b6)));
774
775 return cc_vex;
776}
777
778
779/*---------------------------------------------------------*/
780/*--- ISEL: Integer expressions (128 bit) ---*/
781/*---------------------------------------------------------*/
782static void
783s390_isel_int128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
784 IRExpr *expr)
785{
786 IRType ty = typeOfIRExpr(env->type_env, expr);
787
788 vassert(ty == Ity_I128);
789
790 /* No need to consider the following
791 - 128-bit constants (they do not exist in VEX)
792 - 128-bit loads from memory (will not be generated)
793 */
794
795 /* Read 128-bit IRTemp */
796 if (expr->tag == Iex_RdTmp) {
797 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
798 return;
799 }
800
801 if (expr->tag == Iex_Binop) {
802 IRExpr *arg1 = expr->Iex.Binop.arg1;
803 IRExpr *arg2 = expr->Iex.Binop.arg2;
804 Bool is_signed_multiply, is_signed_divide;
805
806 switch (expr->Iex.Binop.op) {
807 case Iop_MullU64:
808 is_signed_multiply = False;
809 goto do_multiply64;
810
811 case Iop_MullS64:
812 is_signed_multiply = True;
813 goto do_multiply64;
814
815 case Iop_DivModU128to64:
816 is_signed_divide = False;
817 goto do_divide64;
818
819 case Iop_DivModS128to64:
820 is_signed_divide = True;
821 goto do_divide64;
822
823 case Iop_64HLto128:
824 *dst_hi = s390_isel_int_expr(env, arg1);
825 *dst_lo = s390_isel_int_expr(env, arg2);
826 return;
827
828 case Iop_DivModS64to64: {
829 HReg r10, r11, h1;
830 s390_opnd_RMI op2;
831
832 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
833 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
834
835 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000836 r10 = make_gpr(10);
837 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000838
839 /* Move 1st operand into r11 and */
840 addInstr(env, s390_insn_move(8, r11, h1));
841
842 /* Divide */
843 addInstr(env, s390_insn_divs(8, r10, r11, op2));
844
845 /* The result is in registers r10 (remainder) and r11 (quotient).
846 Move the result into the reg pair that is being returned such
847 such that the low 64 bits are the quotient and the upper 64 bits
848 are the remainder. (see libvex_ir.h). */
849 *dst_hi = newVRegI(env);
850 *dst_lo = newVRegI(env);
851 addInstr(env, s390_insn_move(8, *dst_hi, r10));
852 addInstr(env, s390_insn_move(8, *dst_lo, r11));
853 return;
854 }
855
856 default:
857 break;
858
859 do_multiply64: {
860 HReg r10, r11, h1;
861 s390_opnd_RMI op2;
862
863 order_commutative_operands(arg1, arg2);
864
865 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
866 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
867
868 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000869 r10 = make_gpr(10);
870 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000871
872 /* Move the first operand to r11 */
873 addInstr(env, s390_insn_move(8, r11, h1));
874
875 /* Multiply */
876 addInstr(env, s390_insn_mul(8, r10, r11, op2, is_signed_multiply));
877
878 /* The result is in registers r10 and r11. Assign to two virtual regs
879 and return. */
880 *dst_hi = newVRegI(env);
881 *dst_lo = newVRegI(env);
882 addInstr(env, s390_insn_move(8, *dst_hi, r10));
883 addInstr(env, s390_insn_move(8, *dst_lo, r11));
884 return;
885 }
886
887 do_divide64: {
888 HReg r10, r11, hi, lo;
889 s390_opnd_RMI op2;
890
891 s390_isel_int128_expr(&hi, &lo, env, arg1);
892 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
893
894 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +0000895 r10 = make_gpr(10);
896 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +0000897
898 /* Move high 64 bits of the 1st operand into r10 and
899 the low 64 bits into r11. */
900 addInstr(env, s390_insn_move(8, r10, hi));
901 addInstr(env, s390_insn_move(8, r11, lo));
902
903 /* Divide */
904 addInstr(env, s390_insn_div(8, r10, r11, op2, is_signed_divide));
905
906 /* The result is in registers r10 (remainder) and r11 (quotient).
907 Move the result into the reg pair that is being returned such
908 such that the low 64 bits are the quotient and the upper 64 bits
909 are the remainder. (see libvex_ir.h). */
910 *dst_hi = newVRegI(env);
911 *dst_lo = newVRegI(env);
912 addInstr(env, s390_insn_move(8, *dst_hi, r10));
913 addInstr(env, s390_insn_move(8, *dst_lo, r11));
914 return;
915 }
916 }
917 }
918
919 vpanic("s390_isel_int128_expr");
920}
921
922
923/* Compute a 128-bit value into two 64-bit registers. These may be either
924 real or virtual regs; in any case they must not be changed by subsequent
925 code emitted by the caller. */
926static void
927s390_isel_int128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
928{
929 s390_isel_int128_expr_wrk(dst_hi, dst_lo, env, expr);
930
931 /* Sanity checks ... */
932 vassert(hregIsVirtual(*dst_hi));
933 vassert(hregIsVirtual(*dst_lo));
934 vassert(hregClass(*dst_hi) == HRcInt64);
935 vassert(hregClass(*dst_lo) == HRcInt64);
936}
937
938
939/*---------------------------------------------------------*/
940/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
941/*---------------------------------------------------------*/
942
943/* Select insns for an integer-typed expression, and add them to the
944 code list. Return a reg holding the result. This reg will be a
945 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
946 want to modify it, ask for a new vreg, copy it in there, and modify
947 the copy. The register allocator will do its best to map both
948 vregs to the same real register, so the copies will often disappear
949 later in the game.
950
951 This should handle expressions of 64, 32, 16 and 8-bit type.
952 All results are returned in a 64bit register.
953 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
954 are arbitrary, so you should mask or sign extend partial values
955 if necessary.
956*/
957
958/* DO NOT CALL THIS DIRECTLY ! */
959static HReg
960s390_isel_int_expr_wrk(ISelEnv *env, IRExpr *expr)
961{
962 IRType ty = typeOfIRExpr(env->type_env, expr);
963 UChar size;
florian9fcff4c2012-09-10 03:09:04 +0000964 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +0000965
966 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
967
968 size = sizeofIRType(ty); /* size of the result after evaluating EXPR */
969
970 switch (expr->tag) {
971
972 /* --------- TEMP --------- */
973 case Iex_RdTmp:
974 /* Return the virtual register that holds the temporary. */
975 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
976
977 /* --------- LOAD --------- */
978 case Iex_Load: {
979 HReg dst = newVRegI(env);
980 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
981
982 if (expr->Iex.Load.end != Iend_BE)
983 goto irreducible;
984
985 addInstr(env, s390_insn_load(size, dst, am));
986
987 return dst;
988 }
989
990 /* --------- BINARY OP --------- */
991 case Iex_Binop: {
992 IRExpr *arg1 = expr->Iex.Binop.arg1;
993 IRExpr *arg2 = expr->Iex.Binop.arg2;
994 HReg h1, res;
995 s390_alu_t opkind;
996 s390_opnd_RMI op2, value, opnd;
997 s390_insn *insn;
998 Bool is_commutative, is_signed_multiply, is_signed_divide;
999
1000 is_commutative = True;
1001
1002 switch (expr->Iex.Binop.op) {
1003 case Iop_MullU8:
1004 case Iop_MullU16:
1005 case Iop_MullU32:
1006 is_signed_multiply = False;
1007 goto do_multiply;
1008
1009 case Iop_MullS8:
1010 case Iop_MullS16:
1011 case Iop_MullS32:
1012 is_signed_multiply = True;
1013 goto do_multiply;
1014
1015 do_multiply: {
1016 HReg r10, r11;
1017 UInt arg_size = size / 2;
1018
1019 order_commutative_operands(arg1, arg2);
1020
1021 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1022 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1023
1024 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001025 r10 = make_gpr(10);
1026 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001027
1028 /* Move the first operand to r11 */
1029 addInstr(env, s390_insn_move(arg_size, r11, h1));
1030
1031 /* Multiply */
1032 addInstr(env, s390_insn_mul(arg_size, r10, r11, op2, is_signed_multiply));
1033
1034 /* The result is in registers r10 and r11. Combine them into a SIZE-bit
1035 value into the destination register. */
1036 res = newVRegI(env);
1037 addInstr(env, s390_insn_move(arg_size, res, r10));
1038 value = s390_opnd_imm(arg_size * 8);
1039 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1040 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1041 addInstr(env, s390_insn_alu(size, S390_ALU_AND, r11, value));
1042 opnd = s390_opnd_reg(r11);
1043 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1044 return res;
1045 }
1046
1047 case Iop_DivModS64to32:
1048 is_signed_divide = True;
1049 goto do_divide;
1050
1051 case Iop_DivModU64to32:
1052 is_signed_divide = False;
1053 goto do_divide;
1054
1055 do_divide: {
1056 HReg r10, r11;
1057
1058 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1059 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1060
1061 /* We use non-virtual registers r10 and r11 as pair */
florian297b6062012-05-08 20:16:17 +00001062 r10 = make_gpr(10);
1063 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001064
1065 /* Split the first operand and put the high 32 bits into r10 and
1066 the low 32 bits into r11. */
1067 addInstr(env, s390_insn_move(8, r10, h1));
1068 addInstr(env, s390_insn_move(8, r11, h1));
1069 value = s390_opnd_imm(32);
1070 addInstr(env, s390_insn_alu(8, S390_ALU_RSH, r10, value));
1071
1072 /* Divide */
1073 addInstr(env, s390_insn_div(4, r10, r11, op2, is_signed_divide));
1074
1075 /* The result is in registers r10 (remainder) and r11 (quotient).
1076 Combine them into a 64-bit value such that the low 32 bits are
1077 the quotient and the upper 32 bits are the remainder. (see
1078 libvex_ir.h). */
1079 res = newVRegI(env);
1080 addInstr(env, s390_insn_move(8, res, r10));
1081 value = s390_opnd_imm(32);
1082 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, res, value));
1083 value = s390_opnd_imm((((ULong)1) << 32) - 1);
1084 addInstr(env, s390_insn_alu(8, S390_ALU_AND, r11, value));
1085 opnd = s390_opnd_reg(r11);
1086 addInstr(env, s390_insn_alu(8, S390_ALU_OR, res, opnd));
1087 return res;
1088 }
1089
florian9fcff4c2012-09-10 03:09:04 +00001090 case Iop_F32toI32S: conv = S390_BFP_F32_TO_I32; goto do_convert;
1091 case Iop_F32toI64S: conv = S390_BFP_F32_TO_I64; goto do_convert;
1092 case Iop_F32toI32U: conv = S390_BFP_F32_TO_U32; goto do_convert;
1093 case Iop_F32toI64U: conv = S390_BFP_F32_TO_U64; goto do_convert;
1094 case Iop_F64toI32S: conv = S390_BFP_F64_TO_I32; goto do_convert;
1095 case Iop_F64toI64S: conv = S390_BFP_F64_TO_I64; goto do_convert;
1096 case Iop_F64toI32U: conv = S390_BFP_F64_TO_U32; goto do_convert;
1097 case Iop_F64toI64U: conv = S390_BFP_F64_TO_U64; goto do_convert;
1098 case Iop_F128toI32S: conv = S390_BFP_F128_TO_I32; goto do_convert_128;
1099 case Iop_F128toI64S: conv = S390_BFP_F128_TO_I64; goto do_convert_128;
1100 case Iop_F128toI32U: conv = S390_BFP_F128_TO_U32; goto do_convert_128;
1101 case Iop_F128toI64U: conv = S390_BFP_F128_TO_U64; goto do_convert_128;
sewardj2019a972011-03-07 16:04:07 +00001102
1103 do_convert: {
florian125e20d2012-10-07 15:42:37 +00001104 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001105
1106 res = newVRegI(env);
1107 h1 = s390_isel_float_expr(env, arg2); /* Process operand */
1108
florian2c74d242012-09-12 19:38:42 +00001109 rounding_mode = get_bfp_rounding_mode(env, arg1);
1110 addInstr(env, s390_insn_bfp_convert(size, conv, res, h1,
1111 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00001112 return res;
1113 }
1114
1115 do_convert_128: {
florian125e20d2012-10-07 15:42:37 +00001116 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00001117 HReg op_hi, op_lo, f13, f15;
1118
1119 res = newVRegI(env);
1120 s390_isel_float128_expr(&op_hi, &op_lo, env, arg2); /* operand */
1121
1122 /* We use non-virtual registers r13 and r15 as pair */
1123 f13 = make_fpr(13);
1124 f15 = make_fpr(15);
1125
1126 /* operand --> (f13, f15) */
1127 addInstr(env, s390_insn_move(8, f13, op_hi));
1128 addInstr(env, s390_insn_move(8, f15, op_lo));
1129
florian2c74d242012-09-12 19:38:42 +00001130 rounding_mode = get_bfp_rounding_mode(env, arg1);
florian9fcff4c2012-09-10 03:09:04 +00001131 addInstr(env, s390_insn_bfp128_convert_from(size, conv, res, f13, f15,
sewardj2019a972011-03-07 16:04:07 +00001132 rounding_mode));
1133 return res;
1134 }
1135
1136 case Iop_8HLto16:
1137 case Iop_16HLto32:
1138 case Iop_32HLto64: {
1139 HReg h2;
1140 UInt arg_size = size / 2;
1141
1142 res = newVRegI(env);
1143 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1144 h2 = s390_isel_int_expr(env, arg2); /* Process 2nd operand */
1145
1146 addInstr(env, s390_insn_move(arg_size, res, h1));
1147 value = s390_opnd_imm(arg_size * 8);
1148 addInstr(env, s390_insn_alu(size, S390_ALU_LSH, res, value));
1149 value = s390_opnd_imm((((ULong)1) << arg_size * 8) - 1);
1150 addInstr(env, s390_insn_alu(size, S390_ALU_AND, h2, value));
1151 opnd = s390_opnd_reg(h2);
1152 addInstr(env, s390_insn_alu(size, S390_ALU_OR, res, opnd));
1153 return res;
1154 }
1155
1156 case Iop_Max32U: {
1157 /* arg1 > arg2 ? arg1 : arg2 using uint32_t arguments */
1158 res = newVRegI(env);
1159 h1 = s390_isel_int_expr(env, arg1);
1160 op2 = s390_isel_int_expr_RMI(env, arg2);
1161
1162 addInstr(env, s390_insn_move(size, res, h1));
1163 addInstr(env, s390_insn_compare(size, res, op2, False /* signed */));
1164 addInstr(env, s390_insn_cond_move(size, S390_CC_L, res, op2));
1165 return res;
1166 }
1167
1168 case Iop_CmpF32:
1169 case Iop_CmpF64: {
1170 HReg cc_s390, h2;
1171
1172 h1 = s390_isel_float_expr(env, arg1);
1173 h2 = s390_isel_float_expr(env, arg2);
1174 cc_s390 = newVRegI(env);
1175
1176 size = (expr->Iex.Binop.op == Iop_CmpF32) ? 4 : 8;
1177
1178 addInstr(env, s390_insn_bfp_compare(size, cc_s390, h1, h2));
1179
1180 return convert_s390_fpcc_to_vex(env, cc_s390);
1181 }
1182
1183 case Iop_CmpF128: {
1184 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15, cc_s390;
1185
1186 s390_isel_float128_expr(&op1_hi, &op1_lo, env, arg1); /* 1st operand */
1187 s390_isel_float128_expr(&op2_hi, &op2_lo, env, arg2); /* 2nd operand */
1188 cc_s390 = newVRegI(env);
1189
1190 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1191 f12 = make_fpr(12);
1192 f13 = make_fpr(13);
1193 f14 = make_fpr(14);
1194 f15 = make_fpr(15);
1195
1196 /* 1st operand --> (f12, f14) */
1197 addInstr(env, s390_insn_move(8, f12, op1_hi));
1198 addInstr(env, s390_insn_move(8, f14, op1_lo));
1199
1200 /* 2nd operand --> (f13, f15) */
1201 addInstr(env, s390_insn_move(8, f13, op2_hi));
1202 addInstr(env, s390_insn_move(8, f15, op2_lo));
1203
1204 res = newVRegI(env);
1205 addInstr(env, s390_insn_bfp128_compare(16, cc_s390, f12, f14, f13, f15));
1206
1207 return convert_s390_fpcc_to_vex(env, cc_s390);
1208 }
1209
1210 case Iop_Add8:
1211 case Iop_Add16:
1212 case Iop_Add32:
1213 case Iop_Add64:
1214 opkind = S390_ALU_ADD;
1215 break;
1216
1217 case Iop_Sub8:
1218 case Iop_Sub16:
1219 case Iop_Sub32:
1220 case Iop_Sub64:
1221 opkind = S390_ALU_SUB;
1222 is_commutative = False;
1223 break;
1224
1225 case Iop_And8:
1226 case Iop_And16:
1227 case Iop_And32:
1228 case Iop_And64:
1229 opkind = S390_ALU_AND;
1230 break;
1231
1232 case Iop_Or8:
1233 case Iop_Or16:
1234 case Iop_Or32:
1235 case Iop_Or64:
1236 opkind = S390_ALU_OR;
1237 break;
1238
1239 case Iop_Xor8:
1240 case Iop_Xor16:
1241 case Iop_Xor32:
1242 case Iop_Xor64:
1243 opkind = S390_ALU_XOR;
1244 break;
1245
1246 case Iop_Shl8:
1247 case Iop_Shl16:
1248 case Iop_Shl32:
1249 case Iop_Shl64:
1250 opkind = S390_ALU_LSH;
1251 is_commutative = False;
1252 break;
1253
1254 case Iop_Shr8:
1255 case Iop_Shr16:
1256 case Iop_Shr32:
1257 case Iop_Shr64:
1258 opkind = S390_ALU_RSH;
1259 is_commutative = False;
1260 break;
1261
1262 case Iop_Sar8:
1263 case Iop_Sar16:
1264 case Iop_Sar32:
1265 case Iop_Sar64:
1266 opkind = S390_ALU_RSHA;
1267 is_commutative = False;
1268 break;
1269
1270 default:
1271 goto irreducible;
1272 }
1273
1274 /* Pattern match: 0 - arg1 --> -arg1 */
1275 if (opkind == S390_ALU_SUB && s390_expr_is_const_zero(arg1)) {
1276 res = newVRegI(env);
1277 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1278 insn = s390_insn_unop(size, S390_NEGATE, res, op2);
1279 addInstr(env, insn);
1280
1281 return res;
1282 }
1283
1284 if (is_commutative) {
1285 order_commutative_operands(arg1, arg2);
1286 }
1287
1288 h1 = s390_isel_int_expr(env, arg1); /* Process 1st operand */
1289 op2 = s390_isel_int_expr_RMI(env, arg2); /* Process 2nd operand */
1290 res = newVRegI(env);
florian5e0f2042012-08-20 13:44:29 +00001291
1292 /* As right shifts of one/two byte opreands are implemented using a
1293 4-byte shift op, we first need to zero/sign-extend the shiftee. */
1294 switch (expr->Iex.Binop.op) {
1295 case Iop_Shr8:
1296 insn = s390_insn_unop(4, S390_ZERO_EXTEND_8, res, s390_opnd_reg(h1));
1297 break;
1298 case Iop_Shr16:
1299 insn = s390_insn_unop(4, S390_ZERO_EXTEND_16, res, s390_opnd_reg(h1));
1300 break;
1301 case Iop_Sar8:
1302 insn = s390_insn_unop(4, S390_SIGN_EXTEND_8, res, s390_opnd_reg(h1));
1303 break;
1304 case Iop_Sar16:
1305 insn = s390_insn_unop(4, S390_SIGN_EXTEND_16, res, s390_opnd_reg(h1));
1306 break;
1307 default:
1308 insn = s390_insn_move(size, res, h1);
1309 break;
1310 }
1311 addInstr(env, insn);
1312
sewardj2019a972011-03-07 16:04:07 +00001313 insn = s390_insn_alu(size, opkind, res, op2);
1314
1315 addInstr(env, insn);
1316
1317 return res;
1318 }
1319
1320 /* --------- UNARY OP --------- */
1321 case Iex_Unop: {
1322 static s390_opnd_RMI mask = { S390_OPND_IMMEDIATE };
1323 static s390_opnd_RMI shift = { S390_OPND_IMMEDIATE };
1324 s390_opnd_RMI opnd;
1325 s390_insn *insn;
1326 IRExpr *arg;
1327 HReg dst, h1;
1328 IROp unop, binop;
1329
1330 arg = expr->Iex.Unop.arg;
1331
1332 /* Special cases are handled here */
1333
1334 /* 32-bit multiply with 32-bit result or
1335 64-bit multiply with 64-bit result */
1336 unop = expr->Iex.Unop.op;
1337 binop = arg->Iex.Binop.op;
1338
1339 if ((arg->tag == Iex_Binop &&
1340 ((unop == Iop_64to32 &&
1341 (binop == Iop_MullS32 || binop == Iop_MullU32)) ||
1342 (unop == Iop_128to64 &&
1343 (binop == Iop_MullS64 || binop == Iop_MullU64))))) {
1344 h1 = s390_isel_int_expr(env, arg->Iex.Binop.arg1); /* 1st opnd */
1345 opnd = s390_isel_int_expr_RMI(env, arg->Iex.Binop.arg2); /* 2nd opnd */
1346 dst = newVRegI(env); /* Result goes into a new register */
1347 addInstr(env, s390_insn_move(size, dst, h1));
1348 addInstr(env, s390_insn_alu(size, S390_ALU_MUL, dst, opnd));
1349
1350 return dst;
1351 }
1352
florian4d71a082011-12-18 00:08:17 +00001353 if (unop == Iop_ReinterpF64asI64 || unop == Iop_ReinterpF32asI32) {
sewardj2019a972011-03-07 16:04:07 +00001354 dst = newVRegI(env);
1355 h1 = s390_isel_float_expr(env, arg); /* Process the operand */
1356 addInstr(env, s390_insn_move(size, dst, h1));
1357
1358 return dst;
1359 }
1360
1361 /* Expressions whose argument is 1-bit wide */
1362 if (typeOfIRExpr(env->type_env, arg) == Ity_I1) {
1363 s390_cc_t cond = s390_isel_cc(env, arg);
1364 dst = newVRegI(env); /* Result goes into a new register */
1365 addInstr(env, s390_insn_cc2bool(dst, cond));
1366
1367 switch (unop) {
1368 case Iop_1Uto8:
1369 case Iop_1Uto32:
florian5f27dcf2012-08-04 04:25:30 +00001370 /* Zero extend */
1371 mask.variant.imm = 1;
1372 addInstr(env, s390_insn_alu(4, S390_ALU_AND, dst, mask));
1373 break;
1374
sewardj2019a972011-03-07 16:04:07 +00001375 case Iop_1Uto64:
florian5f27dcf2012-08-04 04:25:30 +00001376 /* Zero extend */
1377 mask.variant.imm = 1;
1378 addInstr(env, s390_insn_alu(8, S390_ALU_AND, dst, mask));
sewardj2019a972011-03-07 16:04:07 +00001379 break;
1380
1381 case Iop_1Sto8:
1382 case Iop_1Sto16:
1383 case Iop_1Sto32:
1384 shift.variant.imm = 31;
1385 addInstr(env, s390_insn_alu(4, S390_ALU_LSH, dst, shift));
1386 addInstr(env, s390_insn_alu(4, S390_ALU_RSHA, dst, shift));
1387 break;
1388
1389 case Iop_1Sto64:
1390 shift.variant.imm = 63;
1391 addInstr(env, s390_insn_alu(8, S390_ALU_LSH, dst, shift));
1392 addInstr(env, s390_insn_alu(8, S390_ALU_RSHA, dst, shift));
1393 break;
1394
1395 default:
1396 goto irreducible;
1397 }
1398
1399 return dst;
1400 }
1401
1402 /* Regular processing */
1403
1404 if (unop == Iop_128to64) {
1405 HReg dst_hi, dst_lo;
1406
1407 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1408 return dst_lo;
1409 }
1410
1411 if (unop == Iop_128HIto64) {
1412 HReg dst_hi, dst_lo;
1413
1414 s390_isel_int128_expr(&dst_hi, &dst_lo, env, arg);
1415 return dst_hi;
1416 }
1417
1418 dst = newVRegI(env); /* Result goes into a new register */
1419 opnd = s390_isel_int_expr_RMI(env, arg); /* Process the operand */
1420
1421 switch (unop) {
1422 case Iop_8Uto16:
1423 case Iop_8Uto32:
1424 case Iop_8Uto64:
1425 insn = s390_insn_unop(size, S390_ZERO_EXTEND_8, dst, opnd);
1426 break;
1427
1428 case Iop_16Uto32:
1429 case Iop_16Uto64:
1430 insn = s390_insn_unop(size, S390_ZERO_EXTEND_16, dst, opnd);
1431 break;
1432
1433 case Iop_32Uto64:
1434 insn = s390_insn_unop(size, S390_ZERO_EXTEND_32, dst, opnd);
1435 break;
1436
1437 case Iop_8Sto16:
1438 case Iop_8Sto32:
1439 case Iop_8Sto64:
1440 insn = s390_insn_unop(size, S390_SIGN_EXTEND_8, dst, opnd);
1441 break;
1442
1443 case Iop_16Sto32:
1444 case Iop_16Sto64:
1445 insn = s390_insn_unop(size, S390_SIGN_EXTEND_16, dst, opnd);
1446 break;
1447
1448 case Iop_32Sto64:
1449 insn = s390_insn_unop(size, S390_SIGN_EXTEND_32, dst, opnd);
1450 break;
1451
1452 case Iop_64to8:
1453 case Iop_64to16:
1454 case Iop_64to32:
1455 case Iop_32to8:
1456 case Iop_32to16:
1457 case Iop_16to8:
1458 /* Down-casts are no-ops. Upstream operations will only look at
1459 the bytes that make up the result of the down-cast. So there
1460 is no point setting the other bytes to 0. */
1461 insn = s390_opnd_copy(8, dst, opnd);
1462 break;
1463
1464 case Iop_64HIto32:
1465 addInstr(env, s390_opnd_copy(8, dst, opnd));
1466 shift.variant.imm = 32;
1467 insn = s390_insn_alu(8, S390_ALU_RSH, dst, shift);
1468 break;
1469
1470 case Iop_32HIto16:
1471 addInstr(env, s390_opnd_copy(4, dst, opnd));
1472 shift.variant.imm = 16;
1473 insn = s390_insn_alu(4, S390_ALU_RSH, dst, shift);
1474 break;
1475
1476 case Iop_16HIto8:
1477 addInstr(env, s390_opnd_copy(2, dst, opnd));
1478 shift.variant.imm = 8;
1479 insn = s390_insn_alu(2, S390_ALU_RSH, dst, shift);
1480 break;
1481
1482 case Iop_Not8:
1483 case Iop_Not16:
1484 case Iop_Not32:
1485 case Iop_Not64:
1486 /* XOR with ffff... */
1487 mask.variant.imm = ~(ULong)0;
1488 addInstr(env, s390_opnd_copy(size, dst, opnd));
1489 insn = s390_insn_alu(size, S390_ALU_XOR, dst, mask);
1490 break;
1491
1492 case Iop_Left8:
1493 case Iop_Left16:
1494 case Iop_Left32:
1495 case Iop_Left64:
1496 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1497 insn = s390_insn_alu(size, S390_ALU_OR, dst, opnd);
1498 break;
1499
1500 case Iop_CmpwNEZ32:
1501 case Iop_CmpwNEZ64: {
1502 /* Use the fact that x | -x == 0 iff x == 0. Otherwise, either X
1503 or -X will have a 1 in the MSB. */
1504 addInstr(env, s390_insn_unop(size, S390_NEGATE, dst, opnd));
1505 addInstr(env, s390_insn_alu(size, S390_ALU_OR, dst, opnd));
1506 shift.variant.imm = (unop == Iop_CmpwNEZ32) ? 31 : 63;
1507 addInstr(env, s390_insn_alu(size, S390_ALU_RSHA, dst, shift));
1508 return dst;
1509 }
1510
1511 case Iop_Clz64: {
1512 HReg r10, r11;
1513
sewardj611b06e2011-03-24 08:57:29 +00001514 /* This will be implemented using FLOGR, if possible. So we need to
1515 set aside a pair of non-virtual registers. The result (number of
1516 left-most zero bits) will be in r10. The value in r11 is unspecified
1517 and must not be used. */
florian297b6062012-05-08 20:16:17 +00001518 r10 = make_gpr(10);
1519 r11 = make_gpr(11);
sewardj2019a972011-03-07 16:04:07 +00001520
sewardj611b06e2011-03-24 08:57:29 +00001521 addInstr(env, s390_insn_clz(8, r10, r11, opnd));
sewardj2019a972011-03-07 16:04:07 +00001522 addInstr(env, s390_insn_move(8, dst, r10));
1523 return dst;
1524 }
1525
1526 default:
1527 goto irreducible;
1528 }
1529
1530 addInstr(env, insn);
1531
1532 return dst;
1533 }
1534
1535 /* --------- GET --------- */
1536 case Iex_Get: {
1537 HReg dst = newVRegI(env);
1538 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1539
1540 /* We never load more than 8 bytes from the guest state, because the
1541 floating point register pair is not contiguous. */
1542 vassert(size <= 8);
1543
1544 addInstr(env, s390_insn_load(size, dst, am));
1545
1546 return dst;
1547 }
1548
1549 case Iex_GetI:
1550 /* not needed */
1551 break;
1552
1553 /* --------- CCALL --------- */
1554 case Iex_CCall: {
1555 HReg dst = newVRegI(env);
1556
1557 doHelperCall(env, False, NULL, expr->Iex.CCall.cee,
florian01ed6e72012-05-27 16:52:43 +00001558 expr->Iex.CCall.args, dst);
sewardj2019a972011-03-07 16:04:07 +00001559 return dst;
1560 }
1561
1562 /* --------- LITERAL --------- */
1563
1564 /* Load a literal into a register. Create a "load immediate"
1565 v-insn and return the register. */
1566 case Iex_Const: {
1567 ULong value;
1568 HReg dst = newVRegI(env);
1569 const IRConst *con = expr->Iex.Const.con;
1570
1571 /* Bitwise copy of the value. No sign/zero-extension */
1572 switch (con->tag) {
1573 case Ico_U64: value = con->Ico.U64; break;
1574 case Ico_U32: value = con->Ico.U32; break;
1575 case Ico_U16: value = con->Ico.U16; break;
1576 case Ico_U8: value = con->Ico.U8; break;
1577 default: vpanic("s390_isel_int_expr: invalid constant");
1578 }
1579
1580 addInstr(env, s390_insn_load_immediate(size, dst, value));
1581
1582 return dst;
1583 }
1584
1585 /* --------- MULTIPLEX --------- */
1586 case Iex_Mux0X: {
1587 IRExpr *cond_expr;
1588 HReg dst, tmp, rX;
1589 s390_opnd_RMI cond, r0, zero;
1590
1591 cond_expr = expr->Iex.Mux0X.cond;
1592
1593 dst = newVRegI(env);
1594 r0 = s390_isel_int_expr_RMI(env, expr->Iex.Mux0X.expr0);
1595 rX = s390_isel_int_expr(env, expr->Iex.Mux0X.exprX);
1596 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.exprX));
1597
1598 if (cond_expr->tag == Iex_Unop && cond_expr->Iex.Unop.op == Iop_1Uto8) {
1599 s390_cc_t cc = s390_isel_cc(env, cond_expr->Iex.Unop.arg);
1600
1601 addInstr(env, s390_insn_move(size, dst, rX));
1602 addInstr(env, s390_insn_cond_move(size, s390_cc_invert(cc), dst, r0));
1603 return dst;
1604 }
1605
1606 /* Assume the condition is true and move rX to the destination reg. */
1607 addInstr(env, s390_insn_move(size, dst, rX));
1608
1609 /* Compute the condition ... */
1610 cond = s390_isel_int_expr_RMI(env, cond_expr);
1611
1612 /* tmp = cond & 0xFF */
1613 tmp = newVRegI(env);
1614 addInstr(env, s390_insn_load_immediate(4, tmp, 0xFF));
1615 addInstr(env, s390_insn_alu(4, S390_ALU_AND, tmp, cond));
1616
1617 /* ... and compare it with zero */
1618 zero = s390_opnd_imm(0);
1619 addInstr(env, s390_insn_compare(4, tmp, zero, 0 /* signed */));
1620
1621 /* ... and if it compared equal move r0 to the destination reg. */
1622 size = sizeofIRType(typeOfIRExpr(env->type_env, expr->Iex.Mux0X.expr0));
1623 addInstr(env, s390_insn_cond_move(size, S390_CC_E, dst, r0));
1624
1625 return dst;
1626 }
1627
1628 default:
1629 break;
1630 }
1631
1632 /* We get here if no pattern matched. */
1633 irreducible:
1634 ppIRExpr(expr);
1635 vpanic("s390_isel_int_expr: cannot reduce tree");
1636}
1637
1638
1639static HReg
1640s390_isel_int_expr(ISelEnv *env, IRExpr *expr)
1641{
1642 HReg dst = s390_isel_int_expr_wrk(env, expr);
1643
1644 /* Sanity checks ... */
1645 vassert(hregClass(dst) == HRcInt64);
1646 vassert(hregIsVirtual(dst));
1647
1648 return dst;
1649}
1650
1651
1652static s390_opnd_RMI
1653s390_isel_int_expr_RMI(ISelEnv *env, IRExpr *expr)
1654{
1655 IRType ty = typeOfIRExpr(env->type_env, expr);
1656 s390_opnd_RMI dst;
1657
1658 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1659 ty == Ity_I64);
1660
1661 if (expr->tag == Iex_Load) {
1662 dst.tag = S390_OPND_AMODE;
1663 dst.variant.am = s390_isel_amode(env, expr->Iex.Load.addr);
1664 } else if (expr->tag == Iex_Get) {
1665 dst.tag = S390_OPND_AMODE;
1666 dst.variant.am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1667 } else if (expr->tag == Iex_Const) {
1668 ULong value;
1669
1670 /* The bit pattern for the value will be stored as is in the least
1671 significant bits of VALUE. */
1672 switch (expr->Iex.Const.con->tag) {
1673 case Ico_U1: value = expr->Iex.Const.con->Ico.U1; break;
1674 case Ico_U8: value = expr->Iex.Const.con->Ico.U8; break;
1675 case Ico_U16: value = expr->Iex.Const.con->Ico.U16; break;
1676 case Ico_U32: value = expr->Iex.Const.con->Ico.U32; break;
1677 case Ico_U64: value = expr->Iex.Const.con->Ico.U64; break;
1678 default:
1679 vpanic("s390_isel_int_expr_RMI");
1680 }
1681
1682 dst.tag = S390_OPND_IMMEDIATE;
1683 dst.variant.imm = value;
1684 } else {
1685 dst.tag = S390_OPND_REG;
1686 dst.variant.reg = s390_isel_int_expr(env, expr);
1687 }
1688
1689 return dst;
1690}
1691
1692
1693/*---------------------------------------------------------*/
1694/*--- ISEL: Floating point expressions (128 bit) ---*/
1695/*---------------------------------------------------------*/
1696static void
1697s390_isel_float128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
1698 IRExpr *expr)
1699{
1700 IRType ty = typeOfIRExpr(env->type_env, expr);
1701
1702 vassert(ty == Ity_F128);
1703
1704 /* Read 128-bit IRTemp */
1705 if (expr->tag == Iex_RdTmp) {
1706 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1707 return;
1708 }
1709
1710 switch (expr->tag) {
1711 case Iex_RdTmp:
1712 /* Return the virtual registers that hold the temporary. */
1713 lookupIRTemp128(dst_hi, dst_lo, env, expr->Iex.RdTmp.tmp);
1714 return;
1715
1716 /* --------- LOAD --------- */
1717 case Iex_Load: {
1718 IRExpr *addr_hi, *addr_lo;
1719 s390_amode *am_hi, *am_lo;
1720
1721 if (expr->Iex.Load.end != Iend_BE)
1722 goto irreducible;
1723
1724 addr_hi = expr->Iex.Load.addr;
1725 addr_lo = IRExpr_Binop(Iop_Add64, addr_hi, mkU64(8));
1726
1727 am_hi = s390_isel_amode(env, addr_hi);
1728 am_lo = s390_isel_amode(env, addr_lo);
1729
1730 *dst_hi = newVRegF(env);
1731 *dst_lo = newVRegF(env);
1732 addInstr(env, s390_insn_load(8, *dst_hi, am_hi));
1733 addInstr(env, s390_insn_load(8, *dst_hi, am_lo));
1734 return;
1735 }
1736
1737
1738 /* --------- GET --------- */
1739 case Iex_Get:
1740 /* This is not supported because loading 128-bit from the guest
1741 state is almost certainly wrong. Use get_fpr_pair instead. */
1742 vpanic("Iex_Get with F128 data");
1743
1744 /* --------- 4-ary OP --------- */
1745 case Iex_Qop:
1746 vpanic("Iex_Qop with F128 data");
1747
1748 /* --------- TERNARY OP --------- */
1749 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00001750 IRTriop *triop = expr->Iex.Triop.details;
1751 IROp op = triop->op;
1752 IRExpr *left = triop->arg2;
1753 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00001754 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001755 HReg op1_hi, op1_lo, op2_hi, op2_lo, f12, f13, f14, f15;
1756
1757 s390_isel_float128_expr(&op1_hi, &op1_lo, env, left); /* 1st operand */
1758 s390_isel_float128_expr(&op2_hi, &op2_lo, env, right); /* 2nd operand */
1759
1760 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1761 f12 = make_fpr(12);
1762 f13 = make_fpr(13);
1763 f14 = make_fpr(14);
1764 f15 = make_fpr(15);
1765
1766 /* 1st operand --> (f12, f14) */
1767 addInstr(env, s390_insn_move(8, f12, op1_hi));
1768 addInstr(env, s390_insn_move(8, f14, op1_lo));
1769
1770 /* 2nd operand --> (f13, f15) */
1771 addInstr(env, s390_insn_move(8, f13, op2_hi));
1772 addInstr(env, s390_insn_move(8, f15, op2_lo));
1773
1774 switch (op) {
1775 case Iop_AddF128: bfpop = S390_BFP_ADD; break;
1776 case Iop_SubF128: bfpop = S390_BFP_SUB; break;
1777 case Iop_MulF128: bfpop = S390_BFP_MUL; break;
1778 case Iop_DivF128: bfpop = S390_BFP_DIV; break;
1779 default:
1780 goto irreducible;
1781 }
1782
florian2c74d242012-09-12 19:38:42 +00001783 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
1784 addInstr(env, s390_insn_bfp128_binop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001785
1786 /* Move result to virtual destination register */
1787 *dst_hi = newVRegF(env);
1788 *dst_lo = newVRegF(env);
1789 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1790 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1791
1792 return;
1793 }
1794
1795 /* --------- BINARY OP --------- */
1796 case Iex_Binop: {
1797 HReg op_hi, op_lo, f12, f13, f14, f15;
sewardj2019a972011-03-07 16:04:07 +00001798
1799 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1800 f12 = make_fpr(12);
1801 f13 = make_fpr(13);
1802 f14 = make_fpr(14);
1803 f15 = make_fpr(15);
1804
1805 switch (expr->Iex.Binop.op) {
1806 case Iop_SqrtF128:
1807 s390_isel_float128_expr(&op_hi, &op_lo, env, expr->Iex.Binop.arg2);
1808
1809 /* operand --> (f13, f15) */
1810 addInstr(env, s390_insn_move(8, f13, op_hi));
1811 addInstr(env, s390_insn_move(8, f15, op_lo));
1812
florian2c74d242012-09-12 19:38:42 +00001813 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Binop.arg1);
1814 addInstr(env, s390_insn_bfp128_unop(16, S390_BFP_SQRT, f12, f14,
1815 f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001816
1817 /* Move result to virtual destination registers */
1818 *dst_hi = newVRegF(env);
1819 *dst_lo = newVRegF(env);
1820 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1821 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1822 return;
1823
1824 case Iop_F64HLtoF128:
1825 *dst_hi = s390_isel_float_expr(env, expr->Iex.Binop.arg1);
1826 *dst_lo = s390_isel_float_expr(env, expr->Iex.Binop.arg2);
1827 return;
1828
1829 default:
1830 goto irreducible;
1831 }
1832 }
1833
1834 /* --------- UNARY OP --------- */
1835 case Iex_Unop: {
florian66e596d2012-09-07 15:00:53 +00001836 IRExpr *left = expr->Iex.Unop.arg;
sewardj2019a972011-03-07 16:04:07 +00001837 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00001838 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00001839 HReg op_hi, op_lo, op, f12, f13, f14, f15;
1840
1841 /* We use non-virtual registers as pairs (f13, f15) and (f12, f14)) */
1842 f12 = make_fpr(12);
1843 f13 = make_fpr(13);
1844 f14 = make_fpr(14);
1845 f15 = make_fpr(15);
1846
florian66e596d2012-09-07 15:00:53 +00001847 switch (expr->Iex.Unop.op) {
florian3f3e50d2012-09-13 03:13:26 +00001848 case Iop_NegF128:
1849 if (left->tag == Iex_Unop &&
1850 (left->Iex.Unop.op == Iop_AbsF32 ||
1851 left->Iex.Unop.op == Iop_AbsF64))
1852 bfpop = S390_BFP_NABS;
1853 else
1854 bfpop = S390_BFP_NEG;
1855 goto float128_opnd;
florian9fcff4c2012-09-10 03:09:04 +00001856 case Iop_AbsF128: bfpop = S390_BFP_ABS; goto float128_opnd;
1857 case Iop_I32StoF128: conv = S390_BFP_I32_TO_F128; goto convert_int;
1858 case Iop_I64StoF128: conv = S390_BFP_I64_TO_F128; goto convert_int;
1859 case Iop_I32UtoF128: conv = S390_BFP_U32_TO_F128; goto convert_int;
1860 case Iop_I64UtoF128: conv = S390_BFP_U64_TO_F128; goto convert_int;
1861 case Iop_F32toF128: conv = S390_BFP_F32_TO_F128; goto convert_float;
1862 case Iop_F64toF128: conv = S390_BFP_F64_TO_F128; goto convert_float;
sewardj2019a972011-03-07 16:04:07 +00001863 default:
1864 goto irreducible;
1865 }
1866
1867 float128_opnd:
1868 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
1869
1870 /* operand --> (f13, f15) */
1871 addInstr(env, s390_insn_move(8, f13, op_hi));
1872 addInstr(env, s390_insn_move(8, f15, op_lo));
1873
florian2c74d242012-09-12 19:38:42 +00001874 addInstr(env, s390_insn_bfp128_unop(16, bfpop, f12, f14, f13, f15));
sewardj2019a972011-03-07 16:04:07 +00001875 goto move_dst;
1876
1877 convert_float:
1878 op = s390_isel_float_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001879 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001880 goto move_dst;
1881
1882 convert_int:
1883 op = s390_isel_int_expr(env, left);
florian9fcff4c2012-09-10 03:09:04 +00001884 addInstr(env, s390_insn_bfp128_convert_to(16, conv, f12, f14, op));
sewardj2019a972011-03-07 16:04:07 +00001885 goto move_dst;
1886
1887 move_dst:
1888 /* Move result to virtual destination registers */
1889 *dst_hi = newVRegF(env);
1890 *dst_lo = newVRegF(env);
1891 addInstr(env, s390_insn_move(8, *dst_hi, f12));
1892 addInstr(env, s390_insn_move(8, *dst_lo, f14));
1893 return;
1894 }
1895
1896 default:
1897 goto irreducible;
1898 }
1899
1900 /* We get here if no pattern matched. */
1901 irreducible:
1902 ppIRExpr(expr);
1903 vpanic("s390_isel_int_expr: cannot reduce tree");
1904}
1905
1906/* Compute a 128-bit value into two 64-bit registers. These may be either
1907 real or virtual regs; in any case they must not be changed by subsequent
1908 code emitted by the caller. */
1909static void
1910s390_isel_float128_expr(HReg *dst_hi, HReg *dst_lo, ISelEnv *env, IRExpr *expr)
1911{
1912 s390_isel_float128_expr_wrk(dst_hi, dst_lo, env, expr);
1913
1914 /* Sanity checks ... */
1915 vassert(hregIsVirtual(*dst_hi));
1916 vassert(hregIsVirtual(*dst_lo));
1917 vassert(hregClass(*dst_hi) == HRcFlt64);
1918 vassert(hregClass(*dst_lo) == HRcFlt64);
1919}
1920
1921
1922/*---------------------------------------------------------*/
1923/*--- ISEL: Floating point expressions (64 bit) ---*/
1924/*---------------------------------------------------------*/
1925
1926static HReg
1927s390_isel_float_expr_wrk(ISelEnv *env, IRExpr *expr)
1928{
1929 IRType ty = typeOfIRExpr(env->type_env, expr);
1930 UChar size;
1931
1932 vassert(ty == Ity_F32 || ty == Ity_F64);
1933
1934 size = sizeofIRType(ty);
1935
1936 switch (expr->tag) {
1937 case Iex_RdTmp:
1938 /* Return the virtual register that holds the temporary. */
1939 return lookupIRTemp(env, expr->Iex.RdTmp.tmp);
1940
1941 /* --------- LOAD --------- */
1942 case Iex_Load: {
1943 HReg dst = newVRegF(env);
1944 s390_amode *am = s390_isel_amode(env, expr->Iex.Load.addr);
1945
1946 if (expr->Iex.Load.end != Iend_BE)
1947 goto irreducible;
1948
1949 addInstr(env, s390_insn_load(size, dst, am));
1950
1951 return dst;
1952 }
1953
1954 /* --------- GET --------- */
1955 case Iex_Get: {
1956 HReg dst = newVRegF(env);
1957 s390_amode *am = s390_amode_for_guest_state(expr->Iex.Get.offset);
1958
1959 addInstr(env, s390_insn_load(size, dst, am));
1960
1961 return dst;
1962 }
1963
1964 /* --------- LITERAL --------- */
1965
1966 /* Load a literal into a register. Create a "load immediate"
1967 v-insn and return the register. */
1968 case Iex_Const: {
1969 ULong value;
1970 HReg dst = newVRegF(env);
1971 const IRConst *con = expr->Iex.Const.con;
1972
1973 /* Bitwise copy of the value. No sign/zero-extension */
1974 switch (con->tag) {
1975 case Ico_F32i: value = con->Ico.F32i; break;
1976 case Ico_F64i: value = con->Ico.F64i; break;
1977 default: vpanic("s390_isel_float_expr: invalid constant");
1978 }
1979
1980 if (value != 0) vpanic("cannot load immediate floating point constant");
1981
1982 addInstr(env, s390_insn_load_immediate(size, dst, value));
1983
1984 return dst;
1985 }
1986
1987 /* --------- 4-ary OP --------- */
1988 case Iex_Qop: {
1989 HReg op1, op2, op3, dst;
1990 s390_bfp_triop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00001991
florian5906a6b2012-10-16 02:53:33 +00001992 op3 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg2);
florian96d7cc32012-06-01 20:41:24 +00001993 op2 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg3);
florian5906a6b2012-10-16 02:53:33 +00001994 op1 = s390_isel_float_expr(env, expr->Iex.Qop.details->arg4);
sewardj2019a972011-03-07 16:04:07 +00001995 dst = newVRegF(env);
1996 addInstr(env, s390_insn_move(size, dst, op1));
1997
florian96d7cc32012-06-01 20:41:24 +00001998 switch (expr->Iex.Qop.details->op) {
sewardj2019a972011-03-07 16:04:07 +00001999 case Iop_MAddF32:
2000 case Iop_MAddF64: bfpop = S390_BFP_MADD; break;
2001 case Iop_MSubF32:
2002 case Iop_MSubF64: bfpop = S390_BFP_MSUB; break;
2003
2004 default:
2005 goto irreducible;
2006 }
2007
florian2c74d242012-09-12 19:38:42 +00002008 set_bfp_rounding_mode_in_fpc(env, expr->Iex.Qop.details->arg1);
2009 addInstr(env, s390_insn_bfp_triop(size, bfpop, dst, op2, op3));
sewardj2019a972011-03-07 16:04:07 +00002010 return dst;
2011 }
2012
2013 /* --------- TERNARY OP --------- */
2014 case Iex_Triop: {
florian420bfa92012-06-02 20:29:22 +00002015 IRTriop *triop = expr->Iex.Triop.details;
2016 IROp op = triop->op;
2017 IRExpr *left = triop->arg2;
2018 IRExpr *right = triop->arg3;
sewardj2019a972011-03-07 16:04:07 +00002019 s390_bfp_binop_t bfpop;
sewardj2019a972011-03-07 16:04:07 +00002020 HReg h1, op2, dst;
2021
2022 h1 = s390_isel_float_expr(env, left); /* Process 1st operand */
2023 op2 = s390_isel_float_expr(env, right); /* Process 2nd operand */
2024 dst = newVRegF(env);
2025 addInstr(env, s390_insn_move(size, dst, h1));
2026 switch (op) {
2027 case Iop_AddF32:
2028 case Iop_AddF64: bfpop = S390_BFP_ADD; break;
2029 case Iop_SubF32:
2030 case Iop_SubF64: bfpop = S390_BFP_SUB; break;
2031 case Iop_MulF32:
2032 case Iop_MulF64: bfpop = S390_BFP_MUL; break;
2033 case Iop_DivF32:
2034 case Iop_DivF64: bfpop = S390_BFP_DIV; break;
2035
2036 default:
2037 goto irreducible;
2038 }
2039
florian2c74d242012-09-12 19:38:42 +00002040 set_bfp_rounding_mode_in_fpc(env, triop->arg1);
2041 addInstr(env, s390_insn_bfp_binop(size, bfpop, dst, op2));
sewardj2019a972011-03-07 16:04:07 +00002042 return dst;
2043 }
2044
2045 /* --------- BINARY OP --------- */
2046 case Iex_Binop: {
2047 IROp op = expr->Iex.Binop.op;
florian9fcff4c2012-09-10 03:09:04 +00002048 IRExpr *irrm = expr->Iex.Binop.arg1;
sewardj2019a972011-03-07 16:04:07 +00002049 IRExpr *left = expr->Iex.Binop.arg2;
2050 HReg h1, dst;
florian9fcff4c2012-09-10 03:09:04 +00002051 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002052
2053 switch (op) {
2054 case Iop_SqrtF32:
2055 case Iop_SqrtF64:
florian9fcff4c2012-09-10 03:09:04 +00002056 h1 = s390_isel_float_expr(env, left);
2057 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002058 set_bfp_rounding_mode_in_fpc(env, irrm);
2059 addInstr(env, s390_insn_bfp_unop(size, S390_BFP_SQRT, dst, h1));
florian9fcff4c2012-09-10 03:09:04 +00002060 return dst;
sewardj2019a972011-03-07 16:04:07 +00002061
florian9fcff4c2012-09-10 03:09:04 +00002062 case Iop_F64toF32: conv = S390_BFP_F64_TO_F32; goto convert_float;
2063 case Iop_I32StoF32: conv = S390_BFP_I32_TO_F32; goto convert_int;
2064 case Iop_I32UtoF32: conv = S390_BFP_U32_TO_F32; goto convert_int;
2065 case Iop_I64StoF32: conv = S390_BFP_I64_TO_F32; goto convert_int;
2066 case Iop_I64StoF64: conv = S390_BFP_I64_TO_F64; goto convert_int;
2067 case Iop_I64UtoF32: conv = S390_BFP_U64_TO_F32; goto convert_int;
2068 case Iop_I64UtoF64: conv = S390_BFP_U64_TO_F64; goto convert_int;
sewardj2019a972011-03-07 16:04:07 +00002069
florian9fcff4c2012-09-10 03:09:04 +00002070 convert_float:
2071 h1 = s390_isel_float_expr(env, left);
2072 goto convert;
florian1c8f7ff2012-09-01 00:12:11 +00002073
florian9fcff4c2012-09-10 03:09:04 +00002074 convert_int:
2075 h1 = s390_isel_int_expr(env, left);
2076 goto convert;
2077
florian2c74d242012-09-12 19:38:42 +00002078 convert: {
florian125e20d2012-10-07 15:42:37 +00002079 s390_bfp_round_t rounding_mode;
florian2c74d242012-09-12 19:38:42 +00002080 /* convert-from-fixed and load-rounded have a rounding mode field
2081 when the floating point extension facility is installed. */
florian9fcff4c2012-09-10 03:09:04 +00002082 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002083 if (s390_host_has_fpext) {
2084 rounding_mode = get_bfp_rounding_mode(env, irrm);
2085 } else {
2086 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002087 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002088 }
florian9fcff4c2012-09-10 03:09:04 +00002089 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
2090 rounding_mode));
2091 return dst;
florian2c74d242012-09-12 19:38:42 +00002092 }
florian9fcff4c2012-09-10 03:09:04 +00002093
sewardj2019a972011-03-07 16:04:07 +00002094 default:
2095 goto irreducible;
2096
2097 case Iop_F128toF64:
2098 case Iop_F128toF32: {
florian9fcff4c2012-09-10 03:09:04 +00002099 HReg op_hi, op_lo, f13, f15;
florian125e20d2012-10-07 15:42:37 +00002100 s390_bfp_round_t rounding_mode;
sewardj2019a972011-03-07 16:04:07 +00002101
florian9fcff4c2012-09-10 03:09:04 +00002102 conv = op == Iop_F128toF32 ? S390_BFP_F128_TO_F32
2103 : S390_BFP_F128_TO_F64;
sewardj2019a972011-03-07 16:04:07 +00002104
florian9fcff4c2012-09-10 03:09:04 +00002105 s390_isel_float128_expr(&op_hi, &op_lo, env, left);
sewardj2019a972011-03-07 16:04:07 +00002106
florian9fcff4c2012-09-10 03:09:04 +00002107 /* We use non-virtual registers as pairs (f13, f15) */
sewardj2019a972011-03-07 16:04:07 +00002108 f13 = make_fpr(13);
sewardj2019a972011-03-07 16:04:07 +00002109 f15 = make_fpr(15);
2110
2111 /* operand --> (f13, f15) */
2112 addInstr(env, s390_insn_move(8, f13, op_hi));
2113 addInstr(env, s390_insn_move(8, f15, op_lo));
2114
2115 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002116 /* load-rounded has a rounding mode field when the floating point
2117 extension facility is installed. */
2118 if (s390_host_has_fpext) {
2119 rounding_mode = get_bfp_rounding_mode(env, irrm);
2120 } else {
2121 set_bfp_rounding_mode_in_fpc(env, irrm);
florian125e20d2012-10-07 15:42:37 +00002122 rounding_mode = S390_BFP_ROUND_PER_FPC;
florian2c74d242012-09-12 19:38:42 +00002123 }
floriancc491a62012-09-10 23:44:37 +00002124 addInstr(env, s390_insn_bfp128_convert_from(size, conv, dst, f13, f15,
florian9fcff4c2012-09-10 03:09:04 +00002125 rounding_mode));
sewardj2019a972011-03-07 16:04:07 +00002126 return dst;
2127 }
2128 }
sewardj2019a972011-03-07 16:04:07 +00002129 }
2130
2131 /* --------- UNARY OP --------- */
2132 case Iex_Unop: {
2133 IROp op = expr->Iex.Unop.op;
2134 IRExpr *left = expr->Iex.Unop.arg;
2135 s390_bfp_unop_t bfpop;
florian9fcff4c2012-09-10 03:09:04 +00002136 s390_conv_t conv;
sewardj2019a972011-03-07 16:04:07 +00002137 HReg h1, dst;
2138
2139 if (op == Iop_F128HItoF64 || op == Iop_F128LOtoF64) {
2140 HReg dst_hi, dst_lo;
2141
2142 s390_isel_float128_expr(&dst_hi, &dst_lo, env, left);
2143 return op == Iop_F128LOtoF64 ? dst_lo : dst_hi;
2144 }
2145
florian4d71a082011-12-18 00:08:17 +00002146 if (op == Iop_ReinterpI64asF64 || op == Iop_ReinterpI32asF32) {
sewardj2019a972011-03-07 16:04:07 +00002147 dst = newVRegF(env);
2148 h1 = s390_isel_int_expr(env, left); /* Process the operand */
2149 addInstr(env, s390_insn_move(size, dst, h1));
2150
2151 return dst;
2152 }
2153
2154 switch (op) {
2155 case Iop_NegF32:
2156 case Iop_NegF64:
2157 if (left->tag == Iex_Unop &&
florian3f3e50d2012-09-13 03:13:26 +00002158 (left->Iex.Unop.op == Iop_AbsF32 ||
2159 left->Iex.Unop.op == Iop_AbsF64))
sewardj2019a972011-03-07 16:04:07 +00002160 bfpop = S390_BFP_NABS;
2161 else
2162 bfpop = S390_BFP_NEG;
2163 break;
2164
2165 case Iop_AbsF32:
florian9fcff4c2012-09-10 03:09:04 +00002166 case Iop_AbsF64:
2167 bfpop = S390_BFP_ABS;
2168 break;
2169
2170 case Iop_I32StoF64: conv = S390_BFP_I32_TO_F64; goto convert_int1;
2171 case Iop_I32UtoF64: conv = S390_BFP_U32_TO_F64; goto convert_int1;
2172 case Iop_F32toF64: conv = S390_BFP_F32_TO_F64; goto convert_float1;
2173
2174 convert_float1:
2175 h1 = s390_isel_float_expr(env, left);
2176 goto convert1;
2177
2178 convert_int1:
2179 h1 = s390_isel_int_expr(env, left);
2180 goto convert1;
2181
2182 convert1:
2183 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002184 /* No rounding mode is needed for these conversions. Just stick
2185 one in. It won't be used later on. */
2186 addInstr(env, s390_insn_bfp_convert(size, conv, dst, h1,
florian125e20d2012-10-07 15:42:37 +00002187 S390_BFP_ROUND_NEAREST_EVEN));
florian9fcff4c2012-09-10 03:09:04 +00002188 return dst;
2189
sewardj2019a972011-03-07 16:04:07 +00002190 default:
2191 goto irreducible;
2192 }
2193
2194 /* Process operand */
florian9fcff4c2012-09-10 03:09:04 +00002195 h1 = s390_isel_float_expr(env, left);
sewardj2019a972011-03-07 16:04:07 +00002196 dst = newVRegF(env);
florian2c74d242012-09-12 19:38:42 +00002197 addInstr(env, s390_insn_bfp_unop(size, bfpop, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002198 return dst;
2199 }
2200
2201 default:
2202 goto irreducible;
2203 }
2204
2205 /* We get here if no pattern matched. */
2206 irreducible:
2207 ppIRExpr(expr);
2208 vpanic("s390_isel_float_expr: cannot reduce tree");
2209}
2210
2211
2212static HReg
2213s390_isel_float_expr(ISelEnv *env, IRExpr *expr)
2214{
2215 HReg dst = s390_isel_float_expr_wrk(env, expr);
2216
2217 /* Sanity checks ... */
2218 vassert(hregClass(dst) == HRcFlt64);
2219 vassert(hregIsVirtual(dst));
2220
2221 return dst;
2222}
2223
2224
2225/*---------------------------------------------------------*/
2226/*--- ISEL: Condition Code ---*/
2227/*---------------------------------------------------------*/
2228
2229/* This function handles all operators that produce a 1-bit result */
2230static s390_cc_t
2231s390_isel_cc(ISelEnv *env, IRExpr *cond)
2232{
2233 UChar size;
2234
2235 vassert(typeOfIRExpr(env->type_env, cond) == Ity_I1);
2236
2237 /* Constant: either 1 or 0 */
2238 if (cond->tag == Iex_Const) {
2239 vassert(cond->Iex.Const.con->tag == Ico_U1);
2240 vassert(cond->Iex.Const.con->Ico.U1 == True
2241 || cond->Iex.Const.con->Ico.U1 == False);
2242
2243 return cond->Iex.Const.con->Ico.U1 == True ? S390_CC_ALWAYS : S390_CC_NEVER;
2244 }
2245
2246 /* Variable: values are 1 or 0 */
2247 if (cond->tag == Iex_RdTmp) {
2248 IRTemp tmp = cond->Iex.RdTmp.tmp;
2249 HReg reg = lookupIRTemp(env, tmp);
2250
2251 /* Load-and-test does not modify REG; so this is OK. */
2252 if (typeOfIRTemp(env->type_env, tmp) == Ity_I1)
2253 size = 4;
2254 else
2255 size = sizeofIRType(typeOfIRTemp(env->type_env, tmp));
2256 addInstr(env, s390_insn_test(size, s390_opnd_reg(reg)));
2257 return S390_CC_NE;
2258 }
2259
2260 /* Unary operators */
2261 if (cond->tag == Iex_Unop) {
2262 IRExpr *arg = cond->Iex.Unop.arg;
2263
2264 switch (cond->Iex.Unop.op) {
2265 case Iop_Not1: /* Not1(cond) */
2266 /* Generate code for EXPR, and negate the test condition */
2267 return s390_cc_invert(s390_isel_cc(env, arg));
2268
2269 /* Iop_32/64to1 select the LSB from their operand */
2270 case Iop_32to1:
2271 case Iop_64to1: {
florianf366a802012-08-03 00:42:18 +00002272 HReg dst = newVRegI(env);
2273 HReg h1 = s390_isel_int_expr(env, arg);
sewardj2019a972011-03-07 16:04:07 +00002274
2275 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2276
florianf366a802012-08-03 00:42:18 +00002277 addInstr(env, s390_insn_move(size, dst, h1));
sewardj2019a972011-03-07 16:04:07 +00002278 addInstr(env, s390_insn_alu(size, S390_ALU_AND, dst, s390_opnd_imm(1)));
2279 addInstr(env, s390_insn_test(size, s390_opnd_reg(dst)));
2280 return S390_CC_NE;
2281 }
2282
2283 case Iop_CmpNEZ8:
2284 case Iop_CmpNEZ16: {
2285 s390_opnd_RMI src;
2286 s390_unop_t op;
2287 HReg dst;
2288
2289 op = (cond->Iex.Unop.op == Iop_CmpNEZ8) ? S390_ZERO_EXTEND_8
2290 : S390_ZERO_EXTEND_16;
2291 dst = newVRegI(env);
2292 src = s390_isel_int_expr_RMI(env, arg);
2293 addInstr(env, s390_insn_unop(4, op, dst, src));
2294 addInstr(env, s390_insn_test(4, s390_opnd_reg(dst)));
2295 return S390_CC_NE;
2296 }
2297
2298 case Iop_CmpNEZ32:
2299 case Iop_CmpNEZ64: {
2300 s390_opnd_RMI src;
2301
2302 src = s390_isel_int_expr_RMI(env, arg);
2303 size = sizeofIRType(typeOfIRExpr(env->type_env, arg));
2304 addInstr(env, s390_insn_test(size, src));
2305 return S390_CC_NE;
2306 }
2307
2308 default:
2309 goto fail;
2310 }
2311 }
2312
2313 /* Binary operators */
2314 if (cond->tag == Iex_Binop) {
2315 IRExpr *arg1 = cond->Iex.Binop.arg1;
2316 IRExpr *arg2 = cond->Iex.Binop.arg2;
2317 HReg reg1, reg2;
2318
2319 size = sizeofIRType(typeOfIRExpr(env->type_env, arg1));
2320
2321 switch (cond->Iex.Binop.op) {
2322 s390_unop_t op;
2323 s390_cc_t result;
2324
2325 case Iop_CmpEQ8:
2326 case Iop_CasCmpEQ8:
2327 op = S390_ZERO_EXTEND_8;
2328 result = S390_CC_E;
2329 goto do_compare_ze;
2330
2331 case Iop_CmpNE8:
2332 case Iop_CasCmpNE8:
2333 op = S390_ZERO_EXTEND_8;
2334 result = S390_CC_NE;
2335 goto do_compare_ze;
2336
2337 case Iop_CmpEQ16:
2338 case Iop_CasCmpEQ16:
2339 op = S390_ZERO_EXTEND_16;
2340 result = S390_CC_E;
2341 goto do_compare_ze;
2342
2343 case Iop_CmpNE16:
2344 case Iop_CasCmpNE16:
2345 op = S390_ZERO_EXTEND_16;
2346 result = S390_CC_NE;
2347 goto do_compare_ze;
2348
2349 do_compare_ze: {
2350 s390_opnd_RMI op1, op2;
2351
2352 op1 = s390_isel_int_expr_RMI(env, arg1);
2353 reg1 = newVRegI(env);
2354 addInstr(env, s390_insn_unop(4, op, reg1, op1));
2355
2356 op2 = s390_isel_int_expr_RMI(env, arg2);
2357 reg2 = newVRegI(env);
2358 addInstr(env, s390_insn_unop(4, op, reg2, op2)); /* zero extend */
2359
2360 op2 = s390_opnd_reg(reg2);
2361 addInstr(env, s390_insn_compare(4, reg1, op2, False));
2362
2363 return result;
2364 }
2365
2366 case Iop_CmpEQ32:
2367 case Iop_CmpEQ64:
2368 case Iop_CasCmpEQ32:
2369 case Iop_CasCmpEQ64:
2370 result = S390_CC_E;
2371 goto do_compare;
2372
2373 case Iop_CmpNE32:
2374 case Iop_CmpNE64:
2375 case Iop_CasCmpNE32:
2376 case Iop_CasCmpNE64:
2377 result = S390_CC_NE;
2378 goto do_compare;
2379
2380 do_compare: {
2381 HReg op1;
2382 s390_opnd_RMI op2;
2383
2384 order_commutative_operands(arg1, arg2);
2385
2386 op1 = s390_isel_int_expr(env, arg1);
2387 op2 = s390_isel_int_expr_RMI(env, arg2);
2388
2389 addInstr(env, s390_insn_compare(size, op1, op2, False));
2390
2391 return result;
2392 }
2393
2394 case Iop_CmpLT32S:
2395 case Iop_CmpLE32S:
2396 case Iop_CmpLT64S:
2397 case Iop_CmpLE64S: {
2398 HReg op1;
2399 s390_opnd_RMI op2;
2400
2401 op1 = s390_isel_int_expr(env, arg1);
2402 op2 = s390_isel_int_expr_RMI(env, arg2);
2403
2404 addInstr(env, s390_insn_compare(size, op1, op2, True));
2405
2406 return (cond->Iex.Binop.op == Iop_CmpLT32S ||
2407 cond->Iex.Binop.op == Iop_CmpLT64S) ? S390_CC_L : S390_CC_LE;
2408 }
2409
2410 case Iop_CmpLT32U:
2411 case Iop_CmpLE32U:
2412 case Iop_CmpLT64U:
2413 case Iop_CmpLE64U: {
2414 HReg op1;
2415 s390_opnd_RMI op2;
2416
2417 op1 = s390_isel_int_expr(env, arg1);
2418 op2 = s390_isel_int_expr_RMI(env, arg2);
2419
2420 addInstr(env, s390_insn_compare(size, op1, op2, False));
2421
2422 return (cond->Iex.Binop.op == Iop_CmpLT32U ||
2423 cond->Iex.Binop.op == Iop_CmpLT64U) ? S390_CC_L : S390_CC_LE;
2424 }
2425
2426 default:
2427 goto fail;
2428 }
2429 }
2430
2431 fail:
2432 ppIRExpr(cond);
2433 vpanic("s390_isel_cc: unexpected operator");
2434}
2435
2436
2437/*---------------------------------------------------------*/
2438/*--- ISEL: Statements ---*/
2439/*---------------------------------------------------------*/
2440
2441static void
2442s390_isel_stmt(ISelEnv *env, IRStmt *stmt)
2443{
2444 if (vex_traceflags & VEX_TRACE_VCODE) {
2445 vex_printf("\n -- ");
2446 ppIRStmt(stmt);
2447 vex_printf("\n");
2448 }
2449
2450 switch (stmt->tag) {
2451
2452 /* --------- STORE --------- */
2453 case Ist_Store: {
2454 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2455 s390_amode *am;
2456 HReg src;
2457
2458 if (stmt->Ist.Store.end != Iend_BE) goto stmt_fail;
2459
2460 am = s390_isel_amode(env, stmt->Ist.Store.addr);
2461
2462 switch (tyd) {
2463 case Ity_I8:
2464 case Ity_I16:
2465 case Ity_I32:
2466 case Ity_I64:
2467 src = s390_isel_int_expr(env, stmt->Ist.Store.data);
2468 break;
2469
2470 case Ity_F32:
2471 case Ity_F64:
2472 src = s390_isel_float_expr(env, stmt->Ist.Store.data);
2473 break;
2474
2475 case Ity_F128:
2476 /* Cannot occur. No such instruction */
2477 vpanic("Ist_Store with F128 data");
2478
2479 default:
2480 goto stmt_fail;
2481 }
2482
2483 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2484 return;
2485 }
2486
2487 /* --------- PUT --------- */
2488 case Ist_Put: {
2489 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2490 HReg src;
2491 s390_amode *am;
florianad43b3a2012-02-20 15:01:14 +00002492 ULong new_value, old_value, difference;
sewardj2019a972011-03-07 16:04:07 +00002493
florianad43b3a2012-02-20 15:01:14 +00002494 /* Detect updates to certain guest registers. We track the contents
2495 of those registers as long as they contain constants. If the new
2496 constant is either zero or in the 8-bit neighbourhood of the
2497 current value we can use a memory-to-memory insn to do the update. */
2498
2499 Int offset = stmt->Ist.Put.offset;
2500
2501 /* Check necessary conditions:
2502 (1) must be one of the registers we care about
2503 (2) assigned value must be a constant */
2504 Int guest_reg = get_guest_reg(offset);
2505
2506 if (guest_reg == GUEST_UNKNOWN) goto not_special;
2507
2508 if (guest_reg == GUEST_IA) {
2509 /* If this is the first assignment to the IA reg, don't special case
2510 it. We need to do a full 8-byte assignment here. The reason is
2511 that in case of a redirected translation the guest IA does not
2512 contain the redirected-to address. Instead it contains the
2513 redirected-from address and those can be far apart. So in order to
2514 do incremnetal updates if the IA in the future we need to get the
2515 initial address of the super block correct. */
2516 if (env->first_IA_assignment) {
2517 env->first_IA_assignment = False;
2518 goto not_special;
2519 }
2520 }
2521
2522 if (stmt->Ist.Put.data->tag != Iex_Const) {
2523 /* Invalidate guest register contents */
2524 env->old_value_valid[guest_reg] = False;
2525 goto not_special;
2526 }
2527
cborntraaf7ad282012-08-08 14:11:33 +00002528 /* We can only handle Ity_I64, but the CC_DEPS field can have floats */
2529 if (tyd != Ity_I64)
2530 goto not_special;
florianad43b3a2012-02-20 15:01:14 +00002531
cborntraaf7ad282012-08-08 14:11:33 +00002532 /* OK. Necessary conditions are satisfied. */
florianad43b3a2012-02-20 15:01:14 +00002533
2534 old_value = env->old_value[guest_reg];
2535 new_value = stmt->Ist.Put.data->Iex.Const.con->Ico.U64;
2536 env->old_value[guest_reg] = new_value;
2537
2538 Bool old_value_is_valid = env->old_value_valid[guest_reg];
2539 env->old_value_valid[guest_reg] = True;
2540
2541 /* If the register already contains the new value, there is nothing
2542 to do here. Unless the guest register requires precise memory
2543 exceptions. */
2544 if (old_value_is_valid && new_value == old_value) {
2545 if (! guest_s390x_state_requires_precise_mem_exns(offset, offset + 8)) {
2546 return;
2547 }
2548 }
2549
2550 /* guest register = 0 */
2551 if (new_value == 0) {
2552 addInstr(env, s390_insn_gzero(sizeofIRType(tyd), offset));
2553 return;
2554 }
2555
2556 if (old_value_is_valid == False) goto not_special;
2557
2558 /* If the new value is in the neighbourhood of the old value
2559 we can use a memory-to-memory insn */
2560 difference = new_value - old_value;
2561
2562 if (s390_host_has_gie && ulong_fits_signed_8bit(difference)) {
2563 addInstr(env, s390_insn_gadd(sizeofIRType(tyd), offset,
2564 (difference & 0xFF), new_value));
2565 return;
2566 }
2567
2568 /* If the high word is the same it is sufficient to load the low word.
2569 Use R0 as a scratch reg. */
2570 if ((old_value >> 32) == (new_value >> 32)) {
florian297b6062012-05-08 20:16:17 +00002571 HReg r0 = make_gpr(0);
2572 HReg gsp = make_gpr(S390_REGNO_GUEST_STATE_POINTER);
florianad43b3a2012-02-20 15:01:14 +00002573 s390_amode *gam;
2574
2575 gam = s390_amode_b12(offset + 4, gsp);
2576 addInstr(env, s390_insn_load_immediate(4, r0,
2577 new_value & 0xFFFFFFFF));
2578 addInstr(env, s390_insn_store(4, gam, r0));
2579 return;
2580 }
2581
2582 /* No special case applies... fall through */
2583
2584 not_special:
sewardj2019a972011-03-07 16:04:07 +00002585 am = s390_amode_for_guest_state(stmt->Ist.Put.offset);
2586
2587 switch (tyd) {
2588 case Ity_I8:
2589 case Ity_I16:
2590 case Ity_I32:
2591 case Ity_I64:
2592 src = s390_isel_int_expr(env, stmt->Ist.Put.data);
2593 break;
2594
2595 case Ity_F32:
2596 case Ity_F64:
2597 src = s390_isel_float_expr(env, stmt->Ist.Put.data);
2598 break;
2599
2600 case Ity_F128:
2601 /* Does not occur. See function put_fpr_pair. */
2602 vpanic("Ist_Put with F128 data");
2603
2604 default:
2605 goto stmt_fail;
2606 }
2607
2608 addInstr(env, s390_insn_store(sizeofIRType(tyd), am, src));
2609 return;
2610 }
2611
2612 /* --------- TMP --------- */
2613 case Ist_WrTmp: {
2614 IRTemp tmp = stmt->Ist.WrTmp.tmp;
2615 IRType tyd = typeOfIRTemp(env->type_env, tmp);
2616 HReg src, dst;
2617
2618 switch (tyd) {
2619 case Ity_I128: {
2620 HReg dst_hi, dst_lo, res_hi, res_lo;
2621
2622 s390_isel_int128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2623 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2624
2625 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2626 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2627 return;
2628 }
2629
2630 case Ity_I8:
2631 case Ity_I16:
2632 case Ity_I32:
2633 case Ity_I64:
2634 src = s390_isel_int_expr(env, stmt->Ist.WrTmp.data);
2635 dst = lookupIRTemp(env, tmp);
2636 break;
2637
2638 case Ity_I1: {
2639 s390_cc_t cond = s390_isel_cc(env, stmt->Ist.WrTmp.data);
2640 dst = lookupIRTemp(env, tmp);
2641 addInstr(env, s390_insn_cc2bool(dst, cond));
2642 return;
2643 }
2644
2645 case Ity_F32:
2646 case Ity_F64:
2647 src = s390_isel_float_expr(env, stmt->Ist.WrTmp.data);
2648 dst = lookupIRTemp(env, tmp);
2649 break;
2650
2651 case Ity_F128: {
2652 HReg dst_hi, dst_lo, res_hi, res_lo;
2653
2654 s390_isel_float128_expr(&res_hi, &res_lo, env, stmt->Ist.WrTmp.data);
2655 lookupIRTemp128(&dst_hi, &dst_lo, env, tmp);
2656
2657 addInstr(env, s390_insn_move(8, dst_hi, res_hi));
2658 addInstr(env, s390_insn_move(8, dst_lo, res_lo));
2659 return;
2660 }
2661
2662 default:
2663 goto stmt_fail;
2664 }
2665
2666 addInstr(env, s390_insn_move(sizeofIRType(tyd), dst, src));
2667 return;
2668 }
2669
2670 /* --------- Call to DIRTY helper --------- */
2671 case Ist_Dirty: {
2672 IRType retty;
2673 IRDirty* d = stmt->Ist.Dirty.details;
2674 Bool passBBP;
florian01ed6e72012-05-27 16:52:43 +00002675 HReg dst;
florianad43b3a2012-02-20 15:01:14 +00002676 Int i;
2677
2678 /* Invalidate tracked values of those guest state registers that are
2679 modified by this helper. */
2680 for (i = 0; i < d->nFxState; ++i) {
sewardjc9069f22012-06-01 16:09:50 +00002681 /* JRS 1 June 2012: AFAICS, s390 guest doesn't use 'repeat'
2682 descriptors in guest state effect descriptions. Hence: */
2683 vassert(d->fxState[i].nRepeats == 0 && d->fxState[i].repeatLen == 0);
florianad43b3a2012-02-20 15:01:14 +00002684 if ((d->fxState[i].fx == Ifx_Write || d->fxState[i].fx == Ifx_Modify)) {
2685 Int guest_reg = get_guest_reg(d->fxState[i].offset);
2686 if (guest_reg != GUEST_UNKNOWN)
2687 env->old_value_valid[guest_reg] = False;
2688 }
2689 }
sewardj2019a972011-03-07 16:04:07 +00002690
2691 if (d->nFxState == 0)
2692 vassert(!d->needsBBP);
2693
2694 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2695
florian01ed6e72012-05-27 16:52:43 +00002696 if (d->tmp == IRTemp_INVALID) {
2697 /* No return value. */
2698 dst = INVALID_HREG;
2699 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002700 return;
florian01ed6e72012-05-27 16:52:43 +00002701 }
sewardj2019a972011-03-07 16:04:07 +00002702
2703 retty = typeOfIRTemp(env->type_env, d->tmp);
2704 if (retty == Ity_I64 || retty == Ity_I32
2705 || retty == Ity_I16 || retty == Ity_I8) {
florian297b6062012-05-08 20:16:17 +00002706 /* Move the returned value to the destination register */
florian01ed6e72012-05-27 16:52:43 +00002707 dst = lookupIRTemp(env, d->tmp);
2708 doHelperCall(env, passBBP, d->guard, d->cee, d->args, dst);
sewardj2019a972011-03-07 16:04:07 +00002709 return;
2710 }
2711 break;
2712 }
2713
2714 case Ist_CAS:
2715 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
2716 IRCAS *cas = stmt->Ist.CAS.details;
2717 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2718 HReg op3 = s390_isel_int_expr(env, cas->dataLo); /* new value */
2719 HReg op1 = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2720 HReg old = lookupIRTemp(env, cas->oldLo);
2721
2722 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2723 addInstr(env, s390_insn_cas(4, op1, op2, op3, old));
2724 } else {
2725 addInstr(env, s390_insn_cas(8, op1, op2, op3, old));
2726 }
2727 return;
2728 } else {
florian448cbba2012-06-06 02:26:01 +00002729 IRCAS *cas = stmt->Ist.CAS.details;
2730 s390_amode *op2 = s390_isel_amode(env, cas->addr);
2731 HReg r8, r9, r10, r11, r1;
2732 HReg op3_high = s390_isel_int_expr(env, cas->dataHi); /* new value */
2733 HReg op3_low = s390_isel_int_expr(env, cas->dataLo); /* new value */
2734 HReg op1_high = s390_isel_int_expr(env, cas->expdHi); /* expected value */
2735 HReg op1_low = s390_isel_int_expr(env, cas->expdLo); /* expected value */
2736 HReg old_low = lookupIRTemp(env, cas->oldLo);
2737 HReg old_high = lookupIRTemp(env, cas->oldHi);
2738
2739 /* Use non-virtual registers r8 and r9 as pair for op1
2740 and move op1 there */
2741 r8 = make_gpr(8);
2742 r9 = make_gpr(9);
2743 addInstr(env, s390_insn_move(8, r8, op1_high));
2744 addInstr(env, s390_insn_move(8, r9, op1_low));
2745
2746 /* Use non-virtual registers r10 and r11 as pair for op3
2747 and move op3 there */
2748 r10 = make_gpr(10);
2749 r11 = make_gpr(11);
2750 addInstr(env, s390_insn_move(8, r10, op3_high));
2751 addInstr(env, s390_insn_move(8, r11, op3_low));
2752
2753 /* Register r1 is used as a scratch register */
2754 r1 = make_gpr(1);
2755
2756 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
2757 addInstr(env, s390_insn_cdas(4, r8, r9, op2, r10, r11,
2758 old_high, old_low, r1));
2759 } else {
2760 addInstr(env, s390_insn_cdas(8, r8, r9, op2, r10, r11,
2761 old_high, old_low, r1));
2762 }
2763 addInstr(env, s390_insn_move(8, op1_high, r8));
2764 addInstr(env, s390_insn_move(8, op1_low, r9));
2765 addInstr(env, s390_insn_move(8, op3_high, r10));
2766 addInstr(env, s390_insn_move(8, op3_low, r11));
2767 return;
sewardj2019a972011-03-07 16:04:07 +00002768 }
2769 break;
2770
2771 /* --------- EXIT --------- */
2772 case Ist_Exit: {
sewardj2019a972011-03-07 16:04:07 +00002773 s390_cc_t cond;
2774 IRConstTag tag = stmt->Ist.Exit.dst->tag;
2775
2776 if (tag != Ico_U64)
2777 vpanic("s390_isel_stmt: Ist_Exit: dst is not a 64-bit value");
2778
florian8844a632012-04-13 04:04:06 +00002779 s390_amode *guest_IA = s390_amode_for_guest_state(stmt->Ist.Exit.offsIP);
sewardj2019a972011-03-07 16:04:07 +00002780 cond = s390_isel_cc(env, stmt->Ist.Exit.guard);
florian8844a632012-04-13 04:04:06 +00002781
2782 /* Case: boring transfer to known address */
2783 if (stmt->Ist.Exit.jk == Ijk_Boring) {
2784 if (env->chaining_allowed) {
2785 /* .. almost always true .. */
2786 /* Skip the event check at the dst if this is a forwards
2787 edge. */
2788 Bool to_fast_entry
2789 = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
2790 if (0) vex_printf("%s", to_fast_entry ? "Y" : ",");
2791 addInstr(env, s390_insn_xdirect(cond, stmt->Ist.Exit.dst->Ico.U64,
2792 guest_IA, to_fast_entry));
2793 } else {
2794 /* .. very occasionally .. */
2795 /* We can't use chaining, so ask for an assisted transfer,
2796 as that's the only alternative that is allowable. */
2797 HReg dst = s390_isel_int_expr(env,
2798 IRExpr_Const(stmt->Ist.Exit.dst));
2799 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA, Ijk_Boring));
2800 }
2801 return;
2802 }
2803
2804 /* Case: assisted transfer to arbitrary address */
2805 switch (stmt->Ist.Exit.jk) {
florian4e0083e2012-08-26 03:41:56 +00002806 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002807 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002808 case Ijk_NoDecode:
florian8844a632012-04-13 04:04:06 +00002809 case Ijk_TInval:
florian2d98d892012-04-14 20:35:17 +00002810 case Ijk_Sys_syscall:
2811 case Ijk_ClientReq:
2812 case Ijk_NoRedir:
2813 case Ijk_Yield:
2814 case Ijk_SigTRAP: {
florian8844a632012-04-13 04:04:06 +00002815 HReg dst = s390_isel_int_expr(env, IRExpr_Const(stmt->Ist.Exit.dst));
2816 addInstr(env, s390_insn_xassisted(cond, dst, guest_IA,
2817 stmt->Ist.Exit.jk));
2818 return;
2819 }
2820 default:
2821 break;
2822 }
2823
2824 /* Do we ever expect to see any other kind? */
2825 goto stmt_fail;
sewardj2019a972011-03-07 16:04:07 +00002826 }
2827
2828 /* --------- MEM FENCE --------- */
sewardja52e37e2011-04-28 18:48:06 +00002829 case Ist_MBE:
2830 switch (stmt->Ist.MBE.event) {
2831 case Imbe_Fence:
2832 addInstr(env, s390_insn_mfence());
2833 return;
2834 default:
2835 break;
2836 }
sewardj2019a972011-03-07 16:04:07 +00002837 break;
2838
2839 /* --------- Miscellaneous --------- */
2840
2841 case Ist_PutI: /* Not needed */
2842 case Ist_IMark: /* Doesn't generate any executable code */
2843 case Ist_NoOp: /* Doesn't generate any executable code */
2844 case Ist_AbiHint: /* Meaningless in IR */
2845 return;
2846
2847 default:
2848 break;
2849 }
2850
2851 stmt_fail:
2852 ppIRStmt(stmt);
2853 vpanic("s390_isel_stmt");
2854}
2855
2856
2857/*---------------------------------------------------------*/
2858/*--- ISEL: Basic block terminators (Nexts) ---*/
2859/*---------------------------------------------------------*/
2860
2861static void
florian8844a632012-04-13 04:04:06 +00002862iselNext(ISelEnv *env, IRExpr *next, IRJumpKind jk, int offsIP)
sewardj2019a972011-03-07 16:04:07 +00002863{
sewardj2019a972011-03-07 16:04:07 +00002864 if (vex_traceflags & VEX_TRACE_VCODE) {
florian8844a632012-04-13 04:04:06 +00002865 vex_printf("\n-- PUT(%d) = ", offsIP);
sewardj2019a972011-03-07 16:04:07 +00002866 ppIRExpr(next);
florian8844a632012-04-13 04:04:06 +00002867 vex_printf("; exit-");
2868 ppIRJumpKind(jk);
sewardj2019a972011-03-07 16:04:07 +00002869 vex_printf("\n");
2870 }
2871
florian8844a632012-04-13 04:04:06 +00002872 s390_amode *guest_IA = s390_amode_for_guest_state(offsIP);
2873
2874 /* Case: boring transfer to known address */
2875 if (next->tag == Iex_Const) {
2876 IRConst *cdst = next->Iex.Const.con;
2877 vassert(cdst->tag == Ico_U64);
2878 if (jk == Ijk_Boring || jk == Ijk_Call) {
2879 /* Boring transfer to known address */
2880 if (env->chaining_allowed) {
2881 /* .. almost always true .. */
2882 /* Skip the event check at the dst if this is a forwards
2883 edge. */
2884 Bool to_fast_entry
2885 = ((Addr64)cdst->Ico.U64) > env->max_ga;
2886 if (0) vex_printf("%s", to_fast_entry ? "X" : ".");
2887 addInstr(env, s390_insn_xdirect(S390_CC_ALWAYS, cdst->Ico.U64,
2888 guest_IA, to_fast_entry));
2889 } else {
2890 /* .. very occasionally .. */
2891 /* We can't use chaining, so ask for an indirect transfer,
2892 as that's the cheapest alternative that is allowable. */
2893 HReg dst = s390_isel_int_expr(env, next);
2894 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2895 Ijk_Boring));
2896 }
2897 return;
2898 }
2899 }
2900
2901 /* Case: call/return (==boring) transfer to any address */
2902 switch (jk) {
2903 case Ijk_Boring:
2904 case Ijk_Ret:
2905 case Ijk_Call: {
2906 HReg dst = s390_isel_int_expr(env, next);
2907 if (env->chaining_allowed) {
2908 addInstr(env, s390_insn_xindir(S390_CC_ALWAYS, dst, guest_IA));
2909 } else {
2910 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA,
2911 Ijk_Boring));
2912 }
2913 return;
2914 }
2915 default:
2916 break;
2917 }
2918
2919 /* Case: some other kind of transfer to any address */
2920 switch (jk) {
florian4e0083e2012-08-26 03:41:56 +00002921 case Ijk_EmFail:
florian4b8efad2012-09-02 18:07:08 +00002922 case Ijk_EmWarn:
florian65b5b3f2012-04-22 02:51:27 +00002923 case Ijk_NoDecode:
florian2d98d892012-04-14 20:35:17 +00002924 case Ijk_TInval:
florian8844a632012-04-13 04:04:06 +00002925 case Ijk_Sys_syscall:
2926 case Ijk_ClientReq:
2927 case Ijk_NoRedir:
2928 case Ijk_Yield:
2929 case Ijk_SigTRAP: {
2930 HReg dst = s390_isel_int_expr(env, next);
2931 addInstr(env, s390_insn_xassisted(S390_CC_ALWAYS, dst, guest_IA, jk));
2932 return;
2933 }
2934 default:
2935 break;
2936 }
2937
2938 vpanic("iselNext");
sewardj2019a972011-03-07 16:04:07 +00002939}
2940
2941
2942/*---------------------------------------------------------*/
2943/*--- Insn selector top-level ---*/
2944/*---------------------------------------------------------*/
2945
florianf26994a2012-04-21 03:34:54 +00002946/* Translate an entire SB to s390 code.
2947 Note: archinfo_host is a pointer to a stack-allocated variable.
2948 Do not assign it to a global variable! */
sewardj2019a972011-03-07 16:04:07 +00002949
2950HInstrArray *
2951iselSB_S390(IRSB *bb, VexArch arch_host, VexArchInfo *archinfo_host,
florian8844a632012-04-13 04:04:06 +00002952 VexAbiInfo *vbi, Int offset_host_evcheck_counter,
2953 Int offset_host_evcheck_fail_addr, Bool chaining_allowed,
2954 Bool add_profinc, Addr64 max_ga)
sewardj2019a972011-03-07 16:04:07 +00002955{
2956 UInt i, j;
2957 HReg hreg, hregHI;
2958 ISelEnv *env;
2959 UInt hwcaps_host = archinfo_host->hwcaps;
2960
florianf26994a2012-04-21 03:34:54 +00002961 /* KLUDGE: export hwcaps. */
2962 s390_host_hwcaps = hwcaps_host;
sewardj2019a972011-03-07 16:04:07 +00002963
sewardj2019a972011-03-07 16:04:07 +00002964 /* Do some sanity checks */
sewardj652b56a2011-04-13 15:38:17 +00002965 vassert((VEX_HWCAPS_S390X(hwcaps_host) & ~(VEX_HWCAPS_S390X_ALL)) == 0);
sewardj2019a972011-03-07 16:04:07 +00002966
2967 /* Make up an initial environment to use. */
2968 env = LibVEX_Alloc(sizeof(ISelEnv));
2969 env->vreg_ctr = 0;
2970
2971 /* Set up output code array. */
2972 env->code = newHInstrArray();
2973
2974 /* Copy BB's type env. */
2975 env->type_env = bb->tyenv;
2976
florianad43b3a2012-02-20 15:01:14 +00002977 /* Set up data structures for tracking guest register values. */
2978 env->first_IA_assignment = True;
2979 for (i = 0; i < NUM_TRACKED_REGS; ++i) {
2980 env->old_value[i] = 0; /* just something to have a defined value */
2981 env->old_value_valid[i] = False;
2982 }
2983
sewardj2019a972011-03-07 16:04:07 +00002984 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
2985 change as we go along. For some reason types_used has Int type -- but
2986 it should be unsigned. Internally we use an unsigned type; so we
2987 assert it here. */
2988 vassert(bb->tyenv->types_used >= 0);
2989
2990 env->n_vregmap = bb->tyenv->types_used;
2991 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2992 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2993
florian2c74d242012-09-12 19:38:42 +00002994 env->previous_bfp_rounding_mode = NULL;
florianc8e4f562012-10-27 16:19:31 +00002995 env->previous_dfp_rounding_mode = NULL;
florian2c74d242012-09-12 19:38:42 +00002996
sewardj2019a972011-03-07 16:04:07 +00002997 /* and finally ... */
2998 env->hwcaps = hwcaps_host;
2999
florian8844a632012-04-13 04:04:06 +00003000 env->max_ga = max_ga;
3001 env->chaining_allowed = chaining_allowed;
3002
sewardj2019a972011-03-07 16:04:07 +00003003 /* For each IR temporary, allocate a suitably-kinded virtual
3004 register. */
3005 j = 0;
3006 for (i = 0; i < env->n_vregmap; i++) {
3007 hregHI = hreg = INVALID_HREG;
3008 switch (bb->tyenv->types[i]) {
3009 case Ity_I1:
3010 case Ity_I8:
3011 case Ity_I16:
3012 case Ity_I32:
3013 hreg = mkHReg(j++, HRcInt64, True);
3014 break;
3015
3016 case Ity_I64:
3017 hreg = mkHReg(j++, HRcInt64, True);
3018 break;
3019
3020 case Ity_I128:
3021 hreg = mkHReg(j++, HRcInt64, True);
3022 hregHI = mkHReg(j++, HRcInt64, True);
3023 break;
3024
3025 case Ity_F32:
3026 case Ity_F64:
3027 hreg = mkHReg(j++, HRcFlt64, True);
3028 break;
3029
3030 case Ity_F128:
3031 hreg = mkHReg(j++, HRcFlt64, True);
3032 hregHI = mkHReg(j++, HRcFlt64, True);
3033 break;
3034
3035 case Ity_V128: /* fall through */
3036 default:
3037 ppIRType(bb->tyenv->types[i]);
3038 vpanic("s390_isel_sb: IRTemp type");
3039 }
3040
3041 env->vregmap[i] = hreg;
3042 env->vregmapHI[i] = hregHI;
3043 }
3044 env->vreg_ctr = j;
3045
florian8844a632012-04-13 04:04:06 +00003046 /* The very first instruction must be an event check. */
3047 s390_amode *counter, *fail_addr;
3048 counter = s390_amode_for_guest_state(offset_host_evcheck_counter);
3049 fail_addr = s390_amode_for_guest_state(offset_host_evcheck_fail_addr);
3050 addInstr(env, s390_insn_evcheck(counter, fail_addr));
3051
3052 /* Possibly a block counter increment (for profiling). At this
3053 point we don't know the address of the counter, so just pretend
3054 it is zero. It will have to be patched later, but before this
3055 translation is used, by a call to LibVEX_patchProfInc. */
3056 if (add_profinc) {
3057 addInstr(env, s390_insn_profinc());
3058 }
3059
sewardj2019a972011-03-07 16:04:07 +00003060 /* Ok, finally we can iterate over the statements. */
3061 for (i = 0; i < bb->stmts_used; i++)
3062 if (bb->stmts[i])
3063 s390_isel_stmt(env, bb->stmts[i]);
3064
florian8844a632012-04-13 04:04:06 +00003065 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
sewardj2019a972011-03-07 16:04:07 +00003066
3067 /* Record the number of vregs we used. */
3068 env->code->n_vregs = env->vreg_ctr;
3069
3070 return env->code;
3071}
3072
3073/*---------------------------------------------------------------*/
3074/*--- end host_s390_isel.c ---*/
3075/*---------------------------------------------------------------*/