Browse Source

Improve matrix and constant buffer debug info. (#2076)

- Hijack dwarf debug info to present matrices as having _11 to _44 fields, similar to vectors
- Better preservation of debug info for constant buffer loads
- Improve and rename resource loading tests
- Improve and reorganize vector members tests, adding matrix members test
Tristan Labelle 6 years ago
parent
commit
55b29a12c4

+ 2 - 0
lib/HLSL/HLOperationLower.cpp

@@ -5500,6 +5500,7 @@ void TranslateCBAddressUserLegacy(Instruction *user, Value *handle,
       Value *newLd = TranslateConstBufMatLdLegacy(
       Value *newLd = TranslateConstBufMatLdLegacy(
         MatTy, handle, legacyIdx, colMajor, hlslOP, /*memElemRepr*/false, DL, Builder);
         MatTy, handle, legacyIdx, colMajor, hlslOP, /*memElemRepr*/false, DL, Builder);
       CI->replaceAllUsesWith(newLd);
       CI->replaceAllUsesWith(newLd);
+      dxilutil::ScatterDebugValueToVectorElements(newLd);
       CI->eraseFromParent();
       CI->eraseFromParent();
     } else if (group == HLOpcodeGroup::HLSubscript) {
     } else if (group == HLOpcodeGroup::HLSubscript) {
       HLSubscriptOpcode subOp = static_cast<HLSubscriptOpcode>(opcode);
       HLSubscriptOpcode subOp = static_cast<HLSubscriptOpcode>(opcode);
@@ -5668,6 +5669,7 @@ void TranslateCBAddressUserLegacy(Instruction *user, Value *handle,
                                    hlslOP, Builder);
                                    hlslOP, Builder);
 
 
     ldInst->replaceAllUsesWith(newLd);
     ldInst->replaceAllUsesWith(newLd);
+    if (Ty->isVectorTy()) dxilutil::ScatterDebugValueToVectorElements(newLd);
     ldInst->eraseFromParent();
     ldInst->eraseFromParent();
   } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(user)) {
   } else if (BitCastInst *BCI = dyn_cast<BitCastInst>(user)) {
     for (auto it = BCI->user_begin(); it != BCI->user_end(); ) {
     for (auto it = BCI->user_begin(); it != BCI->user_end(); ) {

+ 24 - 0
tools/clang/lib/CodeGen/CGDebugInfo.cpp

@@ -1050,6 +1050,30 @@ bool CGDebugInfo::TryCollectHLSLRecordElements(const RecordType *Ty,
 
 
     return true;
     return true;
   }
   }
+  else if (hlsl::IsHLSLMatType(QualTy)) {
+    // The HLSL matrix type is defined as containing a field 'h' of
+    // array of extended vector type, but logically we want to represent
+    // it as per-element fields.
+    QualType ElemQualTy = hlsl::GetHLSLMatElementType(QualTy);
+    uint32_t NumRows, NumCols;
+    hlsl::GetHLSLMatRowColCount(QualTy, NumRows, NumCols);
+    unsigned ElemSizeInBits = CGM.getContext().getTypeSize(ElemQualTy);
+    for (unsigned RowIdx = 0; RowIdx < NumRows; ++RowIdx) {
+      for (unsigned ColIdx = 0; ColIdx < NumCols; ++ColIdx) {
+        char FieldName[] = "_11";
+        FieldName[1] += RowIdx;
+        FieldName[2] += ColIdx;
+        unsigned RowMajorIdx = RowIdx * NumCols + ColIdx;
+        unsigned OffsetInBits = ElemSizeInBits * RowMajorIdx;
+        llvm::DIType *FieldType = createFieldType(FieldName, ElemQualTy, 0,
+          SourceLocation(), AccessSpecifier::AS_public, OffsetInBits,
+          /* tunit */ nullptr, DITy, Ty->getDecl());
+        Elements.emplace_back(FieldType);
+      }
+    }
+
+    return true;
+  }
   else if (hlsl::IsHLSLResourceType(QualTy) || hlsl::IsHLSLStreamOutputType(QualTy)) {
   else if (hlsl::IsHLSLResourceType(QualTy) || hlsl::IsHLSLStreamOutputType(QualTy)) {
     // Should appear as having no members rather than exposing our internal handles.
     // Should appear as having no members rather than exposing our internal handles.
     return true;
     return true;

+ 1 - 1
tools/clang/test/CodeGenHLSL/debug/_readme.txt

@@ -13,7 +13,7 @@ The current workaround is to include the following in your test to explicitly ma
 the quoted source file:
 the quoted source file:
 
 
   // Exclude quoted source file (see readme)
   // Exclude quoted source file (see readme)
-  // CHECK: {{!"[^"]*\\0A[^"]*"}}
+  // CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
 
 
 This will match a metadata string containing \0A (newline), which should only appear
 This will match a metadata string containing \0A (newline), which should only appear
 in the quoted source file. It will not match itself in the quoted source file because
 in the quoted source file. It will not match itself in the quoted source file because

+ 22 - 0
tools/clang/test/CodeGenHLSL/debug/locals/constantbuffer_loadlegacy_vector.hlsl

@@ -0,0 +1,22 @@
+// RUN: %dxc -E main -T vs_6_0 -Zi %s | FileCheck %s
+
+// Test that the debug information for the result of a texture load
+// is preserved after scalarization and optims.
+
+// CHECK: call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32
+// CHECK: extractvalue %dx.types.CBufRet.i32
+// CHECK-DAG: call void @llvm.dbg.value
+// CHECK-DAG: extractvalue %dx.types.CBufRet.i32
+// CHECK: call void @llvm.dbg.value
+// CHECK: call void @dx.op.storeOutput.i32
+// CHECK: call void @dx.op.storeOutput.i32
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+
+int2 cb;
+int2 main() : OUT
+{
+    int2 result = cb;
+    return result;
+}

+ 21 - 0
tools/clang/test/CodeGenHLSL/debug/locals/matrix_no_opt.hlsl

@@ -0,0 +1,21 @@
+// RUN: %dxc -E main -T vs_6_0 -Zi -Od %s | FileCheck %s
+
+// Test that local matrices preserve debug info without optimizations
+
+// CHECK: %[[mat:.*]] = alloca [4 x i32]
+// CHECK: call void @llvm.dbg.declare(metadata [4 x i32]* %[[mat]], metadata ![[divar:.*]], metadata ![[diexpr:.*]])
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+
+// CHECK-DAG: ![[divar]] = !DILocalVariable(tag: DW_TAG_auto_variable, name: "mat"
+// CHECK-DAG: ![[diexpr]] = !DIExpression()
+
+int2x2 cb_mat;
+int main() : OUT
+{
+  // Initialize from CB to ensure the variable is not optimized away
+  int2x2 mat = cb_mat;
+  // Consume all values but return a scalar to avoid another alloca [4 x i32]
+  return determinant(mat);
+}

+ 26 - 0
tools/clang/test/CodeGenHLSL/debug/locals/matrix_opt.hlsl

@@ -0,0 +1,26 @@
+// RUN: %dxc -E main -T vs_6_0 -Zi %s | FileCheck %s
+
+// Test that local matrices preserve debug info with optimizations
+
+// CHECK: call void @llvm.dbg.value
+// CHECK: call void @llvm.dbg.value
+// CHECK: call void @llvm.dbg.value
+// CHECK: call void @llvm.dbg.value
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+
+// CHECK-DAG: !DILocalVariable(tag: DW_TAG_auto_variable, name: "mat"
+// CHECK-DAG: !DIExpression(DW_OP_bit_piece, 0, 32)
+// CHECK-DAG: !DIExpression(DW_OP_bit_piece, 32, 32)
+// CHECK-DAG: !DIExpression(DW_OP_bit_piece, 64, 32)
+// CHECK-DAG: !DIExpression(DW_OP_bit_piece, 96, 32)
+
+int2x2 cb_mat;
+int main() : OUT
+{
+  // Initialize from CB to ensure the variable is not optimized away
+  int2x2 mat = cb_mat;
+  // Consume all values but return a scalar to avoid another alloca [4 x i32]
+  return determinant(mat);
+}

+ 4 - 4
tools/clang/test/CodeGenHLSL/debug/locals/structuredbuffer_load.hlsl → tools/clang/test/CodeGenHLSL/debug/locals/structuredbuffer_load_vector.hlsl

@@ -4,14 +4,14 @@
 // is preserved after scalarization and optims.
 // is preserved after scalarization and optims.
 
 
 // CHECK: call %dx.types.ResRet.i32 @dx.op.bufferLoad.i32
 // CHECK: call %dx.types.ResRet.i32 @dx.op.bufferLoad.i32
-// CHECK: call void @llvm.dbg.value
-// CHECK: extractvalue %dx.types.ResRet.i32
-// CHECK: extractvalue %dx.types.ResRet.i32
+// CHECK-DAG: call void @llvm.dbg.value
+// CHECK-DAG: extractvalue %dx.types.ResRet.i32
+// CHECK-DAG: extractvalue %dx.types.ResRet.i32
 // CHECK: call void @dx.op.storeOutput.i32
 // CHECK: call void @dx.op.storeOutput.i32
 // CHECK: call void @dx.op.storeOutput.i32
 // CHECK: call void @dx.op.storeOutput.i32
 
 
 // Exclude quoted source file (see readme)
 // Exclude quoted source file (see readme)
-// CHECK: {{!"[^"]*\\0A[^"]*"}}
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
 
 
 StructuredBuffer<int2> buf;
 StructuredBuffer<int2> buf;
 int2 main() : OUT
 int2 main() : OUT

+ 0 - 25
tools/clang/test/CodeGenHLSL/debug/locals/texture_load.hlsl

@@ -1,25 +0,0 @@
-// RUN: %dxc -E main -T ps_6_0 -Zi %s | FileCheck %s
-
-// Test that the debug information for the result of a texture load
-// is preserved after scalarization and optims.
-
-// CHECK: call %dx.types.ResRet.f32 @dx.op.textureLoad.f32
-// CHECK: call void @llvm.dbg.value
-// CHECK: extractvalue %dx.types.ResRet.f32
-// CHECK: extractvalue %dx.types.ResRet.f32
-// CHECK: extractvalue %dx.types.ResRet.f32
-// CHECK: extractvalue %dx.types.ResRet.f32
-// CHECK: call void @dx.op.storeOutput.f32
-// CHECK: call void @dx.op.storeOutput.f32
-// CHECK: call void @dx.op.storeOutput.f32
-// CHECK: call void @dx.op.storeOutput.f32
-
-// Exclude quoted source file (see readme)
-// CHECK: {{!"[^"]*\\0A[^"]*"}}
-
-Texture1D<float4> tex;
-float4 main() : SV_Target
-{
-    float4 texel = tex.Load(0);
-    return texel;
-}

+ 21 - 0
tools/clang/test/CodeGenHLSL/debug/locals/texture_load_vector.hlsl

@@ -0,0 +1,21 @@
+// RUN: %dxc -E main -T ps_6_0 -Zi %s | FileCheck %s
+
+// Test that the debug information for the result of a texture load
+// is preserved after scalarization and optims.
+
+// CHECK: call %dx.types.ResRet.f32 @dx.op.textureLoad.f32
+// CHECK-DAG: call void @llvm.dbg.value
+// CHECK-DAG: extractvalue %dx.types.ResRet.f32
+// CHECK-DAG: extractvalue %dx.types.ResRet.f32
+// CHECK: call void @dx.op.storeOutput.f32
+// CHECK: call void @dx.op.storeOutput.f32
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+
+Texture1D<float2> tex;
+float2 main() : SV_Target
+{
+    float2 texel = tex.Load(0);
+    return texel;
+}

+ 0 - 26
tools/clang/test/CodeGenHLSL/debug/locals/texture_sample.hlsl

@@ -1,26 +0,0 @@
-// RUN: %dxc -E main -T ps_6_0 -Zi %s | FileCheck %s
-
-// Test that the debug information for the result of a texture sample
-// is preserved after scalarization and optims.
-
-// CHECK: call %dx.types.ResRet.f32 @dx.op.sample.f32
-// CHECK: call void @llvm.dbg.value
-// CHECK: extractvalue %dx.types.ResRet.f32
-// CHECK: extractvalue %dx.types.ResRet.f32
-// CHECK: extractvalue %dx.types.ResRet.f32
-// CHECK: extractvalue %dx.types.ResRet.f32
-// CHECK: call void @dx.op.storeOutput.f32
-// CHECK: call void @dx.op.storeOutput.f32
-// CHECK: call void @dx.op.storeOutput.f32
-// CHECK: call void @dx.op.storeOutput.f32
-
-// Exclude quoted source file (see readme)
-// CHECK: {{!"[^"]*\\0A[^"]*"}}
-
-sampler samp;
-Texture2D<float4> tex;
-float4 main() : SV_Target
-{
-    float4 texel = tex.Sample(samp, 0);
-    return texel;
-}

+ 22 - 0
tools/clang/test/CodeGenHLSL/debug/locals/texture_sample_vector.hlsl

@@ -0,0 +1,22 @@
+// RUN: %dxc -E main -T ps_6_0 -Zi %s | FileCheck %s
+
+// Test that the debug information for the result of a texture sample
+// is preserved after scalarization and optims.
+
+// CHECK: call %dx.types.ResRet.f32 @dx.op.sample.f32
+// CHECK-DAG: call void @llvm.dbg.value
+// CHECK-DAG: extractvalue %dx.types.ResRet.f32
+// CHECK-DAG: extractvalue %dx.types.ResRet.f32
+// CHECK: call void @dx.op.storeOutput.f32
+// CHECK: call void @dx.op.storeOutput.f32
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+
+sampler samp;
+Texture2D<float2> tex;
+float2 main() : SV_Target
+{
+    float2 texel = tex.Sample(samp, 0);
+    return texel;
+}

+ 0 - 0
tools/clang/test/CodeGenHLSL/debug/locals/input_vector.hlsl → tools/clang/test/CodeGenHLSL/debug/shader_params/input_vector.hlsl


+ 0 - 0
tools/clang/test/CodeGenHLSL/debug/locals/input_vector_in_struct.hlsl → tools/clang/test/CodeGenHLSL/debug/shader_params/input_vector_in_struct.hlsl


+ 14 - 0
tools/clang/test/CodeGenHLSL/debug/types/matrix_members.hlsl

@@ -0,0 +1,14 @@
+// RUN: %dxc -T vs_6_0 -E main -Od -Zi %s | FileCheck %s
+
+// Test that the debug info for HLSL matrices exposes per-component fields.
+
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "int2x2"
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_class_type, name: "matrix<int, 2, 2>", {{.*}}, size: 128, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_11", {{.*}}, size: 32, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_12", {{.*}}, size: 32, align: 32, offset: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_21", {{.*}}, size: 32, align: 32, offset: 64
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_22", {{.*}}, size: 32, align: 32, offset: 96
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+int2x2 main(int2x2 v : IN) : OUT { return v; }

+ 15 - 0
tools/clang/test/CodeGenHLSL/debug/types/matrix_members_bool.hlsl

@@ -0,0 +1,15 @@
+// RUN: %dxc -T vs_6_0 -E main -Od -Zi %s | FileCheck %s
+
+// Test that the debug info for HLSL bool matrices exposes per-component fields
+// in the memory representation of matrices (32-bits)
+
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "bool2x2"
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_class_type, name: "matrix<bool, 2, 2>", {{.*}}, size: 128, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_11", {{.*}}, size: 32, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_12", {{.*}}, size: 32, align: 32, offset: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_21", {{.*}}, size: 32, align: 32, offset: 64
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "_22", {{.*}}, size: 32, align: 32, offset: 96
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+bool2x2 main(bool2x2 v : IN) : OUT { return v; }

+ 12 - 0
tools/clang/test/CodeGenHLSL/debug/types/vector_members.hlsl

@@ -0,0 +1,12 @@
+// RUN: %dxc -T vs_6_0 -E main -Od -Zi %s | FileCheck %s
+
+// Test that the debug info for HLSL vectors exposes per-component fields.
+
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "int2"
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_class_type, name: "vector<int, 2>", {{.*}}, size: 64, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "x", {{.*}}, size: 32, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "y", {{.*}}, size: 32, align: 32, offset: 32
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+int2 main(int2 v : IN) : OUT { return v; }

+ 13 - 0
tools/clang/test/CodeGenHLSL/debug/types/vector_members_bool.hlsl

@@ -0,0 +1,13 @@
+// RUN: %dxc -T vs_6_0 -E main -Od -Zi %s | FileCheck %s
+
+// Test that the debug info for HLSL bool vectors exposes per-component fields
+// in the memory representation of bools (32-bits)
+
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "bool2"
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_class_type, name: "vector<bool, 2>", {{.*}}, size: 64, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "x", {{.*}}, size: 32, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "y", {{.*}}, size: 32, align: 32, offset: 32
+
+// Exclude quoted source file (see readme)
+// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}
+bool2 main(bool2 v : IN) : OUT { return v; }

+ 0 - 9
tools/clang/test/CodeGenHLSL/debug/vector_members.hlsl

@@ -1,9 +0,0 @@
-// RUN: %dxc -T vs_6_0 -E main -Od -Zi %s | FileCheck %s
-
-// Test that the debug info for HLSL vectors exposes per-component fields.
-
-// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "int2"
-// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "vector<int, 2>", {{.*}}, size: 64, align: 32
-// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "x", {{.*}}, size: 32, align: 32
-// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "y", {{.*}}, size: 32, align: 32, offset: 32
-int2 main(int2 v : IN) : OUT { return v; }

+ 0 - 10
tools/clang/test/CodeGenHLSL/debug/vector_members_bool.hlsl

@@ -1,10 +0,0 @@
-// RUN: %dxc -T vs_6_0 -E main -Od -Zi %s | FileCheck %s
-
-// Test that the debug info for HLSL bool vectors exposes per-component fields
-// in the memory representation of bools (32-bits)
-
-// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "bool2"
-// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "vector<bool, 2>", {{.*}}, size: 64, align: 32
-// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "x", {{.*}}, size: 32, align: 32
-// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "y", {{.*}}, size: 32, align: 32, offset: 32
-bool2 main(bool2 v : IN) : OUT { return v; }