Skip to content

Commit 84c0a09

Browse files
authored
Fix debug info offsets for vectors with 16-bit types (microsoft#6775)
This fixes a bug where the offsets for elements in vectors with 16-bit types doesn't take into account alignment bits and PIX wouldn't display vector element values correctly in the shader debugger. Eg. if `-enable-16bit-types` wasn't set, the offsets for a min16float4 would be 0, 16, 32, 48 instead of 0, 32, 64, 96. Also removed the assert in PopulateAllocaMap_StructType that was checking whether the calculated aligned offset matches the packed offset (from SortedMembers) because it was false for members with sizes smaller than the alignment size.
1 parent c4e9976 commit 84c0a09

File tree

5 files changed

+138
-29
lines changed

5 files changed

+138
-29
lines changed

lib/DxilPIXPasses/DxilDbgValueToDbgDeclare.cpp

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -138,28 +138,8 @@ class OffsetManager {
138138
unsigned AlignMask = DescendTypeToGetAlignMask(Ty);
139139
if (AlignMask) {
140140
VALUE_TO_DECLARE_LOG("Aligning to %d", AlignMask);
141-
// This is some magic arithmetic. Here's an example:
142-
//
143-
// Assume the natural alignment for Ty is 16 bits. Then
144-
//
145-
// AlignMask = 0x0000000f(15)
146-
//
147-
// If the current aligned offset is
148-
//
149-
// CurrentAlignedOffset = 0x00000048(72)
150-
//
151-
// Then
152-
//
153-
// T = CurrentAlignOffset + AlignMask = 0x00000057(87)
154-
//
155-
// Which mean
156-
//
157-
// T & ~CurrentOffset = 0x00000050(80)
158-
//
159-
// is the aligned offset where Ty should be placed.
160-
AlignMask = AlignMask - 1;
161141
m_CurrentAlignedOffset =
162-
(m_CurrentAlignedOffset + AlignMask) & ~AlignMask;
142+
llvm::RoundUpToAlignment(m_CurrentAlignedOffset, AlignMask);
163143
} else {
164144
VALUE_TO_DECLARE_LOG("Failed to find alignment");
165145
}
@@ -1317,7 +1297,7 @@ void VariableRegisters::PopulateAllocaMap_StructType(
13171297
const llvm::DITypeIdentifierMap EmptyMap;
13181298

13191299
for (auto OffsetAndMember : SortedMembers) {
1320-
VALUE_TO_DECLARE_LOG("Member: %s at aligned offset %d",
1300+
VALUE_TO_DECLARE_LOG("Member: %s at packed offset %d",
13211301
OffsetAndMember.second->getName().str().c_str(),
13221302
OffsetAndMember.first);
13231303
// Align the offsets to the member's type natural alignment. This
@@ -1331,9 +1311,12 @@ void VariableRegisters::PopulateAllocaMap_StructType(
13311311
// size would be lost
13321312
PopulateAllocaMap(OffsetAndMember.second);
13331313
} else {
1334-
assert(m_Offsets.GetCurrentAlignedOffset() ==
1335-
StructStart + OffsetAndMember.first &&
1336-
"Offset mismatch in DIStructType");
1314+
if (OffsetAndMember.second->getAlignInBits() ==
1315+
OffsetAndMember.second->getSizeInBits()) {
1316+
assert(m_Offsets.GetCurrentAlignedOffset() ==
1317+
StructStart + OffsetAndMember.first &&
1318+
"Offset mismatch in DIStructType");
1319+
}
13371320
if (IsResourceObject(OffsetAndMember.second)) {
13381321
m_Offsets.AddResourceType(OffsetAndMember.second);
13391322
} else {

tools/clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,14 +1043,19 @@ bool CGDebugInfo::TryCollectHLSLRecordElements(const RecordType *Ty,
10431043
// extended vector type, which is represented as an array in DWARF.
10441044
// However, we logically represent it as one field per component.
10451045
QualType ElemQualTy = hlsl::GetHLSLVecElementType(QualTy);
1046+
unsigned AlignBits = CGM.getContext().getTypeAlign(ElemQualTy);
10461047
unsigned VecSize = hlsl::GetHLSLVecSize(QualTy);
10471048
unsigned ElemSizeInBits = CGM.getContext().getTypeSize(ElemQualTy);
1049+
unsigned CurrentAlignedOffset = 0;
10481050
for (unsigned ElemIdx = 0; ElemIdx < VecSize; ++ElemIdx) {
10491051
StringRef FieldName = StringRef(&"xyzw"[ElemIdx], 1);
1050-
unsigned OffsetInBits = ElemSizeInBits * ElemIdx;
1051-
llvm::DIType *FieldType = createFieldType(FieldName, ElemQualTy, 0,
1052-
SourceLocation(), AccessSpecifier::AS_public, OffsetInBits,
1053-
/* tunit */ nullptr, DITy, Ty->getDecl());
1052+
CurrentAlignedOffset =
1053+
llvm::RoundUpToAlignment(CurrentAlignedOffset, AlignBits);
1054+
llvm::DIType *FieldType =
1055+
createFieldType(FieldName, ElemQualTy, 0, SourceLocation(),
1056+
AccessSpecifier::AS_public, CurrentAlignedOffset,
1057+
/* tunit */ nullptr, DITy, Ty->getDecl());
1058+
CurrentAlignedOffset += ElemSizeInBits;
10541059
Elements.emplace_back(FieldType);
10551060
}
10561061

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Validate that the offsets for a min16float vector is correct if 16-bit types aren't enabled
2+
// RUN: %dxc -T cs_6_5 -Od -Zi -Qembed_debug %s | FileCheck %s
3+
4+
// CHECK-NOT: {{.*}}!DIDerivedType{{.*}}name: "x"{{.*}}offset: {{.*}}
5+
// CHECK: {{.*}}!DIDerivedType{{.*}}name: "y"{{.*}}offset: 32{{.*}}
6+
// CHECK: {{.*}}!DIDerivedType{{.*}}name: "z"{{.*}}offset: 64{{.*}}
7+
// CHECK: {{.*}}!DIDerivedType{{.*}}name: "w"{{.*}}offset: 96{{.*}}
8+
9+
RWStructuredBuffer<int> UAV : register(u0);
10+
11+
[numthreads(1, 1, 1)]
12+
void main() {
13+
min16float4 vector;
14+
vector.x = UAV[0];
15+
vector.y = UAV[1];
16+
vector.z = UAV[2];
17+
vector.w = UAV[3];
18+
UAV[16] = vector.x + vector.y + vector.z + vector.w;
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Validate that the offsets for a min16float vector is correct if 16-bit types are enabled
2+
// RUN: %dxc -T cs_6_5 -Od -Zi -Qembed_debug -enable-16bit-types %s | FileCheck %s
3+
4+
// CHECK-NOT: {{.*}}!DIDerivedType{{.*}}name: "x"{{.*}}offset: {{.*}}
5+
// CHECK: {{.*}}!DIDerivedType{{.*}}name: "y"{{.*}}offset: 16{{.*}}
6+
// CHECK: {{.*}}!DIDerivedType{{.*}}name: "z"{{.*}}offset: 32{{.*}}
7+
// CHECK: {{.*}}!DIDerivedType{{.*}}name: "w"{{.*}}offset: 48{{.*}}
8+
9+
RWStructuredBuffer<int> UAV : register(u0);
10+
11+
[numthreads(1, 1, 1)]
12+
void main() {
13+
min16float4 vector;
14+
vector.x = UAV[0];
15+
vector.y = UAV[1];
16+
vector.z = UAV[2];
17+
vector.w = UAV[3];
18+
UAV[16] = vector.x + vector.y + vector.z + vector.w;
19+
}

tools/clang/unittests/HLSL/PixDiaTest.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ class PixDiaTest {
188188
TEST_METHOD(DxcPixDxilDebugInfo_BitFields_Overlap)
189189
TEST_METHOD(DxcPixDxilDebugInfo_Min16SizesAndOffsets_Enabled)
190190
TEST_METHOD(DxcPixDxilDebugInfo_Min16SizesAndOffsets_Disabled)
191+
TEST_METHOD(DxcPixDxilDebugInfo_Min16VectorOffsets_Enabled)
192+
TEST_METHOD(DxcPixDxilDebugInfo_Min16VectorOffsets_Disabled)
191193
TEST_METHOD(
192194
DxcPixDxilDebugInfo_VariableScopes_InlinedFunctions_TwiceInlinedFunctions)
193195
TEST_METHOD(
@@ -661,6 +663,10 @@ class PixDiaTest {
661663
std::array<DWORD, 4> const &memberSizes,
662664
std::vector<const wchar_t *> extraArgs = {
663665
L"-Od"});
666+
void RunVectorSizeAndOffsetTestCase(const char *hlsl,
667+
std::array<DWORD, 4> const &memberOffsets,
668+
std::vector<const wchar_t *> extraArgs = {
669+
L"-Od"});
664670
DebuggerInterfaces
665671
CompileAndCreateDxcDebug(const char *hlsl, const wchar_t *profile,
666672
IDxcIncludeHandler *includer = nullptr,
@@ -3162,6 +3168,83 @@ void main()
31623168
RunSizeAndOffsetTestCase(hlsl, {0, 32, 64, 96}, {16, 16, 16, 16}, {L"-Od"});
31633169
}
31643170

3171+
TEST_F(PixDiaTest, DxcPixDxilDebugInfo_Min16VectorOffsets_Enabled) {
3172+
if (m_ver.SkipDxilVersion(1, 5))
3173+
return;
3174+
3175+
const char *hlsl = R"(
3176+
RWStructuredBuffer<int> UAV: register(u0);
3177+
3178+
[numthreads(1, 1, 1)]
3179+
void main()
3180+
{
3181+
min16float4 vector;
3182+
vector.x = UAV[0];
3183+
vector.y = UAV[1];
3184+
vector.z = UAV[2];
3185+
vector.w = UAV[3];
3186+
UAV[16] = vector.x + vector.y + vector.z + vector.w; //STOP_HERE
3187+
}
3188+
3189+
3190+
)";
3191+
RunVectorSizeAndOffsetTestCase(hlsl, {0, 16, 32, 48},
3192+
{L"-Od", L"-enable-16bit-types"});
3193+
}
3194+
3195+
TEST_F(PixDiaTest, DxcPixDxilDebugInfo_Min16VectorOffsets_Disabled) {
3196+
if (m_ver.SkipDxilVersion(1, 5))
3197+
return;
3198+
3199+
const char *hlsl = R"(
3200+
RWStructuredBuffer<int> UAV: register(u0);
3201+
3202+
[numthreads(1, 1, 1)]
3203+
void main()
3204+
{
3205+
min16float4 vector;
3206+
vector.x = UAV[0];
3207+
vector.y = UAV[1];
3208+
vector.z = UAV[2];
3209+
vector.w = UAV[3];
3210+
UAV[16] = vector.x + vector.y + vector.z + vector.w; //STOP_HERE
3211+
}
3212+
3213+
3214+
)";
3215+
RunVectorSizeAndOffsetTestCase(hlsl, {0, 32, 64, 96});
3216+
}
3217+
void PixDiaTest::RunVectorSizeAndOffsetTestCase(
3218+
const char *hlsl, std::array<DWORD, 4> const &memberOffsets,
3219+
std::vector<const wchar_t *> extraArgs) {
3220+
if (m_ver.SkipDxilVersion(1, 5))
3221+
return;
3222+
auto debugInfo =
3223+
CompileAndCreateDxcDebug(hlsl, L"cs_6_5", nullptr, extraArgs).debugInfo;
3224+
auto live = GetLiveVariablesAt(hlsl, "STOP_HERE", debugInfo);
3225+
CComPtr<IDxcPixVariable> variable;
3226+
VERIFY_SUCCEEDED(live->GetVariableByName(L"vector", &variable));
3227+
CComPtr<IDxcPixType> type;
3228+
VERIFY_SUCCEEDED(variable->GetType(&type));
3229+
3230+
CComPtr<IDxcPixType> unAliasedType;
3231+
VERIFY_SUCCEEDED(UnAliasType(type, &unAliasedType));
3232+
CComPtr<IDxcPixStructType> structType;
3233+
VERIFY_SUCCEEDED(unAliasedType->QueryInterface(IID_PPV_ARGS(&structType)));
3234+
3235+
DWORD fieldCount = 0;
3236+
VERIFY_SUCCEEDED(structType->GetNumFields(&fieldCount));
3237+
VERIFY_ARE_EQUAL(fieldCount, 4u);
3238+
3239+
for (size_t i = 0; i < memberOffsets.size(); i++) {
3240+
CComPtr<IDxcPixStructField> field;
3241+
VERIFY_SUCCEEDED(structType->GetFieldByIndex(i, &field));
3242+
DWORD offsetInBits = 0;
3243+
VERIFY_SUCCEEDED(field->GetOffsetInBits(&offsetInBits));
3244+
VERIFY_ARE_EQUAL(memberOffsets[i], offsetInBits);
3245+
}
3246+
}
3247+
31653248
TEST_F(PixDiaTest, DxcPixDxilDebugInfo_SubProgramsInNamespaces) {
31663249
if (m_ver.SkipDxilVersion(1, 2))
31673250
return;

0 commit comments

Comments
 (0)