//===- subzero/src/IceInstX86BaseImpl.h - Generic X86 instructions -*- C++ -*=//
//
//                        The Subzero Code Generator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Implements the InstX86Base class and its descendants.
///
//===----------------------------------------------------------------------===//

#ifndef SUBZERO_SRC_ICEINSTX86BASEIMPL_H
#define SUBZERO_SRC_ICEINSTX86BASEIMPL_H

#include "IceInstX86Base.h"

#include "IceAssemblerX86Base.h"
#include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceDefs.h"
#include "IceInst.h"
#include "IceOperand.h"
#include "IceTargetLowering.h"

namespace Ice {

namespace X86Internal {

template <class Machine>
const char *InstX86Base<Machine>::getWidthString(Type Ty) {
  return Traits::TypeAttributes[Ty].WidthString;
}

template <class Machine>
const char *InstX86Base<Machine>::getFldString(Type Ty) {
  return Traits::TypeAttributes[Ty].FldString;
}

template <class Machine>
typename InstX86Base<Machine>::Traits::Cond::BrCond
InstX86Base<Machine>::getOppositeCondition(typename Traits::Cond::BrCond Cond) {
  return Traits::InstBrAttributes[Cond].Opposite;
}

template <class Machine>
InstX86FakeRMW<Machine>::InstX86FakeRMW(Cfg *Func, Operand *Data, Operand *Addr,
                                        InstArithmetic::OpKind Op,
                                        Variable *Beacon)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::FakeRMW, 3, nullptr),
      Op(Op) {
  this->addSource(Data);
  this->addSource(Addr);
  this->addSource(Beacon);
}

template <class Machine>
InstX86Mul<Machine>::InstX86Mul(Cfg *Func, Variable *Dest, Variable *Source1,
                                Operand *Source2)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Mul, 2, Dest) {
  this->addSource(Source1);
  this->addSource(Source2);
}

template <class Machine>
InstX86Shld<Machine>::InstX86Shld(Cfg *Func, Variable *Dest, Variable *Source1,
                                  Operand *Source2)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Shld, 3, Dest) {
  this->addSource(Dest);
  this->addSource(Source1);
  this->addSource(Source2);
}

template <class Machine>
InstX86Shrd<Machine>::InstX86Shrd(Cfg *Func, Variable *Dest, Variable *Source1,
                                  Operand *Source2)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Shrd, 3, Dest) {
  this->addSource(Dest);
  this->addSource(Source1);
  this->addSource(Source2);
}

template <class Machine>
InstX86Label<Machine>::InstX86Label(
    Cfg *Func, typename InstX86Base<Machine>::Traits::TargetLowering *Target)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Label, 0, nullptr),
      Number(Target->makeNextLabelNumber()) {}

template <class Machine>
IceString InstX86Label<Machine>::getName(const Cfg *Func) const {
  return ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number);
}

template <class Machine>
InstX86Br<Machine>::InstX86Br(
    Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
    const InstX86Label<Machine> *Label,
    typename InstX86Base<Machine>::Traits::Cond::BrCond Condition, Mode Kind)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Br, 0, nullptr),
      Condition(Condition), TargetTrue(TargetTrue), TargetFalse(TargetFalse),
      Label(Label), Kind(Kind) {}

template <class Machine>
bool InstX86Br<Machine>::optimizeBranch(const CfgNode *NextNode) {
  // If there is no next block, then there can be no fallthrough to optimize.
  if (NextNode == nullptr)
    return false;
  // Intra-block conditional branches can't be optimized.
  if (Label)
    return false;
  // If there is no fallthrough node, such as a non-default case label for a
  // switch instruction, then there is no opportunity to optimize.
  if (getTargetFalse() == nullptr)
    return false;

  // Unconditional branch to the next node can be removed.
  if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None &&
      getTargetFalse() == NextNode) {
    assert(getTargetTrue() == nullptr);
    this->setDeleted();
    return true;
  }
  // If the fallthrough is to the next node, set fallthrough to nullptr to
  // indicate.
  if (getTargetFalse() == NextNode) {
    TargetFalse = nullptr;
    return true;
  }
  // If TargetTrue is the next node, and TargetFalse is not nullptr (which was
  // already tested above), then invert the branch condition, swap the targets,
  // and set new fallthrough to nullptr.
  if (getTargetTrue() == NextNode) {
    assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
    Condition = this->getOppositeCondition(Condition);
    TargetTrue = getTargetFalse();
    TargetFalse = nullptr;
    return true;
  }
  return false;
}

template <class Machine>
bool InstX86Br<Machine>::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
  bool Found = false;
  if (TargetFalse == OldNode) {
    TargetFalse = NewNode;
    Found = true;
  }
  if (TargetTrue == OldNode) {
    TargetTrue = NewNode;
    Found = true;
  }
  return Found;
}

template <class Machine>
InstX86Jmp<Machine>::InstX86Jmp(Cfg *Func, Operand *Target)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Jmp, 1, nullptr) {
  this->addSource(Target);
}

template <class Machine>
InstX86Call<Machine>::InstX86Call(Cfg *Func, Variable *Dest,
                                  Operand *CallTarget)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Call, 1, Dest) {
  this->HasSideEffects = true;
  this->addSource(CallTarget);
}

template <class Machine>
InstX86Cmov<Machine>::InstX86Cmov(
    Cfg *Func, Variable *Dest, Operand *Source,
    typename InstX86Base<Machine>::Traits::Cond::BrCond Condition)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmov, 2, Dest),
      Condition(Condition) {
  // The final result is either the original Dest, or Source, so mark both as
  // sources.
  this->addSource(Dest);
  this->addSource(Source);
}

template <class Machine>
InstX86Cmpps<Machine>::InstX86Cmpps(
    Cfg *Func, Variable *Dest, Operand *Source,
    typename InstX86Base<Machine>::Traits::Cond::CmppsCond Condition)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cmpps, 2, Dest),
      Condition(Condition) {
  this->addSource(Dest);
  this->addSource(Source);
}

template <class Machine>
InstX86Cmpxchg<Machine>::InstX86Cmpxchg(Cfg *Func, Operand *DestOrAddr,
                                        Variable *Eax, Variable *Desired,
                                        bool Locked)
    : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Cmpxchg, 3,
                                   llvm::dyn_cast<Variable>(DestOrAddr),
                                   Locked) {
  assert(InstX86Base<Machine>::Traits::getBaseReg(Eax->getRegNum()) ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
  this->addSource(DestOrAddr);
  this->addSource(Eax);
  this->addSource(Desired);
}

template <class Machine>
InstX86Cmpxchg8b<Machine>::InstX86Cmpxchg8b(
    Cfg *Func, typename InstX86Base<Machine>::Traits::X86OperandMem *Addr,
    Variable *Edx, Variable *Eax, Variable *Ecx, Variable *Ebx, bool Locked)
    : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Cmpxchg, 5,
                                   nullptr, Locked) {
  assert(Edx->getRegNum() ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
  assert(Eax->getRegNum() ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
  assert(Ecx->getRegNum() ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_ecx);
  assert(Ebx->getRegNum() ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_ebx);
  this->addSource(Addr);
  this->addSource(Edx);
  this->addSource(Eax);
  this->addSource(Ecx);
  this->addSource(Ebx);
}

template <class Machine>
InstX86Cvt<Machine>::InstX86Cvt(Cfg *Func, Variable *Dest, Operand *Source,
                                CvtVariant Variant)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Cvt, 1, Dest),
      Variant(Variant) {
  this->addSource(Source);
}

template <class Machine>
InstX86Icmp<Machine>::InstX86Icmp(Cfg *Func, Operand *Src0, Operand *Src1)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Icmp, 2, nullptr) {
  this->addSource(Src0);
  this->addSource(Src1);
}

template <class Machine>
InstX86Ucomiss<Machine>::InstX86Ucomiss(Cfg *Func, Operand *Src0, Operand *Src1)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Ucomiss, 2, nullptr) {
  this->addSource(Src0);
  this->addSource(Src1);
}

template <class Machine>
InstX86UD2<Machine>::InstX86UD2(Cfg *Func)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::UD2, 0, nullptr) {}

template <class Machine>
InstX86Test<Machine>::InstX86Test(Cfg *Func, Operand *Src1, Operand *Src2)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Test, 2, nullptr) {
  this->addSource(Src1);
  this->addSource(Src2);
}

template <class Machine>
InstX86Mfence<Machine>::InstX86Mfence(Cfg *Func)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Mfence, 0, nullptr) {
  this->HasSideEffects = true;
}

template <class Machine>
InstX86Store<Machine>::InstX86Store(
    Cfg *Func, Operand *Value,
    typename InstX86Base<Machine>::Traits::X86Operand *Mem)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Store, 2, nullptr) {
  this->addSource(Value);
  this->addSource(Mem);
}

template <class Machine>
InstX86StoreP<Machine>::InstX86StoreP(
    Cfg *Func, Variable *Value,
    typename InstX86Base<Machine>::Traits::X86OperandMem *Mem)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::StoreP, 2, nullptr) {
  this->addSource(Value);
  this->addSource(Mem);
}

template <class Machine>
InstX86StoreQ<Machine>::InstX86StoreQ(
    Cfg *Func, Variable *Value,
    typename InstX86Base<Machine>::Traits::X86OperandMem *Mem)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::StoreQ, 2, nullptr) {
  this->addSource(Value);
  this->addSource(Mem);
}

template <class Machine>
InstX86Nop<Machine>::InstX86Nop(Cfg *Func, InstX86Nop::NopVariant Variant)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Nop, 0, nullptr),
      Variant(Variant) {}

template <class Machine>
InstX86Fld<Machine>::InstX86Fld(Cfg *Func, Operand *Src)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fld, 1, nullptr) {
  this->addSource(Src);
}

template <class Machine>
InstX86Fstp<Machine>::InstX86Fstp(Cfg *Func, Variable *Dest)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Fstp, 0, Dest) {}

template <class Machine>
InstX86Pop<Machine>::InstX86Pop(Cfg *Func, Variable *Dest)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Pop, 0, Dest) {
  // A pop instruction affects the stack pointer and so it should not be
  // allowed to be automatically dead-code eliminated. (The corresponding push
  // instruction doesn't need this treatment because it has no dest variable
  // and therefore won't be dead-code eliminated.) This is needed for
  // late-stage liveness analysis (e.g. asm-verbose mode).
  this->HasSideEffects = true;
}

template <class Machine>
InstX86Push<Machine>::InstX86Push(Cfg *Func, Variable *Source)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Push, 1, nullptr) {
  this->addSource(Source);
}

template <class Machine>
InstX86Ret<Machine>::InstX86Ret(Cfg *Func, Variable *Source)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Ret, Source ? 1 : 0,
                           nullptr) {
  if (Source)
    this->addSource(Source);
}

template <class Machine>
InstX86Setcc<Machine>::InstX86Setcc(
    Cfg *Func, Variable *Dest,
    typename InstX86Base<Machine>::Traits::Cond::BrCond Cond)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Setcc, 0, Dest),
      Condition(Cond) {}

template <class Machine>
InstX86Xadd<Machine>::InstX86Xadd(Cfg *Func, Operand *Dest, Variable *Source,
                                  bool Locked)
    : InstX86BaseLockable<Machine>(Func, InstX86Base<Machine>::Xadd, 2,
                                   llvm::dyn_cast<Variable>(Dest), Locked) {
  this->addSource(Dest);
  this->addSource(Source);
}

template <class Machine>
InstX86Xchg<Machine>::InstX86Xchg(Cfg *Func, Operand *Dest, Variable *Source)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::Xchg, 2,
                           llvm::dyn_cast<Variable>(Dest)) {
  this->addSource(Dest);
  this->addSource(Source);
}

template <class Machine>
InstX86IacaStart<Machine>::InstX86IacaStart(Cfg *Func)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::IacaStart, 0, nullptr) {
  assert(Func->getContext()->getFlags().getAllowIacaMarks());
}

template <class Machine>
InstX86IacaEnd<Machine>::InstX86IacaEnd(Cfg *Func)
    : InstX86Base<Machine>(Func, InstX86Base<Machine>::IacaEnd, 0, nullptr) {
  assert(Func->getContext()->getFlags().getAllowIacaMarks());
}

// ======================== Dump routines ======================== //

template <class Machine>
void InstX86Base<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "[" << Traits::TargetName << "] ";
  Inst::dump(Func);
}

template <class Machine>
void InstX86FakeRMW<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Type Ty = getData()->getType();
  Str << "rmw " << InstArithmetic::getOpName(getOp()) << " " << Ty << " *";
  getAddr()->dump(Func);
  Str << ", ";
  getData()->dump(Func);
  Str << ", beacon=";
  getBeacon()->dump(Func);
}

template <class Machine>
void InstX86Label<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Str << getName(Func) << ":";
}

template <class Machine>
void InstX86Label<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Asm->bindLocalLabel(Number);
}

template <class Machine>
void InstX86Label<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << getName(Func) << ":";
}

template <class Machine> void InstX86Br<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Str << "\t";

  if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
    Str << "jmp";
  } else {
    Str << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].EmitString;
  }

  if (Label) {
    Str << "\t" << Label->getName(Func);
  } else {
    if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
      Str << "\t" << getTargetFalse()->getAsmName();
    } else {
      Str << "\t" << getTargetTrue()->getAsmName();
      if (getTargetFalse()) {
        Str << "\n\tjmp\t" << getTargetFalse()->getAsmName();
      }
    }
  }
}

template <class Machine>
void InstX86Br<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  if (Label) {
    class Label *L = Asm->getOrCreateLocalLabel(Label->getNumber());
    if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
      Asm->jmp(L, isNear());
    } else {
      Asm->j(Condition, L, isNear());
    }
  } else {
    if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
      class Label *L =
          Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex());
      assert(!getTargetTrue());
      Asm->jmp(L, isNear());
    } else {
      class Label *L =
          Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex());
      Asm->j(Condition, L, isNear());
      if (getTargetFalse()) {
        class Label *L2 =
            Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex());
        Asm->jmp(L2, isNear());
      }
    }
  }
}

template <class Machine> void InstX86Br<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "br ";

  if (Condition == InstX86Base<Machine>::Traits::Cond::Br_None) {
    Str << "label %"
        << (Label ? Label->getName(Func) : getTargetFalse()->getName());
    return;
  }

  Str << InstX86Base<Machine>::Traits::InstBrAttributes[Condition]
             .DisplayString;
  if (Label) {
    Str << ", label %" << Label->getName(Func);
  } else {
    Str << ", label %" << getTargetTrue()->getName();
    if (getTargetFalse()) {
      Str << ", label %" << getTargetFalse()->getName();
    }
  }

  Str << " // (" << (isNear() ? "near" : "far") << " jump)";
}

template <class Machine> void InstX86Jmp<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  Str << "\tjmp\t*";
  getJmpTarget()->emit(Func);
}

template <class Machine>
void InstX86Jmp<Machine>::emitIAS(const Cfg *Func) const {
  // Note: Adapted (mostly copied) from InstX86Call<Machine>::emitIAS().
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Operand *Target = getJmpTarget();
  if (const auto *Var = llvm::dyn_cast<Variable>(Target)) {
    if (Var->hasReg()) {
      Asm->jmp(InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum()));
    } else {
      // The jmp instruction with a memory operand should be possible to
      // encode, but it isn't a valid sandboxed instruction, and there
      // shouldn't be a register allocation issue to jump through a scratch
      // register, so we don't really need to bother implementing it.
      llvm::report_fatal_error("Assembler can't jmp to memory operand");
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(
                 Target)) {
    (void)Mem;
    assert(Mem->getSegmentRegister() ==
           InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
    llvm::report_fatal_error("Assembler can't jmp to memory operand");
  } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Target)) {
    assert(CR->getOffset() == 0 && "We only support jumping to a function");
    Asm->jmp(CR);
  } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Target)) {
    // NaCl trampoline calls refer to an address within the sandbox directly.
    // This is usually only needed for non-IRT builds and otherwise not very
    // portable or stable. Usually this is only done for "calls" and not jumps.
    // TODO(jvoung): Support this when there is a lowering that actually
    // triggers this case.
    (void)Imm;
    llvm::report_fatal_error("Unexpected jmp to absolute address");
  } else {
    llvm::report_fatal_error("Unexpected operand type");
  }
}

template <class Machine> void InstX86Jmp<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "jmp ";
  getJmpTarget()->dump(Func);
}

template <class Machine>
void InstX86Call<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  Str << "\tcall\t";
  Operand *CallTarget = getCallTarget();
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  if (const auto *CI = llvm::dyn_cast<ConstantInteger32>(CallTarget)) {
    // Emit without a leading '$'.
    Str << CI->getValue();
  } else if (const auto DirectCallTarget =
                 llvm::dyn_cast<ConstantRelocatable>(CallTarget)) {
    DirectCallTarget->emitWithoutPrefix(Target);
  } else {
    Str << "*";
    CallTarget->emit(Func);
  }
}

template <class Machine>
void InstX86Call<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Operand *CallTarget = getCallTarget();
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  if (const auto *Var = llvm::dyn_cast<Variable>(CallTarget)) {
    if (Var->hasReg()) {
      Asm->call(InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum()));
    } else {
      Asm->call(Target->stackVarToAsmOperand(Var));
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(
                 CallTarget)) {
    assert(Mem->getSegmentRegister() ==
           InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
    Asm->call(Mem->toAsmAddress(Asm, Target));
  } else if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(CallTarget)) {
    assert(CR->getOffset() == 0 && "We only support calling a function");
    Asm->call(CR);
  } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(CallTarget)) {
    Asm->call(Immediate(Imm->getValue()));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine>
void InstX86Call<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  if (this->getDest()) {
    this->dumpDest(Func);
    Str << " = ";
  }
  Str << "call ";
  getCallTarget()->dump(Func);
}

// The this->Opcode parameter needs to be char* and not IceString because of
// template issues.
template <class Machine>
void InstX86Base<Machine>::emitTwoAddress(const char *Opcode, const Inst *Inst,
                                          const Cfg *Func) {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(Inst->getSrcSize() == 2);
  Operand *Dest = Inst->getDest();
  if (Dest == nullptr)
    Dest = Inst->getSrc(0);
  assert(Dest == Inst->getSrc(0));
  Operand *Src1 = Inst->getSrc(1);
  Str << "\t" << Opcode << InstX86Base<Machine>::getWidthString(Dest->getType())
      << "\t";
  Src1->emit(Func);
  Str << ", ";
  Dest->emit(Func);
}

template <class Machine>
void emitIASOpTyGPR(const Cfg *Func, Type Ty, const Operand *Op,
                    const typename InstX86Base<
                        Machine>::Traits::Assembler::GPREmitterOneOp &Emitter) {
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  if (const auto *Var = llvm::dyn_cast<Variable>(Op)) {
    if (Var->hasReg()) {
      // We cheat a little and use GPRRegister even for byte operations.
      typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg =
          InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum());
      (Asm->*(Emitter.Reg))(Ty, VarReg);
    } else {
      typename InstX86Base<Machine>::Traits::Address StackAddr(
          Target->stackVarToAsmOperand(Var));
      (Asm->*(Emitter.Addr))(Ty, StackAddr);
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Op)) {
    Mem->emitSegmentOverride(Asm);
    (Asm->*(Emitter.Addr))(Ty, Mem->toAsmAddress(Asm, Target));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine, bool VarCanBeByte, bool SrcCanBeByte>
void emitIASRegOpTyGPR(
    const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
    const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
        &Emitter) {
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(Var->hasReg());
  // We cheat a little and use GPRRegister even for byte operations.
  typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg =
      VarCanBeByte
          ? InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum())
          : InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum());
  if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
    if (SrcVar->hasReg()) {
      typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg =
          SrcCanBeByte
              ? InstX86Base<Machine>::Traits::getEncodedGPR(SrcVar->getRegNum())
              : InstX86Base<Machine>::Traits::getEncodedGPR(
                    SrcVar->getRegNum());
      (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg);
    } else {
      typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
          Target->stackVarToAsmOperand(SrcVar);
      (Asm->*(Emitter.GPRAddr))(Ty, VarReg, SrcStackAddr);
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
    Mem->emitSegmentOverride(Asm);
    (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target));
  } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
    (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue()));
  } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
    AssemblerFixup *Fixup =
        Asm->createFixup(InstX86Base<Machine>::Traits::RelFixup, Reloc);
    (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Reloc->getOffset(), Fixup));
  } else if (const auto *Split = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::VariableSplit>(Src)) {
    (Asm->*(Emitter.GPRAddr))(Ty, VarReg, Split->toAsmAddress(Func));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine>
void emitIASAddrOpTyGPR(
    const Cfg *Func, Type Ty,
    const typename InstX86Base<Machine>::Traits::Address &Addr,
    const Operand *Src,
    const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp
        &Emitter) {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  // Src can only be Reg or Immediate.
  if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
    assert(SrcVar->hasReg());
    typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg =
        InstX86Base<Machine>::Traits::getEncodedGPR(SrcVar->getRegNum());
    (Asm->*(Emitter.AddrGPR))(Ty, Addr, SrcReg);
  } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
    (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Imm->getValue()));
  } else if (const auto *Reloc = llvm::dyn_cast<ConstantRelocatable>(Src)) {
    AssemblerFixup *Fixup =
        Asm->createFixup(InstX86Base<Machine>::Traits::RelFixup, Reloc);
    (Asm->*(Emitter.AddrImm))(Ty, Addr, Immediate(Reloc->getOffset(), Fixup));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine>
void emitIASAsAddrOpTyGPR(
    const Cfg *Func, Type Ty, const Operand *Op0, const Operand *Op1,
    const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterAddrOp
        &Emitter) {
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  if (const auto *Op0Var = llvm::dyn_cast<Variable>(Op0)) {
    assert(!Op0Var->hasReg());
    typename InstX86Base<Machine>::Traits::Address StackAddr(
        Target->stackVarToAsmOperand(Op0Var));
    emitIASAddrOpTyGPR<Machine>(Func, Ty, StackAddr, Op1, Emitter);
  } else if (const auto *Op0Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Op0)) {
    typename InstX86Base<Machine>::Traits::Assembler *Asm =
        Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
    Op0Mem->emitSegmentOverride(Asm);
    emitIASAddrOpTyGPR<Machine>(Func, Ty, Op0Mem->toAsmAddress(Asm, Target),
                                Op1, Emitter);
  } else if (const auto *Split = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::VariableSplit>(Op0)) {
    emitIASAddrOpTyGPR<Machine>(Func, Ty, Split->toAsmAddress(Func), Op1,
                                Emitter);
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine>
void InstX86Base<Machine>::emitIASGPRShift(
    const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
    const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftOp
        &Emitter) {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  // Technically, the Dest Var can be mem as well, but we only use Reg. We can
  // extend this to check Dest if we decide to use that form.
  assert(Var->hasReg());
  // We cheat a little and use GPRRegister even for byte operations.
  typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister VarReg =
      InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum());
  // Src must be reg == ECX or an Imm8. This is asserted by the assembler.
  if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
    assert(SrcVar->hasReg());
    typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg =
        InstX86Base<Machine>::Traits::getEncodedGPR(SrcVar->getRegNum());
    (Asm->*(Emitter.GPRGPR))(Ty, VarReg, SrcReg);
  } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
    (Asm->*(Emitter.GPRImm))(Ty, VarReg, Immediate(Imm->getValue()));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine>
void emitIASGPRShiftDouble(
    const Cfg *Func, const Variable *Dest, const Operand *Src1Op,
    const Operand *Src2Op,
    const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterShiftD
        &Emitter) {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  // Dest can be reg or mem, but we only use the reg variant.
  assert(Dest->hasReg());
  typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister DestReg =
      InstX86Base<Machine>::Traits::getEncodedGPR(Dest->getRegNum());
  // SrcVar1 must be reg.
  const auto *SrcVar1 = llvm::cast<Variable>(Src1Op);
  assert(SrcVar1->hasReg());
  typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister SrcReg =
      InstX86Base<Machine>::Traits::getEncodedGPR(SrcVar1->getRegNum());
  Type Ty = SrcVar1->getType();
  // Src2 can be the implicit CL register or an immediate.
  if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src2Op)) {
    (Asm->*(Emitter.GPRGPRImm))(Ty, DestReg, SrcReg,
                                Immediate(Imm->getValue()));
  } else {
    assert(llvm::cast<Variable>(Src2Op)->getRegNum() ==
           InstX86Base<Machine>::Traits::RegisterSet::Reg_cl);
    (Asm->*(Emitter.GPRGPR))(Ty, DestReg, SrcReg);
  }
}

template <class Machine>
void emitIASXmmShift(
    const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
    const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterShiftOp
        &Emitter) {
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(Var->hasReg());
  typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister VarReg =
      InstX86Base<Machine>::Traits::getEncodedXmm(Var->getRegNum());
  if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
    if (SrcVar->hasReg()) {
      typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
          InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum());
      (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg);
    } else {
      typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
          Target->stackVarToAsmOperand(SrcVar);
      (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
    assert(Mem->getSegmentRegister() ==
           InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
    (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target));
  } else if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src)) {
    (Asm->*(Emitter.XmmImm))(Ty, VarReg, Immediate(Imm->getValue()));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine>
void emitIASRegOpTyXMM(
    const Cfg *Func, Type Ty, const Variable *Var, const Operand *Src,
    const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
        &Emitter) {
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(Var->hasReg());
  typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister VarReg =
      InstX86Base<Machine>::Traits::getEncodedXmm(Var->getRegNum());
  if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
    if (SrcVar->hasReg()) {
      typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
          InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum());
      (Asm->*(Emitter.XmmXmm))(Ty, VarReg, SrcReg);
    } else {
      typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
          Target->stackVarToAsmOperand(SrcVar);
      (Asm->*(Emitter.XmmAddr))(Ty, VarReg, SrcStackAddr);
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
    assert(Mem->getSegmentRegister() ==
           InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
    (Asm->*(Emitter.XmmAddr))(Ty, VarReg, Mem->toAsmAddress(Asm, Target));
  } else if (const auto *Imm = llvm::dyn_cast<Constant>(Src)) {
    (Asm->*(Emitter.XmmAddr))(
        Ty, VarReg,
        InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine, typename DReg_t, typename SReg_t,
          DReg_t (*destEnc)(int32_t), SReg_t (*srcEnc)(int32_t)>
void emitIASCastRegOp(const Cfg *Func, Type DestTy, const Variable *Dest,
                      Type SrcTy, const Operand *Src,
                      const typename InstX86Base<Machine>::Traits::Assembler::
                          template CastEmitterRegOp<DReg_t, SReg_t> &Emitter) {
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(Dest->hasReg());
  DReg_t DestReg = destEnc(Dest->getRegNum());
  if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
    if (SrcVar->hasReg()) {
      SReg_t SrcReg = srcEnc(SrcVar->getRegNum());
      (Asm->*(Emitter.RegReg))(DestTy, DestReg, SrcTy, SrcReg);
    } else {
      typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
          Target->stackVarToAsmOperand(SrcVar);
      (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy, SrcStackAddr);
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
    Mem->emitSegmentOverride(Asm);
    (Asm->*(Emitter.RegAddr))(DestTy, DestReg, SrcTy,
                              Mem->toAsmAddress(Asm, Target));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine, typename DReg_t, typename SReg_t,
          DReg_t (*destEnc)(int32_t), SReg_t (*srcEnc)(int32_t)>
void emitIASThreeOpImmOps(
    const Cfg *Func, Type DispatchTy, const Variable *Dest, const Operand *Src0,
    const Operand *Src1,
    const typename InstX86Base<Machine>::Traits::Assembler::
        template ThreeOpImmEmitter<DReg_t, SReg_t> Emitter) {
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  // This only handles Dest being a register, and Src1 being an immediate.
  assert(Dest->hasReg());
  DReg_t DestReg = destEnc(Dest->getRegNum());
  Immediate Imm(llvm::cast<ConstantInteger32>(Src1)->getValue());
  if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src0)) {
    if (SrcVar->hasReg()) {
      SReg_t SrcReg = srcEnc(SrcVar->getRegNum());
      (Asm->*(Emitter.RegRegImm))(DispatchTy, DestReg, SrcReg, Imm);
    } else {
      typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
          Target->stackVarToAsmOperand(SrcVar);
      (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg, SrcStackAddr, Imm);
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src0)) {
    Mem->emitSegmentOverride(Asm);
    (Asm->*(Emitter.RegAddrImm))(DispatchTy, DestReg,
                                 Mem->toAsmAddress(Asm, Target), Imm);
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine>
void emitIASMovlikeXMM(
    const Cfg *Func, const Variable *Dest, const Operand *Src,
    const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterMovOps
        Emitter) {
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  if (Dest->hasReg()) {
    typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg =
        InstX86Base<Machine>::Traits::getEncodedXmm(Dest->getRegNum());
    if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
      if (SrcVar->hasReg()) {
        (Asm->*(Emitter.XmmXmm))(
            DestReg,
            InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()));
      } else {
        typename InstX86Base<Machine>::Traits::Address StackAddr(
            Target->stackVarToAsmOperand(SrcVar));
        (Asm->*(Emitter.XmmAddr))(DestReg, StackAddr);
      }
    } else if (const auto *SrcMem = llvm::dyn_cast<
                   typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
      assert(SrcMem->getSegmentRegister() ==
             InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
      (Asm->*(Emitter.XmmAddr))(DestReg, SrcMem->toAsmAddress(Asm, Target));
    } else {
      llvm_unreachable("Unexpected operand type");
    }
  } else {
    typename InstX86Base<Machine>::Traits::Address StackAddr(
        Target->stackVarToAsmOperand(Dest));
    // Src must be a register in this case.
    const auto *SrcVar = llvm::cast<Variable>(Src);
    assert(SrcVar->hasReg());
    (Asm->*(Emitter.AddrXmm))(
        StackAddr,
        InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()));
  }
}

template <class Machine>
void InstX86Sqrtss<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  Type Ty = this->getSrc(0)->getType();
  assert(isScalarFloatingType(Ty));
  Str << "\tsqrt" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString
      << "\t";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Addss<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "add%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .SdSsString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Padd<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "padd%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .PackString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Pmull<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  bool TypesAreValid = this->getDest()->getType() == IceType_v4i32 ||
                       this->getDest()->getType() == IceType_v8i16;
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  bool InstructionSetIsValid =
      this->getDest()->getType() == IceType_v8i16 ||
      Target->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1;
  (void)TypesAreValid;
  (void)InstructionSetIsValid;
  assert(TypesAreValid);
  assert(InstructionSetIsValid);
  snprintf(
      buf, llvm::array_lengthof(buf), "pmull%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .PackString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Pmull<Machine>::emitIAS(const Cfg *Func) const {
  Type Ty = this->getDest()->getType();
  bool TypesAreValid = Ty == IceType_v4i32 || Ty == IceType_v8i16;
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  bool InstructionSetIsValid =
      Ty == IceType_v8i16 ||
      Target->getInstructionSet() >= InstX86Base<Machine>::Traits::SSE4_1;
  (void)TypesAreValid;
  (void)InstructionSetIsValid;
  assert(TypesAreValid);
  assert(InstructionSetIsValid);
  assert(this->getSrcSize() == 2);
  Type ElementTy = typeElementType(Ty);
  emitIASRegOpTyXMM<Machine>(Func, ElementTy, this->getDest(), this->getSrc(1),
                             this->Emitter);
}

template <class Machine>
void InstX86Subss<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "sub%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .SdSsString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Psub<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "psub%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .PackString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Mulss<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "mul%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .SdSsString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Pmuludq<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  assert(this->getSrc(0)->getType() == IceType_v4i32 &&
         this->getSrc(1)->getType() == IceType_v4i32);
  this->emitTwoAddress(this->Opcode, this, Func);
}

template <class Machine>
void InstX86Divss<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "div%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .SdSsString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine> void InstX86Div<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 3);
  Operand *Src1 = this->getSrc(1);
  Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t";
  Src1->emit(Func);
}

template <class Machine>
void InstX86Div<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 3);
  const Operand *Src = this->getSrc(1);
  Type Ty = Src->getType();
  static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp
      Emitter = {&InstX86Base<Machine>::Traits::Assembler::div,
                 &InstX86Base<Machine>::Traits::Assembler::div};
  emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter);
}

template <class Machine>
void InstX86Idiv<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 3);
  Operand *Src1 = this->getSrc(1);
  Str << "\t" << this->Opcode << this->getWidthString(Src1->getType()) << "\t";
  Src1->emit(Func);
}

template <class Machine>
void InstX86Idiv<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 3);
  const Operand *Src = this->getSrc(1);
  Type Ty = Src->getType();
  static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp
      Emitter = {&InstX86Base<Machine>::Traits::Assembler::idiv,
                 &InstX86Base<Machine>::Traits::Assembler::idiv};
  emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter);
}

// pblendvb and blendvps take xmm0 as a final implicit argument.
template <class Machine>
void emitVariableBlendInst(const char *Opcode, const Inst *Inst,
                           const Cfg *Func) {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(Inst->getSrcSize() == 3);
  assert(llvm::cast<Variable>(Inst->getSrc(2))->getRegNum() ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_xmm0);
  Str << "\t" << Opcode << "\t";
  Inst->getSrc(1)->emit(Func);
  Str << ", ";
  Inst->getDest()->emit(Func);
}

template <class Machine>
void emitIASVariableBlendInst(
    const Inst *Inst, const Cfg *Func,
    const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
        &Emitter) {
  assert(Inst->getSrcSize() == 3);
  assert(llvm::cast<Variable>(Inst->getSrc(2))->getRegNum() ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_xmm0);
  const Variable *Dest = Inst->getDest();
  const Operand *Src = Inst->getSrc(1);
  emitIASRegOpTyXMM<Machine>(Func, Dest->getType(), Dest, Src, Emitter);
}

template <class Machine>
void InstX86Blendvps<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  assert(InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
         InstX86Base<Machine>::Traits::SSE4_1);
  emitVariableBlendInst<Machine>(this->Opcode, this, Func);
}

template <class Machine>
void InstX86Blendvps<Machine>::emitIAS(const Cfg *Func) const {
  assert(InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
         InstX86Base<Machine>::Traits::SSE4_1);
  static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
      Emitter = {&InstX86Base<Machine>::Traits::Assembler::blendvps,
                 &InstX86Base<Machine>::Traits::Assembler::blendvps};
  emitIASVariableBlendInst<Machine>(this, Func, Emitter);
}

template <class Machine>
void InstX86Pblendvb<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  assert(InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
         InstX86Base<Machine>::Traits::SSE4_1);
  emitVariableBlendInst<Machine>(this->Opcode, this, Func);
}

template <class Machine>
void InstX86Pblendvb<Machine>::emitIAS(const Cfg *Func) const {
  assert(InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
         InstX86Base<Machine>::Traits::SSE4_1);
  static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
      Emitter = {&InstX86Base<Machine>::Traits::Assembler::pblendvb,
                 &InstX86Base<Machine>::Traits::Assembler::pblendvb};
  emitIASVariableBlendInst<Machine>(this, Func, Emitter);
}

template <class Machine>
void InstX86Imul<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  Variable *Dest = this->getDest();
  if (isByteSizedArithType(Dest->getType())) {
    // The 8-bit version of imul only allows the form "imul r/m8".
    const auto *Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0));
    (void)Src0Var;
    assert(Src0Var->getRegNum() ==
           InstX86Base<Machine>::Traits::RegisterSet::Reg_al);
    Str << "\timulb\t";
    this->getSrc(1)->emit(Func);
  } else if (llvm::isa<Constant>(this->getSrc(1))) {
    Str << "\timul" << this->getWidthString(Dest->getType()) << "\t";
    this->getSrc(1)->emit(Func);
    Str << ", ";
    this->getSrc(0)->emit(Func);
    Str << ", ";
    Dest->emit(Func);
  } else {
    this->emitTwoAddress("imul", this, Func);
  }
}

template <class Machine>
void InstX86Imul<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  const Variable *Var = this->getDest();
  Type Ty = Var->getType();
  const Operand *Src = this->getSrc(1);
  if (isByteSizedArithType(Ty)) {
    // The 8-bit version of imul only allows the form "imul r/m8".
    const auto *Src0Var = llvm::dyn_cast<Variable>(this->getSrc(0));
    (void)Src0Var;
    assert(Src0Var->getRegNum() ==
           InstX86Base<Machine>::Traits::RegisterSet::Reg_al);
    static const typename InstX86Base<
        Machine>::Traits::Assembler::GPREmitterOneOp Emitter = {
        &InstX86Base<Machine>::Traits::Assembler::imul,
        &InstX86Base<Machine>::Traits::Assembler::imul};
    emitIASOpTyGPR<Machine>(Func, Ty, this->getSrc(1), Emitter);
  } else {
    // The two-address version is used when multiplying by a non-constant
    // or doing an 8-bit multiply.
    assert(Var == this->getSrc(0));
    static const typename InstX86Base<
        Machine>::Traits::Assembler::GPREmitterRegOp Emitter = {
        &InstX86Base<Machine>::Traits::Assembler::imul,
        &InstX86Base<Machine>::Traits::Assembler::imul,
        &InstX86Base<Machine>::Traits::Assembler::imul};
    emitIASRegOpTyGPR<Machine>(Func, Ty, Var, Src, Emitter);
  }
}

template <class Machine>
void InstX86ImulImm<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  Variable *Dest = this->getDest();
  assert(Dest->getType() == IceType_i16 || Dest->getType() == IceType_i32);
  assert(llvm::isa<Constant>(this->getSrc(1)));
  Str << "\timul" << this->getWidthString(Dest->getType()) << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  Dest->emit(Func);
}

template <class Machine>
void InstX86ImulImm<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  const Variable *Dest = this->getDest();
  Type Ty = Dest->getType();
  assert(llvm::isa<Constant>(this->getSrc(1)));
  static const typename InstX86Base<Machine>::Traits::Assembler::
      template ThreeOpImmEmitter<
          typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
          typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister>
          Emitter = {&InstX86Base<Machine>::Traits::Assembler::imul,
                     &InstX86Base<Machine>::Traits::Assembler::imul};
  emitIASThreeOpImmOps<
      Machine, typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
      typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
      InstX86Base<Machine>::Traits::getEncodedGPR,
      InstX86Base<Machine>::Traits::getEncodedGPR>(
      Func, Ty, Dest, this->getSrc(0), this->getSrc(1), Emitter);
}

template <class Machine>
void InstX86Insertps<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 3);
  assert(InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
         InstX86Base<Machine>::Traits::SSE4_1);
  const Variable *Dest = this->getDest();
  assert(Dest == this->getSrc(0));
  Type Ty = Dest->getType();
  static const typename InstX86Base<Machine>::Traits::Assembler::
      template ThreeOpImmEmitter<
          typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
          typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
          Emitter = {&InstX86Base<Machine>::Traits::Assembler::insertps,
                     &InstX86Base<Machine>::Traits::Assembler::insertps};
  emitIASThreeOpImmOps<
      Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
      typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
      InstX86Base<Machine>::Traits::getEncodedXmm,
      InstX86Base<Machine>::Traits::getEncodedXmm>(
      Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter);
}

template <class Machine>
void InstX86Cbwdq<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  Operand *Src0 = this->getSrc(0);
  int32_t DestReg = this->getDest()->getRegNum();
  int32_t SrcReg = llvm::cast<Variable>(Src0)->getRegNum();
  (void)DestReg;
  (void)SrcReg;
  switch (Src0->getType()) {
  default:
    llvm_unreachable("unexpected source type!");
    break;
  case IceType_i8:
    assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_al);
    assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ax ||
           DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ah);
    Str << "\t"
        << "cbtw";
    break;
  case IceType_i16:
    assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ax);
    assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_dx);
    Str << "\t"
        << "cwtd";
    break;
  case IceType_i32:
    assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
    assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
    Str << "\t"
        << "cltd";
    break;
  case IceType_i64:
    assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
    Str << "\t"
        << "cdto";
    break;
  }
}

template <class Machine>
void InstX86Cbwdq<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(this->getSrcSize() == 1);
  Operand *Src0 = this->getSrc(0);
  int32_t DestReg = this->getDest()->getRegNum();
  int32_t SrcReg = llvm::cast<Variable>(Src0)->getRegNum();
  (void)DestReg;
  (void)SrcReg;
  switch (Src0->getType()) {
  default:
    llvm_unreachable("unexpected source type!");
    break;
  case IceType_i8:
    assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_al);
    assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ax ||
           DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ah);
    Asm->cbw();
    break;
  case IceType_i16:
    assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_ax);
    assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_dx);
    Asm->cwd();
    break;
  case IceType_i32:
    assert(SrcReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
    assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
    Asm->cdq();
    break;
  case IceType_i64:
    assert(DestReg == InstX86Base<Machine>::Traits::RegisterSet::Reg_edx);
    Asm->cqo();
    break;
  }
}

template <class Machine> void InstX86Mul<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  assert(llvm::isa<Variable>(this->getSrc(0)));
  assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
  assert(
      this->getDest()->getRegNum() ==
      InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); // TODO: allow edx?
  Str << "\tmul" << this->getWidthString(this->getDest()->getType()) << "\t";
  this->getSrc(1)->emit(Func);
}

template <class Machine>
void InstX86Mul<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  assert(llvm::isa<Variable>(this->getSrc(0)));
  assert(llvm::cast<Variable>(this->getSrc(0))->getRegNum() ==
         InstX86Base<Machine>::Traits::RegisterSet::Reg_eax);
  assert(
      this->getDest()->getRegNum() ==
      InstX86Base<Machine>::Traits::RegisterSet::Reg_eax); // TODO: allow edx?
  const Operand *Src = this->getSrc(1);
  Type Ty = Src->getType();
  static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterOneOp
      Emitter = {&InstX86Base<Machine>::Traits::Assembler::mul,
                 &InstX86Base<Machine>::Traits::Assembler::mul};
  emitIASOpTyGPR<Machine>(Func, Ty, Src, Emitter);
}

template <class Machine> void InstX86Mul<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  this->dumpDest(Func);
  Str << " = mul." << this->getDest()->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Shld<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Variable *Dest = this->getDest();
  assert(this->getSrcSize() == 3);
  assert(Dest == this->getSrc(0));
  Str << "\tshld" << this->getWidthString(Dest->getType()) << "\t";
  this->getSrc(2)->emit(Func);
  Str << ", ";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  Dest->emit(Func);
}

template <class Machine>
void InstX86Shld<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 3);
  assert(this->getDest() == this->getSrc(0));
  const Variable *Dest = this->getDest();
  const Operand *Src1 = this->getSrc(1);
  const Operand *Src2 = this->getSrc(2);
  static const typename InstX86Base<
      Machine>::Traits::Assembler::GPREmitterShiftD Emitter = {
      &InstX86Base<Machine>::Traits::Assembler::shld,
      &InstX86Base<Machine>::Traits::Assembler::shld};
  emitIASGPRShiftDouble<Machine>(Func, Dest, Src1, Src2, Emitter);
}

template <class Machine>
void InstX86Shld<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  this->dumpDest(Func);
  Str << " = shld." << this->getDest()->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Shrd<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Variable *Dest = this->getDest();
  assert(this->getSrcSize() == 3);
  assert(Dest == this->getSrc(0));
  Str << "\tshrd" << this->getWidthString(Dest->getType()) << "\t";
  this->getSrc(2)->emit(Func);
  Str << ", ";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  Dest->emit(Func);
}

template <class Machine>
void InstX86Shrd<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 3);
  assert(this->getDest() == this->getSrc(0));
  const Variable *Dest = this->getDest();
  const Operand *Src1 = this->getSrc(1);
  const Operand *Src2 = this->getSrc(2);
  static const typename InstX86Base<
      Machine>::Traits::Assembler::GPREmitterShiftD Emitter = {
      &InstX86Base<Machine>::Traits::Assembler::shrd,
      &InstX86Base<Machine>::Traits::Assembler::shrd};
  emitIASGPRShiftDouble<Machine>(Func, Dest, Src1, Src2, Emitter);
}

template <class Machine>
void InstX86Shrd<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  this->dumpDest(Func);
  Str << " = shrd." << this->getDest()->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Cmov<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Variable *Dest = this->getDest();
  Str << "\t";
  assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
  assert(this->getDest()->hasReg());
  Str << "cmov"
      << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString
      << this->getWidthString(Dest->getType()) << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  Dest->emit(Func);
}

template <class Machine>
void InstX86Cmov<Machine>::emitIAS(const Cfg *Func) const {
  assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
  assert(this->getDest()->hasReg());
  assert(this->getSrcSize() == 2);
  Operand *Src = this->getSrc(1);
  Type SrcTy = Src->getType();
  assert(SrcTy == IceType_i16 || SrcTy == IceType_i32 ||
         (InstX86Base<Machine>::Traits::Is64Bit));
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  if (const auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
    if (SrcVar->hasReg()) {
      Asm->cmov(
          SrcTy, Condition, InstX86Base<Machine>::Traits::getEncodedGPR(
                                this->getDest()->getRegNum()),
          InstX86Base<Machine>::Traits::getEncodedGPR(SrcVar->getRegNum()));
    } else {
      Asm->cmov(SrcTy, Condition, InstX86Base<Machine>::Traits::getEncodedGPR(
                                      this->getDest()->getRegNum()),
                Target->stackVarToAsmOperand(SrcVar));
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
    assert(Mem->getSegmentRegister() ==
           InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
    Asm->cmov(SrcTy, Condition, InstX86Base<Machine>::Traits::getEncodedGPR(
                                    this->getDest()->getRegNum()),
              Mem->toAsmAddress(Asm, Target));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine>
void InstX86Cmov<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "cmov"
      << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString
      << ".";
  Str << this->getDest()->getType() << " ";
  this->dumpDest(Func);
  Str << ", ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Cmpps<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid);
  Str << "\t";
  Str << "cmp"
      << InstX86Base<Machine>::Traits::InstCmppsAttributes[Condition].EmitString
      << "ps"
      << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Cmpps<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(this->getSrcSize() == 2);
  assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid);
  // Assuming there isn't any load folding for cmpps, and vector constants are
  // not allowed in PNaCl.
  assert(llvm::isa<Variable>(this->getSrc(1)));
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  const auto *SrcVar = llvm::cast<Variable>(this->getSrc(1));
  if (SrcVar->hasReg()) {
    Asm->cmpps(InstX86Base<Machine>::Traits::getEncodedXmm(
                   this->getDest()->getRegNum()),
               InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()),
               Condition);
  } else {
    typename InstX86Base<Machine>::Traits::Address SrcStackAddr =
        Target->stackVarToAsmOperand(SrcVar);
    Asm->cmpps(InstX86Base<Machine>::Traits::getEncodedXmm(
                   this->getDest()->getRegNum()),
               SrcStackAddr, Condition);
  }
}

template <class Machine>
void InstX86Cmpps<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  assert(Condition < InstX86Base<Machine>::Traits::Cond::Cmpps_Invalid);
  this->dumpDest(Func);
  Str << " = cmp"
      << InstX86Base<Machine>::Traits::InstCmppsAttributes[Condition].EmitString
      << "ps"
      << "\t";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Cmpxchg<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 3);
  if (this->Locked) {
    Str << "\tlock";
  }
  Str << "\tcmpxchg" << this->getWidthString(this->getSrc(0)->getType())
      << "\t";
  this->getSrc(2)->emit(Func);
  Str << ", ";
  this->getSrc(0)->emit(Func);
}

template <class Machine>
void InstX86Cmpxchg<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 3);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Type Ty = this->getSrc(0)->getType();
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  const auto Mem =
      llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
          this->getSrc(0));
  assert(Mem->getSegmentRegister() ==
         InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
  const typename InstX86Base<Machine>::Traits::Address Addr =
      Mem->toAsmAddress(Asm, Target);
  const auto *VarReg = llvm::cast<Variable>(this->getSrc(2));
  assert(VarReg->hasReg());
  const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg =
      InstX86Base<Machine>::Traits::getEncodedGPR(VarReg->getRegNum());
  Asm->cmpxchg(Ty, Addr, Reg, this->Locked);
}

template <class Machine>
void InstX86Cmpxchg<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  if (this->Locked) {
    Str << "lock ";
  }
  Str << "cmpxchg." << this->getSrc(0)->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Cmpxchg8b<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 5);
  if (this->Locked) {
    Str << "\tlock";
  }
  Str << "\tcmpxchg8b\t";
  this->getSrc(0)->emit(Func);
}

template <class Machine>
void InstX86Cmpxchg8b<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 5);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  const auto Mem =
      llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
          this->getSrc(0));
  assert(Mem->getSegmentRegister() ==
         InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  const typename InstX86Base<Machine>::Traits::Address Addr =
      Mem->toAsmAddress(Asm, Target);
  Asm->cmpxchg8b(Addr, this->Locked);
}

template <class Machine>
void InstX86Cmpxchg8b<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  if (this->Locked) {
    Str << "lock ";
  }
  Str << "cmpxchg8b ";
  this->dumpSources(Func);
}

template <class Machine> void InstX86Cvt<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  Str << "\tcvt";
  if (isTruncating())
    Str << "t";
  Str << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
                                                          ->getType()]
             .CvtString << "2"
      << InstX86Base<
             Machine>::Traits::TypeAttributes[this->getDest()->getType()]
             .CvtString << "\t";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Cvt<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 1);
  const Variable *Dest = this->getDest();
  const Operand *Src = this->getSrc(0);
  Type DestTy = Dest->getType();
  Type SrcTy = Src->getType();
  switch (Variant) {
  case Si2ss: {
    assert(isScalarIntegerType(SrcTy));
    if (!InstX86Base<Machine>::Traits::Is64Bit) {
      assert(typeWidthInBytes(SrcTy) <= 4);
    } else {
      assert(SrcTy == IceType_i32 || SrcTy == IceType_i64);
    }
    assert(isScalarFloatingType(DestTy));
    static const typename InstX86Base<Machine>::Traits::Assembler::
        template CastEmitterRegOp<
            typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
            typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister>
            Emitter = {&InstX86Base<Machine>::Traits::Assembler::cvtsi2ss,
                       &InstX86Base<Machine>::Traits::Assembler::cvtsi2ss};
    emitIASCastRegOp<
        Machine,
        typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
        typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
        InstX86Base<Machine>::Traits::getEncodedXmm,
        InstX86Base<Machine>::Traits::getEncodedGPR>(Func, DestTy, Dest, SrcTy,
                                                     Src, Emitter);
    return;
  }
  case Tss2si: {
    assert(isScalarFloatingType(SrcTy));
    assert(isScalarIntegerType(DestTy));
    if (!InstX86Base<Machine>::Traits::Is64Bit) {
      assert(typeWidthInBytes(DestTy) <= 4);
    } else {
      assert(DestTy == IceType_i32 || DestTy == IceType_i64);
    }
    static const typename InstX86Base<Machine>::Traits::Assembler::
        template CastEmitterRegOp<
            typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
            typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
            Emitter = {&InstX86Base<Machine>::Traits::Assembler::cvttss2si,
                       &InstX86Base<Machine>::Traits::Assembler::cvttss2si};
    emitIASCastRegOp<
        Machine,
        typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
        typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
        InstX86Base<Machine>::Traits::getEncodedGPR,
        InstX86Base<Machine>::Traits::getEncodedXmm>(Func, DestTy, Dest, SrcTy,
                                                     Src, Emitter);
    return;
  }
  case Float2float: {
    assert(isScalarFloatingType(SrcTy));
    assert(isScalarFloatingType(DestTy));
    assert(DestTy != SrcTy);
    static const typename InstX86Base<
        Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = {
        &InstX86Base<Machine>::Traits::Assembler::cvtfloat2float,
        &InstX86Base<Machine>::Traits::Assembler::cvtfloat2float};
    emitIASRegOpTyXMM<Machine>(Func, SrcTy, Dest, Src, Emitter);
    return;
  }
  case Dq2ps: {
    assert(isVectorIntegerType(SrcTy));
    assert(isVectorFloatingType(DestTy));
    static const typename InstX86Base<
        Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = {
        &InstX86Base<Machine>::Traits::Assembler::cvtdq2ps,
        &InstX86Base<Machine>::Traits::Assembler::cvtdq2ps};
    emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, Emitter);
    return;
  }
  case Tps2dq: {
    assert(isVectorFloatingType(SrcTy));
    assert(isVectorIntegerType(DestTy));
    static const typename InstX86Base<
        Machine>::Traits::Assembler::XmmEmitterRegOp Emitter = {
        &InstX86Base<Machine>::Traits::Assembler::cvttps2dq,
        &InstX86Base<Machine>::Traits::Assembler::cvttps2dq};
    emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, Emitter);
    return;
  }
  }
}

template <class Machine> void InstX86Cvt<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  this->dumpDest(Func);
  Str << " = cvt";
  if (isTruncating())
    Str << "t";
  Str << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
                                                          ->getType()]
             .CvtString << "2"
      << InstX86Base<
             Machine>::Traits::TypeAttributes[this->getDest()->getType()]
             .CvtString << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Icmp<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  Str << "\tcmp" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  this->getSrc(0)->emit(Func);
}

template <class Machine>
void InstX86Icmp<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  const Operand *Src0 = this->getSrc(0);
  const Operand *Src1 = this->getSrc(1);
  Type Ty = Src0->getType();
  static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
      RegEmitter = {&InstX86Base<Machine>::Traits::Assembler::cmp,
                    &InstX86Base<Machine>::Traits::Assembler::cmp,
                    &InstX86Base<Machine>::Traits::Assembler::cmp};
  static const typename InstX86Base<
      Machine>::Traits::Assembler::GPREmitterAddrOp AddrEmitter = {
      &InstX86Base<Machine>::Traits::Assembler::cmp,
      &InstX86Base<Machine>::Traits::Assembler::cmp};
  if (const auto *SrcVar0 = llvm::dyn_cast<Variable>(Src0)) {
    if (SrcVar0->hasReg()) {
      emitIASRegOpTyGPR<Machine>(Func, Ty, SrcVar0, Src1, RegEmitter);
      return;
    }
  }
  emitIASAsAddrOpTyGPR<Machine>(Func, Ty, Src0, Src1, AddrEmitter);
}

template <class Machine>
void InstX86Icmp<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "cmp." << this->getSrc(0)->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Ucomiss<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  Str << "\tucomi"
      << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
                                                          ->getType()]
             .SdSsString << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  this->getSrc(0)->emit(Func);
}

template <class Machine>
void InstX86Ucomiss<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  // Currently src0 is always a variable by convention, to avoid having two
  // memory operands.
  assert(llvm::isa<Variable>(this->getSrc(0)));
  const auto *Src0Var = llvm::cast<Variable>(this->getSrc(0));
  Type Ty = Src0Var->getType();
  static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
      Emitter = {&InstX86Base<Machine>::Traits::Assembler::ucomiss,
                 &InstX86Base<Machine>::Traits::Assembler::ucomiss};
  emitIASRegOpTyXMM<Machine>(Func, Ty, Src0Var, this->getSrc(1), Emitter);
}

template <class Machine>
void InstX86Ucomiss<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "ucomiss." << this->getSrc(0)->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine> void InstX86UD2<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 0);
  Str << "\tud2";
}

template <class Machine>
void InstX86UD2<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Asm->ud2();
}

template <class Machine> void InstX86UD2<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "ud2";
}

template <class Machine>
void InstX86Test<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  Str << "\ttest" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  this->getSrc(0)->emit(Func);
}

template <class Machine>
void InstX86Test<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  const Operand *Src0 = this->getSrc(0);
  const Operand *Src1 = this->getSrc(1);
  Type Ty = Src0->getType();
  // The Reg/Addr form of test is not encodeable.
  static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
      RegEmitter = {&InstX86Base<Machine>::Traits::Assembler::test, nullptr,
                    &InstX86Base<Machine>::Traits::Assembler::test};
  static const typename InstX86Base<
      Machine>::Traits::Assembler::GPREmitterAddrOp AddrEmitter = {
      &InstX86Base<Machine>::Traits::Assembler::test,
      &InstX86Base<Machine>::Traits::Assembler::test};
  if (const auto *SrcVar0 = llvm::dyn_cast<Variable>(Src0)) {
    if (SrcVar0->hasReg()) {
      emitIASRegOpTyGPR<Machine>(Func, Ty, SrcVar0, Src1, RegEmitter);
      return;
    }
  }
  emitIASAsAddrOpTyGPR<Machine>(Func, Ty, Src0, Src1, AddrEmitter);
}

template <class Machine>
void InstX86Test<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "test." << this->getSrc(0)->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Mfence<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 0);
  Str << "\tmfence";
}

template <class Machine>
void InstX86Mfence<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Asm->mfence();
}

template <class Machine>
void InstX86Mfence<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "mfence";
}

template <class Machine>
void InstX86Store<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  Type Ty = this->getSrc(0)->getType();
  Str << "\tmov" << this->getWidthString(Ty)
      << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  this->getSrc(1)->emit(Func);
}

template <class Machine>
void InstX86Store<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  const Operand *Dest = this->getSrc(1);
  const Operand *Src = this->getSrc(0);
  Type DestTy = Dest->getType();
  if (isScalarFloatingType(DestTy)) {
    // Src must be a register, since Dest is a Mem operand of some kind.
    const auto *SrcVar = llvm::cast<Variable>(Src);
    assert(SrcVar->hasReg());
    typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
        InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum());
    typename InstX86Base<Machine>::Traits::Assembler *Asm =
        Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
    auto *Target = InstX86Base<Machine>::getTarget(Func);
    if (const auto *DestVar = llvm::dyn_cast<Variable>(Dest)) {
      assert(!DestVar->hasReg());
      typename InstX86Base<Machine>::Traits::Address StackAddr(
          Target->stackVarToAsmOperand(DestVar));
      Asm->movss(DestTy, StackAddr, SrcReg);
    } else {
      const auto DestMem =
          llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
              Dest);
      assert(DestMem->getSegmentRegister() ==
             InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
      Asm->movss(DestTy, DestMem->toAsmAddress(Asm, Target), SrcReg);
    }
    return;
  } else {
    assert(isScalarIntegerType(DestTy));
    static const typename InstX86Base<
        Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = {
        &InstX86Base<Machine>::Traits::Assembler::mov,
        &InstX86Base<Machine>::Traits::Assembler::mov};
    emitIASAsAddrOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRAddrEmitter);
  }
}

template <class Machine>
void InstX86Store<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "mov." << this->getSrc(0)->getType() << " ";
  this->getSrc(1)->dump(Func);
  Str << ", ";
  this->getSrc(0)->dump(Func);
}

template <class Machine>
void InstX86StoreP<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  assert(isVectorType(this->getSrc(1)->getType()));
  Str << "\tmovups\t";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  this->getSrc(1)->emit(Func);
}

template <class Machine>
void InstX86StoreP<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(this->getSrcSize() == 2);
  const auto *SrcVar = llvm::cast<Variable>(this->getSrc(0));
  const auto DestMem =
      llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
          this->getSrc(1));
  assert(DestMem->getSegmentRegister() ==
         InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
  assert(SrcVar->hasReg());
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  Asm->movups(DestMem->toAsmAddress(Asm, Target),
              InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()));
}

template <class Machine>
void InstX86StoreP<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "storep." << this->getSrc(0)->getType() << " ";
  this->getSrc(1)->dump(Func);
  Str << ", ";
  this->getSrc(0)->dump(Func);
}

template <class Machine>
void InstX86StoreQ<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  assert(this->getSrc(1)->getType() == IceType_i64 ||
         this->getSrc(1)->getType() == IceType_f64 ||
         isVectorType(this->getSrc(1)->getType()));
  Str << "\tmovq\t";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  this->getSrc(1)->emit(Func);
}

template <class Machine>
void InstX86StoreQ<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(this->getSrcSize() == 2);
  const auto *SrcVar = llvm::cast<Variable>(this->getSrc(0));
  const auto DestMem =
      llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
          this->getSrc(1));
  assert(DestMem->getSegmentRegister() ==
         InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
  assert(SrcVar->hasReg());
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  Asm->movq(DestMem->toAsmAddress(Asm, Target),
            InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()));
}

template <class Machine>
void InstX86StoreQ<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "storeq." << this->getSrc(0)->getType() << " ";
  this->getSrc(1)->dump(Func);
  Str << ", ";
  this->getSrc(0)->dump(Func);
}

template <class Machine> void InstX86Lea<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  assert(this->getDest()->hasReg());
  Str << "\tleal\t";
  Operand *Src0 = this->getSrc(0);
  if (const auto *Src0Var = llvm::dyn_cast<Variable>(Src0)) {
    Type Ty = Src0Var->getType();
    // lea on x86-32 doesn't accept mem128 operands, so cast VSrc0 to an
    // acceptable type.
    Src0Var->asType(isVectorType(Ty) ? IceType_i32 : Ty, Variable::NoRegister)
        ->emit(Func);
  } else {
    Src0->emit(Func);
  }
  Str << ", ";
  this->getDest()->emit(Func);
}

inline bool isIntegerConstant(const Operand *Op) {
  return llvm::isa<ConstantInteger32>(Op) || llvm::isa<ConstantInteger64>(Op);
}

template <class Machine> void InstX86Mov<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  Operand *Src = this->getSrc(0);
  Type SrcTy = Src->getType();
  Type DestTy = this->getDest()->getType();
  if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 &&
      isIntegerConstant(Src)) {
    Str << "\tmovabs\t";
  } else {
    Str << "\tmov"
        << (!isScalarFloatingType(DestTy)
                ? this->getWidthString(DestTy)
                : InstX86Base<Machine>::Traits::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.
  // TODO: This assert disallows usages such as copying a floating
  // point value between a vector and a scalar (which movss is used for). Clean
  // this up.
  assert(
      InstX86Base<Machine>::getTarget(Func)->typeWidthInBytesOnStack(DestTy) ==
      InstX86Base<Machine>::getTarget(Func)->typeWidthInBytesOnStack(SrcTy));
  const Operand *NewSrc = Src;
  if (auto *SrcVar = llvm::dyn_cast<Variable>(Src)) {
    int32_t NewRegNum = Variable::NoRegister;
    if (SrcVar->hasReg())
      NewRegNum = InstX86Base<Machine>::Traits::getGprForType(
          DestTy, SrcVar->getRegNum());
    if (SrcTy != DestTy)
      NewSrc = SrcVar->asType(DestTy, NewRegNum);
  }
  NewSrc->emit(Func);
  Str << ", ";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Mov<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 1);
  const Variable *Dest = this->getDest();
  const Operand *Src = this->getSrc(0);
  Type DestTy = Dest->getType();
  Type SrcTy = Src->getType();
  // Mov can be used for GPRs or XMM registers. Also, the type does not
  // necessarily match (Mov can be used for bitcasts). However, when the type
  // does not match, one of the operands must be a register. Thus, the strategy
  // is to find out if Src or Dest are a register, then use that register's
  // type to decide on which emitter set to use. The emitter set will include
  // reg-reg movs, but that case should be unused when the types don't match.
  static const typename InstX86Base<Machine>::Traits::Assembler::XmmEmitterRegOp
      XmmRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::movss,
                       &InstX86Base<Machine>::Traits::Assembler::movss};
  static const typename InstX86Base<Machine>::Traits::Assembler::GPREmitterRegOp
      GPRRegEmitter = {&InstX86Base<Machine>::Traits::Assembler::mov,
                       &InstX86Base<Machine>::Traits::Assembler::mov,
                       &InstX86Base<Machine>::Traits::Assembler::mov};
  static const typename InstX86Base<
      Machine>::Traits::Assembler::GPREmitterAddrOp GPRAddrEmitter = {
      &InstX86Base<Machine>::Traits::Assembler::mov,
      &InstX86Base<Machine>::Traits::Assembler::mov};
  // 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.
  // TODO: This assert disallows usages such as copying a floating
  // point value between a vector and a scalar (which movss is used for). Clean
  // this up.
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  assert(Target->typeWidthInBytesOnStack(this->getDest()->getType()) ==
         Target->typeWidthInBytesOnStack(Src->getType()));
  if (Dest->hasReg()) {
    if (isScalarFloatingType(DestTy)) {
      emitIASRegOpTyXMM<Machine>(Func, DestTy, Dest, Src, XmmRegEmitter);
      return;
    } else {
      assert(isScalarIntegerType(DestTy));
      // Widen DestTy for truncation (see above note). We should only do this
      // when both Src and Dest are integer types.
      if (InstX86Base<Machine>::Traits::Is64Bit && DestTy == IceType_i64 &&
          isIntegerConstant(Src)) {
        uint64_t Value = -1;
        if (const auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src)) {
          Value = C64->getValue();
        } else {
          Value = llvm::cast<ConstantInteger32>(Src)->getValue();
        }
        Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>()
            ->movabs(
                InstX86Base<Machine>::Traits::getEncodedGPR(Dest->getRegNum()),
                Value);
        return;
      }
      if (isScalarIntegerType(SrcTy)) {
        SrcTy = DestTy;
      }
      emitIASRegOpTyGPR<Machine>(Func, DestTy, Dest, Src, GPRRegEmitter);
      return;
    }
  } else {
    // Dest must be Stack and Src *could* be a register. Use Src's type to
    // decide on the emitters.
    typename InstX86Base<Machine>::Traits::Address StackAddr(
        Target->stackVarToAsmOperand(Dest));
    if (isScalarFloatingType(SrcTy)) {
      // Src must be a register.
      const auto *SrcVar = llvm::cast<Variable>(Src);
      assert(SrcVar->hasReg());
      typename InstX86Base<Machine>::Traits::Assembler *Asm =
          Func->getAssembler<
              typename InstX86Base<Machine>::Traits::Assembler>();
      Asm->movss(SrcTy, StackAddr, InstX86Base<Machine>::Traits::getEncodedXmm(
                                       SrcVar->getRegNum()));
      return;
    } else {
      // Src can be a register or immediate.
      assert(isScalarIntegerType(SrcTy));
      emitIASAddrOpTyGPR<Machine>(Func, SrcTy, StackAddr, Src, GPRAddrEmitter);
      return;
    }
    return;
  }
}

template <class Machine>
void InstX86Movd<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(this->getSrcSize() == 1);
  const Variable *Dest = this->getDest();
  const auto *SrcVar = llvm::cast<Variable>(this->getSrc(0));
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  // For insert/extract element (one of Src/Dest is an Xmm vector and the other
  // is an int type).
  if (SrcVar->getType() == IceType_i32 ||
      (InstX86Base<Machine>::Traits::Is64Bit &&
       SrcVar->getType() == IceType_i64)) {
    assert(isVectorType(Dest->getType()) ||
           (isScalarFloatingType(Dest->getType()) &&
            typeWidthInBytes(SrcVar->getType()) ==
                typeWidthInBytes(Dest->getType())));
    assert(Dest->hasReg());
    typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister DestReg =
        InstX86Base<Machine>::Traits::getEncodedXmm(Dest->getRegNum());
    if (SrcVar->hasReg()) {
      Asm->movd(
          SrcVar->getType(), DestReg,
          InstX86Base<Machine>::Traits::getEncodedGPR(SrcVar->getRegNum()));
    } else {
      typename InstX86Base<Machine>::Traits::Address StackAddr(
          Target->stackVarToAsmOperand(SrcVar));
      Asm->movd(SrcVar->getType(), DestReg, StackAddr);
    }
  } else {
    assert(isVectorType(SrcVar->getType()) ||
           (isScalarFloatingType(SrcVar->getType()) &&
            typeWidthInBytes(SrcVar->getType()) ==
                typeWidthInBytes(Dest->getType())));
    assert(SrcVar->hasReg());
    assert(Dest->getType() == IceType_i32 ||
           (InstX86Base<Machine>::Traits::Is64Bit &&
            Dest->getType() == IceType_i64));
    typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister SrcReg =
        InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum());
    if (Dest->hasReg()) {
      Asm->movd(Dest->getType(),
                InstX86Base<Machine>::Traits::getEncodedGPR(Dest->getRegNum()),
                SrcReg);
    } else {
      typename InstX86Base<Machine>::Traits::Address StackAddr(
          Target->stackVarToAsmOperand(Dest));
      Asm->movd(Dest->getType(), StackAddr, SrcReg);
    }
  }
}

template <class Machine>
void InstX86Movp<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  // TODO(wala,stichnot): movups works with all vector operands, but there
  // exist other instructions (movaps, movdqa, movdqu) that may perform better,
  // depending on the data type and alignment of the operands.
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  Str << "\tmovups\t";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Movp<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 1);
  assert(isVectorType(this->getDest()->getType()));
  const Variable *Dest = this->getDest();
  const Operand *Src = this->getSrc(0);
  static const typename InstX86Base<
      Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = {
      &InstX86Base<Machine>::Traits::Assembler::movups,
      &InstX86Base<Machine>::Traits::Assembler::movups,
      &InstX86Base<Machine>::Traits::Assembler::movups};
  emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter);
}

template <class Machine>
void InstX86Movq<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  assert(this->getDest()->getType() == IceType_i64 ||
         this->getDest()->getType() == IceType_f64);
  Str << "\tmovq\t";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Movq<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 1);
  assert(this->getDest()->getType() == IceType_i64 ||
         this->getDest()->getType() == IceType_f64);
  const Variable *Dest = this->getDest();
  const Operand *Src = this->getSrc(0);
  static const typename InstX86Base<
      Machine>::Traits::Assembler::XmmEmitterMovOps Emitter = {
      &InstX86Base<Machine>::Traits::Assembler::movq,
      &InstX86Base<Machine>::Traits::Assembler::movq,
      &InstX86Base<Machine>::Traits::Assembler::movq};
  emitIASMovlikeXMM<Machine>(Func, Dest, Src, Emitter);
}

template <class Machine>
void InstX86MovssRegs<Machine>::emitIAS(const Cfg *Func) const {
  // This is Binop variant is only intended to be used for reg-reg moves where
  // part of the Dest register is untouched.
  assert(this->getSrcSize() == 2);
  const Variable *Dest = this->getDest();
  assert(Dest == this->getSrc(0));
  const auto *SrcVar = llvm::cast<Variable>(this->getSrc(1));
  assert(Dest->hasReg() && SrcVar->hasReg());
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Asm->movss(IceType_f32,
             InstX86Base<Machine>::Traits::getEncodedXmm(Dest->getRegNum()),
             InstX86Base<Machine>::Traits::getEncodedXmm(SrcVar->getRegNum()));
}

template <class Machine>
void InstX86Movsx<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 1);
  const Variable *Dest = this->getDest();
  const Operand *Src = this->getSrc(0);
  // Dest must be a > 8-bit register, but Src can be 8-bit. In practice we just
  // use the full register for Dest to avoid having an OperandSizeOverride
  // prefix. It also allows us to only dispatch on SrcTy.
  Type SrcTy = Src->getType();
  assert(typeWidthInBytes(Dest->getType()) > 1);
  assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy));
  emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src,
                                          this->Emitter);
}

template <class Machine>
void InstX86Movzx<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 1);
  const Variable *Dest = this->getDest();
  const Operand *Src = this->getSrc(0);
  Type SrcTy = Src->getType();
  assert(typeWidthInBytes(Dest->getType()) > 1);
  assert(typeWidthInBytes(Dest->getType()) > typeWidthInBytes(SrcTy));
  emitIASRegOpTyGPR<Machine, false, true>(Func, SrcTy, Dest, Src,
                                          this->Emitter);
}

template <class Machine> void InstX86Nop<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  // TODO: Emit the right code for each variant.
  Str << "\tnop\t# variant = " << Variant;
}

template <class Machine>
void InstX86Nop<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  // TODO: Emit the right code for the variant.
  Asm->nop();
}

template <class Machine> void InstX86Nop<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "nop (variant = " << Variant << ")";
}

template <class Machine> void InstX86Fld<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  Type Ty = this->getSrc(0)->getType();
  const auto *Var = llvm::dyn_cast<Variable>(this->getSrc(0));
  if (Var && Var->hasReg()) {
    // This is a physical xmm register, so we need to spill it to a temporary
    // stack slot.  Function prolog emission guarantees that there is sufficient
    // space to do this.
    Str << "\tmov"
        << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString << "\t";
    Var->emit(Func);
    Str << ", (%esp)\n";
    Str << "\tfld" << this->getFldString(Ty) << "\t"
        << "(%esp)";
    return;
  }
  Str << "\tfld" << this->getFldString(Ty) << "\t";
  this->getSrc(0)->emit(Func);
}

template <class Machine>
void InstX86Fld<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(this->getSrcSize() == 1);
  const Operand *Src = this->getSrc(0);
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  Type Ty = Src->getType();
  if (const auto *Var = llvm::dyn_cast<Variable>(Src)) {
    if (Var->hasReg()) {
      // This is a physical xmm register, so we need to spill it to a temporary
      // stack slot.  Function prolog emission guarantees that there is
      // sufficient space to do this.
      typename InstX86Base<Machine>::Traits::Address StackSlot =
          typename InstX86Base<Machine>::Traits::Address(
              InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0,
              AssemblerFixup::NoFixup);
      Asm->movss(Ty, StackSlot,
                 InstX86Base<Machine>::Traits::getEncodedXmm(Var->getRegNum()));
      Asm->fld(Ty, StackSlot);
    } else {
      typename InstX86Base<Machine>::Traits::Address StackAddr(
          Target->stackVarToAsmOperand(Var));
      Asm->fld(Ty, StackAddr);
    }
  } else if (const auto *Mem = llvm::dyn_cast<
                 typename InstX86Base<Machine>::Traits::X86OperandMem>(Src)) {
    assert(Mem->getSegmentRegister() ==
           InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
    Asm->fld(Ty, Mem->toAsmAddress(Asm, Target));
  } else if (const auto *Imm = llvm::dyn_cast<Constant>(Src)) {
    Asm->fld(Ty, InstX86Base<Machine>::Traits::Address::ofConstPool(Asm, Imm));
  } else {
    llvm_unreachable("Unexpected operand type");
  }
}

template <class Machine> void InstX86Fld<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "fld." << this->getSrc(0)->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Fstp<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 0);
  // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to
  // "partially" delete the fstp if the Dest is unused. Even if Dest is unused,
  // the fstp should be kept for the SideEffects of popping the stack.
  if (!this->getDest()) {
    Str << "\tfstp\tst(0)";
    return;
  }
  Type Ty = this->getDest()->getType();
  if (!this->getDest()->hasReg()) {
    Str << "\tfstp" << this->getFldString(Ty) << "\t";
    this->getDest()->emit(Func);
    return;
  }
  // Dest is a physical (xmm) register, so st(0) needs to go through memory.
  // Hack this by using caller-reserved memory at the top of stack, spilling
  // st(0) there, and loading it into the xmm register.
  Str << "\tfstp" << this->getFldString(Ty) << "\t"
      << "(%esp)\n";
  Str << "\tmov" << InstX86Base<Machine>::Traits::TypeAttributes[Ty].SdSsString
      << "\t"
      << "(%esp), ";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Fstp<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  assert(this->getSrcSize() == 0);
  const Variable *Dest = this->getDest();
  // TODO(jvoung,stichnot): Utilize this by setting Dest to nullptr to
  // "partially" delete the fstp if the Dest is unused. Even if Dest is unused,
  // the fstp should be kept for the SideEffects of popping the stack.
  if (!Dest) {
    Asm->fstp(InstX86Base<Machine>::Traits::RegisterSet::getEncodedSTReg(0));
    return;
  }
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  Type Ty = Dest->getType();
  if (!Dest->hasReg()) {
    typename InstX86Base<Machine>::Traits::Address StackAddr(
        Target->stackVarToAsmOperand(Dest));
    Asm->fstp(Ty, StackAddr);
  } else {
    // Dest is a physical (xmm) register, so st(0) needs to go through memory.
    // Hack this by using caller-reserved memory at the top of stack, spilling
    // st(0) there, and loading it into the xmm register.
    typename InstX86Base<Machine>::Traits::Address StackSlot =
        typename InstX86Base<Machine>::Traits::Address(
            InstX86Base<Machine>::Traits::RegisterSet::Encoded_Reg_esp, 0,
            AssemblerFixup::NoFixup);
    Asm->fstp(Ty, StackSlot);
    Asm->movss(Ty,
               InstX86Base<Machine>::Traits::getEncodedXmm(Dest->getRegNum()),
               StackSlot);
  }
}

template <class Machine>
void InstX86Fstp<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  this->dumpDest(Func);
  Str << " = fstp." << this->getDest()->getType() << ", st(0)";
}

template <class Machine>
void InstX86Pcmpeq<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "pcmpeq%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .PackString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Pcmpgt<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "pcmpgt%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .PackString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Pextr<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 2);
  // pextrb and pextrd are SSE4.1 instructions.
  assert(this->getSrc(0)->getType() == IceType_v8i16 ||
         this->getSrc(0)->getType() == IceType_v8i1 ||
         InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
             InstX86Base<Machine>::Traits::SSE4_1);
  Str << "\t" << this->Opcode
      << InstX86Base<Machine>::Traits::TypeAttributes[this->getSrc(0)
                                                          ->getType()]
             .PackString << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  this->getSrc(0)->emit(Func);
  Str << ", ";
  Variable *Dest = this->getDest();
  // pextrw must take a register dest. There is an SSE4.1 version that takes a
  // memory dest, but we aren't using it. For uniformity, just restrict them
  // all to have a register dest for now.
  assert(Dest->hasReg());
  Dest->asType(IceType_i32, Dest->getRegNum())->emit(Func);
}

template <class Machine>
void InstX86Pextr<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  // pextrb and pextrd are SSE4.1 instructions.
  const Variable *Dest = this->getDest();
  Type DispatchTy = InstX86Base<Machine>::Traits::getInVectorElementType(
      this->getSrc(0)->getType());
  assert(DispatchTy == IceType_i16 ||
         InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
             InstX86Base<Machine>::Traits::SSE4_1);
  // pextrw must take a register dest. There is an SSE4.1 version that takes a
  // memory dest, but we aren't using it. For uniformity, just restrict them
  // all to have a register dest for now.
  assert(Dest->hasReg());
  // pextrw's Src(0) must be a register (both SSE4.1 and SSE2).
  assert(llvm::cast<Variable>(this->getSrc(0))->hasReg());
  static const typename InstX86Base<Machine>::Traits::Assembler::
      template ThreeOpImmEmitter<
          typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
          typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
          Emitter = {&InstX86Base<Machine>::Traits::Assembler::pextr, nullptr};
  emitIASThreeOpImmOps<
      Machine, typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
      typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
      InstX86Base<Machine>::Traits::getEncodedGPR,
      InstX86Base<Machine>::Traits::getEncodedXmm>(
      Func, DispatchTy, Dest, this->getSrc(0), this->getSrc(1), Emitter);
}

template <class Machine>
void InstX86Pinsr<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 3);
  // pinsrb and pinsrd are SSE4.1 instructions.
  assert(this->getDest()->getType() == IceType_v8i16 ||
         this->getDest()->getType() == IceType_v8i1 ||
         InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
             InstX86Base<Machine>::Traits::SSE4_1);
  Str << "\t" << this->Opcode
      << InstX86Base<
             Machine>::Traits::TypeAttributes[this->getDest()->getType()]
             .PackString << "\t";
  this->getSrc(2)->emit(Func);
  Str << ", ";
  Operand *Src1 = this->getSrc(1);
  if (const auto *Src1Var = llvm::dyn_cast<Variable>(Src1)) {
    // If src1 is a register, it should always be r32.
    if (Src1Var->hasReg()) {
      int32_t NewRegNum =
          InstX86Base<Machine>::Traits::getBaseReg(Src1Var->getRegNum());
      const Variable *NewSrc = Src1Var->asType(IceType_i32, NewRegNum);
      NewSrc->emit(Func);
    } else {
      Src1Var->emit(Func);
    }
  } else {
    Src1->emit(Func);
  }
  Str << ", ";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Pinsr<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 3);
  assert(this->getDest() == this->getSrc(0));
  // pinsrb and pinsrd are SSE4.1 instructions.
  const Operand *Src0 = this->getSrc(1);
  Type DispatchTy = Src0->getType();
  assert(DispatchTy == IceType_i16 ||
         InstX86Base<Machine>::getTarget(Func)->getInstructionSet() >=
             InstX86Base<Machine>::Traits::SSE4_1);
  // If src1 is a register, it should always be r32 (this should fall out from
  // the encodings for ByteRegs overlapping the encodings for r32), but we have
  // to make sure the register allocator didn't choose an 8-bit high register
  // like "ah".
  if (BuildDefs::asserts()) {
    if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0)) {
      if (Src0Var->hasReg()) {
        int32_t RegNum = Src0Var->getRegNum();
        int32_t BaseRegNum = InstX86Base<Machine>::Traits::getBaseReg(RegNum);
        (void)BaseRegNum;
        assert(InstX86Base<Machine>::Traits::getEncodedGPR(RegNum) ==
               InstX86Base<Machine>::Traits::getEncodedGPR(BaseRegNum));
      }
    }
  }
  static const typename InstX86Base<Machine>::Traits::Assembler::
      template ThreeOpImmEmitter<
          typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
          typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister>
          Emitter = {&InstX86Base<Machine>::Traits::Assembler::pinsr,
                     &InstX86Base<Machine>::Traits::Assembler::pinsr};
  emitIASThreeOpImmOps<
      Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
      typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister,
      InstX86Base<Machine>::Traits::getEncodedXmm,
      InstX86Base<Machine>::Traits::getEncodedGPR>(
      Func, DispatchTy, this->getDest(), Src0, this->getSrc(2), Emitter);
}

template <class Machine>
void InstX86Pshufd<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  const Variable *Dest = this->getDest();
  Type Ty = Dest->getType();
  static const typename InstX86Base<Machine>::Traits::Assembler::
      template ThreeOpImmEmitter<
          typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
          typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
          Emitter = {&InstX86Base<Machine>::Traits::Assembler::pshufd,
                     &InstX86Base<Machine>::Traits::Assembler::pshufd};
  emitIASThreeOpImmOps<
      Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
      typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
      InstX86Base<Machine>::Traits::getEncodedXmm,
      InstX86Base<Machine>::Traits::getEncodedXmm>(
      Func, Ty, Dest, this->getSrc(0), this->getSrc(1), Emitter);
}

template <class Machine>
void InstX86Shufps<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 3);
  const Variable *Dest = this->getDest();
  assert(Dest == this->getSrc(0));
  Type Ty = Dest->getType();
  static const typename InstX86Base<Machine>::Traits::Assembler::
      template ThreeOpImmEmitter<
          typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
          typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister>
          Emitter = {&InstX86Base<Machine>::Traits::Assembler::shufps,
                     &InstX86Base<Machine>::Traits::Assembler::shufps};
  emitIASThreeOpImmOps<
      Machine, typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
      typename InstX86Base<Machine>::Traits::RegisterSet::XmmRegister,
      InstX86Base<Machine>::Traits::getEncodedXmm,
      InstX86Base<Machine>::Traits::getEncodedXmm>(
      Func, Ty, Dest, this->getSrc(1), this->getSrc(2), Emitter);
}

template <class Machine> void InstX86Pop<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 0);
  Str << "\tpop\t";
  this->getDest()->emit(Func);
}

template <class Machine>
void InstX86Pop<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 0);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  if (this->getDest()->hasReg()) {
    Asm->popl(InstX86Base<Machine>::Traits::getEncodedGPR(
        this->getDest()->getRegNum()));
  } else {
    auto *Target = InstX86Base<Machine>::getTarget(Func);
    Asm->popl(Target->stackVarToAsmOperand(this->getDest()));
  }
}

template <class Machine> void InstX86Pop<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  this->dumpDest(Func);
  Str << " = pop." << this->getDest()->getType() << " ";
}

template <class Machine>
void InstX86Push<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  assert(this->getSrcSize() == 1);
  // Push is currently only used for saving GPRs.
  const auto *Var = llvm::cast<Variable>(this->getSrc(0));
  assert(Var->hasReg());
  Str << "\tpush\t";
  Var->emit(Func);
}

template <class Machine>
void InstX86Push<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 1);
  // Push is currently only used for saving GPRs.
  const auto *Var = llvm::cast<Variable>(this->getSrc(0));
  assert(Var->hasReg());
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Asm->pushl(InstX86Base<Machine>::Traits::getEncodedGPR(Var->getRegNum()));
}

template <class Machine>
void InstX86Push<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "push." << this->getSrc(0)->getType() << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Psll<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  assert(this->getDest()->getType() == IceType_v8i16 ||
         this->getDest()->getType() == IceType_v8i1 ||
         this->getDest()->getType() == IceType_v4i32 ||
         this->getDest()->getType() == IceType_v4i1);
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "psll%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .PackString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Psra<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  assert(this->getDest()->getType() == IceType_v8i16 ||
         this->getDest()->getType() == IceType_v8i1 ||
         this->getDest()->getType() == IceType_v4i32 ||
         this->getDest()->getType() == IceType_v4i1);
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "psra%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .PackString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine>
void InstX86Psrl<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  char buf[30];
  snprintf(
      buf, llvm::array_lengthof(buf), "psrl%s",
      InstX86Base<Machine>::Traits::TypeAttributes[this->getDest()->getType()]
          .PackString);
  this->emitTwoAddress(buf, this, Func);
}

template <class Machine> void InstX86Ret<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Str << "\tret";
}

template <class Machine>
void InstX86Ret<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Asm->ret();
}

template <class Machine> void InstX86Ret<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Type Ty =
      (this->getSrcSize() == 0 ? IceType_void : this->getSrc(0)->getType());
  Str << "ret." << Ty << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Setcc<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Str << "\tset"
      << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString
      << "\t";
  this->Dest->emit(Func);
}

template <class Machine>
void InstX86Setcc<Machine>::emitIAS(const Cfg *Func) const {
  assert(Condition != InstX86Base<Machine>::Traits::Cond::Br_None);
  assert(this->getDest()->getType() == IceType_i1);
  assert(this->getSrcSize() == 0);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  if (this->getDest()->hasReg())
    Asm->setcc(Condition, InstX86Base<Machine>::Traits::getEncodedByteReg(
                              this->getDest()->getRegNum()));
  else
    Asm->setcc(Condition, Target->stackVarToAsmOperand(this->getDest()));
  return;
}

template <class Machine>
void InstX86Setcc<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "setcc."
      << InstX86Base<Machine>::Traits::InstBrAttributes[Condition].DisplayString
      << " ";
  this->dumpDest(Func);
}

template <class Machine>
void InstX86Xadd<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  if (this->Locked) {
    Str << "\tlock";
  }
  Str << "\txadd" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  this->getSrc(0)->emit(Func);
}

template <class Machine>
void InstX86Xadd<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Type Ty = this->getSrc(0)->getType();
  const auto Mem =
      llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
          this->getSrc(0));
  assert(Mem->getSegmentRegister() ==
         InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  const typename InstX86Base<Machine>::Traits::Address Addr =
      Mem->toAsmAddress(Asm, Target);
  const auto *VarReg = llvm::cast<Variable>(this->getSrc(1));
  assert(VarReg->hasReg());
  const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg =
      InstX86Base<Machine>::Traits::getEncodedGPR(VarReg->getRegNum());
  Asm->xadd(Ty, Addr, Reg, this->Locked);
}

template <class Machine>
void InstX86Xadd<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  if (this->Locked) {
    Str << "lock ";
  }
  Type Ty = this->getSrc(0)->getType();
  Str << "xadd." << Ty << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86Xchg<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Str << "\txchg" << this->getWidthString(this->getSrc(0)->getType()) << "\t";
  this->getSrc(1)->emit(Func);
  Str << ", ";
  this->getSrc(0)->emit(Func);
}

template <class Machine>
void InstX86Xchg<Machine>::emitIAS(const Cfg *Func) const {
  assert(this->getSrcSize() == 2);
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Type Ty = this->getSrc(0)->getType();
  const auto *VarReg1 = llvm::cast<Variable>(this->getSrc(1));
  assert(VarReg1->hasReg());
  const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg1 =
      InstX86Base<Machine>::Traits::getEncodedGPR(VarReg1->getRegNum());

  if (const auto *VarReg0 = llvm::dyn_cast<Variable>(this->getSrc(0))) {
    assert(VarReg0->hasReg());
    const typename InstX86Base<Machine>::Traits::RegisterSet::GPRRegister Reg0 =
        InstX86Base<Machine>::Traits::getEncodedGPR(VarReg0->getRegNum());
    Asm->xchg(Ty, Reg0, Reg1);
    return;
  }

  const auto *Mem =
      llvm::cast<typename InstX86Base<Machine>::Traits::X86OperandMem>(
          this->getSrc(0));
  assert(Mem->getSegmentRegister() ==
         InstX86Base<Machine>::Traits::X86OperandMem::DefaultSegment);
  auto *Target = InstX86Base<Machine>::getTarget(Func);
  const typename InstX86Base<Machine>::Traits::Address Addr =
      Mem->toAsmAddress(Asm, Target);
  Asm->xchg(Ty, Addr, Reg1);
}

template <class Machine>
void InstX86Xchg<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Type Ty = this->getSrc(0)->getType();
  Str << "xchg." << Ty << " ";
  this->dumpSources(Func);
}

template <class Machine>
void InstX86IacaStart<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Str << "\t# IACA_START\n"
      << "\t.byte 0x0F, 0x0B\n"
      << "\tmovl\t$111, %ebx\n"
      << "\t.byte 0x64, 0x67, 0x90";
}

template <class Machine>
void InstX86IacaStart<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Asm->iaca_start();
}

template <class Machine>
void InstX86IacaStart<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "IACA_START";
}

template <class Machine>
void InstX86IacaEnd<Machine>::emit(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrEmit();
  Str << "\t# IACA_END\n"
      << "\tmovl\t$222, %ebx\n"
      << "\t.byte 0x64, 0x67, 0x90\n"
      << "\t.byte 0x0F, 0x0B";
}

template <class Machine>
void InstX86IacaEnd<Machine>::emitIAS(const Cfg *Func) const {
  typename InstX86Base<Machine>::Traits::Assembler *Asm =
      Func->getAssembler<typename InstX86Base<Machine>::Traits::Assembler>();
  Asm->iaca_end();
}

template <class Machine>
void InstX86IacaEnd<Machine>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "IACA_END";
}

} // end of namespace X86Internal

} // end of namespace Ice

#endif // SUBZERO_SRC_ICEINSTX86BASEIMPL_H
