[llvm] 774b957 - [SPIR-V] improve performance of Module Analysis stage in the part of processing "other instructions" (#76047)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 18 08:48:42 PST 2024
Author: Vyacheslav Levytskyy
Date: 2024-01-18T08:48:38-08:00
New Revision: 774b9577866239f577180fdd8b78159f0a5794a5
URL: https://github.com/llvm/llvm-project/commit/774b9577866239f577180fdd8b78159f0a5794a5
DIFF: https://github.com/llvm/llvm-project/commit/774b9577866239f577180fdd8b78159f0a5794a5.diff
LOG: [SPIR-V] improve performance of Module Analysis stage in the part of processing "other instructions" (#76047)
The goal of this PR is to fix an issue when Module Analysis stage is not
able to complete processing of a really big LLVM source:
https://github.com/llvm/llvm-project/issues/76048.
There is an example of a bulky LLVM source:
https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/test/SpecConstants/long-spec-const-composite.ll
Processing of this file with
`llc -mtriple=spirv64-unknown-unknown -O0 long-spec-const-composite.ll
-o long-spec-const-composite.spvt`
to produce SPIR-V output using LLVM SPIR-V backend takes too long, and
I've never been able to see it actually completes. After the patch from
this PR applied elapsed time for me is ~30 sec.
The fix changes underlying data structure to be `std::set` to trace
instructions with identical operands instead of the existing approach of
the `findSameInstrInMS()` function.
Added:
Modified:
llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 027e4c2b46d873..7222a93357b79f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -263,34 +263,6 @@ void SPIRVModuleAnalysis::processDefInstrs(const Module &M) {
[](const SPIRV::DTSortableEntry *E) { return E->getIsFunc(); }, true);
}
-// True if there is an instruction in the MS list with all the same operands as
-// the given instruction has (after the given starting index).
-// TODO: maybe it needs to check Opcodes too.
-static bool findSameInstrInMS(const MachineInstr &A,
- SPIRV::ModuleSectionType MSType,
- SPIRV::ModuleAnalysisInfo &MAI,
- unsigned StartOpIndex = 0) {
- for (const auto *B : MAI.MS[MSType]) {
- const unsigned NumAOps = A.getNumOperands();
- if (NumAOps != B->getNumOperands() || A.getNumDefs() != B->getNumDefs())
- continue;
- bool AllOpsMatch = true;
- for (unsigned i = StartOpIndex; i < NumAOps && AllOpsMatch; ++i) {
- if (A.getOperand(i).isReg() && B->getOperand(i).isReg()) {
- Register RegA = A.getOperand(i).getReg();
- Register RegB = B->getOperand(i).getReg();
- AllOpsMatch = MAI.getRegisterAlias(A.getMF(), RegA) ==
- MAI.getRegisterAlias(B->getMF(), RegB);
- } else {
- AllOpsMatch = A.getOperand(i).isIdenticalTo(B->getOperand(i));
- }
- }
- if (AllOpsMatch)
- return true;
- }
- return false;
-}
-
// Look for IDs declared with Import linkage, and map the corresponding function
// to the register defining that variable (which will usually be the result of
// an OpFunction). This lets us call externally imported functions using
@@ -319,15 +291,43 @@ void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI,
}
}
+using InstrSignature = SmallVector<size_t>;
+using InstrTraces = std::set<InstrSignature>;
+
+// Returns a representation of an instruction as a vector of MachineOperand
+// hash values, see llvm::hash_value(const MachineOperand &MO) for details.
+// This creates a signature of the instruction with the same content
+// that MachineOperand::isIdenticalTo uses for comparison.
+static InstrSignature instrToSignature(MachineInstr &MI,
+ SPIRV::ModuleAnalysisInfo &MAI) {
+ InstrSignature Signature;
+ for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
+ const MachineOperand &MO = MI.getOperand(i);
+ size_t h;
+ if (MO.isReg()) {
+ Register RegAlias = MAI.getRegisterAlias(MI.getMF(), MO.getReg());
+ // mimic llvm::hash_value(const MachineOperand &MO)
+ h = hash_combine(MO.getType(), (unsigned)RegAlias, MO.getSubReg(),
+ MO.isDef());
+ } else {
+ h = hash_value(MO);
+ }
+ Signature.push_back(h);
+ }
+ return Signature;
+}
+
// Collect the given instruction in the specified MS. We assume global register
// numbering has already occurred by this point. We can directly compare reg
// arguments when detecting duplicates.
static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI,
- SPIRV::ModuleSectionType MSType,
+ SPIRV::ModuleSectionType MSType, InstrTraces &IS,
bool Append = true) {
MAI.setSkipEmission(&MI);
- if (findSameInstrInMS(MI, MSType, MAI))
- return; // Found a duplicate, so don't add it.
+ InstrSignature MISign = instrToSignature(MI, MAI);
+ auto FoundMI = IS.insert(MISign);
+ if (!FoundMI.second)
+ return; // insert failed, so we found a duplicate; don't add it to MAI.MS
// No duplicates, so add it.
if (Append)
MAI.MS[MSType].push_back(&MI);
@@ -338,6 +338,7 @@ static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI,
// Some global instructions make reference to function-local ID regs, so cannot
// be correctly collected until these registers are globally numbered.
void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
+ InstrTraces IS;
for (auto F = M.begin(), E = M.end(); F != E; ++F) {
if ((*F).isDeclaration())
continue;
@@ -349,20 +350,20 @@ void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
continue;
const unsigned OpCode = MI.getOpcode();
if (OpCode == SPIRV::OpName || OpCode == SPIRV::OpMemberName) {
- collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames);
+ collectOtherInstr(MI, MAI, SPIRV::MB_DebugNames, IS);
} else if (OpCode == SPIRV::OpEntryPoint) {
- collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints);
+ collectOtherInstr(MI, MAI, SPIRV::MB_EntryPoints, IS);
} else if (TII->isDecorationInstr(MI)) {
- collectOtherInstr(MI, MAI, SPIRV::MB_Annotations);
+ collectOtherInstr(MI, MAI, SPIRV::MB_Annotations, IS);
collectFuncNames(MI, &*F);
} else if (TII->isConstantInstr(MI)) {
// Now OpSpecConstant*s are not in DT,
// but they need to be collected anyway.
- collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars);
+ collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS);
} else if (OpCode == SPIRV::OpFunction) {
collectFuncNames(MI, &*F);
} else if (OpCode == SPIRV::OpTypeForwardPointer) {
- collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, false);
+ collectOtherInstr(MI, MAI, SPIRV::MB_TypeConstVars, IS, false);
}
}
}
More information about the llvm-commits
mailing list