blob: 2cb76fc89d9b4dd3a1e2b75f352b37f904c72557 [file] [log] [blame] [edit]
//===- SandboxIR.cpp - A transactional overlay IR on top of LLVM IR -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/SandboxIR/SandboxIR.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Constants.h"
#include "llvm/Support/Debug.h"
#include <sstream>
using namespace llvm::sandboxir;
Value *Use::get() const { return Ctx->getValue(LLVMUse->get()); }
void Use::set(Value *V) {
auto &Tracker = Ctx->getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<UseSet>(*this, Tracker));
LLVMUse->set(V->Val);
}
unsigned Use::getOperandNo() const { return Usr->getUseOperandNo(*this); }
void Use::swap(Use &OtherUse) {
auto &Tracker = Ctx->getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<UseSwap>(*this, OtherUse, Tracker));
LLVMUse->swap(*OtherUse.LLVMUse);
}
#ifndef NDEBUG
void Use::dump(raw_ostream &OS) const {
Value *Def = nullptr;
if (LLVMUse == nullptr)
OS << "<null> LLVM Use! ";
else
Def = Ctx->getValue(LLVMUse->get());
OS << "Def: ";
if (Def == nullptr)
OS << "NULL";
else
OS << *Def;
OS << "\n";
OS << "User: ";
if (Usr == nullptr)
OS << "NULL";
else
OS << *Usr;
OS << "\n";
OS << "OperandNo: ";
if (Usr == nullptr)
OS << "N/A";
else
OS << getOperandNo();
OS << "\n";
}
void Use::dump() const { dump(dbgs()); }
#endif // NDEBUG
Use OperandUseIterator::operator*() const { return Use; }
OperandUseIterator &OperandUseIterator::operator++() {
assert(Use.LLVMUse != nullptr && "Already at end!");
User *User = Use.getUser();
Use = User->getOperandUseInternal(Use.getOperandNo() + 1, /*Verify=*/false);
return *this;
}
UserUseIterator &UserUseIterator::operator++() {
// Get the corresponding llvm::Use, get the next in the list, and update the
// sandboxir::Use.
llvm::Use *&LLVMUse = Use.LLVMUse;
assert(LLVMUse != nullptr && "Already at end!");
LLVMUse = LLVMUse->getNext();
if (LLVMUse == nullptr) {
Use.Usr = nullptr;
return *this;
}
auto *Ctx = Use.Ctx;
auto *LLVMUser = LLVMUse->getUser();
Use.Usr = cast_or_null<sandboxir::User>(Ctx->getValue(LLVMUser));
return *this;
}
OperandUseIterator OperandUseIterator::operator+(unsigned Num) const {
sandboxir::Use U = Use.getUser()->getOperandUseInternal(
Use.getOperandNo() + Num, /*Verify=*/true);
return OperandUseIterator(U);
}
OperandUseIterator OperandUseIterator::operator-(unsigned Num) const {
assert(Use.getOperandNo() >= Num && "Out of bounds!");
sandboxir::Use U = Use.getUser()->getOperandUseInternal(
Use.getOperandNo() - Num, /*Verify=*/true);
return OperandUseIterator(U);
}
int OperandUseIterator::operator-(const OperandUseIterator &Other) const {
int ThisOpNo = Use.getOperandNo();
int OtherOpNo = Other.Use.getOperandNo();
return ThisOpNo - OtherOpNo;
}
Value::Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx)
: SubclassID(SubclassID), Val(Val), Ctx(Ctx) {
#ifndef NDEBUG
UID = Ctx.getNumValues();
#endif
}
Value::use_iterator Value::use_begin() {
llvm::Use *LLVMUse = nullptr;
if (Val->use_begin() != Val->use_end())
LLVMUse = &*Val->use_begin();
User *User = LLVMUse != nullptr ? cast_or_null<sandboxir::User>(Ctx.getValue(
Val->use_begin()->getUser()))
: nullptr;
return use_iterator(Use(LLVMUse, User, Ctx));
}
Value::user_iterator Value::user_begin() {
auto UseBegin = Val->use_begin();
auto UseEnd = Val->use_end();
bool AtEnd = UseBegin == UseEnd;
llvm::Use *LLVMUse = AtEnd ? nullptr : &*UseBegin;
User *User =
AtEnd ? nullptr
: cast_or_null<sandboxir::User>(Ctx.getValue(&*LLVMUse->getUser()));
return user_iterator(Use(LLVMUse, User, Ctx), UseToUser());
}
unsigned Value::getNumUses() const { return range_size(Val->users()); }
void Value::replaceUsesWithIf(
Value *OtherV, llvm::function_ref<bool(const Use &)> ShouldReplace) {
assert(getType() == OtherV->getType() && "Can't replace with different type");
llvm::Value *OtherVal = OtherV->Val;
// We are delegating RUWIf to LLVM IR's RUWIf.
Val->replaceUsesWithIf(
OtherVal, [&ShouldReplace, this](llvm::Use &LLVMUse) -> bool {
User *DstU = cast_or_null<User>(Ctx.getValue(LLVMUse.getUser()));
if (DstU == nullptr)
return false;
Use UseToReplace(&LLVMUse, DstU, Ctx);
if (!ShouldReplace(UseToReplace))
return false;
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<UseSet>(UseToReplace, Tracker));
return true;
});
}
void Value::replaceAllUsesWith(Value *Other) {
assert(getType() == Other->getType() &&
"Replacing with Value of different type!");
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
for (auto Use : uses())
Tracker.track(std::make_unique<UseSet>(Use, Tracker));
}
// We are delegating RAUW to LLVM IR's RAUW.
Val->replaceAllUsesWith(Other->Val);
}
#ifndef NDEBUG
std::string Value::getUid() const {
std::stringstream SS;
SS << "SB" << UID << ".";
return SS.str();
}
void Value::dumpCommonHeader(raw_ostream &OS) const {
OS << getUid() << " " << getSubclassIDStr(SubclassID) << " ";
}
void Value::dumpCommonFooter(raw_ostream &OS) const {
OS.indent(2) << "Val: ";
if (Val)
OS << *Val;
else
OS << "NULL";
OS << "\n";
}
void Value::dumpCommonPrefix(raw_ostream &OS) const {
if (Val)
OS << *Val;
else
OS << "NULL ";
}
void Value::dumpCommonSuffix(raw_ostream &OS) const {
OS << " ; " << getUid() << " (" << getSubclassIDStr(SubclassID) << ")";
}
void Value::printAsOperandCommon(raw_ostream &OS) const {
if (Val)
Val->printAsOperand(OS);
else
OS << "NULL ";
}
void Argument::printAsOperand(raw_ostream &OS) const {
printAsOperandCommon(OS);
}
void Argument::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void Argument::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
Use User::getOperandUseDefault(unsigned OpIdx, bool Verify) const {
assert((!Verify || OpIdx < getNumOperands()) && "Out of bounds!");
assert(isa<llvm::User>(Val) && "Non-users have no operands!");
llvm::Use *LLVMUse;
if (OpIdx != getNumOperands())
LLVMUse = &cast<llvm::User>(Val)->getOperandUse(OpIdx);
else
LLVMUse = cast<llvm::User>(Val)->op_end();
return Use(LLVMUse, const_cast<User *>(this), Ctx);
}
#ifndef NDEBUG
void User::verifyUserOfLLVMUse(const llvm::Use &Use) const {
assert(Ctx.getValue(Use.getUser()) == this &&
"Use not found in this SBUser's operands!");
}
#endif
bool User::classof(const Value *From) {
switch (From->getSubclassID()) {
#define DEF_VALUE(ID, CLASS)
#define DEF_USER(ID, CLASS) \
case ClassID::ID: \
return true;
#define DEF_INSTR(ID, OPC, CLASS) \
case ClassID::ID: \
return true;
#include "llvm/SandboxIR/SandboxIRValues.def"
default:
return false;
}
}
void User::setOperand(unsigned OperandIdx, Value *Operand) {
assert(isa<llvm::User>(Val) && "No operands!");
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<UseSet>(getOperandUse(OperandIdx), Tracker));
// We are delegating to llvm::User::setOperand().
cast<llvm::User>(Val)->setOperand(OperandIdx, Operand->Val);
}
bool User::replaceUsesOfWith(Value *FromV, Value *ToV) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
for (auto OpIdx : seq<unsigned>(0, getNumOperands())) {
auto Use = getOperandUse(OpIdx);
if (Use.get() == FromV)
Tracker.track(std::make_unique<UseSet>(Use, Tracker));
}
}
// We are delegating RUOW to LLVM IR's RUOW.
return cast<llvm::User>(Val)->replaceUsesOfWith(FromV->Val, ToV->Val);
}
#ifndef NDEBUG
void User::dumpCommonHeader(raw_ostream &OS) const {
Value::dumpCommonHeader(OS);
// TODO: This is incomplete
}
#endif // NDEBUG
BBIterator &BBIterator::operator++() {
auto ItE = BB->end();
assert(It != ItE && "Already at end!");
++It;
if (It == ItE)
return *this;
Instruction &NextI = *cast<sandboxir::Instruction>(Ctx->getValue(&*It));
unsigned Num = NextI.getNumOfIRInstrs();
assert(Num > 0 && "Bad getNumOfIRInstrs()");
It = std::next(It, Num - 1);
return *this;
}
BBIterator &BBIterator::operator--() {
assert(It != BB->begin() && "Already at begin!");
if (It == BB->end()) {
--It;
return *this;
}
Instruction &CurrI = **this;
unsigned Num = CurrI.getNumOfIRInstrs();
assert(Num > 0 && "Bad getNumOfIRInstrs()");
assert(std::prev(It, Num - 1) != BB->begin() && "Already at begin!");
It = std::prev(It, Num);
return *this;
}
const char *Instruction::getOpcodeName(Opcode Opc) {
switch (Opc) {
#define OP(OPC) \
case Opcode::OPC: \
return #OPC;
#define OPCODES(...) __VA_ARGS__
#define DEF_INSTR(ID, OPC, CLASS) OPC
#include "llvm/SandboxIR/SandboxIRValues.def"
}
llvm_unreachable("Unknown Opcode");
}
llvm::Instruction *Instruction::getTopmostLLVMInstruction() const {
Instruction *Prev = getPrevNode();
if (Prev == nullptr) {
// If at top of the BB, return the first BB instruction.
return &*cast<llvm::BasicBlock>(getParent()->Val)->begin();
}
// Else get the Previous sandbox IR instruction's bottom IR instruction and
// return its successor.
llvm::Instruction *PrevBotI = cast<llvm::Instruction>(Prev->Val);
return PrevBotI->getNextNode();
}
BBIterator Instruction::getIterator() const {
auto *I = cast<llvm::Instruction>(Val);
return BasicBlock::iterator(I->getParent(), I->getIterator(), &Ctx);
}
Instruction *Instruction::getNextNode() const {
assert(getParent() != nullptr && "Detached!");
assert(getIterator() != getParent()->end() && "Already at end!");
// `Val` is the bottom-most LLVM IR instruction. Get the next in the chain,
// and get the corresponding sandboxir Instruction that maps to it. This works
// even for SandboxIR Instructions that map to more than one LLVM Instruction.
auto *LLVMI = cast<llvm::Instruction>(Val);
assert(LLVMI->getParent() != nullptr && "LLVM IR instr is detached!");
auto *NextLLVMI = LLVMI->getNextNode();
auto *NextI = cast_or_null<Instruction>(Ctx.getValue(NextLLVMI));
if (NextI == nullptr)
return nullptr;
return NextI;
}
Instruction *Instruction::getPrevNode() const {
assert(getParent() != nullptr && "Detached!");
auto It = getIterator();
if (It != getParent()->begin())
return std::prev(getIterator()).get();
return nullptr;
}
void Instruction::removeFromParent() {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<RemoveFromParent>(this, Tracker));
// Detach all the LLVM IR instructions from their parent BB.
for (llvm::Instruction *I : getLLVMInstrs())
I->removeFromParent();
}
void Instruction::eraseFromParent() {
assert(users().empty() && "Still connected to users, can't erase!");
std::unique_ptr<Value> Detached = Ctx.detach(this);
auto LLVMInstrs = getLLVMInstrs();
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
Tracker.track(
std::make_unique<EraseFromParent>(std::move(Detached), Tracker));
// We don't actually delete the IR instruction, because then it would be
// impossible to bring it back from the dead at the same memory location.
// Instead we remove it from its BB and track its current location.
for (llvm::Instruction *I : LLVMInstrs)
I->removeFromParent();
// TODO: Multi-instructions need special treatment because some of the
// references are internal to the instruction.
for (llvm::Instruction *I : LLVMInstrs)
I->dropAllReferences();
} else {
// Erase in reverse to avoid erasing nstructions with attached uses.
for (llvm::Instruction *I : reverse(LLVMInstrs))
I->eraseFromParent();
}
}
void Instruction::moveBefore(BasicBlock &BB, const BBIterator &WhereIt) {
if (std::next(getIterator()) == WhereIt)
// Destination is same as origin, nothing to do.
return;
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<MoveInstr>(this, Tracker));
auto *LLVMBB = cast<llvm::BasicBlock>(BB.Val);
llvm::BasicBlock::iterator It;
if (WhereIt == BB.end()) {
It = LLVMBB->end();
} else {
Instruction *WhereI = &*WhereIt;
It = WhereI->getTopmostLLVMInstruction()->getIterator();
}
// TODO: Move this to the verifier of sandboxir::Instruction.
assert(is_sorted(getLLVMInstrs(),
[](auto *I1, auto *I2) { return I1->comesBefore(I2); }) &&
"Expected program order!");
// Do the actual move in LLVM IR.
for (auto *I : getLLVMInstrs())
I->moveBefore(*LLVMBB, It);
}
void Instruction::insertBefore(Instruction *BeforeI) {
llvm::Instruction *BeforeTopI = BeforeI->getTopmostLLVMInstruction();
// TODO: Move this to the verifier of sandboxir::Instruction.
assert(is_sorted(getLLVMInstrs(),
[](auto *I1, auto *I2) { return I1->comesBefore(I2); }) &&
"Expected program order!");
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<InsertIntoBB>(this, Tracker));
// Insert the LLVM IR Instructions in program order.
for (llvm::Instruction *I : getLLVMInstrs())
I->insertBefore(BeforeTopI);
}
void Instruction::insertAfter(Instruction *AfterI) {
insertInto(AfterI->getParent(), std::next(AfterI->getIterator()));
}
void Instruction::insertInto(BasicBlock *BB, const BBIterator &WhereIt) {
llvm::BasicBlock *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
llvm::Instruction *LLVMBeforeI;
llvm::BasicBlock::iterator LLVMBeforeIt;
Instruction *BeforeI;
if (WhereIt != BB->end()) {
BeforeI = &*WhereIt;
LLVMBeforeI = BeforeI->getTopmostLLVMInstruction();
LLVMBeforeIt = LLVMBeforeI->getIterator();
} else {
BeforeI = nullptr;
LLVMBeforeI = nullptr;
LLVMBeforeIt = LLVMBB->end();
}
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<InsertIntoBB>(this, Tracker));
// Insert the LLVM IR Instructions in program order.
for (llvm::Instruction *I : getLLVMInstrs())
I->insertInto(LLVMBB, LLVMBeforeIt);
}
BasicBlock *Instruction::getParent() const {
// Get the LLVM IR Instruction that this maps to, get its parent, and get the
// corresponding sandboxir::BasicBlock by looking it up in sandboxir::Context.
auto *BB = cast<llvm::Instruction>(Val)->getParent();
if (BB == nullptr)
return nullptr;
return cast<BasicBlock>(Ctx.getValue(BB));
}
bool Instruction::classof(const sandboxir::Value *From) {
switch (From->getSubclassID()) {
#define DEF_INSTR(ID, OPC, CLASS) \
case ClassID::ID: \
return true;
#include "llvm/SandboxIR/SandboxIRValues.def"
default:
return false;
}
}
#ifndef NDEBUG
void Instruction::dump(raw_ostream &OS) const {
OS << "Unimplemented! Please override dump().";
}
void Instruction::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
Value *SelectInst::createCommon(Value *Cond, Value *True, Value *False,
const Twine &Name, IRBuilder<> &Builder,
Context &Ctx) {
llvm::Value *NewV =
Builder.CreateSelect(Cond->Val, True->Val, False->Val, Name);
if (auto *NewSI = dyn_cast<llvm::SelectInst>(NewV))
return Ctx.createSelectInst(NewSI);
assert(isa<llvm::Constant>(NewV) && "Expected constant");
return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
}
Value *SelectInst::create(Value *Cond, Value *True, Value *False,
Instruction *InsertBefore, Context &Ctx,
const Twine &Name) {
llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(BeforeIR);
return createCommon(Cond, True, False, Name, Builder, Ctx);
}
Value *SelectInst::create(Value *Cond, Value *True, Value *False,
BasicBlock *InsertAtEnd, Context &Ctx,
const Twine &Name) {
auto *IRInsertAtEnd = cast<llvm::BasicBlock>(InsertAtEnd->Val);
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(IRInsertAtEnd);
return createCommon(Cond, True, False, Name, Builder, Ctx);
}
bool SelectInst::classof(const Value *From) {
return From->getSubclassID() == ClassID::Select;
}
#ifndef NDEBUG
void SelectInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void SelectInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
BranchInst *BranchInst::create(BasicBlock *IfTrue, Instruction *InsertBefore,
Context &Ctx) {
auto &Builder = Ctx.getLLVMIRBuilder();
llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
Builder.SetInsertPoint(cast<llvm::Instruction>(LLVMBefore));
llvm::BranchInst *NewBr =
Builder.CreateBr(cast<llvm::BasicBlock>(IfTrue->Val));
return Ctx.createBranchInst(NewBr);
}
BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd,
Context &Ctx) {
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
llvm::BranchInst *NewBr =
Builder.CreateBr(cast<llvm::BasicBlock>(IfTrue->Val));
return Ctx.createBranchInst(NewBr);
}
BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *IfFalse,
Value *Cond, Instruction *InsertBefore,
Context &Ctx) {
auto &Builder = Ctx.getLLVMIRBuilder();
llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
Builder.SetInsertPoint(LLVMBefore);
llvm::BranchInst *NewBr =
Builder.CreateCondBr(Cond->Val, cast<llvm::BasicBlock>(IfTrue->Val),
cast<llvm::BasicBlock>(IfFalse->Val));
return Ctx.createBranchInst(NewBr);
}
BranchInst *BranchInst::create(BasicBlock *IfTrue, BasicBlock *IfFalse,
Value *Cond, BasicBlock *InsertAtEnd,
Context &Ctx) {
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
llvm::BranchInst *NewBr =
Builder.CreateCondBr(Cond->Val, cast<llvm::BasicBlock>(IfTrue->Val),
cast<llvm::BasicBlock>(IfFalse->Val));
return Ctx.createBranchInst(NewBr);
}
bool BranchInst::classof(const Value *From) {
return From->getSubclassID() == ClassID::Br;
}
Value *BranchInst::getCondition() const {
assert(isConditional() && "Cannot get condition of an uncond branch!");
return Ctx.getValue(cast<llvm::BranchInst>(Val)->getCondition());
}
BasicBlock *BranchInst::getSuccessor(unsigned SuccIdx) const {
assert(SuccIdx < getNumSuccessors() &&
"Successor # out of range for Branch!");
return cast_or_null<BasicBlock>(
Ctx.getValue(cast<llvm::BranchInst>(Val)->getSuccessor(SuccIdx)));
}
void BranchInst::setSuccessor(unsigned Idx, BasicBlock *NewSucc) {
assert((Idx == 0 || Idx == 1) && "Out of bounds!");
setOperand(2u - Idx, NewSucc);
}
BasicBlock *BranchInst::LLVMBBToSBBB::operator()(llvm::BasicBlock *BB) const {
return cast<BasicBlock>(Ctx.getValue(BB));
}
const BasicBlock *
BranchInst::ConstLLVMBBToSBBB::operator()(const llvm::BasicBlock *BB) const {
return cast<BasicBlock>(Ctx.getValue(BB));
}
#ifndef NDEBUG
void BranchInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void BranchInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
void LoadInst::setVolatile(bool V) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
Tracker.track(std::make_unique<
GenericSetter<&LoadInst::isVolatile, &LoadInst::setVolatile>>(
this, Tracker));
}
cast<llvm::LoadInst>(Val)->setVolatile(V);
}
LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
Instruction *InsertBefore, Context &Ctx,
const Twine &Name) {
return create(Ty, Ptr, Align, InsertBefore, /*IsVolatile=*/false, Ctx, Name);
}
LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
Instruction *InsertBefore, bool IsVolatile,
Context &Ctx, const Twine &Name) {
llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(BeforeIR);
auto *NewLI =
Builder.CreateAlignedLoad(Ty, Ptr->Val, Align, IsVolatile, Name);
auto *NewSBI = Ctx.createLoadInst(NewLI);
return NewSBI;
}
LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
BasicBlock *InsertAtEnd, Context &Ctx,
const Twine &Name) {
return create(Ty, Ptr, Align, InsertAtEnd, /*IsVolatile=*/false, Ctx, Name);
}
LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,
BasicBlock *InsertAtEnd, bool IsVolatile,
Context &Ctx, const Twine &Name) {
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
auto *NewLI =
Builder.CreateAlignedLoad(Ty, Ptr->Val, Align, IsVolatile, Name);
auto *NewSBI = Ctx.createLoadInst(NewLI);
return NewSBI;
}
bool LoadInst::classof(const Value *From) {
return From->getSubclassID() == ClassID::Load;
}
Value *LoadInst::getPointerOperand() const {
return Ctx.getValue(cast<llvm::LoadInst>(Val)->getPointerOperand());
}
#ifndef NDEBUG
void LoadInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void LoadInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
void StoreInst::setVolatile(bool V) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
Tracker.track(
std::make_unique<
GenericSetter<&StoreInst::isVolatile, &StoreInst::setVolatile>>(
this, Tracker));
}
cast<llvm::StoreInst>(Val)->setVolatile(V);
}
StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
Instruction *InsertBefore, Context &Ctx) {
return create(V, Ptr, Align, InsertBefore, /*IsVolatile=*/false, Ctx);
}
StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
Instruction *InsertBefore, bool IsVolatile,
Context &Ctx) {
llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(BeforeIR);
auto *NewSI = Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, IsVolatile);
auto *NewSBI = Ctx.createStoreInst(NewSI);
return NewSBI;
}
StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
BasicBlock *InsertAtEnd, Context &Ctx) {
return create(V, Ptr, Align, InsertAtEnd, /*IsVolatile=*/false, Ctx);
}
StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,
BasicBlock *InsertAtEnd, bool IsVolatile,
Context &Ctx) {
auto *InsertAtEndIR = cast<llvm::BasicBlock>(InsertAtEnd->Val);
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(InsertAtEndIR);
auto *NewSI = Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, IsVolatile);
auto *NewSBI = Ctx.createStoreInst(NewSI);
return NewSBI;
}
bool StoreInst::classof(const Value *From) {
return From->getSubclassID() == ClassID::Store;
}
Value *StoreInst::getValueOperand() const {
return Ctx.getValue(cast<llvm::StoreInst>(Val)->getValueOperand());
}
Value *StoreInst::getPointerOperand() const {
return Ctx.getValue(cast<llvm::StoreInst>(Val)->getPointerOperand());
}
#ifndef NDEBUG
void StoreInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void StoreInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
UnreachableInst *UnreachableInst::create(Instruction *InsertBefore,
Context &Ctx) {
auto &Builder = Ctx.getLLVMIRBuilder();
llvm::Instruction *LLVMBefore = InsertBefore->getTopmostLLVMInstruction();
Builder.SetInsertPoint(LLVMBefore);
llvm::UnreachableInst *NewUI = Builder.CreateUnreachable();
return Ctx.createUnreachableInst(NewUI);
}
UnreachableInst *UnreachableInst::create(BasicBlock *InsertAtEnd,
Context &Ctx) {
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
llvm::UnreachableInst *NewUI = Builder.CreateUnreachable();
return Ctx.createUnreachableInst(NewUI);
}
bool UnreachableInst::classof(const Value *From) {
return From->getSubclassID() == ClassID::Unreachable;
}
#ifndef NDEBUG
void UnreachableInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void UnreachableInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
ReturnInst *ReturnInst::createCommon(Value *RetVal, IRBuilder<> &Builder,
Context &Ctx) {
llvm::ReturnInst *NewRI;
if (RetVal != nullptr)
NewRI = Builder.CreateRet(RetVal->Val);
else
NewRI = Builder.CreateRetVoid();
return Ctx.createReturnInst(NewRI);
}
ReturnInst *ReturnInst::create(Value *RetVal, Instruction *InsertBefore,
Context &Ctx) {
llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(BeforeIR);
return createCommon(RetVal, Builder, Ctx);
}
ReturnInst *ReturnInst::create(Value *RetVal, BasicBlock *InsertAtEnd,
Context &Ctx) {
auto &Builder = Ctx.getLLVMIRBuilder();
Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
return createCommon(RetVal, Builder, Ctx);
}
Value *ReturnInst::getReturnValue() const {
auto *LLVMRetVal = cast<llvm::ReturnInst>(Val)->getReturnValue();
return LLVMRetVal != nullptr ? Ctx.getValue(LLVMRetVal) : nullptr;
}
#ifndef NDEBUG
void ReturnInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void ReturnInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
Value *CallBase::getCalledOperand() const {
return Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledOperand());
}
Use CallBase::getCalledOperandUse() const {
llvm::Use *LLVMUse = &cast<llvm::CallBase>(Val)->getCalledOperandUse();
return Use(LLVMUse, cast<User>(Ctx.getValue(LLVMUse->getUser())), Ctx);
}
Function *CallBase::getCalledFunction() const {
return cast_or_null<Function>(
Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledFunction()));
}
Function *CallBase::getCaller() {
return cast<Function>(Ctx.getValue(cast<llvm::CallBase>(Val)->getCaller()));
}
void CallBase::setCalledFunction(Function *F) {
// F's function type is private, so we rely on `setCalledFunction()` to update
// it. But even though we are calling `setCalledFunction()` we also need to
// track this change at the SandboxIR level, which is why we call
// `setCalledOperand()` here.
// Note: This may break if `setCalledFunction()` early returns if `F`
// is already set, but we do have a unit test for it.
setCalledOperand(F);
cast<llvm::CallBase>(Val)->setCalledFunction(F->getFunctionType(),
cast<llvm::Function>(F->Val));
}
CallInst *CallInst::create(FunctionType *FTy, Value *Func,
ArrayRef<Value *> Args, BasicBlock::iterator WhereIt,
BasicBlock *WhereBB, Context &Ctx,
const Twine &NameStr) {
auto &Builder = Ctx.getLLVMIRBuilder();
if (WhereIt != WhereBB->end())
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
else
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
SmallVector<llvm::Value *> LLVMArgs;
LLVMArgs.reserve(Args.size());
for (Value *Arg : Args)
LLVMArgs.push_back(Arg->Val);
llvm::CallInst *NewCI = Builder.CreateCall(FTy, Func->Val, LLVMArgs, NameStr);
return Ctx.createCallInst(NewCI);
}
CallInst *CallInst::create(FunctionType *FTy, Value *Func,
ArrayRef<Value *> Args, Instruction *InsertBefore,
Context &Ctx, const Twine &NameStr) {
return CallInst::create(FTy, Func, Args, InsertBefore->getIterator(),
InsertBefore->getParent(), Ctx, NameStr);
}
CallInst *CallInst::create(FunctionType *FTy, Value *Func,
ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
Context &Ctx, const Twine &NameStr) {
return CallInst::create(FTy, Func, Args, InsertAtEnd->end(), InsertAtEnd, Ctx,
NameStr);
}
#ifndef NDEBUG
void CallInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void CallInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
BasicBlock *IfNormal, BasicBlock *IfException,
ArrayRef<Value *> Args, BBIterator WhereIt,
BasicBlock *WhereBB, Context &Ctx,
const Twine &NameStr) {
auto &Builder = Ctx.getLLVMIRBuilder();
if (WhereIt != WhereBB->end())
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
else
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
SmallVector<llvm::Value *> LLVMArgs;
LLVMArgs.reserve(Args.size());
for (Value *Arg : Args)
LLVMArgs.push_back(Arg->Val);
llvm::InvokeInst *Invoke = Builder.CreateInvoke(
FTy, Func->Val, cast<llvm::BasicBlock>(IfNormal->Val),
cast<llvm::BasicBlock>(IfException->Val), LLVMArgs, NameStr);
return Ctx.createInvokeInst(Invoke);
}
InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
BasicBlock *IfNormal, BasicBlock *IfException,
ArrayRef<Value *> Args,
Instruction *InsertBefore, Context &Ctx,
const Twine &NameStr) {
return create(FTy, Func, IfNormal, IfException, Args,
InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
NameStr);
}
InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
BasicBlock *IfNormal, BasicBlock *IfException,
ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
Context &Ctx, const Twine &NameStr) {
return create(FTy, Func, IfNormal, IfException, Args, InsertAtEnd->end(),
InsertAtEnd, Ctx, NameStr);
}
BasicBlock *InvokeInst::getNormalDest() const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getNormalDest()));
}
BasicBlock *InvokeInst::getUnwindDest() const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getUnwindDest()));
}
void InvokeInst::setNormalDest(BasicBlock *BB) {
setOperand(1, BB);
assert(getNormalDest() == BB && "LLVM IR uses a different operan index!");
}
void InvokeInst::setUnwindDest(BasicBlock *BB) {
setOperand(2, BB);
assert(getUnwindDest() == BB && "LLVM IR uses a different operan index!");
}
Instruction *InvokeInst::getLandingPadInst() const {
return cast<Instruction>(
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getLandingPadInst()));
;
}
BasicBlock *InvokeInst::getSuccessor(unsigned SuccIdx) const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getSuccessor(SuccIdx)));
}
#ifndef NDEBUG
void InvokeInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void InvokeInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
BasicBlock *DefaultDest,
ArrayRef<BasicBlock *> IndirectDests,
ArrayRef<Value *> Args, BBIterator WhereIt,
BasicBlock *WhereBB, Context &Ctx,
const Twine &NameStr) {
auto &Builder = Ctx.getLLVMIRBuilder();
if (WhereIt != WhereBB->end())
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
else
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
SmallVector<llvm::BasicBlock *> LLVMIndirectDests;
LLVMIndirectDests.reserve(IndirectDests.size());
for (BasicBlock *IndDest : IndirectDests)
LLVMIndirectDests.push_back(cast<llvm::BasicBlock>(IndDest->Val));
SmallVector<llvm::Value *> LLVMArgs;
LLVMArgs.reserve(Args.size());
for (Value *Arg : Args)
LLVMArgs.push_back(Arg->Val);
llvm::CallBrInst *CallBr = Builder.CreateCallBr(
FTy, Func->Val, cast<llvm::BasicBlock>(DefaultDest->Val),
LLVMIndirectDests, LLVMArgs, NameStr);
return Ctx.createCallBrInst(CallBr);
}
CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
BasicBlock *DefaultDest,
ArrayRef<BasicBlock *> IndirectDests,
ArrayRef<Value *> Args,
Instruction *InsertBefore, Context &Ctx,
const Twine &NameStr) {
return create(FTy, Func, DefaultDest, IndirectDests, Args,
InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
NameStr);
}
CallBrInst *CallBrInst::create(FunctionType *FTy, Value *Func,
BasicBlock *DefaultDest,
ArrayRef<BasicBlock *> IndirectDests,
ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
Context &Ctx, const Twine &NameStr) {
return create(FTy, Func, DefaultDest, IndirectDests, Args, InsertAtEnd->end(),
InsertAtEnd, Ctx, NameStr);
}
Value *CallBrInst::getIndirectDestLabel(unsigned Idx) const {
return Ctx.getValue(cast<llvm::CallBrInst>(Val)->getIndirectDestLabel(Idx));
}
Value *CallBrInst::getIndirectDestLabelUse(unsigned Idx) const {
return Ctx.getValue(
cast<llvm::CallBrInst>(Val)->getIndirectDestLabelUse(Idx));
}
BasicBlock *CallBrInst::getDefaultDest() const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::CallBrInst>(Val)->getDefaultDest()));
}
BasicBlock *CallBrInst::getIndirectDest(unsigned Idx) const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::CallBrInst>(Val)->getIndirectDest(Idx)));
}
llvm::SmallVector<BasicBlock *, 16> CallBrInst::getIndirectDests() const {
SmallVector<BasicBlock *, 16> BBs;
for (llvm::BasicBlock *LLVMBB :
cast<llvm::CallBrInst>(Val)->getIndirectDests())
BBs.push_back(cast<BasicBlock>(Ctx.getValue(LLVMBB)));
return BBs;
}
void CallBrInst::setDefaultDest(BasicBlock *BB) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
Tracker.track(std::make_unique<GenericSetter<&CallBrInst::getDefaultDest,
&CallBrInst::setDefaultDest>>(
this, Tracker));
}
cast<llvm::CallBrInst>(Val)->setDefaultDest(cast<llvm::BasicBlock>(BB->Val));
}
void CallBrInst::setIndirectDest(unsigned Idx, BasicBlock *BB) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(
std::make_unique<CallBrInstSetIndirectDest>(this, Idx, Tracker));
cast<llvm::CallBrInst>(Val)->setIndirectDest(Idx,
cast<llvm::BasicBlock>(BB->Val));
}
BasicBlock *CallBrInst::getSuccessor(unsigned Idx) const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::CallBrInst>(Val)->getSuccessor(Idx)));
}
#ifndef NDEBUG
void CallBrInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void CallBrInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
ArrayRef<Value *> IdxList,
BasicBlock::iterator WhereIt,
BasicBlock *WhereBB, Context &Ctx,
const Twine &NameStr) {
auto &Builder = Ctx.getLLVMIRBuilder();
if (WhereIt != WhereBB->end())
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
else
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
SmallVector<llvm::Value *> LLVMIdxList;
LLVMIdxList.reserve(IdxList.size());
for (Value *Idx : IdxList)
LLVMIdxList.push_back(Idx->Val);
llvm::Value *NewV = Builder.CreateGEP(Ty, Ptr->Val, LLVMIdxList, NameStr);
if (auto *NewGEP = dyn_cast<llvm::GetElementPtrInst>(NewV))
return Ctx.createGetElementPtrInst(NewGEP);
assert(isa<llvm::Constant>(NewV) && "Expected constant");
return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
}
Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
ArrayRef<Value *> IdxList,
Instruction *InsertBefore, Context &Ctx,
const Twine &NameStr) {
return GetElementPtrInst::create(Ty, Ptr, IdxList,
InsertBefore->getIterator(),
InsertBefore->getParent(), Ctx, NameStr);
}
Value *GetElementPtrInst::create(Type *Ty, Value *Ptr,
ArrayRef<Value *> IdxList,
BasicBlock *InsertAtEnd, Context &Ctx,
const Twine &NameStr) {
return GetElementPtrInst::create(Ty, Ptr, IdxList, InsertAtEnd->end(),
InsertAtEnd, Ctx, NameStr);
}
Value *GetElementPtrInst::getPointerOperand() const {
return Ctx.getValue(cast<llvm::GetElementPtrInst>(Val)->getPointerOperand());
}
#ifndef NDEBUG
void GetElementPtrInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void GetElementPtrInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
BasicBlock *PHINode::LLVMBBToBB::operator()(llvm::BasicBlock *LLVMBB) const {
return cast<BasicBlock>(Ctx.getValue(LLVMBB));
}
PHINode *PHINode::create(Type *Ty, unsigned NumReservedValues,
Instruction *InsertBefore, Context &Ctx,
const Twine &Name) {
llvm::PHINode *NewPHI = llvm::PHINode::Create(
Ty, NumReservedValues, Name, InsertBefore->getTopmostLLVMInstruction());
return Ctx.createPHINode(NewPHI);
}
bool PHINode::classof(const Value *From) {
return From->getSubclassID() == ClassID::PHI;
}
Value *PHINode::getIncomingValue(unsigned Idx) const {
return Ctx.getValue(cast<llvm::PHINode>(Val)->getIncomingValue(Idx));
}
void PHINode::setIncomingValue(unsigned Idx, Value *V) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<PHISetIncoming>(
*this, Idx, PHISetIncoming::What::Value, Tracker));
cast<llvm::PHINode>(Val)->setIncomingValue(Idx, V->Val);
}
BasicBlock *PHINode::getIncomingBlock(unsigned Idx) const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::PHINode>(Val)->getIncomingBlock(Idx)));
}
BasicBlock *PHINode::getIncomingBlock(const Use &U) const {
llvm::Use *LLVMUse = U.LLVMUse;
llvm::BasicBlock *BB = cast<llvm::PHINode>(Val)->getIncomingBlock(*LLVMUse);
return cast<BasicBlock>(Ctx.getValue(BB));
}
void PHINode::setIncomingBlock(unsigned Idx, BasicBlock *BB) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<PHISetIncoming>(
*this, Idx, PHISetIncoming::What::Block, Tracker));
cast<llvm::PHINode>(Val)->setIncomingBlock(Idx,
cast<llvm::BasicBlock>(BB->Val));
}
void PHINode::addIncoming(Value *V, BasicBlock *BB) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<PHIAddIncoming>(*this, Tracker));
cast<llvm::PHINode>(Val)->addIncoming(V->Val,
cast<llvm::BasicBlock>(BB->Val));
}
Value *PHINode::removeIncomingValue(unsigned Idx) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<PHIRemoveIncoming>(*this, Idx, Tracker));
llvm::Value *LLVMV =
cast<llvm::PHINode>(Val)->removeIncomingValue(Idx,
/*DeletePHIIfEmpty=*/false);
return Ctx.getValue(LLVMV);
}
Value *PHINode::removeIncomingValue(BasicBlock *BB) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<PHIRemoveIncoming>(
*this, getBasicBlockIndex(BB), Tracker));
auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
llvm::Value *LLVMV =
cast<llvm::PHINode>(Val)->removeIncomingValue(LLVMBB,
/*DeletePHIIfEmpty=*/false);
return Ctx.getValue(LLVMV);
}
int PHINode::getBasicBlockIndex(const BasicBlock *BB) const {
auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
return cast<llvm::PHINode>(Val)->getBasicBlockIndex(LLVMBB);
}
Value *PHINode::getIncomingValueForBlock(const BasicBlock *BB) const {
auto *LLVMBB = cast<llvm::BasicBlock>(BB->Val);
llvm::Value *LLVMV =
cast<llvm::PHINode>(Val)->getIncomingValueForBlock(LLVMBB);
return Ctx.getValue(LLVMV);
}
Value *PHINode::hasConstantValue() const {
llvm::Value *LLVMV = cast<llvm::PHINode>(Val)->hasConstantValue();
return LLVMV != nullptr ? Ctx.getValue(LLVMV) : nullptr;
}
void PHINode::replaceIncomingBlockWith(const BasicBlock *Old, BasicBlock *New) {
assert(New && Old && "Sandbox IR PHI node got a null basic block!");
for (unsigned Idx = 0, NumOps = cast<llvm::PHINode>(Val)->getNumOperands();
Idx != NumOps; ++Idx)
if (getIncomingBlock(Idx) == Old)
setIncomingBlock(Idx, New);
}
void PHINode::removeIncomingValueIf(function_ref<bool(unsigned)> Predicate) {
// Avoid duplicate tracking by going through this->removeIncomingValue here at
// the expense of some performance. Copy PHI::removeIncomingValueIf more
// directly if performance becomes an issue.
// Removing the element at index X, moves the element previously at X + 1
// to X. Working from the end avoids complications from that.
unsigned Idx = getNumIncomingValues();
while (Idx > 0) {
if (Predicate(Idx - 1))
removeIncomingValue(Idx - 1);
--Idx;
}
}
static llvm::Instruction::CastOps getLLVMCastOp(Instruction::Opcode Opc) {
switch (Opc) {
case Instruction::Opcode::ZExt:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::ZExt);
case Instruction::Opcode::SExt:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::SExt);
case Instruction::Opcode::FPToUI:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPToUI);
case Instruction::Opcode::FPToSI:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPToSI);
case Instruction::Opcode::FPExt:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPExt);
case Instruction::Opcode::PtrToInt:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::PtrToInt);
case Instruction::Opcode::IntToPtr:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::IntToPtr);
case Instruction::Opcode::SIToFP:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::SIToFP);
case Instruction::Opcode::UIToFP:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::UIToFP);
case Instruction::Opcode::Trunc:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::Trunc);
case Instruction::Opcode::FPTrunc:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::FPTrunc);
case Instruction::Opcode::BitCast:
return static_cast<llvm::Instruction::CastOps>(llvm::Instruction::BitCast);
case Instruction::Opcode::AddrSpaceCast:
return static_cast<llvm::Instruction::CastOps>(
llvm::Instruction::AddrSpaceCast);
default:
llvm_unreachable("Opcode not suitable for CastInst!");
}
}
AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace, BBIterator WhereIt,
BasicBlock *WhereBB, Context &Ctx,
Value *ArraySize, const Twine &Name) {
auto &Builder = Ctx.getLLVMIRBuilder();
if (WhereIt == WhereBB->end())
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
else
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
auto *NewAlloca = Builder.CreateAlloca(Ty, AddrSpace, ArraySize->Val, Name);
return Ctx.createAllocaInst(NewAlloca);
}
AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace,
Instruction *InsertBefore, Context &Ctx,
Value *ArraySize, const Twine &Name) {
return create(Ty, AddrSpace, InsertBefore->getIterator(),
InsertBefore->getParent(), Ctx, ArraySize, Name);
}
AllocaInst *AllocaInst::create(Type *Ty, unsigned AddrSpace,
BasicBlock *InsertAtEnd, Context &Ctx,
Value *ArraySize, const Twine &Name) {
return create(Ty, AddrSpace, InsertAtEnd->end(), InsertAtEnd, Ctx, ArraySize,
Name);
}
void AllocaInst::setAllocatedType(Type *Ty) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
Tracker.track(
std::make_unique<GenericSetter<&AllocaInst::getAllocatedType,
&AllocaInst::setAllocatedType>>(
this, Tracker));
}
cast<llvm::AllocaInst>(Val)->setAllocatedType(Ty);
}
void AllocaInst::setAlignment(Align Align) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
Tracker.track(
std::make_unique<
GenericSetter<&AllocaInst::getAlign, &AllocaInst::setAlignment>>(
this, Tracker));
}
cast<llvm::AllocaInst>(Val)->setAlignment(Align);
}
void AllocaInst::setUsedWithInAlloca(bool V) {
auto &Tracker = Ctx.getTracker();
if (Tracker.isTracking()) {
Tracker.track(
std::make_unique<GenericSetter<&AllocaInst::isUsedWithInAlloca,
&AllocaInst::setUsedWithInAlloca>>(
this, Tracker));
}
cast<llvm::AllocaInst>(Val)->setUsedWithInAlloca(V);
}
Value *AllocaInst::getArraySize() {
return Ctx.getValue(cast<llvm::AllocaInst>(Val)->getArraySize());
}
#ifndef NDEBUG
void AllocaInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void AllocaInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
BBIterator WhereIt, BasicBlock *WhereBB, Context &Ctx,
const Twine &Name) {
assert(getLLVMCastOp(Op) && "Opcode not suitable for CastInst!");
auto &Builder = Ctx.getLLVMIRBuilder();
if (WhereIt == WhereBB->end())
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
else
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
auto *NewV =
Builder.CreateCast(getLLVMCastOp(Op), Operand->Val, DestTy, Name);
if (auto *NewCI = dyn_cast<llvm::CastInst>(NewV))
return Ctx.createCastInst(NewCI);
assert(isa<llvm::Constant>(NewV) && "Expected constant");
return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
}
Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
Instruction *InsertBefore, Context &Ctx,
const Twine &Name) {
return create(DestTy, Op, Operand, InsertBefore->getIterator(),
InsertBefore->getParent(), Ctx, Name);
}
Value *CastInst::create(Type *DestTy, Opcode Op, Value *Operand,
BasicBlock *InsertAtEnd, Context &Ctx,
const Twine &Name) {
return create(DestTy, Op, Operand, InsertAtEnd->end(), InsertAtEnd, Ctx,
Name);
}
bool CastInst::classof(const Value *From) {
return From->getSubclassID() == ClassID::Cast;
}
#ifndef NDEBUG
void CastInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void CastInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
void PHINode::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void PHINode::dump() const {
dump(dbgs());
dbgs() << "\n";
}
void OpaqueInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void OpaqueInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
Constant *Constant::createInt(Type *Ty, uint64_t V, Context &Ctx,
bool IsSigned) {
llvm::Constant *LLVMC = llvm::ConstantInt::get(Ty, V, IsSigned);
return Ctx.getOrCreateConstant(LLVMC);
}
#ifndef NDEBUG
void Constant::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void Constant::dump() const {
dump(dbgs());
dbgs() << "\n";
}
void Function::dumpNameAndArgs(raw_ostream &OS) const {
auto *F = cast<llvm::Function>(Val);
OS << *F->getReturnType() << " @" << F->getName() << "(";
interleave(
F->args(),
[this, &OS](const llvm::Argument &LLVMArg) {
auto *SBArg = cast_or_null<Argument>(Ctx.getValue(&LLVMArg));
if (SBArg == nullptr)
OS << "NULL";
else
SBArg->printAsOperand(OS);
},
[&] { OS << ", "; });
OS << ")";
}
void Function::dump(raw_ostream &OS) const {
dumpNameAndArgs(OS);
OS << " {\n";
auto *LLVMF = cast<llvm::Function>(Val);
interleave(
*LLVMF,
[this, &OS](const llvm::BasicBlock &LLVMBB) {
auto *BB = cast_or_null<BasicBlock>(Ctx.getValue(&LLVMBB));
if (BB == nullptr)
OS << "NULL";
else
OS << *BB;
},
[&OS] { OS << "\n"; });
OS << "}\n";
}
void Function::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG
BasicBlock::iterator::pointer
BasicBlock::iterator::getInstr(llvm::BasicBlock::iterator It) const {
return cast_or_null<Instruction>(Ctx->getValue(&*It));
}
std::unique_ptr<Value> Context::detachLLVMValue(llvm::Value *V) {
std::unique_ptr<Value> Erased;
auto It = LLVMValueToValueMap.find(V);
if (It != LLVMValueToValueMap.end()) {
auto *Val = It->second.release();
Erased = std::unique_ptr<Value>(Val);
LLVMValueToValueMap.erase(It);
}
return Erased;
}
std::unique_ptr<Value> Context::detach(Value *V) {
assert(V->getSubclassID() != Value::ClassID::Constant &&
"Can't detach a constant!");
assert(V->getSubclassID() != Value::ClassID::User && "Can't detach a user!");
return detachLLVMValue(V->Val);
}
Value *Context::registerValue(std::unique_ptr<Value> &&VPtr) {
assert(VPtr->getSubclassID() != Value::ClassID::User &&
"Can't register a user!");
// Track creation of instructions.
// Please note that we don't allow the creation of detached instructions,
// meaning that the instructions need to be inserted into a block upon
// creation. This is why the tracker class combines creation and insertion.
auto &Tracker = getTracker();
if (Tracker.isTracking())
if (auto *I = dyn_cast<Instruction>(VPtr.get()))
Tracker.track(std::make_unique<CreateAndInsertInst>(I, Tracker));
Value *V = VPtr.get();
[[maybe_unused]] auto Pair =
LLVMValueToValueMap.insert({VPtr->Val, std::move(VPtr)});
assert(Pair.second && "Already exists!");
return V;
}
Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
auto Pair = LLVMValueToValueMap.insert({LLVMV, nullptr});
auto It = Pair.first;
if (!Pair.second)
return It->second.get();
if (auto *C = dyn_cast<llvm::Constant>(LLVMV)) {
if (auto *F = dyn_cast<llvm::Function>(LLVMV))
It->second = std::unique_ptr<Function>(new Function(F, *this));
else
It->second = std::unique_ptr<Constant>(new Constant(C, *this));
auto *NewC = It->second.get();
for (llvm::Value *COp : C->operands())
getOrCreateValueInternal(COp, C);
return NewC;
}
if (auto *Arg = dyn_cast<llvm::Argument>(LLVMV)) {
It->second = std::unique_ptr<Argument>(new Argument(Arg, *this));
return It->second.get();
}
if (auto *BB = dyn_cast<llvm::BasicBlock>(LLVMV)) {
assert(isa<BlockAddress>(U) &&
"This won't create a SBBB, don't call this function directly!");
if (auto *SBBB = getValue(BB))
return SBBB;
return nullptr;
}
assert(isa<llvm::Instruction>(LLVMV) && "Expected Instruction");
switch (cast<llvm::Instruction>(LLVMV)->getOpcode()) {
case llvm::Instruction::Select: {
auto *LLVMSel = cast<llvm::SelectInst>(LLVMV);
It->second = std::unique_ptr<SelectInst>(new SelectInst(LLVMSel, *this));
return It->second.get();
}
case llvm::Instruction::Br: {
auto *LLVMBr = cast<llvm::BranchInst>(LLVMV);
It->second = std::unique_ptr<BranchInst>(new BranchInst(LLVMBr, *this));
return It->second.get();
}
case llvm::Instruction::Load: {
auto *LLVMLd = cast<llvm::LoadInst>(LLVMV);
It->second = std::unique_ptr<LoadInst>(new LoadInst(LLVMLd, *this));
return It->second.get();
}
case llvm::Instruction::Store: {
auto *LLVMSt = cast<llvm::StoreInst>(LLVMV);
It->second = std::unique_ptr<StoreInst>(new StoreInst(LLVMSt, *this));
return It->second.get();
}
case llvm::Instruction::Ret: {
auto *LLVMRet = cast<llvm::ReturnInst>(LLVMV);
It->second = std::unique_ptr<ReturnInst>(new ReturnInst(LLVMRet, *this));
return It->second.get();
}
case llvm::Instruction::Call: {
auto *LLVMCall = cast<llvm::CallInst>(LLVMV);
It->second = std::unique_ptr<CallInst>(new CallInst(LLVMCall, *this));
return It->second.get();
}
case llvm::Instruction::Invoke: {
auto *LLVMInvoke = cast<llvm::InvokeInst>(LLVMV);
It->second = std::unique_ptr<InvokeInst>(new InvokeInst(LLVMInvoke, *this));
return It->second.get();
}
case llvm::Instruction::CallBr: {
auto *LLVMCallBr = cast<llvm::CallBrInst>(LLVMV);
It->second = std::unique_ptr<CallBrInst>(new CallBrInst(LLVMCallBr, *this));
return It->second.get();
}
case llvm::Instruction::GetElementPtr: {
auto *LLVMGEP = cast<llvm::GetElementPtrInst>(LLVMV);
It->second = std::unique_ptr<GetElementPtrInst>(
new GetElementPtrInst(LLVMGEP, *this));
return It->second.get();
}
case llvm::Instruction::Alloca: {
auto *LLVMAlloca = cast<llvm::AllocaInst>(LLVMV);
It->second = std::unique_ptr<AllocaInst>(new AllocaInst(LLVMAlloca, *this));
return It->second.get();
}
case llvm::Instruction::ZExt:
case llvm::Instruction::SExt:
case llvm::Instruction::FPToUI:
case llvm::Instruction::FPToSI:
case llvm::Instruction::FPExt:
case llvm::Instruction::PtrToInt:
case llvm::Instruction::IntToPtr:
case llvm::Instruction::SIToFP:
case llvm::Instruction::UIToFP:
case llvm::Instruction::Trunc:
case llvm::Instruction::FPTrunc:
case llvm::Instruction::BitCast:
case llvm::Instruction::AddrSpaceCast: {
auto *LLVMCast = cast<llvm::CastInst>(LLVMV);
It->second = std::unique_ptr<CastInst>(new CastInst(LLVMCast, *this));
return It->second.get();
}
case llvm::Instruction::PHI: {
auto *LLVMPhi = cast<llvm::PHINode>(LLVMV);
It->second = std::unique_ptr<PHINode>(new PHINode(LLVMPhi, *this));
return It->second.get();
}
case llvm::Instruction::Unreachable: {
auto *LLVMUnreachable = cast<llvm::UnreachableInst>(LLVMV);
It->second = std::unique_ptr<UnreachableInst>(
new UnreachableInst(LLVMUnreachable, *this));
return It->second.get();
}
default:
break;
}
It->second = std::unique_ptr<OpaqueInst>(
new OpaqueInst(cast<llvm::Instruction>(LLVMV), *this));
return It->second.get();
}
BasicBlock *Context::createBasicBlock(llvm::BasicBlock *LLVMBB) {
assert(getValue(LLVMBB) == nullptr && "Already exists!");
auto NewBBPtr = std::unique_ptr<BasicBlock>(new BasicBlock(LLVMBB, *this));
auto *BB = cast<BasicBlock>(registerValue(std::move(NewBBPtr)));
// Create SandboxIR for BB's body.
BB->buildBasicBlockFromLLVMIR(LLVMBB);
return BB;
}
SelectInst *Context::createSelectInst(llvm::SelectInst *SI) {
auto NewPtr = std::unique_ptr<SelectInst>(new SelectInst(SI, *this));
return cast<SelectInst>(registerValue(std::move(NewPtr)));
}
BranchInst *Context::createBranchInst(llvm::BranchInst *BI) {
auto NewPtr = std::unique_ptr<BranchInst>(new BranchInst(BI, *this));
return cast<BranchInst>(registerValue(std::move(NewPtr)));
}
LoadInst *Context::createLoadInst(llvm::LoadInst *LI) {
auto NewPtr = std::unique_ptr<LoadInst>(new LoadInst(LI, *this));
return cast<LoadInst>(registerValue(std::move(NewPtr)));
}
StoreInst *Context::createStoreInst(llvm::StoreInst *SI) {
auto NewPtr = std::unique_ptr<StoreInst>(new StoreInst(SI, *this));
return cast<StoreInst>(registerValue(std::move(NewPtr)));
}
ReturnInst *Context::createReturnInst(llvm::ReturnInst *I) {
auto NewPtr = std::unique_ptr<ReturnInst>(new ReturnInst(I, *this));
return cast<ReturnInst>(registerValue(std::move(NewPtr)));
}
CallInst *Context::createCallInst(llvm::CallInst *I) {
auto NewPtr = std::unique_ptr<CallInst>(new CallInst(I, *this));
return cast<CallInst>(registerValue(std::move(NewPtr)));
}
InvokeInst *Context::createInvokeInst(llvm::InvokeInst *I) {
auto NewPtr = std::unique_ptr<InvokeInst>(new InvokeInst(I, *this));
return cast<InvokeInst>(registerValue(std::move(NewPtr)));
}
CallBrInst *Context::createCallBrInst(llvm::CallBrInst *I) {
auto NewPtr = std::unique_ptr<CallBrInst>(new CallBrInst(I, *this));
return cast<CallBrInst>(registerValue(std::move(NewPtr)));
}
UnreachableInst *Context::createUnreachableInst(llvm::UnreachableInst *UI) {
auto NewPtr =
std::unique_ptr<UnreachableInst>(new UnreachableInst(UI, *this));
return cast<UnreachableInst>(registerValue(std::move(NewPtr)));
}
GetElementPtrInst *
Context::createGetElementPtrInst(llvm::GetElementPtrInst *I) {
auto NewPtr =
std::unique_ptr<GetElementPtrInst>(new GetElementPtrInst(I, *this));
return cast<GetElementPtrInst>(registerValue(std::move(NewPtr)));
}
AllocaInst *Context::createAllocaInst(llvm::AllocaInst *I) {
auto NewPtr = std::unique_ptr<AllocaInst>(new AllocaInst(I, *this));
return cast<AllocaInst>(registerValue(std::move(NewPtr)));
}
CastInst *Context::createCastInst(llvm::CastInst *I) {
auto NewPtr = std::unique_ptr<CastInst>(new CastInst(I, *this));
return cast<CastInst>(registerValue(std::move(NewPtr)));
}
PHINode *Context::createPHINode(llvm::PHINode *I) {
auto NewPtr = std::unique_ptr<PHINode>(new PHINode(I, *this));
return cast<PHINode>(registerValue(std::move(NewPtr)));
}
Value *Context::getValue(llvm::Value *V) const {
auto It = LLVMValueToValueMap.find(V);
if (It != LLVMValueToValueMap.end())
return It->second.get();
return nullptr;
}
Function *Context::createFunction(llvm::Function *F) {
assert(getValue(F) == nullptr && "Already exists!");
auto NewFPtr = std::unique_ptr<Function>(new Function(F, *this));
auto *SBF = cast<Function>(registerValue(std::move(NewFPtr)));
// Create arguments.
for (auto &Arg : F->args())
getOrCreateArgument(&Arg);
// Create BBs.
for (auto &BB : *F)
createBasicBlock(&BB);
return SBF;
}
Function *BasicBlock::getParent() const {
auto *BB = cast<llvm::BasicBlock>(Val);
auto *F = BB->getParent();
if (F == nullptr)
// Detached
return nullptr;
return cast_or_null<Function>(Ctx.getValue(F));
}
void BasicBlock::buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB) {
for (llvm::Instruction &IRef : reverse(*LLVMBB)) {
llvm::Instruction *I = &IRef;
Ctx.getOrCreateValue(I);
for (auto [OpIdx, Op] : enumerate(I->operands())) {
// Skip instruction's label operands
if (isa<llvm::BasicBlock>(Op))
continue;
// Skip metadata
if (isa<llvm::MetadataAsValue>(Op))
continue;
// Skip asm
if (isa<llvm::InlineAsm>(Op))
continue;
Ctx.getOrCreateValue(Op);
}
}
#if !defined(NDEBUG) && defined(SBVEC_EXPENSIVE_CHECKS)
verify();
#endif
}
BasicBlock::iterator BasicBlock::begin() const {
llvm::BasicBlock *BB = cast<llvm::BasicBlock>(Val);
llvm::BasicBlock::iterator It = BB->begin();
if (!BB->empty()) {
auto *V = Ctx.getValue(&*BB->begin());
assert(V != nullptr && "No SandboxIR for BB->begin()!");
auto *I = cast<Instruction>(V);
unsigned Num = I->getNumOfIRInstrs();
assert(Num >= 1u && "Bad getNumOfIRInstrs()");
It = std::next(It, Num - 1);
}
return iterator(BB, It, &Ctx);
}
Instruction *BasicBlock::getTerminator() const {
auto *TerminatorV =
Ctx.getValue(cast<llvm::BasicBlock>(Val)->getTerminator());
return cast_or_null<Instruction>(TerminatorV);
}
Instruction &BasicBlock::front() const {
auto *BB = cast<llvm::BasicBlock>(Val);
assert(!BB->empty() && "Empty block!");
auto *SBI = cast<Instruction>(getContext().getValue(&*BB->begin()));
assert(SBI != nullptr && "Expected Instr!");
return *SBI;
}
Instruction &BasicBlock::back() const {
auto *BB = cast<llvm::BasicBlock>(Val);
assert(!BB->empty() && "Empty block!");
auto *SBI = cast<Instruction>(getContext().getValue(&*BB->rbegin()));
assert(SBI != nullptr && "Expected Instr!");
return *SBI;
}
#ifndef NDEBUG
void BasicBlock::dump(raw_ostream &OS) const {
llvm::BasicBlock *BB = cast<llvm::BasicBlock>(Val);
const auto &Name = BB->getName();
OS << Name;
if (!Name.empty())
OS << ":\n";
// If there are Instructions in the BB that are not mapped to SandboxIR, then
// use a crash-proof dump.
if (any_of(*BB, [this](llvm::Instruction &I) {
return Ctx.getValue(&I) == nullptr;
})) {
OS << "<Crash-proof mode!>\n";
DenseSet<Instruction *> Visited;
for (llvm::Instruction &IRef : *BB) {
Value *SBV = Ctx.getValue(&IRef);
if (SBV == nullptr)
OS << IRef << " *** No SandboxIR ***\n";
else {
auto *SBI = dyn_cast<Instruction>(SBV);
if (SBI == nullptr) {
OS << IRef << " *** Not a SBInstruction!!! ***\n";
} else {
if (Visited.insert(SBI).second)
OS << *SBI << "\n";
}
}
}
} else {
for (auto &SBI : *this) {
SBI.dump(OS);
OS << "\n";
}
}
}
void BasicBlock::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG