Skip to content

Commit d47b802

Browse files
authored
Merge pull request swiftlang#30173 from atrick/fix-temp-rvalue-access
Fix MemBehavior and TempRValueOpt to handle access markers
2 parents 939d618 + 880db42 commit d47b802

19 files changed

+460
-217
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)