[llvm] [SandboxIR][NFC] Move Instruction classes into a separate file (PR #110294)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 27 09:40:49 PDT 2024


https://github.com/vporpo updated https://github.com/llvm/llvm-project/pull/110294

>From 8312de0a9479f2df39c6184a939dcfef201bdee6 Mon Sep 17 00:00:00 2001
From: Vasileios Porpodas <vporpodas at google.com>
Date: Thu, 26 Sep 2024 14:25:38 -0700
Subject: [PATCH] [SandboxIR][NFC] Move Instruction classes into a separate
 file

---
 llvm/benchmarks/SandboxIRBench.cpp            |    3 +-
 llvm/include/llvm/SandboxIR/Constant.h        |    1 +
 llvm/include/llvm/SandboxIR/Context.h         |    1 +
 llvm/include/llvm/SandboxIR/Instruction.h     | 2741 +++++++++++++++++
 llvm/include/llvm/SandboxIR/Region.h          |    2 +-
 llvm/include/llvm/SandboxIR/SandboxIR.h       | 2718 ----------------
 llvm/include/llvm/SandboxIR/Utils.h           |    2 +-
 .../SandboxVectorizer/DependencyGraph.h       |    2 +-
 .../SandboxVectorizer/Passes/BottomUpVec.h    |    2 +-
 llvm/lib/SandboxIR/BasicBlock.cpp             |    2 +-
 llvm/lib/SandboxIR/CMakeLists.txt             |    1 +
 llvm/lib/SandboxIR/Context.cpp                |    5 +-
 llvm/lib/SandboxIR/Instruction.cpp            | 1965 ++++++++++++
 llvm/lib/SandboxIR/SandboxIR.cpp              | 1952 ------------
 llvm/lib/SandboxIR/Tracker.cpp                |    2 +-
 .../SandboxVectorizer/Passes/BottomUpVec.cpp  |    1 +
 llvm/unittests/SandboxIR/TrackerTest.cpp      |    2 +-
 .../SandboxVectorizer/LegalityTest.cpp        |    2 +-
 18 files changed, 4724 insertions(+), 4680 deletions(-)
 create mode 100644 llvm/include/llvm/SandboxIR/Instruction.h
 create mode 100644 llvm/lib/SandboxIR/Instruction.cpp

diff --git a/llvm/benchmarks/SandboxIRBench.cpp b/llvm/benchmarks/SandboxIRBench.cpp
index d4601d5f53d07a..8f7ab1a3768997 100644
--- a/llvm/benchmarks/SandboxIRBench.cpp
+++ b/llvm/benchmarks/SandboxIRBench.cpp
@@ -18,7 +18,8 @@
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Module.h"
-#include "llvm/SandboxIR/SandboxIR.h"
+#include "llvm/SandboxIR/Instruction.h"
+#include "llvm/SandboxIR/Module.h"
 #include "llvm/Support/SourceMgr.h"
 #include <memory>
 #include <sstream>
diff --git a/llvm/include/llvm/SandboxIR/Constant.h b/llvm/include/llvm/SandboxIR/Constant.h
index bc0e3d8849237a..a8cc66ba9d6540 100644
--- a/llvm/include/llvm/SandboxIR/Constant.h
+++ b/llvm/include/llvm/SandboxIR/Constant.h
@@ -17,6 +17,7 @@
 #include "llvm/IR/GlobalObject.h"
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/IR/GlobalVariable.h"
+#include "llvm/SandboxIR/Argument.h"
 #include "llvm/SandboxIR/Context.h"
 #include "llvm/SandboxIR/Type.h"
 #include "llvm/SandboxIR/User.h"
diff --git a/llvm/include/llvm/SandboxIR/Context.h b/llvm/include/llvm/SandboxIR/Context.h
index 092b791bc2acb9..37f52d74209cb3 100644
--- a/llvm/include/llvm/SandboxIR/Context.h
+++ b/llvm/include/llvm/SandboxIR/Context.h
@@ -159,6 +159,7 @@ class Context {
 
 public:
   Context(LLVMContext &LLVMCtx);
+  ~Context();
 
   Tracker &getTracker() { return IRTracker; }
   /// Convenience function for `getTracker().save()`
diff --git a/llvm/include/llvm/SandboxIR/Instruction.h b/llvm/include/llvm/SandboxIR/Instruction.h
new file mode 100644
index 00000000000000..f5f5bb5c4443c2
--- /dev/null
+++ b/llvm/include/llvm/SandboxIR/Instruction.h
@@ -0,0 +1,2741 @@
+//===- Instruction.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SANDBOXIR_INSTRUCTION_H
+#define LLVM_SANDBOXIR_INSTRUCTION_H
+
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/PatternMatch.h"
+#include "llvm/SandboxIR/BasicBlock.h"
+#include "llvm/SandboxIR/Constant.h"
+#include "llvm/SandboxIR/User.h"
+
+namespace llvm::sandboxir {
+
+/// A sandboxir::User with operands, opcode and linked with previous/next
+/// instructions in an instruction list.
+class Instruction : public User {
+public:
+  enum class Opcode {
+#define OP(OPC) OPC,
+#define OPCODES(...) __VA_ARGS__
+#define DEF_INSTR(ID, OPC, CLASS) OPC
+#include "llvm/SandboxIR/SandboxIRValues.def"
+  };
+
+protected:
+  Instruction(ClassID ID, Opcode Opc, llvm::Instruction *I,
+              sandboxir::Context &SBCtx)
+      : User(ID, I, SBCtx), Opc(Opc) {}
+
+  Opcode Opc;
+
+  /// A SandboxIR Instruction may map to multiple LLVM IR Instruction. This
+  /// returns its topmost LLVM IR instruction.
+  llvm::Instruction *getTopmostLLVMInstruction() const;
+  friend class VAArgInst;          // For getTopmostLLVMInstruction().
+  friend class FreezeInst;         // For getTopmostLLVMInstruction().
+  friend class FenceInst;          // For getTopmostLLVMInstruction().
+  friend class SelectInst;         // For getTopmostLLVMInstruction().
+  friend class ExtractElementInst; // For getTopmostLLVMInstruction().
+  friend class InsertElementInst;  // For getTopmostLLVMInstruction().
+  friend class ShuffleVectorInst;  // For getTopmostLLVMInstruction().
+  friend class ExtractValueInst;   // For getTopmostLLVMInstruction().
+  friend class InsertValueInst;    // For getTopmostLLVMInstruction().
+  friend class BranchInst;         // For getTopmostLLVMInstruction().
+  friend class LoadInst;           // For getTopmostLLVMInstruction().
+  friend class StoreInst;          // For getTopmostLLVMInstruction().
+  friend class ReturnInst;         // For getTopmostLLVMInstruction().
+  friend class CallInst;           // For getTopmostLLVMInstruction().
+  friend class InvokeInst;         // For getTopmostLLVMInstruction().
+  friend class CallBrInst;         // For getTopmostLLVMInstruction().
+  friend class LandingPadInst;     // For getTopmostLLVMInstruction().
+  friend class CatchPadInst;       // For getTopmostLLVMInstruction().
+  friend class CleanupPadInst;     // For getTopmostLLVMInstruction().
+  friend class CatchReturnInst;    // For getTopmostLLVMInstruction().
+  friend class CleanupReturnInst;  // For getTopmostLLVMInstruction().
+  friend class GetElementPtrInst;  // For getTopmostLLVMInstruction().
+  friend class ResumeInst;         // For getTopmostLLVMInstruction().
+  friend class CatchSwitchInst;    // For getTopmostLLVMInstruction().
+  friend class SwitchInst;         // For getTopmostLLVMInstruction().
+  friend class UnaryOperator;      // For getTopmostLLVMInstruction().
+  friend class BinaryOperator;     // For getTopmostLLVMInstruction().
+  friend class AtomicRMWInst;      // For getTopmostLLVMInstruction().
+  friend class AtomicCmpXchgInst;  // For getTopmostLLVMInstruction().
+  friend class AllocaInst;         // For getTopmostLLVMInstruction().
+  friend class CastInst;           // For getTopmostLLVMInstruction().
+  friend class PHINode;            // For getTopmostLLVMInstruction().
+  friend class UnreachableInst;    // For getTopmostLLVMInstruction().
+  friend class CmpInst;            // For getTopmostLLVMInstruction().
+
+  /// \Returns the LLVM IR Instructions that this SandboxIR maps to in program
+  /// order.
+  virtual SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const = 0;
+  friend class EraseFromParent; // For getLLVMInstrs().
+
+public:
+  static const char *getOpcodeName(Opcode Opc);
+  /// This is used by BasicBlock::iterator.
+  virtual unsigned getNumOfIRInstrs() const = 0;
+  /// \Returns a BasicBlock::iterator for this Instruction.
+  BBIterator getIterator() const;
+  /// \Returns the next sandboxir::Instruction in the block, or nullptr if at
+  /// the end of the block.
+  Instruction *getNextNode() const;
+  /// \Returns the previous sandboxir::Instruction in the block, or nullptr if
+  /// at the beginning of the block.
+  Instruction *getPrevNode() const;
+  /// \Returns this Instruction's opcode. Note that SandboxIR has its own opcode
+  /// state to allow for new SandboxIR-specific instructions.
+  Opcode getOpcode() const { return Opc; }
+
+  const char *getOpcodeName() const { return getOpcodeName(Opc); }
+
+  // Note that these functions below are calling into llvm::Instruction.
+  // A sandbox IR instruction could introduce a new opcode that could change the
+  // behavior of one of these functions. It is better that these functions are
+  // only added as needed and new sandbox IR instructions must explicitly check
+  // if any of these functions could have a different behavior.
+
+  bool isTerminator() const {
+    return cast<llvm::Instruction>(Val)->isTerminator();
+  }
+  bool isUnaryOp() const { return cast<llvm::Instruction>(Val)->isUnaryOp(); }
+  bool isBinaryOp() const { return cast<llvm::Instruction>(Val)->isBinaryOp(); }
+  bool isIntDivRem() const {
+    return cast<llvm::Instruction>(Val)->isIntDivRem();
+  }
+  bool isShift() const { return cast<llvm::Instruction>(Val)->isShift(); }
+  bool isCast() const { return cast<llvm::Instruction>(Val)->isCast(); }
+  bool isFuncletPad() const {
+    return cast<llvm::Instruction>(Val)->isFuncletPad();
+  }
+  bool isSpecialTerminator() const {
+    return cast<llvm::Instruction>(Val)->isSpecialTerminator();
+  }
+  bool isOnlyUserOfAnyOperand() const {
+    return cast<llvm::Instruction>(Val)->isOnlyUserOfAnyOperand();
+  }
+  bool isLogicalShift() const {
+    return cast<llvm::Instruction>(Val)->isLogicalShift();
+  }
+
+  //===--------------------------------------------------------------------===//
+  // Metadata manipulation.
+  //===--------------------------------------------------------------------===//
+
+  /// Return true if the instruction has any metadata attached to it.
+  bool hasMetadata() const {
+    return cast<llvm::Instruction>(Val)->hasMetadata();
+  }
+
+  /// Return true if this instruction has metadata attached to it other than a
+  /// debug location.
+  bool hasMetadataOtherThanDebugLoc() const {
+    return cast<llvm::Instruction>(Val)->hasMetadataOtherThanDebugLoc();
+  }
+
+  /// Return true if this instruction has the given type of metadata attached.
+  bool hasMetadata(unsigned KindID) const {
+    return cast<llvm::Instruction>(Val)->hasMetadata(KindID);
+  }
+
+  // TODO: Implement getMetadata and getAllMetadata after sandboxir::MDNode is
+  // available.
+
+  // TODO: More missing functions
+
+  /// Detach this from its parent BasicBlock without deleting it.
+  void removeFromParent();
+  /// Detach this Value from its parent and delete it.
+  void eraseFromParent();
+  /// Insert this detached instruction before \p BeforeI.
+  void insertBefore(Instruction *BeforeI);
+  /// Insert this detached instruction after \p AfterI.
+  void insertAfter(Instruction *AfterI);
+  /// Insert this detached instruction into \p BB at \p WhereIt.
+  void insertInto(BasicBlock *BB, const BBIterator &WhereIt);
+  /// Move this instruction to \p WhereIt.
+  void moveBefore(BasicBlock &BB, const BBIterator &WhereIt);
+  /// Move this instruction before \p Before.
+  void moveBefore(Instruction *Before) {
+    moveBefore(*Before->getParent(), Before->getIterator());
+  }
+  /// Move this instruction after \p After.
+  void moveAfter(Instruction *After) {
+    moveBefore(*After->getParent(), std::next(After->getIterator()));
+  }
+  // TODO: This currently relies on LLVM IR Instruction::comesBefore which is
+  // can be linear-time.
+  /// Given an instruction Other in the same basic block as this instruction,
+  /// return true if this instruction comes before Other.
+  bool comesBefore(const Instruction *Other) const {
+    return cast<llvm::Instruction>(Val)->comesBefore(
+        cast<llvm::Instruction>(Other->Val));
+  }
+  /// \Returns the BasicBlock containing this Instruction, or null if it is
+  /// detached.
+  BasicBlock *getParent() const;
+  /// For isa/dyn_cast.
+  static bool classof(const sandboxir::Value *From);
+
+  /// Determine whether the no signed wrap flag is set.
+  bool hasNoUnsignedWrap() const {
+    return cast<llvm::Instruction>(Val)->hasNoUnsignedWrap();
+  }
+  /// Set or clear the nuw flag on this instruction, which must be an operator
+  /// which supports this flag. See LangRef.html for the meaning of this flag.
+  void setHasNoUnsignedWrap(bool B = true);
+  /// Determine whether the no signed wrap flag is set.
+  bool hasNoSignedWrap() const {
+    return cast<llvm::Instruction>(Val)->hasNoSignedWrap();
+  }
+  /// Set or clear the nsw flag on this instruction, which must be an operator
+  /// which supports this flag. See LangRef.html for the meaning of this flag.
+  void setHasNoSignedWrap(bool B = true);
+  /// Determine whether all fast-math-flags are set.
+  bool isFast() const { return cast<llvm::Instruction>(Val)->isFast(); }
+  /// Set or clear all fast-math-flags on this instruction, which must be an
+  /// operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setFast(bool B);
+  /// Determine whether the allow-reassociation flag is set.
+  bool hasAllowReassoc() const {
+    return cast<llvm::Instruction>(Val)->hasAllowReassoc();
+  }
+  /// Set or clear the reassociation flag on this instruction, which must be
+  /// an operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setHasAllowReassoc(bool B);
+  /// Determine whether the exact flag is set.
+  bool isExact() const { return cast<llvm::Instruction>(Val)->isExact(); }
+  /// Set or clear the exact flag on this instruction, which must be an operator
+  /// which supports this flag. See LangRef.html for the meaning of this flag.
+  void setIsExact(bool B = true);
+  /// Determine whether the no-NaNs flag is set.
+  bool hasNoNaNs() const { return cast<llvm::Instruction>(Val)->hasNoNaNs(); }
+  /// Set or clear the no-nans flag on this instruction, which must be an
+  /// operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setHasNoNaNs(bool B);
+  /// Determine whether the no-infs flag is set.
+  bool hasNoInfs() const { return cast<llvm::Instruction>(Val)->hasNoInfs(); }
+  /// Set or clear the no-infs flag on this instruction, which must be an
+  /// operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setHasNoInfs(bool B);
+  /// Determine whether the no-signed-zeros flag is set.
+  bool hasNoSignedZeros() const {
+    return cast<llvm::Instruction>(Val)->hasNoSignedZeros();
+  }
+  /// Set or clear the no-signed-zeros flag on this instruction, which must be
+  /// an operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setHasNoSignedZeros(bool B);
+  /// Determine whether the allow-reciprocal flag is set.
+  bool hasAllowReciprocal() const {
+    return cast<llvm::Instruction>(Val)->hasAllowReciprocal();
+  }
+  /// Set or clear the allow-reciprocal flag on this instruction, which must be
+  /// an operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setHasAllowReciprocal(bool B);
+  /// Determine whether the allow-contract flag is set.
+  bool hasAllowContract() const {
+    return cast<llvm::Instruction>(Val)->hasAllowContract();
+  }
+  /// Set or clear the allow-contract flag on this instruction, which must be
+  /// an operator which supports this flag. See LangRef.html for the meaning of
+  /// this flag.
+  void setHasAllowContract(bool B);
+  /// Determine whether the approximate-math-functions flag is set.
+  bool hasApproxFunc() const {
+    return cast<llvm::Instruction>(Val)->hasApproxFunc();
+  }
+  /// Set or clear the approximate-math-functions flag on this instruction,
+  /// which must be an operator which supports this flag. See LangRef.html for
+  /// the meaning of this flag.
+  void setHasApproxFunc(bool B);
+  /// Convenience function for getting all the fast-math flags, which must be an
+  /// operator which supports these flags. See LangRef.html for the meaning of
+  /// these flags.
+  FastMathFlags getFastMathFlags() const {
+    return cast<llvm::Instruction>(Val)->getFastMathFlags();
+  }
+  /// Convenience function for setting multiple fast-math flags on this
+  /// instruction, which must be an operator which supports these flags. See
+  /// LangRef.html for the meaning of these flags.
+  void setFastMathFlags(FastMathFlags FMF);
+  /// Convenience function for transferring all fast-math flag values to this
+  /// instruction, which must be an operator which supports these flags. See
+  /// LangRef.html for the meaning of these flags.
+  void copyFastMathFlags(FastMathFlags FMF);
+
+  bool isAssociative() const {
+    return cast<llvm::Instruction>(Val)->isAssociative();
+  }
+
+  bool isCommutative() const {
+    return cast<llvm::Instruction>(Val)->isCommutative();
+  }
+
+  bool isIdempotent() const {
+    return cast<llvm::Instruction>(Val)->isIdempotent();
+  }
+
+  bool isNilpotent() const {
+    return cast<llvm::Instruction>(Val)->isNilpotent();
+  }
+
+  bool mayWriteToMemory() const {
+    return cast<llvm::Instruction>(Val)->mayWriteToMemory();
+  }
+
+  bool mayReadFromMemory() const {
+    return cast<llvm::Instruction>(Val)->mayReadFromMemory();
+  }
+  bool mayReadOrWriteMemory() const {
+    return cast<llvm::Instruction>(Val)->mayReadOrWriteMemory();
+  }
+
+  bool isAtomic() const { return cast<llvm::Instruction>(Val)->isAtomic(); }
+
+  bool hasAtomicLoad() const {
+    return cast<llvm::Instruction>(Val)->hasAtomicLoad();
+  }
+
+  bool hasAtomicStore() const {
+    return cast<llvm::Instruction>(Val)->hasAtomicStore();
+  }
+
+  bool isVolatile() const { return cast<llvm::Instruction>(Val)->isVolatile(); }
+
+  Type *getAccessType() const;
+
+  bool mayThrow(bool IncludePhaseOneUnwind = false) const {
+    return cast<llvm::Instruction>(Val)->mayThrow(IncludePhaseOneUnwind);
+  }
+
+  bool isFenceLike() const {
+    return cast<llvm::Instruction>(Val)->isFenceLike();
+  }
+
+  bool mayHaveSideEffects() const {
+    return cast<llvm::Instruction>(Val)->mayHaveSideEffects();
+  }
+
+  // TODO: Missing functions.
+
+  bool isStackSaveOrRestoreIntrinsic() const {
+    auto *I = cast<llvm::Instruction>(Val);
+    return match(I,
+                 PatternMatch::m_Intrinsic<llvm::Intrinsic::stackrestore>()) ||
+           match(I, PatternMatch::m_Intrinsic<llvm::Intrinsic::stacksave>());
+  }
+
+  /// We consider \p I as a Memory Dependency Candidate instruction if it
+  /// reads/write memory or if it has side-effects. This is used by the
+  /// dependency graph.
+  bool isMemDepCandidate() const {
+    auto *I = cast<llvm::Instruction>(Val);
+    return I->mayReadOrWriteMemory() &&
+           (!isa<llvm::IntrinsicInst>(I) ||
+            (cast<llvm::IntrinsicInst>(I)->getIntrinsicID() !=
+                 Intrinsic::sideeffect &&
+             cast<llvm::IntrinsicInst>(I)->getIntrinsicID() !=
+                 Intrinsic::pseudoprobe));
+  }
+
+#ifndef NDEBUG
+  void dumpOS(raw_ostream &OS) const override;
+#endif
+};
+
+/// Instructions that contain a single LLVM Instruction can inherit from this.
+template <typename LLVMT> class SingleLLVMInstructionImpl : public Instruction {
+  SingleLLVMInstructionImpl(ClassID ID, Opcode Opc, llvm::Instruction *I,
+                            sandboxir::Context &SBCtx)
+      : Instruction(ID, Opc, I, SBCtx) {}
+
+  // All instructions are friends with this so they can call the constructor.
+#define DEF_INSTR(ID, OPC, CLASS) friend class CLASS;
+#include "llvm/SandboxIR/SandboxIRValues.def"
+  friend class UnaryInstruction;
+  friend class CallBase;
+  friend class FuncletPadInst;
+  friend class CmpInst;
+
+  Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
+    return getOperandUseDefault(OpIdx, Verify);
+  }
+  SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
+    return {cast<llvm::Instruction>(Val)};
+  }
+
+public:
+  unsigned getUseOperandNo(const Use &Use) const final {
+    return getUseOperandNoDefault(Use);
+  }
+  unsigned getNumOfIRInstrs() const final { return 1u; }
+#ifndef NDEBUG
+  void verify() const final { assert(isa<LLVMT>(Val) && "Expected LLVMT!"); }
+  void dumpOS(raw_ostream &OS) const override {
+    dumpCommonPrefix(OS);
+    dumpCommonSuffix(OS);
+  }
+#endif
+};
+
+class FenceInst : public SingleLLVMInstructionImpl<llvm::FenceInst> {
+  FenceInst(llvm::FenceInst *FI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::Fence, Opcode::Fence, FI, Ctx) {}
+  friend Context; // For constructor;
+
+public:
+  static FenceInst *create(AtomicOrdering Ordering, BBIterator WhereIt,
+                           BasicBlock *WhereBB, Context &Ctx,
+                           SyncScope::ID SSID = SyncScope::System);
+  /// Returns the ordering constraint of this fence instruction.
+  AtomicOrdering getOrdering() const {
+    return cast<llvm::FenceInst>(Val)->getOrdering();
+  }
+  /// Sets the ordering constraint of this fence instruction.  May only be
+  /// Acquire, Release, AcquireRelease, or SequentiallyConsistent.
+  void setOrdering(AtomicOrdering Ordering);
+  /// Returns the synchronization scope ID of this fence instruction.
+  SyncScope::ID getSyncScopeID() const {
+    return cast<llvm::FenceInst>(Val)->getSyncScopeID();
+  }
+  /// Sets the synchronization scope ID of this fence instruction.
+  void setSyncScopeID(SyncScope::ID SSID);
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::Fence;
+  }
+};
+
+class SelectInst : public SingleLLVMInstructionImpl<llvm::SelectInst> {
+  /// Use Context::createSelectInst(). Don't call the
+  /// constructor directly.
+  SelectInst(llvm::SelectInst *CI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::Select, Opcode::Select, CI, Ctx) {}
+  friend Context; // for SelectInst()
+  static Value *createCommon(Value *Cond, Value *True, Value *False,
+                             const Twine &Name, IRBuilder<> &Builder,
+                             Context &Ctx);
+
+public:
+  static Value *create(Value *Cond, Value *True, Value *False,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *Cond, Value *True, Value *False,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+
+  const Value *getCondition() const { return getOperand(0); }
+  const Value *getTrueValue() const { return getOperand(1); }
+  const Value *getFalseValue() const { return getOperand(2); }
+  Value *getCondition() { return getOperand(0); }
+  Value *getTrueValue() { return getOperand(1); }
+  Value *getFalseValue() { return getOperand(2); }
+
+  void setCondition(Value *New) { setOperand(0, New); }
+  void setTrueValue(Value *New) { setOperand(1, New); }
+  void setFalseValue(Value *New) { setOperand(2, New); }
+  void swapValues();
+
+  /// Return a string if the specified operands are invalid for a select
+  /// operation, otherwise return null.
+  static const char *areInvalidOperands(Value *Cond, Value *True,
+                                        Value *False) {
+    return llvm::SelectInst::areInvalidOperands(Cond->Val, True->Val,
+                                                False->Val);
+  }
+
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From);
+};
+
+class InsertElementInst final
+    : public SingleLLVMInstructionImpl<llvm::InsertElementInst> {
+  /// Use Context::createInsertElementInst() instead.
+  InsertElementInst(llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::InsertElement, Opcode::InsertElement,
+                                  I, Ctx) {}
+  friend class Context; // For accessing the constructor in create*()
+
+public:
+  static Value *create(Value *Vec, Value *NewElt, Value *Idx,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *Vec, Value *NewElt, Value *Idx,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::InsertElement;
+  }
+  static bool isValidOperands(const Value *Vec, const Value *NewElt,
+                              const Value *Idx) {
+    return llvm::InsertElementInst::isValidOperands(Vec->Val, NewElt->Val,
+                                                    Idx->Val);
+  }
+};
+
+class ExtractElementInst final
+    : public SingleLLVMInstructionImpl<llvm::ExtractElementInst> {
+  /// Use Context::createExtractElementInst() instead.
+  ExtractElementInst(llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::ExtractElement,
+                                  Opcode::ExtractElement, I, Ctx) {}
+  friend class Context; // For accessing the constructor in
+                        // create*()
+
+public:
+  static Value *create(Value *Vec, Value *Idx, Instruction *InsertBefore,
+                       Context &Ctx, const Twine &Name = "");
+  static Value *create(Value *Vec, Value *Idx, BasicBlock *InsertAtEnd,
+                       Context &Ctx, const Twine &Name = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::ExtractElement;
+  }
+
+  static bool isValidOperands(const Value *Vec, const Value *Idx) {
+    return llvm::ExtractElementInst::isValidOperands(Vec->Val, Idx->Val);
+  }
+  Value *getVectorOperand() { return getOperand(0); }
+  Value *getIndexOperand() { return getOperand(1); }
+  const Value *getVectorOperand() const { return getOperand(0); }
+  const Value *getIndexOperand() const { return getOperand(1); }
+  VectorType *getVectorOperandType() const;
+};
+
+class ShuffleVectorInst final
+    : public SingleLLVMInstructionImpl<llvm::ShuffleVectorInst> {
+  /// Use Context::createShuffleVectorInst() instead.
+  ShuffleVectorInst(llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::ShuffleVector, Opcode::ShuffleVector,
+                                  I, Ctx) {}
+  friend class Context; // For accessing the constructor in create*()
+
+public:
+  static Value *create(Value *V1, Value *V2, Value *Mask,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *V1, Value *V2, Value *Mask,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *V1, Value *V2, ArrayRef<int> Mask,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *V1, Value *V2, ArrayRef<int> Mask,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::ShuffleVector;
+  }
+
+  /// Swap the operands and adjust the mask to preserve the semantics of the
+  /// instruction.
+  void commute();
+
+  /// Return true if a shufflevector instruction can be formed with the
+  /// specified operands.
+  static bool isValidOperands(const Value *V1, const Value *V2,
+                              const Value *Mask) {
+    return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val,
+                                                    Mask->Val);
+  }
+  static bool isValidOperands(const Value *V1, const Value *V2,
+                              ArrayRef<int> Mask) {
+    return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val, Mask);
+  }
+
+  /// Overload to return most specific vector type.
+  VectorType *getType() const;
+
+  /// Return the shuffle mask value of this instruction for the given element
+  /// index. Return PoisonMaskElem if the element is undef.
+  int getMaskValue(unsigned Elt) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->getMaskValue(Elt);
+  }
+
+  /// Convert the input shuffle mask operand to a vector of integers. Undefined
+  /// elements of the mask are returned as PoisonMaskElem.
+  static void getShuffleMask(const Constant *Mask,
+                             SmallVectorImpl<int> &Result) {
+    llvm::ShuffleVectorInst::getShuffleMask(cast<llvm::Constant>(Mask->Val),
+                                            Result);
+  }
+
+  /// Return the mask for this instruction as a vector of integers. Undefined
+  /// elements of the mask are returned as PoisonMaskElem.
+  void getShuffleMask(SmallVectorImpl<int> &Result) const {
+    cast<llvm::ShuffleVectorInst>(Val)->getShuffleMask(Result);
+  }
+
+  /// Return the mask for this instruction, for use in bitcode.
+  Constant *getShuffleMaskForBitcode() const;
+
+  static Constant *convertShuffleMaskForBitcode(ArrayRef<int> Mask,
+                                                Type *ResultTy);
+
+  void setShuffleMask(ArrayRef<int> Mask);
+
+  ArrayRef<int> getShuffleMask() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->getShuffleMask();
+  }
+
+  /// Return true if this shuffle returns a vector with a different number of
+  /// elements than its source vectors.
+  /// Examples: shufflevector <4 x n> A, <4 x n> B, <1,2,3>
+  ///           shufflevector <4 x n> A, <4 x n> B, <1,2,3,4,5>
+  bool changesLength() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->changesLength();
+  }
+
+  /// Return true if this shuffle returns a vector with a greater number of
+  /// elements than its source vectors.
+  /// Example: shufflevector <2 x n> A, <2 x n> B, <1,2,3>
+  bool increasesLength() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->increasesLength();
+  }
+
+  /// Return true if this shuffle mask chooses elements from exactly one source
+  /// vector.
+  /// Example: <7,5,undef,7>
+  /// This assumes that vector operands (of length \p NumSrcElts) are the same
+  /// length as the mask.
+  static bool isSingleSourceMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isSingleSourceMask(Mask, NumSrcElts);
+  }
+  static bool isSingleSourceMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isSingleSourceMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  /// Return true if this shuffle chooses elements from exactly one source
+  /// vector without changing the length of that vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3>
+  bool isSingleSource() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isSingleSource();
+  }
+
+  /// Return true if this shuffle mask chooses elements from exactly one source
+  /// vector without lane crossings. A shuffle using this mask is not
+  /// necessarily a no-op because it may change the number of elements from its
+  /// input vectors or it may provide demanded bits knowledge via undef lanes.
+  /// Example: <undef,undef,2,3>
+  static bool isIdentityMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isIdentityMask(Mask, NumSrcElts);
+  }
+  static bool isIdentityMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isIdentityMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  /// Return true if this shuffle chooses elements from exactly one source
+  /// vector without lane crossings and does not change the number of elements
+  /// from its input vectors.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef>
+  bool isIdentity() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isIdentity();
+  }
+
+  /// Return true if this shuffle lengthens exactly one source vector with
+  /// undefs in the high elements.
+  bool isIdentityWithPadding() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isIdentityWithPadding();
+  }
+
+  /// Return true if this shuffle extracts the first N elements of exactly one
+  /// source vector.
+  bool isIdentityWithExtract() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isIdentityWithExtract();
+  }
+
+  /// Return true if this shuffle concatenates its 2 source vectors. This
+  /// returns false if either input is undefined. In that case, the shuffle is
+  /// is better classified as an identity with padding operation.
+  bool isConcat() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isConcat();
+  }
+
+  /// Return true if this shuffle mask chooses elements from its source vectors
+  /// without lane crossings. A shuffle using this mask would be
+  /// equivalent to a vector select with a constant condition operand.
+  /// Example: <4,1,6,undef>
+  /// This returns false if the mask does not choose from both input vectors.
+  /// In that case, the shuffle is better classified as an identity shuffle.
+  /// This assumes that vector operands are the same length as the mask
+  /// (a length-changing shuffle can never be equivalent to a vector select).
+  static bool isSelectMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isSelectMask(Mask, NumSrcElts);
+  }
+  static bool isSelectMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isSelectMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  /// Return true if this shuffle chooses elements from its source vectors
+  /// without lane crossings and all operands have the same number of elements.
+  /// In other words, this shuffle is equivalent to a vector select with a
+  /// constant condition operand.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,1,6,3>
+  /// This returns false if the mask does not choose from both input vectors.
+  /// In that case, the shuffle is better classified as an identity shuffle.
+  bool isSelect() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isSelect();
+  }
+
+  /// Return true if this shuffle mask swaps the order of elements from exactly
+  /// one source vector.
+  /// Example: <7,6,undef,4>
+  /// This assumes that vector operands (of length \p NumSrcElts) are the same
+  /// length as the mask.
+  static bool isReverseMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isReverseMask(Mask, NumSrcElts);
+  }
+  static bool isReverseMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isReverseMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  /// Return true if this shuffle swaps the order of elements from exactly
+  /// one source vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef>
+  bool isReverse() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isReverse();
+  }
+
+  /// Return true if this shuffle mask chooses all elements with the same value
+  /// as the first element of exactly one source vector.
+  /// Example: <4,undef,undef,4>
+  /// This assumes that vector operands (of length \p NumSrcElts) are the same
+  /// length as the mask.
+  static bool isZeroEltSplatMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isZeroEltSplatMask(Mask, NumSrcElts);
+  }
+  static bool isZeroEltSplatMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isZeroEltSplatMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  /// Return true if all elements of this shuffle are the same value as the
+  /// first element of exactly one source vector without changing the length
+  /// of that vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,0,undef,0>
+  bool isZeroEltSplat() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isZeroEltSplat();
+  }
+
+  /// Return true if this shuffle mask is a transpose mask.
+  /// Transpose vector masks transpose a 2xn matrix. They read corresponding
+  /// even- or odd-numbered vector elements from two n-dimensional source
+  /// vectors and write each result into consecutive elements of an
+  /// n-dimensional destination vector. Two shuffles are necessary to complete
+  /// the transpose, one for the even elements and another for the odd elements.
+  /// This description closely follows how the TRN1 and TRN2 AArch64
+  /// instructions operate.
+  ///
+  /// For example, a simple 2x2 matrix can be transposed with:
+  ///
+  ///   ; Original matrix
+  ///   m0 = < a, b >
+  ///   m1 = < c, d >
+  ///
+  ///   ; Transposed matrix
+  ///   t0 = < a, c > = shufflevector m0, m1, < 0, 2 >
+  ///   t1 = < b, d > = shufflevector m0, m1, < 1, 3 >
+  ///
+  /// For matrices having greater than n columns, the resulting nx2 transposed
+  /// matrix is stored in two result vectors such that one vector contains
+  /// interleaved elements from all the even-numbered rows and the other vector
+  /// contains interleaved elements from all the odd-numbered rows. For example,
+  /// a 2x4 matrix can be transposed with:
+  ///
+  ///   ; Original matrix
+  ///   m0 = < a, b, c, d >
+  ///   m1 = < e, f, g, h >
+  ///
+  ///   ; Transposed matrix
+  ///   t0 = < a, e, c, g > = shufflevector m0, m1 < 0, 4, 2, 6 >
+  ///   t1 = < b, f, d, h > = shufflevector m0, m1 < 1, 5, 3, 7 >
+  static bool isTransposeMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isTransposeMask(Mask, NumSrcElts);
+  }
+  static bool isTransposeMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isTransposeMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  /// Return true if this shuffle transposes the elements of its inputs without
+  /// changing the length of the vectors. This operation may also be known as a
+  /// merge or interleave. See the description for isTransposeMask() for the
+  /// exact specification.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6>
+  bool isTranspose() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isTranspose();
+  }
+
+  /// Return true if this shuffle mask is a splice mask, concatenating the two
+  /// inputs together and then extracts an original width vector starting from
+  /// the splice index.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
+  /// This assumes that vector operands (of length \p NumSrcElts) are the same
+  /// length as the mask.
+  static bool isSpliceMask(ArrayRef<int> Mask, int NumSrcElts, int &Index) {
+    return llvm::ShuffleVectorInst::isSpliceMask(Mask, NumSrcElts, Index);
+  }
+  static bool isSpliceMask(const Constant *Mask, int NumSrcElts, int &Index) {
+    return llvm::ShuffleVectorInst::isSpliceMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts, Index);
+  }
+
+  /// Return true if this shuffle splices two inputs without changing the length
+  /// of the vectors. This operation concatenates the two inputs together and
+  /// then extracts an original width vector starting from the splice index.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
+  bool isSplice(int &Index) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isSplice(Index);
+  }
+
+  /// Return true if this shuffle mask is an extract subvector mask.
+  /// A valid extract subvector mask returns a smaller vector from a single
+  /// source operand. The base extraction index is returned as well.
+  static bool isExtractSubvectorMask(ArrayRef<int> Mask, int NumSrcElts,
+                                     int &Index) {
+    return llvm::ShuffleVectorInst::isExtractSubvectorMask(Mask, NumSrcElts,
+                                                           Index);
+  }
+  static bool isExtractSubvectorMask(const Constant *Mask, int NumSrcElts,
+                                     int &Index) {
+    return llvm::ShuffleVectorInst::isExtractSubvectorMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts, Index);
+  }
+
+  /// Return true if this shuffle mask is an extract subvector mask.
+  bool isExtractSubvectorMask(int &Index) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isExtractSubvectorMask(Index);
+  }
+
+  /// Return true if this shuffle mask is an insert subvector mask.
+  /// A valid insert subvector mask inserts the lowest elements of a second
+  /// source operand into an in-place first source operand.
+  /// Both the sub vector width and the insertion index is returned.
+  static bool isInsertSubvectorMask(ArrayRef<int> Mask, int NumSrcElts,
+                                    int &NumSubElts, int &Index) {
+    return llvm::ShuffleVectorInst::isInsertSubvectorMask(Mask, NumSrcElts,
+                                                          NumSubElts, Index);
+  }
+  static bool isInsertSubvectorMask(const Constant *Mask, int NumSrcElts,
+                                    int &NumSubElts, int &Index) {
+    return llvm::ShuffleVectorInst::isInsertSubvectorMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts, NumSubElts, Index);
+  }
+
+  /// Return true if this shuffle mask is an insert subvector mask.
+  bool isInsertSubvectorMask(int &NumSubElts, int &Index) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isInsertSubvectorMask(NumSubElts,
+                                                                     Index);
+  }
+
+  /// Return true if this shuffle mask replicates each of the \p VF elements
+  /// in a vector \p ReplicationFactor times.
+  /// For example, the mask for \p ReplicationFactor=3 and \p VF=4 is:
+  ///   <0,0,0,1,1,1,2,2,2,3,3,3>
+  static bool isReplicationMask(ArrayRef<int> Mask, int &ReplicationFactor,
+                                int &VF) {
+    return llvm::ShuffleVectorInst::isReplicationMask(Mask, ReplicationFactor,
+                                                      VF);
+  }
+  static bool isReplicationMask(const Constant *Mask, int &ReplicationFactor,
+                                int &VF) {
+    return llvm::ShuffleVectorInst::isReplicationMask(
+        cast<llvm::Constant>(Mask->Val), ReplicationFactor, VF);
+  }
+
+  /// Return true if this shuffle mask is a replication mask.
+  bool isReplicationMask(int &ReplicationFactor, int &VF) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isReplicationMask(
+        ReplicationFactor, VF);
+  }
+
+  /// Return true if this shuffle mask represents "clustered" mask of size VF,
+  /// i.e. each index between [0..VF) is used exactly once in each submask of
+  /// size VF.
+  /// For example, the mask for \p VF=4 is:
+  /// 0, 1, 2, 3, 3, 2, 0, 1 - "clustered", because each submask of size 4
+  /// (0,1,2,3 and 3,2,0,1) uses indices [0..VF) exactly one time.
+  /// 0, 1, 2, 3, 3, 3, 1, 0 - not "clustered", because
+  ///                          element 3 is used twice in the second submask
+  ///                          (3,3,1,0) and index 2 is not used at all.
+  static bool isOneUseSingleSourceMask(ArrayRef<int> Mask, int VF) {
+    return llvm::ShuffleVectorInst::isOneUseSingleSourceMask(Mask, VF);
+  }
+
+  /// Return true if this shuffle mask is a one-use-single-source("clustered")
+  /// mask.
+  bool isOneUseSingleSourceMask(int VF) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isOneUseSingleSourceMask(VF);
+  }
+
+  /// Change values in a shuffle permute mask assuming the two vector operands
+  /// of length InVecNumElts have swapped position.
+  static void commuteShuffleMask(MutableArrayRef<int> Mask,
+                                 unsigned InVecNumElts) {
+    llvm::ShuffleVectorInst::commuteShuffleMask(Mask, InVecNumElts);
+  }
+
+  /// Return if this shuffle interleaves its two input vectors together.
+  bool isInterleave(unsigned Factor) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isInterleave(Factor);
+  }
+
+  /// Return true if the mask interleaves one or more input vectors together.
+  ///
+  /// I.e. <0, LaneLen, ... , LaneLen*(Factor - 1), 1, LaneLen + 1, ...>
+  /// E.g. For a Factor of 2 (LaneLen=4):
+  ///   <0, 4, 1, 5, 2, 6, 3, 7>
+  /// E.g. For a Factor of 3 (LaneLen=4):
+  ///   <4, 0, 9, 5, 1, 10, 6, 2, 11, 7, 3, 12>
+  /// E.g. For a Factor of 4 (LaneLen=2):
+  ///   <0, 2, 6, 4, 1, 3, 7, 5>
+  ///
+  /// NumInputElts is the total number of elements in the input vectors.
+  ///
+  /// StartIndexes are the first indexes of each vector being interleaved,
+  /// substituting any indexes that were undef
+  /// E.g. <4, -1, 2, 5, 1, 3> (Factor=3): StartIndexes=<4, 0, 2>
+  ///
+  /// Note that this does not check if the input vectors are consecutive:
+  /// It will return true for masks such as
+  /// <0, 4, 6, 1, 5, 7> (Factor=3, LaneLen=2)
+  static bool isInterleaveMask(ArrayRef<int> Mask, unsigned Factor,
+                               unsigned NumInputElts,
+                               SmallVectorImpl<unsigned> &StartIndexes) {
+    return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor, NumInputElts,
+                                                     StartIndexes);
+  }
+  static bool isInterleaveMask(ArrayRef<int> Mask, unsigned Factor,
+                               unsigned NumInputElts) {
+    return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor,
+                                                     NumInputElts);
+  }
+
+  /// Check if the mask is a DE-interleave mask of the given factor
+  /// \p Factor like:
+  ///     <Index, Index+Factor, ..., Index+(NumElts-1)*Factor>
+  static bool isDeInterleaveMaskOfFactor(ArrayRef<int> Mask, unsigned Factor,
+                                         unsigned &Index) {
+    return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor,
+                                                               Index);
+  }
+  static bool isDeInterleaveMaskOfFactor(ArrayRef<int> Mask, unsigned Factor) {
+    return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor);
+  }
+
+  /// Checks if the shuffle is a bit rotation of the first operand across
+  /// multiple subelements, e.g:
+  ///
+  /// shuffle <8 x i8> %a, <8 x i8> poison, <8 x i32> <1, 0, 3, 2, 5, 4, 7, 6>
+  ///
+  /// could be expressed as
+  ///
+  /// rotl <4 x i16> %a, 8
+  ///
+  /// If it can be expressed as a rotation, returns the number of subelements to
+  /// group by in NumSubElts and the number of bits to rotate left in RotateAmt.
+  static bool isBitRotateMask(ArrayRef<int> Mask, unsigned EltSizeInBits,
+                              unsigned MinSubElts, unsigned MaxSubElts,
+                              unsigned &NumSubElts, unsigned &RotateAmt) {
+    return llvm::ShuffleVectorInst::isBitRotateMask(
+        Mask, EltSizeInBits, MinSubElts, MaxSubElts, NumSubElts, RotateAmt);
+  }
+};
+
+class InsertValueInst
+    : public SingleLLVMInstructionImpl<llvm::InsertValueInst> {
+  /// Use Context::createInsertValueInst(). Don't call the constructor directly.
+  InsertValueInst(llvm::InsertValueInst *IVI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::InsertValue, Opcode::InsertValue,
+                                  IVI, Ctx) {}
+  friend Context; // for InsertValueInst()
+
+public:
+  static Value *create(Value *Agg, Value *Val, ArrayRef<unsigned> Idxs,
+                       BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
+                       const Twine &Name = "");
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::InsertValue;
+  }
+
+  using idx_iterator = llvm::InsertValueInst::idx_iterator;
+  inline idx_iterator idx_begin() const {
+    return cast<llvm::InsertValueInst>(Val)->idx_begin();
+  }
+  inline idx_iterator idx_end() const {
+    return cast<llvm::InsertValueInst>(Val)->idx_end();
+  }
+  inline iterator_range<idx_iterator> indices() const {
+    return cast<llvm::InsertValueInst>(Val)->indices();
+  }
+
+  Value *getAggregateOperand() {
+    return getOperand(getAggregateOperandIndex());
+  }
+  const Value *getAggregateOperand() const {
+    return getOperand(getAggregateOperandIndex());
+  }
+  static unsigned getAggregateOperandIndex() {
+    return llvm::InsertValueInst::getAggregateOperandIndex();
+  }
+
+  Value *getInsertedValueOperand() {
+    return getOperand(getInsertedValueOperandIndex());
+  }
+  const Value *getInsertedValueOperand() const {
+    return getOperand(getInsertedValueOperandIndex());
+  }
+  static unsigned getInsertedValueOperandIndex() {
+    return llvm::InsertValueInst::getInsertedValueOperandIndex();
+  }
+
+  ArrayRef<unsigned> getIndices() const {
+    return cast<llvm::InsertValueInst>(Val)->getIndices();
+  }
+
+  unsigned getNumIndices() const {
+    return cast<llvm::InsertValueInst>(Val)->getNumIndices();
+  }
+
+  unsigned hasIndices() const {
+    return cast<llvm::InsertValueInst>(Val)->hasIndices();
+  }
+};
+
+class BranchInst : public SingleLLVMInstructionImpl<llvm::BranchInst> {
+  /// Use Context::createBranchInst(). Don't call the constructor directly.
+  BranchInst(llvm::BranchInst *BI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::Br, Opcode::Br, BI, Ctx) {}
+  friend Context; // for BranchInst()
+
+public:
+  static BranchInst *create(BasicBlock *IfTrue, Instruction *InsertBefore,
+                            Context &Ctx);
+  static BranchInst *create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd,
+                            Context &Ctx);
+  static BranchInst *create(BasicBlock *IfTrue, BasicBlock *IfFalse,
+                            Value *Cond, Instruction *InsertBefore,
+                            Context &Ctx);
+  static BranchInst *create(BasicBlock *IfTrue, BasicBlock *IfFalse,
+                            Value *Cond, BasicBlock *InsertAtEnd, Context &Ctx);
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From);
+  bool isUnconditional() const {
+    return cast<llvm::BranchInst>(Val)->isUnconditional();
+  }
+  bool isConditional() const {
+    return cast<llvm::BranchInst>(Val)->isConditional();
+  }
+  Value *getCondition() const;
+  void setCondition(Value *V) { setOperand(0, V); }
+  unsigned getNumSuccessors() const { return 1 + isConditional(); }
+  BasicBlock *getSuccessor(unsigned SuccIdx) const;
+  void setSuccessor(unsigned Idx, BasicBlock *NewSucc);
+  void swapSuccessors() { swapOperandsInternal(1, 2); }
+
+private:
+  struct LLVMBBToSBBB {
+    Context &Ctx;
+    LLVMBBToSBBB(Context &Ctx) : Ctx(Ctx) {}
+    BasicBlock *operator()(llvm::BasicBlock *BB) const;
+  };
+
+  struct ConstLLVMBBToSBBB {
+    Context &Ctx;
+    ConstLLVMBBToSBBB(Context &Ctx) : Ctx(Ctx) {}
+    const BasicBlock *operator()(const llvm::BasicBlock *BB) const;
+  };
+
+public:
+  using sb_succ_op_iterator =
+      mapped_iterator<llvm::BranchInst::succ_op_iterator, LLVMBBToSBBB>;
+  iterator_range<sb_succ_op_iterator> successors() {
+    iterator_range<llvm::BranchInst::succ_op_iterator> LLVMRange =
+        cast<llvm::BranchInst>(Val)->successors();
+    LLVMBBToSBBB BBMap(Ctx);
+    sb_succ_op_iterator MappedBegin = map_iterator(LLVMRange.begin(), BBMap);
+    sb_succ_op_iterator MappedEnd = map_iterator(LLVMRange.end(), BBMap);
+    return make_range(MappedBegin, MappedEnd);
+  }
+
+  using const_sb_succ_op_iterator =
+      mapped_iterator<llvm::BranchInst::const_succ_op_iterator,
+                      ConstLLVMBBToSBBB>;
+  iterator_range<const_sb_succ_op_iterator> successors() const {
+    iterator_range<llvm::BranchInst::const_succ_op_iterator> ConstLLVMRange =
+        static_cast<const llvm::BranchInst *>(cast<llvm::BranchInst>(Val))
+            ->successors();
+    ConstLLVMBBToSBBB ConstBBMap(Ctx);
+    const_sb_succ_op_iterator ConstMappedBegin =
+        map_iterator(ConstLLVMRange.begin(), ConstBBMap);
+    const_sb_succ_op_iterator ConstMappedEnd =
+        map_iterator(ConstLLVMRange.end(), ConstBBMap);
+    return make_range(ConstMappedBegin, ConstMappedEnd);
+  }
+};
+
+/// An abstract class, parent of unary instructions.
+class UnaryInstruction
+    : public SingleLLVMInstructionImpl<llvm::UnaryInstruction> {
+protected:
+  UnaryInstruction(ClassID ID, Opcode Opc, llvm::Instruction *LLVMI,
+                   Context &Ctx)
+      : SingleLLVMInstructionImpl(ID, Opc, LLVMI, Ctx) {}
+
+public:
+  static bool classof(const Instruction *I) {
+    return isa<LoadInst>(I) || isa<CastInst>(I) || isa<FreezeInst>(I);
+  }
+  static bool classof(const Value *V) {
+    return isa<Instruction>(V) && classof(cast<Instruction>(V));
+  }
+};
+
+class ExtractValueInst : public UnaryInstruction {
+  /// Use Context::createExtractValueInst() instead.
+  ExtractValueInst(llvm::ExtractValueInst *EVI, Context &Ctx)
+      : UnaryInstruction(ClassID::ExtractValue, Opcode::ExtractValue, EVI,
+                         Ctx) {}
+  friend Context; // for ExtractValueInst()
+
+public:
+  static Value *create(Value *Agg, ArrayRef<unsigned> Idxs, BBIterator WhereIt,
+                       BasicBlock *WhereBB, Context &Ctx,
+                       const Twine &Name = "");
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::ExtractValue;
+  }
+
+  /// Returns the type of the element that would be extracted
+  /// with an extractvalue instruction with the specified parameters.
+  ///
+  /// Null is returned if the indices are invalid for the specified type.
+  static Type *getIndexedType(Type *Agg, ArrayRef<unsigned> Idxs);
+
+  using idx_iterator = llvm::ExtractValueInst::idx_iterator;
+
+  inline idx_iterator idx_begin() const {
+    return cast<llvm::ExtractValueInst>(Val)->idx_begin();
+  }
+  inline idx_iterator idx_end() const {
+    return cast<llvm::ExtractValueInst>(Val)->idx_end();
+  }
+  inline iterator_range<idx_iterator> indices() const {
+    return cast<llvm::ExtractValueInst>(Val)->indices();
+  }
+
+  Value *getAggregateOperand() {
+    return getOperand(getAggregateOperandIndex());
+  }
+  const Value *getAggregateOperand() const {
+    return getOperand(getAggregateOperandIndex());
+  }
+  static unsigned getAggregateOperandIndex() {
+    return llvm::ExtractValueInst::getAggregateOperandIndex();
+  }
+
+  ArrayRef<unsigned> getIndices() const {
+    return cast<llvm::ExtractValueInst>(Val)->getIndices();
+  }
+
+  unsigned getNumIndices() const {
+    return cast<llvm::ExtractValueInst>(Val)->getNumIndices();
+  }
+
+  unsigned hasIndices() const {
+    return cast<llvm::ExtractValueInst>(Val)->hasIndices();
+  }
+};
+
+class VAArgInst : public UnaryInstruction {
+  VAArgInst(llvm::VAArgInst *FI, Context &Ctx)
+      : UnaryInstruction(ClassID::VAArg, Opcode::VAArg, FI, Ctx) {}
+  friend Context; // For constructor;
+
+public:
+  static VAArgInst *create(Value *List, Type *Ty, BBIterator WhereIt,
+                           BasicBlock *WhereBB, Context &Ctx,
+                           const Twine &Name = "");
+  Value *getPointerOperand();
+  const Value *getPointerOperand() const {
+    return const_cast<VAArgInst *>(this)->getPointerOperand();
+  }
+  static unsigned getPointerOperandIndex() {
+    return llvm::VAArgInst::getPointerOperandIndex();
+  }
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::VAArg;
+  }
+};
+
+class FreezeInst : public UnaryInstruction {
+  FreezeInst(llvm::FreezeInst *FI, Context &Ctx)
+      : UnaryInstruction(ClassID::Freeze, Opcode::Freeze, FI, Ctx) {}
+  friend Context; // For constructor;
+
+public:
+  static FreezeInst *create(Value *V, BBIterator WhereIt, BasicBlock *WhereBB,
+                            Context &Ctx, const Twine &Name = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::Freeze;
+  }
+};
+
+class LoadInst final : public UnaryInstruction {
+  /// Use LoadInst::create() instead of calling the constructor.
+  LoadInst(llvm::LoadInst *LI, Context &Ctx)
+      : UnaryInstruction(ClassID::Load, Opcode::Load, LI, Ctx) {}
+  friend Context; // for LoadInst()
+
+public:
+  /// Return true if this is a load from a volatile memory location.
+  bool isVolatile() const { return cast<llvm::LoadInst>(Val)->isVolatile(); }
+  /// Specify whether this is a volatile load or not.
+  void setVolatile(bool V);
+
+  static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align,
+                          Instruction *InsertBefore, Context &Ctx,
+                          const Twine &Name = "");
+  static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align,
+                          Instruction *InsertBefore, bool IsVolatile,
+                          Context &Ctx, const Twine &Name = "");
+  static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align,
+                          BasicBlock *InsertAtEnd, Context &Ctx,
+                          const Twine &Name = "");
+  static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align,
+                          BasicBlock *InsertAtEnd, bool IsVolatile,
+                          Context &Ctx, const Twine &Name = "");
+
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From);
+  Value *getPointerOperand() const;
+  Align getAlign() const { return cast<llvm::LoadInst>(Val)->getAlign(); }
+  bool isUnordered() const { return cast<llvm::LoadInst>(Val)->isUnordered(); }
+  bool isSimple() const { return cast<llvm::LoadInst>(Val)->isSimple(); }
+};
+
+class StoreInst final : public SingleLLVMInstructionImpl<llvm::StoreInst> {
+  /// Use StoreInst::create().
+  StoreInst(llvm::StoreInst *SI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::Store, Opcode::Store, SI, Ctx) {}
+  friend Context; // for StoreInst()
+
+public:
+  /// Return true if this is a store from a volatile memory location.
+  bool isVolatile() const { return cast<llvm::StoreInst>(Val)->isVolatile(); }
+  /// Specify whether this is a volatile store or not.
+  void setVolatile(bool V);
+
+  static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align,
+                           Instruction *InsertBefore, Context &Ctx);
+  static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align,
+                           Instruction *InsertBefore, bool IsVolatile,
+                           Context &Ctx);
+  static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align,
+                           BasicBlock *InsertAtEnd, Context &Ctx);
+  static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align,
+                           BasicBlock *InsertAtEnd, bool IsVolatile,
+                           Context &Ctx);
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From);
+  Value *getValueOperand() const;
+  Value *getPointerOperand() const;
+  Align getAlign() const { return cast<llvm::StoreInst>(Val)->getAlign(); }
+  bool isSimple() const { return cast<llvm::StoreInst>(Val)->isSimple(); }
+  bool isUnordered() const { return cast<llvm::StoreInst>(Val)->isUnordered(); }
+};
+
+class UnreachableInst final : public Instruction {
+  /// Use UnreachableInst::create() instead of calling the constructor.
+  UnreachableInst(llvm::UnreachableInst *I, Context &Ctx)
+      : Instruction(ClassID::Unreachable, Opcode::Unreachable, I, Ctx) {}
+  friend Context;
+  Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
+    return getOperandUseDefault(OpIdx, Verify);
+  }
+  SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
+    return {cast<llvm::Instruction>(Val)};
+  }
+
+public:
+  static UnreachableInst *create(Instruction *InsertBefore, Context &Ctx);
+  static UnreachableInst *create(BasicBlock *InsertAtEnd, Context &Ctx);
+  static bool classof(const Value *From);
+  unsigned getNumSuccessors() const { return 0; }
+  unsigned getUseOperandNo(const Use &Use) const final {
+    llvm_unreachable("UnreachableInst has no operands!");
+  }
+  unsigned getNumOfIRInstrs() const final { return 1u; }
+};
+
+class ReturnInst final : public SingleLLVMInstructionImpl<llvm::ReturnInst> {
+  /// Use ReturnInst::create() instead of calling the constructor.
+  ReturnInst(llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::Ret, Opcode::Ret, I, Ctx) {}
+  ReturnInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(SubclassID, Opcode::Ret, I, Ctx) {}
+  friend class Context; // For accessing the constructor in create*()
+  static ReturnInst *createCommon(Value *RetVal, IRBuilder<> &Builder,
+                                  Context &Ctx);
+
+public:
+  static ReturnInst *create(Value *RetVal, Instruction *InsertBefore,
+                            Context &Ctx);
+  static ReturnInst *create(Value *RetVal, BasicBlock *InsertAtEnd,
+                            Context &Ctx);
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::Ret;
+  }
+  /// \Returns null if there is no return value.
+  Value *getReturnValue() const;
+};
+
+class CallBase : public SingleLLVMInstructionImpl<llvm::CallBase> {
+  CallBase(ClassID ID, Opcode Opc, llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(ID, Opc, I, Ctx) {}
+  friend class CallInst;   // For constructor.
+  friend class InvokeInst; // For constructor.
+  friend class CallBrInst; // For constructor.
+
+public:
+  static bool classof(const Value *From) {
+    auto Opc = From->getSubclassID();
+    return Opc == Instruction::ClassID::Call ||
+           Opc == Instruction::ClassID::Invoke ||
+           Opc == Instruction::ClassID::CallBr;
+  }
+
+  FunctionType *getFunctionType() const;
+
+  op_iterator data_operands_begin() { return op_begin(); }
+  const_op_iterator data_operands_begin() const {
+    return const_cast<CallBase *>(this)->data_operands_begin();
+  }
+  op_iterator data_operands_end() {
+    auto *LLVMCB = cast<llvm::CallBase>(Val);
+    auto Dist = LLVMCB->data_operands_end() - LLVMCB->data_operands_begin();
+    return op_begin() + Dist;
+  }
+  const_op_iterator data_operands_end() const {
+    auto *LLVMCB = cast<llvm::CallBase>(Val);
+    auto Dist = LLVMCB->data_operands_end() - LLVMCB->data_operands_begin();
+    return op_begin() + Dist;
+  }
+  iterator_range<op_iterator> data_ops() {
+    return make_range(data_operands_begin(), data_operands_end());
+  }
+  iterator_range<const_op_iterator> data_ops() const {
+    return make_range(data_operands_begin(), data_operands_end());
+  }
+  bool data_operands_empty() const {
+    return data_operands_end() == data_operands_begin();
+  }
+  unsigned data_operands_size() const {
+    return std::distance(data_operands_begin(), data_operands_end());
+  }
+  bool isDataOperand(Use U) const {
+    assert(this == U.getUser() &&
+           "Only valid to query with a use of this instruction!");
+    return cast<llvm::CallBase>(Val)->isDataOperand(U.LLVMUse);
+  }
+  unsigned getDataOperandNo(Use U) const {
+    assert(isDataOperand(U) && "Data operand # out of range!");
+    return cast<llvm::CallBase>(Val)->getDataOperandNo(U.LLVMUse);
+  }
+
+  /// Return the total number operands (not operand bundles) used by
+  /// every operand bundle in this OperandBundleUser.
+  unsigned getNumTotalBundleOperands() const {
+    return cast<llvm::CallBase>(Val)->getNumTotalBundleOperands();
+  }
+
+  op_iterator arg_begin() { return op_begin(); }
+  const_op_iterator arg_begin() const { return op_begin(); }
+  op_iterator arg_end() {
+    return data_operands_end() - getNumTotalBundleOperands();
+  }
+  const_op_iterator arg_end() const {
+    return const_cast<CallBase *>(this)->arg_end();
+  }
+  iterator_range<op_iterator> args() {
+    return make_range(arg_begin(), arg_end());
+  }
+  iterator_range<const_op_iterator> args() const {
+    return make_range(arg_begin(), arg_end());
+  }
+  bool arg_empty() const { return arg_end() == arg_begin(); }
+  unsigned arg_size() const { return arg_end() - arg_begin(); }
+
+  Value *getArgOperand(unsigned OpIdx) const {
+    assert(OpIdx < arg_size() && "Out of bounds!");
+    return getOperand(OpIdx);
+  }
+  void setArgOperand(unsigned OpIdx, Value *NewOp) {
+    assert(OpIdx < arg_size() && "Out of bounds!");
+    setOperand(OpIdx, NewOp);
+  }
+
+  Use getArgOperandUse(unsigned Idx) const {
+    assert(Idx < arg_size() && "Out of bounds!");
+    return getOperandUse(Idx);
+  }
+  Use getArgOperandUse(unsigned Idx) {
+    assert(Idx < arg_size() && "Out of bounds!");
+    return getOperandUse(Idx);
+  }
+
+  bool isArgOperand(Use U) const {
+    return cast<llvm::CallBase>(Val)->isArgOperand(U.LLVMUse);
+  }
+  unsigned getArgOperandNo(Use U) const {
+    return cast<llvm::CallBase>(Val)->getArgOperandNo(U.LLVMUse);
+  }
+  bool hasArgument(const Value *V) const { return is_contained(args(), V); }
+
+  Value *getCalledOperand() const;
+  Use getCalledOperandUse() const;
+
+  Function *getCalledFunction() const;
+  bool isIndirectCall() const {
+    return cast<llvm::CallBase>(Val)->isIndirectCall();
+  }
+  bool isCallee(Use U) const {
+    return cast<llvm::CallBase>(Val)->isCallee(U.LLVMUse);
+  }
+  Function *getCaller();
+  const Function *getCaller() const {
+    return const_cast<CallBase *>(this)->getCaller();
+  }
+  bool isMustTailCall() const {
+    return cast<llvm::CallBase>(Val)->isMustTailCall();
+  }
+  bool isTailCall() const { return cast<llvm::CallBase>(Val)->isTailCall(); }
+  Intrinsic::ID getIntrinsicID() const {
+    return cast<llvm::CallBase>(Val)->getIntrinsicID();
+  }
+  void setCalledOperand(Value *V) { getCalledOperandUse().set(V); }
+  void setCalledFunction(Function *F);
+  CallingConv::ID getCallingConv() const {
+    return cast<llvm::CallBase>(Val)->getCallingConv();
+  }
+  bool isInlineAsm() const { return cast<llvm::CallBase>(Val)->isInlineAsm(); }
+};
+
+class CallInst final : public CallBase {
+  /// Use Context::createCallInst(). Don't call the
+  /// constructor directly.
+  CallInst(llvm::Instruction *I, Context &Ctx)
+      : CallBase(ClassID::Call, Opcode::Call, I, Ctx) {}
+  friend class Context; // For accessing the constructor in
+                        // create*()
+
+public:
+  static CallInst *create(FunctionType *FTy, Value *Func,
+                          ArrayRef<Value *> Args, BBIterator WhereIt,
+                          BasicBlock *WhereBB, Context &Ctx,
+                          const Twine &NameStr = "");
+  static CallInst *create(FunctionType *FTy, Value *Func,
+                          ArrayRef<Value *> Args, Instruction *InsertBefore,
+                          Context &Ctx, const Twine &NameStr = "");
+  static CallInst *create(FunctionType *FTy, Value *Func,
+                          ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
+                          Context &Ctx, const Twine &NameStr = "");
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::Call;
+  }
+};
+
+class InvokeInst final : public CallBase {
+  /// Use Context::createInvokeInst(). Don't call the
+  /// constructor directly.
+  InvokeInst(llvm::Instruction *I, Context &Ctx)
+      : CallBase(ClassID::Invoke, Opcode::Invoke, I, Ctx) {}
+  friend class Context; // For accessing the constructor in
+                        // create*()
+
+public:
+  static InvokeInst *create(FunctionType *FTy, Value *Func,
+                            BasicBlock *IfNormal, BasicBlock *IfException,
+                            ArrayRef<Value *> Args, BBIterator WhereIt,
+                            BasicBlock *WhereBB, Context &Ctx,
+                            const Twine &NameStr = "");
+  static InvokeInst *create(FunctionType *FTy, Value *Func,
+                            BasicBlock *IfNormal, BasicBlock *IfException,
+                            ArrayRef<Value *> Args, Instruction *InsertBefore,
+                            Context &Ctx, const Twine &NameStr = "");
+  static InvokeInst *create(FunctionType *FTy, Value *Func,
+                            BasicBlock *IfNormal, BasicBlock *IfException,
+                            ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
+                            Context &Ctx, const Twine &NameStr = "");
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::Invoke;
+  }
+  BasicBlock *getNormalDest() const;
+  BasicBlock *getUnwindDest() const;
+  void setNormalDest(BasicBlock *BB);
+  void setUnwindDest(BasicBlock *BB);
+  LandingPadInst *getLandingPadInst() const;
+  BasicBlock *getSuccessor(unsigned SuccIdx) const;
+  void setSuccessor(unsigned SuccIdx, BasicBlock *NewSucc) {
+    assert(SuccIdx < 2 && "Successor # out of range for invoke!");
+    if (SuccIdx == 0)
+      setNormalDest(NewSucc);
+    else
+      setUnwindDest(NewSucc);
+  }
+  unsigned getNumSuccessors() const {
+    return cast<llvm::InvokeInst>(Val)->getNumSuccessors();
+  }
+};
+
+class CallBrInst final : public CallBase {
+  /// Use Context::createCallBrInst(). Don't call the
+  /// constructor directly.
+  CallBrInst(llvm::Instruction *I, Context &Ctx)
+      : CallBase(ClassID::CallBr, Opcode::CallBr, I, Ctx) {}
+  friend class Context; // For accessing the constructor in
+                        // create*()
+
+public:
+  static CallBrInst *create(FunctionType *FTy, Value *Func,
+                            BasicBlock *DefaultDest,
+                            ArrayRef<BasicBlock *> IndirectDests,
+                            ArrayRef<Value *> Args, BBIterator WhereIt,
+                            BasicBlock *WhereBB, Context &Ctx,
+                            const Twine &NameStr = "");
+  static CallBrInst *create(FunctionType *FTy, Value *Func,
+                            BasicBlock *DefaultDest,
+                            ArrayRef<BasicBlock *> IndirectDests,
+                            ArrayRef<Value *> Args, Instruction *InsertBefore,
+                            Context &Ctx, const Twine &NameStr = "");
+  static CallBrInst *create(FunctionType *FTy, Value *Func,
+                            BasicBlock *DefaultDest,
+                            ArrayRef<BasicBlock *> IndirectDests,
+                            ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
+                            Context &Ctx, const Twine &NameStr = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::CallBr;
+  }
+  unsigned getNumIndirectDests() const {
+    return cast<llvm::CallBrInst>(Val)->getNumIndirectDests();
+  }
+  Value *getIndirectDestLabel(unsigned Idx) const;
+  Value *getIndirectDestLabelUse(unsigned Idx) const;
+  BasicBlock *getDefaultDest() const;
+  BasicBlock *getIndirectDest(unsigned Idx) const;
+  SmallVector<BasicBlock *, 16> getIndirectDests() const;
+  void setDefaultDest(BasicBlock *BB);
+  void setIndirectDest(unsigned Idx, BasicBlock *BB);
+  BasicBlock *getSuccessor(unsigned Idx) const;
+  unsigned getNumSuccessors() const {
+    return cast<llvm::CallBrInst>(Val)->getNumSuccessors();
+  }
+};
+
+class LandingPadInst : public SingleLLVMInstructionImpl<llvm::LandingPadInst> {
+  LandingPadInst(llvm::LandingPadInst *LP, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::LandingPad, Opcode::LandingPad, LP,
+                                  Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  static LandingPadInst *create(Type *RetTy, unsigned NumReservedClauses,
+                                BBIterator WhereIt, BasicBlock *WhereBB,
+                                Context &Ctx, const Twine &Name = "");
+  /// Return 'true' if this landingpad instruction is a
+  /// cleanup. I.e., it should be run when unwinding even if its landing pad
+  /// doesn't catch the exception.
+  bool isCleanup() const {
+    return cast<llvm::LandingPadInst>(Val)->isCleanup();
+  }
+  /// Indicate that this landingpad instruction is a cleanup.
+  void setCleanup(bool V);
+
+  // TODO: We are not implementing addClause() because we have no way to revert
+  // it for now.
+
+  /// Get the value of the clause at index Idx. Use isCatch/isFilter to
+  /// determine what type of clause this is.
+  Constant *getClause(unsigned Idx) const;
+
+  /// Return 'true' if the clause and index Idx is a catch clause.
+  bool isCatch(unsigned Idx) const {
+    return cast<llvm::LandingPadInst>(Val)->isCatch(Idx);
+  }
+  /// Return 'true' if the clause and index Idx is a filter clause.
+  bool isFilter(unsigned Idx) const {
+    return cast<llvm::LandingPadInst>(Val)->isFilter(Idx);
+  }
+  /// Get the number of clauses for this landing pad.
+  unsigned getNumClauses() const {
+    return cast<llvm::LandingPadInst>(Val)->getNumOperands();
+  }
+  // TODO: We are not implementing reserveClauses() because we can't revert it.
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::LandingPad;
+  }
+};
+
+class FuncletPadInst : public SingleLLVMInstructionImpl<llvm::FuncletPadInst> {
+  FuncletPadInst(ClassID SubclassID, Opcode Opc, llvm::Instruction *I,
+                 Context &Ctx)
+      : SingleLLVMInstructionImpl(SubclassID, Opc, I, Ctx) {}
+  friend class CatchPadInst;   // For constructor.
+  friend class CleanupPadInst; // For constructor.
+
+public:
+  /// Return the number of funcletpad arguments.
+  unsigned arg_size() const {
+    return cast<llvm::FuncletPadInst>(Val)->arg_size();
+  }
+  /// Return the outer EH-pad this funclet is nested within.
+  ///
+  /// Note: This returns the associated CatchSwitchInst if this FuncletPadInst
+  /// is a CatchPadInst.
+  Value *getParentPad() const;
+  void setParentPad(Value *ParentPad);
+  /// Return the Idx-th funcletpad argument.
+  Value *getArgOperand(unsigned Idx) const;
+  /// Set the Idx-th funcletpad argument.
+  void setArgOperand(unsigned Idx, Value *V);
+
+  // TODO: Implement missing functions: arg_operands().
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::CatchPad ||
+           From->getSubclassID() == ClassID::CleanupPad;
+  }
+};
+
+class CatchPadInst : public FuncletPadInst {
+  CatchPadInst(llvm::CatchPadInst *CPI, Context &Ctx)
+      : FuncletPadInst(ClassID::CatchPad, Opcode::CatchPad, CPI, Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  CatchSwitchInst *getCatchSwitch() const;
+  // TODO: We have not implemented setCatchSwitch() because we can't revert it
+  // for now, as there is no CatchPadInst member function that can undo it.
+
+  static CatchPadInst *create(Value *ParentPad, ArrayRef<Value *> Args,
+                              BBIterator WhereIt, BasicBlock *WhereBB,
+                              Context &Ctx, const Twine &Name = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::CatchPad;
+  }
+};
+
+class CleanupPadInst : public FuncletPadInst {
+  CleanupPadInst(llvm::CleanupPadInst *CPI, Context &Ctx)
+      : FuncletPadInst(ClassID::CleanupPad, Opcode::CleanupPad, CPI, Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  static CleanupPadInst *create(Value *ParentPad, ArrayRef<Value *> Args,
+                                BBIterator WhereIt, BasicBlock *WhereBB,
+                                Context &Ctx, const Twine &Name = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::CleanupPad;
+  }
+};
+
+class CatchReturnInst
+    : public SingleLLVMInstructionImpl<llvm::CatchReturnInst> {
+  CatchReturnInst(llvm::CatchReturnInst *CRI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::CatchRet, Opcode::CatchRet, CRI,
+                                  Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  static CatchReturnInst *create(CatchPadInst *CatchPad, BasicBlock *BB,
+                                 BBIterator WhereIt, BasicBlock *WhereBB,
+                                 Context &Ctx);
+  CatchPadInst *getCatchPad() const;
+  void setCatchPad(CatchPadInst *CatchPad);
+  BasicBlock *getSuccessor() const;
+  void setSuccessor(BasicBlock *NewSucc);
+  unsigned getNumSuccessors() {
+    return cast<llvm::CatchReturnInst>(Val)->getNumSuccessors();
+  }
+  Value *getCatchSwitchParentPad() const;
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::CatchRet;
+  }
+};
+
+class CleanupReturnInst
+    : public SingleLLVMInstructionImpl<llvm::CleanupReturnInst> {
+  CleanupReturnInst(llvm::CleanupReturnInst *CRI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::CleanupRet, Opcode::CleanupRet, CRI,
+                                  Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  static CleanupReturnInst *create(CleanupPadInst *CleanupPad,
+                                   BasicBlock *UnwindBB, BBIterator WhereIt,
+                                   BasicBlock *WhereBB, Context &Ctx);
+  bool hasUnwindDest() const {
+    return cast<llvm::CleanupReturnInst>(Val)->hasUnwindDest();
+  }
+  bool unwindsToCaller() const {
+    return cast<llvm::CleanupReturnInst>(Val)->unwindsToCaller();
+  }
+  CleanupPadInst *getCleanupPad() const;
+  void setCleanupPad(CleanupPadInst *CleanupPad);
+  unsigned getNumSuccessors() const {
+    return cast<llvm::CleanupReturnInst>(Val)->getNumSuccessors();
+  }
+  BasicBlock *getUnwindDest() const;
+  void setUnwindDest(BasicBlock *NewDest);
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::CleanupRet;
+  }
+};
+
+class GetElementPtrInst final
+    : public SingleLLVMInstructionImpl<llvm::GetElementPtrInst> {
+  /// Use Context::createGetElementPtrInst(). Don't call
+  /// the constructor directly.
+  GetElementPtrInst(llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::GetElementPtr, Opcode::GetElementPtr,
+                                  I, Ctx) {}
+  GetElementPtrInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(SubclassID, Opcode::GetElementPtr, I, Ctx) {}
+  friend class Context; // For accessing the constructor in
+                        // create*()
+
+public:
+  static Value *create(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
+                       BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
+                       const Twine &NameStr = "");
+  static Value *create(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &NameStr = "");
+  static Value *create(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &NameStr = "");
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::GetElementPtr;
+  }
+
+  Type *getSourceElementType() const;
+  Type *getResultElementType() const;
+  unsigned getAddressSpace() const {
+    return cast<llvm::GetElementPtrInst>(Val)->getAddressSpace();
+  }
+
+  inline op_iterator idx_begin() { return op_begin() + 1; }
+  inline const_op_iterator idx_begin() const {
+    return const_cast<GetElementPtrInst *>(this)->idx_begin();
+  }
+  inline op_iterator idx_end() { return op_end(); }
+  inline const_op_iterator idx_end() const {
+    return const_cast<GetElementPtrInst *>(this)->idx_end();
+  }
+  inline iterator_range<op_iterator> indices() {
+    return make_range(idx_begin(), idx_end());
+  }
+  inline iterator_range<const_op_iterator> indices() const {
+    return const_cast<GetElementPtrInst *>(this)->indices();
+  }
+
+  Value *getPointerOperand() const;
+  static unsigned getPointerOperandIndex() {
+    return llvm::GetElementPtrInst::getPointerOperandIndex();
+  }
+  Type *getPointerOperandType() const;
+  unsigned getPointerAddressSpace() const {
+    return cast<llvm::GetElementPtrInst>(Val)->getPointerAddressSpace();
+  }
+  unsigned getNumIndices() const {
+    return cast<llvm::GetElementPtrInst>(Val)->getNumIndices();
+  }
+  bool hasIndices() const {
+    return cast<llvm::GetElementPtrInst>(Val)->hasIndices();
+  }
+  bool hasAllConstantIndices() const {
+    return cast<llvm::GetElementPtrInst>(Val)->hasAllConstantIndices();
+  }
+  GEPNoWrapFlags getNoWrapFlags() const {
+    return cast<llvm::GetElementPtrInst>(Val)->getNoWrapFlags();
+  }
+  bool isInBounds() const {
+    return cast<llvm::GetElementPtrInst>(Val)->isInBounds();
+  }
+  bool hasNoUnsignedSignedWrap() const {
+    return cast<llvm::GetElementPtrInst>(Val)->hasNoUnsignedSignedWrap();
+  }
+  bool hasNoUnsignedWrap() const {
+    return cast<llvm::GetElementPtrInst>(Val)->hasNoUnsignedWrap();
+  }
+  bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const {
+    return cast<llvm::GetElementPtrInst>(Val)->accumulateConstantOffset(DL,
+                                                                        Offset);
+  }
+  // TODO: Add missing member functions.
+};
+
+class CatchSwitchInst
+    : public SingleLLVMInstructionImpl<llvm::CatchSwitchInst> {
+public:
+  CatchSwitchInst(llvm::CatchSwitchInst *CSI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::CatchSwitch, Opcode::CatchSwitch,
+                                  CSI, Ctx) {}
+
+  static CatchSwitchInst *create(Value *ParentPad, BasicBlock *UnwindBB,
+                                 unsigned NumHandlers, BBIterator WhereIt,
+                                 BasicBlock *WhereBB, Context &Ctx,
+                                 const Twine &Name = "");
+
+  Value *getParentPad() const;
+  void setParentPad(Value *ParentPad);
+
+  bool hasUnwindDest() const {
+    return cast<llvm::CatchSwitchInst>(Val)->hasUnwindDest();
+  }
+  bool unwindsToCaller() const {
+    return cast<llvm::CatchSwitchInst>(Val)->unwindsToCaller();
+  }
+  BasicBlock *getUnwindDest() const;
+  void setUnwindDest(BasicBlock *UnwindDest);
+
+  unsigned getNumHandlers() const {
+    return cast<llvm::CatchSwitchInst>(Val)->getNumHandlers();
+  }
+
+private:
+  static BasicBlock *handler_helper(Value *V) { return cast<BasicBlock>(V); }
+  static const BasicBlock *handler_helper(const Value *V) {
+    return cast<BasicBlock>(V);
+  }
+
+public:
+  using DerefFnTy = BasicBlock *(*)(Value *);
+  using handler_iterator = mapped_iterator<op_iterator, DerefFnTy>;
+  using handler_range = iterator_range<handler_iterator>;
+  using ConstDerefFnTy = const BasicBlock *(*)(const Value *);
+  using const_handler_iterator =
+      mapped_iterator<const_op_iterator, ConstDerefFnTy>;
+  using const_handler_range = iterator_range<const_handler_iterator>;
+
+  handler_iterator handler_begin() {
+    op_iterator It = op_begin() + 1;
+    if (hasUnwindDest())
+      ++It;
+    return handler_iterator(It, DerefFnTy(handler_helper));
+  }
+  const_handler_iterator handler_begin() const {
+    const_op_iterator It = op_begin() + 1;
+    if (hasUnwindDest())
+      ++It;
+    return const_handler_iterator(It, ConstDerefFnTy(handler_helper));
+  }
+  handler_iterator handler_end() {
+    return handler_iterator(op_end(), DerefFnTy(handler_helper));
+  }
+  const_handler_iterator handler_end() const {
+    return const_handler_iterator(op_end(), ConstDerefFnTy(handler_helper));
+  }
+  handler_range handlers() {
+    return make_range(handler_begin(), handler_end());
+  }
+  const_handler_range handlers() const {
+    return make_range(handler_begin(), handler_end());
+  }
+
+  void addHandler(BasicBlock *Dest);
+
+  // TODO: removeHandler() cannot be reverted because there is no equivalent
+  // addHandler() with a handler_iterator to specify the position. So we can't
+  // implement it for now.
+
+  unsigned getNumSuccessors() const { return getNumOperands() - 1; }
+  BasicBlock *getSuccessor(unsigned Idx) const {
+    assert(Idx < getNumSuccessors() &&
+           "Successor # out of range for catchswitch!");
+    return cast<BasicBlock>(getOperand(Idx + 1));
+  }
+  void setSuccessor(unsigned Idx, BasicBlock *NewSucc) {
+    assert(Idx < getNumSuccessors() &&
+           "Successor # out of range for catchswitch!");
+    setOperand(Idx + 1, NewSucc);
+  }
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::CatchSwitch;
+  }
+};
+
+class ResumeInst : public SingleLLVMInstructionImpl<llvm::ResumeInst> {
+public:
+  ResumeInst(llvm::ResumeInst *CSI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::Resume, Opcode::Resume, CSI, Ctx) {}
+
+  static ResumeInst *create(Value *Exn, BBIterator WhereIt, BasicBlock *WhereBB,
+                            Context &Ctx);
+  Value *getValue() const;
+  unsigned getNumSuccessors() const {
+    return cast<llvm::ResumeInst>(Val)->getNumSuccessors();
+  }
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::Resume;
+  }
+};
+
+class SwitchInst : public SingleLLVMInstructionImpl<llvm::SwitchInst> {
+public:
+  SwitchInst(llvm::SwitchInst *SI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::Switch, Opcode::Switch, SI, Ctx) {}
+
+  static constexpr const unsigned DefaultPseudoIndex =
+      llvm::SwitchInst::DefaultPseudoIndex;
+
+  static SwitchInst *create(Value *V, BasicBlock *Dest, unsigned NumCases,
+                            BasicBlock::iterator WhereIt, BasicBlock *WhereBB,
+                            Context &Ctx, const Twine &Name = "");
+
+  Value *getCondition() const;
+  void setCondition(Value *V);
+  BasicBlock *getDefaultDest() const;
+  bool defaultDestUndefined() const {
+    return cast<llvm::SwitchInst>(Val)->defaultDestUndefined();
+  }
+  void setDefaultDest(BasicBlock *DefaultCase);
+  unsigned getNumCases() const {
+    return cast<llvm::SwitchInst>(Val)->getNumCases();
+  }
+
+  using CaseHandle =
+      llvm::SwitchInst::CaseHandleImpl<SwitchInst, ConstantInt, BasicBlock>;
+  using ConstCaseHandle =
+      llvm::SwitchInst::CaseHandleImpl<const SwitchInst, const ConstantInt,
+                                       const BasicBlock>;
+  using CaseIt = llvm::SwitchInst::CaseIteratorImpl<CaseHandle>;
+  using ConstCaseIt = llvm::SwitchInst::CaseIteratorImpl<ConstCaseHandle>;
+
+  /// Returns a read/write iterator that points to the first case in the
+  /// SwitchInst.
+  CaseIt case_begin() { return CaseIt(this, 0); }
+  ConstCaseIt case_begin() const { return ConstCaseIt(this, 0); }
+  /// Returns a read/write iterator that points one past the last in the
+  /// SwitchInst.
+  CaseIt case_end() { return CaseIt(this, getNumCases()); }
+  ConstCaseIt case_end() const { return ConstCaseIt(this, getNumCases()); }
+  /// Iteration adapter for range-for loops.
+  iterator_range<CaseIt> cases() {
+    return make_range(case_begin(), case_end());
+  }
+  iterator_range<ConstCaseIt> cases() const {
+    return make_range(case_begin(), case_end());
+  }
+  CaseIt case_default() { return CaseIt(this, DefaultPseudoIndex); }
+  ConstCaseIt case_default() const {
+    return ConstCaseIt(this, DefaultPseudoIndex);
+  }
+  CaseIt findCaseValue(const ConstantInt *C) {
+    return CaseIt(
+        this,
+        const_cast<const SwitchInst *>(this)->findCaseValue(C)->getCaseIndex());
+  }
+  ConstCaseIt findCaseValue(const ConstantInt *C) const {
+    ConstCaseIt I = llvm::find_if(cases(), [C](const ConstCaseHandle &Case) {
+      return Case.getCaseValue() == C;
+    });
+    if (I != case_end())
+      return I;
+    return case_default();
+  }
+  ConstantInt *findCaseDest(BasicBlock *BB);
+
+  void addCase(ConstantInt *OnVal, BasicBlock *Dest);
+  /// This method removes the specified case and its successor from the switch
+  /// instruction. Note that this operation may reorder the remaining cases at
+  /// index idx and above.
+  /// Note:
+  /// This action invalidates iterators for all cases following the one removed,
+  /// including the case_end() iterator. It returns an iterator for the next
+  /// case.
+  CaseIt removeCase(CaseIt It);
+
+  unsigned getNumSuccessors() const {
+    return cast<llvm::SwitchInst>(Val)->getNumSuccessors();
+  }
+  BasicBlock *getSuccessor(unsigned Idx) const;
+  void setSuccessor(unsigned Idx, BasicBlock *NewSucc);
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::Switch;
+  }
+};
+
+class UnaryOperator : public UnaryInstruction {
+  static Opcode getUnaryOpcode(llvm::Instruction::UnaryOps UnOp) {
+    switch (UnOp) {
+    case llvm::Instruction::FNeg:
+      return Opcode::FNeg;
+    case llvm::Instruction::UnaryOpsEnd:
+      llvm_unreachable("Bad UnOp!");
+    }
+    llvm_unreachable("Unhandled UnOp!");
+  }
+  UnaryOperator(llvm::UnaryOperator *UO, Context &Ctx)
+      : UnaryInstruction(ClassID::UnOp, getUnaryOpcode(UO->getOpcode()), UO,
+                         Ctx) {}
+  friend Context; // for constructor.
+public:
+  static Value *create(Instruction::Opcode Op, Value *OpV, BBIterator WhereIt,
+                       BasicBlock *WhereBB, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Instruction::Opcode Op, Value *OpV,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Instruction::Opcode Op, Value *OpV,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
+                                      Value *CopyFrom, BBIterator WhereIt,
+                                      BasicBlock *WhereBB, Context &Ctx,
+                                      const Twine &Name = "");
+  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
+                                      Value *CopyFrom,
+                                      Instruction *InsertBefore, Context &Ctx,
+                                      const Twine &Name = "");
+  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
+                                      Value *CopyFrom, BasicBlock *InsertAtEnd,
+                                      Context &Ctx, const Twine &Name = "");
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::UnOp;
+  }
+};
+
+class BinaryOperator : public SingleLLVMInstructionImpl<llvm::BinaryOperator> {
+protected:
+  static Opcode getBinOpOpcode(llvm::Instruction::BinaryOps BinOp) {
+    switch (BinOp) {
+    case llvm::Instruction::Add:
+      return Opcode::Add;
+    case llvm::Instruction::FAdd:
+      return Opcode::FAdd;
+    case llvm::Instruction::Sub:
+      return Opcode::Sub;
+    case llvm::Instruction::FSub:
+      return Opcode::FSub;
+    case llvm::Instruction::Mul:
+      return Opcode::Mul;
+    case llvm::Instruction::FMul:
+      return Opcode::FMul;
+    case llvm::Instruction::UDiv:
+      return Opcode::UDiv;
+    case llvm::Instruction::SDiv:
+      return Opcode::SDiv;
+    case llvm::Instruction::FDiv:
+      return Opcode::FDiv;
+    case llvm::Instruction::URem:
+      return Opcode::URem;
+    case llvm::Instruction::SRem:
+      return Opcode::SRem;
+    case llvm::Instruction::FRem:
+      return Opcode::FRem;
+    case llvm::Instruction::Shl:
+      return Opcode::Shl;
+    case llvm::Instruction::LShr:
+      return Opcode::LShr;
+    case llvm::Instruction::AShr:
+      return Opcode::AShr;
+    case llvm::Instruction::And:
+      return Opcode::And;
+    case llvm::Instruction::Or:
+      return Opcode::Or;
+    case llvm::Instruction::Xor:
+      return Opcode::Xor;
+    case llvm::Instruction::BinaryOpsEnd:
+      llvm_unreachable("Bad BinOp!");
+    }
+    llvm_unreachable("Unhandled BinOp!");
+  }
+  BinaryOperator(llvm::BinaryOperator *BinOp, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::BinaryOperator,
+                                  getBinOpOpcode(BinOp->getOpcode()), BinOp,
+                                  Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS,
+                       BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+
+  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
+                                      Value *RHS, Value *CopyFrom,
+                                      BBIterator WhereIt, BasicBlock *WhereBB,
+                                      Context &Ctx, const Twine &Name = "");
+  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
+                                      Value *RHS, Value *CopyFrom,
+                                      Instruction *InsertBefore, Context &Ctx,
+                                      const Twine &Name = "");
+  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
+                                      Value *RHS, Value *CopyFrom,
+                                      BasicBlock *InsertAtEnd, Context &Ctx,
+                                      const Twine &Name = "");
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::BinaryOperator;
+  }
+  void swapOperands() { swapOperandsInternal(0, 1); }
+};
+
+/// An or instruction, which can be marked as "disjoint", indicating that the
+/// inputs don't have a 1 in the same bit position. Meaning this instruction
+/// can also be treated as an add.
+class PossiblyDisjointInst : public BinaryOperator {
+public:
+  void setIsDisjoint(bool B);
+  bool isDisjoint() const {
+    return cast<llvm::PossiblyDisjointInst>(Val)->isDisjoint();
+  }
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From) {
+    return isa<Instruction>(From) &&
+           cast<Instruction>(From)->getOpcode() == Opcode::Or;
+  }
+};
+
+class AtomicRMWInst : public SingleLLVMInstructionImpl<llvm::AtomicRMWInst> {
+  AtomicRMWInst(llvm::AtomicRMWInst *Atomic, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::AtomicRMW,
+                                  Instruction::Opcode::AtomicRMW, Atomic, Ctx) {
+  }
+  friend class Context; // For constructor.
+
+public:
+  using BinOp = llvm::AtomicRMWInst::BinOp;
+  BinOp getOperation() const {
+    return cast<llvm::AtomicRMWInst>(Val)->getOperation();
+  }
+  static StringRef getOperationName(BinOp Op) {
+    return llvm::AtomicRMWInst::getOperationName(Op);
+  }
+  static bool isFPOperation(BinOp Op) {
+    return llvm::AtomicRMWInst::isFPOperation(Op);
+  }
+  void setOperation(BinOp Op) {
+    cast<llvm::AtomicRMWInst>(Val)->setOperation(Op);
+  }
+  Align getAlign() const { return cast<llvm::AtomicRMWInst>(Val)->getAlign(); }
+  void setAlignment(Align Align);
+  bool isVolatile() const {
+    return cast<llvm::AtomicRMWInst>(Val)->isVolatile();
+  }
+  void setVolatile(bool V);
+  AtomicOrdering getOrdering() const {
+    return cast<llvm::AtomicRMWInst>(Val)->getOrdering();
+  }
+  void setOrdering(AtomicOrdering Ordering);
+  SyncScope::ID getSyncScopeID() const {
+    return cast<llvm::AtomicRMWInst>(Val)->getSyncScopeID();
+  }
+  void setSyncScopeID(SyncScope::ID SSID);
+  Value *getPointerOperand();
+  const Value *getPointerOperand() const {
+    return const_cast<AtomicRMWInst *>(this)->getPointerOperand();
+  }
+  Value *getValOperand();
+  const Value *getValOperand() const {
+    return const_cast<AtomicRMWInst *>(this)->getValOperand();
+  }
+  unsigned getPointerAddressSpace() const {
+    return cast<llvm::AtomicRMWInst>(Val)->getPointerAddressSpace();
+  }
+  bool isFloatingPointOperation() const {
+    return cast<llvm::AtomicRMWInst>(Val)->isFloatingPointOperation();
+  }
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::AtomicRMW;
+  }
+
+  static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
+                               MaybeAlign Align, AtomicOrdering Ordering,
+                               BBIterator WhereIt, BasicBlock *WhereBB,
+                               Context &Ctx,
+                               SyncScope::ID SSID = SyncScope::System,
+                               const Twine &Name = "");
+  static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
+                               MaybeAlign Align, AtomicOrdering Ordering,
+                               Instruction *InsertBefore, Context &Ctx,
+                               SyncScope::ID SSID = SyncScope::System,
+                               const Twine &Name = "");
+  static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
+                               MaybeAlign Align, AtomicOrdering Ordering,
+                               BasicBlock *InsertAtEnd, Context &Ctx,
+                               SyncScope::ID SSID = SyncScope::System,
+                               const Twine &Name = "");
+};
+
+class AtomicCmpXchgInst
+    : public SingleLLVMInstructionImpl<llvm::AtomicCmpXchgInst> {
+  AtomicCmpXchgInst(llvm::AtomicCmpXchgInst *Atomic, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::AtomicCmpXchg,
+                                  Instruction::Opcode::AtomicCmpXchg, Atomic,
+                                  Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  /// Return the alignment of the memory that is being allocated by the
+  /// instruction.
+  Align getAlign() const {
+    return cast<llvm::AtomicCmpXchgInst>(Val)->getAlign();
+  }
+
+  void setAlignment(Align Align);
+  /// Return true if this is a cmpxchg from a volatile memory
+  /// location.
+  bool isVolatile() const {
+    return cast<llvm::AtomicCmpXchgInst>(Val)->isVolatile();
+  }
+  /// Specify whether this is a volatile cmpxchg.
+  void setVolatile(bool V);
+  /// Return true if this cmpxchg may spuriously fail.
+  bool isWeak() const { return cast<llvm::AtomicCmpXchgInst>(Val)->isWeak(); }
+  void setWeak(bool IsWeak);
+  static bool isValidSuccessOrdering(AtomicOrdering Ordering) {
+    return llvm::AtomicCmpXchgInst::isValidSuccessOrdering(Ordering);
+  }
+  static bool isValidFailureOrdering(AtomicOrdering Ordering) {
+    return llvm::AtomicCmpXchgInst::isValidFailureOrdering(Ordering);
+  }
+  AtomicOrdering getSuccessOrdering() const {
+    return cast<llvm::AtomicCmpXchgInst>(Val)->getSuccessOrdering();
+  }
+  void setSuccessOrdering(AtomicOrdering Ordering);
+
+  AtomicOrdering getFailureOrdering() const {
+    return cast<llvm::AtomicCmpXchgInst>(Val)->getFailureOrdering();
+  }
+  void setFailureOrdering(AtomicOrdering Ordering);
+  AtomicOrdering getMergedOrdering() const {
+    return cast<llvm::AtomicCmpXchgInst>(Val)->getMergedOrdering();
+  }
+  SyncScope::ID getSyncScopeID() const {
+    return cast<llvm::AtomicCmpXchgInst>(Val)->getSyncScopeID();
+  }
+  void setSyncScopeID(SyncScope::ID SSID);
+  Value *getPointerOperand();
+  const Value *getPointerOperand() const {
+    return const_cast<AtomicCmpXchgInst *>(this)->getPointerOperand();
+  }
+
+  Value *getCompareOperand();
+  const Value *getCompareOperand() const {
+    return const_cast<AtomicCmpXchgInst *>(this)->getCompareOperand();
+  }
+
+  Value *getNewValOperand();
+  const Value *getNewValOperand() const {
+    return const_cast<AtomicCmpXchgInst *>(this)->getNewValOperand();
+  }
+
+  /// Returns the address space of the pointer operand.
+  unsigned getPointerAddressSpace() const {
+    return cast<llvm::AtomicCmpXchgInst>(Val)->getPointerAddressSpace();
+  }
+
+  static AtomicCmpXchgInst *
+  create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align,
+         AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering,
+         BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
+         SyncScope::ID SSID = SyncScope::System, const Twine &Name = "");
+  static AtomicCmpXchgInst *
+  create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align,
+         AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering,
+         Instruction *InsertBefore, Context &Ctx,
+         SyncScope::ID SSID = SyncScope::System, const Twine &Name = "");
+  static AtomicCmpXchgInst *
+  create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align,
+         AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering,
+         BasicBlock *InsertAtEnd, Context &Ctx,
+         SyncScope::ID SSID = SyncScope::System, const Twine &Name = "");
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::AtomicCmpXchg;
+  }
+};
+
+class AllocaInst final : public UnaryInstruction {
+  AllocaInst(llvm::AllocaInst *AI, Context &Ctx)
+      : UnaryInstruction(ClassID::Alloca, Instruction::Opcode::Alloca, AI,
+                         Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  static AllocaInst *create(Type *Ty, unsigned AddrSpace, BBIterator WhereIt,
+                            BasicBlock *WhereBB, Context &Ctx,
+                            Value *ArraySize = nullptr, const Twine &Name = "");
+  static AllocaInst *create(Type *Ty, unsigned AddrSpace,
+                            Instruction *InsertBefore, Context &Ctx,
+                            Value *ArraySize = nullptr, const Twine &Name = "");
+  static AllocaInst *create(Type *Ty, unsigned AddrSpace,
+                            BasicBlock *InsertAtEnd, Context &Ctx,
+                            Value *ArraySize = nullptr, const Twine &Name = "");
+
+  /// Return true if there is an allocation size parameter to the allocation
+  /// instruction that is not 1.
+  bool isArrayAllocation() const {
+    return cast<llvm::AllocaInst>(Val)->isArrayAllocation();
+  }
+  /// Get the number of elements allocated. For a simple allocation of a single
+  /// element, this will return a constant 1 value.
+  Value *getArraySize();
+  const Value *getArraySize() const {
+    return const_cast<AllocaInst *>(this)->getArraySize();
+  }
+  /// Overload to return most specific pointer type.
+  PointerType *getType() const;
+  /// Return the address space for the allocation.
+  unsigned getAddressSpace() const {
+    return cast<llvm::AllocaInst>(Val)->getAddressSpace();
+  }
+  /// Get allocation size in bytes. Returns std::nullopt if size can't be
+  /// determined, e.g. in case of a VLA.
+  std::optional<TypeSize> getAllocationSize(const DataLayout &DL) const {
+    return cast<llvm::AllocaInst>(Val)->getAllocationSize(DL);
+  }
+  /// Get allocation size in bits. Returns std::nullopt if size can't be
+  /// determined, e.g. in case of a VLA.
+  std::optional<TypeSize> getAllocationSizeInBits(const DataLayout &DL) const {
+    return cast<llvm::AllocaInst>(Val)->getAllocationSizeInBits(DL);
+  }
+  /// Return the type that is being allocated by the instruction.
+  Type *getAllocatedType() const;
+  /// for use only in special circumstances that need to generically
+  /// transform a whole instruction (eg: IR linking and vectorization).
+  void setAllocatedType(Type *Ty);
+  /// Return the alignment of the memory that is being allocated by the
+  /// instruction.
+  Align getAlign() const { return cast<llvm::AllocaInst>(Val)->getAlign(); }
+  void setAlignment(Align Align);
+  /// Return true if this alloca is in the entry block of the function and is a
+  /// constant size. If so, the code generator will fold it into the
+  /// prolog/epilog code, so it is basically free.
+  bool isStaticAlloca() const {
+    return cast<llvm::AllocaInst>(Val)->isStaticAlloca();
+  }
+  /// Return true if this alloca is used as an inalloca argument to a call. Such
+  /// allocas are never considered static even if they are in the entry block.
+  bool isUsedWithInAlloca() const {
+    return cast<llvm::AllocaInst>(Val)->isUsedWithInAlloca();
+  }
+  /// Specify whether this alloca is used to represent the arguments to a call.
+  void setUsedWithInAlloca(bool V);
+
+  static bool classof(const Value *From) {
+    if (auto *I = dyn_cast<Instruction>(From))
+      return I->getSubclassID() == Instruction::ClassID::Alloca;
+    return false;
+  }
+};
+
+class CastInst : public UnaryInstruction {
+  static Opcode getCastOpcode(llvm::Instruction::CastOps CastOp) {
+    switch (CastOp) {
+    case llvm::Instruction::ZExt:
+      return Opcode::ZExt;
+    case llvm::Instruction::SExt:
+      return Opcode::SExt;
+    case llvm::Instruction::FPToUI:
+      return Opcode::FPToUI;
+    case llvm::Instruction::FPToSI:
+      return Opcode::FPToSI;
+    case llvm::Instruction::FPExt:
+      return Opcode::FPExt;
+    case llvm::Instruction::PtrToInt:
+      return Opcode::PtrToInt;
+    case llvm::Instruction::IntToPtr:
+      return Opcode::IntToPtr;
+    case llvm::Instruction::SIToFP:
+      return Opcode::SIToFP;
+    case llvm::Instruction::UIToFP:
+      return Opcode::UIToFP;
+    case llvm::Instruction::Trunc:
+      return Opcode::Trunc;
+    case llvm::Instruction::FPTrunc:
+      return Opcode::FPTrunc;
+    case llvm::Instruction::BitCast:
+      return Opcode::BitCast;
+    case llvm::Instruction::AddrSpaceCast:
+      return Opcode::AddrSpaceCast;
+    case llvm::Instruction::CastOpsEnd:
+      llvm_unreachable("Bad CastOp!");
+    }
+    llvm_unreachable("Unhandled CastOp!");
+  }
+  /// Use Context::createCastInst(). Don't call the
+  /// constructor directly.
+  CastInst(llvm::CastInst *CI, Context &Ctx)
+      : UnaryInstruction(ClassID::Cast, getCastOpcode(CI->getOpcode()), CI,
+                         Ctx) {}
+  friend Context; // for SBCastInstruction()
+
+public:
+  static Value *create(Type *DestTy, Opcode Op, Value *Operand,
+                       BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Type *DestTy, Opcode Op, Value *Operand,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Type *DestTy, Opcode Op, Value *Operand,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From);
+  Type *getSrcTy() const;
+  Type *getDestTy() const;
+};
+
+/// Instruction that can have a nneg flag (zext/uitofp).
+class PossiblyNonNegInst : public CastInst {
+public:
+  bool hasNonNeg() const {
+    return cast<llvm::PossiblyNonNegInst>(Val)->hasNonNeg();
+  }
+  void setNonNeg(bool B);
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From) {
+    if (auto *I = dyn_cast<Instruction>(From)) {
+      switch (I->getOpcode()) {
+      case Opcode::ZExt:
+      case Opcode::UIToFP:
+        return true;
+      default:
+        return false;
+      }
+    }
+    return false;
+  }
+};
+
+// Helper class to simplify stamping out CastInst subclasses.
+template <Instruction::Opcode Op> class CastInstImpl : public CastInst {
+public:
+  static Value *create(Value *Src, Type *DestTy, BBIterator WhereIt,
+                       BasicBlock *WhereBB, Context &Ctx,
+                       const Twine &Name = "") {
+    return CastInst::create(DestTy, Op, Src, WhereIt, WhereBB, Ctx, Name);
+  }
+  static Value *create(Value *Src, Type *DestTy, Instruction *InsertBefore,
+                       Context &Ctx, const Twine &Name = "") {
+    return create(Src, DestTy, InsertBefore->getIterator(),
+                  InsertBefore->getParent(), Ctx, Name);
+  }
+  static Value *create(Value *Src, Type *DestTy, BasicBlock *InsertAtEnd,
+                       Context &Ctx, const Twine &Name = "") {
+    return create(Src, DestTy, InsertAtEnd->end(), InsertAtEnd, Ctx, Name);
+  }
+
+  static bool classof(const Value *From) {
+    if (auto *I = dyn_cast<Instruction>(From))
+      return I->getOpcode() == Op;
+    return false;
+  }
+};
+
+class TruncInst final : public CastInstImpl<Instruction::Opcode::Trunc> {};
+class ZExtInst final : public CastInstImpl<Instruction::Opcode::ZExt> {};
+class SExtInst final : public CastInstImpl<Instruction::Opcode::SExt> {};
+class FPTruncInst final : public CastInstImpl<Instruction::Opcode::FPTrunc> {};
+class FPExtInst final : public CastInstImpl<Instruction::Opcode::FPExt> {};
+class UIToFPInst final : public CastInstImpl<Instruction::Opcode::UIToFP> {};
+class SIToFPInst final : public CastInstImpl<Instruction::Opcode::SIToFP> {};
+class FPToUIInst final : public CastInstImpl<Instruction::Opcode::FPToUI> {};
+class FPToSIInst final : public CastInstImpl<Instruction::Opcode::FPToSI> {};
+class IntToPtrInst final : public CastInstImpl<Instruction::Opcode::IntToPtr> {
+};
+class PtrToIntInst final : public CastInstImpl<Instruction::Opcode::PtrToInt> {
+};
+class BitCastInst final : public CastInstImpl<Instruction::Opcode::BitCast> {};
+class AddrSpaceCastInst final
+    : public CastInstImpl<Instruction::Opcode::AddrSpaceCast> {
+public:
+  /// \Returns the pointer operand.
+  Value *getPointerOperand() { return getOperand(0); }
+  /// \Returns the pointer operand.
+  const Value *getPointerOperand() const {
+    return const_cast<AddrSpaceCastInst *>(this)->getPointerOperand();
+  }
+  /// \Returns the operand index of the pointer operand.
+  static unsigned getPointerOperandIndex() { return 0u; }
+  /// \Returns the address space of the pointer operand.
+  unsigned getSrcAddressSpace() const {
+    return getPointerOperand()->getType()->getPointerAddressSpace();
+  }
+  /// \Returns the address space of the result.
+  unsigned getDestAddressSpace() const {
+    return getType()->getPointerAddressSpace();
+  }
+};
+
+class PHINode final : public SingleLLVMInstructionImpl<llvm::PHINode> {
+  /// Use Context::createPHINode(). Don't call the constructor directly.
+  PHINode(llvm::PHINode *PHI, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::PHI, Opcode::PHI, PHI, Ctx) {}
+  friend Context; // for PHINode()
+  /// Helper for mapped_iterator.
+  struct LLVMBBToBB {
+    Context &Ctx;
+    LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {}
+    BasicBlock *operator()(llvm::BasicBlock *LLVMBB) const;
+  };
+
+public:
+  static PHINode *create(Type *Ty, unsigned NumReservedValues,
+                         Instruction *InsertBefore, Context &Ctx,
+                         const Twine &Name = "");
+  /// For isa/dyn_cast.
+  static bool classof(const Value *From);
+
+  using const_block_iterator =
+      mapped_iterator<llvm::PHINode::const_block_iterator, LLVMBBToBB>;
+
+  const_block_iterator block_begin() const {
+    LLVMBBToBB BBGetter(Ctx);
+    return const_block_iterator(cast<llvm::PHINode>(Val)->block_begin(),
+                                BBGetter);
+  }
+  const_block_iterator block_end() const {
+    LLVMBBToBB BBGetter(Ctx);
+    return const_block_iterator(cast<llvm::PHINode>(Val)->block_end(),
+                                BBGetter);
+  }
+  iterator_range<const_block_iterator> blocks() const {
+    return make_range(block_begin(), block_end());
+  }
+
+  op_range incoming_values() { return operands(); }
+
+  const_op_range incoming_values() const { return operands(); }
+
+  unsigned getNumIncomingValues() const {
+    return cast<llvm::PHINode>(Val)->getNumIncomingValues();
+  }
+  Value *getIncomingValue(unsigned Idx) const;
+  void setIncomingValue(unsigned Idx, Value *V);
+  static unsigned getOperandNumForIncomingValue(unsigned Idx) {
+    return llvm::PHINode::getOperandNumForIncomingValue(Idx);
+  }
+  static unsigned getIncomingValueNumForOperand(unsigned Idx) {
+    return llvm::PHINode::getIncomingValueNumForOperand(Idx);
+  }
+  BasicBlock *getIncomingBlock(unsigned Idx) const;
+  BasicBlock *getIncomingBlock(const Use &U) const;
+
+  void setIncomingBlock(unsigned Idx, BasicBlock *BB);
+
+  void addIncoming(Value *V, BasicBlock *BB);
+
+  Value *removeIncomingValue(unsigned Idx);
+  Value *removeIncomingValue(BasicBlock *BB);
+
+  int getBasicBlockIndex(const BasicBlock *BB) const;
+  Value *getIncomingValueForBlock(const BasicBlock *BB) const;
+
+  Value *hasConstantValue() const;
+
+  bool hasConstantOrUndefValue() const {
+    return cast<llvm::PHINode>(Val)->hasConstantOrUndefValue();
+  }
+  bool isComplete() const { return cast<llvm::PHINode>(Val)->isComplete(); }
+  void replaceIncomingBlockWith(const BasicBlock *Old, BasicBlock *New);
+  void removeIncomingValueIf(function_ref<bool(unsigned)> Predicate);
+  // TODO: Implement
+  // void copyIncomingBlocks(iterator_range<const_block_iterator> BBRange,
+  //                         uint32_t ToIdx = 0)
+};
+
+// Wraps a static function that takes a single Predicate parameter
+// LLVMValType should be the type of the wrapped class
+#define WRAP_STATIC_PREDICATE(FunctionName)                                    \
+  static auto FunctionName(Predicate P) { return LLVMValType::FunctionName(P); }
+// Wraps a member function that takes no parameters
+// LLVMValType should be the type of the wrapped class
+#define WRAP_MEMBER(FunctionName)                                              \
+  auto FunctionName() const { return cast<LLVMValType>(Val)->FunctionName(); }
+// Wraps both--a common idiom in the CmpInst classes
+#define WRAP_BOTH(FunctionName)                                                \
+  WRAP_STATIC_PREDICATE(FunctionName)                                          \
+  WRAP_MEMBER(FunctionName)
+
+class CmpInst : public SingleLLVMInstructionImpl<llvm::CmpInst> {
+protected:
+  using LLVMValType = llvm::CmpInst;
+  /// Use Context::createCmpInst(). Don't call the constructor directly.
+  CmpInst(llvm::CmpInst *CI, Context &Ctx, ClassID Id, Opcode Opc)
+      : SingleLLVMInstructionImpl(Id, Opc, CI, Ctx) {}
+  friend Context; // for CmpInst()
+  static Value *createCommon(Value *Cond, Value *True, Value *False,
+                             const Twine &Name, IRBuilder<> &Builder,
+                             Context &Ctx);
+
+public:
+  using Predicate = llvm::CmpInst::Predicate;
+
+  static CmpInst *create(Predicate Pred, Value *S1, Value *S2,
+                         Instruction *InsertBefore, Context &Ctx,
+                         const Twine &Name = "");
+  static CmpInst *createWithCopiedFlags(Predicate Pred, Value *S1, Value *S2,
+                                        const Instruction *FlagsSource,
+                                        Instruction *InsertBefore, Context &Ctx,
+                                        const Twine &Name = "");
+  void setPredicate(Predicate P);
+  void swapOperands();
+
+  WRAP_MEMBER(getPredicate);
+  WRAP_BOTH(isFPPredicate);
+  WRAP_BOTH(isIntPredicate);
+  WRAP_STATIC_PREDICATE(getPredicateName);
+  WRAP_BOTH(getInversePredicate);
+  WRAP_BOTH(getOrderedPredicate);
+  WRAP_BOTH(getUnorderedPredicate);
+  WRAP_BOTH(getSwappedPredicate);
+  WRAP_BOTH(isStrictPredicate);
+  WRAP_BOTH(isNonStrictPredicate);
+  WRAP_BOTH(getStrictPredicate);
+  WRAP_BOTH(getNonStrictPredicate);
+  WRAP_BOTH(getFlippedStrictnessPredicate);
+  WRAP_MEMBER(isCommutative);
+  WRAP_BOTH(isEquality);
+  WRAP_BOTH(isRelational);
+  WRAP_BOTH(isSigned);
+  WRAP_BOTH(getSignedPredicate);
+  WRAP_BOTH(getUnsignedPredicate);
+  WRAP_BOTH(getFlippedSignednessPredicate);
+  WRAP_BOTH(isTrueWhenEqual);
+  WRAP_BOTH(isFalseWhenEqual);
+  WRAP_BOTH(isUnsigned);
+  WRAP_STATIC_PREDICATE(isOrdered);
+  WRAP_STATIC_PREDICATE(isUnordered);
+
+  static bool isImpliedTrueByMatchingCmp(Predicate Pred1, Predicate Pred2) {
+    return llvm::CmpInst::isImpliedTrueByMatchingCmp(Pred1, Pred2);
+  }
+  static bool isImpliedFalseByMatchingCmp(Predicate Pred1, Predicate Pred2) {
+    return llvm::CmpInst::isImpliedFalseByMatchingCmp(Pred1, Pred2);
+  }
+
+  /// Method for support type inquiry through isa, cast, and dyn_cast:
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::ICmp ||
+           From->getSubclassID() == ClassID::FCmp;
+  }
+
+  /// Create a result type for fcmp/icmp
+  static Type *makeCmpResultType(Type *OpndType);
+
+#ifndef NDEBUG
+  void dumpOS(raw_ostream &OS) const override;
+  LLVM_DUMP_METHOD void dump() const;
+#endif
+};
+
+class ICmpInst : public CmpInst {
+  /// Use Context::createICmpInst(). Don't call the constructor directly.
+  ICmpInst(llvm::ICmpInst *CI, Context &Ctx)
+      : CmpInst(CI, Ctx, ClassID::ICmp, Opcode::ICmp) {}
+  friend class Context; // For constructor.
+  using LLVMValType = llvm::ICmpInst;
+
+public:
+  void swapOperands();
+
+  WRAP_BOTH(getSignedPredicate);
+  WRAP_BOTH(getUnsignedPredicate);
+  WRAP_BOTH(isEquality);
+  WRAP_MEMBER(isCommutative);
+  WRAP_MEMBER(isRelational);
+  WRAP_STATIC_PREDICATE(isGT);
+  WRAP_STATIC_PREDICATE(isLT);
+  WRAP_STATIC_PREDICATE(isGE);
+  WRAP_STATIC_PREDICATE(isLE);
+
+  static auto predicates() { return llvm::ICmpInst::predicates(); }
+  static bool compare(const APInt &LHS, const APInt &RHS,
+                      ICmpInst::Predicate Pred) {
+    return llvm::ICmpInst::compare(LHS, RHS, Pred);
+  }
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::ICmp;
+  }
+};
+
+class FCmpInst : public CmpInst {
+  /// Use Context::createFCmpInst(). Don't call the constructor directly.
+  FCmpInst(llvm::FCmpInst *CI, Context &Ctx)
+      : CmpInst(CI, Ctx, ClassID::FCmp, Opcode::FCmp) {}
+  friend class Context; // For constructor.
+  using LLVMValType = llvm::FCmpInst;
+
+public:
+  void swapOperands();
+
+  WRAP_BOTH(isEquality);
+  WRAP_MEMBER(isCommutative);
+  WRAP_MEMBER(isRelational);
+
+  static auto predicates() { return llvm::FCmpInst::predicates(); }
+  static bool compare(const APFloat &LHS, const APFloat &RHS,
+                      FCmpInst::Predicate Pred) {
+    return llvm::FCmpInst::compare(LHS, RHS, Pred);
+  }
+
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::FCmp;
+  }
+};
+
+#undef WRAP_STATIC_PREDICATE
+#undef WRAP_MEMBER
+#undef WRAP_BOTH
+
+/// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to
+/// an OpaqueInstr.
+class OpaqueInst : public SingleLLVMInstructionImpl<llvm::Instruction> {
+  OpaqueInst(llvm::Instruction *I, sandboxir::Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::Opaque, Opcode::Opaque, I, Ctx) {}
+  OpaqueInst(ClassID SubclassID, llvm::Instruction *I, sandboxir::Context &Ctx)
+      : SingleLLVMInstructionImpl(SubclassID, Opcode::Opaque, I, Ctx) {}
+  friend class Context; // For constructor.
+
+public:
+  static bool classof(const sandboxir::Value *From) {
+    return From->getSubclassID() == ClassID::Opaque;
+  }
+};
+
+} // namespace llvm::sandboxir
+
+#endif // LLVM_SANDBOXIR_INSTRUCTION_H
diff --git a/llvm/include/llvm/SandboxIR/Region.h b/llvm/include/llvm/SandboxIR/Region.h
index 884f1324df7829..67411f3fb741da 100644
--- a/llvm/include/llvm/SandboxIR/Region.h
+++ b/llvm/include/llvm/SandboxIR/Region.h
@@ -13,7 +13,7 @@
 
 #include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/iterator_range.h"
-#include "llvm/SandboxIR/SandboxIR.h"
+#include "llvm/SandboxIR/Instruction.h"
 #include "llvm/Support/raw_ostream.h"
 
 namespace llvm::sandboxir {
diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index 2376450d190115..85fa7ad8e40640 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -192,2724 +192,6 @@ class CmpInst;
 class ICmpInst;
 class FCmpInst;
 
-/// A sandboxir::User with operands, opcode and linked with previous/next
-/// instructions in an instruction list.
-class Instruction : public sandboxir::User {
-public:
-  enum class Opcode {
-#define OP(OPC) OPC,
-#define OPCODES(...) __VA_ARGS__
-#define DEF_INSTR(ID, OPC, CLASS) OPC
-#include "llvm/SandboxIR/SandboxIRValues.def"
-  };
-
-protected:
-  Instruction(ClassID ID, Opcode Opc, llvm::Instruction *I,
-              sandboxir::Context &SBCtx)
-      : sandboxir::User(ID, I, SBCtx), Opc(Opc) {}
-
-  Opcode Opc;
-
-  /// A SandboxIR Instruction may map to multiple LLVM IR Instruction. This
-  /// returns its topmost LLVM IR instruction.
-  llvm::Instruction *getTopmostLLVMInstruction() const;
-  friend class VAArgInst;          // For getTopmostLLVMInstruction().
-  friend class FreezeInst;         // For getTopmostLLVMInstruction().
-  friend class FenceInst;          // For getTopmostLLVMInstruction().
-  friend class SelectInst;         // For getTopmostLLVMInstruction().
-  friend class ExtractElementInst; // For getTopmostLLVMInstruction().
-  friend class InsertElementInst;  // For getTopmostLLVMInstruction().
-  friend class ShuffleVectorInst;  // For getTopmostLLVMInstruction().
-  friend class ExtractValueInst;   // For getTopmostLLVMInstruction().
-  friend class InsertValueInst;    // For getTopmostLLVMInstruction().
-  friend class BranchInst;         // For getTopmostLLVMInstruction().
-  friend class LoadInst;           // For getTopmostLLVMInstruction().
-  friend class StoreInst;          // For getTopmostLLVMInstruction().
-  friend class ReturnInst;         // For getTopmostLLVMInstruction().
-  friend class CallInst;           // For getTopmostLLVMInstruction().
-  friend class InvokeInst;         // For getTopmostLLVMInstruction().
-  friend class CallBrInst;         // For getTopmostLLVMInstruction().
-  friend class LandingPadInst;     // For getTopmostLLVMInstruction().
-  friend class CatchPadInst;       // For getTopmostLLVMInstruction().
-  friend class CleanupPadInst;     // For getTopmostLLVMInstruction().
-  friend class CatchReturnInst;    // For getTopmostLLVMInstruction().
-  friend class CleanupReturnInst;  // For getTopmostLLVMInstruction().
-  friend class GetElementPtrInst;  // For getTopmostLLVMInstruction().
-  friend class ResumeInst;         // For getTopmostLLVMInstruction().
-  friend class CatchSwitchInst;    // For getTopmostLLVMInstruction().
-  friend class SwitchInst;         // For getTopmostLLVMInstruction().
-  friend class UnaryOperator;      // For getTopmostLLVMInstruction().
-  friend class BinaryOperator;     // For getTopmostLLVMInstruction().
-  friend class AtomicRMWInst;      // For getTopmostLLVMInstruction().
-  friend class AtomicCmpXchgInst;  // For getTopmostLLVMInstruction().
-  friend class AllocaInst;         // For getTopmostLLVMInstruction().
-  friend class CastInst;           // For getTopmostLLVMInstruction().
-  friend class PHINode;            // For getTopmostLLVMInstruction().
-  friend class UnreachableInst;    // For getTopmostLLVMInstruction().
-  friend class CmpInst;            // For getTopmostLLVMInstruction().
-
-  /// \Returns the LLVM IR Instructions that this SandboxIR maps to in program
-  /// order.
-  virtual SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const = 0;
-  friend class EraseFromParent; // For getLLVMInstrs().
-
-public:
-  static const char *getOpcodeName(Opcode Opc);
-  /// This is used by BasicBlock::iterator.
-  virtual unsigned getNumOfIRInstrs() const = 0;
-  /// \Returns a BasicBlock::iterator for this Instruction.
-  BBIterator getIterator() const;
-  /// \Returns the next sandboxir::Instruction in the block, or nullptr if at
-  /// the end of the block.
-  Instruction *getNextNode() const;
-  /// \Returns the previous sandboxir::Instruction in the block, or nullptr if
-  /// at the beginning of the block.
-  Instruction *getPrevNode() const;
-  /// \Returns this Instruction's opcode. Note that SandboxIR has its own opcode
-  /// state to allow for new SandboxIR-specific instructions.
-  Opcode getOpcode() const { return Opc; }
-
-  const char *getOpcodeName() const { return getOpcodeName(Opc); }
-
-  // Note that these functions below are calling into llvm::Instruction.
-  // A sandbox IR instruction could introduce a new opcode that could change the
-  // behavior of one of these functions. It is better that these functions are
-  // only added as needed and new sandbox IR instructions must explicitly check
-  // if any of these functions could have a different behavior.
-
-  bool isTerminator() const {
-    return cast<llvm::Instruction>(Val)->isTerminator();
-  }
-  bool isUnaryOp() const { return cast<llvm::Instruction>(Val)->isUnaryOp(); }
-  bool isBinaryOp() const { return cast<llvm::Instruction>(Val)->isBinaryOp(); }
-  bool isIntDivRem() const {
-    return cast<llvm::Instruction>(Val)->isIntDivRem();
-  }
-  bool isShift() const { return cast<llvm::Instruction>(Val)->isShift(); }
-  bool isCast() const { return cast<llvm::Instruction>(Val)->isCast(); }
-  bool isFuncletPad() const {
-    return cast<llvm::Instruction>(Val)->isFuncletPad();
-  }
-  bool isSpecialTerminator() const {
-    return cast<llvm::Instruction>(Val)->isSpecialTerminator();
-  }
-  bool isOnlyUserOfAnyOperand() const {
-    return cast<llvm::Instruction>(Val)->isOnlyUserOfAnyOperand();
-  }
-  bool isLogicalShift() const {
-    return cast<llvm::Instruction>(Val)->isLogicalShift();
-  }
-
-  //===--------------------------------------------------------------------===//
-  // Metadata manipulation.
-  //===--------------------------------------------------------------------===//
-
-  /// Return true if the instruction has any metadata attached to it.
-  bool hasMetadata() const {
-    return cast<llvm::Instruction>(Val)->hasMetadata();
-  }
-
-  /// Return true if this instruction has metadata attached to it other than a
-  /// debug location.
-  bool hasMetadataOtherThanDebugLoc() const {
-    return cast<llvm::Instruction>(Val)->hasMetadataOtherThanDebugLoc();
-  }
-
-  /// Return true if this instruction has the given type of metadata attached.
-  bool hasMetadata(unsigned KindID) const {
-    return cast<llvm::Instruction>(Val)->hasMetadata(KindID);
-  }
-
-  // TODO: Implement getMetadata and getAllMetadata after sandboxir::MDNode is
-  // available.
-
-  // TODO: More missing functions
-
-  /// Detach this from its parent BasicBlock without deleting it.
-  void removeFromParent();
-  /// Detach this Value from its parent and delete it.
-  void eraseFromParent();
-  /// Insert this detached instruction before \p BeforeI.
-  void insertBefore(Instruction *BeforeI);
-  /// Insert this detached instruction after \p AfterI.
-  void insertAfter(Instruction *AfterI);
-  /// Insert this detached instruction into \p BB at \p WhereIt.
-  void insertInto(BasicBlock *BB, const BBIterator &WhereIt);
-  /// Move this instruction to \p WhereIt.
-  void moveBefore(BasicBlock &BB, const BBIterator &WhereIt);
-  /// Move this instruction before \p Before.
-  void moveBefore(Instruction *Before) {
-    moveBefore(*Before->getParent(), Before->getIterator());
-  }
-  /// Move this instruction after \p After.
-  void moveAfter(Instruction *After) {
-    moveBefore(*After->getParent(), std::next(After->getIterator()));
-  }
-  // TODO: This currently relies on LLVM IR Instruction::comesBefore which is
-  // can be linear-time.
-  /// Given an instruction Other in the same basic block as this instruction,
-  /// return true if this instruction comes before Other.
-  bool comesBefore(const Instruction *Other) const {
-    return cast<llvm::Instruction>(Val)->comesBefore(
-        cast<llvm::Instruction>(Other->Val));
-  }
-  /// \Returns the BasicBlock containing this Instruction, or null if it is
-  /// detached.
-  BasicBlock *getParent() const;
-  /// For isa/dyn_cast.
-  static bool classof(const sandboxir::Value *From);
-
-  /// Determine whether the no signed wrap flag is set.
-  bool hasNoUnsignedWrap() const {
-    return cast<llvm::Instruction>(Val)->hasNoUnsignedWrap();
-  }
-  /// Set or clear the nuw flag on this instruction, which must be an operator
-  /// which supports this flag. See LangRef.html for the meaning of this flag.
-  void setHasNoUnsignedWrap(bool B = true);
-  /// Determine whether the no signed wrap flag is set.
-  bool hasNoSignedWrap() const {
-    return cast<llvm::Instruction>(Val)->hasNoSignedWrap();
-  }
-  /// Set or clear the nsw flag on this instruction, which must be an operator
-  /// which supports this flag. See LangRef.html for the meaning of this flag.
-  void setHasNoSignedWrap(bool B = true);
-  /// Determine whether all fast-math-flags are set.
-  bool isFast() const { return cast<llvm::Instruction>(Val)->isFast(); }
-  /// Set or clear all fast-math-flags on this instruction, which must be an
-  /// operator which supports this flag. See LangRef.html for the meaning of
-  /// this flag.
-  void setFast(bool B);
-  /// Determine whether the allow-reassociation flag is set.
-  bool hasAllowReassoc() const {
-    return cast<llvm::Instruction>(Val)->hasAllowReassoc();
-  }
-  /// Set or clear the reassociation flag on this instruction, which must be
-  /// an operator which supports this flag. See LangRef.html for the meaning of
-  /// this flag.
-  void setHasAllowReassoc(bool B);
-  /// Determine whether the exact flag is set.
-  bool isExact() const { return cast<llvm::Instruction>(Val)->isExact(); }
-  /// Set or clear the exact flag on this instruction, which must be an operator
-  /// which supports this flag. See LangRef.html for the meaning of this flag.
-  void setIsExact(bool B = true);
-  /// Determine whether the no-NaNs flag is set.
-  bool hasNoNaNs() const { return cast<llvm::Instruction>(Val)->hasNoNaNs(); }
-  /// Set or clear the no-nans flag on this instruction, which must be an
-  /// operator which supports this flag. See LangRef.html for the meaning of
-  /// this flag.
-  void setHasNoNaNs(bool B);
-  /// Determine whether the no-infs flag is set.
-  bool hasNoInfs() const { return cast<llvm::Instruction>(Val)->hasNoInfs(); }
-  /// Set or clear the no-infs flag on this instruction, which must be an
-  /// operator which supports this flag. See LangRef.html for the meaning of
-  /// this flag.
-  void setHasNoInfs(bool B);
-  /// Determine whether the no-signed-zeros flag is set.
-  bool hasNoSignedZeros() const {
-    return cast<llvm::Instruction>(Val)->hasNoSignedZeros();
-  }
-  /// Set or clear the no-signed-zeros flag on this instruction, which must be
-  /// an operator which supports this flag. See LangRef.html for the meaning of
-  /// this flag.
-  void setHasNoSignedZeros(bool B);
-  /// Determine whether the allow-reciprocal flag is set.
-  bool hasAllowReciprocal() const {
-    return cast<llvm::Instruction>(Val)->hasAllowReciprocal();
-  }
-  /// Set or clear the allow-reciprocal flag on this instruction, which must be
-  /// an operator which supports this flag. See LangRef.html for the meaning of
-  /// this flag.
-  void setHasAllowReciprocal(bool B);
-  /// Determine whether the allow-contract flag is set.
-  bool hasAllowContract() const {
-    return cast<llvm::Instruction>(Val)->hasAllowContract();
-  }
-  /// Set or clear the allow-contract flag on this instruction, which must be
-  /// an operator which supports this flag. See LangRef.html for the meaning of
-  /// this flag.
-  void setHasAllowContract(bool B);
-  /// Determine whether the approximate-math-functions flag is set.
-  bool hasApproxFunc() const {
-    return cast<llvm::Instruction>(Val)->hasApproxFunc();
-  }
-  /// Set or clear the approximate-math-functions flag on this instruction,
-  /// which must be an operator which supports this flag. See LangRef.html for
-  /// the meaning of this flag.
-  void setHasApproxFunc(bool B);
-  /// Convenience function for getting all the fast-math flags, which must be an
-  /// operator which supports these flags. See LangRef.html for the meaning of
-  /// these flags.
-  FastMathFlags getFastMathFlags() const {
-    return cast<llvm::Instruction>(Val)->getFastMathFlags();
-  }
-  /// Convenience function for setting multiple fast-math flags on this
-  /// instruction, which must be an operator which supports these flags. See
-  /// LangRef.html for the meaning of these flags.
-  void setFastMathFlags(FastMathFlags FMF);
-  /// Convenience function for transferring all fast-math flag values to this
-  /// instruction, which must be an operator which supports these flags. See
-  /// LangRef.html for the meaning of these flags.
-  void copyFastMathFlags(FastMathFlags FMF);
-
-  bool isAssociative() const {
-    return cast<llvm::Instruction>(Val)->isAssociative();
-  }
-
-  bool isCommutative() const {
-    return cast<llvm::Instruction>(Val)->isCommutative();
-  }
-
-  bool isIdempotent() const {
-    return cast<llvm::Instruction>(Val)->isIdempotent();
-  }
-
-  bool isNilpotent() const {
-    return cast<llvm::Instruction>(Val)->isNilpotent();
-  }
-
-  bool mayWriteToMemory() const {
-    return cast<llvm::Instruction>(Val)->mayWriteToMemory();
-  }
-
-  bool mayReadFromMemory() const {
-    return cast<llvm::Instruction>(Val)->mayReadFromMemory();
-  }
-  bool mayReadOrWriteMemory() const {
-    return cast<llvm::Instruction>(Val)->mayReadOrWriteMemory();
-  }
-
-  bool isAtomic() const { return cast<llvm::Instruction>(Val)->isAtomic(); }
-
-  bool hasAtomicLoad() const {
-    return cast<llvm::Instruction>(Val)->hasAtomicLoad();
-  }
-
-  bool hasAtomicStore() const {
-    return cast<llvm::Instruction>(Val)->hasAtomicStore();
-  }
-
-  bool isVolatile() const { return cast<llvm::Instruction>(Val)->isVolatile(); }
-
-  Type *getAccessType() const;
-
-  bool mayThrow(bool IncludePhaseOneUnwind = false) const {
-    return cast<llvm::Instruction>(Val)->mayThrow(IncludePhaseOneUnwind);
-  }
-
-  bool isFenceLike() const {
-    return cast<llvm::Instruction>(Val)->isFenceLike();
-  }
-
-  bool mayHaveSideEffects() const {
-    return cast<llvm::Instruction>(Val)->mayHaveSideEffects();
-  }
-
-  // TODO: Missing functions.
-
-  bool isStackSaveOrRestoreIntrinsic() const {
-    auto *I = cast<llvm::Instruction>(Val);
-    return match(I,
-                 PatternMatch::m_Intrinsic<llvm::Intrinsic::stackrestore>()) ||
-           match(I, PatternMatch::m_Intrinsic<llvm::Intrinsic::stacksave>());
-  }
-
-  /// We consider \p I as a Memory Dependency Candidate instruction if it
-  /// reads/write memory or if it has side-effects. This is used by the
-  /// dependency graph.
-  bool isMemDepCandidate() const {
-    auto *I = cast<llvm::Instruction>(Val);
-    return I->mayReadOrWriteMemory() &&
-           (!isa<llvm::IntrinsicInst>(I) ||
-            (cast<llvm::IntrinsicInst>(I)->getIntrinsicID() !=
-                 Intrinsic::sideeffect &&
-             cast<llvm::IntrinsicInst>(I)->getIntrinsicID() !=
-                 Intrinsic::pseudoprobe));
-  }
-
-#ifndef NDEBUG
-  void dumpOS(raw_ostream &OS) const override;
-#endif
-};
-
-/// Instructions that contain a single LLVM Instruction can inherit from this.
-template <typename LLVMT> class SingleLLVMInstructionImpl : public Instruction {
-  SingleLLVMInstructionImpl(ClassID ID, Opcode Opc, llvm::Instruction *I,
-                            sandboxir::Context &SBCtx)
-      : Instruction(ID, Opc, I, SBCtx) {}
-
-  // All instructions are friends with this so they can call the constructor.
-#define DEF_INSTR(ID, OPC, CLASS) friend class CLASS;
-#include "llvm/SandboxIR/SandboxIRValues.def"
-  friend class UnaryInstruction;
-  friend class CallBase;
-  friend class FuncletPadInst;
-  friend class CmpInst;
-
-  Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
-    return getOperandUseDefault(OpIdx, Verify);
-  }
-  SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
-    return {cast<llvm::Instruction>(Val)};
-  }
-
-public:
-  unsigned getUseOperandNo(const Use &Use) const final {
-    return getUseOperandNoDefault(Use);
-  }
-  unsigned getNumOfIRInstrs() const final { return 1u; }
-#ifndef NDEBUG
-  void verify() const final { assert(isa<LLVMT>(Val) && "Expected LLVMT!"); }
-  void dumpOS(raw_ostream &OS) const override {
-    dumpCommonPrefix(OS);
-    dumpCommonSuffix(OS);
-  }
-#endif
-};
-
-class FenceInst : public SingleLLVMInstructionImpl<llvm::FenceInst> {
-  FenceInst(llvm::FenceInst *FI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::Fence, Opcode::Fence, FI, Ctx) {}
-  friend Context; // For constructor;
-
-public:
-  static FenceInst *create(AtomicOrdering Ordering, BBIterator WhereIt,
-                           BasicBlock *WhereBB, Context &Ctx,
-                           SyncScope::ID SSID = SyncScope::System);
-  /// Returns the ordering constraint of this fence instruction.
-  AtomicOrdering getOrdering() const {
-    return cast<llvm::FenceInst>(Val)->getOrdering();
-  }
-  /// Sets the ordering constraint of this fence instruction.  May only be
-  /// Acquire, Release, AcquireRelease, or SequentiallyConsistent.
-  void setOrdering(AtomicOrdering Ordering);
-  /// Returns the synchronization scope ID of this fence instruction.
-  SyncScope::ID getSyncScopeID() const {
-    return cast<llvm::FenceInst>(Val)->getSyncScopeID();
-  }
-  /// Sets the synchronization scope ID of this fence instruction.
-  void setSyncScopeID(SyncScope::ID SSID);
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::Fence;
-  }
-};
-
-class SelectInst : public SingleLLVMInstructionImpl<llvm::SelectInst> {
-  /// Use Context::createSelectInst(). Don't call the
-  /// constructor directly.
-  SelectInst(llvm::SelectInst *CI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::Select, Opcode::Select, CI, Ctx) {}
-  friend Context; // for SelectInst()
-  static Value *createCommon(Value *Cond, Value *True, Value *False,
-                             const Twine &Name, IRBuilder<> &Builder,
-                             Context &Ctx);
-
-public:
-  static Value *create(Value *Cond, Value *True, Value *False,
-                       Instruction *InsertBefore, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Value *Cond, Value *True, Value *False,
-                       BasicBlock *InsertAtEnd, Context &Ctx,
-                       const Twine &Name = "");
-
-  const Value *getCondition() const { return getOperand(0); }
-  const Value *getTrueValue() const { return getOperand(1); }
-  const Value *getFalseValue() const { return getOperand(2); }
-  Value *getCondition() { return getOperand(0); }
-  Value *getTrueValue() { return getOperand(1); }
-  Value *getFalseValue() { return getOperand(2); }
-
-  void setCondition(Value *New) { setOperand(0, New); }
-  void setTrueValue(Value *New) { setOperand(1, New); }
-  void setFalseValue(Value *New) { setOperand(2, New); }
-  void swapValues();
-
-  /// Return a string if the specified operands are invalid for a select
-  /// operation, otherwise return null.
-  static const char *areInvalidOperands(Value *Cond, Value *True,
-                                        Value *False) {
-    return llvm::SelectInst::areInvalidOperands(Cond->Val, True->Val,
-                                                False->Val);
-  }
-
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From);
-};
-
-class InsertElementInst final
-    : public SingleLLVMInstructionImpl<llvm::InsertElementInst> {
-  /// Use Context::createInsertElementInst() instead.
-  InsertElementInst(llvm::Instruction *I, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::InsertElement, Opcode::InsertElement,
-                                  I, Ctx) {}
-  friend class Context; // For accessing the constructor in create*()
-
-public:
-  static Value *create(Value *Vec, Value *NewElt, Value *Idx,
-                       Instruction *InsertBefore, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Value *Vec, Value *NewElt, Value *Idx,
-                       BasicBlock *InsertAtEnd, Context &Ctx,
-                       const Twine &Name = "");
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::InsertElement;
-  }
-  static bool isValidOperands(const Value *Vec, const Value *NewElt,
-                              const Value *Idx) {
-    return llvm::InsertElementInst::isValidOperands(Vec->Val, NewElt->Val,
-                                                    Idx->Val);
-  }
-};
-
-class ExtractElementInst final
-    : public SingleLLVMInstructionImpl<llvm::ExtractElementInst> {
-  /// Use Context::createExtractElementInst() instead.
-  ExtractElementInst(llvm::Instruction *I, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::ExtractElement,
-                                  Opcode::ExtractElement, I, Ctx) {}
-  friend class Context; // For accessing the constructor in
-                        // create*()
-
-public:
-  static Value *create(Value *Vec, Value *Idx, Instruction *InsertBefore,
-                       Context &Ctx, const Twine &Name = "");
-  static Value *create(Value *Vec, Value *Idx, BasicBlock *InsertAtEnd,
-                       Context &Ctx, const Twine &Name = "");
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::ExtractElement;
-  }
-
-  static bool isValidOperands(const Value *Vec, const Value *Idx) {
-    return llvm::ExtractElementInst::isValidOperands(Vec->Val, Idx->Val);
-  }
-  Value *getVectorOperand() { return getOperand(0); }
-  Value *getIndexOperand() { return getOperand(1); }
-  const Value *getVectorOperand() const { return getOperand(0); }
-  const Value *getIndexOperand() const { return getOperand(1); }
-  VectorType *getVectorOperandType() const;
-};
-
-class ShuffleVectorInst final
-    : public SingleLLVMInstructionImpl<llvm::ShuffleVectorInst> {
-  /// Use Context::createShuffleVectorInst() instead.
-  ShuffleVectorInst(llvm::Instruction *I, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::ShuffleVector, Opcode::ShuffleVector,
-                                  I, Ctx) {}
-  friend class Context; // For accessing the constructor in create*()
-
-public:
-  static Value *create(Value *V1, Value *V2, Value *Mask,
-                       Instruction *InsertBefore, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Value *V1, Value *V2, Value *Mask,
-                       BasicBlock *InsertAtEnd, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Value *V1, Value *V2, ArrayRef<int> Mask,
-                       Instruction *InsertBefore, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Value *V1, Value *V2, ArrayRef<int> Mask,
-                       BasicBlock *InsertAtEnd, Context &Ctx,
-                       const Twine &Name = "");
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::ShuffleVector;
-  }
-
-  /// Swap the operands and adjust the mask to preserve the semantics of the
-  /// instruction.
-  void commute();
-
-  /// Return true if a shufflevector instruction can be formed with the
-  /// specified operands.
-  static bool isValidOperands(const Value *V1, const Value *V2,
-                              const Value *Mask) {
-    return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val,
-                                                    Mask->Val);
-  }
-  static bool isValidOperands(const Value *V1, const Value *V2,
-                              ArrayRef<int> Mask) {
-    return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val, Mask);
-  }
-
-  /// Overload to return most specific vector type.
-  VectorType *getType() const;
-
-  /// Return the shuffle mask value of this instruction for the given element
-  /// index. Return PoisonMaskElem if the element is undef.
-  int getMaskValue(unsigned Elt) const {
-    return cast<llvm::ShuffleVectorInst>(Val)->getMaskValue(Elt);
-  }
-
-  /// Convert the input shuffle mask operand to a vector of integers. Undefined
-  /// elements of the mask are returned as PoisonMaskElem.
-  static void getShuffleMask(const Constant *Mask,
-                             SmallVectorImpl<int> &Result) {
-    llvm::ShuffleVectorInst::getShuffleMask(cast<llvm::Constant>(Mask->Val),
-                                            Result);
-  }
-
-  /// Return the mask for this instruction as a vector of integers. Undefined
-  /// elements of the mask are returned as PoisonMaskElem.
-  void getShuffleMask(SmallVectorImpl<int> &Result) const {
-    cast<llvm::ShuffleVectorInst>(Val)->getShuffleMask(Result);
-  }
-
-  /// Return the mask for this instruction, for use in bitcode.
-  Constant *getShuffleMaskForBitcode() const;
-
-  static Constant *convertShuffleMaskForBitcode(ArrayRef<int> Mask,
-                                                Type *ResultTy);
-
-  void setShuffleMask(ArrayRef<int> Mask);
-
-  ArrayRef<int> getShuffleMask() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->getShuffleMask();
-  }
-
-  /// Return true if this shuffle returns a vector with a different number of
-  /// elements than its source vectors.
-  /// Examples: shufflevector <4 x n> A, <4 x n> B, <1,2,3>
-  ///           shufflevector <4 x n> A, <4 x n> B, <1,2,3,4,5>
-  bool changesLength() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->changesLength();
-  }
-
-  /// Return true if this shuffle returns a vector with a greater number of
-  /// elements than its source vectors.
-  /// Example: shufflevector <2 x n> A, <2 x n> B, <1,2,3>
-  bool increasesLength() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->increasesLength();
-  }
-
-  /// Return true if this shuffle mask chooses elements from exactly one source
-  /// vector.
-  /// Example: <7,5,undef,7>
-  /// This assumes that vector operands (of length \p NumSrcElts) are the same
-  /// length as the mask.
-  static bool isSingleSourceMask(ArrayRef<int> Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isSingleSourceMask(Mask, NumSrcElts);
-  }
-  static bool isSingleSourceMask(const Constant *Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isSingleSourceMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts);
-  }
-
-  /// Return true if this shuffle chooses elements from exactly one source
-  /// vector without changing the length of that vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3>
-  bool isSingleSource() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isSingleSource();
-  }
-
-  /// Return true if this shuffle mask chooses elements from exactly one source
-  /// vector without lane crossings. A shuffle using this mask is not
-  /// necessarily a no-op because it may change the number of elements from its
-  /// input vectors or it may provide demanded bits knowledge via undef lanes.
-  /// Example: <undef,undef,2,3>
-  static bool isIdentityMask(ArrayRef<int> Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isIdentityMask(Mask, NumSrcElts);
-  }
-  static bool isIdentityMask(const Constant *Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isIdentityMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts);
-  }
-
-  /// Return true if this shuffle chooses elements from exactly one source
-  /// vector without lane crossings and does not change the number of elements
-  /// from its input vectors.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef>
-  bool isIdentity() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isIdentity();
-  }
-
-  /// Return true if this shuffle lengthens exactly one source vector with
-  /// undefs in the high elements.
-  bool isIdentityWithPadding() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isIdentityWithPadding();
-  }
-
-  /// Return true if this shuffle extracts the first N elements of exactly one
-  /// source vector.
-  bool isIdentityWithExtract() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isIdentityWithExtract();
-  }
-
-  /// Return true if this shuffle concatenates its 2 source vectors. This
-  /// returns false if either input is undefined. In that case, the shuffle is
-  /// is better classified as an identity with padding operation.
-  bool isConcat() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isConcat();
-  }
-
-  /// Return true if this shuffle mask chooses elements from its source vectors
-  /// without lane crossings. A shuffle using this mask would be
-  /// equivalent to a vector select with a constant condition operand.
-  /// Example: <4,1,6,undef>
-  /// This returns false if the mask does not choose from both input vectors.
-  /// In that case, the shuffle is better classified as an identity shuffle.
-  /// This assumes that vector operands are the same length as the mask
-  /// (a length-changing shuffle can never be equivalent to a vector select).
-  static bool isSelectMask(ArrayRef<int> Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isSelectMask(Mask, NumSrcElts);
-  }
-  static bool isSelectMask(const Constant *Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isSelectMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts);
-  }
-
-  /// Return true if this shuffle chooses elements from its source vectors
-  /// without lane crossings and all operands have the same number of elements.
-  /// In other words, this shuffle is equivalent to a vector select with a
-  /// constant condition operand.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,1,6,3>
-  /// This returns false if the mask does not choose from both input vectors.
-  /// In that case, the shuffle is better classified as an identity shuffle.
-  bool isSelect() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isSelect();
-  }
-
-  /// Return true if this shuffle mask swaps the order of elements from exactly
-  /// one source vector.
-  /// Example: <7,6,undef,4>
-  /// This assumes that vector operands (of length \p NumSrcElts) are the same
-  /// length as the mask.
-  static bool isReverseMask(ArrayRef<int> Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isReverseMask(Mask, NumSrcElts);
-  }
-  static bool isReverseMask(const Constant *Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isReverseMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts);
-  }
-
-  /// Return true if this shuffle swaps the order of elements from exactly
-  /// one source vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef>
-  bool isReverse() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isReverse();
-  }
-
-  /// Return true if this shuffle mask chooses all elements with the same value
-  /// as the first element of exactly one source vector.
-  /// Example: <4,undef,undef,4>
-  /// This assumes that vector operands (of length \p NumSrcElts) are the same
-  /// length as the mask.
-  static bool isZeroEltSplatMask(ArrayRef<int> Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isZeroEltSplatMask(Mask, NumSrcElts);
-  }
-  static bool isZeroEltSplatMask(const Constant *Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isZeroEltSplatMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts);
-  }
-
-  /// Return true if all elements of this shuffle are the same value as the
-  /// first element of exactly one source vector without changing the length
-  /// of that vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,0,undef,0>
-  bool isZeroEltSplat() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isZeroEltSplat();
-  }
-
-  /// Return true if this shuffle mask is a transpose mask.
-  /// Transpose vector masks transpose a 2xn matrix. They read corresponding
-  /// even- or odd-numbered vector elements from two n-dimensional source
-  /// vectors and write each result into consecutive elements of an
-  /// n-dimensional destination vector. Two shuffles are necessary to complete
-  /// the transpose, one for the even elements and another for the odd elements.
-  /// This description closely follows how the TRN1 and TRN2 AArch64
-  /// instructions operate.
-  ///
-  /// For example, a simple 2x2 matrix can be transposed with:
-  ///
-  ///   ; Original matrix
-  ///   m0 = < a, b >
-  ///   m1 = < c, d >
-  ///
-  ///   ; Transposed matrix
-  ///   t0 = < a, c > = shufflevector m0, m1, < 0, 2 >
-  ///   t1 = < b, d > = shufflevector m0, m1, < 1, 3 >
-  ///
-  /// For matrices having greater than n columns, the resulting nx2 transposed
-  /// matrix is stored in two result vectors such that one vector contains
-  /// interleaved elements from all the even-numbered rows and the other vector
-  /// contains interleaved elements from all the odd-numbered rows. For example,
-  /// a 2x4 matrix can be transposed with:
-  ///
-  ///   ; Original matrix
-  ///   m0 = < a, b, c, d >
-  ///   m1 = < e, f, g, h >
-  ///
-  ///   ; Transposed matrix
-  ///   t0 = < a, e, c, g > = shufflevector m0, m1 < 0, 4, 2, 6 >
-  ///   t1 = < b, f, d, h > = shufflevector m0, m1 < 1, 5, 3, 7 >
-  static bool isTransposeMask(ArrayRef<int> Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isTransposeMask(Mask, NumSrcElts);
-  }
-  static bool isTransposeMask(const Constant *Mask, int NumSrcElts) {
-    return llvm::ShuffleVectorInst::isTransposeMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts);
-  }
-
-  /// Return true if this shuffle transposes the elements of its inputs without
-  /// changing the length of the vectors. This operation may also be known as a
-  /// merge or interleave. See the description for isTransposeMask() for the
-  /// exact specification.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6>
-  bool isTranspose() const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isTranspose();
-  }
-
-  /// Return true if this shuffle mask is a splice mask, concatenating the two
-  /// inputs together and then extracts an original width vector starting from
-  /// the splice index.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
-  /// This assumes that vector operands (of length \p NumSrcElts) are the same
-  /// length as the mask.
-  static bool isSpliceMask(ArrayRef<int> Mask, int NumSrcElts, int &Index) {
-    return llvm::ShuffleVectorInst::isSpliceMask(Mask, NumSrcElts, Index);
-  }
-  static bool isSpliceMask(const Constant *Mask, int NumSrcElts, int &Index) {
-    return llvm::ShuffleVectorInst::isSpliceMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts, Index);
-  }
-
-  /// Return true if this shuffle splices two inputs without changing the length
-  /// of the vectors. This operation concatenates the two inputs together and
-  /// then extracts an original width vector starting from the splice index.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
-  bool isSplice(int &Index) const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isSplice(Index);
-  }
-
-  /// Return true if this shuffle mask is an extract subvector mask.
-  /// A valid extract subvector mask returns a smaller vector from a single
-  /// source operand. The base extraction index is returned as well.
-  static bool isExtractSubvectorMask(ArrayRef<int> Mask, int NumSrcElts,
-                                     int &Index) {
-    return llvm::ShuffleVectorInst::isExtractSubvectorMask(Mask, NumSrcElts,
-                                                           Index);
-  }
-  static bool isExtractSubvectorMask(const Constant *Mask, int NumSrcElts,
-                                     int &Index) {
-    return llvm::ShuffleVectorInst::isExtractSubvectorMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts, Index);
-  }
-
-  /// Return true if this shuffle mask is an extract subvector mask.
-  bool isExtractSubvectorMask(int &Index) const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isExtractSubvectorMask(Index);
-  }
-
-  /// Return true if this shuffle mask is an insert subvector mask.
-  /// A valid insert subvector mask inserts the lowest elements of a second
-  /// source operand into an in-place first source operand.
-  /// Both the sub vector width and the insertion index is returned.
-  static bool isInsertSubvectorMask(ArrayRef<int> Mask, int NumSrcElts,
-                                    int &NumSubElts, int &Index) {
-    return llvm::ShuffleVectorInst::isInsertSubvectorMask(Mask, NumSrcElts,
-                                                          NumSubElts, Index);
-  }
-  static bool isInsertSubvectorMask(const Constant *Mask, int NumSrcElts,
-                                    int &NumSubElts, int &Index) {
-    return llvm::ShuffleVectorInst::isInsertSubvectorMask(
-        cast<llvm::Constant>(Mask->Val), NumSrcElts, NumSubElts, Index);
-  }
-
-  /// Return true if this shuffle mask is an insert subvector mask.
-  bool isInsertSubvectorMask(int &NumSubElts, int &Index) const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isInsertSubvectorMask(NumSubElts,
-                                                                     Index);
-  }
-
-  /// Return true if this shuffle mask replicates each of the \p VF elements
-  /// in a vector \p ReplicationFactor times.
-  /// For example, the mask for \p ReplicationFactor=3 and \p VF=4 is:
-  ///   <0,0,0,1,1,1,2,2,2,3,3,3>
-  static bool isReplicationMask(ArrayRef<int> Mask, int &ReplicationFactor,
-                                int &VF) {
-    return llvm::ShuffleVectorInst::isReplicationMask(Mask, ReplicationFactor,
-                                                      VF);
-  }
-  static bool isReplicationMask(const Constant *Mask, int &ReplicationFactor,
-                                int &VF) {
-    return llvm::ShuffleVectorInst::isReplicationMask(
-        cast<llvm::Constant>(Mask->Val), ReplicationFactor, VF);
-  }
-
-  /// Return true if this shuffle mask is a replication mask.
-  bool isReplicationMask(int &ReplicationFactor, int &VF) const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isReplicationMask(
-        ReplicationFactor, VF);
-  }
-
-  /// Return true if this shuffle mask represents "clustered" mask of size VF,
-  /// i.e. each index between [0..VF) is used exactly once in each submask of
-  /// size VF.
-  /// For example, the mask for \p VF=4 is:
-  /// 0, 1, 2, 3, 3, 2, 0, 1 - "clustered", because each submask of size 4
-  /// (0,1,2,3 and 3,2,0,1) uses indices [0..VF) exactly one time.
-  /// 0, 1, 2, 3, 3, 3, 1, 0 - not "clustered", because
-  ///                          element 3 is used twice in the second submask
-  ///                          (3,3,1,0) and index 2 is not used at all.
-  static bool isOneUseSingleSourceMask(ArrayRef<int> Mask, int VF) {
-    return llvm::ShuffleVectorInst::isOneUseSingleSourceMask(Mask, VF);
-  }
-
-  /// Return true if this shuffle mask is a one-use-single-source("clustered")
-  /// mask.
-  bool isOneUseSingleSourceMask(int VF) const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isOneUseSingleSourceMask(VF);
-  }
-
-  /// Change values in a shuffle permute mask assuming the two vector operands
-  /// of length InVecNumElts have swapped position.
-  static void commuteShuffleMask(MutableArrayRef<int> Mask,
-                                 unsigned InVecNumElts) {
-    llvm::ShuffleVectorInst::commuteShuffleMask(Mask, InVecNumElts);
-  }
-
-  /// Return if this shuffle interleaves its two input vectors together.
-  bool isInterleave(unsigned Factor) const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isInterleave(Factor);
-  }
-
-  /// Return true if the mask interleaves one or more input vectors together.
-  ///
-  /// I.e. <0, LaneLen, ... , LaneLen*(Factor - 1), 1, LaneLen + 1, ...>
-  /// E.g. For a Factor of 2 (LaneLen=4):
-  ///   <0, 4, 1, 5, 2, 6, 3, 7>
-  /// E.g. For a Factor of 3 (LaneLen=4):
-  ///   <4, 0, 9, 5, 1, 10, 6, 2, 11, 7, 3, 12>
-  /// E.g. For a Factor of 4 (LaneLen=2):
-  ///   <0, 2, 6, 4, 1, 3, 7, 5>
-  ///
-  /// NumInputElts is the total number of elements in the input vectors.
-  ///
-  /// StartIndexes are the first indexes of each vector being interleaved,
-  /// substituting any indexes that were undef
-  /// E.g. <4, -1, 2, 5, 1, 3> (Factor=3): StartIndexes=<4, 0, 2>
-  ///
-  /// Note that this does not check if the input vectors are consecutive:
-  /// It will return true for masks such as
-  /// <0, 4, 6, 1, 5, 7> (Factor=3, LaneLen=2)
-  static bool isInterleaveMask(ArrayRef<int> Mask, unsigned Factor,
-                               unsigned NumInputElts,
-                               SmallVectorImpl<unsigned> &StartIndexes) {
-    return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor, NumInputElts,
-                                                     StartIndexes);
-  }
-  static bool isInterleaveMask(ArrayRef<int> Mask, unsigned Factor,
-                               unsigned NumInputElts) {
-    return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor,
-                                                     NumInputElts);
-  }
-
-  /// Check if the mask is a DE-interleave mask of the given factor
-  /// \p Factor like:
-  ///     <Index, Index+Factor, ..., Index+(NumElts-1)*Factor>
-  static bool isDeInterleaveMaskOfFactor(ArrayRef<int> Mask, unsigned Factor,
-                                         unsigned &Index) {
-    return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor,
-                                                               Index);
-  }
-  static bool isDeInterleaveMaskOfFactor(ArrayRef<int> Mask, unsigned Factor) {
-    return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor);
-  }
-
-  /// Checks if the shuffle is a bit rotation of the first operand across
-  /// multiple subelements, e.g:
-  ///
-  /// shuffle <8 x i8> %a, <8 x i8> poison, <8 x i32> <1, 0, 3, 2, 5, 4, 7, 6>
-  ///
-  /// could be expressed as
-  ///
-  /// rotl <4 x i16> %a, 8
-  ///
-  /// If it can be expressed as a rotation, returns the number of subelements to
-  /// group by in NumSubElts and the number of bits to rotate left in RotateAmt.
-  static bool isBitRotateMask(ArrayRef<int> Mask, unsigned EltSizeInBits,
-                              unsigned MinSubElts, unsigned MaxSubElts,
-                              unsigned &NumSubElts, unsigned &RotateAmt) {
-    return llvm::ShuffleVectorInst::isBitRotateMask(
-        Mask, EltSizeInBits, MinSubElts, MaxSubElts, NumSubElts, RotateAmt);
-  }
-};
-
-class InsertValueInst
-    : public SingleLLVMInstructionImpl<llvm::InsertValueInst> {
-  /// Use Context::createInsertValueInst(). Don't call the constructor directly.
-  InsertValueInst(llvm::InsertValueInst *IVI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::InsertValue, Opcode::InsertValue,
-                                  IVI, Ctx) {}
-  friend Context; // for InsertValueInst()
-
-public:
-  static Value *create(Value *Agg, Value *Val, ArrayRef<unsigned> Idxs,
-                       BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
-                       const Twine &Name = "");
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::InsertValue;
-  }
-
-  using idx_iterator = llvm::InsertValueInst::idx_iterator;
-  inline idx_iterator idx_begin() const {
-    return cast<llvm::InsertValueInst>(Val)->idx_begin();
-  }
-  inline idx_iterator idx_end() const {
-    return cast<llvm::InsertValueInst>(Val)->idx_end();
-  }
-  inline iterator_range<idx_iterator> indices() const {
-    return cast<llvm::InsertValueInst>(Val)->indices();
-  }
-
-  Value *getAggregateOperand() {
-    return getOperand(getAggregateOperandIndex());
-  }
-  const Value *getAggregateOperand() const {
-    return getOperand(getAggregateOperandIndex());
-  }
-  static unsigned getAggregateOperandIndex() {
-    return llvm::InsertValueInst::getAggregateOperandIndex();
-  }
-
-  Value *getInsertedValueOperand() {
-    return getOperand(getInsertedValueOperandIndex());
-  }
-  const Value *getInsertedValueOperand() const {
-    return getOperand(getInsertedValueOperandIndex());
-  }
-  static unsigned getInsertedValueOperandIndex() {
-    return llvm::InsertValueInst::getInsertedValueOperandIndex();
-  }
-
-  ArrayRef<unsigned> getIndices() const {
-    return cast<llvm::InsertValueInst>(Val)->getIndices();
-  }
-
-  unsigned getNumIndices() const {
-    return cast<llvm::InsertValueInst>(Val)->getNumIndices();
-  }
-
-  unsigned hasIndices() const {
-    return cast<llvm::InsertValueInst>(Val)->hasIndices();
-  }
-};
-
-class BranchInst : public SingleLLVMInstructionImpl<llvm::BranchInst> {
-  /// Use Context::createBranchInst(). Don't call the constructor directly.
-  BranchInst(llvm::BranchInst *BI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::Br, Opcode::Br, BI, Ctx) {}
-  friend Context; // for BranchInst()
-
-public:
-  static BranchInst *create(BasicBlock *IfTrue, Instruction *InsertBefore,
-                            Context &Ctx);
-  static BranchInst *create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd,
-                            Context &Ctx);
-  static BranchInst *create(BasicBlock *IfTrue, BasicBlock *IfFalse,
-                            Value *Cond, Instruction *InsertBefore,
-                            Context &Ctx);
-  static BranchInst *create(BasicBlock *IfTrue, BasicBlock *IfFalse,
-                            Value *Cond, BasicBlock *InsertAtEnd, Context &Ctx);
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From);
-  bool isUnconditional() const {
-    return cast<llvm::BranchInst>(Val)->isUnconditional();
-  }
-  bool isConditional() const {
-    return cast<llvm::BranchInst>(Val)->isConditional();
-  }
-  Value *getCondition() const;
-  void setCondition(Value *V) { setOperand(0, V); }
-  unsigned getNumSuccessors() const { return 1 + isConditional(); }
-  BasicBlock *getSuccessor(unsigned SuccIdx) const;
-  void setSuccessor(unsigned Idx, BasicBlock *NewSucc);
-  void swapSuccessors() { swapOperandsInternal(1, 2); }
-
-private:
-  struct LLVMBBToSBBB {
-    Context &Ctx;
-    LLVMBBToSBBB(Context &Ctx) : Ctx(Ctx) {}
-    BasicBlock *operator()(llvm::BasicBlock *BB) const;
-  };
-
-  struct ConstLLVMBBToSBBB {
-    Context &Ctx;
-    ConstLLVMBBToSBBB(Context &Ctx) : Ctx(Ctx) {}
-    const BasicBlock *operator()(const llvm::BasicBlock *BB) const;
-  };
-
-public:
-  using sb_succ_op_iterator =
-      mapped_iterator<llvm::BranchInst::succ_op_iterator, LLVMBBToSBBB>;
-  iterator_range<sb_succ_op_iterator> successors() {
-    iterator_range<llvm::BranchInst::succ_op_iterator> LLVMRange =
-        cast<llvm::BranchInst>(Val)->successors();
-    LLVMBBToSBBB BBMap(Ctx);
-    sb_succ_op_iterator MappedBegin = map_iterator(LLVMRange.begin(), BBMap);
-    sb_succ_op_iterator MappedEnd = map_iterator(LLVMRange.end(), BBMap);
-    return make_range(MappedBegin, MappedEnd);
-  }
-
-  using const_sb_succ_op_iterator =
-      mapped_iterator<llvm::BranchInst::const_succ_op_iterator,
-                      ConstLLVMBBToSBBB>;
-  iterator_range<const_sb_succ_op_iterator> successors() const {
-    iterator_range<llvm::BranchInst::const_succ_op_iterator> ConstLLVMRange =
-        static_cast<const llvm::BranchInst *>(cast<llvm::BranchInst>(Val))
-            ->successors();
-    ConstLLVMBBToSBBB ConstBBMap(Ctx);
-    const_sb_succ_op_iterator ConstMappedBegin =
-        map_iterator(ConstLLVMRange.begin(), ConstBBMap);
-    const_sb_succ_op_iterator ConstMappedEnd =
-        map_iterator(ConstLLVMRange.end(), ConstBBMap);
-    return make_range(ConstMappedBegin, ConstMappedEnd);
-  }
-};
-
-/// An abstract class, parent of unary instructions.
-class UnaryInstruction
-    : public SingleLLVMInstructionImpl<llvm::UnaryInstruction> {
-protected:
-  UnaryInstruction(ClassID ID, Opcode Opc, llvm::Instruction *LLVMI,
-                   Context &Ctx)
-      : SingleLLVMInstructionImpl(ID, Opc, LLVMI, Ctx) {}
-
-public:
-  static bool classof(const Instruction *I) {
-    return isa<LoadInst>(I) || isa<CastInst>(I) || isa<FreezeInst>(I);
-  }
-  static bool classof(const Value *V) {
-    return isa<Instruction>(V) && classof(cast<Instruction>(V));
-  }
-};
-
-class ExtractValueInst : public UnaryInstruction {
-  /// Use Context::createExtractValueInst() instead.
-  ExtractValueInst(llvm::ExtractValueInst *EVI, Context &Ctx)
-      : UnaryInstruction(ClassID::ExtractValue, Opcode::ExtractValue, EVI,
-                         Ctx) {}
-  friend Context; // for ExtractValueInst()
-
-public:
-  static Value *create(Value *Agg, ArrayRef<unsigned> Idxs, BBIterator WhereIt,
-                       BasicBlock *WhereBB, Context &Ctx,
-                       const Twine &Name = "");
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::ExtractValue;
-  }
-
-  /// Returns the type of the element that would be extracted
-  /// with an extractvalue instruction with the specified parameters.
-  ///
-  /// Null is returned if the indices are invalid for the specified type.
-  static Type *getIndexedType(Type *Agg, ArrayRef<unsigned> Idxs);
-
-  using idx_iterator = llvm::ExtractValueInst::idx_iterator;
-
-  inline idx_iterator idx_begin() const {
-    return cast<llvm::ExtractValueInst>(Val)->idx_begin();
-  }
-  inline idx_iterator idx_end() const {
-    return cast<llvm::ExtractValueInst>(Val)->idx_end();
-  }
-  inline iterator_range<idx_iterator> indices() const {
-    return cast<llvm::ExtractValueInst>(Val)->indices();
-  }
-
-  Value *getAggregateOperand() {
-    return getOperand(getAggregateOperandIndex());
-  }
-  const Value *getAggregateOperand() const {
-    return getOperand(getAggregateOperandIndex());
-  }
-  static unsigned getAggregateOperandIndex() {
-    return llvm::ExtractValueInst::getAggregateOperandIndex();
-  }
-
-  ArrayRef<unsigned> getIndices() const {
-    return cast<llvm::ExtractValueInst>(Val)->getIndices();
-  }
-
-  unsigned getNumIndices() const {
-    return cast<llvm::ExtractValueInst>(Val)->getNumIndices();
-  }
-
-  unsigned hasIndices() const {
-    return cast<llvm::ExtractValueInst>(Val)->hasIndices();
-  }
-};
-
-class VAArgInst : public UnaryInstruction {
-  VAArgInst(llvm::VAArgInst *FI, Context &Ctx)
-      : UnaryInstruction(ClassID::VAArg, Opcode::VAArg, FI, Ctx) {}
-  friend Context; // For constructor;
-
-public:
-  static VAArgInst *create(Value *List, Type *Ty, BBIterator WhereIt,
-                           BasicBlock *WhereBB, Context &Ctx,
-                           const Twine &Name = "");
-  Value *getPointerOperand();
-  const Value *getPointerOperand() const {
-    return const_cast<VAArgInst *>(this)->getPointerOperand();
-  }
-  static unsigned getPointerOperandIndex() {
-    return llvm::VAArgInst::getPointerOperandIndex();
-  }
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::VAArg;
-  }
-};
-
-class FreezeInst : public UnaryInstruction {
-  FreezeInst(llvm::FreezeInst *FI, Context &Ctx)
-      : UnaryInstruction(ClassID::Freeze, Opcode::Freeze, FI, Ctx) {}
-  friend Context; // For constructor;
-
-public:
-  static FreezeInst *create(Value *V, BBIterator WhereIt, BasicBlock *WhereBB,
-                            Context &Ctx, const Twine &Name = "");
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::Freeze;
-  }
-};
-
-class LoadInst final : public UnaryInstruction {
-  /// Use LoadInst::create() instead of calling the constructor.
-  LoadInst(llvm::LoadInst *LI, Context &Ctx)
-      : UnaryInstruction(ClassID::Load, Opcode::Load, LI, Ctx) {}
-  friend Context; // for LoadInst()
-
-public:
-  /// Return true if this is a load from a volatile memory location.
-  bool isVolatile() const { return cast<llvm::LoadInst>(Val)->isVolatile(); }
-  /// Specify whether this is a volatile load or not.
-  void setVolatile(bool V);
-
-  static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align,
-                          Instruction *InsertBefore, Context &Ctx,
-                          const Twine &Name = "");
-  static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align,
-                          Instruction *InsertBefore, bool IsVolatile,
-                          Context &Ctx, const Twine &Name = "");
-  static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align,
-                          BasicBlock *InsertAtEnd, Context &Ctx,
-                          const Twine &Name = "");
-  static LoadInst *create(Type *Ty, Value *Ptr, MaybeAlign Align,
-                          BasicBlock *InsertAtEnd, bool IsVolatile,
-                          Context &Ctx, const Twine &Name = "");
-
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From);
-  Value *getPointerOperand() const;
-  Align getAlign() const { return cast<llvm::LoadInst>(Val)->getAlign(); }
-  bool isUnordered() const { return cast<llvm::LoadInst>(Val)->isUnordered(); }
-  bool isSimple() const { return cast<llvm::LoadInst>(Val)->isSimple(); }
-};
-
-class StoreInst final : public SingleLLVMInstructionImpl<llvm::StoreInst> {
-  /// Use StoreInst::create().
-  StoreInst(llvm::StoreInst *SI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::Store, Opcode::Store, SI, Ctx) {}
-  friend Context; // for StoreInst()
-
-public:
-  /// Return true if this is a store from a volatile memory location.
-  bool isVolatile() const { return cast<llvm::StoreInst>(Val)->isVolatile(); }
-  /// Specify whether this is a volatile store or not.
-  void setVolatile(bool V);
-
-  static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align,
-                           Instruction *InsertBefore, Context &Ctx);
-  static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align,
-                           Instruction *InsertBefore, bool IsVolatile,
-                           Context &Ctx);
-  static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align,
-                           BasicBlock *InsertAtEnd, Context &Ctx);
-  static StoreInst *create(Value *V, Value *Ptr, MaybeAlign Align,
-                           BasicBlock *InsertAtEnd, bool IsVolatile,
-                           Context &Ctx);
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From);
-  Value *getValueOperand() const;
-  Value *getPointerOperand() const;
-  Align getAlign() const { return cast<llvm::StoreInst>(Val)->getAlign(); }
-  bool isSimple() const { return cast<llvm::StoreInst>(Val)->isSimple(); }
-  bool isUnordered() const { return cast<llvm::StoreInst>(Val)->isUnordered(); }
-};
-
-class UnreachableInst final : public Instruction {
-  /// Use UnreachableInst::create() instead of calling the constructor.
-  UnreachableInst(llvm::UnreachableInst *I, Context &Ctx)
-      : Instruction(ClassID::Unreachable, Opcode::Unreachable, I, Ctx) {}
-  friend Context;
-  Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
-    return getOperandUseDefault(OpIdx, Verify);
-  }
-  SmallVector<llvm::Instruction *, 1> getLLVMInstrs() const final {
-    return {cast<llvm::Instruction>(Val)};
-  }
-
-public:
-  static UnreachableInst *create(Instruction *InsertBefore, Context &Ctx);
-  static UnreachableInst *create(BasicBlock *InsertAtEnd, Context &Ctx);
-  static bool classof(const Value *From);
-  unsigned getNumSuccessors() const { return 0; }
-  unsigned getUseOperandNo(const Use &Use) const final {
-    llvm_unreachable("UnreachableInst has no operands!");
-  }
-  unsigned getNumOfIRInstrs() const final { return 1u; }
-};
-
-class ReturnInst final : public SingleLLVMInstructionImpl<llvm::ReturnInst> {
-  /// Use ReturnInst::create() instead of calling the constructor.
-  ReturnInst(llvm::Instruction *I, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::Ret, Opcode::Ret, I, Ctx) {}
-  ReturnInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx)
-      : SingleLLVMInstructionImpl(SubclassID, Opcode::Ret, I, Ctx) {}
-  friend class Context; // For accessing the constructor in create*()
-  static ReturnInst *createCommon(Value *RetVal, IRBuilder<> &Builder,
-                                  Context &Ctx);
-
-public:
-  static ReturnInst *create(Value *RetVal, Instruction *InsertBefore,
-                            Context &Ctx);
-  static ReturnInst *create(Value *RetVal, BasicBlock *InsertAtEnd,
-                            Context &Ctx);
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::Ret;
-  }
-  /// \Returns null if there is no return value.
-  Value *getReturnValue() const;
-};
-
-class CallBase : public SingleLLVMInstructionImpl<llvm::CallBase> {
-  CallBase(ClassID ID, Opcode Opc, llvm::Instruction *I, Context &Ctx)
-      : SingleLLVMInstructionImpl(ID, Opc, I, Ctx) {}
-  friend class CallInst;   // For constructor.
-  friend class InvokeInst; // For constructor.
-  friend class CallBrInst; // For constructor.
-
-public:
-  static bool classof(const Value *From) {
-    auto Opc = From->getSubclassID();
-    return Opc == Instruction::ClassID::Call ||
-           Opc == Instruction::ClassID::Invoke ||
-           Opc == Instruction::ClassID::CallBr;
-  }
-
-  FunctionType *getFunctionType() const;
-
-  op_iterator data_operands_begin() { return op_begin(); }
-  const_op_iterator data_operands_begin() const {
-    return const_cast<CallBase *>(this)->data_operands_begin();
-  }
-  op_iterator data_operands_end() {
-    auto *LLVMCB = cast<llvm::CallBase>(Val);
-    auto Dist = LLVMCB->data_operands_end() - LLVMCB->data_operands_begin();
-    return op_begin() + Dist;
-  }
-  const_op_iterator data_operands_end() const {
-    auto *LLVMCB = cast<llvm::CallBase>(Val);
-    auto Dist = LLVMCB->data_operands_end() - LLVMCB->data_operands_begin();
-    return op_begin() + Dist;
-  }
-  iterator_range<op_iterator> data_ops() {
-    return make_range(data_operands_begin(), data_operands_end());
-  }
-  iterator_range<const_op_iterator> data_ops() const {
-    return make_range(data_operands_begin(), data_operands_end());
-  }
-  bool data_operands_empty() const {
-    return data_operands_end() == data_operands_begin();
-  }
-  unsigned data_operands_size() const {
-    return std::distance(data_operands_begin(), data_operands_end());
-  }
-  bool isDataOperand(Use U) const {
-    assert(this == U.getUser() &&
-           "Only valid to query with a use of this instruction!");
-    return cast<llvm::CallBase>(Val)->isDataOperand(U.LLVMUse);
-  }
-  unsigned getDataOperandNo(Use U) const {
-    assert(isDataOperand(U) && "Data operand # out of range!");
-    return cast<llvm::CallBase>(Val)->getDataOperandNo(U.LLVMUse);
-  }
-
-  /// Return the total number operands (not operand bundles) used by
-  /// every operand bundle in this OperandBundleUser.
-  unsigned getNumTotalBundleOperands() const {
-    return cast<llvm::CallBase>(Val)->getNumTotalBundleOperands();
-  }
-
-  op_iterator arg_begin() { return op_begin(); }
-  const_op_iterator arg_begin() const { return op_begin(); }
-  op_iterator arg_end() {
-    return data_operands_end() - getNumTotalBundleOperands();
-  }
-  const_op_iterator arg_end() const {
-    return const_cast<CallBase *>(this)->arg_end();
-  }
-  iterator_range<op_iterator> args() {
-    return make_range(arg_begin(), arg_end());
-  }
-  iterator_range<const_op_iterator> args() const {
-    return make_range(arg_begin(), arg_end());
-  }
-  bool arg_empty() const { return arg_end() == arg_begin(); }
-  unsigned arg_size() const { return arg_end() - arg_begin(); }
-
-  Value *getArgOperand(unsigned OpIdx) const {
-    assert(OpIdx < arg_size() && "Out of bounds!");
-    return getOperand(OpIdx);
-  }
-  void setArgOperand(unsigned OpIdx, Value *NewOp) {
-    assert(OpIdx < arg_size() && "Out of bounds!");
-    setOperand(OpIdx, NewOp);
-  }
-
-  Use getArgOperandUse(unsigned Idx) const {
-    assert(Idx < arg_size() && "Out of bounds!");
-    return getOperandUse(Idx);
-  }
-  Use getArgOperandUse(unsigned Idx) {
-    assert(Idx < arg_size() && "Out of bounds!");
-    return getOperandUse(Idx);
-  }
-
-  bool isArgOperand(Use U) const {
-    return cast<llvm::CallBase>(Val)->isArgOperand(U.LLVMUse);
-  }
-  unsigned getArgOperandNo(Use U) const {
-    return cast<llvm::CallBase>(Val)->getArgOperandNo(U.LLVMUse);
-  }
-  bool hasArgument(const Value *V) const { return is_contained(args(), V); }
-
-  Value *getCalledOperand() const;
-  Use getCalledOperandUse() const;
-
-  Function *getCalledFunction() const;
-  bool isIndirectCall() const {
-    return cast<llvm::CallBase>(Val)->isIndirectCall();
-  }
-  bool isCallee(Use U) const {
-    return cast<llvm::CallBase>(Val)->isCallee(U.LLVMUse);
-  }
-  Function *getCaller();
-  const Function *getCaller() const {
-    return const_cast<CallBase *>(this)->getCaller();
-  }
-  bool isMustTailCall() const {
-    return cast<llvm::CallBase>(Val)->isMustTailCall();
-  }
-  bool isTailCall() const { return cast<llvm::CallBase>(Val)->isTailCall(); }
-  Intrinsic::ID getIntrinsicID() const {
-    return cast<llvm::CallBase>(Val)->getIntrinsicID();
-  }
-  void setCalledOperand(Value *V) { getCalledOperandUse().set(V); }
-  void setCalledFunction(Function *F);
-  CallingConv::ID getCallingConv() const {
-    return cast<llvm::CallBase>(Val)->getCallingConv();
-  }
-  bool isInlineAsm() const { return cast<llvm::CallBase>(Val)->isInlineAsm(); }
-};
-
-class CallInst final : public CallBase {
-  /// Use Context::createCallInst(). Don't call the
-  /// constructor directly.
-  CallInst(llvm::Instruction *I, Context &Ctx)
-      : CallBase(ClassID::Call, Opcode::Call, I, Ctx) {}
-  friend class Context; // For accessing the constructor in
-                        // create*()
-
-public:
-  static CallInst *create(FunctionType *FTy, Value *Func,
-                          ArrayRef<Value *> Args, BBIterator WhereIt,
-                          BasicBlock *WhereBB, Context &Ctx,
-                          const Twine &NameStr = "");
-  static CallInst *create(FunctionType *FTy, Value *Func,
-                          ArrayRef<Value *> Args, Instruction *InsertBefore,
-                          Context &Ctx, const Twine &NameStr = "");
-  static CallInst *create(FunctionType *FTy, Value *Func,
-                          ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
-                          Context &Ctx, const Twine &NameStr = "");
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::Call;
-  }
-};
-
-class InvokeInst final : public CallBase {
-  /// Use Context::createInvokeInst(). Don't call the
-  /// constructor directly.
-  InvokeInst(llvm::Instruction *I, Context &Ctx)
-      : CallBase(ClassID::Invoke, Opcode::Invoke, I, Ctx) {}
-  friend class Context; // For accessing the constructor in
-                        // create*()
-
-public:
-  static InvokeInst *create(FunctionType *FTy, Value *Func,
-                            BasicBlock *IfNormal, BasicBlock *IfException,
-                            ArrayRef<Value *> Args, BBIterator WhereIt,
-                            BasicBlock *WhereBB, Context &Ctx,
-                            const Twine &NameStr = "");
-  static InvokeInst *create(FunctionType *FTy, Value *Func,
-                            BasicBlock *IfNormal, BasicBlock *IfException,
-                            ArrayRef<Value *> Args, Instruction *InsertBefore,
-                            Context &Ctx, const Twine &NameStr = "");
-  static InvokeInst *create(FunctionType *FTy, Value *Func,
-                            BasicBlock *IfNormal, BasicBlock *IfException,
-                            ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
-                            Context &Ctx, const Twine &NameStr = "");
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::Invoke;
-  }
-  BasicBlock *getNormalDest() const;
-  BasicBlock *getUnwindDest() const;
-  void setNormalDest(BasicBlock *BB);
-  void setUnwindDest(BasicBlock *BB);
-  LandingPadInst *getLandingPadInst() const;
-  BasicBlock *getSuccessor(unsigned SuccIdx) const;
-  void setSuccessor(unsigned SuccIdx, BasicBlock *NewSucc) {
-    assert(SuccIdx < 2 && "Successor # out of range for invoke!");
-    if (SuccIdx == 0)
-      setNormalDest(NewSucc);
-    else
-      setUnwindDest(NewSucc);
-  }
-  unsigned getNumSuccessors() const {
-    return cast<llvm::InvokeInst>(Val)->getNumSuccessors();
-  }
-};
-
-class CallBrInst final : public CallBase {
-  /// Use Context::createCallBrInst(). Don't call the
-  /// constructor directly.
-  CallBrInst(llvm::Instruction *I, Context &Ctx)
-      : CallBase(ClassID::CallBr, Opcode::CallBr, I, Ctx) {}
-  friend class Context; // For accessing the constructor in
-                        // create*()
-
-public:
-  static CallBrInst *create(FunctionType *FTy, Value *Func,
-                            BasicBlock *DefaultDest,
-                            ArrayRef<BasicBlock *> IndirectDests,
-                            ArrayRef<Value *> Args, BBIterator WhereIt,
-                            BasicBlock *WhereBB, Context &Ctx,
-                            const Twine &NameStr = "");
-  static CallBrInst *create(FunctionType *FTy, Value *Func,
-                            BasicBlock *DefaultDest,
-                            ArrayRef<BasicBlock *> IndirectDests,
-                            ArrayRef<Value *> Args, Instruction *InsertBefore,
-                            Context &Ctx, const Twine &NameStr = "");
-  static CallBrInst *create(FunctionType *FTy, Value *Func,
-                            BasicBlock *DefaultDest,
-                            ArrayRef<BasicBlock *> IndirectDests,
-                            ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
-                            Context &Ctx, const Twine &NameStr = "");
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::CallBr;
-  }
-  unsigned getNumIndirectDests() const {
-    return cast<llvm::CallBrInst>(Val)->getNumIndirectDests();
-  }
-  Value *getIndirectDestLabel(unsigned Idx) const;
-  Value *getIndirectDestLabelUse(unsigned Idx) const;
-  BasicBlock *getDefaultDest() const;
-  BasicBlock *getIndirectDest(unsigned Idx) const;
-  SmallVector<BasicBlock *, 16> getIndirectDests() const;
-  void setDefaultDest(BasicBlock *BB);
-  void setIndirectDest(unsigned Idx, BasicBlock *BB);
-  BasicBlock *getSuccessor(unsigned Idx) const;
-  unsigned getNumSuccessors() const {
-    return cast<llvm::CallBrInst>(Val)->getNumSuccessors();
-  }
-};
-
-class LandingPadInst : public SingleLLVMInstructionImpl<llvm::LandingPadInst> {
-  LandingPadInst(llvm::LandingPadInst *LP, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::LandingPad, Opcode::LandingPad, LP,
-                                  Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  static LandingPadInst *create(Type *RetTy, unsigned NumReservedClauses,
-                                BBIterator WhereIt, BasicBlock *WhereBB,
-                                Context &Ctx, const Twine &Name = "");
-  /// Return 'true' if this landingpad instruction is a
-  /// cleanup. I.e., it should be run when unwinding even if its landing pad
-  /// doesn't catch the exception.
-  bool isCleanup() const {
-    return cast<llvm::LandingPadInst>(Val)->isCleanup();
-  }
-  /// Indicate that this landingpad instruction is a cleanup.
-  void setCleanup(bool V);
-
-  // TODO: We are not implementing addClause() because we have no way to revert
-  // it for now.
-
-  /// Get the value of the clause at index Idx. Use isCatch/isFilter to
-  /// determine what type of clause this is.
-  Constant *getClause(unsigned Idx) const;
-
-  /// Return 'true' if the clause and index Idx is a catch clause.
-  bool isCatch(unsigned Idx) const {
-    return cast<llvm::LandingPadInst>(Val)->isCatch(Idx);
-  }
-  /// Return 'true' if the clause and index Idx is a filter clause.
-  bool isFilter(unsigned Idx) const {
-    return cast<llvm::LandingPadInst>(Val)->isFilter(Idx);
-  }
-  /// Get the number of clauses for this landing pad.
-  unsigned getNumClauses() const {
-    return cast<llvm::LandingPadInst>(Val)->getNumOperands();
-  }
-  // TODO: We are not implementing reserveClauses() because we can't revert it.
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::LandingPad;
-  }
-};
-
-class FuncletPadInst : public SingleLLVMInstructionImpl<llvm::FuncletPadInst> {
-  FuncletPadInst(ClassID SubclassID, Opcode Opc, llvm::Instruction *I,
-                 Context &Ctx)
-      : SingleLLVMInstructionImpl(SubclassID, Opc, I, Ctx) {}
-  friend class CatchPadInst;   // For constructor.
-  friend class CleanupPadInst; // For constructor.
-
-public:
-  /// Return the number of funcletpad arguments.
-  unsigned arg_size() const {
-    return cast<llvm::FuncletPadInst>(Val)->arg_size();
-  }
-  /// Return the outer EH-pad this funclet is nested within.
-  ///
-  /// Note: This returns the associated CatchSwitchInst if this FuncletPadInst
-  /// is a CatchPadInst.
-  Value *getParentPad() const;
-  void setParentPad(Value *ParentPad);
-  /// Return the Idx-th funcletpad argument.
-  Value *getArgOperand(unsigned Idx) const;
-  /// Set the Idx-th funcletpad argument.
-  void setArgOperand(unsigned Idx, Value *V);
-
-  // TODO: Implement missing functions: arg_operands().
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::CatchPad ||
-           From->getSubclassID() == ClassID::CleanupPad;
-  }
-};
-
-class CatchPadInst : public FuncletPadInst {
-  CatchPadInst(llvm::CatchPadInst *CPI, Context &Ctx)
-      : FuncletPadInst(ClassID::CatchPad, Opcode::CatchPad, CPI, Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  CatchSwitchInst *getCatchSwitch() const;
-  // TODO: We have not implemented setCatchSwitch() because we can't revert it
-  // for now, as there is no CatchPadInst member function that can undo it.
-
-  static CatchPadInst *create(Value *ParentPad, ArrayRef<Value *> Args,
-                              BBIterator WhereIt, BasicBlock *WhereBB,
-                              Context &Ctx, const Twine &Name = "");
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::CatchPad;
-  }
-};
-
-class CleanupPadInst : public FuncletPadInst {
-  CleanupPadInst(llvm::CleanupPadInst *CPI, Context &Ctx)
-      : FuncletPadInst(ClassID::CleanupPad, Opcode::CleanupPad, CPI, Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  static CleanupPadInst *create(Value *ParentPad, ArrayRef<Value *> Args,
-                                BBIterator WhereIt, BasicBlock *WhereBB,
-                                Context &Ctx, const Twine &Name = "");
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::CleanupPad;
-  }
-};
-
-class CatchReturnInst
-    : public SingleLLVMInstructionImpl<llvm::CatchReturnInst> {
-  CatchReturnInst(llvm::CatchReturnInst *CRI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::CatchRet, Opcode::CatchRet, CRI,
-                                  Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  static CatchReturnInst *create(CatchPadInst *CatchPad, BasicBlock *BB,
-                                 BBIterator WhereIt, BasicBlock *WhereBB,
-                                 Context &Ctx);
-  CatchPadInst *getCatchPad() const;
-  void setCatchPad(CatchPadInst *CatchPad);
-  BasicBlock *getSuccessor() const;
-  void setSuccessor(BasicBlock *NewSucc);
-  unsigned getNumSuccessors() {
-    return cast<llvm::CatchReturnInst>(Val)->getNumSuccessors();
-  }
-  Value *getCatchSwitchParentPad() const;
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::CatchRet;
-  }
-};
-
-class CleanupReturnInst
-    : public SingleLLVMInstructionImpl<llvm::CleanupReturnInst> {
-  CleanupReturnInst(llvm::CleanupReturnInst *CRI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::CleanupRet, Opcode::CleanupRet, CRI,
-                                  Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  static CleanupReturnInst *create(CleanupPadInst *CleanupPad,
-                                   BasicBlock *UnwindBB, BBIterator WhereIt,
-                                   BasicBlock *WhereBB, Context &Ctx);
-  bool hasUnwindDest() const {
-    return cast<llvm::CleanupReturnInst>(Val)->hasUnwindDest();
-  }
-  bool unwindsToCaller() const {
-    return cast<llvm::CleanupReturnInst>(Val)->unwindsToCaller();
-  }
-  CleanupPadInst *getCleanupPad() const;
-  void setCleanupPad(CleanupPadInst *CleanupPad);
-  unsigned getNumSuccessors() const {
-    return cast<llvm::CleanupReturnInst>(Val)->getNumSuccessors();
-  }
-  BasicBlock *getUnwindDest() const;
-  void setUnwindDest(BasicBlock *NewDest);
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::CleanupRet;
-  }
-};
-
-class GetElementPtrInst final
-    : public SingleLLVMInstructionImpl<llvm::GetElementPtrInst> {
-  /// Use Context::createGetElementPtrInst(). Don't call
-  /// the constructor directly.
-  GetElementPtrInst(llvm::Instruction *I, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::GetElementPtr, Opcode::GetElementPtr,
-                                  I, Ctx) {}
-  GetElementPtrInst(ClassID SubclassID, llvm::Instruction *I, Context &Ctx)
-      : SingleLLVMInstructionImpl(SubclassID, Opcode::GetElementPtr, I, Ctx) {}
-  friend class Context; // For accessing the constructor in
-                        // create*()
-
-public:
-  static Value *create(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
-                       BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
-                       const Twine &NameStr = "");
-  static Value *create(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
-                       Instruction *InsertBefore, Context &Ctx,
-                       const Twine &NameStr = "");
-  static Value *create(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
-                       BasicBlock *InsertAtEnd, Context &Ctx,
-                       const Twine &NameStr = "");
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::GetElementPtr;
-  }
-
-  Type *getSourceElementType() const;
-  Type *getResultElementType() const;
-  unsigned getAddressSpace() const {
-    return cast<llvm::GetElementPtrInst>(Val)->getAddressSpace();
-  }
-
-  inline op_iterator idx_begin() { return op_begin() + 1; }
-  inline const_op_iterator idx_begin() const {
-    return const_cast<GetElementPtrInst *>(this)->idx_begin();
-  }
-  inline op_iterator idx_end() { return op_end(); }
-  inline const_op_iterator idx_end() const {
-    return const_cast<GetElementPtrInst *>(this)->idx_end();
-  }
-  inline iterator_range<op_iterator> indices() {
-    return make_range(idx_begin(), idx_end());
-  }
-  inline iterator_range<const_op_iterator> indices() const {
-    return const_cast<GetElementPtrInst *>(this)->indices();
-  }
-
-  Value *getPointerOperand() const;
-  static unsigned getPointerOperandIndex() {
-    return llvm::GetElementPtrInst::getPointerOperandIndex();
-  }
-  Type *getPointerOperandType() const;
-  unsigned getPointerAddressSpace() const {
-    return cast<llvm::GetElementPtrInst>(Val)->getPointerAddressSpace();
-  }
-  unsigned getNumIndices() const {
-    return cast<llvm::GetElementPtrInst>(Val)->getNumIndices();
-  }
-  bool hasIndices() const {
-    return cast<llvm::GetElementPtrInst>(Val)->hasIndices();
-  }
-  bool hasAllConstantIndices() const {
-    return cast<llvm::GetElementPtrInst>(Val)->hasAllConstantIndices();
-  }
-  GEPNoWrapFlags getNoWrapFlags() const {
-    return cast<llvm::GetElementPtrInst>(Val)->getNoWrapFlags();
-  }
-  bool isInBounds() const {
-    return cast<llvm::GetElementPtrInst>(Val)->isInBounds();
-  }
-  bool hasNoUnsignedSignedWrap() const {
-    return cast<llvm::GetElementPtrInst>(Val)->hasNoUnsignedSignedWrap();
-  }
-  bool hasNoUnsignedWrap() const {
-    return cast<llvm::GetElementPtrInst>(Val)->hasNoUnsignedWrap();
-  }
-  bool accumulateConstantOffset(const DataLayout &DL, APInt &Offset) const {
-    return cast<llvm::GetElementPtrInst>(Val)->accumulateConstantOffset(DL,
-                                                                        Offset);
-  }
-  // TODO: Add missing member functions.
-};
-
-class CatchSwitchInst
-    : public SingleLLVMInstructionImpl<llvm::CatchSwitchInst> {
-public:
-  CatchSwitchInst(llvm::CatchSwitchInst *CSI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::CatchSwitch, Opcode::CatchSwitch,
-                                  CSI, Ctx) {}
-
-  static CatchSwitchInst *create(Value *ParentPad, BasicBlock *UnwindBB,
-                                 unsigned NumHandlers, BBIterator WhereIt,
-                                 BasicBlock *WhereBB, Context &Ctx,
-                                 const Twine &Name = "");
-
-  Value *getParentPad() const;
-  void setParentPad(Value *ParentPad);
-
-  bool hasUnwindDest() const {
-    return cast<llvm::CatchSwitchInst>(Val)->hasUnwindDest();
-  }
-  bool unwindsToCaller() const {
-    return cast<llvm::CatchSwitchInst>(Val)->unwindsToCaller();
-  }
-  BasicBlock *getUnwindDest() const;
-  void setUnwindDest(BasicBlock *UnwindDest);
-
-  unsigned getNumHandlers() const {
-    return cast<llvm::CatchSwitchInst>(Val)->getNumHandlers();
-  }
-
-private:
-  static BasicBlock *handler_helper(Value *V) { return cast<BasicBlock>(V); }
-  static const BasicBlock *handler_helper(const Value *V) {
-    return cast<BasicBlock>(V);
-  }
-
-public:
-  using DerefFnTy = BasicBlock *(*)(Value *);
-  using handler_iterator = mapped_iterator<op_iterator, DerefFnTy>;
-  using handler_range = iterator_range<handler_iterator>;
-  using ConstDerefFnTy = const BasicBlock *(*)(const Value *);
-  using const_handler_iterator =
-      mapped_iterator<const_op_iterator, ConstDerefFnTy>;
-  using const_handler_range = iterator_range<const_handler_iterator>;
-
-  handler_iterator handler_begin() {
-    op_iterator It = op_begin() + 1;
-    if (hasUnwindDest())
-      ++It;
-    return handler_iterator(It, DerefFnTy(handler_helper));
-  }
-  const_handler_iterator handler_begin() const {
-    const_op_iterator It = op_begin() + 1;
-    if (hasUnwindDest())
-      ++It;
-    return const_handler_iterator(It, ConstDerefFnTy(handler_helper));
-  }
-  handler_iterator handler_end() {
-    return handler_iterator(op_end(), DerefFnTy(handler_helper));
-  }
-  const_handler_iterator handler_end() const {
-    return const_handler_iterator(op_end(), ConstDerefFnTy(handler_helper));
-  }
-  handler_range handlers() {
-    return make_range(handler_begin(), handler_end());
-  }
-  const_handler_range handlers() const {
-    return make_range(handler_begin(), handler_end());
-  }
-
-  void addHandler(BasicBlock *Dest);
-
-  // TODO: removeHandler() cannot be reverted because there is no equivalent
-  // addHandler() with a handler_iterator to specify the position. So we can't
-  // implement it for now.
-
-  unsigned getNumSuccessors() const { return getNumOperands() - 1; }
-  BasicBlock *getSuccessor(unsigned Idx) const {
-    assert(Idx < getNumSuccessors() &&
-           "Successor # out of range for catchswitch!");
-    return cast<BasicBlock>(getOperand(Idx + 1));
-  }
-  void setSuccessor(unsigned Idx, BasicBlock *NewSucc) {
-    assert(Idx < getNumSuccessors() &&
-           "Successor # out of range for catchswitch!");
-    setOperand(Idx + 1, NewSucc);
-  }
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::CatchSwitch;
-  }
-};
-
-class ResumeInst : public SingleLLVMInstructionImpl<llvm::ResumeInst> {
-public:
-  ResumeInst(llvm::ResumeInst *CSI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::Resume, Opcode::Resume, CSI, Ctx) {}
-
-  static ResumeInst *create(Value *Exn, BBIterator WhereIt, BasicBlock *WhereBB,
-                            Context &Ctx);
-  Value *getValue() const;
-  unsigned getNumSuccessors() const {
-    return cast<llvm::ResumeInst>(Val)->getNumSuccessors();
-  }
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::Resume;
-  }
-};
-
-class SwitchInst : public SingleLLVMInstructionImpl<llvm::SwitchInst> {
-public:
-  SwitchInst(llvm::SwitchInst *SI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::Switch, Opcode::Switch, SI, Ctx) {}
-
-  static constexpr const unsigned DefaultPseudoIndex =
-      llvm::SwitchInst::DefaultPseudoIndex;
-
-  static SwitchInst *create(Value *V, BasicBlock *Dest, unsigned NumCases,
-                            BasicBlock::iterator WhereIt, BasicBlock *WhereBB,
-                            Context &Ctx, const Twine &Name = "");
-
-  Value *getCondition() const;
-  void setCondition(Value *V);
-  BasicBlock *getDefaultDest() const;
-  bool defaultDestUndefined() const {
-    return cast<llvm::SwitchInst>(Val)->defaultDestUndefined();
-  }
-  void setDefaultDest(BasicBlock *DefaultCase);
-  unsigned getNumCases() const {
-    return cast<llvm::SwitchInst>(Val)->getNumCases();
-  }
-
-  using CaseHandle =
-      llvm::SwitchInst::CaseHandleImpl<SwitchInst, ConstantInt, BasicBlock>;
-  using ConstCaseHandle =
-      llvm::SwitchInst::CaseHandleImpl<const SwitchInst, const ConstantInt,
-                                       const BasicBlock>;
-  using CaseIt = llvm::SwitchInst::CaseIteratorImpl<CaseHandle>;
-  using ConstCaseIt = llvm::SwitchInst::CaseIteratorImpl<ConstCaseHandle>;
-
-  /// Returns a read/write iterator that points to the first case in the
-  /// SwitchInst.
-  CaseIt case_begin() { return CaseIt(this, 0); }
-  ConstCaseIt case_begin() const { return ConstCaseIt(this, 0); }
-  /// Returns a read/write iterator that points one past the last in the
-  /// SwitchInst.
-  CaseIt case_end() { return CaseIt(this, getNumCases()); }
-  ConstCaseIt case_end() const { return ConstCaseIt(this, getNumCases()); }
-  /// Iteration adapter for range-for loops.
-  iterator_range<CaseIt> cases() {
-    return make_range(case_begin(), case_end());
-  }
-  iterator_range<ConstCaseIt> cases() const {
-    return make_range(case_begin(), case_end());
-  }
-  CaseIt case_default() { return CaseIt(this, DefaultPseudoIndex); }
-  ConstCaseIt case_default() const {
-    return ConstCaseIt(this, DefaultPseudoIndex);
-  }
-  CaseIt findCaseValue(const ConstantInt *C) {
-    return CaseIt(
-        this,
-        const_cast<const SwitchInst *>(this)->findCaseValue(C)->getCaseIndex());
-  }
-  ConstCaseIt findCaseValue(const ConstantInt *C) const {
-    ConstCaseIt I = llvm::find_if(cases(), [C](const ConstCaseHandle &Case) {
-      return Case.getCaseValue() == C;
-    });
-    if (I != case_end())
-      return I;
-    return case_default();
-  }
-  ConstantInt *findCaseDest(BasicBlock *BB);
-
-  void addCase(ConstantInt *OnVal, BasicBlock *Dest);
-  /// This method removes the specified case and its successor from the switch
-  /// instruction. Note that this operation may reorder the remaining cases at
-  /// index idx and above.
-  /// Note:
-  /// This action invalidates iterators for all cases following the one removed,
-  /// including the case_end() iterator. It returns an iterator for the next
-  /// case.
-  CaseIt removeCase(CaseIt It);
-
-  unsigned getNumSuccessors() const {
-    return cast<llvm::SwitchInst>(Val)->getNumSuccessors();
-  }
-  BasicBlock *getSuccessor(unsigned Idx) const;
-  void setSuccessor(unsigned Idx, BasicBlock *NewSucc);
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::Switch;
-  }
-};
-
-class UnaryOperator : public UnaryInstruction {
-  static Opcode getUnaryOpcode(llvm::Instruction::UnaryOps UnOp) {
-    switch (UnOp) {
-    case llvm::Instruction::FNeg:
-      return Opcode::FNeg;
-    case llvm::Instruction::UnaryOpsEnd:
-      llvm_unreachable("Bad UnOp!");
-    }
-    llvm_unreachable("Unhandled UnOp!");
-  }
-  UnaryOperator(llvm::UnaryOperator *UO, Context &Ctx)
-      : UnaryInstruction(ClassID::UnOp, getUnaryOpcode(UO->getOpcode()), UO,
-                         Ctx) {}
-  friend Context; // for constructor.
-public:
-  static Value *create(Instruction::Opcode Op, Value *OpV, BBIterator WhereIt,
-                       BasicBlock *WhereBB, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Instruction::Opcode Op, Value *OpV,
-                       Instruction *InsertBefore, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Instruction::Opcode Op, Value *OpV,
-                       BasicBlock *InsertAtEnd, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
-                                      Value *CopyFrom, BBIterator WhereIt,
-                                      BasicBlock *WhereBB, Context &Ctx,
-                                      const Twine &Name = "");
-  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
-                                      Value *CopyFrom,
-                                      Instruction *InsertBefore, Context &Ctx,
-                                      const Twine &Name = "");
-  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
-                                      Value *CopyFrom, BasicBlock *InsertAtEnd,
-                                      Context &Ctx, const Twine &Name = "");
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::UnOp;
-  }
-};
-
-class BinaryOperator : public SingleLLVMInstructionImpl<llvm::BinaryOperator> {
-protected:
-  static Opcode getBinOpOpcode(llvm::Instruction::BinaryOps BinOp) {
-    switch (BinOp) {
-    case llvm::Instruction::Add:
-      return Opcode::Add;
-    case llvm::Instruction::FAdd:
-      return Opcode::FAdd;
-    case llvm::Instruction::Sub:
-      return Opcode::Sub;
-    case llvm::Instruction::FSub:
-      return Opcode::FSub;
-    case llvm::Instruction::Mul:
-      return Opcode::Mul;
-    case llvm::Instruction::FMul:
-      return Opcode::FMul;
-    case llvm::Instruction::UDiv:
-      return Opcode::UDiv;
-    case llvm::Instruction::SDiv:
-      return Opcode::SDiv;
-    case llvm::Instruction::FDiv:
-      return Opcode::FDiv;
-    case llvm::Instruction::URem:
-      return Opcode::URem;
-    case llvm::Instruction::SRem:
-      return Opcode::SRem;
-    case llvm::Instruction::FRem:
-      return Opcode::FRem;
-    case llvm::Instruction::Shl:
-      return Opcode::Shl;
-    case llvm::Instruction::LShr:
-      return Opcode::LShr;
-    case llvm::Instruction::AShr:
-      return Opcode::AShr;
-    case llvm::Instruction::And:
-      return Opcode::And;
-    case llvm::Instruction::Or:
-      return Opcode::Or;
-    case llvm::Instruction::Xor:
-      return Opcode::Xor;
-    case llvm::Instruction::BinaryOpsEnd:
-      llvm_unreachable("Bad BinOp!");
-    }
-    llvm_unreachable("Unhandled BinOp!");
-  }
-  BinaryOperator(llvm::BinaryOperator *BinOp, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::BinaryOperator,
-                                  getBinOpOpcode(BinOp->getOpcode()), BinOp,
-                                  Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS,
-                       BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS,
-                       Instruction *InsertBefore, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Instruction::Opcode Op, Value *LHS, Value *RHS,
-                       BasicBlock *InsertAtEnd, Context &Ctx,
-                       const Twine &Name = "");
-
-  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
-                                      Value *RHS, Value *CopyFrom,
-                                      BBIterator WhereIt, BasicBlock *WhereBB,
-                                      Context &Ctx, const Twine &Name = "");
-  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
-                                      Value *RHS, Value *CopyFrom,
-                                      Instruction *InsertBefore, Context &Ctx,
-                                      const Twine &Name = "");
-  static Value *createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
-                                      Value *RHS, Value *CopyFrom,
-                                      BasicBlock *InsertAtEnd, Context &Ctx,
-                                      const Twine &Name = "");
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::BinaryOperator;
-  }
-  void swapOperands() { swapOperandsInternal(0, 1); }
-};
-
-/// An or instruction, which can be marked as "disjoint", indicating that the
-/// inputs don't have a 1 in the same bit position. Meaning this instruction
-/// can also be treated as an add.
-class PossiblyDisjointInst : public BinaryOperator {
-public:
-  void setIsDisjoint(bool B);
-  bool isDisjoint() const {
-    return cast<llvm::PossiblyDisjointInst>(Val)->isDisjoint();
-  }
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From) {
-    return isa<Instruction>(From) &&
-           cast<Instruction>(From)->getOpcode() == Opcode::Or;
-  }
-};
-
-class AtomicRMWInst : public SingleLLVMInstructionImpl<llvm::AtomicRMWInst> {
-  AtomicRMWInst(llvm::AtomicRMWInst *Atomic, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::AtomicRMW,
-                                  Instruction::Opcode::AtomicRMW, Atomic, Ctx) {
-  }
-  friend class Context; // For constructor.
-
-public:
-  using BinOp = llvm::AtomicRMWInst::BinOp;
-  BinOp getOperation() const {
-    return cast<llvm::AtomicRMWInst>(Val)->getOperation();
-  }
-  static StringRef getOperationName(BinOp Op) {
-    return llvm::AtomicRMWInst::getOperationName(Op);
-  }
-  static bool isFPOperation(BinOp Op) {
-    return llvm::AtomicRMWInst::isFPOperation(Op);
-  }
-  void setOperation(BinOp Op) {
-    cast<llvm::AtomicRMWInst>(Val)->setOperation(Op);
-  }
-  Align getAlign() const { return cast<llvm::AtomicRMWInst>(Val)->getAlign(); }
-  void setAlignment(Align Align);
-  bool isVolatile() const {
-    return cast<llvm::AtomicRMWInst>(Val)->isVolatile();
-  }
-  void setVolatile(bool V);
-  AtomicOrdering getOrdering() const {
-    return cast<llvm::AtomicRMWInst>(Val)->getOrdering();
-  }
-  void setOrdering(AtomicOrdering Ordering);
-  SyncScope::ID getSyncScopeID() const {
-    return cast<llvm::AtomicRMWInst>(Val)->getSyncScopeID();
-  }
-  void setSyncScopeID(SyncScope::ID SSID);
-  Value *getPointerOperand();
-  const Value *getPointerOperand() const {
-    return const_cast<AtomicRMWInst *>(this)->getPointerOperand();
-  }
-  Value *getValOperand();
-  const Value *getValOperand() const {
-    return const_cast<AtomicRMWInst *>(this)->getValOperand();
-  }
-  unsigned getPointerAddressSpace() const {
-    return cast<llvm::AtomicRMWInst>(Val)->getPointerAddressSpace();
-  }
-  bool isFloatingPointOperation() const {
-    return cast<llvm::AtomicRMWInst>(Val)->isFloatingPointOperation();
-  }
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::AtomicRMW;
-  }
-
-  static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
-                               MaybeAlign Align, AtomicOrdering Ordering,
-                               BBIterator WhereIt, BasicBlock *WhereBB,
-                               Context &Ctx,
-                               SyncScope::ID SSID = SyncScope::System,
-                               const Twine &Name = "");
-  static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
-                               MaybeAlign Align, AtomicOrdering Ordering,
-                               Instruction *InsertBefore, Context &Ctx,
-                               SyncScope::ID SSID = SyncScope::System,
-                               const Twine &Name = "");
-  static AtomicRMWInst *create(BinOp Op, Value *Ptr, Value *Val,
-                               MaybeAlign Align, AtomicOrdering Ordering,
-                               BasicBlock *InsertAtEnd, Context &Ctx,
-                               SyncScope::ID SSID = SyncScope::System,
-                               const Twine &Name = "");
-};
-
-class AtomicCmpXchgInst
-    : public SingleLLVMInstructionImpl<llvm::AtomicCmpXchgInst> {
-  AtomicCmpXchgInst(llvm::AtomicCmpXchgInst *Atomic, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::AtomicCmpXchg,
-                                  Instruction::Opcode::AtomicCmpXchg, Atomic,
-                                  Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  /// Return the alignment of the memory that is being allocated by the
-  /// instruction.
-  Align getAlign() const {
-    return cast<llvm::AtomicCmpXchgInst>(Val)->getAlign();
-  }
-
-  void setAlignment(Align Align);
-  /// Return true if this is a cmpxchg from a volatile memory
-  /// location.
-  bool isVolatile() const {
-    return cast<llvm::AtomicCmpXchgInst>(Val)->isVolatile();
-  }
-  /// Specify whether this is a volatile cmpxchg.
-  void setVolatile(bool V);
-  /// Return true if this cmpxchg may spuriously fail.
-  bool isWeak() const { return cast<llvm::AtomicCmpXchgInst>(Val)->isWeak(); }
-  void setWeak(bool IsWeak);
-  static bool isValidSuccessOrdering(AtomicOrdering Ordering) {
-    return llvm::AtomicCmpXchgInst::isValidSuccessOrdering(Ordering);
-  }
-  static bool isValidFailureOrdering(AtomicOrdering Ordering) {
-    return llvm::AtomicCmpXchgInst::isValidFailureOrdering(Ordering);
-  }
-  AtomicOrdering getSuccessOrdering() const {
-    return cast<llvm::AtomicCmpXchgInst>(Val)->getSuccessOrdering();
-  }
-  void setSuccessOrdering(AtomicOrdering Ordering);
-
-  AtomicOrdering getFailureOrdering() const {
-    return cast<llvm::AtomicCmpXchgInst>(Val)->getFailureOrdering();
-  }
-  void setFailureOrdering(AtomicOrdering Ordering);
-  AtomicOrdering getMergedOrdering() const {
-    return cast<llvm::AtomicCmpXchgInst>(Val)->getMergedOrdering();
-  }
-  SyncScope::ID getSyncScopeID() const {
-    return cast<llvm::AtomicCmpXchgInst>(Val)->getSyncScopeID();
-  }
-  void setSyncScopeID(SyncScope::ID SSID);
-  Value *getPointerOperand();
-  const Value *getPointerOperand() const {
-    return const_cast<AtomicCmpXchgInst *>(this)->getPointerOperand();
-  }
-
-  Value *getCompareOperand();
-  const Value *getCompareOperand() const {
-    return const_cast<AtomicCmpXchgInst *>(this)->getCompareOperand();
-  }
-
-  Value *getNewValOperand();
-  const Value *getNewValOperand() const {
-    return const_cast<AtomicCmpXchgInst *>(this)->getNewValOperand();
-  }
-
-  /// Returns the address space of the pointer operand.
-  unsigned getPointerAddressSpace() const {
-    return cast<llvm::AtomicCmpXchgInst>(Val)->getPointerAddressSpace();
-  }
-
-  static AtomicCmpXchgInst *
-  create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align,
-         AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering,
-         BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
-         SyncScope::ID SSID = SyncScope::System, const Twine &Name = "");
-  static AtomicCmpXchgInst *
-  create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align,
-         AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering,
-         Instruction *InsertBefore, Context &Ctx,
-         SyncScope::ID SSID = SyncScope::System, const Twine &Name = "");
-  static AtomicCmpXchgInst *
-  create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align,
-         AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering,
-         BasicBlock *InsertAtEnd, Context &Ctx,
-         SyncScope::ID SSID = SyncScope::System, const Twine &Name = "");
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::AtomicCmpXchg;
-  }
-};
-
-class AllocaInst final : public UnaryInstruction {
-  AllocaInst(llvm::AllocaInst *AI, Context &Ctx)
-      : UnaryInstruction(ClassID::Alloca, Instruction::Opcode::Alloca, AI,
-                         Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  static AllocaInst *create(Type *Ty, unsigned AddrSpace, BBIterator WhereIt,
-                            BasicBlock *WhereBB, Context &Ctx,
-                            Value *ArraySize = nullptr, const Twine &Name = "");
-  static AllocaInst *create(Type *Ty, unsigned AddrSpace,
-                            Instruction *InsertBefore, Context &Ctx,
-                            Value *ArraySize = nullptr, const Twine &Name = "");
-  static AllocaInst *create(Type *Ty, unsigned AddrSpace,
-                            BasicBlock *InsertAtEnd, Context &Ctx,
-                            Value *ArraySize = nullptr, const Twine &Name = "");
-
-  /// Return true if there is an allocation size parameter to the allocation
-  /// instruction that is not 1.
-  bool isArrayAllocation() const {
-    return cast<llvm::AllocaInst>(Val)->isArrayAllocation();
-  }
-  /// Get the number of elements allocated. For a simple allocation of a single
-  /// element, this will return a constant 1 value.
-  Value *getArraySize();
-  const Value *getArraySize() const {
-    return const_cast<AllocaInst *>(this)->getArraySize();
-  }
-  /// Overload to return most specific pointer type.
-  PointerType *getType() const;
-  /// Return the address space for the allocation.
-  unsigned getAddressSpace() const {
-    return cast<llvm::AllocaInst>(Val)->getAddressSpace();
-  }
-  /// Get allocation size in bytes. Returns std::nullopt if size can't be
-  /// determined, e.g. in case of a VLA.
-  std::optional<TypeSize> getAllocationSize(const DataLayout &DL) const {
-    return cast<llvm::AllocaInst>(Val)->getAllocationSize(DL);
-  }
-  /// Get allocation size in bits. Returns std::nullopt if size can't be
-  /// determined, e.g. in case of a VLA.
-  std::optional<TypeSize> getAllocationSizeInBits(const DataLayout &DL) const {
-    return cast<llvm::AllocaInst>(Val)->getAllocationSizeInBits(DL);
-  }
-  /// Return the type that is being allocated by the instruction.
-  Type *getAllocatedType() const;
-  /// for use only in special circumstances that need to generically
-  /// transform a whole instruction (eg: IR linking and vectorization).
-  void setAllocatedType(Type *Ty);
-  /// Return the alignment of the memory that is being allocated by the
-  /// instruction.
-  Align getAlign() const { return cast<llvm::AllocaInst>(Val)->getAlign(); }
-  void setAlignment(Align Align);
-  /// Return true if this alloca is in the entry block of the function and is a
-  /// constant size. If so, the code generator will fold it into the
-  /// prolog/epilog code, so it is basically free.
-  bool isStaticAlloca() const {
-    return cast<llvm::AllocaInst>(Val)->isStaticAlloca();
-  }
-  /// Return true if this alloca is used as an inalloca argument to a call. Such
-  /// allocas are never considered static even if they are in the entry block.
-  bool isUsedWithInAlloca() const {
-    return cast<llvm::AllocaInst>(Val)->isUsedWithInAlloca();
-  }
-  /// Specify whether this alloca is used to represent the arguments to a call.
-  void setUsedWithInAlloca(bool V);
-
-  static bool classof(const Value *From) {
-    if (auto *I = dyn_cast<Instruction>(From))
-      return I->getSubclassID() == Instruction::ClassID::Alloca;
-    return false;
-  }
-};
-
-class CastInst : public UnaryInstruction {
-  static Opcode getCastOpcode(llvm::Instruction::CastOps CastOp) {
-    switch (CastOp) {
-    case llvm::Instruction::ZExt:
-      return Opcode::ZExt;
-    case llvm::Instruction::SExt:
-      return Opcode::SExt;
-    case llvm::Instruction::FPToUI:
-      return Opcode::FPToUI;
-    case llvm::Instruction::FPToSI:
-      return Opcode::FPToSI;
-    case llvm::Instruction::FPExt:
-      return Opcode::FPExt;
-    case llvm::Instruction::PtrToInt:
-      return Opcode::PtrToInt;
-    case llvm::Instruction::IntToPtr:
-      return Opcode::IntToPtr;
-    case llvm::Instruction::SIToFP:
-      return Opcode::SIToFP;
-    case llvm::Instruction::UIToFP:
-      return Opcode::UIToFP;
-    case llvm::Instruction::Trunc:
-      return Opcode::Trunc;
-    case llvm::Instruction::FPTrunc:
-      return Opcode::FPTrunc;
-    case llvm::Instruction::BitCast:
-      return Opcode::BitCast;
-    case llvm::Instruction::AddrSpaceCast:
-      return Opcode::AddrSpaceCast;
-    case llvm::Instruction::CastOpsEnd:
-      llvm_unreachable("Bad CastOp!");
-    }
-    llvm_unreachable("Unhandled CastOp!");
-  }
-  /// Use Context::createCastInst(). Don't call the
-  /// constructor directly.
-  CastInst(llvm::CastInst *CI, Context &Ctx)
-      : UnaryInstruction(ClassID::Cast, getCastOpcode(CI->getOpcode()), CI,
-                         Ctx) {}
-  friend Context; // for SBCastInstruction()
-
-public:
-  static Value *create(Type *DestTy, Opcode Op, Value *Operand,
-                       BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Type *DestTy, Opcode Op, Value *Operand,
-                       Instruction *InsertBefore, Context &Ctx,
-                       const Twine &Name = "");
-  static Value *create(Type *DestTy, Opcode Op, Value *Operand,
-                       BasicBlock *InsertAtEnd, Context &Ctx,
-                       const Twine &Name = "");
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From);
-  Type *getSrcTy() const;
-  Type *getDestTy() const;
-};
-
-/// Instruction that can have a nneg flag (zext/uitofp).
-class PossiblyNonNegInst : public CastInst {
-public:
-  bool hasNonNeg() const {
-    return cast<llvm::PossiblyNonNegInst>(Val)->hasNonNeg();
-  }
-  void setNonNeg(bool B);
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From) {
-    if (auto *I = dyn_cast<Instruction>(From)) {
-      switch (I->getOpcode()) {
-      case Opcode::ZExt:
-      case Opcode::UIToFP:
-        return true;
-      default:
-        return false;
-      }
-    }
-    return false;
-  }
-};
-
-// Helper class to simplify stamping out CastInst subclasses.
-template <Instruction::Opcode Op> class CastInstImpl : public CastInst {
-public:
-  static Value *create(Value *Src, Type *DestTy, BBIterator WhereIt,
-                       BasicBlock *WhereBB, Context &Ctx,
-                       const Twine &Name = "") {
-    return CastInst::create(DestTy, Op, Src, WhereIt, WhereBB, Ctx, Name);
-  }
-  static Value *create(Value *Src, Type *DestTy, Instruction *InsertBefore,
-                       Context &Ctx, const Twine &Name = "") {
-    return create(Src, DestTy, InsertBefore->getIterator(),
-                  InsertBefore->getParent(), Ctx, Name);
-  }
-  static Value *create(Value *Src, Type *DestTy, BasicBlock *InsertAtEnd,
-                       Context &Ctx, const Twine &Name = "") {
-    return create(Src, DestTy, InsertAtEnd->end(), InsertAtEnd, Ctx, Name);
-  }
-
-  static bool classof(const Value *From) {
-    if (auto *I = dyn_cast<Instruction>(From))
-      return I->getOpcode() == Op;
-    return false;
-  }
-};
-
-class TruncInst final : public CastInstImpl<Instruction::Opcode::Trunc> {};
-class ZExtInst final : public CastInstImpl<Instruction::Opcode::ZExt> {};
-class SExtInst final : public CastInstImpl<Instruction::Opcode::SExt> {};
-class FPTruncInst final : public CastInstImpl<Instruction::Opcode::FPTrunc> {};
-class FPExtInst final : public CastInstImpl<Instruction::Opcode::FPExt> {};
-class UIToFPInst final : public CastInstImpl<Instruction::Opcode::UIToFP> {};
-class SIToFPInst final : public CastInstImpl<Instruction::Opcode::SIToFP> {};
-class FPToUIInst final : public CastInstImpl<Instruction::Opcode::FPToUI> {};
-class FPToSIInst final : public CastInstImpl<Instruction::Opcode::FPToSI> {};
-class IntToPtrInst final : public CastInstImpl<Instruction::Opcode::IntToPtr> {
-};
-class PtrToIntInst final : public CastInstImpl<Instruction::Opcode::PtrToInt> {
-};
-class BitCastInst final : public CastInstImpl<Instruction::Opcode::BitCast> {};
-class AddrSpaceCastInst final
-    : public CastInstImpl<Instruction::Opcode::AddrSpaceCast> {
-public:
-  /// \Returns the pointer operand.
-  Value *getPointerOperand() { return getOperand(0); }
-  /// \Returns the pointer operand.
-  const Value *getPointerOperand() const {
-    return const_cast<AddrSpaceCastInst *>(this)->getPointerOperand();
-  }
-  /// \Returns the operand index of the pointer operand.
-  static unsigned getPointerOperandIndex() { return 0u; }
-  /// \Returns the address space of the pointer operand.
-  unsigned getSrcAddressSpace() const {
-    return getPointerOperand()->getType()->getPointerAddressSpace();
-  }
-  /// \Returns the address space of the result.
-  unsigned getDestAddressSpace() const {
-    return getType()->getPointerAddressSpace();
-  }
-};
-
-class PHINode final : public SingleLLVMInstructionImpl<llvm::PHINode> {
-  /// Use Context::createPHINode(). Don't call the constructor directly.
-  PHINode(llvm::PHINode *PHI, Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::PHI, Opcode::PHI, PHI, Ctx) {}
-  friend Context; // for PHINode()
-  /// Helper for mapped_iterator.
-  struct LLVMBBToBB {
-    Context &Ctx;
-    LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {}
-    BasicBlock *operator()(llvm::BasicBlock *LLVMBB) const;
-  };
-
-public:
-  static PHINode *create(Type *Ty, unsigned NumReservedValues,
-                         Instruction *InsertBefore, Context &Ctx,
-                         const Twine &Name = "");
-  /// For isa/dyn_cast.
-  static bool classof(const Value *From);
-
-  using const_block_iterator =
-      mapped_iterator<llvm::PHINode::const_block_iterator, LLVMBBToBB>;
-
-  const_block_iterator block_begin() const {
-    LLVMBBToBB BBGetter(Ctx);
-    return const_block_iterator(cast<llvm::PHINode>(Val)->block_begin(),
-                                BBGetter);
-  }
-  const_block_iterator block_end() const {
-    LLVMBBToBB BBGetter(Ctx);
-    return const_block_iterator(cast<llvm::PHINode>(Val)->block_end(),
-                                BBGetter);
-  }
-  iterator_range<const_block_iterator> blocks() const {
-    return make_range(block_begin(), block_end());
-  }
-
-  op_range incoming_values() { return operands(); }
-
-  const_op_range incoming_values() const { return operands(); }
-
-  unsigned getNumIncomingValues() const {
-    return cast<llvm::PHINode>(Val)->getNumIncomingValues();
-  }
-  Value *getIncomingValue(unsigned Idx) const;
-  void setIncomingValue(unsigned Idx, Value *V);
-  static unsigned getOperandNumForIncomingValue(unsigned Idx) {
-    return llvm::PHINode::getOperandNumForIncomingValue(Idx);
-  }
-  static unsigned getIncomingValueNumForOperand(unsigned Idx) {
-    return llvm::PHINode::getIncomingValueNumForOperand(Idx);
-  }
-  BasicBlock *getIncomingBlock(unsigned Idx) const;
-  BasicBlock *getIncomingBlock(const Use &U) const;
-
-  void setIncomingBlock(unsigned Idx, BasicBlock *BB);
-
-  void addIncoming(Value *V, BasicBlock *BB);
-
-  Value *removeIncomingValue(unsigned Idx);
-  Value *removeIncomingValue(BasicBlock *BB);
-
-  int getBasicBlockIndex(const BasicBlock *BB) const;
-  Value *getIncomingValueForBlock(const BasicBlock *BB) const;
-
-  Value *hasConstantValue() const;
-
-  bool hasConstantOrUndefValue() const {
-    return cast<llvm::PHINode>(Val)->hasConstantOrUndefValue();
-  }
-  bool isComplete() const { return cast<llvm::PHINode>(Val)->isComplete(); }
-  void replaceIncomingBlockWith(const BasicBlock *Old, BasicBlock *New);
-  void removeIncomingValueIf(function_ref<bool(unsigned)> Predicate);
-  // TODO: Implement
-  // void copyIncomingBlocks(iterator_range<const_block_iterator> BBRange,
-  //                         uint32_t ToIdx = 0)
-};
-
-// Wraps a static function that takes a single Predicate parameter
-// LLVMValType should be the type of the wrapped class
-#define WRAP_STATIC_PREDICATE(FunctionName)                                    \
-  static auto FunctionName(Predicate P) { return LLVMValType::FunctionName(P); }
-// Wraps a member function that takes no parameters
-// LLVMValType should be the type of the wrapped class
-#define WRAP_MEMBER(FunctionName)                                              \
-  auto FunctionName() const { return cast<LLVMValType>(Val)->FunctionName(); }
-// Wraps both--a common idiom in the CmpInst classes
-#define WRAP_BOTH(FunctionName)                                                \
-  WRAP_STATIC_PREDICATE(FunctionName)                                          \
-  WRAP_MEMBER(FunctionName)
-
-class CmpInst : public SingleLLVMInstructionImpl<llvm::CmpInst> {
-protected:
-  using LLVMValType = llvm::CmpInst;
-  /// Use Context::createCmpInst(). Don't call the constructor directly.
-  CmpInst(llvm::CmpInst *CI, Context &Ctx, ClassID Id, Opcode Opc)
-      : SingleLLVMInstructionImpl(Id, Opc, CI, Ctx) {}
-  friend Context; // for CmpInst()
-  static Value *createCommon(Value *Cond, Value *True, Value *False,
-                             const Twine &Name, IRBuilder<> &Builder,
-                             Context &Ctx);
-
-public:
-  using Predicate = llvm::CmpInst::Predicate;
-
-  static CmpInst *create(Predicate Pred, Value *S1, Value *S2,
-                         Instruction *InsertBefore, Context &Ctx,
-                         const Twine &Name = "");
-  static CmpInst *createWithCopiedFlags(Predicate Pred, Value *S1, Value *S2,
-                                        const Instruction *FlagsSource,
-                                        Instruction *InsertBefore, Context &Ctx,
-                                        const Twine &Name = "");
-  void setPredicate(Predicate P);
-  void swapOperands();
-
-  WRAP_MEMBER(getPredicate);
-  WRAP_BOTH(isFPPredicate);
-  WRAP_BOTH(isIntPredicate);
-  WRAP_STATIC_PREDICATE(getPredicateName);
-  WRAP_BOTH(getInversePredicate);
-  WRAP_BOTH(getOrderedPredicate);
-  WRAP_BOTH(getUnorderedPredicate);
-  WRAP_BOTH(getSwappedPredicate);
-  WRAP_BOTH(isStrictPredicate);
-  WRAP_BOTH(isNonStrictPredicate);
-  WRAP_BOTH(getStrictPredicate);
-  WRAP_BOTH(getNonStrictPredicate);
-  WRAP_BOTH(getFlippedStrictnessPredicate);
-  WRAP_MEMBER(isCommutative);
-  WRAP_BOTH(isEquality);
-  WRAP_BOTH(isRelational);
-  WRAP_BOTH(isSigned);
-  WRAP_BOTH(getSignedPredicate);
-  WRAP_BOTH(getUnsignedPredicate);
-  WRAP_BOTH(getFlippedSignednessPredicate);
-  WRAP_BOTH(isTrueWhenEqual);
-  WRAP_BOTH(isFalseWhenEqual);
-  WRAP_BOTH(isUnsigned);
-  WRAP_STATIC_PREDICATE(isOrdered);
-  WRAP_STATIC_PREDICATE(isUnordered);
-
-  static bool isImpliedTrueByMatchingCmp(Predicate Pred1, Predicate Pred2) {
-    return llvm::CmpInst::isImpliedTrueByMatchingCmp(Pred1, Pred2);
-  }
-  static bool isImpliedFalseByMatchingCmp(Predicate Pred1, Predicate Pred2) {
-    return llvm::CmpInst::isImpliedFalseByMatchingCmp(Pred1, Pred2);
-  }
-
-  /// Method for support type inquiry through isa, cast, and dyn_cast:
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::ICmp ||
-           From->getSubclassID() == ClassID::FCmp;
-  }
-
-  /// Create a result type for fcmp/icmp
-  static Type *makeCmpResultType(Type *OpndType);
-
-#ifndef NDEBUG
-  void dumpOS(raw_ostream &OS) const override;
-  LLVM_DUMP_METHOD void dump() const;
-#endif
-};
-
-class ICmpInst : public CmpInst {
-  /// Use Context::createICmpInst(). Don't call the constructor directly.
-  ICmpInst(llvm::ICmpInst *CI, Context &Ctx)
-      : CmpInst(CI, Ctx, ClassID::ICmp, Opcode::ICmp) {}
-  friend class Context; // For constructor.
-  using LLVMValType = llvm::ICmpInst;
-
-public:
-  void swapOperands();
-
-  WRAP_BOTH(getSignedPredicate);
-  WRAP_BOTH(getUnsignedPredicate);
-  WRAP_BOTH(isEquality);
-  WRAP_MEMBER(isCommutative);
-  WRAP_MEMBER(isRelational);
-  WRAP_STATIC_PREDICATE(isGT);
-  WRAP_STATIC_PREDICATE(isLT);
-  WRAP_STATIC_PREDICATE(isGE);
-  WRAP_STATIC_PREDICATE(isLE);
-
-  static auto predicates() { return llvm::ICmpInst::predicates(); }
-  static bool compare(const APInt &LHS, const APInt &RHS,
-                      ICmpInst::Predicate Pred) {
-    return llvm::ICmpInst::compare(LHS, RHS, Pred);
-  }
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::ICmp;
-  }
-};
-
-class FCmpInst : public CmpInst {
-  /// Use Context::createFCmpInst(). Don't call the constructor directly.
-  FCmpInst(llvm::FCmpInst *CI, Context &Ctx)
-      : CmpInst(CI, Ctx, ClassID::FCmp, Opcode::FCmp) {}
-  friend class Context; // For constructor.
-  using LLVMValType = llvm::FCmpInst;
-
-public:
-  void swapOperands();
-
-  WRAP_BOTH(isEquality);
-  WRAP_MEMBER(isCommutative);
-  WRAP_MEMBER(isRelational);
-
-  static auto predicates() { return llvm::FCmpInst::predicates(); }
-  static bool compare(const APFloat &LHS, const APFloat &RHS,
-                      FCmpInst::Predicate Pred) {
-    return llvm::FCmpInst::compare(LHS, RHS, Pred);
-  }
-
-  static bool classof(const Value *From) {
-    return From->getSubclassID() == ClassID::FCmp;
-  }
-};
-
-#undef WRAP_STATIC_PREDICATE
-#undef WRAP_MEMBER
-#undef WRAP_BOTH
-
-/// An LLLVM Instruction that has no SandboxIR equivalent class gets mapped to
-/// an OpaqueInstr.
-class OpaqueInst : public SingleLLVMInstructionImpl<llvm::Instruction> {
-  OpaqueInst(llvm::Instruction *I, sandboxir::Context &Ctx)
-      : SingleLLVMInstructionImpl(ClassID::Opaque, Opcode::Opaque, I, Ctx) {}
-  OpaqueInst(ClassID SubclassID, llvm::Instruction *I, sandboxir::Context &Ctx)
-      : SingleLLVMInstructionImpl(SubclassID, Opcode::Opaque, I, Ctx) {}
-  friend class Context; // For constructor.
-
-public:
-  static bool classof(const sandboxir::Value *From) {
-    return From->getSubclassID() == ClassID::Opaque;
-  }
-};
-
 } // namespace sandboxir
 } // namespace llvm
 
diff --git a/llvm/include/llvm/SandboxIR/Utils.h b/llvm/include/llvm/SandboxIR/Utils.h
index 4e8a175f547059..690848932229e4 100644
--- a/llvm/include/llvm/SandboxIR/Utils.h
+++ b/llvm/include/llvm/SandboxIR/Utils.h
@@ -13,7 +13,7 @@
 #define LLVM_SANDBOXIR_UTILS_H
 
 #include "llvm/Analysis/MemoryLocation.h"
-#include "llvm/SandboxIR/SandboxIR.h"
+#include "llvm/SandboxIR/Instruction.h"
 
 namespace llvm::sandboxir {
 
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
index 5437853c366ae6..7f6e6d11e5f53a 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
@@ -24,7 +24,7 @@
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/iterator_range.h"
-#include "llvm/SandboxIR/SandboxIR.h"
+#include "llvm/SandboxIR/Instruction.h"
 #include "llvm/Transforms/Vectorize/SandboxVectorizer/Interval.h"
 
 namespace llvm::sandboxir {
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h
index 99582e3e0e0233..a2108f07c28e50 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h
@@ -13,8 +13,8 @@
 #define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_BOTTOMUPVEC_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/SandboxIR/Constant.h"
 #include "llvm/SandboxIR/Pass.h"
-#include "llvm/SandboxIR/SandboxIR.h"
 #include "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h"
 
 namespace llvm::sandboxir {
diff --git a/llvm/lib/SandboxIR/BasicBlock.cpp b/llvm/lib/SandboxIR/BasicBlock.cpp
index 7eba53ffb5ec4a..ebca41aa39da82 100644
--- a/llvm/lib/SandboxIR/BasicBlock.cpp
+++ b/llvm/lib/SandboxIR/BasicBlock.cpp
@@ -8,7 +8,7 @@
 
 #include "llvm/SandboxIR/BasicBlock.h"
 #include "llvm/SandboxIR/Context.h"
-#include "llvm/SandboxIR/SandboxIR.h" // TODO: remove this
+#include "llvm/SandboxIR/Instruction.h"
 
 namespace llvm::sandboxir {
 
diff --git a/llvm/lib/SandboxIR/CMakeLists.txt b/llvm/lib/SandboxIR/CMakeLists.txt
index deea86d442d395..7c817ed133ed8e 100644
--- a/llvm/lib/SandboxIR/CMakeLists.txt
+++ b/llvm/lib/SandboxIR/CMakeLists.txt
@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMSandboxIR
   BasicBlock.cpp
   Constant.cpp
   Context.cpp
+  Instruction.cpp
   Module.cpp
   Pass.cpp
   PassManager.cpp
diff --git a/llvm/lib/SandboxIR/Context.cpp b/llvm/lib/SandboxIR/Context.cpp
index d10cb18e6d3684..0a61e329b78c51 100644
--- a/llvm/lib/SandboxIR/Context.cpp
+++ b/llvm/lib/SandboxIR/Context.cpp
@@ -7,7 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/SandboxIR/Context.h"
-#include "llvm/SandboxIR/SandboxIR.h"
+#include "llvm/SandboxIR/Instruction.h"
+#include "llvm/SandboxIR/Module.h"
 
 namespace llvm::sandboxir {
 
@@ -670,6 +671,8 @@ Context::Context(LLVMContext &LLVMCtx)
     : LLVMCtx(LLVMCtx), IRTracker(*this),
       LLVMIRBuilder(LLVMCtx, ConstantFolder()) {}
 
+Context::~Context() {}
+
 Module *Context::getModule(llvm::Module *LLVMM) const {
   auto It = LLVMModuleToModuleMap.find(LLVMM);
   if (It != LLVMModuleToModuleMap.end())
diff --git a/llvm/lib/SandboxIR/Instruction.cpp b/llvm/lib/SandboxIR/Instruction.cpp
new file mode 100644
index 00000000000000..919a44fca8b041
--- /dev/null
+++ b/llvm/lib/SandboxIR/Instruction.cpp
@@ -0,0 +1,1965 @@
+//===- Instruction.cpp - The Instructions of Sandbox IR -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/SandboxIR/Instruction.h"
+
+namespace llvm::sandboxir {
+
+const char *Instruction::getOpcodeName(Opcode Opc) {
+  switch (Opc) {
+#define OP(OPC)                                                                \
+  case Opcode::OPC:                                                            \
+    return #OPC;
+#define OPCODES(...) __VA_ARGS__
+#define DEF_INSTR(ID, OPC, CLASS) OPC
+#include "llvm/SandboxIR/SandboxIRValues.def"
+  }
+  llvm_unreachable("Unknown Opcode");
+}
+
+llvm::Instruction *Instruction::getTopmostLLVMInstruction() const {
+  Instruction *Prev = getPrevNode();
+  if (Prev == nullptr) {
+    // If at top of the BB, return the first BB instruction.
+    return &*cast<llvm::BasicBlock>(getParent()->Val)->begin();
+  }
+  // Else get the Previous sandbox IR instruction's bottom IR instruction and
+  // return its successor.
+  llvm::Instruction *PrevBotI = cast<llvm::Instruction>(Prev->Val);
+  return PrevBotI->getNextNode();
+}
+
+BBIterator Instruction::getIterator() const {
+  auto *I = cast<llvm::Instruction>(Val);
+  return BasicBlock::iterator(I->getParent(), I->getIterator(), &Ctx);
+}
+
+Instruction *Instruction::getNextNode() const {
+  assert(getParent() != nullptr && "Detached!");
+  assert(getIterator() != getParent()->end() && "Already at end!");
+  // `Val` is the bottom-most LLVM IR instruction. Get the next in the chain,
+  // and get the corresponding sandboxir Instruction that maps to it. This works
+  // even for SandboxIR Instructions that map to more than one LLVM Instruction.
+  auto *LLVMI = cast<llvm::Instruction>(Val);
+  assert(LLVMI->getParent() != nullptr && "LLVM IR instr is detached!");
+  auto *NextLLVMI = LLVMI->getNextNode();
+  auto *NextI = cast_or_null<Instruction>(Ctx.getValue(NextLLVMI));
+  if (NextI == nullptr)
+    return nullptr;
+  return NextI;
+}
+
+Instruction *Instruction::getPrevNode() const {
+  assert(getParent() != nullptr && "Detached!");
+  auto It = getIterator();
+  if (It != getParent()->begin())
+    return std::prev(getIterator()).get();
+  return nullptr;
+}
+
+void Instruction::removeFromParent() {
+  Ctx.getTracker().emplaceIfTracking<RemoveFromParent>(this);
+
+  // Detach all the LLVM IR instructions from their parent BB.
+  for (llvm::Instruction *I : getLLVMInstrs())
+    I->removeFromParent();
+}
+
+void Instruction::eraseFromParent() {
+  assert(users().empty() && "Still connected to users, can't erase!");
+  std::unique_ptr<Value> Detached = Ctx.detach(this);
+  auto LLVMInstrs = getLLVMInstrs();
+
+  auto &Tracker = Ctx.getTracker();
+  if (Tracker.isTracking()) {
+    Tracker.track(std::make_unique<EraseFromParent>(std::move(Detached)));
+    // We don't actually delete the IR instruction, because then it would be
+    // impossible to bring it back from the dead at the same memory location.
+    // Instead we remove it from its BB and track its current location.
+    for (llvm::Instruction *I : LLVMInstrs)
+      I->removeFromParent();
+    // TODO: Multi-instructions need special treatment because some of the
+    // references are internal to the instruction.
+    for (llvm::Instruction *I : LLVMInstrs)
+      I->dropAllReferences();
+  } else {
+    // Erase in reverse to avoid erasing nstructions with attached uses.
+    for (llvm::Instruction *I : reverse(LLVMInstrs))
+      I->eraseFromParent();
+  }
+}
+
+void Instruction::moveBefore(BasicBlock &BB, const BBIterator &WhereIt) {
+  if (std::next(getIterator()) == WhereIt)
+    // Destination is same as origin, nothing to do.
+    return;
+
+  Ctx.getTracker().emplaceIfTracking<MoveInstr>(this);
+
+  auto *LLVMBB = cast<llvm::BasicBlock>(BB.Val);
+  llvm::BasicBlock::iterator It;
+  if (WhereIt == BB.end()) {
+    It = LLVMBB->end();
+  } else {
+    Instruction *WhereI = &*WhereIt;
+    It = WhereI->getTopmostLLVMInstruction()->getIterator();
+  }
+  // TODO: Move this to the verifier of sandboxir::Instruction.
+  assert(is_sorted(getLLVMInstrs(),
+                   [](auto *I1, auto *I2) { return I1->comesBefore(I2); }) &&
+         "Expected program order!");
+  // Do the actual move in LLVM IR.
+  for (auto *I : getLLVMInstrs())
+    I->moveBefore(*LLVMBB, It);
+}
+
+void Instruction::insertBefore(Instruction *BeforeI) {
+  llvm::Instruction *BeforeTopI = BeforeI->getTopmostLLVMInstruction();
+  // TODO: Move this to the verifier of sandboxir::Instruction.
+  assert(is_sorted(getLLVMInstrs(),
+                   [](auto *I1, auto *I2) { return I1->comesBefore(I2); }) &&
+         "Expected program order!");
+
+  Ctx.getTracker().emplaceIfTracking<InsertIntoBB>(this);
+
+  // Insert the LLVM IR Instructions in program order.
+  for (llvm::Instruction *I : getLLVMInstrs())
+    I->insertBefore(BeforeTopI);
+}
+
+void Instruction::insertAfter(Instruction *AfterI) {
+  insertInto(AfterI->getParent(), std::next(AfterI->getIterator()));
+}
+
+void Instruction::insertInto(BasicBlock *BB, const BBIterator &WhereIt) {
+  llvm::BasicBlock *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
+  llvm::Instruction *LLVMBeforeI;
+  llvm::BasicBlock::iterator LLVMBeforeIt;
+  Instruction *BeforeI;
+  if (WhereIt != BB->end()) {
+    BeforeI = &*WhereIt;
+    LLVMBeforeI = BeforeI->getTopmostLLVMInstruction();
+    LLVMBeforeIt = LLVMBeforeI->getIterator();
+  } else {
+    BeforeI = nullptr;
+    LLVMBeforeI = nullptr;
+    LLVMBeforeIt = LLVMBB->end();
+  }
+
+  Ctx.getTracker().emplaceIfTracking<InsertIntoBB>(this);
+
+  // Insert the LLVM IR Instructions in program order.
+  for (llvm::Instruction *I : getLLVMInstrs())
+    I->insertInto(LLVMBB, LLVMBeforeIt);
+}
+
+BasicBlock *Instruction::getParent() const {
+  // Get the LLVM IR Instruction that this maps to, get its parent, and get the
+  // corresponding sandboxir::BasicBlock by looking it up in sandboxir::Context.
+  auto *BB = cast<llvm::Instruction>(Val)->getParent();
+  if (BB == nullptr)
+    return nullptr;
+  return cast<BasicBlock>(Ctx.getValue(BB));
+}
+
+bool Instruction::classof(const sandboxir::Value *From) {
+  switch (From->getSubclassID()) {
+#define DEF_INSTR(ID, OPC, CLASS)                                              \
+  case ClassID::ID:                                                            \
+    return true;
+#include "llvm/SandboxIR/SandboxIRValues.def"
+  default:
+    return false;
+  }
+}
+
+void Instruction::setHasNoUnsignedWrap(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::hasNoUnsignedWrap,
+                                       &Instruction::setHasNoUnsignedWrap>>(
+          this);
+  cast<llvm::Instruction>(Val)->setHasNoUnsignedWrap(B);
+}
+
+void Instruction::setHasNoSignedWrap(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::hasNoSignedWrap,
+                                       &Instruction::setHasNoSignedWrap>>(this);
+  cast<llvm::Instruction>(Val)->setHasNoSignedWrap(B);
+}
+
+void Instruction::setFast(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&Instruction::isFast, &Instruction::setFast>>(this);
+  cast<llvm::Instruction>(Val)->setFast(B);
+}
+
+void Instruction::setIsExact(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&Instruction::isExact, &Instruction::setIsExact>>(this);
+  cast<llvm::Instruction>(Val)->setIsExact(B);
+}
+
+void Instruction::setHasAllowReassoc(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::hasAllowReassoc,
+                                       &Instruction::setHasAllowReassoc>>(this);
+  cast<llvm::Instruction>(Val)->setHasAllowReassoc(B);
+}
+
+void Instruction::setHasNoNaNs(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&Instruction::hasNoNaNs, &Instruction::setHasNoNaNs>>(
+          this);
+  cast<llvm::Instruction>(Val)->setHasNoNaNs(B);
+}
+
+void Instruction::setHasNoInfs(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&Instruction::hasNoInfs, &Instruction::setHasNoInfs>>(
+          this);
+  cast<llvm::Instruction>(Val)->setHasNoInfs(B);
+}
+
+void Instruction::setHasNoSignedZeros(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::hasNoSignedZeros,
+                                       &Instruction::setHasNoSignedZeros>>(
+          this);
+  cast<llvm::Instruction>(Val)->setHasNoSignedZeros(B);
+}
+
+void Instruction::setHasAllowReciprocal(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::hasAllowReciprocal,
+                                       &Instruction::setHasAllowReciprocal>>(
+          this);
+  cast<llvm::Instruction>(Val)->setHasAllowReciprocal(B);
+}
+
+void Instruction::setHasAllowContract(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::hasAllowContract,
+                                       &Instruction::setHasAllowContract>>(
+          this);
+  cast<llvm::Instruction>(Val)->setHasAllowContract(B);
+}
+
+void Instruction::setFastMathFlags(FastMathFlags FMF) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::getFastMathFlags,
+                                       &Instruction::copyFastMathFlags>>(this);
+  cast<llvm::Instruction>(Val)->setFastMathFlags(FMF);
+}
+
+void Instruction::copyFastMathFlags(FastMathFlags FMF) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::getFastMathFlags,
+                                       &Instruction::copyFastMathFlags>>(this);
+  cast<llvm::Instruction>(Val)->copyFastMathFlags(FMF);
+}
+
+Type *Instruction::getAccessType() const {
+  return Ctx.getType(cast<llvm::Instruction>(Val)->getAccessType());
+}
+
+void Instruction::setHasApproxFunc(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&Instruction::hasApproxFunc,
+                                       &Instruction::setHasApproxFunc>>(this);
+  cast<llvm::Instruction>(Val)->setHasApproxFunc(B);
+}
+
+#ifndef NDEBUG
+void Instruction::dumpOS(raw_ostream &OS) const {
+  OS << "Unimplemented! Please override dump().";
+}
+#endif // NDEBUG
+
+VAArgInst *VAArgInst::create(Value *List, Type *Ty, BBIterator WhereIt,
+                             BasicBlock *WhereBB, Context &Ctx,
+                             const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  auto *LLVMI =
+      cast<llvm::VAArgInst>(Builder.CreateVAArg(List->Val, Ty->LLVMTy, Name));
+  return Ctx.createVAArgInst(LLVMI);
+}
+
+Value *VAArgInst::getPointerOperand() {
+  return Ctx.getValue(cast<llvm::VAArgInst>(Val)->getPointerOperand());
+}
+
+FreezeInst *FreezeInst::create(Value *V, BBIterator WhereIt,
+                               BasicBlock *WhereBB, Context &Ctx,
+                               const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  auto *LLVMI = cast<llvm::FreezeInst>(Builder.CreateFreeze(V->Val, Name));
+  return Ctx.createFreezeInst(LLVMI);
+}
+
+FenceInst *FenceInst::create(AtomicOrdering Ordering, BBIterator WhereIt,
+                             BasicBlock *WhereBB, Context &Ctx,
+                             SyncScope::ID SSID) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  llvm::FenceInst *LLVMI = Builder.CreateFence(Ordering, SSID);
+  return Ctx.createFenceInst(LLVMI);
+}
+
+void FenceInst::setOrdering(AtomicOrdering Ordering) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&FenceInst::getOrdering, &FenceInst::setOrdering>>(
+          this);
+  cast<llvm::FenceInst>(Val)->setOrdering(Ordering);
+}
+
+void FenceInst::setSyncScopeID(SyncScope::ID SSID) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&FenceInst::getSyncScopeID,
+                                       &FenceInst::setSyncScopeID>>(this);
+  cast<llvm::FenceInst>(Val)->setSyncScopeID(SSID);
+}
+
+Value *SelectInst::createCommon(Value *Cond, Value *True, Value *False,
+                                const Twine &Name, IRBuilder<> &Builder,
+                                Context &Ctx) {
+  llvm::Value *NewV =
+      Builder.CreateSelect(Cond->Val, True->Val, False->Val, Name);
+  if (auto *NewSI = dyn_cast<llvm::SelectInst>(NewV))
+    return Ctx.createSelectInst(NewSI);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *SelectInst::create(Value *Cond, Value *True, Value *False,
+                          Instruction *InsertBefore, Context &Ctx,
+                          const Twine &Name) {
+  llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(BeforeIR);
+  return createCommon(Cond, True, False, Name, Builder, Ctx);
+}
+
+Value *SelectInst::create(Value *Cond, Value *True, Value *False,
+                          BasicBlock *InsertAtEnd, Context &Ctx,
+                          const Twine &Name) {
+  auto *IRInsertAtEnd = cast<llvm::BasicBlock>(InsertAtEnd->Val);
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(IRInsertAtEnd);
+  return createCommon(Cond, True, False, Name, Builder, Ctx);
+}
+
+void SelectInst::swapValues() {
+  Ctx.getTracker().emplaceIfTracking<UseSwap>(getOperandUse(1),
+                                              getOperandUse(2));
+  cast<llvm::SelectInst>(Val)->swapValues();
+}
+
+bool SelectInst::classof(const Value *From) {
+  return From->getSubclassID() == ClassID::Select;
+}
+
+BranchInst *BranchInst::create(BasicBlock *IfTrue, Instruction *InsertBefore,
+                               Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
+  Builder.SetInsertPoint(cast<llvm::Instruction>(LLVMBefore));
+  llvm::BranchInst *NewBr =
+      Builder.CreateBr(cast<llvm::BasicBlock>(IfTrue->Val));
+  return Ctx.createBranchInst(NewBr);
+}
+
+BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd,
+                               Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::BranchInst *NewBr =
+      Builder.CreateBr(cast<llvm::BasicBlock>(IfTrue->Val));
+  return Ctx.createBranchInst(NewBr);
+}
+
+BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *IfFalse,
+                               Value *Cond, Instruction *InsertBefore,
+                               Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
+  Builder.SetInsertPoint(LLVMBefore);
+  llvm::BranchInst *NewBr =
+      Builder.CreateCondBr(Cond->Val, cast<llvm::BasicBlock>(IfTrue->Val),
+                           cast<llvm::BasicBlock>(IfFalse->Val));
+  return Ctx.createBranchInst(NewBr);
+}
+
+BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *IfFalse,
+                               Value *Cond, BasicBlock *InsertAtEnd,
+                               Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::BranchInst *NewBr =
+      Builder.CreateCondBr(Cond->Val, cast<llvm::BasicBlock>(IfTrue->Val),
+                           cast<llvm::BasicBlock>(IfFalse->Val));
+  return Ctx.createBranchInst(NewBr);
+}
+
+bool BranchInst::classof(const Value *From) {
+  return From->getSubclassID() == ClassID::Br;
+}
+
+Value *BranchInst::getCondition() const {
+  assert(isConditional() && "Cannot get condition of an uncond branch!");
+  return Ctx.getValue(cast<llvm::BranchInst>(Val)->getCondition());
+}
+
+BasicBlock *BranchInst::getSuccessor(unsigned SuccIdx) const {
+  assert(SuccIdx < getNumSuccessors() &&
+         "Successor # out of range for Branch!");
+  return cast_or_null<BasicBlock>(
+      Ctx.getValue(cast<llvm::BranchInst>(Val)->getSuccessor(SuccIdx)));
+}
+
+void BranchInst::setSuccessor(unsigned Idx, BasicBlock *NewSucc) {
+  assert((Idx == 0 || Idx == 1) && "Out of bounds!");
+  setOperand(2u - Idx, NewSucc);
+}
+
+BasicBlock *BranchInst::LLVMBBToSBBB::operator()(llvm::BasicBlock *BB) const {
+  return cast<BasicBlock>(Ctx.getValue(BB));
+}
+const BasicBlock *
+BranchInst::ConstLLVMBBToSBBB::operator()(const llvm::BasicBlock *BB) const {
+  return cast<BasicBlock>(Ctx.getValue(BB));
+}
+
+void LoadInst::setVolatile(bool V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&LoadInst::isVolatile, &LoadInst::setVolatile>>(this);
+  cast<llvm::LoadInst>(Val)->setVolatile(V);
+}
+
+LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
+                           Instruction *InsertBefore, Context &Ctx,
+                           const Twine &Name) {
+  return create(Ty, Ptr, Align, InsertBefore, /*IsVolatile=*/false, Ctx, Name);
+}
+
+LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
+                           Instruction *InsertBefore, bool IsVolatile,
+                           Context &Ctx, const Twine &Name) {
+  llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(BeforeIR);
+  auto *NewLI =
+      Builder.CreateAlignedLoad(Ty->LLVMTy, Ptr->Val, Align, IsVolatile, Name);
+  auto *NewSBI = Ctx.createLoadInst(NewLI);
+  return NewSBI;
+}
+
+LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
+                           BasicBlock *InsertAtEnd, Context &Ctx,
+                           const Twine &Name) {
+  return create(Ty, Ptr, Align, InsertAtEnd, /*IsVolatile=*/false, Ctx, Name);
+}
+
+LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
+                           BasicBlock *InsertAtEnd, bool IsVolatile,
+                           Context &Ctx, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  auto *NewLI =
+      Builder.CreateAlignedLoad(Ty->LLVMTy, Ptr->Val, Align, IsVolatile, Name);
+  auto *NewSBI = Ctx.createLoadInst(NewLI);
+  return NewSBI;
+}
+
+bool LoadInst::classof(const Value *From) {
+  return From->getSubclassID() == ClassID::Load;
+}
+
+Value *LoadInst::getPointerOperand() const {
+  return Ctx.getValue(cast<llvm::LoadInst>(Val)->getPointerOperand());
+}
+
+void StoreInst::setVolatile(bool V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&StoreInst::isVolatile, &StoreInst::setVolatile>>(this);
+  cast<llvm::StoreInst>(Val)->setVolatile(V);
+}
+
+StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
+                             Instruction *InsertBefore, Context &Ctx) {
+  return create(V, Ptr, Align, InsertBefore, /*IsVolatile=*/false, Ctx);
+}
+
+StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
+                             Instruction *InsertBefore, bool IsVolatile,
+                             Context &Ctx) {
+  llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(BeforeIR);
+  auto *NewSI = Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, IsVolatile);
+  auto *NewSBI = Ctx.createStoreInst(NewSI);
+  return NewSBI;
+}
+
+StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
+                             BasicBlock *InsertAtEnd, Context &Ctx) {
+  return create(V, Ptr, Align, InsertAtEnd, /*IsVolatile=*/false, Ctx);
+}
+
+StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
+                             BasicBlock *InsertAtEnd, bool IsVolatile,
+                             Context &Ctx) {
+  auto *InsertAtEndIR = cast<llvm::BasicBlock>(InsertAtEnd->Val);
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(InsertAtEndIR);
+  auto *NewSI = Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, IsVolatile);
+  auto *NewSBI = Ctx.createStoreInst(NewSI);
+  return NewSBI;
+}
+
+bool StoreInst::classof(const Value *From) {
+  return From->getSubclassID() == ClassID::Store;
+}
+
+Value *StoreInst::getValueOperand() const {
+  return Ctx.getValue(cast<llvm::StoreInst>(Val)->getValueOperand());
+}
+
+Value *StoreInst::getPointerOperand() const {
+  return Ctx.getValue(cast<llvm::StoreInst>(Val)->getPointerOperand());
+}
+
+UnreachableInst *UnreachableInst::create(Instruction *InsertBefore,
+                                         Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
+  Builder.SetInsertPoint(LLVMBefore);
+  llvm::UnreachableInst *NewUI = Builder.CreateUnreachable();
+  return Ctx.createUnreachableInst(NewUI);
+}
+
+UnreachableInst *UnreachableInst::create(BasicBlock *InsertAtEnd,
+                                         Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::UnreachableInst *NewUI = Builder.CreateUnreachable();
+  return Ctx.createUnreachableInst(NewUI);
+}
+
+bool UnreachableInst::classof(const Value *From) {
+  return From->getSubclassID() == ClassID::Unreachable;
+}
+
+ReturnInst *ReturnInst::createCommon(Value *RetVal, IRBuilder<> &Builder,
+                                     Context &Ctx) {
+  llvm::ReturnInst *NewRI;
+  if (RetVal != nullptr)
+    NewRI = Builder.CreateRet(RetVal->Val);
+  else
+    NewRI = Builder.CreateRetVoid();
+  return Ctx.createReturnInst(NewRI);
+}
+
+ReturnInst *ReturnInst::create(Value *RetVal, Instruction *InsertBefore,
+                               Context &Ctx) {
+  llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(BeforeIR);
+  return createCommon(RetVal, Builder, Ctx);
+}
+
+ReturnInst *ReturnInst::create(Value *RetVal, BasicBlock *InsertAtEnd,
+                               Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  return createCommon(RetVal, Builder, Ctx);
+}
+
+Value *ReturnInst::getReturnValue() const {
+  auto *LLVMRetVal = cast<llvm::ReturnInst>(Val)->getReturnValue();
+  return LLVMRetVal != nullptr ? Ctx.getValue(LLVMRetVal) : nullptr;
+}
+
+FunctionType *CallBase::getFunctionType() const {
+  return cast<FunctionType>(
+      Ctx.getType(cast<llvm::CallBase>(Val)->getFunctionType()));
+}
+
+Value *CallBase::getCalledOperand() const {
+  return Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledOperand());
+}
+
+Use CallBase::getCalledOperandUse() const {
+  llvm::Use *LLVMUse = &cast<llvm::CallBase>(Val)->getCalledOperandUse();
+  return Use(LLVMUse, cast<User>(Ctx.getValue(LLVMUse->getUser())), Ctx);
+}
+
+Function *CallBase::getCalledFunction() const {
+  return cast_or_null<Function>(
+      Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledFunction()));
+}
+Function *CallBase::getCaller() {
+  return cast<Function>(Ctx.getValue(cast<llvm::CallBase>(Val)->getCaller()));
+}
+
+void CallBase::setCalledFunction(Function *F) {
+  // F's function type is private, so we rely on `setCalledFunction()` to update
+  // it. But even though we are calling `setCalledFunction()` we also need to
+  // track this change at the SandboxIR level, which is why we call
+  // `setCalledOperand()` here.
+  // Note: This may break if `setCalledFunction()` early returns if `F`
+  // is already set, but we do have a unit test for it.
+  setCalledOperand(F);
+  cast<llvm::CallBase>(Val)->setCalledFunction(
+      cast<llvm::FunctionType>(F->getFunctionType()->LLVMTy),
+      cast<llvm::Function>(F->Val));
+}
+
+CallInst *CallInst::create(FunctionType *FTy, Value *Func,
+                           ArrayRef<Value *> Args, BasicBlock::iterator WhereIt,
+                           BasicBlock *WhereBB, Context &Ctx,
+                           const Twine &NameStr) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  SmallVector<llvm::Value *> LLVMArgs;
+  LLVMArgs.reserve(Args.size());
+  for (Value *Arg : Args)
+    LLVMArgs.push_back(Arg->Val);
+  llvm::CallInst *NewCI = Builder.CreateCall(
+      cast<llvm::FunctionType>(FTy->LLVMTy), Func->Val, LLVMArgs, NameStr);
+  return Ctx.createCallInst(NewCI);
+}
+
+CallInst *CallInst::create(FunctionType *FTy, Value *Func,
+                           ArrayRef<Value *> Args, Instruction *InsertBefore,
+                           Context &Ctx, const Twine &NameStr) {
+  return CallInst::create(FTy, Func, Args, InsertBefore->getIterator(),
+                          InsertBefore->getParent(), Ctx, NameStr);
+}
+
+CallInst *CallInst::create(FunctionType *FTy, Value *Func,
+                           ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
+                           Context &Ctx, const Twine &NameStr) {
+  return CallInst::create(FTy, Func, Args, InsertAtEnd->end(), InsertAtEnd, Ctx,
+                          NameStr);
+}
+
+InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
+                               BasicBlock *IfNormal, BasicBlock *IfException,
+                               ArrayRef<Value *> Args, BBIterator WhereIt,
+                               BasicBlock *WhereBB, Context &Ctx,
+                               const Twine &NameStr) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  SmallVector<llvm::Value *> LLVMArgs;
+  LLVMArgs.reserve(Args.size());
+  for (Value *Arg : Args)
+    LLVMArgs.push_back(Arg->Val);
+  llvm::InvokeInst *Invoke = Builder.CreateInvoke(
+      cast<llvm::FunctionType>(FTy->LLVMTy), Func->Val,
+      cast<llvm::BasicBlock>(IfNormal->Val),
+      cast<llvm::BasicBlock>(IfException->Val), LLVMArgs, NameStr);
+  return Ctx.createInvokeInst(Invoke);
+}
+
+InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
+                               BasicBlock *IfNormal, BasicBlock *IfException,
+                               ArrayRef<Value *> Args,
+                               Instruction *InsertBefore, Context &Ctx,
+                               const Twine &NameStr) {
+  return create(FTy, Func, IfNormal, IfException, Args,
+                InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
+                NameStr);
+}
+
+InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
+                               BasicBlock *IfNormal, BasicBlock *IfException,
+                               ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
+                               Context &Ctx, const Twine &NameStr) {
+  return create(FTy, Func, IfNormal, IfException, Args, InsertAtEnd->end(),
+                InsertAtEnd, Ctx, NameStr);
+}
+
+BasicBlock *InvokeInst::getNormalDest() const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::InvokeInst>(Val)->getNormalDest()));
+}
+BasicBlock *InvokeInst::getUnwindDest() const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::InvokeInst>(Val)->getUnwindDest()));
+}
+void InvokeInst::setNormalDest(BasicBlock *BB) {
+  setOperand(1, BB);
+  assert(getNormalDest() == BB && "LLVM IR uses a different operan index!");
+}
+void InvokeInst::setUnwindDest(BasicBlock *BB) {
+  setOperand(2, BB);
+  assert(getUnwindDest() == BB && "LLVM IR uses a different operan index!");
+}
+LandingPadInst *InvokeInst::getLandingPadInst() const {
+  return cast<LandingPadInst>(
+      Ctx.getValue(cast<llvm::InvokeInst>(Val)->getLandingPadInst()));
+  ;
+}
+BasicBlock *InvokeInst::getSuccessor(unsigned SuccIdx) const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::InvokeInst>(Val)->getSuccessor(SuccIdx)));
+}
+
+CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
+                               BasicBlock *DefaultDest,
+                               ArrayRef<BasicBlock *> IndirectDests,
+                               ArrayRef<Value *> Args, BBIterator WhereIt,
+                               BasicBlock *WhereBB, Context &Ctx,
+                               const Twine &NameStr) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+
+  SmallVector<llvm::BasicBlock *> LLVMIndirectDests;
+  LLVMIndirectDests.reserve(IndirectDests.size());
+  for (BasicBlock *IndDest : IndirectDests)
+    LLVMIndirectDests.push_back(cast<llvm::BasicBlock>(IndDest->Val));
+
+  SmallVector<llvm::Value *> LLVMArgs;
+  LLVMArgs.reserve(Args.size());
+  for (Value *Arg : Args)
+    LLVMArgs.push_back(Arg->Val);
+
+  llvm::CallBrInst *CallBr =
+      Builder.CreateCallBr(cast<llvm::FunctionType>(FTy->LLVMTy), Func->Val,
+                           cast<llvm::BasicBlock>(DefaultDest->Val),
+                           LLVMIndirectDests, LLVMArgs, NameStr);
+  return Ctx.createCallBrInst(CallBr);
+}
+
+CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
+                               BasicBlock *DefaultDest,
+                               ArrayRef<BasicBlock *> IndirectDests,
+                               ArrayRef<Value *> Args,
+                               Instruction *InsertBefore, Context &Ctx,
+                               const Twine &NameStr) {
+  return create(FTy, Func, DefaultDest, IndirectDests, Args,
+                InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
+                NameStr);
+}
+CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
+                               BasicBlock *DefaultDest,
+                               ArrayRef<BasicBlock *> IndirectDests,
+                               ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
+                               Context &Ctx, const Twine &NameStr) {
+  return create(FTy, Func, DefaultDest, IndirectDests, Args, InsertAtEnd->end(),
+                InsertAtEnd, Ctx, NameStr);
+}
+
+Value *CallBrInst::getIndirectDestLabel(unsigned Idx) const {
+  return Ctx.getValue(cast<llvm::CallBrInst>(Val)->getIndirectDestLabel(Idx));
+}
+Value *CallBrInst::getIndirectDestLabelUse(unsigned Idx) const {
+  return Ctx.getValue(
+      cast<llvm::CallBrInst>(Val)->getIndirectDestLabelUse(Idx));
+}
+BasicBlock *CallBrInst::getDefaultDest() const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::CallBrInst>(Val)->getDefaultDest()));
+}
+BasicBlock *CallBrInst::getIndirectDest(unsigned Idx) const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::CallBrInst>(Val)->getIndirectDest(Idx)));
+}
+llvm::SmallVector<BasicBlock *, 16> CallBrInst::getIndirectDests() const {
+  SmallVector<BasicBlock *, 16> BBs;
+  for (llvm::BasicBlock *LLVMBB :
+       cast<llvm::CallBrInst>(Val)->getIndirectDests())
+    BBs.push_back(cast<BasicBlock>(Ctx.getValue(LLVMBB)));
+  return BBs;
+}
+void CallBrInst::setDefaultDest(BasicBlock *BB) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&CallBrInst::getDefaultDest,
+                                       &CallBrInst::setDefaultDest>>(this);
+  cast<llvm::CallBrInst>(Val)->setDefaultDest(cast<llvm::BasicBlock>(BB->Val));
+}
+void CallBrInst::setIndirectDest(unsigned Idx, BasicBlock *BB) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetterWithIdx<&CallBrInst::getIndirectDest,
+                                              &CallBrInst::setIndirectDest>>(
+          this, Idx);
+  cast<llvm::CallBrInst>(Val)->setIndirectDest(Idx,
+                                               cast<llvm::BasicBlock>(BB->Val));
+}
+BasicBlock *CallBrInst::getSuccessor(unsigned Idx) const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::CallBrInst>(Val)->getSuccessor(Idx)));
+}
+
+LandingPadInst *LandingPadInst::create(Type *RetTy, unsigned NumReservedClauses,
+                                       BBIterator WhereIt, BasicBlock *WhereBB,
+                                       Context &Ctx, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  llvm::LandingPadInst *LLVMI =
+      Builder.CreateLandingPad(RetTy->LLVMTy, NumReservedClauses, Name);
+  return Ctx.createLandingPadInst(LLVMI);
+}
+
+void LandingPadInst::setCleanup(bool V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&LandingPadInst::isCleanup,
+                                       &LandingPadInst::setCleanup>>(this);
+  cast<llvm::LandingPadInst>(Val)->setCleanup(V);
+}
+
+Constant *LandingPadInst::getClause(unsigned Idx) const {
+  return cast<Constant>(
+      Ctx.getValue(cast<llvm::LandingPadInst>(Val)->getClause(Idx)));
+}
+
+Value *FuncletPadInst::getParentPad() const {
+  return Ctx.getValue(cast<llvm::FuncletPadInst>(Val)->getParentPad());
+}
+
+void FuncletPadInst::setParentPad(Value *ParentPad) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&FuncletPadInst::getParentPad,
+                                       &FuncletPadInst::setParentPad>>(this);
+  cast<llvm::FuncletPadInst>(Val)->setParentPad(ParentPad->Val);
+}
+
+Value *FuncletPadInst::getArgOperand(unsigned Idx) const {
+  return Ctx.getValue(cast<llvm::FuncletPadInst>(Val)->getArgOperand(Idx));
+}
+
+void FuncletPadInst::setArgOperand(unsigned Idx, Value *V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetterWithIdx<&FuncletPadInst::getArgOperand,
+                                              &FuncletPadInst::setArgOperand>>(
+          this, Idx);
+  cast<llvm::FuncletPadInst>(Val)->setArgOperand(Idx, V->Val);
+}
+
+CatchSwitchInst *CatchPadInst::getCatchSwitch() const {
+  return cast<CatchSwitchInst>(
+      Ctx.getValue(cast<llvm::CatchPadInst>(Val)->getCatchSwitch()));
+}
+
+CatchPadInst *CatchPadInst::create(Value *ParentPad, ArrayRef<Value *> Args,
+                                   BBIterator WhereIt, BasicBlock *WhereBB,
+                                   Context &Ctx, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  SmallVector<llvm::Value *> LLVMArgs;
+  LLVMArgs.reserve(Args.size());
+  for (auto *Arg : Args)
+    LLVMArgs.push_back(Arg->Val);
+  llvm::CatchPadInst *LLVMI =
+      Builder.CreateCatchPad(ParentPad->Val, LLVMArgs, Name);
+  return Ctx.createCatchPadInst(LLVMI);
+}
+
+CleanupPadInst *CleanupPadInst::create(Value *ParentPad, ArrayRef<Value *> Args,
+                                       BBIterator WhereIt, BasicBlock *WhereBB,
+                                       Context &Ctx, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  SmallVector<llvm::Value *> LLVMArgs;
+  LLVMArgs.reserve(Args.size());
+  for (auto *Arg : Args)
+    LLVMArgs.push_back(Arg->Val);
+  llvm::CleanupPadInst *LLVMI =
+      Builder.CreateCleanupPad(ParentPad->Val, LLVMArgs, Name);
+  return Ctx.createCleanupPadInst(LLVMI);
+}
+
+CatchReturnInst *CatchReturnInst::create(CatchPadInst *CatchPad, BasicBlock *BB,
+                                         BBIterator WhereIt,
+                                         BasicBlock *WhereBB, Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  llvm::CatchReturnInst *LLVMI = Builder.CreateCatchRet(
+      cast<llvm::CatchPadInst>(CatchPad->Val), cast<llvm::BasicBlock>(BB->Val));
+  return Ctx.createCatchReturnInst(LLVMI);
+}
+
+CatchPadInst *CatchReturnInst::getCatchPad() const {
+  return cast<CatchPadInst>(
+      Ctx.getValue(cast<llvm::CatchReturnInst>(Val)->getCatchPad()));
+}
+
+void CatchReturnInst::setCatchPad(CatchPadInst *CatchPad) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&CatchReturnInst::getCatchPad,
+                                       &CatchReturnInst::setCatchPad>>(this);
+  cast<llvm::CatchReturnInst>(Val)->setCatchPad(
+      cast<llvm::CatchPadInst>(CatchPad->Val));
+}
+
+BasicBlock *CatchReturnInst::getSuccessor() const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::CatchReturnInst>(Val)->getSuccessor()));
+}
+
+void CatchReturnInst::setSuccessor(BasicBlock *NewSucc) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&CatchReturnInst::getSuccessor,
+                                       &CatchReturnInst::setSuccessor>>(this);
+  cast<llvm::CatchReturnInst>(Val)->setSuccessor(
+      cast<llvm::BasicBlock>(NewSucc->Val));
+}
+
+Value *CatchReturnInst::getCatchSwitchParentPad() const {
+  return Ctx.getValue(
+      cast<llvm::CatchReturnInst>(Val)->getCatchSwitchParentPad());
+}
+
+CleanupReturnInst *CleanupReturnInst::create(CleanupPadInst *CleanupPad,
+                                             BasicBlock *UnwindBB,
+                                             BBIterator WhereIt,
+                                             BasicBlock *WhereBB,
+                                             Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  auto *LLVMUnwindBB =
+      UnwindBB != nullptr ? cast<llvm::BasicBlock>(UnwindBB->Val) : nullptr;
+  llvm::CleanupReturnInst *LLVMI = Builder.CreateCleanupRet(
+      cast<llvm::CleanupPadInst>(CleanupPad->Val), LLVMUnwindBB);
+  return Ctx.createCleanupReturnInst(LLVMI);
+}
+
+CleanupPadInst *CleanupReturnInst::getCleanupPad() const {
+  return cast<CleanupPadInst>(
+      Ctx.getValue(cast<llvm::CleanupReturnInst>(Val)->getCleanupPad()));
+}
+
+void CleanupReturnInst::setCleanupPad(CleanupPadInst *CleanupPad) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&CleanupReturnInst::getCleanupPad,
+                                       &CleanupReturnInst::setCleanupPad>>(
+          this);
+  cast<llvm::CleanupReturnInst>(Val)->setCleanupPad(
+      cast<llvm::CleanupPadInst>(CleanupPad->Val));
+}
+
+BasicBlock *CleanupReturnInst::getUnwindDest() const {
+  return cast_or_null<BasicBlock>(
+      Ctx.getValue(cast<llvm::CleanupReturnInst>(Val)->getUnwindDest()));
+}
+
+void CleanupReturnInst::setUnwindDest(BasicBlock *NewDest) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&CleanupReturnInst::getUnwindDest,
+                                       &CleanupReturnInst::setUnwindDest>>(
+          this);
+  cast<llvm::CleanupReturnInst>(Val)->setUnwindDest(
+      cast<llvm::BasicBlock>(NewDest->Val));
+}
+
+Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
+                                 ArrayRef<Value *> IdxList,
+                                 BasicBlock::iterator WhereIt,
+                                 BasicBlock *WhereBB, Context &Ctx,
+                                 const Twine &NameStr) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  SmallVector<llvm::Value *> LLVMIdxList;
+  LLVMIdxList.reserve(IdxList.size());
+  for (Value *Idx : IdxList)
+    LLVMIdxList.push_back(Idx->Val);
+  llvm::Value *NewV =
+      Builder.CreateGEP(Ty->LLVMTy, Ptr->Val, LLVMIdxList, NameStr);
+  if (auto *NewGEP = dyn_cast<llvm::GetElementPtrInst>(NewV))
+    return Ctx.createGetElementPtrInst(NewGEP);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
+                                 ArrayRef<Value *> IdxList,
+                                 Instruction *InsertBefore, Context &Ctx,
+                                 const Twine &NameStr) {
+  return GetElementPtrInst::create(Ty, Ptr, IdxList,
+                                   InsertBefore->getIterator(),
+                                   InsertBefore->getParent(), Ctx, NameStr);
+}
+
+Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
+                                 ArrayRef<Value *> IdxList,
+                                 BasicBlock *InsertAtEnd, Context &Ctx,
+                                 const Twine &NameStr) {
+  return GetElementPtrInst::create(Ty, Ptr, IdxList, InsertAtEnd->end(),
+                                   InsertAtEnd, Ctx, NameStr);
+}
+
+Type *GetElementPtrInst::getSourceElementType() const {
+  return Ctx.getType(
+      cast<llvm::GetElementPtrInst>(Val)->getSourceElementType());
+}
+
+Type *GetElementPtrInst::getResultElementType() const {
+  return Ctx.getType(
+      cast<llvm::GetElementPtrInst>(Val)->getResultElementType());
+}
+
+Value *GetElementPtrInst::getPointerOperand() const {
+  return Ctx.getValue(cast<llvm::GetElementPtrInst>(Val)->getPointerOperand());
+}
+
+Type *GetElementPtrInst::getPointerOperandType() const {
+  return Ctx.getType(
+      cast<llvm::GetElementPtrInst>(Val)->getPointerOperandType());
+}
+
+BasicBlock *PHINode::LLVMBBToBB::operator()(llvm::BasicBlock *LLVMBB) const {
+  return cast<BasicBlock>(Ctx.getValue(LLVMBB));
+}
+
+PHINode *PHINode::create(Type *Ty, unsigned NumReservedValues,
+                         Instruction *InsertBefore, Context &Ctx,
+                         const Twine &Name) {
+  llvm::PHINode *NewPHI = llvm::PHINode::Create(
+      Ty->LLVMTy, NumReservedValues, Name,
+      InsertBefore->getTopmostLLVMInstruction()->getIterator());
+  return Ctx.createPHINode(NewPHI);
+}
+
+bool PHINode::classof(const Value *From) {
+  return From->getSubclassID() == ClassID::PHI;
+}
+
+Value *PHINode::getIncomingValue(unsigned Idx) const {
+  return Ctx.getValue(cast<llvm::PHINode>(Val)->getIncomingValue(Idx));
+}
+void PHINode::setIncomingValue(unsigned Idx, Value *V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetterWithIdx<&PHINode::getIncomingValue,
+                                              &PHINode::setIncomingValue>>(this,
+                                                                           Idx);
+  cast<llvm::PHINode>(Val)->setIncomingValue(Idx, V->Val);
+}
+BasicBlock *PHINode::getIncomingBlock(unsigned Idx) const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::PHINode>(Val)->getIncomingBlock(Idx)));
+}
+BasicBlock *PHINode::getIncomingBlock(const Use &U) const {
+  llvm::Use *LLVMUse = U.LLVMUse;
+  llvm::BasicBlock *BB = cast<llvm::PHINode>(Val)->getIncomingBlock(*LLVMUse);
+  return cast<BasicBlock>(Ctx.getValue(BB));
+}
+void PHINode::setIncomingBlock(unsigned Idx, BasicBlock *BB) {
+  // Helper to disambiguate PHINode::getIncomingBlock(unsigned).
+  constexpr BasicBlock *(PHINode::*GetIncomingBlockFn)(unsigned) const =
+      &PHINode::getIncomingBlock;
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetterWithIdx<GetIncomingBlockFn, &PHINode::setIncomingBlock>>(
+          this, Idx);
+  cast<llvm::PHINode>(Val)->setIncomingBlock(Idx,
+                                             cast<llvm::BasicBlock>(BB->Val));
+}
+void PHINode::addIncoming(Value *V, BasicBlock *BB) {
+  auto &Tracker = Ctx.getTracker();
+  Tracker.emplaceIfTracking<PHIAddIncoming>(this);
+
+  cast<llvm::PHINode>(Val)->addIncoming(V->Val,
+                                        cast<llvm::BasicBlock>(BB->Val));
+}
+Value *PHINode::removeIncomingValue(unsigned Idx) {
+  auto &Tracker = Ctx.getTracker();
+  Tracker.emplaceIfTracking<PHIRemoveIncoming>(this, Idx);
+  llvm::Value *LLVMV =
+      cast<llvm::PHINode>(Val)->removeIncomingValue(Idx,
+                                                    /*DeletePHIIfEmpty=*/false);
+  return Ctx.getValue(LLVMV);
+}
+Value *PHINode::removeIncomingValue(BasicBlock *BB) {
+  auto &Tracker = Ctx.getTracker();
+  Tracker.emplaceIfTracking<PHIRemoveIncoming>(this, getBasicBlockIndex(BB));
+
+  auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
+  llvm::Value *LLVMV =
+      cast<llvm::PHINode>(Val)->removeIncomingValue(LLVMBB,
+                                                    /*DeletePHIIfEmpty=*/false);
+  return Ctx.getValue(LLVMV);
+}
+int PHINode::getBasicBlockIndex(const BasicBlock *BB) const {
+  auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
+  return cast<llvm::PHINode>(Val)->getBasicBlockIndex(LLVMBB);
+}
+Value *PHINode::getIncomingValueForBlock(const BasicBlock *BB) const {
+  auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
+  llvm::Value *LLVMV =
+      cast<llvm::PHINode>(Val)->getIncomingValueForBlock(LLVMBB);
+  return Ctx.getValue(LLVMV);
+}
+Value *PHINode::hasConstantValue() const {
+  llvm::Value *LLVMV = cast<llvm::PHINode>(Val)->hasConstantValue();
+  return LLVMV != nullptr ? Ctx.getValue(LLVMV) : nullptr;
+}
+void PHINode::replaceIncomingBlockWith(const BasicBlock *Old, BasicBlock *New) {
+  assert(New && Old && "Sandbox IR PHI node got a null basic block!");
+  for (unsigned Idx = 0, NumOps = cast<llvm::PHINode>(Val)->getNumOperands();
+       Idx != NumOps; ++Idx)
+    if (getIncomingBlock(Idx) == Old)
+      setIncomingBlock(Idx, New);
+}
+void PHINode::removeIncomingValueIf(function_ref<bool(unsigned)> Predicate) {
+  // Avoid duplicate tracking by going through this->removeIncomingValue here at
+  // the expense of some performance. Copy PHI::removeIncomingValueIf more
+  // directly if performance becomes an issue.
+
+  // Removing the element at index X, moves the element previously at X + 1
+  // to X. Working from the end avoids complications from that.
+  unsigned Idx = getNumIncomingValues();
+  while (Idx > 0) {
+    if (Predicate(Idx - 1))
+      removeIncomingValue(Idx - 1);
+    --Idx;
+  }
+}
+
+static llvm::Instruction::CastOps getLLVMCastOp(Instruction::Opcode Opc) {
+  switch (Opc) {
+  case Instruction::Opcode::ZExt:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::ZExt);
+  case Instruction::Opcode::SExt:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::SExt);
+  case Instruction::Opcode::FPToUI:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPToUI);
+  case Instruction::Opcode::FPToSI:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPToSI);
+  case Instruction::Opcode::FPExt:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPExt);
+  case Instruction::Opcode::PtrToInt:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::PtrToInt);
+  case Instruction::Opcode::IntToPtr:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::IntToPtr);
+  case Instruction::Opcode::SIToFP:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::SIToFP);
+  case Instruction::Opcode::UIToFP:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::UIToFP);
+  case Instruction::Opcode::Trunc:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::Trunc);
+  case Instruction::Opcode::FPTrunc:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPTrunc);
+  case Instruction::Opcode::BitCast:
+    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::BitCast);
+  case Instruction::Opcode::AddrSpaceCast:
+    return static_cast<llvm::Instruction::CastOps>(
+        llvm::Instruction::AddrSpaceCast);
+  default:
+    llvm_unreachable("Opcode not suitable for CastInst!");
+  }
+}
+
+/// \Returns the LLVM opcode that corresponds to \p Opc.
+static llvm::Instruction::UnaryOps getLLVMUnaryOp(Instruction::Opcode Opc) {
+  switch (Opc) {
+  case Instruction::Opcode::FNeg:
+    return static_cast<llvm::Instruction::UnaryOps>(llvm::Instruction::FNeg);
+  default:
+    llvm_unreachable("Not a unary op!");
+  }
+}
+
+CatchSwitchInst *CatchSwitchInst::create(Value *ParentPad, BasicBlock *UnwindBB,
+                                         unsigned NumHandlers,
+                                         BBIterator WhereIt,
+                                         BasicBlock *WhereBB, Context &Ctx,
+                                         const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  llvm::CatchSwitchInst *LLVMCSI = Builder.CreateCatchSwitch(
+      ParentPad->Val, cast<llvm::BasicBlock>(UnwindBB->Val), NumHandlers, Name);
+  return Ctx.createCatchSwitchInst(LLVMCSI);
+}
+
+Value *CatchSwitchInst::getParentPad() const {
+  return Ctx.getValue(cast<llvm::CatchSwitchInst>(Val)->getParentPad());
+}
+
+void CatchSwitchInst::setParentPad(Value *ParentPad) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&CatchSwitchInst::getParentPad,
+                                       &CatchSwitchInst::setParentPad>>(this);
+  cast<llvm::CatchSwitchInst>(Val)->setParentPad(ParentPad->Val);
+}
+
+BasicBlock *CatchSwitchInst::getUnwindDest() const {
+  return cast_or_null<BasicBlock>(
+      Ctx.getValue(cast<llvm::CatchSwitchInst>(Val)->getUnwindDest()));
+}
+
+void CatchSwitchInst::setUnwindDest(BasicBlock *UnwindDest) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&CatchSwitchInst::getUnwindDest,
+                                       &CatchSwitchInst::setUnwindDest>>(this);
+  cast<llvm::CatchSwitchInst>(Val)->setUnwindDest(
+      cast<llvm::BasicBlock>(UnwindDest->Val));
+}
+
+void CatchSwitchInst::addHandler(BasicBlock *Dest) {
+  Ctx.getTracker().emplaceIfTracking<CatchSwitchAddHandler>(this);
+  cast<llvm::CatchSwitchInst>(Val)->addHandler(
+      cast<llvm::BasicBlock>(Dest->Val));
+}
+
+ResumeInst *ResumeInst::create(Value *Exn, BBIterator WhereIt,
+                               BasicBlock *WhereBB, Context &Ctx) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  auto *LLVMI = cast<llvm::ResumeInst>(Builder.CreateResume(Exn->Val));
+  return Ctx.createResumeInst(LLVMI);
+}
+
+Value *ResumeInst::getValue() const {
+  return Ctx.getValue(cast<llvm::ResumeInst>(Val)->getValue());
+}
+
+SwitchInst *SwitchInst::create(Value *V, BasicBlock *Dest, unsigned NumCases,
+                               BasicBlock::iterator WhereIt,
+                               BasicBlock *WhereBB, Context &Ctx,
+                               const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  llvm::SwitchInst *LLVMSwitch =
+      Builder.CreateSwitch(V->Val, cast<llvm::BasicBlock>(Dest->Val), NumCases);
+  return Ctx.createSwitchInst(LLVMSwitch);
+}
+
+Value *SwitchInst::getCondition() const {
+  return Ctx.getValue(cast<llvm::SwitchInst>(Val)->getCondition());
+}
+
+void SwitchInst::setCondition(Value *V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&SwitchInst::getCondition, &SwitchInst::setCondition>>(
+          this);
+  cast<llvm::SwitchInst>(Val)->setCondition(V->Val);
+}
+
+BasicBlock *SwitchInst::getDefaultDest() const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::SwitchInst>(Val)->getDefaultDest()));
+}
+
+void SwitchInst::setDefaultDest(BasicBlock *DefaultCase) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&SwitchInst::getDefaultDest,
+                                       &SwitchInst::setDefaultDest>>(this);
+  cast<llvm::SwitchInst>(Val)->setDefaultDest(
+      cast<llvm::BasicBlock>(DefaultCase->Val));
+}
+ConstantInt *SwitchInst::findCaseDest(BasicBlock *BB) {
+  auto *LLVMC = cast<llvm::SwitchInst>(Val)->findCaseDest(
+      cast<llvm::BasicBlock>(BB->Val));
+  return LLVMC != nullptr ? cast<ConstantInt>(Ctx.getValue(LLVMC)) : nullptr;
+}
+
+void SwitchInst::addCase(ConstantInt *OnVal, BasicBlock *Dest) {
+  Ctx.getTracker().emplaceIfTracking<SwitchAddCase>(this, OnVal);
+  // TODO: Track this!
+  cast<llvm::SwitchInst>(Val)->addCase(cast<llvm::ConstantInt>(OnVal->Val),
+                                       cast<llvm::BasicBlock>(Dest->Val));
+}
+
+SwitchInst::CaseIt SwitchInst::removeCase(CaseIt It) {
+  auto &Case = *It;
+  Ctx.getTracker().emplaceIfTracking<SwitchRemoveCase>(
+      this, Case.getCaseValue(), Case.getCaseSuccessor());
+
+  auto *LLVMSwitch = cast<llvm::SwitchInst>(Val);
+  unsigned CaseNum = It - case_begin();
+  llvm::SwitchInst::CaseIt LLVMIt(LLVMSwitch, CaseNum);
+  auto LLVMCaseIt = LLVMSwitch->removeCase(LLVMIt);
+  unsigned Num = LLVMCaseIt - LLVMSwitch->case_begin();
+  return CaseIt(this, Num);
+}
+
+BasicBlock *SwitchInst::getSuccessor(unsigned Idx) const {
+  return cast<BasicBlock>(
+      Ctx.getValue(cast<llvm::SwitchInst>(Val)->getSuccessor(Idx)));
+}
+
+void SwitchInst::setSuccessor(unsigned Idx, BasicBlock *NewSucc) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetterWithIdx<&SwitchInst::getSuccessor,
+                                              &SwitchInst::setSuccessor>>(this,
+                                                                          Idx);
+  cast<llvm::SwitchInst>(Val)->setSuccessor(
+      Idx, cast<llvm::BasicBlock>(NewSucc->Val));
+}
+
+Value *UnaryOperator::create(Instruction::Opcode Op, Value *OpV,
+                             BBIterator WhereIt, BasicBlock *WhereBB,
+                             Context &Ctx, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt == WhereBB->end())
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  else
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  auto *NewLLVMV = Builder.CreateUnOp(getLLVMUnaryOp(Op), OpV->Val, Name);
+  if (auto *NewUnOpV = dyn_cast<llvm::UnaryOperator>(NewLLVMV)) {
+    return Ctx.createUnaryOperator(NewUnOpV);
+  }
+  assert(isa<llvm::Constant>(NewLLVMV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewLLVMV));
+}
+
+Value *UnaryOperator::create(Instruction::Opcode Op, Value *OpV,
+                             Instruction *InsertBefore, Context &Ctx,
+                             const Twine &Name) {
+  return create(Op, OpV, InsertBefore->getIterator(), InsertBefore->getParent(),
+                Ctx, Name);
+}
+
+Value *UnaryOperator::create(Instruction::Opcode Op, Value *OpV,
+                             BasicBlock *InsertAfter, Context &Ctx,
+                             const Twine &Name) {
+  return create(Op, OpV, InsertAfter->end(), InsertAfter, Ctx, Name);
+}
+
+Value *UnaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
+                                            Value *CopyFrom, BBIterator WhereIt,
+                                            BasicBlock *WhereBB, Context &Ctx,
+                                            const Twine &Name) {
+  auto *NewV = create(Op, OpV, WhereIt, WhereBB, Ctx, Name);
+  if (auto *UnI = dyn_cast<llvm::UnaryOperator>(NewV->Val))
+    UnI->copyIRFlags(CopyFrom->Val);
+  return NewV;
+}
+
+Value *UnaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
+                                            Value *CopyFrom,
+                                            Instruction *InsertBefore,
+                                            Context &Ctx, const Twine &Name) {
+  return createWithCopiedFlags(Op, OpV, CopyFrom, InsertBefore->getIterator(),
+                               InsertBefore->getParent(), Ctx, Name);
+}
+
+Value *UnaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
+                                            Value *CopyFrom,
+                                            BasicBlock *InsertAtEnd,
+                                            Context &Ctx, const Twine &Name) {
+  return createWithCopiedFlags(Op, OpV, CopyFrom, InsertAtEnd->end(),
+                               InsertAtEnd, Ctx, Name);
+}
+
+/// \Returns the LLVM opcode that corresponds to \p Opc.
+static llvm::Instruction::BinaryOps getLLVMBinaryOp(Instruction::Opcode Opc) {
+  switch (Opc) {
+  case Instruction::Opcode::Add:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Add);
+  case Instruction::Opcode::FAdd:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FAdd);
+  case Instruction::Opcode::Sub:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Sub);
+  case Instruction::Opcode::FSub:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FSub);
+  case Instruction::Opcode::Mul:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Mul);
+  case Instruction::Opcode::FMul:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FMul);
+  case Instruction::Opcode::UDiv:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::UDiv);
+  case Instruction::Opcode::SDiv:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::SDiv);
+  case Instruction::Opcode::FDiv:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FDiv);
+  case Instruction::Opcode::URem:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::URem);
+  case Instruction::Opcode::SRem:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::SRem);
+  case Instruction::Opcode::FRem:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FRem);
+  case Instruction::Opcode::Shl:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Shl);
+  case Instruction::Opcode::LShr:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::LShr);
+  case Instruction::Opcode::AShr:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::AShr);
+  case Instruction::Opcode::And:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::And);
+  case Instruction::Opcode::Or:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Or);
+  case Instruction::Opcode::Xor:
+    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Xor);
+  default:
+    llvm_unreachable("Not a binary op!");
+  }
+}
+Value *BinaryOperator::create(Instruction::Opcode Op, Value *LHS, Value *RHS,
+                              BBIterator WhereIt, BasicBlock *WhereBB,
+                              Context &Ctx, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt == WhereBB->end())
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  else
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  llvm::Value *NewV =
+      Builder.CreateBinOp(getLLVMBinaryOp(Op), LHS->Val, RHS->Val, Name);
+  if (auto *NewBinOp = dyn_cast<llvm::BinaryOperator>(NewV))
+    return Ctx.createBinaryOperator(NewBinOp);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *BinaryOperator::create(Instruction::Opcode Op, Value *LHS, Value *RHS,
+                              Instruction *InsertBefore, Context &Ctx,
+                              const Twine &Name) {
+  return create(Op, LHS, RHS, InsertBefore->getIterator(),
+                InsertBefore->getParent(), Ctx, Name);
+}
+
+Value *BinaryOperator::create(Instruction::Opcode Op, Value *LHS, Value *RHS,
+                              BasicBlock *InsertAtEnd, Context &Ctx,
+                              const Twine &Name) {
+  return create(Op, LHS, RHS, InsertAtEnd->end(), InsertAtEnd, Ctx, Name);
+}
+
+Value *BinaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
+                                             Value *RHS, Value *CopyFrom,
+                                             BBIterator WhereIt,
+                                             BasicBlock *WhereBB, Context &Ctx,
+                                             const Twine &Name) {
+
+  Value *NewV = create(Op, LHS, RHS, WhereIt, WhereBB, Ctx, Name);
+  if (auto *NewBO = dyn_cast<BinaryOperator>(NewV))
+    cast<llvm::BinaryOperator>(NewBO->Val)->copyIRFlags(CopyFrom->Val);
+  return NewV;
+}
+
+Value *BinaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
+                                             Value *RHS, Value *CopyFrom,
+                                             Instruction *InsertBefore,
+                                             Context &Ctx, const Twine &Name) {
+  return createWithCopiedFlags(Op, LHS, RHS, CopyFrom,
+                               InsertBefore->getIterator(),
+                               InsertBefore->getParent(), Ctx, Name);
+}
+
+Value *BinaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
+                                             Value *RHS, Value *CopyFrom,
+                                             BasicBlock *InsertAtEnd,
+                                             Context &Ctx, const Twine &Name) {
+  return createWithCopiedFlags(Op, LHS, RHS, CopyFrom, InsertAtEnd->end(),
+                               InsertAtEnd, Ctx, Name);
+}
+
+void PossiblyDisjointInst::setIsDisjoint(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&PossiblyDisjointInst::isDisjoint,
+                                       &PossiblyDisjointInst::setIsDisjoint>>(
+          this);
+  cast<llvm::PossiblyDisjointInst>(Val)->setIsDisjoint(B);
+}
+
+void AtomicRMWInst::setAlignment(Align Align) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicRMWInst::getAlign,
+                                       &AtomicRMWInst::setAlignment>>(this);
+  cast<llvm::AtomicRMWInst>(Val)->setAlignment(Align);
+}
+
+void AtomicRMWInst::setVolatile(bool V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicRMWInst::isVolatile,
+                                       &AtomicRMWInst::setVolatile>>(this);
+  cast<llvm::AtomicRMWInst>(Val)->setVolatile(V);
+}
+
+void AtomicRMWInst::setOrdering(AtomicOrdering Ordering) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicRMWInst::getOrdering,
+                                       &AtomicRMWInst::setOrdering>>(this);
+  cast<llvm::AtomicRMWInst>(Val)->setOrdering(Ordering);
+}
+
+void AtomicRMWInst::setSyncScopeID(SyncScope::ID SSID) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicRMWInst::getSyncScopeID,
+                                       &AtomicRMWInst::setSyncScopeID>>(this);
+  cast<llvm::AtomicRMWInst>(Val)->setSyncScopeID(SSID);
+}
+
+Value *AtomicRMWInst::getPointerOperand() {
+  return Ctx.getValue(cast<llvm::AtomicRMWInst>(Val)->getPointerOperand());
+}
+
+Value *AtomicRMWInst::getValOperand() {
+  return Ctx.getValue(cast<llvm::AtomicRMWInst>(Val)->getValOperand());
+}
+
+AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
+                                     MaybeAlign Align, AtomicOrdering Ordering,
+                                     BBIterator WhereIt, BasicBlock *WhereBB,
+                                     Context &Ctx, SyncScope::ID SSID,
+                                     const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt == WhereBB->end())
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  else
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  auto *LLVMAtomicRMW =
+      Builder.CreateAtomicRMW(Op, Ptr->Val, Val->Val, Align, Ordering, SSID);
+  LLVMAtomicRMW->setName(Name);
+  return Ctx.createAtomicRMWInst(LLVMAtomicRMW);
+}
+
+AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
+                                     MaybeAlign Align, AtomicOrdering Ordering,
+                                     Instruction *InsertBefore, Context &Ctx,
+                                     SyncScope::ID SSID, const Twine &Name) {
+  return create(Op, Ptr, Val, Align, Ordering, InsertBefore->getIterator(),
+                InsertBefore->getParent(), Ctx, SSID, Name);
+}
+
+AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
+                                     MaybeAlign Align, AtomicOrdering Ordering,
+                                     BasicBlock *InsertAtEnd, Context &Ctx,
+                                     SyncScope::ID SSID, const Twine &Name) {
+  return create(Op, Ptr, Val, Align, Ordering, InsertAtEnd->end(), InsertAtEnd,
+                Ctx, SSID, Name);
+}
+
+void AtomicCmpXchgInst::setSyncScopeID(SyncScope::ID SSID) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getSyncScopeID,
+                                       &AtomicCmpXchgInst::setSyncScopeID>>(
+          this);
+  cast<llvm::AtomicCmpXchgInst>(Val)->setSyncScopeID(SSID);
+}
+
+Value *AtomicCmpXchgInst::getPointerOperand() {
+  return Ctx.getValue(cast<llvm::AtomicCmpXchgInst>(Val)->getPointerOperand());
+}
+
+Value *AtomicCmpXchgInst::getCompareOperand() {
+  return Ctx.getValue(cast<llvm::AtomicCmpXchgInst>(Val)->getCompareOperand());
+}
+
+Value *AtomicCmpXchgInst::getNewValOperand() {
+  return Ctx.getValue(cast<llvm::AtomicCmpXchgInst>(Val)->getNewValOperand());
+}
+
+AtomicCmpXchgInst *
+AtomicCmpXchgInst::create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align,
+                          AtomicOrdering SuccessOrdering,
+                          AtomicOrdering FailureOrdering, BBIterator WhereIt,
+                          BasicBlock *WhereBB, Context &Ctx, SyncScope::ID SSID,
+                          const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt == WhereBB->end())
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  else
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  auto *LLVMAtomicCmpXchg =
+      Builder.CreateAtomicCmpXchg(Ptr->Val, Cmp->Val, New->Val, Align,
+                                  SuccessOrdering, FailureOrdering, SSID);
+  LLVMAtomicCmpXchg->setName(Name);
+  return Ctx.createAtomicCmpXchgInst(LLVMAtomicCmpXchg);
+}
+
+AtomicCmpXchgInst *AtomicCmpXchgInst::create(Value *Ptr, Value *Cmp, Value *New,
+                                             MaybeAlign Align,
+                                             AtomicOrdering SuccessOrdering,
+                                             AtomicOrdering FailureOrdering,
+                                             Instruction *InsertBefore,
+                                             Context &Ctx, SyncScope::ID SSID,
+                                             const Twine &Name) {
+  return create(Ptr, Cmp, New, Align, SuccessOrdering, FailureOrdering,
+                InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
+                SSID, Name);
+}
+
+AtomicCmpXchgInst *AtomicCmpXchgInst::create(Value *Ptr, Value *Cmp, Value *New,
+                                             MaybeAlign Align,
+                                             AtomicOrdering SuccessOrdering,
+                                             AtomicOrdering FailureOrdering,
+                                             BasicBlock *InsertAtEnd,
+                                             Context &Ctx, SyncScope::ID SSID,
+                                             const Twine &Name) {
+  return create(Ptr, Cmp, New, Align, SuccessOrdering, FailureOrdering,
+                InsertAtEnd->end(), InsertAtEnd, Ctx, SSID, Name);
+}
+
+void AtomicCmpXchgInst::setAlignment(Align Align) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getAlign,
+                                       &AtomicCmpXchgInst::setAlignment>>(this);
+  cast<llvm::AtomicCmpXchgInst>(Val)->setAlignment(Align);
+}
+
+void AtomicCmpXchgInst::setVolatile(bool V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::isVolatile,
+                                       &AtomicCmpXchgInst::setVolatile>>(this);
+  cast<llvm::AtomicCmpXchgInst>(Val)->setVolatile(V);
+}
+
+void AtomicCmpXchgInst::setWeak(bool IsWeak) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::isWeak,
+                                       &AtomicCmpXchgInst::setWeak>>(this);
+  cast<llvm::AtomicCmpXchgInst>(Val)->setWeak(IsWeak);
+}
+
+void AtomicCmpXchgInst::setSuccessOrdering(AtomicOrdering Ordering) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getSuccessOrdering,
+                                       &AtomicCmpXchgInst::setSuccessOrdering>>(
+          this);
+  cast<llvm::AtomicCmpXchgInst>(Val)->setSuccessOrdering(Ordering);
+}
+
+void AtomicCmpXchgInst::setFailureOrdering(AtomicOrdering Ordering) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getFailureOrdering,
+                                       &AtomicCmpXchgInst::setFailureOrdering>>(
+          this);
+  cast<llvm::AtomicCmpXchgInst>(Val)->setFailureOrdering(Ordering);
+}
+
+AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace, BBIterator WhereIt,
+                               BasicBlock *WhereBB, Context &Ctx,
+                               Value *ArraySize, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt == WhereBB->end())
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  else
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  auto *NewAlloca =
+      Builder.CreateAlloca(Ty->LLVMTy, AddrSpace, ArraySize->Val, Name);
+  return Ctx.createAllocaInst(NewAlloca);
+}
+
+AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace,
+                               Instruction *InsertBefore, Context &Ctx,
+                               Value *ArraySize, const Twine &Name) {
+  return create(Ty, AddrSpace, InsertBefore->getIterator(),
+                InsertBefore->getParent(), Ctx, ArraySize, Name);
+}
+
+AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace,
+                               BasicBlock *InsertAtEnd, Context &Ctx,
+                               Value *ArraySize, const Twine &Name) {
+  return create(Ty, AddrSpace, InsertAtEnd->end(), InsertAtEnd, Ctx, ArraySize,
+                Name);
+}
+
+Type *AllocaInst::getAllocatedType() const {
+  return Ctx.getType(cast<llvm::AllocaInst>(Val)->getAllocatedType());
+}
+
+void AllocaInst::setAllocatedType(Type *Ty) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AllocaInst::getAllocatedType,
+                                       &AllocaInst::setAllocatedType>>(this);
+  cast<llvm::AllocaInst>(Val)->setAllocatedType(Ty->LLVMTy);
+}
+
+void AllocaInst::setAlignment(Align Align) {
+  Ctx.getTracker()
+      .emplaceIfTracking<
+          GenericSetter<&AllocaInst::getAlign, &AllocaInst::setAlignment>>(
+          this);
+  cast<llvm::AllocaInst>(Val)->setAlignment(Align);
+}
+
+void AllocaInst::setUsedWithInAlloca(bool V) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&AllocaInst::isUsedWithInAlloca,
+                                       &AllocaInst::setUsedWithInAlloca>>(this);
+  cast<llvm::AllocaInst>(Val)->setUsedWithInAlloca(V);
+}
+
+Value *AllocaInst::getArraySize() {
+  return Ctx.getValue(cast<llvm::AllocaInst>(Val)->getArraySize());
+}
+
+PointerType *AllocaInst::getType() const {
+  return cast<PointerType>(Ctx.getType(cast<llvm::AllocaInst>(Val)->getType()));
+}
+
+Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
+                        BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
+                        const Twine &Name) {
+  assert(getLLVMCastOp(Op) && "Opcode not suitable for CastInst!");
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt == WhereBB->end())
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  else
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  auto *NewV =
+      Builder.CreateCast(getLLVMCastOp(Op), Operand->Val, DestTy->LLVMTy, Name);
+  if (auto *NewCI = dyn_cast<llvm::CastInst>(NewV))
+    return Ctx.createCastInst(NewCI);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
+                        Instruction *InsertBefore, Context &Ctx,
+                        const Twine &Name) {
+  return create(DestTy, Op, Operand, InsertBefore->getIterator(),
+                InsertBefore->getParent(), Ctx, Name);
+}
+
+Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
+                        BasicBlock *InsertAtEnd, Context &Ctx,
+                        const Twine &Name) {
+  return create(DestTy, Op, Operand, InsertAtEnd->end(), InsertAtEnd, Ctx,
+                Name);
+}
+
+bool CastInst::classof(const Value *From) {
+  return From->getSubclassID() == ClassID::Cast;
+}
+
+Type *CastInst::getSrcTy() const {
+  return Ctx.getType(cast<llvm::CastInst>(Val)->getSrcTy());
+}
+
+Type *CastInst::getDestTy() const {
+  return Ctx.getType(cast<llvm::CastInst>(Val)->getDestTy());
+}
+
+void PossiblyNonNegInst::setNonNeg(bool B) {
+  Ctx.getTracker()
+      .emplaceIfTracking<GenericSetter<&PossiblyNonNegInst::hasNonNeg,
+                                       &PossiblyNonNegInst::setNonNeg>>(this);
+  cast<llvm::PossiblyNonNegInst>(Val)->setNonNeg(B);
+}
+
+Value *InsertElementInst::create(Value *Vec, Value *NewElt, Value *Idx,
+                                 Instruction *InsertBefore, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
+  llvm::Value *NewV =
+      Builder.CreateInsertElement(Vec->Val, NewElt->Val, Idx->Val, Name);
+  if (auto *NewInsert = dyn_cast<llvm::InsertElementInst>(NewV))
+    return Ctx.createInsertElementInst(NewInsert);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *InsertElementInst::create(Value *Vec, Value *NewElt, Value *Idx,
+                                 BasicBlock *InsertAtEnd, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::Value *NewV =
+      Builder.CreateInsertElement(Vec->Val, NewElt->Val, Idx->Val, Name);
+  if (auto *NewInsert = dyn_cast<llvm::InsertElementInst>(NewV))
+    return Ctx.createInsertElementInst(NewInsert);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ExtractElementInst::create(Value *Vec, Value *Idx,
+                                  Instruction *InsertBefore, Context &Ctx,
+                                  const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
+  llvm::Value *NewV = Builder.CreateExtractElement(Vec->Val, Idx->Val, Name);
+  if (auto *NewExtract = dyn_cast<llvm::ExtractElementInst>(NewV))
+    return Ctx.createExtractElementInst(NewExtract);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ExtractElementInst::create(Value *Vec, Value *Idx,
+                                  BasicBlock *InsertAtEnd, Context &Ctx,
+                                  const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::Value *NewV = Builder.CreateExtractElement(Vec->Val, Idx->Val, Name);
+  if (auto *NewExtract = dyn_cast<llvm::ExtractElementInst>(NewV))
+    return Ctx.createExtractElementInst(NewExtract);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ShuffleVectorInst::create(Value *V1, Value *V2, Value *Mask,
+                                 Instruction *InsertBefore, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
+  llvm::Value *NewV =
+      Builder.CreateShuffleVector(V1->Val, V2->Val, Mask->Val, Name);
+  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
+    return Ctx.createShuffleVectorInst(NewShuffle);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ShuffleVectorInst::create(Value *V1, Value *V2, Value *Mask,
+                                 BasicBlock *InsertAtEnd, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::Value *NewV =
+      Builder.CreateShuffleVector(V1->Val, V2->Val, Mask->Val, Name);
+  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
+    return Ctx.createShuffleVectorInst(NewShuffle);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ShuffleVectorInst::create(Value *V1, Value *V2, ArrayRef<int> Mask,
+                                 Instruction *InsertBefore, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
+  llvm::Value *NewV = Builder.CreateShuffleVector(V1->Val, V2->Val, Mask, Name);
+  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
+    return Ctx.createShuffleVectorInst(NewShuffle);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ShuffleVectorInst::create(Value *V1, Value *V2, ArrayRef<int> Mask,
+                                 BasicBlock *InsertAtEnd, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::Value *NewV = Builder.CreateShuffleVector(V1->Val, V2->Val, Mask, Name);
+  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
+    return Ctx.createShuffleVectorInst(NewShuffle);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+void ShuffleVectorInst::setShuffleMask(ArrayRef<int> Mask) {
+  Ctx.getTracker().emplaceIfTracking<ShuffleVectorSetMask>(this);
+  cast<llvm::ShuffleVectorInst>(Val)->setShuffleMask(Mask);
+}
+
+VectorType *ShuffleVectorInst::getType() const {
+  return cast<VectorType>(
+      Ctx.getType(cast<llvm::ShuffleVectorInst>(Val)->getType()));
+}
+
+void ShuffleVectorInst::commute() {
+  Ctx.getTracker().emplaceIfTracking<ShuffleVectorSetMask>(this);
+  Ctx.getTracker().emplaceIfTracking<UseSwap>(getOperandUse(0),
+                                              getOperandUse(1));
+  cast<llvm::ShuffleVectorInst>(Val)->commute();
+}
+
+Constant *ShuffleVectorInst::getShuffleMaskForBitcode() const {
+  return Ctx.getOrCreateConstant(
+      cast<llvm::ShuffleVectorInst>(Val)->getShuffleMaskForBitcode());
+}
+
+Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(ArrayRef<int> Mask,
+                                                          Type *ResultTy) {
+  return ResultTy->getContext().getOrCreateConstant(
+      llvm::ShuffleVectorInst::convertShuffleMaskForBitcode(Mask,
+                                                            ResultTy->LLVMTy));
+}
+
+VectorType *ExtractElementInst::getVectorOperandType() const {
+  return cast<VectorType>(Ctx.getType(getVectorOperand()->getType()->LLVMTy));
+}
+
+Value *ExtractValueInst::create(Value *Agg, ArrayRef<unsigned> Idxs,
+                                BBIterator WhereIt, BasicBlock *WhereBB,
+                                Context &Ctx, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  llvm::Value *NewV = Builder.CreateExtractValue(Agg->Val, Idxs, Name);
+  if (auto *NewExtractValueInst = dyn_cast<llvm::ExtractValueInst>(NewV))
+    return Ctx.createExtractValueInst(NewExtractValueInst);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Type *ExtractValueInst::getIndexedType(Type *Agg, ArrayRef<unsigned> Idxs) {
+  auto *LLVMTy = llvm::ExtractValueInst::getIndexedType(Agg->LLVMTy, Idxs);
+  return Agg->getContext().getType(LLVMTy);
+}
+
+Value *InsertValueInst::create(Value *Agg, Value *Val, ArrayRef<unsigned> Idxs,
+                               BBIterator WhereIt, BasicBlock *WhereBB,
+                               Context &Ctx, const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  if (WhereIt != WhereBB->end())
+    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
+  else
+    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
+  llvm::Value *NewV = Builder.CreateInsertValue(Agg->Val, Val->Val, Idxs, Name);
+  if (auto *NewInsertValueInst = dyn_cast<llvm::InsertValueInst>(NewV))
+    return Ctx.createInsertValueInst(NewInsertValueInst);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+ConstantTokenNone *ConstantTokenNone::get(Context &Ctx) {
+  auto *LLVMC = llvm::ConstantTokenNone::get(Ctx.LLVMCtx);
+  return cast<ConstantTokenNone>(Ctx.getOrCreateConstant(LLVMC));
+}
+
+} // namespace llvm::sandboxir
diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp
index 5baeffef32e5e5..63f65bfc88544b 100644
--- a/llvm/lib/SandboxIR/SandboxIR.cpp
+++ b/llvm/lib/SandboxIR/SandboxIR.cpp
@@ -106,1955 +106,3 @@ int OperandUseIterator::operator-(const OperandUseIterator &Other) const {
   int OtherOpNo = Other.Use.getOperandNo();
   return ThisOpNo - OtherOpNo;
 }
-
-const char *Instruction::getOpcodeName(Opcode Opc) {
-  switch (Opc) {
-#define OP(OPC)                                                                \
-  case Opcode::OPC:                                                            \
-    return #OPC;
-#define OPCODES(...) __VA_ARGS__
-#define DEF_INSTR(ID, OPC, CLASS) OPC
-#include "llvm/SandboxIR/SandboxIRValues.def"
-  }
-  llvm_unreachable("Unknown Opcode");
-}
-
-llvm::Instruction *Instruction::getTopmostLLVMInstruction() const {
-  Instruction *Prev = getPrevNode();
-  if (Prev == nullptr) {
-    // If at top of the BB, return the first BB instruction.
-    return &*cast<llvm::BasicBlock>(getParent()->Val)->begin();
-  }
-  // Else get the Previous sandbox IR instruction's bottom IR instruction and
-  // return its successor.
-  llvm::Instruction *PrevBotI = cast<llvm::Instruction>(Prev->Val);
-  return PrevBotI->getNextNode();
-}
-
-BBIterator Instruction::getIterator() const {
-  auto *I = cast<llvm::Instruction>(Val);
-  return BasicBlock::iterator(I->getParent(), I->getIterator(), &Ctx);
-}
-
-Instruction *Instruction::getNextNode() const {
-  assert(getParent() != nullptr && "Detached!");
-  assert(getIterator() != getParent()->end() && "Already at end!");
-  // `Val` is the bottom-most LLVM IR instruction. Get the next in the chain,
-  // and get the corresponding sandboxir Instruction that maps to it. This works
-  // even for SandboxIR Instructions that map to more than one LLVM Instruction.
-  auto *LLVMI = cast<llvm::Instruction>(Val);
-  assert(LLVMI->getParent() != nullptr && "LLVM IR instr is detached!");
-  auto *NextLLVMI = LLVMI->getNextNode();
-  auto *NextI = cast_or_null<Instruction>(Ctx.getValue(NextLLVMI));
-  if (NextI == nullptr)
-    return nullptr;
-  return NextI;
-}
-
-Instruction *Instruction::getPrevNode() const {
-  assert(getParent() != nullptr && "Detached!");
-  auto It = getIterator();
-  if (It != getParent()->begin())
-    return std::prev(getIterator()).get();
-  return nullptr;
-}
-
-void Instruction::removeFromParent() {
-  Ctx.getTracker().emplaceIfTracking<RemoveFromParent>(this);
-
-  // Detach all the LLVM IR instructions from their parent BB.
-  for (llvm::Instruction *I : getLLVMInstrs())
-    I->removeFromParent();
-}
-
-void Instruction::eraseFromParent() {
-  assert(users().empty() && "Still connected to users, can't erase!");
-  std::unique_ptr<Value> Detached = Ctx.detach(this);
-  auto LLVMInstrs = getLLVMInstrs();
-
-  auto &Tracker = Ctx.getTracker();
-  if (Tracker.isTracking()) {
-    Tracker.track(std::make_unique<EraseFromParent>(std::move(Detached)));
-    // We don't actually delete the IR instruction, because then it would be
-    // impossible to bring it back from the dead at the same memory location.
-    // Instead we remove it from its BB and track its current location.
-    for (llvm::Instruction *I : LLVMInstrs)
-      I->removeFromParent();
-    // TODO: Multi-instructions need special treatment because some of the
-    // references are internal to the instruction.
-    for (llvm::Instruction *I : LLVMInstrs)
-      I->dropAllReferences();
-  } else {
-    // Erase in reverse to avoid erasing nstructions with attached uses.
-    for (llvm::Instruction *I : reverse(LLVMInstrs))
-      I->eraseFromParent();
-  }
-}
-
-void Instruction::moveBefore(BasicBlock &BB, const BBIterator &WhereIt) {
-  if (std::next(getIterator()) == WhereIt)
-    // Destination is same as origin, nothing to do.
-    return;
-
-  Ctx.getTracker().emplaceIfTracking<MoveInstr>(this);
-
-  auto *LLVMBB = cast<llvm::BasicBlock>(BB.Val);
-  llvm::BasicBlock::iterator It;
-  if (WhereIt == BB.end()) {
-    It = LLVMBB->end();
-  } else {
-    Instruction *WhereI = &*WhereIt;
-    It = WhereI->getTopmostLLVMInstruction()->getIterator();
-  }
-  // TODO: Move this to the verifier of sandboxir::Instruction.
-  assert(is_sorted(getLLVMInstrs(),
-                   [](auto *I1, auto *I2) { return I1->comesBefore(I2); }) &&
-         "Expected program order!");
-  // Do the actual move in LLVM IR.
-  for (auto *I : getLLVMInstrs())
-    I->moveBefore(*LLVMBB, It);
-}
-
-void Instruction::insertBefore(Instruction *BeforeI) {
-  llvm::Instruction *BeforeTopI = BeforeI->getTopmostLLVMInstruction();
-  // TODO: Move this to the verifier of sandboxir::Instruction.
-  assert(is_sorted(getLLVMInstrs(),
-                   [](auto *I1, auto *I2) { return I1->comesBefore(I2); }) &&
-         "Expected program order!");
-
-  Ctx.getTracker().emplaceIfTracking<InsertIntoBB>(this);
-
-  // Insert the LLVM IR Instructions in program order.
-  for (llvm::Instruction *I : getLLVMInstrs())
-    I->insertBefore(BeforeTopI);
-}
-
-void Instruction::insertAfter(Instruction *AfterI) {
-  insertInto(AfterI->getParent(), std::next(AfterI->getIterator()));
-}
-
-void Instruction::insertInto(BasicBlock *BB, const BBIterator &WhereIt) {
-  llvm::BasicBlock *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
-  llvm::Instruction *LLVMBeforeI;
-  llvm::BasicBlock::iterator LLVMBeforeIt;
-  Instruction *BeforeI;
-  if (WhereIt != BB->end()) {
-    BeforeI = &*WhereIt;
-    LLVMBeforeI = BeforeI->getTopmostLLVMInstruction();
-    LLVMBeforeIt = LLVMBeforeI->getIterator();
-  } else {
-    BeforeI = nullptr;
-    LLVMBeforeI = nullptr;
-    LLVMBeforeIt = LLVMBB->end();
-  }
-
-  Ctx.getTracker().emplaceIfTracking<InsertIntoBB>(this);
-
-  // Insert the LLVM IR Instructions in program order.
-  for (llvm::Instruction *I : getLLVMInstrs())
-    I->insertInto(LLVMBB, LLVMBeforeIt);
-}
-
-BasicBlock *Instruction::getParent() const {
-  // Get the LLVM IR Instruction that this maps to, get its parent, and get the
-  // corresponding sandboxir::BasicBlock by looking it up in sandboxir::Context.
-  auto *BB = cast<llvm::Instruction>(Val)->getParent();
-  if (BB == nullptr)
-    return nullptr;
-  return cast<BasicBlock>(Ctx.getValue(BB));
-}
-
-bool Instruction::classof(const sandboxir::Value *From) {
-  switch (From->getSubclassID()) {
-#define DEF_INSTR(ID, OPC, CLASS)                                              \
-  case ClassID::ID:                                                            \
-    return true;
-#include "llvm/SandboxIR/SandboxIRValues.def"
-  default:
-    return false;
-  }
-}
-
-void Instruction::setHasNoUnsignedWrap(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::hasNoUnsignedWrap,
-                                       &Instruction::setHasNoUnsignedWrap>>(
-          this);
-  cast<llvm::Instruction>(Val)->setHasNoUnsignedWrap(B);
-}
-
-void Instruction::setHasNoSignedWrap(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::hasNoSignedWrap,
-                                       &Instruction::setHasNoSignedWrap>>(this);
-  cast<llvm::Instruction>(Val)->setHasNoSignedWrap(B);
-}
-
-void Instruction::setFast(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&Instruction::isFast, &Instruction::setFast>>(this);
-  cast<llvm::Instruction>(Val)->setFast(B);
-}
-
-void Instruction::setIsExact(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&Instruction::isExact, &Instruction::setIsExact>>(this);
-  cast<llvm::Instruction>(Val)->setIsExact(B);
-}
-
-void Instruction::setHasAllowReassoc(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::hasAllowReassoc,
-                                       &Instruction::setHasAllowReassoc>>(this);
-  cast<llvm::Instruction>(Val)->setHasAllowReassoc(B);
-}
-
-void Instruction::setHasNoNaNs(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&Instruction::hasNoNaNs, &Instruction::setHasNoNaNs>>(
-          this);
-  cast<llvm::Instruction>(Val)->setHasNoNaNs(B);
-}
-
-void Instruction::setHasNoInfs(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&Instruction::hasNoInfs, &Instruction::setHasNoInfs>>(
-          this);
-  cast<llvm::Instruction>(Val)->setHasNoInfs(B);
-}
-
-void Instruction::setHasNoSignedZeros(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::hasNoSignedZeros,
-                                       &Instruction::setHasNoSignedZeros>>(
-          this);
-  cast<llvm::Instruction>(Val)->setHasNoSignedZeros(B);
-}
-
-void Instruction::setHasAllowReciprocal(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::hasAllowReciprocal,
-                                       &Instruction::setHasAllowReciprocal>>(
-          this);
-  cast<llvm::Instruction>(Val)->setHasAllowReciprocal(B);
-}
-
-void Instruction::setHasAllowContract(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::hasAllowContract,
-                                       &Instruction::setHasAllowContract>>(
-          this);
-  cast<llvm::Instruction>(Val)->setHasAllowContract(B);
-}
-
-void Instruction::setFastMathFlags(FastMathFlags FMF) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::getFastMathFlags,
-                                       &Instruction::copyFastMathFlags>>(this);
-  cast<llvm::Instruction>(Val)->setFastMathFlags(FMF);
-}
-
-void Instruction::copyFastMathFlags(FastMathFlags FMF) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::getFastMathFlags,
-                                       &Instruction::copyFastMathFlags>>(this);
-  cast<llvm::Instruction>(Val)->copyFastMathFlags(FMF);
-}
-
-Type *Instruction::getAccessType() const {
-  return Ctx.getType(cast<llvm::Instruction>(Val)->getAccessType());
-}
-
-void Instruction::setHasApproxFunc(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&Instruction::hasApproxFunc,
-                                       &Instruction::setHasApproxFunc>>(this);
-  cast<llvm::Instruction>(Val)->setHasApproxFunc(B);
-}
-
-#ifndef NDEBUG
-void Instruction::dumpOS(raw_ostream &OS) const {
-  OS << "Unimplemented! Please override dump().";
-}
-#endif // NDEBUG
-
-VAArgInst *VAArgInst::create(Value *List, Type *Ty, BBIterator WhereIt,
-                             BasicBlock *WhereBB, Context &Ctx,
-                             const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  auto *LLVMI =
-      cast<llvm::VAArgInst>(Builder.CreateVAArg(List->Val, Ty->LLVMTy, Name));
-  return Ctx.createVAArgInst(LLVMI);
-}
-
-Value *VAArgInst::getPointerOperand() {
-  return Ctx.getValue(cast<llvm::VAArgInst>(Val)->getPointerOperand());
-}
-
-FreezeInst *FreezeInst::create(Value *V, BBIterator WhereIt,
-                               BasicBlock *WhereBB, Context &Ctx,
-                               const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  auto *LLVMI = cast<llvm::FreezeInst>(Builder.CreateFreeze(V->Val, Name));
-  return Ctx.createFreezeInst(LLVMI);
-}
-
-FenceInst *FenceInst::create(AtomicOrdering Ordering, BBIterator WhereIt,
-                             BasicBlock *WhereBB, Context &Ctx,
-                             SyncScope::ID SSID) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  llvm::FenceInst *LLVMI = Builder.CreateFence(Ordering, SSID);
-  return Ctx.createFenceInst(LLVMI);
-}
-
-void FenceInst::setOrdering(AtomicOrdering Ordering) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&FenceInst::getOrdering, &FenceInst::setOrdering>>(
-          this);
-  cast<llvm::FenceInst>(Val)->setOrdering(Ordering);
-}
-
-void FenceInst::setSyncScopeID(SyncScope::ID SSID) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&FenceInst::getSyncScopeID,
-                                       &FenceInst::setSyncScopeID>>(this);
-  cast<llvm::FenceInst>(Val)->setSyncScopeID(SSID);
-}
-
-Value *SelectInst::createCommon(Value *Cond, Value *True, Value *False,
-                                const Twine &Name, IRBuilder<> &Builder,
-                                Context &Ctx) {
-  llvm::Value *NewV =
-      Builder.CreateSelect(Cond->Val, True->Val, False->Val, Name);
-  if (auto *NewSI = dyn_cast<llvm::SelectInst>(NewV))
-    return Ctx.createSelectInst(NewSI);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *SelectInst::create(Value *Cond, Value *True, Value *False,
-                          Instruction *InsertBefore, Context &Ctx,
-                          const Twine &Name) {
-  llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(BeforeIR);
-  return createCommon(Cond, True, False, Name, Builder, Ctx);
-}
-
-Value *SelectInst::create(Value *Cond, Value *True, Value *False,
-                          BasicBlock *InsertAtEnd, Context &Ctx,
-                          const Twine &Name) {
-  auto *IRInsertAtEnd = cast<llvm::BasicBlock>(InsertAtEnd->Val);
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(IRInsertAtEnd);
-  return createCommon(Cond, True, False, Name, Builder, Ctx);
-}
-
-void SelectInst::swapValues() {
-  Ctx.getTracker().emplaceIfTracking<UseSwap>(getOperandUse(1),
-                                              getOperandUse(2));
-  cast<llvm::SelectInst>(Val)->swapValues();
-}
-
-bool SelectInst::classof(const Value *From) {
-  return From->getSubclassID() == ClassID::Select;
-}
-
-BranchInst *BranchInst::create(BasicBlock *IfTrue, Instruction *InsertBefore,
-                               Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
-  Builder.SetInsertPoint(cast<llvm::Instruction>(LLVMBefore));
-  llvm::BranchInst *NewBr =
-      Builder.CreateBr(cast<llvm::BasicBlock>(IfTrue->Val));
-  return Ctx.createBranchInst(NewBr);
-}
-
-BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd,
-                               Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  llvm::BranchInst *NewBr =
-      Builder.CreateBr(cast<llvm::BasicBlock>(IfTrue->Val));
-  return Ctx.createBranchInst(NewBr);
-}
-
-BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *IfFalse,
-                               Value *Cond, Instruction *InsertBefore,
-                               Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
-  Builder.SetInsertPoint(LLVMBefore);
-  llvm::BranchInst *NewBr =
-      Builder.CreateCondBr(Cond->Val, cast<llvm::BasicBlock>(IfTrue->Val),
-                           cast<llvm::BasicBlock>(IfFalse->Val));
-  return Ctx.createBranchInst(NewBr);
-}
-
-BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *IfFalse,
-                               Value *Cond, BasicBlock *InsertAtEnd,
-                               Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  llvm::BranchInst *NewBr =
-      Builder.CreateCondBr(Cond->Val, cast<llvm::BasicBlock>(IfTrue->Val),
-                           cast<llvm::BasicBlock>(IfFalse->Val));
-  return Ctx.createBranchInst(NewBr);
-}
-
-bool BranchInst::classof(const Value *From) {
-  return From->getSubclassID() == ClassID::Br;
-}
-
-Value *BranchInst::getCondition() const {
-  assert(isConditional() && "Cannot get condition of an uncond branch!");
-  return Ctx.getValue(cast<llvm::BranchInst>(Val)->getCondition());
-}
-
-BasicBlock *BranchInst::getSuccessor(unsigned SuccIdx) const {
-  assert(SuccIdx < getNumSuccessors() &&
-         "Successor # out of range for Branch!");
-  return cast_or_null<BasicBlock>(
-      Ctx.getValue(cast<llvm::BranchInst>(Val)->getSuccessor(SuccIdx)));
-}
-
-void BranchInst::setSuccessor(unsigned Idx, BasicBlock *NewSucc) {
-  assert((Idx == 0 || Idx == 1) && "Out of bounds!");
-  setOperand(2u - Idx, NewSucc);
-}
-
-BasicBlock *BranchInst::LLVMBBToSBBB::operator()(llvm::BasicBlock *BB) const {
-  return cast<BasicBlock>(Ctx.getValue(BB));
-}
-const BasicBlock *
-BranchInst::ConstLLVMBBToSBBB::operator()(const llvm::BasicBlock *BB) const {
-  return cast<BasicBlock>(Ctx.getValue(BB));
-}
-
-void LoadInst::setVolatile(bool V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&LoadInst::isVolatile, &LoadInst::setVolatile>>(this);
-  cast<llvm::LoadInst>(Val)->setVolatile(V);
-}
-
-LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
-                           Instruction *InsertBefore, Context &Ctx,
-                           const Twine &Name) {
-  return create(Ty, Ptr, Align, InsertBefore, /*IsVolatile=*/false, Ctx, Name);
-}
-
-LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
-                           Instruction *InsertBefore, bool IsVolatile,
-                           Context &Ctx, const Twine &Name) {
-  llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(BeforeIR);
-  auto *NewLI =
-      Builder.CreateAlignedLoad(Ty->LLVMTy, Ptr->Val, Align, IsVolatile, Name);
-  auto *NewSBI = Ctx.createLoadInst(NewLI);
-  return NewSBI;
-}
-
-LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
-                           BasicBlock *InsertAtEnd, Context &Ctx,
-                           const Twine &Name) {
-  return create(Ty, Ptr, Align, InsertAtEnd, /*IsVolatile=*/false, Ctx, Name);
-}
-
-LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
-                           BasicBlock *InsertAtEnd, bool IsVolatile,
-                           Context &Ctx, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  auto *NewLI =
-      Builder.CreateAlignedLoad(Ty->LLVMTy, Ptr->Val, Align, IsVolatile, Name);
-  auto *NewSBI = Ctx.createLoadInst(NewLI);
-  return NewSBI;
-}
-
-bool LoadInst::classof(const Value *From) {
-  return From->getSubclassID() == ClassID::Load;
-}
-
-Value *LoadInst::getPointerOperand() const {
-  return Ctx.getValue(cast<llvm::LoadInst>(Val)->getPointerOperand());
-}
-
-void StoreInst::setVolatile(bool V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&StoreInst::isVolatile, &StoreInst::setVolatile>>(this);
-  cast<llvm::StoreInst>(Val)->setVolatile(V);
-}
-
-StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
-                             Instruction *InsertBefore, Context &Ctx) {
-  return create(V, Ptr, Align, InsertBefore, /*IsVolatile=*/false, Ctx);
-}
-
-StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
-                             Instruction *InsertBefore, bool IsVolatile,
-                             Context &Ctx) {
-  llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(BeforeIR);
-  auto *NewSI = Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, IsVolatile);
-  auto *NewSBI = Ctx.createStoreInst(NewSI);
-  return NewSBI;
-}
-
-StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
-                             BasicBlock *InsertAtEnd, Context &Ctx) {
-  return create(V, Ptr, Align, InsertAtEnd, /*IsVolatile=*/false, Ctx);
-}
-
-StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
-                             BasicBlock *InsertAtEnd, bool IsVolatile,
-                             Context &Ctx) {
-  auto *InsertAtEndIR = cast<llvm::BasicBlock>(InsertAtEnd->Val);
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(InsertAtEndIR);
-  auto *NewSI = Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, IsVolatile);
-  auto *NewSBI = Ctx.createStoreInst(NewSI);
-  return NewSBI;
-}
-
-bool StoreInst::classof(const Value *From) {
-  return From->getSubclassID() == ClassID::Store;
-}
-
-Value *StoreInst::getValueOperand() const {
-  return Ctx.getValue(cast<llvm::StoreInst>(Val)->getValueOperand());
-}
-
-Value *StoreInst::getPointerOperand() const {
-  return Ctx.getValue(cast<llvm::StoreInst>(Val)->getPointerOperand());
-}
-
-UnreachableInst *UnreachableInst::create(Instruction *InsertBefore,
-                                         Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
-  Builder.SetInsertPoint(LLVMBefore);
-  llvm::UnreachableInst *NewUI = Builder.CreateUnreachable();
-  return Ctx.createUnreachableInst(NewUI);
-}
-
-UnreachableInst *UnreachableInst::create(BasicBlock *InsertAtEnd,
-                                         Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  llvm::UnreachableInst *NewUI = Builder.CreateUnreachable();
-  return Ctx.createUnreachableInst(NewUI);
-}
-
-bool UnreachableInst::classof(const Value *From) {
-  return From->getSubclassID() == ClassID::Unreachable;
-}
-
-ReturnInst *ReturnInst::createCommon(Value *RetVal, IRBuilder<> &Builder,
-                                     Context &Ctx) {
-  llvm::ReturnInst *NewRI;
-  if (RetVal != nullptr)
-    NewRI = Builder.CreateRet(RetVal->Val);
-  else
-    NewRI = Builder.CreateRetVoid();
-  return Ctx.createReturnInst(NewRI);
-}
-
-ReturnInst *ReturnInst::create(Value *RetVal, Instruction *InsertBefore,
-                               Context &Ctx) {
-  llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(BeforeIR);
-  return createCommon(RetVal, Builder, Ctx);
-}
-
-ReturnInst *ReturnInst::create(Value *RetVal, BasicBlock *InsertAtEnd,
-                               Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  return createCommon(RetVal, Builder, Ctx);
-}
-
-Value *ReturnInst::getReturnValue() const {
-  auto *LLVMRetVal = cast<llvm::ReturnInst>(Val)->getReturnValue();
-  return LLVMRetVal != nullptr ? Ctx.getValue(LLVMRetVal) : nullptr;
-}
-
-FunctionType *CallBase::getFunctionType() const {
-  return cast<FunctionType>(
-      Ctx.getType(cast<llvm::CallBase>(Val)->getFunctionType()));
-}
-
-Value *CallBase::getCalledOperand() const {
-  return Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledOperand());
-}
-
-Use CallBase::getCalledOperandUse() const {
-  llvm::Use *LLVMUse = &cast<llvm::CallBase>(Val)->getCalledOperandUse();
-  return Use(LLVMUse, cast<User>(Ctx.getValue(LLVMUse->getUser())), Ctx);
-}
-
-Function *CallBase::getCalledFunction() const {
-  return cast_or_null<Function>(
-      Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledFunction()));
-}
-Function *CallBase::getCaller() {
-  return cast<Function>(Ctx.getValue(cast<llvm::CallBase>(Val)->getCaller()));
-}
-
-void CallBase::setCalledFunction(Function *F) {
-  // F's function type is private, so we rely on `setCalledFunction()` to update
-  // it. But even though we are calling `setCalledFunction()` we also need to
-  // track this change at the SandboxIR level, which is why we call
-  // `setCalledOperand()` here.
-  // Note: This may break if `setCalledFunction()` early returns if `F`
-  // is already set, but we do have a unit test for it.
-  setCalledOperand(F);
-  cast<llvm::CallBase>(Val)->setCalledFunction(
-      cast<llvm::FunctionType>(F->getFunctionType()->LLVMTy),
-      cast<llvm::Function>(F->Val));
-}
-
-CallInst *CallInst::create(FunctionType *FTy, Value *Func,
-                           ArrayRef<Value *> Args, BasicBlock::iterator WhereIt,
-                           BasicBlock *WhereBB, Context &Ctx,
-                           const Twine &NameStr) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  SmallVector<llvm::Value *> LLVMArgs;
-  LLVMArgs.reserve(Args.size());
-  for (Value *Arg : Args)
-    LLVMArgs.push_back(Arg->Val);
-  llvm::CallInst *NewCI = Builder.CreateCall(
-      cast<llvm::FunctionType>(FTy->LLVMTy), Func->Val, LLVMArgs, NameStr);
-  return Ctx.createCallInst(NewCI);
-}
-
-CallInst *CallInst::create(FunctionType *FTy, Value *Func,
-                           ArrayRef<Value *> Args, Instruction *InsertBefore,
-                           Context &Ctx, const Twine &NameStr) {
-  return CallInst::create(FTy, Func, Args, InsertBefore->getIterator(),
-                          InsertBefore->getParent(), Ctx, NameStr);
-}
-
-CallInst *CallInst::create(FunctionType *FTy, Value *Func,
-                           ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
-                           Context &Ctx, const Twine &NameStr) {
-  return CallInst::create(FTy, Func, Args, InsertAtEnd->end(), InsertAtEnd, Ctx,
-                          NameStr);
-}
-
-InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
-                               BasicBlock *IfNormal, BasicBlock *IfException,
-                               ArrayRef<Value *> Args, BBIterator WhereIt,
-                               BasicBlock *WhereBB, Context &Ctx,
-                               const Twine &NameStr) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  SmallVector<llvm::Value *> LLVMArgs;
-  LLVMArgs.reserve(Args.size());
-  for (Value *Arg : Args)
-    LLVMArgs.push_back(Arg->Val);
-  llvm::InvokeInst *Invoke = Builder.CreateInvoke(
-      cast<llvm::FunctionType>(FTy->LLVMTy), Func->Val,
-      cast<llvm::BasicBlock>(IfNormal->Val),
-      cast<llvm::BasicBlock>(IfException->Val), LLVMArgs, NameStr);
-  return Ctx.createInvokeInst(Invoke);
-}
-
-InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
-                               BasicBlock *IfNormal, BasicBlock *IfException,
-                               ArrayRef<Value *> Args,
-                               Instruction *InsertBefore, Context &Ctx,
-                               const Twine &NameStr) {
-  return create(FTy, Func, IfNormal, IfException, Args,
-                InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
-                NameStr);
-}
-
-InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
-                               BasicBlock *IfNormal, BasicBlock *IfException,
-                               ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
-                               Context &Ctx, const Twine &NameStr) {
-  return create(FTy, Func, IfNormal, IfException, Args, InsertAtEnd->end(),
-                InsertAtEnd, Ctx, NameStr);
-}
-
-BasicBlock *InvokeInst::getNormalDest() const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::InvokeInst>(Val)->getNormalDest()));
-}
-BasicBlock *InvokeInst::getUnwindDest() const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::InvokeInst>(Val)->getUnwindDest()));
-}
-void InvokeInst::setNormalDest(BasicBlock *BB) {
-  setOperand(1, BB);
-  assert(getNormalDest() == BB && "LLVM IR uses a different operan index!");
-}
-void InvokeInst::setUnwindDest(BasicBlock *BB) {
-  setOperand(2, BB);
-  assert(getUnwindDest() == BB && "LLVM IR uses a different operan index!");
-}
-LandingPadInst *InvokeInst::getLandingPadInst() const {
-  return cast<LandingPadInst>(
-      Ctx.getValue(cast<llvm::InvokeInst>(Val)->getLandingPadInst()));
-  ;
-}
-BasicBlock *InvokeInst::getSuccessor(unsigned SuccIdx) const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::InvokeInst>(Val)->getSuccessor(SuccIdx)));
-}
-
-CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
-                               BasicBlock *DefaultDest,
-                               ArrayRef<BasicBlock *> IndirectDests,
-                               ArrayRef<Value *> Args, BBIterator WhereIt,
-                               BasicBlock *WhereBB, Context &Ctx,
-                               const Twine &NameStr) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-
-  SmallVector<llvm::BasicBlock *> LLVMIndirectDests;
-  LLVMIndirectDests.reserve(IndirectDests.size());
-  for (BasicBlock *IndDest : IndirectDests)
-    LLVMIndirectDests.push_back(cast<llvm::BasicBlock>(IndDest->Val));
-
-  SmallVector<llvm::Value *> LLVMArgs;
-  LLVMArgs.reserve(Args.size());
-  for (Value *Arg : Args)
-    LLVMArgs.push_back(Arg->Val);
-
-  llvm::CallBrInst *CallBr =
-      Builder.CreateCallBr(cast<llvm::FunctionType>(FTy->LLVMTy), Func->Val,
-                           cast<llvm::BasicBlock>(DefaultDest->Val),
-                           LLVMIndirectDests, LLVMArgs, NameStr);
-  return Ctx.createCallBrInst(CallBr);
-}
-
-CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
-                               BasicBlock *DefaultDest,
-                               ArrayRef<BasicBlock *> IndirectDests,
-                               ArrayRef<Value *> Args,
-                               Instruction *InsertBefore, Context &Ctx,
-                               const Twine &NameStr) {
-  return create(FTy, Func, DefaultDest, IndirectDests, Args,
-                InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
-                NameStr);
-}
-CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
-                               BasicBlock *DefaultDest,
-                               ArrayRef<BasicBlock *> IndirectDests,
-                               ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
-                               Context &Ctx, const Twine &NameStr) {
-  return create(FTy, Func, DefaultDest, IndirectDests, Args, InsertAtEnd->end(),
-                InsertAtEnd, Ctx, NameStr);
-}
-
-Value *CallBrInst::getIndirectDestLabel(unsigned Idx) const {
-  return Ctx.getValue(cast<llvm::CallBrInst>(Val)->getIndirectDestLabel(Idx));
-}
-Value *CallBrInst::getIndirectDestLabelUse(unsigned Idx) const {
-  return Ctx.getValue(
-      cast<llvm::CallBrInst>(Val)->getIndirectDestLabelUse(Idx));
-}
-BasicBlock *CallBrInst::getDefaultDest() const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::CallBrInst>(Val)->getDefaultDest()));
-}
-BasicBlock *CallBrInst::getIndirectDest(unsigned Idx) const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::CallBrInst>(Val)->getIndirectDest(Idx)));
-}
-llvm::SmallVector<BasicBlock *, 16> CallBrInst::getIndirectDests() const {
-  SmallVector<BasicBlock *, 16> BBs;
-  for (llvm::BasicBlock *LLVMBB :
-       cast<llvm::CallBrInst>(Val)->getIndirectDests())
-    BBs.push_back(cast<BasicBlock>(Ctx.getValue(LLVMBB)));
-  return BBs;
-}
-void CallBrInst::setDefaultDest(BasicBlock *BB) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&CallBrInst::getDefaultDest,
-                                       &CallBrInst::setDefaultDest>>(this);
-  cast<llvm::CallBrInst>(Val)->setDefaultDest(cast<llvm::BasicBlock>(BB->Val));
-}
-void CallBrInst::setIndirectDest(unsigned Idx, BasicBlock *BB) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetterWithIdx<&CallBrInst::getIndirectDest,
-                                              &CallBrInst::setIndirectDest>>(
-          this, Idx);
-  cast<llvm::CallBrInst>(Val)->setIndirectDest(Idx,
-                                               cast<llvm::BasicBlock>(BB->Val));
-}
-BasicBlock *CallBrInst::getSuccessor(unsigned Idx) const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::CallBrInst>(Val)->getSuccessor(Idx)));
-}
-
-LandingPadInst *LandingPadInst::create(Type *RetTy, unsigned NumReservedClauses,
-                                       BBIterator WhereIt, BasicBlock *WhereBB,
-                                       Context &Ctx, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  llvm::LandingPadInst *LLVMI =
-      Builder.CreateLandingPad(RetTy->LLVMTy, NumReservedClauses, Name);
-  return Ctx.createLandingPadInst(LLVMI);
-}
-
-void LandingPadInst::setCleanup(bool V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&LandingPadInst::isCleanup,
-                                       &LandingPadInst::setCleanup>>(this);
-  cast<llvm::LandingPadInst>(Val)->setCleanup(V);
-}
-
-Constant *LandingPadInst::getClause(unsigned Idx) const {
-  return cast<Constant>(
-      Ctx.getValue(cast<llvm::LandingPadInst>(Val)->getClause(Idx)));
-}
-
-Value *FuncletPadInst::getParentPad() const {
-  return Ctx.getValue(cast<llvm::FuncletPadInst>(Val)->getParentPad());
-}
-
-void FuncletPadInst::setParentPad(Value *ParentPad) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&FuncletPadInst::getParentPad,
-                                       &FuncletPadInst::setParentPad>>(this);
-  cast<llvm::FuncletPadInst>(Val)->setParentPad(ParentPad->Val);
-}
-
-Value *FuncletPadInst::getArgOperand(unsigned Idx) const {
-  return Ctx.getValue(cast<llvm::FuncletPadInst>(Val)->getArgOperand(Idx));
-}
-
-void FuncletPadInst::setArgOperand(unsigned Idx, Value *V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetterWithIdx<&FuncletPadInst::getArgOperand,
-                                              &FuncletPadInst::setArgOperand>>(
-          this, Idx);
-  cast<llvm::FuncletPadInst>(Val)->setArgOperand(Idx, V->Val);
-}
-
-CatchSwitchInst *CatchPadInst::getCatchSwitch() const {
-  return cast<CatchSwitchInst>(
-      Ctx.getValue(cast<llvm::CatchPadInst>(Val)->getCatchSwitch()));
-}
-
-CatchPadInst *CatchPadInst::create(Value *ParentPad, ArrayRef<Value *> Args,
-                                   BBIterator WhereIt, BasicBlock *WhereBB,
-                                   Context &Ctx, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  SmallVector<llvm::Value *> LLVMArgs;
-  LLVMArgs.reserve(Args.size());
-  for (auto *Arg : Args)
-    LLVMArgs.push_back(Arg->Val);
-  llvm::CatchPadInst *LLVMI =
-      Builder.CreateCatchPad(ParentPad->Val, LLVMArgs, Name);
-  return Ctx.createCatchPadInst(LLVMI);
-}
-
-CleanupPadInst *CleanupPadInst::create(Value *ParentPad, ArrayRef<Value *> Args,
-                                       BBIterator WhereIt, BasicBlock *WhereBB,
-                                       Context &Ctx, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  SmallVector<llvm::Value *> LLVMArgs;
-  LLVMArgs.reserve(Args.size());
-  for (auto *Arg : Args)
-    LLVMArgs.push_back(Arg->Val);
-  llvm::CleanupPadInst *LLVMI =
-      Builder.CreateCleanupPad(ParentPad->Val, LLVMArgs, Name);
-  return Ctx.createCleanupPadInst(LLVMI);
-}
-
-CatchReturnInst *CatchReturnInst::create(CatchPadInst *CatchPad, BasicBlock *BB,
-                                         BBIterator WhereIt,
-                                         BasicBlock *WhereBB, Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  llvm::CatchReturnInst *LLVMI = Builder.CreateCatchRet(
-      cast<llvm::CatchPadInst>(CatchPad->Val), cast<llvm::BasicBlock>(BB->Val));
-  return Ctx.createCatchReturnInst(LLVMI);
-}
-
-CatchPadInst *CatchReturnInst::getCatchPad() const {
-  return cast<CatchPadInst>(
-      Ctx.getValue(cast<llvm::CatchReturnInst>(Val)->getCatchPad()));
-}
-
-void CatchReturnInst::setCatchPad(CatchPadInst *CatchPad) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&CatchReturnInst::getCatchPad,
-                                       &CatchReturnInst::setCatchPad>>(this);
-  cast<llvm::CatchReturnInst>(Val)->setCatchPad(
-      cast<llvm::CatchPadInst>(CatchPad->Val));
-}
-
-BasicBlock *CatchReturnInst::getSuccessor() const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::CatchReturnInst>(Val)->getSuccessor()));
-}
-
-void CatchReturnInst::setSuccessor(BasicBlock *NewSucc) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&CatchReturnInst::getSuccessor,
-                                       &CatchReturnInst::setSuccessor>>(this);
-  cast<llvm::CatchReturnInst>(Val)->setSuccessor(
-      cast<llvm::BasicBlock>(NewSucc->Val));
-}
-
-Value *CatchReturnInst::getCatchSwitchParentPad() const {
-  return Ctx.getValue(
-      cast<llvm::CatchReturnInst>(Val)->getCatchSwitchParentPad());
-}
-
-CleanupReturnInst *CleanupReturnInst::create(CleanupPadInst *CleanupPad,
-                                             BasicBlock *UnwindBB,
-                                             BBIterator WhereIt,
-                                             BasicBlock *WhereBB,
-                                             Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  auto *LLVMUnwindBB =
-      UnwindBB != nullptr ? cast<llvm::BasicBlock>(UnwindBB->Val) : nullptr;
-  llvm::CleanupReturnInst *LLVMI = Builder.CreateCleanupRet(
-      cast<llvm::CleanupPadInst>(CleanupPad->Val), LLVMUnwindBB);
-  return Ctx.createCleanupReturnInst(LLVMI);
-}
-
-CleanupPadInst *CleanupReturnInst::getCleanupPad() const {
-  return cast<CleanupPadInst>(
-      Ctx.getValue(cast<llvm::CleanupReturnInst>(Val)->getCleanupPad()));
-}
-
-void CleanupReturnInst::setCleanupPad(CleanupPadInst *CleanupPad) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&CleanupReturnInst::getCleanupPad,
-                                       &CleanupReturnInst::setCleanupPad>>(
-          this);
-  cast<llvm::CleanupReturnInst>(Val)->setCleanupPad(
-      cast<llvm::CleanupPadInst>(CleanupPad->Val));
-}
-
-BasicBlock *CleanupReturnInst::getUnwindDest() const {
-  return cast_or_null<BasicBlock>(
-      Ctx.getValue(cast<llvm::CleanupReturnInst>(Val)->getUnwindDest()));
-}
-
-void CleanupReturnInst::setUnwindDest(BasicBlock *NewDest) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&CleanupReturnInst::getUnwindDest,
-                                       &CleanupReturnInst::setUnwindDest>>(
-          this);
-  cast<llvm::CleanupReturnInst>(Val)->setUnwindDest(
-      cast<llvm::BasicBlock>(NewDest->Val));
-}
-
-Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
-                                 ArrayRef<Value *> IdxList,
-                                 BasicBlock::iterator WhereIt,
-                                 BasicBlock *WhereBB, Context &Ctx,
-                                 const Twine &NameStr) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  SmallVector<llvm::Value *> LLVMIdxList;
-  LLVMIdxList.reserve(IdxList.size());
-  for (Value *Idx : IdxList)
-    LLVMIdxList.push_back(Idx->Val);
-  llvm::Value *NewV =
-      Builder.CreateGEP(Ty->LLVMTy, Ptr->Val, LLVMIdxList, NameStr);
-  if (auto *NewGEP = dyn_cast<llvm::GetElementPtrInst>(NewV))
-    return Ctx.createGetElementPtrInst(NewGEP);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
-                                 ArrayRef<Value *> IdxList,
-                                 Instruction *InsertBefore, Context &Ctx,
-                                 const Twine &NameStr) {
-  return GetElementPtrInst::create(Ty, Ptr, IdxList,
-                                   InsertBefore->getIterator(),
-                                   InsertBefore->getParent(), Ctx, NameStr);
-}
-
-Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
-                                 ArrayRef<Value *> IdxList,
-                                 BasicBlock *InsertAtEnd, Context &Ctx,
-                                 const Twine &NameStr) {
-  return GetElementPtrInst::create(Ty, Ptr, IdxList, InsertAtEnd->end(),
-                                   InsertAtEnd, Ctx, NameStr);
-}
-
-Type *GetElementPtrInst::getSourceElementType() const {
-  return Ctx.getType(
-      cast<llvm::GetElementPtrInst>(Val)->getSourceElementType());
-}
-
-Type *GetElementPtrInst::getResultElementType() const {
-  return Ctx.getType(
-      cast<llvm::GetElementPtrInst>(Val)->getResultElementType());
-}
-
-Value *GetElementPtrInst::getPointerOperand() const {
-  return Ctx.getValue(cast<llvm::GetElementPtrInst>(Val)->getPointerOperand());
-}
-
-Type *GetElementPtrInst::getPointerOperandType() const {
-  return Ctx.getType(
-      cast<llvm::GetElementPtrInst>(Val)->getPointerOperandType());
-}
-
-BasicBlock *PHINode::LLVMBBToBB::operator()(llvm::BasicBlock *LLVMBB) const {
-  return cast<BasicBlock>(Ctx.getValue(LLVMBB));
-}
-
-PHINode *PHINode::create(Type *Ty, unsigned NumReservedValues,
-                         Instruction *InsertBefore, Context &Ctx,
-                         const Twine &Name) {
-  llvm::PHINode *NewPHI = llvm::PHINode::Create(
-      Ty->LLVMTy, NumReservedValues, Name,
-      InsertBefore->getTopmostLLVMInstruction()->getIterator());
-  return Ctx.createPHINode(NewPHI);
-}
-
-bool PHINode::classof(const Value *From) {
-  return From->getSubclassID() == ClassID::PHI;
-}
-
-Value *PHINode::getIncomingValue(unsigned Idx) const {
-  return Ctx.getValue(cast<llvm::PHINode>(Val)->getIncomingValue(Idx));
-}
-void PHINode::setIncomingValue(unsigned Idx, Value *V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetterWithIdx<&PHINode::getIncomingValue,
-                                              &PHINode::setIncomingValue>>(this,
-                                                                           Idx);
-  cast<llvm::PHINode>(Val)->setIncomingValue(Idx, V->Val);
-}
-BasicBlock *PHINode::getIncomingBlock(unsigned Idx) const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::PHINode>(Val)->getIncomingBlock(Idx)));
-}
-BasicBlock *PHINode::getIncomingBlock(const Use &U) const {
-  llvm::Use *LLVMUse = U.LLVMUse;
-  llvm::BasicBlock *BB = cast<llvm::PHINode>(Val)->getIncomingBlock(*LLVMUse);
-  return cast<BasicBlock>(Ctx.getValue(BB));
-}
-void PHINode::setIncomingBlock(unsigned Idx, BasicBlock *BB) {
-  // Helper to disambiguate PHINode::getIncomingBlock(unsigned).
-  constexpr BasicBlock *(PHINode::*GetIncomingBlockFn)(unsigned) const =
-      &PHINode::getIncomingBlock;
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetterWithIdx<GetIncomingBlockFn, &PHINode::setIncomingBlock>>(
-          this, Idx);
-  cast<llvm::PHINode>(Val)->setIncomingBlock(Idx,
-                                             cast<llvm::BasicBlock>(BB->Val));
-}
-void PHINode::addIncoming(Value *V, BasicBlock *BB) {
-  auto &Tracker = Ctx.getTracker();
-  Tracker.emplaceIfTracking<PHIAddIncoming>(this);
-
-  cast<llvm::PHINode>(Val)->addIncoming(V->Val,
-                                        cast<llvm::BasicBlock>(BB->Val));
-}
-Value *PHINode::removeIncomingValue(unsigned Idx) {
-  auto &Tracker = Ctx.getTracker();
-  Tracker.emplaceIfTracking<PHIRemoveIncoming>(this, Idx);
-  llvm::Value *LLVMV =
-      cast<llvm::PHINode>(Val)->removeIncomingValue(Idx,
-                                                    /*DeletePHIIfEmpty=*/false);
-  return Ctx.getValue(LLVMV);
-}
-Value *PHINode::removeIncomingValue(BasicBlock *BB) {
-  auto &Tracker = Ctx.getTracker();
-  Tracker.emplaceIfTracking<PHIRemoveIncoming>(this, getBasicBlockIndex(BB));
-
-  auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
-  llvm::Value *LLVMV =
-      cast<llvm::PHINode>(Val)->removeIncomingValue(LLVMBB,
-                                                    /*DeletePHIIfEmpty=*/false);
-  return Ctx.getValue(LLVMV);
-}
-int PHINode::getBasicBlockIndex(const BasicBlock *BB) const {
-  auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
-  return cast<llvm::PHINode>(Val)->getBasicBlockIndex(LLVMBB);
-}
-Value *PHINode::getIncomingValueForBlock(const BasicBlock *BB) const {
-  auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
-  llvm::Value *LLVMV =
-      cast<llvm::PHINode>(Val)->getIncomingValueForBlock(LLVMBB);
-  return Ctx.getValue(LLVMV);
-}
-Value *PHINode::hasConstantValue() const {
-  llvm::Value *LLVMV = cast<llvm::PHINode>(Val)->hasConstantValue();
-  return LLVMV != nullptr ? Ctx.getValue(LLVMV) : nullptr;
-}
-void PHINode::replaceIncomingBlockWith(const BasicBlock *Old, BasicBlock *New) {
-  assert(New && Old && "Sandbox IR PHI node got a null basic block!");
-  for (unsigned Idx = 0, NumOps = cast<llvm::PHINode>(Val)->getNumOperands();
-       Idx != NumOps; ++Idx)
-    if (getIncomingBlock(Idx) == Old)
-      setIncomingBlock(Idx, New);
-}
-void PHINode::removeIncomingValueIf(function_ref<bool(unsigned)> Predicate) {
-  // Avoid duplicate tracking by going through this->removeIncomingValue here at
-  // the expense of some performance. Copy PHI::removeIncomingValueIf more
-  // directly if performance becomes an issue.
-
-  // Removing the element at index X, moves the element previously at X + 1
-  // to X. Working from the end avoids complications from that.
-  unsigned Idx = getNumIncomingValues();
-  while (Idx > 0) {
-    if (Predicate(Idx - 1))
-      removeIncomingValue(Idx - 1);
-    --Idx;
-  }
-}
-
-static llvm::Instruction::CastOps getLLVMCastOp(Instruction::Opcode Opc) {
-  switch (Opc) {
-  case Instruction::Opcode::ZExt:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::ZExt);
-  case Instruction::Opcode::SExt:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::SExt);
-  case Instruction::Opcode::FPToUI:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPToUI);
-  case Instruction::Opcode::FPToSI:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPToSI);
-  case Instruction::Opcode::FPExt:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPExt);
-  case Instruction::Opcode::PtrToInt:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::PtrToInt);
-  case Instruction::Opcode::IntToPtr:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::IntToPtr);
-  case Instruction::Opcode::SIToFP:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::SIToFP);
-  case Instruction::Opcode::UIToFP:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::UIToFP);
-  case Instruction::Opcode::Trunc:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::Trunc);
-  case Instruction::Opcode::FPTrunc:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPTrunc);
-  case Instruction::Opcode::BitCast:
-    return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::BitCast);
-  case Instruction::Opcode::AddrSpaceCast:
-    return static_cast<llvm::Instruction::CastOps>(
-        llvm::Instruction::AddrSpaceCast);
-  default:
-    llvm_unreachable("Opcode not suitable for CastInst!");
-  }
-}
-
-/// \Returns the LLVM opcode that corresponds to \p Opc.
-static llvm::Instruction::UnaryOps getLLVMUnaryOp(Instruction::Opcode Opc) {
-  switch (Opc) {
-  case Instruction::Opcode::FNeg:
-    return static_cast<llvm::Instruction::UnaryOps>(llvm::Instruction::FNeg);
-  default:
-    llvm_unreachable("Not a unary op!");
-  }
-}
-
-CatchSwitchInst *CatchSwitchInst::create(Value *ParentPad, BasicBlock *UnwindBB,
-                                         unsigned NumHandlers,
-                                         BBIterator WhereIt,
-                                         BasicBlock *WhereBB, Context &Ctx,
-                                         const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  llvm::CatchSwitchInst *LLVMCSI = Builder.CreateCatchSwitch(
-      ParentPad->Val, cast<llvm::BasicBlock>(UnwindBB->Val), NumHandlers, Name);
-  return Ctx.createCatchSwitchInst(LLVMCSI);
-}
-
-Value *CatchSwitchInst::getParentPad() const {
-  return Ctx.getValue(cast<llvm::CatchSwitchInst>(Val)->getParentPad());
-}
-
-void CatchSwitchInst::setParentPad(Value *ParentPad) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&CatchSwitchInst::getParentPad,
-                                       &CatchSwitchInst::setParentPad>>(this);
-  cast<llvm::CatchSwitchInst>(Val)->setParentPad(ParentPad->Val);
-}
-
-BasicBlock *CatchSwitchInst::getUnwindDest() const {
-  return cast_or_null<BasicBlock>(
-      Ctx.getValue(cast<llvm::CatchSwitchInst>(Val)->getUnwindDest()));
-}
-
-void CatchSwitchInst::setUnwindDest(BasicBlock *UnwindDest) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&CatchSwitchInst::getUnwindDest,
-                                       &CatchSwitchInst::setUnwindDest>>(this);
-  cast<llvm::CatchSwitchInst>(Val)->setUnwindDest(
-      cast<llvm::BasicBlock>(UnwindDest->Val));
-}
-
-void CatchSwitchInst::addHandler(BasicBlock *Dest) {
-  Ctx.getTracker().emplaceIfTracking<CatchSwitchAddHandler>(this);
-  cast<llvm::CatchSwitchInst>(Val)->addHandler(
-      cast<llvm::BasicBlock>(Dest->Val));
-}
-
-ResumeInst *ResumeInst::create(Value *Exn, BBIterator WhereIt,
-                               BasicBlock *WhereBB, Context &Ctx) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  auto *LLVMI = cast<llvm::ResumeInst>(Builder.CreateResume(Exn->Val));
-  return Ctx.createResumeInst(LLVMI);
-}
-
-Value *ResumeInst::getValue() const {
-  return Ctx.getValue(cast<llvm::ResumeInst>(Val)->getValue());
-}
-
-SwitchInst *SwitchInst::create(Value *V, BasicBlock *Dest, unsigned NumCases,
-                               BasicBlock::iterator WhereIt,
-                               BasicBlock *WhereBB, Context &Ctx,
-                               const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  llvm::SwitchInst *LLVMSwitch =
-      Builder.CreateSwitch(V->Val, cast<llvm::BasicBlock>(Dest->Val), NumCases);
-  return Ctx.createSwitchInst(LLVMSwitch);
-}
-
-Value *SwitchInst::getCondition() const {
-  return Ctx.getValue(cast<llvm::SwitchInst>(Val)->getCondition());
-}
-
-void SwitchInst::setCondition(Value *V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&SwitchInst::getCondition, &SwitchInst::setCondition>>(
-          this);
-  cast<llvm::SwitchInst>(Val)->setCondition(V->Val);
-}
-
-BasicBlock *SwitchInst::getDefaultDest() const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::SwitchInst>(Val)->getDefaultDest()));
-}
-
-void SwitchInst::setDefaultDest(BasicBlock *DefaultCase) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&SwitchInst::getDefaultDest,
-                                       &SwitchInst::setDefaultDest>>(this);
-  cast<llvm::SwitchInst>(Val)->setDefaultDest(
-      cast<llvm::BasicBlock>(DefaultCase->Val));
-}
-ConstantInt *SwitchInst::findCaseDest(BasicBlock *BB) {
-  auto *LLVMC = cast<llvm::SwitchInst>(Val)->findCaseDest(
-      cast<llvm::BasicBlock>(BB->Val));
-  return LLVMC != nullptr ? cast<ConstantInt>(Ctx.getValue(LLVMC)) : nullptr;
-}
-
-void SwitchInst::addCase(ConstantInt *OnVal, BasicBlock *Dest) {
-  Ctx.getTracker().emplaceIfTracking<SwitchAddCase>(this, OnVal);
-  // TODO: Track this!
-  cast<llvm::SwitchInst>(Val)->addCase(cast<llvm::ConstantInt>(OnVal->Val),
-                                       cast<llvm::BasicBlock>(Dest->Val));
-}
-
-SwitchInst::CaseIt SwitchInst::removeCase(CaseIt It) {
-  auto &Case = *It;
-  Ctx.getTracker().emplaceIfTracking<SwitchRemoveCase>(
-      this, Case.getCaseValue(), Case.getCaseSuccessor());
-
-  auto *LLVMSwitch = cast<llvm::SwitchInst>(Val);
-  unsigned CaseNum = It - case_begin();
-  llvm::SwitchInst::CaseIt LLVMIt(LLVMSwitch, CaseNum);
-  auto LLVMCaseIt = LLVMSwitch->removeCase(LLVMIt);
-  unsigned Num = LLVMCaseIt - LLVMSwitch->case_begin();
-  return CaseIt(this, Num);
-}
-
-BasicBlock *SwitchInst::getSuccessor(unsigned Idx) const {
-  return cast<BasicBlock>(
-      Ctx.getValue(cast<llvm::SwitchInst>(Val)->getSuccessor(Idx)));
-}
-
-void SwitchInst::setSuccessor(unsigned Idx, BasicBlock *NewSucc) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetterWithIdx<&SwitchInst::getSuccessor,
-                                              &SwitchInst::setSuccessor>>(this,
-                                                                          Idx);
-  cast<llvm::SwitchInst>(Val)->setSuccessor(
-      Idx, cast<llvm::BasicBlock>(NewSucc->Val));
-}
-
-Value *UnaryOperator::create(Instruction::Opcode Op, Value *OpV,
-                             BBIterator WhereIt, BasicBlock *WhereBB,
-                             Context &Ctx, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt == WhereBB->end())
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  else
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  auto *NewLLVMV = Builder.CreateUnOp(getLLVMUnaryOp(Op), OpV->Val, Name);
-  if (auto *NewUnOpV = dyn_cast<llvm::UnaryOperator>(NewLLVMV)) {
-    return Ctx.createUnaryOperator(NewUnOpV);
-  }
-  assert(isa<llvm::Constant>(NewLLVMV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewLLVMV));
-}
-
-Value *UnaryOperator::create(Instruction::Opcode Op, Value *OpV,
-                             Instruction *InsertBefore, Context &Ctx,
-                             const Twine &Name) {
-  return create(Op, OpV, InsertBefore->getIterator(), InsertBefore->getParent(),
-                Ctx, Name);
-}
-
-Value *UnaryOperator::create(Instruction::Opcode Op, Value *OpV,
-                             BasicBlock *InsertAfter, Context &Ctx,
-                             const Twine &Name) {
-  return create(Op, OpV, InsertAfter->end(), InsertAfter, Ctx, Name);
-}
-
-Value *UnaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
-                                            Value *CopyFrom, BBIterator WhereIt,
-                                            BasicBlock *WhereBB, Context &Ctx,
-                                            const Twine &Name) {
-  auto *NewV = create(Op, OpV, WhereIt, WhereBB, Ctx, Name);
-  if (auto *UnI = dyn_cast<llvm::UnaryOperator>(NewV->Val))
-    UnI->copyIRFlags(CopyFrom->Val);
-  return NewV;
-}
-
-Value *UnaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
-                                            Value *CopyFrom,
-                                            Instruction *InsertBefore,
-                                            Context &Ctx, const Twine &Name) {
-  return createWithCopiedFlags(Op, OpV, CopyFrom, InsertBefore->getIterator(),
-                               InsertBefore->getParent(), Ctx, Name);
-}
-
-Value *UnaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *OpV,
-                                            Value *CopyFrom,
-                                            BasicBlock *InsertAtEnd,
-                                            Context &Ctx, const Twine &Name) {
-  return createWithCopiedFlags(Op, OpV, CopyFrom, InsertAtEnd->end(),
-                               InsertAtEnd, Ctx, Name);
-}
-
-/// \Returns the LLVM opcode that corresponds to \p Opc.
-static llvm::Instruction::BinaryOps getLLVMBinaryOp(Instruction::Opcode Opc) {
-  switch (Opc) {
-  case Instruction::Opcode::Add:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Add);
-  case Instruction::Opcode::FAdd:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FAdd);
-  case Instruction::Opcode::Sub:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Sub);
-  case Instruction::Opcode::FSub:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FSub);
-  case Instruction::Opcode::Mul:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Mul);
-  case Instruction::Opcode::FMul:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FMul);
-  case Instruction::Opcode::UDiv:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::UDiv);
-  case Instruction::Opcode::SDiv:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::SDiv);
-  case Instruction::Opcode::FDiv:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FDiv);
-  case Instruction::Opcode::URem:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::URem);
-  case Instruction::Opcode::SRem:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::SRem);
-  case Instruction::Opcode::FRem:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::FRem);
-  case Instruction::Opcode::Shl:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Shl);
-  case Instruction::Opcode::LShr:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::LShr);
-  case Instruction::Opcode::AShr:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::AShr);
-  case Instruction::Opcode::And:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::And);
-  case Instruction::Opcode::Or:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Or);
-  case Instruction::Opcode::Xor:
-    return static_cast<llvm::Instruction::BinaryOps>(llvm::Instruction::Xor);
-  default:
-    llvm_unreachable("Not a binary op!");
-  }
-}
-Value *BinaryOperator::create(Instruction::Opcode Op, Value *LHS, Value *RHS,
-                              BBIterator WhereIt, BasicBlock *WhereBB,
-                              Context &Ctx, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt == WhereBB->end())
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  else
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  llvm::Value *NewV =
-      Builder.CreateBinOp(getLLVMBinaryOp(Op), LHS->Val, RHS->Val, Name);
-  if (auto *NewBinOp = dyn_cast<llvm::BinaryOperator>(NewV))
-    return Ctx.createBinaryOperator(NewBinOp);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *BinaryOperator::create(Instruction::Opcode Op, Value *LHS, Value *RHS,
-                              Instruction *InsertBefore, Context &Ctx,
-                              const Twine &Name) {
-  return create(Op, LHS, RHS, InsertBefore->getIterator(),
-                InsertBefore->getParent(), Ctx, Name);
-}
-
-Value *BinaryOperator::create(Instruction::Opcode Op, Value *LHS, Value *RHS,
-                              BasicBlock *InsertAtEnd, Context &Ctx,
-                              const Twine &Name) {
-  return create(Op, LHS, RHS, InsertAtEnd->end(), InsertAtEnd, Ctx, Name);
-}
-
-Value *BinaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
-                                             Value *RHS, Value *CopyFrom,
-                                             BBIterator WhereIt,
-                                             BasicBlock *WhereBB, Context &Ctx,
-                                             const Twine &Name) {
-
-  Value *NewV = create(Op, LHS, RHS, WhereIt, WhereBB, Ctx, Name);
-  if (auto *NewBO = dyn_cast<BinaryOperator>(NewV))
-    cast<llvm::BinaryOperator>(NewBO->Val)->copyIRFlags(CopyFrom->Val);
-  return NewV;
-}
-
-Value *BinaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
-                                             Value *RHS, Value *CopyFrom,
-                                             Instruction *InsertBefore,
-                                             Context &Ctx, const Twine &Name) {
-  return createWithCopiedFlags(Op, LHS, RHS, CopyFrom,
-                               InsertBefore->getIterator(),
-                               InsertBefore->getParent(), Ctx, Name);
-}
-
-Value *BinaryOperator::createWithCopiedFlags(Instruction::Opcode Op, Value *LHS,
-                                             Value *RHS, Value *CopyFrom,
-                                             BasicBlock *InsertAtEnd,
-                                             Context &Ctx, const Twine &Name) {
-  return createWithCopiedFlags(Op, LHS, RHS, CopyFrom, InsertAtEnd->end(),
-                               InsertAtEnd, Ctx, Name);
-}
-
-void PossiblyDisjointInst::setIsDisjoint(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&PossiblyDisjointInst::isDisjoint,
-                                       &PossiblyDisjointInst::setIsDisjoint>>(
-          this);
-  cast<llvm::PossiblyDisjointInst>(Val)->setIsDisjoint(B);
-}
-
-void AtomicRMWInst::setAlignment(Align Align) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicRMWInst::getAlign,
-                                       &AtomicRMWInst::setAlignment>>(this);
-  cast<llvm::AtomicRMWInst>(Val)->setAlignment(Align);
-}
-
-void AtomicRMWInst::setVolatile(bool V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicRMWInst::isVolatile,
-                                       &AtomicRMWInst::setVolatile>>(this);
-  cast<llvm::AtomicRMWInst>(Val)->setVolatile(V);
-}
-
-void AtomicRMWInst::setOrdering(AtomicOrdering Ordering) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicRMWInst::getOrdering,
-                                       &AtomicRMWInst::setOrdering>>(this);
-  cast<llvm::AtomicRMWInst>(Val)->setOrdering(Ordering);
-}
-
-void AtomicRMWInst::setSyncScopeID(SyncScope::ID SSID) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicRMWInst::getSyncScopeID,
-                                       &AtomicRMWInst::setSyncScopeID>>(this);
-  cast<llvm::AtomicRMWInst>(Val)->setSyncScopeID(SSID);
-}
-
-Value *AtomicRMWInst::getPointerOperand() {
-  return Ctx.getValue(cast<llvm::AtomicRMWInst>(Val)->getPointerOperand());
-}
-
-Value *AtomicRMWInst::getValOperand() {
-  return Ctx.getValue(cast<llvm::AtomicRMWInst>(Val)->getValOperand());
-}
-
-AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
-                                     MaybeAlign Align, AtomicOrdering Ordering,
-                                     BBIterator WhereIt, BasicBlock *WhereBB,
-                                     Context &Ctx, SyncScope::ID SSID,
-                                     const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt == WhereBB->end())
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  else
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  auto *LLVMAtomicRMW =
-      Builder.CreateAtomicRMW(Op, Ptr->Val, Val->Val, Align, Ordering, SSID);
-  LLVMAtomicRMW->setName(Name);
-  return Ctx.createAtomicRMWInst(LLVMAtomicRMW);
-}
-
-AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
-                                     MaybeAlign Align, AtomicOrdering Ordering,
-                                     Instruction *InsertBefore, Context &Ctx,
-                                     SyncScope::ID SSID, const Twine &Name) {
-  return create(Op, Ptr, Val, Align, Ordering, InsertBefore->getIterator(),
-                InsertBefore->getParent(), Ctx, SSID, Name);
-}
-
-AtomicRMWInst *AtomicRMWInst::create(BinOp Op, Value *Ptr, Value *Val,
-                                     MaybeAlign Align, AtomicOrdering Ordering,
-                                     BasicBlock *InsertAtEnd, Context &Ctx,
-                                     SyncScope::ID SSID, const Twine &Name) {
-  return create(Op, Ptr, Val, Align, Ordering, InsertAtEnd->end(), InsertAtEnd,
-                Ctx, SSID, Name);
-}
-
-void AtomicCmpXchgInst::setSyncScopeID(SyncScope::ID SSID) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getSyncScopeID,
-                                       &AtomicCmpXchgInst::setSyncScopeID>>(
-          this);
-  cast<llvm::AtomicCmpXchgInst>(Val)->setSyncScopeID(SSID);
-}
-
-Value *AtomicCmpXchgInst::getPointerOperand() {
-  return Ctx.getValue(cast<llvm::AtomicCmpXchgInst>(Val)->getPointerOperand());
-}
-
-Value *AtomicCmpXchgInst::getCompareOperand() {
-  return Ctx.getValue(cast<llvm::AtomicCmpXchgInst>(Val)->getCompareOperand());
-}
-
-Value *AtomicCmpXchgInst::getNewValOperand() {
-  return Ctx.getValue(cast<llvm::AtomicCmpXchgInst>(Val)->getNewValOperand());
-}
-
-AtomicCmpXchgInst *
-AtomicCmpXchgInst::create(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align,
-                          AtomicOrdering SuccessOrdering,
-                          AtomicOrdering FailureOrdering, BBIterator WhereIt,
-                          BasicBlock *WhereBB, Context &Ctx, SyncScope::ID SSID,
-                          const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt == WhereBB->end())
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  else
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  auto *LLVMAtomicCmpXchg =
-      Builder.CreateAtomicCmpXchg(Ptr->Val, Cmp->Val, New->Val, Align,
-                                  SuccessOrdering, FailureOrdering, SSID);
-  LLVMAtomicCmpXchg->setName(Name);
-  return Ctx.createAtomicCmpXchgInst(LLVMAtomicCmpXchg);
-}
-
-AtomicCmpXchgInst *AtomicCmpXchgInst::create(Value *Ptr, Value *Cmp, Value *New,
-                                             MaybeAlign Align,
-                                             AtomicOrdering SuccessOrdering,
-                                             AtomicOrdering FailureOrdering,
-                                             Instruction *InsertBefore,
-                                             Context &Ctx, SyncScope::ID SSID,
-                                             const Twine &Name) {
-  return create(Ptr, Cmp, New, Align, SuccessOrdering, FailureOrdering,
-                InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
-                SSID, Name);
-}
-
-AtomicCmpXchgInst *AtomicCmpXchgInst::create(Value *Ptr, Value *Cmp, Value *New,
-                                             MaybeAlign Align,
-                                             AtomicOrdering SuccessOrdering,
-                                             AtomicOrdering FailureOrdering,
-                                             BasicBlock *InsertAtEnd,
-                                             Context &Ctx, SyncScope::ID SSID,
-                                             const Twine &Name) {
-  return create(Ptr, Cmp, New, Align, SuccessOrdering, FailureOrdering,
-                InsertAtEnd->end(), InsertAtEnd, Ctx, SSID, Name);
-}
-
-void AtomicCmpXchgInst::setAlignment(Align Align) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getAlign,
-                                       &AtomicCmpXchgInst::setAlignment>>(this);
-  cast<llvm::AtomicCmpXchgInst>(Val)->setAlignment(Align);
-}
-
-void AtomicCmpXchgInst::setVolatile(bool V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::isVolatile,
-                                       &AtomicCmpXchgInst::setVolatile>>(this);
-  cast<llvm::AtomicCmpXchgInst>(Val)->setVolatile(V);
-}
-
-void AtomicCmpXchgInst::setWeak(bool IsWeak) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::isWeak,
-                                       &AtomicCmpXchgInst::setWeak>>(this);
-  cast<llvm::AtomicCmpXchgInst>(Val)->setWeak(IsWeak);
-}
-
-void AtomicCmpXchgInst::setSuccessOrdering(AtomicOrdering Ordering) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getSuccessOrdering,
-                                       &AtomicCmpXchgInst::setSuccessOrdering>>(
-          this);
-  cast<llvm::AtomicCmpXchgInst>(Val)->setSuccessOrdering(Ordering);
-}
-
-void AtomicCmpXchgInst::setFailureOrdering(AtomicOrdering Ordering) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AtomicCmpXchgInst::getFailureOrdering,
-                                       &AtomicCmpXchgInst::setFailureOrdering>>(
-          this);
-  cast<llvm::AtomicCmpXchgInst>(Val)->setFailureOrdering(Ordering);
-}
-
-AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace, BBIterator WhereIt,
-                               BasicBlock *WhereBB, Context &Ctx,
-                               Value *ArraySize, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt == WhereBB->end())
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  else
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  auto *NewAlloca =
-      Builder.CreateAlloca(Ty->LLVMTy, AddrSpace, ArraySize->Val, Name);
-  return Ctx.createAllocaInst(NewAlloca);
-}
-
-AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace,
-                               Instruction *InsertBefore, Context &Ctx,
-                               Value *ArraySize, const Twine &Name) {
-  return create(Ty, AddrSpace, InsertBefore->getIterator(),
-                InsertBefore->getParent(), Ctx, ArraySize, Name);
-}
-
-AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace,
-                               BasicBlock *InsertAtEnd, Context &Ctx,
-                               Value *ArraySize, const Twine &Name) {
-  return create(Ty, AddrSpace, InsertAtEnd->end(), InsertAtEnd, Ctx, ArraySize,
-                Name);
-}
-
-Type *AllocaInst::getAllocatedType() const {
-  return Ctx.getType(cast<llvm::AllocaInst>(Val)->getAllocatedType());
-}
-
-void AllocaInst::setAllocatedType(Type *Ty) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AllocaInst::getAllocatedType,
-                                       &AllocaInst::setAllocatedType>>(this);
-  cast<llvm::AllocaInst>(Val)->setAllocatedType(Ty->LLVMTy);
-}
-
-void AllocaInst::setAlignment(Align Align) {
-  Ctx.getTracker()
-      .emplaceIfTracking<
-          GenericSetter<&AllocaInst::getAlign, &AllocaInst::setAlignment>>(
-          this);
-  cast<llvm::AllocaInst>(Val)->setAlignment(Align);
-}
-
-void AllocaInst::setUsedWithInAlloca(bool V) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&AllocaInst::isUsedWithInAlloca,
-                                       &AllocaInst::setUsedWithInAlloca>>(this);
-  cast<llvm::AllocaInst>(Val)->setUsedWithInAlloca(V);
-}
-
-Value *AllocaInst::getArraySize() {
-  return Ctx.getValue(cast<llvm::AllocaInst>(Val)->getArraySize());
-}
-
-PointerType *AllocaInst::getType() const {
-  return cast<PointerType>(Ctx.getType(cast<llvm::AllocaInst>(Val)->getType()));
-}
-
-Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
-                        BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
-                        const Twine &Name) {
-  assert(getLLVMCastOp(Op) && "Opcode not suitable for CastInst!");
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt == WhereBB->end())
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  else
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  auto *NewV =
-      Builder.CreateCast(getLLVMCastOp(Op), Operand->Val, DestTy->LLVMTy, Name);
-  if (auto *NewCI = dyn_cast<llvm::CastInst>(NewV))
-    return Ctx.createCastInst(NewCI);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
-                        Instruction *InsertBefore, Context &Ctx,
-                        const Twine &Name) {
-  return create(DestTy, Op, Operand, InsertBefore->getIterator(),
-                InsertBefore->getParent(), Ctx, Name);
-}
-
-Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
-                        BasicBlock *InsertAtEnd, Context &Ctx,
-                        const Twine &Name) {
-  return create(DestTy, Op, Operand, InsertAtEnd->end(), InsertAtEnd, Ctx,
-                Name);
-}
-
-bool CastInst::classof(const Value *From) {
-  return From->getSubclassID() == ClassID::Cast;
-}
-
-Type *CastInst::getSrcTy() const {
-  return Ctx.getType(cast<llvm::CastInst>(Val)->getSrcTy());
-}
-
-Type *CastInst::getDestTy() const {
-  return Ctx.getType(cast<llvm::CastInst>(Val)->getDestTy());
-}
-
-void PossiblyNonNegInst::setNonNeg(bool B) {
-  Ctx.getTracker()
-      .emplaceIfTracking<GenericSetter<&PossiblyNonNegInst::hasNonNeg,
-                                       &PossiblyNonNegInst::setNonNeg>>(this);
-  cast<llvm::PossiblyNonNegInst>(Val)->setNonNeg(B);
-}
-
-Value *InsertElementInst::create(Value *Vec, Value *NewElt, Value *Idx,
-                                 Instruction *InsertBefore, Context &Ctx,
-                                 const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
-  llvm::Value *NewV =
-      Builder.CreateInsertElement(Vec->Val, NewElt->Val, Idx->Val, Name);
-  if (auto *NewInsert = dyn_cast<llvm::InsertElementInst>(NewV))
-    return Ctx.createInsertElementInst(NewInsert);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *InsertElementInst::create(Value *Vec, Value *NewElt, Value *Idx,
-                                 BasicBlock *InsertAtEnd, Context &Ctx,
-                                 const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  llvm::Value *NewV =
-      Builder.CreateInsertElement(Vec->Val, NewElt->Val, Idx->Val, Name);
-  if (auto *NewInsert = dyn_cast<llvm::InsertElementInst>(NewV))
-    return Ctx.createInsertElementInst(NewInsert);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *ExtractElementInst::create(Value *Vec, Value *Idx,
-                                  Instruction *InsertBefore, Context &Ctx,
-                                  const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
-  llvm::Value *NewV = Builder.CreateExtractElement(Vec->Val, Idx->Val, Name);
-  if (auto *NewExtract = dyn_cast<llvm::ExtractElementInst>(NewV))
-    return Ctx.createExtractElementInst(NewExtract);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *ExtractElementInst::create(Value *Vec, Value *Idx,
-                                  BasicBlock *InsertAtEnd, Context &Ctx,
-                                  const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  llvm::Value *NewV = Builder.CreateExtractElement(Vec->Val, Idx->Val, Name);
-  if (auto *NewExtract = dyn_cast<llvm::ExtractElementInst>(NewV))
-    return Ctx.createExtractElementInst(NewExtract);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *ShuffleVectorInst::create(Value *V1, Value *V2, Value *Mask,
-                                 Instruction *InsertBefore, Context &Ctx,
-                                 const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
-  llvm::Value *NewV =
-      Builder.CreateShuffleVector(V1->Val, V2->Val, Mask->Val, Name);
-  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
-    return Ctx.createShuffleVectorInst(NewShuffle);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *ShuffleVectorInst::create(Value *V1, Value *V2, Value *Mask,
-                                 BasicBlock *InsertAtEnd, Context &Ctx,
-                                 const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  llvm::Value *NewV =
-      Builder.CreateShuffleVector(V1->Val, V2->Val, Mask->Val, Name);
-  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
-    return Ctx.createShuffleVectorInst(NewShuffle);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *ShuffleVectorInst::create(Value *V1, Value *V2, ArrayRef<int> Mask,
-                                 Instruction *InsertBefore, Context &Ctx,
-                                 const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
-  llvm::Value *NewV = Builder.CreateShuffleVector(V1->Val, V2->Val, Mask, Name);
-  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
-    return Ctx.createShuffleVectorInst(NewShuffle);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Value *ShuffleVectorInst::create(Value *V1, Value *V2, ArrayRef<int> Mask,
-                                 BasicBlock *InsertAtEnd, Context &Ctx,
-                                 const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
-  llvm::Value *NewV = Builder.CreateShuffleVector(V1->Val, V2->Val, Mask, Name);
-  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
-    return Ctx.createShuffleVectorInst(NewShuffle);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-void ShuffleVectorInst::setShuffleMask(ArrayRef<int> Mask) {
-  Ctx.getTracker().emplaceIfTracking<ShuffleVectorSetMask>(this);
-  cast<llvm::ShuffleVectorInst>(Val)->setShuffleMask(Mask);
-}
-
-VectorType *ShuffleVectorInst::getType() const {
-  return cast<VectorType>(
-      Ctx.getType(cast<llvm::ShuffleVectorInst>(Val)->getType()));
-}
-
-void ShuffleVectorInst::commute() {
-  Ctx.getTracker().emplaceIfTracking<ShuffleVectorSetMask>(this);
-  Ctx.getTracker().emplaceIfTracking<UseSwap>(getOperandUse(0),
-                                              getOperandUse(1));
-  cast<llvm::ShuffleVectorInst>(Val)->commute();
-}
-
-Constant *ShuffleVectorInst::getShuffleMaskForBitcode() const {
-  return Ctx.getOrCreateConstant(
-      cast<llvm::ShuffleVectorInst>(Val)->getShuffleMaskForBitcode());
-}
-
-Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(ArrayRef<int> Mask,
-                                                          Type *ResultTy) {
-  return ResultTy->getContext().getOrCreateConstant(
-      llvm::ShuffleVectorInst::convertShuffleMaskForBitcode(Mask,
-                                                            ResultTy->LLVMTy));
-}
-
-VectorType *ExtractElementInst::getVectorOperandType() const {
-  return cast<VectorType>(Ctx.getType(getVectorOperand()->getType()->LLVMTy));
-}
-
-Value *ExtractValueInst::create(Value *Agg, ArrayRef<unsigned> Idxs,
-                                BBIterator WhereIt, BasicBlock *WhereBB,
-                                Context &Ctx, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  llvm::Value *NewV = Builder.CreateExtractValue(Agg->Val, Idxs, Name);
-  if (auto *NewExtractValueInst = dyn_cast<llvm::ExtractValueInst>(NewV))
-    return Ctx.createExtractValueInst(NewExtractValueInst);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-Type *ExtractValueInst::getIndexedType(Type *Agg, ArrayRef<unsigned> Idxs) {
-  auto *LLVMTy = llvm::ExtractValueInst::getIndexedType(Agg->LLVMTy, Idxs);
-  return Agg->getContext().getType(LLVMTy);
-}
-
-Value *InsertValueInst::create(Value *Agg, Value *Val, ArrayRef<unsigned> Idxs,
-                               BBIterator WhereIt, BasicBlock *WhereBB,
-                               Context &Ctx, const Twine &Name) {
-  auto &Builder = Ctx.getLLVMIRBuilder();
-  if (WhereIt != WhereBB->end())
-    Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
-  else
-    Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
-  llvm::Value *NewV = Builder.CreateInsertValue(Agg->Val, Val->Val, Idxs, Name);
-  if (auto *NewInsertValueInst = dyn_cast<llvm::InsertValueInst>(NewV))
-    return Ctx.createInsertValueInst(NewInsertValueInst);
-  assert(isa<llvm::Constant>(NewV) && "Expected constant");
-  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
-}
-
-ConstantTokenNone *ConstantTokenNone::get(Context &Ctx) {
-  auto *LLVMC = llvm::ConstantTokenNone::get(Ctx.LLVMCtx);
-  return cast<ConstantTokenNone>(Ctx.getOrCreateConstant(LLVMC));
-}
diff --git a/llvm/lib/SandboxIR/Tracker.cpp b/llvm/lib/SandboxIR/Tracker.cpp
index b1f472d7928f4a..abcad39330094d 100644
--- a/llvm/lib/SandboxIR/Tracker.cpp
+++ b/llvm/lib/SandboxIR/Tracker.cpp
@@ -10,7 +10,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Instruction.h"
-#include "llvm/SandboxIR/SandboxIR.h"
+#include "llvm/SandboxIR/Instruction.h"
 #include <sstream>
 
 using namespace llvm::sandboxir;
diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp
index 0c44d05f0474d5..7ebbcabb004df7 100644
--- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp
+++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/SandboxIR/Instruction.h"
 
 using namespace llvm::sandboxir;
 
diff --git a/llvm/unittests/SandboxIR/TrackerTest.cpp b/llvm/unittests/SandboxIR/TrackerTest.cpp
index da5416395ec42f..5823f4e14a8542 100644
--- a/llvm/unittests/SandboxIR/TrackerTest.cpp
+++ b/llvm/unittests/SandboxIR/TrackerTest.cpp
@@ -11,7 +11,7 @@
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Module.h"
-#include "llvm/SandboxIR/SandboxIR.h"
+#include "llvm/SandboxIR/Instruction.h"
 #include "llvm/Support/SourceMgr.h"
 #include "gmock/gmock-matchers.h"
 #include "gtest/gtest.h"
diff --git a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp
index a136be41ae363b..89255a108ed6cb 100644
--- a/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp
@@ -8,7 +8,7 @@
 
 #include "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h"
 #include "llvm/AsmParser/Parser.h"
-#include "llvm/SandboxIR/SandboxIR.h"
+#include "llvm/SandboxIR/Instruction.h"
 #include "llvm/Support/SourceMgr.h"
 #include "gtest/gtest.h"
 



More information about the llvm-commits mailing list