[llvm] [SPIRV] Emit NonSemantic DebugValue (PR #224158)

Diego Novillo via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 22 06:46:55 PDT 2026


================
@@ -1533,12 +1904,104 @@ SPIRVNonSemanticDebugHandler::resolveDebugLocTarget(const MachineInstr *MI) {
     // above skips it.
     MI = findAdjacentEmittedInstruction(MI, MAI, true);
     assert(MI && "Merge instruction must be followed by a terminator");
+    // The assert is compiled out in a release build, and returning MI there
+    // would give an engaged optional holding null.
+    if (!MI)
+      return std::nullopt;
   }
 
   return MI;
 }
 
-void SPIRVNonSemanticDebugHandler::emitDebugScopeForInstruction(
+void SPIRVNonSemanticDebugHandler::resolveDebugRecord(
+    const MachineInstr &MI, const MachineInstr *LastEmitted) {
+  SPIRV::ModuleAnalysisInfo &MAI = *CurrentMAI;
+  const MachineFunction &MF = *MI.getMF();
+
+  // A record sits at its own position, except in a merge region: nothing may
+  // be emitted between a merge and its terminator, so it belongs ahead of the
+  // merge.
+  const MachineInstr *Anchor =
+      LastEmitted && isMergeInstruction(LastEmitted->getOpcode()) ? LastEmitted
+                                                                  : &MI;
+
+  // A #dbg_declare reaches Machine IR as an indirect DBG_VALUE. Its storage is
+  // an OpVariable in the entry block, so it is in the output by the time any
+  // record naming it is reached.
+  if (std::optional<Register> LocReg = getDebugDeclareStorageReg(MI)) {
+    MCRegister StorageReg = MAI.getRegisterAlias(&MF, *LocReg);
+    if (StorageReg.isValid())
+      placeRecord(SPIRV::NonSemanticExtInst::DebugDeclare, MI, StorageReg,
+                  Anchor);
+    return;
+  }
+
+  // A constant assignment names the id emitted for it at module scope, which
+  // every function body follows.
+  if (std::optional<MCRegister> ConstReg = getConstantValueReg(MI)) {
+    placeRecord(SPIRV::NonSemanticExtInst::DebugValue, MI, *ConstReg, Anchor);
+    return;
+  }
+
+  std::optional<Register> ValReg = getDebugValueReg(MI);
+  if (!ValReg)
+    return;
+  MCRegister ValueReg = MAI.getRegisterAlias(&MF, *ValReg);
+  if (!ValueReg.isValid())
+    return;
+
+  // NonSemantic.Shader.DebugInfo states that "Forward references are not
+  // allowed, to be compliant with SPV_KHR_non_semantic_info", so the id has to
+  // be in the output already. A module section precedes every function body.
+  //
+  // For anything else, SPIR-V requires a definition in a function block to
+  // dominate a non-phi use, and requires a block to precede every block it
+  // dominates, so a dominating definition is also one already printed. A
+  // record naming a definition that does not dominate it is dropped.
+  const MachineInstr *Def = MF.getRegInfo().getUniqueVRegDef(*ValReg);
+  if (ModuleScopeIds.contains(ValueReg) ||
+      (isEmitted(Def, MAI) && DomTree->dominates(Def, &MI)))
+    placeRecord(SPIRV::NonSemanticExtInst::DebugValue, MI, ValueReg, Anchor);
+}
+
+void SPIRVNonSemanticDebugHandler::analyzeDebugRecords(
+    const MachineFunction &MF) {
+  assert(CurrentMAI && "CurrentMAI must be set");
+
+  for (const MachineBasicBlock &MBB : MF) {
+    const MachineInstr *LastEmitted = nullptr;
+    for (const MachineInstr &MI : MBB) {
+      if (MI.isDebugValueLike()) {
+        if (!DomTree) {
----------------
dnovillo wrote:

Yup. Done.

https://github.com/llvm/llvm-project/pull/224158


More information about the llvm-commits mailing list