Skip to content

Commit 1121ee5

Browse files
committed
Add new flags "reborrow" and "escaping" to SILArgument.
"reborrow" flag on the SILArgument avoids transitive walk over the phi operandsi to determine if it is a reborrow in multiple utilities. SIL transforms must keep the flag up-to-date by calling SILArgument::setReborrow. SILVerifier checks to ensure the flag is not invalidated. Currently "escaping" is not used anywhere.
1 parent 6051885 commit 1121ee5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+504
-133
lines changed

include/swift/SIL/OwnershipUseVisitor.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,11 @@ bool OwnershipUseVisitor<Impl>::visitInteriorUses(SILValue ssaDef) {
317317
// Inner adjacent reborrows are considered inner borrow scopes.
318318
if (auto phi = SILArgument::asPhi(ssaDef)) {
319319
if (!visitInnerAdjacentPhis(phi, [&](SILArgument *innerPhi) {
320-
// TODO: Remove this call to isGuaranteedForwarding.
321-
// The phi itself should know if it is a reborrow.
322-
if (isGuaranteedForwarding(innerPhi)) {
323-
return visitGuaranteedUses(innerPhi);
324-
} else {
325-
return visitInnerAdjacentReborrow(innerPhi);
326-
}
327-
})) {
320+
if (innerPhi->isGuaranteedForwarding()) {
321+
return visitGuaranteedUses(innerPhi);
322+
}
323+
return visitInnerAdjacentReborrow(innerPhi);
324+
})) {
328325
return false;
329326
}
330327
}

include/swift/SIL/OwnershipUtils.h

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -57,45 +57,13 @@ bool canOpcodeForwardInnerGuaranteedValues(SILValue value);
5757
/// the operation may be trivially rewritten with Guaranteed ownership.
5858
bool canOpcodeForwardInnerGuaranteedValues(Operand *use);
5959

60+
bool computeIsScoped(SILArgument *arg);
61+
62+
bool computeIsReborrow(SILArgument *arg);
63+
6064
// This is the use-def equivalent of use->getOperandOwnership() ==
6165
// OperandOwnership::GuaranteedForwarding.
62-
inline bool isGuaranteedForwarding(SILValue value) {
63-
if (value->getOwnershipKind() != OwnershipKind::Guaranteed) {
64-
return false;
65-
}
66-
// NOTE: canOpcodeForwardInnerGuaranteedValues returns true for transformation
67-
// terminator results.
68-
if (canOpcodeForwardInnerGuaranteedValues(value) ||
69-
isa<SILFunctionArgument>(value)) {
70-
return true;
71-
}
72-
// If not a phi, return false
73-
auto *phi = dyn_cast<SILPhiArgument>(value);
74-
if (!phi || !phi->isPhi()) {
75-
return false;
76-
}
77-
// For a phi, if we find GuaranteedForwarding phi operand on any incoming
78-
// path, we return true. Additional verification is added to ensure
79-
// GuaranteedForwarding phi operands are found on zero or all paths in the
80-
// OwnershipVerifier.
81-
bool isGuaranteedForwardingPhi = false;
82-
phi->visitTransitiveIncomingPhiOperands([&](auto *, auto *op) -> bool {
83-
auto opValue = op->get();
84-
assert(opValue->getOwnershipKind().isCompatibleWith(
85-
OwnershipKind::Guaranteed));
86-
if (canOpcodeForwardInnerGuaranteedValues(opValue) ||
87-
isa<SILFunctionArgument>(opValue)) {
88-
isGuaranteedForwardingPhi = true;
89-
return false;
90-
}
91-
auto *phi = dyn_cast<SILPhiArgument>(opValue);
92-
if (!phi || !phi->isPhi()) {
93-
return false;
94-
}
95-
return true;
96-
});
97-
return isGuaranteedForwardingPhi;
98-
}
66+
bool computeIsGuaranteedForwarding(SILValue value);
9967

10068
/// Is the opcode that produces \p value capable of forwarding owned values?
10169
///
@@ -523,7 +491,7 @@ class BorrowedValueKind {
523491
})) {
524492
return Kind::Invalid;
525493
}
526-
if (isGuaranteedForwarding(value)) {
494+
if (cast<SILArgument>(value)->isGuaranteedForwarding()) {
527495
return Kind::Invalid;
528496
}
529497
return Kind::Phi;

include/swift/SIL/SILArgument.h

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,31 @@ class SILArgument : public ValueBase {
7777
SILType type, ValueOwnershipKind ownershipKind,
7878
const ValueDecl *inputDecl = nullptr);
7979

80+
SILArgument(ValueKind subClassKind, SILBasicBlock *inputParentBlock,
81+
SILType type, ValueOwnershipKind ownershipKind, bool reborrow,
82+
bool escaping, const ValueDecl *inputDecl = nullptr);
83+
8084
// A special constructor, only intended for use in
8185
// SILBasicBlock::replacePHIArg and replaceFunctionArg.
8286
explicit SILArgument(ValueKind subClassKind, SILType type,
8387
ValueOwnershipKind ownershipKind,
8488
const ValueDecl *inputDecl = nullptr)
85-
: ValueBase(subClassKind, type),
86-
parentBlock(nullptr), decl(inputDecl) {
89+
: ValueBase(subClassKind, type), parentBlock(nullptr), decl(inputDecl) {
8790
sharedUInt8().SILArgument.valueOwnershipKind = uint8_t(ownershipKind);
91+
// When the optimizer creates reborrows, reborrow flag needs to be set by
92+
// calling setReborrow.
93+
sharedUInt8().SILArgument.reborrow = false;
94+
sharedUInt8().SILArgument.escaping = false;
95+
}
96+
97+
explicit SILArgument(ValueKind subClassKind, SILType type,
98+
ValueOwnershipKind ownershipKind, bool reborrow,
99+
bool escaping, const ValueDecl *inputDecl = nullptr)
100+
: ValueBase(subClassKind, type), parentBlock(nullptr), decl(inputDecl) {
101+
assert(ownershipKind != OwnershipKind::Owned || (reborrow == true));
102+
sharedUInt8().SILArgument.valueOwnershipKind = uint8_t(ownershipKind);
103+
sharedUInt8().SILArgument.reborrow = reborrow;
104+
sharedUInt8().SILArgument.escaping = escaping;
88105
}
89106

90107
public:
@@ -95,10 +112,41 @@ class SILArgument : public ValueBase {
95112
return ValueOwnershipKind(sharedUInt8().SILArgument.valueOwnershipKind);
96113
}
97114

115+
bool isScoped() const {
116+
auto ownershipKind = getOwnershipKind();
117+
if (ownershipKind == OwnershipKind::Owned) {
118+
return true;
119+
}
120+
if (ownershipKind != OwnershipKind::Guaranteed) {
121+
return false;
122+
}
123+
return isReborrow();
124+
}
125+
126+
bool isReborrow() const {
127+
return ValueOwnershipKind(sharedUInt8().SILArgument.reborrow);
128+
}
129+
130+
bool isGuaranteedForwarding() const {
131+
return getOwnershipKind() == OwnershipKind::Guaranteed && !isReborrow();
132+
}
133+
134+
bool isEscaping() const {
135+
return ValueOwnershipKind(sharedUInt8().SILArgument.escaping);
136+
}
137+
98138
void setOwnershipKind(ValueOwnershipKind newKind) {
99139
sharedUInt8().SILArgument.valueOwnershipKind = uint8_t(newKind);
100140
}
101141

142+
void setReborrow(bool isReborrow) {
143+
sharedUInt8().SILArgument.reborrow = isReborrow;
144+
}
145+
146+
void setEscaping(bool isEscaping) {
147+
sharedUInt8().SILArgument.escaping = isEscaping;
148+
}
149+
102150
SILBasicBlock *getParent() const { return parentBlock; }
103151

104152
/// Returns true if this argument is erased from a basic block.
@@ -226,12 +274,25 @@ class SILPhiArgument : public SILArgument {
226274
const ValueDecl *decl = nullptr)
227275
: SILArgument(ValueKind::SILPhiArgument, parentBlock, type, ownershipKind,
228276
decl) {}
277+
278+
SILPhiArgument(SILBasicBlock *parentBlock, SILType type,
279+
ValueOwnershipKind ownershipKind, bool isReborrow,
280+
bool isEscaping, const ValueDecl *decl = nullptr)
281+
: SILArgument(ValueKind::SILPhiArgument, parentBlock, type, ownershipKind,
282+
isReborrow, isEscaping, decl) {}
283+
229284
// A special constructor, only intended for use in
230285
// SILBasicBlock::replacePHIArg.
231286
explicit SILPhiArgument(SILType type, ValueOwnershipKind ownershipKind,
232287
const ValueDecl *decl = nullptr)
233288
: SILArgument(ValueKind::SILPhiArgument, type, ownershipKind, decl) {}
234289

290+
explicit SILPhiArgument(SILType type, ValueOwnershipKind ownershipKind,
291+
bool isReborrow, bool isEscaping,
292+
const ValueDecl *decl = nullptr)
293+
: SILArgument(ValueKind::SILPhiArgument, type, ownershipKind, isReborrow,
294+
isEscaping, decl) {}
295+
235296
public:
236297
/// Return true if this is block argument is a phi, as opposed to a terminator
237298
/// result.

include/swift/SIL/SILBasicBlock.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,17 +352,30 @@ public SwiftObjectHeader {
352352
ValueOwnershipKind kind,
353353
const ValueDecl *decl = nullptr);
354354

355+
SILPhiArgument *replacePhiArgument(unsigned i, SILType type,
356+
ValueOwnershipKind kind, bool isReborrow,
357+
bool isEscaping,
358+
const ValueDecl *decl = nullptr);
359+
355360
/// Replace phi argument \p i and RAUW all uses.
356361
SILPhiArgument *
357362
replacePhiArgumentAndReplaceAllUses(unsigned i, SILType type,
358363
ValueOwnershipKind kind,
359364
const ValueDecl *decl = nullptr);
360365

366+
SILPhiArgument *replacePhiArgumentAndReplaceAllUses(
367+
unsigned i, SILType type, ValueOwnershipKind kind, bool isReborrow,
368+
bool isEscaping, const ValueDecl *decl = nullptr);
369+
361370
/// Allocate a new argument of type \p Ty and append it to the argument
362371
/// list. Optionally you can pass in a value decl parameter.
363372
SILPhiArgument *createPhiArgument(SILType Ty, ValueOwnershipKind Kind,
364373
const ValueDecl *D = nullptr);
365374

375+
SILPhiArgument *createPhiArgument(SILType Ty, ValueOwnershipKind Kind,
376+
bool isReborrow, bool isEscaping,
377+
const ValueDecl *D = nullptr);
378+
366379
/// Insert a new SILPhiArgument with type \p Ty and \p Decl at position \p
367380
/// AtArgPos.
368381
SILPhiArgument *insertPhiArgument(unsigned AtArgPos, SILType Ty,

include/swift/SIL/SILCloner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,8 @@ void SILCloner<ImplClass>::clonePhiArgs(SILBasicBlock *oldBB) {
734734
// Create new arguments for each of the original block's arguments.
735735
for (auto *Arg : oldBB->getSILPhiArguments()) {
736736
SILValue mappedArg = mappedBB->createPhiArgument(
737-
getOpType(Arg->getType()), Arg->getOwnershipKind());
737+
getOpType(Arg->getType()), Arg->getOwnershipKind(), Arg->isReborrow(),
738+
Arg->isEscaping());
738739

739740
asImpl().mapValue(Arg, mappedArg);
740741
}

include/swift/SIL/SILNode.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ class alignas(8) SILNode :
181181
SHARED_TEMPLATE_FIELD(typename, SwitchEnumInstBase, bool hasDefault);
182182
SHARED_TEMPLATE_FIELD(SILInstructionKind, LoadReferenceInstBase, bool isTake);
183183
SHARED_TEMPLATE_FIELD(SILInstructionKind, StoreReferenceInstBase, bool isInitializationOfDest);
184-
SHARED_FIELD(SILArgument, uint8_t valueOwnershipKind);
185184
SHARED_FIELD(MultipleValueInstructionResult, uint8_t valueOwnershipKind);
186185
SHARED_FIELD(UncheckedOwnershipConversionInst, uint8_t valueOwnershipKind);
187186
SHARED_FIELD(StoreInst, uint8_t ownershipQualifier);
@@ -203,6 +202,11 @@ class alignas(8) SILNode :
203202
SHARED_FIELD(ConvertFunctionInst, bool withoutActuallyEscaping);
204203
SHARED_FIELD(BeginCOWMutationInst, bool native);
205204

205+
SHARED_FIELD(SILArgument, uint8_t
206+
valueOwnershipKind : NumVOKindBits,
207+
reborrow : 1,
208+
escaping : 1);
209+
206210
SHARED_FIELD(DebugValueInst, uint8_t
207211
poisonRefs : 1,
208212
usesMoveableValueDebugInfo : 1,

include/swift/SIL/SILValue.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,8 @@ class ValueBase : public SILNode, public SILAllocated<ValueBase> {
570570

571571
bool isLexical() const;
572572

573+
bool isGuaranteedForwarding() const;
574+
573575
/// Unsafely eliminate moveonly from this value's type. Returns true if the
574576
/// value's underlying type was move only and thus was changed. Returns false
575577
/// otherwise.

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,11 +435,11 @@ OperandOwnershipClassifier::visitSelectEnumInst(SelectEnumInst *i) {
435435
}
436436

437437
OperandOwnership OperandOwnershipClassifier::visitBranchInst(BranchInst *bi) {
438-
ValueOwnershipKind destBlockArgOwnershipKind =
439-
bi->getDestBB()->getArgument(getOperandIndex())->getOwnershipKind();
438+
auto *destArg = bi->getDestBB()->getArgument(getOperandIndex());
439+
ValueOwnershipKind destBlockArgOwnershipKind = destArg->getOwnershipKind();
440440

441441
if (destBlockArgOwnershipKind == OwnershipKind::Guaranteed) {
442-
return isGuaranteedForwarding(getValue())
442+
return destArg->isGuaranteedForwarding()
443443
? OperandOwnership::GuaranteedForwarding
444444
: OperandOwnership::Reborrow;
445445
}

lib/SIL/IR/SILArgument.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ SILArgument::SILArgument(ValueKind subClassKind,
3131
: ValueBase(subClassKind, type),
3232
parentBlock(inputParentBlock), decl(inputDecl) {
3333
sharedUInt8().SILArgument.valueOwnershipKind = uint8_t(ownershipKind);
34+
// When the optimizer creates reborrows, reborrow flag needs to be set by
35+
// calling setReborrow.
36+
sharedUInt8().SILArgument.reborrow = false;
37+
sharedUInt8().SILArgument.escaping = false;
38+
inputParentBlock->insertArgument(inputParentBlock->args_end(), this);
39+
}
40+
41+
SILArgument::SILArgument(ValueKind subClassKind,
42+
SILBasicBlock *inputParentBlock, SILType type,
43+
ValueOwnershipKind ownershipKind, bool reborrow,
44+
bool escaping, const ValueDecl *inputDecl)
45+
: ValueBase(subClassKind, type), parentBlock(inputParentBlock),
46+
decl(inputDecl) {
47+
sharedUInt8().SILArgument.valueOwnershipKind = uint8_t(ownershipKind);
48+
sharedUInt8().SILArgument.reborrow = reborrow;
49+
sharedUInt8().SILArgument.escaping = escaping;
3450
inputParentBlock->insertArgument(inputParentBlock->args_end(), this);
3551
}
3652

lib/SIL/IR/SILBasicBlock.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,31 @@ SILPhiArgument *SILBasicBlock::replacePhiArgument(unsigned i, SILType Ty,
223223
return NewArg;
224224
}
225225

226+
SILPhiArgument *SILBasicBlock::replacePhiArgument(unsigned i, SILType Ty,
227+
ValueOwnershipKind Kind,
228+
bool isReborrow,
229+
bool isEscaping,
230+
const ValueDecl *D) {
231+
assert(!isEntry() && "PHI Arguments can not be in the entry block");
232+
SILFunction *F = getParent();
233+
SILModule &M = F->getModule();
234+
if (Ty.isTrivial(*F))
235+
Kind = OwnershipKind::None;
236+
237+
assert(ArgumentList[i]->use_empty() && "Expected no uses of the old BB arg!");
238+
239+
SILPhiArgument *NewArg =
240+
new (M) SILPhiArgument(Ty, Kind, isReborrow, isEscaping, D);
241+
NewArg->setParent(this);
242+
ArgumentList[i]->parentBlock = nullptr;
243+
244+
// TODO: When we switch to malloc/free allocation we'll be leaking memory
245+
// here.
246+
*(ArgumentList.begin() + i) = NewArg;
247+
248+
return NewArg;
249+
}
250+
226251
SILPhiArgument *SILBasicBlock::replacePhiArgumentAndReplaceAllUses(
227252
unsigned i, SILType ty, ValueOwnershipKind kind, const ValueDecl *d) {
228253
// Put in an undef placeholder before we do the replacement since
@@ -248,6 +273,32 @@ SILPhiArgument *SILBasicBlock::replacePhiArgumentAndReplaceAllUses(
248273
return newArg;
249274
}
250275

276+
SILPhiArgument *SILBasicBlock::replacePhiArgumentAndReplaceAllUses(
277+
unsigned i, SILType ty, ValueOwnershipKind kind, bool isReborrow,
278+
bool isEscaping, const ValueDecl *d) {
279+
// Put in an undef placeholder before we do the replacement since
280+
// replacePhiArgument() expects the replaced argument to not have
281+
// any uses.
282+
SmallVector<Operand *, 16> operands;
283+
SILValue undef = SILUndef::get(ty, *getParent());
284+
SILArgument *arg = getArgument(i);
285+
while (!arg->use_empty()) {
286+
Operand *use = *arg->use_begin();
287+
use->set(undef);
288+
operands.push_back(use);
289+
}
290+
291+
// Perform the replacement.
292+
auto *newArg = replacePhiArgument(i, ty, kind, isReborrow, isEscaping, d);
293+
294+
// Wire back up the uses.
295+
while (!operands.empty()) {
296+
operands.pop_back_val()->set(newArg);
297+
}
298+
299+
return newArg;
300+
}
301+
251302
SILPhiArgument *SILBasicBlock::createPhiArgument(SILType Ty,
252303
ValueOwnershipKind Kind,
253304
const ValueDecl *D) {
@@ -257,6 +308,18 @@ SILPhiArgument *SILBasicBlock::createPhiArgument(SILType Ty,
257308
return new (getModule()) SILPhiArgument(this, Ty, Kind, D);
258309
}
259310

311+
SILPhiArgument *SILBasicBlock::createPhiArgument(SILType Ty,
312+
ValueOwnershipKind Kind,
313+
bool isReborrow,
314+
bool isEscaping,
315+
const ValueDecl *D) {
316+
assert(!isEntry() && "PHI Arguments can not be in the entry block");
317+
if (Ty.isTrivial(*getParent()))
318+
Kind = OwnershipKind::None;
319+
return new (getModule())
320+
SILPhiArgument(this, Ty, Kind, isReborrow, isEscaping, D);
321+
}
322+
260323
SILPhiArgument *SILBasicBlock::insertPhiArgument(unsigned AtArgPos, SILType Ty,
261324
ValueOwnershipKind Kind,
262325
const ValueDecl *D) {

0 commit comments

Comments
 (0)