blob: 740403efc07c0cd3fc4836aa6a660166e2886092 [file] [log] [blame]
/*---------------------------------------------------------------*/
/*--- begin host_ppc_defs.c ---*/
/*---------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2004-2013 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_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_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
/* 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
/* vector gather (byte-by-byte bit matrix transpose) */
case Pav_BITMTXXPOSE:
return "vgbbd";
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 == 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 == 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_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_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_AvBCDV128Trinary ( PPCAvOp op, HReg dst,
HReg src1, HReg src2, PPCRI* ps ) {
PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
i->tag = Pin_AvBCDV128Trinary;
i->Pin.AvBCDV128Trinary.op = op;
i->Pin.AvBCDV128Trinary.dst = dst;
i->Pin.AvBCDV128Trinary.src1 = src1;
i->Pin.AvBCDV128Trinary.src2 = src2;
i->Pin.AvBCDV128Trinary.ps = ps;
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:
vex_printf("l%carx ", i->Pin.LoadL.sz==4 ? 'w' : 'd');
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:
vex_printf("st%ccx. ", i->Pin.StoreC.sz==4 ? 'w' : 'd');
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_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_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_AvBCDV128Trinary:
vex_printf("%s(w) ", showPPCAvOp(i->Pin.AvBCDV128Trinary.op));
ppHRegPPC(i->Pin.AvBCDV128Trinary.dst);
vex_printf(",");
ppHRegPPC(i->Pin.AvBCDV128Trinary.src1);
vex_printf(",");
ppHRegPPC(i->Pin.AvBCDV128Trinary.src2);
vex_printf(",");
ppPPCRI(i->Pin.AvBCDV128Trinary.ps);
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);