Skip to content

Commit 90f3846

Browse files
committed
[sil] Define ValueBase::getNextInstruction().
Sometimes when you are working with SILValues, you need a "next" insertion point. This creates a problem with the SILValue API since even though one can get an instruction or an insertion point for a value, to find the appropriate next instruction one needs to pierce through the API and see if one has a SILArgument or SILInstruction breaking the whole point of abstraction. The specific problem here is that a SILArgument's "next instruction" is the first element of the block (that is ValueBase::getDefiningInsertionPoint()) and SILInstruction's "next instruction" is std::next(ValueBase::getDefiningInsertionPoint()). This new API (ValueBase::getNextInstruction()) handles this case for the compiler writer and eliminates unnecessary code contortions. I also did a little cleanup where I moved a doxygen comment from a near by a const_casting trampoline method to the method that the trampoline called (see getDefiningInsertionPoint()).
1 parent 4db2aa6 commit 90f3846

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

include/swift/SIL/SILValue.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,11 +468,46 @@ class ValueBase : public SILNode, public SILAllocated<ValueBase> {
468468
/// For instruction results, this returns getDefiningInstruction(). For
469469
/// arguments, this returns SILBasicBlock::begin() for the argument's parent
470470
/// block. Returns nullptr for SILUndef.
471+
SILInstruction *getDefiningInsertionPoint();
472+
473+
// Const version of \see getDefiningInsertionPoint.
471474
const SILInstruction *getDefiningInsertionPoint() const {
472475
return const_cast<ValueBase *>(this)->getDefiningInsertionPoint();
473476
}
474477

475-
SILInstruction *getDefiningInsertionPoint();
478+
/// Return the next SIL instruction to execute /after/ this value is
479+
/// available.
480+
///
481+
/// Operationally this means that:
482+
///
483+
/// * For SILArguments, this returns the first instruction in the block. This
484+
/// is the main divergence from getDefiningInsertionPoint (see discussion
485+
/// below).
486+
///
487+
/// * For SILInstructions, this returns std::next.
488+
///
489+
/// * For SILUndef, this returns nullptr.
490+
///
491+
/// DISCUSSION: The reason that this exists is that when one wants a "next"
492+
/// instruction pointer, one often times wants to write:
493+
///
494+
/// if (auto *insertPt = value->getDefiningInsertionPoint())
495+
/// return std::next(insertPt);
496+
///
497+
/// This is incorrect for SILArguments since after processing a SILArgument,
498+
/// we need to process the actual first instruction in the block. With this
499+
/// API, one can simply do:
500+
///
501+
/// if (auto *inst = value->getNextInstruction())
502+
/// return inst;
503+
///
504+
/// And get the correct answer every time.
505+
SILInstruction *getNextInstruction();
506+
507+
// Const version of \see getDefiningInsertionPoint.
508+
const SILInstruction *getNextInstruction() const {
509+
return const_cast<ValueBase *>(this)->getNextInstruction();
510+
}
476511

477512
struct DefiningInstructionResult {
478513
SILInstruction *Instruction;

lib/SIL/IR/SILValue.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ SILInstruction *ValueBase::getDefiningInsertionPoint() {
8181
return nullptr;
8282
}
8383

84+
SILInstruction *ValueBase::getNextInstruction() {
85+
if (auto *inst = getDefiningInstruction())
86+
return std::next(inst);
87+
if (auto *arg = dyn_cast<SILArgument>(this))
88+
return &*arg->getParentBlock()->begin();
89+
return nullptr;
90+
}
91+
8492
Optional<ValueBase::DefiningInstructionResult>
8593
ValueBase::getDefiningInstructionResult() {
8694
if (auto *inst = dyn_cast<SingleValueInstruction>(this))

0 commit comments

Comments
 (0)