Skip to content

Commit 5091aee

Browse files
committed
Add an AccessedStorageDumper pass to verify findAccessedStorage.
Rename the existing pass to AccessedStorageAnalysisDumper. AccessedStorage is useful on its own as a utility without the analysis. We need a way to test the utility itself. Add test cases for the previous commit that introduced FindPhiStorageVisitor.
1 parent acf72bd commit 5091aee

File tree

7 files changed

+237
-13
lines changed

7 files changed

+237
-13
lines changed

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ PASS(CrossModuleSerializationSetup, "cross-module-serialization-setup",
6868
"Setup serialization flags for cross-module optimization")
6969
PASS(AccessSummaryDumper, "access-summary-dump",
7070
"Dump Address Parameter Access Summary")
71+
PASS(AccessedStorageAnalysisDumper, "accessed-storage-analysis-dump",
72+
"Dump Accessed Storage Analysis Summaries")
7173
PASS(AccessedStorageDumper, "accessed-storage-dump",
72-
"Dump Accessed Storage Summary")
74+
"Dump Accessed Storage Information")
7375
PASS(AccessMarkerElimination, "access-marker-elim",
7476
"Access Marker Elimination.")
7577
PASS(AddressLowering, "address-lowering",

lib/SIL/Utils/MemAccessUtils.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ const char *AccessedStorage::getKindName(AccessedStorage::Kind k) {
190190
}
191191

192192
void AccessedStorage::print(raw_ostream &os) const {
193+
if (!*this) {
194+
os << "INVALID\n";
195+
return;
196+
}
193197
os << getKindName(getKind()) << " ";
194198
switch (getKind()) {
195199
case Box:
@@ -246,10 +250,16 @@ class FindPhiStorageVisitor
246250
this->visit(pointerWorklist.pop_back_val());
247251
}
248252
// If a common path component was found, recursively look for the storage.
249-
if (commonDefinition && commonDefinition.getValue()) {
250-
auto storage = storageVisitor.findStorage(commonDefinition.getValue());
251-
(void)storage; // The same storageVisitor called us. It has already
252-
// recorded the storage that it found.
253+
if (commonDefinition) {
254+
if (commonDefinition.getValue()) {
255+
auto storage = storageVisitor.findStorage(commonDefinition.getValue());
256+
(void)storage; // The same storageVisitor called us. It has already
257+
// recorded the storage that it found.
258+
} else {
259+
// If divergent paths were found, invalidate any previously discovered
260+
// storage.
261+
storageVisitor.setStorage(AccessedStorage());
262+
}
253263
}
254264
}
255265

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//===--- AccessedStorageAnalysisDumper.cpp - accessed storage anlaysis ----===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#define DEBUG_TYPE "sil-accessed-storage-analysys-dumper"
14+
#include "swift/SIL/SILArgument.h"
15+
#include "swift/SIL/SILFunction.h"
16+
#include "swift/SIL/SILInstruction.h"
17+
#include "swift/SIL/SILValue.h"
18+
#include "swift/SILOptimizer/Analysis/AccessedStorageAnalysis.h"
19+
#include "swift/SILOptimizer/PassManager/Passes.h"
20+
#include "swift/SILOptimizer/PassManager/Transforms.h"
21+
#include "llvm/Support/Debug.h"
22+
23+
using namespace swift;
24+
25+
namespace {
26+
27+
/// Dumps per-function information on dynamically enforced formal accesses.
28+
class AccessedStorageAnalysisDumper : public SILModuleTransform {
29+
30+
void run() override {
31+
auto *analysis = PM->getAnalysis<AccessedStorageAnalysis>();
32+
33+
for (auto &fn : *getModule()) {
34+
llvm::outs() << "@" << fn.getName() << "\n";
35+
if (fn.empty()) {
36+
llvm::outs() << "<unknown>\n";
37+
continue;
38+
}
39+
const FunctionAccessedStorage &summary = analysis->getEffects(&fn);
40+
summary.print(llvm::outs());
41+
}
42+
}
43+
};
44+
45+
} // end anonymous namespace
46+
47+
SILTransform *swift::createAccessedStorageAnalysisDumper() {
48+
return new AccessedStorageAnalysisDumper();
49+
}

lib/SILOptimizer/UtilityPasses/AccessedStorageDumper.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,44 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#define DEBUG_TYPE "sil-accessed-storage-dumper"
14-
#include "swift/SIL/SILArgument.h"
14+
#include "swift/SIL/MemAccessUtils.h"
1515
#include "swift/SIL/SILFunction.h"
1616
#include "swift/SIL/SILInstruction.h"
1717
#include "swift/SIL/SILValue.h"
18-
#include "swift/SILOptimizer/Analysis/AccessedStorageAnalysis.h"
1918
#include "swift/SILOptimizer/PassManager/Passes.h"
2019
#include "swift/SILOptimizer/PassManager/Transforms.h"
2120
#include "llvm/Support/Debug.h"
2221

2322
using namespace swift;
2423

24+
static void dumpAccessedStorage(SILInstruction *inst) {
25+
visitAccessedAddress(
26+
inst,
27+
[&](Operand *operand) {
28+
inst->print(llvm::outs());
29+
findAccessedStorage(operand->get()).print(llvm::outs());
30+
}
31+
);
32+
}
33+
2534
namespace {
2635

27-
/// Dumps per-function information on dynamically enforced formal accesses.
36+
/// Dumps sorage information for each access.
2837
class AccessedStorageDumper : public SILModuleTransform {
2938

3039
void run() override {
31-
auto *analysis = PM->getAnalysis<AccessedStorageAnalysis>();
32-
3340
for (auto &fn : *getModule()) {
3441
llvm::outs() << "@" << fn.getName() << "\n";
3542
if (fn.empty()) {
3643
llvm::outs() << "<unknown>\n";
3744
continue;
3845
}
39-
const FunctionAccessedStorage &summary = analysis->getEffects(&fn);
40-
summary.print(llvm::outs());
46+
for (auto &bb : fn) {
47+
for (auto &inst : bb) {
48+
if (inst.mayReadOrWriteMemory())
49+
dumpAccessedStorage(&inst);
50+
}
51+
}
4152
}
4253
}
4354
};

lib/SILOptimizer/UtilityPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
target_sources(swiftSILOptimizer PRIVATE
22
AADumper.cpp
33
AccessSummaryDumper.cpp
4+
AccessedStorageAnalysisDumper.cpp
45
AccessedStorageDumper.cpp
56
BasicCalleePrinter.cpp
67
BasicInstructionPropertyDumper.cpp
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// RUN: %target-sil-opt %s -accessed-storage-dump -enable-sil-verify-all -o /dev/null | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Builtin
6+
import Swift
7+
import SwiftShims
8+
9+
struct MyStruct {
10+
@_hasStorage @_hasInitialValue var i: Int64 { get set }
11+
@_hasStorage @_hasInitialValue var j: Int64 { get set }
12+
}
13+
14+
// CHECK-LABEL: @testStructPhiCommon
15+
// CHECK: store
16+
// CHECK: Argument %0 = argument of bb0 : $*MyStruct
17+
sil hidden @testStructPhiCommon : $@convention(thin) (@inout MyStruct) -> () {
18+
bb0(%0 : $*MyStruct):
19+
%2 = struct_element_addr %0 : $*MyStruct, #MyStruct.i
20+
cond_br undef, bb1, bb2
21+
22+
bb1:
23+
%3 = address_to_pointer %2 : $*Int64 to $Builtin.RawPointer
24+
br bb3(%3 : $Builtin.RawPointer)
25+
26+
bb2:
27+
%5 = address_to_pointer %2 : $*Int64 to $Builtin.RawPointer
28+
br bb3(%5 : $Builtin.RawPointer)
29+
30+
bb3(%6 : $Builtin.RawPointer) :
31+
%7 = pointer_to_address %6 : $Builtin.RawPointer to $*Int64
32+
%8 = integer_literal $Builtin.Int64, 2
33+
%9 = struct $Int64 (%8 : $Builtin.Int64)
34+
store %9 to %7 : $*Int64
35+
%22 = tuple ()
36+
return %22 : $()
37+
}
38+
39+
// A pointer phi leading to different access paths should be
40+
// considered illegal, but we don't have a way to verify it yet.
41+
//
42+
// CHECK-LABEL: @testStructPhiDivergent
43+
// CHECK: store
44+
// CHECK: INVALID
45+
sil hidden @testStructPhiDivergent : $@convention(thin) (@inout MyStruct) -> () {
46+
bb0(%0 : $*MyStruct):
47+
cond_br undef, bb1, bb2
48+
49+
bb1:
50+
%2 = struct_element_addr %0 : $*MyStruct, #MyStruct.i
51+
%3 = address_to_pointer %2 : $*Int64 to $Builtin.RawPointer
52+
br bb3(%3 : $Builtin.RawPointer)
53+
54+
bb2:
55+
%4 = struct_element_addr %0 : $*MyStruct, #MyStruct.j
56+
%5 = address_to_pointer %4 : $*Int64 to $Builtin.RawPointer
57+
br bb3(%5 : $Builtin.RawPointer)
58+
59+
bb3(%6 : $Builtin.RawPointer) :
60+
%7 = pointer_to_address %6 : $Builtin.RawPointer to $*Int64
61+
%8 = integer_literal $Builtin.Int64, 2
62+
%9 = struct $Int64 (%8 : $Builtin.Int64)
63+
store %9 to %7 : $*Int64
64+
%22 = tuple ()
65+
return %22 : $()
66+
}
67+
68+
// Test FindPhiStorageVisitor with a combination of
69+
// - valid storage for address_to_pointer %1
70+
// - invalid common definition between #MyStruct.i and #MyStruct.j
71+
//
72+
// Make sure that visiting the invalid common definition also
73+
// invalidates storage.
74+
//
75+
// CHECK-LABEL: @testStructPhiChained
76+
// CHECK: store
77+
// CHECK: INVALID
78+
sil hidden @testStructPhiChained : $@convention(thin) (@inout MyStruct, @inout Int64) -> () {
79+
bb0(%0 : $*MyStruct, %1 : $*Int64):
80+
cond_br undef, bb1, bb5
81+
82+
bb1:
83+
cond_br undef, bb2, bb3
84+
85+
bb2:
86+
%2 = address_to_pointer %1 : $*Int64 to $Builtin.RawPointer
87+
br bb4(%2 : $Builtin.RawPointer)
88+
89+
bb3:
90+
%3 = struct_element_addr %0 : $*MyStruct, #MyStruct.i
91+
%4 = address_to_pointer %3 : $*Int64 to $Builtin.RawPointer
92+
br bb4(%4 : $Builtin.RawPointer)
93+
94+
bb4(%6 : $Builtin.RawPointer) :
95+
br bb6(%6 : $Builtin.RawPointer)
96+
97+
bb5:
98+
%7 = struct_element_addr %0 : $*MyStruct, #MyStruct.j
99+
%8 = address_to_pointer %7 : $*Int64 to $Builtin.RawPointer
100+
br bb6(%8 : $Builtin.RawPointer)
101+
102+
bb6(%9 : $Builtin.RawPointer) :
103+
%10 = pointer_to_address %9 : $Builtin.RawPointer to $*Int64
104+
%11 = integer_literal $Builtin.Int64, 2
105+
%12 = struct $Int64 (%11 : $Builtin.Int64)
106+
store %12 to %10 : $*Int64
107+
%22 = tuple ()
108+
return %22 : $()
109+
}
110+
111+
struct _MyBridgeStorage {
112+
@_hasStorage var rawValue : Builtin.BridgeObject
113+
}
114+
115+
struct _MyArrayBuffer<T> {
116+
@_hasStorage var _storage : _MyBridgeStorage
117+
}
118+
119+
120+
struct MyArray<T> {
121+
@_hasStorage var _buffer : _MyArrayBuffer<T>
122+
}
123+
124+
// CHECK-LABEL: @arrayValue
125+
// CHECK: load [trivial] %{{.*}} : $*Builtin.Int64
126+
// CHECK: Unidentified %{{.*}} = ref_tail_addr [immutable] [[REF:%[0-9]+]] : $__ContiguousArrayStorageBase, $Int64
127+
// CHECK: load [trivial] %{{.*}} : $*Builtin.Int64
128+
// CHECK: Unidentified %{{.*}} = ref_tail_addr [immutable] [[REF]] : $__ContiguousArrayStorageBase, $Int64
129+
sil [ossa] @arrayValue : $@convention(thin) (@guaranteed MyArray<Int64>) -> Int64 {
130+
bb0(%0 : @guaranteed $MyArray<Int64>):
131+
%1 = integer_literal $Builtin.Word, 3
132+
%2 = integer_literal $Builtin.Word, 4
133+
%3 = integer_literal $Builtin.Int1, -1
134+
%4 = struct_extract %0 : $MyArray<Int64>, #MyArray._buffer
135+
%5 = struct_extract %4 : $_MyArrayBuffer<Int64>, #_MyArrayBuffer._storage
136+
%6 = struct_extract %5 : $_MyBridgeStorage, #_MyBridgeStorage.rawValue
137+
%7 = unchecked_ref_cast %6 : $Builtin.BridgeObject to $__ContiguousArrayStorageBase
138+
%8 = ref_tail_addr [immutable] %7 : $__ContiguousArrayStorageBase, $Int64
139+
%9 = index_addr %8 : $*Int64, %1 : $Builtin.Word
140+
%10 = struct_element_addr %9 : $*Int64, #Int64._value
141+
%11 = load [trivial] %10 : $*Builtin.Int64
142+
%12 = index_addr %8 : $*Int64, %2 : $Builtin.Word
143+
%13 = struct_element_addr %12 : $*Int64, #Int64._value
144+
%14 = load [trivial] %13 : $*Builtin.Int64
145+
%15 = builtin "sadd_with_overflow_Int64"(%11 : $Builtin.Int64, %14 : $Builtin.Int64, %3 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
146+
%16 = tuple_extract %15 : $(Builtin.Int64, Builtin.Int1), 0
147+
%17 = tuple_extract %15 : $(Builtin.Int64, Builtin.Int1), 1
148+
cond_fail %17 : $Builtin.Int1, "arithmetic overflow"
149+
%19 = struct $Int64 (%16 : $Builtin.Int64)
150+
return %19 : $Int64
151+
}

test/SILOptimizer/accessed_storage_analysis.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-sil-opt %s -accessed-storage-dump -enable-sil-verify-all -o /dev/null | %FileCheck %s
1+
// RUN: %target-sil-opt %s -accessed-storage-analysis-dump -enable-sil-verify-all -o /dev/null | %FileCheck %s
22

33
sil_stage canonical
44

0 commit comments

Comments
 (0)