Skip to content

Commit badc565

Browse files
committed
Fix SIL MemBehavior queries with access markers.
This is in prepration for other bug fixes. Clarify the SIL utilities that return canonical address values for formal access given the address used by some memory operation: - stripAccessMarkers - getAddressAccess - getAccessedAddress These are closely related to the code in MemAccessUtils. Make sure passes use these utilities consistently so that optimizations aren't defeated by normal variations in SIL patterns. Create an isLetAddress() utility alongside these basic utilities to make sure it is used consistently with the address corresponding to formal access. When this query is used inconsistently, it defeats optimization. It can also cause correctness bugs because some optimizations assume that 'let' initialization is only performed on a unique address value. Functional changes to Memory Behavior: - An instruction with side effects now conservatively still has side effects even when the queried value is a 'let'. Let values are certainly sensitive to side effects, such as the parent object being deallocated. - Return the correct MemBehavior for begin/end_access markers.
1 parent b58ea4b commit badc565

17 files changed

+376
-188
lines changed

include/swift/SIL/InstructionUtils.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ namespace swift {
2525
/// nothing left to strip.
2626
SILValue getUnderlyingObject(SILValue V);
2727

28-
/// Strip off indexing and address projections.
29-
///
30-
/// This is similar to getUnderlyingObject, except that it does not strip any
31-
/// object-to-address projections, like ref_element_addr. In other words, the
32-
/// result is always an address value.
33-
SILValue getUnderlyingAddressRoot(SILValue V);
34-
3528
SILValue getUnderlyingObjectStopAtMarkDependence(SILValue V);
3629

3730
SILValue stripSinglePredecessorArgs(SILValue V);
@@ -56,11 +49,6 @@ SILValue stripUpCasts(SILValue V);
5649
/// upcasts and downcasts.
5750
SILValue stripClassCasts(SILValue V);
5851

59-
/// Return the underlying SILValue after stripping off non-projection address
60-
/// casts. The result will still be an address--this does not look through
61-
/// pointer-to-address.
62-
SILValue stripAddressAccess(SILValue V);
63-
6452
/// Return the underlying SILValue after stripping off all address projection
6553
/// instructions.
6654
SILValue stripAddressProjections(SILValue V);

include/swift/SIL/MemAccessUtils.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,50 @@
4646

4747
namespace swift {
4848

49-
// stripAddressAccess() is declared in InstructionUtils.h.
49+
/// Get the base address of a formal access by stripping access markers and
50+
/// borrows.
51+
///
52+
/// If \p v is an address, then the returned value is also an address
53+
/// (pointer-to-address is not stripped).
54+
SILValue stripAccessMarkers(SILValue v);
55+
56+
/// Attempt to return the address corresponding to a variable's formal access
57+
/// by stripping indexing and address projections.
58+
///
59+
/// \p v must be an address.
60+
///
61+
/// Returns an address. If the a formal access was successfully identified, and
62+
/// access markers have not yet been removed, then the returned address is
63+
/// produced by a begin_access marker.
64+
///
65+
/// To get the base address of the formal access behind the access marker,
66+
/// either call stripAccessMarkers() on the returned value, or call
67+
/// getAccessedAddress() on \p v.
68+
///
69+
/// To identify the underlying storage object of the access, use
70+
/// findAccessedStorage() on either \p v or the returned address.
71+
SILValue getAddressAccess(SILValue v);
72+
73+
/// Convenience for stripAccessMarkers(getAddressAccess(V)).
74+
SILValue getAccessedAddress(SILValue v);
75+
76+
/// Return true if \p accessedAddress points to a let-variable.
77+
///
78+
/// Precondition: \p accessedAddress must be an address-type value representing
79+
/// the base of a formal access (not a projection within the access).
80+
///
81+
/// let-variables are only written during let-variable initialization, which is
82+
/// assumed to store directly to the same, unaliased accessedAddress.
83+
///
84+
/// The address of a let-variable must be the base of a formal access . A 'let'
85+
/// member of a struct is *not* a let-variable, because it's memory may be
86+
/// written when formally modifying the outer struct. A let-variable is either
87+
/// an entire local variable, global variable, or class property (this is the
88+
/// definition of the base address of a formal access).
89+
///
90+
/// The caller should derive the accessed address using
91+
/// stripAccessMarkers(getAccessedAddress(ptr)).
92+
bool isLetAddress(SILValue accessedAddress);
5093

5194
inline bool accessKindMayConflict(SILAccessKind a, SILAccessKind b) {
5295
return !(a == SILAccessKind::Read && b == SILAccessKind::Read);
@@ -104,7 +147,7 @@ inline bool accessKindMayConflict(SILAccessKind a, SILAccessKind b) {
104147
class AccessedStorage {
105148
public:
106149
/// Enumerate over all valid begin_access bases. Clients can use a covered
107-
/// switch to warn if findAccessedAddressBase ever adds a case.
150+
/// switch to warn if AccessedStorage ever adds a case.
108151
enum Kind : uint8_t {
109152
Box,
110153
Stack,

include/swift/SIL/SILNodes.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,9 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
591591
SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
592592
SINGLE_VALUE_INST(StoreBorrowInst, store_borrow,
593593
SILInstruction, MayWrite, DoesNotRelease)
594+
// begin_access may trap. Trapping is unordered with respect to memory access,
595+
// and with respect to other traps, but it is still conservatively considered
596+
// a side effect.
594597
SINGLE_VALUE_INST(BeginAccessInst, begin_access,
595598
SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
596599
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \
@@ -803,6 +806,10 @@ NON_VALUE_INST(DestroyValueInst, destroy_value,
803806
SILInstruction, MayHaveSideEffects, MayRelease)
804807
NON_VALUE_INST(EndBorrowInst, end_borrow,
805808
SILInstruction, MayHaveSideEffects, DoesNotRelease)
809+
// end_access is considered to have side effects because it modifies runtime
810+
// state outside of the memory modified by the access that is visible to
811+
// Swift. This "side effect" only needs to creates a dependency on begin_access
812+
// instructions.
806813
NON_VALUE_INST(EndAccessInst, end_access,
807814
SILInstruction, MayHaveSideEffects, DoesNotRelease)
808815
NON_VALUE_INST(BeginUnpairedAccessInst, begin_unpaired_access,

include/swift/SILOptimizer/Analysis/AliasAnalysis.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -299,10 +299,6 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
299299
/// Otherwise, return an empty type.
300300
SILType computeTBAAType(SILValue V);
301301

302-
/// Check if \p V points to a let-member.
303-
/// Nobody can write into let members.
304-
bool isLetPointer(SILValue V);
305-
306302
} // end namespace swift
307303

308304
namespace llvm {

include/swift/SILOptimizer/Analysis/ValueTracking.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#ifndef SWIFT_SILOPTIMIZER_ANALYSIS_VALUETRACKING_H
1818
#define SWIFT_SILOPTIMIZER_ANALYSIS_VALUETRACKING_H
1919

20-
#include "swift/SIL/InstructionUtils.h"
20+
#include "swift/SIL/MemAccessUtils.h"
2121
#include "swift/SIL/SILArgument.h"
2222
#include "swift/SIL/SILInstruction.h"
2323

@@ -50,7 +50,8 @@ bool pointsToLocalObject(SILValue V);
5050
/// indirection (e.g. ref_element_addr, project_box, etc.).
5151
inline bool isUniquelyIdentified(SILValue V) {
5252
return pointsToLocalObject(V)
53-
|| isExclusiveArgument(getUnderlyingAddressRoot(V));
53+
|| (V->getType().isAddress()
54+
&& isExclusiveArgument(getAccessedAddress(V)));
5455
}
5556

5657
enum class IsZeroKind {

lib/IRGen/IRGenSIL.cpp

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,42 @@
1616
//===----------------------------------------------------------------------===//
1717

1818
#define DEBUG_TYPE "irgensil"
19-
#include "llvm/IR/DIBuilder.h"
20-
#include "llvm/IR/Function.h"
21-
#include "llvm/IR/Module.h"
22-
#include "llvm/IR/Instructions.h"
23-
#include "llvm/IR/IntrinsicInst.h"
24-
#include "llvm/IR/InlineAsm.h"
25-
#include "llvm/IR/Intrinsics.h"
26-
#include "llvm/ADT/MapVector.h"
27-
#include "llvm/ADT/SmallBitVector.h"
28-
#include "llvm/ADT/TinyPtrVector.h"
29-
#include "llvm/Support/SaveAndRestore.h"
30-
#include "llvm/Support/Debug.h"
31-
#include "llvm/Transforms/Utils/Local.h"
32-
#include "clang/AST/ASTContext.h"
33-
#include "clang/Basic/TargetInfo.h"
34-
#include "swift/Basic/ExternalUnion.h"
35-
#include "swift/Basic/Range.h"
36-
#include "swift/Basic/STLExtras.h"
3719
#include "swift/AST/ASTContext.h"
3820
#include "swift/AST/IRGenOptions.h"
39-
#include "swift/AST/Pattern.h"
4021
#include "swift/AST/ParameterList.h"
22+
#include "swift/AST/Pattern.h"
4123
#include "swift/AST/SubstitutionMap.h"
4224
#include "swift/AST/Types.h"
25+
#include "swift/Basic/ExternalUnion.h"
26+
#include "swift/Basic/Range.h"
27+
#include "swift/Basic/STLExtras.h"
4328
#include "swift/SIL/ApplySite.h"
4429
#include "swift/SIL/Dominance.h"
30+
#include "swift/SIL/InstructionUtils.h"
31+
#include "swift/SIL/MemAccessUtils.h"
4532
#include "swift/SIL/PrettyStackTrace.h"
4633
#include "swift/SIL/SILDebugScope.h"
4734
#include "swift/SIL/SILDeclRef.h"
4835
#include "swift/SIL/SILLinkage.h"
4936
#include "swift/SIL/SILModule.h"
5037
#include "swift/SIL/SILType.h"
5138
#include "swift/SIL/SILVisitor.h"
52-
#include "swift/SIL/InstructionUtils.h"
39+
#include "clang/AST/ASTContext.h"
40+
#include "clang/Basic/TargetInfo.h"
5341
#include "clang/CodeGen/CodeGenABITypes.h"
42+
#include "llvm/ADT/MapVector.h"
43+
#include "llvm/ADT/SmallBitVector.h"
44+
#include "llvm/ADT/TinyPtrVector.h"
45+
#include "llvm/IR/DIBuilder.h"
46+
#include "llvm/IR/Function.h"
47+
#include "llvm/IR/InlineAsm.h"
48+
#include "llvm/IR/Instructions.h"
49+
#include "llvm/IR/IntrinsicInst.h"
50+
#include "llvm/IR/Intrinsics.h"
51+
#include "llvm/IR/Module.h"
52+
#include "llvm/Support/Debug.h"
53+
#include "llvm/Support/SaveAndRestore.h"
54+
#include "llvm/Transforms/Utils/Local.h"
5455

5556
#include "CallEmission.h"
5657
#include "Explosion.h"
@@ -3567,8 +3568,11 @@ void IRGenSILFunction::visitRefTailAddrInst(RefTailAddrInst *i) {
35673568
}
35683569

35693570
static bool isInvariantAddress(SILValue v) {
3570-
auto root = getUnderlyingAddressRoot(v);
3571-
if (auto ptrRoot = dyn_cast<PointerToAddressInst>(root)) {
3571+
SILValue accessedAddress = getAccessedAddress(v);
3572+
if (accessedAddress->getType().isAddress() && isLetAddress(accessedAddress)) {
3573+
return true;
3574+
}
3575+
if (auto *ptrRoot = dyn_cast<PointerToAddressInst>(accessedAddress)) {
35723576
return ptrRoot->isInvariant();
35733577
}
35743578
// TODO: We could be more aggressive about considering addresses based on

lib/SIL/InstructionUtils.cpp

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -52,28 +52,6 @@ SILValue swift::getUnderlyingObject(SILValue v) {
5252
}
5353
}
5454

55-
/// Strip off casts and address projections into the interior of a value. Unlike
56-
/// getUnderlyingObject, this does not find the root of a heap object--a class
57-
/// property is itself an address root.
58-
SILValue swift::getUnderlyingAddressRoot(SILValue v) {
59-
while (true) {
60-
SILValue v2 = stripIndexingInsts(stripCasts(v));
61-
v2 = stripOwnershipInsts(v2);
62-
switch (v2->getKind()) {
63-
case ValueKind::StructElementAddrInst:
64-
case ValueKind::TupleElementAddrInst:
65-
case ValueKind::UncheckedTakeEnumDataAddrInst:
66-
v2 = cast<SingleValueInstruction>(v2)->getOperand(0);
67-
break;
68-
default:
69-
break;
70-
}
71-
if (v2 == v)
72-
return v2;
73-
v = v2;
74-
}
75-
}
76-
7755
SILValue swift::getUnderlyingObjectStopAtMarkDependence(SILValue v) {
7856
while (true) {
7957
SILValue v2 = stripCastsWithoutMarkDependence(v);
@@ -224,18 +202,6 @@ SILValue swift::stripClassCasts(SILValue v) {
224202
}
225203
}
226204

227-
SILValue swift::stripAddressAccess(SILValue V) {
228-
while (true) {
229-
switch (V->getKind()) {
230-
default:
231-
return V;
232-
case ValueKind::BeginBorrowInst:
233-
case ValueKind::BeginAccessInst:
234-
V = cast<SingleValueInstruction>(V)->getOperand(0);
235-
}
236-
}
237-
}
238-
239205
SILValue swift::stripAddressProjections(SILValue V) {
240206
while (true) {
241207
V = stripSinglePredecessorArgs(V);

lib/SIL/MemAccessUtils.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,56 @@
2121

2222
using namespace swift;
2323

24+
SILValue swift::stripAccessMarkers(SILValue v) {
25+
while (true) {
26+
switch (v->getKind()) {
27+
default:
28+
return v;
29+
30+
case ValueKind::BeginBorrowInst:
31+
case ValueKind::BeginAccessInst:
32+
v = cast<SingleValueInstruction>(v)->getOperand(0);
33+
}
34+
}
35+
}
36+
37+
// TODO: When the optimizer stops stripping begin_access markers, then we should
38+
// be able to assert that the result is a BeginAccessInst and the default case
39+
// is unreachable.
40+
SILValue swift::getAccessedAddress(SILValue v) {
41+
assert(v->getType().isAddress());
42+
while (true) {
43+
switch (v->getKind()) {
44+
default:
45+
return v;
46+
47+
case ValueKind::BeginBorrowInst:
48+
case ValueKind::StructElementAddrInst:
49+
case ValueKind::TupleElementAddrInst:
50+
case ValueKind::UncheckedTakeEnumDataAddrInst:
51+
case ValueKind::TailAddrInst:
52+
case ValueKind::IndexAddrInst:
53+
v = cast<SingleValueInstruction>(v)->getOperand(0);
54+
continue;
55+
};
56+
}
57+
}
58+
59+
bool swift::isLetAddress(SILValue accessedAddress) {
60+
assert(accessedAddress == getAccessedAddress(accessedAddress)
61+
&& "caller must find the address root");
62+
// Is this an address of a "let" class member?
63+
if (auto *rea = dyn_cast<RefElementAddrInst>(accessedAddress))
64+
return rea->getField()->isLet();
65+
66+
// Is this an address of a global "let"?
67+
if (auto *gai = dyn_cast<GlobalAddrInst>(accessedAddress)) {
68+
auto *globalDecl = gai->getReferencedGlobal()->getDecl();
69+
return globalDecl && globalDecl->isLet();
70+
}
71+
return false;
72+
}
73+
2474
AccessedStorage::AccessedStorage(SILValue base, Kind kind) {
2575
assert(base && "invalid storage base");
2676
initKind(kind);

lib/SILOptimizer/Analysis/AliasAnalysis.cpp

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -330,14 +330,18 @@ static bool isTypedAccessOracle(SILInstruction *I) {
330330
/// given value is directly derived from a memory location, it cannot
331331
/// alias. Call arguments also cannot alias because they must follow \@in, @out,
332332
/// @inout, or \@in_guaranteed conventions.
333-
static bool isAddressRootTBAASafe(SILValue V) {
334-
if (isa<SILFunctionArgument>(V))
333+
static bool isAccessedAddressTBAASafe(SILValue V) {
334+
if (!V->getType().isAddress())
335+
return false;
336+
337+
SILValue accessedAddress = getAccessedAddress(V);
338+
if (isa<SILFunctionArgument>(accessedAddress))
335339
return true;
336340

337-
if (auto *PtrToAddr = dyn_cast<PointerToAddressInst>(V))
341+
if (auto *PtrToAddr = dyn_cast<PointerToAddressInst>(accessedAddress))
338342
return PtrToAddr->isStrict();
339343

340-
switch (V->getKind()) {
344+
switch (accessedAddress->getKind()) {
341345
default:
342346
return false;
343347
case ValueKind::AllocStackInst:
@@ -352,6 +356,8 @@ static bool isAddressRootTBAASafe(SILValue V) {
352356
/// TypedAccessOracle which enable one to ascertain via undefined behavior the
353357
/// "true" type of the instruction.
354358
static SILType findTypedAccessType(SILValue V) {
359+
assert(V->getType().isAddress());
360+
355361
// First look at the origin of V and see if we have any instruction that is a
356362
// typed oracle.
357363
// TODO: MultiValueInstruction
@@ -370,7 +376,7 @@ static SILType findTypedAccessType(SILValue V) {
370376
}
371377

372378
SILType swift::computeTBAAType(SILValue V) {
373-
if (isAddressRootTBAASafe(getUnderlyingAddressRoot(V)))
379+
if (isAccessedAddressTBAASafe(V))
374380
return findTypedAccessType(V);
375381

376382
// FIXME: add ref_element_addr check here. TBAA says that objects cannot be
@@ -743,34 +749,6 @@ bool AliasAnalysis::mayValueReleaseInterfereWithInstruction(
743749
return EA->mayReleaseContent(releasedReference, accessedPointer);
744750
}
745751

746-
bool swift::isLetPointer(SILValue V) {
747-
// Traverse the "access" path for V and check that it starts with "let"
748-
// and everything along this path is a value-type (i.e. struct or tuple).
749-
750-
// Is this an address of a "let" class member?
751-
if (auto *REA = dyn_cast<RefElementAddrInst>(V))
752-
return REA->getField()->isLet();
753-
754-
// Is this an address of a global "let"?
755-
if (auto *GAI = dyn_cast<GlobalAddrInst>(V)) {
756-
auto *GlobalDecl = GAI->getReferencedGlobal()->getDecl();
757-
return GlobalDecl && GlobalDecl->isLet();
758-
}
759-
760-
// Is this an address of a struct "let" member?
761-
if (auto *SEA = dyn_cast<StructElementAddrInst>(V))
762-
// Check if it is a "let" in the parent struct.
763-
// Check if its parent is a "let".
764-
return isLetPointer(SEA->getOperand());
765-
766-
767-
// Check if a parent of a tuple is a "let"
768-
if (auto *TEA = dyn_cast<TupleElementAddrInst>(V))
769-
return isLetPointer(TEA->getOperand());
770-
771-
return false;
772-
}
773-
774752
void AliasAnalysis::initialize(SILPassManager *PM) {
775753
SEA = PM->getAnalysis<SideEffectAnalysis>();
776754
EA = PM->getAnalysis<EscapeAnalysis>();

0 commit comments

Comments
 (0)