Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ line upon naming the release. Refer to previous for appropriate section names.

- Fixed an optimizer crash when scalarizing an out-of-bounds vector access
[#8940](https://github.com/microsoft/DirectXShaderCompiler/issues/8940).
- Reduced GVN compile time on large shaders with many resource accesses by
limiting non-local memory dependency walks for calls once a result is known
to be unusable; generated code is unchanged.

### Upcoming Preview Release

Expand Down
51 changes: 42 additions & 9 deletions lib/Analysis/MemoryDependenceAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ static const unsigned int BlockScanLimit = 500;
// Limit on the number of memdep results to process.
static const unsigned int NumResultsLimit = 100;

// HLSL Change Begin - Limit non-local call dependency walks.
// Without a limit, a query for a read-only call whose clobbers are all on
// conditional paths walks every block back to the function entry, making GVN
// quadratic on large shaders with many inlined call sites. The limit is only
// applied once the walk has found a non-Def dependency (see
// getNonLocalCallDependency).
static const unsigned int CallBlockNumberLimit = 100;
// HLSL Change End

char MemoryDependenceAnalysis::ID = 0;

// Register this pass...
Expand Down Expand Up @@ -785,6 +794,18 @@ MemoryDependenceAnalysis::getNonLocalCallDependency(CallSite QueryCS) {

SmallPtrSet<BasicBlock*, 64> Visited;

// HLSL Change Begin - Track whether a non-Def dependency has been found.
auto IsNonDefDep = [](const MemDepResult &R) {
return !R.isNonLocal() && !R.isDef() && !R.isDirty();
};
bool FoundNonDefDep = false;
for (const NonLocalDepEntry &E : Cache)
if (IsNonDefDep(E.getResult())) {
FoundNonDefDep = true;
break;
}
// HLSL Change End

unsigned NumSortedEntries = Cache.size();
DEBUG(AssertSorted(Cache));

Expand Down Expand Up @@ -833,15 +854,26 @@ MemoryDependenceAnalysis::getNonLocalCallDependency(CallSite QueryCS) {
// Find out if this block has a local dependency for QueryInst.
MemDepResult Dep;

if (ScanPos != DirtyBB->begin()) {
Dep = getCallSiteDependencyFrom(QueryCS, isReadonlyCall,ScanPos, DirtyBB);
} else if (DirtyBB != &DirtyBB->getParent()->getEntryBlock()) {
// No dependence found. If this is the entry block of the function, it is
// a clobber, otherwise it is unknown.
Dep = MemDepResult::getNonLocal();
} else {
Dep = MemDepResult::getNonFuncLocal();
}
// HLSL Change Begin - Once the walk has visited too many blocks and has
// already found a dependency that is not a Def (a clobber or unknown),
// stop scanning and conservatively mark this and any remaining blocks
// Unknown. Such a result already cannot prove the query redundant, so
// scanning further only costs compile time. Unknown is not NonLocal, so
// predecessors are not added to the worklist.
if (FoundNonDefDep && Visited.size() > CallBlockNumberLimit) {
Dep = MemDepResult::getUnknown();
} else
// HLSL Change End
if (ScanPos != DirtyBB->begin()) {
Dep = getCallSiteDependencyFrom(QueryCS, isReadonlyCall, ScanPos,
DirtyBB);
} else if (DirtyBB != &DirtyBB->getParent()->getEntryBlock()) {
// No dependence found. If this is the entry block of the function, it
// is a clobber, otherwise it is unknown.
Dep = MemDepResult::getNonLocal();
} else {
Dep = MemDepResult::getNonFuncLocal();
}

// If we had a dirty entry for the block, update it. Otherwise, just add
// a new entry.
Expand All @@ -853,6 +885,7 @@ MemoryDependenceAnalysis::getNonLocalCallDependency(CallSite QueryCS) {
// If the block has a dependency (i.e. it isn't completely transparent to
// the value), remember the association!
if (!Dep.isNonLocal()) {
FoundNonDefDep |= IsNonDefDep(Dep); // HLSL Change
// Keep the ReverseNonLocalDeps map up to date so we can efficiently
// update this when we remove instructions.
if (Instruction *Inst = Dep.getInst())
Expand Down
Loading
Loading