Skip to content

Commit 0395920

Browse files
authored
Merge pull request swiftlang#30369 from atrick/fix-verify-exclusivity
Fix MemBehavior calls to getAccessedAddress to avoid an assert.
2 parents dbbe45e + 7145a80 commit 0395920

File tree

3 files changed

+80
-12
lines changed

3 files changed

+80
-12
lines changed

lib/SILOptimizer/Analysis/MemoryBehavior.cpp

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ class MemoryBehaviorVisitor
5656
/// The value we are attempting to discover memory behavior relative to.
5757
SILValue V;
5858

59+
/// Cache either the address of the access corresponding to memory at 'V', or
60+
/// 'V' itself if it isn't recognized as part of an access. The cached value
61+
/// is always a valid SILValue.
62+
SILValue cachedValueAddress;
63+
5964
Optional<bool> cachedIsLetValue;
6065

6166
/// The SILType of the value.
@@ -77,11 +82,21 @@ class MemoryBehaviorVisitor
7782
return *TypedAccessTy;
7883
}
7984

85+
/// If 'V' is an address projection within a formal access, return the
86+
/// canonical address of the formal access. Otherwise, return 'V' itself,
87+
/// which is either a reference or unknown pointer or address.
88+
SILValue getValueAddress() {
89+
if (!cachedValueAddress) {
90+
cachedValueAddress = V->getType().isAddress() ? getAccessedAddress(V) : V;
91+
}
92+
return cachedValueAddress;
93+
}
94+
8095
/// Return true if 'V's accessed address is that of a let variables.
8196
bool isLetValue() {
8297
if (!cachedIsLetValue) {
8398
cachedIsLetValue =
84-
V->getType().isAddress() && isLetAddress(getAccessedAddress(V));
99+
V->getType().isAddress() && isLetAddress(getValueAddress());
85100
}
86101
return cachedIsLetValue.getValue();
87102
}
@@ -124,15 +139,11 @@ class MemoryBehaviorVisitor
124139

125140
MemBehavior visitBeginAccessInst(BeginAccessInst *beginAccess) {
126141
switch (beginAccess->getAccessKind()) {
127-
case SILAccessKind::Init:
128142
case SILAccessKind::Deinit:
129-
// No address aliasing is expected for variable initialization or
130-
// deinitialization.
131-
if (stripAccessMarkers(beginAccess) != getAccessedAddress(V))
132-
return MemBehavior::None;
133-
134-
return MemBehavior::MayWrite;
135-
143+
// A [deinit] only directly reads from the object. The fact that it frees
144+
// memory is modeled more precisely by the release operations within the
145+
// deinit scope. Therefore, handle it like a [read] here...
146+
LLVM_FALLTHROUGH;
136147
case SILAccessKind::Read:
137148
if (!mayAlias(beginAccess->getSource()))
138149
return MemBehavior::None;
@@ -141,10 +152,14 @@ class MemoryBehaviorVisitor
141152

142153
case SILAccessKind::Modify:
143154
if (isLetValue()) {
144-
assert(stripAccessMarkers(beginAccess) != getAccessedAddress(V)
155+
assert(stripAccessMarkers(beginAccess) != getValueAddress()
145156
&& "let modification not allowed");
146157
return MemBehavior::None;
147158
}
159+
// [modify] has a special case for ignoring 'let's, but otherwise is
160+
// identical to an [init]...
161+
LLVM_FALLTHROUGH;
162+
case SILAccessKind::Init:
148163
if (!mayAlias(beginAccess->getSource()))
149164
return MemBehavior::None;
150165

@@ -229,15 +244,15 @@ MemBehavior MemoryBehaviorVisitor::visitLoadInst(LoadInst *LI) {
229244
return MemBehavior::None;
230245

231246
LLVM_DEBUG(llvm::dbgs() << " Could not prove that load inst does not alias "
232-
"pointer. Returning may read.");
247+
"pointer. Returning may read.\n");
233248
return MemBehavior::MayRead;
234249
}
235250

236251
MemBehavior MemoryBehaviorVisitor::visitStoreInst(StoreInst *SI) {
237252
// No store besides the initialization of a "let"-variable
238253
// can have any effect on the value of this "let" variable.
239254
if (isLetValue()
240-
&& (getAccessedAddress(SI->getDest()) != getAccessedAddress(V))) {
255+
&& (getAccessedAddress(SI->getDest()) != getValueAddress())) {
241256
return MemBehavior::None;
242257
}
243258
// If the store dest cannot alias the pointer in question, then the

test/SILOptimizer/access_marker_verify.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,3 +1080,27 @@ public func getStaticProp() -> HasStaticProp {
10801080
// CHECK: [[ADR:%.*]] = pointer_to_address [[RP]] : $Builtin.RawPointer to [strict] $*HasStaticProp
10811081
// CHECK: load [copy] [[ADR]] : $*HasStaticProp
10821082
// CHECK-LABEL: } // end sil function '$s20access_marker_verify13getStaticPropAA03HaseF0CyF'
1083+
1084+
// ===-----------------------------------------------------------------------===
1085+
// Test computeMemBehavior with a non-address value. In this case, the
1086+
// address for an access of StreamClass.buffer is compared with the
1087+
// ContiguousArrayStorageBase value.
1088+
//
1089+
// <rdar://60046018> assert: (v->getType().isAddress()) in getAccessedAddress.
1090+
1091+
public final class StreamClass {
1092+
private var buffer: [UInt8]
1093+
1094+
public init() {
1095+
self.buffer = []
1096+
}
1097+
}
1098+
1099+
// CHECK-LABEL: sil [ossa] @$s20access_marker_verify25testNonAddressMemBehavioryySiF : $@convention(thin) (Int) -> () {
1100+
// The relevant SIL instructions for this test don't appear until the string interpolation is inlined.
1101+
// Just make sure it does not assert.
1102+
// CHECK-LABEL: } // end sil function '$s20access_marker_verify25testNonAddressMemBehavioryySiF'
1103+
public func testNonAddressMemBehavior(_ N: Int) {
1104+
let listOfStrings: [String] = (0..<10).map { "This is the number: \($0)!\n" }
1105+
let stream = StreamClass()
1106+
}

test/SILOptimizer/mem-behavior-all.sil

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,32 @@ bb0(%0 : $*Builtin.Int32):
112112
end_access %write : $*Builtin.Int32
113113
return %val : $Builtin.Int32
114114
}
115+
116+
// ===-----------------------------------------------------------------------===
117+
// Test the effect of a [deinit] access on a global 'let'
118+
//
119+
// Test <rdar://60046018> Assert: (v->getType().isAddress()), getAccessedAddress
120+
121+
sil_global hidden [let] @globalC : $C
122+
123+
// CHECK-LABEL: @testDeinitInstVsNonAddressValue
124+
// CHECK: PAIR #5.
125+
// CHECK-NEXT: load %{{.*}} : $*C
126+
// CHECK-NEXT: begin_access [deinit] [static] %{{.*}} : $*Builtin.Int32
127+
// CHECK-NEXT: r=1,w=0,se=0
128+
// CHECK: PAIR #16.
129+
// CHECK-NEXT: %6 = begin_access [deinit] [static] %5 : $*Builtin.Int32 // user: %7
130+
// CHECK-NEXT: %2 = load %1 : $*C // user: %3
131+
// CHECK-NEXT: r=1,w=0,se=0
132+
sil hidden @testDeinitInstVsNonAddressValue : $@convention(thin) (@guaranteed C) -> () {
133+
bb0(%0 : $C):
134+
%1 = global_addr @globalC : $*C
135+
%2 = load %1 : $*C
136+
%3 = ref_element_addr %2 : $C, #C.prop
137+
%4 = load %3 : $*Builtin.Int32
138+
%5 = ref_element_addr %0 : $C, #C.prop
139+
%6 = begin_access [deinit] [static] %5 : $*Builtin.Int32
140+
end_access %6 : $*Builtin.Int32
141+
%8 = tuple ()
142+
return %8 : $()
143+
}

0 commit comments

Comments
 (0)