/*---------------------------------------------------------------*/
/*--- begin host_ppc_defs.c ---*/
/*---------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2004-2017 OpenWorks LLP
info@open-works.net
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.
Neither the names of the U.S. Department of Energy nor the
University of California nor the names of its contributors may be
used to endorse or promote products derived from this software
without prior written permission.
*/
#include "libvex_basictypes.h"
#include "libvex.h"
#include "libvex_trc_values.h"
#include "main_util.h"
#include "host_generic_regs.h"
#include "host_ppc_defs.h"
/* --------- Registers. --------- */
const RRegUniverse* getRRegUniverse_PPC ( Bool mode64 )
{
/* The real-register universe is a big constant, so we just want to
initialise it once. rRegUniverse_PPC_initted values: 0=not initted,
1=initted for 32-bit-mode, 2=initted for 64-bit-mode */
static RRegUniverse rRegUniverse_PPC;
static UInt rRegUniverse_PPC_initted = 0;
/* Handy shorthand, nothing more */
RRegUniverse* ru = &rRegUniverse_PPC;
/* This isn't thread-safe. Sigh. */
UInt howNeeded = mode64 ? 2 : 1;
if (LIKELY(rRegUniverse_PPC_initted == howNeeded))
return ru;
RRegUniverse__init(ru);
/* Add the registers. The initial segment of this array must be
those available for allocation by reg-alloc, and those that
follow are not available for allocation. */
// GPR0 = scratch reg where poss. - some ops interpret as value zero
// GPR1 = stack pointer
// GPR2 = TOC pointer
ru->regs[ru->size++] = hregPPC_GPR3(mode64);
ru->regs[ru->size++] = hregPPC_GPR4(mode64);
ru->regs[ru->size++] = hregPPC_GPR5(mode64);
ru->regs[ru->size++] = hregPPC_GPR6(mode64);
ru->regs[ru->size++] = hregPPC_GPR7(mode64);
ru->regs[ru->size++] = hregPPC_GPR8(mode64);
ru->regs[ru->size++] = hregPPC_GPR9(mode64);
ru->regs[ru->size++] = hregPPC_GPR10(mode64);
if (!mode64) {
/* in mode64:
r11 used for calls by ptr / env ptr for some langs
r12 used for exception handling and global linkage code */
ru->regs[ru->size++] = hregPPC_GPR11(mode64);
ru->regs[ru->size++] = hregPPC_GPR12(mode64);
}
// GPR13 = thread specific pointer
// GPR14 and above are callee save. Yay.
ru->regs[ru->size++] = hregPPC_GPR14(mode64);
ru->regs[ru->size++] = hregPPC_GPR15(mode64);
ru->regs[ru->size++] = hregPPC_GPR16(mode64);
ru->regs[ru->size++] = hregPPC_GPR17(mode64);
ru->regs[ru->size++] = hregPPC_GPR18(mode64);
ru->regs[ru->size++] = hregPPC_GPR19(mode64);
ru->regs[ru->size++] = hregPPC_GPR20(mode64);
ru->regs[ru->size++] = hregPPC_GPR21(mode64);
ru->regs[ru->size++] = hregPPC_GPR22(mode64);
ru->regs[ru->size++] = hregPPC_GPR23(mode64);
ru->regs[ru->size++] = hregPPC_GPR24(mode64);
ru->regs[ru->size++] = hregPPC_GPR25(mode64);
ru->regs[ru->size++] = hregPPC_GPR26(mode64);
ru->regs[ru->size++] = hregPPC_GPR27(mode64);
ru->regs[ru->size++] = hregPPC_GPR28(mode64);
// GPR29 is reserved for the dispatcher
// GPR30 is reserved as AltiVec spill reg temporary
// GPR31 is reserved for the GuestStatePtr
/* Don't waste the reg-allocs's time trawling through zillions of
FP registers - they mostly will never be used. We'll tolerate
the occasional extra spill instead. */
/* For both ppc32-linux and ppc64-linux, f14-f31 are callee save.
So use them. */
ru->regs[ru->size++] = hregPPC_FPR14(mode64);
ru->regs[ru->size++] = hregPPC_FPR15(mode64);
ru->regs[ru->size++] = hregPPC_FPR16(mode64);
ru->regs[ru->size++] = hregPPC_FPR17(mode64);
ru->regs[ru->size++] = hregPPC_FPR18(mode64);
ru->regs[ru->size++] = hregPPC_FPR19(mode64);
ru->regs[ru->size++] = hregPPC_FPR20(mode64);
ru->regs[ru->size++] = hregPPC_FPR21(mode64);
/* Same deal re Altivec */
/* For both ppc32-linux and ppc64-linux, v20-v31 are callee save.
So use them. */
/* NB, vr29 is used as a scratch temporary -- do not allocate */
ru->regs[ru->size++] = hregPPC_VR20(mode64);
ru->regs[ru->size++] = hregPPC_VR21(mode64);
ru->regs[ru->size++] = hregPPC_VR22(mode64);
ru->regs[ru->size++] = hregPPC_VR23(mode64);
ru->regs[ru->size++] = hregPPC_VR24(mode64);
ru->regs[ru->size++] = hregPPC_VR25(mode64);
ru->regs[ru->size++] = hregPPC_VR26(mode64);
ru->regs[ru->size++] = hregPPC_VR27(mode64);
ru->allocable = ru->size;
/* And other regs, not available to the allocator. */
ru->regs[ru->size++] = hregPPC_GPR1(mode64);
ru->regs[ru->size++] = hregPPC_GPR29(mode64);
ru->regs[ru->size++] = hregPPC_GPR30(mode64);
ru->regs[ru->size++] = hregPPC_GPR31(mode64);
ru->regs[ru->size++] = hregPPC_VR29(mode64);
rRegUniverse_PPC_initted = howNeeded;
RRegUniverse__check_is_sane(ru);
return ru;
}
void ppHRegPPC ( HReg reg )
{
Int r;
static const HChar* ireg32_names[32]
= { "%r0", "%r1", "%r2", "%r3",
"%r4", "%r5", "%r6", "%r7",
"%r8", "%r9", "%r10", "%r11",
"%r12", "%r13", "%r14", "%r15",
"%r16", "%r17", "%r18", "%r19",
"%r20", "%r21", "%r22", "%r23",
"%r24", "%r25", "%r26", "%r27",
"%r28", "%r29", "%r30", "%r31" };
/* Be generic for all virtual regs. */
if (hregIsVirtual(reg)) {
ppHReg(reg);
return;
}
/* But specific for real regs. */
switch (hregClass(reg)) {
case HRcInt64:
r = hregEncoding(reg);
vassert(r >= 0 && r < 32);
vex_printf("%s", ireg32_names[r]);
return;
case HRcInt32:
r = hregEncoding(reg);
vassert(r >= 0 && r < 32);
vex_printf("%s", ireg32_names[r]);
return;
case HRcFlt64:
r = hregEncoding(reg);
vassert(r >= 0 && r < 32);
vex_printf("%%fr%d", r);
return;
case HRcVec128:
r = hregEncoding(reg);
vassert(r >= 0 && r < 32);
vex_printf("%%v%d", r);
return;
default:
vpanic("ppHRegPPC");
}
}
/* --------- Condition codes, Intel encoding. --------- */
const HChar* showPPCCondCode ( PPCCondCode cond )
{
if (cond.test == Pct_ALWAYS) return "always";
switch (cond.flag) {
case Pcf_7SO:
return (cond.test == Pct_TRUE) ? "cr7.so=1" : "cr7.so=0";
case Pcf_7EQ:
return (cond.test == Pct_TRUE) ? "cr7.eq=1" : "cr7.eq=0";
case Pcf_7GT:
return (cond.test == Pct_TRUE) ? "cr7.gt=1" : "cr7.gt=0";
case Pcf_7LT:
return (cond.test == Pct_TRUE) ? "cr7.lt=1" : "cr7.lt=0";
case Pcf_NONE:
return "no-flag";
default: vpanic("ppPPCCondCode");
}
}
/* construct condition code */
PPCCondCode mk_PPCCondCode ( PPCCondTest test, PPCCondFlag flag )
{
PPCCondCode cc;
cc.flag = flag;
cc.test = test;
if (test == Pct_ALWAYS) {
vassert(flag == Pcf_NONE);
} else {
vassert(flag != Pcf_NONE);
}
return cc;
}
/* false->true, true->false */
PPCCondTest invertCondTest ( PPCCondTest ct )
{
vassert(ct != Pct_ALWAYS);
return (ct == Pct_TRUE) ? Pct_FALSE : Pct_TRUE;
}
/* --------- PPCAMode: memory address expressions. --------- */
PPCAMode* PPCAMode_IR ( Int idx, HReg base ) {
PPCAMode* am = LibVEX_Alloc_inline(sizeof(PPCAMode));
vassert(idx >= -0x8000 && idx < 0x8000);
am->tag = Pam_IR;
am->Pam.IR.base = base;
am->Pam.IR.index = idx;
return am;
}
PPCAMode* PPCAMode_RR ( HReg idx, HReg base ) {
PPCAMode* am = LibVEX_Alloc_inline(sizeof(PPCAMode));
am->tag = Pam_RR;
am->Pam.RR.base = base;
am->Pam.RR.index = idx;
return am;
}
PPCAMode* dopyPPCAMode ( PPCAMode* am ) {
switch (am->tag) {
case Pam_IR:
return PPCAMode_IR( am->Pam.IR.index, am->Pam.IR.base );
case Pam_RR:
return PPCAMode_RR( am->Pam.RR.index, am->Pam.RR.base );
default:
vpanic("dopyPPCAMode");
}
}
void ppPPCAMode ( PPCAMode* am ) {
switch (am->tag) {
case Pam_IR:
if (am->Pam.IR.index == 0)
vex_printf("0(");
else
vex_printf("%d(", (Int)am->Pam.IR.index);
ppHRegPPC(am->Pam.IR.base);
vex_printf(")");
return;
case Pam_RR:
ppHRegPPC(am->Pam.RR.base);
vex_printf(",");
ppHRegPPC(am->Pam.RR.index);
return;
default:
vpanic("ppPPCAMode");
}
}
static void addRegUsage_PPCAMode ( HRegUsage* u, PPCAMode* am ) {
switch (am->tag) {
case Pam_IR:
addHRegUse(u, HRmRead, am->Pam.IR.base);
return;
case Pam_RR:
addHRegUse(u, HRmRead, am->Pam.RR.base);
addHRegUse(u, HRmRead, am->Pam.RR.index);
return;
default:
vpanic("addRegUsage_PPCAMode");
}
}
static void mapRegs_PPCAMode ( HRegRemap* m, PPCAMode* am ) {
switch (am->tag) {
case Pam_IR:
am->Pam.IR.base = lookupHRegRemap(m, am->Pam.IR.base);
return;
case Pam_RR:
am->Pam.RR.base = lookupHRegRemap(m, am->Pam.RR.base);
am->Pam.RR.index = lookupHRegRemap(m, am->Pam.RR.index);
return;
default:
vpanic("mapRegs_PPCAMode");
}
}
/* --------- Operand, which can be a reg or a u16/s16. --------- */
PPCRH* PPCRH_Imm ( Bool syned, UShort imm16 ) {
PPCRH* op = LibVEX_Alloc_inline(sizeof(PPCRH));
op->tag = Prh_Imm;
op->Prh.Imm.syned = syned;
op->Prh.Imm.imm16 = imm16;
/* If this is a signed value, ensure it's not -32768, so that we
are guaranteed always to be able to negate if needed. */
if (syned)
vassert(imm16 != 0x8000);
vassert(syned == True || syned == False);
return op;
}
PPCRH* PPCRH_Reg ( HReg reg ) {
PPCRH* op = LibVEX_Alloc_inline(sizeof(PPCRH));
op->tag = Prh_Reg;
op->Prh.Reg.reg = reg;
return op;
}
void ppPPCRH ( PPCRH* op ) {
switch (op->tag) {
case Prh_Imm:
if (op->Prh.Imm.syned)
vex_printf("%d", (Int)(Short)op->Prh.Imm.imm16);
else
vex_printf("%u", (UInt)(UShort)op->Prh.Imm.imm16);
return;
case Prh_Reg:
ppHRegPPC(op->Prh.Reg.reg);
return;
default:
vpanic("ppPPCRH");
}
}
/* An PPCRH can only be used in a "read" context (what would it mean
to write or modify a literal?) and so we enumerate its registers
accordingly. */
static void addRegUsage_PPCRH ( HRegUsage* u, PPCRH* op ) {
switch (op->tag) {
case Prh_Imm:
return;
case Prh_Reg:
addHRegUse(u, HRmRead, op->Prh.Reg.reg);
return;
default:
vpanic("addRegUsage_PPCRH");
}
}
static void mapRegs_PPCRH ( HRegRemap* m, PPCRH* op ) {
switch (op->tag) {
case Prh_Imm:
return;
case Prh_Reg:
op->Prh.Reg.reg = lookupHRegRemap(m, op->Prh.Reg.reg);
return;
default:
vpanic("mapRegs_PPCRH");
}
}
/* --------- Operand, which can be a reg or a u32/64. --------- */
PPCRI* PPCRI_Imm ( ULong imm64 ) {
PPCRI* op = LibVEX_Alloc_inline(sizeof(PPCRI));
op->tag = Pri_Imm;
op->Pri.Imm = imm64;
return op;
}
PPCRI* PPCRI_Reg ( HReg reg ) {
PPCRI* op = LibVEX_Alloc_inline(sizeof(PPCRI));
op->tag = Pri_Reg;
op->Pri.Reg = reg;
return op;
}
void ppPPCRI ( PPCRI* dst ) {
switch (dst->tag) {
case Pri_Imm:
vex_printf("0x%llx", dst->Pri.Imm);
break;
case Pri_Reg:
ppHRegPPC(dst->Pri.Reg);
break;
default:
vpanic("ppPPCRI");
}
}
/* An PPCRI can only be used in a "read" context (what would it
mean to write or modify a literal?) and so we enumerate its
registers accordingly. */
static void addRegUsage_PPCRI ( HRegUsage* u, PPCRI* dst ) {
switch (dst->tag) {
case Pri_Imm:
return;
case Pri_Reg:
addHRegUse(u, HRmRead, dst->Pri.Reg);
return;
default:
vpanic("addRegUsage_PPCRI");
}
}
static void mapRegs_PPCRI ( HRegRemap* m, PPCRI* dst ) {
switch (dst->tag) {
case Pri_Imm:
return;
case Pri_Reg:
dst->Pri.Reg = lookupHRegRemap(m, dst->Pri.Reg);
return;
default:
vpanic("mapRegs_PPCRI");
}
}
/* --------- Operand, which can be a vector reg or a simm5. --------- */
PPCVI5s* PPCVI5s_Imm ( Char simm5 ) {
PPCVI5s* op = LibVEX_Alloc_inline(sizeof(PPCVI5s));
op->tag = Pvi_Imm;
op->Pvi.Imm5s = simm5;
vassert(simm5 >= -16 && simm5 <= 15);
return op;
}
PPCVI5s* PPCVI5s_Reg ( HReg reg ) {
PPCVI5s* op = LibVEX_Alloc_inline(sizeof(PPCVI5s));
op->tag = Pvi_Reg;
op->Pvi.Reg = reg;
vassert(hregClass(reg) == HRcVec128);
return op;
}
void ppPPCVI5s ( PPCVI5s* src ) {
switch (src->tag) {
case Pvi_Imm:
vex_printf("%d", (Int)src->Pvi.Imm5s);
break;
case Pvi_Reg:
ppHRegPPC(src->Pvi.Reg);
break;
default:
vpanic("ppPPCVI5s");
}
}
/* An PPCVI5s can only be used in a "read" context (what would it
mean to write or modify a literal?) and so we enumerate its
registers accordingly. */
static void addRegUsage_PPCVI5s ( HRegUsage* u, PPCVI5s* dst ) {
switch (dst->tag) {
case Pvi_Imm:
return;
case Pvi_Reg:
addHRegUse(u, HRmRead, dst->Pvi.Reg);
return;
default:
vpanic("addRegUsage_PPCVI5s");
}
}
static void mapRegs_PPCVI5s ( HRegRemap* m, PPCVI5s* dst ) {
switch (dst->tag) {
case Pvi_Imm:
return;
case Pvi_Reg:
dst->Pvi.Reg = lookupHRegRemap(m, dst->Pvi.Reg);
return;
default:
vpanic("mapRegs_PPCVI5s");
}
}
/* --------- Instructions. --------- */
const HChar* showPPCUnaryOp ( PPCUnaryOp op ) {
switch (op) {
case Pun_NOT: return "not";
case Pun_NEG: return "neg";
case Pun_CLZ32: return "cntlzw";
case Pun_CLZ64: return "cntlzd";
case Pun_CTZ32: return "cnttzw";
case Pun_CTZ64: return "cnttzd";
case Pun_EXTSW: return "extsw";
default: vpanic("showPPCUnaryOp");
}
}
const HChar* showPPCAluOp ( PPCAluOp op, Bool immR ) {
switch (op) {
case Palu_ADD: return immR ? "addi" : "add";
case Palu_SUB: return immR ? "subi" : "sub";
case Palu_AND: return immR ? "andi." : "and";
case Palu_OR: return immR ? "ori" : "or";
case Palu_XOR: return immR ? "xori" : "xor";
default: vpanic("showPPCAluOp");
}
}
const HChar* showPPCShftOp ( PPCShftOp op, Bool immR, Bool sz32 ) {
switch (op) {
case Pshft_SHL: return sz32 ? (immR ? "slwi" : "slw") :
(immR ? "sldi" : "sld");
case Pshft_SHR: return sz32 ? (immR ? "srwi" : "srw") :
(immR ? "srdi" : "srd");
case Pshft_SAR: return sz32 ? (immR ? "srawi" : "sraw") :
(immR ? "sradi" : "srad");
default: vpanic("showPPCShftOp");
}
}
const HChar* showPPCFpOp ( PPCFpOp op ) {
switch (op) {
case Pfp_ADDD: return "fadd";
case Pfp_SUBD: return "fsub";
case Pfp_MULD: return "fmul";
case Pfp_DIVD: return "fdiv";
case Pfp_MADDD: return "fmadd";
case Pfp_MSUBD: return "fmsub";
case Pfp_MADDS: return "fmadds";
case Pfp_MSUBS: return "fmsubs";
case Pfp_ADDS: return "fadds";
case Pfp_SUBS: return "fsubs";
case Pfp_MULS: return "fmuls";
case Pfp_DIVS: return "fdivs";
case Pfp_SQRT: return "fsqrt";
case Pfp_ABS: return "fabs";
case Pfp_NEG: return "fneg";
case Pfp_MOV: return "fmr";
case Pfp_RES: return "fres";
case Pfp_RSQRTE: return "frsqrte";
case Pfp_FRIM: return "frim";
case Pfp_FRIN: return "frin";
case Pfp_FRIP: return "frip";
case Pfp_FRIZ: return "friz";
case Pfp_FPADDQ: return "xsaddqp";
case Pfp_FPSUBQ: return "xsubqp";
case Pfp_FPMULQ: return "xsmulqp";
case Pfp_FPDIVQ: return "xsdivqp";
case Pfp_FPMULADDQ: return "xsmaddqp";
case Pfp_FPMULSUBQ: return "xsmsubqp";
case Pfp_FPNEGMULADDQ: return "xsnmaddqp";
case Pfp_FPNEGMULSUBQ: return "xsnmsubqp";
case Pfp_FPADDQRNDODD: return "xsaddqpo";
case Pfp_FPSUBQRNDODD: return "xsubqpo";
case Pfp_FPMULQRNDODD: return "xsmulqpo";
case Pfp_FPDIVQRNDODD: return "xsaddqpo";
case Pfp_FPMULADDQRNDODD: return "xsmaddqpo";
case Pfp_FPMULSUBQRNDODD: return "xsmsubqpo";
case Pfp_FPNEGMULADDQRNDODD: return "xsnmaddqpo";
case Pfp_FPNEGMULSUBQRNDODD: return "xsnmsubqpo";
case Pfp_FPQTOD: return "xscvqpdp";
case Pfp_FPQTODRNDODD: return "xscvqpdpo";
case Pfp_FPDTOQ: return "xscvdpqp";
case Pfp_IDSTOQ: return "xscvsdqp";
case Pfp_IDUTOQ: return "xscvudqp";
case Pfp_TRUNCFPQTOISD: return "xscvqpsdz";
case Pfp_TRUNCFPQTOISW: return "xscvqpswz";
case Pfp_TRUNCFPQTOIUD: return "xscvqpudz";
case Pfp_TRUNCFPQTOIUW: return "xscvqpuwz";
case Pfp_DFPADD: return "dadd";
case Pfp_DFPADDQ: return "daddq";
case Pfp_DFPSUB: return "dsub";
case Pfp_DFPSUBQ: return "dsubq";
case Pfp_DFPMUL: return "dmul";
case Pfp_DFPMULQ: return "dmulq";
case Pfp_DFPDIV: return "ddivd";
case Pfp_DFPDIVQ: return "ddivq";
case Pfp_DCTDP: return "dctdp";
case Pfp_DRSP: return "drsp";
case Pfp_DCTFIX: return "dctfix";
case Pfp_DCFFIX: return "dcffix";
case Pfp_DCTQPQ: return "dctqpq";
case Pfp_DCFFIXQ: return "dcffixq";
case Pfp_DQUA: return "dqua";
case Pfp_DQUAQ: return "dquaq";
case Pfp_DXEX: return "dxex";
case Pfp_DXEXQ: return "dxexq";
case Pfp_DIEX: return "diex";
case Pfp_DIEXQ: return "diexq";
case Pfp_RRDTR: return "rrdtr";
default: vpanic("showPPCFpOp");
}
}
const HChar* showPPCAvOp ( PPCAvOp op ) {
switch (op) {
/* Unary */
case Pav_MOV: return "vmr"; /* Mov */
case Pav_AND: return "vand"; /* Bitwise */
case Pav_OR: return "vor";
case Pav_XOR: return "vxor";
case Pav_NOT: return "vnot";
case Pav_UNPCKH8S: return "vupkhsb"; /* Unpack */
case Pav_UNPCKH16S: return "vupkhsh";
case Pav_UNPCKL8S: return "vupklsb";
case Pav_UNPCKL16S: return "vupklsh";
case Pav_UNPCKHPIX: return "vupkhpx";
case Pav_UNPCKLPIX: return "vupklpx";
/* Integer binary */
case Pav_ADDU: return "vaddu_m"; // b,h,w,dw
case Pav_QADDU: return "vaddu_s"; // b,h,w,dw
case Pav_QADDS: return "vadds_s"; // b,h,w,dw
case Pav_SUBU: return "vsubu_m"; // b,h,w,dw
case Pav_QSUBU: return "vsubu_s"; // b,h,w,dw
case Pav_QSUBS: return "vsubs_s"; // b,h,w,dw
case Pav_MULU: return "vmulu"; // w
case Pav_OMULU: return "vmulou"; // b,h,w
case Pav_OMULS: return "vmulos"; // b,h,w
case Pav_EMULU: return "vmuleu"; // b,h,w
case Pav_EMULS: return "vmules"; // b,h,w
case Pav_AVGU: return "vavgu"; // b,h,w
case Pav_AVGS: return "vavgs"; // b,h,w
case Pav_MAXU: return "vmaxu"; // b,h,w
case Pav_MAXS: return "vmaxs"; // b,h,w
case Pav_MINU: return "vminu"; // b,h,w
case Pav_MINS: return "vmins"; // b,h,w
/* Compare (always affects CR field 6) */
case Pav_CMPEQU: return "vcmpequ"; // b,h,w
case Pav_CMPGTU: return "vcmpgtu"; // b,h,w
case Pav_CMPGTS: return "vcmpgts"; // b,h,w
/* Shift */
case Pav_SHL: return "vsl"; // ' ',b,h,w,dw
case Pav_SHR: return "vsr"; // ' ',b,h,w,dw
case Pav_SAR: return "vsra"; // b,h,w,dw
case Pav_ROTL: return "vrl"; // b,h,w,dw
/* Pack */
case Pav_PACKUU: return "vpku_um"; // h,w,dw
case Pav_QPACKUU: return "vpku_us"; // h,w
case Pav_QPACKSU: return "vpks_us"; // h,w
case Pav_QPACKSS: return "vpks_ss"; // h,w
case Pav_PACKPXL: return "vpkpx";
/* Merge */
case Pav_MRGHI: return "vmrgh"; // b,h,w
case Pav_MRGLO: return "vmrgl"; // b,h,w
/* Concatenation */
case Pav_CATODD: return "vmrgow"; // w
case Pav_CATEVEN: return "vmrgew"; // w
/* SHA */
case Pav_SHA256: return "vshasigmaw"; // w
case Pav_SHA512: return "vshasigmaw"; // dw
/* BCD */
case Pav_BCDAdd: return "bcdadd."; // qw
case Pav_BCDSub: return "bcdsub."; // qw
case Pav_I128StoBCD128: return "bcdcfsq."; //qw
case Pav_BCD128toI128S: return "bcdctsq."; //qw
/* I128 mult by 10 */
case Pav_MulI128by10: return "vmul10uq"; //qw
case Pav_MulI128by10Carry: return "vmul10cuq"; //qw
case Pav_MulI128by10E: return "vmul10euq"; //qw
case Pav_MulI128by10ECarry: return "vmul10ecuq"; //qw
/* F128 to I128 signed */
case Pav_F128toI128S: return "xsrqpi|x"; //qw
/* F128 round to F128 */
case Pav_ROUNDFPQ: return "xsrqpxp";
/* Polynomial arith */
case Pav_POLYMULADD: return "vpmsum"; // b, h, w, d
/* Cipher */
case Pav_CIPHERV128: case Pav_CIPHERLV128:
case Pav_NCIPHERV128: case Pav_NCIPHERLV128:
case Pav_CIPHERSUBV128: return "v_cipher_"; // qw
/* zero count */
case Pav_ZEROCNTBYTE: case Pav_ZEROCNTWORD:
case Pav_ZEROCNTHALF: case Pav_ZEROCNTDBL:
return "vclz_"; // b, h, w, d
/* trailing zero count */
case Pav_TRAILINGZEROCNTBYTE: case Pav_TRAILINGZEROCNTWORD:
case Pav_TRAILINGZEROCNTHALF: case Pav_TRAILINGZEROCNTDBL:
return "vctz_"; // b, h, w, d
/* vector gather (byte-by-byte bit matrix transpose) */
case Pav_BITMTXXPOSE:
return "vgbbd";
/* Vector Half-precision format to single precision conversion */
case Pav_F16toF32x4:
return"xvcvhpsp";
/* Vector Single-precision format to Half-precision conversion */
case Pav_F32toF16x4:
return"xvcvsphp";
/* Vector Half-precision format to Double precision conversion */
case Pav_F16toF64x2:
return"xvcvhpdp";
/* Vector Half-precision format to Double precision conversion */
case Pav_F64toF16x2:
return"xvcvdphp";
default: vpanic("showPPCAvOp");
}
}
const HChar* showPPCAvFpOp ( PPCAvFpOp op ) {
switch (op) {
/* Floating Point Binary */
case Pavfp_ADDF: return "vaddfp";
case Pavfp_SUBF: return "vsubfp";
case Pavfp_MULF: return "vmaddfp";
case Pavfp_MAXF: return "vmaxfp";
case Pavfp_MINF: return "vminfp";
case Pavfp_CMPEQF: return "vcmpeqfp";
case Pavfp_CMPGTF: return "vcmpgtfp";
case Pavfp_CMPGEF: return "vcmpgefp";
/* Floating Point Unary */
case Pavfp_RCPF: return "vrefp";
case Pavfp_RSQRTF: return "vrsqrtefp";
case Pavfp_CVTU2F: return "vcfux";
case Pavfp_CVTS2F: return "vcfsx";
case Pavfp_QCVTF2U: return "vctuxs";
case Pavfp_QCVTF2S: return "vctsxs";
case Pavfp_ROUNDM: return "vrfim";
case Pavfp_ROUNDP: return "vrfip";
case Pavfp_ROUNDN: return "vrfin";
case Pavfp_ROUNDZ: return "vrfiz";
default: vpanic("showPPCAvFpOp");
}
}
PPCInstr* PPCInstr_LI ( HReg dst, ULong imm64, Bool mode64 )
{
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_LI;
i->Pin.LI.dst = dst;
i->Pin.LI.imm64 = imm64;
if (!mode64)
vassert( (Long)imm64 == (Long)(Int)(UInt)imm64 );
return i;
}
PPCInstr* PPCInstr_Alu ( PPCAluOp op, HReg dst,
HReg srcL, PPCRH* srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Alu;
i->Pin.Alu.op = op;
i->Pin.Alu.dst = dst;
i->Pin.Alu.srcL = srcL;
i->Pin.Alu.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_Shft ( PPCShftOp op, Bool sz32,
HReg dst, HReg srcL, PPCRH* srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Shft;
i->Pin.Shft.op = op;
i->Pin.Shft.sz32 = sz32;
i->Pin.Shft.dst = dst;
i->Pin.Shft.srcL = srcL;
i->Pin.Shft.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AddSubC ( Bool isAdd, Bool setC,
HReg dst, HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AddSubC;
i->Pin.AddSubC.isAdd = isAdd;
i->Pin.AddSubC.setC = setC;
i->Pin.AddSubC.dst = dst;
i->Pin.AddSubC.srcL = srcL;
i->Pin.AddSubC.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_Cmp ( Bool syned, Bool sz32,
UInt crfD, HReg srcL, PPCRH* srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Cmp;
i->Pin.Cmp.syned = syned;
i->Pin.Cmp.sz32 = sz32;
i->Pin.Cmp.crfD = crfD;
i->Pin.Cmp.srcL = srcL;
i->Pin.Cmp.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_Unary ( PPCUnaryOp op, HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Unary;
i->Pin.Unary.op = op;
i->Pin.Unary.dst = dst;
i->Pin.Unary.src = src;
return i;
}
PPCInstr* PPCInstr_MulL ( Bool syned, Bool hi, Bool sz32,
HReg dst, HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_MulL;
i->Pin.MulL.syned = syned;
i->Pin.MulL.hi = hi;
i->Pin.MulL.sz32 = sz32;
i->Pin.MulL.dst = dst;
i->Pin.MulL.srcL = srcL;
i->Pin.MulL.srcR = srcR;
/* if doing the low word, the signedness is irrelevant, but tie it
down anyway. */
if (!hi) vassert(!syned);
return i;
}
PPCInstr* PPCInstr_Div ( Bool extended, Bool syned, Bool sz32,
HReg dst, HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Div;
i->Pin.Div.extended = extended;
i->Pin.Div.syned = syned;
i->Pin.Div.sz32 = sz32;
i->Pin.Div.dst = dst;
i->Pin.Div.srcL = srcL;
i->Pin.Div.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_Call ( PPCCondCode cond,
Addr64 target, UInt argiregs, RetLoc rloc ) {
UInt mask;
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Call;
i->Pin.Call.cond = cond;
i->Pin.Call.target = target;
i->Pin.Call.argiregs = argiregs;
i->Pin.Call.rloc = rloc;
/* Only r3 .. r10 inclusive may be used as arg regs. Hence: */
mask = (1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10);
vassert(0 == (argiregs & ~mask));
vassert(is_sane_RetLoc(rloc));
return i;
}
PPCInstr* PPCInstr_XDirect ( Addr64 dstGA, PPCAMode* amCIA,
PPCCondCode cond, Bool toFastEP ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_XDirect;
i->Pin.XDirect.dstGA = dstGA;
i->Pin.XDirect.amCIA = amCIA;
i->Pin.XDirect.cond = cond;
i->Pin.XDirect.toFastEP = toFastEP;
return i;
}
PPCInstr* PPCInstr_XIndir ( HReg dstGA, PPCAMode* amCIA,
PPCCondCode cond ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_XIndir;
i->Pin.XIndir.dstGA = dstGA;
i->Pin.XIndir.amCIA = amCIA;
i->Pin.XIndir.cond = cond;
return i;
}
PPCInstr* PPCInstr_XAssisted ( HReg dstGA, PPCAMode* amCIA,
PPCCondCode cond, IRJumpKind jk ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_XAssisted;
i->Pin.XAssisted.dstGA = dstGA;
i->Pin.XAssisted.amCIA = amCIA;
i->Pin.XAssisted.cond = cond;
i->Pin.XAssisted.jk = jk;
return i;
}
PPCInstr* PPCInstr_CMov ( PPCCondCode cond,
HReg dst, PPCRI* src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_CMov;
i->Pin.CMov.cond = cond;
i->Pin.CMov.src = src;
i->Pin.CMov.dst = dst;
vassert(cond.test != Pct_ALWAYS);
return i;
}
PPCInstr* PPCInstr_Load ( UChar sz,
HReg dst, PPCAMode* src, Bool mode64 ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Load;
i->Pin.Load.sz = sz;
i->Pin.Load.src = src;
i->Pin.Load.dst = dst;
vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
if (sz == 8) vassert(mode64);
return i;
}
PPCInstr* PPCInstr_LoadL ( UChar sz,
HReg dst, HReg src, Bool mode64 )
{
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_LoadL;
i->Pin.LoadL.sz = sz;
i->Pin.LoadL.src = src;
i->Pin.LoadL.dst = dst;
vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
if (sz == 8) vassert(mode64);
return i;
}
PPCInstr* PPCInstr_Store ( UChar sz, PPCAMode* dst, HReg src,
Bool mode64 ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Store;
i->Pin.Store.sz = sz;
i->Pin.Store.src = src;
i->Pin.Store.dst = dst;
vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
if (sz == 8) vassert(mode64);
return i;
}
PPCInstr* PPCInstr_StoreC ( UChar sz, HReg dst, HReg src, Bool mode64 ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_StoreC;
i->Pin.StoreC.sz = sz;
i->Pin.StoreC.src = src;
i->Pin.StoreC.dst = dst;
vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
if (sz == 8) vassert(mode64);
return i;
}
PPCInstr* PPCInstr_Set ( PPCCondCode cond, HReg dst ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Set;
i->Pin.Set.cond = cond;
i->Pin.Set.dst = dst;
return i;
}
PPCInstr* PPCInstr_MfCR ( HReg dst )
{
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_MfCR;
i->Pin.MfCR.dst = dst;
return i;
}
PPCInstr* PPCInstr_MFence ( void )
{
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_MFence;
return i;
}
PPCInstr* PPCInstr_FpUnary ( PPCFpOp op, HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpUnary;
i->Pin.FpUnary.op = op;
i->Pin.FpUnary.dst = dst;
i->Pin.FpUnary.src = src;
return i;
}
PPCInstr* PPCInstr_FpBinary ( PPCFpOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpBinary;
i->Pin.FpBinary.op = op;
i->Pin.FpBinary.dst = dst;
i->Pin.FpBinary.srcL = srcL;
i->Pin.FpBinary.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_Fp128Unary(PPCFpOp op, HReg dst, HReg src) {
PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
i->tag = Pin_Fp128Unary;
i->Pin.Fp128Unary.op = op;
i->Pin.Fp128Unary.dst = dst;
i->Pin.Fp128Unary.src = src;
return i;
}
PPCInstr* PPCInstr_Fp128Binary(PPCFpOp op, HReg dst, HReg srcL, HReg srcR) {
PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
i->tag = Pin_Fp128Binary;
i->Pin.Fp128Binary.op = op;
i->Pin.Fp128Binary.dst = dst;
i->Pin.Fp128Binary.srcL = srcL;
i->Pin.Fp128Binary.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_Fp128Trinary(PPCFpOp op, HReg dst, HReg srcL, HReg srcR) {
PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
i->tag = Pin_Fp128Trinary;
i->Pin.Fp128Trinary.op = op;
i->Pin.Fp128Trinary.dst = dst;
i->Pin.Fp128Trinary.srcL = srcL;
i->Pin.Fp128Trinary.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_FpMulAcc ( PPCFpOp op, HReg dst, HReg srcML,
HReg srcMR, HReg srcAcc )
{
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpMulAcc;
i->Pin.FpMulAcc.op = op;
i->Pin.FpMulAcc.dst = dst;
i->Pin.FpMulAcc.srcML = srcML;
i->Pin.FpMulAcc.srcMR = srcMR;
i->Pin.FpMulAcc.srcAcc = srcAcc;
return i;
}
PPCInstr* PPCInstr_FpLdSt ( Bool isLoad, UChar sz,
HReg reg, PPCAMode* addr ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpLdSt;
i->Pin.FpLdSt.isLoad = isLoad;
i->Pin.FpLdSt.sz = sz;
i->Pin.FpLdSt.reg = reg;
i->Pin.FpLdSt.addr = addr;
vassert(sz == 4 || sz == 8);
return i;
}
PPCInstr* PPCInstr_FpSTFIW ( HReg addr, HReg data )
{
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpSTFIW;
i->Pin.FpSTFIW.addr = addr;
i->Pin.FpSTFIW.data = data;
return i;
}
PPCInstr* PPCInstr_FpRSP ( HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpRSP;
i->Pin.FpRSP.dst = dst;
i->Pin.FpRSP.src = src;
return i;
}
PPCInstr* PPCInstr_Dfp64Unary(PPCFpOp op, HReg dst, HReg src) {
PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
i->tag = Pin_Dfp64Unary;
i->Pin.Dfp64Unary.op = op;
i->Pin.Dfp64Unary.dst = dst;
i->Pin.Dfp64Unary.src = src;
return i;
}
PPCInstr* PPCInstr_Dfp64Binary(PPCFpOp op, HReg dst, HReg srcL, HReg srcR) {
PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
i->tag = Pin_Dfp64Binary;
i->Pin.Dfp64Binary.op = op;
i->Pin.Dfp64Binary.dst = dst;
i->Pin.Dfp64Binary.srcL = srcL;
i->Pin.Dfp64Binary.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_DfpShift ( PPCFpOp op, HReg dst, HReg src, PPCRI* shift ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_DfpShift;
i->Pin.DfpShift.op = op;
i->Pin.DfpShift.shift = shift;
i->Pin.DfpShift.src = src;
i->Pin.DfpShift.dst = dst;
return i;
}
PPCInstr* PPCInstr_Dfp128Unary(PPCFpOp op, HReg dst_hi, HReg dst_lo,
HReg src_hi, HReg src_lo) {
PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
i->tag = Pin_Dfp128Unary;
i->Pin.Dfp128Unary.op = op;
i->Pin.Dfp128Unary.dst_hi = dst_hi;
i->Pin.Dfp128Unary.dst_lo = dst_lo;
i->Pin.Dfp128Unary.src_hi = src_hi;
i->Pin.Dfp128Unary.src_lo = src_lo;
return i;
}
PPCInstr* PPCInstr_Dfp128Binary(PPCFpOp op, HReg dst_hi, HReg dst_lo,
HReg srcR_hi, HReg srcR_lo) {
/* dst is used to pass the srcL argument and return the result */
PPCInstr* i = LibVEX_Alloc_inline( sizeof(PPCInstr) );
i->tag = Pin_Dfp128Binary;
i->Pin.Dfp128Binary.op = op;
i->Pin.Dfp128Binary.dst_hi = dst_hi;
i->Pin.Dfp128Binary.dst_lo = dst_lo;
i->Pin.Dfp128Binary.srcR_hi = srcR_hi;
i->Pin.Dfp128Binary.srcR_lo = srcR_lo;
return i;
}
PPCInstr* PPCInstr_DfpShift128 ( PPCFpOp op, HReg dst_hi, HReg dst_lo,
HReg src_hi, HReg src_lo,
PPCRI* shift ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_DfpShift128;
i->Pin.DfpShift128.op = op;
i->Pin.DfpShift128.shift = shift;
i->Pin.DfpShift128.src_hi = src_hi;
i->Pin.DfpShift128.src_lo = src_lo;
i->Pin.DfpShift128.dst_hi = dst_hi;
i->Pin.DfpShift128.dst_lo = dst_lo;
return i;
}
PPCInstr* PPCInstr_DfpRound ( HReg dst, HReg src, PPCRI* r_rmc ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_DfpRound;
i->Pin.DfpRound.dst = dst;
i->Pin.DfpRound.src = src;
i->Pin.DfpRound.r_rmc = r_rmc;
return i;
}
PPCInstr* PPCInstr_DfpRound128 ( HReg dst_hi, HReg dst_lo, HReg src_hi,
HReg src_lo, PPCRI* r_rmc ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_DfpRound128;
i->Pin.DfpRound128.dst_hi = dst_hi;
i->Pin.DfpRound128.dst_lo = dst_lo;
i->Pin.DfpRound128.src_hi = src_hi;
i->Pin.DfpRound128.src_lo = src_lo;
i->Pin.DfpRound128.r_rmc = r_rmc;
return i;
}
PPCInstr* PPCInstr_DfpQuantize ( PPCFpOp op, HReg dst, HReg srcL, HReg srcR,
PPCRI* rmc ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_DfpQuantize;
i->Pin.DfpQuantize.op = op;
i->Pin.DfpQuantize.dst = dst;
i->Pin.DfpQuantize.srcL = srcL;
i->Pin.DfpQuantize.srcR = srcR;
i->Pin.DfpQuantize.rmc = rmc;
return i;
}
PPCInstr* PPCInstr_DfpQuantize128 ( PPCFpOp op, HReg dst_hi, HReg dst_lo,
HReg src_hi, HReg src_lo, PPCRI* rmc ) {
/* dst is used to pass left operand in and return result */
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_DfpQuantize128;
i->Pin.DfpQuantize128.op = op;
i->Pin.DfpQuantize128.dst_hi = dst_hi;
i->Pin.DfpQuantize128.dst_lo = dst_lo;
i->Pin.DfpQuantize128.src_hi = src_hi;
i->Pin.DfpQuantize128.src_lo = src_lo;
i->Pin.DfpQuantize128.rmc = rmc;
return i;
}
PPCInstr* PPCInstr_DfpD128toD64 ( PPCFpOp op, HReg dst,
HReg src_hi, HReg src_lo ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_DfpD128toD64;
i->Pin.DfpD128toD64.op = op;
i->Pin.DfpD128toD64.src_hi = src_hi;
i->Pin.DfpD128toD64.src_lo = src_lo;
i->Pin.DfpD128toD64.dst = dst;
return i;
}
PPCInstr* PPCInstr_DfpI64StoD128 ( PPCFpOp op, HReg dst_hi,
HReg dst_lo, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_DfpI64StoD128;
i->Pin.DfpI64StoD128.op = op;
i->Pin.DfpI64StoD128.src = src;
i->Pin.DfpI64StoD128.dst_hi = dst_hi;
i->Pin.DfpI64StoD128.dst_lo = dst_lo;
return i;
}
PPCInstr* PPCInstr_ExtractExpD128 ( PPCFpOp op, HReg dst,
HReg src_hi, HReg src_lo ) {
/* dst is used to pass the srcL argument */
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_ExtractExpD128;
i->Pin.ExtractExpD128.op = op;
i->Pin.ExtractExpD128.dst = dst;
i->Pin.ExtractExpD128.src_hi = src_hi;
i->Pin.ExtractExpD128.src_lo = src_lo;
return i;
}
PPCInstr* PPCInstr_InsertExpD128 ( PPCFpOp op, HReg dst_hi, HReg dst_lo,
HReg srcL, HReg srcR_hi, HReg srcR_lo ) {
/* dst is used to pass the srcL argument */
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_InsertExpD128;
i->Pin.InsertExpD128.op = op;
i->Pin.InsertExpD128.dst_hi = dst_hi;
i->Pin.InsertExpD128.dst_lo = dst_lo;
i->Pin.InsertExpD128.srcL = srcL;
i->Pin.InsertExpD128.srcR_hi = srcR_hi;
i->Pin.InsertExpD128.srcR_lo = srcR_lo;
return i;
}
PPCInstr* PPCInstr_Dfp64Cmp (/* UInt crfD,*/ HReg dst, HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Dfp64Cmp;
i->Pin.Dfp64Cmp.dst = dst;
i->Pin.Dfp64Cmp.srcL = srcL;
i->Pin.Dfp64Cmp.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_Dfp128Cmp ( HReg dst, HReg srcL_hi, HReg srcL_lo,
HReg srcR_hi, HReg srcR_lo ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_Dfp128Cmp;
i->Pin.Dfp128Cmp.dst = dst;
i->Pin.Dfp128Cmp.srcL_hi = srcL_hi;
i->Pin.Dfp128Cmp.srcL_lo = srcL_lo;
i->Pin.Dfp128Cmp.srcR_hi = srcR_hi;
i->Pin.Dfp128Cmp.srcR_lo = srcR_lo;
return i;
}
PPCInstr* PPCInstr_EvCheck ( PPCAMode* amCounter,
PPCAMode* amFailAddr ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_EvCheck;
i->Pin.EvCheck.amCounter = amCounter;
i->Pin.EvCheck.amFailAddr = amFailAddr;
return i;
}
PPCInstr* PPCInstr_ProfInc ( void ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_ProfInc;
return i;
}
/*
Valid combo | fromI | int32 | syned | flt64 |
--------------------------------------------
| n n n n |
--------------------------------------------
F64->I64U | n n n y |
--------------------------------------------
| n n y n |
--------------------------------------------
F64->I64S | n n y y |
--------------------------------------------
| n y n n |
--------------------------------------------
F64->I32U | n y n y |
--------------------------------------------
| n y y n |
--------------------------------------------
F64->I32S | n y y y |
--------------------------------------------
I64U->F32 | y n n n |
--------------------------------------------
I64U->F64 | y n n y |
--------------------------------------------
| y n y n |
--------------------------------------------
I64S->F64 | y n y y |
--------------------------------------------
| y y n n |
--------------------------------------------
| y y n y |
--------------------------------------------
| y y y n |
--------------------------------------------
| y y y y |
--------------------------------------------
*/
PPCInstr* PPCInstr_FpCftI ( Bool fromI, Bool int32, Bool syned,
Bool flt64, HReg dst, HReg src ) {
Bool tmp = fromI | int32 | syned | flt64;
vassert(tmp == True || tmp == False); // iow, no high bits set
UShort conversion = 0;
conversion = (fromI << 3) | (int32 << 2) | (syned << 1) | flt64;
switch (conversion) {
// Supported conversion operations
case 1: case 3: case 5: case 7:
case 8: case 9: case 11:
break;
default:
vpanic("PPCInstr_FpCftI(ppc_host)");
}
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpCftI;
i->Pin.FpCftI.fromI = fromI;
i->Pin.FpCftI.int32 = int32;
i->Pin.FpCftI.syned = syned;
i->Pin.FpCftI.flt64 = flt64;
i->Pin.FpCftI.dst = dst;
i->Pin.FpCftI.src = src;
return i;
}
PPCInstr* PPCInstr_FpCMov ( PPCCondCode cond, HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpCMov;
i->Pin.FpCMov.cond = cond;
i->Pin.FpCMov.dst = dst;
i->Pin.FpCMov.src = src;
vassert(cond.test != Pct_ALWAYS);
return i;
}
PPCInstr* PPCInstr_FpLdFPSCR ( HReg src, Bool dfp_rm ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpLdFPSCR;
i->Pin.FpLdFPSCR.src = src;
i->Pin.FpLdFPSCR.dfp_rm = dfp_rm ? 1 : 0;
return i;
}
PPCInstr* PPCInstr_FpCmp ( HReg dst, HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_FpCmp;
i->Pin.FpCmp.dst = dst;
i->Pin.FpCmp.srcL = srcL;
i->Pin.FpCmp.srcR = srcR;
return i;
}
/* Read/Write Link Register */
PPCInstr* PPCInstr_RdWrLR ( Bool wrLR, HReg gpr ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_RdWrLR;
i->Pin.RdWrLR.wrLR = wrLR;
i->Pin.RdWrLR.gpr = gpr;
return i;
}
/* AltiVec */
PPCInstr* PPCInstr_AvLdSt ( Bool isLoad, UChar sz,
HReg reg, PPCAMode* addr ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvLdSt;
i->Pin.AvLdSt.isLoad = isLoad;
i->Pin.AvLdSt.sz = sz;
i->Pin.AvLdSt.reg = reg;
i->Pin.AvLdSt.addr = addr;
return i;
}
PPCInstr* PPCInstr_AvUnary ( PPCAvOp op, HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvUnary;
i->Pin.AvUnary.op = op;
i->Pin.AvUnary.dst = dst;
i->Pin.AvUnary.src = src;
return i;
}
PPCInstr* PPCInstr_AvBinary ( PPCAvOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBinary;
i->Pin.AvBinary.op = op;
i->Pin.AvBinary.dst = dst;
i->Pin.AvBinary.srcL = srcL;
i->Pin.AvBinary.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvBinaryInt ( PPCAvOp op, HReg dst,
HReg src, PPCRI* val ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBinaryInt;
i->Pin.AvBinaryInt.op = op;
i->Pin.AvBinaryInt.dst = dst;
i->Pin.AvBinaryInt.src = src;
i->Pin.AvBinaryInt.val = val;
return i;
}
PPCInstr* PPCInstr_AvBin8x16 ( PPCAvOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBin8x16;
i->Pin.AvBin8x16.op = op;
i->Pin.AvBin8x16.dst = dst;
i->Pin.AvBin8x16.srcL = srcL;
i->Pin.AvBin8x16.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvBin16x8 ( PPCAvOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBin16x8;
i->Pin.AvBin16x8.op = op;
i->Pin.AvBin16x8.dst = dst;
i->Pin.AvBin16x8.srcL = srcL;
i->Pin.AvBin16x8.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvBin32x4 ( PPCAvOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBin32x4;
i->Pin.AvBin32x4.op = op;
i->Pin.AvBin32x4.dst = dst;
i->Pin.AvBin32x4.srcL = srcL;
i->Pin.AvBin32x4.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvBin64x2 ( PPCAvOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBin64x2;
i->Pin.AvBin64x2.op = op;
i->Pin.AvBin64x2.dst = dst;
i->Pin.AvBin64x2.srcL = srcL;
i->Pin.AvBin64x2.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvBin32Fx4 ( PPCAvFpOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBin32Fx4;
i->Pin.AvBin32Fx4.op = op;
i->Pin.AvBin32Fx4.dst = dst;
i->Pin.AvBin32Fx4.srcL = srcL;
i->Pin.AvBin32Fx4.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvUn32Fx4 ( PPCAvFpOp op, HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvUn32Fx4;
i->Pin.AvUn32Fx4.op = op;
i->Pin.AvUn32Fx4.dst = dst;
i->Pin.AvUn32Fx4.src = src;
return i;
}
PPCInstr* PPCInstr_AvPerm ( HReg dst, HReg srcL, HReg srcR, HReg ctl ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvPerm;
i->Pin.AvPerm.dst = dst;
i->Pin.AvPerm.srcL = srcL;
i->Pin.AvPerm.srcR = srcR;
i->Pin.AvPerm.ctl = ctl;
return i;
}
PPCInstr* PPCInstr_AvSel ( HReg ctl, HReg dst, HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvSel;
i->Pin.AvSel.ctl = ctl;
i->Pin.AvSel.dst = dst;
i->Pin.AvSel.srcL = srcL;
i->Pin.AvSel.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvSh ( Bool shLeft, HReg dst, PPCAMode* addr ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvSh;
i->Pin.AvSh.shLeft = shLeft;
i->Pin.AvSh.dst = dst;
i->Pin.AvSh.addr = addr;
return i;
}
PPCInstr* PPCInstr_AvShlDbl ( UChar shift, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvShlDbl;
i->Pin.AvShlDbl.shift = shift;
i->Pin.AvShlDbl.dst = dst;
i->Pin.AvShlDbl.srcL = srcL;
i->Pin.AvShlDbl.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvSplat ( UChar sz, HReg dst, PPCVI5s* src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvSplat;
i->Pin.AvSplat.sz = sz;
i->Pin.AvSplat.dst = dst;
i->Pin.AvSplat.src = src;
return i;
}
PPCInstr* PPCInstr_AvCMov ( PPCCondCode cond, HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvCMov;
i->Pin.AvCMov.cond = cond;
i->Pin.AvCMov.dst = dst;
i->Pin.AvCMov.src = src;
vassert(cond.test != Pct_ALWAYS);
return i;
}
PPCInstr* PPCInstr_AvLdVSCR ( HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvLdVSCR;
i->Pin.AvLdVSCR.src = src;
return i;
}
PPCInstr* PPCInstr_AvCipherV128Unary ( PPCAvOp op, HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvCipherV128Unary;
i->Pin.AvCipherV128Unary.op = op;
i->Pin.AvCipherV128Unary.dst = dst;
i->Pin.AvCipherV128Unary.src = src;
return i;
}
PPCInstr* PPCInstr_AvCipherV128Binary ( PPCAvOp op, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvCipherV128Binary;
i->Pin.AvCipherV128Binary.op = op;
i->Pin.AvCipherV128Binary.dst = dst;
i->Pin.AvCipherV128Binary.srcL = srcL;
i->Pin.AvCipherV128Binary.srcR = srcR;
return i;
}
PPCInstr* PPCInstr_AvHashV128Binary ( PPCAvOp op, HReg dst,
HReg src, PPCRI* s_field ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvHashV128Binary;
i->Pin.AvHashV128Binary.op = op;
i->Pin.AvHashV128Binary.dst = dst;
i->Pin.AvHashV128Binary.src = src;
i->Pin.AvHashV128Binary.s_field = s_field;
return i;
}
PPCInstr* PPCInstr_AvBCDV128Binary ( PPCAvOp op, HReg dst,
HReg src1, HReg src2 ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBCDV128Binary;
i->Pin.AvBCDV128Binary.op = op;
i->Pin.AvBCDV128Binary.dst = dst;
i->Pin.AvBCDV128Binary.src1 = src1;
i->Pin.AvBCDV128Binary.src2 = src2;
return i;
}
/* Pretty Print instructions */
static void ppLoadImm ( HReg dst, ULong imm, Bool mode64 ) {
vex_printf("li_word ");
ppHRegPPC(dst);
if (!mode64) {
vex_printf(",0x%08x", (UInt)imm);
} else {
vex_printf(",0x%016llx", imm);
}
}
static void ppMovReg ( HReg dst, HReg src ) {
if (!sameHReg(dst, src)) {
vex_printf("mr ");
ppHRegPPC(dst);
vex_printf(",");
ppHRegPPC(src);
}
}
void ppPPCInstr ( const PPCInstr* i, Bool mode64 )
{
switch (i->tag) {
case Pin_LI:
ppLoadImm(i->Pin.LI.dst, i->Pin.LI.imm64, mode64);
break;
case Pin_Alu: {
HReg r_srcL = i->Pin.Alu.srcL;
PPCRH* rh_srcR = i->Pin.Alu.srcR;
/* special-case "mr" */
if (i->Pin.Alu.op == Palu_OR && // or Rd,Rs,Rs == mr Rd,Rs
rh_srcR->tag == Prh_Reg &&
sameHReg(rh_srcR->Prh.Reg.reg, r_srcL)) {
vex_printf("mr ");
ppHRegPPC(i->Pin.Alu.dst);
vex_printf(",");
ppHRegPPC(r_srcL);
return;
}
/* special-case "li" */
if (i->Pin.Alu.op == Palu_ADD && // addi Rd,0,imm == li Rd,imm
rh_srcR->tag == Prh_Imm &&
hregEncoding(r_srcL) == 0) {
vex_printf("li ");
ppHRegPPC(i->Pin.Alu.dst);
vex_printf(",");
ppPPCRH(rh_srcR);
return;
}
/* generic */
vex_printf("%s ", showPPCAluOp(i->Pin.Alu.op,
toBool(rh_srcR->tag == Prh_Imm)));
ppHRegPPC(i->Pin.Alu.dst);
vex_printf(",");
ppHRegPPC(r_srcL);
vex_printf(",");
ppPPCRH(rh_srcR);
return;
}
case Pin_Shft: {
HReg r_srcL = i->Pin.Shft.srcL;
PPCRH* rh_srcR = i->Pin.Shft.srcR;
vex_printf("%s ", showPPCShftOp(i->Pin.Shft.op,
toBool(rh_srcR->tag == Prh_Imm),
i->Pin.Shft.sz32));
ppHRegPPC(i->Pin.Shft.dst);
vex_printf(",");
ppHRegPPC(r_srcL);
vex_printf(",");
ppPPCRH(rh_srcR);
return;
}
case Pin_AddSubC:
vex_printf("%s%s ",
i->Pin.AddSubC.isAdd ? "add" : "sub",
i->Pin.AddSubC.setC ? "c" : "e");
ppHRegPPC(i->Pin.AddSubC.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AddSubC.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AddSubC.srcR);
return;
case Pin_Cmp:
vex_printf("%s%c%s %%cr%u,",
i->Pin.Cmp.syned ? "cmp" : "cmpl",
i->Pin.Cmp.sz32 ? 'w' : 'd',
i->Pin.Cmp.srcR->tag == Prh_Imm ? "i" : "",
i->Pin.Cmp.crfD);
ppHRegPPC(i->Pin.Cmp.srcL);
vex_printf(",");
ppPPCRH(i->Pin.Cmp.srcR);
return;
case Pin_Unary:
vex_printf("%s ", showPPCUnaryOp(i->Pin.Unary.op));
ppHRegPPC(i->Pin.Unary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Unary.src);
return;
case Pin_MulL:
vex_printf("mul%c%c%s ",
i->Pin.MulL.hi ? 'h' : 'l',
i->Pin.MulL.sz32 ? 'w' : 'd',
i->Pin.MulL.hi ? (i->Pin.MulL.syned ? "s" : "u") : "");
ppHRegPPC(i->Pin.MulL.dst);
vex_printf(",");
ppHRegPPC(i->Pin.MulL.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.MulL.srcR);
return;
case Pin_Div:
vex_printf("div%c%s%s ",
i->Pin.Div.sz32 ? 'w' : 'd',
i->Pin.Div.extended ? "e" : "",
i->Pin.Div.syned ? "" : "u");
ppHRegPPC(i->Pin.Div.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Div.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.Div.srcR);
return;
case Pin_Call: {
Int n;
vex_printf("call: ");
if (i->Pin.Call.cond.test != Pct_ALWAYS) {
vex_printf("if (%s) ", showPPCCondCode(i->Pin.Call.cond));
}
vex_printf("{ ");
ppLoadImm(hregPPC_GPR10(mode64), i->Pin.Call.target, mode64);
vex_printf(" ; mtctr r10 ; bctrl [");
for (n = 0; n < 32; n++) {
if (i->Pin.Call.argiregs & (1<<n)) {
vex_printf("r%d", n);
if ((i->Pin.Call.argiregs >> n) > 1)
vex_printf(",");
}
}
vex_printf(",");
ppRetLoc(i->Pin.Call.rloc);
vex_printf("] }");
break;
}
case Pin_XDirect:
vex_printf("(xDirect) ");
vex_printf("if (%s) { ",
showPPCCondCode(i->Pin.XDirect.cond));
if (mode64) {
vex_printf("imm64 r30,0x%llx; ", i->Pin.XDirect.dstGA);
vex_printf("std r30,");
} else {
vex_printf("imm32 r30,0x%llx; ", i->Pin.XDirect.dstGA);
vex_printf("stw r30,");
}
ppPPCAMode(i->Pin.XDirect.amCIA);
vex_printf("; ");
if (mode64) {
vex_printf("imm64-fixed5 r30,$disp_cp_chain_me_to_%sEP; ",
i->Pin.XDirect.toFastEP ? "fast" : "slow");
} else {
vex_printf("imm32-fixed2 r30,$disp_cp_chain_me_to_%sEP; ",
i->Pin.XDirect.toFastEP ? "fast" : "slow");
}
vex_printf("mtctr r30; bctrl }");
return;
case Pin_XIndir:
vex_printf("(xIndir) ");
vex_printf("if (%s) { ",
showPPCCondCode(i->Pin.XIndir.cond));
vex_printf("%s ", mode64 ? "std" : "stw");
ppHRegPPC(i->Pin.XIndir.dstGA);
vex_printf(",");
ppPPCAMode(i->Pin.XIndir.amCIA);
vex_printf("; ");
vex_printf("imm%s r30,$disp_cp_xindir; ", mode64 ? "64" : "32");
vex_printf("mtctr r30; bctr }");
return;
case Pin_XAssisted:
vex_printf("(xAssisted) ");
vex_printf("if (%s) { ",
showPPCCondCode(i->Pin.XAssisted.cond));
vex_printf("%s ", mode64 ? "std" : "stw");
ppHRegPPC(i->Pin.XAssisted.dstGA);
vex_printf(",");
ppPPCAMode(i->Pin.XAssisted.amCIA);
vex_printf("; ");
vex_printf("li r31,$IRJumpKind_to_TRCVAL(%d); ",
(Int)i->Pin.XAssisted.jk);
vex_printf("imm%s r30,$disp_cp_xindir; ", mode64 ? "64" : "32");
vex_printf("mtctr r30; bctr }");
return;
case Pin_CMov:
vex_printf("cmov (%s) ", showPPCCondCode(i->Pin.CMov.cond));
ppHRegPPC(i->Pin.CMov.dst);
vex_printf(",");
ppPPCRI(i->Pin.CMov.src);
vex_printf(": ");
if (i->Pin.CMov.cond.test != Pct_ALWAYS) {
vex_printf("if (%s) ", showPPCCondCode(i->Pin.CMov.cond));
}
vex_printf("{ ");
if (i->Pin.CMov.src->tag == Pri_Imm) {
ppLoadImm(i->Pin.CMov.dst, i->Pin.CMov.src->Pri.Imm, mode64);
} else {
ppMovReg(i->Pin.CMov.dst, i->Pin.CMov.src->Pri.Reg);
}
vex_printf(" }");
return;
case Pin_Load: {
Bool idxd = toBool(i->Pin.Load.src->tag == Pam_RR);
UChar sz = i->Pin.Load.sz;
HChar c_sz = sz==1 ? 'b' : sz==2 ? 'h' : sz==4 ? 'w' : 'd';
vex_printf("l%c%s%s ", c_sz, sz==8 ? "" : "z", idxd ? "x" : "" );
ppHRegPPC(i->Pin.Load.dst);
vex_printf(",");
ppPPCAMode(i->Pin.Load.src);
return;
}
case Pin_LoadL: {
UChar sz = i->Pin.LoadL.sz;
HChar c_sz = sz==1 ? 'b' : sz==2 ? 'h' : sz==4 ? 'w' : 'd';
vex_printf("l%carx ", c_sz);
ppHRegPPC(i->Pin.LoadL.dst);
vex_printf(",%%r0,");
ppHRegPPC(i->Pin.LoadL.src);
return;
}
case Pin_Store: {
UChar sz = i->Pin.Store.sz;
Bool idxd = toBool(i->Pin.Store.dst->tag == Pam_RR);
HChar c_sz = sz==1 ? 'b' : sz==2 ? 'h' : sz==4 ? 'w' : /*8*/ 'd';
vex_printf("st%c%s ", c_sz, idxd ? "x" : "" );
ppHRegPPC(i->Pin.Store.src);
vex_printf(",");
ppPPCAMode(i->Pin.Store.dst);
return;
}
case Pin_StoreC: {
UChar sz = i->Pin.StoreC.sz;
HChar c_sz = sz==1 ? 'b' : sz==2 ? 'h' : sz==4 ? 'w' : 'd';
vex_printf("st%ccx. ", c_sz);
ppHRegPPC(i->Pin.StoreC.src);
vex_printf(",%%r0,");
ppHRegPPC(i->Pin.StoreC.dst);
return;
}
case Pin_Set: {
PPCCondCode cc = i->Pin.Set.cond;
vex_printf("set (%s),", showPPCCondCode(cc));
ppHRegPPC(i->Pin.Set.dst);
if (cc.test == Pct_ALWAYS) {
vex_printf(": { li ");
ppHRegPPC(i->Pin.Set.dst);
vex_printf(",1 }");
} else {
vex_printf(": { mfcr r0 ; rlwinm ");
ppHRegPPC(i->Pin.Set.dst);
vex_printf(",r0,%u,31,31", cc.flag+1);
if (cc.test == Pct_FALSE) {
vex_printf("; xori ");
ppHRegPPC(i->Pin.Set.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Set.dst);
vex_printf(",1");
}
vex_printf(" }");
}
return;
}
case Pin_MfCR:
vex_printf("mfcr ");
ppHRegPPC(i->Pin.MfCR.dst);
break;
case Pin_MFence:
vex_printf("mfence (=sync)");
return;
case Pin_FpUnary:
vex_printf("%s ", showPPCFpOp(i->Pin.FpUnary.op));
ppHRegPPC(i->Pin.FpUnary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.FpUnary.src);
return;
case Pin_FpBinary:
vex_printf("%s ", showPPCFpOp(i->Pin.FpBinary.op));
ppHRegPPC(i->Pin.FpBinary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.FpBinary.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.FpBinary.srcR);
return;
case Pin_Fp128Unary:
vex_printf("%s ", showPPCFpOp(i->Pin.Fp128Unary.op));
ppHRegPPC(i->Pin.Fp128Unary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Fp128Unary.src);
return;
case Pin_Fp128Binary:
vex_printf("%s ", showPPCFpOp(i->Pin.Fp128Binary.op));
ppHRegPPC(i->Pin.Fp128Binary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Fp128Binary.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.Fp128Binary.srcR);
return;
case Pin_Fp128Trinary:
vex_printf("%s ", showPPCFpOp(i->Pin.Fp128Trinary.op));
ppHRegPPC(i->Pin.Fp128Trinary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Fp128Trinary.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.Fp128Trinary.srcR);
return;
case Pin_FpMulAcc:
vex_printf("%s ", showPPCFpOp(i->Pin.FpMulAcc.op));
ppHRegPPC(i->Pin.FpMulAcc.dst);
vex_printf(",");
ppHRegPPC(i->Pin.FpMulAcc.srcML);
vex_printf(",");
ppHRegPPC(i->Pin.FpMulAcc.srcMR);
vex_printf(",");
ppHRegPPC(i->Pin.FpMulAcc.srcAcc);
return;
case Pin_FpLdSt: {
UChar sz = i->Pin.FpLdSt.sz;
Bool idxd = toBool(i->Pin.FpLdSt.addr->tag == Pam_RR);
if (i->Pin.FpLdSt.isLoad) {
vex_printf("lf%c%s ",
(sz==4 ? 's' : 'd'),
idxd ? "x" : "" );
ppHRegPPC(i->Pin.FpLdSt.reg);
vex_printf(",");
ppPPCAMode(i->Pin.FpLdSt.addr);
} else {
vex_printf("stf%c%s ",
(sz==4 ? 's' : 'd'),
idxd ? "x" : "" );
ppHRegPPC(i->Pin.FpLdSt.reg);
vex_printf(",");
ppPPCAMode(i->Pin.FpLdSt.addr);
}
return;
}
case Pin_FpSTFIW:
vex_printf("stfiwz ");
ppHRegPPC(i->Pin.FpSTFIW.data);
vex_printf(",0(");
ppHRegPPC(i->Pin.FpSTFIW.addr);
vex_printf(")");
return;
case Pin_FpRSP:
vex_printf("frsp ");
ppHRegPPC(i->Pin.FpRSP.dst);
vex_printf(",");
ppHRegPPC(i->Pin.FpRSP.src);
return;
case Pin_FpCftI: {
const HChar* str = "fc?????";
/* Note that "fcfids" is missing from below. That instruction would
* satisfy the predicate:
* (i->Pin.FpCftI.fromI == True && i->Pin.FpCftI.int32 == False)
* which would go into a final "else" clause to make this if-else
* block balanced. But we're able to implement fcfids by leveraging
* the fcfid implementation, so it wasn't necessary to include it here.
*/
if (i->Pin.FpCftI.fromI == False && i->Pin.FpCftI.int32 == False)
if (i->Pin.FpCftI.syned == True)
str = "fctid";
else
str = "fctidu";
else if (i->Pin.FpCftI.fromI == False && i->Pin.FpCftI.int32 == True)
if (i->Pin.FpCftI.syned == True)
str = "fctiw";
else
str = "fctiwu";
else if (i->Pin.FpCftI.fromI == True && i->Pin.FpCftI.int32 == False) {
if (i->Pin.FpCftI.syned == True) {
str = "fcfid";
} else {
if (i->Pin.FpCftI.flt64 == True)
str = "fcfidu";
else
str = "fcfidus";
}
}
vex_printf("%s ", str);
ppHRegPPC(i->Pin.FpCftI.dst);
vex_printf(",");
ppHRegPPC(i->Pin.FpCftI.src);
return;
}
case Pin_FpCMov:
vex_printf("fpcmov (%s) ", showPPCCondCode(i->Pin.FpCMov.cond));
ppHRegPPC(i->Pin.FpCMov.dst);
vex_printf(",");
ppHRegPPC(i->Pin.FpCMov.src);
vex_printf(": ");
vex_printf("if (fr_dst != fr_src) { ");
if (i->Pin.FpCMov.cond.test != Pct_ALWAYS) {
vex_printf("if (%s) { ", showPPCCondCode(i->Pin.FpCMov.cond));
}
vex_printf("fmr ");
ppHRegPPC(i->Pin.FpCMov.dst);
vex_printf(",");
ppHRegPPC(i->Pin.FpCMov.src);
if (i->Pin.FpCMov.cond.test != Pct_ALWAYS)
vex_printf(" }");
vex_printf(" }");
return;
case Pin_FpLdFPSCR:
vex_printf("mtfsf 0xFF,");
ppHRegPPC(i->Pin.FpLdFPSCR.src);
vex_printf(",0, %s", i->Pin.FpLdFPSCR.dfp_rm ? "1" : "0");
return;
case Pin_FpCmp:
vex_printf("fcmpo %%cr1,");
ppHRegPPC(i->Pin.FpCmp.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.FpCmp.srcR);
vex_printf("; mfcr ");
ppHRegPPC(i->Pin.FpCmp.dst);
vex_printf("; rlwinm ");
ppHRegPPC(i->Pin.FpCmp.dst);
vex_printf(",");
ppHRegPPC(i->Pin.FpCmp.dst);
vex_printf(",8,28,31");
return;
case Pin_RdWrLR:
vex_printf("%s ", i->Pin.RdWrLR.wrLR ? "mtlr" : "mflr");
ppHRegPPC(i->Pin.RdWrLR.gpr);
return;
case Pin_AvLdSt: {
UChar sz = i->Pin.AvLdSt.sz;
const HChar* str_size;
if (i->Pin.AvLdSt.addr->tag == Pam_IR) {
ppLoadImm(hregPPC_GPR30(mode64),
i->Pin.AvLdSt.addr->Pam.IR.index, mode64);
vex_printf(" ; ");
}
str_size = sz==1 ? "eb" : sz==2 ? "eh" : sz==4 ? "ew" : "";
if (i->Pin.AvLdSt.isLoad)
vex_printf("lv%sx ", str_size);
else
vex_printf("stv%sx ", str_size);
ppHRegPPC(i->Pin.AvLdSt.reg);
vex_printf(",");
if (i->Pin.AvLdSt.addr->tag == Pam_IR)
vex_printf("%%r30");
else
ppHRegPPC(i->Pin.AvLdSt.addr->Pam.RR.index);
vex_printf(",");
ppHRegPPC(i->Pin.AvLdSt.addr->Pam.RR.base);
return;
}
case Pin_AvUnary:
vex_printf("%s ", showPPCAvOp(i->Pin.AvUnary.op));
ppHRegPPC(i->Pin.AvUnary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvUnary.src);
return;
case Pin_AvBinary:
vex_printf("%s ", showPPCAvOp(i->Pin.AvBinary.op));
ppHRegPPC(i->Pin.AvBinary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBinary.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvBinary.srcR);
return;
case Pin_AvBinaryInt:
vex_printf("%s ", showPPCAvOp(i->Pin.AvBinaryInt.op));
ppHRegPPC(i->Pin.AvBinaryInt.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBinaryInt.src);
vex_printf(",");
ppPPCRI(i->Pin.AvBinaryInt.val);
return;
case Pin_AvBin8x16:
vex_printf("%s(b) ", showPPCAvOp(i->Pin.AvBin8x16.op));
ppHRegPPC(i->Pin.AvBin8x16.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin8x16.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin8x16.srcR);
return;
case Pin_AvBin16x8:
vex_printf("%s(h) ", showPPCAvOp(i->Pin.AvBin16x8.op));
ppHRegPPC(i->Pin.AvBin16x8.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin16x8.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin16x8.srcR);
return;
case Pin_AvBin32x4:
vex_printf("%s(w) ", showPPCAvOp(i->Pin.AvBin32x4.op));
ppHRegPPC(i->Pin.AvBin32x4.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin32x4.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin32x4.srcR);
return;
case Pin_AvBin64x2:
vex_printf("%s(w) ", showPPCAvOp(i->Pin.AvBin64x2.op));
ppHRegPPC(i->Pin.AvBin64x2.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin64x2.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin64x2.srcR);
return;
case Pin_AvBin32Fx4:
vex_printf("%s ", showPPCAvFpOp(i->Pin.AvBin32Fx4.op));
ppHRegPPC(i->Pin.AvBin32Fx4.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin32Fx4.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvBin32Fx4.srcR);
return;
case Pin_AvUn32Fx4:
vex_printf("%s ", showPPCAvFpOp(i->Pin.AvUn32Fx4.op));
ppHRegPPC(i->Pin.AvUn32Fx4.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvUn32Fx4.src);
return;
case Pin_AvPerm:
vex_printf("vperm ");
ppHRegPPC(i->Pin.AvPerm.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvPerm.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvPerm.srcR);
vex_printf(",");
ppHRegPPC(i->Pin.AvPerm.ctl);
return;
case Pin_AvSel:
vex_printf("vsel ");
ppHRegPPC(i->Pin.AvSel.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvSel.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvSel.srcR);
vex_printf(",");
ppHRegPPC(i->Pin.AvSel.ctl);
return;
case Pin_AvSh:
/* This only generates the following instructions with RA
* register number set to 0.
*/
if (i->Pin.AvSh.addr->tag == Pam_IR) {
ppLoadImm(hregPPC_GPR30(mode64),
i->Pin.AvSh.addr->Pam.IR.index, mode64);
vex_printf(" ; ");
}
if (i->Pin.AvSh.shLeft)
vex_printf("lvsl ");
else
vex_printf("lvsr ");
ppHRegPPC(i->Pin.AvSh.dst);
if (i->Pin.AvSh.addr->tag == Pam_IR)
vex_printf("%%r30");
else
ppHRegPPC(i->Pin.AvSh.addr->Pam.RR.index);
vex_printf(",");
ppHRegPPC(i->Pin.AvSh.addr->Pam.RR.base);
return;
case Pin_AvShlDbl:
vex_printf("vsldoi ");
ppHRegPPC(i->Pin.AvShlDbl.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvShlDbl.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvShlDbl.srcR);
vex_printf(",%d", i->Pin.AvShlDbl.shift);
return;
case Pin_AvSplat: {
UChar sz = i->Pin.AvSplat.sz;
HChar ch_sz = toUChar( (sz == 8) ? 'b' : (sz == 16) ? 'h' : 'w' );
vex_printf("vsplt%s%c ",
i->Pin.AvSplat.src->tag == Pvi_Imm ? "is" : "", ch_sz);
ppHRegPPC(i->Pin.AvSplat.dst);
vex_printf(",");
ppPPCVI5s(i->Pin.AvSplat.src);
if (i->Pin.AvSplat.src->tag == Pvi_Reg)
vex_printf(", %d", (128/sz)-1); /* louis lane */
return;
}
case Pin_AvCMov:
vex_printf("avcmov (%s) ", showPPCCondCode(i->Pin.AvCMov.cond));
ppHRegPPC(i->Pin.AvCMov.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvCMov.src);
vex_printf(": ");
vex_printf("if (v_dst != v_src) { ");
if (i->Pin.AvCMov.cond.test != Pct_ALWAYS) {
vex_printf("if (%s) { ", showPPCCondCode(i->Pin.AvCMov.cond));
}
vex_printf("vmr ");
ppHRegPPC(i->Pin.AvCMov.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvCMov.src);
if (i->Pin.FpCMov.cond.test != Pct_ALWAYS)
vex_printf(" }");
vex_printf(" }");
return;
case Pin_AvLdVSCR:
vex_printf("mtvscr ");
ppHRegPPC(i->Pin.AvLdVSCR.src);
return;
case Pin_AvCipherV128Unary:
vex_printf("%s(w) ", showPPCAvOp(i->Pin.AvCipherV128Unary.op));
ppHRegPPC(i->Pin.AvCipherV128Unary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvCipherV128Unary.src);
return;
case Pin_AvCipherV128Binary:
vex_printf("%s(w) ", showPPCAvOp(i->Pin.AvCipherV128Binary.op));
ppHRegPPC(i->Pin.AvCipherV128Binary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvCipherV128Binary.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.AvCipherV128Binary.srcR);
return;
case Pin_AvHashV128Binary:
vex_printf("%s(w) ", showPPCAvOp(i->Pin.AvHashV128Binary.op));
ppHRegPPC(i->Pin.AvHashV128Binary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvHashV128Binary.src);
vex_printf(",");
ppPPCRI(i->Pin.AvHashV128Binary.s_field);
return;
case Pin_AvBCDV128Binary:
vex_printf("%s(w) ", showPPCAvOp(i->Pin.AvBCDV128Binary.op));
ppHRegPPC(i->Pin.AvBCDV128Binary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBCDV128Binary.src1);
vex_printf(",");
ppHRegPPC(i->Pin.AvBCDV128Binary.src2);
return;
case Pin_Dfp64Unary:
vex_printf("%s ", showPPCFpOp(i->Pin.Dfp64Unary.op));
ppHRegPPC(i->Pin.Dfp64Unary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp64Unary.src);
return;
case Pin_Dfp64Binary:
vex_printf("%s ", showPPCFpOp(i->Pin.Dfp64Binary.op));
ppHRegPPC(i->Pin.Dfp64Binary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp64Binary.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp64Binary.srcR);
return;
case Pin_DfpShift:
vex_printf("%s ", showPPCFpOp(i->Pin.DfpShift.op));
ppHRegPPC(i->Pin.DfpShift.dst);
vex_printf(",");
ppHRegPPC(i->Pin.DfpShift.src);
vex_printf(",");
ppPPCRI(i->Pin.DfpShift.shift);
return;
case Pin_Dfp128Unary:
vex_printf("%s ", showPPCFpOp(i->Pin.Dfp128Unary.op));
ppHRegPPC(i->Pin.Dfp128Unary.dst_hi);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp128Unary.src_hi);
return;
case Pin_Dfp128Binary:
vex_printf("%s ", showPPCFpOp(i->Pin.Dfp128Binary.op));
ppHRegPPC(i->Pin.Dfp128Binary.dst_hi);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp128Binary.srcR_hi);
return;
case Pin_DfpShift128:
vex_printf("%s ", showPPCFpOp(i->Pin.DfpShift128.op));
ppHRegPPC(i->Pin.DfpShift128.dst_hi);
vex_printf(",");
ppHRegPPC(i->Pin.DfpShift128.src_hi);
vex_printf(",");
ppPPCRI(i->Pin.DfpShift128.shift);
return;
case Pin_DfpRound:
vex_printf("drintx ");
ppHRegPPC(i->Pin.DfpRound.dst);
vex_printf(",");
ppHRegPPC(i->Pin.DfpRound.src);
vex_printf(",");
ppPPCRI(i->Pin.DfpRound.r_rmc); /* R in bit 3 and RMC in bits 2:0 */
return;
case Pin_DfpRound128:
vex_printf("drintxq ");
ppHRegPPC(i->Pin.DfpRound128.dst_hi);
vex_printf(",");
ppHRegPPC(i->Pin.DfpRound128.src_hi);
vex_printf(",");
ppPPCRI(i->Pin.DfpRound128.r_rmc); /* R in bit 3 and RMC in bits 2:0 */
return;
case Pin_DfpQuantize:
vex_printf("%s ", showPPCFpOp(i->Pin.DfpQuantize.op));
ppHRegPPC(i->Pin.DfpQuantize.dst);
vex_printf(",");
ppHRegPPC(i->Pin.DfpQuantize.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.DfpQuantize.srcR);
vex_printf(",");
ppPPCRI(i->Pin.DfpQuantize.rmc);
return;
case Pin_DfpQuantize128:
/* Dst is used to pass in left source and return result */
vex_printf("dquaq ");
ppHRegPPC(i->Pin.DfpQuantize128.dst_hi);
vex_printf(",");
ppHRegPPC(i->Pin.DfpQuantize128.dst_hi);
vex_printf(",");
ppHRegPPC(i->Pin.DfpQuantize128.src_hi);
vex_printf(",");
ppPPCRI(i->Pin.DfpQuantize128.rmc);
return;
case Pin_DfpD128toD64:
vex_printf("%s ", showPPCFpOp(i->Pin.DfpD128toD64.op));
ppHRegPPC(i->Pin.DfpD128toD64.dst);
vex_printf(",");
ppHRegPPC(i->Pin.DfpD128toD64.src_hi);
vex_printf(",");
return;
case Pin_DfpI64StoD128:
vex_printf("%s ", showPPCFpOp(i->Pin.DfpI64StoD128.op));
ppHRegPPC(i->Pin.DfpI64StoD128.dst_hi);
vex_printf(",");
ppHRegPPC(i->Pin.DfpI64StoD128.src);
vex_printf(",");
return;
case Pin_ExtractExpD128:
vex_printf("dxexq ");
ppHRegPPC(i->Pin.ExtractExpD128.dst);
vex_printf(",");
ppHRegPPC(i->Pin.ExtractExpD128.src_hi);
return;
case Pin_InsertExpD128:
vex_printf("diexq ");
ppHRegPPC(i->Pin.InsertExpD128.dst_hi);
vex_printf(",");
ppHRegPPC(i->Pin.InsertExpD128.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.InsertExpD128.srcR_hi);
return;
case Pin_Dfp64Cmp:
vex_printf("dcmpo %%cr1,");
ppHRegPPC(i->Pin.Dfp64Cmp.srcL);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp64Cmp.srcR);
vex_printf("; mfcr ");
ppHRegPPC(i->Pin.Dfp64Cmp.dst);
vex_printf("; rlwinm ");
ppHRegPPC(i->Pin.Dfp64Cmp.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp64Cmp.dst);
vex_printf(",8,28,31");
return;
case Pin_Dfp128Cmp:
vex_printf("dcmpoq %%cr1,");
ppHRegPPC(i->Pin.Dfp128Cmp.srcL_hi);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp128Cmp.srcR_hi);
vex_printf("; mfcr ");
ppHRegPPC(i->Pin.Dfp128Cmp.dst);
vex_printf("; rlwinm ");
ppHRegPPC(i->Pin.Dfp128Cmp.dst);
vex_printf(",");
ppHRegPPC(i->Pin.Dfp128Cmp.dst);
vex_printf(",8,28,31");
return;
case Pin_EvCheck:
/* Note that the counter dec is 32 bit even in 64-bit mode. */
vex_printf("(evCheck) ");
vex_printf("lwz r30,");
ppPPCAMode(i->Pin.EvCheck.amCounter);
vex_printf("; addic. r30,r30,-1; ");
vex_printf("stw r30,");
ppPPCAMode(i->Pin.EvCheck.amCounter);
vex_printf("; bge nofail; lwz r30,");
ppPPCAMode(i->Pin.EvCheck.amFailAddr);
vex_printf("; mtctr r30; bctr; nofail:");
return;
case Pin_ProfInc:
if (mode64) {
vex_printf("(profInc) imm64-fixed5 r30,$NotKnownYet; ");
vex_printf("ld r29,(r30); addi r29,r29,1; std r29,(r30)");
} else {
vex_printf("(profInc) imm32-fixed2 r30,$NotKnownYet; ");
vex_printf("lwz r29,4(r30); addic. r29,r29,1; stw r29,4(r30)");
vex_printf("lwz r29,0(r30); addze r29,r29; stw r29,0(r30)");
}
break;
default:
vex_printf("\nppPPCInstr: No such tag(%d)\n", (Int)i->tag);
vpanic("ppPPCInstr");
}
}
/* --------- Helpers for register allocation. --------- */
void getRegUsage_PPCInstr ( HRegUsage* u, const PPCInstr* i, Bool mode64 )
{
initHRegUsage(u);
switch (i->tag) {
case Pin_LI:
addHRegUse(u, HRmWrite, i->Pin.LI.dst);
break;
case Pin_Alu:
addHRegUse(u, HRmRead, i->Pin.Alu.srcL);
addRegUsage_PPCRH(u, i->Pin.Alu.srcR);
addHRegUse(u, HRmWrite, i->Pin.Alu.dst);
return;
case Pin_Shft:
addHRegUse(u, HRmRead, i->Pin.Shft.srcL);
addRegUsage_PPCRH(u, i->Pin.Shft.srcR);
addHRegUse(u, HRmWrite, i->Pin.Shft.dst);
return;
case Pin_AddSubC:
addHRegUse(u, HRmWrite, i->Pin.AddSubC.dst);
addHRegUse(u, HRmRead, i->Pin.AddSubC.srcL);
addHRegUse(u, HRmRead, i->Pin.AddSubC.srcR);
return;
case Pin_Cmp:
addHRegUse(u, HRmRead, i->Pin.Cmp.srcL);
addRegUsage_PPCRH(u, i->Pin.Cmp.srcR);
return;
case Pin_Unary:
addHRegUse(u, HRmWrite, i->Pin.Unary.dst);
addHRegUse(u, HRmRead, i->Pin.Unary.src);
return;
case Pin_MulL:
addHRegUse(u, HRmWrite, i->Pin.MulL.dst);
addHRegUse(u, HRmRead, i->Pin.MulL.srcL);
addHRegUse(u, HRmRead, i->Pin.MulL.srcR);
return;
case Pin_Div:
addHRegUse(u, HRmWrite, i->Pin.Div.dst);
addHRegUse(u, HRmRead, i->Pin.Div.srcL);
addHRegUse(u, HRmRead, i->Pin.Div.srcR);
return;
case Pin_Call: {
UInt argir;
/* This is a bit subtle. */
/* First off, claim it trashes all the caller-saved regs
which fall within the register allocator's jurisdiction.
These I believe to be:
mode32: r3 to r12
mode64: r3 to r10
*/
/* XXXXXXXXXXXXXXXXX BUG! This doesn't say anything about the FP
or Altivec registers. We get away with this ONLY because
getAllocatableRegs_PPC gives the allocator callee-saved fp
and Altivec regs, and no caller-save ones. */
addHRegUse(u, HRmWrite, hregPPC_GPR3(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR4(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR5(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR6(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR7(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR8(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR9(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR10(mode64));
if (!mode64) {
addHRegUse(u, HRmWrite, hregPPC_GPR11(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR12(mode64));
}
/* Now we have to state any parameter-carrying registers
which might be read. This depends on the argiregs field. */
argir = i->Pin.Call.argiregs;
if (argir &(1<<10)) addHRegUse(u, HRmRead, hregPPC_GPR10(mode64));
if (argir & (1<<9)) addHRegUse(u, HRmRead, hregPPC_GPR9(mode64));
if (argir & (1<<8)) addHRegUse(u, HRmRead, hregPPC_GPR8(mode64));
if (argir & (1<<7)) addHRegUse(u, HRmRead, hregPPC_GPR7(mode64));
if (argir & (1<<6)) addHRegUse(u, HRmRead, hregPPC_GPR6(mode64));
if (argir & (1<<5)) addHRegUse(u, HRmRead, hregPPC_GPR5(mode64));
if (argir & (1<<4)) addHRegUse(u, HRmRead, hregPPC_GPR4(mode64));
if (argir & (1<<3)) addHRegUse(u, HRmRead, hregPPC_GPR3(mode64));
vassert(0 == (argir & ~((1<<3)|(1<<4)|(1<<5)|(1<<6)
|(1<<7)|(1<<8)|(1<<9)|(1<<10))));
/* Finally, there is the issue that the insn trashes a
register because the literal target address has to be
loaded into a register. %r10 seems a suitable victim.
(Can't use %r0, as some insns interpret it as value zero). */
addHRegUse(u, HRmWrite, hregPPC_GPR10(mode64));
/* Upshot of this is that the assembler really must use %r10,
and no other, as a destination temporary. */
return;
}
/* XDirect/XIndir/XAssisted are also a bit subtle. They
conditionally exit the block. Hence we only need to list (1)
the registers that they read, and (2) the registers that they
write in the case where the block is not exited. (2) is empty,
hence only (1) is relevant here. */
case Pin_XDirect:
addRegUsage_PPCAMode(u, i->Pin.XDirect.amCIA);
return;
case Pin_XIndir:
addHRegUse(u, HRmRead, i->Pin.XIndir.dstGA);
addRegUsage_PPCAMode(u, i->Pin.XIndir.amCIA);
return;
case Pin_XAssisted:
addHRegUse(u, HRmRead, i->Pin.XAssisted.dstGA);
addRegUsage_PPCAMode(u, i->Pin.XAssisted.amCIA);
return;
case Pin_CMov:
addRegUsage_PPCRI(u, i->Pin.CMov.src);
addHRegUse(u, HRmWrite, i->Pin.CMov.dst);
return;
case Pin_Load:
addRegUsage_PPCAMode(u, i->Pin.Load.src);
addHRegUse(u, HRmWrite, i->Pin.Load.dst);
return;
case Pin_LoadL:
addHRegUse(u, HRmRead, i->Pin.LoadL.src);
addHRegUse(u, HRmWrite, i->Pin.LoadL.dst);
return;
case Pin_Store:
addHRegUse(u, HRmRead, i->Pin.Store.src);
addRegUsage_PPCAMode(u, i->Pin.Store.dst);
return;
case Pin_StoreC:
addHRegUse(u, HRmRead, i->Pin.StoreC.src);
addHRegUse(u, HRmRead, i->Pin.StoreC.dst);
return;
case Pin_Set:
addHRegUse(u, HRmWrite, i->Pin.Set.dst);
return;
case Pin_MfCR:
addHRegUse(u, HRmWrite, i->Pin.MfCR.dst);
return;
case Pin_MFence:
return;
case Pin_FpUnary:
addHRegUse(u, HRmWrite, i->Pin.FpUnary.dst);
addHRegUse(u, HRmRead, i->Pin.FpUnary.src);
return;
case Pin_FpBinary:
addHRegUse(u, HRmWrite, i->Pin.FpBinary.dst);
addHRegUse(u, HRmRead, i->Pin.FpBinary.srcL);
addHRegUse(u, HRmRead, i->Pin.FpBinary.srcR);
return;
case Pin_Fp128Unary:
addHRegUse(u, HRmWrite, i->Pin.Fp128Unary.dst);
addHRegUse(u, HRmRead, i->Pin.Fp128Unary.src);
return;
case Pin_Fp128Binary:
addHRegUse(u, HRmWrite, i->Pin.Fp128Binary.dst);
addHRegUse(u, HRmRead, i->Pin.Fp128Binary.srcL);
addHRegUse(u, HRmRead, i->Pin.Fp128Binary.srcR);
return;
case Pin_Fp128Trinary:
addHRegUse(u, HRmModify, i->Pin.Fp128Trinary.dst);
addHRegUse(u, HRmRead, i->Pin.Fp128Trinary.srcL);
addHRegUse(u, HRmRead, i->Pin.Fp128Trinary.srcR);
return;
case Pin_FpMulAcc:
addHRegUse(u, HRmWrite, i->Pin.FpMulAcc.dst);
addHRegUse(u, HRmRead, i->Pin.FpMulAcc.srcML);
addHRegUse(u, HRmRead, i->Pin.FpMulAcc.srcMR);
addHRegUse(u, HRmRead, i->Pin.FpMulAcc.srcAcc);
return;
case Pin_FpLdSt:
addHRegUse(u, (i->Pin.FpLdSt.isLoad ? HRmWrite : HRmRead),
i->Pin.FpLdSt.reg);
addRegUsage_PPCAMode(u, i->Pin.FpLdSt.addr);
return;
case Pin_FpSTFIW:
addHRegUse(u, HRmRead, i->Pin.FpSTFIW.addr);
addHRegUse(u, HRmRead, i->Pin.FpSTFIW.data);
return;
case Pin_FpRSP:
addHRegUse(u, HRmWrite, i->Pin.FpRSP.dst);
addHRegUse(u, HRmRead, i->Pin.FpRSP.src);
return;
case Pin_FpCftI:
addHRegUse(u, HRmWrite, i->Pin.FpCftI.dst);
addHRegUse(u, HRmRead, i->Pin.FpCftI.src);
return;
case Pin_FpCMov:
addHRegUse(u, HRmModify, i->Pin.FpCMov.dst);
addHRegUse(u, HRmRead, i->Pin.FpCMov.src);
return;
case Pin_FpLdFPSCR:
addHRegUse(u, HRmRead, i->Pin.FpLdFPSCR.src);
return;
case Pin_FpCmp:
addHRegUse(u, HRmWrite, i->Pin.FpCmp.dst);
addHRegUse(u, HRmRead, i->Pin.FpCmp.srcL);
addHRegUse(u, HRmRead, i->Pin.FpCmp.srcR);
return;
case Pin_RdWrLR:
addHRegUse(u, (i->Pin.RdWrLR.wrLR ? HRmRead : HRmWrite),
i->Pin.RdWrLR.gpr);
return;
case Pin_AvLdSt:
addHRegUse(u, (i->Pin.AvLdSt.isLoad ? HRmWrite : HRmRead),
i->Pin.AvLdSt.reg);
if (i->Pin.AvLdSt.addr->tag == Pam_IR)
addHRegUse(u, HRmWrite, hregPPC_GPR30(mode64));
addRegUsage_PPCAMode(u, i->Pin.AvLdSt.addr);
return;
case Pin_AvUnary:
addHRegUse(u, HRmWrite, i->Pin.AvUnary.dst);
addHRegUse(u, HRmRead, i->Pin.AvUnary.src);
return;
case Pin_AvBinary:
if (i->Pin.AvBinary.op == Pav_XOR
&& sameHReg(i->Pin.AvBinary.dst, i->Pin.AvBinary.srcL)
&& sameHReg(i->Pin.AvBinary.dst, i->Pin.AvBinary.srcR)) {
/* reg-alloc needs to understand 'xor r,r,r' as a write of r */
/* (as opposed to a rite of passage :-) */
addHRegUse(u, HRmWrite, i->Pin.AvBinary.dst);
} else {
addHRegUse(u, HRmWrite, i->Pin.AvBinary.dst);
addHRegUse(u, HRmRead, i->Pin.AvBinary.srcL);
addHRegUse(u, HRmRead, i->Pin.AvBinary.srcR);
}
return;
case Pin_AvBinaryInt:
addHRegUse(u, HRmWrite, i->Pin.AvBinaryInt.dst);
addHRegUse(u, HRmRead, i->Pin.AvBinaryInt.src);
return;
case Pin_AvBin8x16:
addHRegUse(u, HRmWrite, i->Pin.AvBin8x16.dst);
addHRegUse(u, HRmRead, i->Pin.AvBin8x16.srcL);
addHRegUse(u, HRmRead, i->Pin.AvBin8x16.srcR);
return;
case Pin_AvBin16x8:
addHRegUse(u, HRmWrite, i->Pin.AvBin16x8.dst);
addHRegUse(u, HRmRead, i->Pin.AvBin16x8.srcL);
addHRegUse(u, HRmRead, i->Pin.AvBin16x8.srcR);
return;
case Pin_AvBin32x4:
addHRegUse(u, HRmWrite, i->Pin.AvBin32x4.dst);
addHRegUse(u, HRmRead, i->Pin.AvBin32x4.srcL);
addHRegUse(u, HRmRead, i->Pin.AvBin32x4.srcR);
return;
case Pin_AvBin64x2:
addHRegUse(u, HRmWrite, i->Pin.AvBin64x2.dst);
addHRegUse(u, HRmRead, i->Pin.AvBin64x2.srcL);
addHRegUse(u, HRmRead, i->Pin.AvBin64x2.srcR);
return;
case Pin_AvBin32Fx4:
addHRegUse(u, HRmWrite, i->Pin.AvBin32Fx4.dst);
addHRegUse(u, HRmRead, i->Pin.AvBin32Fx4.srcL);
addHRegUse(u, HRmRead, i->Pin.AvBin32Fx4.srcR);
if (i->Pin.AvBin32Fx4.op == Pavfp_MULF)
addHRegUse(u, HRmWrite, hregPPC_VR29(mode64));
return;
case Pin_AvUn32Fx4:
addHRegUse(u, HRmWrite, i->Pin.AvUn32Fx4.dst);
addHRegUse(u, HRmRead, i->Pin.AvUn32Fx4.src);
return;
case Pin_AvPerm:
addHRegUse(u, HRmWrite, i->Pin.AvPerm.dst);
addHRegUse(u, HRmRead, i->Pin.AvPerm.srcL);
addHRegUse(u, HRmRead, i->Pin.AvPerm.srcR);
addHRegUse(u, HRmRead, i->Pin.AvPerm.ctl);
return;
case Pin_AvSel:
addHRegUse(u, HRmWrite, i->Pin.AvSel.dst);
addHRegUse(u, HRmRead, i->Pin.AvSel.ctl);
addHRegUse(u, HRmRead, i->Pin.AvSel.srcL);
addHRegUse(u, HRmRead, i->Pin.AvSel.srcR);
return;
case Pin_AvSh:
addHRegUse(u, HRmWrite, i->Pin.AvSh.dst);
if (i->Pin.AvSh.addr->tag == Pam_IR)
addHRegUse(u, HRmWrite, hregPPC_GPR30(mode64));
addRegUsage_PPCAMode(u, i->Pin.AvSh.addr);
return;
case Pin_AvShlDbl:
addHRegUse(u, HRmWrite, i->Pin.AvShlDbl.dst);
addHRegUse(u, HRmRead, i->Pin.AvShlDbl.srcL);
addHRegUse(u, HRmRead, i->Pin.AvShlDbl.srcR);
return;
case Pin_AvSplat:
addHRegUse(u, HRmWrite, i->Pin.AvSplat.dst);
addRegUsage_PPCVI5s(u, i->Pin.AvSplat.src);
return;
case Pin_AvCMov:
addHRegUse(u, HRmModify, i->Pin.AvCMov.dst);
addHRegUse(u, HRmRead, i->Pin.AvCMov.src);
return;
case Pin_AvLdVSCR:
addHRegUse(u, HRmRead, i->Pin.AvLdVSCR.src);
return;
case Pin_AvCipherV128Unary:
addHRegUse(u, HRmWrite, i->Pin.AvCipherV128Unary.dst);
addHRegUse(u, HRmRead, i->Pin.AvCipherV128Unary.src);
return;
case Pin_AvCipherV128Binary:
addHRegUse(u, HRmWrite, i->Pin.AvCipherV128Binary.dst);
addHRegUse(u, HRmRead, i->Pin.AvCipherV128Binary.srcL);
addHRegUse(u, HRmRead, i->Pin.AvCipherV128Binary.srcR);
return;
case Pin_AvHashV128Binary:
addHRegUse(u, HRmWrite, i->Pin.AvHashV128Binary.dst);
addHRegUse(u, HRmRead, i->Pin.AvHashV128Binary.src);
addRegUsage_PPCRI(u, i->Pin.AvHashV128Binary.s_field);
return;
case Pin_AvBCDV128Binary:
addHRegUse(u, HRmWrite, i->Pin.AvBCDV128Binary.dst);
addHRegUse(u, HRmRead, i->Pin.AvBCDV128Binary.src1);
addHRegUse(u, HRmRead, i->Pin.AvBCDV128Binary.src2);
return;
case Pin_Dfp64Unary:
addHRegUse(u, HRmWrite, i->Pin.Dfp64Unary.dst);
addHRegUse(u, HRmRead, i->Pin.Dfp64Unary.src);
return;
case Pin_Dfp64Binary:
addHRegUse(u, HRmWrite, i->Pin.Dfp64Binary.dst);
addHRegUse(u, HRmRead, i->Pin.Dfp64Binary.srcL);
addHRegUse(u, HRmRead, i->Pin.Dfp64Binary.srcR);
return;
case Pin_DfpShift:
addRegUsage_PPCRI(u, i->Pin.DfpShift.shift);
addHRegUse(u, HRmWrite, i->Pin.DfpShift.src);
addHRegUse(u, HRmWrite, i->Pin.DfpShift.dst);
return;
case Pin_Dfp128Unary:
addHRegUse(u, HRmWrite, i->Pin.Dfp128Unary.dst_hi);
addHRegUse(u, HRmWrite, i->Pin.Dfp128Unary.dst_lo);
addHRegUse(u, HRmRead, i->Pin.Dfp128Unary.src_hi);
addHRegUse(u, HRmRead, i->Pin.Dfp128Unary.src_lo);
return;
case Pin_Dfp128Binary:
addHRegUse(u, HRmWrite, i->Pin.Dfp128Binary.dst_hi);
addHRegUse(u, HRmWrite, i->Pin.Dfp128Binary.dst_lo);
addHRegUse(u, HRmRead, i->Pin.Dfp128Binary.srcR_hi);
addHRegUse(u, HRmRead, i->Pin.Dfp128Binary.srcR_lo);
return;
case Pin_DfpRound:
addHRegUse(u, HRmWrite, i->Pin.DfpRound.dst);
addHRegUse(u, HRmRead, i->Pin.DfpRound.src);
return;
case Pin_DfpRound128:
addHRegUse(u, HRmWrite, i->Pin.DfpRound128.dst_hi);
addHRegUse(u, HRmWrite, i->Pin.DfpRound128.dst_lo);
addHRegUse(u, HRmRead, i->Pin.DfpRound128.src_hi);
addHRegUse(u, HRmRead, i->Pin.DfpRound128.src_lo);
return;
case Pin_DfpQuantize:
addRegUsage_PPCRI(u, i->Pin.DfpQuantize.rmc);
addHRegUse(u, HRmWrite, i->Pin.DfpQuantize.dst);
addHRegUse(u, HRmRead, i->Pin.DfpQuantize.srcL);
addHRegUse(u, HRmRead, i->Pin.DfpQuantize.srcR);
return;
case Pin_DfpQuantize128:
addHRegUse(u, HRmWrite, i->Pin.DfpQuantize128.dst_hi);
addHRegUse(u, HRmWrite, i->Pin.DfpQuantize128.dst_lo);
addHRegUse(u, HRmRead, i->Pin.DfpQuantize128.src_hi);
addHRegUse(u, HRmRead, i->Pin.DfpQuantize128.src_lo);
return;
case Pin_DfpShift128:
addRegUsage_PPCRI(u, i->Pin.DfpShift128.shift);
addHRegUse(u, HRmWrite, i->Pin.DfpShift128.src_hi);
addHRegUse(u, HRmWrite, i->Pin.DfpShift128.src_lo);
addHRegUse(u, HRmWrite, i->Pin.DfpShift128.dst_hi);
addHRegUse(u, HRmWrite, i->Pin.DfpShift128.dst_lo);
return;
case Pin_DfpD128toD64:
addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.src_hi);
addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.src_lo);
addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.dst);
return;
case Pin_DfpI64StoD128:
addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.src);
addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.dst_hi);
addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.dst_lo);
return;
case Pin_ExtractExpD128:
addHRegUse(u, HRmWrite, i->Pin.ExtractExpD128.dst);
addHRegUse(u, HRmRead, i->Pin.ExtractExpD128.src_hi);
addHRegUse(u, HRmRead, i->Pin.ExtractExpD128.src_lo);
return;
case Pin_InsertExpD128:
addHRegUse(u, HRmWrite, i->Pin.InsertExpD128.dst_hi);
addHRegUse(u, HRmWrite, i->Pin.InsertExpD128.dst_lo);
addHRegUse(u, HRmRead, i->Pin.InsertExpD128.srcL);
addHRegUse(u, HRmRead, i->Pin.InsertExpD128.srcR_hi);
addHRegUse(u, HRmRead, i->Pin.InsertExpD128.srcR_lo);
return;
case Pin_Dfp64Cmp:
addHRegUse(u, HRmWrite, i->Pin.Dfp64Cmp.dst);
addHRegUse(u, HRmRead, i->Pin.Dfp64Cmp.srcL);
addHRegUse(u, HRmRead, i->Pin.Dfp64Cmp.srcR);
return;
case Pin_Dfp128Cmp:
addHRegUse(u, HRmWrite, i->Pin.Dfp128Cmp.dst);
addHRegUse(u, HRmRead, i->Pin.Dfp128Cmp.srcL_hi);
addHRegUse(u, HRmRead, i->Pin.Dfp128Cmp.srcL_lo);
addHRegUse(u, HRmRead, i->Pin.Dfp128Cmp.srcR_hi);
addHRegUse(u, HRmRead, i->Pin.Dfp128Cmp.srcR_lo);
return;
case Pin_EvCheck:
/* We expect both amodes only to mention the GSP (r31), so this
is in fact pointless, since GSP isn't allocatable, but
anyway.. */
addRegUsage_PPCAMode(u, i->Pin.EvCheck.amCounter);
addRegUsage_PPCAMode(u, i->Pin.EvCheck.amFailAddr);
addHRegUse(u, HRmWrite, hregPPC_GPR30(mode64)); /* also unavail to RA */
return;
case Pin_ProfInc:
addHRegUse(u, HRmWrite, hregPPC_GPR29(mode64));
addHRegUse(u, HRmWrite, hregPPC_GPR30(mode64));
return;
default:
ppPPCInstr(i, mode64);
vpanic("getRegUsage_PPCInstr");
}
}
/* local helper */
static void mapReg( HRegRemap* m, HReg* r )
{
*r = lookupHRegRemap(m, *r);
}
void mapRegs_PPCInstr ( HRegRemap* m, PPCInstr* i, Bool mode64 )
{
switch (i->tag) {
case Pin_LI:
mapReg(m, &i->Pin.LI.dst);
return;
case Pin_Alu:
mapReg(m, &i->Pin.Alu.dst);
mapReg(m, &i->Pin.Alu.srcL);
mapRegs_PPCRH(m, i->Pin.Alu.srcR);
return;
case Pin_Shft:
mapReg(m, &i->Pin.Shft.dst);
mapReg(m, &i->Pin.Shft.srcL);
mapRegs_PPCRH(m, i->Pin.Shft.srcR);
return;
case Pin_AddSubC:
mapReg(m, &i->Pin.AddSubC.dst);
mapReg(m, &i->Pin.AddSubC.srcL);
mapReg(m, &i->Pin.AddSubC.srcR);
return;
case Pin_Cmp:
mapReg(m, &i->Pin.Cmp.srcL);
mapRegs_PPCRH(m, i->Pin.Cmp.srcR);
return;
case Pin_Unary:
mapReg(m, &i->Pin.Unary.dst);
mapReg(m, &i->Pin.Unary.src);
return;
case Pin_MulL:
mapReg(m, &i->Pin.MulL.dst);
mapReg(m, &i->Pin.MulL.srcL);
mapReg(m, &i->Pin.MulL.srcR);
return;
case Pin_Div:
mapReg(m, &i->Pin.Div.dst);
mapReg(m, &i->Pin.Div.srcL);
mapReg(m, &i->Pin.Div.srcR);
return;
case Pin_Call:
return;
case Pin_XDirect:
mapRegs_PPCAMode(m, i->Pin.XDirect.amCIA);
return;
case Pin_XIndir:
mapReg(m, &i->Pin.XIndir.dstGA);
mapRegs_PPCAMode(m, i->Pin.XIndir.amCIA);
return;
case Pin_XAssisted:
mapReg(m, &i->Pin.XAssisted.dstGA);
mapRegs_PPCAMode(m, i->Pin.XAssisted.amCIA);
return;
case Pin_CMov:
mapRegs_PPCRI(m, i->Pin.CMov.src);
mapReg(m, &i->Pin.CMov.dst);
return;
case Pin_Load:
mapRegs_PPCAMode(m, i->Pin.Load.src);
mapReg(m, &i->Pin.Load.dst);
return;
case Pin_LoadL:
mapReg(m, &i->Pin.LoadL.src);
mapReg(m, &i->Pin.LoadL.dst);
return;
case Pin_Store:
mapReg(m, &i->Pin.Store.src);
mapRegs_PPCAMode(m, i->Pin.Store.dst);
return;
case Pin_StoreC:
mapReg(m, &i->Pin.StoreC.src);
mapReg(m, &i->Pin.StoreC.dst);
return;
case Pin_Set:
mapReg(m, &i->Pin.Set.dst);
return;
case Pin_MfCR:
mapReg(m, &i->Pin.MfCR.dst);
return;
case Pin_MFence:
return;
case Pin_FpUnary:
mapReg(m, &i->Pin.FpUnary.dst);
mapReg(m, &i->Pin.FpUnary.src);
return;
case Pin_FpBinary:
mapReg(m, &i->Pin.FpBinary.dst);
mapReg(m, &i->Pin.FpBinary.srcL);
mapReg(m, &i->Pin.FpBinary.srcR);
return;
case Pin_Fp128Unary:
mapReg(m, &i->Pin.Fp128Unary.dst);
mapReg(m, &i->Pin.Fp128Unary.src);
return;
case Pin_Fp128Binary:
mapReg(m, &i->Pin.Fp128Binary.dst);
mapReg(m, &i->Pin.Fp128Binary.srcL);
mapReg(m, &i->Pin.Fp128Binary.srcR);
return;
case Pin_Fp128Trinary:
mapReg(m, &i->Pin.Fp128Trinary.dst);
mapReg(m, &i->Pin.Fp128Trinary.srcL);
mapReg(m, &i->Pin.Fp128Trinary.srcR);
return;
case Pin_FpMulAcc:
mapReg(m, &i->Pin.FpMulAcc.dst);
mapReg(m, &i->Pin.FpMulAcc.srcML);
mapReg(m, &i->Pin.FpMulAcc.srcMR);
mapReg(m, &i->Pin.FpMulAcc.srcAcc);
return;
case Pin_FpLdSt:
mapReg(m, &i->Pin.FpLdSt.reg);
mapRegs_PPCAMode(m, i->Pin.FpLdSt.addr);
return;
case Pin_FpSTFIW:
mapReg(m, &i->Pin.FpSTFIW.addr);
mapReg(m, &i->Pin.FpSTFIW.data);
return;
case Pin_FpRSP:
mapReg(m, &i->Pin.FpRSP.dst);
mapReg(m, &i->Pin.FpRSP.src);
return;
case Pin_FpCftI:
mapReg(m, &i->Pin.FpCftI.dst);
mapReg(m, &i->Pin.FpCftI.src);
return;
case Pin_FpCMov:
mapReg(m, &i->Pin.FpCMov.dst);
mapReg(m, &i->Pin.FpCMov.src);
return;
case Pin_FpLdFPSCR:
mapReg(m, &i->Pin.FpLdFPSCR.src);
return;
case Pin_FpCmp:
mapReg(m, &i->Pin.FpCmp.dst);
mapReg(m, &i->Pin.FpCmp.srcL);
mapReg(m, &i->Pin.FpCmp.srcR);
return;
case Pin_RdWrLR:
mapReg(m, &i->Pin.RdWrLR.gpr);
return;
case Pin_AvLdSt:
mapReg(m, &i->Pin.AvLdSt.reg);
mapRegs_PPCAMode(m, i->Pin.AvLdSt.addr);
return;
case Pin_AvUnary:
mapReg(m, &i->Pin.AvUnary.dst);
mapReg(m, &i->Pin.AvUnary.src);
return;
case Pin_AvBinary:
mapReg(m, &i->Pin.AvBinary.dst);
mapReg(m, &i->Pin.AvBinary.srcL);
mapReg(m, &i->Pin.AvBinary.srcR);
return;
case Pin_AvBinaryInt:
mapReg(m, &i->Pin.AvBinaryInt.dst);
mapReg(m, &i->Pin.AvBinaryInt.src);
return;
case Pin_AvBin8x16:
mapReg(m, &i->Pin.AvBin8x16.dst);
mapReg(m, &i->Pin.AvBin8x16.srcL);
mapReg(m, &i->Pin.AvBin8x16.srcR);
return;
case Pin_AvBin16x8:
mapReg(m, &i->Pin.AvBin16x8.dst);
mapReg(m, &i->Pin.AvBin16x8.srcL);
mapReg(m, &i->Pin.AvBin16x8.srcR);
return;
case Pin_AvBin32x4:
mapReg(m, &i->Pin.AvBin32x4.dst);
mapReg(m, &i->Pin.AvBin32x4.srcL);
mapReg(m, &i->Pin.AvBin32x4.srcR);
return;
case Pin_AvBin64x2:
mapReg(m, &i->Pin.AvBin64x2.dst);
mapReg(m, &i->Pin.AvBin64x2.srcL);
mapReg(m, &i->Pin.AvBin64x2.srcR);
return;
case Pin_AvBin32Fx4:
mapReg(m, &i->Pin.AvBin32Fx4.dst);
mapReg(m, &i->Pin.AvBin32Fx4.srcL);
mapReg(m, &i->Pin.AvBin32Fx4.srcR);
return;
case Pin_AvUn32Fx4:
mapReg(m, &i->Pin.AvUn32Fx4.dst);
mapReg(m, &i->Pin.AvUn32Fx4.src);
return;
case Pin_AvPerm:
mapReg(m, &i->Pin.AvPerm.dst);
mapReg(m, &i->Pin.AvPerm.srcL);
mapReg(m, &i->Pin.AvPerm.srcR);
mapReg(m, &i->Pin.AvPerm.ctl);
return;
case Pin_AvSel:
mapReg(m, &i->Pin.AvSel.dst);
mapReg(m, &i->Pin.AvSel.srcL);
mapReg(m, &i->Pin.AvSel.srcR);
mapReg(m, &i->Pin.AvSel.ctl);
return;
case Pin_AvSh:
mapReg(m, &i->Pin.AvSh.dst);
mapRegs_PPCAMode(m, i->Pin.AvSh.addr);
return;
case Pin_AvShlDbl:
mapReg(m, &i->Pin.AvShlDbl.dst);
mapReg(m, &i->Pin.AvShlDbl.srcL);
mapReg(m, &i->Pin.AvShlDbl.srcR);
return;
case Pin_AvSplat:
mapReg(m, &i->Pin.AvSplat.dst);
mapRegs_PPCVI5s(m, i->Pin.AvSplat.src);
return;
case Pin_AvCMov:
mapReg(m, &i->Pin.AvCMov.dst);
mapReg(m, &i->Pin.AvCMov.src);
return;
case Pin_AvLdVSCR:
mapReg(m, &i->Pin.AvLdVSCR.src);
return;
case Pin_AvCipherV128Unary:
mapReg(m, &i->Pin.AvCipherV128Unary.dst);
mapReg(m, &i->Pin.AvCipherV128Unary.src);
return;
case Pin_AvCipherV128Binary:
mapReg(m, &i->Pin.AvCipherV128Binary.dst);
mapReg(m, &i->Pin.AvCipherV128Binary.srcL);
mapReg(m, &i->Pin.AvCipherV128Binary.srcR);
return;
case Pin_AvHashV128Binary:
mapRegs_PPCRI(m, i->Pin.AvHashV128Binary.s_field);
mapReg(m, &i->Pin.AvHashV128Binary.dst);
mapReg(m, &i->Pin.AvHashV128Binary.src);
return;
case Pin_AvBCDV128Binary:
mapReg(m, &i->Pin.AvBCDV128Binary.dst);
mapReg(m, &i->Pin.AvBCDV128Binary.src1);
mapReg(m, &i->Pin.AvBCDV128Binary.src2);
return;
case Pin_Dfp64Unary:
mapReg(m, &i->Pin.Dfp64Unary.dst);
mapReg(m, &i->Pin.Dfp64Unary.src);
return;
case Pin_Dfp64Binary:
mapReg(m, &i->Pin.Dfp64Binary.dst);
mapReg(m, &i->Pin.Dfp64Binary.srcL);
mapReg(m, &i->Pin.Dfp64Binary.srcR);
return;
case Pin_DfpShift:
mapRegs_PPCRI(m, i->Pin.DfpShift.shift);
mapReg(m, &i->Pin.DfpShift.src);
mapReg(m, &i->Pin.DfpShift.dst);
return;
case Pin_Dfp128Unary:
mapReg(m, &i->Pin.Dfp128Unary.dst_hi);
mapReg(m, &i->Pin.Dfp128Unary.dst_lo);
mapReg(m, &i->Pin.Dfp128Unary.src_hi);
mapReg(m, &i->Pin.Dfp128Unary.src_lo);
return;
case Pin_Dfp128Binary:
mapReg(m, &i->Pin.Dfp128Binary.dst_hi);
mapReg(m, &i->Pin.Dfp128Binary.dst_lo);
mapReg(m, &i->Pin.Dfp128Binary.srcR_hi);
mapReg(m, &i->Pin.Dfp128Binary.srcR_lo);
return;
case Pin_DfpShift128:
mapRegs_PPCRI(m, i->Pin.DfpShift128.shift);
mapReg(m, &i->Pin.DfpShift128.src_hi);
mapReg(m, &i->Pin.DfpShift128.src_lo);
mapReg(m, &i->Pin.DfpShift128.dst_hi);
mapReg(m, &i->Pin.DfpShift128.dst_lo);
return;
case Pin_DfpRound:
mapReg(m, &i->Pin.DfpRound.dst);
mapReg(m, &i->Pin.DfpRound.src);
return;
case Pin_DfpRound128:
mapReg(m, &i->Pin.DfpRound128.dst_hi);
mapReg(m, &i->Pin.DfpRound128.dst_lo);
mapReg(m, &i->Pin.DfpRound128.src_hi);
mapReg(m, &i->Pin.DfpRound128.src_lo);
return;
case Pin_DfpQuantize:
mapRegs_PPCRI(m, i->Pin.DfpQuantize.rmc);
mapReg(m, &i->Pin.DfpQuantize.dst);
mapReg(m, &i->Pin.DfpQuantize.srcL);
mapReg(m, &i->Pin.DfpQuantize.srcR);
return;
case Pin_DfpQuantize128:
mapRegs_PPCRI(m, i->Pin.DfpQuantize128.rmc);
mapReg(m, &i->Pin.DfpQuantize128.dst_hi);
mapReg(m, &i->Pin.DfpQuantize128.dst_lo);
mapReg(m, &i->Pin.DfpQuantize128.src_hi);
mapReg(m, &i->Pin.DfpQuantize128.src_lo);
return;
case Pin_DfpD128toD64:
mapReg(m, &i->Pin.DfpD128toD64.src_hi);
mapReg(m, &i->Pin.DfpD128toD64.src_lo);
mapReg(m, &i->Pin.DfpD128toD64.dst);
return;
case Pin_DfpI64StoD128:
mapReg(m, &i->Pin.DfpI64StoD128.src);
mapReg(m, &i->Pin.DfpI64StoD128.dst_hi);
mapReg(m, &i->Pin.DfpI64StoD128.dst_lo);
return;
case Pin_ExtractExpD128:
mapReg(m, &i->Pin.ExtractExpD128.dst);
mapReg(m, &i->Pin.ExtractExpD128.src_hi);
mapReg(m, &i->Pin.ExtractExpD128.src_lo);
return;
case Pin_InsertExpD128:
mapReg(m, &i->Pin.InsertExpD128.dst_hi);
mapReg(m, &i->Pin.InsertExpD128.dst_lo);
mapReg(m, &i->Pin.InsertExpD128.srcL);
mapReg(m, &i->Pin.InsertExpD128.srcR_hi);
mapReg(m, &i->Pin.InsertExpD128.srcR_lo);
return;
case Pin_Dfp64Cmp:
mapReg(m, &i->Pin.Dfp64Cmp.dst);
mapReg(m, &i->Pin.Dfp64Cmp.srcL);
mapReg(m, &i->Pin.Dfp64Cmp.srcR);
return;
case Pin_Dfp128Cmp:
mapReg(m, &i->Pin.Dfp128Cmp.dst);
mapReg(m, &i->Pin.Dfp128Cmp.srcL_hi);
mapReg(m, &i->Pin.Dfp128Cmp.srcL_lo);
mapReg(m, &i->Pin.Dfp128Cmp.srcR_hi);
mapReg(m, &i->Pin.Dfp128Cmp.srcR_lo);
return;
case Pin_EvCheck:
/* We expect both amodes only to mention the GSP (r31), so this
is in fact pointless, since GSP isn't allocatable, but
anyway.. */
mapRegs_PPCAMode(m, i->Pin.EvCheck.amCounter);
mapRegs_PPCAMode(m, i->Pin.EvCheck.amFailAddr);
return;
case Pin_ProfInc:
/* hardwires r29 and r30 -- nothing to modify. */
return;
default:
ppPPCInstr(i, mode64);
vpanic("mapRegs_PPCInstr");
}
}
/* Figure out if i 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_PPCInstr ( const PPCInstr* i, HReg* src, HReg* dst )
{
/* Moves between integer regs */
if (i->tag == Pin_Alu) {
// or Rd,Rs,Rs == mr Rd,Rs
if (i->Pin.Alu.op != Palu_OR)
return False;
if (i->Pin.Alu.srcR->tag != Prh_Reg)
return False;
if (! sameHReg(i->Pin.Alu.srcR->Prh.Reg.reg, i->Pin.Alu.srcL))
return False;
*src = i->Pin.Alu.srcL;
*dst = i->Pin.Alu.dst;
return True;
}
/* Moves between FP regs */
if (i->tag == Pin_FpUnary) {
if (i->Pin.FpUnary.op != Pfp_MOV)
return False;
*src = i->Pin.FpUnary.src;
*dst = i->Pin.FpUnary.dst;
return True;
}
return False;
}
/* Generate ppc spill/reload instructions under the direction of the
register allocator. Note it's critical these don't write the
condition codes. */
void genSpill_PPC ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
HReg rreg, Int offsetB, Bool mode64 )
{
PPCAMode* am;
vassert(!hregIsVirtual(rreg));
*i1 = *i2 = NULL;
am = PPCAMode_IR( offsetB, GuestStatePtr(mode64) );
switch (hregClass(rreg)) {
case HRcInt64:
vassert(mode64);
*i1 = PPCInstr_Store( 8, am, rreg, mode64 );
return;
case HRcInt32:
vassert(!mode64);
*i1 = PPCInstr_Store( 4, am, rreg, mode64 );
return;
case HRcFlt64:
*i1 = PPCInstr_FpLdSt ( False/*store*/, 8, rreg, am );
return;
case HRcVec128:
// XXX: GPR30 used as spill register to kludge AltiVec
// AMode_IR
*i1 = PPCInstr_AvLdSt ( False/*store*/, 16, rreg, am );
return;
default:
ppHRegClass(hregClass(rreg));
vpanic("genSpill_PPC: unimplemented regclass");
}
}
void genReload_PPC ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
HReg rreg, Int offsetB, Bool mode64 )
{
PPCAMode* am;
vassert(!hregIsVirtual(rreg));
*i1 = *i2 = NULL;
am = PPCAMode_IR( offsetB, GuestStatePtr(mode64) );
switch (hregClass(rreg)) {
case HRcInt64:
vassert(mode64);
*i1 = PPCInstr_Load( 8, rreg, am, mode64 );
return;
case HRcInt32:
vassert(!mode64);
*i1 = PPCInstr_Load( 4, rreg, am, mode64 );
return;
case HRcFlt64:
*i1 = PPCInstr_FpLdSt ( True/*load*/, 8, rreg, am );
return;
case HRcVec128:
// XXX: GPR30 used as spill register to kludge AltiVec AMode_IR
*i1 = PPCInstr_AvLdSt ( True/*load*/, 16, rreg, am );
return;
default:
ppHRegClass(hregClass(rreg));
vpanic("genReload_PPC: unimplemented regclass");
}
}
/* --------- The ppc assembler (bleh.) --------- */
inline static UInt iregEnc ( HReg r, Bool mode64 )
{
UInt n;
vassert(hregClass(r) == (mode64 ? HRcInt64 : HRcInt32));
vassert(!hregIsVirtual(r));
n = hregEncoding(r);
vassert(n <= 32);
return n;
}
inline static UInt fregEnc ( HReg fr )
{
UInt n;
vassert(hregClass(fr) == HRcFlt64);
vassert(!hregIsVirtual(fr));
n = hregEncoding(fr);
vassert(n <= 32);
return n;
}
inline static UInt vregEnc ( HReg v )
{
UInt n;
vassert(hregClass(v) == HRcVec128);
vassert(!hregIsVirtual(v));
n = hregEncoding(v);
vassert(n <= 32);
return n;
}
/* Emit an instruction ppc-endianly */
static UChar* emit32 ( UChar* p, UInt w32, VexEndness endness_host )
{
if (endness_host == VexEndnessBE) {
*p++ = toUChar((w32 >> 24) & 0x000000FF);
*p++ = toUChar((w32 >> 16) & 0x000000FF);
*p++ = toUChar((w32 >> 8) & 0x000000FF);
*p++ = toUChar((w32) & 0x000000FF);
} else {
*p++ = toUChar((w32) & 0x000000FF);
*p++ = toUChar((w32 >> 8) & 0x000000FF);
*p++ = toUChar((w32 >> 16) & 0x000000FF);
*p++ = toUChar((w32 >> 24) & 0x000000FF);
}
return p;
}
/* Fetch an instruction ppc-endianly */
static UInt fetch32 ( UChar* p, VexEndness endness_host )
{
UInt w32 = 0;
if (endness_host == VexEndnessBE) {
w32 |= ((0xFF & (UInt)p[0]) << 24);
w32 |= ((0xFF & (UInt)p[1]) << 16);
w32 |= ((0xFF & (UInt)p[2]) << 8);
w32 |= ((0xFF & (UInt)p[3]) << 0);
} else {
w32 |= ((0xFF & (UInt)p[3]) << 24);
w32 |= ((0xFF & (UInt)p[2]) << 16);
w32 |= ((0xFF & (UInt)p[1]) << 8);
w32 |= ((0xFF & (UInt)p[0]) << 0);
}
return w32;
}
/* The following mkForm[...] functions refer to ppc instruction forms
as per PPC32 p576
*/
static UChar* mkFormD ( UChar* p, UInt opc1,
UInt r1, UInt r2, UInt imm, VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
imm = imm & 0xFFFF;
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (imm));
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormMD ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt imm1, UInt imm2, UInt opc2,
VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(imm1 < 0x40);
vassert(imm2 < 0x40);
vassert(opc2 < 0x08);
imm2 = ((imm2 & 0x1F) << 1) | (imm2 >> 5);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
((imm1 & 0x1F)<<11) | (imm2<<5) |
(opc2<<2) | ((imm1 >> 5)<<1));
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormX ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt opc2, UInt b0, VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(opc2 < 0x400);
vassert(b0 < 0x2);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
(r3<<11) | (opc2<<1) | (b0));
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormXO ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt b10, UInt opc2, UInt b0,
VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(b10 < 0x2);
vassert(opc2 < 0x200);
vassert(b0 < 0x2);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
(r3<<11) | (b10 << 10) | (opc2<<1) | (b0));
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormXL ( UChar* p, UInt opc1, UInt f1, UInt f2,
UInt f3, UInt opc2, UInt b0, VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(f1 < 0x20);
vassert(f2 < 0x20);
vassert(f3 < 0x20);
vassert(opc2 < 0x400);
vassert(b0 < 0x2);
theInstr = ((opc1<<26) | (f1<<21) | (f2<<16) |
(f3<<11) | (opc2<<1) | (b0));
return emit32(p, theInstr, endness_host);
}
// Note: for split field ops, give mnemonic arg
static UChar* mkFormXFX ( UChar* p, UInt r1, UInt f2, UInt opc2,
VexEndness endness_host )
{
UInt theInstr;
vassert(r1 < 0x20);
vassert(f2 < 0x20);
vassert(opc2 < 0x400);
switch (opc2) {
case 144: // mtcrf
vassert(f2 < 0x100);
f2 = f2 << 1;
break;
case 339: // mfspr
case 371: // mftb
case 467: // mtspr
vassert(f2 < 0x400);
// re-arrange split field
f2 = ((f2>>5) & 0x1F) | ((f2 & 0x1F)<<5);
break;
default: vpanic("mkFormXFX(ppch)");
}
theInstr = ((31<<26) | (r1<<21) | (f2<<11) | (opc2<<1));
return emit32(p, theInstr, endness_host);
}
// Only used by mtfsf
static UChar* mkFormXFL ( UChar* p, UInt FM, UInt freg, UInt dfp_rm,
VexEndness endness_host )
{
UInt theInstr;
vassert(FM < 0x100);
vassert(freg < 0x20);
theInstr = ((63<<26) | (FM<<17) | (dfp_rm<<16) | (freg<<11) | (711<<1));
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormXS ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt imm, UInt opc2, UInt b0,
VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(imm < 0x40);
vassert(opc2 < 0x400);
vassert(b0 < 0x2);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
((imm & 0x1F)<<11) | (opc2<<2) | ((imm>>5)<<1) | (b0));
return emit32(p, theInstr, endness_host);
}
#if 0
// 'b'
static UChar* mkFormI ( UChar* p, UInt LI, UInt AA, UInt LK,
VexEndness endness_host )
{
UInt theInstr;
vassert(LI < 0x1000000);
vassert(AA < 0x2);
vassert(LK < 0x2);
theInstr = ((18<<26) | (LI<<2) | (AA<<1) | (LK));
return emit32(p, theInstr, endness_host);
}
#endif
// 'bc'
static UChar* mkFormB ( UChar* p, UInt BO, UInt BI,
UInt BD, UInt AA, UInt LK, VexEndness endness_host )
{
UInt theInstr;
vassert(BO < 0x20);
vassert(BI < 0x20);
vassert(BD < 0x4000);
vassert(AA < 0x2);
vassert(LK < 0x2);
theInstr = ((16<<26) | (BO<<21) | (BI<<16) |
(BD<<2) | (AA<<1) | (LK));
return emit32(p, theInstr, endness_host);
}
// rotates
static UChar* mkFormM ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt f3, UInt MB, UInt ME, UInt Rc,
VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(f3 < 0x20);
vassert(MB < 0x20);
vassert(ME < 0x20);
vassert(Rc < 0x2);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
(f3<<11) | (MB<<6) | (ME<<1) | (Rc));
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormA ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt r4, UInt opc2, UInt b0,
VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(r4 < 0x20);
vassert(opc2 < 0x20);
vassert(b0 < 0x2 );
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (r3<<11) |
(r4<<6) | (opc2<<1) | (b0));
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormZ22 ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt constant, UInt opc2, UInt b0,
VexEndness endness_host)
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(constant < 0x40); /* 6 bit constant */
vassert(opc2 < 0x200); /* 9 bit field */
vassert(b0 < 0x2);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
(constant<<10) | (opc2<<1) | (b0));
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormZ23 ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt rmc, UInt opc2, UInt b0,
VexEndness endness_host)
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(rmc < 0x4);
vassert(opc2 < 0x100);
vassert(b0 < 0x2);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
(r3<<11) | (rmc<<9) | (opc2<<1) | (b0));
return emit32(p, theInstr, endness_host);
}
static UChar* doAMode_IR ( UChar* p, UInt opc1, UInt rSD,
PPCAMode* am, Bool mode64, VexEndness endness_host )
{
UInt rA, idx;
vassert(am->tag == Pam_IR);
vassert(am->Pam.IR.index < 0x10000);
rA = iregEnc(am->Pam.IR.base, mode64);
idx = am->Pam.IR.index;
if (opc1 == 58 || opc1 == 62) { // ld/std: mode64 only
vassert(mode64);
/* stay sane with DS form: lowest 2 bits must be 00. This
should be guaranteed to us by iselWordExpr_AMode. */
vassert(0 == (idx & 3));
}
p = mkFormD(p, opc1, rSD, rA, idx, endness_host);
return p;
}
static UChar* doAMode_RR ( UChar* p, UInt opc1, UInt opc2,
UInt rSD, PPCAMode* am, Bool mode64,
VexEndness endness_host )
{
UInt rA, rB;
vassert(am->tag == Pam_RR);
rA = iregEnc(am->Pam.RR.base, mode64);
rB = iregEnc(am->Pam.RR.index, mode64);
p = mkFormX(p, opc1, rSD, rA, rB, opc2, 0, endness_host);
return p;
}
/* Load imm to r_dst */
static UChar* mkLoadImm ( UChar* p, UInt r_dst, ULong imm, Bool mode64,
VexEndness endness_host )
{
vassert(r_dst < 0x20);
if (!mode64) {
/* In 32-bit mode, make sure the top 32 bits of imm are a sign
extension of the bottom 32 bits, so that the range tests
below work correctly. */
UInt u32 = (UInt)imm;
Int s32 = (Int)u32;
Long s64 = (Long)s32;
imm = (ULong)s64;
}
if (imm >= 0xFFFFFFFFFFFF8000ULL || imm < 0x8000) {
// sign-extendable from 16 bits
// addi r_dst,0,imm => li r_dst,imm
p = mkFormD(p, 14, r_dst, 0, imm & 0xFFFF, endness_host);
} else {
if (imm >= 0xFFFFFFFF80000000ULL || imm < 0x80000000ULL) {
// sign-extendable from 32 bits
// addis r_dst,r0,(imm>>16) => lis r_dst, (imm>>16)
p = mkFormD(p, 15, r_dst, 0, (imm>>16) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm & 0xFFFF)
p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
} else {
// full 64bit immediate load: 5 (five!) insns.
vassert(mode64);
// load high word
// lis r_dst, (imm>>48) & 0xFFFF
p = mkFormD(p, 15, r_dst, 0, (imm>>48) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm>>32) & 0xFFFF
if ((imm>>32) & 0xFFFF)
p = mkFormD(p, 24, r_dst, r_dst, (imm>>32) & 0xFFFF, endness_host);
// shift r_dst low word to high word => rldicr
p = mkFormMD(p, 30, r_dst, r_dst, 32, 31, 1, endness_host);
// load low word
// oris r_dst, r_dst, (imm>>16) & 0xFFFF
if ((imm>>16) & 0xFFFF)
p = mkFormD(p, 25, r_dst, r_dst, (imm>>16) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm) & 0xFFFF
if (imm & 0xFFFF)
p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
}
}
return p;
}
/* A simplified version of mkLoadImm that always generates 2 or 5
instructions (32 or 64 bits respectively) even if it could generate
fewer. This is needed for generating fixed sized patchable
sequences. */
static UChar* mkLoadImm_EXACTLY2or5 ( UChar* p,
UInt r_dst, ULong imm, Bool mode64,
VexEndness endness_host )
{
vassert(r_dst < 0x20);
if (!mode64) {
/* In 32-bit mode, make sure the top 32 bits of imm are a sign
extension of the bottom 32 bits. (Probably unnecessary.) */
UInt u32 = (UInt)imm;
Int s32 = (Int)u32;
Long s64 = (Long)s32;
imm = (ULong)s64;
}
if (!mode64) {
// addis r_dst,r0,(imm>>16) => lis r_dst, (imm>>16)
p = mkFormD(p, 15, r_dst, 0, (imm>>16) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm & 0xFFFF)
p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
} else {
// full 64bit immediate load: 5 (five!) insns.
// load high word
// lis r_dst, (imm>>48) & 0xFFFF
p = mkFormD(p, 15, r_dst, 0, (imm>>48) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm>>32) & 0xFFFF
p = mkFormD(p, 24, r_dst, r_dst, (imm>>32) & 0xFFFF, endness_host);
// shift r_dst low word to high word => rldicr
p = mkFormMD(p, 30, r_dst, r_dst, 32, 31, 1, endness_host);
// load low word
// oris r_dst, r_dst, (imm>>16) & 0xFFFF
p = mkFormD(p, 25, r_dst, r_dst, (imm>>16) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm) & 0xFFFF
p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
}
return p;
}
/* Checks whether the sequence of bytes at p was indeed created
by mkLoadImm_EXACTLY2or5 with the given parameters. */
static Bool isLoadImm_EXACTLY2or5 ( UChar* p_to_check,
UInt r_dst, ULong imm, Bool mode64,
VexEndness endness_host )
{
vassert(r_dst < 0x20);
if (!mode64) {
/* In 32-bit mode, make sure the top 32 bits of imm are a sign
extension of the bottom 32 bits. (Probably unnecessary.) */
UInt u32 = (UInt)imm;
Int s32 = (Int)u32;
Long s64 = (Long)s32;
imm = (ULong)s64;
}
if (!mode64) {
UInt expect[2] = { 0, 0 };
UChar* p = (UChar*)&expect[0];
// addis r_dst,r0,(imm>>16) => lis r_dst, (imm>>16)
p = mkFormD(p, 15, r_dst, 0, (imm>>16) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm & 0xFFFF)
p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
vassert(p == (UChar*)&expect[2]);
return fetch32(p_to_check + 0, endness_host) == expect[0]
&& fetch32(p_to_check + 4, endness_host) == expect[1];
} else {
UInt expect[5] = { 0, 0, 0, 0, 0 };
UChar* p = (UChar*)&expect[0];
// full 64bit immediate load: 5 (five!) insns.
// load high word
// lis r_dst, (imm>>48) & 0xFFFF
p = mkFormD(p, 15, r_dst, 0, (imm>>48) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm>>32) & 0xFFFF
p = mkFormD(p, 24, r_dst, r_dst, (imm>>32) & 0xFFFF, endness_host);
// shift r_dst low word to high word => rldicr
p = mkFormMD(p, 30, r_dst, r_dst, 32, 31, 1, endness_host);
// load low word
// oris r_dst, r_dst, (imm>>16) & 0xFFFF
p = mkFormD(p, 25, r_dst, r_dst, (imm>>16) & 0xFFFF, endness_host);
// ori r_dst, r_dst, (imm) & 0xFFFF
p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
vassert(p == (UChar*)&expect[5]);
return fetch32(p_to_check + 0, endness_host) == expect[0]
&& fetch32(p_to_check + 4, endness_host) == expect[1]
&& fetch32(p_to_check + 8, endness_host) == expect[2]
&& fetch32(p_to_check + 12, endness_host) == expect[3]
&& fetch32(p_to_check + 16, endness_host) == expect[4];
}
}
/* Generate a machine-word sized load or store. Simplified version of
the Pin_Load and Pin_Store cases below. */
static UChar* do_load_or_store_machine_word (
UChar* p, Bool isLoad,
UInt reg, PPCAMode* am, Bool mode64, VexEndness endness_host )
{
if (isLoad) {
UInt opc1, sz = mode64 ? 8 : 4;
switch (am->tag) {
case Pam_IR:
if (mode64) {
vassert(0 == (am->Pam.IR.index & 3));
}
switch (sz) {
case 4: opc1 = 32; vassert(!mode64); break;
case 8: opc1 = 58; vassert(mode64); break;
default: vassert(0);
}
p = doAMode_IR(p, opc1, reg, am, mode64, endness_host);
break;
case Pam_RR:
/* we could handle this case, but we don't expect to ever
need to. */
vassert(0);
default:
vassert(0);
}
} else /*store*/ {
UInt opc1, sz = mode64 ? 8 : 4;
switch (am->tag) {
case Pam_IR:
if (mode64) {
vassert(0 == (am->Pam.IR.index & 3));
}
switch (sz) {
case 4: opc1 = 36; vassert(!mode64); break;
case 8: opc1 = 62; vassert(mode64); break;
default: vassert(0);
}
p = doAMode_IR(p, opc1, reg, am, mode64, endness_host);
break;
case Pam_RR:
/* we could handle this case, but we don't expect to ever
need to. */
vassert(0);
default:
vassert(0);
}
}
return p;
}
/* Generate a 32-bit sized load or store. Simplified version of
do_load_or_store_machine_word above. */
static UChar* do_load_or_store_word32 (
UChar* p, Bool isLoad,
UInt reg, PPCAMode* am, Bool mode64, VexEndness endness_host )
{
if (isLoad) {
UInt opc1;
switch (am->tag) {
case Pam_IR:
if (mode64) {
vassert(0 == (am->Pam.IR.index & 3));
}
opc1 = 32;
p = doAMode_IR(p, opc1, reg, am, mode64, endness_host);
break;
case Pam_RR:
/* we could handle this case, but we don't expect to ever
need to. */
vassert(0);
default:
vassert(0);
}
} else /*store*/ {
UInt opc1;
switch (am->tag) {
case Pam_IR:
if (mode64) {
vassert(0 == (am->Pam.IR.index & 3));
}
opc1 = 36;
p = doAMode_IR(p, opc1, reg, am, mode64, endness_host);
break;
case Pam_RR:
/* we could handle this case, but we don't expect to ever
need to. */
vassert(0);
default:
vassert(0);
}
}
return p;
}
/* Move r_dst to r_src */
static UChar* mkMoveReg ( UChar* p, UInt r_dst, UInt r_src,
VexEndness endness_host )
{
vassert(r_dst < 0x20);
vassert(r_src < 0x20);
if (r_dst != r_src) {
/* or r_dst, r_src, r_src */
p = mkFormX(p, 31, r_src, r_dst, r_src, 444, 0, endness_host );
}
return p;
}
static UChar* mkFormVX ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt opc2, VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(opc2 < 0x800);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (r3<<11) | opc2);
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormVSXRND ( UChar* p, UInt opc1, UInt R, UInt r1,
UInt r2, UInt RMC, UInt opc2, UChar EX,
VexEndness endness_host )
{
/* The register mapping is all done using VR register numbers for the
* V128 support. This means that the operands for this instruction have
* been loaded into a VR register. The 32 VR registers map to VSR registers
* 32 to 63. For these instructions, the hardware adds 32 to the source
* and destination register numbers. Do not need to adjust the register
* numbers for these instructions.
*/
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(opc2 < 0x100);
vassert(EX < 0x2);
vassert(R < 0x2);
vassert(RMC < 0x4);
theInstr = ((opc1<<26) | (r1<<21) | (R<<16) | (r2<<11) | (RMC<<9) |
(opc2 << 1) | EX);
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormVX_BX_TX ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt opc2, VexEndness endness_host )
{
/* The register mapping is all done using VR register numbers for the
* V128 support. This means that the operands for this instruction have
* been loaded into a VR register. The 32 VR registers map to VSR registers
* 32 to 63. So to make the issued instruction reference the
* corresponding VR register we have to add 32 to the source and
* destination operand numbers, then load the new operand number into the
* correct bit fields.
*
* r1 = 32xTX + T; r3 = 32xBX + B;
* TX is bit 0, BX is bit 1, T is in bits [25:21], B is in bit [14:11]
* opc2 is in bits [10:2]
*/
UInt T, TX, B, BX;
UInt theInstr;
r1 += 32; // adjust the VSR register number to map to the VR number
r3 += 32;
vassert(opc1 < 0x40);
vassert(r1 < 0x40);
vassert(r2 < 0x20);
vassert(r3 < 0x40);
vassert(opc2 < 0x800);
T = r1 & 0x1F;
TX = r1 >> 5;
B = r3 & 0x1F;
BX = r3 >> 5;
theInstr = ((opc1<<26) | (T<<21) | (r2<<16) | (B<<11) | (opc2<<2)
| (BX<<1) | TX);
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormVXR0 ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt opc2, UChar R0,
VexEndness endness_host )
{
/* The register mapping is all done using VR register numbers for the
* V128 support. This means that the operands for this instruction have
* been loaded into a VR register. The 32 VR registers map to VSR registers
* 32 to 63. For these instructions, the hardware adds 32 to the source
* and destination register numbers. Do not need to adjust the register
* numbers for these instructions.
*/
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20); // register numbers are between 0 and 31 (5-bits)
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(opc2 < 0x800);
vassert(R0 < 0x2);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (r3<<11) | (opc2<<1) | R0);
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormVXI ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt opc2, VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(opc2 < 0x27);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (r3<<11) | opc2<<1);
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormVXR ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt Rc, UInt opc2,
VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(Rc < 0x2);
vassert(opc2 < 0x400);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
(r3<<11) | (Rc<<10) | opc2);
return emit32(p, theInstr, endness_host);
}
static UChar* mkFormVA ( UChar* p, UInt opc1, UInt r1, UInt r2,
UInt r3, UInt r4, UInt opc2, VexEndness endness_host )
{
UInt theInstr;
vassert(opc1 < 0x40);
vassert(r1 < 0x20);
vassert(r2 < 0x20);
vassert(r3 < 0x20);
vassert(r4 < 0x20);
vassert(opc2 < 0x40);
theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
(r3<<11) | (r4<<6) | opc2);
return emit32(p, theInstr, endness_host);
}
/* Emit an instruction into buf and return the number of bytes used.
Note that buf is not the insn's final place, and therefore it is
imperative to emit position-independent code. If the emitted
instruction was a profiler inc, set *is_profInc to True, else leave
it unchanged.
*/
Int emit_PPCInstr ( /*MB_MOD*/Bool* is_profInc,
UChar* buf, Int nbuf, const PPCInstr* i,
Bool mode64, VexEndness endness_host,
const void* disp_cp_chain_me_to_slowEP,
const void* disp_cp_chain_me_to_fastEP,
const void* disp_cp_xindir,
const void* disp_cp_xassisted)
{
UChar* p = &buf[0];
vassert(nbuf >= 32);
if (0) {
vex_printf("asm ");ppPPCInstr(i, mode64); vex_printf("\n");
}
switch (i->tag) {
case Pin_LI:
p = mkLoadImm(p, iregEnc(i->Pin.LI.dst, mode64),
i->Pin.LI.imm64, mode64, endness_host);
goto done;
case Pin_Alu: {
PPCRH* srcR = i->Pin.Alu.srcR;
Bool immR = toBool(srcR->tag == Prh_Imm);
UInt r_dst = iregEnc(i->Pin.Alu.dst, mode64);
UInt r_srcL = iregEnc(i->Pin.Alu.srcL, mode64);
UInt r_srcR = immR ? (-1)/*bogus*/ :
iregEnc(srcR->Prh.Reg.reg, mode64);
switch (i->Pin.Alu.op) {
case Palu_ADD:
if (immR) {
/* addi (PPC32 p350) */
vassert(srcR->Prh.Imm.syned);
vassert(srcR->Prh.Imm.imm16 != 0x8000);
p = mkFormD(p, 14, r_dst, r_srcL, srcR->Prh.Imm.imm16, endness_host);
} else {
/* add (PPC32 p347) */
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 266, 0, endness_host);
}
break;
case Palu_SUB:
if (immR) {
/* addi (PPC32 p350), but with negated imm */
vassert(srcR->Prh.Imm.syned);
vassert(srcR->Prh.Imm.imm16 != 0x8000);
p = mkFormD(p, 14, r_dst, r_srcL, (- srcR->Prh.Imm.imm16),
endness_host);
} else {
/* subf (PPC32 p537), with args the "wrong" way round */
p = mkFormXO(p, 31, r_dst, r_srcR, r_srcL, 0, 40, 0, endness_host);
}
break;
case Palu_AND:
if (immR) {
/* andi. (PPC32 p358) */
vassert(!srcR->Prh.Imm.syned);
p = mkFormD(p, 28, r_srcL, r_dst, srcR->Prh.Imm.imm16, endness_host);
} else {
/* and (PPC32 p356) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 28, 0, endness_host);
}
break;
case Palu_OR:
if (immR) {
/* ori (PPC32 p497) */
vassert(!srcR->Prh.Imm.syned);
p = mkFormD(p, 24, r_srcL, r_dst, srcR->Prh.Imm.imm16, endness_host);
} else {
/* or (PPC32 p495) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 444, 0, endness_host);
}
break;
case Palu_XOR:
if (immR) {
/* xori (PPC32 p550) */
vassert(!srcR->Prh.Imm.syned);
p = mkFormD(p, 26, r_srcL, r_dst, srcR->Prh.Imm.imm16, endness_host);
} else {
/* xor (PPC32 p549) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 316, 0, endness_host);
}
break;
default:
goto bad;
}
goto done;
}
case Pin_Shft: {
PPCRH* srcR = i->Pin.Shft.srcR;
Bool sz32 = i->Pin.Shft.sz32;
Bool immR = toBool(srcR->tag == Prh_Imm);
UInt r_dst = iregEnc(i->Pin.Shft.dst, mode64);
UInt r_srcL = iregEnc(i->Pin.Shft.srcL, mode64);
UInt r_srcR = immR ? (-1)/*bogus*/ :
iregEnc(srcR->Prh.Reg.reg, mode64);
if (!mode64)
vassert(sz32);
switch (i->Pin.Shft.op) {
case Pshft_SHL:
if (sz32) {
if (immR) {
/* rd = rs << n, 1 <= n <= 31
is
rlwinm rd,rs,n,0,31-n (PPC32 p501)
*/
UInt n = srcR->Prh.Imm.imm16;
vassert(!srcR->Prh.Imm.syned);
vassert(n > 0 && n < 32);
p = mkFormM(p, 21, r_srcL, r_dst, n, 0, 31-n, 0, endness_host);
} else {
/* slw (PPC32 p505) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 24, 0, endness_host);
}
} else {
if (immR) {
/* rd = rs << n, 1 <= n <= 63
is
rldicr rd,rs,n,63-n (PPC64 p559)
*/
UInt n = srcR->Prh.Imm.imm16;
vassert(!srcR->Prh.Imm.syned);
vassert(n > 0 && n < 64);
p = mkFormMD(p, 30, r_srcL, r_dst, n, 63-n, 1, endness_host);
} else {
/* sld (PPC64 p568) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 27, 0, endness_host);
}
}
break;
case Pshft_SHR:
if (sz32) {
if (immR) {
/* rd = rs >>u n, 1 <= n <= 31
is
rlwinm rd,rs,32-n,n,31 (PPC32 p501)
*/
UInt n = srcR->Prh.Imm.imm16;
vassert(!srcR->Prh.Imm.syned);
vassert(n > 0 && n < 32);
p = mkFormM(p, 21, r_srcL, r_dst, 32-n, n, 31, 0, endness_host);
} else {
/* srw (PPC32 p508) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 536, 0, endness_host);
}
} else {
if (immR) {
/* rd = rs >>u n, 1 <= n <= 63
is
rldicl rd,rs,64-n,n (PPC64 p558)
*/
UInt n = srcR->Prh.Imm.imm16;
vassert(!srcR->Prh.Imm.syned);
vassert(n > 0 && n < 64);
p = mkFormMD(p, 30, r_srcL, r_dst, 64-n, n, 0, endness_host);
} else {
/* srd (PPC64 p574) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 539, 0, endness_host);
}
}
break;
case Pshft_SAR:
if (sz32) {
if (immR) {
/* srawi (PPC32 p507) */
UInt n = srcR->Prh.Imm.imm16;
vassert(!srcR->Prh.Imm.syned);
/* In 64-bit mode, we allow right shifts by zero bits
as that is a handy way to sign extend the lower 32
bits into the upper 32 bits. */
if (mode64)
vassert(n >= 0 && n < 32);
else
vassert(n > 0 && n < 32);
p = mkFormX(p, 31, r_srcL, r_dst, n, 824, 0, endness_host);
} else {
/* sraw (PPC32 p506) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 792, 0, endness_host);
}
} else {
if (immR) {
/* sradi (PPC64 p571) */
UInt n = srcR->Prh.Imm.imm16;
vassert(!srcR->Prh.Imm.syned);
vassert(n > 0 && n < 64);
p = mkFormXS(p, 31, r_srcL, r_dst, n, 413, 0, endness_host);
} else {
/* srad (PPC32 p570) */
p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 794, 0, endness_host);
}
}
break;
default:
goto bad;
}
goto done;
}
case Pin_AddSubC: {
Bool isAdd = i->Pin.AddSubC.isAdd;
Bool setC = i->Pin.AddSubC.setC;
UInt r_srcL = iregEnc(i->Pin.AddSubC.srcL, mode64);
UInt r_srcR = iregEnc(i->Pin.AddSubC.srcR, mode64);
UInt r_dst = iregEnc(i->Pin.AddSubC.dst, mode64);
if (isAdd) {
if (setC) /* addc (PPC32 p348) */
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 10, 0, endness_host);
else /* adde (PPC32 p349) */
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 138, 0, endness_host);
} else {
/* subfX, with args the "wrong" way round */
if (setC) /* subfc (PPC32 p538) */
p = mkFormXO(p, 31, r_dst, r_srcR, r_srcL, 0, 8, 0, endness_host);
else /* subfe (PPC32 p539) */
p = mkFormXO(p, 31, r_dst, r_srcR, r_srcL, 0, 136, 0, endness_host);
}
goto done;
}
case Pin_Cmp: {
Bool syned = i->Pin.Cmp.syned;
Bool sz32 = i->Pin.Cmp.sz32;
UInt fld1 = i->Pin.Cmp.crfD << 2;
UInt r_srcL = iregEnc(i->Pin.Cmp.srcL, mode64);
UInt r_srcR, imm_srcR;
PPCRH* srcR = i->Pin.Cmp.srcR;
if (!mode64) // cmp double word invalid for mode32
vassert(sz32);
else if (!sz32) // mode64 && cmp64: set L=1
fld1 |= 1;
switch (srcR->tag) {
case Prh_Imm:
vassert(syned == srcR->Prh.Imm.syned);
imm_srcR = srcR->Prh.Imm.imm16;
if (syned) { // cmpw/di (signed) (PPC32 p368)
vassert(imm_srcR != 0x8000);
p = mkFormD(p, 11, fld1, r_srcL, imm_srcR, endness_host);
} else { // cmplw/di (unsigned) (PPC32 p370)
p = mkFormD(p, 10, fld1, r_srcL, imm_srcR, endness_host);
}
break;
case Prh_Reg:
r_srcR = iregEnc(srcR->Prh.Reg.reg, mode64);
if (syned) // cmpwi (signed) (PPC32 p367)
p = mkFormX(p, 31, fld1, r_srcL, r_srcR, 0, 0, endness_host);
else // cmplwi (unsigned) (PPC32 p379)
p = mkFormX(p, 31, fld1, r_srcL, r_srcR, 32, 0, endness_host);
break;
default:
goto bad;
}
goto done;
}
case Pin_Unary: {
UInt r_dst = iregEnc(i->Pin.Unary.dst, mode64);
UInt r_src = iregEnc(i->Pin.Unary.src, mode64);
switch (i->Pin.Unary.op) {
case Pun_NOT: // nor r_dst,r_src,r_src
p = mkFormX(p, 31, r_src, r_dst, r_src, 124, 0, endness_host);
break;
case Pun_NEG: // neg r_dst,r_src
p = mkFormXO(p, 31, r_dst, r_src, 0, 0, 104, 0, endness_host);
break;
case Pun_CLZ32: // cntlzw r_dst, r_src
p = mkFormX(p, 31, r_src, r_dst, 0, 26, 0, endness_host);
break;
case Pun_CLZ64: // cntlzd r_dst, r_src
vassert(mode64);
p = mkFormX(p, 31, r_src, r_dst, 0, 58, 0, endness_host);
break;
case Pun_CTZ32: // cnttzw r_dst, r_src
/* Note oder of src and dst is backwards from normal */
p = mkFormX(p, 31, r_src, r_dst, 0, 538, 0, endness_host);
break;
case Pun_CTZ64: // cnttzd r_dst, r_src
/* Note oder of src and dst is backwards from normal */
vassert(mode64);
p = mkFormX(p, 31, r_src, r_dst, 0, 570, 0, endness_host);
break;
case Pun_EXTSW: // extsw r_dst, r_src
vassert(mode64);
p = mkFormX(p, 31, r_src, r_dst, 0, 986, 0, endness_host);
break;
default: goto bad;
}
goto done;
}
case Pin_MulL: {
Bool syned = i->Pin.MulL.syned;
Bool sz32 = i->Pin.MulL.sz32;
UInt r_dst = iregEnc(i->Pin.MulL.dst, mode64);
UInt r_srcL = iregEnc(i->Pin.MulL.srcL, mode64);
UInt r_srcR = iregEnc(i->Pin.MulL.srcR, mode64);
if (!mode64)
vassert(sz32);
if (i->Pin.MulL.hi) {
// mul hi words, must consider sign
if (sz32) {
if (syned) // mulhw r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 75, 0,
endness_host);
else // mulhwu r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 11, 0,
endness_host);
} else {
if (syned) // mulhd r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 73, 0,
endness_host);
else // mulhdu r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 9, 0, endness_host);
}
} else {
// mul low word, sign is irrelevant
vassert(!i->Pin.MulL.syned);
if (sz32) // mullw r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 235, 0, endness_host);
else // mulld r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 233, 0, endness_host);
}
goto done;
}
case Pin_Div: {
Bool syned = i->Pin.Div.syned;
Bool sz32 = i->Pin.Div.sz32;
UInt r_dst = iregEnc(i->Pin.Div.dst, mode64);
UInt r_srcL = iregEnc(i->Pin.Div.srcL, mode64);
UInt r_srcR = iregEnc(i->Pin.Div.srcR, mode64);
if (!mode64)
vassert(sz32);
if (i->Pin.Div.extended) {
if (sz32) {
if (syned)
// divwe r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 427, 0,
endness_host);
else
// divweu r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 395, 0,
endness_host);
} else {
if (syned)
// divde r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 425, 0,
endness_host);
else
// divdeu r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 393, 0,
endness_host);
}
} else if (sz32) {
if (syned) // divw r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 491, 0, endness_host);
else // divwu r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 459, 0, endness_host);
} else {
if (syned) // divd r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 489, 0, endness_host);
else // divdu r_dst,r_srcL,r_srcR
p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 457, 0, endness_host);
}
goto done;
}
case Pin_Call: {
if (i->Pin.Call.cond.test != Pct_ALWAYS
&& i->Pin.Call.rloc.pri != RLPri_None) {
/* The call might not happen (it isn't unconditional) and it
returns a result. In this case we will need to generate a
control flow diamond to put 0x555..555 in the return
register(s) in the case where the call doesn't happen. If
this ever becomes necessary, maybe copy code from the ARM
equivalent. Until that day, just give up. */
goto bad;
}
PPCCondCode cond = i->Pin.Call.cond;
UInt r_dst = 10;
/* As per detailed comment for Pin_Call in
getRegUsage_PPCInstr above, %r10 is used as an address temp */
/* jump over the following insns if condition does not hold */
UChar* ptmp = NULL;
if (cond.test != Pct_ALWAYS) {
/* jmp fwds if !condition */
/* don't know how many bytes to jump over yet...
make space for a jump instruction and fill in later. */
ptmp = p; /* fill in this bit later */
p += 4; // p += 4
}
/* load target to r_dst */ // p += 4|8|20
p = mkLoadImm(p, r_dst, i->Pin.Call.target, mode64, endness_host);
/* mtspr 9,r_dst => move r_dst to count register */
p = mkFormXFX(p, r_dst, 9, 467, endness_host); // p += 4
/* bctrl => branch to count register (and save to lr) */
p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 1, endness_host); // p += 4
/* Fix up the conditional jump, if there was one. */
if (cond.test != Pct_ALWAYS) {
Int delta = p - ptmp;
vassert(delta >= 16 && delta <= 32);
/* bc !ct,cf,delta */
mkFormB(ptmp, invertCondTest(cond.test),
cond.flag, (delta>>2), 0, 0, endness_host);
}
goto done;
}
case Pin_XDirect: {
/* NB: what goes on here has to be very closely coordinated
with the chainXDirect_PPC and unchainXDirect_PPC below. */
/* We're generating chain-me requests here, so we need to be
sure this is actually allowed -- no-redir translations
can't use chain-me's. Hence: */
vassert(disp_cp_chain_me_to_slowEP != NULL);
vassert(disp_cp_chain_me_to_fastEP != NULL);
/* First off, if this is conditional, create a conditional jump
over the rest of it. Or at least, leave a space for it that
we will shortly fill in. */
UChar* ptmp = NULL;
if (i->Pin.XDirect.cond.test != Pct_ALWAYS) {
vassert(i->Pin.XDirect.cond.flag != Pcf_NONE);
ptmp = p;
p += 4;
} else {
vassert(i->Pin.XDirect.cond.flag == Pcf_NONE);
}
/* Update the guest CIA. */
/* imm32/64 r30, dstGA */
if (!mode64) vassert(0 == (((ULong)i->Pin.XDirect.dstGA) >> 32));
p = mkLoadImm(p, /*r*/30, (ULong)i->Pin.XDirect.dstGA, mode64,
endness_host);
/* stw/std r30, amCIA */
p = do_load_or_store_machine_word(
p, False/*!isLoad*/,
/*r*/30, i->Pin.XDirect.amCIA, mode64, endness_host
);
/* --- FIRST PATCHABLE BYTE follows --- */
/* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're calling
to) backs up the return address, so as to find the address of
the first patchable byte. So: don't change the number of
instructions (32-bit: 4, 64-bit: 7) below. */
/* imm32/64-fixed r30, VG_(disp_cp_chain_me_to_{slowEP,fastEP} */
const void* disp_cp_chain_me
= i->Pin.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP
: disp_cp_chain_me_to_slowEP;
p = mkLoadImm_EXACTLY2or5(
p, /*r*/30, (Addr)disp_cp_chain_me, mode64, endness_host);
/* mtctr r30 */
p = mkFormXFX(p, /*r*/30, 9, 467, endness_host);
/* bctrl */
p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 1, endness_host);
/* --- END of PATCHABLE BYTES --- */
/* Fix up the conditional jump, if there was one. */
if (i->Pin.XDirect.cond.test != Pct_ALWAYS) {
Int delta = p - ptmp;
vassert(delta >= 16 && delta <= 64 && 0 == (delta & 3));
/* bc !ct,cf,delta */
mkFormB(ptmp, invertCondTest(i->Pin.XDirect.cond.test),
i->Pin.XDirect.cond.flag, (delta>>2), 0, 0, endness_host);
}
goto done;
}
case Pin_XIndir: {
/* We're generating transfers that could lead indirectly to a
chain-me, so we need to be sure this is actually allowed --
no-redir translations are not allowed to reach normal
translations without going through the scheduler. That means
no XDirects or XIndirs out from no-redir translations.
Hence: */
vassert(disp_cp_xindir != NULL);
/* First off, if this is conditional, create a conditional jump
over the rest of it. Or at least, leave a space for it that
we will shortly fill in. */
UChar* ptmp = NULL;
if (i->Pin.XIndir.cond.test != Pct_ALWAYS) {
vassert(i->Pin.XIndir.cond.flag != Pcf_NONE);
ptmp = p;
p += 4;
} else {
vassert(i->Pin.XIndir.cond.flag == Pcf_NONE);
}
/* Update the guest CIA. */
/* stw/std r-dstGA, amCIA */
p = do_load_or_store_machine_word(
p, False/*!isLoad*/,
iregEnc(i->Pin.XIndir.dstGA, mode64),
i->Pin.XIndir.amCIA, mode64, endness_host
);
/* imm32/64 r30, VG_(disp_cp_xindir) */
p = mkLoadImm(p, /*r*/30, (ULong)(Addr)disp_cp_xindir, mode64,
endness_host);
/* mtctr r30 */
p = mkFormXFX(p, /*r*/30, 9, 467, endness_host);
/* bctr */
p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 0, endness_host);
/* Fix up the conditional jump, if there was one. */
if (i->Pin.XIndir.cond.test != Pct_ALWAYS) {
Int delta = p - ptmp;
vassert(delta >= 16 && delta <= 32 && 0 == (delta & 3));
/* bc !ct,cf,delta */
mkFormB(ptmp, invertCondTest(i->Pin.XIndir.cond.test),
i->Pin.XIndir.cond.flag, (delta>>2), 0, 0, endness_host);
}
goto done;
}
case Pin_XAssisted: {
/* First off, if this is conditional, create a conditional jump
over the rest of it. Or at least, leave a space for it that
we will shortly fill in. */
UChar* ptmp = NULL;
if (i->Pin.XAssisted.cond.test != Pct_ALWAYS) {
vassert(i->Pin.XAssisted.cond.flag != Pcf_NONE);
ptmp = p;
p += 4;
} else {
vassert(i->Pin.XAssisted.cond.flag == Pcf_NONE);
}
/* Update the guest CIA. */
/* stw/std r-dstGA, amCIA */
p = do_load_or_store_machine_word(
p, False/*!isLoad*/,
iregEnc(i->Pin.XIndir.dstGA, mode64),
i->Pin.XIndir.amCIA, mode64, endness_host
);
/* imm32/64 r31, $magic_number */
UInt trcval = 0;
switch (i->Pin.XAssisted.jk) {
case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
//case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break;
//case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break;
//case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break;
case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
case Ijk_InvalICache: trcval = VEX_TRC_JMP_INVALICACHE; break;
case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
//case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break;
case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break;
case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
/* We don't expect to see the following being assisted. */
//case Ijk_Ret:
//case Ijk_Call:
/* fallthrough */
default:
ppIRJumpKind(i->Pin.XAssisted.jk);
vpanic("emit_ARMInstr.Pin_XAssisted: unexpected jump kind");
}
vassert(trcval != 0);
p = mkLoadImm(p, /*r*/31, trcval, mode64, endness_host);
/* imm32/64 r30, VG_(disp_cp_xassisted) */
p = mkLoadImm(p, /*r*/30,
(ULong)(Addr)disp_cp_xassisted, mode64,
endness_host);
/* mtctr r30 */
p = mkFormXFX(p, /*r*/30, 9, 467, endness_host);
/* bctr */
p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 0, endness_host);
/* Fix up the conditional jump, if there was one. */
if (i->Pin.XAssisted.cond.test != Pct_ALWAYS) {
Int delta = p - ptmp;
vassert(delta >= 16 && delta <= 32 && 0 == (delta & 3));
/* bc !ct,cf,delta */
mkFormB(ptmp, invertCondTest(i->Pin.XAssisted.cond.test),
i->Pin.XAssisted.cond.flag, (delta>>2), 0, 0, endness_host);
}
goto done;
}
case Pin_CMov: {
UInt r_dst, r_src;
ULong imm_src;
PPCCondCode cond;
vassert(i->Pin.CMov.cond.test != Pct_ALWAYS);
r_dst = iregEnc(i->Pin.CMov.dst, mode64);
cond = i->Pin.CMov.cond;
/* branch (if cond fails) over move instrs */
UChar* ptmp = NULL;
if (cond.test != Pct_ALWAYS) {
/* don't know how many bytes to jump over yet...
make space for a jump instruction and fill in later. */
ptmp = p; /* fill in this bit later */
p += 4;
}
// cond true: move src => dst
switch (i->Pin.CMov.src->tag) {
case Pri_Imm:
imm_src = i->Pin.CMov.src->Pri.Imm;
p = mkLoadImm(p, r_dst, imm_src, mode64, endness_host); // p += 4|8|20
break;
case Pri_Reg:
r_src = iregEnc(i->Pin.CMov.src->Pri.Reg, mode64);
p = mkMoveReg(p, r_dst, r_src, endness_host); // p += 4
break;
default: goto bad;
}
/* Fix up the conditional jump, if there was one. */
if (cond.test != Pct_ALWAYS) {
Int delta = p - ptmp;
vassert(delta >= 8 && delta <= 24);
/* bc !ct,cf,delta */
mkFormB(ptmp, invertCondTest(cond.test),
cond.flag, (delta>>2), 0, 0, endness_host);
}
goto done;
}
case Pin_Load: {
PPCAMode* am_addr = i->Pin.Load.src;
UInt r_dst = iregEnc(i->Pin.Load.dst, mode64);
UInt opc1, opc2, sz = i->Pin.Load.sz;
switch (am_addr->tag) {
case Pam_IR:
if (mode64 && (sz == 4 || sz == 8)) {
/* should be guaranteed to us by iselWordExpr_AMode */
vassert(0 == (am_addr->Pam.IR.index & 3));
}
switch(sz) {
case 1: opc1 = 34; break;
case 2: opc1 = 40; break;
case 4: opc1 = 32; break;
case 8: opc1 = 58; vassert(mode64); break;
default: goto bad;
}
p = doAMode_IR(p, opc1, r_dst, am_addr, mode64, endness_host);
goto done;
case Pam_RR:
switch(sz) {
case 1: opc2 = 87; break;
case 2: opc2 = 279; break;
case 4: opc2 = 23; break;
case 8: opc2 = 21; vassert(mode64); break;
default: goto bad;
}
p = doAMode_RR(p, 31, opc2, r_dst, am_addr, mode64, endness_host);
goto done;
default:
goto bad;
}
}
case Pin_LoadL: {
if (i->Pin.LoadL.sz == 1) {
p = mkFormX(p, 31, iregEnc(i->Pin.LoadL.dst, mode64),
0, iregEnc(i->Pin.LoadL.src, mode64), 52, 0, endness_host);
goto done;
}
if (i->Pin.LoadL.sz == 2) {
p = mkFormX(p, 31, iregEnc(i->Pin.LoadL.dst, mode64),
0, iregEnc(i->Pin.LoadL.src, mode64), 116, 0, endness_host);
goto done;
}
if (i->Pin.LoadL.sz == 4) {
p = mkFormX(p, 31, iregEnc(i->Pin.LoadL.dst, mode64),
0, iregEnc(i->Pin.LoadL.src, mode64), 20, 0, endness_host);
goto done;
}
if (i->Pin.LoadL.sz == 8 && mode64) {
p = mkFormX(p, 31, iregEnc(i->Pin.LoadL.dst, mode64),
0, iregEnc(i->Pin.LoadL.src, mode64), 84, 0, endness_host);
goto done;
}
goto bad;
}
case Pin_Set: {
/* Make the destination register be 1 or 0, depending on whether
the relevant condition holds. */
UInt r_dst = iregEnc(i->Pin.Set.dst, mode64);
PPCCondCode cond = i->Pin.Set.cond;
UInt rot_imm, r_tmp;
if (cond.test == Pct_ALWAYS) {
// Just load 1 to dst => li dst,1
p = mkFormD(p, 14, r_dst, 0, 1, endness_host);
} else {
vassert(cond.flag != Pcf_NONE);
rot_imm = 1 + cond.flag;
r_tmp = 0; // Not set in getAllocable, so no need to declare.
// r_tmp = CR => mfcr r_tmp
p = mkFormX(p, 31, r_tmp, 0, 0, 19, 0, endness_host);
// r_dst = flag (rotate left and mask)
// => rlwinm r_dst,r_tmp,rot_imm,31,31
p = mkFormM(p, 21, r_tmp, r_dst, rot_imm, 31, 31, 0, endness_host);
if (cond.test == Pct_FALSE) {
// flip bit => xori r_dst,r_dst,1
p = mkFormD(p, 26, r_dst, r_dst, 1, endness_host);
}
}
goto done;
}
case Pin_MfCR:
// mfcr dst
p = mkFormX(p, 31, iregEnc(i->Pin.MfCR.dst, mode64), 0, 0, 19, 0,
endness_host);
goto done;
case Pin_MFence: {
p = mkFormX(p, 31, 0, 0, 0, 598, 0, endness_host); // sync, PPC32 p616
// CAB: Should this be isync?
// p = mkFormXL(p, 19, 0, 0, 0, 150, 0); // isync, PPC32 p467
goto done;
}
case Pin_Store: {
PPCAMode* am_addr = i->Pin.Store.dst;
UInt r_src = iregEnc(i->Pin.Store.src, mode64);
UInt opc1, opc2, sz = i->Pin.Store.sz;
switch (i->Pin.Store.dst->tag) {
case Pam_IR:
if (mode64 && (sz == 4 || sz == 8)) {
/* should be guaranteed to us by iselWordExpr_AMode */
vassert(0 == (am_addr->Pam.IR.index & 3));
}
switch(sz) {
case 1: opc1 = 38; break;
case 2: opc1 = 44; break;
case 4: opc1 = 36; break;
case 8: vassert(mode64);
opc1 = 62; break;
default:
goto bad;
}
p = doAMode_IR(p, opc1, r_src, am_addr, mode64, endness_host);
goto done;
case Pam_RR:
switch(sz) {
case 1: opc2 = 215; break;
case 2: opc2 = 407; break;
case 4: opc2 = 151; break;
case 8: vassert(mode64);
opc2 = 149; break;
default:
goto bad;
}
p = doAMode_RR(p, 31, opc2, r_src, am_addr, mode64, endness_host);
goto done;
default:
goto bad;
}
goto done;
}
case Pin_StoreC: {
if (i->Pin.StoreC.sz == 1) {
p = mkFormX(p, 31, iregEnc(i->Pin.StoreC.src, mode64),
0, iregEnc(i->Pin.StoreC.dst, mode64), 694, 1, endness_host);
goto done;
}
if (i->Pin.StoreC.sz == 2) {
p = mkFormX(p, 31, iregEnc(i->Pin.StoreC.src, mode64),
0, iregEnc(i->Pin.StoreC.dst, mode64), 726, 1, endness_host);
goto done;
}
if (i->Pin.StoreC.sz == 4) {
p = mkFormX(p, 31, iregEnc(i->Pin.StoreC.src, mode64),
0, iregEnc(i->Pin.StoreC.dst, mode64), 150, 1, endness_host);
goto done;
}
if (i->Pin.StoreC.sz == 8 && mode64) {
p = mkFormX(p, 31, iregEnc(i->Pin.StoreC.src, mode64),
0, iregEnc(i->Pin.StoreC.dst, mode64), 214, 1, endness_host);
goto done;
}
goto bad;
}
case Pin_FpUnary: {
UInt fr_dst = fregEnc(i->Pin.FpUnary.dst);
UInt fr_src = fregEnc(i->Pin.FpUnary.src);
switch (i->Pin.FpUnary.op) {
case Pfp_RSQRTE: // frsqrtre, PPC32 p424
p = mkFormA( p, 63, fr_dst, 0, fr_src, 0, 26, 0, endness_host );
break;
case Pfp_RES: // fres, PPC32 p421
p = mkFormA( p, 59, fr_dst, 0, fr_src, 0, 24, 0, endness_host );
break;
case Pfp_SQRT: // fsqrt, PPC32 p427
p = mkFormA( p, 63, fr_dst, 0, fr_src, 0, 22, 0, endness_host );
break;
case Pfp_ABS: // fabs, PPC32 p399
p = mkFormX(p, 63, fr_dst, 0, fr_src, 264, 0, endness_host);
break;
case Pfp_NEG: // fneg, PPC32 p416
p = mkFormX(p, 63, fr_dst, 0, fr_src, 40, 0, endness_host);
break;
case Pfp_MOV: // fmr, PPC32 p410
p = mkFormX(p, 63, fr_dst, 0, fr_src, 72, 0, endness_host);
break;
case Pfp_FRIM: // frim, PPC ISA 2.05 p137
p = mkFormX(p, 63, fr_dst, 0, fr_src, 488, 0, endness_host);
break;
case Pfp_FRIP: // frip, PPC ISA 2.05 p137
p = mkFormX(p, 63, fr_dst, 0, fr_src, 456, 0, endness_host);
break;
case Pfp_FRIN: // frin, PPC ISA 2.05 p137
p = mkFormX(p, 63, fr_dst, 0, fr_src, 392, 0, endness_host);
break;
case Pfp_FRIZ: // friz, PPC ISA 2.05 p137
p = mkFormX(p, 63, fr_dst, 0, fr_src, 424, 0, endness_host);
break;
default:
goto bad;
}
goto done;
}
case Pin_FpBinary: {
UInt fr_dst = fregEnc(i->Pin.FpBinary.dst);
UInt fr_srcL = fregEnc(i->Pin.FpBinary.srcL);
UInt fr_srcR = fregEnc(i->Pin.FpBinary.srcR);
switch (i->Pin.FpBinary.op) {
case Pfp_ADDD: // fadd, PPC32 p400
p = mkFormA( p, 63, fr_dst, fr_srcL, fr_srcR, 0, 21, 0, endness_host );
break;
case Pfp_ADDS: // fadds, PPC32 p401
p = mkFormA( p, 59, fr_dst, fr_srcL, fr_srcR, 0, 21, 0, endness_host );
break;
case Pfp_SUBD: // fsub, PPC32 p429
p = mkFormA( p, 63, fr_dst, fr_srcL, fr_srcR, 0, 20, 0, endness_host );
break;
case Pfp_SUBS: // fsubs, PPC32 p430
p = mkFormA( p, 59, fr_dst, fr_srcL, fr_srcR, 0, 20, 0, endness_host );
break;
case Pfp_MULD: // fmul, PPC32 p413
p = mkFormA( p, 63, fr_dst, fr_srcL, 0, fr_srcR, 25, 0, endness_host );
break;
case Pfp_MULS: // fmuls, PPC32 p414
p = mkFormA( p, 59, fr_dst, fr_srcL, 0, fr_srcR, 25, 0, endness_host );
break;
case Pfp_DIVD: // fdiv, PPC32 p406
p = mkFormA( p, 63, fr_dst, fr_srcL, fr_srcR, 0, 18, 0, endness_host );
break;
case Pfp_DIVS: // fdivs, PPC32 p407
p = mkFormA( p, 59, fr_dst, fr_srcL, fr_srcR, 0, 18, 0, endness_host );
break;
default:
goto bad;
}
goto done;
}
case Pin_Fp128Unary: {
/* Note Fp128 instructions use the vector scalar registers. The register
* mapping for the V128 type assumes the a vector instruction. The
* PPC hardware has a single register file that the vector scalar
* registers and the vector registers map to. The 32 vector
* registers instructions map to the same registers as the vector
* scalar registers 32 to 63. mkFormVXR0 does the needed
* adjustment.
*/
UInt fr_dst = vregEnc(i->Pin.Fp128Unary.dst);
UInt fr_src = vregEnc(i->Pin.Fp128Unary.src);
switch (i->Pin.Fp128Unary.op) {
case Pfp_FPSQRTQ: // xssqrtqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, 27, fr_src, 804, 0, endness_host );
break;
case Pfp_FPSQRTQRNDODD: // xssqrtqpo, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, 27, fr_src, 804, 1, endness_host );
break;
case Pfp_FPQTOD: // xscvqpdp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, 20, fr_src, 836, 0, endness_host );
break;
case Pfp_FPQTODRNDODD: // xscvqpdpo, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, 20, fr_src, 836, 1, endness_host );
break;
case Pfp_FPDTOQ: // xscvdpqp
p = mkFormVXR0( p, 63, fr_dst, 22, fr_src, 836, 0, endness_host );
break;
case Pfp_IDSTOQ: // xscvsdqp
p = mkFormVXR0( p, 63, fr_dst, 10, fr_src, 836, 0, endness_host );
break;
case Pfp_IDUTOQ: // xscvudqp
p = mkFormVXR0( p, 63, fr_dst, 2, fr_src, 836, 0, endness_host );
break;
case Pfp_TRUNCFPQTOISD: // xscvqpsdz
p = mkFormVXR0( p, 63, fr_dst, 25, fr_src, 836, 0, endness_host );
break;
case Pfp_TRUNCFPQTOISW: // xscvqpswz
p = mkFormVXR0( p, 63, fr_dst, 9, fr_src, 836, 0, endness_host );
break;
case Pfp_TRUNCFPQTOIUD: // xscvqpudz
p = mkFormVXR0( p, 63, fr_dst, 17, fr_src, 836, 0, endness_host );
break;
case Pfp_TRUNCFPQTOIUW: // xscvqpuwz
p = mkFormVXR0( p, 63, fr_dst, 1, fr_src, 836, 0, endness_host );
break;
default:
goto bad;
}
goto done;
}
case Pin_Fp128Binary: {
/* Note Fp128 instructions use the vector registers */
UInt fr_dst = vregEnc(i->Pin.Fp128Binary.dst);
UInt fr_srcL = vregEnc(i->Pin.Fp128Binary.srcL);
UInt fr_srcR = vregEnc(i->Pin.Fp128Binary.srcR);
/* Note this issues a Vector scalar instruction. The register
* mapping for the V128 type assumes the a vector instruction. The
* PPC hardware has a single register file that the vector scalar
* registers and the vector registers map to. The 32 vector
* registers instructions map to the same registers as the vector
* scalar registers 32 to 63. For these instructions the HW adds
* 32 to the register numbers to access the VSRR register. No need
* to adjust the numbers to map to the VR register that contians the
* operands.
*/
switch (i->Pin.Fp128Binary.op) {
case Pfp_FPADDQ: // xsaddqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 4, 0, endness_host );
break;
case Pfp_FPADDQRNDODD: // xsaddqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 4, 1, endness_host );
break;
case Pfp_FPSUBQ: // xssubqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 516, 0, endness_host );
break;
case Pfp_FPSUBQRNDODD: // xssubqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 516, 1, endness_host );
break;
case Pfp_FPMULQ: // xsmulqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 36, 0, endness_host );
break;
case Pfp_FPMULQRNDODD: // xsmulqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 36, 1, endness_host );
break;
case Pfp_FPDIVQ: // xsdivqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 548, 0, endness_host );
break;
case Pfp_FPDIVQRNDODD: // xsdivqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 548, 1, endness_host );
break;
case Pfp_FPMULADDQ: // xsmaddqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 388, 0, endness_host );
break;
case Pfp_FPMULADDQRNDODD: // xsmaddqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 388, 1, endness_host );
break;
case Pfp_FPMULSUBQ: // xsmsubqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 420, 0, endness_host );
break;
case Pfp_FPMULSUBQRNDODD: // xsmsubsqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 420, 1, endness_host );
break;
case Pfp_FPNEGMULADDQ: // xsnmaddqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 452, 0, endness_host );
break;
case Pfp_FPNEGMULADDQRNDODD: // xsnmaddqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 452, 1, endness_host );
break;
case Pfp_FPNEGMULSUBQ: // xsnmsubqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 484, 0, endness_host );
break;
case Pfp_FPNEGMULSUBQRNDODD: // xsnmsubsqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 484, 1, endness_host );
break;
default:
goto bad;
}
goto done;
}
case Pin_Fp128Trinary: {
/* Note Fp128 instructions use the vector registers */
UInt fr_dst = vregEnc(i->Pin.Fp128Binary.dst);
UInt fr_srcL = vregEnc(i->Pin.Fp128Binary.srcL);
UInt fr_srcR = vregEnc(i->Pin.Fp128Binary.srcR);
/* Note this issues a Vector scalar instruction. The register
* mapping for the V128 type assumes the a vector instruction. The
* PPC hardware has a single register file that the vector scalar
* registers and the vector registers map to. The 32 vector
* registers instructions map to the same registers as the vector
* scalar registers 32 to 63. For these instructions the HW adds
* 32 to the register numbers to access the VSRR register. No need
* to adjust the numbers to map to the VR register that contians the
* operands.
*/
switch (i->Pin.Fp128Binary.op) {
case Pfp_FPMULADDQ: // xsmaddqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 388, 0, endness_host );
break;
case Pfp_FPMULADDQRNDODD: // xsmaddqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 388, 1, endness_host );
break;
case Pfp_FPMULSUBQ: // xsmsubqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 420, 0, endness_host );
break;
case Pfp_FPMULSUBQRNDODD: // xsmsubsqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 420, 1, endness_host );
break;
case Pfp_FPNEGMULADDQ: // xsnmaddqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 452, 0, endness_host );
break;
case Pfp_FPNEGMULADDQRNDODD: // xsnmaddqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 452, 1, endness_host );
break;
case Pfp_FPNEGMULSUBQ: // xsnmsubqp, use rounding specified by RN
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 484, 0, endness_host );
break;
case Pfp_FPNEGMULSUBQRNDODD: // xsnmsubsqpo, round to odd
p = mkFormVXR0( p, 63, fr_dst, fr_srcL, fr_srcR, 484, 1, endness_host );
break;
default:
goto bad;
}
goto done;
}
case Pin_FpMulAcc: {
UInt fr_dst = fregEnc(i->Pin.FpMulAcc.dst);
UInt fr_srcML = fregEnc(i->Pin.FpMulAcc.srcML);
UInt fr_srcMR = fregEnc(i->Pin.FpMulAcc.srcMR);
UInt fr_srcAcc = fregEnc(i->Pin.FpMulAcc.srcAcc);
switch (i->Pin.FpMulAcc.op) {
case Pfp_MADDD: // fmadd, PPC32 p408
p = mkFormA( p, 63, fr_dst, fr_srcML, fr_srcAcc, fr_srcMR, 29, 0,
endness_host );
break;
case Pfp_MADDS: // fmadds, PPC32 p409
p = mkFormA( p, 59, fr_dst, fr_srcML, fr_srcAcc, fr_srcMR, 29, 0,
endness_host );
break;
case Pfp_MSUBD: // fmsub, PPC32 p411
p = mkFormA( p, 63, fr_dst, fr_srcML, fr_srcAcc, fr_srcMR, 28, 0,
endness_host );
break;
case Pfp_MSUBS: // fmsubs, PPC32 p412
p = mkFormA( p, 59, fr_dst, fr_srcML, fr_srcAcc, fr_srcMR, 28, 0,
endness_host );
break;
default:
goto bad;
}
goto done;
}
case Pin_FpLdSt: {
PPCAMode* am_addr = i->Pin.FpLdSt.addr;
UInt f_reg = fregEnc(i->Pin.FpLdSt.reg);
Bool idxd = toBool(i->Pin.FpLdSt.addr->tag == Pam_RR);
UChar sz = i->Pin.FpLdSt.sz;
UInt opc;
vassert(sz == 4 || sz == 8);
if (i->Pin.FpLdSt.isLoad) { // Load from memory
if (idxd) { // lf[s|d]x, PPC32 p444|440
opc = (sz == 4) ? 535 : 599;
p = doAMode_RR(p, 31, opc, f_reg, am_addr, mode64, endness_host);
} else { // lf[s|d], PPC32 p441|437
opc = (sz == 4) ? 48 : 50;
p = doAMode_IR(p, opc, f_reg, am_addr, mode64, endness_host);
}
} else { // Store to memory
if (idxd) { // stf[s|d]x, PPC32 p521|516
opc = (sz == 4) ? 663 : 727;
p = doAMode_RR(p, 31, opc, f_reg, am_addr, mode64, endness_host);
} else { // stf[s|d], PPC32 p518|513
opc = (sz == 4) ? 52 : 54;
p = doAMode_IR(p, opc, f_reg, am_addr, mode64, endness_host);
}
}
goto done;
}
case Pin_FpSTFIW: {
UInt ir_addr = iregEnc(i->Pin.FpSTFIW.addr, mode64);
UInt fr_data = fregEnc(i->Pin.FpSTFIW.data);
// stfiwx (store fp64[lo32] as int32), PPC32 p517
// Use rA==0, so that EA == rB == ir_addr
p = mkFormX(p, 31, fr_data, 0/*rA=0*/, ir_addr, 983, 0, endness_host);
goto done;
}
case Pin_FpRSP: {
UInt fr_dst = fregEnc(i->Pin.FpRSP.dst);
UInt fr_src = fregEnc(i->Pin.FpRSP.src);
// frsp, PPC32 p423
p = mkFormX(p, 63, fr_dst, 0, fr_src, 12, 0, endness_host);
goto done;
}
case Pin_FpCftI: {
UInt fr_dst = fregEnc(i->Pin.FpCftI.dst);
UInt fr_src = fregEnc(i->Pin.FpCftI.src);
if (i->Pin.FpCftI.fromI == False && i->Pin.FpCftI.int32 == True) {
if (i->Pin.FpCftI.syned == True) {
// fctiw (conv f64 to i32), PPC32 p404
p = mkFormX(p, 63, fr_dst, 0, fr_src, 14, 0, endness_host);
goto done;
} else {
// fctiwu (conv f64 to u32)
p = mkFormX(p, 63, fr_dst, 0, fr_src, 142, 0, endness_host);
goto done;
}
}
if (i->Pin.FpCftI.fromI == False && i->Pin.FpCftI.int32 == False) {
if (i->Pin.FpCftI.syned == True) {
// fctid (conv f64 to i64), PPC64 p437
p = mkFormX(p, 63, fr_dst, 0, fr_src, 814, 0, endness_host);
goto done;
} else {
// fctidu (conv f64 to u64)
p = mkFormX(p, 63, fr_dst, 0, fr_src, 942, 0, endness_host);
goto done;
}
}
if (i->Pin.FpCftI.fromI == True && i->Pin.FpCftI.int32 == False) {
if (i->Pin.FpCftI.syned == True) {
// fcfid (conv i64 to f64), PPC64 p434
p = mkFormX(p, 63, fr_dst, 0, fr_src, 846, 0, endness_host);
goto done;
} else if (i->Pin.FpCftI.flt64 == True) {
// fcfidu (conv u64 to f64)
p = mkFormX(p, 63, fr_dst, 0, fr_src, 974, 0, endness_host);
goto done;
} else {
// fcfidus (conv u64 to f32)
p = mkFormX(p, 59, fr_dst, 0, fr_src, 974, 0, endness_host);
goto done;
}
}
goto bad;
}
case Pin_FpCMov: {
UInt fr_dst = fregEnc(i->Pin.FpCMov.dst);
UInt fr_src = fregEnc(i->Pin.FpCMov.src);
PPCCondCode cc = i->Pin.FpCMov.cond;
if (fr_dst == fr_src) goto done;
vassert(cc.test != Pct_ALWAYS);
/* jmp fwds if !condition */
if (cc.test != Pct_ALWAYS) {
/* bc !ct,cf,n_bytes>>2 */
p = mkFormB(p, invertCondTest(cc.test), cc.flag, 8>>2, 0, 0,
endness_host);
}
// fmr, PPC32 p410
p = mkFormX(p, 63, fr_dst, 0, fr_src, 72, 0, endness_host);
goto done;
}
case Pin_FpLdFPSCR: {
UInt fr_src = fregEnc(i->Pin.FpLdFPSCR.src);
p = mkFormXFL(p, 0xFF, fr_src, i->Pin.FpLdFPSCR.dfp_rm, endness_host); // mtfsf, PPC32 p480
goto done;
}
case Pin_FpCmp: {
UChar crfD = 1;
UInt r_dst = iregEnc(i->Pin.FpCmp.dst, mode64);
UInt fr_srcL = fregEnc(i->Pin.FpCmp.srcL);
UInt fr_srcR = fregEnc(i->Pin.FpCmp.srcR);
vassert(crfD < 8);
// fcmpo, PPC32 p402
p = mkFormX(p, 63, crfD<<2, fr_srcL, fr_srcR, 32, 0, endness_host);
// mfcr (mv CR to r_dst), PPC32 p467
p = mkFormX(p, 31, r_dst, 0, 0, 19, 0, endness_host);
// rlwinm r_dst,r_dst,8,28,31, PPC32 p501
// => rotate field 1 to bottomw of word, masking out upper 28
p = mkFormM(p, 21, r_dst, r_dst, 8, 28, 31, 0, endness_host);
goto done;
}
case Pin_RdWrLR: {
UInt reg = iregEnc(i->Pin.RdWrLR.gpr, mode64);
/* wrLR==True ? mtlr r4 : mflr r4 */
p = mkFormXFX(p, reg, 8, (i->Pin.RdWrLR.wrLR==True) ? 467 : 339,
endness_host);
goto done;
}
/* AltiVec */
case Pin_AvLdSt: {
UInt opc2, v_reg, r_idx, r_base;
UChar sz = i->Pin.AvLdSt.sz;
Bool idxd = toBool(i->Pin.AvLdSt.addr->tag == Pam_RR);
vassert(sz == 1 || sz == 2 || sz == 4 || sz == 16);
v_reg = vregEnc(i->Pin.AvLdSt.reg);
r_base = iregEnc(i->Pin.AvLdSt.addr->Pam.RR.base, mode64);
// Only have AltiVec AMode_RR: kludge AMode_IR
if (!idxd) {
r_idx = 30; // XXX: Using r30 as temp
p = mkLoadImm(p, r_idx,
i->Pin.AvLdSt.addr->Pam.IR.index, mode64, endness_host);
} else {
r_idx = iregEnc(i->Pin.AvLdSt.addr->Pam.RR.index, mode64);
}
if (i->Pin.FpLdSt.isLoad) { // Load from memory (1,2,4,16)
opc2 = (sz==1) ? 7 : (sz==2) ? 39 : (sz==4) ? 71 : 103;
p = mkFormX(p, 31, v_reg, r_idx, r_base, opc2, 0, endness_host);
} else { // Store to memory (1,2,4,16)
opc2 = (sz==1) ? 135 : (sz==2) ? 167 : (sz==4) ? 199 : 231;
p = mkFormX(p, 31, v_reg, r_idx, r_base, opc2, 0, endness_host);
}
goto done;
}
case Pin_AvUnary: {
UInt v_dst = vregEnc(i->Pin.AvUnary.dst);
UInt v_src = vregEnc(i->Pin.AvUnary.src);
UInt opc2 = 0xFFFFFFFF, opc3 = 0xFFFFFFFF; /* invalid */
switch (i->Pin.AvUnary.op) {
case Pav_MOV: opc2 = 1156; break; // vor vD,vS,vS
case Pav_NOT: opc2 = 1284; break; // vnor vD,vS,vS
case Pav_UNPCKH8S: opc2 = 526; break; // vupkhsb
case Pav_UNPCKH16S: opc2 = 590; break; // vupkhsh
case Pav_UNPCKL8S: opc2 = 654; break; // vupklsb
case Pav_UNPCKL16S: opc2 = 718; break; // vupklsh
case Pav_UNPCKHPIX: opc2 = 846; break; // vupkhpx
case Pav_UNPCKLPIX: opc2 = 974; break; // vupklpx
case Pav_ZEROCNTBYTE: opc2 = 1794; break; // vclzb
case Pav_ZEROCNTHALF: opc2 = 1858; break; // vclzh
case Pav_ZEROCNTWORD: opc2 = 1922; break; // vclzw
case Pav_ZEROCNTDBL: opc2 = 1986; break; // vclzd
case Pav_TRAILINGZEROCNTBYTE: opc2 = 1538; break; // vctzb
case Pav_TRAILINGZEROCNTHALF: opc2 = 1538; break; // vctzh
case Pav_TRAILINGZEROCNTWORD: opc2 = 1538; break; // vctzw
case Pav_TRAILINGZEROCNTDBL: opc2 = 1538; break; // vctzd
case Pav_BITMTXXPOSE: opc2 = 1292; break; // vgbbd
case Pav_BCD128toI128S: opc2 = 385; break; //bcdctsq.
case Pav_MulI128by10: opc2 = 513; break; // vmul10uq
case Pav_MulI128by10Carry: opc2 = 1; break; // vmul10cuq
case Pav_F16toF64x2: opc2 = 347; opc3 = 16; break; // xvcvhpdp
case Pav_F64toF16x2: opc2 = 347; opc3 = 17; break; // xvcvdphp
case Pav_F16toF32x4: opc2 = 475; opc3 = 24; break; // xvcvhpsp
case Pav_F32toF16x4: opc2 = 475; opc3 = 25; break; // xvcvsphp
default:
goto bad;
}
switch (i->Pin.AvUnary.op) {
case Pav_MOV:
case Pav_NOT:
p = mkFormVX( p, 4, v_dst, v_src, v_src, opc2, endness_host );
break;
case Pav_F16toF32x4:
{
/* I64 source has four 16-bit float values in the upper 64-bit
* of the source vector register, lower 64-bits are undefined.
*/
/* Scatter the four F16 values in the Vector register */
p = mkFormVX( p, 4, v_dst, 0, v_src, 590, endness_host );// vupkhsh
/* The layout of the vector register is now: S0F0 S1F1 S2F2 S3F3
* where S is the sign extension of the 16-bit F value. We don't
* care about the extended signs.
*/
/* Input, in v_dst, is now correct for the xvcvhpsp instruction */
p = mkFormVX_BX_TX( p, 60, v_dst, opc3, v_dst, opc2,
endness_host );
}
break;
case Pav_F64toF16x2:
case Pav_F16toF64x2:
case Pav_F32toF16x4:
/* Note this issues a Vector scalar instruction. The register
* mapping for the V128 type assumes the a vector instruction. The
* PPC hardware has a single register file that the vector scalar
* registers and the vector registers map to. The 32 vector registers
* instructions map to the same registers as the vector scalar
* registers 32 to 63. mkFormVX_BX_TX does the needed adjustment.
*/
p = mkFormVX_BX_TX( p, 60, v_dst, opc3, v_src, opc2, endness_host );
break;
case Pav_BCD128toI128S: // bcdctsq
p = mkFormVX( p, 4, v_dst, 0, v_src, (1<<10 | 385), endness_host );
break;
case Pav_MulI128by10:
case Pav_MulI128by10Carry:
p = mkFormVX( p, 4, v_dst, v_src, 0, opc2, endness_host );
break;
case Pav_TRAILINGZEROCNTBYTE:
p = mkFormVX( p, 4, v_dst, 28, v_src, opc2, endness_host );
break;
case Pav_TRAILINGZEROCNTHALF:
p = mkFormVX( p, 4, v_dst, 29, v_src, opc2, endness_host );
break;
case Pav_TRAILINGZEROCNTWORD:
p = mkFormVX( p, 4, v_dst, 30, v_src, opc2, endness_host );
break;
case Pav_TRAILINGZEROCNTDBL:
p = mkFormVX( p, 4, v_dst, 31, v_src, opc2, endness_host );
break;
default:
p = mkFormVX( p, 4, v_dst, 0, v_src, opc2, endness_host );
break;
}
goto done;
}
case Pin_AvBinary: {
UInt v_dst = vregEnc(i->Pin.AvBinary.dst);
UInt v_srcL = vregEnc(i->Pin.AvBinary.srcL);
UInt v_srcR = vregEnc(i->Pin.AvBinary.srcR);
UInt opc2;
if (i->Pin.AvBinary.op == Pav_SHL) {
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 1036, endness_host ); // vslo
p = mkFormVX( p, 4, v_dst, v_dst, v_srcR, 452, endness_host ); // vsl
goto done;
}
if (i->Pin.AvBinary.op == Pav_SHR) {
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 1100, endness_host ); // vsro
p = mkFormVX( p, 4, v_dst, v_dst, v_srcR, 708, endness_host ); // vsr
goto done;
}
switch (i->Pin.AvBinary.op) {
/* Bitwise */
case Pav_AND: opc2 = 1028; break; // vand
case Pav_OR: opc2 = 1156; break; // vor
case Pav_XOR: opc2 = 1220; break; // vxor
/* Mult by 10 */
case Pav_MulI128by10E: opc2 = 577; break; // vmul10euq
case Pav_MulI128by10ECarry: opc2 = 65; break; // vmul10ecuq
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
goto done;
}
case Pin_AvBinaryInt: {
UInt ps = i->Pin.AvBinaryInt.val->Pri.Imm;
UInt dst = vregEnc(i->Pin.AvBinaryInt.dst);
UInt src = vregEnc(i->Pin.AvBinaryInt.src);
switch (i->Pin.AvBinaryInt.op) {
/* BCD */
case Pav_I128StoBCD128: // bcdcfsq
{
/* v_srcR actually contains the value of the one-bit ps field */
int opc2 = 385;
p = mkFormVX( p, 4, dst, 2, src,
(1 << 10 | (ps << 9) | opc2), endness_host );
}
break;
case Pav_F128toI128S: // xsrqpi, xsrqpix
{
int opc2 = 5;
UInt EX = ps & 0x1;
UInt R = (ps >> 3) & 0x1;
UInt RMC = (ps >> 1) & 0x3;
/* Note this issues a Vector scalar instruction. The register
* mapping for the V128 type assumes the a vector instruction. The
* PPC hardware has a single register file that the vector scalar
* registers and the vector registers map to. The 32 vector
* registers instructions map to the same registers as the vector
* scalar registers 32 to 63. For these instructions the HW adds
* 32 to the register numbers to access the VSRR register. No need
* to adjust the numbers to map to the VR register that contians
* the operands.
*/
p = mkFormVSXRND( p, 63, R, dst, src, RMC, opc2, EX,
endness_host );
}
break;
case Pav_ROUNDFPQ: // xsrqpxp
{
int opc2 = 37;
UInt EX = ps & 0x1;
UInt RMC = (ps >> 1) & 0x3;
UInt R = (ps >> 3) & 0x1;
p = mkFormVSXRND( p, 63, R, dst, src, RMC, opc2, EX,
endness_host );
}
break;
default:
goto bad;
}
goto done;
}
case Pin_AvBin8x16: {
UInt v_dst = vregEnc(i->Pin.AvBin8x16.dst);
UInt v_srcL = vregEnc(i->Pin.AvBin8x16.srcL);
UInt v_srcR = vregEnc(i->Pin.AvBin8x16.srcR);
UInt opc2;
switch (i->Pin.AvBin8x16.op) {
case Pav_ADDU: opc2 = 0; break; // vaddubm
case Pav_QADDU: opc2 = 512; break; // vaddubs
case Pav_QADDS: opc2 = 768; break; // vaddsbs
case Pav_SUBU: opc2 = 1024; break; // vsububm
case Pav_QSUBU: opc2 = 1536; break; // vsububs
case Pav_QSUBS: opc2 = 1792; break; // vsubsbs
case Pav_OMULU: opc2 = 8; break; // vmuloub
case Pav_OMULS: opc2 = 264; break; // vmulosb
case Pav_EMULU: opc2 = 520; break; // vmuleub
case Pav_EMULS: opc2 = 776; break; // vmulesb
case Pav_AVGU: opc2 = 1026; break; // vavgub
case Pav_AVGS: opc2 = 1282; break; // vavgsb
case Pav_MAXU: opc2 = 2; break; // vmaxub
case Pav_MAXS: opc2 = 258; break; // vmaxsb
case Pav_MINU: opc2 = 514; break; // vminub
case Pav_MINS: opc2 = 770; break; // vminsb
case Pav_CMPEQU: opc2 = 6; break; // vcmpequb
case Pav_CMPGTU: opc2 = 518; break; // vcmpgtub
case Pav_CMPGTS: opc2 = 774; break; // vcmpgtsb
case Pav_SHL: opc2 = 260; break; // vslb
case Pav_SHR: opc2 = 516; break; // vsrb
case Pav_SAR: opc2 = 772; break; // vsrab
case Pav_ROTL: opc2 = 4; break; // vrlb
case Pav_MRGHI: opc2 = 12; break; // vmrghb
case Pav_MRGLO: opc2 = 268; break; // vmrglb
case Pav_POLYMULADD: opc2 = 1032; break; // vpmsumb
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
goto done;
}
case Pin_AvBin16x8: {
UInt v_dst = vregEnc(i->Pin.AvBin16x8.dst);
UInt v_srcL = vregEnc(i->Pin.AvBin16x8.srcL);
UInt v_srcR = vregEnc(i->Pin.AvBin16x8.srcR);
UInt opc2;
switch (i->Pin.AvBin16x8.op) {
case Pav_ADDU: opc2 = 64; break; // vadduhm
case Pav_QADDU: opc2 = 576; break; // vadduhs
case Pav_QADDS: opc2 = 832; break; // vaddshs
case Pav_SUBU: opc2 = 1088; break; // vsubuhm
case Pav_QSUBU: opc2 = 1600; break; // vsubuhs
case Pav_QSUBS: opc2 = 1856; break; // vsubshs
case Pav_OMULU: opc2 = 72; break; // vmulouh
case Pav_OMULS: opc2 = 328; break; // vmulosh
case Pav_EMULU: opc2 = 584; break; // vmuleuh
case Pav_EMULS: opc2 = 840; break; // vmulesh
case Pav_AVGU: opc2 = 1090; break; // vavguh
case Pav_AVGS: opc2 = 1346; break; // vavgsh
case Pav_MAXU: opc2 = 66; break; // vmaxuh
case Pav_MAXS: opc2 = 322; break; // vmaxsh
case Pav_MINS: opc2 = 834; break; // vminsh
case Pav_MINU: opc2 = 578; break; // vminuh
case Pav_CMPEQU: opc2 = 70; break; // vcmpequh
case Pav_CMPGTU: opc2 = 582; break; // vcmpgtuh
case Pav_CMPGTS: opc2 = 838; break; // vcmpgtsh
case Pav_SHL: opc2 = 324; break; // vslh
case Pav_SHR: opc2 = 580; break; // vsrh
case Pav_SAR: opc2 = 836; break; // vsrah
case Pav_ROTL: opc2 = 68; break; // vrlh
case Pav_PACKUU: opc2 = 14; break; // vpkuhum
case Pav_QPACKUU: opc2 = 142; break; // vpkuhus
case Pav_QPACKSU: opc2 = 270; break; // vpkshus
case Pav_QPACKSS: opc2 = 398; break; // vpkshss
case Pav_PACKPXL: opc2 = 782; break; // vpkpx
case Pav_MRGHI: opc2 = 76; break; // vmrghh
case Pav_MRGLO: opc2 = 332; break; // vmrglh
case Pav_POLYMULADD: opc2 = 1224; break; // vpmsumh
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
goto done;
}
case Pin_AvBin32x4: {
UInt v_dst = vregEnc(i->Pin.AvBin32x4.dst);
UInt v_srcL = vregEnc(i->Pin.AvBin32x4.srcL);
UInt v_srcR = vregEnc(i->Pin.AvBin32x4.srcR);
UInt opc2;
switch (i->Pin.AvBin32x4.op) {
case Pav_ADDU: opc2 = 128; break; // vadduwm
case Pav_QADDU: opc2 = 640; break; // vadduws
case Pav_QADDS: opc2 = 896; break; // vaddsws
case Pav_SUBU: opc2 = 1152; break; // vsubuwm
case Pav_QSUBU: opc2 = 1664; break; // vsubuws
case Pav_QSUBS: opc2 = 1920; break; // vsubsws
case Pav_MULU: opc2 = 137; break; // vmuluwm
case Pav_OMULU: opc2 = 136; break; // vmulouw
case Pav_OMULS: opc2 = 392; break; // vmulosw
case Pav_EMULU: opc2 = 648; break; // vmuleuw
case Pav_EMULS: opc2 = 904; break; // vmulesw
case Pav_AVGU: opc2 = 1154; break; // vavguw
case Pav_AVGS: opc2 = 1410; break; // vavgsw
case Pav_MAXU: opc2 = 130; break; // vmaxuw
case Pav_MAXS: opc2 = 386; break; // vmaxsw
case Pav_MINS: opc2 = 898; break; // vminsw
case Pav_MINU: opc2 = 642; break; // vminuw
case Pav_CMPEQU: opc2 = 134; break; // vcmpequw
case Pav_CMPGTS: opc2 = 902; break; // vcmpgtsw
case Pav_CMPGTU: opc2 = 646; break; // vcmpgtuw
case Pav_SHL: opc2 = 388; break; // vslw
case Pav_SHR: opc2 = 644; break; // vsrw
case Pav_SAR: opc2 = 900; break; // vsraw
case Pav_ROTL: opc2 = 132; break; // vrlw
case Pav_PACKUU: opc2 = 78; break; // vpkuwum
case Pav_QPACKUU: opc2 = 206; break; // vpkuwus
case Pav_QPACKSU: opc2 = 334; break; // vpkswus
case Pav_QPACKSS: opc2 = 462; break; // vpkswss
case Pav_MRGHI: opc2 = 140; break; // vmrghw
case Pav_MRGLO: opc2 = 396; break; // vmrglw
case Pav_CATODD: opc2 = 1676; break; // vmrgow
case Pav_CATEVEN: opc2 = 1932; break; // vmrgew
case Pav_POLYMULADD: opc2 = 1160; break; // vpmsumw
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
goto done;
}
case Pin_AvBin64x2: {
UInt v_dst = vregEnc(i->Pin.AvBin64x2.dst);
UInt v_srcL = vregEnc(i->Pin.AvBin64x2.srcL);
UInt v_srcR = vregEnc(i->Pin.AvBin64x2.srcR);
UInt opc2;
switch (i->Pin.AvBin64x2.op) {
case Pav_ADDU: opc2 = 192; break; // vaddudm vector double add
case Pav_SUBU: opc2 = 1216; break; // vsubudm vector double add
case Pav_MAXU: opc2 = 194; break; // vmaxud vector double max
case Pav_MAXS: opc2 = 450; break; // vmaxsd vector double max
case Pav_MINU: opc2 = 706; break; // vminud vector double min
case Pav_MINS: opc2 = 962; break; // vminsd vector double min
case Pav_CMPEQU: opc2 = 199; break; // vcmpequd vector double compare
case Pav_CMPGTU: opc2 = 711; break; // vcmpgtud vector double compare
case Pav_CMPGTS: opc2 = 967; break; // vcmpgtsd vector double compare
case Pav_SHL: opc2 = 1476; break; // vsld
case Pav_SHR: opc2 = 1732; break; // vsrd
case Pav_SAR: opc2 = 964; break; // vsrad
case Pav_ROTL: opc2 = 196; break; // vrld
case Pav_PACKUU: opc2 = 1102; break; // vpkudum
case Pav_QPACKUU: opc2 = 1230; break; // vpkudus, vpksdus (emulated)
case Pav_QPACKSS: opc2 = 1486; break; // vpksdsm
case Pav_MRGHI: opc2 = 1614; break; // vmrghw
case Pav_MRGLO: opc2 = 1742; break; // vmrglw
case Pav_POLYMULADD: opc2 = 1096; break; // vpmsumd
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
goto done;
}
case Pin_AvCipherV128Unary: {
UInt v_dst = vregEnc(i->Pin.AvCipherV128Unary.dst);
UInt v_src = vregEnc(i->Pin.AvCipherV128Unary.src);
UInt opc2;
switch (i->Pin.AvCipherV128Unary.op) {
case Pav_CIPHERSUBV128: opc2 = 1480; break; // vsbox
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, v_src, 0, opc2, endness_host );
goto done;
}
case Pin_AvCipherV128Binary: {
UInt v_dst = vregEnc(i->Pin.AvCipherV128Binary.dst);
UInt v_srcL = vregEnc(i->Pin.AvCipherV128Binary.srcL);
UInt v_srcR = vregEnc(i->Pin.AvCipherV128Binary.srcR);
UInt opc2;
switch (i->Pin.AvCipherV128Binary.op) {
case Pav_CIPHERV128: opc2 = 1288; break; // vcipher
case Pav_CIPHERLV128: opc2 = 1289; break; // vcipherlast
case Pav_NCIPHERV128: opc2 = 1352; break; // vncipher
case Pav_NCIPHERLV128: opc2 = 1353; break; // vncipherlast
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
goto done;
}
case Pin_AvHashV128Binary: {
UInt v_dst = vregEnc(i->Pin.AvHashV128Binary.dst);
UInt v_src = vregEnc(i->Pin.AvHashV128Binary.src);
PPCRI* s_field = i->Pin.AvHashV128Binary.s_field;
UInt opc2;
switch (i->Pin.AvHashV128Binary.op) {
case Pav_SHA256: opc2 = 1666; break; // vshasigmaw
case Pav_SHA512: opc2 = 1730; break; // vshasigmad
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, v_src, s_field->Pri.Imm, opc2, endness_host );
goto done;
}
case Pin_AvBCDV128Binary: {
UInt v_dst = vregEnc(i->Pin.AvBCDV128Binary.dst);
UInt v_src1 = vregEnc(i->Pin.AvBCDV128Binary.src1);
UInt v_src2 = vregEnc(i->Pin.AvBCDV128Binary.src2);
UInt ps = 0; /* Issue the instruction with ps=0. The IR code will
* fix up the result if ps=1.
*/
UInt opc2;
switch (i->Pin.AvBCDV128Binary.op) {
case Pav_BCDAdd: opc2 = 1; break; // bcdadd
case Pav_BCDSub: opc2 = 65; break; // bcdsub
default:
goto bad;
}
p = mkFormVXR( p, 4, v_dst, v_src1, v_src2,
0x1, ps | opc2, endness_host );
goto done;
}
case Pin_AvBin32Fx4: {
UInt v_dst = vregEnc(i->Pin.AvBin32Fx4.dst);
UInt v_srcL = vregEnc(i->Pin.AvBin32Fx4.srcL);
UInt v_srcR = vregEnc(i->Pin.AvBin32Fx4.srcR);
switch (i->Pin.AvBin32Fx4.op) {
case Pavfp_ADDF:
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 10, endness_host ); // vaddfp
break;
case Pavfp_SUBF:
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 74, endness_host ); // vsubfp
break;
case Pavfp_MAXF:
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 1034, endness_host ); // vmaxfp
break;
case Pavfp_MINF:
p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 1098, endness_host ); // vminfp
break;
case Pavfp_MULF: {
/* Make a vmulfp from a vmaddfp:
load -0.0 (0x8000_0000) to each 32-bit word of vB
this makes the add a noop.
*/
UInt vB = 29; // XXX: Using v29 for temp do not change
// without also changing
// getRegUsage_PPCInstr
UInt konst = 0x1F;
// Better way to load -0.0 (0x80000000) ?
// vspltisw vB,0x1F (0x1F => each word of vB)
p = mkFormVX( p, 4, vB, konst, 0, 908, endness_host );
// vslw vB,vB,vB (each word of vB = (0x1F << 0x1F) = 0x80000000
p = mkFormVX( p, 4, vB, vB, vB, 388, endness_host );
// Finally, do the multiply:
p = mkFormVA( p, 4, v_dst, v_srcL, vB, v_srcR, 46, endness_host );
break;
}
case Pavfp_CMPEQF: // vcmpeqfp
p = mkFormVXR( p, 4, v_dst, v_srcL, v_srcR, 0, 198, endness_host);
break;
case Pavfp_CMPGTF: // vcmpgtfp
p = mkFormVXR( p, 4, v_dst, v_srcL, v_srcR, 0, 710, endness_host );
break;
case Pavfp_CMPGEF: // vcmpgefp
p = mkFormVXR( p, 4, v_dst, v_srcL, v_srcR, 0, 454, endness_host );
break;
default:
goto bad;
}
goto done;
}
case Pin_AvUn32Fx4: {
UInt v_dst = vregEnc(i->Pin.AvUn32Fx4.dst);
UInt v_src = vregEnc(i->Pin.AvUn32Fx4.src);
UInt opc2;
switch (i->Pin.AvUn32Fx4.op) {
case Pavfp_RCPF: opc2 = 266; break; // vrefp
case Pavfp_RSQRTF: opc2 = 330; break; // vrsqrtefp
case Pavfp_CVTU2F: opc2 = 778; break; // vcfux
case Pavfp_CVTS2F: opc2 = 842; break; // vcfsx
case Pavfp_QCVTF2U: opc2 = 906; break; // vctuxs
case Pavfp_QCVTF2S: opc2 = 970; break; // vctsxs
case Pavfp_ROUNDM: opc2 = 714; break; // vrfim
case Pavfp_ROUNDP: opc2 = 650; break; // vrfip
case Pavfp_ROUNDN: opc2 = 522; break; // vrfin
case Pavfp_ROUNDZ: opc2 = 586; break; // vrfiz
default:
goto bad;
}
p = mkFormVX( p, 4, v_dst, 0, v_src, opc2, endness_host );
goto done;
}
case Pin_AvPerm: { // vperm
UInt v_dst = vregEnc(i->Pin.AvPerm.dst);
UInt v_srcL = vregEnc(i->Pin.AvPerm.srcL);
UInt v_srcR = vregEnc(i->Pin.AvPerm.srcR);
UInt v_ctl = vregEnc(i->Pin.AvPerm.ctl);
p = mkFormVA( p, 4, v_dst, v_srcL, v_srcR, v_ctl, 43, endness_host );
goto done;
}
case Pin_AvSel: { // vsel
UInt v_ctl = vregEnc(i->Pin.AvSel.ctl);
UInt v_dst = vregEnc(i->Pin.AvSel.dst);
UInt v_srcL = vregEnc(i->Pin.AvSel.srcL);
UInt v_srcR = vregEnc(i->Pin.AvSel.srcR);
p = mkFormVA( p, 4, v_dst, v_srcL, v_srcR, v_ctl, 42, endness_host );
goto done;
}
case Pin_AvSh: { // vsl or vsr
UInt v_dst = vregEnc(i->Pin.AvSh.dst);
Bool idxd = toBool(i->Pin.AvSh.addr->tag == Pam_RR);
UInt r_idx, r_base;
r_base = iregEnc(i->Pin.AvSh.addr->Pam.RR.base, mode64);
if (!idxd) {
r_idx = 30; // XXX: Using r30 as temp
p = mkLoadImm(p, r_idx,
i->Pin.AvSh.addr->Pam.IR.index, mode64, endness_host);
} else {
r_idx = iregEnc(i->Pin.AvSh.addr->Pam.RR.index, mode64);
}
if (i->Pin.AvSh.shLeft)
//vsl VRT,RA,RB
p = mkFormVXI( p, 31, v_dst, r_idx, r_base, 6, endness_host );
else
//vsr VRT,RA,RB
p = mkFormVXI( p, 31, v_dst, r_idx, r_base, 38, endness_host );
goto done;
}
case Pin_AvShlDbl: { // vsldoi
UInt shift = i->Pin.AvShlDbl.shift;
UInt v_dst = vregEnc(i->Pin.AvShlDbl.dst);
UInt v_srcL = vregEnc(i->Pin.AvShlDbl.srcL);
UInt v_srcR = vregEnc(i->Pin.AvShlDbl.srcR);
vassert(shift <= 0xF);
p = mkFormVA( p, 4, v_dst, v_srcL, v_srcR, shift, 44, endness_host );
goto done;
}
case Pin_AvSplat: { // vsplt(is)(b,h,w)
UInt v_dst = vregEnc(i->Pin.AvShlDbl.dst);
UChar sz = i->Pin.AvSplat.sz;
UInt v_src, opc2;
vassert(sz == 8 || sz == 16 || sz == 32);
if (i->Pin.AvSplat.src->tag == Pvi_Imm) {
Char simm5;
opc2 = (sz == 8) ? 780 : (sz == 16) ? 844 : 908; // 8,16,32
/* expects 5-bit-signed-imm */
simm5 = i->Pin.AvSplat.src->Pvi.Imm5s;
vassert(simm5 >= -16 && simm5 <= 15);
simm5 = simm5 & 0x1F;
p = mkFormVX( p, 4, v_dst, (UInt)simm5, 0, opc2, endness_host );
}
else { // Pri_Reg
UInt lowest_lane;
opc2 = (sz == 8) ? 524 : (sz == 16) ? 588 : 652; // 8,16,32
vassert(hregClass(i->Pin.AvSplat.src->Pvi.Reg) == HRcVec128);
v_src = vregEnc(i->Pin.AvSplat.src->Pvi.Reg);
lowest_lane = (128/sz)-1;
p = mkFormVX( p, 4, v_dst, lowest_lane, v_src, opc2, endness_host );
}
goto done;
}
case Pin_AvCMov: {
UInt v_dst = vregEnc(i->Pin.AvCMov.dst);
UInt v_src = vregEnc(i->Pin.AvCMov.src);
PPCCondCode cc = i->Pin.AvCMov.cond;
if (v_dst == v_src) goto done;
vassert(cc.test != Pct_ALWAYS);
/* jmp fwds 2 insns if !condition */
if (cc.test != Pct_ALWAYS) {
/* bc !ct,cf,n_bytes>>2 */
p = mkFormB(p, invertCondTest(cc.test), cc.flag, 8>>2, 0, 0,
endness_host);
}
/* vmr */
p = mkFormVX( p, 4, v_dst, v_src, v_src, 1156, endness_host );
goto done;
}
case Pin_AvLdVSCR: { // mtvscr
UInt v_src = vregEnc(i->Pin.AvLdVSCR.src);
p = mkFormVX( p, 4, 0, 0, v_src, 1604, endness_host );
goto done;
}
case Pin_Dfp64Unary: {
UInt fr_dst = fregEnc( i->Pin.FpUnary.dst );
UInt fr_src = fregEnc( i->Pin.FpUnary.src );
switch (i->Pin.Dfp64Unary.op) {
case Pfp_MOV: // fmr, PPC32 p410
p = mkFormX( p, 63, fr_dst, 0, fr_src, 72, 0, endness_host );
break;
case Pfp_DCTDP: // D32 to D64
p = mkFormX( p, 59, fr_dst, 0, fr_src, 258, 0, endness_host );
break;
case Pfp_DRSP: // D64 to D32
p = mkFormX( p, 59, fr_dst, 0, fr_src, 770, 0, endness_host );
break;
case Pfp_DCFFIX: // I64 to D64 conversion
/* ONLY WORKS ON POWER7 */
p = mkFormX( p, 59, fr_dst, 0, fr_src, 802, 0, endness_host );
break;
case Pfp_DCTFIX: // D64 to I64 conversion
p = mkFormX( p, 59, fr_dst, 0, fr_src, 290, 0, endness_host );
break;
case Pfp_DXEX: // Extract exponent
p = mkFormX( p, 59, fr_dst, 0, fr_src, 354, 0, endness_host );
break;
default:
goto bad;
}
goto done;
}
case Pin_Dfp64Binary: {
UInt fr_dst = fregEnc( i->Pin.Dfp64Binary.dst );
UInt fr_srcL = fregEnc( i->Pin.Dfp64Binary.srcL );
UInt fr_srcR = fregEnc( i->Pin.Dfp64Binary.srcR );
switch (i->Pin.Dfp64Binary.op) {
case Pfp_DFPADD: /* dadd, dfp add, use default RM from reg ignore mode
* from the Iop instruction. */
p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 2, 0, endness_host );
break;
case Pfp_DFPSUB: /* dsub, dfp subtract, use default RM from reg ignore
* mode from the Iop instruction. */
p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 514, 0, endness_host );
break;
case Pfp_DFPMUL: /* dmul, dfp multipy, use default RM from reg ignore
* mode from the Iop instruction. */
p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 34, 0, endness_host );
break;
case Pfp_DFPDIV: /* ddiv, dfp divide, use default RM from reg ignore
* mode from the Iop instruction. */
p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 546, 0, endness_host );
break;
case Pfp_DIEX: /* diex, insert exponent */
p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 866, 0, endness_host );
break;
default:
goto bad;
}
goto done;
}
case Pin_DfpShift: {
UInt fr_src = fregEnc(i->Pin.DfpShift.src);
UInt fr_dst = fregEnc(i->Pin.DfpShift.dst);
UInt shift;
shift = i->Pin.DfpShift.shift->Pri.Imm;
switch (i->Pin.DfpShift.op) {
case Pfp_DSCLI: /* dscli, DFP shift left by fr_srcR */
p = mkFormZ22( p, 59, fr_dst, fr_src, shift, 66, 0, endness_host );
break;
case Pfp_DSCRI: /* dscri, DFP shift right by fr_srcR */
p = mkFormZ22( p, 59, fr_dst, fr_src, shift, 98, 0, endness_host );
break;
default:
vex_printf("ERROR: emit_PPCInstr default case\n");
goto bad;
}
goto done;
}
case Pin_ExtractExpD128: {
UInt fr_dst = fregEnc(i->Pin.ExtractExpD128.dst);
UInt fr_srcHi = fregEnc(i->Pin.ExtractExpD128.src_hi);
UInt fr_srcLo = fregEnc(i->Pin.ExtractExpD128.src_lo);
switch (i->Pin.ExtractExpD128.op) {
case Pfp_DXEXQ:
/* Setup the upper and lower registers of the source operand
* register pair.
*/
p = mkFormX( p, 63, 12, 0, fr_srcHi, 72, 0, endness_host );
p = mkFormX( p, 63, 13, 0, fr_srcLo, 72, 0, endness_host );
p = mkFormX( p, 63, 10, 0, 12, 354, 0, endness_host );
/* The instruction will put the 64-bit result in
* register 10.
*/
p = mkFormX(p, 63, fr_dst, 0, 10, 72, 0, endness_host);
break;
default:
vex_printf("Error: emit_PPCInstr case Pin_DfpExtractExp, case inst Default\n");
goto bad;
}
goto done;
}
case Pin_Dfp128Unary: {
UInt fr_dstHi = fregEnc(i->Pin.Dfp128Unary.dst_hi);
UInt fr_dstLo = fregEnc(i->Pin.Dfp128Unary.dst_lo);
UInt fr_srcLo = fregEnc(i->Pin.Dfp128Unary.src_lo);
/* Do instruction with 128-bit source operands in registers (10,11)
* and (12,13).
*/
switch (i->Pin.Dfp128Unary.op) {
case Pfp_DCTQPQ: // D64 to D128, srcLo holds 64 bit operand
p = mkFormX( p, 63, 12, 0, fr_srcLo, 72, 0, endness_host );
p = mkFormX( p, 63, 10, 0, 12, 258, 0, endness_host );
/* The instruction will put the 128-bit result in
* registers (10,11). Note, the operand in the instruction only
* reference the first of the two registers in the pair.
*/
p = mkFormX(p, 63, fr_dstHi, 0, 10, 72, 0, endness_host);
p = mkFormX(p, 63, fr_dstLo, 0, 11, 72, 0, endness_host);
break;
default:
vex_printf("Error: emit_PPCInstr case Pin_Dfp128Unary, case inst Default\
\n");
goto bad;
}
goto done;
}
case Pin_Dfp128Binary: {
/* dst is used to supply the left source operand and return
* the result.
*/
UInt fr_dstHi = fregEnc( i->Pin.Dfp128Binary.dst_hi );
UInt fr_dstLo = fregEnc( i->Pin.Dfp128Binary.dst_lo );
UInt fr_srcRHi = fregEnc( i->Pin.Dfp128Binary.srcR_hi );
UInt fr_srcRLo = fregEnc( i->Pin.Dfp128Binary.srcR_lo );
/* Setup the upper and lower registers of the source operand
* register pair.
*/
p = mkFormX( p, 63, 10, 0, fr_dstHi, 72, 0, endness_host );
p = mkFormX( p, 63, 11, 0, fr_dstLo, 72, 0, endness_host );
p = mkFormX( p, 63, 12, 0, fr_srcRHi, 72, 0, endness_host );
p = mkFormX( p, 63, 13, 0, fr_srcRLo, 72, 0, endness_host );
/* Do instruction with 128-bit source operands in registers (10,11)
* and (12,13).
*/
switch (i->Pin.Dfp128Binary.op) {
case Pfp_DFPADDQ:
p = mkFormX( p, 63, 10, 10, 12, 2, 0, endness_host );
break;
case Pfp_DFPSUBQ:
p = mkFormX( p, 63, 10, 10, 12, 514, 0, endness_host );
break;
case Pfp_DFPMULQ:
p = mkFormX( p, 63, 10, 10, 12, 34, 0, endness_host );
break;
case Pfp_DFPDIVQ:
p = mkFormX( p, 63, 10, 10, 12, 546, 0, endness_host );
break;
default:
goto bad;
}
/* The instruction will put the 128-bit result in
* registers (10,11). Note, the operand in the instruction only
* reference the first of the two registers in the pair.
*/
p = mkFormX(p, 63, fr_dstHi, 0, 10, 72, 0, endness_host);
p = mkFormX(p, 63, fr_dstLo, 0, 11, 72, 0, endness_host);
goto done;
}
case Pin_DfpShift128: {
UInt fr_src_hi = fregEnc(i->Pin.DfpShift128.src_hi);
UInt fr_src_lo = fregEnc(i->Pin.DfpShift128.src_lo);
UInt fr_dst_hi = fregEnc(i->Pin.DfpShift128.dst_hi);
UInt fr_dst_lo = fregEnc(i->Pin.DfpShift128.dst_lo);
UInt shift;
shift = i->Pin.DfpShift128.shift->Pri.Imm;
/* setup source operand in register 12, 13 pair */
p = mkFormX(p, 63, 12, 0, fr_src_hi, 72, 0, endness_host);
p = mkFormX(p, 63, 13, 0, fr_src_lo, 72, 0, endness_host);
/* execute instruction putting result in register 10, 11 pair */
switch (i->Pin.DfpShift128.op) {
case Pfp_DSCLIQ: /* dscliq, DFP shift left, fr_srcR is the integer
* shift amount.
*/
p = mkFormZ22( p, 63, 10, 12, shift, 66, 0, endness_host );
break;
case Pfp_DSCRIQ: /* dscriq, DFP shift right, fr_srcR is the integer
* shift amount.
*/
p = mkFormZ22( p, 63, 10, 12, shift, 98, 0, endness_host );
break;
default:
vex_printf("ERROR: emit_PPCInstr quad default case %d \n",
(Int)i->Pin.DfpShift128.op);
goto bad;
}
/* The instruction put the 128-bit result in registers (10,11).
* Note, the operand in the instruction only reference the first of
* the two registers in the pair.
*/
p = mkFormX(p, 63, fr_dst_hi, 0, 10, 72, 0, endness_host);
p = mkFormX(p, 63, fr_dst_lo, 0, 11, 72, 0, endness_host);
goto done;
}
case Pin_DfpRound: {
UInt fr_dst = fregEnc(i->Pin.DfpRound.dst);
UInt fr_src = fregEnc(i->Pin.DfpRound.src);
UInt r_rmc, r, rmc;
r_rmc = i->Pin.DfpRound.r_rmc->Pri.Imm;
r = (r_rmc & 0x8) >> 3;
rmc = r_rmc & 0x3;
// drintx
p = mkFormZ23(p, 59, fr_dst, r, fr_src, rmc, 99, 0, endness_host);
goto done;
}
case Pin_DfpRound128: {
UInt fr_dstHi = fregEnc(i->Pin.DfpRound128.dst_hi);
UInt fr_dstLo = fregEnc(i->Pin.DfpRound128.dst_lo);
UInt fr_srcHi = fregEnc(i->Pin.DfpRound128.src_hi);
UInt fr_srcLo = fregEnc(i->Pin.DfpRound128.src_lo);
UInt r_rmc, r, rmc;
r_rmc = i->Pin.DfpRound128.r_rmc->Pri.Imm;
r = (r_rmc & 0x8) >> 3;
rmc = r_rmc & 0x3;
/* Setup the upper and lower registers of the source operand
* register pair.
*/
p = mkFormX(p, 63, 12, 0, fr_srcHi, 72, 0, endness_host);
p = mkFormX(p, 63, 13, 0, fr_srcLo, 72, 0, endness_host);
/* Do drintx instruction with 128-bit source operands in
* registers (12,13).
*/
p = mkFormZ23(p, 63, 10, r, 12, rmc, 99, 0, endness_host);
/* The instruction will put the 128-bit result in
* registers (10,11). Note, the operand in the instruction only
* reference the first of the two registers in the pair.
*/
p = mkFormX(p, 63, fr_dstHi, 0, 10, 72, 0, endness_host);
p = mkFormX(p, 63, fr_dstLo, 0, 11, 72, 0, endness_host);
goto done;
}
case Pin_DfpQuantize: {
UInt fr_dst = fregEnc(i->Pin.DfpQuantize.dst);
UInt fr_srcL = fregEnc(i->Pin.DfpQuantize.srcL);
UInt fr_srcR = fregEnc(i->Pin.DfpQuantize.srcR);
UInt rmc;
rmc = i->Pin.DfpQuantize.rmc->Pri.Imm;
switch (i->Pin.DfpQuantize.op) {
case Pfp_DQUA:
p = mkFormZ23(p, 59, fr_dst, fr_srcL, fr_srcR, rmc, 3, 0, endness_host);
break;
case Pfp_RRDTR:
p = mkFormZ23(p, 59, fr_dst, fr_srcL, fr_srcR, rmc, 35, 0, endness_host);
break;
default:
break;
}
goto done;
}
case Pin_DfpQuantize128: {
UInt fr_dst_hi = fregEnc(i->Pin.DfpQuantize128.dst_hi);
UInt fr_dst_lo = fregEnc(i->Pin.DfpQuantize128.dst_lo);
UInt fr_src_hi = fregEnc(i->Pin.DfpQuantize128.src_hi);
UInt fr_src_lo = fregEnc(i->Pin.DfpQuantize128.src_lo);
UInt rmc;
rmc = i->Pin.DfpQuantize128.rmc->Pri.Imm;
/* Setup the upper and lower registers of the source operand
* register pairs. Note, left source operand passed in via the
* dst register pair.
*/
p = mkFormX(p, 63, 10, 0, fr_dst_hi, 72, 0, endness_host);
p = mkFormX(p, 63, 11, 0, fr_dst_lo, 72, 0, endness_host);
p = mkFormX(p, 63, 12, 0, fr_src_hi, 72, 0, endness_host);
p = mkFormX(p, 63, 13, 0, fr_src_lo, 72, 0, endness_host);
/* Do dquaq instruction with 128-bit source operands in
* registers (12,13).
*/
switch (i->Pin.DfpQuantize128.op) {
case Pfp_DQUAQ:
p = mkFormZ23(p, 63, 10, 10, 12, rmc, 3, 0, endness_host);
break;
case Pfp_DRRNDQ:
p = mkFormZ23(p, 63, 10, 10, 12, rmc, 35, 0, endness_host);
break;
default:
vpanic("Pin_DfpQuantize128: default case, couldn't find inst to issue \n");
break;
}
/* The instruction will put the 128-bit result in
* registers (10,11). Note, the operand in the instruction only
* reference the first of the two registers in the pair.
*/
p = mkFormX(p, 63, fr_dst_hi, 0, 10, 72, 0, endness_host);
p = mkFormX(p, 63, fr_dst_lo, 0, 11, 72, 0, endness_host);
goto done;
}
case Pin_DfpD128toD64: {
UInt fr_dst = fregEnc( i->Pin.DfpD128toD64.dst );
UInt fr_srcHi = fregEnc( i->Pin.DfpD128toD64.src_hi );
UInt fr_srcLo = fregEnc( i->Pin.DfpD128toD64.src_lo );
/* Setup the upper and lower registers of the source operand
* register pair.
*/
p = mkFormX( p, 63, 10, 0, fr_dst, 72, 0, endness_host );
p = mkFormX( p, 63, 12, 0, fr_srcHi, 72, 0, endness_host );
p = mkFormX( p, 63, 13, 0, fr_srcLo, 72, 0, endness_host );
/* Do instruction with 128-bit source operands in registers (10,11) */
switch (i->Pin.Dfp128Binary.op) {
case Pfp_DRDPQ:
p = mkFormX( p, 63, 10, 0, 12, 770, 0, endness_host );
break;
case Pfp_DCTFIXQ:
p = mkFormX( p, 63, 10, 0, 12, 290, 0, endness_host );
break;
default:
goto bad;
}
/* The instruction will put the 64-bit result in registers 10. */
p = mkFormX(p, 63, fr_dst, 0, 10, 72, 0, endness_host);
goto done;
}
case Pin_DfpI64StoD128: {
UInt fr_dstHi = fregEnc( i->Pin.DfpI64StoD128.dst_hi );
UInt fr_dstLo = fregEnc( i->Pin.DfpI64StoD128.dst_lo );
UInt fr_src = fregEnc( i->Pin.DfpI64StoD128.src );
switch (i->Pin.Dfp128Binary.op) {
case Pfp_DCFFIXQ:
p = mkFormX( p, 63, 10, 11, fr_src, 802, 0, endness_host );
break;
default:
goto bad;
}
/* The instruction will put the 64-bit result in registers 10, 11. */
p = mkFormX(p, 63, fr_dstHi, 0, 10, 72, 0, endness_host);
p = mkFormX(p, 63, fr_dstLo, 0, 11, 72, 0, endness_host);
goto done;
}
case Pin_InsertExpD128: {
UInt fr_dstHi = fregEnc(i->Pin.InsertExpD128.dst_hi);
UInt fr_dstLo = fregEnc(i->Pin.InsertExpD128.dst_lo);
UInt fr_srcL = fregEnc(i->Pin.InsertExpD128.srcL);
UInt fr_srcRHi = fregEnc(i->Pin.InsertExpD128.srcR_hi);
UInt fr_srcRLo = fregEnc(i->Pin.InsertExpD128.srcR_lo);
/* The left operand is a single F64 value, the right is an F128
* register pair.
*/
p = mkFormX(p, 63, 10, 0, fr_srcL, 72, 0, endness_host);
p = mkFormX(p, 63, 12, 0, fr_srcRHi, 72, 0, endness_host);
p = mkFormX(p, 63, 13, 0, fr_srcRLo, 72, 0, endness_host);
p = mkFormX(p, 63, 10, 10, 12, 866, 0, endness_host );
/* The instruction will put the 128-bit result into
* registers (10,11). Note, the operand in the instruction only
* reference the first of the two registers in the pair.
*/
p = mkFormX(p, 63, fr_dstHi, 0, 10, 72, 0, endness_host);
p = mkFormX(p, 63, fr_dstLo, 0, 11, 72, 0, endness_host);
goto done;
}
case Pin_Dfp64Cmp:{
UChar crfD = 1;
UInt r_dst = iregEnc(i->Pin.Dfp64Cmp.dst, mode64);
UInt fr_srcL = fregEnc(i->Pin.Dfp64Cmp.srcL);
UInt fr_srcR = fregEnc(i->Pin.Dfp64Cmp.srcR);
vassert(crfD < 8);
// dcmpo, dcmpu
p = mkFormX(p, 59, crfD<<2, fr_srcL, fr_srcR, 130, 0, endness_host);
// mfcr (mv CR to r_dst)
p = mkFormX(p, 31, r_dst, 0, 0, 19, 0, endness_host);
// rlwinm r_dst,r_dst,8,28,31
// => rotate field 1 to bottomw of word, masking out upper 28
p = mkFormM(p, 21, r_dst, r_dst, 8, 28, 31, 0, endness_host);
goto done;
}
case Pin_Dfp128Cmp: {
UChar crfD = 1;
UInt r_dst = iregEnc(i->Pin.Dfp128Cmp.dst, mode64);
UInt fr_srcL_hi = fregEnc(i->Pin.Dfp128Cmp.srcL_hi);
UInt fr_srcL_lo = fregEnc(i->Pin.Dfp128Cmp.srcL_lo);
UInt fr_srcR_hi = fregEnc(i->Pin.Dfp128Cmp.srcR_hi);
UInt fr_srcR_lo = fregEnc(i->Pin.Dfp128Cmp.srcR_lo);
vassert(crfD < 8);
// dcmpoq, dcmpuq
/* Setup the upper and lower registers of the source operand
* register pair.
*/
p = mkFormX(p, 63, 10, 0, fr_srcL_hi, 72, 0, endness_host);
p = mkFormX(p, 63, 11, 0, fr_srcL_lo, 72, 0, endness_host);
p = mkFormX(p, 63, 12, 0, fr_srcR_hi, 72, 0, endness_host);
p = mkFormX(p, 63, 13, 0, fr_srcR_lo, 72, 0, endness_host);
p = mkFormX(p, 63, crfD<<2, 10, 12, 130, 0, endness_host);
// mfcr (mv CR to r_dst)
p = mkFormX(p, 31, r_dst, 0, 0, 19, 0, endness_host);
// rlwinm r_dst,r_dst,8,28,31
// => rotate field 1 to bottomw of word, masking out upper 28
p = mkFormM(p, 21, r_dst, r_dst, 8, 28, 31, 0, endness_host);
goto done;
}
case Pin_EvCheck: {
/* This requires a 32-bit dec/test in both 32- and 64-bit
modes. */
/* We generate:
lwz r30, amCounter
addic. r30, r30, -1
stw r30, amCounter
bge nofail
lwz/ld r30, amFailAddr
mtctr r30
bctr
nofail:
*/
UChar* p0 = p;
/* lwz r30, amCounter */
p = do_load_or_store_word32(p, True/*isLoad*/, /*r*/30,
i->Pin.EvCheck.amCounter, mode64,
endness_host);
/* addic. r30,r30,-1 */
p = emit32(p, 0x37DEFFFF, endness_host);
/* stw r30, amCounter */
p = do_load_or_store_word32(p, False/*!isLoad*/, /*r*/30,
i->Pin.EvCheck.amCounter, mode64,
endness_host);
/* bge nofail */
p = emit32(p, 0x40800010, endness_host);
/* lwz/ld r30, amFailAddr */
p = do_load_or_store_machine_word(p, True/*isLoad*/, /*r*/30,
i->Pin.EvCheck.amFailAddr, mode64,
endness_host);
/* mtctr r30 */
p = mkFormXFX(p, /*r*/30, 9, 467, endness_host);
/* bctr */
p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 0, endness_host);
/* nofail: */
/* Crosscheck */
vassert(evCheckSzB_PPC() == (UChar*)p - (UChar*)p0);
goto done;
}
case Pin_ProfInc: {
/* We generate:
(ctrP is unknown now, so use 0x65556555(65556555) in the
expectation that a later call to LibVEX_patchProfCtr
will be used to fill in the immediate fields once the
right value is known.)
32-bit:
imm32-exactly r30, 0x65556555
lwz r29, 4(r30)
addic. r29, r29, 1
stw r29, 4(r30)
lwz r29, 0(r30)
addze r29, r29
stw r29, 0(r30)
64-bit:
imm64-exactly r30, 0x6555655565556555
ld r29, 0(r30)
addi r29, r29, 1
std r29, 0(r30)
*/
if (mode64) {
p = mkLoadImm_EXACTLY2or5(
p, /*r*/30, 0x6555655565556555ULL, True/*mode64*/, endness_host);
p = emit32(p, 0xEBBE0000, endness_host);
p = emit32(p, 0x3BBD0001, endness_host);
p = emit32(p, 0xFBBE0000, endness_host);
} else {
p = mkLoadImm_EXACTLY2or5(
p, /*r*/30, 0x65556555ULL, False/*!mode64*/, endness_host);
p = emit32(p, 0x83BE0004, endness_host);
p = emit32(p, 0x37BD0001, endness_host);
p = emit32(p, 0x93BE0004, endness_host);
p = emit32(p, 0x83BE0000, endness_host);
p = emit32(p, 0x7FBD0194, endness_host);
p = emit32(p, 0x93BE0000, endness_host);
}
/* Tell the caller .. */
vassert(!(*is_profInc));
*is_profInc = True;
goto done;
}
default:
goto bad;
}
bad:
vex_printf("\n=> ");
ppPPCInstr(i, mode64);
vpanic("emit_PPCInstr");
/*NOTREACHED*/
done:
vassert(p - &buf[0] <= 64);
return p - &buf[0];
}
/* How big is an event check? See case for Pin_EvCheck in
emit_PPCInstr just above. That crosschecks what this returns, so
we can tell if we're inconsistent. */
Int evCheckSzB_PPC (void)
{
return 28;
}
/* NB: what goes on here has to be very closely coordinated with the
emitInstr case for XDirect, above. */
VexInvalRange chainXDirect_PPC ( VexEndness endness_host,
void* place_to_chain,
const void* disp_cp_chain_me_EXPECTED,
const void* place_to_jump_to,
Bool mode64 )
{
if (mode64) {
vassert((endness_host == VexEndnessBE) ||
(endness_host == VexEndnessLE));
} else {
vassert(endness_host == VexEndnessBE);
}
/* What we're expecting to see is:
imm32/64-fixed r30, disp_cp_chain_me_to_EXPECTED
mtctr r30
bctrl
viz
<8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
7F C9 03 A6
4E 80 04 21
*/
UChar* p = (UChar*)place_to_chain;
vassert(0 == (3 & (HWord)p));
vassert(isLoadImm_EXACTLY2or5(p, /*r*/30,
(Addr)disp_cp_chain_me_EXPECTED,
mode64, endness_host));
vassert(fetch32(p + (mode64 ? 20 : 8) + 0, endness_host) == 0x7FC903A6);
vassert(fetch32(p + (mode64 ? 20 : 8) + 4, endness_host) == 0x4E800421);
/* And what we want to change it to is:
imm32/64-fixed r30, place_to_jump_to
mtctr r30
bctr
viz
<8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
7F C9 03 A6
4E 80 04 20
The replacement has the same length as the original.
*/
p = mkLoadImm_EXACTLY2or5(p, /*r*/30,
(Addr)place_to_jump_to, mode64,
endness_host);
p = emit32(p, 0x7FC903A6, endness_host);
p = emit32(p, 0x4E800420, endness_host);
Int len = p - (UChar*)place_to_chain;
vassert(len == (mode64 ? 28 : 16)); /* stay sane */
VexInvalRange vir = {(HWord)place_to_chain, len};
return vir;
}
/* NB: what goes on here has to be very closely coordinated with the
emitInstr case for XDirect, above. */
VexInvalRange unchainXDirect_PPC ( VexEndness endness_host,
void* place_to_unchain,
const void* place_to_jump_to_EXPECTED,
const void* disp_cp_chain_me,
Bool mode64 )
{
if (mode64) {
vassert((endness_host == VexEndnessBE) ||
(endness_host == VexEndnessLE));
} else {
vassert(endness_host == VexEndnessBE);
}
/* What we're expecting to see is:
imm32/64-fixed r30, place_to_jump_to_EXPECTED
mtctr r30
bctr
viz
<8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
7F C9 03 A6
4E 80 04 20
*/
UChar* p = (UChar*)place_to_unchain;
vassert(0 == (3 & (HWord)p));
vassert(isLoadImm_EXACTLY2or5(p, /*r*/30,
(Addr)place_to_jump_to_EXPECTED,
mode64, endness_host));
vassert(fetch32(p + (mode64 ? 20 : 8) + 0, endness_host) == 0x7FC903A6);
vassert(fetch32(p + (mode64 ? 20 : 8) + 4, endness_host) == 0x4E800420);
/* And what we want to change it to is:
imm32/64-fixed r30, disp_cp_chain_me
mtctr r30
bctrl
viz
<8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
7F C9 03 A6
4E 80 04 21
The replacement has the same length as the original.
*/
p = mkLoadImm_EXACTLY2or5(p, /*r*/30,
(Addr)disp_cp_chain_me, mode64,
endness_host);
p = emit32(p, 0x7FC903A6, endness_host);
p = emit32(p, 0x4E800421, endness_host);
Int len = p - (UChar*)place_to_unchain;
vassert(len == (mode64 ? 28 : 16)); /* stay sane */
VexInvalRange vir = {(HWord)place_to_unchain, len};
return vir;
}
/* Patch the counter address into a profile inc point, as previously
created by the Pin_ProfInc case for emit_PPCInstr. */
VexInvalRange patchProfInc_PPC ( VexEndness endness_host,
void* place_to_patch,
const ULong* location_of_counter,
Bool mode64 )
{
if (mode64) {
vassert((endness_host == VexEndnessBE) ||
(endness_host == VexEndnessLE));
} else {
vassert(endness_host == VexEndnessBE);
}
UChar* p = (UChar*)place_to_patch;
vassert(0 == (3 & (HWord)p));
Int len = 0;
if (mode64) {
vassert(isLoadImm_EXACTLY2or5(p, /*r*/30,
0x6555655565556555ULL, True/*mode64*/,
endness_host));
vassert(fetch32(p + 20, endness_host) == 0xEBBE0000);
vassert(fetch32(p + 24, endness_host) == 0x3BBD0001);
vassert(fetch32(p + 28, endness_host) == 0xFBBE0000);
p = mkLoadImm_EXACTLY2or5(p, /*r*/30,
(Addr)location_of_counter,
True/*mode64*/, endness_host);
len = p - (UChar*)place_to_patch;
vassert(len == 20);
} else {
vassert(isLoadImm_EXACTLY2or5(p, /*r*/30,
0x65556555ULL, False/*!mode64*/,
endness_host));
vassert(fetch32(p + 8, endness_host) == 0x83BE0004);
vassert(fetch32(p + 12, endness_host) == 0x37BD0001);
vassert(fetch32(p + 16, endness_host) == 0x93BE0004);
vassert(fetch32(p + 20, endness_host) == 0x83BE0000);
vassert(fetch32(p + 24, endness_host) == 0x7FBD0194);
vassert(fetch32(p + 28, endness_host) == 0x93BE0000);
p = mkLoadImm_EXACTLY2or5(p, /*r*/30,
(Addr)location_of_counter,
False/*!mode64*/, endness_host);
len = p - (UChar*)place_to_patch;
vassert(len == 8);
}
VexInvalRange vir = {(HWord)place_to_patch, len};
return vir;
}
/*---------------------------------------------------------------*/
/*--- end host_ppc_defs.c ---*/
/*---------------------------------------------------------------*/