Skip to content

Commit 049d785

Browse files
committed
Add visitAccessPathBaseUses API
For the move-only checker
1 parent 2d91316 commit 049d785

File tree

4 files changed

+133
-2
lines changed

4 files changed

+133
-2
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,12 @@ bool visitAccessStorageUses(AccessUseVisitor &visitor, AccessStorage storage,
13971397
bool visitAccessPathUses(AccessUseVisitor &visitor, AccessPath accessPath,
13981398
SILFunction *function);
13991399

1400+
/// Similar to visitAccessPathUses, but the visitor is restricted to a specific
1401+
/// access base, such as a particular ref_element_addr.
1402+
bool visitAccessPathBaseUses(AccessUseVisitor &visitor,
1403+
AccessPathWithBase accessPathWithBase,
1404+
SILFunction *function);
1405+
14001406
} // end namespace swift
14011407

14021408
//===----------------------------------------------------------------------===//

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,6 +1534,16 @@ class AccessPathDefUseTraversal {
15341534
// The origin of the def-use traversal.
15351535
AccessStorage storage;
15361536

1537+
// The base of the formal access. For class storage, it is the
1538+
// ref_element_addr. For global storage it is the global_addr or initializer
1539+
// apply. For other storage, it is the same as accessPath.getRoot().
1540+
//
1541+
// 'base' is typically invalid, maning that all uses of 'storage' for the
1542+
// access path will be visited. When 'base' is set, the the visitor is
1543+
// restricted to a specific access base, such as a particular
1544+
// ref_element_addr.
1545+
SILValue base;
1546+
15371547
// Indices of the path to match from inner to outer component.
15381548
// A cursor is used to represent the most recently visited def.
15391549
// During def-use traversal, the cursor starts at the end of pathIndices and
@@ -1581,6 +1591,20 @@ class AccessPathDefUseTraversal {
15811591
});
15821592
}
15831593

1594+
AccessPathDefUseTraversal(AccessUseVisitor &visitor,
1595+
AccessPathWithBase accessPathWithBase,
1596+
SILFunction *function)
1597+
: visitor(visitor), storage(accessPathWithBase.accessPath.getStorage()),
1598+
base(accessPathWithBase.getAccessBase().getBaseAddress()) {
1599+
1600+
auto accessPath = accessPathWithBase.accessPath;
1601+
assert(accessPath.isValid());
1602+
1603+
initializePathIndices(accessPath);
1604+
1605+
initializeDFS(base);
1606+
}
1607+
15841608
// Return true is all uses have been visited.
15851609
bool visitUses() {
15861610
// Return false if initialization failed.
@@ -1601,8 +1625,8 @@ class AccessPathDefUseTraversal {
16011625
if (phi->isPhi())
16021626
visitedPhis.insert(phi);
16031627
}
1604-
pushUsers(root,
1605-
DFSEntry(nullptr, storage.isReference(), pathIndices.size(), 0));
1628+
bool isRef = !base && storage.isReference();
1629+
pushUsers(root, DFSEntry(nullptr, isRef, pathIndices.size(), 0));
16061630
}
16071631

16081632
void pushUsers(SILValue def, const DFSEntry &dfs) {
@@ -1654,6 +1678,10 @@ void AccessPathDefUseTraversal::initializePathIndices(AccessPath accessPath) {
16541678
if (int offset = accessPath.getOffset()) {
16551679
pathIndices.push_back(AccessPath::Index::forOffset(offset));
16561680
}
1681+
// If traversal starts at the base address, then class storage is irrelevant.
1682+
if (base)
1683+
return;
1684+
16571685
// The search will start from the object root, not the formal access base,
16581686
// so add the class index to the front.
16591687
if (storage.getKind() == AccessStorage::Class) {
@@ -1966,6 +1994,13 @@ bool swift::visitAccessPathUses(AccessUseVisitor &visitor,
19661994
return AccessPathDefUseTraversal(visitor, accessPath, function).visitUses();
19671995
}
19681996

1997+
bool swift::visitAccessPathBaseUses(AccessUseVisitor &visitor,
1998+
AccessPathWithBase accessPathWithBase,
1999+
SILFunction *function) {
2000+
return AccessPathDefUseTraversal(visitor, accessPathWithBase, function)
2001+
.visitUses();
2002+
}
2003+
19692004
bool swift::visitAccessStorageUses(AccessUseVisitor &visitor,
19702005
AccessStorage storage,
19712006
SILFunction *function) {

lib/SILOptimizer/UtilityPasses/UnitTestRunner.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868

6969
#include "swift/AST/Type.h"
7070
#include "swift/Basic/TaggedUnion.h"
71+
#include "swift/SIL/MemAccessUtils.h"
7172
#include "swift/SIL/PrunedLiveness.h"
7273
#include "swift/SIL/SILArgumentArrayRef.h"
7374
#include "swift/SIL/SILBasicBlock.h"
@@ -621,6 +622,44 @@ struct SimplifyCFGTryJumpThreading : UnitTest {
621622
}
622623
};
623624

625+
//===----------------------------------------------------------------------===//
626+
// MARK: AccessPath Unit Tests
627+
//===----------------------------------------------------------------------===//
628+
629+
struct AccessUseTestVisitor : public AccessUseVisitor {
630+
AccessUseTestVisitor()
631+
: AccessUseVisitor(AccessUseType::Overlapping,
632+
NestedAccessType::IgnoreAccessBegin) {}
633+
634+
bool visitUse(Operand *op, AccessUseType useTy) override {
635+
switch (useTy) {
636+
case AccessUseType::Exact:
637+
llvm::errs() << "Exact Use: ";
638+
break;
639+
case AccessUseType::Inner:
640+
llvm::errs() << "Inner Use: ";
641+
break;
642+
case AccessUseType::Overlapping:
643+
llvm::errs() << "Overlapping Use ";
644+
break;
645+
}
646+
llvm::errs() << *op->getUser();
647+
return true;
648+
}
649+
};
650+
651+
struct AccessPathBaseTest : UnitTest {
652+
AccessPathBaseTest(UnitTestRunner *pass) : UnitTest(pass) {}
653+
void invoke(Arguments &arguments) override {
654+
auto value = arguments.takeValue();
655+
getFunction()->dump();
656+
llvm::outs() << "Access path base: " << value;
657+
auto accessPathWithBase = AccessPathWithBase::compute(value);
658+
AccessUseTestVisitor visitor;
659+
visitAccessPathBaseUses(visitor, accessPathWithBase, getFunction());
660+
}
661+
};
662+
624663
/// [new_tests] Add the new UnitTest subclass above this line.
625664

626665
//===----------------------------------------------------------------------===//
@@ -637,6 +676,7 @@ void UnitTestRunner::withTest(StringRef name, Doit doit) {
637676
}
638677

639678
// Alphabetical mapping from string to unit test subclass.
679+
ADD_UNIT_TEST_SUBCLASS("accesspath-base", AccessPathBaseTest)
640680
ADD_UNIT_TEST_SUBCLASS("canonicalize-ossa-lifetime", CanonicalizeOSSALifetimeTest)
641681
ADD_UNIT_TEST_SUBCLASS("canonicalize-borrow-scope",
642682
CanonicalizeBorrowScopeTest)

test/SILOptimizer/accesspath_unit.sil

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %target-sil-opt -unit-test-runner %s -o /dev/null 2>&1 | %FileCheck %s
2+
3+
sil_stage raw
4+
5+
import Builtin
6+
7+
import Swift
8+
9+
struct S {}
10+
11+
class Klass {
12+
var f: S
13+
}
14+
15+
// CHECK-LABEL: begin running test 1 of 2 on testRefElement: accesspath-base with: @trace[0]
16+
// CHECK: [[P1:%.*]] = ref_element_addr %0 : $Klass, #Klass.f
17+
// CHECK: [[A1:%.*]] = begin_access [read] [dynamic] [[P1]] : $*S
18+
// CHECK: [[P2:%.*]] = ref_element_addr %0 : $Klass, #Klass.f
19+
// CHECK: [[A2:%.*]] = begin_access [read] [dynamic] [[P2]] : $*S
20+
// CHECK: Access path base: [[P1]] = ref_element_addr %0 : $Klass, #Klass.f
21+
// CHECK-NEXT: Exact Use: %{{.*}} = load [trivial] [[A1]] : $*S
22+
// CHECK-NEXT: Exact Use: end_access [[A1]] : $*S
23+
// CHECK-LABEL: end running test 1 of 2 on testRefElement: accesspath-base with: @trace[0]
24+
25+
// CHECK-LABEL: begin running test 2 of 2 on testRefElement: accesspath-base with: @trace[1]
26+
// CHECK: [[P1:%.*]] = ref_element_addr %0 : $Klass, #Klass.f
27+
// CHECK: [[A1:%.*]] = begin_access [read] [dynamic] [[P1]] : $*S
28+
// CHECK: [[P2:%.*]] = ref_element_addr %0 : $Klass, #Klass.f
29+
// CHECK: [[A2:%.*]] = begin_access [read] [dynamic] [[P2]] : $*S
30+
// CHECK: Access path base: [[P2]] = ref_element_addr %0 : $Klass, #Klass.f
31+
// CHECK-NEXT: Exact Use: %{{.*}} = load [trivial] [[A2]] : $*S
32+
// CHECK-NEXT: Exact Use: end_access [[A2]] : $*S
33+
// CHECK-LABEL: end running test 2 of 2 on testRefElement: accesspath-base with: @trace[1]
34+
sil hidden [ossa] @testRefElement : $@convention(thin) (@guaranteed Klass) -> () {
35+
bb0(%0 : @guaranteed $Klass):
36+
test_specification "accesspath-base @trace[0]"
37+
%p1 = ref_element_addr %0 : $Klass, #Klass.f
38+
debug_value [trace] %p1 : $*S
39+
%a1 = begin_access [read] [dynamic] %p1 : $*S
40+
%l1 = load [trivial] %a1 : $*S
41+
end_access %a1 : $*S
42+
test_specification "accesspath-base @trace[1]"
43+
%p2 = ref_element_addr %0 : $Klass, #Klass.f
44+
debug_value [trace] %p2 : $*S
45+
%a2 = begin_access [read] [dynamic] %p2 : $*S
46+
%l2 = load [trivial] %a2 : $*S
47+
end_access %a2 : $*S
48+
%99 = tuple ()
49+
return %99 : $()
50+
}

0 commit comments

Comments
 (0)