blob: bf178f83df77f13bd84f29d55c373b5f2c9e372a [file] [log] [blame]
/* -*- mode: C; c-basic-offset: 3; -*- */
/*---------------------------------------------------------------*/
/*--- begin host_s390_defs.c ---*/
/*---------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright IBM Corp. 2010-2013
Copyright (C) 2012-2013 Florian Krohm (britzel@acm.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
The GNU General Public License is contained in the file COPYING.
*/
/* Contributed by Florian Krohm */
#include "libvex_basictypes.h"
#include "libvex.h"
#include "libvex_trc_values.h"
#include "libvex_s390x_common.h"
#include "main_util.h"
#include "main_globals.h"
#include "host_generic_regs.h"
#include "host_s390_defs.h"
#include "s390_disasm.h"
#include "guest_s390_defs.h" /* S390X_GUEST_OFFSET */
#include <stdarg.h>
/* KLUDGE: We need to know the hwcaps of the host when generating
code. But that info is not passed to emit_S390Instr. Only mode64 is
being passed. So, ideally, we want this passed as an argument, too.
Until then, we use a global variable. This variable is set as a side
effect of iselSB_S390. This is safe because instructions are selected
before they are emitted. */
UInt s390_host_hwcaps;
/*------------------------------------------------------------*/
/*--- Forward declarations ---*/
/*------------------------------------------------------------*/
static Bool s390_insn_is_reg_reg_move(const s390_insn *, HReg *src, HReg *dst);
static void s390_insn_map_regs(HRegRemap *, s390_insn *);
static void s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *);
static UInt s390_tchain_load64_len(void);
/*------------------------------------------------------------*/
/*--- Registers ---*/
/*------------------------------------------------------------*/
/* Decompile the given register into a static buffer and return it */
const HChar *
s390_hreg_as_string(HReg reg)
{
static HChar buf[10];
static const HChar ireg_names[16][5] = {
"%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"
};
static const HChar freg_names[16][5] = {
"%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
"%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15"
};
UInt r; /* hregNumber() returns an UInt */
r = hregNumber(reg);
/* Be generic for all virtual regs. */
if (hregIsVirtual(reg)) {
buf[0] = '\0';
switch (hregClass(reg)) {
case HRcInt64: vex_sprintf(buf, "%%vR%d", r); break;
case HRcFlt64: vex_sprintf(buf, "%%vF%d", r); break;
default: goto fail;
}
return buf;
}
/* But specific for real regs. */
vassert(r < 16);
switch (hregClass(reg)) {
case HRcInt64: return ireg_names[r];
case HRcFlt64: return freg_names[r];
default: goto fail;
}
fail: vpanic("s390_hreg_as_string");
}
/* Tell the register allocator which registers can be allocated. */
static void
s390_hreg_get_allocable(Int *nregs, HReg **arr)
{
UInt i;
/* Total number of allocable registers (all classes) */
*nregs = 16 /* GPRs */
- 1 /* r0 */
- 1 /* r12 scratch register for translation chaining support */
- 1 /* r13 guest state pointer */
- 1 /* r14 link register */
- 1 /* r15 stack pointer */
+ 16 /* FPRs */
;
*arr = LibVEX_Alloc(*nregs * sizeof(HReg));
i = 0;
/* GPR0 is not available because it is interpreted as 0, when used
as a base or index register. */
(*arr)[i++] = mkHReg(1, HRcInt64, False);
(*arr)[i++] = mkHReg(2, HRcInt64, False);
(*arr)[i++] = mkHReg(3, HRcInt64, False);
(*arr)[i++] = mkHReg(4, HRcInt64, False);
(*arr)[i++] = mkHReg(5, HRcInt64, False);
(*arr)[i++] = mkHReg(6, HRcInt64, False);
(*arr)[i++] = mkHReg(7, HRcInt64, False);
(*arr)[i++] = mkHReg(8, HRcInt64, False);
(*arr)[i++] = mkHReg(9, HRcInt64, False);
/* GPR10 and GPR11 are used for instructions that use register pairs.
Otherwise, they are available to the allocator */
(*arr)[i++] = mkHReg(10, HRcInt64, False);
(*arr)[i++] = mkHReg(11, HRcInt64, False);
/* GPR12 is not available because it us used as a scratch register
in translation chaining. */
/* GPR13 is not available because it is used as guest state pointer */
/* GPR14 is not available because it is used as link register */
/* GPR15 is not available because it is used as stack pointer */
/* Add the available real (non-virtual) FPRs */
(*arr)[i++] = mkHReg(0, HRcFlt64, False);
(*arr)[i++] = mkHReg(1, HRcFlt64, False);
(*arr)[i++] = mkHReg(2, HRcFlt64, False);
(*arr)[i++] = mkHReg(3, HRcFlt64, False);
(*arr)[i++] = mkHReg(4, HRcFlt64, False);
(*arr)[i++] = mkHReg(5, HRcFlt64, False);
(*arr)[i++] = mkHReg(6, HRcFlt64, False);
(*arr)[i++] = mkHReg(7, HRcFlt64, False);
(*arr)[i++] = mkHReg(8, HRcFlt64, False);
(*arr)[i++] = mkHReg(9, HRcFlt64, False);
(*arr)[i++] = mkHReg(10, HRcFlt64, False);
(*arr)[i++] = mkHReg(11, HRcFlt64, False);
(*arr)[i++] = mkHReg(12, HRcFlt64, False);
(*arr)[i++] = mkHReg(13, HRcFlt64, False);
(*arr)[i++] = mkHReg(14, HRcFlt64, False);
(*arr)[i++] = mkHReg(15, HRcFlt64, False);
/* FPR12 - FPR15 are also used as register pairs for 128-bit
floating point operations */
}
/* Return the real register that holds the guest state pointer */
HReg
s390_hreg_guest_state_pointer(void)
{
return mkHReg(S390_REGNO_GUEST_STATE_POINTER, HRcInt64, False);
}
/* Is VALUE within the domain of a 20-bit signed integer. */
static __inline__ Bool
fits_signed_20bit(Int value)
{
return ((value << 12) >> 12) == value;
}
/* Is VALUE within the domain of a 12-bit unsigned integer. */
static __inline__ Bool
fits_unsigned_12bit(Int value)
{
return (value & 0xFFF) == value;
}
/*------------------------------------------------------------*/
/*--- Addressing modes (amodes) ---*/
/*------------------------------------------------------------*/
/* Construct a b12 amode. */
s390_amode *
s390_amode_b12(Int d, HReg b)
{
s390_amode *am = LibVEX_Alloc(sizeof(s390_amode));
vassert(fits_unsigned_12bit(d));
am->tag = S390_AMODE_B12;
am->d = d;
am->b = b;
am->x = mkHReg(0, HRcInt64, False); /* hregNumber(am->x) == 0 */
return am;
}
/* Construct a b20 amode. */
s390_amode *
s390_amode_b20(Int d, HReg b)
{
s390_amode *am = LibVEX_Alloc(sizeof(s390_amode));
vassert(fits_signed_20bit(d));
am->tag = S390_AMODE_B20;
am->d = d;
am->b = b;
am->x = mkHReg(0, HRcInt64, False); /* hregNumber(am->x) == 0 */
return am;
}
/* Construct a bx12 amode. */
s390_amode *
s390_amode_bx12(Int d, HReg b, HReg x)
{
s390_amode *am = LibVEX_Alloc(sizeof(s390_amode));
vassert(fits_unsigned_12bit(d));
vassert(hregNumber(b) != 0);
vassert(hregNumber(x) != 0);
am->tag = S390_AMODE_BX12;
am->d = d;
am->b = b;
am->x = x;
return am;
}
/* Construct a bx20 amode. */
s390_amode *
s390_amode_bx20(Int d, HReg b, HReg x)
{
s390_amode *am = LibVEX_Alloc(sizeof(s390_amode));
vassert(fits_signed_20bit(d));
vassert(hregNumber(b) != 0);
vassert(hregNumber(x) != 0);
am->tag = S390_AMODE_BX20;
am->d = d;
am->b = b;
am->x = x;
return am;
}
/* Construct an AMODE for accessing the guest state at OFFSET.
OFFSET can be at most 3 * sizeof(VexGuestS390XState) + LibVEX_N_SPILL_BYTES
which may be too large for a B12 addressing mode.
Use a B20 amode as a fallback which will be safe for any offset.
*/
s390_amode *
s390_amode_for_guest_state(Int offset)
{
if (fits_unsigned_12bit(offset))
return s390_amode_b12(offset, s390_hreg_guest_state_pointer());
if (fits_signed_20bit(offset))
return s390_amode_b20(offset, s390_hreg_guest_state_pointer());
vpanic("invalid guest state offset");
}
/* Decompile the given amode into a static buffer and return it. */
const HChar *
s390_amode_as_string(const s390_amode *am)
{
static HChar buf[30];
HChar *p;
buf[0] = '\0';
p = buf;
switch (am->tag) {
case S390_AMODE_B12:
case S390_AMODE_B20:
vex_sprintf(p, "%d(%s)", am->d, s390_hreg_as_string(am->b));
break;
case S390_AMODE_BX12:
case S390_AMODE_BX20:
/* s390_hreg_as_string returns pointer to local buffer. Need to
split this into two printfs */
p += vex_sprintf(p, "%d(%s,", am->d, s390_hreg_as_string(am->x));
vex_sprintf(p, "%s)", s390_hreg_as_string(am->b));
break;
default:
vpanic("s390_amode_as_string");
}
return buf;
}
/* Helper function for s390_amode_is_sane */
static __inline__ Bool
is_virtual_gpr(HReg reg)
{
return hregIsVirtual(reg) && hregClass(reg) == HRcInt64;
}
/* Sanity check for an amode */
Bool
s390_amode_is_sane(const s390_amode *am)
{
switch (am->tag) {
case S390_AMODE_B12:
return is_virtual_gpr(am->b) && fits_unsigned_12bit(am->d);
case S390_AMODE_B20:
return is_virtual_gpr(am->b) && fits_signed_20bit(am->d);
case S390_AMODE_BX12:
return is_virtual_gpr(am->b) && is_virtual_gpr(am->x) &&
fits_unsigned_12bit(am->d);
case S390_AMODE_BX20:
return is_virtual_gpr(am->b) && is_virtual_gpr(am->x) &&
fits_signed_20bit(am->d);
default:
vpanic("s390_amode_is_sane");
}
}
/* Record the register use of an amode */
static void
s390_amode_get_reg_usage(HRegUsage *u, const s390_amode *am)
{
switch (am->tag) {
case S390_AMODE_B12:
case S390_AMODE_B20:
addHRegUse(u, HRmRead, am->b);
return;
case S390_AMODE_BX12:
case S390_AMODE_BX20:
addHRegUse(u, HRmRead, am->b);
addHRegUse(u, HRmRead, am->x);
return;
default:
vpanic("s390_amode_get_reg_usage");
}
}
static void
s390_amode_map_regs(HRegRemap *m, s390_amode *am)
{
switch (am->tag) {
case S390_AMODE_B12:
case S390_AMODE_B20:
am->b = lookupHRegRemap(m, am->b);
return;
case S390_AMODE_BX12:
case S390_AMODE_BX20:
am->b = lookupHRegRemap(m, am->b);
am->x = lookupHRegRemap(m, am->x);
return;
default:
vpanic("s390_amode_map_regs");
}
}
void
ppS390AMode(s390_amode *am)
{
vex_printf("%s", s390_amode_as_string(am));
}
void
ppS390Instr(s390_insn *insn, Bool mode64)
{
vex_printf("%s", s390_insn_as_string(insn));
}
void
ppHRegS390(HReg reg)
{
vex_printf("%s", s390_hreg_as_string(reg));
}
/*------------------------------------------------------------*/
/*--- Helpers for register allocation ---*/
/*------------------------------------------------------------*/
/* Called once per translation. */
void
getAllocableRegs_S390(Int *nregs, HReg **arr, Bool mode64)
{
s390_hreg_get_allocable(nregs, arr);
}
/* Tell the register allocator how the given instruction uses the registers
it refers to. */
void
getRegUsage_S390Instr(HRegUsage *u, s390_insn *insn, Bool mode64)
{
s390_insn_get_reg_usage(u, insn);
}
/* Map the registers of the given instruction */
void
mapRegs_S390Instr(HRegRemap *m, s390_insn *insn, Bool mode64)
{
s390_insn_map_regs(m, insn);
}
/* Figure out if the given insn represents a reg-reg move, and if so
assign the source and destination to *src and *dst. If in doubt say No.
Used by the register allocator to do move coalescing. */
Bool
isMove_S390Instr(s390_insn *insn, HReg *src, HReg *dst)
{
return s390_insn_is_reg_reg_move(insn, src, dst);
}
/* Generate s390 spill/reload instructions under the direction of the
register allocator. Note it's critical these don't write the
condition codes. This is like an Ist_Put */
void
genSpill_S390(HInstr **i1, HInstr **i2, HReg rreg, Int offsetB, Bool mode64)
{
s390_amode *am;
vassert(offsetB >= 0);
vassert(!hregIsVirtual(rreg));
*i1 = *i2 = NULL;
am = s390_amode_for_guest_state(offsetB);
switch (hregClass(rreg)) {
case HRcInt64:
case HRcFlt64:
*i1 = s390_insn_store(8, am, rreg);
return;
default:
ppHRegClass(hregClass(rreg));
vpanic("genSpill_S390: unimplemented regclass");
}
}
/* This is like an Iex_Get */
void
genReload_S390(HInstr **i1, HInstr **i2, HReg rreg, Int offsetB, Bool mode64)
{
s390_amode *am;
vassert(offsetB >= 0);
vassert(!hregIsVirtual(rreg));
*i1 = *i2 = NULL;
am = s390_amode_for_guest_state(offsetB);
switch (hregClass(rreg)) {
case HRcInt64:
case HRcFlt64:
*i1 = s390_insn_load(8, rreg, am);
return;
default:
ppHRegClass(hregClass(rreg));
vpanic("genReload_S390: unimplemented regclass");
}
}
/* Helper function for s390_insn_get_reg_usage */
static void
s390_opnd_RMI_get_reg_usage(HRegUsage *u, s390_opnd_RMI op)
{
switch (op.tag) {
case S390_OPND_REG:
addHRegUse(u, HRmRead, op.variant.reg);
break;
case S390_OPND_AMODE:
s390_amode_get_reg_usage(u, op.variant.am);
break;
case S390_OPND_IMMEDIATE:
break;
default:
vpanic("s390_opnd_RMI_get_reg_usage");
}
}
/* Tell the register allocator how the given insn uses the registers */
static void
s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
{
initHRegUsage(u);
switch (insn->tag) {
case S390_INSN_LOAD:
addHRegUse(u, HRmWrite, insn->variant.load.dst);
s390_amode_get_reg_usage(u, insn->variant.load.src);
break;
case S390_INSN_LOAD_IMMEDIATE:
addHRegUse(u, HRmWrite, insn->variant.load_immediate.dst);
break;
case S390_INSN_STORE:
addHRegUse(u, HRmRead, insn->variant.store.src);
s390_amode_get_reg_usage(u, insn->variant.store.dst);
break;
case S390_INSN_MOVE:
addHRegUse(u, HRmRead, insn->variant.move.src);
addHRegUse(u, HRmWrite, insn->variant.move.dst);
break;
case S390_INSN_MEMCPY:
s390_amode_get_reg_usage(u, insn->variant.memcpy.src);
s390_amode_get_reg_usage(u, insn->variant.memcpy.dst);
break;
case S390_INSN_COND_MOVE:
s390_opnd_RMI_get_reg_usage(u, insn->variant.cond_move.src);
addHRegUse(u, HRmWrite, insn->variant.cond_move.dst);
break;
case S390_INSN_ALU:
addHRegUse(u, HRmWrite, insn->variant.alu.dst);
addHRegUse(u, HRmRead, insn->variant.alu.dst); /* op1 */
s390_opnd_RMI_get_reg_usage(u, insn->variant.alu.op2);
break;
case S390_INSN_SMUL:
case S390_INSN_UMUL:
addHRegUse(u, HRmRead, insn->variant.mul.dst_lo); /* op1 */
addHRegUse(u, HRmWrite, insn->variant.mul.dst_lo);
addHRegUse(u, HRmWrite, insn->variant.mul.dst_hi);
s390_opnd_RMI_get_reg_usage(u, insn->variant.mul.op2);
break;
case S390_INSN_SDIV:
case S390_INSN_UDIV:
addHRegUse(u, HRmRead, insn->variant.div.op1_lo);
addHRegUse(u, HRmRead, insn->variant.div.op1_hi);
addHRegUse(u, HRmWrite, insn->variant.div.op1_lo);
addHRegUse(u, HRmWrite, insn->variant.div.op1_hi);
s390_opnd_RMI_get_reg_usage(u, insn->variant.div.op2);
break;
case S390_INSN_DIVS:
addHRegUse(u, HRmRead, insn->variant.divs.op1);
addHRegUse(u, HRmWrite, insn->variant.divs.op1); /* quotient */
addHRegUse(u, HRmWrite, insn->variant.divs.rem); /* remainder */
s390_opnd_RMI_get_reg_usage(u, insn->variant.divs.op2);
break;
case S390_INSN_CLZ:
addHRegUse(u, HRmWrite, insn->variant.clz.num_bits);
addHRegUse(u, HRmWrite, insn->variant.clz.clobber);
s390_opnd_RMI_get_reg_usage(u, insn->variant.clz.src);
break;
case S390_INSN_UNOP:
addHRegUse(u, HRmWrite, insn->variant.unop.dst);
s390_opnd_RMI_get_reg_usage(u, insn->variant.unop.src);
break;
case S390_INSN_TEST:
s390_opnd_RMI_get_reg_usage(u, insn->variant.test.src);
break;
case S390_INSN_CC2BOOL:
addHRegUse(u, HRmWrite, insn->variant.cc2bool.dst);
break;
case S390_INSN_CAS:
addHRegUse(u, HRmRead, insn->variant.cas.op1);
s390_amode_get_reg_usage(u, insn->variant.cas.op2);
addHRegUse(u, HRmRead, insn->variant.cas.op3);
addHRegUse(u, HRmWrite, insn->variant.cas.old_mem);
break;
case S390_INSN_CDAS: {
s390_cdas *cdas = insn->variant.cdas.details;
addHRegUse(u, HRmRead, cdas->op1_high);
addHRegUse(u, HRmRead, cdas->op1_low);
s390_amode_get_reg_usage(u, cdas->op2);
addHRegUse(u, HRmRead, cdas->op3_high);
addHRegUse(u, HRmRead, cdas->op3_low);
addHRegUse(u, HRmWrite, cdas->old_mem_high);
addHRegUse(u, HRmWrite, cdas->old_mem_low);
addHRegUse(u, HRmWrite, cdas->scratch);
break;
}
case S390_INSN_COMPARE:
addHRegUse(u, HRmRead, insn->variant.compare.src1);
s390_opnd_RMI_get_reg_usage(u, insn->variant.compare.src2);
break;
case S390_INSN_HELPER_CALL: {
UInt i;
/* Assume that all volatile registers are clobbered. ABI says,
volatile registers are: r0 - r5. Valgrind's register allocator
does not know about r0, so we can leave that out */
for (i = 1; i <= 5; ++i) {
addHRegUse(u, HRmWrite, mkHReg(i, HRcInt64, False));
}
/* Ditto for floating point registers. f0 - f7 are volatile */
for (i = 0; i <= 7; ++i) {
addHRegUse(u, HRmWrite, mkHReg(i, HRcFlt64, False));
}
/* The registers that are used for passing arguments will be read.
Not all of them may, but in general we need to assume that. */
for (i = 0; i < insn->variant.helper_call.details->num_args; ++i) {
addHRegUse(u, HRmRead, mkHReg(s390_gprno_from_arg_index(i),
HRcInt64, False));
}
/* s390_insn_helper_call_emit also reads / writes the link register
and stack pointer. But those registers are not visible to the
register allocator. So we don't need to do anything for them. */
break;
}
case S390_INSN_BFP_TRIOP:
addHRegUse(u, HRmWrite, insn->variant.bfp_triop.dst);
addHRegUse(u, HRmRead, insn->variant.bfp_triop.dst); /* first */
addHRegUse(u, HRmRead, insn->variant.bfp_triop.op2); /* second */
addHRegUse(u, HRmRead, insn->variant.bfp_triop.op3); /* third */
break;
case S390_INSN_BFP_BINOP:
addHRegUse(u, HRmWrite, insn->variant.bfp_binop.dst_hi);
addHRegUse(u, HRmRead, insn->variant.bfp_binop.dst_hi); /* left */
addHRegUse(u, HRmRead, insn->variant.bfp_binop.op2_hi); /* right */
if (insn->size == 16) {
addHRegUse(u, HRmWrite, insn->variant.bfp_binop.dst_lo);
addHRegUse(u, HRmRead, insn->variant.bfp_binop.dst_lo); /* left */
addHRegUse(u, HRmRead, insn->variant.bfp_binop.op2_lo); /* right */
}
break;
case S390_INSN_BFP_UNOP:
addHRegUse(u, HRmWrite, insn->variant.bfp_unop.dst_hi);
addHRegUse(u, HRmRead, insn->variant.bfp_unop.op_hi); /* operand */
if (insn->size == 16) {
addHRegUse(u, HRmWrite, insn->variant.bfp_unop.dst_lo);
addHRegUse(u, HRmRead, insn->variant.bfp_unop.op_lo); /* operand */
}
break;
case S390_INSN_BFP_COMPARE:
addHRegUse(u, HRmWrite, insn->variant.bfp_compare.dst);
addHRegUse(u, HRmRead, insn->variant.bfp_compare.op1_hi); /* left */
addHRegUse(u, HRmRead, insn->variant.bfp_compare.op2_hi); /* right */
if (insn->size == 16) {
addHRegUse(u, HRmRead, insn->variant.bfp_compare.op1_lo); /* left */
addHRegUse(u, HRmRead, insn->variant.bfp_compare.op2_lo); /* right */
}
break;
case S390_INSN_BFP_CONVERT:
addHRegUse(u, HRmWrite, insn->variant.bfp_convert.dst_hi);
if (! hregIsInvalid(insn->variant.bfp_convert.dst_lo))
addHRegUse(u, HRmWrite, insn->variant.bfp_convert.dst_lo);
addHRegUse(u, HRmRead, insn->variant.bfp_convert.op_hi);
if (! hregIsInvalid(insn->variant.bfp_convert.op_lo))
addHRegUse(u, HRmRead, insn->variant.bfp_convert.op_lo);
break;
case S390_INSN_DFP_BINOP: {
s390_dfp_binop *dfp_binop = insn->variant.dfp_binop.details;
addHRegUse(u, HRmWrite, dfp_binop->dst_hi);
addHRegUse(u, HRmRead, dfp_binop->op2_hi); /* left */
addHRegUse(u, HRmRead, dfp_binop->op3_hi); /* right */
if (insn->size == 16) {
addHRegUse(u, HRmWrite, dfp_binop->dst_lo);
addHRegUse(u, HRmRead, dfp_binop->op2_lo); /* left */
addHRegUse(u, HRmRead, dfp_binop->op3_lo); /* right */
}
break;
}
case S390_INSN_DFP_UNOP:
addHRegUse(u, HRmWrite, insn->variant.dfp_unop.dst_hi);
addHRegUse(u, HRmRead, insn->variant.dfp_unop.op_hi); /* operand */
if (insn->size == 16) {
addHRegUse(u, HRmWrite, insn->variant.dfp_unop.dst_lo);
addHRegUse(u, HRmRead, insn->variant.dfp_unop.op_lo); /* operand */
}
break;
case S390_INSN_DFP_INTOP:
addHRegUse(u, HRmWrite, insn->variant.dfp_intop.dst_hi);
addHRegUse(u, HRmRead, insn->variant.dfp_intop.op2);
addHRegUse(u, HRmRead, insn->variant.dfp_intop.op3_hi);
if (insn->size == 16) {
addHRegUse(u, HRmWrite, insn->variant.dfp_intop.dst_lo);
addHRegUse(u, HRmRead, insn->variant.dfp_intop.op3_lo);
}
break;
case S390_INSN_DFP_COMPARE:
addHRegUse(u, HRmWrite, insn->variant.dfp_compare.dst);
addHRegUse(u, HRmRead, insn->variant.dfp_compare.op1_hi); /* left */
addHRegUse(u, HRmRead, insn->variant.dfp_compare.op2_hi); /* right */
if (insn->size == 16) {
addHRegUse(u, HRmRead, insn->variant.dfp_compare.op1_lo); /* left */
addHRegUse(u, HRmRead, insn->variant.dfp_compare.op2_lo); /* right */
}
break;
case S390_INSN_DFP_CONVERT:
addHRegUse(u, HRmWrite, insn->variant.dfp_convert.dst_hi);
if (! hregIsInvalid(insn->variant.dfp_convert.dst_lo))
addHRegUse(u, HRmWrite, insn->variant.dfp_convert.dst_lo);
addHRegUse(u, HRmRead, insn->variant.dfp_convert.op_hi); /* operand */
if (! hregIsInvalid(insn->variant.dfp_convert.op_lo))
addHRegUse(u, HRmRead, insn->variant.dfp_convert.op_lo); /* operand */
break;
case S390_INSN_DFP_REROUND:
addHRegUse(u, HRmWrite, insn->variant.dfp_reround.dst_hi);
addHRegUse(u, HRmRead, insn->variant.dfp_reround.op2); /* left */
addHRegUse(u, HRmRead, insn->variant.dfp_reround.op3_hi); /* right */
if (insn->size == 16) {
addHRegUse(u, HRmWrite, insn->variant.dfp_reround.dst_lo);
addHRegUse(u, HRmRead, insn->variant.dfp_reround.op3_lo); /* right */
}
break;
case S390_INSN_FP_CONVERT: {
s390_fp_convert *fp_convert = insn->variant.fp_convert.details;
addHRegUse(u, HRmWrite, fp_convert->dst_hi);
if (! hregIsInvalid(fp_convert->dst_lo))
addHRegUse(u, HRmWrite, fp_convert->dst_lo);
addHRegUse(u, HRmRead, fp_convert->op_hi);
if (! hregIsInvalid(fp_convert->op_lo))
addHRegUse(u, HRmRead, fp_convert->op_lo);
addHRegUse(u, HRmWrite, fp_convert->r1);
break;
}
case S390_INSN_MIMM:
s390_amode_get_reg_usage(u, insn->variant.mimm.dst);
break;
case S390_INSN_MADD:
s390_amode_get_reg_usage(u, insn->variant.madd.dst);
break;
case S390_INSN_MFENCE:
break;
case S390_INSN_SET_FPC_BFPRM:
addHRegUse(u, HRmRead, insn->variant.set_fpc_bfprm.mode);
break;
case S390_INSN_SET_FPC_DFPRM:
addHRegUse(u, HRmRead, insn->variant.set_fpc_dfprm.mode);
break;
case S390_INSN_EVCHECK:
s390_amode_get_reg_usage(u, insn->variant.evcheck.counter);
s390_amode_get_reg_usage(u, insn->variant.evcheck.fail_addr);
break;
case S390_INSN_PROFINC:
/* Does not use any register visible to the register allocator */
break;
case S390_INSN_XDIRECT:
s390_amode_get_reg_usage(u, insn->variant.xdirect.guest_IA);
break;
case S390_INSN_XINDIR:
addHRegUse(u, HRmRead, insn->variant.xindir.dst);
s390_amode_get_reg_usage(u, insn->variant.xindir.guest_IA);
break;
case S390_INSN_XASSISTED:
addHRegUse(u, HRmRead, insn->variant.xassisted.dst);
s390_amode_get_reg_usage(u, insn->variant.xassisted.guest_IA);
break;
default:
vpanic("s390_insn_get_reg_usage");
}
}
/* Helper function for s390_insn_map_regs */
static void
s390_opnd_RMI_map_regs(HRegRemap *m, s390_opnd_RMI *op)
{
switch (op->tag) {
case S390_OPND_REG:
op->variant.reg = lookupHRegRemap(m, op->variant.reg);
break;
case S390_OPND_IMMEDIATE:
break;
case S390_OPND_AMODE:
s390_amode_map_regs(m, op->variant.am);
break;
default:
vpanic("s390_opnd_RMI_map_regs");
}
}
static void
s390_insn_map_regs(HRegRemap *m, s390_insn *insn)
{
switch (insn->tag) {
case S390_INSN_LOAD:
insn->variant.load.dst = lookupHRegRemap(m, insn->variant.load.dst);
s390_amode_map_regs(m, insn->variant.load.src);
break;
case S390_INSN_STORE:
s390_amode_map_regs(m, insn->variant.store.dst);
insn->variant.store.src = lookupHRegRemap(m, insn->variant.store.src);
break;
case S390_INSN_MOVE:
insn->variant.move.dst = lookupHRegRemap(m, insn->variant.move.dst);
insn->variant.move.src = lookupHRegRemap(m, insn->variant.move.src);
break;
case S390_INSN_MEMCPY:
s390_amode_map_regs(m, insn->variant.memcpy.dst);
s390_amode_map_regs(m, insn->variant.memcpy.src);
break;
case S390_INSN_COND_MOVE:
insn->variant.cond_move.dst = lookupHRegRemap(m, insn->variant.cond_move.dst);
s390_opnd_RMI_map_regs(m, &insn->variant.cond_move.src);
break;
case S390_INSN_LOAD_IMMEDIATE:
insn->variant.load_immediate.dst =
lookupHRegRemap(m, insn->variant.load_immediate.dst);
break;
case S390_INSN_ALU:
insn->variant.alu.dst = lookupHRegRemap(m, insn->variant.alu.dst);
s390_opnd_RMI_map_regs(m, &insn->variant.alu.op2);
break;
case S390_INSN_SMUL:
case S390_INSN_UMUL:
insn->variant.mul.dst_hi = lookupHRegRemap(m, insn->variant.mul.dst_hi);
insn->variant.mul.dst_lo = lookupHRegRemap(m, insn->variant.mul.dst_lo);
s390_opnd_RMI_map_regs(m, &insn->variant.mul.op2);
break;
case S390_INSN_SDIV:
case S390_INSN_UDIV:
insn->variant.div.op1_hi = lookupHRegRemap(m, insn->variant.div.op1_hi);
insn->variant.div.op1_lo = lookupHRegRemap(m, insn->variant.div.op1_lo);
s390_opnd_RMI_map_regs(m, &insn->variant.div.op2);
break;
case S390_INSN_DIVS:
insn->variant.divs.op1 = lookupHRegRemap(m, insn->variant.divs.op1);
insn->variant.divs.rem = lookupHRegRemap(m, insn->variant.divs.rem);
s390_opnd_RMI_map_regs(m, &insn->variant.divs.op2);
break;
case S390_INSN_CLZ:
insn->variant.clz.num_bits = lookupHRegRemap(m, insn->variant.clz.num_bits);
insn->variant.clz.clobber = lookupHRegRemap(m, insn->variant.clz.clobber);
s390_opnd_RMI_map_regs(m, &insn->variant.clz.src);
break;
case S390_INSN_UNOP:
insn->variant.unop.dst = lookupHRegRemap(m, insn->variant.unop.dst);
s390_opnd_RMI_map_regs(m, &insn->variant.unop.src);
break;
case S390_INSN_TEST:
s390_opnd_RMI_map_regs(m, &insn->variant.test.src);
break;
case S390_INSN_CC2BOOL:
insn->variant.cc2bool.dst = lookupHRegRemap(m, insn->variant.cc2bool.dst);
break;
case S390_INSN_CAS:
insn->variant.cas.op1 = lookupHRegRemap(m, insn->variant.cas.op1);
s390_amode_map_regs(m, insn->variant.cas.op2);
insn->variant.cas.op3 = lookupHRegRemap(m, insn->variant.cas.op3);
insn->variant.cas.old_mem = lookupHRegRemap(m, insn->variant.cas.old_mem);
break;
case S390_INSN_CDAS: {
s390_cdas *cdas = insn->variant.cdas.details;
cdas->op1_high = lookupHRegRemap(m, cdas->op1_high);
cdas->op1_low = lookupHRegRemap(m, cdas->op1_low);
s390_amode_map_regs(m, cdas->op2);
cdas->op3_high = lookupHRegRemap(m, cdas->op3_high);
cdas->op3_low = lookupHRegRemap(m, cdas->op3_low);
cdas->old_mem_high = lookupHRegRemap(m, cdas->old_mem_high);
cdas->old_mem_low = lookupHRegRemap(m, cdas->old_mem_low);
cdas->scratch = lookupHRegRemap(m, cdas->scratch);
break;
}
case S390_INSN_COMPARE:
insn->variant.compare.src1 = lookupHRegRemap(m, insn->variant.compare.src1);
s390_opnd_RMI_map_regs(m, &insn->variant.compare.src2);
break;
case S390_INSN_HELPER_CALL:
/* s390_insn_helper_call_emit also reads / writes the link register
and stack pointer. But those registers are not visible to the
register allocator. So we don't need to do anything for them.
As for the arguments of the helper call -- they will be loaded into
non-virtual registers. Again, we don't need to do anything for those
here. */
break;
case S390_INSN_BFP_TRIOP:
insn->variant.bfp_triop.dst =
lookupHRegRemap(m, insn->variant.bfp_triop.dst);
insn->variant.bfp_triop.op2 =
lookupHRegRemap(m, insn->variant.bfp_triop.op2);
insn->variant.bfp_triop.op3 =
lookupHRegRemap(m, insn->variant.bfp_triop.op3);
break;
case S390_INSN_BFP_BINOP:
insn->variant.bfp_binop.dst_hi =
lookupHRegRemap(m, insn->variant.bfp_binop.dst_hi);
insn->variant.bfp_binop.op2_hi =
lookupHRegRemap(m, insn->variant.bfp_binop.op2_hi);
if (insn->size == 16) {
insn->variant.bfp_binop.dst_lo =
lookupHRegRemap(m, insn->variant.bfp_binop.dst_lo);
insn->variant.bfp_binop.op2_lo =
lookupHRegRemap(m, insn->variant.bfp_binop.op2_lo);
}
break;
case S390_INSN_BFP_UNOP:
insn->variant.bfp_unop.dst_hi =
lookupHRegRemap(m, insn->variant.bfp_unop.dst_hi);
insn->variant.bfp_unop.op_hi =
lookupHRegRemap(m, insn->variant.bfp_unop.op_hi);
if (insn->size == 16) {
insn->variant.bfp_unop.dst_lo =
lookupHRegRemap(m, insn->variant.bfp_unop.dst_lo);
insn->variant.bfp_unop.op_lo =
lookupHRegRemap(m, insn->variant.bfp_unop.op_lo);
}
break;
case S390_INSN_BFP_COMPARE:
insn->variant.bfp_compare.dst =
lookupHRegRemap(m, insn->variant.bfp_compare.dst);
insn->variant.bfp_compare.op1_hi =
lookupHRegRemap(m, insn->variant.bfp_compare.op1_hi);
insn->variant.bfp_compare.op2_hi =
lookupHRegRemap(m, insn->variant.bfp_compare.op2_hi);
if (insn->size == 16) {
insn->variant.bfp_compare.op1_lo =
lookupHRegRemap(m, insn->variant.bfp_compare.op1_lo);
insn->variant.bfp_compare.op2_lo =
lookupHRegRemap(m, insn->variant.bfp_compare.op2_lo);
}
break;
case S390_INSN_BFP_CONVERT:
insn->variant.bfp_convert.dst_hi =
lookupHRegRemap(m, insn->variant.bfp_convert.dst_hi);
if (! hregIsInvalid(insn->variant.bfp_convert.dst_lo))
insn->variant.bfp_convert.dst_lo =
lookupHRegRemap(m, insn->variant.bfp_convert.dst_lo);
insn->variant.bfp_convert.op_hi =
lookupHRegRemap(m, insn->variant.bfp_convert.op_hi);
if (! hregIsInvalid(insn->variant.bfp_convert.op_lo))
insn->variant.bfp_convert.op_lo =
lookupHRegRemap(m, insn->variant.bfp_convert.op_lo);
break;
case S390_INSN_DFP_BINOP: {
s390_dfp_binop *dfp_binop = insn->variant.dfp_binop.details;
dfp_binop->dst_hi = lookupHRegRemap(m, dfp_binop->dst_hi);
dfp_binop->op2_hi = lookupHRegRemap(m, dfp_binop->op2_hi);
dfp_binop->op3_hi = lookupHRegRemap(m, dfp_binop->op3_hi);
if (insn->size == 16) {
dfp_binop->dst_lo = lookupHRegRemap(m, dfp_binop->dst_lo);
dfp_binop->op2_lo = lookupHRegRemap(m, dfp_binop->op2_lo);
dfp_binop->op3_lo = lookupHRegRemap(m, dfp_binop->op3_lo);
}
break;
}
case S390_INSN_DFP_UNOP:
insn->variant.dfp_unop.dst_hi =
lookupHRegRemap(m, insn->variant.dfp_unop.dst_hi);
insn->variant.dfp_unop.op_hi =
lookupHRegRemap(m, insn->variant.dfp_unop.op_hi);
if (insn->size == 16) {
insn->variant.dfp_unop.dst_lo =
lookupHRegRemap(m, insn->variant.dfp_unop.dst_lo);
insn->variant.dfp_unop.op_lo =
lookupHRegRemap(m, insn->variant.dfp_unop.op_lo);
}
break;
case S390_INSN_DFP_INTOP:
insn->variant.dfp_intop.dst_hi =
lookupHRegRemap(m, insn->variant.dfp_intop.dst_hi);
insn->variant.dfp_intop.op2 =
lookupHRegRemap(m, insn->variant.dfp_intop.op2);
insn->variant.dfp_intop.op3_hi =
lookupHRegRemap(m, insn->variant.dfp_intop.op3_hi);
if (insn->size == 16) {
insn->variant.dfp_intop.dst_lo =
lookupHRegRemap(m, insn->variant.dfp_intop.dst_lo);
insn->variant.dfp_intop.op3_lo =
lookupHRegRemap(m, insn->variant.dfp_intop.op3_lo);
}
break;
case S390_INSN_DFP_COMPARE:
insn->variant.dfp_compare.dst =
lookupHRegRemap(m, insn->variant.dfp_compare.dst);
insn->variant.dfp_compare.op1_hi =
lookupHRegRemap(m, insn->variant.dfp_compare.op1_hi);
insn->variant.dfp_compare.op2_hi =
lookupHRegRemap(m, insn->variant.dfp_compare.op2_hi);
if (insn->size == 16) {
insn->variant.dfp_compare.op1_lo =
lookupHRegRemap(m, insn->variant.dfp_compare.op1_lo);
insn->variant.dfp_compare.op2_lo =
lookupHRegRemap(m, insn->variant.dfp_compare.op2_lo);
}
break;
case S390_INSN_DFP_CONVERT:
insn->variant.dfp_convert.dst_hi =
lookupHRegRemap(m, insn->variant.dfp_convert.dst_hi);
if (! hregIsInvalid(insn->variant.dfp_convert.dst_lo))
insn->variant.dfp_convert.dst_lo =
lookupHRegRemap(m, insn->variant.dfp_convert.dst_lo);
insn->variant.dfp_convert.op_hi =
lookupHRegRemap(m, insn->variant.dfp_convert.op_hi);
if (! hregIsInvalid(insn->variant.dfp_convert.op_lo))
insn->variant.dfp_convert.op_lo =
lookupHRegRemap(m, insn->variant.dfp_convert.op_lo);
break;
case S390_INSN_DFP_REROUND:
insn->variant.dfp_reround.dst_hi =
lookupHRegRemap(m, insn->variant.dfp_reround.dst_hi);
insn->variant.dfp_reround.op2 =
lookupHRegRemap(m, insn->variant.dfp_reround.op2);
insn->variant.dfp_reround.op3_hi =
lookupHRegRemap(m, insn->variant.dfp_reround.op3_hi);
if (insn->size == 16) {
insn->variant.dfp_reround.dst_lo =
lookupHRegRemap(m, insn->variant.dfp_reround.dst_lo);
insn->variant.dfp_reround.op3_lo =
lookupHRegRemap(m, insn->variant.dfp_reround.op3_lo);
}
break;
case S390_INSN_FP_CONVERT: {
s390_fp_convert *fp_convert = insn->variant.fp_convert.details;
fp_convert->dst_hi = lookupHRegRemap(m, fp_convert->dst_hi);
if (! hregIsInvalid(fp_convert->dst_lo))
fp_convert->dst_lo = lookupHRegRemap(m, fp_convert->dst_lo);
fp_convert->op_hi = lookupHRegRemap(m, fp_convert->op_hi);
if (! hregIsInvalid(fp_convert->op_lo))
fp_convert->op_lo = lookupHRegRemap(m, fp_convert->op_lo);
fp_convert->r1 = lookupHRegRemap(m, fp_convert->r1);
break;
}
case S390_INSN_MIMM:
s390_amode_map_regs(m, insn->variant.mimm.dst);
break;
case S390_INSN_MADD:
s390_amode_map_regs(m, insn->variant.madd.dst);
break;
case S390_INSN_MFENCE:
break;
case S390_INSN_SET_FPC_BFPRM:
insn->variant.set_fpc_bfprm.mode =
lookupHRegRemap(m, insn->variant.set_fpc_bfprm.mode);
break;
case S390_INSN_SET_FPC_DFPRM:
insn->variant.set_fpc_dfprm.mode =
lookupHRegRemap(m, insn->variant.set_fpc_dfprm.mode);
break;
case S390_INSN_EVCHECK:
s390_amode_map_regs(m, insn->variant.evcheck.counter);
s390_amode_map_regs(m, insn->variant.evcheck.fail_addr);
break;
case S390_INSN_PROFINC:
/* Does not use any register visible to the register allocator */
break;
case S390_INSN_XDIRECT:
s390_amode_map_regs(m, insn->variant.xdirect.guest_IA);
break;
case S390_INSN_XINDIR:
s390_amode_map_regs(m, insn->variant.xindir.guest_IA);
insn->variant.xindir.dst =
lookupHRegRemap(m, insn->variant.xindir.dst);
break;
case S390_INSN_XASSISTED:
s390_amode_map_regs(m, insn->variant.xassisted.guest_IA);
insn->variant.xassisted.dst =
lookupHRegRemap(m, insn->variant.xassisted.dst);
break;
default:
vpanic("s390_insn_map_regs");
}
}
/* Return True, if INSN is a move between two registers of the same class.
In that case assign the source and destination registers to SRC and DST,
respectively. */
static Bool
s390_insn_is_reg_reg_move(const s390_insn *insn, HReg *src, HReg *dst)
{
if (insn->tag == S390_INSN_MOVE &&
hregClass(insn->variant.move.src) == hregClass(insn->variant.move.dst)) {
*src = insn->variant.move.src;
*dst = insn->variant.move.dst;
return True;
}
return False;
}
/*------------------------------------------------------------*/
/*--- Functions to emit a sequence of bytes ---*/
/*------------------------------------------------------------*/
static __inline__ UChar *
emit_2bytes(UChar *p, ULong val)
{
return (UChar *)__builtin_memcpy(p, ((UChar *)&val) + 6, 2) + 2;
}
static __inline__ UChar *
emit_4bytes(UChar *p, ULong val)
{
return (UChar *)__builtin_memcpy(p, ((UChar *)&val) + 4, 4) + 4;
}
static __inline__ UChar *
emit_6bytes(UChar *p, ULong val)
{
return (UChar *)__builtin_memcpy(p, ((UChar *)&val) + 2, 6) + 6;
}
/*------------------------------------------------------------*/
/*--- Functions to emit various instruction formats ---*/
/*------------------------------------------------------------*/
static UChar *
emit_RI(UChar *p, UInt op, UChar r1, UShort i2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 20;
the_insn |= ((ULong)i2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RIL(UChar *p, ULong op, UChar r1, UInt i2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 36;
the_insn |= ((ULong)i2) << 0;
return emit_6bytes(p, the_insn);
}
static UChar *
emit_RR(UChar *p, UInt op, UChar r1, UChar r2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 4;
the_insn |= ((ULong)r2) << 0;
return emit_2bytes(p, the_insn);
}
static UChar *
emit_RRE(UChar *p, UInt op, UChar r1, UChar r2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 4;
the_insn |= ((ULong)r2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RRF(UChar *p, UInt op, UChar r1, UChar r3, UChar r2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 12;
the_insn |= ((ULong)r3) << 4;
the_insn |= ((ULong)r2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RRF2(UChar *p, UInt op, UChar m3, UChar m4, UChar r1, UChar r2)
{
ULong the_insn = op;
the_insn |= ((ULong)m3) << 12;
the_insn |= ((ULong)m4) << 8;
the_insn |= ((ULong)r1) << 4;
the_insn |= ((ULong)r2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RRF3(UChar *p, UInt op, UChar r3, UChar r1, UChar r2)
{
ULong the_insn = op;
the_insn |= ((ULong)r3) << 12;
the_insn |= ((ULong)r1) << 4;
the_insn |= ((ULong)r2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RRF4(UChar *p, UInt op, UChar r3, UChar m4, UChar r1, UChar r2)
{
ULong the_insn = op;
the_insn |= ((ULong)r3) << 12;
the_insn |= ((ULong)m4) << 8;
the_insn |= ((ULong)r1) << 4;
the_insn |= ((ULong)r2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RRF5(UChar *p, UInt op, UChar m4, UChar r1, UChar r2)
{
ULong the_insn = op;
the_insn |= ((ULong)m4) << 8;
the_insn |= ((ULong)r1) << 4;
the_insn |= ((ULong)r2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RS(UChar *p, UInt op, UChar r1, UChar r3, UChar b2, UShort d2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 20;
the_insn |= ((ULong)r3) << 16;
the_insn |= ((ULong)b2) << 12;
the_insn |= ((ULong)d2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RSY(UChar *p, ULong op, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 36;
the_insn |= ((ULong)r3) << 32;
the_insn |= ((ULong)b2) << 28;
the_insn |= ((ULong)dl2) << 16;
the_insn |= ((ULong)dh2) << 8;
return emit_6bytes(p, the_insn);
}
static UChar *
emit_RX(UChar *p, UInt op, UChar r1, UChar x2, UChar b2, UShort d2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 20;
the_insn |= ((ULong)x2) << 16;
the_insn |= ((ULong)b2) << 12;
the_insn |= ((ULong)d2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_RXF(UChar *p, ULong op, UChar r3, UChar x2, UChar b2, UShort d2, UChar r1)
{
ULong the_insn = op;
the_insn |= ((ULong)r3) << 36;
the_insn |= ((ULong)x2) << 32;
the_insn |= ((ULong)b2) << 28;
the_insn |= ((ULong)d2) << 16;
the_insn |= ((ULong)r1) << 12;
return emit_6bytes(p, the_insn);
}
static UChar *
emit_RXY(UChar *p, ULong op, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
ULong the_insn = op;
the_insn |= ((ULong)r1) << 36;
the_insn |= ((ULong)x2) << 32;
the_insn |= ((ULong)b2) << 28;
the_insn |= ((ULong)dl2) << 16;
the_insn |= ((ULong)dh2) << 8;
return emit_6bytes(p, the_insn);
}
static UChar *
emit_S(UChar *p, UInt op, UChar b2, UShort d2)
{
ULong the_insn = op;
the_insn |= ((ULong)b2) << 12;
the_insn |= ((ULong)d2) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_SI(UChar *p, UInt op, UChar i2, UChar b1, UShort d1)
{
ULong the_insn = op;
the_insn |= ((ULong)i2) << 16;
the_insn |= ((ULong)b1) << 12;
the_insn |= ((ULong)d1) << 0;
return emit_4bytes(p, the_insn);
}
static UChar *
emit_SIL(UChar *p, ULong op, UChar b1, UShort d1, UShort i2)
{
ULong the_insn = op;
the_insn |= ((ULong)b1) << 28;
the_insn |= ((ULong)d1) << 16;
the_insn |= ((ULong)i2) << 0;
return emit_6bytes(p, the_insn);
}
static UChar *
emit_SIY(UChar *p, ULong op, UChar i2, UChar b1, UShort dl1, UChar dh1)
{
ULong the_insn = op;
the_insn |= ((ULong)i2) << 32;
the_insn |= ((ULong)b1) << 28;
the_insn |= ((ULong)dl1) << 16;
the_insn |= ((ULong)dh1) << 8;
return emit_6bytes(p, the_insn);
}
static UChar *
emit_SSa(UChar *p, ULong op, UChar l, UChar b1, UShort d1, UChar b2, UShort d2)
{
ULong the_insn = op;
the_insn |= ((ULong)l) << 32;
the_insn |= ((ULong)b1) << 28;
the_insn |= ((ULong)d1) << 16;
the_insn |= ((ULong)b2) << 12;
the_insn |= ((ULong)d2) << 0;
return emit_6bytes(p, the_insn);
}
/*------------------------------------------------------------*/
/*--- Functions to emit particular instructions ---*/
/*------------------------------------------------------------*/
static UChar *
s390_emit_AR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "ar", r1, r2);
return emit_RR(p, 0x1a00, r1, r2);
}
static UChar *
s390_emit_AGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "agr", r1, r2);
return emit_RRE(p, 0xb9080000, r1, r2);
}
static UChar *
s390_emit_A(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "a", r1, d2, x2, b2);
return emit_RX(p, 0x5a000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_AY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "ay", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe3000000005aULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_AG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "ag", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000008ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_AFI(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, INT), "afi", r1, i2);
return emit_RIL(p, 0xc20900000000ULL, r1, i2);
}
static UChar *
s390_emit_AGFI(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, INT), "agfi", r1, i2);
return emit_RIL(p, 0xc20800000000ULL, r1, i2);
}
static UChar *
s390_emit_AH(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "ah", r1, d2, x2, b2);
return emit_RX(p, 0x4a000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_AHY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "ahy", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe3000000007aULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_AHI(UChar *p, UChar r1, UShort i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, INT), "ahi", r1, (Int)(Short)i2);
return emit_RI(p, 0xa70a0000, r1, i2);
}
static UChar *
s390_emit_AGHI(UChar *p, UChar r1, UShort i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, INT), "aghi", r1, (Int)(Short)i2);
return emit_RI(p, 0xa70b0000, r1, i2);
}
static UChar *
s390_emit_AGSI(UChar *p, UChar i2, UChar b1, UShort dl1, UChar dh1)
{
vassert(s390_host_has_gie);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, SDXB, INT), "agsi", dh1, dl1, 0, b1, (Int)(Char)i2);
return emit_SIY(p, 0xeb000000007aULL, i2, b1, dl1, dh1);
}
static UChar *
s390_emit_ASI(UChar *p, UChar i2, UChar b1, UShort dl1, UChar dh1)
{
vassert(s390_host_has_gie);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, SDXB, INT), "asi", dh1, dl1, 0, b1, (Int)(Char)i2);
return emit_SIY(p, 0xeb000000006aULL, i2, b1, dl1, dh1);
}
static UChar *
s390_emit_NR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "nr", r1, r2);
return emit_RR(p, 0x1400, r1, r2);
}
static UChar *
s390_emit_NGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "ngr", r1, r2);
return emit_RRE(p, 0xb9800000, r1, r2);
}
static UChar *
s390_emit_N(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "n", r1, d2, x2, b2);
return emit_RX(p, 0x54000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_NY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "ny", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000054ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_NG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "ng", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000080ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_NIHF(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "nihf", r1, i2);
return emit_RIL(p, 0xc00a00000000ULL, r1, i2);
}
static UChar *
s390_emit_NILF(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "nilf", r1, i2);
return emit_RIL(p, 0xc00b00000000ULL, r1, i2);
}
static UChar *
s390_emit_NILL(UChar *p, UChar r1, UShort i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "nill", r1, i2);
return emit_RI(p, 0xa5070000, r1, i2);
}
static UChar *
s390_emit_BASR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "basr", r1, r2);
return emit_RR(p, 0x0d00, r1, r2);
}
static UChar *
s390_emit_BCR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC2(XMNM, GPR), S390_XMNM_BCR, r1, r2);
return emit_RR(p, 0x0700, r1, r2);
}
static UChar *
s390_emit_BRC(UChar *p, UChar r1, UShort i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC2(XMNM, PCREL), S390_XMNM_BRC, r1, (Int)(Short)i2);
return emit_RI(p, 0xa7040000, r1, i2);
}
static UChar *
s390_emit_BRCL(UChar *p, UChar r1, ULong i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC2(XMNM, PCREL), S390_XMNM_BRCL, r1, i2);
return emit_RIL(p, 0xc00400000000ULL, r1, i2);
}
static UChar *
s390_emit_CR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "cr", r1, r2);
return emit_RR(p, 0x1900, r1, r2);
}
static UChar *
s390_emit_CGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "cgr", r1, r2);
return emit_RRE(p, 0xb9200000, r1, r2);
}
static UChar *
s390_emit_C(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "c", r1, d2, x2, b2);
return emit_RX(p, 0x59000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_CY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "cy", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000059ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_CG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "cg", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000020ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_CFI(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, INT), "cfi", r1, i2);
return emit_RIL(p, 0xc20d00000000ULL, r1, i2);
}
static UChar *
s390_emit_CGFI(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, INT), "cgfi", r1, i2);
return emit_RIL(p, 0xc20c00000000ULL, r1, i2);
}
static UChar *
s390_emit_CS(UChar *p, UChar r1, UChar r3, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC4(MNM, GPR, GPR, UDXB), "cs", r1, r3, d2, 0, b2);
return emit_RS(p, 0xba000000, r1, r3, b2, d2);
}
static UChar *
s390_emit_CSY(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "csy", r1, r3, dh2, dl2, 0, b2);
return emit_RSY(p, 0xeb0000000014ULL, r1, r3, b2, dl2, dh2);
}
static UChar *
s390_emit_CSG(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "csg", r1, r3, dh2, dl2, 0, b2);
return emit_RSY(p, 0xeb0000000030ULL, r1, r3, b2, dl2, dh2);
}
static UChar *
s390_emit_CDS(UChar *p, UChar r1, UChar r3, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC4(MNM, GPR, GPR, UDXB), "cds", r1, r3, d2, 0, b2);
return emit_RS(p, 0xbb000000, r1, r3, b2, d2);
}
static UChar *
s390_emit_CDSY(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "cdsy", r1, r3, dh2, dl2, 0, b2);
return emit_RSY(p, 0xeb0000000031ULL, r1, r3, b2, dl2, dh2);
}
static UChar *
s390_emit_CDSG(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "cdsg", r1, r3, dh2, dl2, 0, b2);
return emit_RSY(p, 0xeb000000003eULL, r1, r3, b2, dl2, dh2);
}
static UChar *
s390_emit_CLR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "clr", r1, r2);
return emit_RR(p, 0x1500, r1, r2);
}
static UChar *
s390_emit_CLGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "clgr", r1, r2);
return emit_RRE(p, 0xb9210000, r1, r2);
}
static UChar *
s390_emit_CL(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "cl", r1, d2, x2, b2);
return emit_RX(p, 0x55000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_CLY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "cly", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000055ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_CLG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "clg", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000021ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_CLFI(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "clfi", r1, i2);
return emit_RIL(p, 0xc20f00000000ULL, r1, i2);
}
static UChar *
s390_emit_CLGFI(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "clgfi", r1, i2);
return emit_RIL(p, 0xc20e00000000ULL, r1, i2);
}
static UChar *
s390_emit_DR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "dr", r1, r2);
return emit_RR(p, 0x1d00, r1, r2);
}
static UChar *
s390_emit_D(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "d", r1, d2, x2, b2);
return emit_RX(p, 0x5d000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_DLR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "dlr", r1, r2);
return emit_RRE(p, 0xb9970000, r1, r2);
}
static UChar *
s390_emit_DLGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "dlgr", r1, r2);
return emit_RRE(p, 0xb9870000, r1, r2);
}
static UChar *
s390_emit_DL(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "dl", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000097ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_DLG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "dlg", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000087ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_DSGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "dsgr", r1, r2);
return emit_RRE(p, 0xb90d0000, r1, r2);
}
static UChar *
s390_emit_DSG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "dsg", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe3000000000dULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_XR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "xr", r1, r2);
return emit_RR(p, 0x1700, r1, r2);
}
static UChar *
s390_emit_XGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "xgr", r1, r2);
return emit_RRE(p, 0xb9820000, r1, r2);
}
static UChar *
s390_emit_X(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "x", r1, d2, x2, b2);
return emit_RX(p, 0x57000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_XY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "xy", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000057ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_XG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "xg", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000082ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_XIHF(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "xihf", r1, i2);
return emit_RIL(p, 0xc00600000000ULL, r1, i2);
}
static UChar *
s390_emit_XILF(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "xilf", r1, i2);
return emit_RIL(p, 0xc00700000000ULL, r1, i2);
}
static UChar *
s390_emit_XC(UChar *p, UInt l, UChar b1, UShort d1, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, UDLB, UDXB), "xc", d1, l, b1, d2, 0, b2);
return emit_SSa(p, 0xd70000000000ULL, l, b1, d1, b2, d2);
}
static UChar *
s390_emit_FLOGR(UChar *p, UChar r1, UChar r2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "flogr", r1, r2);
return emit_RRE(p, 0xb9830000, r1, r2);
}
static UChar *
s390_emit_IC(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "ic", r1, d2, x2, b2);
return emit_RX(p, 0x43000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_ICY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "icy", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000073ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_IIHF(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "iihf", r1, i2);
return emit_RIL(p, 0xc00800000000ULL, r1, i2);
}
static UChar *
s390_emit_IIHH(UChar *p, UChar r1, UShort i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "iihh", r1, i2);
return emit_RI(p, 0xa5000000, r1, i2);
}
static UChar *
s390_emit_IIHL(UChar *p, UChar r1, UShort i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "iihl", r1, i2);
return emit_RI(p, 0xa5010000, r1, i2);
}
static UChar *
s390_emit_IILF(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "iilf", r1, i2);
return emit_RIL(p, 0xc00900000000ULL, r1, i2);
}
static UChar *
s390_emit_IILH(UChar *p, UChar r1, UShort i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "iilh", r1, i2);
return emit_RI(p, 0xa5020000, r1, i2);
}
static UChar *
s390_emit_IILL(UChar *p, UChar r1, UShort i2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UINT), "iill", r1, i2);
return emit_RI(p, 0xa5030000, r1, i2);
}
static UChar *
s390_emit_IPM(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC2(MNM, GPR), "ipm", r1);
return emit_RRE(p, 0xb2220000, r1, r2);
}
static UChar *
s390_emit_LR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lr", r1, r2);
return emit_RR(p, 0x1800, r1, r2);
}
static UChar *
s390_emit_LGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lgr", r1, r2);
return emit_RRE(p, 0xb9040000, r1, r2);
}
static UChar *
s390_emit_LGFR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lgfr", r1, r2);
return emit_RRE(p, 0xb9140000, r1, r2);
}
static UChar *
s390_emit_L(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "l", r1, d2, x2, b2);
return emit_RX(p, 0x58000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_LY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "ly", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000058ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_LG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "lg", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000004ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_LGF(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp || dh2 == 0);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "lgf", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000014ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_LGFI(UChar *p, UChar r1, UInt i2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, INT), "lgfi", r1, i2);
return emit_RIL(p, 0xc00100000000ULL, r1, i2);
}
static UChar *
s390_emit_LTR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "ltr", r1, r2);
return emit_RR(p, 0x1200, r1, r2);
}
static UChar *
s390_emit_LTGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "ltgr", r1, r2);
return emit_RRE(p, 0xb9020000, r1, r2);
}
static UChar *
s390_emit_LT(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "lt", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000012ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_LTG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "ltg", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000002ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_LBR(UChar *p, UChar r1, UChar r2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lbr", r1, r2);
return emit_RRE(p, 0xb9260000, r1, r2);
}
static UChar *
s390_emit_LGBR(UChar *p, UChar r1, UChar r2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lgbr", r1, r2);
return emit_RRE(p, 0xb9060000, r1, r2);
}
static UChar *
s390_emit_LB(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "lb", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000076ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_LGB(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "lgb", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000077ULL, r1, x2, b2, dl2, dh2);
}
static UChar *
s390_emit_LCR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lcr", r1, r2);
return emit_RR(p, 0x1300, r1, r2);
}
static UChar *
s390_emit_LCGR(UChar *p, UChar r1, UChar r2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lcgr", r1, r2);
return emit_RRE(p, 0xb9030000, r1, r2);
}
static UChar *
s390_emit_LHR(UChar *p, UChar r1, UChar r2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lhr", r1, r2);
return emit_RRE(p, 0xb9270000, r1, r2);
}
static UChar *
s390_emit_LGHR(UChar *p, UChar r1, UChar r2)
{
vassert(s390_host_has_eimm);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, GPR), "lghr", r1, r2);
return emit_RRE(p, 0xb9070000, r1, r2);
}
static UChar *
s390_emit_LH(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
{
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, UDXB), "lh", r1, d2, x2, b2);
return emit_RX(p, 0x48000000, r1, x2, b2, d2);
}
static UChar *
s390_emit_LHY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
{
vassert(s390_host_has_ldisp);
if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, SDXB), "lhy", r1, dh2, dl2, x2, b2);
return emit_RXY(p, 0xe30000000078ULL, r1, x2, b2, dl2, dh2);
}
static UChar *