瀏覽代碼

[spirv] wrap instructions with OpNoLine (#3229)

The current DXC emits `OpLine` for the first instruction in the location
and does not emit the same `OpLine` for the following instructions.
However, it does not specify the end of the effectiveness of the
`OpLine`, which is technically wrong based on the spec of OpLine and
OpNoLine. We have to specify the `OpLine` is not applied to the
following instructions when we meet an instruction without the location
information.
Jaebaek Seo 4 年之前
父節點
當前提交
8fea615e3c

+ 1 - 1
external/SPIRV-Headers

@@ -1 +1 @@
-Subproject commit c43a43c7cc3af55910b9bec2a71e3e8a622443cf
+Subproject commit 05836bdba63e7debce9fa9feaed42f20cd43af9d

+ 1 - 1
external/SPIRV-Tools

@@ -1 +1 @@
-Subproject commit 5c64374dd6cbfff1294ec78cdae1bc9de870a07d
+Subproject commit 82b378d671836b51343b010ca9ec32db14485147

+ 39 - 11
tools/clang/lib/SPIRV/EmitVisitor.cpp

@@ -202,7 +202,8 @@ void EmitVisitor::emitDebugNameForInstruction(uint32_t resultId,
 }
 
 void EmitVisitor::emitDebugLine(spv::Op op, const SourceLocation &loc,
-                                std::vector<uint32_t> *section) {
+                                std::vector<uint32_t> *section,
+                                bool isDebugScope) {
   if (!spvOptions.debugInfoLine)
     return;
 
@@ -217,6 +218,8 @@ void EmitVisitor::emitDebugLine(spv::Op op, const SourceLocation &loc,
   // immediately precede either an OpBranch or OpBranchConditional instruction.
   if (lastOpWasMergeInst) {
     lastOpWasMergeInst = false;
+    debugLine = 0;
+    debugColumn = 0;
     return;
   }
 
@@ -233,29 +236,53 @@ void EmitVisitor::emitDebugLine(spv::Op op, const SourceLocation &loc,
   if (op == spv::Op::OpVariable)
     return;
 
+  // If no SourceLocation is provided, we have to emit OpNoLine to
+  // specify the previous OpLine is not applied to this instruction.
+  if (loc == SourceLocation()) {
+    if (!isDebugScope && (debugLine != 0 || debugColumn != 0)) {
+      curInst.clear();
+      curInst.push_back(static_cast<uint32_t>(spv::Op::OpNoLine));
+      curInst[0] |= static_cast<uint32_t>(curInst.size()) << 16;
+      section->insert(section->end(), curInst.begin(), curInst.end());
+    }
+    debugLine = 0;
+    debugColumn = 0;
+    return;
+  }
+
   auto fileId = debugMainFileId;
   const auto &sm = astContext.getSourceManager();
   const char *fileName = sm.getPresumedLoc(loc).getFilename();
   if (fileName)
     fileId = getOrCreateOpStringId(fileName);
 
-  if (!fileId)
-    return;
-
   uint32_t line = sm.getPresumedLineNumber(loc);
   uint32_t column = sm.getPresumedColumnNumber(loc);
 
-  if (!line || !column)
-    return;
+  // If it is a terminator, just reset the last line and column because
+  // a terminator makes the OpLine not effective.
+  bool resetLine = (op >= spv::Op::OpBranch && op <= spv::Op::OpUnreachable) ||
+                   op == spv::Op::OpTerminateInvocation;
 
-  if (line == debugLine && column == debugColumn)
+  if (!fileId || !line || !column ||
+      (line == debugLine && column == debugColumn)) {
+    if (resetLine) {
+      debugLine = 0;
+      debugColumn = 0;
+    }
     return;
+  }
 
   assert(section);
 
-  // We must update these two values to emit the next Opline.
-  debugLine = line;
-  debugColumn = column;
+  if (resetLine) {
+    debugLine = 0;
+    debugColumn = 0;
+  } else {
+    // Keep the last line and column to avoid printing the duplicated OpLine.
+    debugLine = line;
+    debugColumn = column;
+  }
 
   curInst.clear();
   curInst.push_back(static_cast<uint32_t>(spv::Op::OpLine));
@@ -312,7 +339,8 @@ void EmitVisitor::initInstruction(SpirvInstruction *inst) {
     isGlobalVar = var->getStorageClass() != spv::StorageClass::Function;
   const auto op = inst->getopcode();
   emitDebugLine(op, inst->getSourceLocation(),
-                isGlobalVar ? &globalVarsBinary : &mainBinary);
+                isGlobalVar ? &globalVarsBinary : &mainBinary,
+                isa<SpirvDebugScope>(inst));
 
   // Initialize the current instruction for emitting.
   curInst.clear();

+ 1 - 1
tools/clang/lib/SPIRV/EmitVisitor.h

@@ -312,7 +312,7 @@ private:
   // Emits an OpLine instruction for the given operation into the given binary
   // section.
   void emitDebugLine(spv::Op op, const SourceLocation &loc,
-                     std::vector<uint32_t> *section);
+                     std::vector<uint32_t> *section, bool isDebugScope = false);
 
   // Initiates the creation of a new instruction with the given Opcode.
   void initInstruction(spv::Op, const SourceLocation &);

+ 9 - 9
tools/clang/test/CodeGenSPIRV/rich.debug.debugdeclare.hlsl

@@ -9,16 +9,16 @@
 // CHECK: [[expr:%\d+]] = OpExtInst %void [[set]] DebugExpression
 // CHECK: [[color:%\d+]] = OpExtInst %void [[set]] DebugLocalVariable {{%\d+}} {{%\d+}} {{%\d+}} 28 20 {{%\d+}} FlagIsLocal 1
 
-// CHECK:        %color = OpFunctionParameter
-// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[color]] %color [[expr]]
-// CHECK:      %condition = OpVariable
-// CHECK:                 OpStore %condition %false
-// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[condition]] %condition [[expr]]
+// CHECK:     %color = OpFunctionParameter
+// CHECK:   {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[color]] %color [[expr]]
+// CHECK: %condition = OpVariable
+// CHECK:              OpStore %condition %false
+// CHECK:   {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[condition]] %condition [[expr]]
 
-// CHECK:            %x = OpFunctionParameter
-// CHECK:            %y = OpFunctionParameter
-// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[x]] %x [[expr]]
-// CHECK-NEXT: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[y]] %y [[expr]]
+// CHECK:       %x = OpFunctionParameter
+// CHECK:       %y = OpFunctionParameter
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[x]] %x [[expr]]
+// CHECK: {{%\d+}} = OpExtInst %void [[set]] DebugDeclare [[y]] %y [[expr]]
 
 void foo(int x, float y)
 {

+ 6 - 6
tools/clang/test/CodeGenSPIRV/rich.debug.debugdeclare.without.init.hlsl

@@ -1,11 +1,11 @@
 // Run: %dxc -T ps_6_0 -E main -fspv-debug=rich
 
-// CHECK:      %i = OpFunctionParameter %_ptr_Function_PS_INPUT
-// CHECK-NEXT: DebugDeclare {{%\d+}} %i
-// CHECK:      %ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
-// CHECK:      %c = OpVariable %_ptr_Function_v4float Function
-// CHECK:      DebugDeclare {{%\d+}} %ps_output
-// CHECK:      DebugDeclare {{%\d+}} %c
+// CHECK: %i = OpFunctionParameter %_ptr_Function_PS_INPUT
+// CHECK: DebugDeclare {{%\d+}} %i
+// CHECK: %ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
+// CHECK: %c = OpVariable %_ptr_Function_v4float Function
+// CHECK: DebugDeclare {{%\d+}} %ps_output
+// CHECK: DebugDeclare {{%\d+}} %c
 
 Texture2D g_tColor;
 

+ 1 - 1
tools/clang/test/CodeGenSPIRV/rich.debug.scope.after.compound.statement.hlsl

@@ -28,7 +28,7 @@ VS_OUTPUT main(float4 pos : POSITION,
 //CHECK:      DebugScope [[bb2]]
 //CHECK-NEXT: OpLine [[file:%\d+]] 32
 //CHECK-NEXT: OpStore [[var_a:%\w+]] %float_6
-//CHECK-NEXT: DebugDeclare [[a]] [[var_a]]
+//CHECK:      DebugDeclare [[a]] [[var_a]]
       float a = 6.0;
       x += a + b + c;
     }

+ 1 - 1
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.branch.hlsl

@@ -52,8 +52,8 @@ void main() {
 // CHECK:                        OpLine [[file]] 57 3
 // CHECK-NEXT:                   OpBranch %while_continue
 // CHECK-NEXT: %while_continue = OpLabel
+// CHECK-NEXT:                   OpLine [[file]] 57 3
 // CHECK-NEXT:                   OpBranch %while_check
-// CHECK-NEXT:    %while_merge = OpLabel
   }
 
 // CHECK:       OpLine [[file]] 61 19