Переглянути джерело

[spirv] Add OpLine for function calls (#1459)

This covers intrinsic functions, intrinsic methods, and user-
defined functions.
Lei Zhang 7 роки тому
батько
коміт
d2bfaa663b

+ 3 - 0
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -484,6 +484,9 @@ public:
                                 llvm::ArrayRef<uint32_t> constituents);
   uint32_t getConstantNull(uint32_t type);
 
+  // === Debug ===
+  void debugLine(uint32_t file, uint32_t line, uint32_t column);
+
 private:
   /// \brief Map from basic blocks' <label-id> to their structured
   /// representation.

+ 5 - 0
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -1258,6 +1258,11 @@ uint32_t ModuleBuilder::getConstantNull(uint32_t typeId) {
   return constId;
 }
 
+void ModuleBuilder::debugLine(uint32_t file, uint32_t line, uint32_t column) {
+  instBuilder.opLine(file, line, column).x();
+  insertPoint->appendInstruction(std::move(constructSite));
+}
+
 BasicBlock *ModuleBuilder::getBasicBlock(uint32_t labelId) {
   auto it = basicBlocks.find(labelId);
   if (it == basicBlocks.end()) {

+ 14 - 2
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -590,7 +590,8 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options)
                    featureManager, options),
       entryFunctionId(0), curFunction(nullptr), curThis(0),
       seenPushConstantAt(), isSpecConstantMode(false),
-      foundNonUniformResourceIndex(false), needsLegalization(false) {
+      foundNonUniformResourceIndex(false), needsLegalization(false),
+      mainSourceFileId(0) {
   if (shaderModel.GetKind() == hlsl::ShaderModel::Kind::Invalid)
     emitError("unknown shader module: %0", {}) << shaderModel.GetName();
 
@@ -612,7 +613,8 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options)
   const auto &inputFiles = ci.getFrontendOpts().Inputs;
   if (options.enableDebugInfo && !inputFiles.empty()) {
     // File name
-    theBuilder.setSourceFileName(theContext.takeNextId(),
+    mainSourceFileId = theContext.takeNextId();
+    theBuilder.setSourceFileName(mainSourceFileId,
                                  inputFiles.front().getFile().str());
 
     // Source code
@@ -1986,6 +1988,8 @@ SpirvEvalInfo SPIRVEmitter::doBinaryOperator(const BinaryOperator *expr) {
 }
 
 SpirvEvalInfo SPIRVEmitter::doCallExpr(const CallExpr *callExpr) {
+  emitDebugLine(callExpr->getLocStart());
+
   if (const auto *operatorCall = dyn_cast<CXXOperatorCallExpr>(callExpr))
     return doCXXOperatorCallExpr(operatorCall);
 
@@ -9950,5 +9954,13 @@ uint32_t SPIRVEmitter::extractVecFromVec4(uint32_t fromId,
   }
 }
 
+void SPIRVEmitter::emitDebugLine(SourceLocation loc) {
+  if (spirvOptions.enableDebugInfo && mainSourceFileId != 0) {
+    auto floc = FullSourceLoc(loc, theCompilerInstance.getSourceManager());
+    theBuilder.debugLine(mainSourceFileId, floc.getSpellingLineNumber(),
+                         floc.getSpellingColumnNumber());
+  }
+}
+
 } // end namespace spirv
 } // end namespace clang

+ 6 - 0
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -873,6 +873,9 @@ private:
                              uint32_t constOffsets, uint32_t sample,
                              uint32_t minLod, uint32_t residencyCodeId);
 
+  /// \brief Emit an OpLine instruction for the given source location.
+  void emitDebugLine(SourceLocation);
+
 private:
   /// \brief Wrapper method to create a fatal error message and report it
   /// in the diagnostic engine associated with this consumer.
@@ -1017,6 +1020,9 @@ private:
   /// This is the Patch Constant Function. This function is not explicitly
   /// called from the entry point function.
   FunctionDecl *patchConstFunc;
+
+  /// The <result-id> of the OpString containing the main source file's path.
+  uint32_t mainSourceFileId;
 };
 
 void SPIRVEmitter::doDeclStmt(const DeclStmt *declStmt) {

+ 33 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.hlsl

@@ -0,0 +1,33 @@
+// Run: %dxc -T ps_6_0 -E main -Zi
+
+// CHECK:      [[file:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.opline.hlsl
+
+Texture2D    MyTexture;
+SamplerState MySampler;
+
+uint foo(uint val) {
+  return val;
+}
+
+// Note that we do two passes for debuging info: first preprocessing and then
+// compiling the preprocessed source code.
+// Because the preprocessor prepends a "#line 1 ..." line to the whole file,
+// the compliation sees line numbers incremented by 1.
+
+float4 main(uint val : A) : SV_Target {
+  // CHECK:      OpLine [[file]] 23 12
+  // CHECK-NEXT: OpLoad %uint %val
+  // CHECK-NEXT: OpBitReverse
+  uint a = reversebits(val);
+
+  // CHECK:      OpLine [[file]] 27 12
+  // CHECK-NEXT: OpLoad %uint %a
+  uint b = foo(a);
+
+  // CHECK:      OpLine [[file]] 31 14
+  // CHECK-NEXT: OpLoad %type_2d_image %MyTexture
+  float4 c = MyTexture.Sample(MySampler, float2(0.1, 0.2));
+
+  return b * c;
+}

+ 4 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -1315,6 +1315,10 @@ TEST_F(FileTest, SpirvDebugOpSource) {
   runFileTest("spirv.debug.opsource.hlsl");
 }
 
+TEST_F(FileTest, SpirvDebugOpLine) {
+  runFileTest("spirv.debug.opline.hlsl");
+}
+
 TEST_F(FileTest, VulkanAttributeErrors) {
   runFileTest("vk.attribute.error.hlsl", Expect::Failure);
 }