-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[SandboxIR] Add more Instruction member functions #98588
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -262,6 +262,115 @@ const char *Instruction::getOpcodeName(Opcode Opc) { | |
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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this necessary? this is part of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still think that |
||
assert(getParent() != nullptr && "Detached!"); | ||
assert(getIterator() != getParent()->end() && "Already at end!"); | ||
auto *LLVMI = cast<llvm::Instruction>(Val); | ||
assert(LLVMI->getParent() != nullptr && "LLVM IR instr is detached!"); | ||
auto *NextLLVMI = LLVMI->getNextNode(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what about multi-instruction instructions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So here is how this works: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah the confusing part is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh I see. can you update the comments around |
||
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() { | ||
// 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!"); | ||
vporpo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// We don't have Tracking yet, so just erase the LLVM IR instructions. | ||
// Erase in reverse to avoid erasing nstructions with attached uses. | ||
for (llvm::Instruction *I : reverse(getLLVMInstrs())) | ||
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 *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!"); | ||
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; | ||
if (WhereIt != BB->end()) { | ||
Instruction *BeforeI = &*WhereIt; | ||
LLVMBeforeI = BeforeI->getTopmostLLVMInstruction(); | ||
LLVMBeforeIt = LLVMBeforeI->getIterator(); | ||
} else { | ||
LLVMBeforeI = nullptr; | ||
LLVMBeforeIt = LLVMBB->end(); | ||
} | ||
for (llvm::Instruction *I : getLLVMInstrs()) | ||
I->insertInto(LLVMBB, LLVMBeforeIt); | ||
} | ||
|
||
BasicBlock *Instruction::getParent() const { | ||
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) \ | ||
|
@@ -344,6 +453,24 @@ 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!"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm debating whether or not this should have
[[nodiscard]]
. Unsure how pervasive you'd want[[nodiscard]]
to be throughout these APIsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel strongly either way, but these
detach()
functions are meant to be used either for detaching or for just deleting the value. I think it's currently only used for deleting them, so the value is discarded. There is no real harm in discarding the returned value as far as I can tell.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we wanted to keep around Values in case we rollback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These APIs are for internal use only. The user won't be able to detach values. The only way a user can delete a value is through the
eraseFromParent()
API, and this will be tracked and can be rolled back.