[llvm] [SPIRV] Emitting DebugSource, DebugCompileUnit (PR #97558)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 5 05:00:30 PDT 2024
================
@@ -0,0 +1,148 @@
+#include "MCTargetDesc/SPIRVBaseInfo.h"
+#include "SPIRVGlobalRegistry.h"
+#include "SPIRVRegisterInfo.h"
+#include "SPIRVTargetMachine.h"
+#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/IR/DebugInfoMetadata.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/Support/Casting.h"
+
+namespace llvm {
+struct SPIRVEmitNonSemanticDI : public MachineFunctionPass {
+ static char ID;
+ SPIRVTargetMachine *TM;
+ SPIRVEmitNonSemanticDI(SPIRVTargetMachine *TM);
+ SPIRVEmitNonSemanticDI();
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+private:
+ bool IsGlobalDIEmitted = false;
+ bool emitGlobalDI(MachineFunction &MF);
+};
+
+void initializeSPIRVEmitNonSemanticDIPass(PassRegistry &);
+
+FunctionPass *createSPIRVEmitNonSemanticDIPass(SPIRVTargetMachine *TM) {
+ return new SPIRVEmitNonSemanticDI(TM);
+}
+} // namespace llvm
+
+using namespace llvm;
+
+INITIALIZE_PASS(SPIRVEmitNonSemanticDI, "spirv-nonsemantic-debug-info",
+ "SPIRV NonSemantic.Shader.DebugInfo.100 emitter", false, false)
+
+char SPIRVEmitNonSemanticDI::ID = 0;
+
+SPIRVEmitNonSemanticDI::SPIRVEmitNonSemanticDI(SPIRVTargetMachine *TM)
+ : MachineFunctionPass(ID), TM(TM) {
+ initializeSPIRVEmitNonSemanticDIPass(*PassRegistry::getPassRegistry());
+}
+
+SPIRVEmitNonSemanticDI::SPIRVEmitNonSemanticDI() : MachineFunctionPass(ID) {
+ initializeSPIRVEmitNonSemanticDIPass(*PassRegistry::getPassRegistry());
+}
+
+bool SPIRVEmitNonSemanticDI::emitGlobalDI(MachineFunction &MF) {
+ MachineModuleInfo &MMI = MF.getMMI();
+ const Module *M = MMI.getModule();
+ NamedMDNode *DbgCu = M->getNamedMetadata("llvm.dbg.cu");
+ if (!DbgCu) {
+ return false;
+ }
+ std::string FilePath;
+ unsigned SourceLanguage;
+ unsigned NumOp = DbgCu->getNumOperands();
+ if (NumOp) {
+ if (const auto *CompileUnit =
+ dyn_cast<DICompileUnit>(DbgCu->getOperand(0))) {
+ DIFile *File = CompileUnit->getFile();
+ FilePath = ((File->getDirectory() + "/" + File->getFilename())).str();
+ SourceLanguage = CompileUnit->getSourceLanguage();
+ }
+ }
+ NamedMDNode *ModuleFlags = M->getNamedMetadata("llvm.module.flags");
+ int64_t DwarfVersion = 0;
+ int64_t DebugInfoVersion = 0;
+ for (auto *Op : ModuleFlags->operands()) {
+ const MDOperand &StrOp = Op->getOperand(1);
+ if (StrOp.equalsStr("Dwarf Version")) {
+ DwarfVersion =
+ cast<ConstantInt>(
+ cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
+ ->getSExtValue();
+ } else if (StrOp.equalsStr("Debug Info Version")) {
+ DebugInfoVersion =
+ cast<ConstantInt>(
+ cast<ConstantAsMetadata>(Op->getOperand(2))->getValue())
+ ->getSExtValue();
+ }
+ }
+ const SPIRVInstrInfo *TII = TM->getSubtargetImpl()->getInstrInfo();
+ const SPIRVRegisterInfo *TRI = TM->getSubtargetImpl()->getRegisterInfo();
+ const RegisterBankInfo *RBI = TM->getSubtargetImpl()->getRegBankInfo();
+ SPIRVGlobalRegistry *GR = TM->getSubtargetImpl()->getSPIRVGlobalRegistry();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ for (MachineBasicBlock &MBB : MF) {
+ MachineIRBuilder MIRBuilder(MBB, MBB.begin());
+
+ MachineInstrBuilder MIB = MIRBuilder.buildInstr(SPIRV::OpString);
+ Register StrReg = MRI.createVirtualRegister(&SPIRV::IDRegClass);
+ MachineOperand StrRegOp = MachineOperand::CreateReg(StrReg, true);
+ MIB.add(StrRegOp);
+ addStringImm(FilePath, MIB);
+
+ const MachineInstr *VoidTyMI =
+ GR->getOrCreateSPIRVType(Type::getVoidTy(M->getContext()), MIRBuilder);
+
+ MIB = MIRBuilder.buildInstr(SPIRV::OpExtInst);
+ Register DebugSourceResIdReg =
+ MRI.createVirtualRegister(&SPIRV::IDRegClass);
+ MIB.addDef(DebugSourceResIdReg); // Result ID
+ MIB.addUse(VoidTyMI->getOperand(0).getReg()); // Result Type
+ MIB.addImm(static_cast<int64_t>(
+ SPIRV::InstructionSet::NonSemantic_Shader_DebugInfo_100)); // Set ID
+ MIB.addImm(SPIRV::NonSemanticExtInst::DebugSource); //
+ MIB.addUse(StrReg);
+ MIB.constrainAllUses(*TII, *TRI, *RBI);
+
+ Register DwarfVersionReg = GR->buildConstantInt(DwarfVersion, MIRBuilder);
----------------
bwlodarcz wrote:
I'm glad that you suggested this. That one is a very interesting and complex topic worthy of a minimum blog post. It summaries to the sentence "what's the main source of complexity when reading code" which tries to answer "what the readable code is" and unfortunately (for programmers ;)) imo. general answer doesn't exist. People are different from each other in terms of learning, reading or perceiving complexity and the answer is dependent from the individual. For me, the main source of complexity lies not in logical connections between parts of the algorithm (algorithm graph) but in extended contexts (multiple frames of abstractions, remembering things which happened before etc.). Every person perceives complexity a little bit differently and is inclined to make different tradeoffs.
The actual organization of algorithm optimizes for the minimization of the context (how much do you need to remember to reason which is correlated to how local the parts of code are). In the current algorithm you have two main contexts (will be three later) which are somewhat separate:
a) the Metadata search which requires `Module`, `MachineModuleInfo` etc.
b) the emitting part which utilizes e.g. `MIRBuilder`
The context a) is only connected by a few variables which are the only thing which I need to remember when reading the b) part. That approach have advantages:
a) It's easy to extract function/method if some section become too big
b) because contexts are visible it's easier to organize lifetimes of a variables in the head
c) minimizing and separating contexts makes utilizing custom local allocators possible (like arena allocators) [in other programs, of course not in LLVM].
Making everything closer to each other, like searching the module for variable exactly where emitter is needing it (which indeed makes logical connections much easier to spot), is creating one big context (because e.g. the Module and it's logic is now needed everywhere and not only in one place) which for me individually is just harder to reason. I think that I should add separating context braces - this will likely make the organizational thought here more visible.
https://github.com/llvm/llvm-project/pull/97558
More information about the llvm-commits
mailing list