-
Notifications
You must be signed in to change notification settings - Fork 10.5k
APIs for terminator results that forward ownership #62493
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 |
---|---|---|
|
@@ -1182,6 +1182,9 @@ class OwnershipForwardingMixin { | |
/// | ||
/// The ownership kind is set on construction and afterwards must be changed | ||
/// explicitly using setOwnershipKind(). | ||
/// | ||
/// TODO: This name is extremely misleading because it may apply to an | ||
/// operation that has no operand at all, like `enum .None`. | ||
class FirstArgOwnershipForwardingSingleValueInst | ||
: public SingleValueInstruction, | ||
public OwnershipForwardingMixin { | ||
|
@@ -1668,6 +1671,8 @@ class UnaryInstructionBase : public InstructionBase<Kind, Base> { | |
|
||
Operand &getOperandRef() { return Operands[0]; } | ||
|
||
const Operand &getOperandRef() const { return Operands[0]; } | ||
|
||
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); } | ||
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); } | ||
|
||
|
@@ -1808,6 +1813,10 @@ class UnaryInstructionWithTypeDependentOperandsBase | |
return this->getAllOperands()[0]; | ||
} | ||
|
||
const Operand &getOperandRef() const { | ||
return this->getAllOperands()[0]; | ||
} | ||
|
||
ArrayRef<Operand> getTypeDependentOperands() const { | ||
return this->getAllOperands().slice(1); | ||
} | ||
|
@@ -6203,6 +6212,8 @@ class EnumInst | |
|
||
Operand &getOperandRef() { return OptionalOperand->asArray()[0]; } | ||
|
||
const Operand &getOperandRef() const { return OptionalOperand->asArray()[0]; } | ||
|
||
ArrayRef<Operand> getAllOperands() const { | ||
return OptionalOperand ? OptionalOperand->asArray() : ArrayRef<Operand>{}; | ||
} | ||
|
@@ -8384,31 +8395,50 @@ class TermInst : public NonValueInstruction { | |
|
||
TermKind getTermKind() const { return TermKind(getKind()); } | ||
|
||
/// Returns true if this is a transformation terminator. | ||
/// Returns true if this terminator may have a result, represented as a block | ||
/// argument in any of its successor blocks. | ||
/// | ||
/// The first operand is the transformed source. | ||
bool isTransformationTerminator() const { | ||
/// Phis (whose operands originate from BranchInst terminators) are not | ||
/// terminator results. | ||
/// | ||
/// CondBr might produce block arguments for legacy reasons. This is gradually | ||
/// being deprecated. For now, they are considered phis. In OSSA, these "phis" | ||
/// must be trivial and critical edges cannot be present. | ||
bool mayHaveTerminatorResult() const { | ||
switch (getTermKind()) { | ||
case TermKind::UnwindInst: | ||
case TermKind::UnreachableInst: | ||
case TermKind::ReturnInst: | ||
case TermKind::ThrowInst: | ||
case TermKind::YieldInst: | ||
case TermKind::TryApplyInst: | ||
case TermKind::BranchInst: | ||
case TermKind::CondBranchInst: | ||
case TermKind::SwitchValueInst: | ||
case TermKind::BranchInst: | ||
case TermKind::SwitchEnumAddrInst: | ||
case TermKind::DynamicMethodBranchInst: | ||
case TermKind::CheckedCastAddrBranchInst: | ||
case TermKind::AwaitAsyncContinuationInst: | ||
return false; | ||
case TermKind::SwitchEnumInst: | ||
case TermKind::CheckedCastBranchInst: | ||
case TermKind::SwitchEnumInst: | ||
case TermKind::SwitchValueInst: | ||
case TermKind::TryApplyInst: | ||
case TermKind::AwaitAsyncContinuationInst: | ||
case TermKind::DynamicMethodBranchInst: | ||
return true; | ||
} | ||
llvm_unreachable("Covered switch isn't covered."); | ||
} | ||
|
||
/// Returns an Operand reference if this terminator forwards ownership of a | ||
/// single operand to a single result for at least one successor | ||
/// block. Otherwise returns nullptr. | ||
/// | ||
/// By convention, terminators can forward ownership of at most one operand to | ||
/// at most one result. The operand value might not be directly forwarded. For | ||
/// example, a switch forwards ownership of the enum type into ownership of | ||
/// the payload. | ||
/// | ||
/// Postcondition: each successor has zero or one block arguments which | ||
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. nit: pre condition(?) 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, the post-condition only holds if the a forwarding operand is returned. I can clarify that in the next PR |
||
/// represents the forwaded result. | ||
const Operand *forwardedOperand() const; | ||
}; | ||
|
||
// Forwards the first operand to a result in each successor block. | ||
|
@@ -8442,6 +8472,10 @@ class OwnershipForwardingTermInst : public TermInst, | |
|
||
SILValue getOperand() const { return getAllOperands()[0].get(); } | ||
|
||
Operand &getOperandRef() { return getAllOperands()[0]; } | ||
|
||
const Operand &getOperandRef() const { return getAllOperands()[0]; } | ||
|
||
/// Create a result for this terminator on the given successor block. | ||
SILPhiArgument *createResult(SILBasicBlock *succ, SILType resultTy); | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,16 +77,17 @@ SILParameterInfo SILFunctionArgument::getKnownParameterInfo() const { | |
// SILBlockArgument | ||
//===----------------------------------------------------------------------===// | ||
|
||
// FIXME: SILPhiArgument should only refer to branch arguments. They usually | ||
// need to be distinguished from projections and casts. Actual phi block | ||
// arguments are substitutable with their incoming values. It is also needlessly | ||
// expensive to call this helper instead of simply specifying phis with an | ||
// opcode. It results in repeated CFG traversals and repeated, unnecessary | ||
// switching over terminator opcodes. | ||
// FIXME: SILPhiArgument should only refer to phis (values merged from | ||
// BranchInst operands). Phis are directly substitutable with their incoming | ||
// values modulo control flow. They usually need to be distinguished from | ||
// projections and casts. It is needlessly expensive to call this helper instead | ||
// of simply specifying phis with an opcode. It results in repeated CFG | ||
// traversals and repeated, unnecessary switching over terminator opcodes. | ||
bool SILPhiArgument::isPhi() const { | ||
// No predecessors indicates an unreachable block. | ||
// No predecessors indicates an unreachable block. Treat this like a | ||
// degenerate phi so we don't consider it a terminator result. | ||
if (getParent()->pred_empty()) | ||
return false; | ||
return true; | ||
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. For the same reason as this, shouldn't we return 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. When there is a single predecessor, we check for terminator results using |
||
|
||
// Multiple predecessors require phis. | ||
auto *predBlock = getParent()->getSinglePredecessorBlock(); | ||
|
@@ -215,7 +216,6 @@ bool SILPhiArgument::getIncomingPhiValues( | |
return false; | ||
|
||
const auto *parentBlock = getParent(); | ||
assert(!parentBlock->pred_empty()); | ||
|
||
unsigned argIndex = getIndex(); | ||
for (auto *predBlock : getParent()->getPredecessorBlocks()) { | ||
|
@@ -323,14 +323,6 @@ bool SILPhiArgument::getSingleTerminatorOperands( | |
return true; | ||
} | ||
|
||
SILValue SILPhiArgument::getSingleTerminatorOperand() const { | ||
const auto *parentBlock = getParent(); | ||
const auto *predBlock = parentBlock->getSinglePredecessorBlock(); | ||
if (!predBlock) | ||
return SILValue(); | ||
return getSingleTerminatorOperandForPred(parentBlock, predBlock, getIndex()); | ||
} | ||
|
||
TermInst *SILPhiArgument::getSingleTerminator() const { | ||
auto *parentBlock = getParent(); | ||
auto *predBlock = parentBlock->getSinglePredecessorBlock(); | ||
|
@@ -349,6 +341,11 @@ TermInst *SILPhiArgument::getTerminatorForResult() const { | |
return nullptr; | ||
} | ||
|
||
const Operand *SILArgument::forwardedTerminatorResultOperand() const { | ||
assert(isTerminatorResult() && "API is invalid for phis"); | ||
return getSingleTerminator()->forwardedOperand(); | ||
} | ||
|
||
SILPhiArgument *BranchInst::getArgForOperand(const Operand *oper) { | ||
assert(oper->getUser() == this); | ||
return cast<SILPhiArgument>( | ||
|
Uh oh!
There was an error while loading. Please reload this page.