Skip to content

Commit 2089d99

Browse files
authored
Merge pull request #65871 from gottesmm/release-5.9-more-batched
[5.9][move-only] A series of batched commits.
2 parents 7899412 + 5023b93 commit 2089d99

24 files changed

+2170
-308
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,6 @@ PASS(AccessMarkerElimination, "access-marker-elim",
112112
"Access Marker Elimination.")
113113
PASS(AddressLowering, "address-lowering",
114114
"SIL Address Lowering")
115-
PASS(EarlyAllocBoxToStack, "early-allocbox-to-stack",
116-
"Stack Promotion of Box Objects. Doesn't attempt to promote noncopyable "
117-
"types captured by escaping closures")
118115
PASS(AllocBoxToStack, "allocbox-to-stack",
119116
"Stack Promotion of Box Objects")
120117
IRGEN_PASS(AllocStackHoisting, "alloc-stack-hoisting",

lib/SILGen/SILGenApply.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4261,7 +4261,19 @@ static void emitBorrowedLValueRecursive(SILGenFunction &SGF,
42614261
}
42624262
}
42634263

4264+
// TODO: This does not take into account resilience, we should probably use
4265+
// getArgumentType()... but we do not have the SILFunctionType here...
42644266
assert(param.getInterfaceType() == value.getType().getASTType());
4267+
4268+
// If we have an indirect_guaranteed argument, move this using store_borrow
4269+
// into an alloc_stack.
4270+
if (SGF.silConv.useLoweredAddresses() &&
4271+
param.isIndirectInGuaranteed() && value.getType().isObject()) {
4272+
SILValue alloca = SGF.emitTemporaryAllocation(loc, value.getType());
4273+
value = SGF.emitFormalEvaluationManagedStoreBorrow(loc, value.getValue(),
4274+
alloca);
4275+
}
4276+
42654277
args[argIndex++] = value;
42664278
}
42674279

lib/SILGen/SILGenBuilder.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,9 +778,19 @@ ManagedValue SILGenBuilder::createStoreBorrow(SILLocation loc,
778778
SILValue address) {
779779
assert(value.getOwnershipKind() == OwnershipKind::Guaranteed);
780780
auto *sbi = createStoreBorrow(loc, value.getValue(), address);
781+
SGF.Cleanups.pushCleanup<EndBorrowCleanup>(sbi);
781782
return ManagedValue(sbi, CleanupHandle::invalid());
782783
}
783784

785+
ManagedValue SILGenBuilder::createFormalAccessStoreBorrow(SILLocation loc,
786+
ManagedValue value,
787+
SILValue address) {
788+
assert(value.getOwnershipKind() == OwnershipKind::Guaranteed);
789+
auto *sbi = createStoreBorrow(loc, value.getValue(), address);
790+
return SGF.emitFormalEvaluationManagedBorrowedRValueWithCleanup(
791+
loc, value.getValue(), sbi);
792+
}
793+
784794
ManagedValue SILGenBuilder::createStoreBorrowOrTrivial(SILLocation loc,
785795
ManagedValue value,
786796
SILValue address) {

lib/SILGen/SILGenBuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ class SILGenBuilder : public SILBuilder {
202202
using SILBuilder::createStoreBorrow;
203203
ManagedValue createStoreBorrow(SILLocation loc, ManagedValue value,
204204
SILValue address);
205+
ManagedValue createFormalAccessStoreBorrow(SILLocation loc, ManagedValue value,
206+
SILValue address);
205207

206208
/// Create a store_borrow if we have a non-trivial value and a store [trivial]
207209
/// otherwise.

lib/SILGen/SILGenProlog.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
3939
}
4040

4141
SILValue SILGenFunction::emitSelfDeclForDestructor(VarDecl *selfDecl) {
42+
SILFunctionConventions conventions = F.getConventionsInContext();
43+
4244
// Emit the implicit 'self' argument.
43-
SILType selfType = getLoweredType(selfDecl->getType());
45+
SILType selfType = conventions.getSILArgumentType(
46+
conventions.getNumSILArguments() - 1, F.getTypeExpansionContext());
47+
selfType = F.mapTypeIntoContext(selfType);
4448
SILValue selfValue = F.begin()->createFunctionArgument(selfType, selfDecl);
4549

4650
// If we have a move only type, then mark it with mark_must_check so we can't

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerTester.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,20 +105,18 @@ class MoveOnlyAddressCheckerTesterPass : public SILFunctionTransform {
105105
<< '\n');
106106

107107
bool madeChange = false;
108-
unsigned diagCount = 0;
109108
if (moveIntroducersToProcess.empty()) {
110109
LLVM_DEBUG(llvm::dbgs() << "No move introducers found?!\n");
111110
} else {
112111
borrowtodestructure::IntervalMapAllocator allocator;
113112
MoveOnlyAddressChecker checker{getFunction(), diagnosticEmitter,
114113
allocator, domTree, poa};
115114
madeChange = checker.check(moveIntroducersToProcess);
116-
diagCount = checker.diagnosticEmitter.getDiagnosticCount();
117115
}
118116

119117
// If we did not emit any diagnostics, emit a diagnostic if we missed any
120118
// copies.
121-
if (!diagCount) {
119+
if (!diagnosticEmitter.emittedDiagnostic()) {
122120
emitCheckerMissedCopyOfNonCopyableTypeErrors(getFunction(),
123121
diagnosticEmitter);
124122
}

lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp

Lines changed: 137 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@
225225
#include "swift/AST/AccessScope.h"
226226
#include "swift/AST/DiagnosticEngine.h"
227227
#include "swift/AST/DiagnosticsSIL.h"
228+
#include "swift/AST/SemanticAttrs.h"
228229
#include "swift/Basic/Debug.h"
229230
#include "swift/Basic/Defer.h"
230231
#include "swift/Basic/FrozenMultiMap.h"
@@ -433,7 +434,7 @@ static bool memInstMustConsume(Operand *memOper) {
433434
return false;
434435
ApplySite applySite(pai);
435436
auto convention = applySite.getArgumentConvention(*memOper);
436-
return convention.isInoutConvention();
437+
return !convention.isInoutConvention();
437438
}
438439
case SILInstructionKind::DestroyAddrInst:
439440
return true;
@@ -492,6 +493,92 @@ static bool isInOutDefThatNeedsEndOfFunctionLiveness(MarkMustCheckInst *markedAd
492493
return false;
493494
}
494495

496+
//===----------------------------------------------------------------------===//
497+
// MARK: Partial Apply Utilities
498+
//===----------------------------------------------------------------------===//
499+
500+
static bool findNonEscapingPartialApplyUses(
501+
PartialApplyInst *pai, TypeTreeLeafTypeRange leafRange,
502+
llvm::SmallMapVector<SILInstruction *, TypeTreeLeafTypeRange, 4>
503+
&livenessUses) {
504+
StackList<Operand *> worklist(pai->getFunction());
505+
for (auto *use : pai->getUses())
506+
worklist.push_back(use);
507+
508+
LLVM_DEBUG(llvm::dbgs() << "Searching for partial apply uses!\n");
509+
while (!worklist.empty()) {
510+
auto *use = worklist.pop_back_val();
511+
512+
if (use->isTypeDependent())
513+
continue;
514+
515+
auto *user = use->getUser();
516+
517+
// These instructions do not cause us to escape.
518+
if (isIncidentalUse(user) || isa<DestroyValueInst>(user))
519+
continue;
520+
521+
// Look through these instructions.
522+
if (isa<BeginBorrowInst>(user) || isa<CopyValueInst>(user) ||
523+
isa<MoveValueInst>(user) ||
524+
// If we capture this partial_apply in another partial_apply, then we
525+
// know that said partial_apply must not have escaped the value since
526+
// otherwise we could not have an inout_aliasable argument or be
527+
// on_stack. Process it recursively so that we treat uses of that
528+
// partial_apply and applies of that partial_apply as uses of our
529+
// partial_apply.
530+
//
531+
// We have this separately from the other look through sections so that
532+
// we can make it clearer what we are doing here.
533+
isa<PartialApplyInst>(user)) {
534+
for (auto *use : cast<SingleValueInstruction>(user)->getUses())
535+
worklist.push_back(use);
536+
continue;
537+
}
538+
539+
// If we have a mark_dependence and are the value, look through the
540+
// mark_dependence.
541+
if (auto *mdi = dyn_cast<MarkDependenceInst>(user)) {
542+
if (mdi->getValue() == use->get()) {
543+
for (auto *use : mdi->getUses())
544+
worklist.push_back(use);
545+
continue;
546+
}
547+
}
548+
549+
if (auto apply = FullApplySite::isa(user)) {
550+
// If we apply the function or pass the function off to an apply, then we
551+
// need to treat the function application as a liveness use of the
552+
// variable since if the partial_apply is invoked within the function
553+
// application, we may access the captured variable.
554+
livenessUses.insert({user, leafRange});
555+
if (apply.beginsCoroutineEvaluation()) {
556+
// If we have a coroutine, we need to treat the abort_apply and
557+
// end_apply as liveness uses since once we execute one of those
558+
// instructions, we have returned control to the coroutine which means
559+
// that we could then access the captured variable again.
560+
auto *bai = cast<BeginApplyInst>(user);
561+
SmallVector<EndApplyInst *, 4> endApplies;
562+
SmallVector<AbortApplyInst *, 4> abortApplies;
563+
bai->getCoroutineEndPoints(endApplies, abortApplies);
564+
for (auto *eai : endApplies)
565+
livenessUses.insert({eai, leafRange});
566+
for (auto *aai : abortApplies)
567+
livenessUses.insert({aai, leafRange});
568+
}
569+
continue;
570+
}
571+
572+
LLVM_DEBUG(
573+
llvm::dbgs()
574+
<< "Found instruction we did not understand... returning false!\n");
575+
LLVM_DEBUG(llvm::dbgs() << "Instruction: " << *user);
576+
return false;
577+
}
578+
579+
return true;
580+
}
581+
495582
//===----------------------------------------------------------------------===//
496583
// MARK: Find Candidate Mark Must Checks
497584
//===----------------------------------------------------------------------===//
@@ -1354,7 +1441,6 @@ struct GatherUsesVisitor final : public TransitiveAddressWalker {
13541441
MoveOnlyAddressCheckerPImpl &moveChecker;
13551442
UseState &useState;
13561443
MarkMustCheckInst *markedValue;
1357-
bool emittedEarlyDiagnostic = false;
13581444
DiagnosticEmitter &diagnosticEmitter;
13591445

13601446
// Pruned liveness used to validate that load [take]/load [copy] can be
@@ -1529,14 +1615,13 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
15291615
if (isa<ProjectBoxInst>(stripAccessMarkers(markedValue->getOperand()))) {
15301616
LLVM_DEBUG(llvm::dbgs()
15311617
<< "Found mark must check [nocopy] use of escaping box: " << *user);
1532-
diagnosticEmitter.emitAddressEscapingClosureCaptureLoadedAndConsumed(markedValue);
1533-
emittedEarlyDiagnostic = true;
1618+
diagnosticEmitter.emitAddressEscapingClosureCaptureLoadedAndConsumed(
1619+
markedValue);
15341620
return true;
15351621
}
15361622
LLVM_DEBUG(llvm::dbgs()
15371623
<< "Found mark must check [nocopy] error: " << *user);
15381624
diagnosticEmitter.emitAddressDiagnosticNoCopy(markedValue, copyAddr);
1539-
emittedEarlyDiagnostic = true;
15401625
return true;
15411626
}
15421627

@@ -1592,15 +1677,13 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
15921677
.didEmitCheckerDoesntUnderstandDiagnostic());
15931678
LLVM_DEBUG(llvm::dbgs()
15941679
<< "Failed to perform borrow to destructure transform!\n");
1595-
emittedEarlyDiagnostic = true;
15961680
return false;
15971681
}
15981682

15991683
// If we emitted an error diagnostic, do not transform further and instead
16001684
// mark that we emitted an early diagnostic and return true.
16011685
if (numDiagnostics != moveChecker.diagnosticEmitter.getDiagnosticCount()) {
16021686
LLVM_DEBUG(llvm::dbgs() << "Emitting borrow to destructure error!\n");
1603-
emittedEarlyDiagnostic = true;
16041687
return true;
16051688
}
16061689

@@ -1621,7 +1704,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
16211704
if (numDiagnostics != moveChecker.diagnosticEmitter.getDiagnosticCount()) {
16221705
LLVM_DEBUG(llvm::dbgs()
16231706
<< "Emitting destructure through deinit error!\n");
1624-
emittedEarlyDiagnostic = true;
16251707
return true;
16261708
}
16271709

@@ -1639,14 +1721,18 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
16391721
<< "Found mark must check [nocopy] error: " << *user);
16401722
auto *fArg = dyn_cast<SILFunctionArgument>(
16411723
stripAccessMarkers(markedValue->getOperand()));
1642-
if (fArg && fArg->isClosureCapture() && fArg->getType().isAddress()) {
1643-
moveChecker.diagnosticEmitter.emitPromotedBoxArgumentError(
1644-
markedValue, fArg);
1724+
// If we have a closure captured that we specialized, we should have a
1725+
// no consume or assign and should emit a normal guaranteed diagnostic.
1726+
if (fArg && fArg->isClosureCapture() &&
1727+
fArg->getArgumentConvention().isInoutConvention()) {
1728+
assert(checkKind == MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
1729+
moveChecker.diagnosticEmitter.emitObjectGuaranteedDiagnostic(
1730+
markedValue);
16451731
} else {
1732+
// Otherwise, we need to emit an escaping closure error.
16461733
moveChecker.diagnosticEmitter
16471734
.emitAddressEscapingClosureCaptureLoadedAndConsumed(markedValue);
16481735
}
1649-
emittedEarlyDiagnostic = true;
16501736
return true;
16511737
}
16521738

@@ -1660,7 +1746,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
16601746

16611747
if (checkForExclusivityHazards(li)) {
16621748
LLVM_DEBUG(llvm::dbgs() << "Found exclusivity violation?!\n");
1663-
emittedEarlyDiagnostic = true;
16641749
return true;
16651750
}
16661751

@@ -1693,7 +1778,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
16931778
// succeeded.
16941779
// Otherwise, emit the diagnostic.
16951780
moveChecker.diagnosticEmitter.emitObjectOwnedDiagnostic(markedValue);
1696-
emittedEarlyDiagnostic = true;
16971781
LLVM_DEBUG(llvm::dbgs() << "Emitted early object level diagnostic.\n");
16981782
return true;
16991783
}
@@ -1702,7 +1786,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
17021786
LLVM_DEBUG(llvm::dbgs() << "Found potential borrow inst: " << *user);
17031787
if (checkForExclusivityHazards(li)) {
17041788
LLVM_DEBUG(llvm::dbgs() << "Found exclusivity violation?!\n");
1705-
emittedEarlyDiagnostic = true;
17061789
return true;
17071790
}
17081791

@@ -1751,7 +1834,6 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
17511834
moveChecker.diagnosticEmitter
17521835
.emitAddressEscapingClosureCaptureLoadedAndConsumed(markedValue);
17531836
}
1754-
emittedEarlyDiagnostic = true;
17551837
return true;
17561838
}
17571839

@@ -1802,8 +1884,22 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
18021884
}
18031885

18041886
if (auto *pas = dyn_cast<PartialApplyInst>(user)) {
1805-
if (pas->isOnStack()) {
1806-
LLVM_DEBUG(llvm::dbgs() << "Found on stack partial apply!\n");
1887+
if (auto *fArg = dyn_cast<SILFunctionArgument>(
1888+
stripAccessMarkers(markedValue->getOperand()))) {
1889+
// If we are processing an inout convention and we emitted an error on the
1890+
// partial_apply, we shouldn't process this mark_must_check, but squelch
1891+
// the compiler doesn't understand error.
1892+
if (fArg->getArgumentConvention().isInoutConvention() &&
1893+
pas->getCalleeFunction()->hasSemanticsAttr(
1894+
semantics::NO_MOVEONLY_DIAGNOSTICS)) {
1895+
diagnosticEmitter.emitEarlierPassEmittedDiagnostic(markedValue);
1896+
return false;
1897+
}
1898+
}
1899+
1900+
if (pas->isOnStack() ||
1901+
ApplySite(pas).getArgumentConvention(*op).isInoutConvention()) {
1902+
LLVM_DEBUG(llvm::dbgs() << "Found on stack partial apply or inout usage!\n");
18071903
// On-stack partial applications and their final consumes are always a
18081904
// liveness use of their captures.
18091905
auto leafRange = TypeTreeLeafTypeRange::get(op->get(), getRootAddress());
@@ -1812,13 +1908,18 @@ bool GatherUsesVisitor::visitUse(Operand *op) {
18121908
return false;
18131909
}
18141910

1815-
useState.livenessUses.insert({user, *leafRange});
1816-
for (auto *use : pas->getConsumingUses()) {
1817-
LLVM_DEBUG(llvm::dbgs()
1818-
<< "Adding consuming use of partial apply as liveness use: "
1819-
<< *use->getUser());
1820-
useState.livenessUses.insert({use->getUser(), *leafRange});
1911+
// Attempt to find calls of the non-escaping partial apply and places
1912+
// where the partial apply is passed to a function. We treat those as
1913+
// liveness uses. If we find a use we don't understand, we return false
1914+
// here.
1915+
if (!findNonEscapingPartialApplyUses(pas, *leafRange,
1916+
useState.livenessUses)) {
1917+
LLVM_DEBUG(
1918+
llvm::dbgs()
1919+
<< "Failed to understand use of a non-escaping partial apply?!\n");
1920+
return false;
18211921
}
1922+
18221923
return true;
18231924
}
18241925
}
@@ -2543,9 +2644,19 @@ bool MoveOnlyAddressChecker::check(
25432644
LLVM_DEBUG(llvm::dbgs() << "Visiting: " << *markedValue);
25442645

25452646
// Perform our address check.
2647+
unsigned diagnosticEmittedByEarlierPassCount =
2648+
diagnosticEmitter.getDiagnosticEmittedByEarlierPassCount();
25462649
if (!pimpl.performSingleCheck(markedValue)) {
2547-
LLVM_DEBUG(llvm::dbgs()
2548-
<< "Failed to perform single check! Emitting error!\n");
2650+
if (diagnosticEmittedByEarlierPassCount !=
2651+
diagnosticEmitter.getDiagnosticEmittedByEarlierPassCount()) {
2652+
LLVM_DEBUG(
2653+
llvm::dbgs()
2654+
<< "Failed to perform single check but found earlier emitted "
2655+
"error. Not emitting checker doesn't understand diagnostic!\n");
2656+
continue;
2657+
}
2658+
LLVM_DEBUG(llvm::dbgs() << "Failed to perform single check! Emitting "
2659+
"compiler doesn't understand diagnostic!\n");
25492660
// If we fail the address check in some way, set the diagnose!
25502661
diagnosticEmitter.emitCheckerDoesntUnderstandDiagnostic(markedValue);
25512662
}

lib/SILOptimizer/Mandatory/MoveOnlyChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ class MoveOnlyCheckerPass : public SILFunctionTransform {
179179
// remain. If we emitted a diagnostic, we just want to rewrite all of the
180180
// non-copyable copies into explicit variants below and let the user
181181
// recompile.
182-
if (!checker.diagnosticEmitter.getDiagnosticCount()) {
182+
if (!checker.diagnosticEmitter.emittedDiagnostic()) {
183183
emitCheckerMissedCopyOfNonCopyableTypeErrors(getFunction(),
184184
checker.diagnosticEmitter);
185185
}

0 commit comments

Comments
 (0)