Files
Ryan Prichard 6024e5c395 Update prebuilt Clang to r547379 (20.0.0).
clang 20.0.0 (based on r547379) from build 12806354.

Bug: http://b/379133546
Test: N/A
Change-Id: I2eb8938af55d809de674be63cb30cf27e801862b

Upstream-Commit: ad834e67b1105d15ef907f6255d4c96e8e733f57
2025-11-26 14:59:46 -05:00

2955 lines
119 KiB
C++

//===- SandboxIR.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
//
//===----------------------------------------------------------------------===//
//
// Sandbox IR is a lightweight overlay transactional IR on top of LLVM IR.
// Features:
// - You can save/rollback the state of the IR at any time.
// - Any changes made to Sandbox IR will automatically update the underlying
// LLVM IR so both IRs are always in sync.
// - Feels like LLVM IR, similar API.
//
// SandboxIR forms a class hierarchy that resembles that of LLVM IR
// but is in the `sandboxir` namespace:
//
// namespace sandboxir {
//
// Value -+- Argument
// |
// +- BasicBlock
// |
// +- User ------+- Constant ------ Function
// |
// +- Instruction -+- BinaryOperator
// |
// +- BranchInst
// |
// +- CastInst --------+- AddrSpaceCastInst
// | |
// | +- BitCastInst
// | |
// | +- FPExtInst
// | |
// | +- FPToSIInst
// | |
// | +- FPToUIInst
// | |
// | +- FPTruncInst
// | |
// | +- IntToPtrInst
// | |
// | +- PtrToIntInst
// | |
// | +- SExtInst
// | |
// | +- SIToFPInst
// | |
// | +- TruncInst
// | |
// | +- UIToFPInst
// | |
// | +- ZExtInst
// |
// +- CallBase -----------+- CallBrInst
// | |
// +- CmpInst +- CallInst
// | |
// +- ExtractElementInst +- InvokeInst
// |
// +- GetElementPtrInst
// |
// +- InsertElementInst
// |
// +- OpaqueInst
// |
// +- PHINode
// |
// +- ReturnInst
// |
// +- SelectInst
// |
// +- ShuffleVectorInst
// |
// +- StoreInst
// |
// +- UnaryInstruction -+- LoadInst
// | |
// | +- CastInst
// |
// +- UnaryOperator
// |
// +- UnreachableInst
//
// Use
//
// } // namespace sandboxir
//
#ifndef LLVM_SANDBOXIR_SANDBOXIR_H
#define LLVM_SANDBOXIR_SANDBOXIR_H
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/User.h"
#include "llvm/IR/Value.h"
#include "llvm/SandboxIR/Tracker.h"
#include "llvm/SandboxIR/Use.h"
#include "llvm/Support/raw_ostream.h"
#include <iterator>
namespace llvm {
namespace sandboxir {
class BasicBlock;
class ConstantInt;
class Context;
class Function;
class Instruction;
class SelectInst;
class ExtractElementInst;
class InsertElementInst;
class ShuffleVectorInst;
class BranchInst;
class UnaryInstruction;
class LoadInst;
class ReturnInst;
class StoreInst;
class User;
class UnreachableInst;
class Value;
class CallBase;
class CallInst;
class InvokeInst;
class CallBrInst;
class FuncletPadInst;
class CatchPadInst;
class CleanupPadInst;
class CatchReturnInst;
class GetElementPtrInst;
class CastInst;
class PtrToIntInst;
class BitCastInst;
class AllocaInst;
class CatchSwitchInst;
class SwitchInst;
class UnaryOperator;
class BinaryOperator;
class AtomicRMWInst;
class AtomicCmpXchgInst;
/// Iterator for the `Use` edges of a User's operands.
/// \Returns the operand `Use` when dereferenced.
class OperandUseIterator {
sandboxir::Use Use;
/// Don't let the user create a non-empty OperandUseIterator.
OperandUseIterator(const class Use &Use) : Use(Use) {}
friend class User; // For constructor
#define DEF_INSTR(ID, OPC, CLASS) friend class CLASS; // For constructor
#include "llvm/SandboxIR/SandboxIRValues.def"
public:
using difference_type = std::ptrdiff_t;
using value_type = sandboxir::Use;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::input_iterator_tag;
OperandUseIterator() = default;
value_type operator*() const;
OperandUseIterator &operator++();
OperandUseIterator operator++(int) {
auto Copy = *this;
this->operator++();
return Copy;
}
bool operator==(const OperandUseIterator &Other) const {
return Use == Other.Use;
}
bool operator!=(const OperandUseIterator &Other) const {
return !(*this == Other);
}
OperandUseIterator operator+(unsigned Num) const;
OperandUseIterator operator-(unsigned Num) const;
int operator-(const OperandUseIterator &Other) const;
};
/// Iterator for the `Use` edges of a Value's users.
/// \Returns a `Use` when dereferenced.
class UserUseIterator {
sandboxir::Use Use;
/// Don't let the user create a non-empty UserUseIterator.
UserUseIterator(const class Use &Use) : Use(Use) {}
friend class Value; // For constructor
public:
using difference_type = std::ptrdiff_t;
using value_type = sandboxir::Use;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::input_iterator_tag;
UserUseIterator() = default;
value_type operator*() const { return Use; }
UserUseIterator &operator++();
bool operator==(const UserUseIterator &Other) const {
return Use == Other.Use;
}
bool operator!=(const UserUseIterator &Other) const {
return !(*this == Other);
}
const sandboxir::Use &getUse() const { return Use; }
};
/// A SandboxIR Value has users. This is the base class.
class Value {
public:
enum class ClassID : unsigned {
#define DEF_VALUE(ID, CLASS) ID,
#define DEF_USER(ID, CLASS) ID,
#define DEF_INSTR(ID, OPC, CLASS) ID,
#include "llvm/SandboxIR/SandboxIRValues.def"
};
protected:
static const char *getSubclassIDStr(ClassID ID) {
switch (ID) {
#define DEF_VALUE(ID, CLASS) \
case ClassID::ID: \
return #ID;
#define DEF_USER(ID, CLASS) \
case ClassID::ID: \
return #ID;
#define DEF_INSTR(ID, OPC, CLASS) \
case ClassID::ID: \
return #ID;
#include "llvm/SandboxIR/SandboxIRValues.def"
}
llvm_unreachable("Unimplemented ID");
}
/// For isa/dyn_cast.
ClassID SubclassID;
#ifndef NDEBUG
/// A unique ID used for forming the name (used for debugging).
unsigned UID;
#endif
/// The LLVM Value that corresponds to this SandboxIR Value.
/// NOTE: Some sandboxir Instructions, like Packs, may include more than one
/// value and in these cases `Val` points to the last instruction in program
/// order.
llvm::Value *Val = nullptr;
friend class Context; // For getting `Val`.
friend class User; // For getting `Val`.
friend class Use; // For getting `Val`.
friend class SelectInst; // For getting `Val`.
friend class ExtractElementInst; // For getting `Val`.
friend class InsertElementInst; // For getting `Val`.
friend class ShuffleVectorInst; // For getting `Val`.
friend class BranchInst; // For getting `Val`.
friend class LoadInst; // For getting `Val`.
friend class StoreInst; // For getting `Val`.
friend class ReturnInst; // For getting `Val`.
friend class CallBase; // For getting `Val`.
friend class CallInst; // For getting `Val`.
friend class InvokeInst; // For getting `Val`.
friend class CallBrInst; // For getting `Val`.
friend class FuncletPadInst; // For getting `Val`.
friend class CatchPadInst; // For getting `Val`.
friend class CleanupPadInst; // For getting `Val`.
friend class CatchReturnInst; // For getting `Val`.
friend class GetElementPtrInst; // For getting `Val`.
friend class CatchSwitchInst; // For getting `Val`.
friend class SwitchInst; // For getting `Val`.
friend class UnaryOperator; // For getting `Val`.
friend class BinaryOperator; // For getting `Val`.
friend class AtomicRMWInst; // For getting `Val`.
friend class AtomicCmpXchgInst; // For getting `Val`.
friend class AllocaInst; // For getting `Val`.
friend class CastInst; // For getting `Val`.
friend class PHINode; // For getting `Val`.
friend class UnreachableInst; // For getting `Val`.
friend class CatchSwitchAddHandler; // For `Val`.
/// All values point to the context.
Context &Ctx;
// This is used by eraseFromParent().
void clearValue() { Val = nullptr; }
template <typename ItTy, typename SBTy> friend class LLVMOpUserItToSBTy;
Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx);
/// Disable copies.
Value(const Value &) = delete;
Value &operator=(const Value &) = delete;
public:
virtual ~Value() = default;
ClassID getSubclassID() const { return SubclassID; }
using use_iterator = UserUseIterator;
using const_use_iterator = UserUseIterator;
use_iterator use_begin();
const_use_iterator use_begin() const {
return const_cast<Value *>(this)->use_begin();
}
use_iterator use_end() { return use_iterator(Use(nullptr, nullptr, Ctx)); }
const_use_iterator use_end() const {
return const_cast<Value *>(this)->use_end();
}
iterator_range<use_iterator> uses() {
return make_range<use_iterator>(use_begin(), use_end());
}
iterator_range<const_use_iterator> uses() const {
return make_range<const_use_iterator>(use_begin(), use_end());
}
/// Helper for mapped_iterator.
struct UseToUser {
User *operator()(const Use &Use) const { return &*Use.getUser(); }
};
using user_iterator = mapped_iterator<sandboxir::UserUseIterator, UseToUser>;
using const_user_iterator = user_iterator;
user_iterator user_begin();
user_iterator user_end() {
return user_iterator(Use(nullptr, nullptr, Ctx), UseToUser());
}
const_user_iterator user_begin() const {
return const_cast<Value *>(this)->user_begin();
}
const_user_iterator user_end() const {
return const_cast<Value *>(this)->user_end();
}
iterator_range<user_iterator> users() {
return make_range<user_iterator>(user_begin(), user_end());
}
iterator_range<const_user_iterator> users() const {
return make_range<const_user_iterator>(user_begin(), user_end());
}
/// \Returns the number of user edges (not necessarily to unique users).
/// WARNING: This is a linear-time operation.
unsigned getNumUses() const;
/// Return true if this value has N uses or more.
/// This is logically equivalent to getNumUses() >= N.
/// WARNING: This can be expensive, as it is linear to the number of users.
bool hasNUsesOrMore(unsigned Num) const {
unsigned Cnt = 0;
for (auto It = use_begin(), ItE = use_end(); It != ItE; ++It) {
if (++Cnt >= Num)
return true;
}
return false;
}
/// Return true if this Value has exactly N uses.
bool hasNUses(unsigned Num) const {
unsigned Cnt = 0;
for (auto It = use_begin(), ItE = use_end(); It != ItE; ++It) {
if (++Cnt > Num)
return false;
}
return Cnt == Num;
}
Type *getType() const { return Val->getType(); }
Context &getContext() const { return Ctx; }
void replaceUsesWithIf(Value *OtherV,
llvm::function_ref<bool(const Use &)> ShouldReplace);
void replaceAllUsesWith(Value *Other);
/// \Returns the LLVM IR name of the bottom-most LLVM value.
StringRef getName() const { return Val->getName(); }
#ifndef NDEBUG
/// Should crash if there is something wrong with the instruction.
virtual void verify() const = 0;
/// Returns the unique id in the form 'SB<number>.' like 'SB1.'
std::string getUid() const;
virtual void dumpCommonHeader(raw_ostream &OS) const;
void dumpCommonFooter(raw_ostream &OS) const;
void dumpCommonPrefix(raw_ostream &OS) const;
void dumpCommonSuffix(raw_ostream &OS) const;
void printAsOperandCommon(raw_ostream &OS) const;
friend raw_ostream &operator<<(raw_ostream &OS, const sandboxir::Value &V) {
V.dumpOS(OS);
return OS;
}
virtual void dumpOS(raw_ostream &OS) const = 0;
LLVM_DUMP_METHOD void dump() const;
#endif
};
/// Argument of a sandboxir::Function.
class Argument : public sandboxir::Value {
Argument(llvm::Argument *Arg, sandboxir::Context &Ctx)
: sandboxir::Value(ClassID::Argument, Arg, Ctx) {}
friend class Context; // For constructor.
public:
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::Argument;
}
#ifndef NDEBUG
void verify() const final {
assert(isa<llvm::Argument>(Val) && "Expected Argument!");
}
void printAsOperand(raw_ostream &OS) const;
void dumpOS(raw_ostream &OS) const final;
#endif
};
/// A sandboxir::User has operands.
class User : public Value {
protected:
User(ClassID ID, llvm::Value *V, Context &Ctx) : Value(ID, V, Ctx) {}
/// \Returns the Use edge that corresponds to \p OpIdx.
/// Note: This is the default implementation that works for instructions that
/// match the underlying LLVM instruction. All others should use a different
/// implementation.
Use getOperandUseDefault(unsigned OpIdx, bool Verify) const;
/// \Returns the Use for the \p OpIdx'th operand. This is virtual to allow
/// instructions to deviate from the LLVM IR operands, which is a requirement
/// for sandboxir Instructions that consist of more than one LLVM Instruction.
virtual Use getOperandUseInternal(unsigned OpIdx, bool Verify) const = 0;
friend class OperandUseIterator; // for getOperandUseInternal()
/// The default implementation works only for single-LLVMIR-instruction
/// Users and only if they match exactly the LLVM instruction.
unsigned getUseOperandNoDefault(const Use &Use) const {
return Use.LLVMUse->getOperandNo();
}
/// \Returns the operand index of \p Use.
virtual unsigned getUseOperandNo(const Use &Use) const = 0;
friend unsigned Use::getOperandNo() const; // For getUseOperandNo()
void swapOperandsInternal(unsigned OpIdxA, unsigned OpIdxB) {
assert(OpIdxA < getNumOperands() && "OpIdxA out of bounds!");
assert(OpIdxB < getNumOperands() && "OpIdxB out of bounds!");
auto UseA = getOperandUse(OpIdxA);
auto UseB = getOperandUse(OpIdxB);
UseA.swap(UseB);
}
#ifndef NDEBUG
void verifyUserOfLLVMUse(const llvm::Use &Use) const;
#endif // NDEBUG
public:
/// For isa/dyn_cast.
static bool classof(const Value *From);
using op_iterator = OperandUseIterator;
using const_op_iterator = OperandUseIterator;
using op_range = iterator_range<op_iterator>;
using const_op_range = iterator_range<const_op_iterator>;
virtual op_iterator op_begin() {
assert(isa<llvm::User>(Val) && "Expect User value!");
return op_iterator(getOperandUseInternal(0, /*Verify=*/false));
}
virtual op_iterator op_end() {
assert(isa<llvm::User>(Val) && "Expect User value!");
return op_iterator(
getOperandUseInternal(getNumOperands(), /*Verify=*/false));
}
virtual const_op_iterator op_begin() const {
return const_cast<User *>(this)->op_begin();
}
virtual const_op_iterator op_end() const {
return const_cast<User *>(this)->op_end();
}
op_range operands() { return make_range<op_iterator>(op_begin(), op_end()); }
const_op_range operands() const {
return make_range<const_op_iterator>(op_begin(), op_end());
}
Value *getOperand(unsigned OpIdx) const { return getOperandUse(OpIdx).get(); }
/// \Returns the operand edge for \p OpIdx. NOTE: This should also work for
/// OpIdx == getNumOperands(), which is used for op_end().
Use getOperandUse(unsigned OpIdx) const {
return getOperandUseInternal(OpIdx, /*Verify=*/true);
}
virtual unsigned getNumOperands() const {
return isa<llvm::User>(Val) ? cast<llvm::User>(Val)->getNumOperands() : 0;
}
virtual void setOperand(unsigned OperandIdx, Value *Operand);
/// Replaces any operands that match \p FromV with \p ToV. Returns whether any
/// operands were replaced.
bool replaceUsesOfWith(Value *FromV, Value *ToV);
#ifndef NDEBUG
void verify() const override {
assert(isa<llvm::User>(Val) && "Expected User!");
}
void dumpCommonHeader(raw_ostream &OS) const final;
void dumpOS(raw_ostream &OS) const override {
// TODO: Remove this tmp implementation once we get the Instruction classes.
}
#endif
};
class Constant : public sandboxir::User {
Constant(llvm::Constant *C, sandboxir::Context &SBCtx)
: sandboxir::User(ClassID::Constant, C, SBCtx) {}
Constant(ClassID ID, llvm::Constant *C, sandboxir::Context &SBCtx)
: sandboxir::User(ID, C, SBCtx) {}
friend class ConstantInt; // For constructor.
friend class Function; // For constructor
friend class Context; // For constructor.
Use getOperandUseInternal(unsigned OpIdx, bool Verify) const override {
return getOperandUseDefault(OpIdx, Verify);
}
public:
/// For isa/dyn_cast.
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::Constant ||
From->getSubclassID() == ClassID::ConstantInt ||
From->getSubclassID() == ClassID::Function;
}
sandboxir::Context &getParent() const { return getContext(); }
unsigned getUseOperandNo(const Use &Use) const override {
return getUseOperandNoDefault(Use);
}
#ifndef NDEBUG
void verify() const override {
assert(isa<llvm::Constant>(Val) && "Expected Constant!");
}
void dumpOS(raw_ostream &OS) const override;
#endif
};
class ConstantInt : public Constant {
ConstantInt(llvm::ConstantInt *C, sandboxir::Context &Ctx)
: Constant(ClassID::ConstantInt, C, Ctx) {}
friend class Context; // For constructor.
Use getOperandUseInternal(unsigned OpIdx, bool Verify) const final {
llvm_unreachable("ConstantInt has no operands!");
}
public:
/// If Ty is a vector type, return a Constant with a splat of the given
/// value. Otherwise return a ConstantInt for the given value.
static ConstantInt *get(Type *Ty, uint64_t V, Context &Ctx,
bool IsSigned = false);
// TODO: Implement missing functions.
/// For isa/dyn_cast.
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::ConstantInt;
}
unsigned getUseOperandNo(const Use &Use) const override {
llvm_unreachable("ConstantInt has no operands!");
}
#ifndef NDEBUG
void verify() const override {
assert(isa<llvm::ConstantInt>(Val) && "Expected a ConstantInst!");
}
void dumpOS(raw_ostream &OS) const override {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
#endif
};
/// Iterator for `Instruction`s in a `BasicBlock.
/// \Returns an sandboxir::Instruction & when derereferenced.
class BBIterator {
public:
using difference_type = std::ptrdiff_t;
using value_type = Instruction;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::bidirectional_iterator_tag;
private:
llvm::BasicBlock *BB;
llvm::BasicBlock::iterator It;
Context *Ctx;
pointer getInstr(llvm::BasicBlock::iterator It) const;
public:
BBIterator() : BB(nullptr), Ctx(nullptr) {}
BBIterator(llvm::BasicBlock *BB, llvm::BasicBlock::iterator It, Context *Ctx)
: BB(BB), It(It), Ctx(Ctx) {}
reference operator*() const { return *getInstr(It); }
BBIterator &operator++();
BBIterator operator++(int) {
auto Copy = *this;
++*this;
return Copy;
}
BBIterator &operator--();
BBIterator operator--(int) {
auto Copy = *this;
--*this;
return Copy;
}
bool operator==(const BBIterator &Other) const {
assert(Ctx == Other.Ctx && "BBIterators in different context!");
return It == Other.It;
}
bool operator!=(const BBIterator &Other) const { return !(*this == Other); }
/// \Returns the SBInstruction that corresponds to this iterator, or null if
/// the instruction is not found in the IR-to-SandboxIR tables.
pointer get() const { return getInstr(It); }
};
/// Contains a list of sandboxir::Instruction's.
class BasicBlock : public Value {
/// Builds a graph that contains all values in \p BB in their original form
/// i.e., no vectorization is taking place here.
void buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB);
friend class Context; // For `buildBasicBlockFromIR`
friend class Instruction; // For LLVM Val.
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
: Value(ClassID::Block, BB, SBCtx) {
buildBasicBlockFromLLVMIR(BB);
}
public:
~BasicBlock() = default;
/// For isa/dyn_cast.
static bool classof(const Value *From) {
return From->getSubclassID() == Value::ClassID::Block;
}
Function *getParent() const;
using iterator = BBIterator;
iterator begin() const;
iterator end() const {
auto *BB = cast<llvm::BasicBlock>(Val);
return iterator(BB, BB->end(), &Ctx);
}
std::reverse_iterator<iterator> rbegin() const {
return std::make_reverse_iterator(end());
}
std::reverse_iterator<iterator> rend() const {
return std::make_reverse_iterator(begin());
}
Context &getContext() const { return Ctx; }
Instruction *getTerminator() const;
bool empty() const { return begin() == end(); }
Instruction &front() const;
Instruction &back() const;
#ifndef NDEBUG
void verify() const final {
assert(isa<llvm::BasicBlock>(Val) && "Expected BasicBlock!");
}
void dumpOS(raw_ostream &OS) const final;
#endif
};
/// 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 SelectInst; // For getTopmostLLVMInstruction().
friend class ExtractElementInst; // For getTopmostLLVMInstruction().
friend class InsertElementInst; // For getTopmostLLVMInstruction().
friend class ShuffleVectorInst; // 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 CatchPadInst; // For getTopmostLLVMInstruction().
friend class CleanupPadInst; // For getTopmostLLVMInstruction().
friend class CatchReturnInst; // For getTopmostLLVMInstruction().
friend class GetElementPtrInst; // 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().
/// \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; }
/// 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()));
}
/// \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);
#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;
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 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 = "");
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() { cast<llvm::SelectInst>(Val)->swapValues(); }
/// 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 {
return cast<VectorType>(getVectorOperand()->getType());
}
};
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() { cast<llvm::ShuffleVectorInst>(Val)->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 cast<llvm::ShuffleVectorInst>(Val)->getType();
}
/// 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, Context &Ctx);
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 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);
}
static bool classof(const Value *V) {
return isa<Instruction>(V) && classof(cast<Instruction>(V));
}
};
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 {
return cast<llvm::CallBase>(Val)->getFunctionType();
}
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);
// TODO: Return a `LandingPadInst` once implemented.
Instruction *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 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 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 {
return cast<llvm::GetElementPtrInst>(Val)->getSourceElementType();
}
Type *getResultElementType() const {
return cast<llvm::GetElementPtrInst>(Val)->getResultElementType();
}
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 {
return cast<llvm::GetElementPtrInst>(Val)->getPointerOperandType();
}
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 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> {
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); }
};
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 = "");
};
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 cast<llvm::AllocaInst>(Val)->getType();
}
/// 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 {
return cast<llvm::AllocaInst>(Val)->getAllocatedType();
}
/// 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 { return cast<llvm::CastInst>(Val)->getSrcTy(); }
Type *getDestTy() const { return cast<llvm::CastInst>(Val)->getDestTy(); }
};
// 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)
};
/// 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;
}
};
class Context {
protected:
LLVMContext &LLVMCtx;
Tracker IRTracker;
/// Maps LLVM Value to the corresponding sandboxir::Value. Owns all
/// SandboxIR objects.
DenseMap<llvm::Value *, std::unique_ptr<sandboxir::Value>>
LLVMValueToValueMap;
/// Remove \p V from the maps and returns the unique_ptr.
std::unique_ptr<Value> detachLLVMValue(llvm::Value *V);
/// Remove \p SBV from all SandboxIR maps and stop owning it. This effectively
/// detaches \p V from the underlying IR.
std::unique_ptr<Value> detach(Value *V);
friend void Instruction::eraseFromParent(); // For detach().
/// Take ownership of VPtr and store it in `LLVMValueToValueMap`.
Value *registerValue(std::unique_ptr<Value> &&VPtr);
friend class EraseFromParent; // For registerValue().
/// This is the actual function that creates sandboxir values for \p V,
/// and among others handles all instruction types.
Value *getOrCreateValueInternal(llvm::Value *V, llvm::User *U = nullptr);
/// Get or create a sandboxir::Argument for an existing LLVM IR \p LLVMArg.
Argument *getOrCreateArgument(llvm::Argument *LLVMArg) {
auto Pair = LLVMValueToValueMap.insert({LLVMArg, nullptr});
auto It = Pair.first;
if (Pair.second) {
It->second = std::unique_ptr<Argument>(new Argument(LLVMArg, *this));
return cast<Argument>(It->second.get());
}
return cast<Argument>(It->second.get());
}
/// Get or create a sandboxir::Value for an existing LLVM IR \p LLVMV.
Value *getOrCreateValue(llvm::Value *LLVMV) {
return getOrCreateValueInternal(LLVMV, 0);
}
/// Get or create a sandboxir::Constant from an existing LLVM IR \p LLVMC.
Constant *getOrCreateConstant(llvm::Constant *LLVMC) {
return cast<Constant>(getOrCreateValueInternal(LLVMC, 0));
}
friend class ConstantInt; // For getOrCreateConstant().
/// Create a sandboxir::BasicBlock for an existing LLVM IR \p BB. This will
/// also create all contents of the block.
BasicBlock *createBasicBlock(llvm::BasicBlock *BB);
friend class BasicBlock; // For getOrCreateValue().
IRBuilder<ConstantFolder> LLVMIRBuilder;
auto &getLLVMIRBuilder() { return LLVMIRBuilder; }
SelectInst *createSelectInst(llvm::SelectInst *SI);
friend SelectInst; // For createSelectInst()
InsertElementInst *createInsertElementInst(llvm::InsertElementInst *IEI);
friend InsertElementInst; // For createInsertElementInst()
ExtractElementInst *createExtractElementInst(llvm::ExtractElementInst *EEI);
friend ExtractElementInst; // For createExtractElementInst()
ShuffleVectorInst *createShuffleVectorInst(llvm::ShuffleVectorInst *SVI);
friend ShuffleVectorInst; // For createShuffleVectorInst()
BranchInst *createBranchInst(llvm::BranchInst *I);
friend BranchInst; // For createBranchInst()
LoadInst *createLoadInst(llvm::LoadInst *LI);
friend LoadInst; // For createLoadInst()
StoreInst *createStoreInst(llvm::StoreInst *SI);
friend StoreInst; // For createStoreInst()
ReturnInst *createReturnInst(llvm::ReturnInst *I);
friend ReturnInst; // For createReturnInst()
CallInst *createCallInst(llvm::CallInst *I);
friend CallInst; // For createCallInst()
InvokeInst *createInvokeInst(llvm::InvokeInst *I);
friend InvokeInst; // For createInvokeInst()
CallBrInst *createCallBrInst(llvm::CallBrInst *I);
friend CallBrInst; // For createCallBrInst()
CatchPadInst *createCatchPadInst(llvm::CatchPadInst *I);
friend CatchPadInst; // For createCatchPadInst()
CleanupPadInst *createCleanupPadInst(llvm::CleanupPadInst *I);
friend CleanupPadInst; // For createCleanupPadInst()
CatchReturnInst *createCatchReturnInst(llvm::CatchReturnInst *I);
friend CatchReturnInst; // For createCatchReturnInst()
GetElementPtrInst *createGetElementPtrInst(llvm::GetElementPtrInst *I);
friend GetElementPtrInst; // For createGetElementPtrInst()
CatchSwitchInst *createCatchSwitchInst(llvm::CatchSwitchInst *I);
friend CatchSwitchInst; // For createCatchSwitchInst()
SwitchInst *createSwitchInst(llvm::SwitchInst *I);
friend SwitchInst; // For createSwitchInst()
UnaryOperator *createUnaryOperator(llvm::UnaryOperator *I);
friend UnaryOperator; // For createUnaryOperator()
BinaryOperator *createBinaryOperator(llvm::BinaryOperator *I);
friend BinaryOperator; // For createBinaryOperator()
AtomicRMWInst *createAtomicRMWInst(llvm::AtomicRMWInst *I);
friend AtomicRMWInst; // For createAtomicRMWInst()
AtomicCmpXchgInst *createAtomicCmpXchgInst(llvm::AtomicCmpXchgInst *I);
friend AtomicCmpXchgInst; // For createAtomicCmpXchgInst()
AllocaInst *createAllocaInst(llvm::AllocaInst *I);
friend AllocaInst; // For createAllocaInst()
CastInst *createCastInst(llvm::CastInst *I);
friend CastInst; // For createCastInst()
PHINode *createPHINode(llvm::PHINode *I);
friend PHINode; // For createPHINode()
UnreachableInst *createUnreachableInst(llvm::UnreachableInst *UI);
friend UnreachableInst; // For createUnreachableInst()
public:
Context(LLVMContext &LLVMCtx)
: LLVMCtx(LLVMCtx), IRTracker(*this),
LLVMIRBuilder(LLVMCtx, ConstantFolder()) {}
Tracker &getTracker() { return IRTracker; }
/// Convenience function for `getTracker().save()`
void save() { IRTracker.save(); }
/// Convenience function for `getTracker().revert()`
void revert() { IRTracker.revert(); }
/// Convenience function for `getTracker().accept()`
void accept() { IRTracker.accept(); }
sandboxir::Value *getValue(llvm::Value *V) const;
const sandboxir::Value *getValue(const llvm::Value *V) const {
return getValue(const_cast<llvm::Value *>(V));
}
/// Create a sandboxir::Function for an existing LLVM IR \p F, including all
/// blocks and instructions.
/// This is the main API function for creating Sandbox IR.
Function *createFunction(llvm::Function *F);
/// \Returns the number of values registered with Context.
size_t getNumValues() const { return LLVMValueToValueMap.size(); }
};
class Function : public Constant {
/// Helper for mapped_iterator.
struct LLVMBBToBB {
Context &Ctx;
LLVMBBToBB(Context &Ctx) : Ctx(Ctx) {}
BasicBlock &operator()(llvm::BasicBlock &LLVMBB) const {
return *cast<BasicBlock>(Ctx.getValue(&LLVMBB));
}
};
/// Use Context::createFunction() instead.
Function(llvm::Function *F, sandboxir::Context &Ctx)
: Constant(ClassID::Function, F, Ctx) {}
friend class Context; // For constructor.
public:
/// For isa/dyn_cast.
static bool classof(const sandboxir::Value *From) {
return From->getSubclassID() == ClassID::Function;
}
Argument *getArg(unsigned Idx) const {
llvm::Argument *Arg = cast<llvm::Function>(Val)->getArg(Idx);
return cast<Argument>(Ctx.getValue(Arg));
}
size_t arg_size() const { return cast<llvm::Function>(Val)->arg_size(); }
bool arg_empty() const { return cast<llvm::Function>(Val)->arg_empty(); }
using iterator = mapped_iterator<llvm::Function::iterator, LLVMBBToBB>;
iterator begin() const {
LLVMBBToBB BBGetter(Ctx);
return iterator(cast<llvm::Function>(Val)->begin(), BBGetter);
}
iterator end() const {
LLVMBBToBB BBGetter(Ctx);
return iterator(cast<llvm::Function>(Val)->end(), BBGetter);
}
FunctionType *getFunctionType() const {
return cast<llvm::Function>(Val)->getFunctionType();
}
#ifndef NDEBUG
void verify() const final {
assert(isa<llvm::Function>(Val) && "Expected Function!");
}
void dumpNameAndArgs(raw_ostream &OS) const;
void dumpOS(raw_ostream &OS) const final;
#endif
};
} // namespace sandboxir
} // namespace llvm
#endif // LLVM_SANDBOXIR_SANDBOXIR_H