Skip to content

Commit 0b07d4b

Browse files
authored
Merge pull request #741 from swiftwasm/master
[pull] swiftwasm from master
2 parents 05604a7 + f7dd406 commit 0b07d4b

File tree

6 files changed

+129
-43
lines changed

6 files changed

+129
-43
lines changed

Diff for: lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

+12-6
Original file line numberDiff line numberDiff line change
@@ -781,10 +781,13 @@ SILInstruction *SILCombiner::visitReleaseValueInst(ReleaseValueInst *RVI) {
781781
}
782782
}
783783

784-
// ReleaseValueInst of an unowned type is an unowned_release.
785-
if (OperandTy.is<UnownedStorageType>())
786-
return Builder.createUnownedRelease(RVI->getLoc(), Operand,
784+
// ReleaseValueInst of a loadable reference storage type needs the
785+
// corresponding release instruction.
786+
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
787+
if (OperandTy.is<Name##StorageType>()) \
788+
return Builder.create##Name##Release(RVI->getLoc(), Operand, \
787789
RVI->getAtomicity());
790+
#include "swift/AST/ReferenceStorage.def"
788791

789792
// ReleaseValueInst of a reference type is a strong_release.
790793
if (OperandTy.isReferenceCounted(RVI->getModule()))
@@ -821,10 +824,13 @@ SILInstruction *SILCombiner::visitRetainValueInst(RetainValueInst *RVI) {
821824
}
822825
}
823826

824-
// RetainValueInst of an unowned type is an unowned_retain.
825-
if (OperandTy.is<UnownedStorageType>())
826-
return Builder.createUnownedRetain(RVI->getLoc(), Operand,
827+
// RetainValueInst of a loadable reference storage type needs the
828+
// corresponding retain instruction.
829+
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
830+
if (OperandTy.is<Name##StorageType>()) \
831+
return Builder.create##Name##Retain(RVI->getLoc(), Operand, \
827832
RVI->getAtomicity());
833+
#include "swift/AST/ReferenceStorage.def"
828834

829835
// RetainValueInst of a reference type is a strong_release.
830836
if (OperandTy.isReferenceCounted(RVI->getModule())) {

Diff for: lib/SILOptimizer/Transforms/SemanticARCOpts.cpp

+66-25
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,36 @@ class LiveRange {
5252
/// introducer and not to be forwarding.
5353
OwnedValueIntroducer introducer;
5454

55+
/// A vector that we store all of our uses into.
56+
///
57+
/// Some properties of this array are:
58+
///
59+
/// 1. It is only mutated in the constructor of LiveRange.
60+
///
61+
/// 2. destroyingUses, ownershipForwardingUses, and unknownConsumingUses are
62+
/// views into this array. We store the respective uses in the aforementioned
63+
/// order. This is why it is important not to mutate consumingUses after we
64+
/// construct the LiveRange since going from small -> large could invalidate
65+
/// the uses.
66+
SmallVector<Operand *, 6> consumingUses;
67+
5568
/// A list of destroy_values of the live range.
56-
SmallVector<Operand *, 2> destroyingUses;
69+
///
70+
/// This is just a view into consuming uses.
71+
ArrayRef<Operand *> destroyingUses;
5772

5873
/// A list of forwarding instructions that forward owned ownership, but that
5974
/// are also able to be converted to guaranteed ownership. If we are able to
6075
/// eliminate this LiveRange due to it being from a guaranteed value, we must
6176
/// flip the ownership of all of these instructions to guaranteed from owned.
6277
///
6378
/// Corresponds to isOwnershipForwardingInst(...).
64-
SmallVector<Operand *, 2> ownershipForwardingUses;
79+
ArrayRef<Operand *> ownershipForwardingUses;
6580

6681
/// Consuming uses that we were not able to understand as a forwarding
6782
/// instruction or a destroy_value. These must be passed a strongly control
6883
/// equivalent +1 value.
69-
SmallVector<Operand *, 2> unknownConsumingUses;
84+
ArrayRef<Operand *> unknownConsumingUses;
7085

7186
public:
7287
LiveRange(SILValue value);
@@ -87,6 +102,11 @@ class LiveRange {
87102
HasConsumingUse_t
88103
hasUnknownConsumingUse(bool assumingFixedPoint = false) const;
89104

105+
/// Return an array ref to /all/ consuming uses. Will include all 3 sorts of
106+
/// consuming uses: destroying uses, forwarding consuming uses, and unknown
107+
/// forwarding instruction.
108+
ArrayRef<Operand *> getAllConsumingUses() const { return consumingUses; }
109+
90110
ArrayRef<Operand *> getDestroyingUses() const { return destroyingUses; }
91111

92112
private:
@@ -121,7 +141,7 @@ class LiveRange {
121141
return ownershipForwardingUses;
122142
}
123143

124-
void convertOwnedGeneralForwardingUsesToGuaranteed();
144+
void convertOwnedGeneralForwardingUsesToGuaranteed() &&;
125145

126146
/// A consuming operation that:
127147
///
@@ -192,6 +212,10 @@ LiveRange::LiveRange(SILValue value)
192212
ownershipForwardingUses(), unknownConsumingUses() {
193213
assert(introducer.value.getOwnershipKind() == ValueOwnershipKind::Owned);
194214

215+
SmallVector<Operand *, 32> tmpDestroyingUses;
216+
SmallVector<Operand *, 32> tmpForwardingConsumingUses;
217+
SmallVector<Operand *, 32> tmpUnknownConsumingUses;
218+
195219
// We know that our silvalue produces an @owned value. Look through all of our
196220
// uses and classify them as either consuming or not.
197221
SmallVector<Operand *, 32> worklist(introducer.value->getUses());
@@ -220,7 +244,7 @@ LiveRange::LiveRange(SILValue value)
220244
// Ok, we know now that we have a consuming use. See if we have a destroy
221245
// value, quickly up front. If we do have one, stash it and continue.
222246
if (isa<DestroyValueInst>(user)) {
223-
destroyingUses.push_back(op);
247+
tmpDestroyingUses.push_back(op);
224248
continue;
225249
}
226250

@@ -244,13 +268,13 @@ LiveRange::LiveRange(SILValue value)
244268
return v.getOwnershipKind() ==
245269
ValueOwnershipKind::Owned;
246270
})) {
247-
unknownConsumingUses.push_back(op);
271+
tmpUnknownConsumingUses.push_back(op);
248272
continue;
249273
}
250274

251275
// Ok, this is a forwarding instruction whose ownership we can flip from
252276
// owned -> guaranteed.
253-
ownershipForwardingUses.push_back(op);
277+
tmpForwardingConsumingUses.push_back(op);
254278

255279
// If we have a non-terminator, just visit its users recursively to see if
256280
// the the users force the live range to be alive.
@@ -284,6 +308,20 @@ LiveRange::LiveRange(SILValue value)
284308
}
285309
}
286310
}
311+
312+
// The order in which we append these to consumingUses matters since we assume
313+
// their order as an invariant. This is done to ensure that we can pass off
314+
// all of our uses or individual sub-arrays of our users without needing to
315+
// move around memory.
316+
llvm::copy(tmpDestroyingUses, std::back_inserter(consumingUses));
317+
llvm::copy(tmpForwardingConsumingUses, std::back_inserter(consumingUses));
318+
llvm::copy(tmpUnknownConsumingUses, std::back_inserter(consumingUses));
319+
320+
auto cUseArrayRef = llvm::makeArrayRef(consumingUses);
321+
destroyingUses = cUseArrayRef.take_front(tmpDestroyingUses.size());
322+
ownershipForwardingUses = cUseArrayRef.slice(
323+
tmpDestroyingUses.size(), tmpForwardingConsumingUses.size());
324+
unknownConsumingUses = cUseArrayRef.take_back(tmpUnknownConsumingUses.size());
287325
}
288326

289327
void LiveRange::insertEndBorrowsAtDestroys(
@@ -339,9 +377,10 @@ void LiveRange::insertEndBorrowsAtDestroys(
339377
}
340378
}
341379

342-
void LiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() {
380+
void LiveRange::convertOwnedGeneralForwardingUsesToGuaranteed() && {
343381
while (!ownershipForwardingUses.empty()) {
344-
auto *i = ownershipForwardingUses.pop_back_val()->getUser();
382+
auto *i = ownershipForwardingUses.back()->getUser();
383+
ownershipForwardingUses = ownershipForwardingUses.drop_back();
345384

346385
// If this is a term inst, just convert all of its incoming values that are
347386
// owned to be guaranteed.
@@ -402,7 +441,8 @@ void LiveRange::convertToGuaranteedAndRAUW(SILValue newGuaranteedValue,
402441
InstModCallbacks callbacks) && {
403442
auto *value = cast<SingleValueInstruction>(introducer.value);
404443
while (!destroyingUses.empty()) {
405-
auto *d = destroyingUses.pop_back_val();
444+
auto *d = destroyingUses.back();
445+
destroyingUses = destroyingUses.drop_back();
406446
callbacks.deleteInst(d->getUser());
407447
++NumEliminatedInsts;
408448
}
@@ -412,7 +452,7 @@ void LiveRange::convertToGuaranteedAndRAUW(SILValue newGuaranteedValue,
412452
// Then change all of our guaranteed forwarding insts to have guaranteed
413453
// ownership kind instead of what ever they previously had (ignoring trivial
414454
// results);
415-
convertOwnedGeneralForwardingUsesToGuaranteed();
455+
std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed();
416456
}
417457

418458
void LiveRange::convertArgToGuaranteed(DeadEndBlocks &deadEndBlocks,
@@ -429,15 +469,16 @@ void LiveRange::convertArgToGuaranteed(DeadEndBlocks &deadEndBlocks,
429469

430470
// Then eliminate all of the destroys...
431471
while (!destroyingUses.empty()) {
432-
auto *d = destroyingUses.pop_back_val();
472+
auto *d = destroyingUses.back();
473+
destroyingUses = destroyingUses.drop_back();
433474
callbacks.deleteInst(d->getUser());
434475
++NumEliminatedInsts;
435476
}
436477

437478
// and change all of our guaranteed forwarding insts to have guaranteed
438479
// ownership kind instead of what ever they previously had (ignoring trivial
439480
// results);
440-
convertOwnedGeneralForwardingUsesToGuaranteed();
481+
std::move(*this).convertOwnedGeneralForwardingUsesToGuaranteed();
441482
}
442483

443484
LiveRange::HasConsumingUse_t
@@ -1297,8 +1338,9 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
12971338
SmallVector<Operand *, 8> scratchSpace;
12981339
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
12991340
if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) {
1300-
return !borrowScope.areUsesWithinScope(
1301-
destroys, scratchSpace, visitedBlocks, getDeadEndBlocks());
1341+
return !borrowScope.areUsesWithinScope(lr.getAllConsumingUses(),
1342+
scratchSpace, visitedBlocks,
1343+
getDeadEndBlocks());
13021344
})) {
13031345
return false;
13041346
}
@@ -1330,12 +1372,11 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
13301372
return false;
13311373
}
13321374

1333-
if (llvm::any_of(borrowScopeIntroducers,
1334-
[&](BorrowedValue borrowScope) {
1335-
return !borrowScope.areUsesWithinScope(
1336-
phiArgLR.getDestroyingUses(), scratchSpace,
1337-
visitedBlocks, getDeadEndBlocks());
1338-
})) {
1375+
if (llvm::any_of(borrowScopeIntroducers, [&](BorrowedValue borrowScope) {
1376+
return !borrowScope.areUsesWithinScope(
1377+
phiArgLR.getAllConsumingUses(), scratchSpace, visitedBlocks,
1378+
getDeadEndBlocks());
1379+
})) {
13391380
return false;
13401381
}
13411382
}
@@ -1641,7 +1682,7 @@ class StorageGuaranteesLoadVisitor
16411682
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
16421683
LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks());
16431684
if (!checker.validateLifetime(access, endScopeUses,
1644-
liveRange.getDestroyingUses())) {
1685+
liveRange.getAllConsumingUses())) {
16451686
// If we fail the linear lifetime check, then just recur:
16461687
return next(access->getOperand());
16471688
}
@@ -1738,8 +1779,8 @@ class StorageGuaranteesLoadVisitor
17381779
LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks());
17391780

17401781
// Returns true on success. So we invert.
1741-
bool foundError = !checker.validateLifetime(baseObject, endScopeInsts,
1742-
liveRange.getDestroyingUses());
1782+
bool foundError = !checker.validateLifetime(
1783+
baseObject, endScopeInsts, liveRange.getAllConsumingUses());
17431784
return answer(foundError);
17441785
}
17451786

@@ -1777,7 +1818,7 @@ class StorageGuaranteesLoadVisitor
17771818
// Returns true on success. So we invert.
17781819
bool foundError = !checker.validateLifetime(
17791820
stack, destroyAddrOperands /*consuming users*/,
1780-
liveRange.getDestroyingUses() /*non consuming users*/);
1821+
liveRange.getAllConsumingUses() /*non consuming users*/);
17811822
return answer(foundError);
17821823
}
17831824

Diff for: lib/SILOptimizer/Utils/InstOptUtils.cpp

+15-11
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ swift::createIncrementBefore(SILValue ptr, SILInstruction *insertPt) {
5858
// If Ptr is refcounted itself, create the strong_retain and
5959
// return.
6060
if (ptr->getType().isReferenceCounted(builder.getModule())) {
61-
if (ptr->getType().is<UnownedStorageType>())
62-
return builder.createUnownedRetain(loc, ptr,
63-
builder.getDefaultAtomicity());
64-
else
65-
return builder.createStrongRetain(loc, ptr,
66-
builder.getDefaultAtomicity());
61+
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
62+
if (ptr->getType().is<Name##StorageType>()) \
63+
return builder.create##Name##Retain(loc, ptr, \
64+
builder.getDefaultAtomicity());
65+
#include "swift/AST/ReferenceStorage.def"
66+
67+
return builder.createStrongRetain(loc, ptr,
68+
builder.getDefaultAtomicity());
6769
}
6870

6971
// Otherwise, create the retain_value.
@@ -85,12 +87,14 @@ swift::createDecrementBefore(SILValue ptr, SILInstruction *insertPt) {
8587

8688
// If ptr has reference semantics itself, create a strong_release.
8789
if (ptr->getType().isReferenceCounted(builder.getModule())) {
88-
if (ptr->getType().is<UnownedStorageType>())
89-
return builder.createUnownedRelease(loc, ptr,
90+
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
91+
if (ptr->getType().is<Name##StorageType>()) \
92+
return builder.create##Name##Release(loc, ptr, \
9093
builder.getDefaultAtomicity());
91-
else
92-
return builder.createStrongRelease(loc, ptr,
93-
builder.getDefaultAtomicity());
94+
#include "swift/AST/ReferenceStorage.def"
95+
96+
return builder.createStrongRelease(loc, ptr,
97+
builder.getDefaultAtomicity());
9498
}
9599

96100
// Otherwise create a release value.

Diff for: test/SILOptimizer/semantic-arc-opts.sil

+29
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class ClassLet {
5959
@_hasStorage let aLet: Klass
6060
@_hasStorage var aVar: Klass
6161
@_hasStorage let aLetTuple: (Klass, Klass)
62+
@_hasStorage let anOptionalLet: FakeOptional<Klass>
6263

6364
@_hasStorage let anotherLet: ClassLet
6465
}
@@ -2204,3 +2205,31 @@ bb6:
22042205
%9999 = tuple()
22052206
return %9999 : $()
22062207
}
2208+
2209+
// Make sure that we do not promote the load [copy] to a load_borrow since it
2210+
// has a use outside of the access scope.
2211+
//
2212+
// CHECK-LABEL: sil [ossa] @deadEndBlockDoNotPromote : $@convention(method) (@guaranteed ClassLet) -> () {
2213+
// CHECK: load_borrow
2214+
// CHECK: load [copy]
2215+
// CHECK: } // end sil function 'deadEndBlockDoNotPromote'
2216+
sil [ossa] @deadEndBlockDoNotPromote : $@convention(method) (@guaranteed ClassLet) -> () {
2217+
bb0(%0 : @guaranteed $ClassLet):
2218+
%4 = ref_element_addr %0 : $ClassLet, #ClassLet.anotherLet
2219+
%5 = load [copy] %4 : $*ClassLet
2220+
%6 = begin_borrow %5 : $ClassLet
2221+
%7 = ref_element_addr %6 : $ClassLet, #ClassLet.anOptionalLet
2222+
%8 = begin_access [read] [dynamic] %7 : $*FakeOptional<Klass>
2223+
%9 = load [copy] %8 : $*FakeOptional<Klass>
2224+
end_access %8 : $*FakeOptional<Klass>
2225+
end_borrow %6 : $ClassLet
2226+
destroy_value %5 : $ClassLet
2227+
switch_enum %9 : $FakeOptional<Klass>, case #FakeOptional.none!enumelt: bb1, case #FakeOptional.some!enumelt: bb2
2228+
2229+
bb1:
2230+
%107 = tuple ()
2231+
return %107 : $()
2232+
2233+
bb2(%39 : @owned $Klass):
2234+
unreachable
2235+
}

Diff for: test/api-digester/compare-dump-abi.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// RUN: %empty-directory(%t.baseline)
66
// RUN: %empty-directory(%t.baseline/ABI)
77

8+
// REQUIRES: rdar62111064
9+
810
// RUN: %swift -emit-module -o %t.mod1/cake.swiftmodule %S/Inputs/cake_baseline/cake.swift -parse-as-library -enable-library-evolution -I %S/Inputs/APINotesLeft %clang-importer-sdk-nosource -emit-module-source-info -emit-module-source-info-path %t.mod1/cake.swiftsourceinfo 2> %t.compiler-diags
911
// RUN: %swift -emit-module -o %t.mod2/cake.swiftmodule %S/Inputs/cake_current/cake.swift -parse-as-library -enable-library-evolution -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource -emit-module-source-info -emit-module-source-info-path %t.mod2/cake.swiftsourceinfo
1012
// RUN: %api-digester -dump-sdk -module cake -output-dir %t.baseline -module-cache-path %t.module-cache %clang-importer-sdk-nosource -I %t.mod1 -I %S/Inputs/APINotesLeft -abi
@@ -21,4 +23,4 @@
2123
// CHECK: cake_current/cake.swift:33:14: error: cake: Class C5 is now without @objc
2224
// CHECK: cake_current/cake.swift:35:23: error: cake: Func C5.dy_foo() is now with dynamic
2325
// CHECK: cake_current/cake.swift:39:15: error: cake: Struct C6 is now with @frozen
24-
// CHECK: cake_current/cake.swift:41:13: error: cake: Enum IceKind is now without @frozen
26+
// CHECK: cake_current/cake.swift:41:13: error: cake: Enum IceKind is now without @frozen

Diff for: tools/swift-api-digester/swift-api-digester.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -2700,6 +2700,10 @@ static StringRef getBaselineFilename(llvm::Triple Triple) {
27002700
return "appletvos.json";
27012701
else if (Triple.isWatchOS())
27022702
return "watchos.json";
2703+
else if (Triple.isOSLinux())
2704+
return "linux.json";
2705+
else if (Triple.isOSWindows())
2706+
return "windows.json";
27032707
else {
27042708
llvm::errs() << "Unsupported triple target\n";
27052709
exit(1);

0 commit comments

Comments
 (0)