blob: 43101b03177e58ae1d1060d257412e913d2fb16b [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. --------- */
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 = hregNumber(reg);
vassert(r >= 0 && r < 32);
vex_printf("%s", ireg32_names[r]);
return;
case HRcInt32:
r = hregNumber(reg);
vassert(r >= 0 && r < 32);
vex_printf("%s", ireg32_names[r]);
return;
case HRcFlt64:
r = hregNumber(reg);
vassert(r >= 0 && r < 32);
vex_printf("%%fr%d", r);
return;
case HRcVec128:
r = hregNumber(reg);
vassert(r >= 0 && r < 32);
vex_printf("%%v%d", r);
return;
default:
vpanic("ppHRegPPC");
}
}
#define MkHRegGPR(_n, _mode64) \
mkHReg(_n, _mode64 ? HRcInt64 : HRcInt32, False)
HReg hregPPC_GPR0 ( Bool mode64 ) { return MkHRegGPR( 0, mode64); }
HReg hregPPC_GPR1 ( Bool mode64 ) { return MkHRegGPR( 1, mode64); }
HReg hregPPC_GPR2 ( Bool mode64 ) { return MkHRegGPR( 2, mode64); }
HReg hregPPC_GPR3 ( Bool mode64 ) { return MkHRegGPR( 3, mode64); }
HReg hregPPC_GPR4 ( Bool mode64 ) { return MkHRegGPR( 4, mode64); }
HReg hregPPC_GPR5 ( Bool mode64 ) { return MkHRegGPR( 5, mode64); }
HReg hregPPC_GPR6 ( Bool mode64 ) { return MkHRegGPR( 6, mode64); }
HReg hregPPC_GPR7 ( Bool mode64 ) { return MkHRegGPR( 7, mode64); }
HReg hregPPC_GPR8 ( Bool mode64 ) { return MkHRegGPR( 8, mode64); }
HReg hregPPC_GPR9 ( Bool mode64 ) { return MkHRegGPR( 9, mode64); }
HReg hregPPC_GPR10 ( Bool mode64 ) { return MkHRegGPR(10, mode64); }
HReg hregPPC_GPR11 ( Bool mode64 ) { return MkHRegGPR(11, mode64); }
HReg hregPPC_GPR12 ( Bool mode64 ) { return MkHRegGPR(12, mode64); }
HReg hregPPC_GPR13 ( Bool mode64 ) { return MkHRegGPR(13, mode64); }
HReg hregPPC_GPR14 ( Bool mode64 ) { return MkHRegGPR(14, mode64); }
HReg hregPPC_GPR15 ( Bool mode64 ) { return MkHRegGPR(15, mode64); }
HReg hregPPC_GPR16 ( Bool mode64 ) { return MkHRegGPR(16, mode64); }
HReg hregPPC_GPR17 ( Bool mode64 ) { return MkHRegGPR(17, mode64); }
HReg hregPPC_GPR18 ( Bool mode64 ) { return MkHRegGPR(18, mode64); }
HReg hregPPC_GPR19 ( Bool mode64 ) { return MkHRegGPR(19, mode64); }
HReg hregPPC_GPR20 ( Bool mode64 ) { return MkHRegGPR(20, mode64); }
HReg hregPPC_GPR21 ( Bool mode64 ) { return MkHRegGPR(21, mode64); }
HReg hregPPC_GPR22 ( Bool mode64 ) { return MkHRegGPR(22, mode64); }
HReg hregPPC_GPR23 ( Bool mode64 ) { return MkHRegGPR(23, mode64); }
HReg hregPPC_GPR24 ( Bool mode64 ) { return MkHRegGPR(24, mode64); }
HReg hregPPC_GPR25 ( Bool mode64 ) { return MkHRegGPR(25, mode64); }
HReg hregPPC_GPR26 ( Bool mode64 ) { return MkHRegGPR(26, mode64); }
HReg hregPPC_GPR27 ( Bool mode64 ) { return MkHRegGPR(27, mode64); }
HReg hregPPC_GPR28 ( Bool mode64 ) { return MkHRegGPR(28, mode64); }
HReg hregPPC_GPR29 ( Bool mode64 ) { return MkHRegGPR(29, mode64); }
HReg hregPPC_GPR30 ( Bool mode64 ) { return MkHRegGPR(30, mode64); }
HReg hregPPC_GPR31 ( Bool mode64 ) { return MkHRegGPR(31, mode64); }
#undef MK_INT_HREG
HReg hregPPC_FPR0 ( void ) { return mkHReg( 0, HRcFlt64, False); }
HReg hregPPC_FPR1 ( void ) { return mkHReg( 1, HRcFlt64, False); }
HReg hregPPC_FPR2 ( void ) { return mkHReg( 2, HRcFlt64, False); }
HReg hregPPC_FPR3 ( void ) { return mkHReg( 3, HRcFlt64, False); }
HReg hregPPC_FPR4 ( void ) { return mkHReg( 4, HRcFlt64, False); }
HReg hregPPC_FPR5 ( void ) { return mkHReg( 5, HRcFlt64, False); }
HReg hregPPC_FPR6 ( void ) { return mkHReg( 6, HRcFlt64, False); }
HReg hregPPC_FPR7 ( void ) { return mkHReg( 7, HRcFlt64, False); }
HReg hregPPC_FPR8 ( void ) { return mkHReg( 8, HRcFlt64, False); }
HReg hregPPC_FPR9 ( void ) { return mkHReg( 9, HRcFlt64, False); }
HReg hregPPC_FPR10 ( void ) { return mkHReg(10, HRcFlt64, False); }
HReg hregPPC_FPR11 ( void ) { return mkHReg(11, HRcFlt64, False); }
HReg hregPPC_FPR12 ( void ) { return mkHReg(12, HRcFlt64, False); }
HReg hregPPC_FPR13 ( void ) { return mkHReg(13, HRcFlt64, False); }
HReg hregPPC_FPR14 ( void ) { return mkHReg(14, HRcFlt64, False); }
HReg hregPPC_FPR15 ( void ) { return mkHReg(15, HRcFlt64, False); }
HReg hregPPC_FPR16 ( void ) { return mkHReg(16, HRcFlt64, False); }
HReg hregPPC_FPR17 ( void ) { return mkHReg(17, HRcFlt64, False); }
HReg hregPPC_FPR18 ( void ) { return mkHReg(18, HRcFlt64, False); }
HReg hregPPC_FPR19 ( void ) { return mkHReg(19, HRcFlt64, False); }
HReg hregPPC_FPR20 ( void ) { return mkHReg(20, HRcFlt64, False); }
HReg hregPPC_FPR21 ( void ) { return mkHReg(21, HRcFlt64, False); }
HReg hregPPC_FPR22 ( void ) { return mkHReg(22, HRcFlt64, False); }
HReg hregPPC_FPR23 ( void ) { return mkHReg(23, HRcFlt64, False); }
HReg hregPPC_FPR24 ( void ) { return mkHReg(24, HRcFlt64, False); }
HReg hregPPC_FPR25 ( void ) { return mkHReg(25, HRcFlt64, False); }
HReg hregPPC_FPR26 ( void ) { return mkHReg(26, HRcFlt64, False); }
HReg hregPPC_FPR27 ( void ) { return mkHReg(27, HRcFlt64, False); }
HReg hregPPC_FPR28 ( void ) { return mkHReg(28, HRcFlt64, False); }
HReg hregPPC_FPR29 ( void ) { return mkHReg(29, HRcFlt64, False); }
HReg hregPPC_FPR30 ( void ) { return mkHReg(30, HRcFlt64, False); }
HReg hregPPC_FPR31 ( void ) { return mkHReg(31, HRcFlt64, False); }
HReg hregPPC_VR0 ( void ) { return mkHReg( 0, HRcVec128, False); }
HReg hregPPC_VR1 ( void ) { return mkHReg( 1, HRcVec128, False); }
HReg hregPPC_VR2 ( void ) { return mkHReg( 2, HRcVec128, False); }
HReg hregPPC_VR3 ( void ) { return mkHReg( 3, HRcVec128, False); }
HReg hregPPC_VR4 ( void ) { return mkHReg( 4, HRcVec128, False); }
HReg hregPPC_VR5 ( void ) { return mkHReg( 5, HRcVec128, False); }
HReg hregPPC_VR6 ( void ) { return mkHReg( 6, HRcVec128, False); }
HReg hregPPC_VR7 ( void ) { return mkHReg( 7, HRcVec128, False); }
HReg hregPPC_VR8 ( void ) { return mkHReg( 8, HRcVec128, False); }
HReg hregPPC_VR9 ( void ) { return mkHReg( 9, HRcVec128, False); }
HReg hregPPC_VR10 ( void ) { return mkHReg(10, HRcVec128, False); }
HReg hregPPC_VR11 ( void ) { return mkHReg(11, HRcVec128, False); }
HReg hregPPC_VR12 ( void ) { return mkHReg(12, HRcVec128, False); }
HReg hregPPC_VR13 ( void ) { return mkHReg(13, HRcVec128, False); }
HReg hregPPC_VR14 ( void ) { return mkHReg(14, HRcVec128, False); }
HReg hregPPC_VR15 ( void ) { return mkHReg(15, HRcVec128, False); }
HReg hregPPC_VR16 ( void ) { return mkHReg(16, HRcVec128, False); }
HReg hregPPC_VR17 ( void ) { return mkHReg(17, HRcVec128, False); }
HReg hregPPC_VR18 ( void ) { return mkHReg(18, HRcVec128, False); }
HReg hregPPC_VR19 ( void ) { return mkHReg(19, HRcVec128, False); }
HReg hregPPC_VR20 ( void ) { return mkHReg(20, HRcVec128, False); }
HReg hregPPC_VR21 ( void ) { return mkHReg(21, HRcVec128, False); }
HReg hregPPC_VR22 ( void ) { return mkHReg(22, HRcVec128, False); }
HReg hregPPC_VR23 ( void ) { return mkHReg(23, HRcVec128, False); }
HReg hregPPC_VR24 ( void ) { return mkHReg(24, HRcVec128, False); }
HReg hregPPC_VR25 ( void ) { return mkHReg(25, HRcVec128, False); }
HReg hregPPC_VR26 ( void ) { return mkHReg(26, HRcVec128, False); }
HReg hregPPC_VR27 ( void ) { return mkHReg(27, HRcVec128, False); }
HReg hregPPC_VR28 ( void ) { return mkHReg(28, HRcVec128, False); }
HReg hregPPC_VR29 ( void ) { return mkHReg(29, HRcVec128, False); }
HReg hregPPC_VR30 ( void ) { return mkHReg(30, HRcVec128, False); }
HReg hregPPC_VR31 ( void ) { return mkHReg(31, HRcVec128, False); }
void getAllocableRegs_PPC ( Int* nregs, HReg** arr, Bool mode64 )
{
UInt i=0;
if (mode64)
*nregs = (32-9) + (32-24) + (32-24);
else
*nregs = (32-7) + (32-24) + (32-24);
*arr = LibVEX_Alloc(*nregs * sizeof(HReg));
// GPR0 = scratch reg where poss. - some ops interpret as value zero
// GPR1 = stack pointer
// GPR2 = TOC pointer
(*arr)[i++] = hregPPC_GPR3(mode64);
(*arr)[i++] = hregPPC_GPR4(mode64);
(*arr)[i++] = hregPPC_GPR5(mode64);
(*arr)[i++] = hregPPC_GPR6(mode64);
(*arr)[i++] = hregPPC_GPR7(mode64);
(*arr)[i++] = hregPPC_GPR8(mode64);
(*arr)[i++] = hregPPC_GPR9(mode64);
(*arr)[i++] = 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 */
(*arr)[i++] = hregPPC_GPR11(mode64);
(*arr)[i++] = hregPPC_GPR12(mode64);
}
// GPR13 = thread specific pointer
// GPR14 and above are callee save. Yay.
(*arr)[i++] = hregPPC_GPR14(mode64);
(*arr)[i++] = hregPPC_GPR15(mode64);
(*arr)[i++] = hregPPC_GPR16(mode64);
(*arr)[i++] = hregPPC_GPR17(mode64);
(*arr)[i++] = hregPPC_GPR18(mode64);
(*arr)[i++] = hregPPC_GPR19(mode64);
(*arr)[i++] = hregPPC_GPR20(mode64);
(*arr)[i++] = hregPPC_GPR21(mode64);
(*arr)[i++] = hregPPC_GPR22(mode64);
(*arr)[i++] = hregPPC_GPR23(mode64);
(*arr)[i++] = hregPPC_GPR24(mode64);
(*arr)[i++] = hregPPC_GPR25(mode64);
(*arr)[i++] = hregPPC_GPR26(mode64);
(*arr)[i++] = hregPPC_GPR27(mode64);
(*arr)[i++] = 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. */
(*arr)[i++] = hregPPC_FPR14();
(*arr)[i++] = hregPPC_FPR15();
(*arr)[i++] = hregPPC_FPR16();
(*arr)[i++] = hregPPC_FPR17();
(*arr)[i++] = hregPPC_FPR18();
(*arr)[i++] = hregPPC_FPR19();
(*arr)[i++] = hregPPC_FPR20();
(*arr)[i++] = hregPPC_FPR21();
/* 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 */
(*arr)[i++] = hregPPC_VR20();
(*arr)[i++] = hregPPC_VR21();
(*arr)[i++] = hregPPC_VR22();
(*arr)[i++] = hregPPC_VR23();
(*arr)[i++] = hregPPC_VR24();
(*arr)[i++] = hregPPC_VR25();
(*arr)[i++] = hregPPC_VR26();
(*arr)[i++] = hregPPC_VR27();
vassert(i == *nregs);
}
/* --------- 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(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(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(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(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(sizeof(PPCRI));
op->tag = Pri_Imm;
op->Pri.Imm = imm64;
return op;
}
PPCRI* PPCRI_Reg ( HReg reg ) {
PPCRI* op = LibVEX_Alloc(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(sizeof(PPCInstr));
i->tag = Pin_MfCR;
i->Pin.MfCR.dst = dst;
return i;
}
PPCInstr* PPCInstr_MFence ( void )
{
PPCInstr* i = LibVEX_Alloc(sizeof(PPCInstr));
i->tag = Pin_MFence;
return i;
}
PPCInstr* PPCInstr_FpUnary ( PPCFpOp op, HReg dst, HReg src ) {
PPCInstr* i = LibVEX_Alloc(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(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(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(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(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(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( 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( 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(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( 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( 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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_AvShlDbl ( UChar shift, HReg dst,
HReg srcL, HReg srcR ) {
PPCInstr* i = LibVEX_Alloc(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(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(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(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(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(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(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(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 (hregNumber(dst) != hregNumber(src)) {
vex_printf("mr ");
ppHRegPPC(dst);
vex_printf(",");
ppHRegPPC(src);
}
}
void ppPPCInstr ( 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 &&
hregNumber(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_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->