aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
diff options
context:
space:
mode:
authorNAKAMURA Takumi <geek4civic@gmail.com>2025-01-09 18:31:57 +0900
committerNAKAMURA Takumi <geek4civic@gmail.com>2025-01-09 18:33:27 +0900
commitdf025ebf872052c0761d44a3ef9b65e9675af8a8 (patch)
tree9b4e94583e2536546d6606270bcdf846c95e1ba2 /llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
parent4428c9d0b1344179f85a72e183a44796976521e3 (diff)
parentbdcf47e4bcb92889665825654bb80a8bbe30379e (diff)
downloadllvm-users/chapuni/cov/single/loop.zip
llvm-users/chapuni/cov/single/loop.tar.gz
llvm-users/chapuni/cov/single/loop.tar.bz2
Merge branch 'users/chapuni/cov/single/base' into users/chapuni/cov/single/loopusers/chapuni/cov/single/loop
Conflicts: clang/lib/CodeGen/CoverageMappingGen.cpp
Diffstat (limited to 'llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp')
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp372
1 files changed, 238 insertions, 134 deletions
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 6371c67..63adf54 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -216,102 +216,262 @@ void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
}
}
-// Collect MI which defines the register in the given machine function.
-static void collectDefInstr(Register Reg, const MachineFunction *MF,
- SPIRV::ModuleAnalysisInfo *MAI,
- SPIRV::ModuleSectionType MSType,
- bool DoInsert = true) {
- assert(MAI->hasRegisterAlias(MF, Reg) && "Cannot find register alias");
- MachineInstr *MI = MF->getRegInfo().getUniqueVRegDef(Reg);
- assert(MI && "There should be an instruction that defines the register");
- MAI->setSkipEmission(MI);
- if (DoInsert)
- MAI->MS[MSType].push_back(MI);
+// 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(const MachineInstr &MI,
+ SPIRV::ModuleAnalysisInfo &MAI,
+ bool UseDefReg) {
+ InstrSignature Signature{MI.getOpcode()};
+ for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
+ const MachineOperand &MO = MI.getOperand(i);
+ size_t h;
+ if (MO.isReg()) {
+ if (!UseDefReg && MO.isDef())
+ continue;
+ Register RegAlias = MAI.getRegisterAlias(MI.getMF(), MO.getReg());
+ if (!RegAlias.isValid()) {
+ LLVM_DEBUG({
+ dbgs() << "Unexpectedly, no global id found for the operand ";
+ MO.print(dbgs());
+ dbgs() << "\nInstruction: ";
+ MI.print(dbgs());
+ dbgs() << "\n";
+ });
+ report_fatal_error("All v-regs must have been mapped to global id's");
+ }
+ // 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;
}
-void SPIRVModuleAnalysis::collectGlobalEntities(
- const std::vector<SPIRV::DTSortableEntry *> &DepsGraph,
- SPIRV::ModuleSectionType MSType,
- std::function<bool(const SPIRV::DTSortableEntry *)> Pred,
- bool UsePreOrder = false) {
- DenseSet<const SPIRV::DTSortableEntry *> Visited;
- for (const auto *E : DepsGraph) {
- std::function<void(const SPIRV::DTSortableEntry *)> RecHoistUtil;
- // NOTE: here we prefer recursive approach over iterative because
- // we don't expect depchains long enough to cause SO.
- RecHoistUtil = [MSType, UsePreOrder, &Visited, &Pred,
- &RecHoistUtil](const SPIRV::DTSortableEntry *E) {
- if (Visited.count(E) || !Pred(E))
- return;
- Visited.insert(E);
-
- // Traversing deps graph in post-order allows us to get rid of
- // register aliases preprocessing.
- // But pre-order is required for correct processing of function
- // declaration and arguments processing.
- if (!UsePreOrder)
- for (auto *S : E->getDeps())
- RecHoistUtil(S);
-
- Register GlobalReg = Register::index2VirtReg(MAI.getNextID());
- bool IsFirst = true;
- for (auto &U : *E) {
- const MachineFunction *MF = U.first;
- Register Reg = U.second;
- MAI.setRegisterAlias(MF, Reg, GlobalReg);
- if (!MF->getRegInfo().getUniqueVRegDef(Reg))
- continue;
- collectDefInstr(Reg, MF, &MAI, MSType, IsFirst);
- IsFirst = false;
- if (E->getIsGV())
- MAI.GlobalVarList.push_back(MF->getRegInfo().getUniqueVRegDef(Reg));
- }
+bool SPIRVModuleAnalysis::isDeclSection(const MachineRegisterInfo &MRI,
+ const MachineInstr &MI) {
+ unsigned Opcode = MI.getOpcode();
+ switch (Opcode) {
+ case SPIRV::OpTypeForwardPointer:
+ // omit now, collect later
+ return false;
+ case SPIRV::OpVariable:
+ return static_cast<SPIRV::StorageClass::StorageClass>(
+ MI.getOperand(2).getImm()) != SPIRV::StorageClass::Function;
+ case SPIRV::OpFunction:
+ case SPIRV::OpFunctionParameter:
+ return true;
+ }
+ if (GR->hasConstFunPtr() && Opcode == SPIRV::OpUndef) {
+ Register DefReg = MI.getOperand(0).getReg();
+ for (MachineInstr &UseMI : MRI.use_instructions(DefReg)) {
+ if (UseMI.getOpcode() != SPIRV::OpConstantFunctionPointerINTEL)
+ continue;
+ // it's a dummy definition, FP constant refers to a function,
+ // and this is resolved in another way; let's skip this definition
+ assert(UseMI.getOperand(2).isReg() &&
+ UseMI.getOperand(2).getReg() == DefReg);
+ MAI.setSkipEmission(&MI);
+ return false;
+ }
+ }
+ return TII->isTypeDeclInstr(MI) || TII->isConstantInstr(MI) ||
+ TII->isInlineAsmDefInstr(MI);
+}
- if (UsePreOrder)
- for (auto *S : E->getDeps())
- RecHoistUtil(S);
- };
- RecHoistUtil(E);
+// This is a special case of a function pointer refering to a possibly
+// forward function declaration. The operand is a dummy OpUndef that
+// requires a special treatment.
+void SPIRVModuleAnalysis::visitFunPtrUse(
+ Register OpReg, InstrGRegsMap &SignatureToGReg,
+ std::map<const Value *, unsigned> &GlobalToGReg, const MachineFunction *MF,
+ const MachineInstr &MI) {
+ const MachineOperand *OpFunDef =
+ GR->getFunctionDefinitionByUse(&MI.getOperand(2));
+ assert(OpFunDef && OpFunDef->isReg());
+ // find the actual function definition and number it globally in advance
+ const MachineInstr *OpDefMI = OpFunDef->getParent();
+ assert(OpDefMI && OpDefMI->getOpcode() == SPIRV::OpFunction);
+ const MachineFunction *FunDefMF = OpDefMI->getParent()->getParent();
+ const MachineRegisterInfo &FunDefMRI = FunDefMF->getRegInfo();
+ do {
+ visitDecl(FunDefMRI, SignatureToGReg, GlobalToGReg, FunDefMF, *OpDefMI);
+ OpDefMI = OpDefMI->getNextNode();
+ } while (OpDefMI && (OpDefMI->getOpcode() == SPIRV::OpFunction ||
+ OpDefMI->getOpcode() == SPIRV::OpFunctionParameter));
+ // associate the function pointer with the newly assigned global number
+ Register GlobalFunDefReg = MAI.getRegisterAlias(FunDefMF, OpFunDef->getReg());
+ assert(GlobalFunDefReg.isValid() &&
+ "Function definition must refer to a global register");
+ MAI.setRegisterAlias(MF, OpReg, GlobalFunDefReg);
+}
+
+// Depth first recursive traversal of dependencies. Repeated visits are guarded
+// by MAI.hasRegisterAlias().
+void SPIRVModuleAnalysis::visitDecl(
+ const MachineRegisterInfo &MRI, InstrGRegsMap &SignatureToGReg,
+ std::map<const Value *, unsigned> &GlobalToGReg, const MachineFunction *MF,
+ const MachineInstr &MI) {
+ unsigned Opcode = MI.getOpcode();
+ DenseSet<Register> Deps;
+
+ // Process each operand of the instruction to resolve dependencies
+ for (const MachineOperand &MO : MI.operands()) {
+ if (!MO.isReg() || MO.isDef())
+ continue;
+ Register OpReg = MO.getReg();
+ // Handle function pointers special case
+ if (Opcode == SPIRV::OpConstantFunctionPointerINTEL &&
+ MRI.getRegClass(OpReg) == &SPIRV::pIDRegClass) {
+ visitFunPtrUse(OpReg, SignatureToGReg, GlobalToGReg, MF, MI);
+ continue;
+ }
+ // Skip already processed instructions
+ if (MAI.hasRegisterAlias(MF, MO.getReg()))
+ continue;
+ // Recursively visit dependencies
+ if (const MachineInstr *OpDefMI = MRI.getUniqueVRegDef(OpReg)) {
+ if (isDeclSection(MRI, *OpDefMI))
+ visitDecl(MRI, SignatureToGReg, GlobalToGReg, MF, *OpDefMI);
+ continue;
+ }
+ // Handle the unexpected case of no unique definition for the SPIR-V
+ // instruction
+ LLVM_DEBUG({
+ dbgs() << "Unexpectedly, no unique definition for the operand ";
+ MO.print(dbgs());
+ dbgs() << "\nInstruction: ";
+ MI.print(dbgs());
+ dbgs() << "\n";
+ });
+ report_fatal_error(
+ "No unique definition is found for the virtual register");
}
+
+ Register GReg;
+ bool IsFunDef = false;
+ if (TII->isSpecConstantInstr(MI)) {
+ GReg = Register::index2VirtReg(MAI.getNextID());
+ MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
+ } else if (Opcode == SPIRV::OpFunction ||
+ Opcode == SPIRV::OpFunctionParameter) {
+ GReg = handleFunctionOrParameter(MF, MI, GlobalToGReg, IsFunDef);
+ } else if (TII->isTypeDeclInstr(MI) || TII->isConstantInstr(MI) ||
+ TII->isInlineAsmDefInstr(MI)) {
+ GReg = handleTypeDeclOrConstant(MI, SignatureToGReg);
+ } else if (Opcode == SPIRV::OpVariable) {
+ GReg = handleVariable(MF, MI, GlobalToGReg);
+ } else {
+ LLVM_DEBUG({
+ dbgs() << "\nInstruction: ";
+ MI.print(dbgs());
+ dbgs() << "\n";
+ });
+ llvm_unreachable("Unexpected instruction is visited");
+ }
+ MAI.setRegisterAlias(MF, MI.getOperand(0).getReg(), GReg);
+ if (!IsFunDef)
+ MAI.setSkipEmission(&MI);
}
-// The function initializes global register alias table for types, consts,
-// global vars and func decls and collects these instruction for output
-// at module level. Also it collects explicit OpExtension/OpCapability
-// instructions.
-void SPIRVModuleAnalysis::processDefInstrs(const Module &M) {
- std::vector<SPIRV::DTSortableEntry *> DepsGraph;
+Register SPIRVModuleAnalysis::handleFunctionOrParameter(
+ const MachineFunction *MF, const MachineInstr &MI,
+ std::map<const Value *, unsigned> &GlobalToGReg, bool &IsFunDef) {
+ const Value *GObj = GR->getGlobalObject(MF, MI.getOperand(0).getReg());
+ assert(GObj && "Unregistered global definition");
+ const Function *F = dyn_cast<Function>(GObj);
+ if (!F)
+ F = dyn_cast<Argument>(GObj)->getParent();
+ assert(F && "Expected a reference to a function or an argument");
+ IsFunDef = !F->isDeclaration();
+ auto It = GlobalToGReg.find(GObj);
+ if (It != GlobalToGReg.end())
+ return It->second;
+ Register GReg = Register::index2VirtReg(MAI.getNextID());
+ GlobalToGReg[GObj] = GReg;
+ if (!IsFunDef)
+ MAI.MS[SPIRV::MB_ExtFuncDecls].push_back(&MI);
+ return GReg;
+}
- GR->buildDepsGraph(DepsGraph, TII, SPVDumpDeps ? MMI : nullptr);
+Register
+SPIRVModuleAnalysis::handleTypeDeclOrConstant(const MachineInstr &MI,
+ InstrGRegsMap &SignatureToGReg) {
+ InstrSignature MISign = instrToSignature(MI, MAI, false);
+ auto It = SignatureToGReg.find(MISign);
+ if (It != SignatureToGReg.end())
+ return It->second;
+ Register GReg = Register::index2VirtReg(MAI.getNextID());
+ SignatureToGReg[MISign] = GReg;
+ MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
+ return GReg;
+}
- collectGlobalEntities(
- DepsGraph, SPIRV::MB_TypeConstVars,
- [](const SPIRV::DTSortableEntry *E) { return !E->getIsFunc(); });
+Register SPIRVModuleAnalysis::handleVariable(
+ const MachineFunction *MF, const MachineInstr &MI,
+ std::map<const Value *, unsigned> &GlobalToGReg) {
+ MAI.GlobalVarList.push_back(&MI);
+ const Value *GObj = GR->getGlobalObject(MF, MI.getOperand(0).getReg());
+ assert(GObj && "Unregistered global definition");
+ auto It = GlobalToGReg.find(GObj);
+ if (It != GlobalToGReg.end())
+ return It->second;
+ Register GReg = Register::index2VirtReg(MAI.getNextID());
+ GlobalToGReg[GObj] = GReg;
+ MAI.MS[SPIRV::MB_TypeConstVars].push_back(&MI);
+ return GReg;
+}
+void SPIRVModuleAnalysis::collectDeclarations(const Module &M) {
+ InstrGRegsMap SignatureToGReg;
+ std::map<const Value *, unsigned> GlobalToGReg;
for (auto F = M.begin(), E = M.end(); F != E; ++F) {
MachineFunction *MF = MMI->getMachineFunction(*F);
if (!MF)
continue;
- // Iterate through and collect OpExtension/OpCapability instructions.
+ const MachineRegisterInfo &MRI = MF->getRegInfo();
+ unsigned PastHeader = 0;
for (MachineBasicBlock &MBB : *MF) {
for (MachineInstr &MI : MBB) {
- if (MI.getOpcode() == SPIRV::OpExtension) {
- // Here, OpExtension just has a single enum operand, not a string.
- auto Ext = SPIRV::Extension::Extension(MI.getOperand(0).getImm());
- MAI.Reqs.addExtension(Ext);
+ if (MI.getNumOperands() == 0)
+ continue;
+ unsigned Opcode = MI.getOpcode();
+ if (Opcode == SPIRV::OpFunction) {
+ if (PastHeader == 0) {
+ PastHeader = 1;
+ continue;
+ }
+ } else if (Opcode == SPIRV::OpFunctionParameter) {
+ if (PastHeader < 2)
+ continue;
+ } else if (PastHeader > 0) {
+ PastHeader = 2;
+ }
+
+ const MachineOperand &DefMO = MI.getOperand(0);
+ switch (Opcode) {
+ case SPIRV::OpExtension:
+ MAI.Reqs.addExtension(SPIRV::Extension::Extension(DefMO.getImm()));
MAI.setSkipEmission(&MI);
- } else if (MI.getOpcode() == SPIRV::OpCapability) {
- auto Cap = SPIRV::Capability::Capability(MI.getOperand(0).getImm());
- MAI.Reqs.addCapability(Cap);
+ break;
+ case SPIRV::OpCapability:
+ MAI.Reqs.addCapability(SPIRV::Capability::Capability(DefMO.getImm()));
MAI.setSkipEmission(&MI);
+ if (PastHeader > 0)
+ PastHeader = 2;
+ break;
+ default:
+ if (DefMO.isReg() && isDeclSection(MRI, MI) &&
+ !MAI.hasRegisterAlias(MF, DefMO.getReg()))
+ visitDecl(MRI, SignatureToGReg, GlobalToGReg, MF, MI);
}
}
}
}
-
- collectGlobalEntities(
- DepsGraph, SPIRV::MB_ExtFuncDecls,
- [](const SPIRV::DTSortableEntry *E) { return E->getIsFunc(); }, true);
}
// Look for IDs declared with Import linkage, and map the corresponding function
@@ -342,58 +502,6 @@ void SPIRVModuleAnalysis::collectFuncNames(MachineInstr &MI,
}
}
-// References to a function via function pointers generate virtual
-// registers without a definition. We are able to resolve this
-// reference using Globar Register info into an OpFunction instruction
-// and replace dummy operands by the corresponding global register references.
-void SPIRVModuleAnalysis::collectFuncPtrs() {
- for (auto &MI : MAI.MS[SPIRV::MB_TypeConstVars])
- if (MI->getOpcode() == SPIRV::OpConstantFunctionPointerINTEL)
- collectFuncPtrs(MI);
-}
-
-void SPIRVModuleAnalysis::collectFuncPtrs(MachineInstr *MI) {
- const MachineOperand *FunUse = &MI->getOperand(2);
- if (const MachineOperand *FunDef = GR->getFunctionDefinitionByUse(FunUse)) {
- const MachineInstr *FunDefMI = FunDef->getParent();
- assert(FunDefMI->getOpcode() == SPIRV::OpFunction &&
- "Constant function pointer must refer to function definition");
- Register FunDefReg = FunDef->getReg();
- Register GlobalFunDefReg =
- MAI.getRegisterAlias(FunDefMI->getMF(), FunDefReg);
- assert(GlobalFunDefReg.isValid() &&
- "Function definition must refer to a global register");
- Register FunPtrReg = FunUse->getReg();
- MAI.setRegisterAlias(MI->getMF(), FunPtrReg, GlobalFunDefReg);
- }
-}
-
-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.
@@ -401,7 +509,7 @@ static void collectOtherInstr(MachineInstr &MI, SPIRV::ModuleAnalysisInfo &MAI,
SPIRV::ModuleSectionType MSType, InstrTraces &IS,
bool Append = true) {
MAI.setSkipEmission(&MI);
- InstrSignature MISign = instrToSignature(MI, MAI);
+ InstrSignature MISign = instrToSignature(MI, MAI, true);
auto FoundMI = IS.insert(MISign);
if (!FoundMI.second)
return; // insert failed, so we found a duplicate; don't add it to MAI.MS
@@ -465,7 +573,7 @@ void SPIRVModuleAnalysis::processOtherInstrs(const Module &M) {
// Number registers in all functions globally from 0 onwards and store
// the result in global register alias table. Some registers are already
-// numbered in collectGlobalEntities.
+// numbered.
void SPIRVModuleAnalysis::numberRegistersGlobally(const Module &M) {
for (auto F = M.begin(), E = M.end(); F != E; ++F) {
if ((*F).isDeclaration())
@@ -1835,15 +1943,11 @@ bool SPIRVModuleAnalysis::runOnModule(Module &M) {
// Process type/const/global var/func decl instructions, number their
// destination registers from 0 to N, collect Extensions and Capabilities.
- processDefInstrs(M);
+ collectDeclarations(M);
// Number rest of registers from N+1 onwards.
numberRegistersGlobally(M);
- // Update references to OpFunction instructions to use Global Registers
- if (GR->hasConstFunPtr())
- collectFuncPtrs();
-
// Collect OpName, OpEntryPoint, OpDecorate etc, process other instructions.
processOtherInstrs(M);