Skip to content

Commit 0d3c614

Browse files
committed
Remove RefElementAddr field from AccessedStorage.
- code simplification critical for comprehension - substantially improves the overhead of AccessedStorage comparison - as a side effect improves precision of analysis in some cases AccessedStorage is meant to be an immutable value type that identifies a storage location with minimal representation. It is used in many global interprocedural data structures. The RefElementAddress instruction that it was derived from does not contribute to the uniqueness of the storage location. It doesn't belong here. It was being used to create a ProjectionPath, which is an extremely inneficient way to compare access paths. Just delete all the code related to that extra field.
1 parent 8cc013e commit 0d3c614

File tree

4 files changed

+31
-46
lines changed

4 files changed

+31
-46
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -29,43 +29,27 @@ inline bool accessKindMayConflict(SILAccessKind a, SILAccessKind b) {
2929
}
3030

3131
/// Represents the identity of a stored class property as a combination
32-
/// of a base, projection and projection path.
33-
/// we pre-compute the base and projection path, even though we can
34-
/// lazily do so, because it is more expensive otherwise
35-
/// We lazily compute the projection path,
36-
/// In the rare occasions we need it, because of Its destructor and
37-
/// its non-trivial copy constructor
32+
/// of a base and projection.
3833
class ObjectProjection {
3934
SILValue object;
40-
const RefElementAddrInst *REA;
4135
Projection proj;
4236

4337
public:
44-
ObjectProjection(const RefElementAddrInst *REA)
45-
: object(stripBorrow(REA->getOperand())), REA(REA),
46-
proj(Projection(REA)) {}
47-
48-
ObjectProjection(SILValue object, const RefElementAddrInst *REA)
49-
: object(object), REA(REA), proj(Projection(REA)) {}
50-
51-
const RefElementAddrInst *getInstr() const { return REA; }
38+
ObjectProjection(SILValue object, const Projection &projection)
39+
: object(object), proj(projection) {
40+
assert(object->getType().isObject());
41+
}
5242

5343
SILValue getObject() const { return object; }
5444

5545
const Projection &getProjection() const { return proj; }
5646

57-
const Optional<ProjectionPath> getProjectionPath() const {
58-
return ProjectionPath::getProjectionPath(stripBorrow(REA->getOperand()),
59-
REA);
60-
}
61-
6247
bool operator==(const ObjectProjection &other) const {
63-
return getObject() == other.getObject() &&
64-
getProjection() == other.getProjection();
48+
return object == other.object && proj == other.proj;
6549
}
6650

6751
bool operator!=(const ObjectProjection &other) const {
68-
return !operator==(other);
52+
return object != other.object || proj != other.proj;
6953
}
7054
};
7155

@@ -189,8 +173,8 @@ class AccessedStorage {
189173

190174
AccessedStorage(SILValue base, Kind kind);
191175

192-
AccessedStorage(SILValue object, const RefElementAddrInst *REA)
193-
: objProj(object, REA) {
176+
AccessedStorage(SILValue object, Projection projection)
177+
: objProj(object, projection) {
194178
initKind(Class);
195179
}
196180

@@ -295,20 +279,20 @@ class AccessedStorage {
295279
if (isUniquelyIdentified() && other.isUniquelyIdentified()) {
296280
return !hasIdenticalBase(other);
297281
}
298-
if (getKind() != Class || other.getKind() != Class) {
299-
return false;
300-
}
301-
if (getObjectProjection().getProjection() ==
302-
other.getObjectProjection().getProjection()) {
303-
return false;
304-
}
305-
auto projPath = getObjectProjection().getProjectionPath();
306-
auto otherProjPath = other.getObjectProjection().getProjectionPath();
307-
if (!projPath.hasValue() || !otherProjPath.hasValue()) {
282+
if (getKind() != Class || other.getKind() != Class)
283+
// At least one side is an Argument or Yield, or is unidentified.
308284
return false;
285+
286+
// Classes are not uniquely identified by their base. However, if the
287+
// underling objects have identical types and distinct property indices then
288+
// they are distinct storage locations.
289+
auto &proj = getObjectProjection();
290+
auto &otherProj = other.getObjectProjection();
291+
if (proj.getObject()->getType() == otherProj.getObject()->getType()
292+
&& proj.getProjection() != otherProj.getProjection()) {
293+
return true;
309294
}
310-
return projPath.getValue().hasNonEmptySymmetricDifference(
311-
otherProjPath.getValue());
295+
return false;
312296
}
313297

314298
/// Returns the ValueDecl for the underlying storage, if it can be

lib/SIL/MemAccessUtils.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,12 @@ AccessedStorage::AccessedStorage(SILValue base, Kind kind) {
101101
case Class: {
102102
// Do a best-effort to find the identity of the object being projected
103103
// from. It is OK to be unsound here (i.e. miss when two ref_element_addrs
104-
// actually refer the same address) because these will be dynamically
105-
// checked.
104+
// actually refer the same address) because these addresses will be
105+
// dynamically checked, and static analysis will be sufficiently
106+
// conservative given that classes are not "uniquely identified".
106107
auto *REA = cast<RefElementAddrInst>(base);
107-
objProj = ObjectProjection(REA);
108+
SILValue Object = stripBorrow(REA->getOperand());
109+
objProj = ObjectProjection(Object, Projection(REA));
108110
}
109111
}
110112
}

lib/SILOptimizer/Analysis/AccessedStorageAnalysis.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,9 @@ transformCalleeStorage(const StorageAccessInfo &storage,
238238
if (auto *arg = dyn_cast<SILFunctionArgument>(obj)) {
239239
SILValue argVal = getCallerArg(fullApply, arg->getIndex());
240240
if (argVal) {
241-
auto *instr = storage.getObjectProjection().getInstr();
241+
auto &proj = storage.getObjectProjection().getProjection();
242242
// Remap the argument source value and inherit the old storage info.
243-
return StorageAccessInfo(AccessedStorage(argVal, instr), storage);
243+
return StorageAccessInfo(AccessedStorage(argVal, proj), storage);
244244
}
245245
}
246246
// Otherwise, continue to reference the value in the callee because we don't

test/SILOptimizer/access_enforcement_opts.sil

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,18 +1352,17 @@ class RefElemClass {
13521352
init()
13531353
}
13541354

1355-
// Merge access overlapping scopes. Scope nesting does not need to be
1356-
// preserved unless the nested accesses are to identical storage.
1355+
// Merge access overlapping scopes.
13571356
//
13581357
// CHECK-LABEL: sil @ref_elem_c : $@convention(thin) (RefElemClass) -> () {
13591358
// CHECK: [[GLOBAL:%.*]] = global_addr @globalX : $*X
1360-
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
1359+
// CHECK-NEXT: [[BEGIN:%.*]] = begin_access [read] [dynamic] [no_nested_conflict] [[GLOBAL]] : $*X
13611360
// CHECK-NEXT: load [[BEGIN]] : $*X
13621361
// CHECK-NEXT: end_access [[BEGIN]] : $*X
13631362
// CHECK-NEXT: [[REFX:%.*]] = ref_element_addr %0 : $RefElemClass, #RefElemClass.x
13641363
// CHECK-NEXT: [[REFY:%.*]] = ref_element_addr %0 : $RefElemClass, #RefElemClass.y
13651364
// CHECK-NEXT: [[BEGINX:%.*]] = begin_access [modify] [dynamic] [[REFX]] : $*BitfieldOne
1366-
// CHECK: [[BEGINY:%.*]] = begin_access [modify] [dynamic] [[REFY]] : $*Int32
1365+
// CHECK: [[BEGINY:%.*]] = begin_access [modify] [dynamic] [no_nested_conflict] [[REFY]] : $*Int32
13671366
// CHECK: end_access [[BEGINX]] : $*BitfieldOne
13681367
// CHECK-NEXT: end_access [[BEGINY]] : $*Int32
13691368
// CHECK-LABEL: } // end sil function 'ref_elem_c'

0 commit comments

Comments
 (0)