Path: blob/main/contrib/llvm-project/llvm/lib/SandboxIR/SandboxIR.cpp
35259 views
//===- SandboxIR.cpp - A transactional overlay IR on top of LLVM IR -------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/SandboxIR/SandboxIR.h"9#include "llvm/ADT/SmallPtrSet.h"10#include "llvm/IR/Constants.h"11#include "llvm/Support/Debug.h"12#include <sstream>1314using namespace llvm::sandboxir;1516Value *Use::get() const { return Ctx->getValue(LLVMUse->get()); }1718void Use::set(Value *V) { LLVMUse->set(V->Val); }1920unsigned Use::getOperandNo() const { return Usr->getUseOperandNo(*this); }2122#ifndef NDEBUG23void Use::dump(raw_ostream &OS) const {24Value *Def = nullptr;25if (LLVMUse == nullptr)26OS << "<null> LLVM Use! ";27else28Def = Ctx->getValue(LLVMUse->get());29OS << "Def: ";30if (Def == nullptr)31OS << "NULL";32else33OS << *Def;34OS << "\n";3536OS << "User: ";37if (Usr == nullptr)38OS << "NULL";39else40OS << *Usr;41OS << "\n";4243OS << "OperandNo: ";44if (Usr == nullptr)45OS << "N/A";46else47OS << getOperandNo();48OS << "\n";49}5051void Use::dump() const { dump(dbgs()); }52#endif // NDEBUG5354Use OperandUseIterator::operator*() const { return Use; }5556OperandUseIterator &OperandUseIterator::operator++() {57assert(Use.LLVMUse != nullptr && "Already at end!");58User *User = Use.getUser();59Use = User->getOperandUseInternal(Use.getOperandNo() + 1, /*Verify=*/false);60return *this;61}6263UserUseIterator &UserUseIterator::operator++() {64// Get the corresponding llvm::Use, get the next in the list, and update the65// sandboxir::Use.66llvm::Use *&LLVMUse = Use.LLVMUse;67assert(LLVMUse != nullptr && "Already at end!");68LLVMUse = LLVMUse->getNext();69if (LLVMUse == nullptr) {70Use.Usr = nullptr;71return *this;72}73auto *Ctx = Use.Ctx;74auto *LLVMUser = LLVMUse->getUser();75Use.Usr = cast_or_null<sandboxir::User>(Ctx->getValue(LLVMUser));76return *this;77}7879Value::Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx)80: SubclassID(SubclassID), Val(Val), Ctx(Ctx) {81#ifndef NDEBUG82UID = Ctx.getNumValues();83#endif84}8586Value::use_iterator Value::use_begin() {87llvm::Use *LLVMUse = nullptr;88if (Val->use_begin() != Val->use_end())89LLVMUse = &*Val->use_begin();90User *User = LLVMUse != nullptr ? cast_or_null<sandboxir::User>(Ctx.getValue(91Val->use_begin()->getUser()))92: nullptr;93return use_iterator(Use(LLVMUse, User, Ctx));94}9596Value::user_iterator Value::user_begin() {97auto UseBegin = Val->use_begin();98auto UseEnd = Val->use_end();99bool AtEnd = UseBegin == UseEnd;100llvm::Use *LLVMUse = AtEnd ? nullptr : &*UseBegin;101User *User =102AtEnd ? nullptr103: cast_or_null<sandboxir::User>(Ctx.getValue(&*LLVMUse->getUser()));104return user_iterator(Use(LLVMUse, User, Ctx), UseToUser());105}106107unsigned Value::getNumUses() const { return range_size(Val->users()); }108109void Value::replaceUsesWithIf(110Value *OtherV, llvm::function_ref<bool(const Use &)> ShouldReplace) {111assert(getType() == OtherV->getType() && "Can't replace with different type");112llvm::Value *OtherVal = OtherV->Val;113// We are delegating RUWIf to LLVM IR's RUWIf.114Val->replaceUsesWithIf(115OtherVal, [&ShouldReplace, this](llvm::Use &LLVMUse) -> bool {116User *DstU = cast_or_null<User>(Ctx.getValue(LLVMUse.getUser()));117if (DstU == nullptr)118return false;119Use UseToReplace(&LLVMUse, DstU, Ctx);120if (!ShouldReplace(UseToReplace))121return false;122auto &Tracker = Ctx.getTracker();123if (Tracker.isTracking())124Tracker.track(std::make_unique<UseSet>(UseToReplace, Tracker));125return true;126});127}128129void Value::replaceAllUsesWith(Value *Other) {130assert(getType() == Other->getType() &&131"Replacing with Value of different type!");132auto &Tracker = Ctx.getTracker();133if (Tracker.isTracking()) {134for (auto Use : uses())135Tracker.track(std::make_unique<UseSet>(Use, Tracker));136}137// We are delegating RAUW to LLVM IR's RAUW.138Val->replaceAllUsesWith(Other->Val);139}140141#ifndef NDEBUG142std::string Value::getUid() const {143std::stringstream SS;144SS << "SB" << UID << ".";145return SS.str();146}147148void Value::dumpCommonHeader(raw_ostream &OS) const {149OS << getUid() << " " << getSubclassIDStr(SubclassID) << " ";150}151152void Value::dumpCommonFooter(raw_ostream &OS) const {153OS.indent(2) << "Val: ";154if (Val)155OS << *Val;156else157OS << "NULL";158OS << "\n";159}160161void Value::dumpCommonPrefix(raw_ostream &OS) const {162if (Val)163OS << *Val;164else165OS << "NULL ";166}167168void Value::dumpCommonSuffix(raw_ostream &OS) const {169OS << " ; " << getUid() << " (" << getSubclassIDStr(SubclassID) << ")";170}171172void Value::printAsOperandCommon(raw_ostream &OS) const {173if (Val)174Val->printAsOperand(OS);175else176OS << "NULL ";177}178179void Argument::printAsOperand(raw_ostream &OS) const {180printAsOperandCommon(OS);181}182void Argument::dump(raw_ostream &OS) const {183dumpCommonPrefix(OS);184dumpCommonSuffix(OS);185}186void Argument::dump() const {187dump(dbgs());188dbgs() << "\n";189}190#endif // NDEBUG191192Use User::getOperandUseDefault(unsigned OpIdx, bool Verify) const {193assert((!Verify || OpIdx < getNumOperands()) && "Out of bounds!");194assert(isa<llvm::User>(Val) && "Non-users have no operands!");195llvm::Use *LLVMUse;196if (OpIdx != getNumOperands())197LLVMUse = &cast<llvm::User>(Val)->getOperandUse(OpIdx);198else199LLVMUse = cast<llvm::User>(Val)->op_end();200return Use(LLVMUse, const_cast<User *>(this), Ctx);201}202203#ifndef NDEBUG204void User::verifyUserOfLLVMUse(const llvm::Use &Use) const {205assert(Ctx.getValue(Use.getUser()) == this &&206"Use not found in this SBUser's operands!");207}208#endif209210bool User::classof(const Value *From) {211switch (From->getSubclassID()) {212#define DEF_VALUE(ID, CLASS)213#define DEF_USER(ID, CLASS) \214case ClassID::ID: \215return true;216#define DEF_INSTR(ID, OPC, CLASS) \217case ClassID::ID: \218return true;219#include "llvm/SandboxIR/SandboxIRValues.def"220default:221return false;222}223}224225void User::setOperand(unsigned OperandIdx, Value *Operand) {226assert(isa<llvm::User>(Val) && "No operands!");227auto &Tracker = Ctx.getTracker();228if (Tracker.isTracking())229Tracker.track(std::make_unique<UseSet>(getOperandUse(OperandIdx), Tracker));230// We are delegating to llvm::User::setOperand().231cast<llvm::User>(Val)->setOperand(OperandIdx, Operand->Val);232}233234bool User::replaceUsesOfWith(Value *FromV, Value *ToV) {235auto &Tracker = Ctx.getTracker();236if (Tracker.isTracking()) {237for (auto OpIdx : seq<unsigned>(0, getNumOperands())) {238auto Use = getOperandUse(OpIdx);239if (Use.get() == FromV)240Tracker.track(std::make_unique<UseSet>(Use, Tracker));241}242}243// We are delegating RUOW to LLVM IR's RUOW.244return cast<llvm::User>(Val)->replaceUsesOfWith(FromV->Val, ToV->Val);245}246247#ifndef NDEBUG248void User::dumpCommonHeader(raw_ostream &OS) const {249Value::dumpCommonHeader(OS);250// TODO: This is incomplete251}252#endif // NDEBUG253254BBIterator &BBIterator::operator++() {255auto ItE = BB->end();256assert(It != ItE && "Already at end!");257++It;258if (It == ItE)259return *this;260Instruction &NextI = *cast<sandboxir::Instruction>(Ctx->getValue(&*It));261unsigned Num = NextI.getNumOfIRInstrs();262assert(Num > 0 && "Bad getNumOfIRInstrs()");263It = std::next(It, Num - 1);264return *this;265}266267BBIterator &BBIterator::operator--() {268assert(It != BB->begin() && "Already at begin!");269if (It == BB->end()) {270--It;271return *this;272}273Instruction &CurrI = **this;274unsigned Num = CurrI.getNumOfIRInstrs();275assert(Num > 0 && "Bad getNumOfIRInstrs()");276assert(std::prev(It, Num - 1) != BB->begin() && "Already at begin!");277It = std::prev(It, Num);278return *this;279}280281const char *Instruction::getOpcodeName(Opcode Opc) {282switch (Opc) {283#define DEF_VALUE(ID, CLASS)284#define DEF_USER(ID, CLASS)285#define OP(OPC) \286case Opcode::OPC: \287return #OPC;288#define DEF_INSTR(ID, OPC, CLASS) OPC289#include "llvm/SandboxIR/SandboxIRValues.def"290}291llvm_unreachable("Unknown Opcode");292}293294llvm::Instruction *Instruction::getTopmostLLVMInstruction() const {295Instruction *Prev = getPrevNode();296if (Prev == nullptr) {297// If at top of the BB, return the first BB instruction.298return &*cast<llvm::BasicBlock>(getParent()->Val)->begin();299}300// Else get the Previous sandbox IR instruction's bottom IR instruction and301// return its successor.302llvm::Instruction *PrevBotI = cast<llvm::Instruction>(Prev->Val);303return PrevBotI->getNextNode();304}305306BBIterator Instruction::getIterator() const {307auto *I = cast<llvm::Instruction>(Val);308return BasicBlock::iterator(I->getParent(), I->getIterator(), &Ctx);309}310311Instruction *Instruction::getNextNode() const {312assert(getParent() != nullptr && "Detached!");313assert(getIterator() != getParent()->end() && "Already at end!");314// `Val` is the bottom-most LLVM IR instruction. Get the next in the chain,315// and get the corresponding sandboxir Instruction that maps to it. This works316// even for SandboxIR Instructions that map to more than one LLVM Instruction.317auto *LLVMI = cast<llvm::Instruction>(Val);318assert(LLVMI->getParent() != nullptr && "LLVM IR instr is detached!");319auto *NextLLVMI = LLVMI->getNextNode();320auto *NextI = cast_or_null<Instruction>(Ctx.getValue(NextLLVMI));321if (NextI == nullptr)322return nullptr;323return NextI;324}325326Instruction *Instruction::getPrevNode() const {327assert(getParent() != nullptr && "Detached!");328auto It = getIterator();329if (It != getParent()->begin())330return std::prev(getIterator()).get();331return nullptr;332}333334void Instruction::removeFromParent() {335auto &Tracker = Ctx.getTracker();336if (Tracker.isTracking())337Tracker.track(std::make_unique<RemoveFromParent>(this, Tracker));338339// Detach all the LLVM IR instructions from their parent BB.340for (llvm::Instruction *I : getLLVMInstrs())341I->removeFromParent();342}343344void Instruction::eraseFromParent() {345assert(users().empty() && "Still connected to users, can't erase!");346std::unique_ptr<Value> Detached = Ctx.detach(this);347auto LLVMInstrs = getLLVMInstrs();348349auto &Tracker = Ctx.getTracker();350if (Tracker.isTracking()) {351Tracker.track(352std::make_unique<EraseFromParent>(std::move(Detached), Tracker));353// We don't actually delete the IR instruction, because then it would be354// impossible to bring it back from the dead at the same memory location.355// Instead we remove it from its BB and track its current location.356for (llvm::Instruction *I : LLVMInstrs)357I->removeFromParent();358// TODO: Multi-instructions need special treatment because some of the359// references are internal to the instruction.360for (llvm::Instruction *I : LLVMInstrs)361I->dropAllReferences();362} else {363// Erase in reverse to avoid erasing nstructions with attached uses.364for (llvm::Instruction *I : reverse(LLVMInstrs))365I->eraseFromParent();366}367}368369void Instruction::moveBefore(BasicBlock &BB, const BBIterator &WhereIt) {370if (std::next(getIterator()) == WhereIt)371// Destination is same as origin, nothing to do.372return;373374auto &Tracker = Ctx.getTracker();375if (Tracker.isTracking())376Tracker.track(std::make_unique<MoveInstr>(this, Tracker));377378auto *LLVMBB = cast<llvm::BasicBlock>(BB.Val);379llvm::BasicBlock::iterator It;380if (WhereIt == BB.end()) {381It = LLVMBB->end();382} else {383Instruction *WhereI = &*WhereIt;384It = WhereI->getTopmostLLVMInstruction()->getIterator();385}386// TODO: Move this to the verifier of sandboxir::Instruction.387assert(is_sorted(getLLVMInstrs(),388[](auto *I1, auto *I2) { return I1->comesBefore(I2); }) &&389"Expected program order!");390// Do the actual move in LLVM IR.391for (auto *I : getLLVMInstrs())392I->moveBefore(*LLVMBB, It);393}394395void Instruction::insertBefore(Instruction *BeforeI) {396llvm::Instruction *BeforeTopI = BeforeI->getTopmostLLVMInstruction();397// TODO: Move this to the verifier of sandboxir::Instruction.398assert(is_sorted(getLLVMInstrs(),399[](auto *I1, auto *I2) { return I1->comesBefore(I2); }) &&400"Expected program order!");401// Insert the LLVM IR Instructions in program order.402for (llvm::Instruction *I : getLLVMInstrs())403I->insertBefore(BeforeTopI);404}405406void Instruction::insertAfter(Instruction *AfterI) {407insertInto(AfterI->getParent(), std::next(AfterI->getIterator()));408}409410void Instruction::insertInto(BasicBlock *BB, const BBIterator &WhereIt) {411llvm::BasicBlock *LLVMBB = cast<llvm::BasicBlock>(BB->Val);412llvm::Instruction *LLVMBeforeI;413llvm::BasicBlock::iterator LLVMBeforeIt;414if (WhereIt != BB->end()) {415Instruction *BeforeI = &*WhereIt;416LLVMBeforeI = BeforeI->getTopmostLLVMInstruction();417LLVMBeforeIt = LLVMBeforeI->getIterator();418} else {419LLVMBeforeI = nullptr;420LLVMBeforeIt = LLVMBB->end();421}422// Insert the LLVM IR Instructions in program order.423for (llvm::Instruction *I : getLLVMInstrs())424I->insertInto(LLVMBB, LLVMBeforeIt);425}426427BasicBlock *Instruction::getParent() const {428// Get the LLVM IR Instruction that this maps to, get its parent, and get the429// corresponding sandboxir::BasicBlock by looking it up in sandboxir::Context.430auto *BB = cast<llvm::Instruction>(Val)->getParent();431if (BB == nullptr)432return nullptr;433return cast<BasicBlock>(Ctx.getValue(BB));434}435436bool Instruction::classof(const sandboxir::Value *From) {437switch (From->getSubclassID()) {438#define DEF_INSTR(ID, OPC, CLASS) \439case ClassID::ID: \440return true;441#include "llvm/SandboxIR/SandboxIRValues.def"442default:443return false;444}445}446447#ifndef NDEBUG448void Instruction::dump(raw_ostream &OS) const {449OS << "Unimplemented! Please override dump().";450}451void Instruction::dump() const {452dump(dbgs());453dbgs() << "\n";454}455#endif // NDEBUG456457Value *SelectInst::createCommon(Value *Cond, Value *True, Value *False,458const Twine &Name, IRBuilder<> &Builder,459Context &Ctx) {460llvm::Value *NewV =461Builder.CreateSelect(Cond->Val, True->Val, False->Val, Name);462if (auto *NewSI = dyn_cast<llvm::SelectInst>(NewV))463return Ctx.createSelectInst(NewSI);464assert(isa<llvm::Constant>(NewV) && "Expected constant");465return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));466}467468Value *SelectInst::create(Value *Cond, Value *True, Value *False,469Instruction *InsertBefore, Context &Ctx,470const Twine &Name) {471llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();472auto &Builder = Ctx.getLLVMIRBuilder();473Builder.SetInsertPoint(BeforeIR);474return createCommon(Cond, True, False, Name, Builder, Ctx);475}476477Value *SelectInst::create(Value *Cond, Value *True, Value *False,478BasicBlock *InsertAtEnd, Context &Ctx,479const Twine &Name) {480auto *IRInsertAtEnd = cast<llvm::BasicBlock>(InsertAtEnd->Val);481auto &Builder = Ctx.getLLVMIRBuilder();482Builder.SetInsertPoint(IRInsertAtEnd);483return createCommon(Cond, True, False, Name, Builder, Ctx);484}485486bool SelectInst::classof(const Value *From) {487return From->getSubclassID() == ClassID::Select;488}489490#ifndef NDEBUG491void SelectInst::dump(raw_ostream &OS) const {492dumpCommonPrefix(OS);493dumpCommonSuffix(OS);494}495496void SelectInst::dump() const {497dump(dbgs());498dbgs() << "\n";499}500#endif // NDEBUG501502LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,503Instruction *InsertBefore, Context &Ctx,504const Twine &Name) {505llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();506auto &Builder = Ctx.getLLVMIRBuilder();507Builder.SetInsertPoint(BeforeIR);508auto *NewLI = Builder.CreateAlignedLoad(Ty, Ptr->Val, Align,509/*isVolatile=*/false, Name);510auto *NewSBI = Ctx.createLoadInst(NewLI);511return NewSBI;512}513514LoadInst *LoadInst::create(Type *Ty, Value *Ptr, MaybeAlign Align,515BasicBlock *InsertAtEnd, Context &Ctx,516const Twine &Name) {517auto &Builder = Ctx.getLLVMIRBuilder();518Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));519auto *NewLI = Builder.CreateAlignedLoad(Ty, Ptr->Val, Align,520/*isVolatile=*/false, Name);521auto *NewSBI = Ctx.createLoadInst(NewLI);522return NewSBI;523}524525bool LoadInst::classof(const Value *From) {526return From->getSubclassID() == ClassID::Load;527}528529Value *LoadInst::getPointerOperand() const {530return Ctx.getValue(cast<llvm::LoadInst>(Val)->getPointerOperand());531}532533#ifndef NDEBUG534void LoadInst::dump(raw_ostream &OS) const {535dumpCommonPrefix(OS);536dumpCommonSuffix(OS);537}538539void LoadInst::dump() const {540dump(dbgs());541dbgs() << "\n";542}543#endif // NDEBUG544StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,545Instruction *InsertBefore, Context &Ctx) {546llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();547auto &Builder = Ctx.getLLVMIRBuilder();548Builder.SetInsertPoint(BeforeIR);549auto *NewSI =550Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, /*isVolatile=*/false);551auto *NewSBI = Ctx.createStoreInst(NewSI);552return NewSBI;553}554StoreInst *StoreInst::create(Value *V, Value *Ptr, MaybeAlign Align,555BasicBlock *InsertAtEnd, Context &Ctx) {556auto *InsertAtEndIR = cast<llvm::BasicBlock>(InsertAtEnd->Val);557auto &Builder = Ctx.getLLVMIRBuilder();558Builder.SetInsertPoint(InsertAtEndIR);559auto *NewSI =560Builder.CreateAlignedStore(V->Val, Ptr->Val, Align, /*isVolatile=*/false);561auto *NewSBI = Ctx.createStoreInst(NewSI);562return NewSBI;563}564565bool StoreInst::classof(const Value *From) {566return From->getSubclassID() == ClassID::Store;567}568569Value *StoreInst::getValueOperand() const {570return Ctx.getValue(cast<llvm::StoreInst>(Val)->getValueOperand());571}572573Value *StoreInst::getPointerOperand() const {574return Ctx.getValue(cast<llvm::StoreInst>(Val)->getPointerOperand());575}576577#ifndef NDEBUG578void StoreInst::dump(raw_ostream &OS) const {579dumpCommonPrefix(OS);580dumpCommonSuffix(OS);581}582583void StoreInst::dump() const {584dump(dbgs());585dbgs() << "\n";586}587#endif // NDEBUG588589ReturnInst *ReturnInst::createCommon(Value *RetVal, IRBuilder<> &Builder,590Context &Ctx) {591llvm::ReturnInst *NewRI;592if (RetVal != nullptr)593NewRI = Builder.CreateRet(RetVal->Val);594else595NewRI = Builder.CreateRetVoid();596return Ctx.createReturnInst(NewRI);597}598599ReturnInst *ReturnInst::create(Value *RetVal, Instruction *InsertBefore,600Context &Ctx) {601llvm::Instruction *BeforeIR = InsertBefore->getTopmostLLVMInstruction();602auto &Builder = Ctx.getLLVMIRBuilder();603Builder.SetInsertPoint(BeforeIR);604return createCommon(RetVal, Builder, Ctx);605}606607ReturnInst *ReturnInst::create(Value *RetVal, BasicBlock *InsertAtEnd,608Context &Ctx) {609auto &Builder = Ctx.getLLVMIRBuilder();610Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));611return createCommon(RetVal, Builder, Ctx);612}613614Value *ReturnInst::getReturnValue() const {615auto *LLVMRetVal = cast<llvm::ReturnInst>(Val)->getReturnValue();616return LLVMRetVal != nullptr ? Ctx.getValue(LLVMRetVal) : nullptr;617}618619#ifndef NDEBUG620void ReturnInst::dump(raw_ostream &OS) const {621dumpCommonPrefix(OS);622dumpCommonSuffix(OS);623}624625void ReturnInst::dump() const {626dump(dbgs());627dbgs() << "\n";628}629630void OpaqueInst::dump(raw_ostream &OS) const {631dumpCommonPrefix(OS);632dumpCommonSuffix(OS);633}634635void OpaqueInst::dump() const {636dump(dbgs());637dbgs() << "\n";638}639#endif // NDEBUG640641Constant *Constant::createInt(Type *Ty, uint64_t V, Context &Ctx,642bool IsSigned) {643llvm::Constant *LLVMC = llvm::ConstantInt::get(Ty, V, IsSigned);644return Ctx.getOrCreateConstant(LLVMC);645}646647#ifndef NDEBUG648void Constant::dump(raw_ostream &OS) const {649dumpCommonPrefix(OS);650dumpCommonSuffix(OS);651}652653void Constant::dump() const {654dump(dbgs());655dbgs() << "\n";656}657658void Function::dumpNameAndArgs(raw_ostream &OS) const {659auto *F = cast<llvm::Function>(Val);660OS << *F->getReturnType() << " @" << F->getName() << "(";661interleave(662F->args(),663[this, &OS](const llvm::Argument &LLVMArg) {664auto *SBArg = cast_or_null<Argument>(Ctx.getValue(&LLVMArg));665if (SBArg == nullptr)666OS << "NULL";667else668SBArg->printAsOperand(OS);669},670[&] { OS << ", "; });671OS << ")";672}673void Function::dump(raw_ostream &OS) const {674dumpNameAndArgs(OS);675OS << " {\n";676auto *LLVMF = cast<llvm::Function>(Val);677interleave(678*LLVMF,679[this, &OS](const llvm::BasicBlock &LLVMBB) {680auto *BB = cast_or_null<BasicBlock>(Ctx.getValue(&LLVMBB));681if (BB == nullptr)682OS << "NULL";683else684OS << *BB;685},686[&OS] { OS << "\n"; });687OS << "}\n";688}689void Function::dump() const {690dump(dbgs());691dbgs() << "\n";692}693#endif // NDEBUG694695BasicBlock::iterator::pointer696BasicBlock::iterator::getInstr(llvm::BasicBlock::iterator It) const {697return cast_or_null<Instruction>(Ctx->getValue(&*It));698}699700std::unique_ptr<Value> Context::detachLLVMValue(llvm::Value *V) {701std::unique_ptr<Value> Erased;702auto It = LLVMValueToValueMap.find(V);703if (It != LLVMValueToValueMap.end()) {704auto *Val = It->second.release();705Erased = std::unique_ptr<Value>(Val);706LLVMValueToValueMap.erase(It);707}708return Erased;709}710711std::unique_ptr<Value> Context::detach(Value *V) {712assert(V->getSubclassID() != Value::ClassID::Constant &&713"Can't detach a constant!");714assert(V->getSubclassID() != Value::ClassID::User && "Can't detach a user!");715return detachLLVMValue(V->Val);716}717718Value *Context::registerValue(std::unique_ptr<Value> &&VPtr) {719assert(VPtr->getSubclassID() != Value::ClassID::User &&720"Can't register a user!");721Value *V = VPtr.get();722[[maybe_unused]] auto Pair =723LLVMValueToValueMap.insert({VPtr->Val, std::move(VPtr)});724assert(Pair.second && "Already exists!");725return V;726}727728Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {729auto Pair = LLVMValueToValueMap.insert({LLVMV, nullptr});730auto It = Pair.first;731if (!Pair.second)732return It->second.get();733734if (auto *C = dyn_cast<llvm::Constant>(LLVMV)) {735It->second = std::unique_ptr<Constant>(new Constant(C, *this));736auto *NewC = It->second.get();737for (llvm::Value *COp : C->operands())738getOrCreateValueInternal(COp, C);739return NewC;740}741if (auto *Arg = dyn_cast<llvm::Argument>(LLVMV)) {742It->second = std::unique_ptr<Argument>(new Argument(Arg, *this));743return It->second.get();744}745if (auto *BB = dyn_cast<llvm::BasicBlock>(LLVMV)) {746assert(isa<BlockAddress>(U) &&747"This won't create a SBBB, don't call this function directly!");748if (auto *SBBB = getValue(BB))749return SBBB;750return nullptr;751}752assert(isa<llvm::Instruction>(LLVMV) && "Expected Instruction");753754switch (cast<llvm::Instruction>(LLVMV)->getOpcode()) {755case llvm::Instruction::Select: {756auto *LLVMSel = cast<llvm::SelectInst>(LLVMV);757It->second = std::unique_ptr<SelectInst>(new SelectInst(LLVMSel, *this));758return It->second.get();759}760case llvm::Instruction::Load: {761auto *LLVMLd = cast<llvm::LoadInst>(LLVMV);762It->second = std::unique_ptr<LoadInst>(new LoadInst(LLVMLd, *this));763return It->second.get();764}765case llvm::Instruction::Store: {766auto *LLVMSt = cast<llvm::StoreInst>(LLVMV);767It->second = std::unique_ptr<StoreInst>(new StoreInst(LLVMSt, *this));768return It->second.get();769}770case llvm::Instruction::Ret: {771auto *LLVMRet = cast<llvm::ReturnInst>(LLVMV);772It->second = std::unique_ptr<ReturnInst>(new ReturnInst(LLVMRet, *this));773return It->second.get();774}775default:776break;777}778779It->second = std::unique_ptr<OpaqueInst>(780new OpaqueInst(cast<llvm::Instruction>(LLVMV), *this));781return It->second.get();782}783784BasicBlock *Context::createBasicBlock(llvm::BasicBlock *LLVMBB) {785assert(getValue(LLVMBB) == nullptr && "Already exists!");786auto NewBBPtr = std::unique_ptr<BasicBlock>(new BasicBlock(LLVMBB, *this));787auto *BB = cast<BasicBlock>(registerValue(std::move(NewBBPtr)));788// Create SandboxIR for BB's body.789BB->buildBasicBlockFromLLVMIR(LLVMBB);790return BB;791}792793SelectInst *Context::createSelectInst(llvm::SelectInst *SI) {794auto NewPtr = std::unique_ptr<SelectInst>(new SelectInst(SI, *this));795return cast<SelectInst>(registerValue(std::move(NewPtr)));796}797798LoadInst *Context::createLoadInst(llvm::LoadInst *LI) {799auto NewPtr = std::unique_ptr<LoadInst>(new LoadInst(LI, *this));800return cast<LoadInst>(registerValue(std::move(NewPtr)));801}802803StoreInst *Context::createStoreInst(llvm::StoreInst *SI) {804auto NewPtr = std::unique_ptr<StoreInst>(new StoreInst(SI, *this));805return cast<StoreInst>(registerValue(std::move(NewPtr)));806}807808ReturnInst *Context::createReturnInst(llvm::ReturnInst *I) {809auto NewPtr = std::unique_ptr<ReturnInst>(new ReturnInst(I, *this));810return cast<ReturnInst>(registerValue(std::move(NewPtr)));811}812813Value *Context::getValue(llvm::Value *V) const {814auto It = LLVMValueToValueMap.find(V);815if (It != LLVMValueToValueMap.end())816return It->second.get();817return nullptr;818}819820Function *Context::createFunction(llvm::Function *F) {821assert(getValue(F) == nullptr && "Already exists!");822auto NewFPtr = std::unique_ptr<Function>(new Function(F, *this));823// Create arguments.824for (auto &Arg : F->args())825getOrCreateArgument(&Arg);826// Create BBs.827for (auto &BB : *F)828createBasicBlock(&BB);829auto *SBF = cast<Function>(registerValue(std::move(NewFPtr)));830return SBF;831}832833Function *BasicBlock::getParent() const {834auto *BB = cast<llvm::BasicBlock>(Val);835auto *F = BB->getParent();836if (F == nullptr)837// Detached838return nullptr;839return cast_or_null<Function>(Ctx.getValue(F));840}841842void BasicBlock::buildBasicBlockFromLLVMIR(llvm::BasicBlock *LLVMBB) {843for (llvm::Instruction &IRef : reverse(*LLVMBB)) {844llvm::Instruction *I = &IRef;845Ctx.getOrCreateValue(I);846for (auto [OpIdx, Op] : enumerate(I->operands())) {847// Skip instruction's label operands848if (isa<llvm::BasicBlock>(Op))849continue;850// Skip metadata851if (isa<llvm::MetadataAsValue>(Op))852continue;853// Skip asm854if (isa<llvm::InlineAsm>(Op))855continue;856Ctx.getOrCreateValue(Op);857}858}859#if !defined(NDEBUG) && defined(SBVEC_EXPENSIVE_CHECKS)860verify();861#endif862}863864BasicBlock::iterator BasicBlock::begin() const {865llvm::BasicBlock *BB = cast<llvm::BasicBlock>(Val);866llvm::BasicBlock::iterator It = BB->begin();867if (!BB->empty()) {868auto *V = Ctx.getValue(&*BB->begin());869assert(V != nullptr && "No SandboxIR for BB->begin()!");870auto *I = cast<Instruction>(V);871unsigned Num = I->getNumOfIRInstrs();872assert(Num >= 1u && "Bad getNumOfIRInstrs()");873It = std::next(It, Num - 1);874}875return iterator(BB, It, &Ctx);876}877878Instruction *BasicBlock::getTerminator() const {879auto *TerminatorV =880Ctx.getValue(cast<llvm::BasicBlock>(Val)->getTerminator());881return cast_or_null<Instruction>(TerminatorV);882}883884Instruction &BasicBlock::front() const {885auto *BB = cast<llvm::BasicBlock>(Val);886assert(!BB->empty() && "Empty block!");887auto *SBI = cast<Instruction>(getContext().getValue(&*BB->begin()));888assert(SBI != nullptr && "Expected Instr!");889return *SBI;890}891892Instruction &BasicBlock::back() const {893auto *BB = cast<llvm::BasicBlock>(Val);894assert(!BB->empty() && "Empty block!");895auto *SBI = cast<Instruction>(getContext().getValue(&*BB->rbegin()));896assert(SBI != nullptr && "Expected Instr!");897return *SBI;898}899900#ifndef NDEBUG901void BasicBlock::dump(raw_ostream &OS) const {902llvm::BasicBlock *BB = cast<llvm::BasicBlock>(Val);903const auto &Name = BB->getName();904OS << Name;905if (!Name.empty())906OS << ":\n";907// If there are Instructions in the BB that are not mapped to SandboxIR, then908// use a crash-proof dump.909if (any_of(*BB, [this](llvm::Instruction &I) {910return Ctx.getValue(&I) == nullptr;911})) {912OS << "<Crash-proof mode!>\n";913DenseSet<Instruction *> Visited;914for (llvm::Instruction &IRef : *BB) {915Value *SBV = Ctx.getValue(&IRef);916if (SBV == nullptr)917OS << IRef << " *** No SandboxIR ***\n";918else {919auto *SBI = dyn_cast<Instruction>(SBV);920if (SBI == nullptr) {921OS << IRef << " *** Not a SBInstruction!!! ***\n";922} else {923if (Visited.insert(SBI).second)924OS << *SBI << "\n";925}926}927}928} else {929for (auto &SBI : *this) {930SBI.dump(OS);931OS << "\n";932}933}934}935void BasicBlock::dump() const {936dump(dbgs());937dbgs() << "\n";938}939#endif // NDEBUG940941942