
/*---------------------------------------------------------------*/
/*--- 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 == 1 || sz == 2 || sz == 4 || sz == 8);
   if (sz == 8) vassert(mode64);
   return i;
}
PPCInstr* PPCInstr_Store ( UChar sz, PPCAMode* dst, HReg src,
                           Bool mode64 ) {
   PPCInstr* i      = LibVEX_Alloc_inline(sizeof(PPCInstr));
   i->tag           = Pin_Store;
   i->Pin.Store.sz  = sz;
   i->Pin.Store.src = src;
   i->Pin.Store.dst = dst;
   vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
   if (sz == 8) vassert(mode64);
   return i;
}
PPCInstr* PPCInstr_StoreC ( UChar sz, HReg dst, HReg src, Bool mode64 ) {
   PPCInstr* i       = LibVEX_Alloc_inline(sizeof(PPCInstr));
   i->tag            = Pin_StoreC;
   i->Pin.StoreC.sz  = sz;
   i->Pin.StoreC.src = src;
   i->Pin.StoreC.dst = dst;
   vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
   if (sz == 8) vassert(mode64);
   return i;
}
PPCInstr* PPCInstr_Set ( PPCCondCode cond, HReg dst ) {
   PPCInstr* i     = LibVEX_Alloc_inline(sizeof(PPCInstr));
   i->tag          = Pin_Set;
   i->Pin.Set.cond = cond;
   i->Pin.Set.dst  = dst;
   return i;
}
PPCInstr* PPCInstr_MfCR ( HReg dst )
{
   PPCInstr* i     = LibVEX_Alloc_inline(sizeof(PPCInstr));
   i->tag          = Pin_MfCR;
   i->Pin.MfCR.dst = dst;
   return i;
}
PPCInstr* PPCInstr_MFence ( void )
{
   PPCInstr* i = LibVEX_Alloc_inline(sizeof(PPCInstr));
   i->tag      = Pin_MFence;
   return i;
}

PPCInstr* PPCInstr_FpUnary ( PPCFpOp op, HReg dst, HReg src ) {
   PPCInstr* i        = LibVEX_Alloc_inline(sizeof(PPCInstr));
   i->tag             = Pin_FpUnary;
   i->Pin.FpUnary.op  = op;
   i->Pin.FpUnary.dst = dst;
   i->Pin.FpUnary.src = src;
   return i;
}
PPCInstr* PPCInstr_FpBinary ( PPCFpOp op, HReg dst,
                              HReg srcL, HReg srcR ) {
   PPCInstr* i          = LibVEX_Alloc_inline(sizeof(PPCInstr));
   i->tag               = Pin_FpBinary;
   i->Pin.FpBinary.op   = op;
   i->Pin.FpBinary.dst  = dst;
   i->Pin.FpBinary.srcL = srcL;
   i->Pin.FpBinary.srcR = srcR;
   return i;
}
PPCInstr* PPCInstr_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: {
      UChar sz = i->Pin.LoadL.sz;
      HChar c_sz = sz==1 ? 'b' : sz==2 ? 'h' : sz==4 ? 'w' : 'd';
      vex_printf("l%carx ", c_sz);
      ppHRegPPC(i->Pin.LoadL.dst);
      vex_printf(",%%r0,");
      ppHRegPPC(i->Pin.LoadL.src);
      return;
   }
   case Pin_Store: {
      UChar sz = i->Pin.Store.sz;
      Bool idxd = toBool(i->Pin.Store.dst->tag == Pam_RR);
      HChar c_sz = sz==1 ? 'b' : sz==2 ? 'h' : sz==4 ? 'w' : /*8*/ 'd';
      vex_printf("st%c%s ", c_sz, idxd ? "x" : "" );
      ppHRegPPC(i->Pin.Store.src);
      vex_printf(",");
      ppPPCAMode(i->Pin.Store.dst);
      return;
   }
   case Pin_StoreC: {
      UChar sz = i->Pin.StoreC.sz;
      HChar c_sz = sz==1 ? 'b' : sz==2 ? 'h' : sz==4 ? 'w' : 'd';
      vex_printf("st%ccx. ", c_sz);
      ppHRegPPC(i->Pin.StoreC.src);
      vex_printf(",%%r0,");
      ppHRegPPC(i->Pin.StoreC.dst);
      return;
   }
   case Pin_Set: {
      PPCCondCode cc = i->Pin.Set.cond;
      vex_printf("set (%s),", showPPCCondCode(cc));
      ppHRegPPC(i->Pin.Set.dst);
      if (cc.test == Pct_ALWAYS) {
         vex_printf(": { li ");
         ppHRegPPC(i->Pin.Set.dst);
         vex_printf(",1 }");
      } else {
         vex_printf(": { mfcr r0 ; rlwinm ");
         ppHRegPPC(i->Pin.Set.dst);
         vex_printf(",r0,%u,31,31", cc.flag+1);
         if (cc.test == Pct_FALSE) {
            vex_printf("; xori ");
            ppHRegPPC(i->Pin.Set.dst);
            vex_printf(",");
            ppHRegPPC(i->Pin.Set.dst);
            vex_printf(",1");
         }
         vex_printf(" }");
      }
      return;
   }
   case Pin_MfCR:
      vex_printf("mfcr ");
      ppHRegPPC(i->Pin.MfCR.dst);
      break;
   case Pin_MFence:
      vex_printf("mfence (=sync)");
      return;

   case Pin_FpUnary:
      vex_printf("%s ", showPPCFpOp(i->Pin.FpUnary.op));
      ppHRegPPC(i->Pin.FpUnary.dst);
      vex_printf(",");
      ppHRegPPC(i->Pin.FpUnary.src);
      return;
   case Pin_FpBinary:
      vex_printf("%s ", showPPCFpOp(i->Pin.FpBinary.op));
      ppHRegPPC(i->Pin.FpBinary.dst);
      vex_printf(",");
      ppHRegPPC(i->Pin.FpBinary.srcL);
      vex_printf(",");
      ppHRegPPC(i->Pin.FpBinary.srcR);
      return;
   case Pin_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);
      addRegUsage_PPCAMode(u, i->Pin.XAssisted.amCIA);
      return;
   case Pin_CMov:
      addRegUsage_PPCRI(u,  i->Pin.CMov.src);
      addHRegUse(u, HRmWrite, i->Pin.CMov.dst);
      return;
   case Pin_Load:
      addRegUsage_PPCAMode(u, i->Pin.Load.src);
      addHRegUse(u, HRmWrite, i->Pin.Load.dst);
      return;
   case Pin_LoadL:
      addHRegUse(u, HRmRead,  i->Pin.LoadL.src);
      addHRegUse(u, HRmWrite, i->Pin.LoadL.dst);
      return;
   case Pin_Store:
      addHRegUse(u, HRmRead,  i->Pin.Store.src);
      addRegUsage_PPCAMode(u, i->Pin.Store.dst);
      return;
   case Pin_StoreC:
      addHRegUse(u, HRmRead, i->Pin.StoreC.src);
      addHRegUse(u, HRmRead, i->Pin.StoreC.dst);
      return;
   case Pin_Set:
      addHRegUse(u, HRmWrite, i->Pin.Set.dst);
      return;
   case Pin_MfCR:
      addHRegUse(u, HRmWrite, i->Pin.MfCR.dst);
      return;
   case Pin_MFence:
      return;

   case Pin_FpUnary:
      addHRegUse(u, HRmWrite, i->Pin.FpUnary.dst);
      addHRegUse(u, HRmRead,  i->Pin.FpUnary.src);
      return;
   case Pin_FpBinary:
      addHRegUse(u, HRmWrite, i->Pin.FpBinary.dst);
      addHRegUse(u, HRmRead,  i->Pin.FpBinary.srcL);
      addHRegUse(u, HRmRead,  i->Pin.FpBinary.srcR);
      return;
   case Pin_FpMulAcc:
      addHRegUse(u, HRmWrite, i->Pin.FpMulAcc.dst);
      addHRegUse(u, HRmRead,  i->Pin.FpMulAcc.srcML);
      addHRegUse(u, HRmRead,  i->Pin.FpMulAcc.srcMR);
      addHRegUse(u, HRmRead,  i->Pin.FpMulAcc.srcAcc);
      return;
   case Pin_FpLdSt:
      addHRegUse(u, (i->Pin.FpLdSt.isLoad ? HRmWrite : HRmRead),
                 i->Pin.FpLdSt.reg);
      addRegUsage_PPCAMode(u, i->Pin.FpLdSt.addr);
      return;
   case Pin_FpSTFIW:
      addHRegUse(u, HRmRead, i->Pin.FpSTFIW.addr);
      addHRegUse(u, HRmRead, i->Pin.FpSTFIW.data);
      return;
   case Pin_FpRSP:
      addHRegUse(u, HRmWrite, i->Pin.FpRSP.dst);
      addHRegUse(u, HRmRead,  i->Pin.FpRSP.src);
      return;
   case Pin_FpCftI:
      addHRegUse(u, HRmWrite, i->Pin.FpCftI.dst);
      addHRegUse(u, HRmRead,  i->Pin.FpCftI.src);
      return;
   case Pin_FpCMov:
      addHRegUse(u, HRmModify, i->Pin.FpCMov.dst);
      addHRegUse(u, HRmRead,   i->Pin.FpCMov.src);
      return;
   case Pin_FpLdFPSCR:
      addHRegUse(u, HRmRead, i->Pin.FpLdFPSCR.src);
      return;
   case Pin_FpCmp:
      addHRegUse(u, HRmWrite, i->Pin.FpCmp.dst);
      addHRegUse(u, HRmRead,  i->Pin.FpCmp.srcL);
      addHRegUse(u, HRmRead,  i->Pin.FpCmp.srcR);
      return;

   case Pin_RdWrLR:
      addHRegUse(u, (i->Pin.RdWrLR.wrLR ? HRmRead : HRmWrite),
                 i->Pin.RdWrLR.gpr);
      return;

   case Pin_AvLdSt:
      addHRegUse(u, (i->Pin.AvLdSt.isLoad ? HRmWrite : HRmRead),
                 i->Pin.AvLdSt.reg);
      if (i->Pin.AvLdSt.addr->tag == Pam_IR)
         addHRegUse(u, HRmWrite, hregPPC_GPR30(mode64));
      addRegUsage_PPCAMode(u, i->Pin.AvLdSt.addr);
      return;
   case Pin_AvUnary:
      addHRegUse(u, HRmWrite, i->Pin.AvUnary.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvUnary.src);
      return;
   case Pin_AvBinary:
      if (i->Pin.AvBinary.op == Pav_XOR
          && sameHReg(i->Pin.AvBinary.dst, i->Pin.AvBinary.srcL)
          && sameHReg(i->Pin.AvBinary.dst, i->Pin.AvBinary.srcR)) {
         /* reg-alloc needs to understand 'xor r,r,r' as a write of r */
         /* (as opposed to a rite of passage :-) */
         addHRegUse(u, HRmWrite, i->Pin.AvBinary.dst);
      } else {
         addHRegUse(u, HRmWrite, i->Pin.AvBinary.dst);
         addHRegUse(u, HRmRead,  i->Pin.AvBinary.srcL);
         addHRegUse(u, HRmRead,  i->Pin.AvBinary.srcR);
      }
      return;
   case Pin_AvBin8x16:
      addHRegUse(u, HRmWrite, i->Pin.AvBin8x16.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvBin8x16.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvBin8x16.srcR);
      return;
   case Pin_AvBin16x8:
      addHRegUse(u, HRmWrite, i->Pin.AvBin16x8.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvBin16x8.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvBin16x8.srcR);
      return;
   case Pin_AvBin32x4:
      addHRegUse(u, HRmWrite, i->Pin.AvBin32x4.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvBin32x4.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvBin32x4.srcR);
      return;
   case Pin_AvBin64x2:
      addHRegUse(u, HRmWrite, i->Pin.AvBin64x2.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvBin64x2.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvBin64x2.srcR);
      return;
   case Pin_AvBin32Fx4:
      addHRegUse(u, HRmWrite, i->Pin.AvBin32Fx4.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvBin32Fx4.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvBin32Fx4.srcR);
      if (i->Pin.AvBin32Fx4.op == Pavfp_MULF)
         addHRegUse(u, HRmWrite, hregPPC_VR29(mode64));
      return;
   case Pin_AvUn32Fx4:
      addHRegUse(u, HRmWrite, i->Pin.AvUn32Fx4.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvUn32Fx4.src);
      return;
   case Pin_AvPerm:
      addHRegUse(u, HRmWrite, i->Pin.AvPerm.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvPerm.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvPerm.srcR);
      addHRegUse(u, HRmRead,  i->Pin.AvPerm.ctl);
      return;
   case Pin_AvSel:
      addHRegUse(u, HRmWrite, i->Pin.AvSel.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvSel.ctl);
      addHRegUse(u, HRmRead,  i->Pin.AvSel.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvSel.srcR);
      return;
   case Pin_AvSh:
      addHRegUse(u, HRmWrite, i->Pin.AvSh.dst);
      if (i->Pin.AvSh.addr->tag == Pam_IR)
         addHRegUse(u, HRmWrite, hregPPC_GPR30(mode64));
      addRegUsage_PPCAMode(u, i->Pin.AvSh.addr);
      return;
   case Pin_AvShlDbl:
      addHRegUse(u, HRmWrite, i->Pin.AvShlDbl.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvShlDbl.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvShlDbl.srcR);
      return;
   case Pin_AvSplat:
      addHRegUse(u, HRmWrite, i->Pin.AvSplat.dst);
      addRegUsage_PPCVI5s(u,  i->Pin.AvSplat.src);
      return;
   case Pin_AvCMov:
      addHRegUse(u, HRmModify, i->Pin.AvCMov.dst);
      addHRegUse(u, HRmRead,   i->Pin.AvCMov.src);
      return;
   case Pin_AvLdVSCR:
      addHRegUse(u, HRmRead, i->Pin.AvLdVSCR.src);
      return;
   case Pin_AvCipherV128Unary:
      addHRegUse(u, HRmWrite, i->Pin.AvCipherV128Unary.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvCipherV128Unary.src);
      return;
   case Pin_AvCipherV128Binary:
      addHRegUse(u, HRmWrite, i->Pin.AvCipherV128Binary.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvCipherV128Binary.srcL);
      addHRegUse(u, HRmRead,  i->Pin.AvCipherV128Binary.srcR);
      return;
   case Pin_AvHashV128Binary:
      addHRegUse(u, HRmWrite, i->Pin.AvHashV128Binary.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvHashV128Binary.src);
      addRegUsage_PPCRI(u,    i->Pin.AvHashV128Binary.s_field);
      return;
   case Pin_AvBCDV128Trinary:
      addHRegUse(u, HRmWrite, i->Pin.AvBCDV128Trinary.dst);
      addHRegUse(u, HRmRead,  i->Pin.AvBCDV128Trinary.src1);
      addHRegUse(u, HRmRead,  i->Pin.AvBCDV128Trinary.src2);
      addRegUsage_PPCRI(u,    i->Pin.AvBCDV128Trinary.ps);
      return;
   case Pin_Dfp64Unary:
      addHRegUse(u, HRmWrite, i->Pin.Dfp64Unary.dst);
      addHRegUse(u, HRmRead, i->Pin.Dfp64Unary.src);
      return;
   case Pin_Dfp64Binary:
      addHRegUse(u, HRmWrite, i->Pin.Dfp64Binary.dst);
      addHRegUse(u, HRmRead, i->Pin.Dfp64Binary.srcL);
      addHRegUse(u, HRmRead, i->Pin.Dfp64Binary.srcR);
      return;
   case Pin_DfpShift:
      addRegUsage_PPCRI(u,    i->Pin.DfpShift.shift);
      addHRegUse(u, HRmWrite, i->Pin.DfpShift.src);
      addHRegUse(u, HRmWrite, i->Pin.DfpShift.dst);
      return;
   case Pin_Dfp128Unary:
      addHRegUse(u, HRmWrite, i->Pin.Dfp128Unary.dst_hi);
      addHRegUse(u, HRmWrite, i->Pin.Dfp128Unary.dst_lo);
      addHRegUse(u, HRmRead,  i->Pin.Dfp128Unary.src_hi);
      addHRegUse(u, HRmRead,  i->Pin.Dfp128Unary.src_lo);
      return;
   case Pin_Dfp128Binary:
      addHRegUse(u, HRmWrite, i->Pin.Dfp128Binary.dst_hi);
      addHRegUse(u, HRmWrite, i->Pin.Dfp128Binary.dst_lo);
      addHRegUse(u, HRmRead, i->Pin.Dfp128Binary.srcR_hi);
      addHRegUse(u, HRmRead, i->Pin.Dfp128Binary.srcR_lo);
      return;
   case Pin_DfpRound:
      addHRegUse(u, HRmWrite, i->Pin.DfpRound.dst);
      addHRegUse(u, HRmRead,  i->Pin.DfpRound.src);
      return;
   case Pin_DfpRound128:
      addHRegUse(u, HRmWrite, i->Pin.DfpRound128.dst_hi);
      addHRegUse(u, HRmWrite, i->Pin.DfpRound128.dst_lo);
      addHRegUse(u, HRmRead,  i->Pin.DfpRound128.src_hi);
      addHRegUse(u, HRmRead,  i->Pin.DfpRound128.src_lo);
      return;
   case Pin_DfpQuantize:
      addRegUsage_PPCRI(u,  i->Pin.DfpQuantize.rmc);
      addHRegUse(u, HRmWrite, i->Pin.DfpQuantize.dst);
      addHRegUse(u, HRmRead,  i->Pin.DfpQuantize.srcL);
      addHRegUse(u, HRmRead,  i->Pin.DfpQuantize.srcR);
      return;
   case Pin_DfpQuantize128:
      addHRegUse(u, HRmWrite, i->Pin.DfpQuantize128.dst_hi);
      addHRegUse(u, HRmWrite, i->Pin.DfpQuantize128.dst_lo);
      addHRegUse(u, HRmRead,  i->Pin.DfpQuantize128.src_hi);
      addHRegUse(u, HRmRead,  i->Pin.DfpQuantize128.src_lo);
      return;
   case Pin_DfpShift128:
      addRegUsage_PPCRI(u,    i->Pin.DfpShift128.shift);
      addHRegUse(u, HRmWrite, i->Pin.DfpShift128.src_hi);
      addHRegUse(u, HRmWrite, i->Pin.DfpShift128.src_lo);
      addHRegUse(u, HRmWrite, i->Pin.DfpShift128.dst_hi);
      addHRegUse(u, HRmWrite, i->Pin.DfpShift128.dst_lo);
      return;
   case Pin_DfpD128toD64:
      addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.src_hi);
      addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.src_lo);
      addHRegUse(u, HRmWrite, i->Pin.DfpD128toD64.dst);
      return;
   case Pin_DfpI64StoD128:
      addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.src);
      addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.dst_hi);
      addHRegUse(u, HRmWrite, i->Pin.DfpI64StoD128.dst_lo);
      return;
   case Pin_ExtractExpD128:
      addHRegUse(u, HRmWrite, i->Pin.ExtractExpD128.dst);
      addHRegUse(u, HRmRead,  i->Pin.ExtractExpD128.src_hi);
      addHRegUse(u, HRmRead,  i->Pin.ExtractExpD128.src_lo);
      return;
   case Pin_InsertExpD128:
      addHRegUse(u, HRmWrite, i->Pin.InsertExpD128.dst_hi);
      addHRegUse(u, HRmWrite, i->Pin.InsertExpD128.dst_lo);
      addHRegUse(u, HRmRead,  i->Pin.InsertExpD128.srcL);
      addHRegUse(u, HRmRead,  i->Pin.InsertExpD128.srcR_hi);
      addHRegUse(u, HRmRead,  i->Pin.InsertExpD128.srcR_lo);
      return;
   case Pin_Dfp64Cmp:
      addHRegUse(u, HRmWrite, i->Pin.Dfp64Cmp.dst);
      addHRegUse(u, HRmRead,  i->Pin.Dfp64Cmp.srcL);
      addHRegUse(u, HRmRead,  i->Pin.Dfp64Cmp.srcR);
      return;
   case Pin_Dfp128Cmp:
      addHRegUse(u, HRmWrite, i->Pin.Dfp128Cmp.dst);
      addHRegUse(u, HRmRead,  i->Pin.Dfp128Cmp.srcL_hi);
      addHRegUse(u, HRmRead,  i->Pin.Dfp128Cmp.srcL_lo);
      addHRegUse(u, HRmRead,  i->Pin.Dfp128Cmp.srcR_hi);
      addHRegUse(u, HRmRead,  i->Pin.Dfp128Cmp.srcR_lo);
      return;                                           
   case Pin_EvCheck:
      /* We expect both amodes only to mention the GSP (r31), so this
         is in fact pointless, since GSP isn't allocatable, but
         anyway.. */
      addRegUsage_PPCAMode(u, i->Pin.EvCheck.amCounter);
      addRegUsage_PPCAMode(u, i->Pin.EvCheck.amFailAddr);
      addHRegUse(u, HRmWrite, hregPPC_GPR30(mode64)); /* also unavail to RA */
      return;
   case Pin_ProfInc:
      addHRegUse(u, HRmWrite, hregPPC_GPR29(mode64));
      addHRegUse(u, HRmWrite, hregPPC_GPR30(mode64));
      return;
   default:
      ppPPCInstr(i, mode64);
      vpanic("getRegUsage_PPCInstr");
   }
}

/* local helper */
static void mapReg( HRegRemap* m, HReg* r )
{
   *r = lookupHRegRemap(m, *r);
}

void mapRegs_PPCInstr ( HRegRemap* m, PPCInstr* i, Bool mode64 )
{
   switch (i->tag) {
   case Pin_LI:
      mapReg(m, &i->Pin.LI.dst);
      return;
   case Pin_Alu:
      mapReg(m, &i->Pin.Alu.dst);
      mapReg(m, &i->Pin.Alu.srcL);
      mapRegs_PPCRH(m, i->Pin.Alu.srcR);
      return;
   case Pin_Shft:
      mapReg(m, &i->Pin.Shft.dst);
      mapReg(m, &i->Pin.Shft.srcL);
      mapRegs_PPCRH(m, i->Pin.Shft.srcR);
      return;
   case Pin_AddSubC:
      mapReg(m, &i->Pin.AddSubC.dst);
      mapReg(m, &i->Pin.AddSubC.srcL);
      mapReg(m, &i->Pin.AddSubC.srcR);
      return;
   case Pin_Cmp:
      mapReg(m, &i->Pin.Cmp.srcL);
      mapRegs_PPCRH(m, i->Pin.Cmp.srcR);
      return;
   case Pin_Unary:
      mapReg(m, &i->Pin.Unary.dst);
      mapReg(m, &i->Pin.Unary.src);
      return;
   case Pin_MulL:
      mapReg(m, &i->Pin.MulL.dst);
      mapReg(m, &i->Pin.MulL.srcL);
      mapReg(m, &i->Pin.MulL.srcR);
      return;
   case Pin_Div:
      mapReg(m, &i->Pin.Div.dst);
      mapReg(m, &i->Pin.Div.srcL);
      mapReg(m, &i->Pin.Div.srcR);
      return;
   case Pin_Call:
      return;
   case Pin_XDirect:
      mapRegs_PPCAMode(m, i->Pin.XDirect.amCIA);
      return;
   case Pin_XIndir:
      mapReg(m, &i->Pin.XIndir.dstGA);
      mapRegs_PPCAMode(m, i->Pin.XIndir.amCIA);
      return;
   case Pin_XAssisted:
      mapReg(m, &i->Pin.XAssisted.dstGA);
      mapRegs_PPCAMode(m, i->Pin.XAssisted.amCIA);
      return;
   case Pin_CMov:
      mapRegs_PPCRI(m, i->Pin.CMov.src);
      mapReg(m, &i->Pin.CMov.dst);
      return;
   case Pin_Load:
      mapRegs_PPCAMode(m, i->Pin.Load.src);
      mapReg(m, &i->Pin.Load.dst);
      return;
   case Pin_LoadL:
      mapReg(m, &i->Pin.LoadL.src);
      mapReg(m, &i->Pin.LoadL.dst);
      return;
   case Pin_Store:
      mapReg(m, &i->Pin.Store.src);
      mapRegs_PPCAMode(m, i->Pin.Store.dst);
      return;
   case Pin_StoreC:
      mapReg(m, &i->Pin.StoreC.src);
      mapReg(m, &i->Pin.StoreC.dst);
      return;
   case Pin_Set:
      mapReg(m, &i->Pin.Set.dst);
      return;
   case Pin_MfCR:
      mapReg(m, &i->Pin.MfCR.dst);
      return;
   case Pin_MFence:
      return;
   case Pin_FpUnary:
      mapReg(m, &i->Pin.FpUnary.dst);
      mapReg(m, &i->Pin.FpUnary.src);
      return;
   case Pin_FpBinary:
      mapReg(m, &i->Pin.FpBinary.dst);
      mapReg(m, &i->Pin.FpBinary.srcL);
      mapReg(m, &i->Pin.FpBinary.srcR);
      return;
   case Pin_FpMulAcc:
      mapReg(m, &i->Pin.FpMulAcc.dst);
      mapReg(m, &i->Pin.FpMulAcc.srcML);
      mapReg(m, &i->Pin.FpMulAcc.srcMR);
      mapReg(m, &i->Pin.FpMulAcc.srcAcc);
      return;
   case Pin_FpLdSt:
      mapReg(m, &i->Pin.FpLdSt.reg);
      mapRegs_PPCAMode(m, i->Pin.FpLdSt.addr);
      return;
   case Pin_FpSTFIW:
      mapReg(m, &i->Pin.FpSTFIW.addr);
      mapReg(m, &i->Pin.FpSTFIW.data);
      return;
   case Pin_FpRSP:
      mapReg(m, &i->Pin.FpRSP.dst);
      mapReg(m, &i->Pin.FpRSP.src);
      return;
   case Pin_FpCftI:
      mapReg(m, &i->Pin.FpCftI.dst);
      mapReg(m, &i->Pin.FpCftI.src);
      return;
   case Pin_FpCMov:
      mapReg(m, &i->Pin.FpCMov.dst);
      mapReg(m, &i->Pin.FpCMov.src);
      return;
   case Pin_FpLdFPSCR:
      mapReg(m, &i->Pin.FpLdFPSCR.src);
      return;
   case Pin_FpCmp:
      mapReg(m, &i->Pin.FpCmp.dst);
      mapReg(m, &i->Pin.FpCmp.srcL);
      mapReg(m, &i->Pin.FpCmp.srcR);
      return;
   case Pin_RdWrLR:
      mapReg(m, &i->Pin.RdWrLR.gpr);
      return;
   case Pin_AvLdSt:
      mapReg(m, &i->Pin.AvLdSt.reg);
      mapRegs_PPCAMode(m, i->Pin.AvLdSt.addr);
      return;
   case Pin_AvUnary:
      mapReg(m, &i->Pin.AvUnary.dst);
      mapReg(m, &i->Pin.AvUnary.src);
      return;
   case Pin_AvBinary:
      mapReg(m, &i->Pin.AvBinary.dst);
      mapReg(m, &i->Pin.AvBinary.srcL);
      mapReg(m, &i->Pin.AvBinary.srcR);
      return;
   case Pin_AvBin8x16:
      mapReg(m, &i->Pin.AvBin8x16.dst);
      mapReg(m, &i->Pin.AvBin8x16.srcL);
      mapReg(m, &i->Pin.AvBin8x16.srcR);
      return;
   case Pin_AvBin16x8:
      mapReg(m, &i->Pin.AvBin16x8.dst);
      mapReg(m, &i->Pin.AvBin16x8.srcL);
      mapReg(m, &i->Pin.AvBin16x8.srcR);
      return;
   case Pin_AvBin32x4:
      mapReg(m, &i->Pin.AvBin32x4.dst);
      mapReg(m, &i->Pin.AvBin32x4.srcL);
      mapReg(m, &i->Pin.AvBin32x4.srcR);
      return;
   case Pin_AvBin64x2:
      mapReg(m, &i->Pin.AvBin64x2.dst);
      mapReg(m, &i->Pin.AvBin64x2.srcL);
      mapReg(m, &i->Pin.AvBin64x2.srcR);
      return;
   case Pin_AvBin32Fx4:
      mapReg(m, &i->Pin.AvBin32Fx4.dst);
      mapReg(m, &i->Pin.AvBin32Fx4.srcL);
      mapReg(m, &i->Pin.AvBin32Fx4.srcR);
      return;
   case Pin_AvUn32Fx4:
      mapReg(m, &i->Pin.AvUn32Fx4.dst);
      mapReg(m, &i->Pin.AvUn32Fx4.src);
      return;
   case Pin_AvPerm:
      mapReg(m, &i->Pin.AvPerm.dst);
      mapReg(m, &i->Pin.AvPerm.srcL);
      mapReg(m, &i->Pin.AvPerm.srcR);
      mapReg(m, &i->Pin.AvPerm.ctl);
      return;
   case Pin_AvSel:
      mapReg(m, &i->Pin.AvSel.dst);
      mapReg(m, &i->Pin.AvSel.srcL);
      mapReg(m, &i->Pin.AvSel.srcR);
      mapReg(m, &i->Pin.AvSel.ctl);
      return;
   case Pin_AvSh:
      mapReg(m, &i->Pin.AvSh.dst);
      mapRegs_PPCAMode(m, i->Pin.AvSh.addr);
      return;
   case Pin_AvShlDbl:
      mapReg(m, &i->Pin.AvShlDbl.dst);
      mapReg(m, &i->Pin.AvShlDbl.srcL);
      mapReg(m, &i->Pin.AvShlDbl.srcR);
      return;
   case Pin_AvSplat:
      mapReg(m, &i->Pin.AvSplat.dst);
      mapRegs_PPCVI5s(m, i->Pin.AvSplat.src);
      return;
   case Pin_AvCMov:
     mapReg(m, &i->Pin.AvCMov.dst);
     mapReg(m, &i->Pin.AvCMov.src);
     return;
   case Pin_AvLdVSCR:
      mapReg(m, &i->Pin.AvLdVSCR.src);
      return;
   case Pin_AvCipherV128Unary:
      mapReg(m, &i->Pin.AvCipherV128Unary.dst);
      mapReg(m, &i->Pin.AvCipherV128Unary.src);
      return;
   case Pin_AvCipherV128Binary:
      mapReg(m, &i->Pin.AvCipherV128Binary.dst);
      mapReg(m, &i->Pin.AvCipherV128Binary.srcL);
      mapReg(m, &i->Pin.AvCipherV128Binary.srcR);
      return;
   case Pin_AvHashV128Binary:
      mapRegs_PPCRI(m, i->Pin.AvHashV128Binary.s_field);
      mapReg(m, &i->Pin.AvHashV128Binary.dst);
      mapReg(m, &i->Pin.AvHashV128Binary.src);
      return;
   case Pin_AvBCDV128Trinary:
      mapReg(m, &i->Pin.AvBCDV128Trinary.dst);
      mapReg(m, &i->Pin.AvBCDV128Trinary.src1);
      mapReg(m, &i->Pin.AvBCDV128Trinary.src2);
      mapRegs_PPCRI(m, i->Pin.AvBCDV128Trinary.ps);
      return;
   case Pin_Dfp64Unary:
      mapReg(m, &i->Pin.Dfp64Unary.dst);
      mapReg(m, &i->Pin.Dfp64Unary.src);
      return;
   case Pin_Dfp64Binary:
      mapReg(m, &i->Pin.Dfp64Binary.dst);
      mapReg(m, &i->Pin.Dfp64Binary.srcL);
      mapReg(m, &i->Pin.Dfp64Binary.srcR);
      return;
   case Pin_DfpShift:
      mapRegs_PPCRI(m, i->Pin.DfpShift.shift);
      mapReg(m, &i->Pin.DfpShift.src);
      mapReg(m, &i->Pin.DfpShift.dst);
      return;
   case Pin_Dfp128Unary:
      mapReg(m, &i->Pin.Dfp128Unary.dst_hi);
      mapReg(m, &i->Pin.Dfp128Unary.dst_lo);
      mapReg(m, &i->Pin.Dfp128Unary.src_hi);
      mapReg(m, &i->Pin.Dfp128Unary.src_lo);
     return;
   case Pin_Dfp128Binary:
      mapReg(m, &i->Pin.Dfp128Binary.dst_hi);
      mapReg(m, &i->Pin.Dfp128Binary.dst_lo);
      mapReg(m, &i->Pin.Dfp128Binary.srcR_hi);
      mapReg(m, &i->Pin.Dfp128Binary.srcR_lo);
      return;
   case Pin_DfpShift128:
      mapRegs_PPCRI(m, i->Pin.DfpShift128.shift);
      mapReg(m, &i->Pin.DfpShift128.src_hi);
      mapReg(m, &i->Pin.DfpShift128.src_lo);
      mapReg(m, &i->Pin.DfpShift128.dst_hi);
      mapReg(m, &i->Pin.DfpShift128.dst_lo);
      return;
   case Pin_DfpRound:
      mapReg(m, &i->Pin.DfpRound.dst);
      mapReg(m, &i->Pin.DfpRound.src);
      return;
   case Pin_DfpRound128:
      mapReg(m, &i->Pin.DfpRound128.dst_hi);
      mapReg(m, &i->Pin.DfpRound128.dst_lo);
      mapReg(m, &i->Pin.DfpRound128.src_hi);
      mapReg(m, &i->Pin.DfpRound128.src_lo);
      return;
   case Pin_DfpQuantize:
      mapRegs_PPCRI(m, i->Pin.DfpQuantize.rmc);
      mapReg(m, &i->Pin.DfpQuantize.dst);
      mapReg(m, &i->Pin.DfpQuantize.srcL);
      mapReg(m, &i->Pin.DfpQuantize.srcR);
      return;
   case Pin_DfpQuantize128:
      mapRegs_PPCRI(m, i->Pin.DfpQuantize128.rmc);
      mapReg(m, &i->Pin.DfpQuantize128.dst_hi);
      mapReg(m, &i->Pin.DfpQuantize128.dst_lo);
      mapReg(m, &i->Pin.DfpQuantize128.src_hi);
      mapReg(m, &i->Pin.DfpQuantize128.src_lo);
      return;
   case Pin_DfpD128toD64:
      mapReg(m, &i->Pin.DfpD128toD64.src_hi);
      mapReg(m, &i->Pin.DfpD128toD64.src_lo);
      mapReg(m, &i->Pin.DfpD128toD64.dst);
      return;
   case Pin_DfpI64StoD128:
      mapReg(m, &i->Pin.DfpI64StoD128.src);
      mapReg(m, &i->Pin.DfpI64StoD128.dst_hi);
      mapReg(m, &i->Pin.DfpI64StoD128.dst_lo);
      return;
   case Pin_ExtractExpD128:
      mapReg(m, &i->Pin.ExtractExpD128.dst);
      mapReg(m, &i->Pin.ExtractExpD128.src_hi);
      mapReg(m, &i->Pin.ExtractExpD128.src_lo);
      return;
   case Pin_InsertExpD128:
      mapReg(m, &i->Pin.InsertExpD128.dst_hi);
      mapReg(m, &i->Pin.InsertExpD128.dst_lo);
      mapReg(m, &i->Pin.InsertExpD128.srcL);
      mapReg(m, &i->Pin.InsertExpD128.srcR_hi);
      mapReg(m, &i->Pin.InsertExpD128.srcR_lo);
      return;
   case Pin_Dfp64Cmp:
      mapReg(m, &i->Pin.Dfp64Cmp.dst);
      mapReg(m, &i->Pin.Dfp64Cmp.srcL);
      mapReg(m, &i->Pin.Dfp64Cmp.srcR);
      return;
   case Pin_Dfp128Cmp:
      mapReg(m, &i->Pin.Dfp128Cmp.dst);
      mapReg(m, &i->Pin.Dfp128Cmp.srcL_hi);
      mapReg(m, &i->Pin.Dfp128Cmp.srcL_lo);
      mapReg(m, &i->Pin.Dfp128Cmp.srcR_hi);
      mapReg(m, &i->Pin.Dfp128Cmp.srcR_lo);
      return;
   case Pin_EvCheck:
      /* We expect both amodes only to mention the GSP (r31), so this
         is in fact pointless, since GSP isn't allocatable, but
         anyway.. */
      mapRegs_PPCAMode(m, i->Pin.EvCheck.amCounter);
      mapRegs_PPCAMode(m, i->Pin.EvCheck.amFailAddr);
      return;
   case Pin_ProfInc:
      /* hardwires r29 and r30 -- nothing to modify. */
      return;
   default:
      ppPPCInstr(i, mode64);
      vpanic("mapRegs_PPCInstr");
   }
}

/* Figure out if i represents a reg-reg move, and if so assign the
   source and destination to *src and *dst.  If in doubt say No.  Used
   by the register allocator to do move coalescing. 
*/
Bool isMove_PPCInstr ( const PPCInstr* i, HReg* src, HReg* dst )
{
   /* Moves between integer regs */
   if (i->tag == Pin_Alu) {
      // or Rd,Rs,Rs == mr Rd,Rs
      if (i->Pin.Alu.op != Palu_OR)
         return False;
      if (i->Pin.Alu.srcR->tag != Prh_Reg)
         return False;
      if (! sameHReg(i->Pin.Alu.srcR->Prh.Reg.reg, i->Pin.Alu.srcL))
         return False;
      *src = i->Pin.Alu.srcL;
      *dst = i->Pin.Alu.dst;
      return True;
   }
   /* Moves between FP regs */
   if (i->tag == Pin_FpUnary) {
      if (i->Pin.FpUnary.op != Pfp_MOV)
         return False;
      *src = i->Pin.FpUnary.src;
      *dst = i->Pin.FpUnary.dst;
      return True;
   }
   return False;
}


/* Generate ppc spill/reload instructions under the direction of the
   register allocator.  Note it's critical these don't write the
   condition codes. */

void genSpill_PPC ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
                    HReg rreg, Int offsetB, Bool mode64 )
{
   PPCAMode* am;
   vassert(!hregIsVirtual(rreg));
   *i1 = *i2 = NULL;
   am = PPCAMode_IR( offsetB, GuestStatePtr(mode64) );
   switch (hregClass(rreg)) {
      case HRcInt64:
         vassert(mode64);
         *i1 = PPCInstr_Store( 8, am, rreg, mode64 );
         return;
      case HRcInt32:
         vassert(!mode64);
         *i1 = PPCInstr_Store( 4, am, rreg, mode64 );
         return;
      case HRcFlt64:
         *i1 = PPCInstr_FpLdSt ( False/*store*/, 8, rreg, am );
         return;
      case HRcVec128:
         // XXX: GPR30 used as spill register to kludge AltiVec
         // AMode_IR
         *i1 = PPCInstr_AvLdSt ( False/*store*/, 16, rreg, am );
         return;
      default: 
         ppHRegClass(hregClass(rreg));
         vpanic("genSpill_PPC: unimplemented regclass");
   }
}

void genReload_PPC ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
                     HReg rreg, Int offsetB, Bool mode64 )
{
   PPCAMode* am;
   vassert(!hregIsVirtual(rreg));
   *i1 = *i2 = NULL;
   am = PPCAMode_IR( offsetB, GuestStatePtr(mode64) );
   switch (hregClass(rreg)) {
      case HRcInt64:
         vassert(mode64);
         *i1 = PPCInstr_Load( 8, rreg, am, mode64 );
         return;
      case HRcInt32:
         vassert(!mode64);
         *i1 = PPCInstr_Load( 4, rreg, am, mode64 );
         return;
      case HRcFlt64:
         *i1 = PPCInstr_FpLdSt ( True/*load*/, 8, rreg, am );
         return;
      case HRcVec128:
         // XXX: GPR30 used as spill register to kludge AltiVec AMode_IR
         *i1 = PPCInstr_AvLdSt ( True/*load*/, 16, rreg, am );
         return;
      default: 
         ppHRegClass(hregClass(rreg));
         vpanic("genReload_PPC: unimplemented regclass");
   }
}


/* --------- The ppc assembler (bleh.) --------- */

inline static UInt iregEnc ( HReg r, Bool mode64 )
{
   UInt n;
   vassert(hregClass(r) == (mode64 ? HRcInt64 : HRcInt32));
   vassert(!hregIsVirtual(r));
   n = hregEncoding(r);
   vassert(n <= 32);
   return n;
}

inline static UInt fregEnc ( HReg fr )
{
   UInt n;
   vassert(hregClass(fr) == HRcFlt64);
   vassert(!hregIsVirtual(fr));
   n = hregEncoding(fr);
   vassert(n <= 32);
   return n;
}

inline static UInt vregEnc ( HReg v )
{
   UInt n;
   vassert(hregClass(v) == HRcVec128);
   vassert(!hregIsVirtual(v));
   n = hregEncoding(v);
   vassert(n <= 32);
   return n;
}

/* Emit an instruction ppc-endianly */
static UChar* emit32 ( UChar* p, UInt w32, VexEndness endness_host )
{
  if (endness_host == VexEndnessBE) {
    *p++ = toUChar((w32 >> 24) & 0x000000FF);
    *p++ = toUChar((w32 >> 16) & 0x000000FF);
    *p++ = toUChar((w32 >>  8) & 0x000000FF);
    *p++ = toUChar((w32)       & 0x000000FF);
  } else {
    *p++ = toUChar((w32)       & 0x000000FF);
    *p++ = toUChar((w32 >>  8) & 0x000000FF);
    *p++ = toUChar((w32 >> 16) & 0x000000FF);
    *p++ = toUChar((w32 >> 24) & 0x000000FF);
  }
   return p;
}

/* Fetch an instruction ppc-endianly */
static UInt fetch32 ( UChar* p, VexEndness endness_host )
{
   UInt w32 = 0;
   if (endness_host == VexEndnessBE) {
      w32 |= ((0xFF & (UInt)p[0]) << 24);
      w32 |= ((0xFF & (UInt)p[1]) << 16);
      w32 |= ((0xFF & (UInt)p[2]) <<  8);
      w32 |= ((0xFF & (UInt)p[3]) <<  0);
  } else {
      w32 |= ((0xFF & (UInt)p[3]) << 24);
      w32 |= ((0xFF & (UInt)p[2]) << 16);
      w32 |= ((0xFF & (UInt)p[1]) <<  8);
      w32 |= ((0xFF & (UInt)p[0]) <<  0);
  }
   return w32;
}

/* The following mkForm[...] functions refer to ppc instruction forms
   as per PPC32 p576
 */

static UChar* mkFormD ( UChar* p, UInt opc1,
                        UInt r1, UInt r2, UInt imm, VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   imm = imm & 0xFFFF;
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (imm));
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormMD ( UChar* p, UInt opc1, UInt r1, UInt r2,
                         UInt imm1, UInt imm2, UInt opc2,
                         VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(imm1 < 0x40);
   vassert(imm2 < 0x40);
   vassert(opc2 < 0x08);
   imm2 = ((imm2 & 0x1F) << 1) | (imm2 >> 5);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               ((imm1 & 0x1F)<<11) | (imm2<<5) |
               (opc2<<2) | ((imm1 >> 5)<<1));
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormX ( UChar* p, UInt opc1, UInt r1, UInt r2,
                        UInt r3, UInt opc2, UInt b0, VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(r3   < 0x20);
   vassert(opc2 < 0x400);
   vassert(b0   < 0x2);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               (r3<<11) | (opc2<<1) | (b0));
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormXO ( UChar* p, UInt opc1, UInt r1, UInt r2,
                         UInt r3, UInt b10, UInt opc2, UInt b0,
                         VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(r3   < 0x20);
   vassert(b10  < 0x2);
   vassert(opc2 < 0x200);
   vassert(b0   < 0x2);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               (r3<<11) | (b10 << 10) | (opc2<<1) | (b0));
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormXL ( UChar* p, UInt opc1, UInt f1, UInt f2,
                         UInt f3, UInt opc2, UInt b0, VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(f1   < 0x20);
   vassert(f2   < 0x20);
   vassert(f3   < 0x20);
   vassert(opc2 < 0x400);
   vassert(b0   < 0x2);
   theInstr = ((opc1<<26) | (f1<<21) | (f2<<16) |
               (f3<<11) | (opc2<<1) | (b0));
   return emit32(p, theInstr, endness_host);
}

// Note: for split field ops, give mnemonic arg
static UChar* mkFormXFX ( UChar* p, UInt r1, UInt f2, UInt opc2,
                          VexEndness endness_host )
{
   UInt theInstr;
   vassert(r1   < 0x20);
   vassert(f2   < 0x20);
   vassert(opc2 < 0x400);
   switch (opc2) {
   case 144:  // mtcrf
      vassert(f2 < 0x100);
      f2 = f2 << 1;
      break;
   case 339:  // mfspr
   case 371:  // mftb
   case 467:  // mtspr
      vassert(f2 < 0x400);
      // re-arrange split field
      f2 = ((f2>>5) & 0x1F) | ((f2 & 0x1F)<<5);
      break;
   default: vpanic("mkFormXFX(ppch)");
   }
   theInstr = ((31<<26) | (r1<<21) | (f2<<11) | (opc2<<1));
   return emit32(p, theInstr, endness_host);
}

// Only used by mtfsf
static UChar* mkFormXFL ( UChar* p, UInt FM, UInt freg, UInt dfp_rm,
                          VexEndness endness_host )
{
   UInt theInstr;
   vassert(FM   < 0x100);
   vassert(freg < 0x20);
   theInstr = ((63<<26) | (FM<<17) | (dfp_rm<<16) | (freg<<11) | (711<<1));
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormXS ( UChar* p, UInt opc1, UInt r1, UInt r2,
                         UInt imm, UInt opc2, UInt b0,
                         VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(imm  < 0x40);
   vassert(opc2 < 0x400);
   vassert(b0   < 0x2);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               ((imm & 0x1F)<<11) | (opc2<<2) | ((imm>>5)<<1) | (b0));
   return emit32(p, theInstr, endness_host);
}


#if 0
// 'b'
static UChar* mkFormI ( UChar* p, UInt LI, UInt AA, UInt LK,
                        VexEndness endness_host )
{
   UInt theInstr;
   vassert(LI  < 0x1000000);
   vassert(AA  < 0x2);
   vassert(LK  < 0x2);
   theInstr = ((18<<26) | (LI<<2) | (AA<<1) | (LK));
   return emit32(p, theInstr, endness_host);
}
#endif

// 'bc'
static UChar* mkFormB ( UChar* p, UInt BO, UInt BI,
                        UInt BD, UInt AA, UInt LK, VexEndness endness_host )
{
   UInt theInstr;
   vassert(BO  < 0x20);
   vassert(BI  < 0x20);
   vassert(BD  < 0x4000);
   vassert(AA  < 0x2);
   vassert(LK  < 0x2);
   theInstr = ((16<<26) | (BO<<21) | (BI<<16) |
               (BD<<2) | (AA<<1) | (LK));
   return emit32(p, theInstr, endness_host);
}

// rotates
static UChar* mkFormM ( UChar* p, UInt opc1, UInt r1, UInt r2,
                        UInt f3, UInt MB, UInt ME, UInt Rc,
                        VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(f3   < 0x20);
   vassert(MB   < 0x20);
   vassert(ME   < 0x20);
   vassert(Rc   < 0x2);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               (f3<<11) | (MB<<6) | (ME<<1) | (Rc));
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormA ( UChar* p, UInt opc1, UInt r1, UInt r2,
                        UInt r3, UInt r4, UInt opc2, UInt b0,
                        VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(r3   < 0x20);
   vassert(r4   < 0x20);
   vassert(opc2 < 0x20);
   vassert(b0   < 0x2 );
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (r3<<11) |
               (r4<<6) | (opc2<<1) | (b0));
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormZ22 ( UChar* p, UInt opc1, UInt r1, UInt r2,
                          UInt constant, UInt opc2, UInt b0,
                          VexEndness endness_host)
{
   UInt theInstr;
   vassert(opc1     < 0x40);
   vassert(r1       < 0x20);
   vassert(r2       < 0x20);
   vassert(constant < 0x40);   /* 6 bit constant */
   vassert(opc2     < 0x200);  /* 9 bit field */
   vassert(b0       < 0x2);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               (constant<<10) | (opc2<<1) | (b0));
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormZ23 ( UChar* p, UInt opc1, UInt r1, UInt r2,
                          UInt r3, UInt rmc, UInt opc2, UInt b0,
                          VexEndness endness_host)
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(r3   < 0x20);
   vassert(rmc  < 0x4);
   vassert(opc2 < 0x100);
   vassert(b0   < 0x2);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               (r3<<11) | (rmc<<9) | (opc2<<1) | (b0));
   return emit32(p, theInstr, endness_host);
}

static UChar* doAMode_IR ( UChar* p, UInt opc1, UInt rSD,
                           PPCAMode* am, Bool mode64, VexEndness endness_host )
{
   UInt rA, idx;
   vassert(am->tag == Pam_IR);
   vassert(am->Pam.IR.index < 0x10000);

   rA  = iregEnc(am->Pam.IR.base, mode64);
   idx = am->Pam.IR.index;

   if (opc1 == 58 || opc1 == 62) { // ld/std: mode64 only
      vassert(mode64);
      /* stay sane with DS form: lowest 2 bits must be 00.  This
         should be guaranteed to us by iselWordExpr_AMode. */
      vassert(0 == (idx & 3));
   }
   p = mkFormD(p, opc1, rSD, rA, idx, endness_host);
   return p;
}

static UChar* doAMode_RR ( UChar* p, UInt opc1, UInt opc2,
                           UInt rSD, PPCAMode* am, Bool mode64,
                           VexEndness endness_host )
{
   UInt rA, rB;
   vassert(am->tag == Pam_RR);

   rA  = iregEnc(am->Pam.RR.base, mode64);
   rB  = iregEnc(am->Pam.RR.index, mode64);
   
   p = mkFormX(p, opc1, rSD, rA, rB, opc2, 0, endness_host);
   return p;
}


/* Load imm to r_dst */
static UChar* mkLoadImm ( UChar* p, UInt r_dst, ULong imm, Bool mode64,
                          VexEndness endness_host )
{
   vassert(r_dst < 0x20);

   if (!mode64) {
      /* In 32-bit mode, make sure the top 32 bits of imm are a sign
         extension of the bottom 32 bits, so that the range tests
         below work correctly. */
      UInt u32 = (UInt)imm;
      Int  s32 = (Int)u32;
      Long s64 = (Long)s32;
      imm = (ULong)s64;
   }

   if (imm >= 0xFFFFFFFFFFFF8000ULL || imm < 0x8000) {
      // sign-extendable from 16 bits

      // addi r_dst,0,imm  => li r_dst,imm
      p = mkFormD(p, 14, r_dst, 0, imm & 0xFFFF, endness_host);
   } else {
      if (imm >= 0xFFFFFFFF80000000ULL || imm < 0x80000000ULL) {
         // sign-extendable from 32 bits

         // addis r_dst,r0,(imm>>16) => lis r_dst, (imm>>16)
         p = mkFormD(p, 15, r_dst, 0, (imm>>16) & 0xFFFF, endness_host);
         // ori r_dst, r_dst, (imm & 0xFFFF)
         p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
      } else {
         // full 64bit immediate load: 5 (five!) insns.
         vassert(mode64);

         // load high word

         // lis r_dst, (imm>>48) & 0xFFFF
         p = mkFormD(p, 15, r_dst, 0, (imm>>48) & 0xFFFF, endness_host);

         // ori r_dst, r_dst, (imm>>32) & 0xFFFF
         if ((imm>>32) & 0xFFFF)
	   p = mkFormD(p, 24, r_dst, r_dst, (imm>>32) & 0xFFFF, endness_host);
         
         // shift r_dst low word to high word => rldicr
         p = mkFormMD(p, 30, r_dst, r_dst, 32, 31, 1, endness_host);

         // load low word

         // oris r_dst, r_dst, (imm>>16) & 0xFFFF
         if ((imm>>16) & 0xFFFF)
            p = mkFormD(p, 25, r_dst, r_dst, (imm>>16) & 0xFFFF, endness_host);

         // ori r_dst, r_dst, (imm) & 0xFFFF
         if (imm & 0xFFFF)
            p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
      }
   }
   return p;
}

/* A simplified version of mkLoadImm that always generates 2 or 5
   instructions (32 or 64 bits respectively) even if it could generate
   fewer.  This is needed for generating fixed sized patchable
   sequences. */
static UChar* mkLoadImm_EXACTLY2or5 ( UChar* p,
                                      UInt r_dst, ULong imm, Bool mode64,
                                      VexEndness endness_host )
{
   vassert(r_dst < 0x20);

   if (!mode64) {
      /* In 32-bit mode, make sure the top 32 bits of imm are a sign
         extension of the bottom 32 bits.  (Probably unnecessary.) */
      UInt u32 = (UInt)imm;
      Int  s32 = (Int)u32;
      Long s64 = (Long)s32;
      imm = (ULong)s64;
   }

   if (!mode64) {
      // addis r_dst,r0,(imm>>16) => lis r_dst, (imm>>16)
      p = mkFormD(p, 15, r_dst, 0, (imm>>16) & 0xFFFF, endness_host);
      // ori r_dst, r_dst, (imm & 0xFFFF)
      p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);

   } else {
      // full 64bit immediate load: 5 (five!) insns.

      // load high word
      // lis r_dst, (imm>>48) & 0xFFFF
      p = mkFormD(p, 15, r_dst, 0, (imm>>48) & 0xFFFF, endness_host);

      // ori r_dst, r_dst, (imm>>32) & 0xFFFF
      p = mkFormD(p, 24, r_dst, r_dst, (imm>>32) & 0xFFFF, endness_host);
         
      // shift r_dst low word to high word => rldicr
      p = mkFormMD(p, 30, r_dst, r_dst, 32, 31, 1, endness_host);

      // load low word
      // oris r_dst, r_dst, (imm>>16) & 0xFFFF
      p = mkFormD(p, 25, r_dst, r_dst, (imm>>16) & 0xFFFF, endness_host);

      // ori r_dst, r_dst, (imm) & 0xFFFF
      p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
   }
   return p;
}

/* Checks whether the sequence of bytes at p was indeed created
   by mkLoadImm_EXACTLY2or5 with the given parameters. */
static Bool isLoadImm_EXACTLY2or5 ( UChar* p_to_check,
                                    UInt r_dst, ULong imm, Bool mode64,
                                    VexEndness endness_host )
{
   vassert(r_dst < 0x20);

   if (!mode64) {
      /* In 32-bit mode, make sure the top 32 bits of imm are a sign
         extension of the bottom 32 bits.  (Probably unnecessary.) */
      UInt u32 = (UInt)imm;
      Int  s32 = (Int)u32;
      Long s64 = (Long)s32;
      imm = (ULong)s64;
   }

   if (!mode64) {
      UInt   expect[2] = { 0, 0 };
      UChar* p         = (UChar*)&expect[0];
      // addis r_dst,r0,(imm>>16) => lis r_dst, (imm>>16)
      p = mkFormD(p, 15, r_dst, 0, (imm>>16) & 0xFFFF, endness_host);
      // ori r_dst, r_dst, (imm & 0xFFFF)
      p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);
      vassert(p == (UChar*)&expect[2]);

      return fetch32(p_to_check + 0, endness_host) == expect[0]
             && fetch32(p_to_check + 4, endness_host) == expect[1];

   } else {
      UInt   expect[5] = { 0, 0, 0, 0, 0 };
      UChar* p         = (UChar*)&expect[0];
      // full 64bit immediate load: 5 (five!) insns.

      // load high word
      // lis r_dst, (imm>>48) & 0xFFFF
      p = mkFormD(p, 15, r_dst, 0, (imm>>48) & 0xFFFF, endness_host);

      // ori r_dst, r_dst, (imm>>32) & 0xFFFF
      p = mkFormD(p, 24, r_dst, r_dst, (imm>>32) & 0xFFFF, endness_host);
         
      // shift r_dst low word to high word => rldicr
      p = mkFormMD(p, 30, r_dst, r_dst, 32, 31, 1, endness_host);

      // load low word
      // oris r_dst, r_dst, (imm>>16) & 0xFFFF
      p = mkFormD(p, 25, r_dst, r_dst, (imm>>16) & 0xFFFF, endness_host);

      // ori r_dst, r_dst, (imm) & 0xFFFF
      p = mkFormD(p, 24, r_dst, r_dst, imm & 0xFFFF, endness_host);

      vassert(p == (UChar*)&expect[5]);

      return fetch32(p_to_check + 0, endness_host) == expect[0]
             && fetch32(p_to_check + 4,  endness_host) == expect[1]
             && fetch32(p_to_check + 8,  endness_host) == expect[2]
             && fetch32(p_to_check + 12, endness_host) == expect[3]
             && fetch32(p_to_check + 16, endness_host) == expect[4];
   }
}


/* Generate a machine-word sized load or store.  Simplified version of
   the Pin_Load and Pin_Store cases below. */
static UChar* do_load_or_store_machine_word ( 
                 UChar* p, Bool isLoad,
                 UInt reg, PPCAMode* am, Bool mode64, VexEndness endness_host )
{
   if (isLoad) {
      UInt opc1, sz = mode64 ? 8 : 4;
      switch (am->tag) {
         case Pam_IR:
            if (mode64) {
               vassert(0 == (am->Pam.IR.index & 3));
            }
            switch (sz) {
               case 4:  opc1 = 32; vassert(!mode64); break;
               case 8:  opc1 = 58; vassert(mode64);  break;
               default: vassert(0);
            }
            p = doAMode_IR(p, opc1, reg, am, mode64, endness_host);
            break;
         case Pam_RR:
            /* we could handle this case, but we don't expect to ever
               need to. */
            vassert(0);
         default:
            vassert(0);
      }
   } else /*store*/ {
      UInt opc1, sz = mode64 ? 8 : 4;
      switch (am->tag) {
         case Pam_IR:
            if (mode64) {
               vassert(0 == (am->Pam.IR.index & 3));
            }
            switch (sz) {
               case 4:  opc1 = 36; vassert(!mode64); break;
               case 8:  opc1 = 62; vassert(mode64);  break;
               default: vassert(0);
            }
            p = doAMode_IR(p, opc1, reg, am, mode64, endness_host);
            break;
         case Pam_RR:
            /* we could handle this case, but we don't expect to ever
               need to. */
            vassert(0);
         default:
            vassert(0);
      }
   }
   return p;
}

/* Generate a 32-bit sized load or store.  Simplified version of
   do_load_or_store_machine_word above. */
static UChar* do_load_or_store_word32 ( 
                 UChar* p, Bool isLoad,
                 UInt reg, PPCAMode* am, Bool mode64, VexEndness endness_host )
{
   if (isLoad) {
      UInt opc1;
      switch (am->tag) {
         case Pam_IR:
            if (mode64) {
               vassert(0 == (am->Pam.IR.index & 3));
            }
            opc1 = 32;
            p = doAMode_IR(p, opc1, reg, am, mode64, endness_host);
            break;
         case Pam_RR:
            /* we could handle this case, but we don't expect to ever
               need to. */
            vassert(0);
         default:
            vassert(0);
      }
   } else /*store*/ {
      UInt opc1;
      switch (am->tag) {
         case Pam_IR:
            if (mode64) {
               vassert(0 == (am->Pam.IR.index & 3));
            }
            opc1 = 36;
            p = doAMode_IR(p, opc1, reg, am, mode64, endness_host);
            break;
         case Pam_RR:
            /* we could handle this case, but we don't expect to ever
               need to. */
            vassert(0);
         default:
            vassert(0);
      }
   }
   return p;
}

/* Move r_dst to r_src */
static UChar* mkMoveReg ( UChar* p, UInt r_dst, UInt r_src,
                          VexEndness endness_host )
{
   vassert(r_dst < 0x20);
   vassert(r_src < 0x20);

   if (r_dst != r_src) {
      /* or r_dst, r_src, r_src */
      p = mkFormX(p, 31, r_src, r_dst, r_src, 444, 0, endness_host );
   }
   return p;
}

static UChar* mkFormVX ( UChar* p, UInt opc1, UInt r1, UInt r2,
                         UInt r3, UInt opc2, VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(r3   < 0x20);
   vassert(opc2 < 0x800);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (r3<<11) | opc2);
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormVXI ( UChar* p, UInt opc1, UInt r1, UInt r2,
                          UInt r3, UInt opc2, VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(r3   < 0x20);
   vassert(opc2 < 0x27);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) | (r3<<11) | opc2<<1);
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormVXR ( UChar* p, UInt opc1, UInt r1, UInt r2,
                          UInt r3, UInt Rc, UInt opc2,
                          VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(r3   < 0x20);
   vassert(Rc   < 0x2);
   vassert(opc2 < 0x400);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               (r3<<11) | (Rc<<10) | opc2);
   return emit32(p, theInstr, endness_host);
}

static UChar* mkFormVA ( UChar* p, UInt opc1, UInt r1, UInt r2,
                         UInt r3, UInt r4, UInt opc2, VexEndness endness_host )
{
   UInt theInstr;
   vassert(opc1 < 0x40);
   vassert(r1   < 0x20);
   vassert(r2   < 0x20);
   vassert(r3   < 0x20);
   vassert(r4   < 0x20);
   vassert(opc2 < 0x40);
   theInstr = ((opc1<<26) | (r1<<21) | (r2<<16) |
               (r3<<11) | (r4<<6) | opc2);
   return emit32(p, theInstr, endness_host);
}



/* Emit an instruction into buf and return the number of bytes used.
   Note that buf is not the insn's final place, and therefore it is
   imperative to emit position-independent code.  If the emitted
   instruction was a profiler inc, set *is_profInc to True, else leave
   it unchanged.
*/
Int emit_PPCInstr ( /*MB_MOD*/Bool* is_profInc,
                    UChar* buf, Int nbuf, const PPCInstr* i, 
                    Bool mode64, VexEndness endness_host,
                    const void* disp_cp_chain_me_to_slowEP,
                    const void* disp_cp_chain_me_to_fastEP,
                    const void* disp_cp_xindir,
                    const void* disp_cp_xassisted)
{
   UChar* p = &buf[0];
   vassert(nbuf >= 32);

   if (0) {
      vex_printf("asm  ");ppPPCInstr(i, mode64); vex_printf("\n");
   }

   switch (i->tag) {

   case Pin_LI:
      p = mkLoadImm(p, iregEnc(i->Pin.LI.dst, mode64),
                    i->Pin.LI.imm64, mode64, endness_host);
      goto done;

   case Pin_Alu: {
      PPCRH* srcR   = i->Pin.Alu.srcR;
      Bool   immR   = toBool(srcR->tag == Prh_Imm);
      UInt   r_dst  = iregEnc(i->Pin.Alu.dst, mode64);
      UInt   r_srcL = iregEnc(i->Pin.Alu.srcL, mode64);
      UInt   r_srcR = immR ? (-1)/*bogus*/ :
                             iregEnc(srcR->Prh.Reg.reg, mode64);

      switch (i->Pin.Alu.op) {
      case Palu_ADD:
         if (immR) {
            /* addi (PPC32 p350) */
            vassert(srcR->Prh.Imm.syned);
            vassert(srcR->Prh.Imm.imm16 != 0x8000);
            p = mkFormD(p, 14, r_dst, r_srcL, srcR->Prh.Imm.imm16, endness_host);
         } else {
            /* add (PPC32 p347) */
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 266, 0, endness_host);
         }
         break;

      case Palu_SUB:
         if (immR) {
            /* addi (PPC32 p350), but with negated imm */
            vassert(srcR->Prh.Imm.syned);
            vassert(srcR->Prh.Imm.imm16 != 0x8000);
            p = mkFormD(p, 14, r_dst, r_srcL, (- srcR->Prh.Imm.imm16),
                        endness_host);
         } else {
            /* subf (PPC32 p537), with args the "wrong" way round */
            p = mkFormXO(p, 31, r_dst, r_srcR, r_srcL, 0, 40, 0, endness_host);
         }
         break;

      case Palu_AND:
         if (immR) {
            /* andi. (PPC32 p358) */
            vassert(!srcR->Prh.Imm.syned);
            p = mkFormD(p, 28, r_srcL, r_dst, srcR->Prh.Imm.imm16, endness_host);
         } else {
            /* and (PPC32 p356) */
            p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 28, 0, endness_host);
         }
         break;

      case Palu_OR:
         if (immR) {
            /* ori (PPC32 p497) */
            vassert(!srcR->Prh.Imm.syned);
            p = mkFormD(p, 24, r_srcL, r_dst, srcR->Prh.Imm.imm16, endness_host);
         } else {
            /* or (PPC32 p495) */
            p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 444, 0, endness_host);
         }
         break;

      case Palu_XOR:
         if (immR) {
            /* xori (PPC32 p550) */
            vassert(!srcR->Prh.Imm.syned);
            p = mkFormD(p, 26, r_srcL, r_dst, srcR->Prh.Imm.imm16, endness_host);
         } else {
            /* xor (PPC32 p549) */
            p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 316, 0, endness_host);
         }
         break;

      default:
         goto bad;
      }
      goto done;
   }

   case Pin_Shft: {
      PPCRH* srcR   = i->Pin.Shft.srcR;
      Bool   sz32   = i->Pin.Shft.sz32;
      Bool   immR   = toBool(srcR->tag == Prh_Imm);
      UInt   r_dst  = iregEnc(i->Pin.Shft.dst, mode64);
      UInt   r_srcL = iregEnc(i->Pin.Shft.srcL, mode64);
      UInt   r_srcR = immR ? (-1)/*bogus*/ :
                             iregEnc(srcR->Prh.Reg.reg, mode64);
      if (!mode64)
         vassert(sz32);

      switch (i->Pin.Shft.op) {
      case Pshft_SHL:
         if (sz32) {
            if (immR) {
               /* rd = rs << n, 1 <= n <= 31
                  is
                  rlwinm rd,rs,n,0,31-n  (PPC32 p501)
               */
               UInt n = srcR->Prh.Imm.imm16;
               vassert(!srcR->Prh.Imm.syned);
               vassert(n > 0 && n < 32);
               p = mkFormM(p, 21, r_srcL, r_dst, n, 0, 31-n, 0, endness_host);
            } else {
               /* slw (PPC32 p505) */
               p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 24, 0, endness_host);
            }
         } else {
            if (immR) {
               /* rd = rs << n, 1 <= n <= 63
                  is
                  rldicr rd,rs,n,63-n  (PPC64 p559)
               */
               UInt n = srcR->Prh.Imm.imm16;
               vassert(!srcR->Prh.Imm.syned);
               vassert(n > 0 && n < 64);
               p = mkFormMD(p, 30, r_srcL, r_dst, n, 63-n, 1, endness_host);
            } else {
               /* sld (PPC64 p568) */
               p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 27, 0, endness_host);
            }
         }
         break;

      case Pshft_SHR:
         if (sz32) {
             if (immR) {
               /* rd = rs >>u n, 1 <= n <= 31
                  is
                  rlwinm rd,rs,32-n,n,31  (PPC32 p501)
               */
               UInt n = srcR->Prh.Imm.imm16;
               vassert(!srcR->Prh.Imm.syned);
               vassert(n > 0 && n < 32);
               p = mkFormM(p, 21, r_srcL, r_dst, 32-n, n, 31, 0, endness_host);
            } else {
               /* srw (PPC32 p508) */
               p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 536, 0, endness_host);
            }
         } else {
            if (immR) {
               /* rd = rs >>u n, 1 <= n <= 63
                  is
                  rldicl rd,rs,64-n,n  (PPC64 p558)
               */
               UInt n = srcR->Prh.Imm.imm16;
               vassert(!srcR->Prh.Imm.syned);
               vassert(n > 0 && n < 64);
               p = mkFormMD(p, 30, r_srcL, r_dst, 64-n, n, 0, endness_host);
            } else {
               /* srd (PPC64 p574) */
               p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 539, 0, endness_host);
            }
         }
         break;

      case Pshft_SAR:
         if (sz32) {
            if (immR) {
               /* srawi (PPC32 p507) */
               UInt n = srcR->Prh.Imm.imm16;
               vassert(!srcR->Prh.Imm.syned);
               /* In 64-bit mode, we allow right shifts by zero bits
                  as that is a handy way to sign extend the lower 32
                  bits into the upper 32 bits. */
               if (mode64)
                  vassert(n >= 0 && n < 32);
               else 
                  vassert(n > 0 && n < 32);
               p = mkFormX(p, 31, r_srcL, r_dst, n, 824, 0, endness_host);
            } else {
               /* sraw (PPC32 p506) */
               p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 792, 0, endness_host);
            }
         } else {
            if (immR) {
               /* sradi (PPC64 p571) */
               UInt n = srcR->Prh.Imm.imm16;
               vassert(!srcR->Prh.Imm.syned);
               vassert(n > 0 && n < 64);
               p = mkFormXS(p, 31, r_srcL, r_dst, n, 413, 0, endness_host);
            } else {
               /* srad (PPC32 p570) */
               p = mkFormX(p, 31, r_srcL, r_dst, r_srcR, 794, 0, endness_host);
            }
         }
         break;

      default:
         goto bad;
      }
      goto done;
   }

   case Pin_AddSubC: {
      Bool isAdd  = i->Pin.AddSubC.isAdd;
      Bool setC   = i->Pin.AddSubC.setC;
      UInt r_srcL = iregEnc(i->Pin.AddSubC.srcL, mode64);
      UInt r_srcR = iregEnc(i->Pin.AddSubC.srcR, mode64);
      UInt r_dst  = iregEnc(i->Pin.AddSubC.dst, mode64);
      
      if (isAdd) {
         if (setC) /* addc (PPC32 p348) */
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 10, 0, endness_host);
         else          /* adde (PPC32 p349) */
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 138, 0, endness_host);
      } else {
         /* subfX, with args the "wrong" way round */
         if (setC) /* subfc (PPC32 p538) */
            p = mkFormXO(p, 31, r_dst, r_srcR, r_srcL, 0, 8, 0, endness_host);
         else          /* subfe (PPC32 p539) */
            p = mkFormXO(p, 31, r_dst, r_srcR, r_srcL, 0, 136, 0, endness_host);
      }
      goto done;
   }

   case Pin_Cmp: {
      Bool syned  = i->Pin.Cmp.syned;
      Bool sz32   = i->Pin.Cmp.sz32;
      UInt fld1   = i->Pin.Cmp.crfD << 2;
      UInt r_srcL = iregEnc(i->Pin.Cmp.srcL, mode64);
      UInt r_srcR, imm_srcR;
      PPCRH* srcR = i->Pin.Cmp.srcR;

      if (!mode64)        // cmp double word invalid for mode32
         vassert(sz32);      
      else if (!sz32)     // mode64 && cmp64: set L=1
         fld1 |= 1;
 
      switch (srcR->tag) {
      case Prh_Imm:
         vassert(syned == srcR->Prh.Imm.syned);
         imm_srcR = srcR->Prh.Imm.imm16;
         if (syned) {  // cmpw/di  (signed)   (PPC32 p368)
            vassert(imm_srcR != 0x8000);
            p = mkFormD(p, 11, fld1, r_srcL, imm_srcR, endness_host);
         } else {      // cmplw/di (unsigned) (PPC32 p370)
            p = mkFormD(p, 10, fld1, r_srcL, imm_srcR, endness_host);
         }
         break;
      case Prh_Reg:
         r_srcR = iregEnc(srcR->Prh.Reg.reg, mode64);
         if (syned)  // cmpwi  (signed)   (PPC32 p367)
            p = mkFormX(p, 31, fld1, r_srcL, r_srcR, 0, 0, endness_host);
         else        // cmplwi (unsigned) (PPC32 p379)
            p = mkFormX(p, 31, fld1, r_srcL, r_srcR, 32, 0, endness_host);
         break;
      default: 
         goto bad;
      }        
      goto done;
   }

   case Pin_Unary: {
      UInt r_dst = iregEnc(i->Pin.Unary.dst, mode64);
      UInt r_src = iregEnc(i->Pin.Unary.src, mode64);

      switch (i->Pin.Unary.op) {
      case Pun_NOT:  // nor r_dst,r_src,r_src
         p = mkFormX(p, 31, r_src, r_dst, r_src, 124, 0, endness_host);
         break;
      case Pun_NEG:  // neg r_dst,r_src
         p = mkFormXO(p, 31, r_dst, r_src, 0, 0, 104, 0, endness_host);
         break;
      case Pun_CLZ32:  // cntlzw r_dst, r_src
         p = mkFormX(p, 31, r_src, r_dst, 0, 26, 0, endness_host);
         break;
      case Pun_CLZ64:  // cntlzd r_dst, r_src
         vassert(mode64);
         p = mkFormX(p, 31, r_src, r_dst, 0, 58, 0, endness_host);
         break;
      case Pun_EXTSW:  // extsw r_dst, r_src
         vassert(mode64);
         p = mkFormX(p, 31, r_src, r_dst, 0, 986, 0, endness_host);
         break;
      default: goto bad;
      }
      goto done;
   }

   case Pin_MulL: {
      Bool syned  = i->Pin.MulL.syned;
      Bool sz32   = i->Pin.MulL.sz32;
      UInt r_dst  = iregEnc(i->Pin.MulL.dst, mode64);
      UInt r_srcL = iregEnc(i->Pin.MulL.srcL, mode64);
      UInt r_srcR = iregEnc(i->Pin.MulL.srcR, mode64);

      if (!mode64)
         vassert(sz32);

      if (i->Pin.MulL.hi) {
         // mul hi words, must consider sign
         if (sz32) {
            if (syned)  // mulhw r_dst,r_srcL,r_srcR
               p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 75, 0,
                            endness_host);
            else        // mulhwu r_dst,r_srcL,r_srcR
               p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 11, 0,
                            endness_host);
         } else {
            if (syned)  // mulhd r_dst,r_srcL,r_srcR
               p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 73, 0,
                            endness_host);
            else        // mulhdu r_dst,r_srcL,r_srcR
               p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 9, 0, endness_host);
         }
      } else {
         // mul low word, sign is irrelevant
         vassert(!i->Pin.MulL.syned);
         if (sz32)      // mullw r_dst,r_srcL,r_srcR
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 235, 0, endness_host);
         else           // mulld r_dst,r_srcL,r_srcR
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 233, 0, endness_host);
      }
      goto done;
   }

   case Pin_Div: {
      Bool syned  = i->Pin.Div.syned;
      Bool sz32   = i->Pin.Div.sz32;
      UInt r_dst  = iregEnc(i->Pin.Div.dst, mode64);
      UInt r_srcL = iregEnc(i->Pin.Div.srcL, mode64);
      UInt r_srcR = iregEnc(i->Pin.Div.srcR, mode64);

      if (!mode64)
         vassert(sz32);

      if (i->Pin.Div.extended) {
         if (sz32) {
            if (syned)
               // divwe r_dst,r_srcL,r_srcR
               p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 427, 0,
                            endness_host);
            else
               // divweu r_dst,r_srcL,r_srcR
               p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 395, 0,
                            endness_host);
         } else {
            if (syned)
               // divde r_dst,r_srcL,r_srcR
               p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 425, 0,
                            endness_host);
            else
               // divdeu r_dst,r_srcL,r_srcR
               p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 393, 0,
                            endness_host);
         }
      } else if (sz32) {
         if (syned)  // divw r_dst,r_srcL,r_srcR
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 491, 0, endness_host);
         else        // divwu r_dst,r_srcL,r_srcR
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 459, 0, endness_host);
      } else {
         if (syned)  // divd r_dst,r_srcL,r_srcR
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 489, 0, endness_host);
         else        // divdu r_dst,r_srcL,r_srcR
            p = mkFormXO(p, 31, r_dst, r_srcL, r_srcR, 0, 457, 0, endness_host);
      }
      goto done;
   }

   case Pin_Call: {
      if (i->Pin.Call.cond.test != Pct_ALWAYS
          && i->Pin.Call.rloc.pri != RLPri_None) {
         /* The call might not happen (it isn't unconditional) and it
            returns a result.  In this case we will need to generate a
            control flow diamond to put 0x555..555 in the return
            register(s) in the case where the call doesn't happen.  If
            this ever becomes necessary, maybe copy code from the ARM
            equivalent.  Until that day, just give up. */
         goto bad;
      }
      PPCCondCode cond  = i->Pin.Call.cond;
      UInt        r_dst = 10;
      /* As per detailed comment for Pin_Call in
         getRegUsage_PPCInstr above, %r10 is used as an address temp */

      /* jump over the following insns if condition does not hold */
      UChar* ptmp = NULL;
      if (cond.test != Pct_ALWAYS) {
         /* jmp fwds if !condition */
         /* don't know how many bytes to jump over yet...
            make space for a jump instruction and fill in later. */
         ptmp = p; /* fill in this bit later */
         p += 4;                                          // p += 4
      }

      /* load target to r_dst */                          // p += 4|8|20
      p = mkLoadImm(p, r_dst, i->Pin.Call.target, mode64, endness_host);

      /* mtspr 9,r_dst => move r_dst to count register */
      p = mkFormXFX(p, r_dst, 9, 467, endness_host);               // p += 4
      
      /* bctrl => branch to count register (and save to lr) */
      p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 1, endness_host); // p += 4

      /* Fix up the conditional jump, if there was one. */
      if (cond.test != Pct_ALWAYS) {
         Int delta = p - ptmp;
         vassert(delta >= 16 && delta <= 32);
         /* bc !ct,cf,delta */
         mkFormB(ptmp, invertCondTest(cond.test),
                 cond.flag, (delta>>2), 0, 0, endness_host);
      }
      goto done;
   }

   case Pin_XDirect: {
      /* NB: what goes on here has to be very closely coordinated
         with the chainXDirect_PPC and unchainXDirect_PPC below. */
      /* We're generating chain-me requests here, so we need to be
            sure this is actually allowed -- no-redir translations
            can't use chain-me's.  Hence: */
      vassert(disp_cp_chain_me_to_slowEP != NULL);
      vassert(disp_cp_chain_me_to_fastEP != NULL);

      /* First off, if this is conditional, create a conditional jump
         over the rest of it.  Or at least, leave a space for it that
         we will shortly fill in. */
      UChar* ptmp = NULL;
      if (i->Pin.XDirect.cond.test != Pct_ALWAYS) {
         vassert(i->Pin.XDirect.cond.flag != Pcf_NONE);
         ptmp = p;
         p += 4;
      } else {
         vassert(i->Pin.XDirect.cond.flag == Pcf_NONE);
      }

      /* Update the guest CIA. */
      /* imm32/64 r30, dstGA */
      if (!mode64) vassert(0 == (((ULong)i->Pin.XDirect.dstGA) >> 32));
      p = mkLoadImm(p, /*r*/30, (ULong)i->Pin.XDirect.dstGA, mode64,
                    endness_host);
      /* stw/std r30, amCIA */
      p = do_load_or_store_machine_word(
             p, False/*!isLoad*/,
             /*r*/30, i->Pin.XDirect.amCIA, mode64, endness_host
          );

      /* --- FIRST PATCHABLE BYTE follows --- */
      /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're calling
         to) backs up the return address, so as to find the address of
         the first patchable byte.  So: don't change the number of
         instructions (32-bit: 4, 64-bit: 7) below. */
      /* imm32/64-fixed r30, VG_(disp_cp_chain_me_to_{slowEP,fastEP} */
      const void* disp_cp_chain_me
               = i->Pin.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP 
                                         : disp_cp_chain_me_to_slowEP;
      p = mkLoadImm_EXACTLY2or5(
             p, /*r*/30, (Addr)disp_cp_chain_me, mode64, endness_host);
      /* mtctr r30 */
      p = mkFormXFX(p, /*r*/30, 9, 467, endness_host);
      /* bctrl */
      p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 1, endness_host);
      /* --- END of PATCHABLE BYTES --- */

      /* Fix up the conditional jump, if there was one. */
      if (i->Pin.XDirect.cond.test != Pct_ALWAYS) {
         Int delta = p - ptmp;
         vassert(delta >= 16 && delta <= 64 && 0 == (delta & 3));
         /* bc !ct,cf,delta */
         mkFormB(ptmp, invertCondTest(i->Pin.XDirect.cond.test),
                 i->Pin.XDirect.cond.flag, (delta>>2), 0, 0, endness_host);
      }
      goto done;
   }

   case Pin_XIndir: {
      /* We're generating transfers that could lead indirectly to a
         chain-me, so we need to be sure this is actually allowed --
         no-redir translations are not allowed to reach normal
         translations without going through the scheduler.  That means
         no XDirects or XIndirs out from no-redir translations.
         Hence: */
      vassert(disp_cp_xindir != NULL);

      /* First off, if this is conditional, create a conditional jump
         over the rest of it.  Or at least, leave a space for it that
         we will shortly fill in. */
      UChar* ptmp = NULL;
      if (i->Pin.XIndir.cond.test != Pct_ALWAYS) {
         vassert(i->Pin.XIndir.cond.flag != Pcf_NONE);
         ptmp = p;
         p += 4;
      } else {
         vassert(i->Pin.XIndir.cond.flag == Pcf_NONE);
      }

      /* Update the guest CIA. */
      /* stw/std r-dstGA, amCIA */
      p = do_load_or_store_machine_word(
             p, False/*!isLoad*/,
             iregEnc(i->Pin.XIndir.dstGA, mode64),
             i->Pin.XIndir.amCIA, mode64, endness_host
          );

      /* imm32/64 r30, VG_(disp_cp_xindir) */
      p = mkLoadImm(p, /*r*/30, (ULong)(Addr)disp_cp_xindir, mode64,
                    endness_host);
      /* mtctr r30 */
      p = mkFormXFX(p, /*r*/30, 9, 467, endness_host);
      /* bctr */
      p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 0, endness_host);

      /* Fix up the conditional jump, if there was one. */
      if (i->Pin.XIndir.cond.test != Pct_ALWAYS) {
         Int delta = p - ptmp;
         vassert(delta >= 16 && delta <= 32 && 0 == (delta & 3));
         /* bc !ct,cf,delta */
         mkFormB(ptmp, invertCondTest(i->Pin.XIndir.cond.test),
                 i->Pin.XIndir.cond.flag, (delta>>2), 0, 0, endness_host);
      }
      goto done;
   }

   case Pin_XAssisted: {
      /* First off, if this is conditional, create a conditional jump
         over the rest of it.  Or at least, leave a space for it that
         we will shortly fill in. */
      UChar* ptmp = NULL;
      if (i->Pin.XAssisted.cond.test != Pct_ALWAYS) {
         vassert(i->Pin.XAssisted.cond.flag != Pcf_NONE);
         ptmp = p;
         p += 4;
      } else {
         vassert(i->Pin.XAssisted.cond.flag == Pcf_NONE);
      }

      /* Update the guest CIA. */
      /* stw/std r-dstGA, amCIA */
      p = do_load_or_store_machine_word(
             p, False/*!isLoad*/,
             iregEnc(i->Pin.XIndir.dstGA, mode64),
             i->Pin.XIndir.amCIA, mode64, endness_host
          );

      /* imm32/64 r31, $magic_number */
      UInt trcval = 0;
      switch (i->Pin.XAssisted.jk) {
         case Ijk_ClientReq:   trcval = VEX_TRC_JMP_CLIENTREQ;   break;
         case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
         //case Ijk_Sys_int128:  trcval = VEX_TRC_JMP_SYS_INT128;  break;
         //case Ijk_Yield:       trcval = VEX_TRC_JMP_YIELD;       break;
         case Ijk_EmWarn:      trcval = VEX_TRC_JMP_EMWARN;      break;
         case Ijk_EmFail:      trcval = VEX_TRC_JMP_EMFAIL;      break;
         //case Ijk_MapFail:     trcval = VEX_TRC_JMP_MAPFAIL;     break;
         case Ijk_NoDecode:    trcval = VEX_TRC_JMP_NODECODE;    break;
         case Ijk_InvalICache: trcval = VEX_TRC_JMP_INVALICACHE; break;
         case Ijk_NoRedir:     trcval = VEX_TRC_JMP_NOREDIR;     break;
         case Ijk_SigTRAP:     trcval = VEX_TRC_JMP_SIGTRAP;     break;
         //case Ijk_SigSEGV:     trcval = VEX_TRC_JMP_SIGSEGV;     break;
         case Ijk_SigBUS:        trcval = VEX_TRC_JMP_SIGBUS;    break;
         case Ijk_Boring:      trcval = VEX_TRC_JMP_BORING;      break;
         /* We don't expect to see the following being assisted. */
         //case Ijk_Ret:
         //case Ijk_Call:
         /* fallthrough */
         default: 
            ppIRJumpKind(i->Pin.XAssisted.jk);
            vpanic("emit_ARMInstr.Pin_XAssisted: unexpected jump kind");
      }
      vassert(trcval != 0);
      p = mkLoadImm(p, /*r*/31, trcval, mode64, endness_host);

      /* imm32/64 r30, VG_(disp_cp_xassisted) */
      p = mkLoadImm(p, /*r*/30,
                    (ULong)(Addr)disp_cp_xassisted, mode64,
                     endness_host);
      /* mtctr r30 */
      p = mkFormXFX(p, /*r*/30, 9, 467, endness_host);
      /* bctr */
      p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 0, endness_host);

      /* Fix up the conditional jump, if there was one. */
      if (i->Pin.XAssisted.cond.test != Pct_ALWAYS) {
         Int delta = p - ptmp;
         vassert(delta >= 16 && delta <= 32 && 0 == (delta & 3));
         /* bc !ct,cf,delta */
         mkFormB(ptmp, invertCondTest(i->Pin.XAssisted.cond.test),
                 i->Pin.XAssisted.cond.flag, (delta>>2), 0, 0, endness_host);
      }
      goto done;
   }

   case Pin_CMov: {
      UInt  r_dst, r_src;
      ULong imm_src;
      PPCCondCode cond;
      vassert(i->Pin.CMov.cond.test != Pct_ALWAYS);

      r_dst = iregEnc(i->Pin.CMov.dst, mode64);
      cond = i->Pin.CMov.cond;

      /* branch (if cond fails) over move instrs */
      UChar* ptmp = NULL;
      if (cond.test != Pct_ALWAYS) {
         /* don't know how many bytes to jump over yet...
            make space for a jump instruction and fill in later. */
         ptmp = p; /* fill in this bit later */
         p += 4;
      }

      // cond true: move src => dst
      switch (i->Pin.CMov.src->tag) {
      case Pri_Imm:
         imm_src = i->Pin.CMov.src->Pri.Imm;
         p = mkLoadImm(p, r_dst, imm_src, mode64, endness_host);  // p += 4|8|20
         break;
      case Pri_Reg:
         r_src = iregEnc(i->Pin.CMov.src->Pri.Reg, mode64);
         p = mkMoveReg(p, r_dst, r_src, endness_host);            // p += 4
         break;
      default: goto bad;
      }

      /* Fix up the conditional jump, if there was one. */
      if (cond.test != Pct_ALWAYS) {
         Int delta = p - ptmp;
         vassert(delta >= 8 && delta <= 24);
         /* bc !ct,cf,delta */
         mkFormB(ptmp, invertCondTest(cond.test),
                 cond.flag, (delta>>2), 0, 0, endness_host);
      }
      goto done;
   }

   case Pin_Load: {
      PPCAMode* am_addr = i->Pin.Load.src;
      UInt r_dst = iregEnc(i->Pin.Load.dst, mode64);
      UInt opc1, opc2, sz = i->Pin.Load.sz;
      switch (am_addr->tag) {
      case Pam_IR:
         if (mode64 && (sz == 4 || sz == 8)) {
            /* should be guaranteed to us by iselWordExpr_AMode */
            vassert(0 == (am_addr->Pam.IR.index & 3));
         }
         switch(sz) {
            case 1:  opc1 = 34; break;
            case 2:  opc1 = 40; break;
            case 4:  opc1 = 32; break;
            case 8:  opc1 = 58; vassert(mode64); break;
            default: goto bad;
         }
         p = doAMode_IR(p, opc1, r_dst, am_addr, mode64, endness_host);
         goto done;
      case Pam_RR:
         switch(sz) {
            case 1:  opc2 = 87;  break;
            case 2:  opc2 = 279; break;
            case 4:  opc2 = 23;  break;
            case 8:  opc2 = 21; vassert(mode64); break;
            default: goto bad;
         }
         p = doAMode_RR(p, 31, opc2, r_dst, am_addr, mode64, endness_host);
         goto done;
      default:
         goto bad;
      }
   }

   case Pin_LoadL: {
      if (i->Pin.LoadL.sz == 1) {
         p = mkFormX(p, 31, iregEnc(i->Pin.LoadL.dst, mode64),
                     0, iregEnc(i->Pin.LoadL.src, mode64), 52, 0, endness_host);
         goto done;
      }
      if (i->Pin.LoadL.sz == 2) {
         p = mkFormX(p, 31, iregEnc(i->Pin.LoadL.dst, mode64),
                     0, iregEnc(i->Pin.LoadL.src, mode64), 116, 0, endness_host);
         goto done;
      }
      if (i->Pin.LoadL.sz == 4) {
         p = mkFormX(p, 31, iregEnc(i->Pin.LoadL.dst, mode64),
                     0, iregEnc(i->Pin.LoadL.src, mode64), 20, 0, endness_host);
         goto done;
      }
      if (i->Pin.LoadL.sz == 8 && mode64) {
         p = mkFormX(p, 31, iregEnc(i->Pin.LoadL.dst, mode64),
                     0, iregEnc(i->Pin.LoadL.src, mode64), 84, 0, endness_host);
         goto done;
      }
      goto bad;
   }

   case Pin_Set: {
      /* Make the destination register be 1 or 0, depending on whether
         the relevant condition holds. */
      UInt        r_dst = iregEnc(i->Pin.Set.dst, mode64);
      PPCCondCode cond  = i->Pin.Set.cond;
      UInt rot_imm, r_tmp;

      if (cond.test == Pct_ALWAYS) {
         // Just load 1 to dst => li dst,1
         p = mkFormD(p, 14, r_dst, 0, 1, endness_host);
      } else {
         vassert(cond.flag != Pcf_NONE);
         rot_imm = 1 + cond.flag;
         r_tmp = 0;  // Not set in getAllocable, so no need to declare.

         // r_tmp = CR  => mfcr r_tmp
         p = mkFormX(p, 31, r_tmp, 0, 0, 19, 0, endness_host);

         // r_dst = flag (rotate left and mask)
         //  => rlwinm r_dst,r_tmp,rot_imm,31,31
         p = mkFormM(p, 21, r_tmp, r_dst, rot_imm, 31, 31, 0, endness_host);

         if (cond.test == Pct_FALSE) {
            // flip bit  => xori r_dst,r_dst,1
            p = mkFormD(p, 26, r_dst, r_dst, 1, endness_host);
         }
      }
      goto done;
   }

   case Pin_MfCR:
      // mfcr dst
      p = mkFormX(p, 31, iregEnc(i->Pin.MfCR.dst, mode64), 0, 0, 19, 0,
                  endness_host);
      goto done;

   case Pin_MFence: {
      p = mkFormX(p, 31, 0, 0, 0, 598, 0, endness_host);   // sync, PPC32 p616
      // CAB: Should this be isync?
      //    p = mkFormXL(p, 19, 0, 0, 0, 150, 0);  // isync, PPC32 p467
      goto done;
   }

   case Pin_Store: {
      PPCAMode* am_addr = i->Pin.Store.dst;
      UInt r_src = iregEnc(i->Pin.Store.src, mode64);
      UInt opc1, opc2, sz = i->Pin.Store.sz;
      switch (i->Pin.Store.dst->tag) {
      case Pam_IR:
         if (mode64 && (sz == 4 || sz == 8)) {
            /* should be guaranteed to us by iselWordExpr_AMode */
            vassert(0 == (am_addr->Pam.IR.index & 3));
         }
         switch(sz) {
         case 1: opc1 = 38; break;
         case 2: opc1 = 44; break;
         case 4: opc1 = 36; break;
         case 8: vassert(mode64);
                 opc1 = 62; break;
         default:
            goto bad;
         }
         p = doAMode_IR(p, opc1, r_src, am_addr, mode64, endness_host);
         goto done;
      case Pam_RR:
         switch(sz) {
         case 1: opc2 = 215; break;
         case 2: opc2 = 407; break;
         case 4: opc2 = 151; break;
         case 8: vassert(mode64);
                 opc2 = 149; break;
         default:
            goto bad;
         }
         p = doAMode_RR(p, 31, opc2, r_src, am_addr, mode64, endness_host);
         goto done;
      default:
         goto bad;
      }
      goto done;
   }

   case Pin_StoreC: {
      if (i->Pin.StoreC.sz == 1) {
         p = mkFormX(p, 31, iregEnc(i->Pin.StoreC.src, mode64),
                     0, iregEnc(i->Pin.StoreC.dst, mode64), 694, 1, endness_host);
         goto done;
      }
      if (i->Pin.StoreC.sz == 2) {
         p = mkFormX(p, 31, iregEnc(i->Pin.StoreC.src, mode64),
                     0, iregEnc(i->Pin.StoreC.dst, mode64), 726, 1, endness_host);
         goto done;
      }

      if (i->Pin.StoreC.sz == 4) {
         p = mkFormX(p, 31, iregEnc(i->Pin.StoreC.src, mode64),
                     0, iregEnc(i->Pin.StoreC.dst, mode64), 150, 1, endness_host);
         goto done;
      }
      if (i->Pin.StoreC.sz == 8 && mode64) {
         p = mkFormX(p, 31, iregEnc(i->Pin.StoreC.src, mode64),
                     0, iregEnc(i->Pin.StoreC.dst, mode64), 214, 1, endness_host);
         goto done;
      }
      goto bad;
   }

   case Pin_FpUnary: {
      UInt fr_dst = fregEnc(i->Pin.FpUnary.dst);
      UInt fr_src = fregEnc(i->Pin.FpUnary.src);
      switch (i->Pin.FpUnary.op) {
      case Pfp_RSQRTE: // frsqrtre, PPC32 p424
         p = mkFormA( p, 63, fr_dst, 0, fr_src, 0, 26, 0, endness_host );
         break;
      case Pfp_RES:   // fres, PPC32 p421
         p = mkFormA( p, 59, fr_dst, 0, fr_src, 0, 24, 0, endness_host );
         break;
      case Pfp_SQRT:  // fsqrt, PPC32 p427
         p = mkFormA( p, 63, fr_dst, 0, fr_src, 0, 22, 0, endness_host );
         break;
      case Pfp_ABS:   // fabs, PPC32 p399
         p = mkFormX(p, 63, fr_dst, 0, fr_src, 264, 0, endness_host);
         break;
      case Pfp_NEG:   // fneg, PPC32 p416
         p = mkFormX(p, 63, fr_dst, 0, fr_src, 40, 0, endness_host);
         break;
      case Pfp_MOV:   // fmr, PPC32 p410
         p = mkFormX(p, 63, fr_dst, 0, fr_src, 72, 0, endness_host);
         break;
      case Pfp_FRIM:  // frim, PPC ISA 2.05 p137
         p = mkFormX(p, 63, fr_dst, 0, fr_src, 488, 0, endness_host);
         break;
      case Pfp_FRIP:  // frip, PPC ISA 2.05 p137
         p = mkFormX(p, 63, fr_dst, 0, fr_src, 456, 0, endness_host);
         break;
      case Pfp_FRIN:  // frin, PPC ISA 2.05 p137
         p = mkFormX(p, 63, fr_dst, 0, fr_src, 392, 0, endness_host);
         break;
      case Pfp_FRIZ:  // friz, PPC ISA 2.05 p137
         p = mkFormX(p, 63, fr_dst, 0, fr_src, 424, 0, endness_host);
         break;
      default:
         goto bad;
      }
      goto done;
   }

   case Pin_FpBinary: {
      UInt fr_dst  = fregEnc(i->Pin.FpBinary.dst);
      UInt fr_srcL = fregEnc(i->Pin.FpBinary.srcL);
      UInt fr_srcR = fregEnc(i->Pin.FpBinary.srcR);
      switch (i->Pin.FpBinary.op) {
      case Pfp_ADDD:   // fadd, PPC32 p400
         p = mkFormA( p, 63, fr_dst, fr_srcL, fr_srcR, 0, 21, 0, endness_host );
         break;
      case Pfp_ADDS:   // fadds, PPC32 p401
         p = mkFormA( p, 59, fr_dst, fr_srcL, fr_srcR, 0, 21, 0, endness_host );
         break;
      case Pfp_SUBD:   // fsub, PPC32 p429
         p = mkFormA( p, 63, fr_dst, fr_srcL, fr_srcR, 0, 20, 0, endness_host );
         break;
      case Pfp_SUBS:   // fsubs, PPC32 p430
         p = mkFormA( p, 59, fr_dst, fr_srcL, fr_srcR, 0, 20, 0, endness_host );
         break;
      case Pfp_MULD:   // fmul, PPC32 p413
         p = mkFormA( p, 63, fr_dst, fr_srcL, 0, fr_srcR, 25, 0, endness_host );
         break;
      case Pfp_MULS:   // fmuls, PPC32 p414
         p = mkFormA( p, 59, fr_dst, fr_srcL, 0, fr_srcR, 25, 0, endness_host );
         break;
      case Pfp_DIVD:   // fdiv, PPC32 p406
         p = mkFormA( p, 63, fr_dst, fr_srcL, fr_srcR, 0, 18, 0, endness_host );
         break;
      case Pfp_DIVS:   // fdivs, PPC32 p407
         p = mkFormA( p, 59, fr_dst, fr_srcL, fr_srcR, 0, 18, 0, endness_host );
         break;
      default:
         goto bad;
      }
      goto done;
   }

   case Pin_FpMulAcc: {
      UInt fr_dst    = fregEnc(i->Pin.FpMulAcc.dst);
      UInt fr_srcML  = fregEnc(i->Pin.FpMulAcc.srcML);
      UInt fr_srcMR  = fregEnc(i->Pin.FpMulAcc.srcMR);
      UInt fr_srcAcc = fregEnc(i->Pin.FpMulAcc.srcAcc);
      switch (i->Pin.FpMulAcc.op) {
      case Pfp_MADDD:   // fmadd, PPC32 p408
         p = mkFormA( p, 63, fr_dst, fr_srcML, fr_srcAcc, fr_srcMR, 29, 0,
                      endness_host );
         break;
      case Pfp_MADDS:   // fmadds, PPC32 p409
         p = mkFormA( p, 59, fr_dst, fr_srcML, fr_srcAcc, fr_srcMR, 29, 0,
                      endness_host );
         break;
      case Pfp_MSUBD:   // fmsub, PPC32 p411
         p = mkFormA( p, 63, fr_dst, fr_srcML, fr_srcAcc, fr_srcMR, 28, 0,
                      endness_host );
         break;
      case Pfp_MSUBS:   // fmsubs, PPC32 p412
         p = mkFormA( p, 59, fr_dst, fr_srcML, fr_srcAcc, fr_srcMR, 28, 0,
                      endness_host );
         break;
      default:
         goto bad;
      }
      goto done;
   }

   case Pin_FpLdSt: {
      PPCAMode* am_addr = i->Pin.FpLdSt.addr;
      UInt f_reg = fregEnc(i->Pin.FpLdSt.reg);
      Bool idxd = toBool(i->Pin.FpLdSt.addr->tag == Pam_RR);
      UChar sz = i->Pin.FpLdSt.sz;
      UInt opc;
      vassert(sz == 4 || sz == 8);

      if (i->Pin.FpLdSt.isLoad) {   // Load from memory
         if (idxd) {  // lf[s|d]x, PPC32 p444|440
            opc = (sz == 4) ? 535 : 599;
            p = doAMode_RR(p, 31, opc, f_reg, am_addr, mode64, endness_host);
         } else {     // lf[s|d], PPC32 p441|437
            opc = (sz == 4) ? 48 : 50;
            p = doAMode_IR(p, opc, f_reg, am_addr, mode64, endness_host);
         }
      } else {                      // Store to memory
         if (idxd) { // stf[s|d]x, PPC32 p521|516
            opc = (sz == 4) ? 663 : 727;
            p = doAMode_RR(p, 31, opc, f_reg, am_addr, mode64, endness_host);
         } else {    // stf[s|d], PPC32 p518|513
            opc = (sz == 4) ? 52 : 54;
            p = doAMode_IR(p, opc, f_reg, am_addr, mode64, endness_host);
         }
      }
      goto done;
   }

   case Pin_FpSTFIW: {
      UInt ir_addr = iregEnc(i->Pin.FpSTFIW.addr, mode64);
      UInt fr_data = fregEnc(i->Pin.FpSTFIW.data);
      // stfiwx (store fp64[lo32] as int32), PPC32 p517
      // Use rA==0, so that EA == rB == ir_addr
      p = mkFormX(p, 31, fr_data, 0/*rA=0*/, ir_addr, 983, 0, endness_host);
      goto done;
   }

   case Pin_FpRSP: {
      UInt fr_dst = fregEnc(i->Pin.FpRSP.dst);
      UInt fr_src = fregEnc(i->Pin.FpRSP.src);
      // frsp, PPC32 p423
      p = mkFormX(p, 63, fr_dst, 0, fr_src, 12, 0, endness_host);
      goto done;
   }

   case Pin_FpCftI: {
      UInt fr_dst = fregEnc(i->Pin.FpCftI.dst);
      UInt fr_src = fregEnc(i->Pin.FpCftI.src);
      if (i->Pin.FpCftI.fromI == False && i->Pin.FpCftI.int32 == True) {
         if (i->Pin.FpCftI.syned == True) {
            // fctiw (conv f64 to i32), PPC32 p404
            p = mkFormX(p, 63, fr_dst, 0, fr_src, 14, 0, endness_host);
            goto done;
         } else {
            // fctiwu (conv f64 to u32)
            p = mkFormX(p, 63, fr_dst, 0, fr_src, 142, 0, endness_host);
            goto done;
         }
      }
      if (i->Pin.FpCftI.fromI == False && i->Pin.FpCftI.int32 == False) {
         if (i->Pin.FpCftI.syned == True) {
            // fctid (conv f64 to i64), PPC64 p437
            p = mkFormX(p, 63, fr_dst, 0, fr_src, 814, 0, endness_host);
            goto done;
         } else {
            // fctidu (conv f64 to u64)
            p = mkFormX(p, 63, fr_dst, 0, fr_src, 942, 0, endness_host);
            goto done;
         }
      }
      if (i->Pin.FpCftI.fromI == True && i->Pin.FpCftI.int32 == False) {
         if (i->Pin.FpCftI.syned == True) {
            // fcfid (conv i64 to f64), PPC64 p434
            p = mkFormX(p, 63, fr_dst, 0, fr_src, 846, 0, endness_host);
            goto done;
         } else if (i->Pin.FpCftI.flt64 == True) {
            // fcfidu (conv u64 to f64)
            p = mkFormX(p, 63, fr_dst, 0, fr_src, 974, 0, endness_host);
            goto done;
         } else {
            // fcfidus (conv u64 to f32)
            p = mkFormX(p, 59, fr_dst, 0, fr_src, 974, 0, endness_host);
            goto done;
         }
      }
      goto bad;
   }

   case Pin_FpCMov: {
      UInt        fr_dst = fregEnc(i->Pin.FpCMov.dst);
      UInt        fr_src = fregEnc(i->Pin.FpCMov.src);
      PPCCondCode cc     = i->Pin.FpCMov.cond;

      if (fr_dst == fr_src) goto done;
      
      vassert(cc.test != Pct_ALWAYS);

      /* jmp fwds if !condition */
      if (cc.test != Pct_ALWAYS) {
         /* bc !ct,cf,n_bytes>>2 */
         p = mkFormB(p, invertCondTest(cc.test), cc.flag, 8>>2, 0, 0,
                     endness_host);
      }

      // fmr, PPC32 p410
      p = mkFormX(p, 63, fr_dst, 0, fr_src, 72, 0, endness_host);
      goto done;
   }

   case Pin_FpLdFPSCR: {
      UInt fr_src = fregEnc(i->Pin.FpLdFPSCR.src);
      p = mkFormXFL(p, 0xFF, fr_src, i->Pin.FpLdFPSCR.dfp_rm, endness_host); // mtfsf, PPC32 p480
      goto done;
   }

   case Pin_FpCmp: {
      UChar crfD    = 1;
      UInt  r_dst   = iregEnc(i->Pin.FpCmp.dst, mode64);
      UInt  fr_srcL = fregEnc(i->Pin.FpCmp.srcL);
      UInt  fr_srcR = fregEnc(i->Pin.FpCmp.srcR);
      vassert(crfD < 8);
      // fcmpo, PPC32 p402
      p = mkFormX(p, 63, crfD<<2, fr_srcL, fr_srcR, 32, 0, endness_host);

      // mfcr (mv CR to r_dst), PPC32 p467
      p = mkFormX(p, 31, r_dst, 0, 0, 19, 0, endness_host);
      
      // rlwinm r_dst,r_dst,8,28,31, PPC32 p501
      //  => rotate field 1 to bottomw of word, masking out upper 28
      p = mkFormM(p, 21, r_dst, r_dst, 8, 28, 31, 0, endness_host);
      goto done;
   }

   case Pin_RdWrLR: {
      UInt reg = iregEnc(i->Pin.RdWrLR.gpr, mode64);
      /* wrLR==True ? mtlr r4 : mflr r4 */
      p = mkFormXFX(p, reg, 8, (i->Pin.RdWrLR.wrLR==True) ? 467 : 339,
                    endness_host);
      goto done;
   }


   /* AltiVec */
   case Pin_AvLdSt: {
      UInt opc2, v_reg, r_idx, r_base;
      UChar sz   = i->Pin.AvLdSt.sz;
      Bool  idxd = toBool(i->Pin.AvLdSt.addr->tag == Pam_RR);
      vassert(sz == 1 || sz == 2 || sz == 4 || sz == 16);

      v_reg  = vregEnc(i->Pin.AvLdSt.reg);
      r_base = iregEnc(i->Pin.AvLdSt.addr->Pam.RR.base, mode64);

      // Only have AltiVec AMode_RR: kludge AMode_IR
      if (!idxd) {
         r_idx = 30;                       // XXX: Using r30 as temp
         p = mkLoadImm(p, r_idx,
                       i->Pin.AvLdSt.addr->Pam.IR.index, mode64, endness_host);
      } else {
         r_idx  = iregEnc(i->Pin.AvLdSt.addr->Pam.RR.index, mode64);
      }

      if (i->Pin.FpLdSt.isLoad) {  // Load from memory (1,2,4,16)
         opc2 = (sz==1) ?   7 : (sz==2) ?  39 : (sz==4) ?  71 : 103;
         p = mkFormX(p, 31, v_reg, r_idx, r_base, opc2, 0, endness_host);
      } else {                      // Store to memory (1,2,4,16)
         opc2 = (sz==1) ? 135 : (sz==2) ? 167 : (sz==4) ? 199 : 231;
         p = mkFormX(p, 31, v_reg, r_idx, r_base, opc2, 0, endness_host);
      }
      goto done;
   }

   case Pin_AvUnary: {
      UInt v_dst = vregEnc(i->Pin.AvUnary.dst);
      UInt v_src = vregEnc(i->Pin.AvUnary.src);
      UInt opc2;
      switch (i->Pin.AvUnary.op) {
      case Pav_MOV:       opc2 = 1156; break; // vor vD,vS,vS
      case Pav_NOT:       opc2 = 1284; break; // vnor vD,vS,vS
      case Pav_UNPCKH8S:  opc2 =  526; break; // vupkhsb
      case Pav_UNPCKH16S: opc2 =  590; break; // vupkhsh
      case Pav_UNPCKL8S:  opc2 =  654; break; // vupklsb
      case Pav_UNPCKL16S: opc2 =  718; break; // vupklsh
      case Pav_UNPCKHPIX: opc2 =  846; break; // vupkhpx
      case Pav_UNPCKLPIX: opc2 =  974; break; // vupklpx

      case Pav_ZEROCNTBYTE: opc2 = 1794; break; // vclzb
      case Pav_ZEROCNTHALF: opc2 = 1858; break; // vclzh
      case Pav_ZEROCNTWORD: opc2 = 1922; break; // vclzw
      case Pav_ZEROCNTDBL:  opc2 = 1986; break; // vclzd
      case Pav_BITMTXXPOSE: opc2 = 1292; break; // vgbbd
      default:
         goto bad;
      }
      switch (i->Pin.AvUnary.op) {
      case Pav_MOV:
      case Pav_NOT:
         p = mkFormVX( p, 4, v_dst, v_src, v_src, opc2, endness_host );
         break;
      default:
         p = mkFormVX( p, 4, v_dst, 0, v_src, opc2, endness_host );
         break;
      }
      goto done;
   }

   case Pin_AvBinary: {
      UInt v_dst  = vregEnc(i->Pin.AvBinary.dst);
      UInt v_srcL = vregEnc(i->Pin.AvBinary.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvBinary.srcR);
      UInt opc2;
      if (i->Pin.AvBinary.op == Pav_SHL) {
         p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 1036, endness_host ); // vslo
         p = mkFormVX( p, 4, v_dst, v_dst,  v_srcR, 452, endness_host );  // vsl
         goto done;
      }
      if (i->Pin.AvBinary.op == Pav_SHR) {
         p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 1100, endness_host ); // vsro
         p = mkFormVX( p, 4, v_dst, v_dst,  v_srcR, 708, endness_host );  // vsr
         goto done;
      }
      switch (i->Pin.AvBinary.op) {
      /* Bitwise */
      case Pav_AND:       opc2 = 1028; break; // vand
      case Pav_OR:        opc2 = 1156; break; // vor
      case Pav_XOR:       opc2 = 1220; break; // vxor
      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
      goto done;
   }

   case Pin_AvBin8x16: {
      UInt v_dst  = vregEnc(i->Pin.AvBin8x16.dst);
      UInt v_srcL = vregEnc(i->Pin.AvBin8x16.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvBin8x16.srcR);
      UInt opc2;
      switch (i->Pin.AvBin8x16.op) {

      case Pav_ADDU:     opc2 =    0; break; // vaddubm
      case Pav_QADDU:    opc2 =  512; break; // vaddubs
      case Pav_QADDS:    opc2 =  768; break; // vaddsbs

      case Pav_SUBU:     opc2 = 1024; break; // vsububm
      case Pav_QSUBU:    opc2 = 1536; break; // vsububs
      case Pav_QSUBS:    opc2 = 1792; break; // vsubsbs

      case Pav_OMULU:   opc2 =    8; break; // vmuloub
      case Pav_OMULS:   opc2 =  264; break; // vmulosb
      case Pav_EMULU:   opc2 =  520; break; // vmuleub
      case Pav_EMULS:   opc2 =  776; break; // vmulesb

      case Pav_AVGU:     opc2 = 1026; break; // vavgub
      case Pav_AVGS:     opc2 = 1282; break; // vavgsb
      case Pav_MAXU:     opc2 =    2; break; // vmaxub
      case Pav_MAXS:     opc2 =  258; break; // vmaxsb
      case Pav_MINU:     opc2 =  514; break; // vminub
      case Pav_MINS:     opc2 =  770; break; // vminsb

      case Pav_CMPEQU:   opc2 =    6; break; // vcmpequb
      case Pav_CMPGTU:   opc2 =  518; break; // vcmpgtub
      case Pav_CMPGTS:   opc2 =  774; break; // vcmpgtsb

      case Pav_SHL:      opc2 =  260; break; // vslb
      case Pav_SHR:      opc2 =  516; break; // vsrb
      case Pav_SAR:      opc2 =  772; break; // vsrab
      case Pav_ROTL:     opc2 =    4; break; // vrlb

      case Pav_MRGHI:    opc2 =   12; break; // vmrghb
      case Pav_MRGLO:    opc2 =  268; break; // vmrglb

      case Pav_POLYMULADD: opc2 = 1032; break; // vpmsumb

      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
      goto done;
   }

   case Pin_AvBin16x8: {
      UInt v_dst  = vregEnc(i->Pin.AvBin16x8.dst);
      UInt v_srcL = vregEnc(i->Pin.AvBin16x8.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvBin16x8.srcR);
      UInt opc2;
      switch (i->Pin.AvBin16x8.op) {

      case Pav_ADDU:    opc2 =   64; break; // vadduhm
      case Pav_QADDU:   opc2 =  576; break; // vadduhs
      case Pav_QADDS:   opc2 =  832; break; // vaddshs

      case Pav_SUBU:    opc2 = 1088; break; // vsubuhm
      case Pav_QSUBU:   opc2 = 1600; break; // vsubuhs
      case Pav_QSUBS:   opc2 = 1856; break; // vsubshs

      case Pav_OMULU:   opc2 =   72; break; // vmulouh
      case Pav_OMULS:   opc2 =  328; break; // vmulosh
      case Pav_EMULU:   opc2 =  584; break; // vmuleuh
      case Pav_EMULS:   opc2 =  840; break; // vmulesh

      case Pav_AVGU:    opc2 = 1090; break; // vavguh
      case Pav_AVGS:    opc2 = 1346; break; // vavgsh
      case Pav_MAXU:    opc2 =   66; break; // vmaxuh
      case Pav_MAXS:    opc2 =  322; break; // vmaxsh
      case Pav_MINS:    opc2 =  834; break; // vminsh
      case Pav_MINU:    opc2 =  578; break; // vminuh

      case Pav_CMPEQU:  opc2 =   70; break; // vcmpequh
      case Pav_CMPGTU:  opc2 =  582; break; // vcmpgtuh
      case Pav_CMPGTS:  opc2 =  838; break; // vcmpgtsh

      case Pav_SHL:     opc2 =  324; break; // vslh
      case Pav_SHR:     opc2 =  580; break; // vsrh
      case Pav_SAR:     opc2 =  836; break; // vsrah
      case Pav_ROTL:    opc2 =   68; break; // vrlh

      case Pav_PACKUU:  opc2 =   14; break; // vpkuhum
      case Pav_QPACKUU: opc2 =  142; break; // vpkuhus
      case Pav_QPACKSU: opc2 =  270; break; // vpkshus
      case Pav_QPACKSS: opc2 =  398; break; // vpkshss
      case Pav_PACKPXL: opc2 =  782; break; // vpkpx

      case Pav_MRGHI:   opc2 =   76; break; // vmrghh
      case Pav_MRGLO:   opc2 =  332; break; // vmrglh

      case Pav_POLYMULADD: opc2 = 1224; break; // vpmsumh

      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
      goto done;
   }

   case Pin_AvBin32x4: {
      UInt v_dst  = vregEnc(i->Pin.AvBin32x4.dst);
      UInt v_srcL = vregEnc(i->Pin.AvBin32x4.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvBin32x4.srcR);
      UInt opc2;
      switch (i->Pin.AvBin32x4.op) {

      case Pav_ADDU:    opc2 =  128; break; // vadduwm
      case Pav_QADDU:   opc2 =  640; break; // vadduws
      case Pav_QADDS:   opc2 =  896; break; // vaddsws

      case Pav_SUBU:    opc2 = 1152; break; // vsubuwm
      case Pav_QSUBU:   opc2 = 1664; break; // vsubuws
      case Pav_QSUBS:   opc2 = 1920; break; // vsubsws

      case Pav_MULU:    opc2 =  137; break; // vmuluwm
      case Pav_OMULU:   opc2 =  136; break; // vmulouw
      case Pav_OMULS:   opc2 =  392; break; // vmulosw
      case Pav_EMULU:   opc2 =  648; break; // vmuleuw
      case Pav_EMULS:   opc2 =  904; break; // vmulesw

      case Pav_AVGU:    opc2 = 1154; break; // vavguw
      case Pav_AVGS:    opc2 = 1410; break; // vavgsw

      case Pav_MAXU:    opc2 =  130; break; // vmaxuw
      case Pav_MAXS:    opc2 =  386; break; // vmaxsw

      case Pav_MINS:    opc2 =  898; break; // vminsw
      case Pav_MINU:    opc2 =  642; break; // vminuw

      case Pav_CMPEQU:  opc2 =  134; break; // vcmpequw
      case Pav_CMPGTS:  opc2 =  902; break; // vcmpgtsw
      case Pav_CMPGTU:  opc2 =  646; break; // vcmpgtuw

      case Pav_SHL:     opc2 =  388; break; // vslw
      case Pav_SHR:     opc2 =  644; break; // vsrw
      case Pav_SAR:     opc2 =  900; break; // vsraw
      case Pav_ROTL:    opc2 =  132; break; // vrlw

      case Pav_PACKUU:  opc2 =   78; break; // vpkuwum
      case Pav_QPACKUU: opc2 =  206; break; // vpkuwus
      case Pav_QPACKSU: opc2 =  334; break; // vpkswus
      case Pav_QPACKSS: opc2 =  462; break; // vpkswss

      case Pav_MRGHI:   opc2 =  140; break; // vmrghw
      case Pav_MRGLO:   opc2 =  396; break; // vmrglw

      case Pav_CATODD:  opc2 = 1676; break; // vmrgow
      case Pav_CATEVEN: opc2 = 1932; break; // vmrgew

      case Pav_POLYMULADD: opc2 = 1160; break; // vpmsumw

      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
      goto done;
   }

   case Pin_AvBin64x2: {
      UInt v_dst  = vregEnc(i->Pin.AvBin64x2.dst);
      UInt v_srcL = vregEnc(i->Pin.AvBin64x2.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvBin64x2.srcR);
      UInt opc2;
      switch (i->Pin.AvBin64x2.op) {
      case Pav_ADDU:    opc2 =  192; break; // vaddudm  vector double add
      case Pav_SUBU:    opc2 = 1216; break; // vsubudm  vector double add
      case Pav_MAXU:    opc2 =  194; break; // vmaxud   vector double max
      case Pav_MAXS:    opc2 =  450; break; // vmaxsd   vector double max
      case Pav_MINU:    opc2 =  706; break; // vminud   vector double min
      case Pav_MINS:    opc2 =  962; break; // vminsd   vector double min
      case Pav_CMPEQU:  opc2 =  199; break; // vcmpequd vector double compare
      case Pav_CMPGTU:  opc2 =  711; break; // vcmpgtud vector double compare
      case Pav_CMPGTS:  opc2 =  967; break; // vcmpgtsd vector double compare
      case Pav_SHL:     opc2 = 1476; break; // vsld
      case Pav_SHR:     opc2 = 1732; break; // vsrd
      case Pav_SAR:     opc2 =  964; break; // vsrad
      case Pav_ROTL:    opc2 =  196; break; // vrld
      case Pav_PACKUU:  opc2 = 1102; break; // vpkudum
      case Pav_QPACKUU: opc2 = 1230; break; // vpkudus, vpksdus (emulated)
      case Pav_QPACKSS: opc2 = 1486; break; // vpksdsm
      case Pav_MRGHI:   opc2 = 1614; break; // vmrghw
      case Pav_MRGLO:   opc2 = 1742; break; // vmrglw
      case Pav_POLYMULADD: opc2 = 1096; break; // vpmsumd
      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
      goto done;
   }
   case Pin_AvCipherV128Unary: {
      UInt v_dst = vregEnc(i->Pin.AvCipherV128Unary.dst);
      UInt v_src = vregEnc(i->Pin.AvCipherV128Unary.src);
      UInt opc2;
      switch (i->Pin.AvCipherV128Unary.op) {
      case Pav_CIPHERSUBV128:   opc2 =  1480; break; // vsbox
      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, v_src, 0, opc2, endness_host );
      goto done;
   }
   case Pin_AvCipherV128Binary: {
      UInt v_dst  = vregEnc(i->Pin.AvCipherV128Binary.dst);
      UInt v_srcL = vregEnc(i->Pin.AvCipherV128Binary.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvCipherV128Binary.srcR);
      UInt opc2;
      switch (i->Pin.AvCipherV128Binary.op) {
      case Pav_CIPHERV128:     opc2 =  1288; break; // vcipher
      case Pav_CIPHERLV128:    opc2 =  1289; break; // vcipherlast
      case Pav_NCIPHERV128:    opc2 =  1352; break; // vncipher
      case Pav_NCIPHERLV128:   opc2 =  1353; break; // vncipherlast
      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, opc2, endness_host );
      goto done;
   }
   case Pin_AvHashV128Binary: {
      UInt v_dst = vregEnc(i->Pin.AvHashV128Binary.dst);
      UInt v_src = vregEnc(i->Pin.AvHashV128Binary.src);
      PPCRI* s_field = i->Pin.AvHashV128Binary.s_field;
      UInt opc2;
      switch (i->Pin.AvHashV128Binary.op) {
      case Pav_SHA256:   opc2 =  1666; break; // vshasigmaw
      case Pav_SHA512:   opc2 =  1730; break; // vshasigmad
      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, v_src, s_field->Pri.Imm, opc2, endness_host );
      goto done;
   }
   case Pin_AvBCDV128Trinary: {
      UInt v_dst  = vregEnc(i->Pin.AvBCDV128Trinary.dst);
      UInt v_src1 = vregEnc(i->Pin.AvBCDV128Trinary.src1);
      UInt v_src2 = vregEnc(i->Pin.AvBCDV128Trinary.src2);
      PPCRI* ps   = i->Pin.AvBCDV128Trinary.ps;
      UInt opc2;
      switch (i->Pin.AvBCDV128Trinary.op) {
      case Pav_BCDAdd:   opc2 =  1; break; // bcdadd
      case Pav_BCDSub:   opc2 = 65; break; // bcdsub
      default:
         goto bad;
      }
      p = mkFormVXR( p, 4, v_dst, v_src1, v_src2,
                     0x1, (ps->Pri.Imm << 9) | opc2, endness_host );
      goto done;
   }
   case Pin_AvBin32Fx4: {
      UInt v_dst  = vregEnc(i->Pin.AvBin32Fx4.dst);
      UInt v_srcL = vregEnc(i->Pin.AvBin32Fx4.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvBin32Fx4.srcR);
      switch (i->Pin.AvBin32Fx4.op) {

      case Pavfp_ADDF:
         p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 10, endness_host );   // vaddfp
         break;
      case Pavfp_SUBF:
         p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 74, endness_host );   // vsubfp
         break;
      case Pavfp_MAXF:
         p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 1034, endness_host ); // vmaxfp
         break;
      case Pavfp_MINF:
         p = mkFormVX( p, 4, v_dst, v_srcL, v_srcR, 1098, endness_host ); // vminfp
         break;

      case Pavfp_MULF: {
         /* Make a vmulfp from a vmaddfp:
            load -0.0 (0x8000_0000) to each 32-bit word of vB
            this makes the add a noop.
         */
         UInt vB = 29;  // XXX: Using v29 for temp do not change
                        // without also changing
                        // getRegUsage_PPCInstr
         UInt konst = 0x1F;

         // Better way to load -0.0 (0x80000000) ?
         // vspltisw vB,0x1F   (0x1F => each word of vB)
         p = mkFormVX( p, 4, vB, konst, 0, 908, endness_host );

         // vslw vB,vB,vB (each word of vB = (0x1F << 0x1F) = 0x80000000
         p = mkFormVX( p, 4, vB, vB, vB, 388, endness_host );

         // Finally, do the multiply:
         p = mkFormVA( p, 4, v_dst, v_srcL, vB, v_srcR, 46, endness_host );
         break;
      }
      case Pavfp_CMPEQF:  // vcmpeqfp
         p = mkFormVXR( p, 4, v_dst, v_srcL, v_srcR, 0, 198, endness_host);
         break;
      case Pavfp_CMPGTF:  // vcmpgtfp
         p = mkFormVXR( p, 4, v_dst, v_srcL, v_srcR, 0, 710, endness_host );
         break;
      case Pavfp_CMPGEF:  // vcmpgefp
         p = mkFormVXR( p, 4, v_dst, v_srcL, v_srcR, 0, 454, endness_host );
         break;

      default:
         goto bad;
      }
      goto done;
   }

   case Pin_AvUn32Fx4: {
      UInt v_dst = vregEnc(i->Pin.AvUn32Fx4.dst);
      UInt v_src = vregEnc(i->Pin.AvUn32Fx4.src);
      UInt opc2;
      switch (i->Pin.AvUn32Fx4.op) {
      case Pavfp_RCPF:    opc2 =  266; break; // vrefp
      case Pavfp_RSQRTF:  opc2 =  330; break; // vrsqrtefp
      case Pavfp_CVTU2F:  opc2 =  778; break; // vcfux
      case Pavfp_CVTS2F:  opc2 =  842; break; // vcfsx
      case Pavfp_QCVTF2U: opc2 =  906; break; // vctuxs
      case Pavfp_QCVTF2S: opc2 =  970; break; // vctsxs
      case Pavfp_ROUNDM:  opc2 =  714; break; // vrfim
      case Pavfp_ROUNDP:  opc2 =  650; break; // vrfip
      case Pavfp_ROUNDN:  opc2 =  522; break; // vrfin
      case Pavfp_ROUNDZ:  opc2 =  586; break; // vrfiz
      default:
         goto bad;
      }
      p = mkFormVX( p, 4, v_dst, 0, v_src, opc2, endness_host );
      goto done;
   }

   case Pin_AvPerm: {  // vperm
      UInt v_dst  = vregEnc(i->Pin.AvPerm.dst);
      UInt v_srcL = vregEnc(i->Pin.AvPerm.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvPerm.srcR);
      UInt v_ctl  = vregEnc(i->Pin.AvPerm.ctl);
      p = mkFormVA( p, 4, v_dst, v_srcL, v_srcR, v_ctl, 43, endness_host );
      goto done;
   }

   case Pin_AvSel: {  // vsel
      UInt v_ctl  = vregEnc(i->Pin.AvSel.ctl);
      UInt v_dst  = vregEnc(i->Pin.AvSel.dst);
      UInt v_srcL = vregEnc(i->Pin.AvSel.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvSel.srcR);
      p = mkFormVA( p, 4, v_dst, v_srcL, v_srcR, v_ctl, 42, endness_host );
      goto done;
   }

   case Pin_AvSh: {  // vsl or vsr
      UInt v_dst  = vregEnc(i->Pin.AvSh.dst);
      Bool  idxd = toBool(i->Pin.AvSh.addr->tag == Pam_RR);
      UInt r_idx, r_base;

      r_base = iregEnc(i->Pin.AvSh.addr->Pam.RR.base, mode64);

      if (!idxd) {
         r_idx = 30; // XXX: Using r30 as temp
         p = mkLoadImm(p, r_idx,
                       i->Pin.AvSh.addr->Pam.IR.index, mode64, endness_host);
      } else {
         r_idx  = iregEnc(i->Pin.AvSh.addr->Pam.RR.index, mode64);
      }

      if (i->Pin.AvSh.shLeft)
         //vsl VRT,RA,RB
         p = mkFormVXI( p, 31, v_dst, r_idx, r_base, 6, endness_host );
      else
         //vsr VRT,RA,RB
         p = mkFormVXI( p, 31, v_dst, r_idx, r_base, 38, endness_host );
      goto done;
   }

   case Pin_AvShlDbl: {  // vsldoi
      UInt shift  = i->Pin.AvShlDbl.shift;
      UInt v_dst  = vregEnc(i->Pin.AvShlDbl.dst);
      UInt v_srcL = vregEnc(i->Pin.AvShlDbl.srcL);
      UInt v_srcR = vregEnc(i->Pin.AvShlDbl.srcR);
      vassert(shift <= 0xF);
      p = mkFormVA( p, 4, v_dst, v_srcL, v_srcR, shift, 44, endness_host );
      goto done;
   }

   case Pin_AvSplat: { // vsplt(is)(b,h,w)
      UInt v_dst = vregEnc(i->Pin.AvShlDbl.dst);
      UChar sz   = i->Pin.AvSplat.sz;
      UInt v_src, opc2;
      vassert(sz == 8 || sz == 16 || sz == 32);

      if (i->Pin.AvSplat.src->tag == Pvi_Imm) {
         Char simm5;
         opc2 = (sz == 8) ? 780 : (sz == 16) ? 844 : 908;   // 8,16,32
         /* expects 5-bit-signed-imm */
         simm5 = i->Pin.AvSplat.src->Pvi.Imm5s;
         vassert(simm5 >= -16 && simm5 <= 15);
         simm5 = simm5 & 0x1F;
         p = mkFormVX( p, 4, v_dst, (UInt)simm5, 0, opc2, endness_host );
      }
      else {  // Pri_Reg
         UInt lowest_lane;
         opc2 = (sz == 8) ? 524 : (sz == 16) ? 588 : 652;  // 8,16,32
         vassert(hregClass(i->Pin.AvSplat.src->Pvi.Reg) == HRcVec128);
         v_src = vregEnc(i->Pin.AvSplat.src->Pvi.Reg);
         lowest_lane = (128/sz)-1;
         p = mkFormVX( p, 4, v_dst, lowest_lane, v_src, opc2, endness_host );
      }
      goto done;
   }

   case Pin_AvCMov: {
      UInt v_dst     = vregEnc(i->Pin.AvCMov.dst);
      UInt v_src     = vregEnc(i->Pin.AvCMov.src);
      PPCCondCode cc = i->Pin.AvCMov.cond;

      if (v_dst == v_src) goto done;
      
      vassert(cc.test != Pct_ALWAYS);

      /* jmp fwds 2 insns if !condition */
      if (cc.test != Pct_ALWAYS) {
         /* bc !ct,cf,n_bytes>>2 */
         p = mkFormB(p, invertCondTest(cc.test), cc.flag, 8>>2, 0, 0,
                     endness_host);
      }
      /* vmr */
      p = mkFormVX( p, 4, v_dst, v_src, v_src, 1156, endness_host );
      goto done;
   }

   case Pin_AvLdVSCR: {  // mtvscr
      UInt v_src = vregEnc(i->Pin.AvLdVSCR.src);
      p = mkFormVX( p, 4, 0, 0, v_src, 1604, endness_host );
      goto done;
   }

   case Pin_Dfp64Unary: {
      UInt fr_dst = fregEnc( i->Pin.FpUnary.dst );
      UInt fr_src = fregEnc( i->Pin.FpUnary.src );

      switch (i->Pin.Dfp64Unary.op) {
      case Pfp_MOV: // fmr, PPC32 p410
         p = mkFormX( p, 63, fr_dst, 0, fr_src, 72, 0, endness_host );
         break;
      case Pfp_DCTDP:   // D32 to D64
         p = mkFormX( p, 59, fr_dst, 0, fr_src, 258, 0, endness_host );
         break;
      case Pfp_DRSP:    // D64 to D32
         p = mkFormX( p, 59, fr_dst, 0, fr_src, 770, 0, endness_host );
         break;
      case Pfp_DCFFIX:   // I64 to D64 conversion
         /* ONLY WORKS ON POWER7 */
         p = mkFormX( p, 59, fr_dst, 0, fr_src, 802, 0, endness_host );
         break;
      case Pfp_DCTFIX:   // D64 to I64 conversion
         p = mkFormX( p, 59, fr_dst, 0, fr_src, 290, 0, endness_host );
         break;
      case Pfp_DXEX:     // Extract exponent
         p = mkFormX( p, 59, fr_dst, 0, fr_src, 354, 0, endness_host );
         break;                                
      default:
         goto bad;
      }
      goto done;
   }

   case Pin_Dfp64Binary: {
      UInt fr_dst = fregEnc( i->Pin.Dfp64Binary.dst );
      UInt fr_srcL = fregEnc( i->Pin.Dfp64Binary.srcL );
      UInt fr_srcR = fregEnc( i->Pin.Dfp64Binary.srcR );
      switch (i->Pin.Dfp64Binary.op) {
      case Pfp_DFPADD: /* dadd, dfp add, use default RM from reg ignore mode
                        * from the Iop instruction. */
         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 2, 0, endness_host );
         break;
      case Pfp_DFPSUB: /* dsub, dfp subtract, use default RM from reg ignore
                        * mode from the Iop instruction. */
         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 514, 0, endness_host );
         break;
      case Pfp_DFPMUL: /* dmul, dfp multipy, use default RM from reg ignore
                        * mode from the Iop instruction. */
         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 34, 0, endness_host );
         break;
      case Pfp_DFPDIV: /* ddiv, dfp divide, use default RM from reg ignore
                        * mode from the Iop instruction. */
         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 546, 0, endness_host );
         break;
      case Pfp_DIEX:  /* diex, insert exponent */
         p = mkFormX( p, 59, fr_dst, fr_srcL, fr_srcR, 866, 0, endness_host );
         break;
      default:
         goto bad;
      }
      goto done;
   }

   case Pin_DfpShift: {
      UInt fr_src = fregEnc(i->Pin.DfpShift.src);
      UInt fr_dst = fregEnc(i->Pin.DfpShift.dst);
      UInt shift;

      shift =  i->Pin.DfpShift.shift->Pri.Imm;

      switch (i->Pin.DfpShift.op) {
      case Pfp_DSCLI:    /* dscli, DFP shift left by fr_srcR */
         p = mkFormZ22( p, 59, fr_dst, fr_src, shift,  66, 0, endness_host );
         break;
      case Pfp_DSCRI:    /* dscri, DFP shift right by fr_srcR */
         p = mkFormZ22( p, 59, fr_dst, fr_src, shift,  98, 0, endness_host );
         break;
      default:
         vex_printf("ERROR: emit_PPCInstr default case\n");
         goto bad;
      }
      goto done;
   }

   case Pin_ExtractExpD128: {
      UInt fr_dst   = fregEnc(i->Pin.ExtractExpD128.dst);
      UInt fr_srcHi = fregEnc(i->Pin.ExtractExpD128.src_hi);
      UInt fr_srcLo = fregEnc(i->Pin.ExtractExpD128.src_lo);

      switch (i->Pin.ExtractExpD128.op) {
      case Pfp_DXEXQ:                                                          
         /* Setup the upper and lower registers of the source operand
          * register pair.
          */
         p = mkFormX( p, 63, 12, 0, fr_srcHi, 72, 0, endness_host );
         p = mkFormX( p, 63, 13, 0, fr_srcLo, 72, 0, endness_host );
         p = mkFormX( p, 63, 10, 0, 12, 354, 0, endness_host );

         /* The instruction will put the 64-bit result in
          * register 10.
          */
         p = mkFormX(p, 63, fr_dst, 0, 10,  72, 0, endness_host);
         break;
      default:
         vex_printf("Error: emit_PPCInstr case Pin_DfpExtractExp, case inst Default\n");
         goto bad;
      }
      goto done;
   }
   case Pin_Dfp128Unary: {
     UInt fr_dstHi = fregEnc(i->Pin.Dfp128Unary.dst_hi);
     UInt fr_dstLo = fregEnc(i->Pin.Dfp128Unary.dst_lo);
     UInt fr_srcLo = fregEnc(i->Pin.Dfp128Unary.src_lo);

     /* Do instruction with 128-bit source operands in registers (10,11)       
      * and (12,13).                                                           
      */
     switch (i->Pin.Dfp128Unary.op) {
     case Pfp_DCTQPQ: // D64 to D128, srcLo holds 64 bit operand              
        p = mkFormX( p, 63, 12, 0, fr_srcLo, 72, 0, endness_host );

        p = mkFormX( p, 63, 10, 0, 12, 258, 0, endness_host );

        /* The instruction will put the 128-bit result in
         * registers (10,11).  Note, the operand in the instruction only
         * reference the first of the two registers in the pair.
         */
        p = mkFormX(p, 63, fr_dstHi, 0, 10,  72, 0, endness_host);
        p = mkFormX(p, 63, fr_dstLo, 0, 11,  72, 0, endness_host);
        break;
     default:
        vex_printf("Error: emit_PPCInstr case Pin_Dfp128Unary, case inst Default\
\n");
        goto bad;
     }
     goto done;
   }

   case Pin_Dfp128Binary: {
      /* dst is used to supply the  left source operand and return
       * the result.
       */
      UInt fr_dstHi = fregEnc( i->Pin.Dfp128Binary.dst_hi );
      UInt fr_dstLo = fregEnc( i->Pin.Dfp128Binary.dst_lo );
      UInt fr_srcRHi = fregEnc( i->Pin.Dfp128Binary.srcR_hi );
      UInt fr_srcRLo = fregEnc( i->Pin.Dfp128Binary.srcR_lo );

      /* Setup the upper and lower registers of the source operand
       * register pair.
       */
      p = mkFormX( p, 63, 10, 0, fr_dstHi, 72, 0, endness_host );
      p = mkFormX( p, 63, 11, 0, fr_dstLo, 72, 0, endness_host );
      p = mkFormX( p, 63, 12, 0, fr_srcRHi, 72, 0, endness_host );
      p = mkFormX( p, 63, 13, 0, fr_srcRLo, 72, 0, endness_host );

      /* Do instruction with 128-bit source operands in registers (10,11)
       * and (12,13).
       */
      switch (i->Pin.Dfp128Binary.op) {
      case Pfp_DFPADDQ:
         p = mkFormX( p, 63, 10, 10, 12, 2, 0, endness_host );
         break;
      case Pfp_DFPSUBQ:
         p = mkFormX( p, 63, 10, 10, 12, 514, 0, endness_host );
         break;
      case Pfp_DFPMULQ:
         p = mkFormX( p, 63, 10, 10, 12, 34, 0, endness_host );
         break;
      case Pfp_DFPDIVQ:
         p = mkFormX( p, 63, 10, 10, 12, 546, 0, endness_host );
         break;
      default:
         goto bad;
      }

      /* The instruction will put the 128-bit result in
       * registers (10,11).  Note, the operand in the instruction only
       * reference the first of the two registers in the pair.
       */
      p = mkFormX(p, 63, fr_dstHi, 0, 10,  72, 0, endness_host);
      p = mkFormX(p, 63, fr_dstLo, 0, 11,  72, 0, endness_host);
      goto done;
   }

   case Pin_DfpShift128: {
      UInt fr_src_hi = fregEnc(i->Pin.DfpShift128.src_hi);
      UInt fr_src_lo = fregEnc(i->Pin.DfpShift128.src_lo);
      UInt fr_dst_hi = fregEnc(i->Pin.DfpShift128.dst_hi);
      UInt fr_dst_lo = fregEnc(i->Pin.DfpShift128.dst_lo);
      UInt shift;

      shift =  i->Pin.DfpShift128.shift->Pri.Imm;

      /* setup source operand in register 12, 13 pair */
      p = mkFormX(p, 63, 12, 0, fr_src_hi, 72, 0, endness_host);
      p = mkFormX(p, 63, 13, 0, fr_src_lo, 72, 0, endness_host);

      /* execute instruction putting result in register 10, 11 pair */
      switch (i->Pin.DfpShift128.op) {
      case Pfp_DSCLIQ:    /* dscliq, DFP shift left, fr_srcR is the integer
                           * shift amount.
                           */
         p = mkFormZ22( p, 63, 10, 12, shift,  66, 0, endness_host );
         break;
      case Pfp_DSCRIQ:    /* dscriq, DFP shift right, fr_srcR is the integer
                           * shift amount.
                           */
         p = mkFormZ22( p, 63, 10, 12, shift,  98, 0, endness_host );
         break;
      default:
         vex_printf("ERROR: emit_PPCInstr quad default case %d \n",
                    i->Pin.DfpShift128.op);
         goto bad;
      }

      /* The instruction put the 128-bit result in registers (10,11). 
       * Note, the operand in the instruction only reference the first of 
       * the two registers in the pair.
       */
      p = mkFormX(p, 63, fr_dst_hi, 0, 10,  72, 0, endness_host);
      p = mkFormX(p, 63, fr_dst_lo, 0, 11,  72, 0, endness_host);
      goto done;
   }

   case Pin_DfpRound: {
      UInt fr_dst = fregEnc(i->Pin.DfpRound.dst);
      UInt fr_src = fregEnc(i->Pin.DfpRound.src);
      UInt r_rmc, r, rmc;

      r_rmc =  i->Pin.DfpRound.r_rmc->Pri.Imm;
      r = (r_rmc & 0x8) >> 3;
      rmc = r_rmc & 0x3;

      // drintx
      p = mkFormZ23(p, 59, fr_dst, r, fr_src, rmc, 99, 0, endness_host);
      goto done;
   }

   case Pin_DfpRound128: {
      UInt fr_dstHi = fregEnc(i->Pin.DfpRound128.dst_hi);
      UInt fr_dstLo = fregEnc(i->Pin.DfpRound128.dst_lo);
      UInt fr_srcHi = fregEnc(i->Pin.DfpRound128.src_hi);
      UInt fr_srcLo = fregEnc(i->Pin.DfpRound128.src_lo);
      UInt r_rmc, r, rmc;

      r_rmc =  i->Pin.DfpRound128.r_rmc->Pri.Imm;
      r = (r_rmc & 0x8) >> 3;
      rmc = r_rmc & 0x3;

      /* Setup the upper and lower registers of the source operand 
       * register pair.
       */
      p = mkFormX(p, 63, 12, 0, fr_srcHi, 72, 0, endness_host);
      p = mkFormX(p, 63, 13, 0, fr_srcLo, 72, 0, endness_host);

      /* Do drintx instruction with 128-bit source operands in 
       * registers (12,13).  
       */
      p = mkFormZ23(p, 63, 10, r, 12, rmc, 99, 0, endness_host);

      /* The instruction will put the 128-bit result in 
       * registers (10,11).  Note, the operand in the instruction only 
       * reference the first of the two registers in the pair.
       */
      p = mkFormX(p, 63, fr_dstHi, 0, 10,  72, 0, endness_host);
      p = mkFormX(p, 63, fr_dstLo, 0, 11,  72, 0, endness_host);
      goto done;
   }

   case Pin_DfpQuantize: {
      UInt fr_dst  = fregEnc(i->Pin.DfpQuantize.dst);
      UInt fr_srcL = fregEnc(i->Pin.DfpQuantize.srcL);
      UInt fr_srcR = fregEnc(i->Pin.DfpQuantize.srcR);
      UInt rmc;

      rmc =  i->Pin.DfpQuantize.rmc->Pri.Imm;

      switch (i->Pin.DfpQuantize.op) {
      case Pfp_DQUA:
         p = mkFormZ23(p, 59, fr_dst, fr_srcL, fr_srcR, rmc, 3, 0, endness_host);
         break;
      case Pfp_RRDTR:
         p = mkFormZ23(p, 59, fr_dst, fr_srcL, fr_srcR, rmc, 35, 0, endness_host);
         break;
      default:
         break;
      }
      goto done;
   }

   case Pin_DfpQuantize128: {
      UInt fr_dst_hi = fregEnc(i->Pin.DfpQuantize128.dst_hi);
      UInt fr_dst_lo = fregEnc(i->Pin.DfpQuantize128.dst_lo);
      UInt fr_src_hi = fregEnc(i->Pin.DfpQuantize128.src_hi);
      UInt fr_src_lo = fregEnc(i->Pin.DfpQuantize128.src_lo);
      UInt rmc;

      rmc =  i->Pin.DfpQuantize128.rmc->Pri.Imm;
      /* Setup the upper and lower registers of the source operand 
       * register pairs.  Note, left source operand passed in via the
       * dst register pair.
       */
      p = mkFormX(p, 63, 10, 0, fr_dst_hi, 72, 0, endness_host);
      p = mkFormX(p, 63, 11, 0, fr_dst_lo, 72, 0, endness_host);
      p = mkFormX(p, 63, 12, 0, fr_src_hi, 72, 0, endness_host);
      p = mkFormX(p, 63, 13, 0, fr_src_lo, 72, 0, endness_host);

      /* Do dquaq instruction with 128-bit source operands in 
       * registers (12,13).  
       */
      switch (i->Pin.DfpQuantize128.op) {
      case Pfp_DQUAQ:
         p = mkFormZ23(p, 63, 10, 10, 12, rmc, 3, 0, endness_host);
         break;
      case Pfp_DRRNDQ:
         p = mkFormZ23(p, 63, 10, 10, 12, rmc, 35, 0, endness_host);
         break;
      default:
         vpanic("Pin_DfpQuantize128: default case, couldn't find inst to issue \n");
         break;
      }

      /* The instruction will put the 128-bit result in 
       * registers (10,11).  Note, the operand in the instruction only 
       * reference the first of the two registers in the pair.
       */
      p = mkFormX(p, 63, fr_dst_hi, 0, 10,  72, 0, endness_host);
      p = mkFormX(p, 63, fr_dst_lo, 0, 11,  72, 0, endness_host);
      goto done;
   }

   case Pin_DfpD128toD64: {
      UInt fr_dst   = fregEnc( i->Pin.DfpD128toD64.dst );
      UInt fr_srcHi = fregEnc( i->Pin.DfpD128toD64.src_hi );
      UInt fr_srcLo = fregEnc( i->Pin.DfpD128toD64.src_lo );

      /* Setup the upper and lower registers of the source operand
       * register pair.
       */
      p = mkFormX( p, 63, 10, 0, fr_dst, 72, 0, endness_host );
      p = mkFormX( p, 63, 12, 0, fr_srcHi, 72, 0, endness_host );
      p = mkFormX( p, 63, 13, 0, fr_srcLo, 72, 0, endness_host );

      /* Do instruction with 128-bit source operands in registers (10,11) */
      switch (i->Pin.Dfp128Binary.op) {
      case Pfp_DRDPQ:
         p = mkFormX( p, 63, 10, 0, 12, 770, 0, endness_host );
         break;
      case Pfp_DCTFIXQ:
         p = mkFormX( p, 63, 10, 0, 12, 290, 0, endness_host );
         break;
      default:
         goto bad;
      }

      /* The instruction will put the 64-bit result in registers 10. */
      p = mkFormX(p, 63, fr_dst, 0, 10,  72, 0, endness_host);
      goto done;
   }

   case Pin_DfpI64StoD128: {
      UInt fr_dstHi = fregEnc( i->Pin.DfpI64StoD128.dst_hi );
      UInt fr_dstLo = fregEnc( i->Pin.DfpI64StoD128.dst_lo );
      UInt fr_src   = fregEnc( i->Pin.DfpI64StoD128.src );

      switch (i->Pin.Dfp128Binary.op) {
      case Pfp_DCFFIXQ:
         p = mkFormX( p, 63, 10, 11, fr_src, 802, 0, endness_host );
         break;
      default:
         goto bad;
      }

      /* The instruction will put the 64-bit result in registers 10, 11. */
      p = mkFormX(p, 63, fr_dstHi, 0, 10,  72, 0, endness_host);
      p = mkFormX(p, 63, fr_dstLo, 0, 11,  72, 0, endness_host);
      goto done;
   }

   case Pin_InsertExpD128: {
      UInt fr_dstHi  = fregEnc(i->Pin.InsertExpD128.dst_hi);
      UInt fr_dstLo  = fregEnc(i->Pin.InsertExpD128.dst_lo);
      UInt fr_srcL   = fregEnc(i->Pin.InsertExpD128.srcL);
      UInt fr_srcRHi = fregEnc(i->Pin.InsertExpD128.srcR_hi);
      UInt fr_srcRLo = fregEnc(i->Pin.InsertExpD128.srcR_lo);

      /* The left operand is a single F64 value, the right is an F128
       * register pair.
       */
      p = mkFormX(p, 63, 10, 0, fr_srcL, 72, 0, endness_host);
      p = mkFormX(p, 63, 12, 0, fr_srcRHi, 72, 0, endness_host);
      p = mkFormX(p, 63, 13, 0, fr_srcRLo, 72, 0, endness_host);
      p = mkFormX(p, 63, 10, 10, 12, 866, 0, endness_host );

      /* The instruction will put the 128-bit result into
       * registers (10,11).  Note, the operand in the instruction only
       * reference the first of the two registers in the pair.
       */
      p = mkFormX(p, 63, fr_dstHi, 0, 10,  72, 0, endness_host);
      p = mkFormX(p, 63, fr_dstLo, 0, 11,  72, 0, endness_host);
      goto done;
   }                                                                           

   case Pin_Dfp64Cmp:{
      UChar crfD    = 1;
      UInt  r_dst   = iregEnc(i->Pin.Dfp64Cmp.dst, mode64);
      UInt  fr_srcL = fregEnc(i->Pin.Dfp64Cmp.srcL);
      UInt  fr_srcR = fregEnc(i->Pin.Dfp64Cmp.srcR);
      vassert(crfD < 8);
      // dcmpo, dcmpu
      p = mkFormX(p, 59, crfD<<2, fr_srcL, fr_srcR, 130, 0, endness_host);

      // mfcr (mv CR to r_dst)
      p = mkFormX(p, 31, r_dst, 0, 0, 19, 0, endness_host);

      // rlwinm r_dst,r_dst,8,28,31
      //  => rotate field 1 to bottomw of word, masking out upper 28
      p = mkFormM(p, 21, r_dst, r_dst, 8, 28, 31, 0, endness_host);
      goto done;
   }

   case Pin_Dfp128Cmp: {
      UChar crfD       = 1;
      UInt  r_dst      = iregEnc(i->Pin.Dfp128Cmp.dst, mode64);
      UInt  fr_srcL_hi = fregEnc(i->Pin.Dfp128Cmp.srcL_hi);
      UInt  fr_srcL_lo = fregEnc(i->Pin.Dfp128Cmp.srcL_lo);
      UInt  fr_srcR_hi = fregEnc(i->Pin.Dfp128Cmp.srcR_hi);
      UInt  fr_srcR_lo = fregEnc(i->Pin.Dfp128Cmp.srcR_lo);
      vassert(crfD < 8);
      // dcmpoq, dcmpuq
      /* Setup the upper and lower registers of the source operand
       * register pair.
       */
      p = mkFormX(p, 63, 10, 0, fr_srcL_hi, 72, 0, endness_host);
      p = mkFormX(p, 63, 11, 0, fr_srcL_lo, 72, 0, endness_host);
      p = mkFormX(p, 63, 12, 0, fr_srcR_hi, 72, 0, endness_host);
      p = mkFormX(p, 63, 13, 0, fr_srcR_lo, 72, 0, endness_host);

      p = mkFormX(p, 63, crfD<<2, 10, 12, 130, 0, endness_host);

      // mfcr (mv CR to r_dst)
      p = mkFormX(p, 31, r_dst, 0, 0, 19, 0, endness_host);

      // rlwinm r_dst,r_dst,8,28,31
      //  => rotate field 1 to bottomw of word, masking out upper 28
      p = mkFormM(p, 21, r_dst, r_dst, 8, 28, 31, 0, endness_host);
      goto done;
   }

   case Pin_EvCheck: {
      /* This requires a 32-bit dec/test in both 32- and 64-bit
         modes. */
      /* We generate:
            lwz     r30, amCounter
            addic.  r30, r30, -1
            stw     r30, amCounter
            bge     nofail
            lwz/ld  r30, amFailAddr
            mtctr   r30
            bctr
           nofail:
      */
      UChar* p0 = p;
      /* lwz r30, amCounter */
      p = do_load_or_store_word32(p, True/*isLoad*/, /*r*/30,
                                  i->Pin.EvCheck.amCounter, mode64,
                                  endness_host);
      /* addic. r30,r30,-1 */
      p = emit32(p, 0x37DEFFFF, endness_host);
      /* stw r30, amCounter */
      p = do_load_or_store_word32(p, False/*!isLoad*/, /*r*/30,
                                  i->Pin.EvCheck.amCounter, mode64,
                                  endness_host);
      /* bge nofail */
      p = emit32(p, 0x40800010, endness_host);
      /* lwz/ld r30, amFailAddr */
      p = do_load_or_store_machine_word(p, True/*isLoad*/, /*r*/30,
                                        i->Pin.EvCheck.amFailAddr, mode64,
                                        endness_host);
      /* mtctr r30 */
      p = mkFormXFX(p, /*r*/30, 9, 467, endness_host);
      /* bctr */
      p = mkFormXL(p, 19, Pct_ALWAYS, 0, 0, 528, 0, endness_host);
      /* nofail: */

      /* Crosscheck */
      vassert(evCheckSzB_PPC() == (UChar*)p - (UChar*)p0);
      goto done;
   }

   case Pin_ProfInc: {
      /* We generate:
               (ctrP is unknown now, so use 0x65556555(65556555) in the
               expectation that a later call to LibVEX_patchProfCtr
               will be used to fill in the immediate fields once the
               right value is known.)
            32-bit:
              imm32-exactly r30, 0x65556555
              lwz     r29, 4(r30)
              addic.  r29, r29, 1
              stw     r29, 4(r30)
              lwz     r29, 0(r30)
              addze   r29, r29
              stw     r29, 0(r30)
            64-bit:
              imm64-exactly r30, 0x6555655565556555
              ld      r29, 0(r30)
              addi    r29, r29, 1
              std     r29, 0(r30)
      */
      if (mode64) {
         p = mkLoadImm_EXACTLY2or5(
                p, /*r*/30, 0x6555655565556555ULL, True/*mode64*/, endness_host);
         p = emit32(p, 0xEBBE0000, endness_host);
         p = emit32(p, 0x3BBD0001, endness_host);
         p = emit32(p, 0xFBBE0000, endness_host);
      } else {
         p = mkLoadImm_EXACTLY2or5(
                p, /*r*/30, 0x65556555ULL, False/*!mode64*/, endness_host);
         p = emit32(p, 0x83BE0004, endness_host);
         p = emit32(p, 0x37BD0001, endness_host);
         p = emit32(p, 0x93BE0004, endness_host);
         p = emit32(p, 0x83BE0000, endness_host);
         p = emit32(p, 0x7FBD0194, endness_host);
         p = emit32(p, 0x93BE0000, endness_host);
      }
      /* Tell the caller .. */
      vassert(!(*is_profInc));
      *is_profInc = True;
      goto done;
   }

   default: 
      goto bad;
   }

  bad:
   vex_printf("\n=> ");
   ppPPCInstr(i, mode64);
   vpanic("emit_PPCInstr");
   /*NOTREACHED*/
   
  done:
   vassert(p - &buf[0] <= 64);
   return p - &buf[0];
}


/* How big is an event check?  See case for Pin_EvCheck in
   emit_PPCInstr just above.  That crosschecks what this returns, so
   we can tell if we're inconsistent. */
Int evCheckSzB_PPC (void)
{
  return 28;
}


/* NB: what goes on here has to be very closely coordinated with the
   emitInstr case for XDirect, above. */
VexInvalRange chainXDirect_PPC ( VexEndness endness_host,
                                 void* place_to_chain,
                                 const void* disp_cp_chain_me_EXPECTED,
                                 const void* place_to_jump_to,
                                 Bool  mode64 )
{
   if (mode64) {
      vassert((endness_host == VexEndnessBE) ||
              (endness_host == VexEndnessLE));
   } else {
      vassert(endness_host == VexEndnessBE);
   }

   /* What we're expecting to see is:
        imm32/64-fixed r30, disp_cp_chain_me_to_EXPECTED
        mtctr r30
        bctrl
      viz
        <8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
        7F C9 03 A6
        4E 80 04 21
   */
   UChar* p = (UChar*)place_to_chain;
   vassert(0 == (3 & (HWord)p));
   vassert(isLoadImm_EXACTLY2or5(p, /*r*/30,
                                 (Addr)disp_cp_chain_me_EXPECTED,
                                 mode64, endness_host));
   vassert(fetch32(p + (mode64 ? 20 : 8) + 0, endness_host) == 0x7FC903A6);
   vassert(fetch32(p + (mode64 ? 20 : 8) + 4, endness_host) == 0x4E800421);
   /* And what we want to change it to is:
        imm32/64-fixed r30, place_to_jump_to
        mtctr r30
        bctr
      viz
        <8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
        7F C9 03 A6
        4E 80 04 20
      The replacement has the same length as the original.
   */
   p = mkLoadImm_EXACTLY2or5(p, /*r*/30,
                             (Addr)place_to_jump_to, mode64, 
                             endness_host);
   p = emit32(p, 0x7FC903A6, endness_host);
   p = emit32(p, 0x4E800420, endness_host);

   Int len = p - (UChar*)place_to_chain;
   vassert(len == (mode64 ? 28 : 16)); /* stay sane */
   VexInvalRange vir = {(HWord)place_to_chain, len};
   return vir;
}


/* NB: what goes on here has to be very closely coordinated with the
   emitInstr case for XDirect, above. */
VexInvalRange unchainXDirect_PPC ( VexEndness endness_host,
                                   void* place_to_unchain,
                                   const void* place_to_jump_to_EXPECTED,
                                   const void* disp_cp_chain_me,
                                   Bool  mode64 )
{
   if (mode64) {
      vassert((endness_host == VexEndnessBE) ||
              (endness_host == VexEndnessLE));
   } else {
      vassert(endness_host == VexEndnessBE);
   }

   /* What we're expecting to see is:
        imm32/64-fixed r30, place_to_jump_to_EXPECTED
        mtctr r30
        bctr
      viz
        <8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
        7F C9 03 A6
        4E 80 04 20
   */
   UChar* p = (UChar*)place_to_unchain;
   vassert(0 == (3 & (HWord)p));
   vassert(isLoadImm_EXACTLY2or5(p, /*r*/30,
                                 (Addr)place_to_jump_to_EXPECTED,
                                 mode64, endness_host));
   vassert(fetch32(p + (mode64 ? 20 : 8) + 0, endness_host) == 0x7FC903A6);
   vassert(fetch32(p + (mode64 ? 20 : 8) + 4, endness_host) == 0x4E800420);
   /* And what we want to change it to is:
        imm32/64-fixed r30, disp_cp_chain_me
        mtctr r30
        bctrl
      viz
        <8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
        7F C9 03 A6
        4E 80 04 21
      The replacement has the same length as the original.
   */
   p = mkLoadImm_EXACTLY2or5(p, /*r*/30,
                             (Addr)disp_cp_chain_me, mode64, 
                             endness_host);
   p = emit32(p, 0x7FC903A6, endness_host);
   p = emit32(p, 0x4E800421, endness_host);

   Int len = p - (UChar*)place_to_unchain;
   vassert(len == (mode64 ? 28 : 16)); /* stay sane */
   VexInvalRange vir = {(HWord)place_to_unchain, len};
   return vir;
}


/* Patch the counter address into a profile inc point, as previously
   created by the Pin_ProfInc case for emit_PPCInstr. */
VexInvalRange patchProfInc_PPC ( VexEndness endness_host,
                                 void*  place_to_patch,
                                 const ULong* location_of_counter,
                                 Bool   mode64 )
{
   if (mode64) {
      vassert((endness_host == VexEndnessBE) ||
              (endness_host == VexEndnessLE));
   } else {
      vassert(endness_host == VexEndnessBE);
   }

   UChar* p = (UChar*)place_to_patch;
   vassert(0 == (3 & (HWord)p));

   Int len = 0;
   if (mode64) {
      vassert(isLoadImm_EXACTLY2or5(p, /*r*/30,
                                    0x6555655565556555ULL, True/*mode64*/,
                                    endness_host));
      vassert(fetch32(p + 20, endness_host) == 0xEBBE0000);
      vassert(fetch32(p + 24, endness_host) == 0x3BBD0001);
      vassert(fetch32(p + 28, endness_host) == 0xFBBE0000);
      p = mkLoadImm_EXACTLY2or5(p, /*r*/30,
                                (Addr)location_of_counter,
                                True/*mode64*/, endness_host);
      len = p - (UChar*)place_to_patch;
      vassert(len == 20);
   } else {
      vassert(isLoadImm_EXACTLY2or5(p, /*r*/30,
                                    0x65556555ULL, False/*!mode64*/, 
                                    endness_host));
      vassert(fetch32(p +  8, endness_host) == 0x83BE0004);
      vassert(fetch32(p + 12, endness_host) == 0x37BD0001);
      vassert(fetch32(p + 16, endness_host) == 0x93BE0004);
      vassert(fetch32(p + 20, endness_host) == 0x83BE0000);
      vassert(fetch32(p + 24, endness_host) == 0x7FBD0194);
      vassert(fetch32(p + 28, endness_host) == 0x93BE0000);
      p = mkLoadImm_EXACTLY2or5(p, /*r*/30,
                                (Addr)location_of_counter,
                                False/*!mode64*/, endness_host);
      len = p - (UChar*)place_to_patch;
      vassert(len == 8);
   }
   VexInvalRange vir = {(HWord)place_to_patch, len};
   return vir;
}


/*---------------------------------------------------------------*/
/*--- end                                     host_ppc_defs.c ---*/
/*---------------------------------------------------------------*/
