//===- subzero/src/IceTargetLoweringX86BaseImpl.h - x86 lowering -*- 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 TargetLoweringX86Base class, which consists almost
/// entirely of the lowering sequence for each high-level instruction.
///
//===----------------------------------------------------------------------===//

#ifndef SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H
#define SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H

#include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceClFlags.h"
#include "IceDefs.h"
#include "IceELFObjectWriter.h"
#include "IceGlobalInits.h"
#include "IceInstVarIter.h"
#include "IceInstX86Base.h"
#include "IceLiveness.h"
#include "IceOperand.h"
#include "IcePhiLoweringImpl.h"
#include "IceUtils.h"
#include "IceVariableSplitting.h"

#include "llvm/Support/MathExtras.h"

#include <stack>

namespace Ice {
namespace X86 {
template <typename T> struct PoolTypeConverter {};

template <> struct PoolTypeConverter<float> {
  using PrimitiveIntType = uint32_t;
  using IceType = ConstantFloat;
  static const Type Ty = IceType_f32;
  static const char *TypeName;
  static const char *AsmTag;
  static const char *PrintfString;
};

template <> struct PoolTypeConverter<double> {
  using PrimitiveIntType = uint64_t;
  using IceType = ConstantDouble;
  static const Type Ty = IceType_f64;
  static const char *TypeName;
  static const char *AsmTag;
  static const char *PrintfString;
};

// Add converter for int type constant pooling
template <> struct PoolTypeConverter<uint32_t> {
  using PrimitiveIntType = uint32_t;
  using IceType = ConstantInteger32;
  static const Type Ty = IceType_i32;
  static const char *TypeName;
  static const char *AsmTag;
  static const char *PrintfString;
};

// Add converter for int type constant pooling
template <> struct PoolTypeConverter<uint16_t> {
  using PrimitiveIntType = uint32_t;
  using IceType = ConstantInteger32;
  static const Type Ty = IceType_i16;
  static const char *TypeName;
  static const char *AsmTag;
  static const char *PrintfString;
};

// Add converter for int type constant pooling
template <> struct PoolTypeConverter<uint8_t> {
  using PrimitiveIntType = uint32_t;
  using IceType = ConstantInteger32;
  static const Type Ty = IceType_i8;
  static const char *TypeName;
  static const char *AsmTag;
  static const char *PrintfString;
};
} // end of namespace X86

namespace X86NAMESPACE {

using Utils::BoolFlagSaver;

template <typename Traits> class BoolFoldingEntry {
  BoolFoldingEntry(const BoolFoldingEntry &) = delete;

public:
  BoolFoldingEntry() = default;
  explicit BoolFoldingEntry(Inst *I);
  BoolFoldingEntry &operator=(const BoolFoldingEntry &) = default;
  /// Instr is the instruction producing the i1-type variable of interest.
  Inst *Instr = nullptr;
  /// IsComplex is the cached result of BoolFolding::hasComplexLowering(Instr).
  bool IsComplex = false;
  /// IsLiveOut is initialized conservatively to true, and is set to false when
  /// we encounter an instruction that ends Var's live range. We disable the
  /// folding optimization when Var is live beyond this basic block. Note that
  /// if liveness analysis is not performed (e.g. in Om1 mode), IsLiveOut will
  /// always be true and the folding optimization will never be performed.
  bool IsLiveOut = true;
  // NumUses counts the number of times Var is used as a source operand in the
  // basic block. If IsComplex is true and there is more than one use of Var,
  // then the folding optimization is disabled for Var.
  uint32_t NumUses = 0;
};

template <typename Traits> class BoolFolding {
public:
  enum BoolFoldingProducerKind {
    PK_None,
    // TODO(jpp): PK_Icmp32 is no longer meaningful. Rename to PK_IcmpNative.
    PK_Icmp32,
    PK_Icmp64,
    PK_Fcmp,
    PK_Trunc,
    PK_Arith // A flag-setting arithmetic instruction.
  };

  /// Currently the actual enum values are not used (other than CK_None), but we
  /// go ahead and produce them anyway for symmetry with the
  /// BoolFoldingProducerKind.
  enum BoolFoldingConsumerKind { CK_None, CK_Br, CK_Select, CK_Sext, CK_Zext };

private:
  BoolFolding(const BoolFolding &) = delete;
  BoolFolding &operator=(const BoolFolding &) = delete;

public:
  BoolFolding() = default;
  static BoolFoldingProducerKind getProducerKind(const Inst *Instr);
  static BoolFoldingConsumerKind getConsumerKind(const Inst *Instr);
  static bool hasComplexLowering(const Inst *Instr);
  static bool isValidFolding(BoolFoldingProducerKind ProducerKind,
                             BoolFoldingConsumerKind ConsumerKind);
  void init(CfgNode *Node);
  const Inst *getProducerFor(const Operand *Opnd) const;
  void dump(const Cfg *Func) const;

private:
  /// Returns true if Producers contains a valid entry for the given VarNum.
  bool containsValid(SizeT VarNum) const {
    auto Element = Producers.find(VarNum);
    return Element != Producers.end() && Element->second.Instr != nullptr;
  }
  void setInvalid(SizeT VarNum) { Producers[VarNum].Instr = nullptr; }
  void invalidateProducersOnStore(const Inst *Instr);
  /// Producers maps Variable::Number to a BoolFoldingEntry.
  CfgUnorderedMap<SizeT, BoolFoldingEntry<Traits>> Producers;
};

template <typename Traits>
BoolFoldingEntry<Traits>::BoolFoldingEntry(Inst *I)
    : Instr(I), IsComplex(BoolFolding<Traits>::hasComplexLowering(I)) {}

template <typename Traits>
typename BoolFolding<Traits>::BoolFoldingProducerKind
BoolFolding<Traits>::getProducerKind(const Inst *Instr) {
  if (llvm::isa<InstIcmp>(Instr)) {
    if (Traits::Is64Bit || Instr->getSrc(0)->getType() != IceType_i64)
      return PK_Icmp32;
    return PK_Icmp64;
  }
  if (llvm::isa<InstFcmp>(Instr))
    return PK_Fcmp;
  if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
    if (Traits::Is64Bit || Arith->getSrc(0)->getType() != IceType_i64) {
      switch (Arith->getOp()) {
      default:
        return PK_None;
      case InstArithmetic::And:
      case InstArithmetic::Or:
        return PK_Arith;
      }
    }
  }
  return PK_None; // TODO(stichnot): remove this

  if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
    switch (Cast->getCastKind()) {
    default:
      return PK_None;
    case InstCast::Trunc:
      return PK_Trunc;
    }
  }
  return PK_None;
}

template <typename Traits>
typename BoolFolding<Traits>::BoolFoldingConsumerKind
BoolFolding<Traits>::getConsumerKind(const Inst *Instr) {
  if (llvm::isa<InstBr>(Instr))
    return CK_Br;
  if (llvm::isa<InstSelect>(Instr))
    return CK_Select;
  return CK_None; // TODO(stichnot): remove this

  if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
    switch (Cast->getCastKind()) {
    default:
      return CK_None;
    case InstCast::Sext:
      return CK_Sext;
    case InstCast::Zext:
      return CK_Zext;
    }
  }
  return CK_None;
}

/// Returns true if the producing instruction has a "complex" lowering sequence.
/// This generally means that its lowering sequence requires more than one
/// conditional branch, namely 64-bit integer compares and some floating-point
/// compares. When this is true, and there is more than one consumer, we prefer
/// to disable the folding optimization because it minimizes branches.
template <typename Traits>
bool BoolFolding<Traits>::hasComplexLowering(const Inst *Instr) {
  switch (getProducerKind(Instr)) {
  default:
    return false;
  case PK_Icmp64:
    return !Traits::Is64Bit;
  case PK_Fcmp:
    return Traits::TableFcmp[llvm::cast<InstFcmp>(Instr)->getCondition()].C2 !=
           Traits::Cond::Br_None;
  }
}

template <typename Traits>
bool BoolFolding<Traits>::isValidFolding(
    typename BoolFolding<Traits>::BoolFoldingProducerKind ProducerKind,
    typename BoolFolding<Traits>::BoolFoldingConsumerKind ConsumerKind) {
  switch (ProducerKind) {
  default:
    return false;
  case PK_Icmp32:
  case PK_Icmp64:
  case PK_Fcmp:
    return (ConsumerKind == CK_Br) || (ConsumerKind == CK_Select);
  case PK_Arith:
    return ConsumerKind == CK_Br;
  }
}

template <typename Traits> void BoolFolding<Traits>::init(CfgNode *Node) {
  Producers.clear();
  for (Inst &Instr : Node->getInsts()) {
    if (Instr.isDeleted())
      continue;
    invalidateProducersOnStore(&Instr);
    // Check whether Instr is a valid producer.
    Variable *Var = Instr.getDest();
    if (Var) { // only consider instructions with an actual dest var
      if (isBooleanType(Var->getType())) {        // only bool-type dest vars
        if (getProducerKind(&Instr) != PK_None) { // white-listed instructions
          Producers[Var->getIndex()] = BoolFoldingEntry<Traits>(&Instr);
        }
      }
    }
    // Check each src variable against the map.
    FOREACH_VAR_IN_INST(Var, Instr) {
      SizeT VarNum = Var->getIndex();
      if (!containsValid(VarNum))
        continue;
      // All valid consumers use Var as the first source operand
      if (IndexOfVarOperandInInst(Var) != 0) {
        setInvalid(VarNum);
        continue;
      }
      // Consumer instructions must be white-listed
      typename BoolFolding<Traits>::BoolFoldingConsumerKind ConsumerKind =
          getConsumerKind(&Instr);
      if (ConsumerKind == CK_None) {
        setInvalid(VarNum);
        continue;
      }
      typename BoolFolding<Traits>::BoolFoldingProducerKind ProducerKind =
          getProducerKind(Producers[VarNum].Instr);
      if (!isValidFolding(ProducerKind, ConsumerKind)) {
        setInvalid(VarNum);
        continue;
      }
      // Avoid creating multiple copies of complex producer instructions.
      if (Producers[VarNum].IsComplex && Producers[VarNum].NumUses > 0) {
        setInvalid(VarNum);
        continue;
      }
      ++Producers[VarNum].NumUses;
      if (Instr.isLastUse(Var)) {
        Producers[VarNum].IsLiveOut = false;
      }
    }
  }
  for (auto &I : Producers) {
    // Ignore entries previously marked invalid.
    if (I.second.Instr == nullptr)
      continue;
    // Disable the producer if its dest may be live beyond this block.
    if (I.second.IsLiveOut) {
      setInvalid(I.first);
      continue;
    }
    // Mark as "dead" rather than outright deleting. This is so that other
    // peephole style optimizations during or before lowering have access to
    // this instruction in undeleted form. See for example
    // tryOptimizedCmpxchgCmpBr().
    I.second.Instr->setDead();
  }
}

template <typename Traits>
const Inst *BoolFolding<Traits>::getProducerFor(const Operand *Opnd) const {
  auto *Var = llvm::dyn_cast<const Variable>(Opnd);
  if (Var == nullptr)
    return nullptr;
  SizeT VarNum = Var->getIndex();
  auto Element = Producers.find(VarNum);
  if (Element == Producers.end())
    return nullptr;
  return Element->second.Instr;
}

template <typename Traits>
void BoolFolding<Traits>::dump(const Cfg *Func) const {
  if (!BuildDefs::dump() || !Func->isVerbose(IceV_Folding))
    return;
  OstreamLocker L(Func->getContext());
  Ostream &Str = Func->getContext()->getStrDump();
  for (auto &I : Producers) {
    if (I.second.Instr == nullptr)
      continue;
    Str << "Found foldable producer:\n  ";
    I.second.Instr->dump(Func);
    Str << "\n";
  }
}

/// If the given instruction has potential memory side effects (e.g. store, rmw,
/// or a call instruction with potential memory side effects), then we must not
/// allow a pre-store Producer instruction with memory operands to be folded
/// into a post-store Consumer instruction.  If this is detected, the Producer
/// is invalidated.
///
/// We use the Producer's IsLiveOut field to determine whether any potential
/// Consumers come after this store instruction.  The IsLiveOut field is
/// initialized to true, and BoolFolding::init() sets IsLiveOut to false when it
/// sees the variable's definitive last use (indicating the variable is not in
/// the node's live-out set).  Thus if we see here that IsLiveOut is false, we
/// know that there can be no consumers after the store, and therefore we know
/// the folding is safe despite the store instruction.
template <typename Traits>
void BoolFolding<Traits>::invalidateProducersOnStore(const Inst *Instr) {
  if (!Instr->isMemoryWrite())
    return;
  for (auto &ProducerPair : Producers) {
    if (!ProducerPair.second.IsLiveOut)
      continue;
    Inst *PInst = ProducerPair.second.Instr;
    if (PInst == nullptr)
      continue;
    bool HasMemOperand = false;
    const SizeT SrcSize = PInst->getSrcSize();
    for (SizeT I = 0; I < SrcSize; ++I) {
      if (llvm::isa<typename Traits::X86OperandMem>(PInst->getSrc(I))) {
        HasMemOperand = true;
        break;
      }
    }
    if (!HasMemOperand)
      continue;
    setInvalid(ProducerPair.first);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::initNodeForLowering(CfgNode *Node) {
  FoldingInfo.init(Node);
  FoldingInfo.dump(Func);
}

template <typename TraitsType>
TargetX86Base<TraitsType>::TargetX86Base(Cfg *Func)
    : TargetLowering(Func), NeedSandboxing(SandboxingType == ST_NaCl) {
  static_assert(
      (Traits::InstructionSet::End - Traits::InstructionSet::Begin) ==
          (TargetInstructionSet::X86InstructionSet_End -
           TargetInstructionSet::X86InstructionSet_Begin),
      "Traits::InstructionSet range different from TargetInstructionSet");
  if (getFlags().getTargetInstructionSet() !=
      TargetInstructionSet::BaseInstructionSet) {
    InstructionSet = static_cast<InstructionSetEnum>(
        (getFlags().getTargetInstructionSet() -
         TargetInstructionSet::X86InstructionSet_Begin) +
        Traits::InstructionSet::Begin);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) {
  RegNumT::setLimit(Traits::RegisterSet::Reg_NUM);
  Traits::initRegisterSet(getFlags(), &TypeToRegisterSet, &RegisterAliases);
  for (size_t i = 0; i < TypeToRegisterSet.size(); ++i)
    TypeToRegisterSetUnfiltered[i] = TypeToRegisterSet[i];
  filterTypeToRegisterSet(Ctx, Traits::RegisterSet::Reg_NUM,
                          TypeToRegisterSet.data(), TypeToRegisterSet.size(),
                          Traits::getRegName, getRegClassName);
  PcRelFixup = Traits::FK_PcRel;
  AbsFixup = getFlags().getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs;
}

template <typename TraitsType>
bool TargetX86Base<TraitsType>::shouldBePooled(const Constant *C) {
  if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(C)) {
    return !Utils::isPositiveZero(ConstFloat->getValue());
  }
  if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(C)) {
    return !Utils::isPositiveZero(ConstDouble->getValue());
  }
  if (getFlags().getRandomizeAndPoolImmediatesOption() != RPI_Pool) {
    return false;
  }
  return C->shouldBeRandomizedOrPooled();
}

template <typename TraitsType>
::Ice::Type TargetX86Base<TraitsType>::getPointerType() {
  if (!Traits::Is64Bit ||
      ::Ice::getFlags().getApplicationBinaryInterface() == ::Ice::ABI_PNaCl) {
    return ::Ice::IceType_i32;
  }
  return ::Ice::IceType_i64;
}

template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() {
  TimerMarker T(TimerStack::TT_O2, Func);

  if (SandboxingType != ST_None) {
    initRebasePtr();
  }

  genTargetHelperCalls();
  Func->dump("After target helper call insertion");

  // Merge Alloca instructions, and lay out the stack.
  static constexpr bool SortAndCombineAllocas = true;
  Func->processAllocas(SortAndCombineAllocas);
  Func->dump("After Alloca processing");

  // Run this early so it can be used to focus optimizations on potentially hot
  // code.
  // TODO(stichnot,ascull): currently only used for regalloc not
  // expensive high level optimizations which could be focused on potentially
  // hot code.
  Func->generateLoopInfo();
  Func->dump("After loop analysis");
  if (getFlags().getLoopInvariantCodeMotion()) {
    Func->loopInvariantCodeMotion();
    Func->dump("After LICM");
  }

  if (getFlags().getLocalCSE() != Ice::LCSE_Disabled) {
    Func->localCSE(getFlags().getLocalCSE() == Ice::LCSE_EnabledSSA);
    Func->dump("After Local CSE");
    Func->floatConstantCSE();
  }
  if (getFlags().getEnableShortCircuit()) {
    Func->shortCircuitJumps();
    Func->dump("After Short Circuiting");
  }

  if (!getFlags().getEnablePhiEdgeSplit()) {
    // Lower Phi instructions.
    Func->placePhiLoads();
    if (Func->hasError())
      return;
    Func->placePhiStores();
    if (Func->hasError())
      return;
    Func->deletePhis();
    if (Func->hasError())
      return;
    Func->dump("After Phi lowering");
  }

  // Address mode optimization.
  Func->getVMetadata()->init(VMK_SingleDefs);
  Func->doAddressOpt();
  Func->materializeVectorShuffles();

  // Find read-modify-write opportunities. Do this after address mode
  // optimization so that doAddressOpt() doesn't need to be applied to RMW
  // instructions as well.
  findRMW();
  Func->dump("After RMW transform");

  // Argument lowering
  Func->doArgLowering();

  // Target lowering. This requires liveness analysis for some parts of the
  // lowering decisions, such as compare/branch fusing. If non-lightweight
  // liveness analysis is used, the instructions need to be renumbered first
  // TODO: This renumbering should only be necessary if we're actually
  // calculating live intervals, which we only do for register allocation.
  Func->renumberInstructions();
  if (Func->hasError())
    return;

  // TODO: It should be sufficient to use the fastest liveness calculation,
  // i.e. livenessLightweight(). However, for some reason that slows down the
  // rest of the translation. Investigate.
  Func->liveness(Liveness_Basic);
  if (Func->hasError())
    return;
  Func->dump("After x86 address mode opt");

  // Disable constant blinding or pooling for load optimization.
  {
    BoolFlagSaver B(RandomizationPoolingPaused, true);
    doLoadOpt();
  }
  Func->genCode();
  if (Func->hasError())
    return;
  if (SandboxingType != ST_None) {
    initSandbox();
  }
  Func->dump("After x86 codegen");
  splitBlockLocalVariables(Func);

  // Register allocation. This requires instruction renumbering and full
  // liveness analysis. Loops must be identified before liveness so variable
  // use weights are correct.
  Func->renumberInstructions();
  if (Func->hasError())
    return;
  Func->liveness(Liveness_Intervals);
  if (Func->hasError())
    return;
  // The post-codegen dump is done here, after liveness analysis and associated
  // cleanup, to make the dump cleaner and more useful.
  Func->dump("After initial x86 codegen");
  // Validate the live range computations. The expensive validation call is
  // deliberately only made when assertions are enabled.
  assert(Func->validateLiveness());
  Func->getVMetadata()->init(VMK_All);
  regAlloc(RAK_Global);
  if (Func->hasError())
    return;
  Func->dump("After linear scan regalloc");

  if (getFlags().getEnablePhiEdgeSplit()) {
    Func->advancedPhiLowering();
    Func->dump("After advanced Phi lowering");
  }

  // Stack frame mapping.
  Func->genFrame();
  if (Func->hasError())
    return;
  Func->dump("After stack frame mapping");

  Func->contractEmptyNodes();
  Func->reorderNodes();

  // Shuffle basic block order if -reorder-basic-blocks is enabled.
  Func->shuffleNodes();

  // Branch optimization.  This needs to be done just before code emission. In
  // particular, no transformations that insert or reorder CfgNodes should be
  // done after branch optimization. We go ahead and do it before nop insertion
  // to reduce the amount of work needed for searching for opportunities.
  Func->doBranchOpt();
  Func->dump("After branch optimization");

  // Nop insertion if -nop-insertion is enabled.
  Func->doNopInsertion();

  // Mark nodes that require sandbox alignment
  if (NeedSandboxing) {
    Func->markNodesForSandboxing();
  }
}

template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() {
  TimerMarker T(TimerStack::TT_Om1, Func);

  if (SandboxingType != ST_None) {
    initRebasePtr();
  }

  genTargetHelperCalls();

  // Do not merge Alloca instructions, and lay out the stack.
  static constexpr bool SortAndCombineAllocas = false;
  Func->processAllocas(SortAndCombineAllocas);
  Func->dump("After Alloca processing");

  Func->placePhiLoads();
  if (Func->hasError())
    return;
  Func->placePhiStores();
  if (Func->hasError())
    return;
  Func->deletePhis();
  if (Func->hasError())
    return;
  Func->dump("After Phi lowering");

  Func->doArgLowering();
  Func->genCode();
  if (Func->hasError())
    return;
  if (SandboxingType != ST_None) {
    initSandbox();
  }
  Func->dump("After initial x86 codegen");

  regAlloc(RAK_InfOnly);
  if (Func->hasError())
    return;
  Func->dump("After regalloc of infinite-weight variables");

  Func->genFrame();
  if (Func->hasError())
    return;
  Func->dump("After stack frame mapping");

  // Shuffle basic block order if -reorder-basic-blocks is enabled.
  Func->shuffleNodes();

  // Nop insertion if -nop-insertion is enabled.
  Func->doNopInsertion();

  // Mark nodes that require sandbox alignment
  if (NeedSandboxing)
    Func->markNodesForSandboxing();
}

inline bool canRMW(const InstArithmetic *Arith) {
  Type Ty = Arith->getDest()->getType();
  // X86 vector instructions write to a register and have no RMW option.
  if (isVectorType(Ty))
    return false;
  bool isI64 = Ty == IceType_i64;

  switch (Arith->getOp()) {
  // Not handled for lack of simple lowering:
  //   shift on i64
  //   mul, udiv, urem, sdiv, srem, frem
  // Not handled for lack of RMW instructions:
  //   fadd, fsub, fmul, fdiv (also vector types)
  default:
    return false;
  case InstArithmetic::Add:
  case InstArithmetic::Sub:
  case InstArithmetic::And:
  case InstArithmetic::Or:
  case InstArithmetic::Xor:
    return true;
  case InstArithmetic::Shl:
  case InstArithmetic::Lshr:
  case InstArithmetic::Ashr:
    return false; // TODO(stichnot): implement
    return !isI64;
  }
}

template <typename TraitsType>
bool isSameMemAddressOperand(const Operand *A, const Operand *B) {
  if (A == B)
    return true;
  if (auto *MemA =
          llvm::dyn_cast<typename TargetX86Base<TraitsType>::X86OperandMem>(
              A)) {
    if (auto *MemB =
            llvm::dyn_cast<typename TargetX86Base<TraitsType>::X86OperandMem>(
                B)) {
      return MemA->getBase() == MemB->getBase() &&
             MemA->getOffset() == MemB->getOffset() &&
             MemA->getIndex() == MemB->getIndex() &&
             MemA->getShift() == MemB->getShift() &&
             MemA->getSegmentRegister() == MemB->getSegmentRegister();
    }
  }
  return false;
}

template <typename TraitsType> void TargetX86Base<TraitsType>::findRMW() {
  TimerMarker _(TimerStack::TT_findRMW, Func);
  Func->dump("Before RMW");
  if (Func->isVerbose(IceV_RMW))
    Func->getContext()->lockStr();
  for (CfgNode *Node : Func->getNodes()) {
    // Walk through the instructions, considering each sequence of 3
    // instructions, and look for the particular RMW pattern. Note that this
    // search can be "broken" (false negatives) if there are intervening
    // deleted instructions, or intervening instructions that could be safely
    // moved out of the way to reveal an RMW pattern.
    auto E = Node->getInsts().end();
    auto I1 = E, I2 = E, I3 = Node->getInsts().begin();
    for (; I3 != E; I1 = I2, I2 = I3, ++I3) {
      // Make I3 skip over deleted instructions.
      while (I3 != E && I3->isDeleted())
        ++I3;
      if (I1 == E || I2 == E || I3 == E)
        continue;
      assert(!I1->isDeleted());
      assert(!I2->isDeleted());
      assert(!I3->isDeleted());
      auto *Load = llvm::dyn_cast<InstLoad>(I1);
      auto *Arith = llvm::dyn_cast<InstArithmetic>(I2);
      auto *Store = llvm::dyn_cast<InstStore>(I3);
      if (!Load || !Arith || !Store)
        continue;
      // Look for:
      //   a = Load addr
      //   b = <op> a, other
      //   Store b, addr
      // Change to:
      //   a = Load addr
      //   b = <op> a, other
      //   x = FakeDef
      //   RMW <op>, addr, other, x
      //   b = Store b, addr, x
      // Note that inferTwoAddress() makes sure setDestRedefined() gets called
      // on the updated Store instruction, to avoid liveness problems later.
      //
      // With this transformation, the Store instruction acquires a Dest
      // variable and is now subject to dead code elimination if there are no
      // more uses of "b".  Variable "x" is a beacon for determining whether the
      // Store instruction gets dead-code eliminated.  If the Store instruction
      // is eliminated, then it must be the case that the RMW instruction ends
      // x's live range, and therefore the RMW instruction will be retained and
      // later lowered.  On the other hand, if the RMW instruction does not end
      // x's live range, then the Store instruction must still be present, and
      // therefore the RMW instruction is ignored during lowering because it is
      // redundant with the Store instruction.
      //
      // Note that if "a" has further uses, the RMW transformation may still
      // trigger, resulting in two loads and one store, which is worse than the
      // original one load and one store.  However, this is probably rare, and
      // caching probably keeps it just as fast.
      if (!isSameMemAddressOperand<TraitsType>(Load->getSourceAddress(),
                                               Store->getAddr()))
        continue;
      Operand *ArithSrcFromLoad = Arith->getSrc(0);
      Operand *ArithSrcOther = Arith->getSrc(1);
      if (ArithSrcFromLoad != Load->getDest()) {
        if (!Arith->isCommutative() || ArithSrcOther != Load->getDest())
          continue;
        std::swap(ArithSrcFromLoad, ArithSrcOther);
      }
      if (Arith->getDest() != Store->getData())
        continue;
      if (!canRMW(Arith))
        continue;
      if (Func->isVerbose(IceV_RMW)) {
        Ostream &Str = Func->getContext()->getStrDump();
        Str << "Found RMW in " << Func->getFunctionName() << ":\n  ";
        Load->dump(Func);
        Str << "\n  ";
        Arith->dump(Func);
        Str << "\n  ";
        Store->dump(Func);
        Str << "\n";
      }
      Variable *Beacon = Func->makeVariable(IceType_i32);
      Beacon->setMustNotHaveReg();
      Store->setRmwBeacon(Beacon);
      auto *BeaconDef = InstFakeDef::create(Func, Beacon);
      Node->getInsts().insert(I3, BeaconDef);
      auto *RMW = InstX86FakeRMW::create(Func, ArithSrcOther, Store->getAddr(),
                                         Beacon, Arith->getOp());
      Node->getInsts().insert(I3, RMW);
    }
  }
  if (Func->isVerbose(IceV_RMW))
    Func->getContext()->unlockStr();
}

// Converts a ConstantInteger32 operand into its constant value, or
// MemoryOrderInvalid if the operand is not a ConstantInteger32.
inline uint64_t getConstantMemoryOrder(Operand *Opnd) {
  if (auto *Integer = llvm::dyn_cast<ConstantInteger32>(Opnd))
    return Integer->getValue();
  return Intrinsics::MemoryOrderInvalid;
}

/// Determines whether the dest of a Load instruction can be folded into one of
/// the src operands of a 2-operand instruction. This is true as long as the
/// load dest matches exactly one of the binary instruction's src operands.
/// Replaces Src0 or Src1 with LoadSrc if the answer is true.
inline bool canFoldLoadIntoBinaryInst(Operand *LoadSrc, Variable *LoadDest,
                                      Operand *&Src0, Operand *&Src1) {
  if (Src0 == LoadDest && Src1 != LoadDest) {
    Src0 = LoadSrc;
    return true;
  }
  if (Src0 != LoadDest && Src1 == LoadDest) {
    Src1 = LoadSrc;
    return true;
  }
  return false;
}

template <typename TraitsType> void TargetX86Base<TraitsType>::doLoadOpt() {
  TimerMarker _(TimerStack::TT_loadOpt, Func);
  for (CfgNode *Node : Func->getNodes()) {
    Context.init(Node);
    while (!Context.atEnd()) {
      Variable *LoadDest = nullptr;
      Operand *LoadSrc = nullptr;
      Inst *CurInst = iteratorToInst(Context.getCur());
      Inst *Next = Context.getNextInst();
      // Determine whether the current instruction is a Load instruction or
      // equivalent.
      if (auto *Load = llvm::dyn_cast<InstLoad>(CurInst)) {
        // An InstLoad always qualifies.
        LoadDest = Load->getDest();
        constexpr bool DoLegalize = false;
        LoadSrc = formMemoryOperand(Load->getSourceAddress(),
                                    LoadDest->getType(), DoLegalize);
      } else if (auto *Intrin = llvm::dyn_cast<InstIntrinsicCall>(CurInst)) {
        // An AtomicLoad intrinsic qualifies as long as it has a valid memory
        // ordering, and can be implemented in a single instruction (i.e., not
        // i64 on x86-32).
        Intrinsics::IntrinsicID ID = Intrin->getIntrinsicInfo().ID;
        if (ID == Intrinsics::AtomicLoad &&
            (Traits::Is64Bit || Intrin->getDest()->getType() != IceType_i64) &&
            Intrinsics::isMemoryOrderValid(
                ID, getConstantMemoryOrder(Intrin->getArg(1)))) {
          LoadDest = Intrin->getDest();
          constexpr bool DoLegalize = false;
          LoadSrc = formMemoryOperand(Intrin->getArg(0), LoadDest->getType(),
                                      DoLegalize);
        }
      }
      // A Load instruction can be folded into the following instruction only
      // if the following instruction ends the Load's Dest variable's live
      // range.
      if (LoadDest && Next && Next->isLastUse(LoadDest)) {
        assert(LoadSrc);
        Inst *NewInst = nullptr;
        if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Next)) {
          Operand *Src0 = Arith->getSrc(0);
          Operand *Src1 = Arith->getSrc(1);
          if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
            NewInst = InstArithmetic::create(Func, Arith->getOp(),
                                             Arith->getDest(), Src0, Src1);
          }
        } else if (auto *Icmp = llvm::dyn_cast<InstIcmp>(Next)) {
          Operand *Src0 = Icmp->getSrc(0);
          Operand *Src1 = Icmp->getSrc(1);
          if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
            NewInst = InstIcmp::create(Func, Icmp->getCondition(),
                                       Icmp->getDest(), Src0, Src1);
          }
        } else if (auto *Fcmp = llvm::dyn_cast<InstFcmp>(Next)) {
          Operand *Src0 = Fcmp->getSrc(0);
          Operand *Src1 = Fcmp->getSrc(1);
          if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
            NewInst = InstFcmp::create(Func, Fcmp->getCondition(),
                                       Fcmp->getDest(), Src0, Src1);
          }
        } else if (auto *Select = llvm::dyn_cast<InstSelect>(Next)) {
          Operand *Src0 = Select->getTrueOperand();
          Operand *Src1 = Select->getFalseOperand();
          if (canFoldLoadIntoBinaryInst(LoadSrc, LoadDest, Src0, Src1)) {
            NewInst = InstSelect::create(Func, Select->getDest(),
                                         Select->getCondition(), Src0, Src1);
          }
        } else if (auto *Cast = llvm::dyn_cast<InstCast>(Next)) {
          // The load dest can always be folded into a Cast instruction.
          auto *Src0 = llvm::dyn_cast<Variable>(Cast->getSrc(0));
          if (Src0 == LoadDest) {
            NewInst = InstCast::create(Func, Cast->getCastKind(),
                                       Cast->getDest(), LoadSrc);
          }
        }
        if (NewInst) {
          CurInst->setDeleted();
          Next->setDeleted();
          Context.insert(NewInst);
          // Update NewInst->LiveRangesEnded so that target lowering may
          // benefit. Also update NewInst->HasSideEffects.
          NewInst->spliceLivenessInfo(Next, CurInst);
        }
      }
      Context.advanceCur();
      Context.advanceNext();
    }
  }
  Func->dump("After load optimization");
}

template <typename TraitsType>
bool TargetX86Base<TraitsType>::doBranchOpt(Inst *I, const CfgNode *NextNode) {
  if (auto *Br = llvm::dyn_cast<InstX86Br>(I)) {
    return Br->optimizeBranch(NextNode);
  }
  return false;
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::getPhysicalRegister(RegNumT RegNum,
                                                         Type Ty) {
  if (Ty == IceType_void)
    Ty = IceType_i32;
  if (PhysicalRegisters[Ty].empty())
    PhysicalRegisters[Ty].resize(Traits::RegisterSet::Reg_NUM);
  assert(unsigned(RegNum) < PhysicalRegisters[Ty].size());
  Variable *Reg = PhysicalRegisters[Ty][RegNum];
  if (Reg == nullptr) {
    Reg = Func->makeVariable(Ty);
    Reg->setRegNum(RegNum);
    PhysicalRegisters[Ty][RegNum] = Reg;
    // Specially mark a named physical register as an "argument" so that it is
    // considered live upon function entry.  Otherwise it's possible to get
    // liveness validation errors for saving callee-save registers.
    Func->addImplicitArg(Reg);
    // Don't bother tracking the live range of a named physical register.
    Reg->setIgnoreLiveness();
  }
  assert(Traits::getGprForType(Ty, RegNum) == RegNum);
  return Reg;
}

template <typename TraitsType>
const char *TargetX86Base<TraitsType>::getRegName(RegNumT RegNum,
                                                  Type Ty) const {
  return Traits::getRegName(Traits::getGprForType(Ty, RegNum));
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::emitVariable(const Variable *Var) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Ctx->getStrEmit();
  if (Var->hasReg()) {
    const bool Is64BitSandboxing = Traits::Is64Bit && NeedSandboxing;
    const Type VarType = (Var->isRematerializable() && Is64BitSandboxing)
                             ? IceType_i64
                             : Var->getType();
    Str << "%" << getRegName(Var->getRegNum(), VarType);
    return;
  }
  if (Var->mustHaveReg()) {
    llvm::report_fatal_error("Infinite-weight Variable (" + Var->getName() +
                             ") has no register assigned - function " +
                             Func->getFunctionName());
  }
  const int32_t Offset = Var->getStackOffset();
  auto BaseRegNum = Var->getBaseRegNum();
  if (BaseRegNum.hasNoValue())
    BaseRegNum = getFrameOrStackReg();

  // Print in the form "Offset(%reg)", omitting Offset when it is 0.
  if (getFlags().getDecorateAsm()) {
    Str << Var->getSymbolicStackOffset();
  } else if (Offset != 0) {
    Str << Offset;
  }
  const Type FrameSPTy = Traits::WordType;
  Str << "(%" << getRegName(BaseRegNum, FrameSPTy) << ")";
}

template <typename TraitsType>
typename TargetX86Base<TraitsType>::X86Address
TargetX86Base<TraitsType>::stackVarToAsmOperand(const Variable *Var) const {
  if (Var->hasReg())
    llvm::report_fatal_error("Stack Variable has a register assigned");
  if (Var->mustHaveReg()) {
    llvm::report_fatal_error("Infinite-weight Variable (" + Var->getName() +
                             ") has no register assigned - function " +
                             Func->getFunctionName());
  }
  int32_t Offset = Var->getStackOffset();
  auto BaseRegNum = Var->getBaseRegNum();
  if (Var->getBaseRegNum().hasNoValue())
    BaseRegNum = getFrameOrStackReg();
  return X86Address(Traits::getEncodedGPR(BaseRegNum), Offset,
                    AssemblerFixup::NoFixup);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::addProlog(CfgNode *Node) {
  // Stack frame layout:
  //
  // +------------------------+
  // | 1. return address      |
  // +------------------------+
  // | 2. preserved registers |
  // +------------------------+ <--- BasePointer (if used)
  // | 3. padding             |
  // +------------------------+
  // | 4. global spill area   |
  // +------------------------+
  // | 5. padding             |
  // +------------------------+
  // | 6. local spill area    |
  // +------------------------+
  // | 7. padding             |
  // +------------------------+
  // | 8. allocas             |
  // +------------------------+
  // | 9. padding             |
  // +------------------------+
  // | 10. out args           |
  // +------------------------+ <--- StackPointer
  //
  // The following variables record the size in bytes of the given areas:
  //  * X86_RET_IP_SIZE_BYTES:   area 1
  //  * PreservedRegsSizeBytes:  area 2
  //  * SpillAreaPaddingBytes:   area 3
  //  * GlobalsSize:             area 4
  //  * LocalsSlotsPaddingBytes: area 5
  //  * GlobalsAndSubsequentPaddingSize: areas 4 - 5
  //  * LocalsSpillAreaSize:     area 6
  //  * FixedAllocaSizeBytes:    areas 7 - 8
  //  * SpillAreaSizeBytes:      areas 3 - 10
  //  * maxOutArgsSizeBytes():   areas 9 - 10

  // Determine stack frame offsets for each Variable without a register
  // assignment. This can be done as one variable per stack slot. Or, do
  // coalescing by running the register allocator again with an infinite set of
  // registers (as a side effect, this gives variables a second chance at
  // physical register assignment).
  //
  // A middle ground approach is to leverage sparsity and allocate one block of
  // space on the frame for globals (variables with multi-block lifetime), and
  // one block to share for locals (single-block lifetime).

  Context.init(Node);
  Context.setInsertPoint(Context.getCur());

  SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
  RegsUsed = SmallBitVector(CalleeSaves.size());
  VarList SortedSpilledVariables, VariablesLinkedToSpillSlots;
  size_t GlobalsSize = 0;
  // If there is a separate locals area, this represents that area. Otherwise
  // it counts any variable not counted by GlobalsSize.
  SpillAreaSizeBytes = 0;
  // If there is a separate locals area, this specifies the alignment for it.
  uint32_t LocalsSlotsAlignmentBytes = 0;
  // The entire spill locations area gets aligned to largest natural alignment
  // of the variables that have a spill slot.
  uint32_t SpillAreaAlignmentBytes = 0;
  // A spill slot linked to a variable with a stack slot should reuse that
  // stack slot.
  std::function<bool(Variable *)> TargetVarHook =
      [&VariablesLinkedToSpillSlots](Variable *Var) {
        // TODO(stichnot): Refactor this into the base class.
        Variable *Root = Var->getLinkedToStackRoot();
        if (Root != nullptr) {
          assert(!Root->hasReg());
          if (!Root->hasReg()) {
            VariablesLinkedToSpillSlots.push_back(Var);
            return true;
          }
        }
        return false;
      };

  // Compute the list of spilled variables and bounds for GlobalsSize, etc.
  getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
                        &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
                        &LocalsSlotsAlignmentBytes, TargetVarHook);
  uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
  SpillAreaSizeBytes += GlobalsSize;

  // Add push instructions for preserved registers.
  uint32_t NumCallee = 0;
  size_t PreservedRegsSizeBytes = 0;
  SmallBitVector Pushed(CalleeSaves.size());
  for (RegNumT i : RegNumBVIter(CalleeSaves)) {
    const auto Canonical = Traits::getBaseReg(i);
    assert(Canonical == Traits::getBaseReg(Canonical));
    if (RegsUsed[i]) {
      Pushed[Canonical] = true;
    }
  }
  for (RegNumT RegNum : RegNumBVIter(Pushed)) {
    assert(RegNum == Traits::getBaseReg(RegNum));
    ++NumCallee;
    PreservedRegsSizeBytes += typeWidthInBytes(Traits::WordType);
    _push_reg(getPhysicalRegister(RegNum, Traits::WordType));
  }
  Ctx->statsUpdateRegistersSaved(NumCallee);

  // Generate "push frameptr; mov frameptr, stackptr"
  if (IsEbpBasedFrame) {
    assert((RegsUsed & getRegisterSet(RegSet_FramePointer, RegSet_None))
               .count() == 0);
    PreservedRegsSizeBytes += typeWidthInBytes(Traits::WordType);
    _link_bp();
  }

  // Align the variables area. SpillAreaPaddingBytes is the size of the region
  // after the preserved registers and before the spill areas.
  // LocalsSlotsPaddingBytes is the amount of padding between the globals and
  // locals area if they are separate.
  assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
  uint32_t SpillAreaPaddingBytes = 0;
  uint32_t LocalsSlotsPaddingBytes = 0;
  alignStackSpillAreas(Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes,
                       SpillAreaAlignmentBytes, GlobalsSize,
                       LocalsSlotsAlignmentBytes, &SpillAreaPaddingBytes,
                       &LocalsSlotsPaddingBytes);
  SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
  uint32_t GlobalsAndSubsequentPaddingSize =
      GlobalsSize + LocalsSlotsPaddingBytes;

  // Functions returning scalar floating point types may need to convert values
  // from an in-register xmm value to the top of the x87 floating point stack.
  // This is done by a movp[sd] and an fld[sd].  Ensure there is enough scratch
  // space on the stack for this.
  const Type ReturnType = Func->getReturnType();
  if (!Traits::X86_PASS_SCALAR_FP_IN_XMM) {
    if (isScalarFloatingType(ReturnType)) {
      // Avoid misaligned double-precision load/store.
      RequiredStackAlignment = std::max<size_t>(
          RequiredStackAlignment, Traits::X86_STACK_ALIGNMENT_BYTES);
      SpillAreaSizeBytes =
          std::max(typeWidthInBytesOnStack(ReturnType), SpillAreaSizeBytes);
    }
  }

  RequiredStackAlignment =
      std::max<size_t>(RequiredStackAlignment, SpillAreaAlignmentBytes);

  if (PrologEmitsFixedAllocas) {
    RequiredStackAlignment =
        std::max(RequiredStackAlignment, FixedAllocaAlignBytes);
  }

  // Combine fixed allocations into SpillAreaSizeBytes if we are emitting the
  // fixed allocations in the prolog.
  if (PrologEmitsFixedAllocas)
    SpillAreaSizeBytes += FixedAllocaSizeBytes;

  // Entering the function has made the stack pointer unaligned. Re-align it by
  // adjusting the stack size.
  uint32_t StackOffset = Traits::X86_RET_IP_SIZE_BYTES + PreservedRegsSizeBytes;
  uint32_t StackSize = Utils::applyAlignment(StackOffset + SpillAreaSizeBytes,
                                             RequiredStackAlignment);
  StackSize = Utils::applyAlignment(StackSize + maxOutArgsSizeBytes(),
                                    RequiredStackAlignment);
  SpillAreaSizeBytes = StackSize - StackOffset;

  if (SpillAreaSizeBytes) {
    // Generate "sub stackptr, SpillAreaSizeBytes"
    _sub_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
  }

  // If the required alignment is greater than the stack pointer's guaranteed
  // alignment, align the stack pointer accordingly.
  if (RequiredStackAlignment > Traits::X86_STACK_ALIGNMENT_BYTES) {
    assert(IsEbpBasedFrame);
    _and(getPhysicalRegister(getStackReg(), Traits::WordType),
         Ctx->getConstantInt32(-RequiredStackAlignment));
  }

  // Account for known-frame-offset alloca instructions that were not already
  // combined into the prolog.
  if (!PrologEmitsFixedAllocas)
    SpillAreaSizeBytes += FixedAllocaSizeBytes;

  Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes);

  // Fill in stack offsets for stack args, and copy args into registers for
  // those that were register-allocated. Args are pushed right to left, so
  // Arg[0] is closest to the stack/frame pointer.
  RegNumT FrameOrStackReg = IsEbpBasedFrame ? getFrameReg() : getStackReg();
  Variable *FramePtr = getPhysicalRegister(FrameOrStackReg, Traits::WordType);
  size_t BasicFrameOffset =
      PreservedRegsSizeBytes + Traits::X86_RET_IP_SIZE_BYTES;
  if (!IsEbpBasedFrame)
    BasicFrameOffset += SpillAreaSizeBytes;

  emitGetIP(Node);

  const VarList &Args = Func->getArgs();
  size_t InArgsSizeBytes = 0;
  unsigned NumXmmArgs = 0;
  unsigned NumGPRArgs = 0;
  for (Variable *Arg : Args) {
    // Skip arguments passed in registers.
    if (isVectorType(Arg->getType())) {
      if (Traits::getRegisterForXmmArgNum(NumXmmArgs).hasValue()) {
        ++NumXmmArgs;
        continue;
      }
    } else if (isScalarFloatingType(Arg->getType())) {
      if (Traits::X86_PASS_SCALAR_FP_IN_XMM &&
          Traits::getRegisterForXmmArgNum(NumXmmArgs).hasValue()) {
        ++NumXmmArgs;
        continue;
      }
    } else {
      assert(isScalarIntegerType(Arg->getType()));
      if (Traits::getRegisterForGprArgNum(Traits::WordType, NumGPRArgs)
              .hasValue()) {
        ++NumGPRArgs;
        continue;
      }
    }
    // For esp-based frames where the allocas are done outside the prolog, the
    // esp value may not stabilize to its home value until after all the
    // fixed-size alloca instructions have executed.  In this case, a stack
    // adjustment is needed when accessing in-args in order to copy them into
    // registers.
    size_t StackAdjBytes = 0;
    if (!IsEbpBasedFrame && !PrologEmitsFixedAllocas)
      StackAdjBytes -= FixedAllocaSizeBytes;
    finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, StackAdjBytes,
                           InArgsSizeBytes);
  }

  // Fill in stack offsets for locals.
  assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
                      SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize,
                      IsEbpBasedFrame && !needsStackPointerAlignment());
  // Assign stack offsets to variables that have been linked to spilled
  // variables.
  for (Variable *Var : VariablesLinkedToSpillSlots) {
    const Variable *Root = Var->getLinkedToStackRoot();
    assert(Root != nullptr);
    Var->setStackOffset(Root->getStackOffset());
  }
  this->HasComputedFrame = true;

  if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
    OstreamLocker L(Func->getContext());
    Ostream &Str = Func->getContext()->getStrDump();

    Str << "Stack layout:\n";
    uint32_t EspAdjustmentPaddingSize =
        SpillAreaSizeBytes - LocalsSpillAreaSize -
        GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
        maxOutArgsSizeBytes();
    Str << " in-args = " << InArgsSizeBytes << " bytes\n"
        << " return address = " << Traits::X86_RET_IP_SIZE_BYTES << " bytes\n"
        << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
        << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
        << " globals spill area = " << GlobalsSize << " bytes\n"
        << " globals-locals spill areas intermediate padding = "
        << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
        << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
        << " esp alignment padding = " << EspAdjustmentPaddingSize
        << " bytes\n";

    Str << "Stack details:\n"
        << " esp adjustment = " << SpillAreaSizeBytes << " bytes\n"
        << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
        << " outgoing args size = " << maxOutArgsSizeBytes() << " bytes\n"
        << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
        << " bytes\n"
        << " is ebp based = " << IsEbpBasedFrame << "\n";
  }
}

/// Helper function for addProlog().
///
/// This assumes Arg is an argument passed on the stack. This sets the frame
/// offset for Arg and updates InArgsSizeBytes according to Arg's width. For an
/// I64 arg that has been split into Lo and Hi components, it calls itself
/// recursively on the components, taking care to handle Lo first because of the
/// little-endian architecture. Lastly, this function generates an instruction
/// to copy Arg into its assigned register if applicable.
template <typename TraitsType>
void TargetX86Base<TraitsType>::finishArgumentLowering(
    Variable *Arg, Variable *FramePtr, size_t BasicFrameOffset,
    size_t StackAdjBytes, size_t &InArgsSizeBytes) {
  if (!Traits::Is64Bit) {
    if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) {
      Variable *Lo = Arg64On32->getLo();
      Variable *Hi = Arg64On32->getHi();
      finishArgumentLowering(Lo, FramePtr, BasicFrameOffset, StackAdjBytes,
                             InArgsSizeBytes);
      finishArgumentLowering(Hi, FramePtr, BasicFrameOffset, StackAdjBytes,
                             InArgsSizeBytes);
      return;
    }
  }
  Type Ty = Arg->getType();
  if (isVectorType(Ty)) {
    InArgsSizeBytes = Traits::applyStackAlignment(InArgsSizeBytes);
  }
  Arg->setStackOffset(BasicFrameOffset + InArgsSizeBytes);
  InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
  if (Arg->hasReg()) {
    assert(Ty != IceType_i64 || Traits::Is64Bit);
    auto *Mem = X86OperandMem::create(
        Func, Ty, FramePtr,
        Ctx->getConstantInt32(Arg->getStackOffset() + StackAdjBytes));
    if (isVectorType(Arg->getType())) {
      _movp(Arg, Mem);
    } else {
      _mov(Arg, Mem);
    }
    // This argument-copying instruction uses an explicit X86OperandMem
    // operand instead of a Variable, so its fill-from-stack operation has to
    // be tracked separately for statistics.
    Ctx->statsUpdateFills();
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::addEpilog(CfgNode *Node) {
  InstList &Insts = Node->getInsts();
  InstList::reverse_iterator RI, E;
  for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
    if (llvm::isa<typename Traits::Insts::Ret>(*RI))
      break;
  }
  if (RI == E)
    return;

  // Convert the reverse_iterator position into its corresponding (forward)
  // iterator position.
  InstList::iterator InsertPoint = reverseToForwardIterator(RI);
  --InsertPoint;
  Context.init(Node);
  Context.setInsertPoint(InsertPoint);

  if (IsEbpBasedFrame) {
    _unlink_bp();
  } else {
    // add stackptr, SpillAreaSizeBytes
    if (SpillAreaSizeBytes != 0) {
      _add_sp(Ctx->getConstantInt32(SpillAreaSizeBytes));
    }
  }

  // Add pop instructions for preserved registers.
  SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
  SmallBitVector Popped(CalleeSaves.size());
  for (int32_t i = CalleeSaves.size() - 1; i >= 0; --i) {
    const auto RegNum = RegNumT::fromInt(i);
    if (RegNum == getFrameReg() && IsEbpBasedFrame)
      continue;
    const RegNumT Canonical = Traits::getBaseReg(RegNum);
    if (CalleeSaves[i] && RegsUsed[i]) {
      Popped[Canonical] = true;
    }
  }
  for (int32_t i = Popped.size() - 1; i >= 0; --i) {
    if (!Popped[i])
      continue;
    const auto RegNum = RegNumT::fromInt(i);
    assert(RegNum == Traits::getBaseReg(RegNum));
    _pop(getPhysicalRegister(RegNum, Traits::WordType));
  }

  if (!NeedSandboxing) {
    return;
  }
  emitSandboxedReturn();
  if (RI->getSrcSize()) {
    auto *RetValue = llvm::cast<Variable>(RI->getSrc(0));
    Context.insert<InstFakeUse>(RetValue);
  }
  RI->setDeleted();
}

template <typename TraitsType> Type TargetX86Base<TraitsType>::stackSlotType() {
  return Traits::WordType;
}

template <typename TraitsType>
template <typename T>
typename std::enable_if<!T::Is64Bit, Operand>::type *
TargetX86Base<TraitsType>::loOperand(Operand *Operand) {
  assert(Operand->getType() == IceType_i64 ||
         Operand->getType() == IceType_f64);
  if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64)
    return Operand;
  if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
    return Var64On32->getLo();
  if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
    auto *ConstInt = llvm::dyn_cast<ConstantInteger32>(
        Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue())));
    // Check if we need to blind/pool the constant.
    return legalize(ConstInt);
  }
  if (auto *Mem = llvm::dyn_cast<X86OperandMem>(Operand)) {
    auto *MemOperand = X86OperandMem::create(
        Func, IceType_i32, Mem->getBase(), Mem->getOffset(), Mem->getIndex(),
        Mem->getShift(), Mem->getSegmentRegister(), Mem->getIsRebased());
    // Test if we should randomize or pool the offset, if so randomize it or
    // pool it then create mem operand with the blinded/pooled constant.
    // Otherwise, return the mem operand as ordinary mem operand.
    return legalize(MemOperand);
  }
  llvm_unreachable("Unsupported operand type");
  return nullptr;
}

template <typename TraitsType>
template <typename T>
typename std::enable_if<!T::Is64Bit, Operand>::type *
TargetX86Base<TraitsType>::hiOperand(Operand *Operand) {
  assert(Operand->getType() == IceType_i64 ||
         Operand->getType() == IceType_f64);
  if (Operand->getType() != IceType_i64 && Operand->getType() != IceType_f64)
    return Operand;
  if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
    return Var64On32->getHi();
  if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
    auto *ConstInt = llvm::dyn_cast<ConstantInteger32>(
        Ctx->getConstantInt32(static_cast<int32_t>(Const->getValue() >> 32)));
    // Check if we need to blind/pool the constant.
    return legalize(ConstInt);
  }
  if (auto *Mem = llvm::dyn_cast<X86OperandMem>(Operand)) {
    Constant *Offset = Mem->getOffset();
    if (Offset == nullptr) {
      Offset = Ctx->getConstantInt32(4);
    } else if (auto *IntOffset = llvm::dyn_cast<ConstantInteger32>(Offset)) {
      Offset = Ctx->getConstantInt32(4 + IntOffset->getValue());
    } else if (auto *SymOffset = llvm::dyn_cast<ConstantRelocatable>(Offset)) {
      assert(!Utils::WouldOverflowAdd(SymOffset->getOffset(), 4));
      Offset =
          Ctx->getConstantSym(4 + SymOffset->getOffset(), SymOffset->getName());
    }
    auto *MemOperand = X86OperandMem::create(
        Func, IceType_i32, Mem->getBase(), Offset, Mem->getIndex(),
        Mem->getShift(), Mem->getSegmentRegister(), Mem->getIsRebased());
    // Test if the Offset is an eligible i32 constants for randomization and
    // pooling. Blind/pool it if it is. Otherwise return as oridinary mem
    // operand.
    return legalize(MemOperand);
  }
  llvm_unreachable("Unsupported operand type");
  return nullptr;
}

template <typename TraitsType>
SmallBitVector
TargetX86Base<TraitsType>::getRegisterSet(RegSetMask Include,
                                          RegSetMask Exclude) const {
  return Traits::getRegisterSet(getFlags(), Include, Exclude);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerAlloca(const InstAlloca *Instr) {
  // Conservatively require the stack to be aligned. Some stack adjustment
  // operations implemented below assume that the stack is aligned before the
  // alloca. All the alloca code ensures that the stack alignment is preserved
  // after the alloca. The stack alignment restriction can be relaxed in some
  // cases.
  RequiredStackAlignment = std::max<size_t>(RequiredStackAlignment,
                                            Traits::X86_STACK_ALIGNMENT_BYTES);

  // For default align=0, set it to the real value 1, to avoid any
  // bit-manipulation problems below.
  const uint32_t AlignmentParam = std::max(1u, Instr->getAlignInBytes());

  // LLVM enforces power of 2 alignment.
  assert(llvm::isPowerOf2_32(AlignmentParam));
  assert(llvm::isPowerOf2_32(Traits::X86_STACK_ALIGNMENT_BYTES));

  const uint32_t Alignment =
      std::max(AlignmentParam, Traits::X86_STACK_ALIGNMENT_BYTES);
  const bool OverAligned = Alignment > Traits::X86_STACK_ALIGNMENT_BYTES;
  const bool OptM1 = Func->getOptLevel() == Opt_m1;
  const bool AllocaWithKnownOffset = Instr->getKnownFrameOffset();
  const bool UseFramePointer =
      hasFramePointer() || OverAligned || !AllocaWithKnownOffset || OptM1;

  if (UseFramePointer)
    setHasFramePointer();

  Variable *esp = getPhysicalRegister(getStackReg(), Traits::WordType);
  if (OverAligned) {
    _and(esp, Ctx->getConstantInt32(-Alignment));
  }

  Variable *Dest = Instr->getDest();
  Operand *TotalSize = legalize(Instr->getSizeInBytes());

  if (const auto *ConstantTotalSize =
          llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
    const uint32_t Value =
        Utils::applyAlignment(ConstantTotalSize->getValue(), Alignment);
    if (UseFramePointer) {
      _sub_sp(Ctx->getConstantInt32(Value));
    } else {
      // If we don't need a Frame Pointer, this alloca has a known offset to the
      // stack pointer. We don't need adjust the stack pointer, nor assign any
      // value to Dest, as Dest is rematerializable.
      assert(Dest->isRematerializable());
      FixedAllocaSizeBytes += Value;
      Context.insert<InstFakeDef>(Dest);
    }
  } else {
    // Non-constant sizes need to be adjusted to the next highest multiple of
    // the required alignment at runtime.
    Variable *T = nullptr;
    if (Traits::Is64Bit && TotalSize->getType() != IceType_i64 &&
        !NeedSandboxing) {
      T = makeReg(IceType_i64);
      _movzx(T, TotalSize);
    } else {
      T = makeReg(IceType_i32);
      _mov(T, TotalSize);
    }
    _add(T, Ctx->getConstantInt32(Alignment - 1));
    _and(T, Ctx->getConstantInt32(-Alignment));
    _sub_sp(T);
  }
  // Add enough to the returned address to account for the out args area.
  uint32_t OutArgsSize = maxOutArgsSizeBytes();
  if (OutArgsSize > 0) {
    Variable *T = makeReg(IceType_i32);
    auto *CalculateOperand = X86OperandMem::create(
        Func, IceType_void, esp, Ctx->getConstantInt(IceType_i32, OutArgsSize));
    _lea(T, CalculateOperand);
    _mov(Dest, T);
  } else {
    _mov(Dest, esp);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerArguments() {
  const bool OptM1 = Func->getOptLevel() == Opt_m1;
  VarList &Args = Func->getArgs();
  unsigned NumXmmArgs = 0;
  bool XmmSlotsRemain = true;
  unsigned NumGprArgs = 0;
  bool GprSlotsRemain = true;

  Context.init(Func->getEntryNode());
  Context.setInsertPoint(Context.getCur());

  for (SizeT i = 0, End = Args.size();
       i < End && (XmmSlotsRemain || GprSlotsRemain); ++i) {
    Variable *Arg = Args[i];
    Type Ty = Arg->getType();
    Variable *RegisterArg = nullptr;
    RegNumT RegNum;
    if (isVectorType(Ty)) {
      RegNum = Traits::getRegisterForXmmArgNum(NumXmmArgs);
      if (RegNum.hasNoValue()) {
        XmmSlotsRemain = false;
        continue;
      }
      ++NumXmmArgs;
      RegisterArg = Func->makeVariable(Ty);
    } else if (isScalarFloatingType(Ty)) {
      if (!Traits::X86_PASS_SCALAR_FP_IN_XMM) {
        continue;
      }
      RegNum = Traits::getRegisterForXmmArgNum(NumXmmArgs);
      if (RegNum.hasNoValue()) {
        XmmSlotsRemain = false;
        continue;
      }
      ++NumXmmArgs;
      RegisterArg = Func->makeVariable(Ty);
    } else if (isScalarIntegerType(Ty)) {
      RegNum = Traits::getRegisterForGprArgNum(Ty, NumGprArgs);
      if (RegNum.hasNoValue()) {
        GprSlotsRemain = false;
        continue;
      }
      ++NumGprArgs;
      RegisterArg = Func->makeVariable(Ty);
    }
    assert(RegNum.hasValue());
    assert(RegisterArg != nullptr);
    // Replace Arg in the argument list with the home register. Then generate
    // an instruction in the prolog to copy the home register to the assigned
    // location of Arg.
    if (BuildDefs::dump())
      RegisterArg->setName(Func, "home_reg:" + Arg->getName());
    RegisterArg->setRegNum(RegNum);
    RegisterArg->setIsArg();
    Arg->setIsArg(false);

    Args[i] = RegisterArg;
    // When not Om1, do the assignment through a temporary, instead of directly
    // from the pre-colored variable, so that a subsequent availabilityGet()
    // call has a chance to work.  (In Om1, don't bother creating extra
    // instructions with extra variables to register-allocate.)
    if (OptM1) {
      Context.insert<InstAssign>(Arg, RegisterArg);
    } else {
      Variable *Tmp = makeReg(RegisterArg->getType());
      Context.insert<InstAssign>(Tmp, RegisterArg);
      Context.insert<InstAssign>(Arg, Tmp);
    }
  }
  if (!OptM1)
    Context.availabilityUpdate();
}

/// Strength-reduce scalar integer multiplication by a constant (for i32 or
/// narrower) for certain constants. The lea instruction can be used to multiply
/// by 3, 5, or 9, and the lsh instruction can be used to multiply by powers of
/// 2. These can be combined such that e.g. multiplying by 100 can be done as 2
/// lea-based multiplies by 5, combined with left-shifting by 2.
template <typename TraitsType>
bool TargetX86Base<TraitsType>::optimizeScalarMul(Variable *Dest, Operand *Src0,
                                                  int32_t Src1) {
  // Disable this optimization for Om1 and O0, just to keep things simple
  // there.
  if (Func->getOptLevel() < Opt_1)
    return false;
  Type Ty = Dest->getType();
  if (Src1 == -1) {
    Variable *T = nullptr;
    _mov(T, Src0);
    _neg(T);
    _mov(Dest, T);
    return true;
  }
  if (Src1 == 0) {
    _mov(Dest, Ctx->getConstantZero(Ty));
    return true;
  }
  if (Src1 == 1) {
    Variable *T = nullptr;
    _mov(T, Src0);
    _mov(Dest, T);
    return true;
  }
  // Don't bother with the edge case where Src1 == MININT.
  if (Src1 == -Src1)
    return false;
  const bool Src1IsNegative = Src1 < 0;
  if (Src1IsNegative)
    Src1 = -Src1;
  uint32_t Count9 = 0;
  uint32_t Count5 = 0;
  uint32_t Count3 = 0;
  uint32_t Count2 = 0;
  uint32_t CountOps = 0;
  while (Src1 > 1) {
    if (Src1 % 9 == 0) {
      ++CountOps;
      ++Count9;
      Src1 /= 9;
    } else if (Src1 % 5 == 0) {
      ++CountOps;
      ++Count5;
      Src1 /= 5;
    } else if (Src1 % 3 == 0) {
      ++CountOps;
      ++Count3;
      Src1 /= 3;
    } else if (Src1 % 2 == 0) {
      if (Count2 == 0)
        ++CountOps;
      ++Count2;
      Src1 /= 2;
    } else {
      return false;
    }
  }
  // Lea optimization only works for i16 and i32 types, not i8.
  if (Ty != IceType_i32 && !(Traits::Is64Bit && Ty == IceType_i64) &&
      (Count3 || Count5 || Count9))
    return false;
  // Limit the number of lea/shl operations for a single multiply, to a
  // somewhat arbitrary choice of 3.
  constexpr uint32_t MaxOpsForOptimizedMul = 3;
  if (CountOps > MaxOpsForOptimizedMul)
    return false;
  Variable *T = makeReg(Traits::WordType);
  if (typeWidthInBytes(Src0->getType()) < typeWidthInBytes(T->getType())) {
    Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    _movzx(T, Src0RM);
  } else {
    _mov(T, Src0);
  }
  Constant *Zero = Ctx->getConstantZero(IceType_i32);
  for (uint32_t i = 0; i < Count9; ++i) {
    constexpr uint16_t Shift = 3; // log2(9-1)
    _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
  }
  for (uint32_t i = 0; i < Count5; ++i) {
    constexpr uint16_t Shift = 2; // log2(5-1)
    _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
  }
  for (uint32_t i = 0; i < Count3; ++i) {
    constexpr uint16_t Shift = 1; // log2(3-1)
    _lea(T, X86OperandMem::create(Func, IceType_void, T, Zero, T, Shift));
  }
  if (Count2) {
    _shl(T, Ctx->getConstantInt(Ty, Count2));
  }
  if (Src1IsNegative)
    _neg(T);
  _mov(Dest, T);
  return true;
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerShift64(InstArithmetic::OpKind Op,
                                             Operand *Src0Lo, Operand *Src0Hi,
                                             Operand *Src1Lo, Variable *DestLo,
                                             Variable *DestHi) {
  // TODO: Refactor the similarities between Shl, Lshr, and Ashr.
  Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
  Constant *Zero = Ctx->getConstantZero(IceType_i32);
  Constant *SignExtend = Ctx->getConstantInt32(0x1f);
  if (auto *ConstantShiftAmount = llvm::dyn_cast<ConstantInteger32>(Src1Lo)) {
    uint32_t ShiftAmount = ConstantShiftAmount->getValue();
    if (ShiftAmount > 32) {
      Constant *ReducedShift = Ctx->getConstantInt32(ShiftAmount - 32);
      switch (Op) {
      default:
        assert(0 && "non-shift op");
        break;
      case InstArithmetic::Shl: {
        // a=b<<c ==>
        //   t2 = b.lo
        //   t2 = shl t2, ShiftAmount-32
        //   t3 = t2
        //   t2 = 0
        _mov(T_2, Src0Lo);
        _shl(T_2, ReducedShift);
        _mov(DestHi, T_2);
        _mov(DestLo, Zero);
      } break;
      case InstArithmetic::Lshr: {
        // a=b>>c (unsigned) ==>
        //   t2 = b.hi
        //   t2 = shr t2, ShiftAmount-32
        //   a.lo = t2
        //   a.hi = 0
        _mov(T_2, Src0Hi);
        _shr(T_2, ReducedShift);
        _mov(DestLo, T_2);
        _mov(DestHi, Zero);
      } break;
      case InstArithmetic::Ashr: {
        // a=b>>c (signed) ==>
        //   t3 = b.hi
        //   t3 = sar t3, 0x1f
        //   t2 = b.hi
        //   t2 = shrd t2, t3, ShiftAmount-32
        //   a.lo = t2
        //   a.hi = t3
        _mov(T_3, Src0Hi);
        _sar(T_3, SignExtend);
        _mov(T_2, Src0Hi);
        _shrd(T_2, T_3, ReducedShift);
        _mov(DestLo, T_2);
        _mov(DestHi, T_3);
      } break;
      }
    } else if (ShiftAmount == 32) {
      switch (Op) {
      default:
        assert(0 && "non-shift op");
        break;
      case InstArithmetic::Shl: {
        // a=b<<c ==>
        //   t2 = b.lo
        //   a.hi = t2
        //   a.lo = 0
        _mov(T_2, Src0Lo);
        _mov(DestHi, T_2);
        _mov(DestLo, Zero);
      } break;
      case InstArithmetic::Lshr: {
        // a=b>>c (unsigned) ==>
        //   t2 = b.hi
        //   a.lo = t2
        //   a.hi = 0
        _mov(T_2, Src0Hi);
        _mov(DestLo, T_2);
        _mov(DestHi, Zero);
      } break;
      case InstArithmetic::Ashr: {
        // a=b>>c (signed) ==>
        //   t2 = b.hi
        //   a.lo = t2
        //   t3 = b.hi
        //   t3 = sar t3, 0x1f
        //   a.hi = t3
        _mov(T_2, Src0Hi);
        _mov(DestLo, T_2);
        _mov(T_3, Src0Hi);
        _sar(T_3, SignExtend);
        _mov(DestHi, T_3);
      } break;
      }
    } else {
      // COMMON PREFIX OF: a=b SHIFT_OP c ==>
      //   t2 = b.lo
      //   t3 = b.hi
      _mov(T_2, Src0Lo);
      _mov(T_3, Src0Hi);
      switch (Op) {
      default:
        assert(0 && "non-shift op");
        break;
      case InstArithmetic::Shl: {
        // a=b<<c ==>
        //   t3 = shld t3, t2, ShiftAmount
        //   t2 = shl t2, ShiftAmount
        _shld(T_3, T_2, ConstantShiftAmount);
        _shl(T_2, ConstantShiftAmount);
      } break;
      case InstArithmetic::Lshr: {
        // a=b>>c (unsigned) ==>
        //   t2 = shrd t2, t3, ShiftAmount
        //   t3 = shr t3, ShiftAmount
        _shrd(T_2, T_3, ConstantShiftAmount);
        _shr(T_3, ConstantShiftAmount);
      } break;
      case InstArithmetic::Ashr: {
        // a=b>>c (signed) ==>
        //   t2 = shrd t2, t3, ShiftAmount
        //   t3 = sar t3, ShiftAmount
        _shrd(T_2, T_3, ConstantShiftAmount);
        _sar(T_3, ConstantShiftAmount);
      } break;
      }
      // COMMON SUFFIX OF: a=b SHIFT_OP c ==>
      //   a.lo = t2
      //   a.hi = t3
      _mov(DestLo, T_2);
      _mov(DestHi, T_3);
    }
  } else {
    // NON-CONSTANT CASES.
    Constant *BitTest = Ctx->getConstantInt32(0x20);
    InstX86Label *Label = InstX86Label::create(Func, this);
    // COMMON PREFIX OF: a=b SHIFT_OP c ==>
    //   t1:ecx = c.lo & 0xff
    //   t2 = b.lo
    //   t3 = b.hi
    T_1 = copyToReg8(Src1Lo, Traits::RegisterSet::Reg_cl);
    _mov(T_2, Src0Lo);
    _mov(T_3, Src0Hi);
    switch (Op) {
    default:
      assert(0 && "non-shift op");
      break;
    case InstArithmetic::Shl: {
      // a=b<<c ==>
      //   t3 = shld t3, t2, t1
      //   t2 = shl t2, t1
      //   test t1, 0x20
      //   je L1
      //   use(t3)
      //   t3 = t2
      //   t2 = 0
      _shld(T_3, T_2, T_1);
      _shl(T_2, T_1);
      _test(T_1, BitTest);
      _br(Traits::Cond::Br_e, Label);
      // T_2 and T_3 are being assigned again because of the intra-block control
      // flow, so we need to use _redefined to avoid liveness problems.
      _redefined(_mov(T_3, T_2));
      _redefined(_mov(T_2, Zero));
    } break;
    case InstArithmetic::Lshr: {
      // a=b>>c (unsigned) ==>
      //   t2 = shrd t2, t3, t1
      //   t3 = shr t3, t1
      //   test t1, 0x20
      //   je L1
      //   use(t2)
      //   t2 = t3
      //   t3 = 0
      _shrd(T_2, T_3, T_1);
      _shr(T_3, T_1);
      _test(T_1, BitTest);
      _br(Traits::Cond::Br_e, Label);
      // T_2 and T_3 are being assigned again because of the intra-block control
      // flow, so we need to use _redefined to avoid liveness problems.
      _redefined(_mov(T_2, T_3));
      _redefined(_mov(T_3, Zero));
    } break;
    case InstArithmetic::Ashr: {
      // a=b>>c (signed) ==>
      //   t2 = shrd t2, t3, t1
      //   t3 = sar t3, t1
      //   test t1, 0x20
      //   je L1
      //   use(t2)
      //   t2 = t3
      //   t3 = sar t3, 0x1f
      Constant *SignExtend = Ctx->getConstantInt32(0x1f);
      _shrd(T_2, T_3, T_1);
      _sar(T_3, T_1);
      _test(T_1, BitTest);
      _br(Traits::Cond::Br_e, Label);
      // T_2 and T_3 are being assigned again because of the intra-block control
      // flow, so T_2 needs to use _redefined to avoid liveness problems. T_3
      // doesn't need special treatment because it is reassigned via _sar
      // instead of _mov.
      _redefined(_mov(T_2, T_3));
      _sar(T_3, SignExtend);
    } break;
    }
    // COMMON SUFFIX OF: a=b SHIFT_OP c ==>
    // L1:
    //   a.lo = t2
    //   a.hi = t3
    Context.insert(Label);
    _mov(DestLo, T_2);
    _mov(DestHi, T_3);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerArithmetic(const InstArithmetic *Instr) {
  Variable *Dest = Instr->getDest();
  if (Dest->isRematerializable()) {
    Context.insert<InstFakeDef>(Dest);
    return;
  }
  Type Ty = Dest->getType();
  Operand *Src0 = legalize(Instr->getSrc(0));
  Operand *Src1 = legalize(Instr->getSrc(1));
  if (Instr->isCommutative()) {
    uint32_t SwapCount = 0;
    if (!llvm::isa<Variable>(Src0) && llvm::isa<Variable>(Src1)) {
      std::swap(Src0, Src1);
      ++SwapCount;
    }
    if (llvm::isa<Constant>(Src0) && !llvm::isa<Constant>(Src1)) {
      std::swap(Src0, Src1);
      ++SwapCount;
    }
    // Improve two-address code patterns by avoiding a copy to the dest
    // register when one of the source operands ends its lifetime here.
    if (!Instr->isLastUse(Src0) && Instr->isLastUse(Src1)) {
      std::swap(Src0, Src1);
      ++SwapCount;
    }
    assert(SwapCount <= 1);
    (void)SwapCount;
  }
  if (!Traits::Is64Bit && Ty == IceType_i64) {
    // These x86-32 helper-call-involved instructions are lowered in this
    // separate switch. This is because loOperand() and hiOperand() may insert
    // redundant instructions for constant blinding and pooling. Such redundant
    // instructions will fail liveness analysis under -Om1 setting. And,
    // actually these arguments do not need to be processed with loOperand()
    // and hiOperand() to be used.
    switch (Instr->getOp()) {
    case InstArithmetic::Udiv:
    case InstArithmetic::Sdiv:
    case InstArithmetic::Urem:
    case InstArithmetic::Srem:
      llvm::report_fatal_error("Helper call was expected");
      return;
    default:
      break;
    }

    auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
    auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
    Operand *Src0Lo = loOperand(Src0);
    Operand *Src0Hi = hiOperand(Src0);
    Operand *Src1Lo = loOperand(Src1);
    Operand *Src1Hi = hiOperand(Src1);
    Variable *T_Lo = nullptr, *T_Hi = nullptr;
    switch (Instr->getOp()) {
    case InstArithmetic::_num:
      llvm_unreachable("Unknown arithmetic operator");
      break;
    case InstArithmetic::Add:
      _mov(T_Lo, Src0Lo);
      _add(T_Lo, Src1Lo);
      _mov(DestLo, T_Lo);
      _mov(T_Hi, Src0Hi);
      _adc(T_Hi, Src1Hi);
      _mov(DestHi, T_Hi);
      break;
    case InstArithmetic::And:
      _mov(T_Lo, Src0Lo);
      _and(T_Lo, Src1Lo);
      _mov(DestLo, T_Lo);
      _mov(T_Hi, Src0Hi);
      _and(T_Hi, Src1Hi);
      _mov(DestHi, T_Hi);
      break;
    case InstArithmetic::Or:
      _mov(T_Lo, Src0Lo);
      _or(T_Lo, Src1Lo);
      _mov(DestLo, T_Lo);
      _mov(T_Hi, Src0Hi);
      _or(T_Hi, Src1Hi);
      _mov(DestHi, T_Hi);
      break;
    case InstArithmetic::Xor:
      _mov(T_Lo, Src0Lo);
      _xor(T_Lo, Src1Lo);
      _mov(DestLo, T_Lo);
      _mov(T_Hi, Src0Hi);
      _xor(T_Hi, Src1Hi);
      _mov(DestHi, T_Hi);
      break;
    case InstArithmetic::Sub:
      _mov(T_Lo, Src0Lo);
      _sub(T_Lo, Src1Lo);
      _mov(DestLo, T_Lo);
      _mov(T_Hi, Src0Hi);
      _sbb(T_Hi, Src1Hi);
      _mov(DestHi, T_Hi);
      break;
    case InstArithmetic::Mul: {
      Variable *T_1 = nullptr, *T_2 = nullptr, *T_3 = nullptr;
      Variable *T_4Lo = makeReg(IceType_i32, Traits::RegisterSet::Reg_eax);
      Variable *T_4Hi = makeReg(IceType_i32, Traits::RegisterSet::Reg_edx);
      // gcc does the following:
      // a=b*c ==>
      //   t1 = b.hi; t1 *=(imul) c.lo
      //   t2 = c.hi; t2 *=(imul) b.lo
      //   t3:eax = b.lo
      //   t4.hi:edx,t4.lo:eax = t3:eax *(mul) c.lo
      //   a.lo = t4.lo
      //   t4.hi += t1
      //   t4.hi += t2
      //   a.hi = t4.hi
      // The mul instruction cannot take an immediate operand.
      Src1Lo = legalize(Src1Lo, Legal_Reg | Legal_Mem);
      _mov(T_1, Src0Hi);
      _imul(T_1, Src1Lo);
      _mov(T_3, Src0Lo, Traits::RegisterSet::Reg_eax);
      _mul(T_4Lo, T_3, Src1Lo);
      // The mul instruction produces two dest variables, edx:eax. We create a
      // fake definition of edx to account for this.
      Context.insert<InstFakeDef>(T_4Hi, T_4Lo);
      Context.insert<InstFakeUse>(T_4Hi);
      _mov(DestLo, T_4Lo);
      _add(T_4Hi, T_1);
      _mov(T_2, Src1Hi);
      _imul(T_2, Src0Lo);
      _add(T_4Hi, T_2);
      _mov(DestHi, T_4Hi);
    } break;
    case InstArithmetic::Shl:
    case InstArithmetic::Lshr:
    case InstArithmetic::Ashr:
      lowerShift64(Instr->getOp(), Src0Lo, Src0Hi, Src1Lo, DestLo, DestHi);
      break;
    case InstArithmetic::Fadd:
    case InstArithmetic::Fsub:
    case InstArithmetic::Fmul:
    case InstArithmetic::Fdiv:
    case InstArithmetic::Frem:
      llvm_unreachable("FP instruction with i64 type");
      break;
    case InstArithmetic::Udiv:
    case InstArithmetic::Sdiv:
    case InstArithmetic::Urem:
    case InstArithmetic::Srem:
      llvm_unreachable("Call-helper-involved instruction for i64 type \
                       should have already been handled before");
      break;
    }
    return;
  }
  if (isVectorType(Ty)) {
    // TODO: Trap on integer divide and integer modulo by zero. See:
    // https://code.google.com/p/nativeclient/issues/detail?id=3899
    if (llvm::isa<X86OperandMem>(Src1))
      Src1 = legalizeToReg(Src1);
    switch (Instr->getOp()) {
    case InstArithmetic::_num:
      llvm_unreachable("Unknown arithmetic operator");
      break;
    case InstArithmetic::Add: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _padd(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::And: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _pand(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Or: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _por(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Xor: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _pxor(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Sub: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _psub(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Mul: {
      bool TypesAreValidForPmull = Ty == IceType_v4i32 || Ty == IceType_v8i16;
      bool InstructionSetIsValidForPmull =
          Ty == IceType_v8i16 || InstructionSet >= Traits::SSE4_1;
      if (TypesAreValidForPmull && InstructionSetIsValidForPmull) {
        Variable *T = makeReg(Ty);
        _movp(T, Src0);
        _pmull(T, Src0 == Src1 ? T : Src1);
        _movp(Dest, T);
      } else if (Ty == IceType_v4i32) {
        // Lowering sequence:
        // Note: The mask arguments have index 0 on the left.
        //
        // movups  T1, Src0
        // pshufd  T2, Src0, {1,0,3,0}
        // pshufd  T3, Src1, {1,0,3,0}
        // # T1 = {Src0[0] * Src1[0], Src0[2] * Src1[2]}
        // pmuludq T1, Src1
        // # T2 = {Src0[1] * Src1[1], Src0[3] * Src1[3]}
        // pmuludq T2, T3
        // # T1 = {lo(T1[0]), lo(T1[2]), lo(T2[0]), lo(T2[2])}
        // shufps  T1, T2, {0,2,0,2}
        // pshufd  T4, T1, {0,2,1,3}
        // movups  Dest, T4

        // Mask that directs pshufd to create a vector with entries
        // Src[1, 0, 3, 0]
        constexpr unsigned Constant1030 = 0x31;
        Constant *Mask1030 = Ctx->getConstantInt32(Constant1030);
        // Mask that directs shufps to create a vector with entries
        // Dest[0, 2], Src[0, 2]
        constexpr unsigned Mask0202 = 0x88;
        // Mask that directs pshufd to create a vector with entries
        // Src[0, 2, 1, 3]
        constexpr unsigned Mask0213 = 0xd8;
        Variable *T1 = makeReg(IceType_v4i32);
        Variable *T2 = makeReg(IceType_v4i32);
        Variable *T3 = makeReg(IceType_v4i32);
        Variable *T4 = makeReg(IceType_v4i32);
        _movp(T1, Src0);
        _pshufd(T2, Src0, Mask1030);
        _pshufd(T3, Src1, Mask1030);
        _pmuludq(T1, Src1);
        _pmuludq(T2, T3);
        _shufps(T1, T2, Ctx->getConstantInt32(Mask0202));
        _pshufd(T4, T1, Ctx->getConstantInt32(Mask0213));
        _movp(Dest, T4);
      } else if (Ty == IceType_v16i8) {
        llvm::report_fatal_error("Scalarized operation was expected");
      } else {
        llvm::report_fatal_error("Invalid vector multiply type");
      }
    } break;
    case InstArithmetic::Shl: {
      assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _psll(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Lshr: {
      assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _psrl(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Ashr: {
      assert(llvm::isa<Constant>(Src1) && "Non-constant shift not scalarized");
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _psra(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Udiv:
    case InstArithmetic::Urem:
    case InstArithmetic::Sdiv:
    case InstArithmetic::Srem:
      llvm::report_fatal_error("Scalarized operation was expected");
      break;
    case InstArithmetic::Fadd: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _addps(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Fsub: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _subps(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Fmul: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _mulps(T, Src0 == Src1 ? T : Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Fdiv: {
      Variable *T = makeReg(Ty);
      _movp(T, Src0);
      _divps(T, Src1);
      _movp(Dest, T);
    } break;
    case InstArithmetic::Frem:
      llvm::report_fatal_error("Scalarized operation was expected");
      break;
    }
    return;
  }
  Variable *T_edx = nullptr;
  Variable *T = nullptr;
  switch (Instr->getOp()) {
  case InstArithmetic::_num:
    llvm_unreachable("Unknown arithmetic operator");
    break;
  case InstArithmetic::Add: {
    const bool ValidType =
        Ty == IceType_i32 || (Ty == IceType_i64 && Traits::Is64Bit);
    auto *Const = llvm::dyn_cast<Constant>(Instr->getSrc(1));
    const bool ValidKind =
        Const != nullptr && (llvm::isa<ConstantInteger32>(Const) ||
                             llvm::isa<ConstantRelocatable>(Const));
    if (getFlags().getAggressiveLea() && ValidType && ValidKind) {
      auto *Var = legalizeToReg(Src0);
      auto *Mem = Traits::X86OperandMem::create(Func, IceType_void, Var, Const);
      T = makeReg(Ty);
      _lea(T, _sandbox_mem_reference(Mem));
      _mov(Dest, T);
      break;
    }
    _mov(T, Src0);
    _add(T, Src1);
    _mov(Dest, T);
  } break;
  case InstArithmetic::And:
    _mov(T, Src0);
    _and(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Or:
    _mov(T, Src0);
    _or(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Xor:
    _mov(T, Src0);
    _xor(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Sub:
    _mov(T, Src0);
    _sub(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Mul:
    if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
      if (optimizeScalarMul(Dest, Src0, C->getValue()))
        return;
    }
    // The 8-bit version of imul only allows the form "imul r/m8" where T must
    // be in al.
    if (isByteSizedArithType(Ty)) {
      _mov(T, Src0, Traits::RegisterSet::Reg_al);
      Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
      _imul(T, Src0 == Src1 ? T : Src1);
      _mov(Dest, T);
    } else if (auto *ImmConst = llvm::dyn_cast<ConstantInteger32>(Src1)) {
      T = makeReg(Ty);
      _imul_imm(T, Src0, ImmConst);
      _mov(Dest, T);
    } else {
      _mov(T, Src0);
      _imul(T, Src0 == Src1 ? T : Src1);
      _mov(Dest, T);
    }
    break;
  case InstArithmetic::Shl:
    _mov(T, Src0);
    if (!llvm::isa<ConstantInteger32>(Src1) &&
        !llvm::isa<ConstantInteger64>(Src1))
      Src1 = copyToReg8(Src1, Traits::RegisterSet::Reg_cl);
    _shl(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Lshr:
    _mov(T, Src0);
    if (!llvm::isa<ConstantInteger32>(Src1) &&
        !llvm::isa<ConstantInteger64>(Src1))
      Src1 = copyToReg8(Src1, Traits::RegisterSet::Reg_cl);
    _shr(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Ashr:
    _mov(T, Src0);
    if (!llvm::isa<ConstantInteger32>(Src1) &&
        !llvm::isa<ConstantInteger64>(Src1))
      Src1 = copyToReg8(Src1, Traits::RegisterSet::Reg_cl);
    _sar(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Udiv: {
    // div and idiv are the few arithmetic operators that do not allow
    // immediates as the operand.
    Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
    RegNumT Eax;
    RegNumT Edx;
    switch (Ty) {
    default:
      llvm::report_fatal_error("Bad type for udiv");
    case IceType_i64:
      Eax = Traits::getRaxOrDie();
      Edx = Traits::getRdxOrDie();
      break;
    case IceType_i32:
      Eax = Traits::RegisterSet::Reg_eax;
      Edx = Traits::RegisterSet::Reg_edx;
      break;
    case IceType_i16:
      Eax = Traits::RegisterSet::Reg_ax;
      Edx = Traits::RegisterSet::Reg_dx;
      break;
    case IceType_i8:
      Eax = Traits::RegisterSet::Reg_al;
      Edx = Traits::RegisterSet::Reg_ah;
      break;
    }
    T_edx = makeReg(Ty, Edx);
    _mov(T, Src0, Eax);
    _mov(T_edx, Ctx->getConstantZero(Ty));
    _div(T_edx, Src1, T);
    _redefined(Context.insert<InstFakeDef>(T, T_edx));
    _mov(Dest, T);
  } break;
  case InstArithmetic::Sdiv:
    // TODO(stichnot): Enable this after doing better performance and cross
    // testing.
    if (false && Func->getOptLevel() >= Opt_1) {
      // Optimize division by constant power of 2, but not for Om1 or O0, just
      // to keep things simple there.
      if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
        const int32_t Divisor = C->getValue();
        const uint32_t UDivisor = Divisor;
        if (Divisor > 0 && llvm::isPowerOf2_32(UDivisor)) {
          uint32_t LogDiv = llvm::Log2_32(UDivisor);
          // LLVM does the following for dest=src/(1<<log):
          //   t=src
          //   sar t,typewidth-1 // -1 if src is negative, 0 if not
          //   shr t,typewidth-log
          //   add t,src
          //   sar t,log
          //   dest=t
          uint32_t TypeWidth = Traits::X86_CHAR_BIT * typeWidthInBytes(Ty);
          _mov(T, Src0);
          // If for some reason we are dividing by 1, just treat it like an
          // assignment.
          if (LogDiv > 0) {
            // The initial sar is unnecessary when dividing by 2.
            if (LogDiv > 1)
              _sar(T, Ctx->getConstantInt(Ty, TypeWidth - 1));
            _shr(T, Ctx->getConstantInt(Ty, TypeWidth - LogDiv));
            _add(T, Src0);
            _sar(T, Ctx->getConstantInt(Ty, LogDiv));
          }
          _mov(Dest, T);
          return;
        }
      }
    }
    Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
    switch (Ty) {
    default:
      llvm::report_fatal_error("Bad type for sdiv");
    case IceType_i64:
      T_edx = makeReg(Ty, Traits::getRdxOrDie());
      _mov(T, Src0, Traits::getRaxOrDie());
      break;
    case IceType_i32:
      T_edx = makeReg(Ty, Traits::RegisterSet::Reg_edx);
      _mov(T, Src0, Traits::RegisterSet::Reg_eax);
      break;
    case IceType_i16:
      T_edx = makeReg(Ty, Traits::RegisterSet::Reg_dx);
      _mov(T, Src0, Traits::RegisterSet::Reg_ax);
      break;
    case IceType_i8:
      T_edx = makeReg(IceType_i16, Traits::RegisterSet::Reg_ax);
      _mov(T, Src0, Traits::RegisterSet::Reg_al);
      break;
    }
    _cbwdq(T_edx, T);
    _idiv(T_edx, Src1, T);
    _redefined(Context.insert<InstFakeDef>(T, T_edx));
    _mov(Dest, T);
    break;
  case InstArithmetic::Urem: {
    Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
    RegNumT Eax;
    RegNumT Edx;
    switch (Ty) {
    default:
      llvm::report_fatal_error("Bad type for urem");
    case IceType_i64:
      Eax = Traits::getRaxOrDie();
      Edx = Traits::getRdxOrDie();
      break;
    case IceType_i32:
      Eax = Traits::RegisterSet::Reg_eax;
      Edx = Traits::RegisterSet::Reg_edx;
      break;
    case IceType_i16:
      Eax = Traits::RegisterSet::Reg_ax;
      Edx = Traits::RegisterSet::Reg_dx;
      break;
    case IceType_i8:
      Eax = Traits::RegisterSet::Reg_al;
      Edx = Traits::RegisterSet::Reg_ah;
      break;
    }
    T_edx = makeReg(Ty, Edx);
    _mov(T_edx, Ctx->getConstantZero(Ty));
    _mov(T, Src0, Eax);
    _div(T, Src1, T_edx);
    _redefined(Context.insert<InstFakeDef>(T_edx, T));
    if (Ty == IceType_i8) {
      // Register ah must be moved into one of {al,bl,cl,dl} before it can be
      // moved into a general 8-bit register.
      auto *T_AhRcvr = makeReg(Ty);
      T_AhRcvr->setRegClass(RCX86_IsAhRcvr);
      _mov(T_AhRcvr, T_edx);
      T_edx = T_AhRcvr;
    }
    _mov(Dest, T_edx);
  } break;
  case InstArithmetic::Srem: {
    // TODO(stichnot): Enable this after doing better performance and cross
    // testing.
    if (false && Func->getOptLevel() >= Opt_1) {
      // Optimize mod by constant power of 2, but not for Om1 or O0, just to
      // keep things simple there.
      if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
        const int32_t Divisor = C->getValue();
        const uint32_t UDivisor = Divisor;
        if (Divisor > 0 && llvm::isPowerOf2_32(UDivisor)) {
          uint32_t LogDiv = llvm::Log2_32(UDivisor);
          // LLVM does the following for dest=src%(1<<log):
          //   t=src
          //   sar t,typewidth-1 // -1 if src is negative, 0 if not
          //   shr t,typewidth-log
          //   add t,src
          //   and t, -(1<<log)
          //   sub t,src
          //   neg t
          //   dest=t
          uint32_t TypeWidth = Traits::X86_CHAR_BIT * typeWidthInBytes(Ty);
          // If for some reason we are dividing by 1, just assign 0.
          if (LogDiv == 0) {
            _mov(Dest, Ctx->getConstantZero(Ty));
            return;
          }
          _mov(T, Src0);
          // The initial sar is unnecessary when dividing by 2.
          if (LogDiv > 1)
            _sar(T, Ctx->getConstantInt(Ty, TypeWidth - 1));
          _shr(T, Ctx->getConstantInt(Ty, TypeWidth - LogDiv));
          _add(T, Src0);
          _and(T, Ctx->getConstantInt(Ty, -(1 << LogDiv)));
          _sub(T, Src0);
          _neg(T);
          _mov(Dest, T);
          return;
        }
      }
    }
    Src1 = legalize(Src1, Legal_Reg | Legal_Mem);
    RegNumT Eax;
    RegNumT Edx;
    switch (Ty) {
    default:
      llvm::report_fatal_error("Bad type for srem");
    case IceType_i64:
      Eax = Traits::getRaxOrDie();
      Edx = Traits::getRdxOrDie();
      break;
    case IceType_i32:
      Eax = Traits::RegisterSet::Reg_eax;
      Edx = Traits::RegisterSet::Reg_edx;
      break;
    case IceType_i16:
      Eax = Traits::RegisterSet::Reg_ax;
      Edx = Traits::RegisterSet::Reg_dx;
      break;
    case IceType_i8:
      Eax = Traits::RegisterSet::Reg_al;
      Edx = Traits::RegisterSet::Reg_ah;
      break;
    }
    T_edx = makeReg(Ty, Edx);
    _mov(T, Src0, Eax);
    _cbwdq(T_edx, T);
    _idiv(T, Src1, T_edx);
    _redefined(Context.insert<InstFakeDef>(T_edx, T));
    if (Ty == IceType_i8) {
      // Register ah must be moved into one of {al,bl,cl,dl} before it can be
      // moved into a general 8-bit register.
      auto *T_AhRcvr = makeReg(Ty);
      T_AhRcvr->setRegClass(RCX86_IsAhRcvr);
      _mov(T_AhRcvr, T_edx);
      T_edx = T_AhRcvr;
    }
    _mov(Dest, T_edx);
  } break;
  case InstArithmetic::Fadd:
    _mov(T, Src0);
    _addss(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Fsub:
    _mov(T, Src0);
    _subss(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Fmul:
    _mov(T, Src0);
    _mulss(T, Src0 == Src1 ? T : Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Fdiv:
    _mov(T, Src0);
    _divss(T, Src1);
    _mov(Dest, T);
    break;
  case InstArithmetic::Frem:
    llvm::report_fatal_error("Helper call was expected");
    break;
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerAssign(const InstAssign *Instr) {
  Variable *Dest = Instr->getDest();
  if (Dest->isRematerializable()) {
    Context.insert<InstFakeDef>(Dest);
    return;
  }
  Operand *Src = Instr->getSrc(0);
  assert(Dest->getType() == Src->getType());
  lowerMove(Dest, Src, false);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerBr(const InstBr *Br) {
  if (Br->isUnconditional()) {
    _br(Br->getTargetUnconditional());
    return;
  }
  Operand *Cond = Br->getCondition();

  // Handle folding opportunities.
  if (const Inst *Producer = FoldingInfo.getProducerFor(Cond)) {
    assert(Producer->isDeleted());
    switch (BoolFolding<Traits>::getProducerKind(Producer)) {
    default:
      break;
    case BoolFolding<Traits>::PK_Icmp32:
    case BoolFolding<Traits>::PK_Icmp64: {
      lowerIcmpAndConsumer(llvm::cast<InstIcmp>(Producer), Br);
      return;
    }
    case BoolFolding<Traits>::PK_Fcmp: {
      lowerFcmpAndConsumer(llvm::cast<InstFcmp>(Producer), Br);
      return;
    }
    case BoolFolding<Traits>::PK_Arith: {
      lowerArithAndConsumer(llvm::cast<InstArithmetic>(Producer), Br);
      return;
    }
    }
  }
  Operand *Src0 = legalize(Cond, Legal_Reg | Legal_Mem);
  Constant *Zero = Ctx->getConstantZero(IceType_i32);
  _cmp(Src0, Zero);
  _br(Traits::Cond::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
}

// constexprMax returns a (constexpr) max(S0, S1), and it is used for defining
// OperandList in lowerCall. std::max() is supposed to work, but it doesn't.
inline constexpr SizeT constexprMax(SizeT S0, SizeT S1) {
  return S0 < S1 ? S1 : S0;
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerCall(const InstCall *Instr) {
  // Common x86 calling convention lowering:
  //
  // * At the point before the call, the stack must be aligned to 16 bytes.
  //
  // * Non-register arguments are pushed onto the stack in right-to-left order,
  // such that the left-most argument ends up on the top of the stack at the
  // lowest memory address.
  //
  // * Stack arguments of vector type are aligned to start at the next highest
  // multiple of 16 bytes. Other stack arguments are aligned to the next word
  // size boundary (4 or 8 bytes, respectively).
  RequiredStackAlignment = std::max<size_t>(RequiredStackAlignment,
                                            Traits::X86_STACK_ALIGNMENT_BYTES);

  using OperandList =
      llvm::SmallVector<Operand *, constexprMax(Traits::X86_MAX_XMM_ARGS,
                                                Traits::X86_MAX_GPR_ARGS)>;
  OperandList XmmArgs;
  CfgVector<std::pair<const Type, Operand *>> GprArgs;
  OperandList StackArgs, StackArgLocations;
  uint32_t ParameterAreaSizeBytes = 0;

  // Classify each argument operand according to the location where the argument
  // is passed.
  for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) {
    Operand *Arg = Instr->getArg(i);
    const Type Ty = Arg->getType();
    // The PNaCl ABI requires the width of arguments to be at least 32 bits.
    assert(typeWidthInBytes(Ty) >= 4);
    if (isVectorType(Ty) &&
        Traits::getRegisterForXmmArgNum(XmmArgs.size()).hasValue()) {
      XmmArgs.push_back(Arg);
    } else if (isScalarFloatingType(Ty) && Traits::X86_PASS_SCALAR_FP_IN_XMM &&
               Traits::getRegisterForXmmArgNum(XmmArgs.size()).hasValue()) {
      XmmArgs.push_back(Arg);
    } else if (isScalarIntegerType(Ty) &&
               Traits::getRegisterForGprArgNum(Ty, GprArgs.size()).hasValue()) {
      GprArgs.emplace_back(Ty, Arg);
    } else {
      // Place on stack.
      StackArgs.push_back(Arg);
      if (isVectorType(Arg->getType())) {
        ParameterAreaSizeBytes =
            Traits::applyStackAlignment(ParameterAreaSizeBytes);
      }
      Variable *esp = getPhysicalRegister(getStackReg(), Traits::WordType);
      Constant *Loc = Ctx->getConstantInt32(ParameterAreaSizeBytes);
      StackArgLocations.push_back(
          Traits::X86OperandMem::create(Func, Ty, esp, Loc));
      ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType());
    }
  }
  // Ensure there is enough space for the fstp/movs for floating returns.
  Variable *Dest = Instr->getDest();
  const Type DestTy = Dest ? Dest->getType() : IceType_void;
  if (!Traits::X86_PASS_SCALAR_FP_IN_XMM) {
    if (isScalarFloatingType(DestTy)) {
      ParameterAreaSizeBytes =
          std::max(static_cast<size_t>(ParameterAreaSizeBytes),
                   typeWidthInBytesOnStack(DestTy));
    }
  }
  // Adjust the parameter area so that the stack is aligned. It is assumed that
  // the stack is already aligned at the start of the calling sequence.
  ParameterAreaSizeBytes = Traits::applyStackAlignment(ParameterAreaSizeBytes);
  assert(ParameterAreaSizeBytes <= maxOutArgsSizeBytes());
  // Copy arguments that are passed on the stack to the appropriate stack
  // locations.  We make sure legalize() is called on each argument at this
  // point, to allow availabilityGet() to work.
  for (SizeT i = 0, NumStackArgs = StackArgs.size(); i < NumStackArgs; ++i) {
    lowerStore(
        InstStore::create(Func, legalize(StackArgs[i]), StackArgLocations[i]));
  }
  // Copy arguments to be passed in registers to the appropriate registers.
  for (SizeT i = 0, NumXmmArgs = XmmArgs.size(); i < NumXmmArgs; ++i) {
    XmmArgs[i] =
        legalizeToReg(legalize(XmmArgs[i]), Traits::getRegisterForXmmArgNum(i));
  }
  // Materialize moves for arguments passed in GPRs.
  for (SizeT i = 0, NumGprArgs = GprArgs.size(); i < NumGprArgs; ++i) {
    const Type SignatureTy = GprArgs[i].first;
    Operand *Arg =
        legalize(GprArgs[i].second, Legal_Default | Legal_Rematerializable);
    GprArgs[i].second =
        legalizeToReg(Arg, Traits::getRegisterForGprArgNum(Arg->getType(), i));
    assert(SignatureTy == IceType_i64 || SignatureTy == IceType_i32);
    assert(SignatureTy == Arg->getType());
    (void)SignatureTy;
  }
  // Generate a FakeUse of register arguments so that they do not get dead code
  // eliminated as a result of the FakeKill of scratch registers after the call.
  // These need to be right before the call instruction.
  for (auto *Arg : XmmArgs) {
    Context.insert<InstFakeUse>(llvm::cast<Variable>(Arg));
  }
  for (auto &ArgPair : GprArgs) {
    Context.insert<InstFakeUse>(llvm::cast<Variable>(ArgPair.second));
  }
  // Generate the call instruction. Assign its result to a temporary with high
  // register allocation weight.
  // ReturnReg doubles as ReturnRegLo as necessary.
  Variable *ReturnReg = nullptr;
  Variable *ReturnRegHi = nullptr;
  if (Dest) {
    switch (DestTy) {
    case IceType_NUM:
    case IceType_void:
    case IceType_i1:
    case IceType_i8:
    case IceType_i16:
      llvm::report_fatal_error("Invalid Call dest type");
      break;
    case IceType_i32:
      ReturnReg = makeReg(DestTy, Traits::RegisterSet::Reg_eax);
      break;
    case IceType_i64:
      if (Traits::Is64Bit) {
        ReturnReg = makeReg(IceType_i64, Traits::getRaxOrDie());
      } else {
        ReturnReg = makeReg(IceType_i32, Traits::RegisterSet::Reg_eax);
        ReturnRegHi = makeReg(IceType_i32, Traits::RegisterSet::Reg_edx);
      }
      break;
    case IceType_f32:
    case IceType_f64:
      if (!Traits::X86_PASS_SCALAR_FP_IN_XMM) {
        // Leave ReturnReg==ReturnRegHi==nullptr, and capture the result with
        // the fstp instruction.
        break;
      }
    // Fallthrough intended.
    case IceType_v4i1:
    case IceType_v8i1:
    case IceType_v16i1:
    case IceType_v16i8:
    case IceType_v8i16:
    case IceType_v4i32:
    case IceType_v4f32:
      ReturnReg = makeReg(DestTy, Traits::RegisterSet::Reg_xmm0);
      break;
    }
  }
  // Emit the call to the function.
  Operand *CallTarget =
      legalize(Instr->getCallTarget(), Legal_Reg | Legal_Imm | Legal_AddrAbs);
  Inst *NewCall = emitCallToTarget(CallTarget, ReturnReg);
  // Keep the upper return register live on 32-bit platform.
  if (ReturnRegHi)
    Context.insert<InstFakeDef>(ReturnRegHi);
  // Mark the call as killing all the caller-save registers.
  Context.insert<InstFakeKill>(NewCall);
  // Handle x86-32 floating point returns.
  if (Dest != nullptr && isScalarFloatingType(DestTy) &&
      !Traits::X86_PASS_SCALAR_FP_IN_XMM) {
    // Special treatment for an FP function which returns its result in st(0).
    // If Dest ends up being a physical xmm register, the fstp emit code will
    // route st(0) through the space reserved in the function argument area
    // we allocated.
    _fstp(Dest);
    // Create a fake use of Dest in case it actually isn't used, because st(0)
    // still needs to be popped.
    Context.insert<InstFakeUse>(Dest);
  }
  // Generate a FakeUse to keep the call live if necessary.
  if (Instr->hasSideEffects() && ReturnReg) {
    Context.insert<InstFakeUse>(ReturnReg);
  }
  // Process the return value, if any.
  if (Dest == nullptr)
    return;
  // Assign the result of the call to Dest.  Route it through a temporary so
  // that the local register availability peephole can be subsequently used.
  Variable *Tmp = nullptr;
  if (isVectorType(DestTy)) {
    assert(ReturnReg && "Vector type requires a return register");
    Tmp = makeReg(DestTy);
    _movp(Tmp, ReturnReg);
    _movp(Dest, Tmp);
  } else if (isScalarFloatingType(DestTy)) {
    if (Traits::X86_PASS_SCALAR_FP_IN_XMM) {
      assert(ReturnReg && "FP type requires a return register");
      _mov(Tmp, ReturnReg);
      _mov(Dest, Tmp);
    }
  } else {
    assert(isScalarIntegerType(DestTy));
    assert(ReturnReg && "Integer type requires a return register");
    if (DestTy == IceType_i64 && !Traits::Is64Bit) {
      assert(ReturnRegHi && "64-bit type requires two return registers");
      auto *Dest64On32 = llvm::cast<Variable64On32>(Dest);
      Variable *DestLo = Dest64On32->getLo();
      Variable *DestHi = Dest64On32->getHi();
      _mov(Tmp, ReturnReg);
      _mov(DestLo, Tmp);
      Variable *TmpHi = nullptr;
      _mov(TmpHi, ReturnRegHi);
      _mov(DestHi, TmpHi);
    } else {
      _mov(Tmp, ReturnReg);
      _mov(Dest, Tmp);
    }
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerCast(const InstCast *Instr) {
  // a = cast(b) ==> t=cast(b); a=t; (link t->b, link a->t, no overlap)
  InstCast::OpKind CastKind = Instr->getCastKind();
  Variable *Dest = Instr->getDest();
  Type DestTy = Dest->getType();
  switch (CastKind) {
  default:
    Func->setError("Cast type not supported");
    return;
  case InstCast::Sext: {
    // Src0RM is the source operand legalized to physical register or memory,
    // but not immediate, since the relevant x86 native instructions don't
    // allow an immediate operand. If the operand is an immediate, we could
    // consider computing the strength-reduced result at translation time, but
    // we're unlikely to see something like that in the bitcode that the
    // optimizer wouldn't have already taken care of.
    Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
    if (isVectorType(DestTy)) {
      if (DestTy == IceType_v16i8) {
        // onemask = materialize(1,1,...); dst = (src & onemask) > 0
        Variable *OneMask = makeVectorOfOnes(DestTy);
        Variable *T = makeReg(DestTy);
        _movp(T, Src0RM);
        _pand(T, OneMask);
        Variable *Zeros = makeVectorOfZeros(DestTy);
        _pcmpgt(T, Zeros);
        _movp(Dest, T);
      } else {
        /// width = width(elty) - 1; dest = (src << width) >> width
        SizeT ShiftAmount =
            Traits::X86_CHAR_BIT * typeWidthInBytes(typeElementType(DestTy)) -
            1;
        Constant *ShiftConstant = Ctx->getConstantInt8(ShiftAmount);
        Variable *T = makeReg(DestTy);
        _movp(T, Src0RM);
        _psll(T, ShiftConstant);
        _psra(T, ShiftConstant);
        _movp(Dest, T);
      }
    } else if (!Traits::Is64Bit && DestTy == IceType_i64) {
      // t1=movsx src; t2=t1; t2=sar t2, 31; dst.lo=t1; dst.hi=t2
      Constant *Shift = Ctx->getConstantInt32(31);
      auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
      auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
      Variable *T_Lo = makeReg(DestLo->getType());
      if (Src0RM->getType() == IceType_i32) {
        _mov(T_Lo, Src0RM);
      } else if (Src0RM->getType() == IceType_i1) {
        _movzx(T_Lo, Src0RM);
        _shl(T_Lo, Shift);
        _sar(T_Lo, Shift);
      } else {
        _movsx(T_Lo, Src0RM);
      }
      _mov(DestLo, T_Lo);
      Variable *T_Hi = nullptr;
      _mov(T_Hi, T_Lo);
      if (Src0RM->getType() != IceType_i1)
        // For i1, the sar instruction is already done above.
        _sar(T_Hi, Shift);
      _mov(DestHi, T_Hi);
    } else if (Src0RM->getType() == IceType_i1) {
      // t1 = src
      // shl t1, dst_bitwidth - 1
      // sar t1, dst_bitwidth - 1
      // dst = t1
      size_t DestBits = Traits::X86_CHAR_BIT * typeWidthInBytes(DestTy);
      Constant *ShiftAmount = Ctx->getConstantInt32(DestBits - 1);
      Variable *T = makeReg(DestTy);
      if (typeWidthInBytes(DestTy) <= typeWidthInBytes(Src0RM->getType())) {
        _mov(T, Src0RM);
      } else {
        // Widen the source using movsx or movzx. (It doesn't matter which one,
        // since the following shl/sar overwrite the bits.)
        _movzx(T, Src0RM);
      }
      _shl(T, ShiftAmount);
      _sar(T, ShiftAmount);
      _mov(Dest, T);
    } else {
      // t1 = movsx src; dst = t1
      Variable *T = makeReg(DestTy);
      _movsx(T, Src0RM);
      _mov(Dest, T);
    }
    break;
  }
  case InstCast::Zext: {
    Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
    if (isVectorType(DestTy)) {
      // onemask = materialize(1,1,...); dest = onemask & src
      Variable *OneMask = makeVectorOfOnes(DestTy);
      Variable *T = makeReg(DestTy);
      _movp(T, Src0RM);
      _pand(T, OneMask);
      _movp(Dest, T);
    } else if (!Traits::Is64Bit && DestTy == IceType_i64) {
      // t1=movzx src; dst.lo=t1; dst.hi=0
      Constant *Zero = Ctx->getConstantZero(IceType_i32);
      auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
      auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
      Variable *Tmp = makeReg(DestLo->getType());
      if (Src0RM->getType() == IceType_i32) {
        _mov(Tmp, Src0RM);
      } else {
        _movzx(Tmp, Src0RM);
      }
      _mov(DestLo, Tmp);
      _mov(DestHi, Zero);
    } else if (Src0RM->getType() == IceType_i1) {
      // t = Src0RM; Dest = t
      Variable *T = nullptr;
      if (DestTy == IceType_i8) {
        _mov(T, Src0RM);
      } else {
        assert(DestTy != IceType_i1);
        assert(Traits::Is64Bit || DestTy != IceType_i64);
        // Use 32-bit for both 16-bit and 32-bit, since 32-bit ops are shorter.
        // In x86-64 we need to widen T to 64-bits to ensure that T -- if
        // written to the stack (i.e., in -Om1) will be fully zero-extended.
        T = makeReg(DestTy == IceType_i64 ? IceType_i64 : IceType_i32);
        _movzx(T, Src0RM);
      }
      _mov(Dest, T);
    } else {
      // t1 = movzx src; dst = t1
      Variable *T = makeReg(DestTy);
      _movzx(T, Src0RM);
      _mov(Dest, T);
    }
    break;
  }
  case InstCast::Trunc: {
    if (isVectorType(DestTy)) {
      // onemask = materialize(1,1,...); dst = src & onemask
      Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
      Type Src0Ty = Src0RM->getType();
      Variable *OneMask = makeVectorOfOnes(Src0Ty);
      Variable *T = makeReg(DestTy);
      _movp(T, Src0RM);
      _pand(T, OneMask);
      _movp(Dest, T);
    } else if (DestTy == IceType_i1 || DestTy == IceType_i8) {
      // Make sure we truncate from and into valid registers.
      Operand *Src0 = legalizeUndef(Instr->getSrc(0));
      if (!Traits::Is64Bit && Src0->getType() == IceType_i64)
        Src0 = loOperand(Src0);
      Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      Variable *T = copyToReg8(Src0RM);
      if (DestTy == IceType_i1)
        _and(T, Ctx->getConstantInt1(1));
      _mov(Dest, T);
    } else {
      Operand *Src0 = legalizeUndef(Instr->getSrc(0));
      if (!Traits::Is64Bit && Src0->getType() == IceType_i64)
        Src0 = loOperand(Src0);
      Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      // t1 = trunc Src0RM; Dest = t1
      Variable *T = makeReg(DestTy);
      _mov(T, Src0RM);
      _mov(Dest, T);
    }
    break;
  }
  case InstCast::Fptrunc:
  case InstCast::Fpext: {
    Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
    // t1 = cvt Src0RM; Dest = t1
    Variable *T = makeReg(DestTy);
    _cvt(T, Src0RM, Traits::Insts::Cvt::Float2float);
    _mov(Dest, T);
    break;
  }
  case InstCast::Fptosi:
    if (isVectorType(DestTy)) {
      assert(DestTy == IceType_v4i32);
      assert(Instr->getSrc(0)->getType() == IceType_v4f32);
      Operand *Src0R = legalizeToReg(Instr->getSrc(0));
      Variable *T = makeReg(DestTy);
      _cvt(T, Src0R, Traits::Insts::Cvt::Tps2dq);
      _movp(Dest, T);
    } else if (!Traits::Is64Bit && DestTy == IceType_i64) {
      llvm::report_fatal_error("Helper call was expected");
    } else {
      Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
      // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
      Variable *T_1 = nullptr;
      if (Traits::Is64Bit && DestTy == IceType_i64) {
        T_1 = makeReg(IceType_i64);
      } else {
        assert(DestTy != IceType_i64);
        T_1 = makeReg(IceType_i32);
      }
      // cvt() requires its integer argument to be a GPR.
      Variable *T_2 = makeReg(DestTy);
      if (isByteSizedType(DestTy)) {
        assert(T_1->getType() == IceType_i32);
        T_1->setRegClass(RCX86_Is32To8);
        T_2->setRegClass(RCX86_IsTrunc8Rcvr);
      }
      _cvt(T_1, Src0RM, Traits::Insts::Cvt::Tss2si);
      _mov(T_2, T_1); // T_1 and T_2 may have different integer types
      if (DestTy == IceType_i1)
        _and(T_2, Ctx->getConstantInt1(1));
      _mov(Dest, T_2);
    }
    break;
  case InstCast::Fptoui:
    if (isVectorType(DestTy)) {
      llvm::report_fatal_error("Helper call was expected");
    } else if (DestTy == IceType_i64 ||
               (!Traits::Is64Bit && DestTy == IceType_i32)) {
      llvm::report_fatal_error("Helper call was expected");
    } else {
      Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
      // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
      assert(DestTy != IceType_i64);
      Variable *T_1 = nullptr;
      if (Traits::Is64Bit && DestTy == IceType_i32) {
        T_1 = makeReg(IceType_i64);
      } else {
        assert(DestTy != IceType_i32);
        T_1 = makeReg(IceType_i32);
      }
      Variable *T_2 = makeReg(DestTy);
      if (isByteSizedType(DestTy)) {
        assert(T_1->getType() == IceType_i32);
        T_1->setRegClass(RCX86_Is32To8);
        T_2->setRegClass(RCX86_IsTrunc8Rcvr);
      }
      _cvt(T_1, Src0RM, Traits::Insts::Cvt::Tss2si);
      _mov(T_2, T_1); // T_1 and T_2 may have different integer types
      if (DestTy == IceType_i1)
        _and(T_2, Ctx->getConstantInt1(1));
      _mov(Dest, T_2);
    }
    break;
  case InstCast::Sitofp:
    if (isVectorType(DestTy)) {
      assert(DestTy == IceType_v4f32);
      assert(Instr->getSrc(0)->getType() == IceType_v4i32);
      Operand *Src0R = legalizeToReg(Instr->getSrc(0));
      Variable *T = makeReg(DestTy);
      _cvt(T, Src0R, Traits::Insts::Cvt::Dq2ps);
      _movp(Dest, T);
    } else if (!Traits::Is64Bit && Instr->getSrc(0)->getType() == IceType_i64) {
      llvm::report_fatal_error("Helper call was expected");
    } else {
      Operand *Src0RM = legalize(Instr->getSrc(0), Legal_Reg | Legal_Mem);
      // Sign-extend the operand.
      // t1.i32 = movsx Src0RM; t2 = Cvt t1.i32; Dest = t2
      Variable *T_1 = nullptr;
      if (Traits::Is64Bit && Src0RM->getType() == IceType_i64) {
        T_1 = makeReg(IceType_i64);
      } else {
        assert(Src0RM->getType() != IceType_i64);
        T_1 = makeReg(IceType_i32);
      }
      Variable *T_2 = makeReg(DestTy);
      if (Src0RM->getType() == T_1->getType())
        _mov(T_1, Src0RM);
      else
        _movsx(T_1, Src0RM);
      _cvt(T_2, T_1, Traits::Insts::Cvt::Si2ss);
      _mov(Dest, T_2);
    }
    break;
  case InstCast::Uitofp: {
    Operand *Src0 = Instr->getSrc(0);
    if (isVectorType(Src0->getType())) {
      llvm::report_fatal_error("Helper call was expected");
    } else if (Src0->getType() == IceType_i64 ||
               (!Traits::Is64Bit && Src0->getType() == IceType_i32)) {
      llvm::report_fatal_error("Helper call was expected");
    } else {
      Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      // Zero-extend the operand.
      // t1.i32 = movzx Src0RM; t2 = Cvt t1.i32; Dest = t2
      Variable *T_1 = nullptr;
      if (Traits::Is64Bit && Src0RM->getType() == IceType_i32) {
        T_1 = makeReg(IceType_i64);
      } else {
        assert(Src0RM->getType() != IceType_i64);
        assert(Traits::Is64Bit || Src0RM->getType() != IceType_i32);
        T_1 = makeReg(IceType_i32);
      }
      Variable *T_2 = makeReg(DestTy);
      if (Src0RM->getType() == T_1->getType())
        _mov(T_1, Src0RM);
      else
        _movzx(T_1, Src0RM)->setMustKeep();
      _cvt(T_2, T_1, Traits::Insts::Cvt::Si2ss);
      _mov(Dest, T_2);
    }
    break;
  }
  case InstCast::Bitcast: {
    Operand *Src0 = Instr->getSrc(0);
    if (DestTy == Src0->getType()) {
      auto *Assign = InstAssign::create(Func, Dest, Src0);
      lowerAssign(Assign);
      return;
    }
    switch (DestTy) {
    default:
      llvm_unreachable("Unexpected Bitcast dest type");
    case IceType_i8: {
      llvm::report_fatal_error("Helper call was expected");
    } break;
    case IceType_i16: {
      llvm::report_fatal_error("Helper call was expected");
    } break;
    case IceType_i32:
    case IceType_f32: {
      Variable *Src0R = legalizeToReg(Src0);
      Variable *T = makeReg(DestTy);
      _movd(T, Src0R);
      _mov(Dest, T);
    } break;
    case IceType_i64: {
      assert(Src0->getType() == IceType_f64);
      if (Traits::Is64Bit) {
        Variable *Src0R = legalizeToReg(Src0);
        Variable *T = makeReg(IceType_i64);
        _movd(T, Src0R);
        _mov(Dest, T);
      } else {
        Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
        // a.i64 = bitcast b.f64 ==>
        //   s.f64 = spill b.f64
        //   t_lo.i32 = lo(s.f64)
        //   a_lo.i32 = t_lo.i32
        //   t_hi.i32 = hi(s.f64)
        //   a_hi.i32 = t_hi.i32
        Operand *SpillLo, *SpillHi;
        if (auto *Src0Var = llvm::dyn_cast<Variable>(Src0RM)) {
          Variable *Spill = Func->makeVariable(IceType_f64);
          Spill->setLinkedTo(Src0Var);
          Spill->setMustNotHaveReg();
          _movq(Spill, Src0RM);
          SpillLo = Traits::VariableSplit::create(Func, Spill,
                                                  Traits::VariableSplit::Low);
          SpillHi = Traits::VariableSplit::create(Func, Spill,
                                                  Traits::VariableSplit::High);
        } else {
          SpillLo = loOperand(Src0RM);
          SpillHi = hiOperand(Src0RM);
        }

        auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
        auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
        Variable *T_Lo = makeReg(IceType_i32);
        Variable *T_Hi = makeReg(IceType_i32);

        _mov(T_Lo, SpillLo);
        _mov(DestLo, T_Lo);
        _mov(T_Hi, SpillHi);
        _mov(DestHi, T_Hi);
      }
    } break;
    case IceType_f64: {
      assert(Src0->getType() == IceType_i64);
      if (Traits::Is64Bit) {
        Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
        Variable *T = makeReg(IceType_f64);
        _movd(T, Src0RM);
        _mov(Dest, T);
      } else {
        Src0 = legalize(Src0);
        if (llvm::isa<X86OperandMem>(Src0)) {
          Variable *T = makeReg(DestTy);
          _movq(T, Src0);
          _movq(Dest, T);
          break;
        }
        // a.f64 = bitcast b.i64 ==>
        //   t_lo.i32 = b_lo.i32
        //   FakeDef(s.f64)
        //   lo(s.f64) = t_lo.i32
        //   t_hi.i32 = b_hi.i32
        //   hi(s.f64) = t_hi.i32
        //   a.f64 = s.f64
        Variable *Spill = Func->makeVariable(IceType_f64);
        Spill->setLinkedTo(Dest);
        Spill->setMustNotHaveReg();

        Variable *T_Lo = nullptr, *T_Hi = nullptr;
        auto *SpillLo = Traits::VariableSplit::create(
            Func, Spill, Traits::VariableSplit::Low);
        auto *SpillHi = Traits::VariableSplit::create(
            Func, Spill, Traits::VariableSplit::High);
        _mov(T_Lo, loOperand(Src0));
        // Technically, the Spill is defined after the _store happens, but
        // SpillLo is considered a "use" of Spill so define Spill before it is
        // used.
        Context.insert<InstFakeDef>(Spill);
        _store(T_Lo, SpillLo);
        _mov(T_Hi, hiOperand(Src0));
        _store(T_Hi, SpillHi);
        _movq(Dest, Spill);
      }
    } break;
    case IceType_v8i1: {
      llvm::report_fatal_error("Helper call was expected");
    } break;
    case IceType_v16i1: {
      llvm::report_fatal_error("Helper call was expected");
    } break;
    case IceType_v8i16:
    case IceType_v16i8:
    case IceType_v4i32:
    case IceType_v4f32: {
      if (Src0->getType() == IceType_i32) {
        // Bitcast requires equal type sizes, which isn't strictly the case
        // between scalars and vectors, but to emulate v4i8 vectors one has to
        // use v16i8 vectors.
        assert(getFlags().getApplicationBinaryInterface() != ABI_PNaCl &&
               "PNaCl only supports real 128-bit vectors");
        _movd(Dest, legalize(Src0, Legal_Reg | Legal_Mem));
      } else {
        _movp(Dest, legalizeToReg(Src0));
      }
    } break;
    }
    break;
  }
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerExtractElement(
    const InstExtractElement *Instr) {
  Operand *SourceVectNotLegalized = Instr->getSrc(0);
  auto *ElementIndex = llvm::dyn_cast<ConstantInteger32>(Instr->getSrc(1));
  // Only constant indices are allowed in PNaCl IR.
  assert(ElementIndex);

  unsigned Index = ElementIndex->getValue();
  Type Ty = SourceVectNotLegalized->getType();
  Type ElementTy = typeElementType(Ty);
  Type InVectorElementTy = Traits::getInVectorElementType(Ty);

  // TODO(wala): Determine the best lowering sequences for each type.
  bool CanUsePextr = Ty == IceType_v8i16 || Ty == IceType_v8i1 ||
                     (InstructionSet >= Traits::SSE4_1 && Ty != IceType_v4f32);
  Variable *ExtractedElementR =
      makeReg(CanUsePextr ? IceType_i32 : InVectorElementTy);
  if (CanUsePextr) {
    // Use pextrb, pextrw, or pextrd.  The "b" and "w" versions clear the upper
    // bits of the destination register, so we represent this by always
    // extracting into an i32 register.  The _mov into Dest below will do
    // truncation as necessary.
    Constant *Mask = Ctx->getConstantInt32(Index);
    Variable *SourceVectR = legalizeToReg(SourceVectNotLegalized);
    _pextr(ExtractedElementR, SourceVectR, Mask);
  } else if (Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v4i1) {
    // Use pshufd and movd/movss.
    Variable *T = nullptr;
    if (Index) {
      // The shuffle only needs to occur if the element to be extracted is not
      // at the lowest index.
      Constant *Mask = Ctx->getConstantInt32(Index);
      T = makeReg(Ty);
      _pshufd(T, legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem), Mask);
    } else {
      T = legalizeToReg(SourceVectNotLegalized);
    }

    if (InVectorElementTy == IceType_i32) {
      _movd(ExtractedElementR, T);
    } else { // Ty == IceType_f32
      // TODO(wala): _movss is only used here because _mov does not allow a
      // vector source and a scalar destination.  _mov should be able to be
      // used here.
      // _movss is a binary instruction, so the FakeDef is needed to keep the
      // live range analysis consistent.
      Context.insert<InstFakeDef>(ExtractedElementR);
      _movss(ExtractedElementR, T);
    }
  } else {
    assert(Ty == IceType_v16i8 || Ty == IceType_v16i1);
    // Spill the value to a stack slot and do the extraction in memory.
    //
    // TODO(wala): use legalize(SourceVectNotLegalized, Legal_Mem) when support
    // for legalizing to mem is implemented.
    Variable *Slot = Func->makeVariable(Ty);
    Slot->setMustNotHaveReg();
    _movp(Slot, legalizeToReg(SourceVectNotLegalized));

    // Compute the location of the element in memory.
    unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
    X86OperandMem *Loc =
        getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
    _mov(ExtractedElementR, Loc);
  }

  if (ElementTy == IceType_i1) {
    // Truncate extracted integers to i1s if necessary.
    Variable *T = makeReg(IceType_i1);
    InstCast *Cast =
        InstCast::create(Func, InstCast::Trunc, T, ExtractedElementR);
    lowerCast(Cast);
    ExtractedElementR = T;
  }

  // Copy the element to the destination.
  Variable *Dest = Instr->getDest();
  _mov(Dest, ExtractedElementR);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerFcmp(const InstFcmp *Fcmp) {
  Variable *Dest = Fcmp->getDest();

  if (isVectorType(Dest->getType())) {
    lowerFcmpVector(Fcmp);
  } else {
    constexpr Inst *Consumer = nullptr;
    lowerFcmpAndConsumer(Fcmp, Consumer);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerFcmpAndConsumer(const InstFcmp *Fcmp,
                                                     const Inst *Consumer) {
  Operand *Src0 = Fcmp->getSrc(0);
  Operand *Src1 = Fcmp->getSrc(1);
  Variable *Dest = Fcmp->getDest();

  if (Consumer != nullptr) {
    if (auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
      if (lowerOptimizeFcmpSelect(Fcmp, Select))
        return;
    }
  }

  if (isVectorType(Dest->getType())) {
    lowerFcmp(Fcmp);
    if (Consumer != nullptr)
      lowerSelectVector(llvm::cast<InstSelect>(Consumer));
    return;
  }

  // Lowering a = fcmp cond, b, c
  //   ucomiss b, c       /* only if C1 != Br_None */
  //                      /* but swap b,c order if SwapOperands==true */
  //   mov a, <default>
  //   j<C1> label        /* only if C1 != Br_None */
  //   j<C2> label        /* only if C2 != Br_None */
  //   FakeUse(a)         /* only if C1 != Br_None */
  //   mov a, !<default>  /* only if C1 != Br_None */
  //   label:             /* only if C1 != Br_None */
  //
  // setcc lowering when C1 != Br_None && C2 == Br_None:
  //   ucomiss b, c       /* but swap b,c order if SwapOperands==true */
  //   setcc a, C1
  InstFcmp::FCond Condition = Fcmp->getCondition();
  assert(Condition < Traits::TableFcmpSize);
  if (Traits::TableFcmp[Condition].SwapScalarOperands)
    std::swap(Src0, Src1);
  const bool HasC1 = (Traits::TableFcmp[Condition].C1 != Traits::Cond::Br_None);
  const bool HasC2 = (Traits::TableFcmp[Condition].C2 != Traits::Cond::Br_None);
  if (HasC1) {
    Src0 = legalize(Src0);
    Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    Variable *T = nullptr;
    _mov(T, Src0);
    _ucomiss(T, Src1RM);
    if (!HasC2) {
      assert(Traits::TableFcmp[Condition].Default);
      setccOrConsumer(Traits::TableFcmp[Condition].C1, Dest, Consumer);
      return;
    }
  }
  int32_t IntDefault = Traits::TableFcmp[Condition].Default;
  if (Consumer == nullptr) {
    Constant *Default = Ctx->getConstantInt(Dest->getType(), IntDefault);
    _mov(Dest, Default);
    if (HasC1) {
      InstX86Label *Label = InstX86Label::create(Func, this);
      _br(Traits::TableFcmp[Condition].C1, Label);
      if (HasC2) {
        _br(Traits::TableFcmp[Condition].C2, Label);
      }
      Constant *NonDefault = Ctx->getConstantInt(Dest->getType(), !IntDefault);
      _redefined(_mov(Dest, NonDefault));
      Context.insert(Label);
    }
    return;
  }
  if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
    CfgNode *TrueSucc = Br->getTargetTrue();
    CfgNode *FalseSucc = Br->getTargetFalse();
    if (IntDefault != 0)
      std::swap(TrueSucc, FalseSucc);
    if (HasC1) {
      _br(Traits::TableFcmp[Condition].C1, FalseSucc);
      if (HasC2) {
        _br(Traits::TableFcmp[Condition].C2, FalseSucc);
      }
      _br(TrueSucc);
      return;
    }
    _br(FalseSucc);
    return;
  }
  if (auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
    Operand *SrcT = Select->getTrueOperand();
    Operand *SrcF = Select->getFalseOperand();
    Variable *SelectDest = Select->getDest();
    if (IntDefault != 0)
      std::swap(SrcT, SrcF);
    lowerMove(SelectDest, SrcF, false);
    if (HasC1) {
      InstX86Label *Label = InstX86Label::create(Func, this);
      _br(Traits::TableFcmp[Condition].C1, Label);
      if (HasC2) {
        _br(Traits::TableFcmp[Condition].C2, Label);
      }
      static constexpr bool IsRedefinition = true;
      lowerMove(SelectDest, SrcT, IsRedefinition);
      Context.insert(Label);
    }
    return;
  }
  llvm::report_fatal_error("Unexpected consumer type");
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerFcmpVector(const InstFcmp *Fcmp) {
  Operand *Src0 = Fcmp->getSrc(0);
  Operand *Src1 = Fcmp->getSrc(1);
  Variable *Dest = Fcmp->getDest();

  if (!isVectorType(Dest->getType()))
    llvm::report_fatal_error("Expected vector compare");

  InstFcmp::FCond Condition = Fcmp->getCondition();
  assert(Condition < Traits::TableFcmpSize);

  if (Traits::TableFcmp[Condition].SwapVectorOperands)
    std::swap(Src0, Src1);

  Variable *T = nullptr;

  if (Condition == InstFcmp::True) {
    // makeVectorOfOnes() requires an integer vector type.
    T = makeVectorOfMinusOnes(IceType_v4i32);
  } else if (Condition == InstFcmp::False) {
    T = makeVectorOfZeros(Dest->getType());
  } else {
    Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    if (llvm::isa<X86OperandMem>(Src1RM))
      Src1RM = legalizeToReg(Src1RM);

    switch (Condition) {
    default: {
      const CmppsCond Predicate = Traits::TableFcmp[Condition].Predicate;
      assert(Predicate != Traits::Cond::Cmpps_Invalid);
      T = makeReg(Src0RM->getType());
      _movp(T, Src0RM);
      _cmpps(T, Src1RM, Predicate);
    } break;
    case InstFcmp::One: {
      // Check both unequal and ordered.
      T = makeReg(Src0RM->getType());
      Variable *T2 = makeReg(Src0RM->getType());
      _movp(T, Src0RM);
      _cmpps(T, Src1RM, Traits::Cond::Cmpps_neq);
      _movp(T2, Src0RM);
      _cmpps(T2, Src1RM, Traits::Cond::Cmpps_ord);
      _pand(T, T2);
    } break;
    case InstFcmp::Ueq: {
      // Check both equal or unordered.
      T = makeReg(Src0RM->getType());
      Variable *T2 = makeReg(Src0RM->getType());
      _movp(T, Src0RM);
      _cmpps(T, Src1RM, Traits::Cond::Cmpps_eq);
      _movp(T2, Src0RM);
      _cmpps(T2, Src1RM, Traits::Cond::Cmpps_unord);
      _por(T, T2);
    } break;
    }
  }

  assert(T != nullptr);
  _movp(Dest, T);
  eliminateNextVectorSextInstruction(Dest);
}

inline bool isZero(const Operand *Opnd) {
  if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Opnd))
    return C64->getValue() == 0;
  if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(Opnd))
    return C32->getValue() == 0;
  return false;
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerIcmpAndConsumer(const InstIcmp *Icmp,
                                                     const Inst *Consumer) {
  Operand *Src0 = legalize(Icmp->getSrc(0));
  Operand *Src1 = legalize(Icmp->getSrc(1));
  Variable *Dest = Icmp->getDest();

  if (isVectorType(Dest->getType())) {
    lowerIcmp(Icmp);
    if (Consumer != nullptr)
      lowerSelectVector(llvm::cast<InstSelect>(Consumer));
    return;
  }

  if (!Traits::Is64Bit && Src0->getType() == IceType_i64) {
    lowerIcmp64(Icmp, Consumer);
    return;
  }

  // cmp b, c
  if (isZero(Src1)) {
    switch (Icmp->getCondition()) {
    default:
      break;
    case InstIcmp::Uge:
      movOrConsumer(true, Dest, Consumer);
      return;
    case InstIcmp::Ult:
      movOrConsumer(false, Dest, Consumer);
      return;
    }
  }
  Operand *Src0RM = legalizeSrc0ForCmp(Src0, Src1);
  _cmp(Src0RM, Src1);
  setccOrConsumer(Traits::getIcmp32Mapping(Icmp->getCondition()), Dest,
                  Consumer);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerIcmpVector(const InstIcmp *Icmp) {
  Operand *Src0 = legalize(Icmp->getSrc(0));
  Operand *Src1 = legalize(Icmp->getSrc(1));
  Variable *Dest = Icmp->getDest();

  if (!isVectorType(Dest->getType()))
    llvm::report_fatal_error("Expected a vector compare");

  Type Ty = Src0->getType();
  // Promote i1 vectors to 128 bit integer vector types.
  if (typeElementType(Ty) == IceType_i1) {
    Type NewTy = IceType_NUM;
    switch (Ty) {
    default:
      llvm::report_fatal_error("unexpected type");
      break;
    case IceType_v4i1:
      NewTy = IceType_v4i32;
      break;
    case IceType_v8i1:
      NewTy = IceType_v8i16;
      break;
    case IceType_v16i1:
      NewTy = IceType_v16i8;
      break;
    }
    Variable *NewSrc0 = Func->makeVariable(NewTy);
    Variable *NewSrc1 = Func->makeVariable(NewTy);
    lowerCast(InstCast::create(Func, InstCast::Sext, NewSrc0, Src0));
    lowerCast(InstCast::create(Func, InstCast::Sext, NewSrc1, Src1));
    Src0 = NewSrc0;
    Src1 = NewSrc1;
    Ty = NewTy;
  }

  InstIcmp::ICond Condition = Icmp->getCondition();

  Operand *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
  Operand *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);

  // SSE2 only has signed comparison operations. Transform unsigned inputs in
  // a manner that allows for the use of signed comparison operations by
  // flipping the high order bits.
  if (Condition == InstIcmp::Ugt || Condition == InstIcmp::Uge ||
      Condition == InstIcmp::Ult || Condition == InstIcmp::Ule) {
    Variable *T0 = makeReg(Ty);
    Variable *T1 = makeReg(Ty);
    Variable *HighOrderBits = makeVectorOfHighOrderBits(Ty);
    _movp(T0, Src0RM);
    _pxor(T0, HighOrderBits);
    _movp(T1, Src1RM);
    _pxor(T1, HighOrderBits);
    Src0RM = T0;
    Src1RM = T1;
  }

  Variable *T = makeReg(Ty);
  switch (Condition) {
  default:
    llvm_unreachable("unexpected condition");
    break;
  case InstIcmp::Eq: {
    if (llvm::isa<X86OperandMem>(Src1RM))
      Src1RM = legalizeToReg(Src1RM);
    _movp(T, Src0RM);
    _pcmpeq(T, Src1RM);
  } break;
  case InstIcmp::Ne: {
    if (llvm::isa<X86OperandMem>(Src1RM))
      Src1RM = legalizeToReg(Src1RM);
    _movp(T, Src0RM);
    _pcmpeq(T, Src1RM);
    Variable *MinusOne = makeVectorOfMinusOnes(Ty);
    _pxor(T, MinusOne);
  } break;
  case InstIcmp::Ugt:
  case InstIcmp::Sgt: {
    if (llvm::isa<X86OperandMem>(Src1RM))
      Src1RM = legalizeToReg(Src1RM);
    _movp(T, Src0RM);
    _pcmpgt(T, Src1RM);
  } break;
  case InstIcmp::Uge:
  case InstIcmp::Sge: {
    // !(Src1RM > Src0RM)
    if (llvm::isa<X86OperandMem>(Src0RM))
      Src0RM = legalizeToReg(Src0RM);
    _movp(T, Src1RM);
    _pcmpgt(T, Src0RM);
    Variable *MinusOne = makeVectorOfMinusOnes(Ty);
    _pxor(T, MinusOne);
  } break;
  case InstIcmp::Ult:
  case InstIcmp::Slt: {
    if (llvm::isa<X86OperandMem>(Src0RM))
      Src0RM = legalizeToReg(Src0RM);
    _movp(T, Src1RM);
    _pcmpgt(T, Src0RM);
  } break;
  case InstIcmp::Ule:
  case InstIcmp::Sle: {
    // !(Src0RM > Src1RM)
    if (llvm::isa<X86OperandMem>(Src1RM))
      Src1RM = legalizeToReg(Src1RM);
    _movp(T, Src0RM);
    _pcmpgt(T, Src1RM);
    Variable *MinusOne = makeVectorOfMinusOnes(Ty);
    _pxor(T, MinusOne);
  } break;
  }

  _movp(Dest, T);
  eliminateNextVectorSextInstruction(Dest);
}

template <typename TraitsType>
template <typename T>
typename std::enable_if<!T::Is64Bit, void>::type
TargetX86Base<TraitsType>::lowerIcmp64(const InstIcmp *Icmp,
                                       const Inst *Consumer) {
  // a=icmp cond, b, c ==> cmp b,c; a=1; br cond,L1; FakeUse(a); a=0; L1:
  Operand *Src0 = legalize(Icmp->getSrc(0));
  Operand *Src1 = legalize(Icmp->getSrc(1));
  Variable *Dest = Icmp->getDest();
  InstIcmp::ICond Condition = Icmp->getCondition();
  assert(Condition < Traits::TableIcmp64Size);
  Operand *Src0LoRM = nullptr;
  Operand *Src0HiRM = nullptr;
  // Legalize the portions of Src0 that are going to be needed.
  if (isZero(Src1)) {
    switch (Condition) {
    default:
      llvm_unreachable("unexpected condition");
      break;
    // These two are not optimized, so we fall through to the general case,
    // which needs the upper and lower halves legalized.
    case InstIcmp::Sgt:
    case InstIcmp::Sle:
    // These four compare after performing an "or" of the high and low half, so
    // they need the upper and lower halves legalized.
    case InstIcmp::Eq:
    case InstIcmp::Ule:
    case InstIcmp::Ne:
    case InstIcmp::Ugt:
      Src0LoRM = legalize(loOperand(Src0), Legal_Reg | Legal_Mem);
    // These two test only the high half's sign bit, so they need only
    // the upper half legalized.
    case InstIcmp::Sge:
    case InstIcmp::Slt:
      Src0HiRM = legalize(hiOperand(Src0), Legal_Reg | Legal_Mem);
      break;

    // These two move constants and hence need no legalization.
    case InstIcmp::Uge:
    case InstIcmp::Ult:
      break;
    }
  } else {
    Src0LoRM = legalize(loOperand(Src0), Legal_Reg | Legal_Mem);
    Src0HiRM = legalize(hiOperand(Src0), Legal_Reg | Legal_Mem);
  }
  // Optimize comparisons with zero.
  if (isZero(Src1)) {
    Constant *SignMask = Ctx->getConstantInt32(0x80000000);
    Variable *Temp = nullptr;
    switch (Condition) {
    default:
      llvm_unreachable("unexpected condition");
      break;
    case InstIcmp::Eq:
    case InstIcmp::Ule:
      // Mov Src0HiRM first, because it was legalized most recently, and will
      // sometimes avoid a move before the OR.
      _mov(Temp, Src0HiRM);
      _or(Temp, Src0LoRM);
      Context.insert<InstFakeUse>(Temp);
      setccOrConsumer(Traits::Cond::Br_e, Dest, Consumer);
      return;
    case InstIcmp::Ne:
    case InstIcmp::Ugt:
      // Mov Src0HiRM first, because it was legalized most recently, and will
      // sometimes avoid a move before the OR.
      _mov(Temp, Src0HiRM);
      _or(Temp, Src0LoRM);
      Context.insert<InstFakeUse>(Temp);
      setccOrConsumer(Traits::Cond::Br_ne, Dest, Consumer);
      return;
    case InstIcmp::Uge:
      movOrConsumer(true, Dest, Consumer);
      return;
    case InstIcmp::Ult:
      movOrConsumer(false, Dest, Consumer);
      return;
    case InstIcmp::Sgt:
      break;
    case InstIcmp::Sge:
      _test(Src0HiRM, SignMask);
      setccOrConsumer(Traits::Cond::Br_e, Dest, Consumer);
      return;
    case InstIcmp::Slt:
      _test(Src0HiRM, SignMask);
      setccOrConsumer(Traits::Cond::Br_ne, Dest, Consumer);
      return;
    case InstIcmp::Sle:
      break;
    }
  }
  // Handle general compares.
  Operand *Src1LoRI = legalize(loOperand(Src1), Legal_Reg | Legal_Imm);
  Operand *Src1HiRI = legalize(hiOperand(Src1), Legal_Reg | Legal_Imm);
  if (Consumer == nullptr) {
    Constant *Zero = Ctx->getConstantInt(Dest->getType(), 0);
    Constant *One = Ctx->getConstantInt(Dest->getType(), 1);
    InstX86Label *LabelFalse = InstX86Label::create(Func, this);
    InstX86Label *LabelTrue = InstX86Label::create(Func, this);
    _mov(Dest, One);
    _cmp(Src0HiRM, Src1HiRI);
    if (Traits::TableIcmp64[Condition].C1 != Traits::Cond::Br_None)
      _br(Traits::TableIcmp64[Condition].C1, LabelTrue);
    if (Traits::TableIcmp64[Condition].C2 != Traits::Cond::Br_None)
      _br(Traits::TableIcmp64[Condition].C2, LabelFalse);
    _cmp(Src0LoRM, Src1LoRI);
    _br(Traits::TableIcmp64[Condition].C3, LabelTrue);
    Context.insert(LabelFalse);
    _redefined(_mov(Dest, Zero));
    Context.insert(LabelTrue);
    return;
  }
  if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
    _cmp(Src0HiRM, Src1HiRI);
    if (Traits::TableIcmp64[Condition].C1 != Traits::Cond::Br_None)
      _br(Traits::TableIcmp64[Condition].C1, Br->getTargetTrue());
    if (Traits::TableIcmp64[Condition].C2 != Traits::Cond::Br_None)
      _br(Traits::TableIcmp64[Condition].C2, Br->getTargetFalse());
    _cmp(Src0LoRM, Src1LoRI);
    _br(Traits::TableIcmp64[Condition].C3, Br->getTargetTrue(),
        Br->getTargetFalse());
    return;
  }
  if (auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
    Operand *SrcT = Select->getTrueOperand();
    Operand *SrcF = Select->getFalseOperand();
    Variable *SelectDest = Select->getDest();
    InstX86Label *LabelFalse = InstX86Label::create(Func, this);
    InstX86Label *LabelTrue = InstX86Label::create(Func, this);
    lowerMove(SelectDest, SrcT, false);
    _cmp(Src0HiRM, Src1HiRI);
    if (Traits::TableIcmp64[Condition].C1 != Traits::Cond::Br_None)
      _br(Traits::TableIcmp64[Condition].C1, LabelTrue);
    if (Traits::TableIcmp64[Condition].C2 != Traits::Cond::Br_None)
      _br(Traits::TableIcmp64[Condition].C2, LabelFalse);
    _cmp(Src0LoRM, Src1LoRI);
    _br(Traits::TableIcmp64[Condition].C3, LabelTrue);
    Context.insert(LabelFalse);
    static constexpr bool IsRedefinition = true;
    lowerMove(SelectDest, SrcF, IsRedefinition);
    Context.insert(LabelTrue);
    return;
  }
  llvm::report_fatal_error("Unexpected consumer type");
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::setccOrConsumer(BrCond Condition,
                                                Variable *Dest,
                                                const Inst *Consumer) {
  if (Consumer == nullptr) {
    _setcc(Dest, Condition);
    return;
  }
  if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
    _br(Condition, Br->getTargetTrue(), Br->getTargetFalse());
    return;
  }
  if (const auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
    Operand *SrcT = Select->getTrueOperand();
    Operand *SrcF = Select->getFalseOperand();
    Variable *SelectDest = Select->getDest();
    lowerSelectMove(SelectDest, Condition, SrcT, SrcF);
    return;
  }
  llvm::report_fatal_error("Unexpected consumer type");
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::movOrConsumer(bool IcmpResult, Variable *Dest,
                                              const Inst *Consumer) {
  if (Consumer == nullptr) {
    _mov(Dest, Ctx->getConstantInt(Dest->getType(), (IcmpResult ? 1 : 0)));
    return;
  }
  if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
    // TODO(sehr,stichnot): This could be done with a single unconditional
    // branch instruction, but subzero doesn't know how to handle the resulting
    // control flow graph changes now.  Make it do so to eliminate mov and cmp.
    _mov(Dest, Ctx->getConstantInt(Dest->getType(), (IcmpResult ? 1 : 0)));
    _cmp(Dest, Ctx->getConstantInt(Dest->getType(), 0));
    _br(Traits::Cond::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
    return;
  }
  if (const auto *Select = llvm::dyn_cast<InstSelect>(Consumer)) {
    Operand *Src = nullptr;
    if (IcmpResult) {
      Src = legalize(Select->getTrueOperand(), Legal_Reg | Legal_Imm);
    } else {
      Src = legalize(Select->getFalseOperand(), Legal_Reg | Legal_Imm);
    }
    Variable *SelectDest = Select->getDest();
    lowerMove(SelectDest, Src, false);
    return;
  }
  llvm::report_fatal_error("Unexpected consumer type");
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerArithAndConsumer(
    const InstArithmetic *Arith, const Inst *Consumer) {
  Variable *T = nullptr;
  Operand *Src0 = legalize(Arith->getSrc(0));
  Operand *Src1 = legalize(Arith->getSrc(1));
  Variable *Dest = Arith->getDest();
  switch (Arith->getOp()) {
  default:
    llvm_unreachable("arithmetic operator not AND or OR");
    break;
  case InstArithmetic::And:
    _mov(T, Src0);
    // Test cannot have an address in the second position.  Since T is
    // guaranteed to be a register and Src1 could be a memory load, ensure
    // that the second argument is a register.
    if (llvm::isa<Constant>(Src1))
      _test(T, Src1);
    else
      _test(Src1, T);
    break;
  case InstArithmetic::Or:
    _mov(T, Src0);
    _or(T, Src1);
    break;
  }

  if (Consumer == nullptr) {
    llvm::report_fatal_error("Expected a consumer instruction");
  }
  if (const auto *Br = llvm::dyn_cast<InstBr>(Consumer)) {
    Context.insert<InstFakeUse>(T);
    Context.insert<InstFakeDef>(Dest);
    _br(Traits::Cond::Br_ne, Br->getTargetTrue(), Br->getTargetFalse());
    return;
  }
  llvm::report_fatal_error("Unexpected consumer type");
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerInsertElement(
    const InstInsertElement *Instr) {
  Operand *SourceVectNotLegalized = Instr->getSrc(0);
  Operand *ElementToInsertNotLegalized = Instr->getSrc(1);
  auto *ElementIndex = llvm::dyn_cast<ConstantInteger32>(Instr->getSrc(2));
  // Only constant indices are allowed in PNaCl IR.
  assert(ElementIndex);
  unsigned Index = ElementIndex->getValue();
  assert(Index < typeNumElements(SourceVectNotLegalized->getType()));

  Type Ty = SourceVectNotLegalized->getType();
  Type ElementTy = typeElementType(Ty);
  Type InVectorElementTy = Traits::getInVectorElementType(Ty);

  if (ElementTy == IceType_i1) {
    // Expand the element to the appropriate size for it to be inserted in the
    // vector.
    Variable *Expanded = Func->makeVariable(InVectorElementTy);
    auto *Cast = InstCast::create(Func, InstCast::Zext, Expanded,
                                  ElementToInsertNotLegalized);
    lowerCast(Cast);
    ElementToInsertNotLegalized = Expanded;
  }

  if (Ty == IceType_v8i16 || Ty == IceType_v8i1 ||
      InstructionSet >= Traits::SSE4_1) {
    // Use insertps, pinsrb, pinsrw, or pinsrd.
    Operand *ElementRM =
        legalize(ElementToInsertNotLegalized, Legal_Reg | Legal_Mem);
    Operand *SourceVectRM =
        legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem);
    Variable *T = makeReg(Ty);
    _movp(T, SourceVectRM);
    if (Ty == IceType_v4f32) {
      _insertps(T, ElementRM, Ctx->getConstantInt32(Index << 4));
    } else {
      // For the pinsrb and pinsrw instructions, when the source operand is a
      // register, it must be a full r32 register like eax, and not ax/al/ah.
      // For filetype=asm, InstX86Pinsr<TraitsType>::emit() compensates for
      // the use
      // of r16 and r8 by converting them through getBaseReg(), while emitIAS()
      // validates that the original and base register encodings are the same.
      if (ElementRM->getType() == IceType_i8 &&
          llvm::isa<Variable>(ElementRM)) {
        // Don't use ah/bh/ch/dh for pinsrb.
        ElementRM = copyToReg8(ElementRM);
      }
      _pinsr(T, ElementRM, Ctx->getConstantInt32(Index));
    }
    _movp(Instr->getDest(), T);
  } else if (Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v4i1) {
    // Use shufps or movss.
    Variable *ElementR = nullptr;
    Operand *SourceVectRM =
        legalize(SourceVectNotLegalized, Legal_Reg | Legal_Mem);

    if (InVectorElementTy == IceType_f32) {
      // ElementR will be in an XMM register since it is floating point.
      ElementR = legalizeToReg(ElementToInsertNotLegalized);
    } else {
      // Copy an integer to an XMM register.
      Operand *T = legalize(ElementToInsertNotLegalized, Legal_Reg | Legal_Mem);
      ElementR = makeReg(Ty);
      _movd(ElementR, T);
    }

    if (Index == 0) {
      Variable *T = makeReg(Ty);
      _movp(T, SourceVectRM);
      _movss(T, ElementR);
      _movp(Instr->getDest(), T);
      return;
    }

    // shufps treats the source and destination operands as vectors of four
    // doublewords. The destination's two high doublewords are selected from
    // the source operand and the two low doublewords are selected from the
    // (original value of) the destination operand. An insertelement operation
    // can be effected with a sequence of two shufps operations with
    // appropriate masks. In all cases below, Element[0] is being inserted into
    // SourceVectOperand. Indices are ordered from left to right.
    //
    // insertelement into index 1 (result is stored in ElementR):
    //   ElementR := ElementR[0, 0] SourceVectRM[0, 0]
    //   ElementR := ElementR[3, 0] SourceVectRM[2, 3]
    //
    // insertelement into index 2 (result is stored in T):
    //   T := SourceVectRM
    //   ElementR := ElementR[0, 0] T[0, 3]
    //   T := T[0, 1] ElementR[0, 3]
    //
    // insertelement into index 3 (result is stored in T):
    //   T := SourceVectRM
    //   ElementR := ElementR[0, 0] T[0, 2]
    //   T := T[0, 1] ElementR[3, 0]
    const unsigned char Mask1[3] = {0, 192, 128};
    const unsigned char Mask2[3] = {227, 196, 52};

    Constant *Mask1Constant = Ctx->getConstantInt32(Mask1[Index - 1]);
    Constant *Mask2Constant = Ctx->getConstantInt32(Mask2[Index - 1]);

    if (Index == 1) {
      _shufps(ElementR, SourceVectRM, Mask1Constant);
      _shufps(ElementR, SourceVectRM, Mask2Constant);
      _movp(Instr->getDest(), ElementR);
    } else {
      Variable *T = makeReg(Ty);
      _movp(T, SourceVectRM);
      _shufps(ElementR, T, Mask1Constant);
      _shufps(T, ElementR, Mask2Constant);
      _movp(Instr->getDest(), T);
    }
  } else {
    assert(Ty == IceType_v16i8 || Ty == IceType_v16i1);
    // Spill the value to a stack slot and perform the insertion in memory.
    //
    // TODO(wala): use legalize(SourceVectNotLegalized, Legal_Mem) when support
    // for legalizing to mem is implemented.
    Variable *Slot = Func->makeVariable(Ty);
    Slot->setMustNotHaveReg();
    _movp(Slot, legalizeToReg(SourceVectNotLegalized));

    // Compute the location of the position to insert in memory.
    unsigned Offset = Index * typeWidthInBytes(InVectorElementTy);
    X86OperandMem *Loc =
        getMemoryOperandForStackSlot(InVectorElementTy, Slot, Offset);
    _store(legalizeToReg(ElementToInsertNotLegalized), Loc);

    Variable *T = makeReg(Ty);
    _movp(T, Slot);
    _movp(Instr->getDest(), T);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerIntrinsicCall(
    const InstIntrinsicCall *Instr) {
  switch (Intrinsics::IntrinsicID ID = Instr->getIntrinsicInfo().ID) {
  case Intrinsics::AtomicCmpxchg: {
    if (!Intrinsics::isMemoryOrderValid(
            ID, getConstantMemoryOrder(Instr->getArg(3)),
            getConstantMemoryOrder(Instr->getArg(4)))) {
      Func->setError("Unexpected memory ordering for AtomicCmpxchg");
      return;
    }
    Variable *DestPrev = Instr->getDest();
    Operand *PtrToMem = legalize(Instr->getArg(0));
    Operand *Expected = legalize(Instr->getArg(1));
    Operand *Desired = legalize(Instr->getArg(2));
    if (tryOptimizedCmpxchgCmpBr(DestPrev, PtrToMem, Expected, Desired))
      return;
    lowerAtomicCmpxchg(DestPrev, PtrToMem, Expected, Desired);
    return;
  }
  case Intrinsics::AtomicFence:
    if (!Intrinsics::isMemoryOrderValid(
            ID, getConstantMemoryOrder(Instr->getArg(0)))) {
      Func->setError("Unexpected memory ordering for AtomicFence");
      return;
    }
    _mfence();
    return;
  case Intrinsics::AtomicFenceAll:
    // NOTE: FenceAll should prevent and load/store from being moved across the
    // fence (both atomic and non-atomic). The InstX8632Mfence instruction is
    // currently marked coarsely as "HasSideEffects".
    _mfence();
    return;
  case Intrinsics::AtomicIsLockFree: {
    // X86 is always lock free for 8/16/32/64 bit accesses.
    // TODO(jvoung): Since the result is constant when given a constant byte
    // size, this opens up DCE opportunities.
    Operand *ByteSize = Instr->getArg(0);
    Variable *Dest = Instr->getDest();
    if (auto *CI = llvm::dyn_cast<ConstantInteger32>(ByteSize)) {
      Constant *Result;
      switch (CI->getValue()) {
      default:
        // Some x86-64 processors support the cmpxchg16b instruction, which can
        // make 16-byte operations lock free (when used with the LOCK prefix).
        // However, that's not supported in 32-bit mode, so just return 0 even
        // for large sizes.
        Result = Ctx->getConstantZero(IceType_i32);
        break;
      case 1:
      case 2:
      case 4:
      case 8:
        Result = Ctx->getConstantInt32(1);
        break;
      }
      _mov(Dest, Result);
      return;
    }
    // The PNaCl ABI requires the byte size to be a compile-time constant.
    Func->setError("AtomicIsLockFree byte size should be compile-time const");
    return;
  }
  case Intrinsics::AtomicLoad: {
    // We require the memory address to be naturally aligned. Given that is the
    // case, then normal loads are atomic.
    if (!Intrinsics::isMemoryOrderValid(
            ID, getConstantMemoryOrder(Instr->getArg(1)))) {
      Func->setError("Unexpected memory ordering for AtomicLoad");
      return;
    }
    Variable *Dest = Instr->getDest();
    if (!Traits::Is64Bit) {
      if (auto *Dest64On32 = llvm::dyn_cast<Variable64On32>(Dest)) {
        // Follow what GCC does and use a movq instead of what lowerLoad()
        // normally does (split the load into two). Thus, this skips
        // load/arithmetic op folding. Load/arithmetic folding can't happen
        // anyway, since this is x86-32 and integer arithmetic only happens on
        // 32-bit quantities.
        Variable *T = makeReg(IceType_f64);
        X86OperandMem *Addr = formMemoryOperand(Instr->getArg(0), IceType_f64);
        _movq(T, Addr);
        // Then cast the bits back out of the XMM register to the i64 Dest.
        auto *Cast = InstCast::create(Func, InstCast::Bitcast, Dest, T);
        lowerCast(Cast);
        // Make sure that the atomic load isn't elided when unused.
        Context.insert<InstFakeUse>(Dest64On32->getLo());
        Context.insert<InstFakeUse>(Dest64On32->getHi());
        return;
      }
    }
    auto *Load = InstLoad::create(Func, Dest, Instr->getArg(0));
    lowerLoad(Load);
    // Make sure the atomic load isn't elided when unused, by adding a FakeUse.
    // Since lowerLoad may fuse the load w/ an arithmetic instruction, insert
    // the FakeUse on the last-inserted instruction's dest.
    Context.insert<InstFakeUse>(Context.getLastInserted()->getDest());
    return;
  }
  case Intrinsics::AtomicRMW:
    if (!Intrinsics::isMemoryOrderValid(
            ID, getConstantMemoryOrder(Instr->getArg(3)))) {
      Func->setError("Unexpected memory ordering for AtomicRMW");
      return;
    }
    lowerAtomicRMW(
        Instr->getDest(),
        static_cast<uint32_t>(
            llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()),
        Instr->getArg(1), Instr->getArg(2));
    return;
  case Intrinsics::AtomicStore: {
    if (!Intrinsics::isMemoryOrderValid(
            ID, getConstantMemoryOrder(Instr->getArg(2)))) {
      Func->setError("Unexpected memory ordering for AtomicStore");
      return;
    }
    // We require the memory address to be naturally aligned. Given that is the
    // case, then normal stores are atomic. Add a fence after the store to make
    // it visible.
    Operand *Value = Instr->getArg(0);
    Operand *Ptr = Instr->getArg(1);
    if (!Traits::Is64Bit && Value->getType() == IceType_i64) {
      // Use a movq instead of what lowerStore() normally does (split the store
      // into two), following what GCC does. Cast the bits from int -> to an
      // xmm register first.
      Variable *T = makeReg(IceType_f64);
      auto *Cast = InstCast::create(Func, InstCast::Bitcast, T, Value);
      lowerCast(Cast);
      // Then store XMM w/ a movq.
      X86OperandMem *Addr = formMemoryOperand(Ptr, IceType_f64);
      _storeq(T, Addr);
      _mfence();
      return;
    }
    auto *Store = InstStore::create(Func, Value, Ptr);
    lowerStore(Store);
    _mfence();
    return;
  }
  case Intrinsics::Bswap: {
    Variable *Dest = Instr->getDest();
    Operand *Val = Instr->getArg(0);
    // In 32-bit mode, bswap only works on 32-bit arguments, and the argument
    // must be a register. Use rotate left for 16-bit bswap.
    if (!Traits::Is64Bit && Val->getType() == IceType_i64) {
      Val = legalizeUndef(Val);
      Variable *T_Lo = legalizeToReg(loOperand(Val));
      Variable *T_Hi = legalizeToReg(hiOperand(Val));
      auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
      auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
      _bswap(T_Lo);
      _bswap(T_Hi);
      _mov(DestLo, T_Hi);
      _mov(DestHi, T_Lo);
    } else if ((Traits::Is64Bit && Val->getType() == IceType_i64) ||
               Val->getType() == IceType_i32) {
      Variable *T = legalizeToReg(Val);
      _bswap(T);
      _mov(Dest, T);
    } else {
      assert(Val->getType() == IceType_i16);
      Constant *Eight = Ctx->getConstantInt16(8);
      Variable *T = nullptr;
      Val = legalize(Val);
      _mov(T, Val);
      _rol(T, Eight);
      _mov(Dest, T);
    }
    return;
  }
  case Intrinsics::Ctpop: {
    Variable *Dest = Instr->getDest();
    Variable *T = nullptr;
    Operand *Val = Instr->getArg(0);
    Type ValTy = Val->getType();
    assert(ValTy == IceType_i32 || ValTy == IceType_i64);

    if (!Traits::Is64Bit) {
      T = Dest;
    } else {
      T = makeReg(IceType_i64);
      if (ValTy == IceType_i32) {
        // in x86-64, __popcountsi2 is not defined, so we cheat a bit by
        // converting it to a 64-bit value, and using ctpop_i64. _movzx should
        // ensure we will not have any bits set on Val's upper 32 bits.
        Variable *V = makeReg(IceType_i64);
        Operand *ValRM = legalize(Val, Legal_Reg | Legal_Mem);
        _movzx(V, ValRM);
        Val = V;
      }
      ValTy = IceType_i64;
    }

    InstCall *Call =
        makeHelperCall(ValTy == IceType_i32 ? RuntimeHelper::H_call_ctpop_i32
                                            : RuntimeHelper::H_call_ctpop_i64,
                       T, 1);
    Call->addArg(Val);
    lowerCall(Call);
    // The popcount helpers always return 32-bit values, while the intrinsic's
    // signature matches the native POPCNT instruction and fills a 64-bit reg
    // (in 64-bit mode). Thus, clear the upper bits of the dest just in case
    // the user doesn't do that in the IR. If the user does that in the IR,
    // then this zero'ing instruction is dead and gets optimized out.
    if (!Traits::Is64Bit) {
      assert(T == Dest);
      if (Val->getType() == IceType_i64) {
        auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
        Constant *Zero = Ctx->getConstantZero(IceType_i32);
        _mov(DestHi, Zero);
      }
    } else {
      assert(Val->getType() == IceType_i64);
      // T is 64 bit. It needs to be copied to dest. We need to:
      //
      // T_1.32 = trunc T.64 to i32
      // T_2.64 = zext T_1.32 to i64
      // Dest.<<right_size>> = T_2.<<right_size>>
      //
      // which ensures the upper 32 bits will always be cleared. Just doing a
      //
      // mov Dest.32 = trunc T.32 to i32
      //
      // is dangerous because there's a chance the compiler will optimize this
      // copy out. To use _movzx we need two new registers (one 32-, and
      // another 64-bit wide.)
      Variable *T_1 = makeReg(IceType_i32);
      _mov(T_1, T);
      Variable *T_2 = makeReg(IceType_i64);
      _movzx(T_2, T_1);
      _mov(Dest, T_2);
    }
    return;
  }
  case Intrinsics::Ctlz: {
    // The "is zero undef" parameter is ignored and we always return a
    // well-defined value.
    Operand *Val = legalize(Instr->getArg(0));
    Operand *FirstVal;
    Operand *SecondVal = nullptr;
    if (!Traits::Is64Bit && Val->getType() == IceType_i64) {
      FirstVal = loOperand(Val);
      SecondVal = hiOperand(Val);
    } else {
      FirstVal = Val;
    }
    constexpr bool IsCttz = false;
    lowerCountZeros(IsCttz, Val->getType(), Instr->getDest(), FirstVal,
                    SecondVal);
    return;
  }
  case Intrinsics::Cttz: {
    // The "is zero undef" parameter is ignored and we always return a
    // well-defined value.
    Operand *Val = legalize(Instr->getArg(0));
    Operand *FirstVal;
    Operand *SecondVal = nullptr;
    if (!Traits::Is64Bit && Val->getType() == IceType_i64) {
      FirstVal = hiOperand(Val);
      SecondVal = loOperand(Val);
    } else {
      FirstVal = Val;
    }
    constexpr bool IsCttz = true;
    lowerCountZeros(IsCttz, Val->getType(), Instr->getDest(), FirstVal,
                    SecondVal);
    return;
  }
  case Intrinsics::Fabs: {
    Operand *Src = legalize(Instr->getArg(0));
    Type Ty = Src->getType();
    Variable *Dest = Instr->getDest();
    Variable *T = makeVectorOfFabsMask(Ty);
    // The pand instruction operates on an m128 memory operand, so if Src is an
    // f32 or f64, we need to make sure it's in a register.
    if (isVectorType(Ty)) {
      if (llvm::isa<X86OperandMem>(Src))
        Src = legalizeToReg(Src);
    } else {
      Src = legalizeToReg(Src);
    }
    _pand(T, Src);
    if (isVectorType(Ty))
      _movp(Dest, T);
    else
      _mov(Dest, T);
    return;
  }
  case Intrinsics::Longjmp: {
    InstCall *Call = makeHelperCall(RuntimeHelper::H_call_longjmp, nullptr, 2);
    Call->addArg(Instr->getArg(0));
    Call->addArg(Instr->getArg(1));
    lowerCall(Call);
    return;
  }
  case Intrinsics::Memcpy: {
    lowerMemcpy(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
    return;
  }
  case Intrinsics::Memmove: {
    lowerMemmove(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
    return;
  }
  case Intrinsics::Memset: {
    lowerMemset(Instr->getArg(0), Instr->getArg(1), Instr->getArg(2));
    return;
  }
  case Intrinsics::NaClReadTP: {
    if (NeedSandboxing) {
      Operand *Src =
          dispatchToConcrete(&ConcreteTarget::createNaClReadTPSrcOperand);
      Variable *Dest = Instr->getDest();
      Variable *T = nullptr;
      _mov(T, Src);
      _mov(Dest, T);
    } else {
      InstCall *Call =
          makeHelperCall(RuntimeHelper::H_call_read_tp, Instr->getDest(), 0);
      lowerCall(Call);
    }
    return;
  }
  case Intrinsics::Setjmp: {
    InstCall *Call =
        makeHelperCall(RuntimeHelper::H_call_setjmp, Instr->getDest(), 1);
    Call->addArg(Instr->getArg(0));
    lowerCall(Call);
    return;
  }
  case Intrinsics::Sqrt: {
    assert(isScalarFloatingType(Instr->getDest()->getType()) ||
           getFlags().getApplicationBinaryInterface() != ::Ice::ABI_PNaCl);
    Operand *Src = legalize(Instr->getArg(0));
    Variable *Dest = Instr->getDest();
    Variable *T = makeReg(Dest->getType());
    _sqrt(T, Src);
    _mov(Dest, T);
    return;
  }
  case Intrinsics::Stacksave: {
    if (!Traits::Is64Bit || !NeedSandboxing) {
      Variable *esp = Func->getTarget()->getPhysicalRegister(getStackReg(),
                                                             Traits::WordType);
      Variable *Dest = Instr->getDest();
      _mov(Dest, esp);
      return;
    }
    Variable *esp = Func->getTarget()->getPhysicalRegister(
        Traits::RegisterSet::Reg_esp, IceType_i32);
    Variable *Dest = Instr->getDest();
    _mov(Dest, esp);

    return;
  }
  case Intrinsics::Stackrestore: {
    Operand *Src = Instr->getArg(0);
    _mov_sp(Src);
    return;
  }

  case Intrinsics::Trap:
    _ud2();
    return;
  case Intrinsics::LoadSubVector: {
    assert(llvm::isa<ConstantInteger32>(Instr->getArg(1)) &&
           "LoadSubVector second argument must be a constant");
    Variable *Dest = Instr->getDest();
    Type Ty = Dest->getType();
    auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(1));
    Operand *Addr = Instr->getArg(0);
    X86OperandMem *Src = formMemoryOperand(Addr, Ty);
    doMockBoundsCheck(Src);

    if (Dest->isRematerializable()) {
      Context.insert<InstFakeDef>(Dest);
      return;
    }

    auto *T = makeReg(Ty);
    switch (SubVectorSize->getValue()) {
    case 4:
      _movd(T, Src);
      break;
    case 8:
      _movq(T, Src);
      break;
    default:
      Func->setError("Unexpected size for LoadSubVector");
      return;
    }
    _movp(Dest, T);
    return;
  }
  case Intrinsics::StoreSubVector: {
    assert(llvm::isa<ConstantInteger32>(Instr->getArg(2)) &&
           "StoreSubVector third argument must be a constant");
    auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(2));
    Operand *Value = Instr->getArg(0);
    Operand *Addr = Instr->getArg(1);
    X86OperandMem *NewAddr = formMemoryOperand(Addr, Value->getType());
    doMockBoundsCheck(NewAddr);

    Value = legalizeToReg(Value);

    switch (SubVectorSize->getValue()) {
    case 4:
      _stored(Value, NewAddr);
      break;
    case 8:
      _storeq(Value, NewAddr);
      break;
    default:
      Func->setError("Unexpected size for StoreSubVector");
      return;
    }
    return;
  }
  case Intrinsics::VectorPackSigned: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Src0->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _packss(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::VectorPackUnsigned: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Src0->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _packus(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::SignMask: {
    Operand *SrcReg = legalizeToReg(Instr->getArg(0));
    Variable *Dest = Instr->getDest();
    Variable *T = makeReg(IceType_i32);
    if (SrcReg->getType() == IceType_v4f32 ||
        SrcReg->getType() == IceType_v4i32 ||
        SrcReg->getType() == IceType_v16i8) {
      _movmsk(T, SrcReg);
    } else {
      // TODO(capn): We could implement v8i16 sign mask using packsswb/pmovmskb
      llvm::report_fatal_error("Invalid type for SignMask intrinsic");
    }
    _mov(Dest, T);
    return;
  }
  case Intrinsics::MultiplyHighSigned: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Dest->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _pmulhw(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::MultiplyHighUnsigned: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Dest->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _pmulhuw(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::MultiplyAddPairs: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Dest->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _pmaddwd(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::AddSaturateSigned: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Dest->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _padds(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::SubtractSaturateSigned: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Dest->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _psubs(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::AddSaturateUnsigned: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Dest->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _paddus(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::SubtractSaturateUnsigned: {
    Operand *Src0 = Instr->getArg(0);
    Operand *Src1 = Instr->getArg(1);
    Variable *Dest = Instr->getDest();
    auto *T = makeReg(Dest->getType());
    auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T, Src0RM);
    _psubus(T, Src1RM);
    _movp(Dest, T);
    return;
  }
  case Intrinsics::Nearbyint: {
    Operand *Src = Instr->getArg(0);
    Variable *Dest = Instr->getDest();
    Type DestTy = Dest->getType();
    if (isVectorType(DestTy)) {
      assert(DestTy == IceType_v4i32);
      assert(Src->getType() == IceType_v4f32);
      Operand *Src0R = legalizeToReg(Src);
      Variable *T = makeReg(DestTy);
      _cvt(T, Src0R, Traits::Insts::Cvt::Ps2dq);
      _movp(Dest, T);
    } else if (!Traits::Is64Bit && DestTy == IceType_i64) {
      llvm::report_fatal_error("Helper call was expected");
    } else {
      Operand *Src0RM = legalize(Src, Legal_Reg | Legal_Mem);
      // t1.i32 = cvt Src0RM; t2.dest_type = t1; Dest = t2.dest_type
      Variable *T_1 = nullptr;
      if (Traits::Is64Bit && DestTy == IceType_i64) {
        T_1 = makeReg(IceType_i64);
      } else {
        assert(DestTy != IceType_i64);
        T_1 = makeReg(IceType_i32);
      }
      // cvt() requires its integer argument to be a GPR.
      Variable *T_2 = makeReg(DestTy);
      if (isByteSizedType(DestTy)) {
        assert(T_1->getType() == IceType_i32);
        T_1->setRegClass(RCX86_Is32To8);
        T_2->setRegClass(RCX86_IsTrunc8Rcvr);
      }
      _cvt(T_1, Src0RM, Traits::Insts::Cvt::Ss2si);
      _mov(T_2, T_1); // T_1 and T_2 may have different integer types
      if (DestTy == IceType_i1)
        _and(T_2, Ctx->getConstantInt1(1));
      _mov(Dest, T_2);
    }
    return;
  }
  case Intrinsics::Round: {
    assert(InstructionSet >= Traits::SSE4_1);
    Variable *Dest = Instr->getDest();
    Operand *Src = Instr->getArg(0);
    Operand *Mode = Instr->getArg(1);
    assert(llvm::isa<ConstantInteger32>(Mode) &&
           "Round last argument must be a constant");
    auto *SrcRM = legalize(Src, Legal_Reg | Legal_Mem);
    int32_t Imm = llvm::cast<ConstantInteger32>(Mode)->getValue();
    (void)Imm;
    assert(Imm >= 0 && Imm < 4 && "Invalid rounding mode");
    auto *T = makeReg(Dest->getType());
    _round(T, SrcRM, Mode);
    _movp(Dest, T);
    return;
  }
  default: // UnknownIntrinsic
    Func->setError("Unexpected intrinsic");
    return;
  }
  return;
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerAtomicCmpxchg(Variable *DestPrev,
                                                   Operand *Ptr,
                                                   Operand *Expected,
                                                   Operand *Desired) {
  Type Ty = Expected->getType();
  if (!Traits::Is64Bit && Ty == IceType_i64) {
    // Reserve the pre-colored registers first, before adding any more
    // infinite-weight variables from formMemoryOperand's legalization.
    Variable *T_edx = makeReg(IceType_i32, Traits::RegisterSet::Reg_edx);
    Variable *T_eax = makeReg(IceType_i32, Traits::RegisterSet::Reg_eax);
    Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx);
    Variable *T_ebx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ebx);
    _mov(T_eax, loOperand(Expected));
    _mov(T_edx, hiOperand(Expected));
    _mov(T_ebx, loOperand(Desired));
    _mov(T_ecx, hiOperand(Desired));
    X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
    constexpr bool Locked = true;
    _cmpxchg8b(Addr, T_edx, T_eax, T_ecx, T_ebx, Locked);
    auto *DestLo = llvm::cast<Variable>(loOperand(DestPrev));
    auto *DestHi = llvm::cast<Variable>(hiOperand(DestPrev));
    _mov(DestLo, T_eax);
    _mov(DestHi, T_edx);
    return;
  }
  RegNumT Eax;
  switch (Ty) {
  default:
    llvm::report_fatal_error("Bad type for cmpxchg");
  case IceType_i64:
    Eax = Traits::getRaxOrDie();
    break;
  case IceType_i32:
    Eax = Traits::RegisterSet::Reg_eax;
    break;
  case IceType_i16:
    Eax = Traits::RegisterSet::Reg_ax;
    break;
  case IceType_i8:
    Eax = Traits::RegisterSet::Reg_al;
    break;
  }
  Variable *T_eax = makeReg(Ty, Eax);
  _mov(T_eax, Expected);
  X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
  Variable *DesiredReg = legalizeToReg(Desired);
  constexpr bool Locked = true;
  _cmpxchg(Addr, T_eax, DesiredReg, Locked);
  _mov(DestPrev, T_eax);
}

template <typename TraitsType>
bool TargetX86Base<TraitsType>::tryOptimizedCmpxchgCmpBr(Variable *Dest,
                                                         Operand *PtrToMem,
                                                         Operand *Expected,
                                                         Operand *Desired) {
  if (Func->getOptLevel() == Opt_m1)
    return false;
  // Peek ahead a few instructions and see how Dest is used.
  // It's very common to have:
  //
  // %x = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* ptr, i32 %expected, ...)
  // [%y_phi = ...] // list of phi stores
  // %p = icmp eq i32 %x, %expected
  // br i1 %p, label %l1, label %l2
  //
  // which we can optimize into:
  //
  // %x = <cmpxchg code>
  // [%y_phi = ...] // list of phi stores
  // br eq, %l1, %l2
  InstList::iterator I = Context.getCur();
  // I is currently the InstIntrinsicCall. Peek past that.
  // This assumes that the atomic cmpxchg has not been lowered yet,
  // so that the instructions seen in the scan from "Cur" is simple.
  assert(llvm::isa<InstIntrinsicCall>(*I));
  Inst *NextInst = Context.getNextInst(I);
  if (!NextInst)
    return false;
  // There might be phi assignments right before the compare+branch, since this
  // could be a backward branch for a loop. This placement of assignments is
  // determined by placePhiStores().
  CfgVector<InstAssign *> PhiAssigns;
  while (auto *PhiAssign = llvm::dyn_cast<InstAssign>(NextInst)) {
    if (PhiAssign->getDest() == Dest)
      return false;
    PhiAssigns.push_back(PhiAssign);
    NextInst = Context.getNextInst(I);
    if (!NextInst)
      return false;
  }
  if (auto *NextCmp = llvm::dyn_cast<InstIcmp>(NextInst)) {
    if (!(NextCmp->getCondition() == InstIcmp::Eq &&
          ((NextCmp->getSrc(0) == Dest && NextCmp->getSrc(1) == Expected) ||
           (NextCmp->getSrc(1) == Dest && NextCmp->getSrc(0) == Expected)))) {
      return false;
    }
    NextInst = Context.getNextInst(I);
    if (!NextInst)
      return false;
    if (auto *NextBr = llvm::dyn_cast<InstBr>(NextInst)) {
      if (!NextBr->isUnconditional() &&
          NextCmp->getDest() == NextBr->getCondition() &&
          NextBr->isLastUse(NextCmp->getDest())) {
        lowerAtomicCmpxchg(Dest, PtrToMem, Expected, Desired);
        for (size_t i = 0; i < PhiAssigns.size(); ++i) {
          // Lower the phi assignments now, before the branch (same placement
          // as before).
          InstAssign *PhiAssign = PhiAssigns[i];
          PhiAssign->setDeleted();
          lowerAssign(PhiAssign);
          Context.advanceNext();
        }
        _br(Traits::Cond::Br_e, NextBr->getTargetTrue(),
            NextBr->getTargetFalse());
        // Skip over the old compare and branch, by deleting them.
        NextCmp->setDeleted();
        NextBr->setDeleted();
        Context.advanceNext();
        Context.advanceNext();
        return true;
      }
    }
  }
  return false;
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerAtomicRMW(Variable *Dest,
                                               uint32_t Operation, Operand *Ptr,
                                               Operand *Val) {
  bool NeedsCmpxchg = false;
  LowerBinOp Op_Lo = nullptr;
  LowerBinOp Op_Hi = nullptr;
  switch (Operation) {
  default:
    Func->setError("Unknown AtomicRMW operation");
    return;
  case Intrinsics::AtomicAdd: {
    if (!Traits::Is64Bit && Dest->getType() == IceType_i64) {
      // All the fall-through paths must set this to true, but use this
      // for asserting.
      NeedsCmpxchg = true;
      Op_Lo = &TargetX86Base<TraitsType>::_add;
      Op_Hi = &TargetX86Base<TraitsType>::_adc;
      break;
    }
    X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
    constexpr bool Locked = true;
    Variable *T = nullptr;
    _mov(T, Val);
    _xadd(Addr, T, Locked);
    _mov(Dest, T);
    return;
  }
  case Intrinsics::AtomicSub: {
    if (!Traits::Is64Bit && Dest->getType() == IceType_i64) {
      NeedsCmpxchg = true;
      Op_Lo = &TargetX86Base<TraitsType>::_sub;
      Op_Hi = &TargetX86Base<TraitsType>::_sbb;
      break;
    }
    X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
    constexpr bool Locked = true;
    Variable *T = nullptr;
    _mov(T, Val);
    _neg(T);
    _xadd(Addr, T, Locked);
    _mov(Dest, T);
    return;
  }
  case Intrinsics::AtomicOr:
    // TODO(jvoung): If Dest is null or dead, then some of these
    // operations do not need an "exchange", but just a locked op.
    // That appears to be "worth" it for sub, or, and, and xor.
    // xadd is probably fine vs lock add for add, and xchg is fine
    // vs an atomic store.
    NeedsCmpxchg = true;
    Op_Lo = &TargetX86Base<TraitsType>::_or;
    Op_Hi = &TargetX86Base<TraitsType>::_or;
    break;
  case Intrinsics::AtomicAnd:
    NeedsCmpxchg = true;
    Op_Lo = &TargetX86Base<TraitsType>::_and;
    Op_Hi = &TargetX86Base<TraitsType>::_and;
    break;
  case Intrinsics::AtomicXor:
    NeedsCmpxchg = true;
    Op_Lo = &TargetX86Base<TraitsType>::_xor;
    Op_Hi = &TargetX86Base<TraitsType>::_xor;
    break;
  case Intrinsics::AtomicExchange:
    if (!Traits::Is64Bit && Dest->getType() == IceType_i64) {
      NeedsCmpxchg = true;
      // NeedsCmpxchg, but no real Op_Lo/Op_Hi need to be done. The values
      // just need to be moved to the ecx and ebx registers.
      Op_Lo = nullptr;
      Op_Hi = nullptr;
      break;
    }
    X86OperandMem *Addr = formMemoryOperand(Ptr, Dest->getType());
    Variable *T = nullptr;
    _mov(T, Val);
    _xchg(Addr, T);
    _mov(Dest, T);
    return;
  }
  // Otherwise, we need a cmpxchg loop.
  (void)NeedsCmpxchg;
  assert(NeedsCmpxchg);
  expandAtomicRMWAsCmpxchg(Op_Lo, Op_Hi, Dest, Ptr, Val);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::expandAtomicRMWAsCmpxchg(LowerBinOp Op_Lo,
                                                         LowerBinOp Op_Hi,
                                                         Variable *Dest,
                                                         Operand *Ptr,
                                                         Operand *Val) {
  // Expand a more complex RMW operation as a cmpxchg loop:
  // For 64-bit:
  //   mov     eax, [ptr]
  //   mov     edx, [ptr + 4]
  // .LABEL:
  //   mov     ebx, eax
  //   <Op_Lo> ebx, <desired_adj_lo>
  //   mov     ecx, edx
  //   <Op_Hi> ecx, <desired_adj_hi>
  //   lock cmpxchg8b [ptr]
  //   jne     .LABEL
  //   mov     <dest_lo>, eax
  //   mov     <dest_lo>, edx
  //
  // For 32-bit:
  //   mov     eax, [ptr]
  // .LABEL:
  //   mov     <reg>, eax
  //   op      <reg>, [desired_adj]
  //   lock cmpxchg [ptr], <reg>
  //   jne     .LABEL
  //   mov     <dest>, eax
  //
  // If Op_{Lo,Hi} are nullptr, then just copy the value.
  Val = legalize(Val);
  Type Ty = Val->getType();
  if (!Traits::Is64Bit && Ty == IceType_i64) {
    Variable *T_edx = makeReg(IceType_i32, Traits::RegisterSet::Reg_edx);
    Variable *T_eax = makeReg(IceType_i32, Traits::RegisterSet::Reg_eax);
    X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
    _mov(T_eax, loOperand(Addr));
    _mov(T_edx, hiOperand(Addr));
    Variable *T_ecx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ecx);
    Variable *T_ebx = makeReg(IceType_i32, Traits::RegisterSet::Reg_ebx);
    InstX86Label *Label = InstX86Label::create(Func, this);
    const bool IsXchg8b = Op_Lo == nullptr && Op_Hi == nullptr;
    if (!IsXchg8b) {
      Context.insert(Label);
      _mov(T_ebx, T_eax);
      (this->*Op_Lo)(T_ebx, loOperand(Val));
      _mov(T_ecx, T_edx);
      (this->*Op_Hi)(T_ecx, hiOperand(Val));
    } else {
      // This is for xchg, which doesn't need an actual Op_Lo/Op_Hi.
      // It just needs the Val loaded into ebx and ecx.
      // That can also be done before the loop.
      _mov(T_ebx, loOperand(Val));
      _mov(T_ecx, hiOperand(Val));
      Context.insert(Label);
    }
    constexpr bool Locked = true;
    _cmpxchg8b(Addr, T_edx, T_eax, T_ecx, T_ebx, Locked);
    _br(Traits::Cond::Br_ne, Label);
    if (!IsXchg8b) {
      // If Val is a variable, model the extended live range of Val through
      // the end of the loop, since it will be re-used by the loop.
      if (auto *ValVar = llvm::dyn_cast<Variable>(Val)) {
        auto *ValLo = llvm::cast<Variable>(loOperand(ValVar));
        auto *ValHi = llvm::cast<Variable>(hiOperand(ValVar));
        Context.insert<InstFakeUse>(ValLo);
        Context.insert<InstFakeUse>(ValHi);
      }
    } else {
      // For xchg, the loop is slightly smaller and ebx/ecx are used.
      Context.insert<InstFakeUse>(T_ebx);
      Context.insert<InstFakeUse>(T_ecx);
    }
    // The address base (if any) is also reused in the loop.
    if (Variable *Base = Addr->getBase())
      Context.insert<InstFakeUse>(Base);
    auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
    auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
    _mov(DestLo, T_eax);
    _mov(DestHi, T_edx);
    return;
  }
  X86OperandMem *Addr = formMemoryOperand(Ptr, Ty);
  RegNumT Eax;
  switch (Ty) {
  default:
    llvm::report_fatal_error("Bad type for atomicRMW");
  case IceType_i64:
    Eax = Traits::getRaxOrDie();
    break;
  case IceType_i32:
    Eax = Traits::RegisterSet::Reg_eax;
    break;
  case IceType_i16:
    Eax = Traits::RegisterSet::Reg_ax;
    break;
  case IceType_i8:
    Eax = Traits::RegisterSet::Reg_al;
    break;
  }
  Variable *T_eax = makeReg(Ty, Eax);
  _mov(T_eax, Addr);
  auto *Label = Context.insert<InstX86Label>(this);
  // We want to pick a different register for T than Eax, so don't use
  // _mov(T == nullptr, T_eax).
  Variable *T = makeReg(Ty);
  _mov(T, T_eax);
  (this->*Op_Lo)(T, Val);
  constexpr bool Locked = true;
  _cmpxchg(Addr, T_eax, T, Locked);
  _br(Traits::Cond::Br_ne, Label);
  // If Val is a variable, model the extended live range of Val through
  // the end of the loop, since it will be re-used by the loop.
  if (auto *ValVar = llvm::dyn_cast<Variable>(Val)) {
    Context.insert<InstFakeUse>(ValVar);
  }
  // The address base (if any) is also reused in the loop.
  if (Variable *Base = Addr->getBase())
    Context.insert<InstFakeUse>(Base);
  _mov(Dest, T_eax);
}

/// Lowers count {trailing, leading} zeros intrinsic.
///
/// We could do constant folding here, but that should have
/// been done by the front-end/middle-end optimizations.
template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerCountZeros(bool Cttz, Type Ty,
                                                Variable *Dest,
                                                Operand *FirstVal,
                                                Operand *SecondVal) {
  // TODO(jvoung): Determine if the user CPU supports LZCNT (BMI).
  // Then the instructions will handle the Val == 0 case much more simply
  // and won't require conversion from bit position to number of zeros.
  //
  // Otherwise:
  //   bsr IF_NOT_ZERO, Val
  //   mov T_DEST, ((Ty == i32) ? 63 : 127)
  //   cmovne T_DEST, IF_NOT_ZERO
  //   xor T_DEST, ((Ty == i32) ? 31 : 63)
  //   mov DEST, T_DEST
  //
  // NOTE: T_DEST must be a register because cmov requires its dest to be a
  // register. Also, bsf and bsr require their dest to be a register.
  //
  // The xor DEST, C(31|63) converts a bit position to # of leading zeroes.
  // E.g., for 000... 00001100, bsr will say that the most significant bit
  // set is at position 3, while the number of leading zeros is 28. Xor is
  // like (M - N) for N <= M, and converts 63 to 32, and 127 to 64 (for the
  // all-zeros case).
  //
  // X8632 only: Similar for 64-bit, but start w/ speculating that the upper 32
  // bits are all zero, and compute the result for that case (checking the
  // lower 32 bits). Then actually compute the result for the upper bits and
  // cmov in the result from the lower computation if the earlier speculation
  // was correct.
  //
  // Cttz, is similar, but uses bsf instead, and doesn't require the xor
  // bit position conversion, and the speculation is reversed.

  // TODO(jpp): refactor this method.
  assert(Ty == IceType_i32 || Ty == IceType_i64);
  const Type DestTy = Traits::Is64Bit ? Dest->getType() : IceType_i32;
  Variable *T = makeReg(DestTy);
  Operand *FirstValRM = legalize(FirstVal, Legal_Mem | Legal_Reg);
  if (Cttz) {
    _bsf(T, FirstValRM);
  } else {
    _bsr(T, FirstValRM);
  }
  Variable *T_Dest = makeReg(DestTy);
  Constant *_31 = Ctx->getConstantInt32(31);
  Constant *_32 = Ctx->getConstantInt(DestTy, 32);
  Constant *_63 = Ctx->getConstantInt(DestTy, 63);
  Constant *_64 = Ctx->getConstantInt(DestTy, 64);
  if (Cttz) {
    if (DestTy == IceType_i64) {
      _mov(T_Dest, _64);
    } else {
      _mov(T_Dest, _32);
    }
  } else {
    Constant *_127 = Ctx->getConstantInt(DestTy, 127);
    if (DestTy == IceType_i64) {
      _mov(T_Dest, _127);
    } else {
      _mov(T_Dest, _63);
    }
  }
  _cmov(T_Dest, T, Traits::Cond::Br_ne);
  if (!Cttz) {
    if (DestTy == IceType_i64) {
      // Even though there's a _63 available at this point, that constant might
      // not be an i32, which will cause the xor emission to fail.
      Constant *_63 = Ctx->getConstantInt32(63);
      _xor(T_Dest, _63);
    } else {
      _xor(T_Dest, _31);
    }
  }
  if (Traits::Is64Bit || Ty == IceType_i32) {
    _mov(Dest, T_Dest);
    return;
  }
  _add(T_Dest, _32);
  auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
  auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
  // Will be using "test" on this, so we need a registerized variable.
  Variable *SecondVar = legalizeToReg(SecondVal);
  Variable *T_Dest2 = makeReg(IceType_i32);
  if (Cttz) {
    _bsf(T_Dest2, SecondVar);
  } else {
    _bsr(T_Dest2, SecondVar);
    _xor(T_Dest2, _31);
  }
  _test(SecondVar, SecondVar);
  _cmov(T_Dest2, T_Dest, Traits::Cond::Br_e);
  _mov(DestLo, T_Dest2);
  _mov(DestHi, Ctx->getConstantZero(IceType_i32));
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::typedLoad(Type Ty, Variable *Dest,
                                          Variable *Base, Constant *Offset) {
  // If Offset is a ConstantRelocatable in Non-SFI mode, we will need to
  // legalize Mem properly.
  if (Offset)
    assert(!llvm::isa<ConstantRelocatable>(Offset));

  auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);

  if (isVectorType(Ty))
    _movp(Dest, Mem);
  else if (Ty == IceType_f64)
    _movq(Dest, Mem);
  else
    _mov(Dest, Mem);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::typedStore(Type Ty, Variable *Value,
                                           Variable *Base, Constant *Offset) {
  // If Offset is a ConstantRelocatable in Non-SFI mode, we will need to
  // legalize Mem properly.
  if (Offset)
    assert(!llvm::isa<ConstantRelocatable>(Offset));

  auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);

  if (isVectorType(Ty))
    _storep(Value, Mem);
  else if (Ty == IceType_f64)
    _storeq(Value, Mem);
  else
    _store(Value, Mem);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::copyMemory(Type Ty, Variable *Dest,
                                           Variable *Src, int32_t OffsetAmt) {
  Constant *Offset = OffsetAmt ? Ctx->getConstantInt32(OffsetAmt) : nullptr;
  // TODO(ascull): this or add nullptr test to _movp, _movq
  Variable *Data = makeReg(Ty);

  typedLoad(Ty, Data, Src, Offset);
  typedStore(Ty, Data, Dest, Offset);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerMemcpy(Operand *Dest, Operand *Src,
                                            Operand *Count) {
  // There is a load and store for each chunk in the unroll
  constexpr uint32_t BytesPerStorep = 16;

  // Check if the operands are constants
  const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
  const bool IsCountConst = CountConst != nullptr;
  const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;

  if (shouldOptimizeMemIntrins() && IsCountConst &&
      CountValue <= BytesPerStorep * Traits::MEMCPY_UNROLL_LIMIT) {
    // Unlikely, but nothing to do if it does happen
    if (CountValue == 0)
      return;

    Variable *SrcBase = legalizeToReg(Src);
    Variable *DestBase = legalizeToReg(Dest);

    // Find the largest type that can be used and use it as much as possible in
    // reverse order. Then handle any remainder with overlapping copies. Since
    // the remainder will be at the end, there will be reduced pressure on the
    // memory unit as the accesses to the same memory are far apart.
    Type Ty = largestTypeInSize(CountValue);
    uint32_t TyWidth = typeWidthInBytes(Ty);

    uint32_t RemainingBytes = CountValue;
    int32_t Offset = (CountValue & ~(TyWidth - 1)) - TyWidth;
    while (RemainingBytes >= TyWidth) {
      copyMemory(Ty, DestBase, SrcBase, Offset);
      RemainingBytes -= TyWidth;
      Offset -= TyWidth;
    }

    if (RemainingBytes == 0)
      return;

    // Lower the remaining bytes. Adjust to larger types in order to make use
    // of overlaps in the copies.
    Type LeftOverTy = firstTypeThatFitsSize(RemainingBytes);
    Offset = CountValue - typeWidthInBytes(LeftOverTy);
    copyMemory(LeftOverTy, DestBase, SrcBase, Offset);
    return;
  }

  // Fall back on a function call
  InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memcpy, nullptr, 3);
  Call->addArg(Dest);
  Call->addArg(Src);
  Call->addArg(Count);
  lowerCall(Call);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerMemmove(Operand *Dest, Operand *Src,
                                             Operand *Count) {
  // There is a load and store for each chunk in the unroll
  constexpr uint32_t BytesPerStorep = 16;

  // Check if the operands are constants
  const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
  const bool IsCountConst = CountConst != nullptr;
  const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;

  if (shouldOptimizeMemIntrins() && IsCountConst &&
      CountValue <= BytesPerStorep * Traits::MEMMOVE_UNROLL_LIMIT) {
    // Unlikely, but nothing to do if it does happen
    if (CountValue == 0)
      return;

    Variable *SrcBase = legalizeToReg(Src);
    Variable *DestBase = legalizeToReg(Dest);

    std::tuple<Type, Constant *, Variable *>
        Moves[Traits::MEMMOVE_UNROLL_LIMIT];
    Constant *Offset;
    Variable *Reg;

    // Copy the data into registers as the source and destination could overlap
    // so make sure not to clobber the memory. This also means overlapping
    // moves can be used as we are taking a safe snapshot of the memory.
    Type Ty = largestTypeInSize(CountValue);
    uint32_t TyWidth = typeWidthInBytes(Ty);

    uint32_t RemainingBytes = CountValue;
    int32_t OffsetAmt = (CountValue & ~(TyWidth - 1)) - TyWidth;
    size_t N = 0;
    while (RemainingBytes >= TyWidth) {
      assert(N <= Traits::MEMMOVE_UNROLL_LIMIT);
      Offset = Ctx->getConstantInt32(OffsetAmt);
      Reg = makeReg(Ty);
      typedLoad(Ty, Reg, SrcBase, Offset);
      RemainingBytes -= TyWidth;
      OffsetAmt -= TyWidth;
      Moves[N++] = std::make_tuple(Ty, Offset, Reg);
    }

    if (RemainingBytes != 0) {
      // Lower the remaining bytes. Adjust to larger types in order to make use
      // of overlaps in the copies.
      assert(N <= Traits::MEMMOVE_UNROLL_LIMIT);
      Ty = firstTypeThatFitsSize(RemainingBytes);
      Offset = Ctx->getConstantInt32(CountValue - typeWidthInBytes(Ty));
      Reg = makeReg(Ty);
      typedLoad(Ty, Reg, SrcBase, Offset);
      Moves[N++] = std::make_tuple(Ty, Offset, Reg);
    }

    // Copy the data out into the destination memory
    for (size_t i = 0; i < N; ++i) {
      std::tie(Ty, Offset, Reg) = Moves[i];
      typedStore(Ty, Reg, DestBase, Offset);
    }

    return;
  }

  // Fall back on a function call
  InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memmove, nullptr, 3);
  Call->addArg(Dest);
  Call->addArg(Src);
  Call->addArg(Count);
  lowerCall(Call);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerMemset(Operand *Dest, Operand *Val,
                                            Operand *Count) {
  constexpr uint32_t BytesPerStorep = 16;
  constexpr uint32_t BytesPerStoreq = 8;
  constexpr uint32_t BytesPerStorei32 = 4;
  assert(Val->getType() == IceType_i8);

  // Check if the operands are constants
  const auto *CountConst = llvm::dyn_cast<const ConstantInteger32>(Count);
  const auto *ValConst = llvm::dyn_cast<const ConstantInteger32>(Val);
  const bool IsCountConst = CountConst != nullptr;
  const bool IsValConst = ValConst != nullptr;
  const uint32_t CountValue = IsCountConst ? CountConst->getValue() : 0;
  const uint32_t ValValue = IsValConst ? ValConst->getValue() : 0;

  // Unlikely, but nothing to do if it does happen
  if (IsCountConst && CountValue == 0)
    return;

  // TODO(ascull): if the count is constant but val is not it would be possible
  // to inline by spreading the value across 4 bytes and accessing subregs e.g.
  // eax, ax and al.
  if (shouldOptimizeMemIntrins() && IsCountConst && IsValConst) {
    Variable *Base = nullptr;
    Variable *VecReg = nullptr;
    const uint32_t MaskValue = (ValValue & 0xff);
    const uint32_t SpreadValue =
        (MaskValue << 24) | (MaskValue << 16) | (MaskValue << 8) | MaskValue;

    auto lowerSet = [this, &Base, SpreadValue, &VecReg](Type Ty,
                                                        uint32_t OffsetAmt) {
      assert(Base != nullptr);
      Constant *Offset = OffsetAmt ? Ctx->getConstantInt32(OffsetAmt) : nullptr;

      // TODO(ascull): is 64-bit better with vector or scalar movq?
      auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);
      if (isVectorType(Ty)) {
        assert(VecReg != nullptr);
        _storep(VecReg, Mem);
      } else if (Ty == IceType_f64) {
        assert(VecReg != nullptr);
        _storeq(VecReg, Mem);
      } else {
        assert(Ty != IceType_i64);
        _store(Ctx->getConstantInt(Ty, SpreadValue), Mem);
      }
    };

    // Find the largest type that can be used and use it as much as possible in
    // reverse order. Then handle any remainder with overlapping copies. Since
    // the remainder will be at the end, there will be reduces pressure on the
    // memory unit as the access to the same memory are far apart.
    Type Ty;
    if (ValValue == 0 && CountValue >= BytesPerStoreq &&
        CountValue <= BytesPerStorep * Traits::MEMSET_UNROLL_LIMIT) {
      // When the value is zero it can be loaded into a vector register cheaply
      // using the xor trick.
      Base = legalizeToReg(Dest);
      VecReg = makeVectorOfZeros(IceType_v16i8);
      Ty = largestTypeInSize(CountValue);
    } else if (CountValue <= BytesPerStorei32 * Traits::MEMSET_UNROLL_LIMIT) {
      // When the value is non-zero or the count is small we can't use vector
      // instructions so are limited to 32-bit stores.
      Base = legalizeToReg(Dest);
      constexpr uint32_t MaxSize = 4;
      Ty = largestTypeInSize(CountValue, MaxSize);
    }

    if (Base) {
      uint32_t TyWidth = typeWidthInBytes(Ty);

      uint32_t RemainingBytes = CountValue;
      uint32_t Offset = (CountValue & ~(TyWidth - 1)) - TyWidth;
      while (RemainingBytes >= TyWidth) {
        lowerSet(Ty, Offset);
        RemainingBytes -= TyWidth;
        Offset -= TyWidth;
      }

      if (RemainingBytes == 0)
        return;

      // Lower the remaining bytes. Adjust to larger types in order to make use
      // of overlaps in the copies.
      Type LeftOverTy = firstTypeThatFitsSize(RemainingBytes);
      Offset = CountValue - typeWidthInBytes(LeftOverTy);
      lowerSet(LeftOverTy, Offset);
      return;
    }
  }

  // Fall back on calling the memset function. The value operand needs to be
  // extended to a stack slot size because the PNaCl ABI requires arguments to
  // be at least 32 bits wide.
  Operand *ValExt;
  if (IsValConst) {
    ValExt = Ctx->getConstantInt(stackSlotType(), ValValue);
  } else {
    Variable *ValExtVar = Func->makeVariable(stackSlotType());
    lowerCast(InstCast::create(Func, InstCast::Zext, ValExtVar, Val));
    ValExt = ValExtVar;
  }
  InstCall *Call = makeHelperCall(RuntimeHelper::H_call_memset, nullptr, 3);
  Call->addArg(Dest);
  Call->addArg(ValExt);
  Call->addArg(Count);
  lowerCall(Call);
}

class AddressOptimizer {
  AddressOptimizer() = delete;
  AddressOptimizer(const AddressOptimizer &) = delete;
  AddressOptimizer &operator=(const AddressOptimizer &) = delete;

public:
  explicit AddressOptimizer(const Cfg *Func)
      : Func(Func), VMetadata(Func->getVMetadata()) {}

  inline void dumpAddressOpt(const ConstantRelocatable *const Relocatable,
                             int32_t Offset, const Variable *Base,
                             const Variable *Index, uint16_t Shift,
                             const Inst *Reason) const;

  inline const Inst *matchAssign(Variable **Var,
                                 ConstantRelocatable **Relocatable,
                                 int32_t *Offset);

  inline const Inst *matchCombinedBaseIndex(Variable **Base, Variable **Index,
                                            uint16_t *Shift);

  inline const Inst *matchShiftedIndex(Variable **Index, uint16_t *Shift);

  inline const Inst *matchOffsetIndexOrBase(Variable **IndexOrBase,
                                            const uint16_t Shift,
                                            ConstantRelocatable **Relocatable,
                                            int32_t *Offset);

private:
  const Cfg *const Func;
  const VariablesMetadata *const VMetadata;

  static bool isAdd(const Inst *Instr) {
    if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Instr)) {
      return (Arith->getOp() == InstArithmetic::Add);
    }
    return false;
  }
};

void AddressOptimizer::dumpAddressOpt(
    const ConstantRelocatable *const Relocatable, int32_t Offset,
    const Variable *Base, const Variable *Index, uint16_t Shift,
    const Inst *Reason) const {
  if (!BuildDefs::dump())
    return;
  if (!Func->isVerbose(IceV_AddrOpt))
    return;
  OstreamLocker L(Func->getContext());
  Ostream &Str = Func->getContext()->getStrDump();
  Str << "Instruction: ";
  Reason->dumpDecorated(Func);
  Str << "  results in Base=";
  if (Base)
    Base->dump(Func);
  else
    Str << "<null>";
  Str << ", Index=";
  if (Index)
    Index->dump(Func);
  else
    Str << "<null>";
  Str << ", Shift=" << Shift << ", Offset=" << Offset
      << ", Relocatable=" << Relocatable << "\n";
}

const Inst *AddressOptimizer::matchAssign(Variable **Var,
                                          ConstantRelocatable **Relocatable,
                                          int32_t *Offset) {
  // Var originates from Var=SrcVar ==> set Var:=SrcVar
  if (*Var == nullptr)
    return nullptr;
  if (const Inst *VarAssign = VMetadata->getSingleDefinition(*Var)) {
    assert(!VMetadata->isMultiDef(*Var));
    if (llvm::isa<InstAssign>(VarAssign)) {
      Operand *SrcOp = VarAssign->getSrc(0);
      assert(SrcOp);
      if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) {
        if (!VMetadata->isMultiDef(SrcVar) &&
            // TODO: ensure SrcVar stays single-BB
            true) {
          *Var = SrcVar;
          return VarAssign;
        }
      } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) {
        int32_t MoreOffset = Const->getValue();
        if (Utils::WouldOverflowAdd(*Offset, MoreOffset))
          return nullptr;
        *Var = nullptr;
        *Offset += MoreOffset;
        return VarAssign;
      } else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) {
        if (*Relocatable == nullptr) {
          // It is always safe to fold a relocatable through assignment -- the
          // assignment frees a slot in the address operand that can be used to
          // hold the Sandbox Pointer -- if any.
          *Var = nullptr;
          *Relocatable = AddReloc;
          return VarAssign;
        }
      }
    }
  }
  return nullptr;
}

const Inst *AddressOptimizer::matchCombinedBaseIndex(Variable **Base,
                                                     Variable **Index,
                                                     uint16_t *Shift) {
  // Index==nullptr && Base is Base=Var1+Var2 ==>
  //   set Base=Var1, Index=Var2, Shift=0
  if (*Base == nullptr)
    return nullptr;
  if (*Index != nullptr)
    return nullptr;
  auto *BaseInst = VMetadata->getSingleDefinition(*Base);
  if (BaseInst == nullptr)
    return nullptr;
  assert(!VMetadata->isMultiDef(*Base));
  if (BaseInst->getSrcSize() < 2)
    return nullptr;
  if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) {
    if (VMetadata->isMultiDef(Var1))
      return nullptr;
    if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) {
      if (VMetadata->isMultiDef(Var2))
        return nullptr;
      if (isAdd(BaseInst) &&
          // TODO: ensure Var1 and Var2 stay single-BB
          true) {
        *Base = Var1;
        *Index = Var2;
        *Shift = 0; // should already have been 0
        return BaseInst;
      }
    }
  }
  return nullptr;
}

const Inst *AddressOptimizer::matchShiftedIndex(Variable **Index,
                                                uint16_t *Shift) {
  // Index is Index=Var*Const && log2(Const)+Shift<=3 ==>
  //   Index=Var, Shift+=log2(Const)
  if (*Index == nullptr)
    return nullptr;
  auto *IndexInst = VMetadata->getSingleDefinition(*Index);
  if (IndexInst == nullptr)
    return nullptr;
  assert(!VMetadata->isMultiDef(*Index));

  // When using an unsigned 32-bit array index on x64, it gets zero-extended
  // before the shift & add. The explicit zero extension can be eliminated
  // because x86 32-bit operations automatically get zero-extended into the
  // corresponding 64-bit register.
  if (auto *CastInst = llvm::dyn_cast<InstCast>(IndexInst)) {
    if (CastInst->getCastKind() == InstCast::Zext) {
      if (auto *Var = llvm::dyn_cast<Variable>(CastInst->getSrc(0))) {
        if (Var->getType() == IceType_i32 &&
            CastInst->getDest()->getType() == IceType_i64) {
          IndexInst = VMetadata->getSingleDefinition(Var);
        }
      }
    }
  }

  if (IndexInst->getSrcSize() < 2)
    return nullptr;
  if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) {
    if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) {
      if (auto *Const =
              llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) {
        if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32)
          return nullptr;
        switch (ArithInst->getOp()) {
        default:
          return nullptr;
        case InstArithmetic::Mul: {
          uint32_t Mult = Const->getValue();
          uint32_t LogMult;
          switch (Mult) {
          case 1:
            LogMult = 0;
            break;
          case 2:
            LogMult = 1;
            break;
          case 4:
            LogMult = 2;
            break;
          case 8:
            LogMult = 3;
            break;
          default:
            return nullptr;
          }
          if (*Shift + LogMult <= 3) {
            *Index = Var;
            *Shift += LogMult;
            return IndexInst;
          }
        }
        case InstArithmetic::Shl: {
          uint32_t ShiftAmount = Const->getValue();
          switch (ShiftAmount) {
          case 0:
          case 1:
          case 2:
          case 3:
            break;
          default:
            return nullptr;
          }
          if (*Shift + ShiftAmount <= 3) {
            *Index = Var;
            *Shift += ShiftAmount;
            return IndexInst;
          }
        }
        }
      }
    }
  }
  return nullptr;
}

const Inst *AddressOptimizer::matchOffsetIndexOrBase(
    Variable **IndexOrBase, const uint16_t Shift,
    ConstantRelocatable **Relocatable, int32_t *Offset) {
  // Base is Base=Var+Const || Base is Base=Const+Var ==>
  //   set Base=Var, Offset+=Const
  // Base is Base=Var-Const ==>
  //   set Base=Var, Offset-=Const
  // Index is Index=Var+Const ==>
  //   set Index=Var, Offset+=(Const<<Shift)
  // Index is Index=Const+Var ==>
  //   set Index=Var, Offset+=(Const<<Shift)
  // Index is Index=Var-Const ==>
  //   set Index=Var, Offset-=(Const<<Shift)
  // Treat Index=Var Or Const as Index=Var + Const
  //    when Var = Var' << N and log2(Const) <= N
  // or when Var = (2^M) * (2^N) and log2(Const) <= (M+N)

  if (*IndexOrBase == nullptr) {
    return nullptr;
  }
  const Inst *Definition = VMetadata->getSingleDefinition(*IndexOrBase);
  if (Definition == nullptr) {
    return nullptr;
  }
  assert(!VMetadata->isMultiDef(*IndexOrBase));
  if (auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(Definition)) {
    switch (ArithInst->getOp()) {
    case InstArithmetic::Add:
    case InstArithmetic::Sub:
    case InstArithmetic::Or:
      break;
    default:
      return nullptr;
    }

    Operand *Src0 = ArithInst->getSrc(0);
    Operand *Src1 = ArithInst->getSrc(1);
    auto *Var0 = llvm::dyn_cast<Variable>(Src0);
    auto *Var1 = llvm::dyn_cast<Variable>(Src1);
    auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0);
    auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1);
    auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0);
    auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1);

    bool IsAdd = false;
    if (ArithInst->getOp() == InstArithmetic::Or) {
      Variable *Var = nullptr;
      ConstantInteger32 *Const = nullptr;
      if (Var0 && Const1) {
        Var = Var0;
        Const = Const1;
      } else if (Const0 && Var1) {
        Var = Var1;
        Const = Const0;
      } else {
        return nullptr;
      }
      auto *VarDef =
          llvm::dyn_cast<InstArithmetic>(VMetadata->getSingleDefinition(Var));
      if (VarDef == nullptr)
        return nullptr;

      SizeT ZeroesAvailable = 0;
      if (VarDef->getOp() == InstArithmetic::Shl) {
        if (auto *ConstInt =
                llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(1))) {
          ZeroesAvailable = ConstInt->getValue();
        }
      } else if (VarDef->getOp() == InstArithmetic::Mul) {
        SizeT PowerOfTwo = 0;
        if (auto *MultConst =
                llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(0))) {
          if (llvm::isPowerOf2_32(MultConst->getValue())) {
            PowerOfTwo += MultConst->getValue();
          }
        }
        if (auto *MultConst =
                llvm::dyn_cast<ConstantInteger32>(VarDef->getSrc(1))) {
          if (llvm::isPowerOf2_32(MultConst->getValue())) {
            PowerOfTwo += MultConst->getValue();
          }
        }
        ZeroesAvailable = llvm::Log2_32(PowerOfTwo) + 1;
      }
      SizeT ZeroesNeeded = llvm::Log2_32(Const->getValue()) + 1;
      if (ZeroesNeeded == 0 || ZeroesNeeded > ZeroesAvailable)
        return nullptr;
      IsAdd = true; // treat it as an add if the above conditions hold
    } else {
      IsAdd = ArithInst->getOp() == InstArithmetic::Add;
    }

    Variable *NewIndexOrBase = nullptr;
    int32_t NewOffset = 0;
    ConstantRelocatable *NewRelocatable = *Relocatable;
    if (Var0 && Var1)
      // TODO(sehr): merge base/index splitting into here.
      return nullptr;
    if (!IsAdd && Var1)
      return nullptr;
    if (Var0)
      NewIndexOrBase = Var0;
    else if (Var1)
      NewIndexOrBase = Var1;
    // Don't know how to add/subtract two relocatables.
    if ((*Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1))
      return nullptr;
    // Don't know how to subtract a relocatable.
    if (!IsAdd && Reloc1)
      return nullptr;
    // Incorporate ConstantRelocatables.
    if (Reloc0)
      NewRelocatable = Reloc0;
    else if (Reloc1)
      NewRelocatable = Reloc1;
    // Compute the updated constant offset.
    if (Const0) {
      const int32_t MoreOffset =
          IsAdd ? Const0->getValue() : -Const0->getValue();
      if (Utils::WouldOverflowAdd(*Offset + NewOffset, MoreOffset))
        return nullptr;
      NewOffset += MoreOffset;
    }
    if (Const1) {
      const int32_t MoreOffset =
          IsAdd ? Const1->getValue() : -Const1->getValue();
      if (Utils::WouldOverflowAdd(*Offset + NewOffset, MoreOffset))
        return nullptr;
      NewOffset += MoreOffset;
    }
    if (Utils::WouldOverflowAdd(*Offset, NewOffset << Shift))
      return nullptr;
    *IndexOrBase = NewIndexOrBase;
    *Offset += (NewOffset << Shift);
    // Shift is always zero if this is called with the base
    *Relocatable = NewRelocatable;
    return Definition;
  }
  return nullptr;
}

template <typename TypeTraits>
typename TargetX86Base<TypeTraits>::X86OperandMem *
TargetX86Base<TypeTraits>::computeAddressOpt(const Inst *Instr, Type MemType,
                                             Operand *Addr) {
  Func->resetCurrentNode();
  if (Func->isVerbose(IceV_AddrOpt)) {
    OstreamLocker L(Func->getContext());
    Ostream &Str = Func->getContext()->getStrDump();
    Str << "\nStarting computeAddressOpt for instruction:\n  ";
    Instr->dumpDecorated(Func);
  }

  OptAddr NewAddr;
  NewAddr.Base = llvm::dyn_cast<Variable>(Addr);
  if (NewAddr.Base == nullptr)
    return nullptr;

  // If the Base has more than one use or is live across multiple blocks, then
  // don't go further. Alternatively (?), never consider a transformation that
  // would change a variable that is currently *not* live across basic block
  // boundaries into one that *is*.
  if (!getFlags().getLoopInvariantCodeMotion()) {
    // Need multi block address opt when licm is enabled.
    // Might make sense to restrict to current node and loop header.
    if (Func->getVMetadata()->isMultiBlock(
            NewAddr.Base) /* || Base->getUseCount() > 1*/)
      return nullptr;
  }
  AddressOptimizer AddrOpt(Func);
  const bool MockBounds = getFlags().getMockBoundsCheck();
  const Inst *Reason = nullptr;
  bool AddressWasOptimized = false;
  // The following unnamed struct identifies the address mode formation steps
  // that could potentially create an invalid memory operand (i.e., no free
  // slots for RebasePtr.) We add all those variables to this struct so that we
  // can use memset() to reset all members to false.
  struct {
    bool AssignBase = false;
    bool AssignIndex = false;
    bool OffsetFromBase = false;
    bool OffsetFromIndex = false;
    bool CombinedBaseIndex = false;
  } Skip;
  // This points to the boolean in Skip that represents the last folding
  // performed. This is used to disable a pattern match that generated an
  // invalid address. Without this, the algorithm would never finish.
  bool *SkipLastFolding = nullptr;
  // NewAddrCheckpoint is used to rollback the address being formed in case an
  // invalid address is formed.
  OptAddr NewAddrCheckpoint;
  Reason = Instr;
  do {
    if (SandboxingType != ST_None) {
      // When sandboxing, we defer the sandboxing of NewAddr to the Concrete
      // Target. If our optimization was overly aggressive, then we simply undo
      // what the previous iteration did, and set the previous pattern's skip
      // bit to true.
      if (!legalizeOptAddrForSandbox(&NewAddr)) {
        *SkipLastFolding = true;
        SkipLastFolding = nullptr;
        NewAddr = NewAddrCheckpoint;
        Reason = nullptr;
      }
    }

    if (Reason) {
      AddrOpt.dumpAddressOpt(NewAddr.Relocatable, NewAddr.Offset, NewAddr.Base,
                             NewAddr.Index, NewAddr.Shift, Reason);
      AddressWasOptimized = true;
      Reason = nullptr;
      SkipLastFolding = nullptr;
      memset(&Skip, 0, sizeof(Skip));
    }

    NewAddrCheckpoint = NewAddr;

    // Update Base and Index to follow through assignments to definitions.
    if (!Skip.AssignBase &&
        (Reason = AddrOpt.matchAssign(&NewAddr.Base, &NewAddr.Relocatable,
                                      &NewAddr.Offset))) {
      SkipLastFolding = &Skip.AssignBase;
      // Assignments of Base from a Relocatable or ConstantInt32 can result
      // in Base becoming nullptr.  To avoid code duplication in this loop we
      // prefer that Base be non-nullptr if possible.
      if ((NewAddr.Base == nullptr) && (NewAddr.Index != nullptr) &&
          NewAddr.Shift == 0) {
        std::swap(NewAddr.Base, NewAddr.Index);
      }
      continue;
    }
    if (!Skip.AssignBase &&
        (Reason = AddrOpt.matchAssign(&NewAddr.Index, &NewAddr.Relocatable,
                                      &NewAddr.Offset))) {
      SkipLastFolding = &Skip.AssignIndex;
      continue;
    }

    if (!MockBounds) {
      // Transition from:
      //   <Relocatable + Offset>(Base) to
      //   <Relocatable + Offset>(Base, Index)
      if (!Skip.CombinedBaseIndex &&
          (Reason = AddrOpt.matchCombinedBaseIndex(
               &NewAddr.Base, &NewAddr.Index, &NewAddr.Shift))) {
        SkipLastFolding = &Skip.CombinedBaseIndex;
        continue;
      }

      // Recognize multiply/shift and update Shift amount.
      // Index becomes Index=Var<<Const && Const+Shift<=3 ==>
      //   Index=Var, Shift+=Const
      // Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==>
      //   Index=Var, Shift+=log2(Const)
      if ((Reason =
               AddrOpt.matchShiftedIndex(&NewAddr.Index, &NewAddr.Shift))) {
        continue;
      }

      // If Shift is zero, the choice of Base and Index was purely arbitrary.
      // Recognize multiply/shift and set Shift amount.
      // Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==>
      //   swap(Index,Base)
      // Similar for Base=Const*Var and Base=Var<<Const
      if (NewAddr.Shift == 0 &&
          (Reason = AddrOpt.matchShiftedIndex(&NewAddr.Base, &NewAddr.Shift))) {
        std::swap(NewAddr.Base, NewAddr.Index);
        continue;
      }
    }

    // Update Offset to reflect additions/subtractions with constants and
    // relocatables.
    // TODO: consider overflow issues with respect to Offset.
    if (!Skip.OffsetFromBase && (Reason = AddrOpt.matchOffsetIndexOrBase(
                                     &NewAddr.Base, /*Shift =*/0,
                                     &NewAddr.Relocatable, &NewAddr.Offset))) {
      SkipLastFolding = &Skip.OffsetFromBase;
      continue;
    }
    if (!Skip.OffsetFromIndex && (Reason = AddrOpt.matchOffsetIndexOrBase(
                                      &NewAddr.Index, NewAddr.Shift,
                                      &NewAddr.Relocatable, &NewAddr.Offset))) {
      SkipLastFolding = &Skip.OffsetFromIndex;
      continue;
    }

    break;
  } while (Reason);

  if (!AddressWasOptimized) {
    return nullptr;
  }

  // Undo any addition of RebasePtr.  It will be added back when the mem
  // operand is sandboxed.
  if (NewAddr.Base == RebasePtr) {
    NewAddr.Base = nullptr;
  }

  if (NewAddr.Index == RebasePtr) {
    NewAddr.Index = nullptr;
    NewAddr.Shift = 0;
  }

  Constant *OffsetOp = nullptr;
  if (NewAddr.Relocatable == nullptr) {
    OffsetOp = Ctx->getConstantInt32(NewAddr.Offset);
  } else {
    OffsetOp =
        Ctx->getConstantSym(NewAddr.Relocatable->getOffset() + NewAddr.Offset,
                            NewAddr.Relocatable->getName());
  }
  // Vanilla ICE load instructions should not use the segment registers, and
  // computeAddressOpt only works at the level of Variables and Constants, not
  // other X86OperandMem, so there should be no mention of segment
  // registers there either.
  static constexpr auto SegmentReg =
      X86OperandMem::SegmentRegisters::DefaultSegment;

  return X86OperandMem::create(Func, MemType, NewAddr.Base, OffsetOp,
                               NewAddr.Index, NewAddr.Shift, SegmentReg);
}

/// Add a mock bounds check on the memory address before using it as a load or
/// store operand.  The basic idea is that given a memory operand [reg], we
/// would first add bounds-check code something like:
///
///   cmp reg, <lb>
///   jl out_of_line_error
///   cmp reg, <ub>
///   jg out_of_line_error
///
/// In reality, the specific code will depend on how <lb> and <ub> are
/// represented, e.g. an immediate, a global, or a function argument.
///
/// As such, we need to enforce that the memory operand does not have the form
/// [reg1+reg2], because then there is no simple cmp instruction that would
/// suffice.  However, we consider [reg+offset] to be OK because the offset is
/// usually small, and so <ub> could have a safety buffer built in and then we
/// could instead branch to a custom out_of_line_error that does the precise
/// check and jumps back if it turns out OK.
///
/// For the purpose of mocking the bounds check, we'll do something like this:
///
///   cmp reg, 0
///   je label
///   cmp reg, 1
///   je label
///   label:
///
/// Also note that we don't need to add a bounds check to a dereference of a
/// simple global variable address.
template <typename TraitsType>
void TargetX86Base<TraitsType>::doMockBoundsCheck(Operand *Opnd) {
  if (!getFlags().getMockBoundsCheck())
    return;
  if (auto *Mem = llvm::dyn_cast<X86OperandMem>(Opnd)) {
    if (Mem->getIndex()) {
      llvm::report_fatal_error("doMockBoundsCheck: Opnd contains index reg");
    }
    Opnd = Mem->getBase();
  }
  // At this point Opnd could be nullptr, or Variable, or Constant, or perhaps
  // something else.  We only care if it is Variable.
  auto *Var = llvm::dyn_cast_or_null<Variable>(Opnd);
  if (Var == nullptr)
    return;
  // We use lowerStore() to copy out-args onto the stack.  This creates a memory
  // operand with the stack pointer as the base register.  Don't do bounds
  // checks on that.
  if (Var->getRegNum() == getStackReg())
    return;

  auto *Label = InstX86Label::create(Func, this);
  _cmp(Opnd, Ctx->getConstantZero(IceType_i32));
  _br(Traits::Cond::Br_e, Label);
  _cmp(Opnd, Ctx->getConstantInt32(1));
  _br(Traits::Cond::Br_e, Label);
  Context.insert(Label);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerLoad(const InstLoad *Load) {
  // A Load instruction can be treated the same as an Assign instruction, after
  // the source operand is transformed into an X86OperandMem operand.  Note that
  // the address mode optimization already creates an X86OperandMem operand, so
  // it doesn't need another level of transformation.
  Variable *DestLoad = Load->getDest();
  Type Ty = DestLoad->getType();
  Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty);
  doMockBoundsCheck(Src0);
  auto *Assign = InstAssign::create(Func, DestLoad, Src0);
  lowerAssign(Assign);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::doAddressOptOther() {
  // Inverts some Icmp instructions which helps doAddressOptLoad later.
  // TODO(manasijm): Refactor to unify the conditions for Var0 and Var1
  Inst *Instr = iteratorToInst(Context.getCur());
  auto *VMetadata = Func->getVMetadata();
  if (auto *Icmp = llvm::dyn_cast<InstIcmp>(Instr)) {
    if (llvm::isa<Constant>(Icmp->getSrc(0)) ||
        llvm::isa<Constant>(Icmp->getSrc(1)))
      return;
    auto *Var0 = llvm::dyn_cast<Variable>(Icmp->getSrc(0));
    if (Var0 == nullptr)
      return;
    if (!VMetadata->isTracked(Var0))
      return;
    auto *Op0Def = VMetadata->getFirstDefinitionSingleBlock(Var0);
    if (Op0Def == nullptr || !llvm::isa<InstLoad>(Op0Def))
      return;
    if (VMetadata->getLocalUseNode(Var0) != Context.getNode())
      return;

    auto *Var1 = llvm::dyn_cast<Variable>(Icmp->getSrc(1));
    if (Var1 != nullptr && VMetadata->isTracked(Var1)) {
      auto *Op1Def = VMetadata->getFirstDefinitionSingleBlock(Var1);
      if (Op1Def != nullptr && !VMetadata->isMultiBlock(Var1) &&
          llvm::isa<InstLoad>(Op1Def)) {
        return; // Both are loads
      }
    }
    Icmp->reverseConditionAndOperands();
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::doAddressOptLoad() {
  Inst *Instr = iteratorToInst(Context.getCur());
  Operand *Addr = Instr->getSrc(0);
  Variable *Dest = Instr->getDest();
  if (auto *OptAddr = computeAddressOpt(Instr, Dest->getType(), Addr)) {
    Instr->setDeleted();
    Context.insert<InstLoad>(Dest, OptAddr);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::doAddressOptLoadSubVector() {
  auto *Intrinsic = llvm::cast<InstIntrinsicCall>(Context.getCur());
  Operand *Addr = Intrinsic->getArg(0);
  Variable *Dest = Intrinsic->getDest();
  if (auto *OptAddr = computeAddressOpt(Intrinsic, Dest->getType(), Addr)) {
    Intrinsic->setDeleted();
    const Ice::Intrinsics::IntrinsicInfo Info = {
        Ice::Intrinsics::LoadSubVector, Ice::Intrinsics::SideEffects_F,
        Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_F};
    auto Target = Ctx->getConstantUndef(Ice::IceType_i32);
    auto *NewLoad = Context.insert<InstIntrinsicCall>(2, Dest, Target, Info);
    NewLoad->addArg(OptAddr);
    NewLoad->addArg(Intrinsic->getArg(1));
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::randomlyInsertNop(float Probability,
                                                  RandomNumberGenerator &RNG) {
  RandomNumberGeneratorWrapper RNGW(RNG);
  if (RNGW.getTrueWithProbability(Probability)) {
    _nop(RNGW(Traits::X86_NUM_NOP_VARIANTS));
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerPhi(const InstPhi * /*Instr*/) {
  Func->setError("Phi found in regular instruction list");
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerRet(const InstRet *Instr) {
  Variable *Reg = nullptr;
  if (Instr->hasRetValue()) {
    Operand *RetValue = legalize(Instr->getRetValue());
    const Type ReturnType = RetValue->getType();
    assert(isVectorType(ReturnType) || isScalarFloatingType(ReturnType) ||
           (ReturnType == IceType_i32) || (ReturnType == IceType_i64));
    Reg = moveReturnValueToRegister(RetValue, ReturnType);
  }
  // Add a ret instruction even if sandboxing is enabled, because addEpilog
  // explicitly looks for a ret instruction as a marker for where to insert the
  // frame removal instructions.
  _ret(Reg);
  // Add a fake use of esp to make sure esp stays alive for the entire
  // function. Otherwise post-call esp adjustments get dead-code eliminated.
  keepEspLiveAtExit();
}

inline uint32_t makePshufdMask(SizeT Index0, SizeT Index1, SizeT Index2,
                               SizeT Index3) {
  const SizeT Mask = (Index0 & 0x3) | ((Index1 & 0x3) << 2) |
                     ((Index2 & 0x3) << 4) | ((Index3 & 0x3) << 6);
  assert(Mask < 256);
  return Mask;
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::lowerShuffleVector_AllFromSameSrc(
    Operand *Src, SizeT Index0, SizeT Index1, SizeT Index2, SizeT Index3) {
  constexpr SizeT SrcBit = 1 << 2;
  assert((Index0 & SrcBit) == (Index1 & SrcBit));
  assert((Index0 & SrcBit) == (Index2 & SrcBit));
  assert((Index0 & SrcBit) == (Index3 & SrcBit));
  (void)SrcBit;

  const Type SrcTy = Src->getType();
  auto *T = makeReg(SrcTy);
  auto *SrcRM = legalize(Src, Legal_Reg | Legal_Mem);
  auto *Mask =
      Ctx->getConstantInt32(makePshufdMask(Index0, Index1, Index2, Index3));
  _pshufd(T, SrcRM, Mask);
  return T;
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::lowerShuffleVector_TwoFromSameSrc(
    Operand *Src0, SizeT Index0, SizeT Index1, Operand *Src1, SizeT Index2,
    SizeT Index3) {
  constexpr SizeT SrcBit = 1 << 2;
  assert((Index0 & SrcBit) == (Index1 & SrcBit) || (Index1 == IGNORE_INDEX));
  assert((Index2 & SrcBit) == (Index3 & SrcBit) || (Index3 == IGNORE_INDEX));
  (void)SrcBit;

  const Type SrcTy = Src0->getType();
  assert(Src1->getType() == SrcTy);
  auto *T = makeReg(SrcTy);
  auto *Src0R = legalizeToReg(Src0);
  auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
  auto *Mask =
      Ctx->getConstantInt32(makePshufdMask(Index0, Index1, Index2, Index3));
  _movp(T, Src0R);
  _shufps(T, Src1RM, Mask);
  return T;
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::lowerShuffleVector_UnifyFromDifferentSrcs(
    Operand *Src0, SizeT Index0, Operand *Src1, SizeT Index1) {
  return lowerShuffleVector_TwoFromSameSrc(Src0, Index0, IGNORE_INDEX, Src1,
                                           Index1, IGNORE_INDEX);
}

inline SizeT makeSrcSwitchMask(SizeT Index0, SizeT Index1, SizeT Index2,
                               SizeT Index3) {
  constexpr SizeT SrcBit = 1 << 2;
  const SizeT Index0Bits = ((Index0 & SrcBit) == 0) ? 0 : (1 << 0);
  const SizeT Index1Bits = ((Index1 & SrcBit) == 0) ? 0 : (1 << 1);
  const SizeT Index2Bits = ((Index2 & SrcBit) == 0) ? 0 : (1 << 2);
  const SizeT Index3Bits = ((Index3 & SrcBit) == 0) ? 0 : (1 << 3);
  return Index0Bits | Index1Bits | Index2Bits | Index3Bits;
}

template <typename TraitsType>
GlobalString TargetX86Base<TraitsType>::lowerShuffleVector_NewMaskName() {
  GlobalString FuncName = Func->getFunctionName();
  const SizeT Id = PshufbMaskCount++;
  if (!BuildDefs::dump() || !FuncName.hasStdString()) {
    return GlobalString::createWithString(
        Ctx,
        "$PS" + std::to_string(FuncName.getID()) + "_" + std::to_string(Id));
  }
  return GlobalString::createWithString(
      Ctx, "Pshufb$" + Func->getFunctionName() + "$" + std::to_string(Id));
}

template <typename TraitsType>
ConstantRelocatable *
TargetX86Base<TraitsType>::lowerShuffleVector_CreatePshufbMask(
    int8_t Idx0, int8_t Idx1, int8_t Idx2, int8_t Idx3, int8_t Idx4,
    int8_t Idx5, int8_t Idx6, int8_t Idx7, int8_t Idx8, int8_t Idx9,
    int8_t Idx10, int8_t Idx11, int8_t Idx12, int8_t Idx13, int8_t Idx14,
    int8_t Idx15) {
  static constexpr uint8_t NumElements = 16;
  const char Initializer[NumElements] = {
      Idx0, Idx1, Idx2,  Idx3,  Idx4,  Idx5,  Idx6,  Idx7,
      Idx8, Idx9, Idx10, Idx11, Idx12, Idx13, Idx14, Idx15,
  };

  static constexpr Type V4VectorType = IceType_v4i32;
  const uint32_t MaskAlignment = typeWidthInBytesOnStack(V4VectorType);
  auto *Mask = VariableDeclaration::create(Func->getGlobalPool());
  GlobalString MaskName = lowerShuffleVector_NewMaskName();
  Mask->setIsConstant(true);
  Mask->addInitializer(VariableDeclaration::DataInitializer::create(
      Func->getGlobalPool(), Initializer, NumElements));
  Mask->setName(MaskName);
  // Mask needs to be 16-byte aligned, or pshufb will seg fault.
  Mask->setAlignment(MaskAlignment);
  Func->addGlobal(Mask);

  constexpr RelocOffsetT Offset = 0;
  return llvm::cast<ConstantRelocatable>(Ctx->getConstantSym(Offset, MaskName));
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerShuffleVector_UsingPshufb(
    Variable *Dest, Operand *Src0, Operand *Src1, int8_t Idx0, int8_t Idx1,
    int8_t Idx2, int8_t Idx3, int8_t Idx4, int8_t Idx5, int8_t Idx6,
    int8_t Idx7, int8_t Idx8, int8_t Idx9, int8_t Idx10, int8_t Idx11,
    int8_t Idx12, int8_t Idx13, int8_t Idx14, int8_t Idx15) {
  const Type DestTy = Dest->getType();
  static constexpr bool NotRebased = false;
  static constexpr Variable *NoBase = nullptr;
  // We use void for the memory operand instead of DestTy because using the
  // latter causes a validation failure: the X86 Inst layer complains that
  // vector mem operands could be under aligned. Thus, using void we avoid the
  // validation error. Note that the mask global declaration is aligned, so it
  // can be used as an XMM mem operand.
  static constexpr Type MaskType = IceType_void;
#define IDX_IN_SRC(N, S)                                                       \
  ((((N) & (1 << 4)) == (S << 4)) ? ((N)&0xf) : CLEAR_ALL_BITS)
  auto *Mask0M = X86OperandMem::create(
      Func, MaskType, NoBase,
      lowerShuffleVector_CreatePshufbMask(
          IDX_IN_SRC(Idx0, 0), IDX_IN_SRC(Idx1, 0), IDX_IN_SRC(Idx2, 0),
          IDX_IN_SRC(Idx3, 0), IDX_IN_SRC(Idx4, 0), IDX_IN_SRC(Idx5, 0),
          IDX_IN_SRC(Idx6, 0), IDX_IN_SRC(Idx7, 0), IDX_IN_SRC(Idx8, 0),
          IDX_IN_SRC(Idx9, 0), IDX_IN_SRC(Idx10, 0), IDX_IN_SRC(Idx11, 0),
          IDX_IN_SRC(Idx12, 0), IDX_IN_SRC(Idx13, 0), IDX_IN_SRC(Idx14, 0),
          IDX_IN_SRC(Idx15, 0)),
      NotRebased);

  auto *T0 = makeReg(DestTy);
  auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
  _movp(T0, Src0RM);

  _pshufb(T0, Mask0M);

  if (Idx0 >= 16 || Idx1 >= 16 || Idx2 >= 16 || Idx3 >= 16 || Idx4 >= 16 ||
      Idx5 >= 16 || Idx6 >= 16 || Idx7 >= 16 || Idx8 >= 16 || Idx9 >= 16 ||
      Idx10 >= 16 || Idx11 >= 16 || Idx12 >= 16 || Idx13 >= 16 || Idx14 >= 16 ||
      Idx15 >= 16) {
    auto *Mask1M = X86OperandMem::create(
        Func, MaskType, NoBase,
        lowerShuffleVector_CreatePshufbMask(
            IDX_IN_SRC(Idx0, 1), IDX_IN_SRC(Idx1, 1), IDX_IN_SRC(Idx2, 1),
            IDX_IN_SRC(Idx3, 1), IDX_IN_SRC(Idx4, 1), IDX_IN_SRC(Idx5, 1),
            IDX_IN_SRC(Idx6, 1), IDX_IN_SRC(Idx7, 1), IDX_IN_SRC(Idx8, 1),
            IDX_IN_SRC(Idx9, 1), IDX_IN_SRC(Idx10, 1), IDX_IN_SRC(Idx11, 1),
            IDX_IN_SRC(Idx12, 1), IDX_IN_SRC(Idx13, 1), IDX_IN_SRC(Idx14, 1),
            IDX_IN_SRC(Idx15, 1)),
        NotRebased);
#undef IDX_IN_SRC
    auto *T1 = makeReg(DestTy);
    auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
    _movp(T1, Src1RM);
    _pshufb(T1, Mask1M);
    _por(T0, T1);
  }

  _movp(Dest, T0);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerShuffleVector(
    const InstShuffleVector *Instr) {
  auto *Dest = Instr->getDest();
  const Type DestTy = Dest->getType();
  auto *Src0 = Instr->getSrc(0);
  auto *Src1 = Instr->getSrc(1);
  const SizeT NumElements = typeNumElements(DestTy);

  auto *T = makeReg(DestTy);

  switch (DestTy) {
  default:
    llvm::report_fatal_error("Unexpected vector type.");
  case IceType_v16i1:
  case IceType_v16i8: {
    static constexpr SizeT ExpectedNumElements = 16;
    assert(ExpectedNumElements == Instr->getNumIndexes());
    (void)ExpectedNumElements;

    if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7)) {
      auto *T = makeReg(DestTy);
      auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      _movp(T, Src0RM);
      _punpckl(T, Src0RM);
      _movp(Dest, T);
      return;
    }

    if (Instr->indexesAre(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7,
                          23)) {
      auto *T = makeReg(DestTy);
      auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
      _movp(T, Src0RM);
      _punpckl(T, Src1RM);
      _movp(Dest, T);
      return;
    }

    if (Instr->indexesAre(8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
                          15, 15)) {
      auto *T = makeReg(DestTy);
      auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      _movp(T, Src0RM);
      _punpckh(T, Src0RM);
      _movp(Dest, T);
      return;
    }

    if (Instr->indexesAre(8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30,
                          15, 31)) {
      auto *T = makeReg(DestTy);
      auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
      _movp(T, Src0RM);
      _punpckh(T, Src1RM);
      _movp(Dest, T);
      return;
    }

    if (InstructionSet < Traits::SSE4_1) {
      // TODO(jpp): figure out how to lower with sse2.
      break;
    }

    const SizeT Index0 = Instr->getIndexValue(0);
    const SizeT Index1 = Instr->getIndexValue(1);
    const SizeT Index2 = Instr->getIndexValue(2);
    const SizeT Index3 = Instr->getIndexValue(3);
    const SizeT Index4 = Instr->getIndexValue(4);
    const SizeT Index5 = Instr->getIndexValue(5);
    const SizeT Index6 = Instr->getIndexValue(6);
    const SizeT Index7 = Instr->getIndexValue(7);
    const SizeT Index8 = Instr->getIndexValue(8);
    const SizeT Index9 = Instr->getIndexValue(9);
    const SizeT Index10 = Instr->getIndexValue(10);
    const SizeT Index11 = Instr->getIndexValue(11);
    const SizeT Index12 = Instr->getIndexValue(12);
    const SizeT Index13 = Instr->getIndexValue(13);
    const SizeT Index14 = Instr->getIndexValue(14);
    const SizeT Index15 = Instr->getIndexValue(15);

    lowerShuffleVector_UsingPshufb(Dest, Src0, Src1, Index0, Index1, Index2,
                                   Index3, Index4, Index5, Index6, Index7,
                                   Index8, Index9, Index10, Index11, Index12,
                                   Index13, Index14, Index15);
    return;
  }
  case IceType_v8i1:
  case IceType_v8i16: {
    static constexpr SizeT ExpectedNumElements = 8;
    assert(ExpectedNumElements == Instr->getNumIndexes());
    (void)ExpectedNumElements;

    if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3)) {
      auto *T = makeReg(DestTy);
      auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      _movp(T, Src0RM);
      _punpckl(T, Src0RM);
      _movp(Dest, T);
      return;
    }

    if (Instr->indexesAre(0, 8, 1, 9, 2, 10, 3, 11)) {
      auto *T = makeReg(DestTy);
      auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
      _movp(T, Src0RM);
      _punpckl(T, Src1RM);
      _movp(Dest, T);
      return;
    }

    if (Instr->indexesAre(4, 4, 5, 5, 6, 6, 7, 7)) {
      auto *T = makeReg(DestTy);
      auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      _movp(T, Src0RM);
      _punpckh(T, Src0RM);
      _movp(Dest, T);
      return;
    }

    if (Instr->indexesAre(4, 12, 5, 13, 6, 14, 7, 15)) {
      auto *T = makeReg(DestTy);
      auto *Src0RM = legalize(Src0, Legal_Reg | Legal_Mem);
      auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
      _movp(T, Src0RM);
      _punpckh(T, Src1RM);
      _movp(Dest, T);
      return;
    }

    if (InstructionSet < Traits::SSE4_1) {
      // TODO(jpp): figure out how to lower with sse2.
      break;
    }

    const SizeT Index0 = Instr->getIndexValue(0);
    const SizeT Index1 = Instr->getIndexValue(1);
    const SizeT Index2 = Instr->getIndexValue(2);
    const SizeT Index3 = Instr->getIndexValue(3);
    const SizeT Index4 = Instr->getIndexValue(4);
    const SizeT Index5 = Instr->getIndexValue(5);
    const SizeT Index6 = Instr->getIndexValue(6);
    const SizeT Index7 = Instr->getIndexValue(7);

#define TO_BYTE_INDEX(I) ((I) << 1)
    lowerShuffleVector_UsingPshufb(
        Dest, Src0, Src1, TO_BYTE_INDEX(Index0), TO_BYTE_INDEX(Index0) + 1,
        TO_BYTE_INDEX(Index1), TO_BYTE_INDEX(Index1) + 1, TO_BYTE_INDEX(Index2),
        TO_BYTE_INDEX(Index2) + 1, TO_BYTE_INDEX(Index3),
        TO_BYTE_INDEX(Index3) + 1, TO_BYTE_INDEX(Index4),
        TO_BYTE_INDEX(Index4) + 1, TO_BYTE_INDEX(Index5),
        TO_BYTE_INDEX(Index5) + 1, TO_BYTE_INDEX(Index6),
        TO_BYTE_INDEX(Index6) + 1, TO_BYTE_INDEX(Index7),
        TO_BYTE_INDEX(Index7) + 1);
#undef TO_BYTE_INDEX
    return;
  }
  case IceType_v4i1:
  case IceType_v4i32:
  case IceType_v4f32: {
    static constexpr SizeT ExpectedNumElements = 4;
    assert(ExpectedNumElements == Instr->getNumIndexes());
    const SizeT Index0 = Instr->getIndexValue(0);
    const SizeT Index1 = Instr->getIndexValue(1);
    const SizeT Index2 = Instr->getIndexValue(2);
    const SizeT Index3 = Instr->getIndexValue(3);
    Variable *T = nullptr;
    switch (makeSrcSwitchMask(Index0, Index1, Index2, Index3)) {
#define CASE_SRCS_IN(S0, S1, S2, S3)                                           \
  case (((S0) << 0) | ((S1) << 1) | ((S2) << 2) | ((S3) << 3))
      CASE_SRCS_IN(0, 0, 0, 0) : {
        T = lowerShuffleVector_AllFromSameSrc(Src0, Index0, Index1, Index2,
                                              Index3);
      }
      break;
      CASE_SRCS_IN(0, 0, 0, 1) : {
        assert(false && "Following code is untested but likely correct; test "
                        "and remove assert.");
        auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index2,
                                                                  Src1, Index3);
        T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Unified,
                                              UNIFIED_INDEX_0, UNIFIED_INDEX_1);
      }
      break;
      CASE_SRCS_IN(0, 0, 1, 0) : {
        auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index2,
                                                                  Src0, Index3);
        T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Unified,
                                              UNIFIED_INDEX_0, UNIFIED_INDEX_1);
      }
      break;
      CASE_SRCS_IN(0, 0, 1, 1) : {
        T = lowerShuffleVector_TwoFromSameSrc(Src0, Index0, Index1, Src1,
                                              Index2, Index3);
      }
      break;
      CASE_SRCS_IN(0, 1, 0, 0) : {
        auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index0,
                                                                  Src1, Index1);
        T = lowerShuffleVector_TwoFromSameSrc(
            Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src0, Index2, Index3);
      }
      break;
      CASE_SRCS_IN(0, 1, 0, 1) : {
        if (Index0 == 0 && (Index1 - ExpectedNumElements) == 0 && Index2 == 1 &&
            (Index3 - ExpectedNumElements) == 1) {
          auto *Src1RM = legalize(Src1, Legal_Reg | Legal_Mem);
          auto *Src0R = legalizeToReg(Src0);
          T = makeReg(DestTy);
          _movp(T, Src0R);
          _punpckl(T, Src1RM);
        } else if (Index0 == Index2 && Index1 == Index3) {
          assert(false && "Following code is untested but likely correct; test "
                          "and remove assert.");
          auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src0, Index0, Src1, Index1);
          T = lowerShuffleVector_AllFromSameSrc(
              Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_0,
              UNIFIED_INDEX_1);
        } else {
          auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src0, Index0, Src1, Index1);
          auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src0, Index2, Src1, Index3);
          T = lowerShuffleVector_TwoFromSameSrc(
              Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
              UNIFIED_INDEX_0, UNIFIED_INDEX_1);
        }
      }
      break;
      CASE_SRCS_IN(0, 1, 1, 0) : {
        if (Index0 == Index3 && Index1 == Index2) {
          auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src0, Index0, Src1, Index1);
          T = lowerShuffleVector_AllFromSameSrc(
              Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_1,
              UNIFIED_INDEX_0);
        } else {
          auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src0, Index0, Src1, Index1);
          auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src1, Index2, Src0, Index3);
          T = lowerShuffleVector_TwoFromSameSrc(
              Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
              UNIFIED_INDEX_0, UNIFIED_INDEX_1);
        }
      }
      break;
      CASE_SRCS_IN(0, 1, 1, 1) : {
        assert(false && "Following code is untested but likely correct; test "
                        "and remove assert.");
        auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index0,
                                                                  Src1, Index1);
        T = lowerShuffleVector_TwoFromSameSrc(
            Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src1, Index2, Index3);
      }
      break;
      CASE_SRCS_IN(1, 0, 0, 0) : {
        auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index0,
                                                                  Src0, Index1);
        T = lowerShuffleVector_TwoFromSameSrc(
            Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src0, Index2, Index3);
      }
      break;
      CASE_SRCS_IN(1, 0, 0, 1) : {
        if (Index0 == Index3 && Index1 == Index2) {
          assert(false && "Following code is untested but likely correct; test "
                          "and remove assert.");
          auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src1, Index0, Src0, Index1);
          T = lowerShuffleVector_AllFromSameSrc(
              Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_1,
              UNIFIED_INDEX_0);
        } else {
          assert(false && "Following code is untested but likely correct; test "
                          "and remove assert.");
          auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src1, Index0, Src0, Index1);
          auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src0, Index2, Src1, Index3);
          T = lowerShuffleVector_TwoFromSameSrc(
              Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
              UNIFIED_INDEX_0, UNIFIED_INDEX_1);
        }
      }
      break;
      CASE_SRCS_IN(1, 0, 1, 0) : {
        if ((Index0 - ExpectedNumElements) == 0 && Index1 == 0 &&
            (Index2 - ExpectedNumElements) == 1 && Index3 == 1) {
          auto *Src1RM = legalize(Src0, Legal_Reg | Legal_Mem);
          auto *Src0R = legalizeToReg(Src1);
          T = makeReg(DestTy);
          _movp(T, Src0R);
          _punpckl(T, Src1RM);
        } else if (Index0 == Index2 && Index1 == Index3) {
          auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src1, Index0, Src0, Index1);
          T = lowerShuffleVector_AllFromSameSrc(
              Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, UNIFIED_INDEX_0,
              UNIFIED_INDEX_1);
        } else {
          auto *Unified0 = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src1, Index0, Src0, Index1);
          auto *Unified1 = lowerShuffleVector_UnifyFromDifferentSrcs(
              Src1, Index2, Src0, Index3);
          T = lowerShuffleVector_TwoFromSameSrc(
              Unified0, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Unified1,
              UNIFIED_INDEX_0, UNIFIED_INDEX_1);
        }
      }
      break;
      CASE_SRCS_IN(1, 0, 1, 1) : {
        assert(false && "Following code is untested but likely correct; test "
                        "and remove assert.");
        auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index0,
                                                                  Src0, Index1);
        T = lowerShuffleVector_TwoFromSameSrc(
            Unified, UNIFIED_INDEX_0, UNIFIED_INDEX_1, Src1, Index2, Index3);
      }
      break;
      CASE_SRCS_IN(1, 1, 0, 0) : {
        T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Src0,
                                              Index2, Index3);
      }
      break;
      CASE_SRCS_IN(1, 1, 0, 1) : {
        assert(false && "Following code is untested but likely correct; test "
                        "and remove assert.");
        auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src0, Index2,
                                                                  Src1, Index3);
        T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Unified,
                                              UNIFIED_INDEX_0, UNIFIED_INDEX_1);
      }
      break;
      CASE_SRCS_IN(1, 1, 1, 0) : {
        auto *Unified = lowerShuffleVector_UnifyFromDifferentSrcs(Src1, Index2,
                                                                  Src0, Index3);
        T = lowerShuffleVector_TwoFromSameSrc(Src1, Index0, Index1, Unified,
                                              UNIFIED_INDEX_0, UNIFIED_INDEX_1);
      }
      break;
      CASE_SRCS_IN(1, 1, 1, 1) : {
        assert(false && "Following code is untested but likely correct; test "
                        "and remove assert.");
        T = lowerShuffleVector_AllFromSameSrc(Src1, Index0, Index1, Index2,
                                              Index3);
      }
      break;
#undef CASE_SRCS_IN
    }

    assert(T != nullptr);
    assert(T->getType() == DestTy);
    _movp(Dest, T);
    return;
  } break;
  }

  // Unoptimized shuffle. Perform a series of inserts and extracts.
  Context.insert<InstFakeDef>(T);
  const Type ElementType = typeElementType(DestTy);
  for (SizeT I = 0; I < Instr->getNumIndexes(); ++I) {
    auto *Index = Instr->getIndex(I);
    const SizeT Elem = Index->getValue();
    auto *ExtElmt = makeReg(ElementType);
    if (Elem < NumElements) {
      lowerExtractElement(
          InstExtractElement::create(Func, ExtElmt, Src0, Index));
    } else {
      lowerExtractElement(InstExtractElement::create(
          Func, ExtElmt, Src1, Ctx->getConstantInt32(Elem - NumElements)));
    }
    auto *NewT = makeReg(DestTy);
    lowerInsertElement(InstInsertElement::create(Func, NewT, T, ExtElmt,
                                                 Ctx->getConstantInt32(I)));
    T = NewT;
  }
  _movp(Dest, T);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerSelect(const InstSelect *Select) {
  Variable *Dest = Select->getDest();

  Operand *Condition = Select->getCondition();
  // Handle folding opportunities.
  if (const Inst *Producer = FoldingInfo.getProducerFor(Condition)) {
    assert(Producer->isDeleted());
    switch (BoolFolding<Traits>::getProducerKind(Producer)) {
    default:
      break;
    case BoolFolding<Traits>::PK_Icmp32:
    case BoolFolding<Traits>::PK_Icmp64: {
      lowerIcmpAndConsumer(llvm::cast<InstIcmp>(Producer), Select);
      return;
    }
    case BoolFolding<Traits>::PK_Fcmp: {
      lowerFcmpAndConsumer(llvm::cast<InstFcmp>(Producer), Select);
      return;
    }
    }
  }

  if (isVectorType(Dest->getType())) {
    lowerSelectVector(Select);
    return;
  }

  Operand *CmpResult = legalize(Condition, Legal_Reg | Legal_Mem);
  Operand *Zero = Ctx->getConstantZero(IceType_i32);
  _cmp(CmpResult, Zero);
  Operand *SrcT = Select->getTrueOperand();
  Operand *SrcF = Select->getFalseOperand();
  const BrCond Cond = Traits::Cond::Br_ne;
  lowerSelectMove(Dest, Cond, SrcT, SrcF);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerSelectMove(Variable *Dest, BrCond Cond,
                                                Operand *SrcT, Operand *SrcF) {
  Type DestTy = Dest->getType();
  if (typeWidthInBytes(DestTy) == 1 || isFloatingType(DestTy)) {
    // The cmov instruction doesn't allow 8-bit or FP operands, so we need
    // explicit control flow.
    // d=cmp e,f; a=d?b:c ==> cmp e,f; a=b; jne L1; a=c; L1:
    auto *Label = InstX86Label::create(Func, this);
    SrcT = legalize(SrcT, Legal_Reg | Legal_Imm);
    _mov(Dest, SrcT);
    _br(Cond, Label);
    SrcF = legalize(SrcF, Legal_Reg | Legal_Imm);
    _redefined(_mov(Dest, SrcF));
    Context.insert(Label);
    return;
  }
  // mov t, SrcF; cmov_cond t, SrcT; mov dest, t
  // But if SrcT is immediate, we might be able to do better, as the cmov
  // instruction doesn't allow an immediate operand:
  // mov t, SrcT; cmov_!cond t, SrcF; mov dest, t
  if (llvm::isa<Constant>(SrcT) && !llvm::isa<Constant>(SrcF)) {
    std::swap(SrcT, SrcF);
    Cond = InstImpl<TraitsType>::InstX86Base::getOppositeCondition(Cond);
  }
  if (!Traits::Is64Bit && DestTy == IceType_i64) {
    SrcT = legalizeUndef(SrcT);
    SrcF = legalizeUndef(SrcF);
    // Set the low portion.
    auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
    lowerSelectIntMove(DestLo, Cond, loOperand(SrcT), loOperand(SrcF));
    // Set the high portion.
    auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
    lowerSelectIntMove(DestHi, Cond, hiOperand(SrcT), hiOperand(SrcF));
    return;
  }

  assert(DestTy == IceType_i16 || DestTy == IceType_i32 ||
         (Traits::Is64Bit && DestTy == IceType_i64));
  lowerSelectIntMove(Dest, Cond, SrcT, SrcF);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerSelectIntMove(Variable *Dest, BrCond Cond,
                                                   Operand *SrcT,
                                                   Operand *SrcF) {
  Variable *T = nullptr;
  SrcF = legalize(SrcF);
  _mov(T, SrcF);
  SrcT = legalize(SrcT, Legal_Reg | Legal_Mem);
  _cmov(T, SrcT, Cond);
  _mov(Dest, T);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerMove(Variable *Dest, Operand *Src,
                                          bool IsRedefinition) {
  assert(Dest->getType() == Src->getType());
  assert(!Dest->isRematerializable());
  if (!Traits::Is64Bit && Dest->getType() == IceType_i64) {
    Src = legalize(Src);
    Operand *SrcLo = loOperand(Src);
    Operand *SrcHi = hiOperand(Src);
    auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
    auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
    Variable *T_Lo = nullptr, *T_Hi = nullptr;
    _mov(T_Lo, SrcLo);
    _redefined(_mov(DestLo, T_Lo), IsRedefinition);
    _mov(T_Hi, SrcHi);
    _redefined(_mov(DestHi, T_Hi), IsRedefinition);
  } else {
    Operand *SrcLegal;
    if (Dest->hasReg()) {
      // If Dest already has a physical register, then only basic legalization
      // is needed, as the source operand can be a register, immediate, or
      // memory.
      SrcLegal = legalize(Src, Legal_Reg, Dest->getRegNum());
    } else {
      // If Dest could be a stack operand, then RI must be a physical register
      // or a scalar integer immediate.
      SrcLegal = legalize(Src, Legal_Reg | Legal_Imm);
    }
    if (isVectorType(Dest->getType())) {
      _redefined(_movp(Dest, SrcLegal), IsRedefinition);
    } else {
      _redefined(_mov(Dest, SrcLegal), IsRedefinition);
    }
  }
}

template <typename TraitsType>
bool TargetX86Base<TraitsType>::lowerOptimizeFcmpSelect(
    const InstFcmp *Fcmp, const InstSelect *Select) {
  Operand *CmpSrc0 = Fcmp->getSrc(0);
  Operand *CmpSrc1 = Fcmp->getSrc(1);
  Operand *SelectSrcT = Select->getTrueOperand();
  Operand *SelectSrcF = Select->getFalseOperand();
  Variable *SelectDest = Select->getDest();

  // TODO(capn): also handle swapped compare/select operand order.
  if (CmpSrc0 != SelectSrcT || CmpSrc1 != SelectSrcF)
    return false;

  // TODO(sehr, stichnot): fcmp/select patterns (e.g., minsd/maxss) go here.
  InstFcmp::FCond Condition = Fcmp->getCondition();
  switch (Condition) {
  default:
    return false;
  case InstFcmp::True:
    break;
  case InstFcmp::False:
    break;
  case InstFcmp::Ogt: {
    Variable *T = makeReg(SelectDest->getType());
    if (isScalarFloatingType(SelectSrcT->getType())) {
      _mov(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
      _maxss(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
      _mov(SelectDest, T);
    } else {
      _movp(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
      _maxps(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
      _movp(SelectDest, T);
    }
    return true;
  } break;
  case InstFcmp::Olt: {
    Variable *T = makeReg(SelectSrcT->getType());
    if (isScalarFloatingType(SelectSrcT->getType())) {
      _mov(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
      _minss(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
      _mov(SelectDest, T);
    } else {
      _movp(T, legalize(SelectSrcT, Legal_Reg | Legal_Mem));
      _minps(T, legalize(SelectSrcF, Legal_Reg | Legal_Mem));
      _movp(SelectDest, T);
    }
    return true;
  } break;
  }
  return false;
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerIcmp(const InstIcmp *Icmp) {
  Variable *Dest = Icmp->getDest();
  if (isVectorType(Dest->getType())) {
    lowerIcmpVector(Icmp);
  } else {
    constexpr Inst *Consumer = nullptr;
    lowerIcmpAndConsumer(Icmp, Consumer);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerSelectVector(const InstSelect *Instr) {
  Variable *Dest = Instr->getDest();
  Type DestTy = Dest->getType();
  Operand *SrcT = Instr->getTrueOperand();
  Operand *SrcF = Instr->getFalseOperand();
  Operand *Condition = Instr->getCondition();

  if (!isVectorType(DestTy))
    llvm::report_fatal_error("Expected a vector select");

  Type SrcTy = SrcT->getType();
  Variable *T = makeReg(SrcTy);
  Operand *SrcTRM = legalize(SrcT, Legal_Reg | Legal_Mem);
  Operand *SrcFRM = legalize(SrcF, Legal_Reg | Legal_Mem);

  if (InstructionSet >= Traits::SSE4_1) {
    // TODO(wala): If the condition operand is a constant, use blendps or
    // pblendw.
    //
    // Use blendvps or pblendvb to implement select.
    if (SrcTy == IceType_v4i1 || SrcTy == IceType_v4i32 ||
        SrcTy == IceType_v4f32) {
      Operand *ConditionRM = legalize(Condition, Legal_Reg | Legal_Mem);
      Variable *xmm0 = makeReg(IceType_v4i32, Traits::RegisterSet::Reg_xmm0);
      _movp(xmm0, ConditionRM);
      _psll(xmm0, Ctx->getConstantInt8(31));
      _movp(T, SrcFRM);
      _blendvps(T, SrcTRM, xmm0);
      _movp(Dest, T);
    } else {
      assert(typeNumElements(SrcTy) == 8 || typeNumElements(SrcTy) == 16);
      Type SignExtTy =
          Condition->getType() == IceType_v8i1 ? IceType_v8i16 : IceType_v16i8;
      Variable *xmm0 = makeReg(SignExtTy, Traits::RegisterSet::Reg_xmm0);
      lowerCast(InstCast::create(Func, InstCast::Sext, xmm0, Condition));
      _movp(T, SrcFRM);
      _pblendvb(T, SrcTRM, xmm0);
      _movp(Dest, T);
    }
    return;
  }
  // Lower select without Traits::SSE4.1:
  // a=d?b:c ==>
  //   if elementtype(d) != i1:
  //      d=sext(d);
  //   a=(b&d)|(c&~d);
  Variable *T2 = makeReg(SrcTy);
  // Sign extend the condition operand if applicable.
  if (SrcTy == IceType_v4f32) {
    // The sext operation takes only integer arguments.
    Variable *T3 = Func->makeVariable(IceType_v4i32);
    lowerCast(InstCast::create(Func, InstCast::Sext, T3, Condition));
    _movp(T, T3);
  } else if (typeElementType(SrcTy) != IceType_i1) {
    lowerCast(InstCast::create(Func, InstCast::Sext, T, Condition));
  } else {
    Operand *ConditionRM = legalize(Condition, Legal_Reg | Legal_Mem);
    _movp(T, ConditionRM);
  }
  _movp(T2, T);
  _pand(T, SrcTRM);
  _pandn(T2, SrcFRM);
  _por(T, T2);
  _movp(Dest, T);

  return;
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerStore(const InstStore *Instr) {
  Operand *Value = Instr->getData();
  Operand *Addr = Instr->getAddr();
  X86OperandMem *NewAddr = formMemoryOperand(Addr, Value->getType());
  doMockBoundsCheck(NewAddr);
  Type Ty = NewAddr->getType();

  if (!Traits::Is64Bit && Ty == IceType_i64) {
    Value = legalizeUndef(Value);
    Operand *ValueHi = legalize(hiOperand(Value), Legal_Reg | Legal_Imm);
    _store(ValueHi, llvm::cast<X86OperandMem>(hiOperand(NewAddr)));
    Operand *ValueLo = legalize(loOperand(Value), Legal_Reg | Legal_Imm);
    _store(ValueLo, llvm::cast<X86OperandMem>(loOperand(NewAddr)));
  } else if (isVectorType(Ty)) {
    _storep(legalizeToReg(Value), NewAddr);
  } else {
    Value = legalize(Value, Legal_Reg | Legal_Imm);
    _store(Value, NewAddr);
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::doAddressOptStore() {
  auto *Instr = llvm::cast<InstStore>(Context.getCur());
  Operand *Addr = Instr->getAddr();
  Operand *Data = Instr->getData();
  if (auto *OptAddr = computeAddressOpt(Instr, Data->getType(), Addr)) {
    Instr->setDeleted();
    auto *NewStore = Context.insert<InstStore>(Data, OptAddr);
    if (Instr->getDest())
      NewStore->setRmwBeacon(Instr->getRmwBeacon());
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::doAddressOptStoreSubVector() {
  auto *Intrinsic = llvm::cast<InstIntrinsicCall>(Context.getCur());
  Operand *Addr = Intrinsic->getArg(1);
  Operand *Data = Intrinsic->getArg(0);
  if (auto *OptAddr = computeAddressOpt(Intrinsic, Data->getType(), Addr)) {
    Intrinsic->setDeleted();
    const Ice::Intrinsics::IntrinsicInfo Info = {
        Ice::Intrinsics::StoreSubVector, Ice::Intrinsics::SideEffects_T,
        Ice::Intrinsics::ReturnsTwice_F, Ice::Intrinsics::MemoryWrite_T};
    auto Target = Ctx->getConstantUndef(Ice::IceType_i32);
    auto *NewStore =
        Context.insert<InstIntrinsicCall>(3, nullptr, Target, Info);
    NewStore->addArg(Data);
    NewStore->addArg(OptAddr);
    NewStore->addArg(Intrinsic->getArg(2));
  }
}

template <typename TraitsType>
Operand *TargetX86Base<TraitsType>::lowerCmpRange(Operand *Comparison,
                                                  uint64_t Min, uint64_t Max) {
  // TODO(ascull): 64-bit should not reach here but only because it is not
  // implemented yet. This should be able to handle the 64-bit case.
  assert(Traits::Is64Bit || Comparison->getType() != IceType_i64);
  // Subtracting 0 is a nop so don't do it
  if (Min != 0) {
    // Avoid clobbering the comparison by copying it
    Variable *T = nullptr;
    _mov(T, Comparison);
    _sub(T, Ctx->getConstantInt32(Min));
    Comparison = T;
  }

  _cmp(Comparison, Ctx->getConstantInt32(Max - Min));

  return Comparison;
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case,
                                                 Operand *Comparison,
                                                 bool DoneCmp,
                                                 CfgNode *DefaultTarget) {
  switch (Case.getKind()) {
  case CaseCluster::JumpTable: {
    InstX86Label *SkipJumpTable;

    Operand *RangeIndex =
        lowerCmpRange(Comparison, Case.getLow(), Case.getHigh());
    if (DefaultTarget == nullptr) {
      // Skip over jump table logic if comparison not in range and no default
      SkipJumpTable = InstX86Label::create(Func, this);
      _br(Traits::Cond::Br_a, SkipJumpTable);
    } else {
      _br(Traits::Cond::Br_a, DefaultTarget);
    }

    InstJumpTable *JumpTable = Case.getJumpTable();
    Context.insert(JumpTable);

    // Make sure the index is a register of the same width as the base
    Variable *Index;
    const Type PointerType = getPointerType();
    if (RangeIndex->getType() != PointerType) {
      Index = makeReg(PointerType);
      if (RangeIndex->getType() == IceType_i64) {
        assert(Traits::Is64Bit);
        _mov(Index, RangeIndex); // trunc
      } else {
        Operand *RangeIndexRM = legalize(RangeIndex, Legal_Reg | Legal_Mem);
        _movzx(Index, RangeIndexRM);
      }
    } else {
      Index = legalizeToReg(RangeIndex);
    }

    constexpr RelocOffsetT RelocOffset = 0;
    constexpr Variable *NoBase = nullptr;
    constexpr Constant *NoOffset = nullptr;
    auto JTName = GlobalString::createWithString(Ctx, JumpTable->getName());
    Constant *Offset = Ctx->getConstantSym(RelocOffset, JTName);
    uint16_t Shift = typeWidthInBytesLog2(PointerType);
    constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment;

    Variable *Target = nullptr;
    if (Traits::Is64Bit && NeedSandboxing) {
      assert(Index != nullptr && Index->getType() == IceType_i32);
    }

    if (PointerType == IceType_i32) {
      _mov(Target, X86OperandMem::create(Func, PointerType, NoBase, Offset,
                                         Index, Shift, Segment));
    } else {
      auto *Base = makeReg(IceType_i64);
      _lea(Base, X86OperandMem::create(Func, IceType_void, NoBase, Offset));
      _mov(Target, X86OperandMem::create(Func, PointerType, Base, NoOffset,
                                         Index, Shift, Segment));
    }

    lowerIndirectJump(Target);

    if (DefaultTarget == nullptr)
      Context.insert(SkipJumpTable);
    return;
  }
  case CaseCluster::Range: {
    if (Case.isUnitRange()) {
      // Single item
      if (!DoneCmp) {
        Constant *Value = Ctx->getConstantInt32(Case.getLow());
        _cmp(Comparison, Value);
      }
      _br(Traits::Cond::Br_e, Case.getTarget());
    } else if (DoneCmp && Case.isPairRange()) {
      // Range of two items with first item aleady compared against
      _br(Traits::Cond::Br_e, Case.getTarget());
      Constant *Value = Ctx->getConstantInt32(Case.getHigh());
      _cmp(Comparison, Value);
      _br(Traits::Cond::Br_e, Case.getTarget());
    } else {
      // Range
      lowerCmpRange(Comparison, Case.getLow(), Case.getHigh());
      _br(Traits::Cond::Br_be, Case.getTarget());
    }
    if (DefaultTarget != nullptr)
      _br(DefaultTarget);
    return;
  }
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerSwitch(const InstSwitch *Instr) {
  // Group cases together and navigate through them with a binary search
  CaseClusterArray CaseClusters = CaseCluster::clusterizeSwitch(Func, Instr);
  Operand *Src0 = Instr->getComparison();
  CfgNode *DefaultTarget = Instr->getLabelDefault();

  assert(CaseClusters.size() != 0); // Should always be at least one

  if (!Traits::Is64Bit && Src0->getType() == IceType_i64) {
    Src0 = legalize(Src0); // get Base/Index into physical registers
    Operand *Src0Lo = loOperand(Src0);
    Operand *Src0Hi = hiOperand(Src0);
    if (CaseClusters.back().getHigh() > UINT32_MAX) {
      // TODO(ascull): handle 64-bit case properly (currently naive version)
      // This might be handled by a higher level lowering of switches.
      SizeT NumCases = Instr->getNumCases();
      if (NumCases >= 2) {
        Src0Lo = legalizeToReg(Src0Lo);
        Src0Hi = legalizeToReg(Src0Hi);
      } else {
        Src0Lo = legalize(Src0Lo, Legal_Reg | Legal_Mem);
        Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem);
      }
      for (SizeT I = 0; I < NumCases; ++I) {
        Constant *ValueLo = Ctx->getConstantInt32(Instr->getValue(I));
        Constant *ValueHi = Ctx->getConstantInt32(Instr->getValue(I) >> 32);
        InstX86Label *Label = InstX86Label::create(Func, this);
        _cmp(Src0Lo, ValueLo);
        _br(Traits::Cond::Br_ne, Label);
        _cmp(Src0Hi, ValueHi);
        _br(Traits::Cond::Br_e, Instr->getLabel(I));
        Context.insert(Label);
      }
      _br(Instr->getLabelDefault());
      return;
    } else {
      // All the values are 32-bit so just check the operand is too and then
      // fall through to the 32-bit implementation. This is a common case.
      Src0Hi = legalize(Src0Hi, Legal_Reg | Legal_Mem);
      Constant *Zero = Ctx->getConstantInt32(0);
      _cmp(Src0Hi, Zero);
      _br(Traits::Cond::Br_ne, DefaultTarget);
      Src0 = Src0Lo;
    }
  }

  // 32-bit lowering

  if (CaseClusters.size() == 1) {
    // Jump straight to default if needed. Currently a common case as jump
    // tables occur on their own.
    constexpr bool DoneCmp = false;
    lowerCaseCluster(CaseClusters.front(), Src0, DoneCmp, DefaultTarget);
    return;
  }

  // Going to be using multiple times so get it in a register early
  Variable *Comparison = legalizeToReg(Src0);

  // A span is over the clusters
  struct SearchSpan {
    SearchSpan(SizeT Begin, SizeT Size, InstX86Label *Label)
        : Begin(Begin), Size(Size), Label(Label) {}

    SizeT Begin;
    SizeT Size;
    InstX86Label *Label;
  };
  // The stack will only grow to the height of the tree so 12 should be plenty
  std::stack<SearchSpan, llvm::SmallVector<SearchSpan, 12>> SearchSpanStack;
  SearchSpanStack.emplace(0, CaseClusters.size(), nullptr);
  bool DoneCmp = false;

  while (!SearchSpanStack.empty()) {
    SearchSpan Span = SearchSpanStack.top();
    SearchSpanStack.pop();

    if (Span.Label != nullptr)
      Context.insert(Span.Label);

    switch (Span.Size) {
    case 0:
      llvm::report_fatal_error("Invalid SearchSpan size");
      break;

    case 1:
      lowerCaseCluster(CaseClusters[Span.Begin], Comparison, DoneCmp,
                       SearchSpanStack.empty() ? nullptr : DefaultTarget);
      DoneCmp = false;
      break;

    case 2: {
      const CaseCluster *CaseA = &CaseClusters[Span.Begin];
      const CaseCluster *CaseB = &CaseClusters[Span.Begin + 1];

      // Placing a range last may allow register clobbering during the range
      // test. That means there is no need to clone the register. If it is a
      // unit range the comparison may have already been done in the binary
      // search (DoneCmp) and so it should be placed first. If this is a range
      // of two items and the comparison with the low value has already been
      // done, comparing with the other element is cheaper than a range test.
      // If the low end of the range is zero then there is no subtraction and
      // nothing to be gained.
      if (!CaseA->isUnitRange() &&
          !(CaseA->getLow() == 0 || (DoneCmp && CaseA->isPairRange()))) {
        std::swap(CaseA, CaseB);
        DoneCmp = false;
      }

      lowerCaseCluster(*CaseA, Comparison, DoneCmp);
      DoneCmp = false;
      lowerCaseCluster(*CaseB, Comparison, DoneCmp,
                       SearchSpanStack.empty() ? nullptr : DefaultTarget);
    } break;

    default:
      // Pick the middle item and branch b or ae
      SizeT PivotIndex = Span.Begin + (Span.Size / 2);
      const CaseCluster &Pivot = CaseClusters[PivotIndex];
      Constant *Value = Ctx->getConstantInt32(Pivot.getLow());
      InstX86Label *Label = InstX86Label::create(Func, this);
      _cmp(Comparison, Value);
      // TODO(ascull): does it alway have to be far?
      _br(Traits::Cond::Br_b, Label, InstX86Br::Far);
      // Lower the left and (pivot+right) sides, falling through to the right
      SearchSpanStack.emplace(Span.Begin, Span.Size / 2, Label);
      SearchSpanStack.emplace(PivotIndex, Span.Size - (Span.Size / 2), nullptr);
      DoneCmp = true;
      break;
    }
  }

  _br(DefaultTarget);
}

/// The following pattern occurs often in lowered C and C++ code:
///
///   %cmp     = fcmp/icmp pred <n x ty> %src0, %src1
///   %cmp.ext = sext <n x i1> %cmp to <n x ty>
///
/// We can eliminate the sext operation by copying the result of pcmpeqd,
/// pcmpgtd, or cmpps (which produce sign extended results) to the result of the
/// sext operation.
template <typename TraitsType>
void TargetX86Base<TraitsType>::eliminateNextVectorSextInstruction(
    Variable *SignExtendedResult) {
  if (auto *NextCast =
          llvm::dyn_cast_or_null<InstCast>(Context.getNextInst())) {
    if (NextCast->getCastKind() == InstCast::Sext &&
        NextCast->getSrc(0) == SignExtendedResult) {
      NextCast->setDeleted();
      _movp(NextCast->getDest(), legalizeToReg(SignExtendedResult));
      // Skip over the instruction.
      Context.advanceNext();
    }
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerUnreachable(
    const InstUnreachable * /*Instr*/) {
  _ud2();
  // Add a fake use of esp to make sure esp adjustments after the unreachable
  // do not get dead-code eliminated.
  keepEspLiveAtExit();
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerBreakpoint(
    const InstBreakpoint * /*Instr*/) {
  _int3();
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerRMW(const InstX86FakeRMW *RMW) {
  // If the beacon variable's live range does not end in this instruction, then
  // it must end in the modified Store instruction that follows. This means
  // that the original Store instruction is still there, either because the
  // value being stored is used beyond the Store instruction, or because dead
  // code elimination did not happen. In either case, we cancel RMW lowering
  // (and the caller deletes the RMW instruction).
  if (!RMW->isLastUse(RMW->getBeacon()))
    return;
  Operand *Src = RMW->getData();
  Type Ty = Src->getType();
  X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
  doMockBoundsCheck(Addr);
  if (!Traits::Is64Bit && Ty == IceType_i64) {
    Src = legalizeUndef(Src);
    Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm);
    Operand *SrcHi = legalize(hiOperand(Src), Legal_Reg | Legal_Imm);
    auto *AddrLo = llvm::cast<X86OperandMem>(loOperand(Addr));
    auto *AddrHi = llvm::cast<X86OperandMem>(hiOperand(Addr));
    switch (RMW->getOp()) {
    default:
      // TODO(stichnot): Implement other arithmetic operators.
      break;
    case InstArithmetic::Add:
      _add_rmw(AddrLo, SrcLo);
      _adc_rmw(AddrHi, SrcHi);
      return;
    case InstArithmetic::Sub:
      _sub_rmw(AddrLo, SrcLo);
      _sbb_rmw(AddrHi, SrcHi);
      return;
    case InstArithmetic::And:
      _and_rmw(AddrLo, SrcLo);
      _and_rmw(AddrHi, SrcHi);
      return;
    case InstArithmetic::Or:
      _or_rmw(AddrLo, SrcLo);
      _or_rmw(AddrHi, SrcHi);
      return;
    case InstArithmetic::Xor:
      _xor_rmw(AddrLo, SrcLo);
      _xor_rmw(AddrHi, SrcHi);
      return;
    }
  } else {
    // x86-32: i8, i16, i32
    // x86-64: i8, i16, i32, i64
    switch (RMW->getOp()) {
    default:
      // TODO(stichnot): Implement other arithmetic operators.
      break;
    case InstArithmetic::Add:
      Src = legalize(Src, Legal_Reg | Legal_Imm);
      _add_rmw(Addr, Src);
      return;
    case InstArithmetic::Sub:
      Src = legalize(Src, Legal_Reg | Legal_Imm);
      _sub_rmw(Addr, Src);
      return;
    case InstArithmetic::And:
      Src = legalize(Src, Legal_Reg | Legal_Imm);
      _and_rmw(Addr, Src);
      return;
    case InstArithmetic::Or:
      Src = legalize(Src, Legal_Reg | Legal_Imm);
      _or_rmw(Addr, Src);
      return;
    case InstArithmetic::Xor:
      Src = legalize(Src, Legal_Reg | Legal_Imm);
      _xor_rmw(Addr, Src);
      return;
    }
  }
  llvm::report_fatal_error("Couldn't lower RMW instruction");
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::lowerOther(const Inst *Instr) {
  if (const auto *RMW = llvm::dyn_cast<InstX86FakeRMW>(Instr)) {
    lowerRMW(RMW);
  } else {
    TargetLowering::lowerOther(Instr);
  }
}

/// Turn an i64 Phi instruction into a pair of i32 Phi instructions, to preserve
/// integrity of liveness analysis. Undef values are also turned into zeroes,
/// since loOperand() and hiOperand() don't expect Undef input.  Also, in
/// Non-SFI mode, add a FakeUse(RebasePtr) for every pooled constant operand.
template <typename TraitsType> void TargetX86Base<TraitsType>::prelowerPhis() {
  if (getFlags().getUseNonsfi()) {
    assert(RebasePtr);
    CfgNode *Node = Context.getNode();
    uint32_t RebasePtrUseCount = 0;
    for (Inst &I : Node->getPhis()) {
      auto *Phi = llvm::dyn_cast<InstPhi>(&I);
      if (Phi->isDeleted())
        continue;
      for (SizeT I = 0; I < Phi->getSrcSize(); ++I) {
        Operand *Src = Phi->getSrc(I);
        // TODO(stichnot): This over-counts for +0.0, and under-counts for other
        // kinds of pooling.
        if (llvm::isa<ConstantRelocatable>(Src) ||
            llvm::isa<ConstantFloat>(Src) || llvm::isa<ConstantDouble>(Src)) {
          ++RebasePtrUseCount;
        }
      }
    }
    if (RebasePtrUseCount) {
      Node->getInsts().push_front(InstFakeUse::create(Func, RebasePtr));
    }
  }
  if (Traits::Is64Bit) {
    // On x86-64 we don't need to prelower phis -- the architecture can handle
    // 64-bit integer natively.
    return;
  }

  // Pause constant blinding or pooling, blinding or pooling will be done later
  // during phi lowering assignments
  BoolFlagSaver B(RandomizationPoolingPaused, true);
  PhiLowering::prelowerPhis32Bit<TargetX86Base<TraitsType>>(
      this, Context.getNode(), Func);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::genTargetHelperCallFor(Inst *Instr) {
  uint32_t StackArgumentsSize = 0;
  if (auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
    RuntimeHelper HelperID = RuntimeHelper::H_Num;
    Variable *Dest = Arith->getDest();
    Type DestTy = Dest->getType();
    if (!Traits::Is64Bit && DestTy == IceType_i64) {
      switch (Arith->getOp()) {
      default:
        return;
      case InstArithmetic::Udiv:
        HelperID = RuntimeHelper::H_udiv_i64;
        break;
      case InstArithmetic::Sdiv:
        HelperID = RuntimeHelper::H_sdiv_i64;
        break;
      case InstArithmetic::Urem:
        HelperID = RuntimeHelper::H_urem_i64;
        break;
      case InstArithmetic::Srem:
        HelperID = RuntimeHelper::H_srem_i64;
        break;
      }
    } else if (isVectorType(DestTy)) {
      Variable *Dest = Arith->getDest();
      Operand *Src0 = Arith->getSrc(0);
      Operand *Src1 = Arith->getSrc(1);
      switch (Arith->getOp()) {
      default:
        return;
      case InstArithmetic::Mul:
        if (DestTy == IceType_v16i8) {
          scalarizeArithmetic(Arith->getOp(), Dest, Src0, Src1);
          Arith->setDeleted();
        }
        return;
      case InstArithmetic::Shl:
      case InstArithmetic::Lshr:
      case InstArithmetic::Ashr:
        if (llvm::isa<Constant>(Src1)) {
          return;
        }
      case InstArithmetic::Udiv:
      case InstArithmetic::Urem:
      case InstArithmetic::Sdiv:
      case InstArithmetic::Srem:
      case InstArithmetic::Frem:
        scalarizeArithmetic(Arith->getOp(), Dest, Src0, Src1);
        Arith->setDeleted();
        return;
      }
    } else {
      switch (Arith->getOp()) {
      default:
        return;
      case InstArithmetic::Frem:
        if (isFloat32Asserting32Or64(DestTy))
          HelperID = RuntimeHelper::H_frem_f32;
        else
          HelperID = RuntimeHelper::H_frem_f64;
      }
    }
    constexpr SizeT MaxSrcs = 2;
    InstCall *Call = makeHelperCall(HelperID, Dest, MaxSrcs);
    Call->addArg(Arith->getSrc(0));
    Call->addArg(Arith->getSrc(1));
    StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
    Context.insert(Call);
    Arith->setDeleted();
  } else if (auto *Cast = llvm::dyn_cast<InstCast>(Instr)) {
    InstCast::OpKind CastKind = Cast->getCastKind();
    Operand *Src0 = Cast->getSrc(0);
    const Type SrcType = Src0->getType();
    Variable *Dest = Cast->getDest();
    const Type DestTy = Dest->getType();
    RuntimeHelper HelperID = RuntimeHelper::H_Num;
    Variable *CallDest = Dest;
    switch (CastKind) {
    default:
      return;
    case InstCast::Fptosi:
      if (!Traits::Is64Bit && DestTy == IceType_i64) {
        HelperID = isFloat32Asserting32Or64(SrcType)
                       ? RuntimeHelper::H_fptosi_f32_i64
                       : RuntimeHelper::H_fptosi_f64_i64;
      } else {
        return;
      }
      break;
    case InstCast::Fptoui:
      if (isVectorType(DestTy)) {
        assert(DestTy == IceType_v4i32);
        assert(SrcType == IceType_v4f32);
        HelperID = RuntimeHelper::H_fptoui_4xi32_f32;
      } else if (DestTy == IceType_i64 ||
                 (!Traits::Is64Bit && DestTy == IceType_i32)) {
        if (Traits::Is64Bit) {
          HelperID = isFloat32Asserting32Or64(SrcType)
                         ? RuntimeHelper::H_fptoui_f32_i64
                         : RuntimeHelper::H_fptoui_f64_i64;
        } else if (isInt32Asserting32Or64(DestTy)) {
          HelperID = isFloat32Asserting32Or64(SrcType)
                         ? RuntimeHelper::H_fptoui_f32_i32
                         : RuntimeHelper::H_fptoui_f64_i32;
        } else {
          HelperID = isFloat32Asserting32Or64(SrcType)
                         ? RuntimeHelper::H_fptoui_f32_i64
                         : RuntimeHelper::H_fptoui_f64_i64;
        }
      } else {
        return;
      }
      break;
    case InstCast::Sitofp:
      if (!Traits::Is64Bit && SrcType == IceType_i64) {
        HelperID = isFloat32Asserting32Or64(DestTy)
                       ? RuntimeHelper::H_sitofp_i64_f32
                       : RuntimeHelper::H_sitofp_i64_f64;
      } else {
        return;
      }
      break;
    case InstCast::Uitofp:
      if (isVectorType(SrcType)) {
        assert(DestTy == IceType_v4f32);
        assert(SrcType == IceType_v4i32);
        HelperID = RuntimeHelper::H_uitofp_4xi32_4xf32;
      } else if (SrcType == IceType_i64 ||
                 (!Traits::Is64Bit && SrcType == IceType_i32)) {
        if (isInt32Asserting32Or64(SrcType)) {
          HelperID = isFloat32Asserting32Or64(DestTy)
                         ? RuntimeHelper::H_uitofp_i32_f32
                         : RuntimeHelper::H_uitofp_i32_f64;
        } else {
          HelperID = isFloat32Asserting32Or64(DestTy)
                         ? RuntimeHelper::H_uitofp_i64_f32
                         : RuntimeHelper::H_uitofp_i64_f64;
        }
      } else {
        return;
      }
      break;
    case InstCast::Bitcast: {
      if (DestTy == Src0->getType())
        return;
      switch (DestTy) {
      default:
        return;
      case IceType_i8:
        assert(Src0->getType() == IceType_v8i1);
        HelperID = RuntimeHelper::H_bitcast_8xi1_i8;
        CallDest = Func->makeVariable(IceType_i32);
        break;
      case IceType_i16:
        assert(Src0->getType() == IceType_v16i1);
        HelperID = RuntimeHelper::H_bitcast_16xi1_i16;
        CallDest = Func->makeVariable(IceType_i32);
        break;
      case IceType_v8i1: {
        assert(Src0->getType() == IceType_i8);
        HelperID = RuntimeHelper::H_bitcast_i8_8xi1;
        Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
        // Arguments to functions are required to be at least 32 bits wide.
        Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
        Src0 = Src0AsI32;
      } break;
      case IceType_v16i1: {
        assert(Src0->getType() == IceType_i16);
        HelperID = RuntimeHelper::H_bitcast_i16_16xi1;
        Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
        // Arguments to functions are required to be at least 32 bits wide.
        Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
        Src0 = Src0AsI32;
      } break;
      }
    } break;
    }
    constexpr SizeT MaxSrcs = 1;
    InstCall *Call = makeHelperCall(HelperID, CallDest, MaxSrcs);
    Call->addArg(Src0);
    StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
    Context.insert(Call);
    // The PNaCl ABI disallows i8/i16 return types, so truncate the helper call
    // result to the appropriate type as necessary.
    if (CallDest->getType() != Dest->getType())
      Context.insert<InstCast>(InstCast::Trunc, Dest, CallDest);
    Cast->setDeleted();
  } else if (auto *Intrinsic = llvm::dyn_cast<InstIntrinsicCall>(Instr)) {
    CfgVector<Type> ArgTypes;
    Type ReturnType = IceType_void;
    switch (Intrinsics::IntrinsicID ID = Intrinsic->getIntrinsicInfo().ID) {
    default:
      return;
    case Intrinsics::Ctpop: {
      Operand *Val = Intrinsic->getArg(0);
      Type ValTy = Val->getType();
      if (ValTy == IceType_i64)
        ArgTypes = {IceType_i64};
      else
        ArgTypes = {IceType_i32};
      ReturnType = IceType_i32;
    } break;
    case Intrinsics::Longjmp:
      ArgTypes = {IceType_i32, IceType_i32};
      ReturnType = IceType_void;
      break;
    case Intrinsics::Memcpy:
      ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
      ReturnType = IceType_void;
      break;
    case Intrinsics::Memmove:
      ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
      ReturnType = IceType_void;
      break;
    case Intrinsics::Memset:
      ArgTypes = {IceType_i32, IceType_i32, IceType_i32};
      ReturnType = IceType_void;
      break;
    case Intrinsics::NaClReadTP:
      ReturnType = IceType_i32;
      break;
    case Intrinsics::Setjmp:
      ArgTypes = {IceType_i32};
      ReturnType = IceType_i32;
      break;
    }
    StackArgumentsSize = getCallStackArgumentsSizeBytes(ArgTypes, ReturnType);
  } else if (auto *Call = llvm::dyn_cast<InstCall>(Instr)) {
    StackArgumentsSize = getCallStackArgumentsSizeBytes(Call);
  } else if (auto *Ret = llvm::dyn_cast<InstRet>(Instr)) {
    if (!Ret->hasRetValue())
      return;
    Operand *RetValue = Ret->getRetValue();
    Type ReturnType = RetValue->getType();
    if (!isScalarFloatingType(ReturnType))
      return;
    StackArgumentsSize = typeWidthInBytes(ReturnType);
  } else {
    return;
  }
  StackArgumentsSize = Traits::applyStackAlignment(StackArgumentsSize);
  updateMaxOutArgsSizeBytes(StackArgumentsSize);
}

template <typename TraitsType>
uint32_t TargetX86Base<TraitsType>::getCallStackArgumentsSizeBytes(
    const CfgVector<Type> &ArgTypes, Type ReturnType) {
  uint32_t OutArgumentsSizeBytes = 0;
  uint32_t XmmArgCount = 0;
  uint32_t GprArgCount = 0;
  for (Type Ty : ArgTypes) {
    // The PNaCl ABI requires the width of arguments to be at least 32 bits.
    assert(typeWidthInBytes(Ty) >= 4);
    if (isVectorType(Ty) && XmmArgCount < Traits::X86_MAX_XMM_ARGS) {
      ++XmmArgCount;
    } else if (isScalarFloatingType(Ty) && Traits::X86_PASS_SCALAR_FP_IN_XMM &&
               XmmArgCount < Traits::X86_MAX_XMM_ARGS) {
      ++XmmArgCount;
    } else if (isScalarIntegerType(Ty) &&
               GprArgCount < Traits::X86_MAX_GPR_ARGS) {
      // The 64 bit ABI allows some integers to be passed in GPRs.
      ++GprArgCount;
    } else {
      if (isVectorType(Ty)) {
        OutArgumentsSizeBytes =
            Traits::applyStackAlignment(OutArgumentsSizeBytes);
      }
      OutArgumentsSizeBytes += typeWidthInBytesOnStack(Ty);
    }
  }
  if (Traits::Is64Bit)
    return OutArgumentsSizeBytes;
  // The 32 bit ABI requires floating point values to be returned on the x87 FP
  // stack. Ensure there is enough space for the fstp/movs for floating returns.
  if (isScalarFloatingType(ReturnType)) {
    OutArgumentsSizeBytes =
        std::max(OutArgumentsSizeBytes,
                 static_cast<uint32_t>(typeWidthInBytesOnStack(ReturnType)));
  }
  return OutArgumentsSizeBytes;
}

template <typename TraitsType>
uint32_t TargetX86Base<TraitsType>::getCallStackArgumentsSizeBytes(
    const InstCall *Instr) {
  // Build a vector of the arguments' types.
  const SizeT NumArgs = Instr->getNumArgs();
  CfgVector<Type> ArgTypes;
  ArgTypes.reserve(NumArgs);
  for (SizeT i = 0; i < NumArgs; ++i) {
    Operand *Arg = Instr->getArg(i);
    ArgTypes.emplace_back(Arg->getType());
  }
  // Compute the return type (if any);
  Type ReturnType = IceType_void;
  Variable *Dest = Instr->getDest();
  if (Dest != nullptr)
    ReturnType = Dest->getType();
  return getCallStackArgumentsSizeBytes(ArgTypes, ReturnType);
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::makeZeroedRegister(Type Ty,
                                                        RegNumT RegNum) {
  Variable *Reg = makeReg(Ty, RegNum);
  switch (Ty) {
  case IceType_i1:
  case IceType_i8:
  case IceType_i16:
  case IceType_i32:
  case IceType_i64:
    // Conservatively do "mov reg, 0" to avoid modifying FLAGS.
    _mov(Reg, Ctx->getConstantZero(Ty));
    break;
  case IceType_f32:
  case IceType_f64:
    Context.insert<InstFakeDef>(Reg);
    _xorps(Reg, Reg);
    break;
  default:
    // All vector types use the same pxor instruction.
    assert(isVectorType(Ty));
    Context.insert<InstFakeDef>(Reg);
    _pxor(Reg, Reg);
    break;
  }
  return Reg;
}

// There is no support for loading or emitting vector constants, so the vector
// values returned from makeVectorOfZeros, makeVectorOfOnes, etc. are
// initialized with register operations.
//
// TODO(wala): Add limited support for vector constants so that complex
// initialization in registers is unnecessary.

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::makeVectorOfZeros(Type Ty,
                                                       RegNumT RegNum) {
  return makeZeroedRegister(Ty, RegNum);
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::makeVectorOfMinusOnes(Type Ty,
                                                           RegNumT RegNum) {
  Variable *MinusOnes = makeReg(Ty, RegNum);
  // Insert a FakeDef so the live range of MinusOnes is not overestimated.
  Context.insert<InstFakeDef>(MinusOnes);
  if (Ty == IceType_f64)
    // Making a vector of minus ones of type f64 is currently only used for the
    // fabs intrinsic.  To use the f64 type to create this mask with pcmpeqq
    // requires SSE 4.1.  Since we're just creating a mask, pcmpeqd does the
    // same job and only requires SSE2.
    _pcmpeq(MinusOnes, MinusOnes, IceType_f32);
  else
    _pcmpeq(MinusOnes, MinusOnes);
  return MinusOnes;
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::makeVectorOfOnes(Type Ty, RegNumT RegNum) {
  Variable *Dest = makeVectorOfZeros(Ty, RegNum);
  Variable *MinusOne = makeVectorOfMinusOnes(Ty);
  _psub(Dest, MinusOne);
  return Dest;
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::makeVectorOfHighOrderBits(Type Ty,
                                                               RegNumT RegNum) {
  assert(Ty == IceType_v4i32 || Ty == IceType_v4f32 || Ty == IceType_v8i16 ||
         Ty == IceType_v16i8);
  if (Ty == IceType_v4f32 || Ty == IceType_v4i32 || Ty == IceType_v8i16) {
    Variable *Reg = makeVectorOfOnes(Ty, RegNum);
    SizeT Shift =
        typeWidthInBytes(typeElementType(Ty)) * Traits::X86_CHAR_BIT - 1;
    _psll(Reg, Ctx->getConstantInt8(Shift));
    return Reg;
  } else {
    // SSE has no left shift operation for vectors of 8 bit integers.
    constexpr uint32_t HIGH_ORDER_BITS_MASK = 0x80808080;
    Constant *ConstantMask = Ctx->getConstantInt32(HIGH_ORDER_BITS_MASK);
    Variable *Reg = makeReg(Ty, RegNum);
    _movd(Reg, legalize(ConstantMask, Legal_Reg | Legal_Mem));
    _pshufd(Reg, Reg, Ctx->getConstantZero(IceType_i8));
    return Reg;
  }
}

/// Construct a mask in a register that can be and'ed with a floating-point
/// value to mask off its sign bit. The value will be <4 x 0x7fffffff> for f32
/// and v4f32, and <2 x 0x7fffffffffffffff> for f64. Construct it as vector of
/// ones logically right shifted one bit.
// TODO(stichnot): Fix the wala
// TODO: above, to represent vector constants in memory.
template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::makeVectorOfFabsMask(Type Ty,
                                                          RegNumT RegNum) {
  Variable *Reg = makeVectorOfMinusOnes(Ty, RegNum);
  _psrl(Reg, Ctx->getConstantInt8(1));
  return Reg;
}

template <typename TraitsType>
typename TargetX86Base<TraitsType>::X86OperandMem *
TargetX86Base<TraitsType>::getMemoryOperandForStackSlot(Type Ty, Variable *Slot,
                                                        uint32_t Offset) {
  // Ensure that Loc is a stack slot.
  assert(Slot->mustNotHaveReg());
  assert(Slot->getRegNum().hasNoValue());
  // Compute the location of Loc in memory.
  // TODO(wala,stichnot): lea should not
  // be required. The address of the stack slot is known at compile time
  // (although not until after addProlog()).
  const Type PointerType = getPointerType();
  Variable *Loc = makeReg(PointerType);
  _lea(Loc, Slot);
  Constant *ConstantOffset = Ctx->getConstantInt32(Offset);
  return X86OperandMem::create(Func, Ty, Loc, ConstantOffset);
}

/// Lowering helper to copy a scalar integer source operand into some 8-bit GPR.
/// Src is assumed to already be legalized.  If the source operand is known to
/// be a memory or immediate operand, a simple mov will suffice.  But if the
/// source operand can be a physical register, then it must first be copied into
/// a physical register that is truncable to 8-bit, then truncated into a
/// physical register that can receive a truncation, and finally copied into the
/// result 8-bit register (which in general can be any 8-bit register).  For
/// example, moving %ebp into %ah may be accomplished as:
///   movl %ebp, %edx
///   mov_trunc %edx, %dl  // this redundant assignment is ultimately elided
///   movb %dl, %ah
/// On the other hand, moving a memory or immediate operand into ah:
///   movb 4(%ebp), %ah
///   movb $my_imm, %ah
///
/// Note #1.  On a 64-bit target, the "movb 4(%ebp), %ah" is likely not
/// encodable, so RegNum=Reg_ah should NOT be given as an argument.  Instead,
/// use RegNum=RegNumT() and then let the caller do a separate copy into
/// Reg_ah.
///
/// Note #2.  ConstantRelocatable operands are also put through this process
/// (not truncated directly) because our ELF emitter does R_386_32 relocations
/// but not R_386_8 relocations.
///
/// Note #3.  If Src is a Variable, the result will be an infinite-weight i8
/// Variable with the RCX86_IsTrunc8Rcvr register class.  As such, this helper
/// is a convenient way to prevent ah/bh/ch/dh from being an (invalid) argument
/// to the pinsrb instruction.
template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::copyToReg8(Operand *Src, RegNumT RegNum) {
  Type Ty = Src->getType();
  assert(isScalarIntegerType(Ty));
  assert(Ty != IceType_i1);
  Variable *Reg = makeReg(IceType_i8, RegNum);
  Reg->setRegClass(RCX86_IsTrunc8Rcvr);
  if (llvm::isa<Variable>(Src) || llvm::isa<ConstantRelocatable>(Src)) {
    Variable *SrcTruncable = makeReg(Ty);
    switch (Ty) {
    case IceType_i64:
      SrcTruncable->setRegClass(RCX86_Is64To8);
      break;
    case IceType_i32:
      SrcTruncable->setRegClass(RCX86_Is32To8);
      break;
    case IceType_i16:
      SrcTruncable->setRegClass(RCX86_Is16To8);
      break;
    default:
      // i8 - just use default register class
      break;
    }
    Variable *SrcRcvr = makeReg(IceType_i8);
    SrcRcvr->setRegClass(RCX86_IsTrunc8Rcvr);
    _mov(SrcTruncable, Src);
    _mov(SrcRcvr, SrcTruncable);
    Src = SrcRcvr;
  }
  _mov(Reg, Src);
  return Reg;
}

/// Helper for legalize() to emit the right code to lower an operand to a
/// register of the appropriate type.
template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::copyToReg(Operand *Src, RegNumT RegNum) {
  Type Ty = Src->getType();
  Variable *Reg = makeReg(Ty, RegNum);
  if (isVectorType(Ty)) {
    _movp(Reg, Src);
  } else {
    _mov(Reg, Src);
  }
  return Reg;
}

template <typename TraitsType>
Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed,
                                             RegNumT RegNum) {
  const bool UseNonsfi = getFlags().getUseNonsfi();
  const Type Ty = From->getType();
  // Assert that a physical register is allowed. To date, all calls to
  // legalize() allow a physical register. If a physical register needs to be
  // explicitly disallowed, then new code will need to be written to force a
  // spill.
  assert(Allowed & Legal_Reg);
  // If we're asking for a specific physical register, make sure we're not
  // allowing any other operand kinds. (This could be future work, e.g. allow
  // the shl shift amount to be either an immediate or in ecx.)
  assert(RegNum.hasNoValue() || Allowed == Legal_Reg);

  // Substitute with an available infinite-weight variable if possible.  Only do
  // this when we are not asking for a specific register, and when the
  // substitution is not locked to a specific register, and when the types
  // match, in order to capture the vast majority of opportunities and avoid
  // corner cases in the lowering.
  if (RegNum.hasNoValue()) {
    if (Variable *Subst = getContext().availabilityGet(From)) {
      // At this point we know there is a potential substitution available.
      if (Subst->mustHaveReg() && !Subst->hasReg()) {
        // At this point we know the substitution will have a register.
        if (From->getType() == Subst->getType()) {
          // At this point we know the substitution's register is compatible.
          return Subst;
        }
      }
    }
  }

  if (auto *Mem = llvm::dyn_cast<X86OperandMem>(From)) {
    // Before doing anything with a Mem operand, we need to ensure that the
    // Base and Index components are in physical registers.
    Variable *Base = Mem->getBase();
    Variable *Index = Mem->getIndex();
    Constant *Offset = Mem->getOffset();
    Variable *RegBase = nullptr;
    Variable *RegIndex = nullptr;
    uint16_t Shift = Mem->getShift();
    if (Base) {
      RegBase = llvm::cast<Variable>(
          legalize(Base, Legal_Reg | Legal_Rematerializable));
    }
    if (Index) {
      // TODO(jpp): perhaps we should only allow Legal_Reg if
      // Base->isRematerializable.
      RegIndex = llvm::cast<Variable>(
          legalize(Index, Legal_Reg | Legal_Rematerializable));
    }

    if (Base != RegBase || Index != RegIndex) {
      Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex, Shift,
                                  Mem->getSegmentRegister());
    }

    // For all Memory Operands, we do randomization/pooling here.
    From = randomizeOrPoolImmediate(Mem);

    if (!(Allowed & Legal_Mem)) {
      From = copyToReg(From, RegNum);
    }
    return From;
  }

  if (auto *Const = llvm::dyn_cast<Constant>(From)) {
    if (llvm::isa<ConstantUndef>(Const)) {
      From = legalizeUndef(Const, RegNum);
      if (isVectorType(Ty))
        return From;
      Const = llvm::cast<Constant>(From);
    }
    // There should be no constants of vector type (other than undef).
    assert(!isVectorType(Ty));

    // If the operand is a 64 bit constant integer we need to legalize it to a
    // register in x86-64.
    if (Traits::Is64Bit) {
      if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Const)) {
        if (!Utils::IsInt(32, C64->getValue())) {
          if (RegNum.hasValue()) {
            assert(Traits::getGprForType(IceType_i64, RegNum) == RegNum);
          }
          return copyToReg(Const, RegNum);
        }
      }
    }

    // If the operand is an 32 bit constant integer, we should check whether we
    // need to randomize it or pool it.
    if (auto *C = llvm::dyn_cast<ConstantInteger32>(Const)) {
      Operand *NewConst = randomizeOrPoolImmediate(C, RegNum);
      if (NewConst != Const) {
        return NewConst;
      }
    }

    if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Const)) {
      // If the operand is a ConstantRelocatable, and Legal_AddrAbs is not
      // specified, and UseNonsfi is indicated, we need to add RebasePtr.
      if (UseNonsfi && !(Allowed & Legal_AddrAbs)) {
        assert(Ty == IceType_i32);
        Variable *NewVar = makeReg(Ty, RegNum);
        auto *Mem = Traits::X86OperandMem::create(Func, Ty, nullptr, CR);
        // LEAs are not automatically sandboxed, thus we explicitly invoke
        // _sandbox_mem_reference.
        _lea(NewVar, _sandbox_mem_reference(Mem));
        From = NewVar;
      }
    } else if (isScalarFloatingType(Ty)) {
      // Convert a scalar floating point constant into an explicit memory
      // operand.
      if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(Const)) {
        if (Utils::isPositiveZero(ConstFloat->getValue()))
          return makeZeroedRegister(Ty, RegNum);
      } else if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(Const)) {
        if (Utils::isPositiveZero(ConstDouble->getValue()))
          return makeZeroedRegister(Ty, RegNum);
      }

      auto *CFrom = llvm::cast<Constant>(From);
      assert(CFrom->getShouldBePooled());
      Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
      auto *Mem = X86OperandMem::create(Func, Ty, nullptr, Offset);
      From = Mem;
    }

    bool NeedsReg = false;
    if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty))
      // Immediate specifically not allowed.
      NeedsReg = true;
    if (!(Allowed & Legal_Mem) && isScalarFloatingType(Ty))
      // On x86, FP constants are lowered to mem operands.
      NeedsReg = true;
    if (NeedsReg) {
      From = copyToReg(From, RegNum);
    }
    return From;
  }

  if (auto *Var = llvm::dyn_cast<Variable>(From)) {
    // Check if the variable is guaranteed a physical register. This can happen
    // either when the variable is pre-colored or when it is assigned infinite
    // weight.
    bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
    bool MustRematerialize =
        (Var->isRematerializable() && !(Allowed & Legal_Rematerializable));
    // We need a new physical register for the operand if:
    // - Mem is not allowed and Var isn't guaranteed a physical register, or
    // - RegNum is required and Var->getRegNum() doesn't match, or
    // - Var is a rematerializable variable and rematerializable pass-through is
    //   not allowed (in which case we need a lea instruction).
    if (MustRematerialize) {
      Variable *NewVar = makeReg(Ty, RegNum);
      // Since Var is rematerializable, the offset will be added when the lea is
      // emitted.
      constexpr Constant *NoOffset = nullptr;
      auto *Mem = X86OperandMem::create(Func, Ty, Var, NoOffset);
      _lea(NewVar, Mem);
      From = NewVar;
    } else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
               (RegNum.hasValue() && RegNum != Var->getRegNum())) {
      From = copyToReg(From, RegNum);
    }
    return From;
  }

  llvm::report_fatal_error("Unhandled operand kind in legalize()");
  return From;
}

/// Provide a trivial wrapper to legalize() for this common usage.
template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::legalizeToReg(Operand *From,
                                                   RegNumT RegNum) {
  return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
}

/// Legalize undef values to concrete values.
template <typename TraitsType>
Operand *TargetX86Base<TraitsType>::legalizeUndef(Operand *From,
                                                  RegNumT RegNum) {
  Type Ty = From->getType();
  if (llvm::isa<ConstantUndef>(From)) {
    // Lower undefs to zero.  Another option is to lower undefs to an
    // uninitialized register; however, using an uninitialized register results
    // in less predictable code.
    //
    // If in the future the implementation is changed to lower undef values to
    // uninitialized registers, a FakeDef will be needed:
    //     Context.insert<InstFakeDef>(Reg);
    // This is in order to ensure that the live range of Reg is not
    // overestimated.  If the constant being lowered is a 64 bit value, then
    // the result should be split and the lo and hi components will need to go
    // in uninitialized registers.
    if (isVectorType(Ty))
      return makeVectorOfZeros(Ty, RegNum);
    return Ctx->getConstantZero(Ty);
  }
  return From;
}

/// For the cmp instruction, if Src1 is an immediate, or known to be a physical
/// register, we can allow Src0 to be a memory operand. Otherwise, Src0 must be
/// copied into a physical register. (Actually, either Src0 or Src1 can be
/// chosen for the physical register, but unfortunately we have to commit to one
/// or the other before register allocation.)
template <typename TraitsType>
Operand *TargetX86Base<TraitsType>::legalizeSrc0ForCmp(Operand *Src0,
                                                       Operand *Src1) {
  bool IsSrc1ImmOrReg = false;
  if (llvm::isa<Constant>(Src1)) {
    IsSrc1ImmOrReg = true;
  } else if (auto *Var = llvm::dyn_cast<Variable>(Src1)) {
    if (Var->hasReg())
      IsSrc1ImmOrReg = true;
  }
  return legalize(Src0, IsSrc1ImmOrReg ? (Legal_Reg | Legal_Mem) : Legal_Reg);
}

template <typename TraitsType>
typename TargetX86Base<TraitsType>::X86OperandMem *
TargetX86Base<TraitsType>::formMemoryOperand(Operand *Opnd, Type Ty,
                                             bool DoLegalize) {
  auto *Mem = llvm::dyn_cast<X86OperandMem>(Opnd);
  // It may be the case that address mode optimization already creates an
  // X86OperandMem, so in that case it wouldn't need another level of
  // transformation.
  if (!Mem) {
    auto *Base = llvm::dyn_cast<Variable>(Opnd);
    auto *Offset = llvm::dyn_cast<Constant>(Opnd);
    assert(Base || Offset);
    if (Offset) {
      // During memory operand building, we do not blind or pool the constant
      // offset, we will work on the whole memory operand later as one entity
      // later, this save one instruction. By turning blinding and pooling off,
      // we guarantee legalize(Offset) will return a Constant*.
      if (!llvm::isa<ConstantRelocatable>(Offset)) {
        BoolFlagSaver B(RandomizationPoolingPaused, true);

        Offset = llvm::cast<Constant>(legalize(Offset));
      }

      assert(llvm::isa<ConstantInteger32>(Offset) ||
             llvm::isa<ConstantRelocatable>(Offset));
    }
    // Not completely sure whether it's OK to leave IsRebased unset when
    // creating the mem operand.  If DoLegalize is true, it will definitely be
    // applied during the legalize() call, but perhaps not during the
    // randomizeOrPoolImmediate() call.  In any case, the emit routines will
    // assert that PIC legalization has been applied.
    Mem = X86OperandMem::create(Func, Ty, Base, Offset);
  }
  // Do legalization, which contains randomization/pooling or do
  // randomization/pooling.
  return llvm::cast<X86OperandMem>(DoLegalize ? legalize(Mem)
                                              : randomizeOrPoolImmediate(Mem));
}

template <typename TraitsType>
Variable *TargetX86Base<TraitsType>::makeReg(Type Type, RegNumT RegNum) {
  // There aren't any 64-bit integer registers for x86-32.
  assert(Traits::Is64Bit || Type != IceType_i64);
  Variable *Reg = Func->makeVariable(Type);
  if (RegNum.hasValue())
    Reg->setRegNum(RegNum);
  else
    Reg->setMustHaveReg();
  return Reg;
}

const Type TypeForSize[] = {IceType_i8, IceType_i16, IceType_i32, IceType_f64,
                            IceType_v16i8};

template <typename TraitsType>
Type TargetX86Base<TraitsType>::largestTypeInSize(uint32_t Size,
                                                  uint32_t MaxSize) {
  assert(Size != 0);
  uint32_t TyIndex = llvm::findLastSet(Size, llvm::ZB_Undefined);
  uint32_t MaxIndex = MaxSize == NoSizeLimit
                          ? llvm::array_lengthof(TypeForSize) - 1
                          : llvm::findLastSet(MaxSize, llvm::ZB_Undefined);
  return TypeForSize[std::min(TyIndex, MaxIndex)];
}

template <typename TraitsType>
Type TargetX86Base<TraitsType>::firstTypeThatFitsSize(uint32_t Size,
                                                      uint32_t MaxSize) {
  assert(Size != 0);
  uint32_t TyIndex = llvm::findLastSet(Size, llvm::ZB_Undefined);
  if (!llvm::isPowerOf2_32(Size))
    ++TyIndex;
  uint32_t MaxIndex = MaxSize == NoSizeLimit
                          ? llvm::array_lengthof(TypeForSize) - 1
                          : llvm::findLastSet(MaxSize, llvm::ZB_Undefined);
  return TypeForSize[std::min(TyIndex, MaxIndex)];
}

template <typename TraitsType> void TargetX86Base<TraitsType>::postLower() {
  if (Func->getOptLevel() == Opt_m1)
    return;
  markRedefinitions();
  Context.availabilityUpdate();
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::makeRandomRegisterPermutation(
    llvm::SmallVectorImpl<RegNumT> &Permutation,
    const SmallBitVector &ExcludeRegisters, uint64_t Salt) const {
  Traits::makeRandomRegisterPermutation(Func, Permutation, ExcludeRegisters,
                                        Salt);
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::emit(const ConstantInteger32 *C) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Ctx->getStrEmit();
  Str << "$" << C->getValue();
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::emit(const ConstantInteger64 *C) const {
  if (!Traits::Is64Bit) {
    llvm::report_fatal_error("Not expecting to emit 64-bit integers");
  } else {
    if (!BuildDefs::dump())
      return;
    Ostream &Str = Ctx->getStrEmit();
    Str << "$" << C->getValue();
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::emit(const ConstantFloat *C) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Ctx->getStrEmit();
  Str << C->getLabelName();
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::emit(const ConstantDouble *C) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Ctx->getStrEmit();
  Str << C->getLabelName();
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::emit(const ConstantUndef *) const {
  llvm::report_fatal_error("undef value encountered by emitter.");
}

template <class Machine>
void TargetX86Base<Machine>::emit(const ConstantRelocatable *C) const {
  if (!BuildDefs::dump())
    return;
  assert(!getFlags().getUseNonsfi() ||
         C->getName().toString() == GlobalOffsetTable);
  Ostream &Str = Ctx->getStrEmit();
  Str << "$";
  emitWithoutPrefix(C);
}

/// Randomize or pool an Immediate.
template <typename TraitsType>
Operand *
TargetX86Base<TraitsType>::randomizeOrPoolImmediate(Constant *Immediate,
                                                    RegNumT RegNum) {
  assert(llvm::isa<ConstantInteger32>(Immediate) ||
         llvm::isa<ConstantRelocatable>(Immediate));
  if (getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None ||
      RandomizationPoolingPaused == true) {
    // Immediates randomization/pooling off or paused
    return Immediate;
  }

  if (Traits::Is64Bit && NeedSandboxing) {
    // Immediate randomization/pooling is currently disabled for x86-64
    // sandboxing for it could generate invalid memory operands.
    assert(false &&
           "Constant pooling/randomization is disabled for x8664 sandbox.");
    return Immediate;
  }

  if (!Immediate->shouldBeRandomizedOrPooled()) {
    // the constant Immediate is not eligible for blinding/pooling
    return Immediate;
  }
  Ctx->statsUpdateRPImms();
  switch (getFlags().getRandomizeAndPoolImmediatesOption()) {
  default:
    llvm::report_fatal_error("Unsupported -randomize-pool-immediates option");
  case RPI_Randomize: {
    // blind the constant
    // FROM:
    //  imm
    // TO:
    //  insert: mov imm+cookie, Reg
    //  insert: lea -cookie[Reg], Reg
    //  => Reg
    // If we have already assigned a phy register, we must come from
    // advancedPhiLowering()=>lowerAssign(). In this case we should reuse the
    // assigned register as this assignment is that start of its use-def
    // chain. So we add RegNum argument here. Note we use 'lea' instruction
    // instead of 'xor' to avoid affecting the flags.
    Variable *Reg = makeReg(IceType_i32, RegNum);
    auto *Integer = llvm::cast<ConstantInteger32>(Immediate);
    uint32_t Value = Integer->getValue();
    uint32_t Cookie = Func->getConstantBlindingCookie();
    _mov(Reg, Ctx->getConstantInt(IceType_i32, Cookie + Value));
    Constant *Offset = Ctx->getConstantInt(IceType_i32, 0 - Cookie);
    _lea(Reg, X86OperandMem::create(Func, IceType_i32, Reg, Offset));
    if (Immediate->getType() == IceType_i32) {
      return Reg;
    }
    Variable *TruncReg = makeReg(Immediate->getType(), RegNum);
    _mov(TruncReg, Reg);
    return TruncReg;
  }
  case RPI_Pool: {
    // pool the constant
    // FROM:
    //  imm
    // TO:
    //  insert: mov $label, Reg
    //  => Reg
    assert(getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Pool);
    assert(Immediate->getShouldBePooled());
    // if we have already assigned a phy register, we must come from
    // advancedPhiLowering()=>lowerAssign(). In this case we should reuse the
    // assigned register as this assignment is that start of its use-def
    // chain. So we add RegNum argument here.
    Variable *Reg = makeReg(Immediate->getType(), RegNum);
    constexpr RelocOffsetT Offset = 0;
    Constant *Symbol = Ctx->getConstantSym(Offset, Immediate->getLabelName());
    constexpr Variable *NoBase = nullptr;
    X86OperandMem *MemOperand =
        X86OperandMem::create(Func, Immediate->getType(), NoBase, Symbol);
    _mov(Reg, MemOperand);
    return Reg;
  }
  }
}

template <typename TraitsType>
typename TargetX86Base<TraitsType>::X86OperandMem *
TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand,
                                                    RegNumT RegNum) {
  assert(MemOperand);
  if (getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None ||
      RandomizationPoolingPaused == true) {
    // immediates randomization/pooling is turned off
    return MemOperand;
  }

  if (Traits::Is64Bit && NeedSandboxing) {
    // Immediate randomization/pooling is currently disabled for x86-64
    // sandboxing for it could generate invalid memory operands.
    assert(false &&
           "Constant pooling/randomization is disabled for x8664 sandbox.");
    return MemOperand;
  }

  // If this memory operand is already a randomized one, we do not randomize it
  // again.
  if (MemOperand->getRandomized())
    return MemOperand;

  auto *C = llvm::dyn_cast_or_null<Constant>(MemOperand->getOffset());

  if (C == nullptr) {
    return MemOperand;
  }

  if (!C->shouldBeRandomizedOrPooled()) {
    return MemOperand;
  }

  // The offset of this mem operand should be blinded or pooled
  Ctx->statsUpdateRPImms();
  switch (getFlags().getRandomizeAndPoolImmediatesOption()) {
  default:
    llvm::report_fatal_error("Unsupported -randomize-pool-immediates option");
  case RPI_Randomize: {
    // blind the constant offset
    // FROM:
    //  offset[base, index, shift]
    // TO:
    //  insert: lea offset+cookie[base], RegTemp
    //  => -cookie[RegTemp, index, shift]
    uint32_t Value =
        llvm::dyn_cast<ConstantInteger32>(MemOperand->getOffset())->getValue();
    uint32_t Cookie = Func->getConstantBlindingCookie();
    Constant *Mask1 =
        Ctx->getConstantInt(MemOperand->getOffset()->getType(), Cookie + Value);
    Constant *Mask2 =
        Ctx->getConstantInt(MemOperand->getOffset()->getType(), 0 - Cookie);

    X86OperandMem *TempMemOperand = X86OperandMem::create(
        Func, MemOperand->getType(), MemOperand->getBase(), Mask1);
    // If we have already assigned a physical register, we must come from
    // advancedPhiLowering()=>lowerAssign(). In this case we should reuse
    // the assigned register as this assignment is that start of its
    // use-def chain. So we add RegNum argument here.
    Variable *RegTemp = makeReg(MemOperand->getOffset()->getType(), RegNum);
    _lea(RegTemp, TempMemOperand);

    X86OperandMem *NewMemOperand = X86OperandMem::create(
        Func, MemOperand->getType(), RegTemp, Mask2, MemOperand->getIndex(),
        MemOperand->getShift(), MemOperand->getSegmentRegister(),
        MemOperand->getIsRebased());

    // Label this memory operand as randomized, so we won't randomize it
    // again in case we call legalize() multiple times on this memory
    // operand.
    NewMemOperand->setRandomized(true);
    return NewMemOperand;
  }
  case RPI_Pool: {
    // pool the constant offset
    // FROM:
    //  offset[base, index, shift]
    // TO:
    //  insert: mov $label, RegTemp
    //  insert: lea [base, RegTemp], RegTemp
    //  =>[RegTemp, index, shift]

    // Memory operand should never exist as source operands in phi lowering
    // assignments, so there is no need to reuse any registers here. For
    // phi lowering, we should not ask for new physical registers in
    // general. However, if we do meet Memory Operand during phi lowering,
    // we should not blind or pool the immediates for now.
    if (RegNum.hasValue())
      return MemOperand;
    Variable *RegTemp = makeReg(IceType_i32);
    assert(MemOperand->getOffset()->getShouldBePooled());
    constexpr RelocOffsetT SymOffset = 0;
    Constant *Symbol =
        Ctx->getConstantSym(SymOffset, MemOperand->getOffset()->getLabelName());
    constexpr Variable *NoBase = nullptr;
    X86OperandMem *SymbolOperand = X86OperandMem::create(
        Func, MemOperand->getOffset()->getType(), NoBase, Symbol);
    _mov(RegTemp, SymbolOperand);
    // If we have a base variable here, we should add the lea instruction
    // to add the value of the base variable to RegTemp. If there is no
    // base variable, we won't need this lea instruction.
    if (MemOperand->getBase()) {
      X86OperandMem *CalculateOperand = X86OperandMem::create(
          Func, MemOperand->getType(), MemOperand->getBase(), nullptr, RegTemp,
          0, MemOperand->getSegmentRegister());
      _lea(RegTemp, CalculateOperand);
    }
    X86OperandMem *NewMemOperand = X86OperandMem::create(
        Func, MemOperand->getType(), RegTemp, nullptr, MemOperand->getIndex(),
        MemOperand->getShift(), MemOperand->getSegmentRegister());
    return NewMemOperand;
  }
  }
}

template <typename TraitsType>
void TargetX86Base<TraitsType>::emitJumpTable(
    const Cfg *, const InstJumpTable *JumpTable) const {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Ctx->getStrEmit();
  const bool UseNonsfi = getFlags().getUseNonsfi();
  const char *Prefix = UseNonsfi ? ".data.rel.ro." : ".rodata.";
  Str << "\t.section\t" << Prefix << JumpTable->getSectionName()
      << ",\"a\",@progbits\n"
         "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"
      << JumpTable->getName() << ":";

  // On X86 ILP32 pointers are 32-bit hence the use of .long
  for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I)
    Str << "\n\t.long\t" << JumpTable->getTarget(I)->getAsmName();
  Str << "\n";
}

template <typename TraitsType>
template <typename T>
void TargetDataX86<TraitsType>::emitConstantPool(GlobalContext *Ctx) {
  if (!BuildDefs::dump())
    return;
  Ostream &Str = Ctx->getStrEmit();
  Type Ty = T::Ty;
  SizeT Align = typeAlignInBytes(Ty);
  ConstantList Pool = Ctx->getConstantPool(Ty);

  Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align
      << "\n";
  Str << "\t.align\t" << Align << "\n";

  // If reorder-pooled-constants option is set to true, we need to shuffle the
  // constant pool before emitting it.
  if (getFlags().getReorderPooledConstants() && !Pool.empty()) {
    // Use the constant's kind value as the salt for creating random number
    // generator.
    Operand::OperandKind K = (*Pool.begin())->getKind();
    RandomNumberGenerator RNG(getFlags().getRandomSeed(),
                              RPE_PooledConstantReordering, K);
    RandomShuffle(Pool.begin(), Pool.end(),
                  [&RNG](uint64_t N) { return (uint32_t)RNG.next(N); });
  }

  for (Constant *C : Pool) {
    if (!C->getShouldBePooled())
      continue;
    auto *Const = llvm::cast<typename T::IceType>(C);
    typename T::IceType::PrimType Value = Const->getValue();
    // Use memcpy() to copy bits from Value into RawValue in a way that avoids
    // breaking strict-aliasing rules.
    typename T::PrimitiveIntType RawValue;
    memcpy(&RawValue, &Value, sizeof(Value));
    char buf[30];
    int CharsPrinted =
        snprintf(buf, llvm::array_lengthof(buf), T::PrintfString, RawValue);
    assert(CharsPrinted >= 0);
    assert((size_t)CharsPrinted < llvm::array_lengthof(buf));
    (void)CharsPrinted; // avoid warnings if asserts are disabled
    Str << Const->getLabelName();
    Str << ":\n\t" << T::AsmTag << "\t" << buf << "\t/* " << T::TypeName << " "
        << Value << " */\n";
  }
}

template <typename TraitsType>
void TargetDataX86<TraitsType>::lowerConstants() {
  if (getFlags().getDisableTranslation())
    return;
  switch (getFlags().getOutFileType()) {
  case FT_Elf: {
    ELFObjectWriter *Writer = Ctx->getObjectWriter();

    Writer->writeConstantPool<ConstantInteger32>(IceType_i8);
    Writer->writeConstantPool<ConstantInteger32>(IceType_i16);
    Writer->writeConstantPool<ConstantInteger32>(IceType_i32);

    Writer->writeConstantPool<ConstantFloat>(IceType_f32);
    Writer->writeConstantPool<ConstantDouble>(IceType_f64);
  } break;
  case FT_Asm:
  case FT_Iasm: {
    OstreamLocker L(Ctx);

    emitConstantPool<PoolTypeConverter<uint8_t>>(Ctx);
    emitConstantPool<PoolTypeConverter<uint16_t>>(Ctx);
    emitConstantPool<PoolTypeConverter<uint32_t>>(Ctx);

    emitConstantPool<PoolTypeConverter<float>>(Ctx);
    emitConstantPool<PoolTypeConverter<double>>(Ctx);
  } break;
  }
}

template <typename TraitsType>
void TargetDataX86<TraitsType>::lowerJumpTables() {
  const bool IsPIC = getFlags().getUseNonsfi();
  switch (getFlags().getOutFileType()) {
  case FT_Elf: {
    ELFObjectWriter *Writer = Ctx->getObjectWriter();
    constexpr FixupKind FK_Abs64 = llvm::ELF::R_X86_64_64;
    const FixupKind RelocationKind =
        (getPointerType() == IceType_i32) ? Traits::FK_Abs : FK_Abs64;
    for (const JumpTableData &JT : Ctx->getJumpTables())
      Writer->writeJumpTable(JT, RelocationKind, IsPIC);
  } break;
  case FT_Asm:
    // Already emitted from Cfg
    break;
  case FT_Iasm: {
    if (!BuildDefs::dump())
      return;
    Ostream &Str = Ctx->getStrEmit();
    const char *Prefix = IsPIC ? ".data.rel.ro." : ".rodata.";
    for (const JumpTableData &JT : Ctx->getJumpTables()) {
      Str << "\t.section\t" << Prefix << JT.getSectionName()
          << ",\"a\",@progbits\n"
             "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"
          << JT.getName().toString() << ":";

      // On X8664 ILP32 pointers are 32-bit hence the use of .long
      for (intptr_t TargetOffset : JT.getTargetOffsets())
        Str << "\n\t.long\t" << JT.getFunctionName() << "+" << TargetOffset;
      Str << "\n";
    }
  } break;
  }
}

template <typename TraitsType>
void TargetDataX86<TraitsType>::lowerGlobals(
    const VariableDeclarationList &Vars, const std::string &SectionSuffix) {
  const bool IsPIC = getFlags().getUseNonsfi();
  switch (getFlags().getOutFileType()) {
  case FT_Elf: {
    ELFObjectWriter *Writer = Ctx->getObjectWriter();
    Writer->writeDataSection(Vars, Traits::FK_Abs, SectionSuffix, IsPIC);
  } break;
  case FT_Asm:
  case FT_Iasm: {
    OstreamLocker L(Ctx);
    for (const VariableDeclaration *Var : Vars) {
      if (getFlags().matchTranslateOnly(Var->getName(), 0)) {
        emitGlobal(*Var, SectionSuffix);
      }
    }
  } break;
  }
}
} // end of namespace X86NAMESPACE
} // end of namespace Ice

#endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H