Skip to content

Commit 462df6c

Browse files
committed
Cleanup/fix the loop access summary in AccessEnforcementOpts.
Reuse AccessStorageAnalysis to summarize accesses. Don't ignore call sites in loops. Don't consider a read access in a loop to conflict with a read outside. Use the unidentified access flag from the analysis. Remove extraneous code, some of which was unreachable. General cleanup.
1 parent dfc2d47 commit 462df6c

File tree

3 files changed

+72
-88
lines changed

3 files changed

+72
-88
lines changed

lib/SILOptimizer/Analysis/AccessedStorageAnalysis.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,16 @@ transformCalleeStorage(const StorageAccessInfo &storage,
258258
}
259259
// If the argument can't be transformed, demote it to an unidentified
260260
// access.
261+
//
262+
// This is an untested bailout. It is only reachable if the call graph
263+
// contains an edge that getCallerArg is unable to analyze OR if
264+
// findAccessedStorageNonNested returns an invalid SILValue, which won't
265+
// pass SIL verification.
266+
//
267+
// FIXME: In case argVal is invalid, support Unidentified access for invalid
268+
// values. This would also be useful for partially invalidating results.
261269
return StorageAccessInfo(
262-
AccessedStorage(storage.getValue(), AccessedStorage::Unidentified),
263-
storage);
270+
AccessedStorage(argVal, AccessedStorage::Unidentified), storage);
264271
}
265272
case AccessedStorage::Nested:
266273
llvm_unreachable("Unexpected nested access");

lib/SILOptimizer/Transforms/AccessEnforcementOpts.cpp

Lines changed: 34 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ using DenseAccessSet = llvm::SmallSetVector<BeginAccessInst *, 4>;
149149
struct RegionState {
150150
DenseAccessSet inScopeConflictFreeAccesses;
151151
DenseAccessSet outOfScopeConflictFreeAccesses;
152-
bool unidentifiedAccess = false;
153152

154153
public:
155154
RegionState(unsigned size) {
@@ -161,7 +160,6 @@ struct RegionState {
161160
void reset() {
162161
inScopeConflictFreeAccesses.clear();
163162
outOfScopeConflictFreeAccesses.clear();
164-
unidentifiedAccess = false;
165163
}
166164

167165
const DenseAccessSet &getInScopeAccesses() {
@@ -224,7 +222,7 @@ class AccessConflictAndMergeAnalysis {
224222
using AccessMap = llvm::SmallDenseMap<BeginAccessInst *, AccessInfo, 32>;
225223
using AccessedStorageSet = llvm::SmallDenseSet<AccessedStorage, 8>;
226224
using LoopRegionToAccessedStorage =
227-
llvm::SmallDenseMap<unsigned, AccessedStorageSet>;
225+
llvm::SmallDenseMap<unsigned, AccessedStorageResult>;
228226
using RegionIDToLocalStateMap = llvm::DenseMap<unsigned, RegionState>;
229227
// Instruction pairs we can merge from dominating instruction to dominated
230228
using MergeablePairs =
@@ -299,15 +297,10 @@ class AccessConflictAndMergeAnalysis {
299297

300298
void visitMayRelease(SILInstruction *instr, RegionState &state);
301299

302-
void mergePredAccesses(unsigned regionID,
303-
RegionIDToLocalStateMap &localRegionStates);
300+
RegionState &mergePredAccesses(unsigned regionID,
301+
RegionIDToLocalStateMap &localRegionStates);
304302

305-
void detectConflictsInLoop(LoopRegion *loopRegion,
306-
RegionIDToLocalStateMap &localRegionStates,
307-
LoopRegionToAccessedStorage &accessSetsOfRegions);
308-
309-
void localDataFlowInBlock(LoopRegion *bbRegion,
310-
RegionIDToLocalStateMap &localRegionStates);
303+
void localDataFlowInBlock(RegionState &state, SILBasicBlock *bb);
311304

312305
private:
313306
void recordInScopeConflicts(RegionState &state,
@@ -369,9 +362,7 @@ void AccessConflictAndMergeAnalysis::recordUnknownConflict(RegionState &state) {
369362
LLVM_DEBUG(llvm::dbgs() << " may conflict with:\n"; accessInfo.dump());
370363
});
371364
// Clear data flow.
372-
state.inScopeConflictFreeAccesses.clear();
373-
state.outOfScopeConflictFreeAccesses.clear();
374-
// FIXME!!!: call reset() after removing RegionState.unidentifiedAccess.
365+
state.reset();
375366
}
376367

377368
// Update data flow `state` by removing accesses that conflict with the
@@ -495,31 +486,16 @@ void AccessConflictAndMergeAnalysis::analyze() {
495486
RegionIDToLocalStateMap localRegionStates;
496487
// This is RPO order of the sub-regions
497488
for (auto subID : region->getSubregions()) {
498-
auto *subRegion = LRFI->getRegion(subID);
499-
// testIrreducibleGraph2 in test/SILOptimizer/access_enforcement_opts:
500-
// If the sub-region is the source of a previously visited backedge,
501-
// Then the in-state is an empty set.
502-
bool disableCrossBlock = false;
503-
if (localRegionStates.find(subID) != localRegionStates.end())
504-
// Irreducible loop - we already set the predecessor to empty set
505-
disableCrossBlock = true;
506-
else
507-
mergePredAccesses(subID, localRegionStates);
489+
RegionState &state = mergePredAccesses(subID, localRegionStates);
508490

491+
auto *subRegion = LRFI->getRegion(subID);
509492
if (subRegion->isBlock()) {
510-
localDataFlowInBlock(subRegion, localRegionStates);
493+
localDataFlowInBlock(state, subRegion->getBlock());
511494
} else {
512495
assert(subRegion->isLoop() && "Expected a loop sub-region");
513-
detectConflictsInLoop(subRegion, localRegionStates,
514-
accessSetsOfRegions);
515-
}
516-
// After doing the control flow on the region, and as mentioned above,
517-
// the sub-region is the source of a previously visited backedge,
518-
// we want to remove the merging candidates from its final state
519-
if (disableCrossBlock) {
520-
// Clear-out the out state: this is risky irreducible control flow
521-
// Only in-block conflict and merging is allowed
522-
localRegionStates.find(subID)->getSecond().reset();
496+
497+
const AccessedStorageResult &loopStorage = accessSetsOfRegions[subID];
498+
recordConflicts(state, loopStorage);
523499
}
524500
}
525501
}
@@ -572,33 +548,33 @@ void AccessConflictAndMergeAnalysis::propagateAccessSetsBottomUp(
572548
const llvm::SmallVector<unsigned, 16> &worklist) {
573549
for (unsigned regionID : reverse(worklist)) {
574550
auto *region = LRFI->getRegion(regionID);
575-
assert(regionToStorageMap.find(regionID) == regionToStorageMap.end() &&
576-
"Should not process a region twice");
577-
AccessedStorageSet &accessedStorageSet = regionToStorageMap[regionID];
551+
auto iterAndInserted =
552+
regionToStorageMap.try_emplace(regionID, AccessedStorageResult());
553+
assert(iterAndInserted.second && "Should not process a region twice");
554+
AccessedStorageResult &accessResult = iterAndInserted.first->second;
578555
for (auto subID : region->getSubregions()) {
579556
auto *subRegion = LRFI->getRegion(subID);
580557
if (subRegion->isLoop()) {
581558
// propagate access sets bottom-up from nested loops.
582-
auto subRegionStorageIt = regionToStorageMap.find(subID);
583-
assert(subRegionStorageIt != regionToStorageMap.end() &&
584-
"Should have processed sub-region");
585-
for (auto storage : subRegionStorageIt->getSecond()) {
586-
accessedStorageSet.insert(storage);
587-
}
559+
auto subRegionResultIter = regionToStorageMap.find(subID);
560+
assert(subRegionResultIter != regionToStorageMap.end()
561+
&& "Should have processed sub-region");
562+
accessResult.mergeFrom(subRegionResultIter->second);
588563
} else {
589564
assert(subRegion->isBlock() && "Expected a block region");
590565
auto *bb = subRegion->getBlock();
591566
for (auto &instr : *bb) {
592-
if (auto *beginAccess = dyn_cast<BeginAccessInst>(&instr)) {
593-
const AccessedStorage &storage =
594-
findAccessedStorageNonNested(beginAccess->getSource());
595-
accessedStorageSet.insert(storage);
596-
}
597-
if (auto *beginAccess = dyn_cast<BeginUnpairedAccessInst>(&instr)) {
598-
const AccessedStorage &storage =
599-
findAccessedStorageNonNested(beginAccess->getSource());
600-
accessedStorageSet.insert(storage);
567+
if (auto fullApply = FullApplySite::isa(&instr)) {
568+
FunctionAccessedStorage calleeAccess;
569+
// Instead of calling getCallSiteEffects, call getCalleeEffects and
570+
// merge ourselves to avoid an extra merge step.
571+
ASA->getCalleeEffects(calleeAccess, fullApply);
572+
accessResult.mergeFrom(calleeAccess.getResult());
573+
continue;
601574
}
575+
// FIXME: Treat may-release conservatively in the anlysis itself by
576+
// adding a mayRelease flag, in addition to the unidentified flag.
577+
accessResult.analyzeInstruction(&instr);
602578
}
603579
}
604580
}
@@ -633,7 +609,6 @@ void AccessConflictAndMergeAnalysis::visitBeginAccess(
633609
// Get the Access info:
634610
auto &beginAccessInfo = result.getAccessInfo(beginAccess);
635611
if (beginAccessInfo.getKind() == AccessedStorage::Unidentified) {
636-
state.unidentifiedAccess = true;
637612
recordUnknownConflict(state);
638613
return;
639614
}
@@ -752,14 +727,13 @@ void AccessConflictAndMergeAnalysis::mergeAccessSet(
752727
void AccessConflictAndMergeAnalysis::mergeState(RegionState &state,
753728
const RegionState &otherState,
754729
bool isInitialized) {
755-
state.unidentifiedAccess |= otherState.unidentifiedAccess;
756730
mergeAccessSet(state.inScopeConflictFreeAccesses,
757731
otherState.inScopeConflictFreeAccesses, isInitialized);
758732
mergeAccessSet(state.outOfScopeConflictFreeAccesses,
759733
otherState.outOfScopeConflictFreeAccesses, isInitialized);
760734
}
761735

762-
void AccessConflictAndMergeAnalysis::mergePredAccesses(
736+
RegionState &AccessConflictAndMergeAnalysis::mergePredAccesses(
763737
unsigned regionID, RegionIDToLocalStateMap &localRegionStates) {
764738
auto regionStateIterAndInserted = localRegionStates.try_emplace(
765739
regionID, RegionState(result.accessMap.size()));
@@ -780,42 +754,16 @@ void AccessConflictAndMergeAnalysis::mergePredAccesses(
780754
if (predStateIter == localRegionStates.end()) {
781755
// Backedge / irreducable control flow - bail
782756
state.reset();
783-
return;
757+
break;
784758
}
785759
mergeState(state, predStateIter->second, isInitialized);
786760
isInitialized = true;
787761
}
762+
return state;
788763
}
789764

790-
void AccessConflictAndMergeAnalysis::detectConflictsInLoop(
791-
LoopRegion *loopRegion, RegionIDToLocalStateMap &localRegionStates,
792-
LoopRegionToAccessedStorage &accessSetsOfRegions) {
793-
assert(loopRegion->isLoop() && "Expected a loop region");
794-
auto loopID = loopRegion->getID();
795-
RegionState &state = localRegionStates.find(loopID)->getSecond();
796-
797-
// FIXME!!!: just call recordConflicts instead one loop summaries are fixed.
798-
if (state.unidentifiedAccess) {
799-
recordUnknownConflict(state);
800-
return;
801-
}
802-
AccessedStorageSet &loopStorage =
803-
accessSetsOfRegions.find(loopID)->getSecond();
804-
for (const AccessedStorage &currStorage : loopStorage) {
805-
// FIXME: The access kind will be part of the loop summary soon.
806-
recordInScopeConflicts(state, currStorage, SILAccessKind::Modify);
807-
808-
removeConflicts(state.inScopeConflictFreeAccesses, currStorage);
809-
810-
removeConflicts(state.outOfScopeConflictFreeAccesses, currStorage);
811-
}
812-
}
813-
814-
void AccessConflictAndMergeAnalysis::localDataFlowInBlock(
815-
LoopRegion *bbRegion, RegionIDToLocalStateMap &localRegionStates) {
816-
assert(bbRegion->isBlock() && "Expected a block region");
817-
auto *bb = bbRegion->getBlock();
818-
RegionState &state = localRegionStates.find(bbRegion->getID())->getSecond();
765+
void AccessConflictAndMergeAnalysis::localDataFlowInBlock(RegionState &state,
766+
SILBasicBlock *bb) {
819767
for (auto &instr : *bb) {
820768
if (auto *beginAccess = dyn_cast<BeginAccessInst>(&instr)) {
821769
visitBeginAccess(beginAccess, state);

test/SILOptimizer/access_enforcement_opts.sil

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,3 +1709,32 @@ bb0:
17091709
%10 = tuple ()
17101710
return %10 : $()
17111711
}
1712+
1713+
// Test transformCalleeStorage when the callee storage is an Argument
1714+
// and the caller storage is an Argument at a different position.
1715+
//
1716+
// CHECK-LABEL: sil @testTransformArgumentCaller : $@convention(thin) (Int64, @guaranteed { var Int64 }, @guaranteed { var Int64 }) -> Int64 {
1717+
// CHECK: begin_access [read] [dynamic] [no_nested_conflict]
1718+
// CHECK-LABEL: } // end sil function 'testTransformArgumentCaller'
1719+
sil @testTransformArgumentCaller : $@convention(thin) (Int64, @guaranteed { var Int64 }, @guaranteed { var Int64 }) -> Int64 {
1720+
bb0(%0 : $Int64, %1 : ${ var Int64 }, %2 : ${ var Int64 }):
1721+
%boxadr = project_box %1 : $ { var Int64 }, 0
1722+
%access = begin_access [read] [dynamic] [no_nested_conflict] %boxadr : $*Int64
1723+
%f = function_ref @testTransformArgumentCallee : $@convention(thin) (@guaranteed { var Int64 }) -> Int64
1724+
%call = apply %f(%2) : $@convention(thin) (@guaranteed { var Int64 }) -> Int64
1725+
store %0 to %access : $*Int64
1726+
end_access %access : $*Int64
1727+
return %call : $Int64
1728+
}
1729+
1730+
// CHECK-LABEL: sil @testTransformArgumentCallee : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 {
1731+
// CHECK: begin_access [read] [dynamic] [no_nested_conflict]
1732+
// CHECK-LABEL: } // end sil function 'testTransformArgumentCallee'
1733+
sil @testTransformArgumentCallee : $@convention(thin) (@guaranteed { var Int64 }) -> Int64 {
1734+
bb0(%0 : ${ var Int64 }):
1735+
%boxadr = project_box %0 : $ { var Int64 }, 0
1736+
%access = begin_access [read] [dynamic] [no_nested_conflict] %boxadr : $*Int64
1737+
%val = load %access : $*Int64
1738+
end_access %access : $*Int64
1739+
return %val : $Int64
1740+
}

0 commit comments

Comments
 (0)