| /* -*- 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 * |
|