Move Subzero Inst traits to the Inst header/source

Bug: b/192890685
Change-Id: Ic6214493dcaad286af519870f4aa93a5c2e4597e
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/55849
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Sean Risser <srisser@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/third_party/subzero/src/IceAssemblerX8632.cpp b/third_party/subzero/src/IceAssemblerX8632.cpp
index 83479cd..8b4b0e1 100644
--- a/third_party/subzero/src/IceAssemblerX8632.cpp
+++ b/third_party/subzero/src/IceAssemblerX8632.cpp
@@ -51,7 +51,7 @@
     }
   }
 
-  GPRRegister Base = Traits::Traits::getEncodedGPR(BaseRegNum);
+  GPRRegister Base = Traits::getEncodedGPR(BaseRegNum);
 
   if (Utils::IsInt(8, Offset)) {
     SetModRM(1, Base);
@@ -2913,8 +2913,7 @@
 void AssemblerX8632::jmp(const Immediate &abs_address) {
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   emitUint8(0xE9);
-  AssemblerFixup *Fixup =
-      createFixup(FK_PcRel, AssemblerFixup::NullSymbol);
+  AssemblerFixup *Fixup = createFixup(FK_PcRel, AssemblerFixup::NullSymbol);
   Fixup->set_addend(abs_address.value() - 4);
   emitFixup(Fixup);
   emitInt32(0);
diff --git a/third_party/subzero/src/IceAssemblerX8632.h b/third_party/subzero/src/IceAssemblerX8632.h
index b845b0b..0d50706 100644
--- a/third_party/subzero/src/IceAssemblerX8632.h
+++ b/third_party/subzero/src/IceAssemblerX8632.h
@@ -40,8 +40,9 @@
 using CmppsCond = CondX86::CmppsCond;
 using GPRRegister = typename Traits::GPRRegister;
 using XmmRegister = typename Traits::XmmRegister;
-using X86OperandMem = typename Traits::X86OperandMem;
-using VariableSplit = typename Traits::VariableSplit;
+
+class X86OperandMem;
+class VariableSplit;
 
 constexpr FixupKind FK_PcRel = llvm::ELF::R_386_PC32;
 constexpr FixupKind FK_Abs = llvm::ELF::R_386_32;
diff --git a/third_party/subzero/src/IceAssemblerX8664.cpp b/third_party/subzero/src/IceAssemblerX8664.cpp
index 6994a36..65b611b 100644
--- a/third_party/subzero/src/IceAssemblerX8664.cpp
+++ b/third_party/subzero/src/IceAssemblerX8664.cpp
@@ -50,8 +50,7 @@
       BaseRegNum = Target->getFrameOrStackReg();
     }
   }
-  SetBase(Traits::Traits::getEncodedGPR(BaseRegNum), Offset,
-          AssemblerFixup::NoFixup);
+  SetBase(Traits::getEncodedGPR(BaseRegNum), Offset, AssemblerFixup::NoFixup);
 }
 
 AsmAddress::AsmAddress(const X86OperandMem *Mem, Ice::Assembler *Asm,
diff --git a/third_party/subzero/src/IceAssemblerX8664.h b/third_party/subzero/src/IceAssemblerX8664.h
index dbab294..ed2e519 100644
--- a/third_party/subzero/src/IceAssemblerX8664.h
+++ b/third_party/subzero/src/IceAssemblerX8664.h
@@ -40,7 +40,8 @@
 using CmppsCond = CondX86::CmppsCond;
 using GPRRegister = typename Traits::GPRRegister;
 using XmmRegister = typename Traits::XmmRegister;
-using X86OperandMem = typename Traits::X86OperandMem;
+
+class X86OperandMem;
 
 constexpr FixupKind FK_PcRel = llvm::ELF::R_X86_64_PC32;
 constexpr FixupKind FK_Abs = llvm::ELF::R_X86_64_32S;
diff --git a/third_party/subzero/src/IceInstX8632.cpp b/third_party/subzero/src/IceInstX8632.cpp
index 51ff578..e623ae1 100644
--- a/third_party/subzero/src/IceInstX8632.cpp
+++ b/third_party/subzero/src/IceInstX8632.cpp
@@ -11,9 +11,6 @@
 /// \brief Defines X8632 specific data related to X8632 Instructions and
 /// Instruction traits.
 ///
-/// These are declared in the IceTargetLoweringX8632Traits.h header file. This
-/// file also defines X8632 operand specific methods (dump and emit.)
-///
 //===----------------------------------------------------------------------===//
 
 #include "IceInstX8632.h"
@@ -24,6 +21,7 @@
 #include "IceConditionCodesX86.h"
 #include "IceDefs.h"
 #include "IceInst.h"
+#include "IceInstX8632.def"
 #include "IceOperand.h"
 #include "IceRegistersX8632.h"
 #include "IceTargetLowering.h"
@@ -32,16 +30,87 @@
 namespace Ice {
 namespace X8632 {
 
+struct InstBrAttributesType {
+  CondX86::BrCond Opposite;
+  const char *const DisplayString;
+  const char *const EmitString;
+};
+
+struct InstCmppsAttributesType {
+  const char *const EmitString;
+};
+
+struct TypeAttributesType {
+  const char *const CvtString;      // i (integer), s (single FP), d (double FP)
+  const char *const SdSsString;     // ss, sd, or <blank>
+  const char *const PdPsString;     // ps, pd, or <blank>
+  const char *const SpSdString;     // ss, sd, ps, pd, or <blank>
+  const char *const IntegralString; // b, w, d, or <blank>
+  const char *const UnpackString;   // bw, wd, dq, or <blank>
+  const char *const PackString;     // wb, dw, or <blank>
+  const char *const WidthString;    // b, w, l, q, or <blank>
+  const char *const FldString;      // s, l, or <blank>
+};
+
+constexpr InstBrAttributesType InstBrAttributes[] = {
+#define X(val, encode, opp, dump, emit) {CondX86::opp, dump, emit},
+    ICEINSTX86BR_TABLE
+#undef X
+};
+
+constexpr InstCmppsAttributesType InstCmppsAttributes[] = {
+#define X(val, emit) {emit},
+    ICEINSTX86CMPPS_TABLE
+#undef X
+};
+
+constexpr TypeAttributesType TypeAttributes[] = {
+#define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld)    \
+  {cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld},
+    ICETYPEX86_TABLE
+#undef X
+};
+
+constexpr const char *InstSegmentRegNames[] = {
+#define X(val, name, prefix) name,
+    SEG_REGX8632_TABLE
+#undef X
+};
+
+constexpr uint8_t InstSegmentPrefixes[] = {
+#define X(val, name, prefix) prefix,
+    SEG_REGX8632_TABLE
+#undef X
+};
+
 const char *InstX86Base::getWidthString(Type Ty) {
-  return Traits::TypeAttributes[Ty].WidthString;
+  return TypeAttributes[Ty].WidthString;
 }
 
 const char *InstX86Base::getFldString(Type Ty) {
-  return Traits::TypeAttributes[Ty].FldString;
+  return TypeAttributes[Ty].FldString;
+}
+
+const char *InstX86Base::getSseSuffixString(Type DestTy, SseSuffix Suffix) {
+  switch (Suffix) {
+  default:
+  case InstX86Base::SseSuffix::None:
+    return "";
+  case InstX86Base::SseSuffix::Packed:
+    return TypeAttributes[DestTy].PdPsString;
+  case InstX86Base::SseSuffix::Unpack:
+    return TypeAttributes[DestTy].UnpackString;
+  case InstX86Base::SseSuffix::Scalar:
+    return TypeAttributes[DestTy].SdSsString;
+  case InstX86Base::SseSuffix::Integral:
+    return TypeAttributes[DestTy].IntegralString;
+  case InstX86Base::SseSuffix::Pack:
+    return TypeAttributes[DestTy].PackString;
+  }
 }
 
 typename Cond::BrCond InstX86Base::getOppositeCondition(BrCond Cond) {
-  return Traits::InstBrAttributes[Cond].Opposite;
+  return InstBrAttributes[Cond].Opposite;
 }
 
 InstX86FakeRMW::InstX86FakeRMW(Cfg *Func, Operand *Data, Operand *Addr,
@@ -375,7 +444,7 @@
   if (Condition == Cond::Br_None) {
     Str << "jmp";
   } else {
-    Str << Traits::InstBrAttributes[Condition].EmitString;
+    Str << InstBrAttributes[Condition].EmitString;
   }
 
   if (Label) {
@@ -434,7 +503,7 @@
     return;
   }
 
-  Str << Traits::InstBrAttributes[Condition].DisplayString;
+  Str << InstBrAttributes[Condition].DisplayString;
   if (Label) {
     Str << ", label %" << Label->getLabelName();
   } else {
@@ -909,7 +978,7 @@
   assert(isScalarFloatingType(Ty));
   Str << "\t"
          "sqrt"
-      << Traits::TypeAttributes[Ty].SpSdString << "\t";
+      << TypeAttributes[Ty].SpSdString << "\t";
   this->getSrc(0)->emit(Func);
   Str << ", ";
   this->getDest()->emit(Func);
@@ -1279,7 +1348,7 @@
   Str << "\t";
   assert(Condition != Cond::Br_None);
   assert(this->getDest()->hasReg());
-  Str << "cmov" << Traits::InstBrAttributes[Condition].DisplayString
+  Str << "cmov" << InstBrAttributes[Condition].DisplayString
       << this->getWidthString(Dest->getType()) << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
@@ -1319,7 +1388,7 @@
   if (!BuildDefs::dump())
     return;
   Ostream &Str = Func->getContext()->getStrDump();
-  Str << "cmov" << Traits::InstBrAttributes[Condition].DisplayString << ".";
+  Str << "cmov" << InstBrAttributes[Condition].DisplayString << ".";
   Str << this->getDest()->getType() << " ";
   this->dumpDest(Func);
   Str << ", ";
@@ -1335,8 +1404,8 @@
   Type DestTy = this->Dest->getType();
   Str << "\t"
          "cmp"
-      << Traits::InstCmppsAttributes[Condition].EmitString
-      << Traits::TypeAttributes[DestTy].PdPsString << "\t";
+      << InstCmppsAttributes[Condition].EmitString
+      << TypeAttributes[DestTy].PdPsString << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
   this->getDest()->emit(Func);
@@ -1369,7 +1438,7 @@
   Ostream &Str = Func->getContext()->getStrDump();
   assert(Condition < Cond::Cmpps_Invalid);
   this->dumpDest(Func);
-  Str << " = cmp" << Traits::InstCmppsAttributes[Condition].EmitString
+  Str << " = cmp" << InstCmppsAttributes[Condition].EmitString
       << "ps"
          "\t";
   this->dumpSources(Func);
@@ -1461,8 +1530,8 @@
          "cvt";
   if (isTruncating())
     Str << "t";
-  Str << Traits::TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
-      << Traits::TypeAttributes[this->getDest()->getType()].CvtString << "\t";
+  Str << TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
+      << TypeAttributes[this->getDest()->getType()].CvtString << "\t";
   this->getSrc(0)->emit(Func);
   Str << ", ";
   this->getDest()->emit(Func);
@@ -1552,8 +1621,8 @@
   Str << " = cvt";
   if (isTruncating())
     Str << "t";
-  Str << Traits::TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
-      << Traits::TypeAttributes[this->getDest()->getType()].CvtString << " ";
+  Str << TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
+      << TypeAttributes[this->getDest()->getType()].CvtString << " ";
   this->dumpSources(Func);
 }
 
@@ -1563,7 +1632,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(this->getSrcSize() == 3);
   Str << "\t" << this->Opcode
-      << Traits::TypeAttributes[this->getDest()->getType()].SpSdString << "\t";
+      << TypeAttributes[this->getDest()->getType()].SpSdString << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
   this->getSrc(0)->emit(Func);
@@ -1629,7 +1698,7 @@
   assert(this->getSrcSize() == 2);
   Str << "\t"
          "ucomi"
-      << Traits::TypeAttributes[this->getSrc(0)->getType()].SdSsString << "\t";
+      << TypeAttributes[this->getSrc(0)->getType()].SdSsString << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
   this->getSrc(0)->emit(Func);
@@ -1766,8 +1835,7 @@
   Type Ty = this->getSrc(0)->getType();
   Str << "\t"
          "mov"
-      << this->getWidthString(Ty) << Traits::TypeAttributes[Ty].SdSsString
-      << "\t";
+      << this->getWidthString(Ty) << TypeAttributes[Ty].SdSsString << "\t";
   this->getSrc(0)->emit(Func);
   Str << ", ";
   this->getSrc(1)->emit(Func);
@@ -1991,9 +2059,8 @@
   Type DestTy = this->getDest()->getType();
   Str << "\t"
          "mov"
-      << (!isScalarFloatingType(DestTy)
-              ? this->getWidthString(DestTy)
-              : Traits::TypeAttributes[DestTy].SdSsString)
+      << (!isScalarFloatingType(DestTy) ? this->getWidthString(DestTy)
+                                        : TypeAttributes[DestTy].SdSsString)
       << "\t";
   // For an integer truncation operation, src is wider than dest. In this case,
   // we use a mov instruction whose data width matches the narrower dest.
@@ -2281,7 +2348,7 @@
     // space to do this.
     Str << "\t"
            "mov"
-        << Traits::TypeAttributes[Ty].SdSsString << "\t";
+        << TypeAttributes[Ty].SdSsString << "\t";
     Var->emit(Func);
     Str << ", (%esp)\n"
            "\t"
@@ -2365,7 +2432,7 @@
          "(%esp)\n";
   Str << "\t"
          "mov"
-      << Traits::TypeAttributes[Ty].SdSsString
+      << TypeAttributes[Ty].SdSsString
       << "\t"
          "(%esp), ";
   this->getDest()->emit(Func);
@@ -2412,8 +2479,7 @@
   assert(this->getSrcSize() == 2);
   // pextrb and pextrd are SSE4.1 instructions.
   Str << "\t" << this->Opcode
-      << Traits::TypeAttributes[this->getSrc(0)->getType()].IntegralString
-      << "\t";
+      << TypeAttributes[this->getSrc(0)->getType()].IntegralString << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
   this->getSrc(0)->emit(Func);
@@ -2450,8 +2516,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(this->getSrcSize() == 3);
   Str << "\t" << this->Opcode
-      << Traits::TypeAttributes[this->getDest()->getType()].IntegralString
-      << "\t";
+      << TypeAttributes[this->getDest()->getType()].IntegralString << "\t";
   this->getSrc(2)->emit(Func);
   Str << ", ";
   Operand *Src1 = this->getSrc(1);
@@ -2617,7 +2682,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   Str << "\t"
          "set"
-      << Traits::InstBrAttributes[Condition].DisplayString << "\t";
+      << InstBrAttributes[Condition].DisplayString << "\t";
   this->Dest->emit(Func);
 }
 
@@ -2639,7 +2704,7 @@
   if (!BuildDefs::dump())
     return;
   Ostream &Str = Func->getContext()->getStrDump();
-  Str << "setcc." << Traits::InstBrAttributes[Condition].DisplayString << " ";
+  Str << "setcc." << InstBrAttributes[Condition].DisplayString << " ";
   this->dumpDest(Func);
 }
 
@@ -2774,48 +2839,14 @@
   Str << "IACA_END";
 }
 
-const TargetX8632Traits::InstBrAttributesType
-    TargetX8632Traits::InstBrAttributes[] = {
-#define X(val, encode, opp, dump, emit) {CondX86::opp, dump, emit},
-        ICEINSTX86BR_TABLE
-#undef X
-};
-
-const TargetX8632Traits::InstCmppsAttributesType
-    TargetX8632Traits::InstCmppsAttributes[] = {
-#define X(val, emit) {emit},
-        ICEINSTX86CMPPS_TABLE
-#undef X
-};
-
-const TargetX8632Traits::TypeAttributesType
-    TargetX8632Traits::TypeAttributes[] = {
-#define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld)    \
-  {cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld},
-        ICETYPEX86_TABLE
-#undef X
-};
-
-const char *TargetX8632Traits::InstSegmentRegNames[] = {
-#define X(val, name, prefix) name,
-    SEG_REGX8632_TABLE
-#undef X
-};
-
-uint8_t TargetX8632Traits::InstSegmentPrefixes[] = {
-#define X(val, name, prefix) prefix,
-    SEG_REGX8632_TABLE
-#undef X
-};
-
-void TargetX8632Traits::X86Operand::dump(const Cfg *, Ostream &Str) const {
+void X86Operand::dump(const Cfg *, Ostream &Str) const {
   if (BuildDefs::dump())
     Str << "<OperandX8632>";
 }
 
-TargetX8632Traits::X86OperandMem::X86OperandMem(
-    Cfg *Func, Type Ty, Variable *Base, Constant *Offset, Variable *Index,
-    uint16_t Shift, SegmentRegisters SegmentReg, bool IsRebased)
+X86OperandMem::X86OperandMem(Cfg *Func, Type Ty, Variable *Base,
+                             Constant *Offset, Variable *Index, uint16_t Shift,
+                             SegmentRegisters SegmentReg, bool IsRebased)
     : X86Operand(kMem, Ty), Base(Base), Offset(Offset), Index(Index),
       Shift(Shift), SegmentReg(SegmentReg), IsRebased(IsRebased) {
   assert(Shift <= 3);
@@ -2836,7 +2867,7 @@
   }
 }
 
-void TargetX8632Traits::X86OperandMem::emit(const Cfg *Func) const {
+void X86OperandMem::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
   validateMemOperandPIC();
@@ -2856,7 +2887,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   if (SegmentReg != DefaultSegment) {
     assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM);
-    Str << "%" << X8632::Traits::InstSegmentRegNames[SegmentReg] << ":";
+    Str << "%" << InstSegmentRegNames[SegmentReg] << ":";
   }
   // Emit as Offset(Base,Index,1<<Shift). Offset is emitted without the leading
   // '$'. Omit the (Base,Index,1<<Shift) part if Base==nullptr.
@@ -2892,13 +2923,12 @@
   }
 }
 
-void TargetX8632Traits::X86OperandMem::dump(const Cfg *Func,
-                                            Ostream &Str) const {
+void X86OperandMem::dump(const Cfg *Func, Ostream &Str) const {
   if (!BuildDefs::dump())
     return;
   if (SegmentReg != DefaultSegment) {
     assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM);
-    Str << X8632::Traits::InstSegmentRegNames[SegmentReg] << ":";
+    Str << InstSegmentRegNames[SegmentReg] << ":";
   }
   bool Dumped = false;
   Str << "[";
@@ -2957,15 +2987,14 @@
   Str << "]";
 }
 
-void TargetX8632Traits::X86OperandMem::emitSegmentOverride(
-    TargetX8632Traits::Assembler *Asm) const {
+void X86OperandMem::emitSegmentOverride(Assembler *Asm) const {
   if (SegmentReg != DefaultSegment) {
     assert(SegmentReg >= 0 && SegmentReg < SegReg_NUM);
-    Asm->emitSegmentOverride(X8632::Traits::InstSegmentPrefixes[SegmentReg]);
+    Asm->emitSegmentOverride(InstSegmentPrefixes[SegmentReg]);
   }
 }
 
-void TargetX8632Traits::VariableSplit::emit(const Cfg *Func) const {
+void VariableSplit::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
   Ostream &Str = Func->getContext()->getStrEmit();
@@ -2979,8 +3008,7 @@
   Str << "(%" << Target->getRegName(Target->getFrameOrStackReg(), Ty) << ")";
 }
 
-void TargetX8632Traits::VariableSplit::dump(const Cfg *Func,
-                                            Ostream &Str) const {
+void VariableSplit::dump(const Cfg *Func, Ostream &Str) const {
   if (!BuildDefs::dump())
     return;
   switch (Part) {
diff --git a/third_party/subzero/src/IceInstX8632.h b/third_party/subzero/src/IceInstX8632.h
index 782df58..b0d2c33 100644
--- a/third_party/subzero/src/IceInstX8632.h
+++ b/third_party/subzero/src/IceInstX8632.h
@@ -31,12 +31,9 @@
 namespace X8632 {
 
 using Traits = TargetX8632Traits;
-using Assembler = typename Traits::Assembler;
-using AssemblerImmediate = typename Assembler::Immediate;
-using TargetLowering = typename Traits::TargetLowering;
-using X86Operand = typename Traits::X86Operand;
-using X86OperandMem = typename Traits::X86OperandMem;
-using VariableSplit = typename Traits::VariableSplit;
+using Assembler = AssemblerX8632;
+using AssemblerImmediate = Assembler::Immediate;
+using TargetLowering = TargetX8632;
 
 using GPRRegister = typename Traits::RegisterSet::GPRRegister;
 using RegisterSet = typename Traits::RegisterSet;
@@ -47,19 +44,147 @@
 using CmppsCond = Cond::CmppsCond;
 
 template <typename SReg_t, typename DReg_t>
-using CastEmitterRegOp =
-    typename Traits::Assembler::template CastEmitterRegOp<SReg_t, DReg_t>;
+using CastEmitterRegOp = Assembler::template CastEmitterRegOp<SReg_t, DReg_t>;
 template <typename SReg_t, typename DReg_t>
-using ThreeOpImmEmitter =
-    typename Traits::Assembler::template ThreeOpImmEmitter<SReg_t, DReg_t>;
-using GPREmitterAddrOp = typename Traits::Assembler::GPREmitterAddrOp;
-using GPREmitterRegOp = typename Traits::Assembler::GPREmitterRegOp;
-using GPREmitterShiftD = typename Traits::Assembler::GPREmitterShiftD;
-using GPREmitterShiftOp = typename Traits::Assembler::GPREmitterShiftOp;
-using GPREmitterOneOp = typename Traits::Assembler::GPREmitterOneOp;
-using XmmEmitterRegOp = typename Traits::Assembler::XmmEmitterRegOp;
-using XmmEmitterShiftOp = typename Traits::Assembler::XmmEmitterShiftOp;
-using XmmEmitterMovOps = typename Traits::Assembler::XmmEmitterMovOps;
+using ThreeOpImmEmitter = Assembler::template ThreeOpImmEmitter<SReg_t, DReg_t>;
+using GPREmitterAddrOp = Assembler::GPREmitterAddrOp;
+using GPREmitterRegOp = Assembler::GPREmitterRegOp;
+using GPREmitterShiftD = Assembler::GPREmitterShiftD;
+using GPREmitterShiftOp = Assembler::GPREmitterShiftOp;
+using GPREmitterOneOp = Assembler::GPREmitterOneOp;
+using XmmEmitterRegOp = Assembler::XmmEmitterRegOp;
+using XmmEmitterShiftOp = Assembler::XmmEmitterShiftOp;
+using XmmEmitterMovOps = Assembler::XmmEmitterMovOps;
+
+/// X86Operand extends the Operand hierarchy. Its subclasses are X86OperandMem
+/// and VariableSplit.
+class X86Operand : public ::Ice::Operand {
+  X86Operand() = delete;
+  X86Operand(const X86Operand &) = delete;
+  X86Operand &operator=(const X86Operand &) = delete;
+
+public:
+  enum OperandKindX8632 { k__Start = ::Ice::Operand::kTarget, kMem, kSplit };
+  using ::Ice::Operand::dump;
+
+  void dump(const Cfg *, Ostream &Str) const override;
+
+protected:
+  X86Operand(OperandKindX8632 Kind, Type Ty)
+      : Operand(static_cast<::Ice::Operand::OperandKind>(Kind), Ty) {}
+};
+
+/// X86OperandMem represents the m32 addressing mode, with optional base and
+/// index registers, a constant offset, and a fixed shift value for the index
+/// register.
+class X86OperandMem : public X86Operand {
+  X86OperandMem() = delete;
+  X86OperandMem(const X86OperandMem &) = delete;
+  X86OperandMem &operator=(const X86OperandMem &) = delete;
+
+public:
+  enum SegmentRegisters {
+    DefaultSegment = -1,
+#define X(val, name, prefix) val,
+    SEG_REGX8632_TABLE
+#undef X
+        SegReg_NUM
+  };
+  static X86OperandMem *create(Cfg *Func, Type Ty, Variable *Base,
+                               Constant *Offset, Variable *Index = nullptr,
+                               uint16_t Shift = 0,
+                               SegmentRegisters SegmentReg = DefaultSegment,
+                               bool IsRebased = false) {
+    return new (Func->allocate<X86OperandMem>()) X86OperandMem(
+        Func, Ty, Base, Offset, Index, Shift, SegmentReg, IsRebased);
+  }
+  static X86OperandMem *create(Cfg *Func, Type Ty, Variable *Base,
+                               Constant *Offset, bool IsRebased) {
+    constexpr Variable *NoIndex = nullptr;
+    constexpr uint16_t NoShift = 0;
+    return new (Func->allocate<X86OperandMem>()) X86OperandMem(
+        Func, Ty, Base, Offset, NoIndex, NoShift, DefaultSegment, IsRebased);
+  }
+  Variable *getBase() const { return Base; }
+  Constant *getOffset() const { return Offset; }
+  Variable *getIndex() const { return Index; }
+  uint16_t getShift() const { return Shift; }
+  SegmentRegisters getSegmentRegister() const { return SegmentReg; }
+  void emitSegmentOverride(Assembler *Asm) const;
+  bool getIsRebased() const { return IsRebased; }
+
+  void validateMemOperandPIC() const {
+    if (!BuildDefs::asserts())
+      return;
+    const bool HasCR =
+        getOffset() && llvm::isa<ConstantRelocatable>(getOffset());
+    (void)HasCR;
+    const bool IsRebased = getIsRebased();
+    (void)IsRebased;
+    assert(!IsRebased);
+  }
+
+  void emit(const Cfg *Func) const override;
+  using X86Operand::dump;
+  void dump(const Cfg *Func, Ostream &Str) const override;
+
+  static bool classof(const Operand *Operand) {
+    return Operand->getKind() == static_cast<OperandKind>(kMem);
+  }
+
+private:
+  X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
+                Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg,
+                bool IsRebased);
+
+  Variable *const Base;
+  Constant *const Offset;
+  Variable *const Index;
+  const uint16_t Shift;
+  const SegmentRegisters SegmentReg : 16;
+  const bool IsRebased;
+};
+
+/// VariableSplit is a way to treat an f64 memory location as a pair of i32
+/// locations (Low and High). This is needed for some cases of the Bitcast
+/// instruction. Since it's not possible for integer registers to access the
+/// XMM registers and vice versa, the lowering forces the f64 to be spilled to
+/// the stack and then accesses through the VariableSplit.
+// TODO(jpp): remove references to VariableSplit from IceInstX86Base as 64bit
+// targets can natively handle these.
+class VariableSplit : public X86Operand {
+  VariableSplit() = delete;
+  VariableSplit(const VariableSplit &) = delete;
+  VariableSplit &operator=(const VariableSplit &) = delete;
+
+public:
+  enum Portion { Low, High };
+  static VariableSplit *create(Cfg *Func, Variable *Var, Portion Part) {
+    return new (Func->allocate<VariableSplit>()) VariableSplit(Func, Var, Part);
+  }
+  const Variable *getVar() const { return Var; }
+  int32_t getOffset() const { return Part == High ? 4 : 0; }
+
+  void emit(const Cfg *Func) const override;
+  using X86Operand::dump;
+  void dump(const Cfg *Func, Ostream &Str) const override;
+
+  static bool classof(const Operand *Operand) {
+    return Operand->getKind() == static_cast<OperandKind>(kSplit);
+  }
+
+private:
+  VariableSplit(Cfg *Func, Variable *Var, Portion Part)
+      : X86Operand(kSplit, IceType_i32), Var(Var), Part(Part) {
+    assert(Var->getType() == IceType_f64);
+    Vars = Func->allocateArrayOf<Variable *>(1);
+    Vars[0] = Var;
+    NumVars = 1;
+  }
+
+  Variable *Var;
+  Portion Part;
+};
 
 class InstX86Base : public InstTarget {
   InstX86Base() = delete;
@@ -199,6 +324,7 @@
 
   static const char *getWidthString(Type Ty);
   static const char *getFldString(Type Ty);
+  static const char *getSseSuffixString(Type DestTy, SseSuffix Suffix);
   static BrCond getOppositeCondition(BrCond Cond);
   void dump(const Cfg *Func) const override;
 
@@ -813,26 +939,7 @@
     const Type DestTy = ArithmeticTypeOverride == IceType_void
                             ? this->getDest()->getType()
                             : ArithmeticTypeOverride;
-    const char *SuffixString = "";
-    switch (Suffix) {
-    case InstX86Base::SseSuffix::None:
-      break;
-    case InstX86Base::SseSuffix::Packed:
-      SuffixString = Traits::TypeAttributes[DestTy].PdPsString;
-      break;
-    case InstX86Base::SseSuffix::Unpack:
-      SuffixString = Traits::TypeAttributes[DestTy].UnpackString;
-      break;
-    case InstX86Base::SseSuffix::Scalar:
-      SuffixString = Traits::TypeAttributes[DestTy].SdSsString;
-      break;
-    case InstX86Base::SseSuffix::Integral:
-      SuffixString = Traits::TypeAttributes[DestTy].IntegralString;
-      break;
-    case InstX86Base::SseSuffix::Pack:
-      SuffixString = Traits::TypeAttributes[DestTy].PackString;
-      break;
-    }
+    const char *SuffixString = getSseSuffixString(DestTy, Suffix);
     this->emitTwoAddress(Func, Opcode, SuffixString);
   }
   void emitIAS(const Cfg *Func) const override {
@@ -885,8 +992,8 @@
     this->validateVectorAddrMode();
     // Shift operations are always integral, and hence always need a suffix.
     const Type DestTy = this->getDest()->getType();
-    this->emitTwoAddress(Func, this->Opcode,
-                         Traits::TypeAttributes[DestTy].IntegralString);
+    const char *SuffixString = getSseSuffixString(DestTy, SseSuffix::Integral);
+    this->emitTwoAddress(Func, this->Opcode, SuffixString);
   }
   void emitIAS(const Cfg *Func) const override {
     this->validateVectorAddrMode();
diff --git a/third_party/subzero/src/IceInstX8664.cpp b/third_party/subzero/src/IceInstX8664.cpp
index 71e7773..d5e0f39 100644
--- a/third_party/subzero/src/IceInstX8664.cpp
+++ b/third_party/subzero/src/IceInstX8664.cpp
@@ -11,10 +11,6 @@
 /// \brief This file defines X8664 specific data related to X8664 Instructions
 /// and Instruction traits.
 ///
-/// These are declared in the IceTargetLoweringX8664Traits.h header file.
-///
-/// This file also defines X8664 operand specific methods (dump and emit.)
-///
 //===----------------------------------------------------------------------===//
 
 #include "IceInstX8664.h"
@@ -25,6 +21,7 @@
 #include "IceConditionCodesX86.h"
 #include "IceDefs.h"
 #include "IceInst.h"
+#include "IceInstX8664.def"
 #include "IceOperand.h"
 #include "IceRegistersX8664.h"
 #include "IceTargetLowering.h"
@@ -33,16 +30,75 @@
 namespace Ice {
 namespace X8664 {
 
+struct InstBrAttributesType {
+  CondX86::BrCond Opposite;
+  const char *const DisplayString;
+  const char *const EmitString;
+};
+
+struct InstCmppsAttributesType {
+  const char *const EmitString;
+};
+
+struct TypeAttributesType {
+  const char *const CvtString;      // i (integer), s (single FP), d (double FP)
+  const char *const SdSsString;     // ss, sd, or <blank>
+  const char *const PdPsString;     // ps, pd, or <blank>
+  const char *const SpSdString;     // ss, sd, ps, pd, or <blank>
+  const char *const IntegralString; // b, w, d, or <blank>
+  const char *const UnpackString;   // bw, wd, dq, or <blank>
+  const char *const PackString;     // wb, dw, or <blank>
+  const char *const WidthString;    // b, w, l, q, or <blank>
+  const char *const FldString;      // s, l, or <blank>
+};
+
+constexpr InstBrAttributesType InstBrAttributes[] = {
+#define X(val, encode, opp, dump, emit) {CondX86::opp, dump, emit},
+    ICEINSTX86BR_TABLE
+#undef X
+};
+
+constexpr InstCmppsAttributesType InstCmppsAttributes[] = {
+#define X(val, emit) {emit},
+    ICEINSTX86CMPPS_TABLE
+#undef X
+};
+
+constexpr TypeAttributesType TypeAttributes[] = {
+#define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld)    \
+  {cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld},
+    ICETYPEX86_TABLE
+#undef X
+};
+
 const char *InstX86Base::getWidthString(Type Ty) {
-  return Traits::TypeAttributes[Ty].WidthString;
+  return TypeAttributes[Ty].WidthString;
 }
 
 const char *InstX86Base::getFldString(Type Ty) {
-  return Traits::TypeAttributes[Ty].FldString;
+  return TypeAttributes[Ty].FldString;
+}
+
+const char *InstX86Base::getSseSuffixString(Type DestTy, SseSuffix Suffix) {
+  switch (Suffix) {
+  default:
+  case InstX86Base::SseSuffix::None:
+    return "";
+  case InstX86Base::SseSuffix::Packed:
+    return TypeAttributes[DestTy].PdPsString;
+  case InstX86Base::SseSuffix::Unpack:
+    return TypeAttributes[DestTy].UnpackString;
+  case InstX86Base::SseSuffix::Scalar:
+    return TypeAttributes[DestTy].SdSsString;
+  case InstX86Base::SseSuffix::Integral:
+    return TypeAttributes[DestTy].IntegralString;
+  case InstX86Base::SseSuffix::Pack:
+    return TypeAttributes[DestTy].PackString;
+  }
 }
 
 typename Cond::BrCond InstX86Base::getOppositeCondition(BrCond Cond) {
-  return Traits::InstBrAttributes[Cond].Opposite;
+  return InstBrAttributes[Cond].Opposite;
 }
 
 InstX86FakeRMW::InstX86FakeRMW(Cfg *Func, Operand *Data, Operand *Addr,
@@ -368,7 +424,7 @@
   if (Condition == Cond::Br_None) {
     Str << "jmp";
   } else {
-    Str << Traits::InstBrAttributes[Condition].EmitString;
+    Str << InstBrAttributes[Condition].EmitString;
   }
 
   if (Label) {
@@ -427,7 +483,7 @@
     return;
   }
 
-  Str << Traits::InstBrAttributes[Condition].DisplayString;
+  Str << InstBrAttributes[Condition].DisplayString;
   if (Label) {
     Str << ", label %" << Label->getLabelName();
   } else {
@@ -914,7 +970,7 @@
   assert(isScalarFloatingType(Ty));
   Str << "\t"
          "sqrt"
-      << Traits::TypeAttributes[Ty].SpSdString << "\t";
+      << TypeAttributes[Ty].SpSdString << "\t";
   this->getSrc(0)->emit(Func);
   Str << ", ";
   this->getDest()->emit(Func);
@@ -1295,7 +1351,7 @@
   Str << "\t";
   assert(Condition != Cond::Br_None);
   assert(this->getDest()->hasReg());
-  Str << "cmov" << Traits::InstBrAttributes[Condition].DisplayString
+  Str << "cmov" << InstBrAttributes[Condition].DisplayString
       << this->getWidthString(Dest->getType()) << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
@@ -1334,7 +1390,7 @@
   if (!BuildDefs::dump())
     return;
   Ostream &Str = Func->getContext()->getStrDump();
-  Str << "cmov" << Traits::InstBrAttributes[Condition].DisplayString << ".";
+  Str << "cmov" << InstBrAttributes[Condition].DisplayString << ".";
   Str << this->getDest()->getType() << " ";
   this->dumpDest(Func);
   Str << ", ";
@@ -1350,8 +1406,8 @@
   Type DestTy = this->Dest->getType();
   Str << "\t"
          "cmp"
-      << Traits::InstCmppsAttributes[Condition].EmitString
-      << Traits::TypeAttributes[DestTy].PdPsString << "\t";
+      << InstCmppsAttributes[Condition].EmitString
+      << TypeAttributes[DestTy].PdPsString << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
   this->getDest()->emit(Func);
@@ -1384,7 +1440,7 @@
   Ostream &Str = Func->getContext()->getStrDump();
   assert(Condition < Cond::Cmpps_Invalid);
   this->dumpDest(Func);
-  Str << " = cmp" << Traits::InstCmppsAttributes[Condition].EmitString
+  Str << " = cmp" << InstCmppsAttributes[Condition].EmitString
       << "ps"
          "\t";
   this->dumpSources(Func);
@@ -1476,8 +1532,8 @@
          "cvt";
   if (isTruncating())
     Str << "t";
-  Str << Traits::TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
-      << Traits::TypeAttributes[this->getDest()->getType()].CvtString << "\t";
+  Str << TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
+      << TypeAttributes[this->getDest()->getType()].CvtString << "\t";
   this->getSrc(0)->emit(Func);
   Str << ", ";
   this->getDest()->emit(Func);
@@ -1567,8 +1623,8 @@
   Str << " = cvt";
   if (isTruncating())
     Str << "t";
-  Str << Traits::TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
-      << Traits::TypeAttributes[this->getDest()->getType()].CvtString << " ";
+  Str << TypeAttributes[this->getSrc(0)->getType()].CvtString << "2"
+      << TypeAttributes[this->getDest()->getType()].CvtString << " ";
   this->dumpSources(Func);
 }
 
@@ -1578,7 +1634,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(this->getSrcSize() == 3);
   Str << "\t" << this->Opcode
-      << Traits::TypeAttributes[this->getDest()->getType()].SpSdString << "\t";
+      << TypeAttributes[this->getDest()->getType()].SpSdString << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
   this->getSrc(0)->emit(Func);
@@ -1644,7 +1700,7 @@
   assert(this->getSrcSize() == 2);
   Str << "\t"
          "ucomi"
-      << Traits::TypeAttributes[this->getSrc(0)->getType()].SdSsString << "\t";
+      << TypeAttributes[this->getSrc(0)->getType()].SdSsString << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
   this->getSrc(0)->emit(Func);
@@ -1781,8 +1837,7 @@
   Type Ty = this->getSrc(0)->getType();
   Str << "\t"
          "mov"
-      << this->getWidthString(Ty) << Traits::TypeAttributes[Ty].SdSsString
-      << "\t";
+      << this->getWidthString(Ty) << TypeAttributes[Ty].SdSsString << "\t";
   this->getSrc(0)->emit(Func);
   Str << ", ";
   this->getSrc(1)->emit(Func);
@@ -2012,9 +2067,8 @@
   } else {
     Str << "\t"
            "mov"
-        << (!isScalarFloatingType(DestTy)
-                ? this->getWidthString(DestTy)
-                : Traits::TypeAttributes[DestTy].SdSsString)
+        << (!isScalarFloatingType(DestTy) ? this->getWidthString(DestTy)
+                                          : TypeAttributes[DestTy].SdSsString)
         << "\t";
   }
   // For an integer truncation operation, src is wider than dest. In this case,
@@ -2352,8 +2406,7 @@
   assert(this->getSrcSize() == 2);
   // pextrb and pextrd are SSE4.1 instructions.
   Str << "\t" << this->Opcode
-      << Traits::TypeAttributes[this->getSrc(0)->getType()].IntegralString
-      << "\t";
+      << TypeAttributes[this->getSrc(0)->getType()].IntegralString << "\t";
   this->getSrc(1)->emit(Func);
   Str << ", ";
   this->getSrc(0)->emit(Func);
@@ -2390,8 +2443,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   assert(this->getSrcSize() == 3);
   Str << "\t" << this->Opcode
-      << Traits::TypeAttributes[this->getDest()->getType()].IntegralString
-      << "\t";
+      << TypeAttributes[this->getDest()->getType()].IntegralString << "\t";
   this->getSrc(2)->emit(Func);
   Str << ", ";
   Operand *Src1 = this->getSrc(1);
@@ -2557,7 +2609,7 @@
   Ostream &Str = Func->getContext()->getStrEmit();
   Str << "\t"
          "set"
-      << Traits::InstBrAttributes[Condition].DisplayString << "\t";
+      << InstBrAttributes[Condition].DisplayString << "\t";
   this->Dest->emit(Func);
 }
 
@@ -2579,7 +2631,7 @@
   if (!BuildDefs::dump())
     return;
   Ostream &Str = Func->getContext()->getStrDump();
-  Str << "setcc." << Traits::InstBrAttributes[Condition].DisplayString << " ";
+  Str << "setcc." << InstBrAttributes[Condition].DisplayString << " ";
   this->dumpDest(Func);
 }
 
@@ -2714,38 +2766,14 @@
   Str << "IACA_END";
 }
 
-const TargetX8664Traits::InstBrAttributesType
-    TargetX8664Traits::InstBrAttributes[] = {
-#define X(val, encode, opp, dump, emit) {CondX86::opp, dump, emit},
-        ICEINSTX86BR_TABLE
-#undef X
-};
-
-const TargetX8664Traits::InstCmppsAttributesType
-    TargetX8664Traits::InstCmppsAttributes[] = {
-#define X(val, emit) {emit},
-        ICEINSTX86CMPPS_TABLE
-#undef X
-};
-
-const TargetX8664Traits::TypeAttributesType
-    TargetX8664Traits::TypeAttributes[] = {
-#define X(tag, elty, cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld)    \
-  {cvt, sdss, pdps, spsd, int_, unpack, pack, width, fld},
-        ICETYPEX86_TABLE
-#undef X
-};
-
-void TargetX8664Traits::X86Operand::dump(const Cfg *, Ostream &Str) const {
+void X86Operand::dump(const Cfg *, Ostream &Str) const {
   if (BuildDefs::dump())
     Str << "<OperandX8664>";
 }
 
-TargetX8664Traits::X86OperandMem::X86OperandMem(Cfg *Func, Type Ty,
-                                                Variable *Base,
-                                                Constant *Offset,
-                                                Variable *Index, uint16_t Shift,
-                                                bool IsRebased)
+X86OperandMem::X86OperandMem(Cfg *Func, Type Ty, Variable *Base,
+                             Constant *Offset, Variable *Index, uint16_t Shift,
+                             bool IsRebased)
     : X86Operand(kMem, Ty), Base(Base), Offset(Offset), Index(Index),
       Shift(Shift), IsRebased(IsRebased) {
   assert(Shift <= 3);
@@ -2766,7 +2794,7 @@
   }
 }
 
-void TargetX8664Traits::X86OperandMem::emit(const Cfg *Func) const {
+void X86OperandMem::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
   const auto *Target = Func->getTarget();
@@ -2819,8 +2847,10 @@
       // X86-64 is ILP32, but %rsp and %rbp are accessed as 64-bit registers.
       // For filetype=asm, they need to be emitted as their 32-bit siblings.
       assert(Base->getType() == IceType_i64);
-      assert(getEncodedGPR(Base->getRegNum()) == RegX8664::Encoded_Reg_rsp ||
-             getEncodedGPR(Base->getRegNum()) == RegX8664::Encoded_Reg_rbp ||
+      assert(Traits::getEncodedGPR(Base->getRegNum()) ==
+                 RegX8664::Encoded_Reg_rsp ||
+             Traits::getEncodedGPR(Base->getRegNum()) ==
+                 RegX8664::Encoded_Reg_rbp ||
              getType() == IceType_void);
       B = B->asType(
           Func, IceType_i32,
@@ -2841,8 +2871,7 @@
   Str << ")";
 }
 
-void TargetX8664Traits::X86OperandMem::dump(const Cfg *Func,
-                                            Ostream &Str) const {
+void X86OperandMem::dump(const Cfg *Func, Ostream &Str) const {
   if (!BuildDefs::dump())
     return;
   bool Dumped = false;
diff --git a/third_party/subzero/src/IceInstX8664.h b/third_party/subzero/src/IceInstX8664.h
index 02582c8..42201ec 100644
--- a/third_party/subzero/src/IceInstX8664.h
+++ b/third_party/subzero/src/IceInstX8664.h
@@ -31,11 +31,9 @@
 namespace X8664 {
 
 using Traits = TargetX8664Traits;
-using Assembler = typename Traits::Assembler;
-using AssemblerImmediate = typename Assembler::Immediate;
-using TargetLowering = typename Traits::TargetLowering;
-using X86Operand = typename Traits::X86Operand;
-using X86OperandMem = typename Traits::X86OperandMem;
+using Assembler = AssemblerX8664;
+using AssemblerImmediate = Assembler::Immediate;
+using TargetLowering = TargetX8664;
 
 using GPRRegister = typename Traits::RegisterSet::GPRRegister;
 using RegisterSet = typename Traits::RegisterSet;
@@ -46,19 +44,88 @@
 using CmppsCond = Cond::CmppsCond;
 
 template <typename SReg_t, typename DReg_t>
-using CastEmitterRegOp =
-    typename Traits::Assembler::template CastEmitterRegOp<SReg_t, DReg_t>;
+using CastEmitterRegOp = Assembler::template CastEmitterRegOp<SReg_t, DReg_t>;
 template <typename SReg_t, typename DReg_t>
-using ThreeOpImmEmitter =
-    typename Traits::Assembler::template ThreeOpImmEmitter<SReg_t, DReg_t>;
-using GPREmitterAddrOp = typename Traits::Assembler::GPREmitterAddrOp;
-using GPREmitterRegOp = typename Traits::Assembler::GPREmitterRegOp;
-using GPREmitterShiftD = typename Traits::Assembler::GPREmitterShiftD;
-using GPREmitterShiftOp = typename Traits::Assembler::GPREmitterShiftOp;
-using GPREmitterOneOp = typename Traits::Assembler::GPREmitterOneOp;
-using XmmEmitterRegOp = typename Traits::Assembler::XmmEmitterRegOp;
-using XmmEmitterShiftOp = typename Traits::Assembler::XmmEmitterShiftOp;
-using XmmEmitterMovOps = typename Traits::Assembler::XmmEmitterMovOps;
+using ThreeOpImmEmitter = Assembler::template ThreeOpImmEmitter<SReg_t, DReg_t>;
+using GPREmitterAddrOp = Assembler::GPREmitterAddrOp;
+using GPREmitterRegOp = Assembler::GPREmitterRegOp;
+using GPREmitterShiftD = Assembler::GPREmitterShiftD;
+using GPREmitterShiftOp = Assembler::GPREmitterShiftOp;
+using GPREmitterOneOp = Assembler::GPREmitterOneOp;
+using XmmEmitterRegOp = Assembler::XmmEmitterRegOp;
+using XmmEmitterShiftOp = Assembler::XmmEmitterShiftOp;
+using XmmEmitterMovOps = Assembler::XmmEmitterMovOps;
+
+/// X86Operand extends the Operand hierarchy. Its subclass is X86OperandMem.
+class X86Operand : public ::Ice::Operand {
+  X86Operand() = delete;
+  X86Operand(const X86Operand &) = delete;
+  X86Operand &operator=(const X86Operand &) = delete;
+
+public:
+  enum OperandKindX8664 { k__Start = ::Ice::Operand::kTarget, kMem, kSplit };
+  using ::Ice::Operand::dump;
+
+  void dump(const Cfg *, Ostream &Str) const override;
+
+protected:
+  X86Operand(OperandKindX8664 Kind, Type Ty)
+      : Operand(static_cast<::Ice::Operand::OperandKind>(Kind), Ty) {}
+};
+
+/// X86OperandMem represents the m64 addressing mode, with optional base and
+/// index registers, a constant offset, and a fixed shift value for the index
+/// register.
+class X86OperandMem : public X86Operand {
+  X86OperandMem() = delete;
+  X86OperandMem(const X86OperandMem &) = delete;
+  X86OperandMem &operator=(const X86OperandMem &) = delete;
+
+public:
+  enum SegmentRegisters { DefaultSegment = -1, SegReg_NUM };
+  static X86OperandMem *
+  create(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
+         Variable *Index = nullptr, uint16_t Shift = 0,
+         SegmentRegisters SegmentRegister = DefaultSegment,
+         bool IsRebased = false) {
+    assert(SegmentRegister == DefaultSegment);
+    (void)SegmentRegister;
+    return new (Func->allocate<X86OperandMem>())
+        X86OperandMem(Func, Ty, Base, Offset, Index, Shift, IsRebased);
+  }
+  static X86OperandMem *create(Cfg *Func, Type Ty, Variable *Base,
+                               Constant *Offset, bool IsRebased) {
+    constexpr Variable *NoIndex = nullptr;
+    constexpr uint16_t NoShift = 0;
+    return new (Func->allocate<X86OperandMem>())
+        X86OperandMem(Func, Ty, Base, Offset, NoIndex, NoShift, IsRebased);
+  }
+  Variable *getBase() const { return Base; }
+  Constant *getOffset() const { return Offset; }
+  Variable *getIndex() const { return Index; }
+  uint16_t getShift() const { return Shift; }
+  SegmentRegisters getSegmentRegister() const { return DefaultSegment; }
+  void emitSegmentOverride(Assembler *) const {}
+  bool getIsRebased() const { return IsRebased; }
+
+  void emit(const Cfg *Func) const override;
+  using X86Operand::dump;
+  void dump(const Cfg *Func, Ostream &Str) const override;
+
+  static bool classof(const Operand *Operand) {
+    return Operand->getKind() == static_cast<OperandKind>(kMem);
+  }
+
+private:
+  X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
+                Variable *Index, uint16_t Shift, bool IsRebased);
+
+  Variable *const Base;
+  Constant *const Offset;
+  Variable *const Index;
+  const uint16_t Shift;
+  const bool IsRebased;
+};
 
 class InstX86Base : public InstTarget {
   InstX86Base() = delete;
@@ -196,6 +263,7 @@
 
   static const char *getWidthString(Type Ty);
   static const char *getFldString(Type Ty);
+  static const char *getSseSuffixString(Type DestTy, SseSuffix Suffix);
   static BrCond getOppositeCondition(BrCond Cond);
   void dump(const Cfg *Func) const override;
 
@@ -810,26 +878,7 @@
     const Type DestTy = ArithmeticTypeOverride == IceType_void
                             ? this->getDest()->getType()
                             : ArithmeticTypeOverride;
-    const char *SuffixString = "";
-    switch (Suffix) {
-    case InstX86Base::SseSuffix::None:
-      break;
-    case InstX86Base::SseSuffix::Packed:
-      SuffixString = Traits::TypeAttributes[DestTy].PdPsString;
-      break;
-    case InstX86Base::SseSuffix::Unpack:
-      SuffixString = Traits::TypeAttributes[DestTy].UnpackString;
-      break;
-    case InstX86Base::SseSuffix::Scalar:
-      SuffixString = Traits::TypeAttributes[DestTy].SdSsString;
-      break;
-    case InstX86Base::SseSuffix::Integral:
-      SuffixString = Traits::TypeAttributes[DestTy].IntegralString;
-      break;
-    case InstX86Base::SseSuffix::Pack:
-      SuffixString = Traits::TypeAttributes[DestTy].PackString;
-      break;
-    }
+    const char *SuffixString = getSseSuffixString(DestTy, Suffix);
     this->emitTwoAddress(Func, Opcode, SuffixString);
   }
   void emitIAS(const Cfg *Func) const override {
@@ -882,8 +931,8 @@
     this->validateVectorAddrMode();
     // Shift operations are always integral, and hence always need a suffix.
     const Type DestTy = this->getDest()->getType();
-    this->emitTwoAddress(Func, this->Opcode,
-                         Traits::TypeAttributes[DestTy].IntegralString);
+    const char *SuffixString = getSseSuffixString(DestTy, SseSuffix::Integral);
+    this->emitTwoAddress(Func, this->Opcode, SuffixString);
   }
   void emitIAS(const Cfg *Func) const override {
     this->validateVectorAddrMode();
diff --git a/third_party/subzero/src/IceTargetLoweringX8632.cpp b/third_party/subzero/src/IceTargetLoweringX8632.cpp
index 0381a53..349f667 100644
--- a/third_party/subzero/src/IceTargetLoweringX8632.cpp
+++ b/third_party/subzero/src/IceTargetLoweringX8632.cpp
@@ -346,7 +346,7 @@
     bool HasMemOperand = false;
     const SizeT SrcSize = PInst->getSrcSize();
     for (SizeT I = 0; I < SrcSize; ++I) {
-      if (llvm::isa<typename Traits::X86OperandMem>(PInst->getSrc(I))) {
+      if (llvm::isa<X86OperandMem>(PInst->getSrc(I))) {
         HasMemOperand = true;
         break;
       }
@@ -587,8 +587,8 @@
 bool isSameMemAddressOperand(const Operand *A, const Operand *B) {
   if (A == B)
     return true;
-  if (auto *MemA = llvm::dyn_cast<typename TargetX8632::X86OperandMem>(A)) {
-    if (auto *MemB = llvm::dyn_cast<typename TargetX8632::X86OperandMem>(B)) {
+  if (auto *MemA = llvm::dyn_cast<X86OperandMem>(A)) {
+    if (auto *MemB = llvm::dyn_cast<X86OperandMem>(B)) {
       return MemA->getBase() == MemB->getBase() &&
              MemA->getOffset() == MemB->getOffset() &&
              MemA->getIndex() == MemB->getIndex() &&
@@ -2113,7 +2113,7 @@
                              llvm::isa<ConstantRelocatable>(Const));
     if (getFlags().getAggressiveLea() && ValidType && ValidKind) {
       auto *Var = legalizeToReg(Src0);
-      auto *Mem = Traits::X86OperandMem::create(Func, IceType_void, Var, Const);
+      auto *Mem = X86OperandMem::create(Func, IceType_void, Var, Const);
       T = makeReg(Ty);
       _lea(T, Mem);
       _mov(Dest, T);
@@ -2543,8 +2543,7 @@
       }
       Variable *esp = getPhysicalRegister(getStackReg(), Traits::WordType);
       Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes);
-      StackArgLocations.push_back(
-          Traits::X86OperandMem::create(Func, Ty, esp, Loc));
+      StackArgLocations.push_back(X86OperandMem::create(Func, Ty, esp, Loc));
       ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType());
     }
   }
@@ -3016,10 +3015,8 @@
         Spill->setLinkedTo(Src0Var);
         Spill->setMustNotHaveReg();
         _movq(Spill, Src0RM);
-        SpillLo = Traits::VariableSplit::create(Func, Spill,
-                                                Traits::VariableSplit::Low);
-        SpillHi = Traits::VariableSplit::create(Func, Spill,
-                                                Traits::VariableSplit::High);
+        SpillLo = VariableSplit::create(Func, Spill, VariableSplit::Low);
+        SpillHi = VariableSplit::create(Func, Spill, VariableSplit::High);
       } else {
         SpillLo = loOperand(Src0RM);
         SpillHi = hiOperand(Src0RM);
@@ -3056,10 +3053,8 @@
       Spill->setMustNotHaveReg();
 
       Variable *T_Lo = nullptr, *T_Hi = nullptr;
-      auto *SpillLo = Traits::VariableSplit::create(Func, Spill,
-                                                    Traits::VariableSplit::Low);
-      auto *SpillHi = Traits::VariableSplit::create(
-          Func, Spill, Traits::VariableSplit::High);
+      auto *SpillLo = VariableSplit::create(Func, Spill, VariableSplit::Low);
+      auto *SpillHi = VariableSplit::create(Func, Spill, VariableSplit::High);
       _mov(T_Lo, loOperand(Src0));
       // Technically, the Spill is defined after the _store happens, but
       // SpillLo is considered a "use" of Spill so define Spill before it is
@@ -5475,8 +5470,8 @@
   return nullptr;
 }
 
-typename TargetX8632::X86OperandMem *
-TargetX8632::computeAddressOpt(const Inst *Instr, Type MemType, Operand *Addr) {
+X86OperandMem *TargetX8632::computeAddressOpt(const Inst *Instr, Type MemType,
+                                              Operand *Addr) {
   Func->resetCurrentNode();
   if (Func->isVerbose(IceV_AddrOpt)) {
     OstreamLocker L(Func->getContext());
@@ -7354,9 +7349,9 @@
   return Reg;
 }
 
-typename TargetX8632::X86OperandMem *
-TargetX8632::getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
-                                          uint32_t Offset) {
+X86OperandMem *TargetX8632::getMemoryOperandForStackSlot(Type Ty,
+                                                         Variable *Slot,
+                                                         uint32_t Offset) {
   // Ensure that Loc is a stack slot.
   assert(Slot->mustNotHaveReg());
   assert(Slot->getRegNum().hasNoValue());
@@ -7631,8 +7626,8 @@
   return legalize(Src0, IsSrc1ImmOrReg ? (Legal_Reg | Legal_Mem) : Legal_Reg);
 }
 
-typename TargetX8632::X86OperandMem *
-TargetX8632::formMemoryOperand(Operand *Opnd, Type Ty, bool DoLegalize) {
+X86OperandMem *TargetX8632::formMemoryOperand(Operand *Opnd, Type Ty,
+                                              bool DoLegalize) {
   auto *Mem = llvm::dyn_cast<X86OperandMem>(Opnd);
   // It may be the case that address mode optimization already creates an
   // X86OperandMem, so in that case it wouldn't need another level of
@@ -7930,8 +7925,8 @@
 std::array<SmallBitVector, RCX86_NUM> TargetX8632::TypeToRegisterSetUnfiltered =
     {{}};
 
-std::array<SmallBitVector, TargetX8632::Traits::RegisterSet::Reg_NUM>
-    TargetX8632::RegisterAliases = {{}};
+std::array<SmallBitVector, RegisterSet::Reg_NUM> TargetX8632::RegisterAliases =
+    {{}};
 
 //------------------------------------------------------------------------------
 //     __      ______  __     __  ______  ______  __  __   __  ______
diff --git a/third_party/subzero/src/IceTargetLoweringX8632.h b/third_party/subzero/src/IceTargetLoweringX8632.h
index 52e28b3..b747ca2 100644
--- a/third_party/subzero/src/IceTargetLoweringX8632.h
+++ b/third_party/subzero/src/IceTargetLoweringX8632.h
@@ -120,15 +120,10 @@
   TargetX8632 &operator=(const TargetX8632 &) = delete;
 
 public:
-  using Traits = TargetX8632Traits;
-  using TargetLowering = typename Traits::TargetLowering;
-
   using BrCond = CondX86::BrCond;
   using CmppsCond = CondX86::CmppsCond;
 
-  using X86Operand = typename Traits::X86Operand;
-  using X86OperandMem = typename Traits::X86OperandMem;
-  using SegmentRegisters = typename Traits::X86OperandMem::SegmentRegisters;
+  using SegmentRegisters = X86OperandMem::SegmentRegisters;
 
   using InstX86Br = Insts::Br;
   using InstX86FakeRMW = Insts::FakeRMW;
diff --git a/third_party/subzero/src/IceTargetLoweringX8632Traits.h b/third_party/subzero/src/IceTargetLoweringX8632Traits.h
index ac5fa32..019a70c 100644
--- a/third_party/subzero/src/IceTargetLoweringX8632Traits.h
+++ b/third_party/subzero/src/IceTargetLoweringX8632Traits.h
@@ -19,7 +19,6 @@
 #include "IceConditionCodesX86.h"
 #include "IceDefs.h"
 #include "IceInst.h"
-#include "IceInstX8632.def"
 #include "IceOperand.h"
 #include "IceRegistersX8632.h"
 #include "IceTargetLowering.h"
@@ -512,183 +511,9 @@
     Type InVectorElementType;
   } TableTypeX8632Attributes[];
   static const size_t TableTypeX8632AttributesSize;
-
-  //----------------------------------------------------------------------------
-  //      __  __   __  ______  ______
-  //    /\ \/\ "-.\ \/\  ___\/\__  _\
-  //    \ \ \ \ \-.  \ \___  \/_/\ \/
-  //     \ \_\ \_\\"\_\/\_____\ \ \_\
-  //      \/_/\/_/ \/_/\/_____/  \/_/
-  //
-  //----------------------------------------------------------------------------
-  using Traits = TargetX8632Traits;
-
-  using TargetLowering = ::Ice::X8632::TargetX8632;
-  using Assembler = ::Ice::X8632::AssemblerX8632;
-
-  /// X86Operand extends the Operand hierarchy. Its subclasses are X86OperandMem
-  /// and VariableSplit.
-  class X86Operand : public ::Ice::Operand {
-    X86Operand() = delete;
-    X86Operand(const X86Operand &) = delete;
-    X86Operand &operator=(const X86Operand &) = delete;
-
-  public:
-    enum OperandKindX8632 { k__Start = ::Ice::Operand::kTarget, kMem, kSplit };
-    using ::Ice::Operand::dump;
-
-    void dump(const Cfg *, Ostream &Str) const override;
-
-  protected:
-    X86Operand(OperandKindX8632 Kind, Type Ty)
-        : Operand(static_cast<::Ice::Operand::OperandKind>(Kind), Ty) {}
-  };
-
-  /// X86OperandMem represents the m32 addressing mode, with optional base and
-  /// index registers, a constant offset, and a fixed shift value for the index
-  /// register.
-  class X86OperandMem : public X86Operand {
-    X86OperandMem() = delete;
-    X86OperandMem(const X86OperandMem &) = delete;
-    X86OperandMem &operator=(const X86OperandMem &) = delete;
-
-  public:
-    enum SegmentRegisters {
-      DefaultSegment = -1,
-#define X(val, name, prefix) val,
-      SEG_REGX8632_TABLE
-#undef X
-          SegReg_NUM
-    };
-    static X86OperandMem *create(Cfg *Func, Type Ty, Variable *Base,
-                                 Constant *Offset, Variable *Index = nullptr,
-                                 uint16_t Shift = 0,
-                                 SegmentRegisters SegmentReg = DefaultSegment,
-                                 bool IsRebased = false) {
-      return new (Func->allocate<X86OperandMem>()) X86OperandMem(
-          Func, Ty, Base, Offset, Index, Shift, SegmentReg, IsRebased);
-    }
-    static X86OperandMem *create(Cfg *Func, Type Ty, Variable *Base,
-                                 Constant *Offset, bool IsRebased) {
-      constexpr Variable *NoIndex = nullptr;
-      constexpr uint16_t NoShift = 0;
-      return new (Func->allocate<X86OperandMem>()) X86OperandMem(
-          Func, Ty, Base, Offset, NoIndex, NoShift, DefaultSegment, IsRebased);
-    }
-    Variable *getBase() const { return Base; }
-    Constant *getOffset() const { return Offset; }
-    Variable *getIndex() const { return Index; }
-    uint16_t getShift() const { return Shift; }
-    SegmentRegisters getSegmentRegister() const { return SegmentReg; }
-    void emitSegmentOverride(Assembler *Asm) const;
-    bool getIsRebased() const { return IsRebased; }
-
-    void validateMemOperandPIC() const {
-      if (!BuildDefs::asserts())
-        return;
-      const bool HasCR =
-          getOffset() && llvm::isa<ConstantRelocatable>(getOffset());
-      (void)HasCR;
-      const bool IsRebased = getIsRebased();
-      (void)IsRebased;
-      assert(!IsRebased);
-    }
-
-    void emit(const Cfg *Func) const override;
-    using X86Operand::dump;
-    void dump(const Cfg *Func, Ostream &Str) const override;
-
-    static bool classof(const Operand *Operand) {
-      return Operand->getKind() == static_cast<OperandKind>(kMem);
-    }
-
-  private:
-    X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
-                  Variable *Index, uint16_t Shift, SegmentRegisters SegmentReg,
-                  bool IsRebased);
-
-    Variable *const Base;
-    Constant *const Offset;
-    Variable *const Index;
-    const uint16_t Shift;
-    const SegmentRegisters SegmentReg : 16;
-    const bool IsRebased;
-  };
-
-  /// VariableSplit is a way to treat an f64 memory location as a pair of i32
-  /// locations (Low and High). This is needed for some cases of the Bitcast
-  /// instruction. Since it's not possible for integer registers to access the
-  /// XMM registers and vice versa, the lowering forces the f64 to be spilled to
-  /// the stack and then accesses through the VariableSplit.
-  // TODO(jpp): remove references to VariableSplit from IceInstX86Base as 64bit
-  // targets can natively handle these.
-  class VariableSplit : public X86Operand {
-    VariableSplit() = delete;
-    VariableSplit(const VariableSplit &) = delete;
-    VariableSplit &operator=(const VariableSplit &) = delete;
-
-  public:
-    enum Portion { Low, High };
-    static VariableSplit *create(Cfg *Func, Variable *Var, Portion Part) {
-      return new (Func->allocate<VariableSplit>())
-          VariableSplit(Func, Var, Part);
-    }
-    const Variable *getVar() const { return Var; }
-    int32_t getOffset() const { return Part == High ? 4 : 0; }
-
-    void emit(const Cfg *Func) const override;
-    using X86Operand::dump;
-    void dump(const Cfg *Func, Ostream &Str) const override;
-
-    static bool classof(const Operand *Operand) {
-      return Operand->getKind() == static_cast<OperandKind>(kSplit);
-    }
-
-  private:
-    VariableSplit(Cfg *Func, Variable *Var, Portion Part)
-        : X86Operand(kSplit, IceType_i32), Var(Var), Part(Part) {
-      assert(Var->getType() == IceType_f64);
-      Vars = Func->allocateArrayOf<Variable *>(1);
-      Vars[0] = Var;
-      NumVars = 1;
-    }
-
-    Variable *Var;
-    Portion Part;
-  };
-
-  // Note: The following data structures are defined in IceInstX8632.cpp.
-
-  static const struct InstBrAttributesType {
-    CondX86::BrCond Opposite;
-    const char *DisplayString;
-    const char *EmitString;
-  } InstBrAttributes[];
-
-  static const struct InstCmppsAttributesType {
-    const char *EmitString;
-  } InstCmppsAttributes[];
-
-  static const struct TypeAttributesType {
-    const char *CvtString;      // i (integer), s (single FP), d (double FP)
-    const char *SdSsString;     // ss, sd, or <blank>
-    const char *PdPsString;     // ps, pd, or <blank>
-    const char *SpSdString;     // ss, sd, ps, pd, or <blank>
-    const char *IntegralString; // b, w, d, or <blank>
-    const char *UnpackString;   // bw, wd, dq, or <blank>
-    const char *PackString;     // wb, dw, or <blank>
-    const char *WidthString;    // b, w, l, q, or <blank>
-    const char *FldString;      // s, l, or <blank>
-  } TypeAttributes[];
-
-  static const char *InstSegmentRegNames[];
-
-  static uint8_t InstSegmentPrefixes[];
 };
 
-using Traits = ::Ice::X8632::TargetX8632Traits;
 } // end of namespace X8632
-
 } // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICETARGETLOWERINGX8632TRAITS_H
diff --git a/third_party/subzero/src/IceTargetLoweringX8664.cpp b/third_party/subzero/src/IceTargetLoweringX8664.cpp
index a782914..37c8d2a 100644
--- a/third_party/subzero/src/IceTargetLoweringX8664.cpp
+++ b/third_party/subzero/src/IceTargetLoweringX8664.cpp
@@ -359,7 +359,7 @@
     bool HasMemOperand = false;
     const SizeT SrcSize = PInst->getSrcSize();
     for (SizeT I = 0; I < SrcSize; ++I) {
-      if (llvm::isa<typename Traits::X86OperandMem>(PInst->getSrc(I))) {
+      if (llvm::isa<X86OperandMem>(PInst->getSrc(I))) {
         HasMemOperand = true;
         break;
       }
@@ -600,8 +600,8 @@
 bool isSameMemAddressOperand(const Operand *A, const Operand *B) {
   if (A == B)
     return true;
-  if (auto *MemA = llvm::dyn_cast<typename TargetX8664::X86OperandMem>(A)) {
-    if (auto *MemB = llvm::dyn_cast<typename TargetX8664::X86OperandMem>(B)) {
+  if (auto *MemA = llvm::dyn_cast<X86OperandMem>(A)) {
+    if (auto *MemB = llvm::dyn_cast<X86OperandMem>(B)) {
       return MemA->getBase() == MemB->getBase() &&
              MemA->getOffset() == MemB->getOffset() &&
              MemA->getIndex() == MemB->getIndex() &&
@@ -1913,7 +1913,7 @@
                              llvm::isa<ConstantRelocatable>(Const));
     if (getFlags().getAggressiveLea() && ValidType && ValidKind) {
       auto *Var = legalizeToReg(Src0);
-      auto *Mem = Traits::X86OperandMem::create(Func, IceType_void, Var, Const);
+      auto *Mem = X86OperandMem::create(Func, IceType_void, Var, Const);
       T = makeReg(Ty);
       _lea(T, Mem);
       _mov(Dest, T);
@@ -2339,8 +2339,7 @@
       }
       Variable *esp = getPhysicalRegister(getStackReg(), Traits::WordType);
       Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes);
-      StackArgLocations.push_back(
-          Traits::X86OperandMem::create(Func, Ty, esp, Loc));
+      StackArgLocations.push_back(X86OperandMem::create(Func, Ty, esp, Loc));
       ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType());
     }
   }
@@ -4871,8 +4870,8 @@
   return nullptr;
 }
 
-typename TargetX8664::X86OperandMem *
-TargetX8664::computeAddressOpt(const Inst *Instr, Type MemType, Operand *Addr) {
+X86OperandMem *TargetX8664::computeAddressOpt(const Inst *Instr, Type MemType,
+                                              Operand *Addr) {
   Func->resetCurrentNode();
   if (Func->isVerbose(IceV_AddrOpt)) {
     OstreamLocker L(Func->getContext());
@@ -6586,9 +6585,9 @@
   return Reg;
 }
 
-typename TargetX8664::X86OperandMem *
-TargetX8664::getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
-                                          uint32_t Offset) {
+X86OperandMem *TargetX8664::getMemoryOperandForStackSlot(Type Ty,
+                                                         Variable *Slot,
+                                                         uint32_t Offset) {
   // Ensure that Loc is a stack slot.
   assert(Slot->mustNotHaveReg());
   assert(Slot->getRegNum().hasNoValue());
@@ -6873,8 +6872,8 @@
   return legalize(Src0, IsSrc1ImmOrReg ? (Legal_Reg | Legal_Mem) : Legal_Reg);
 }
 
-typename TargetX8664::X86OperandMem *
-TargetX8664::formMemoryOperand(Operand *Opnd, Type Ty, bool DoLegalize) {
+X86OperandMem *TargetX8664::formMemoryOperand(Operand *Opnd, Type Ty,
+                                              bool DoLegalize) {
   auto *Mem = llvm::dyn_cast<X86OperandMem>(Opnd);
   // It may be the case that address mode optimization already creates an
   // X86OperandMem, so in that case it wouldn't need another level of
@@ -7170,8 +7169,8 @@
 std::array<SmallBitVector, RCX86_NUM> TargetX8664::TypeToRegisterSetUnfiltered =
     {{}};
 
-std::array<SmallBitVector, TargetX8664::Traits::RegisterSet::Reg_NUM>
-    TargetX8664::RegisterAliases = {{}};
+std::array<SmallBitVector, RegisterSet::Reg_NUM> TargetX8664::RegisterAliases =
+    {{}};
 
 //------------------------------------------------------------------------------
 //     __      ______  __     __  ______  ______  __  __   __  ______
@@ -7224,8 +7223,7 @@
     Variable *reg = getPhysicalRegister(RegNum, IceType_v4f32);
     Variable *rsp =
         getPhysicalRegister(Traits::RegisterSet::Reg_rsp, Traits::WordType);
-    auto *address =
-        Traits::X86OperandMem::create(Func, reg->getType(), rsp, nullptr);
+    auto *address = X86OperandMem::create(Func, reg->getType(), rsp, nullptr);
     _sub_sp(
         Ctx->getConstantInt32(16)); // TODO(capn): accumulate all the offsets
                                     // and adjust the stack pointer once.
@@ -7240,8 +7238,7 @@
     Variable *reg = getPhysicalRegister(RegNum, IceType_v4f32);
     Variable *rsp =
         getPhysicalRegister(Traits::RegisterSet::Reg_rsp, Traits::WordType);
-    auto *address =
-        Traits::X86OperandMem::create(Func, reg->getType(), rsp, nullptr);
+    auto *address = X86OperandMem::create(Func, reg->getType(), rsp, nullptr);
     _movp(reg, address);
     _add_sp(
         Ctx->getConstantInt32(16)); // TODO(capn): accumulate all the offsets
diff --git a/third_party/subzero/src/IceTargetLoweringX8664.h b/third_party/subzero/src/IceTargetLoweringX8664.h
index b31134a..e6cce45 100644
--- a/third_party/subzero/src/IceTargetLoweringX8664.h
+++ b/third_party/subzero/src/IceTargetLoweringX8664.h
@@ -121,15 +121,10 @@
   TargetX8664 &operator=(const TargetX8664 &) = delete;
 
 public:
-  using Traits = TargetX8664Traits;
-  using TargetLowering = typename Traits::TargetLowering;
-
   using BrCond = CondX86::BrCond;
   using CmppsCond = CondX86::CmppsCond;
 
-  using X86Operand = typename Traits::X86Operand;
-  using X86OperandMem = typename Traits::X86OperandMem;
-  using SegmentRegisters = typename Traits::X86OperandMem::SegmentRegisters;
+  using SegmentRegisters = X86OperandMem::SegmentRegisters;
 
   using InstX86Br = Insts::Br;
   using InstX86FakeRMW = Insts::FakeRMW;
diff --git a/third_party/subzero/src/IceTargetLoweringX8664Traits.h b/third_party/subzero/src/IceTargetLoweringX8664Traits.h
index 5c8734a..edeac04 100644
--- a/third_party/subzero/src/IceTargetLoweringX8664Traits.h
+++ b/third_party/subzero/src/IceTargetLoweringX8664Traits.h
@@ -19,7 +19,6 @@
 #include "IceConditionCodesX86.h"
 #include "IceDefs.h"
 #include "IceInst.h"
-#include "IceInstX8664.def"
 #include "IceOperand.h"
 #include "IceRegistersX8664.h"
 #include "IceTargetLowering.h"
@@ -573,120 +572,9 @@
     Type InVectorElementType;
   } TableTypeX8664Attributes[];
   static const size_t TableTypeX8664AttributesSize;
-
-  //----------------------------------------------------------------------------
-  //      __  __   __  ______  ______
-  //    /\ \/\ "-.\ \/\  ___\/\__  _\
-  //    \ \ \ \ \-.  \ \___  \/_/\ \/
-  //     \ \_\ \_\\"\_\/\_____\ \ \_\
-  //      \/_/\/_/ \/_/\/_____/  \/_/
-  //
-  //----------------------------------------------------------------------------
-  using Traits = TargetX8664Traits;
-
-  using TargetLowering = ::Ice::X8664::TargetX8664;
-  using Assembler = ::Ice::X8664::AssemblerX8664;
-
-  /// X86Operand extends the Operand hierarchy. Its subclasses are X86OperandMem
-  /// and VariableSplit.
-  class X86Operand : public ::Ice::Operand {
-    X86Operand() = delete;
-    X86Operand(const X86Operand &) = delete;
-    X86Operand &operator=(const X86Operand &) = delete;
-
-  public:
-    enum OperandKindX8664 { k__Start = ::Ice::Operand::kTarget, kMem, kSplit };
-    using ::Ice::Operand::dump;
-
-    void dump(const Cfg *, Ostream &Str) const override;
-
-  protected:
-    X86Operand(OperandKindX8664 Kind, Type Ty)
-        : Operand(static_cast<::Ice::Operand::OperandKind>(Kind), Ty) {}
-  };
-
-  /// X86OperandMem represents the m64 addressing mode, with optional base and
-  /// index registers, a constant offset, and a fixed shift value for the index
-  /// register.
-  class X86OperandMem : public X86Operand {
-    X86OperandMem() = delete;
-    X86OperandMem(const X86OperandMem &) = delete;
-    X86OperandMem &operator=(const X86OperandMem &) = delete;
-
-  public:
-    enum SegmentRegisters { DefaultSegment = -1, SegReg_NUM };
-    static X86OperandMem *
-    create(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
-           Variable *Index = nullptr, uint16_t Shift = 0,
-           SegmentRegisters SegmentRegister = DefaultSegment,
-           bool IsRebased = false) {
-      assert(SegmentRegister == DefaultSegment);
-      (void)SegmentRegister;
-      return new (Func->allocate<X86OperandMem>())
-          X86OperandMem(Func, Ty, Base, Offset, Index, Shift, IsRebased);
-    }
-    static X86OperandMem *create(Cfg *Func, Type Ty, Variable *Base,
-                                 Constant *Offset, bool IsRebased) {
-      constexpr Variable *NoIndex = nullptr;
-      constexpr uint16_t NoShift = 0;
-      return new (Func->allocate<X86OperandMem>())
-          X86OperandMem(Func, Ty, Base, Offset, NoIndex, NoShift, IsRebased);
-    }
-    Variable *getBase() const { return Base; }
-    Constant *getOffset() const { return Offset; }
-    Variable *getIndex() const { return Index; }
-    uint16_t getShift() const { return Shift; }
-    SegmentRegisters getSegmentRegister() const { return DefaultSegment; }
-    void emitSegmentOverride(Assembler *) const {}
-    bool getIsRebased() const { return IsRebased; }
-
-    void emit(const Cfg *Func) const override;
-    using X86Operand::dump;
-    void dump(const Cfg *Func, Ostream &Str) const override;
-
-    static bool classof(const Operand *Operand) {
-      return Operand->getKind() == static_cast<OperandKind>(kMem);
-    }
-
-  private:
-    X86OperandMem(Cfg *Func, Type Ty, Variable *Base, Constant *Offset,
-                  Variable *Index, uint16_t Shift, bool IsRebased);
-
-    Variable *const Base;
-    Constant *const Offset;
-    Variable *const Index;
-    const uint16_t Shift;
-    const bool IsRebased;
-  };
-
-  // Note: The following data structures are defined in IceInstX8664.cpp.
-
-  static const struct InstBrAttributesType {
-    CondX86::BrCond Opposite;
-    const char *DisplayString;
-    const char *EmitString;
-  } InstBrAttributes[];
-
-  static const struct InstCmppsAttributesType {
-    const char *EmitString;
-  } InstCmppsAttributes[];
-
-  static const struct TypeAttributesType {
-    const char *CvtString;      // i (integer), s (single FP), d (double FP)
-    const char *SdSsString;     // ss, sd, or <blank>
-    const char *PdPsString;     // ps, pd, or <blank>
-    const char *SpSdString;     // ss, sd, ps, pd, or <blank>
-    const char *IntegralString; // b, w, d, or <blank>
-    const char *UnpackString;   // bw, wd, dq, or <blank>
-    const char *PackString;     // wb, dw, or <blank>
-    const char *WidthString;    // b, w, l, q, or <blank>
-    const char *FldString;      // s, l, or <blank>
-  } TypeAttributes[];
 };
 
-using Traits = ::Ice::X8664::TargetX8664Traits;
 } // end of namespace X8664
-
 } // end of namespace Ice
 
 #endif // SUBZERO_SRC_ICETARGETLOWERINGX8664TRAITS_H