Skip to content

Commit ceb1fda

Browse files
authored
Merge pull request #34930 from gottesmm/pr-d981ca4c510954e4ca19818a4303454d4bda80e3
[semantic-arc] Prevent future pointer invalidation issues in the OwnedToGuaranteedPhiOp transform.
2 parents 6400a43 + 5dbd34d commit ceb1fda

File tree

4 files changed

+63
-7
lines changed

4 files changed

+63
-7
lines changed

lib/SILOptimizer/SemanticARC/Context.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,44 @@ struct LLVM_LIBRARY_VISIBILITY Context {
6464
/// our LiveRange can not see through joined live ranges, we know that we
6565
/// should only be able to have a single owned value introducer for each
6666
/// consumed operand.
67-
FrozenMultiMap<SILValue, Operand *> joinedOwnedIntroducerToConsumedOperands;
67+
///
68+
/// NOTE: To work around potential invalidation of our consuming operands when
69+
/// adding values to edges on the CFG, we store our Operands as a
70+
/// SILBasicBlock and an operand number. We only add values to edges and never
71+
/// remove/modify edges so the operand number should be safe.
72+
struct ConsumingOperandState {
73+
PointerUnion<SILBasicBlock *, SILInstruction *> parent;
74+
unsigned operandNumber;
75+
76+
ConsumingOperandState() : parent(nullptr), operandNumber(UINT_MAX) {}
77+
78+
ConsumingOperandState(Operand *op)
79+
: parent(), operandNumber(op->getOperandNumber()) {
80+
if (auto *ti = dyn_cast<TermInst>(op->getUser())) {
81+
parent = ti->getParent();
82+
} else {
83+
parent = op->getUser();
84+
}
85+
}
86+
87+
ConsumingOperandState(const ConsumingOperandState &other) :
88+
parent(other.parent), operandNumber(other.operandNumber) {}
89+
90+
ConsumingOperandState &operator=(const ConsumingOperandState &other) {
91+
parent = other.parent;
92+
operandNumber = other.operandNumber;
93+
return *this;
94+
}
95+
96+
~ConsumingOperandState() = default;
97+
98+
operator bool() const {
99+
return bool(parent) && operandNumber != UINT_MAX;
100+
}
101+
};
102+
103+
FrozenMultiMap<SILValue, ConsumingOperandState>
104+
joinedOwnedIntroducerToConsumedOperands;
68105

69106
/// If set to true, then we should only run cheap optimizations that do not
70107
/// build up data structures or analyze code in depth.

lib/SILOptimizer/SemanticARC/CopyValueOpts.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,9 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(
224224
});
225225

226226
if (canOptimizePhi) {
227+
Context::ConsumingOperandState state(opPhi);
227228
opPhi.visitResults([&](SILValue value) {
228-
ctx.joinedOwnedIntroducerToConsumedOperands.insert(value,
229-
opPhi.getOperand());
229+
ctx.joinedOwnedIntroducerToConsumedOperands.insert(value, state);
230230
return true;
231231
});
232232
}

lib/SILOptimizer/SemanticARC/OwnedToGuaranteedPhiOpt.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,18 @@
1919
#include "Context.h"
2020
#include "OwnershipPhiOperand.h"
2121
#include "Transforms.h"
22+
#include "swift/Basic/STLExtras.h"
2223

2324
using namespace swift;
2425
using namespace swift::semanticarc;
2526

27+
namespace {
28+
using ConsumingOperandState = Context::ConsumingOperandState;
29+
} // anonymous namespace
30+
31+
template <typename OperandRangeTy>
2632
static bool canEliminatePhi(
27-
Context::FrozenMultiMapRange optimizableIntroducerRange,
33+
OperandRangeTy optimizableIntroducerRange,
2834
ArrayRef<OwnershipPhiOperand> incomingValueOperandList,
2935
SmallVectorImpl<OwnedValueIntroducer> &ownedValueIntroducerAccumulator) {
3036
for (auto incomingValueOperand : incomingValueOperandList) {
@@ -161,9 +167,19 @@ bool swift::semanticarc::tryConvertOwnedPhisToGuaranteedPhis(Context &ctx) {
161167
// eliminated if it was not for the given phi. If all of them are, we can
162168
// optimize!
163169
{
164-
auto rawFoundOptimizableIntroducerArray = pair.second;
165-
if (!canEliminatePhi(rawFoundOptimizableIntroducerArray,
166-
incomingValueOperandList, ownedValueIntroducers)) {
170+
std::function<Operand *(const Context::ConsumingOperandState)> lambda =
171+
[&](const Context::ConsumingOperandState &state) -> Operand * {
172+
unsigned opNum = state.operandNumber;
173+
if (state.parent.is<SILBasicBlock *>()) {
174+
SILBasicBlock *block = state.parent.get<SILBasicBlock *>();
175+
return &block->getTerminator()->getAllOperands()[opNum];
176+
}
177+
SILInstruction *inst = state.parent.get<SILInstruction *>();
178+
return &inst->getAllOperands()[opNum];
179+
};
180+
auto operandsTransformed = makeTransformRange(pair.second, lambda);
181+
if (!canEliminatePhi(operandsTransformed, incomingValueOperandList,
182+
ownedValueIntroducers)) {
167183
continue;
168184
}
169185
}

lib/SILOptimizer/SemanticARC/OwnershipPhiOperand.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class LLVM_LIBRARY_VISIBILITY OwnershipPhiOperand {
6464
}
6565
}
6666

67+
operator const Operand *() const { return op; }
68+
operator Operand *() { return op; }
69+
6770
Operand *getOperand() const { return op; }
6871
SILValue getValue() const { return op->get(); }
6972
SILType getType() const { return op->get()->getType(); }

0 commit comments

Comments
 (0)