1313#ifdef _WIN32
1414
1515#include < array>
16+ #include < set>
1617
1718#include " dxc/DxilContainer/DxilContainer.h"
1819#include " dxc/Support/WinIncludes.h"
@@ -186,6 +187,7 @@ class PixDiaTest {
186187 TEST_METHOD (DxcPixDxilDebugInfo_BitFields_Derived)
187188 TEST_METHOD (DxcPixDxilDebugInfo_BitFields_Bool)
188189 TEST_METHOD (DxcPixDxilDebugInfo_BitFields_Overlap)
190+ TEST_METHOD (DxcPixDxilDebugInfo_BitFields_uint64)
189191 TEST_METHOD (DxcPixDxilDebugInfo_Min16SizesAndOffsets_Enabled)
190192 TEST_METHOD (DxcPixDxilDebugInfo_Min16SizesAndOffsets_Disabled)
191193 TEST_METHOD (DxcPixDxilDebugInfo_Min16VectorOffsets_Enabled)
@@ -658,11 +660,11 @@ class PixDiaTest {
658660 const char *hlsl, const wchar_t *profile,
659661 const char *lineAtWhichToExamineVariables,
660662 std::vector<VariableComponentInfo> const &ExpectedVariables);
661- void RunSizeAndOffsetTestCase ( const char *hlsl,
662- std::array<DWORD, 4 > const &memberOffsets ,
663- std::array<DWORD, 4 > const &memberSizes ,
664- std::vector< const wchar_t *> extraArgs = {
665- L" -Od" });
663+ CComPtr<IDxcPixDxilStorage>
664+ RunSizeAndOffsetTestCase ( const char *hlsl ,
665+ std::array<DWORD, 4 > const &memberOffsets ,
666+ std::array<DWORD, 4 > const &memberSizes,
667+ std::vector< const wchar_t *> extraArgs = { L" -Od" });
666668 void RunVectorSizeAndOffsetTestCase (const char *hlsl,
667669 std::array<DWORD, 4 > const &memberOffsets,
668670 std::vector<const wchar_t *> extraArgs = {
@@ -2948,12 +2950,11 @@ void main()
29482950 VERIFY_ARE_EQUAL (32u , secondFieldOffset);
29492951}
29502952
2951- void PixDiaTest::RunSizeAndOffsetTestCase (
2952- const char *hlsl, std::array<DWORD, 4 > const &memberOffsets,
2953- std::array<DWORD, 4 > const &memberSizes,
2954- std::vector<const wchar_t *> extraArgs) {
2955- if (m_ver.SkipDxilVersion (1 , 5 ))
2956- return ;
2953+ CComPtr<IDxcPixDxilStorage>
2954+ PixDiaTest::RunSizeAndOffsetTestCase (const char *hlsl,
2955+ std::array<DWORD, 4 > const &memberOffsets,
2956+ std::array<DWORD, 4 > const &memberSizes,
2957+ std::vector<const wchar_t *> extraArgs) {
29572958 auto debugInfo =
29582959 CompileAndCreateDxcDebug (hlsl, L" cs_6_5" , nullptr , extraArgs).debugInfo ;
29592960 auto live = GetLiveVariablesAt (hlsl, " STOP_HERE" , debugInfo);
@@ -2974,9 +2975,46 @@ void PixDiaTest::RunSizeAndOffsetTestCase(
29742975 VERIFY_SUCCEEDED (field->GetFieldSizeInBits (&sizeInBits));
29752976 VERIFY_ARE_EQUAL (memberSizes[i], sizeInBits);
29762977 }
2978+ // Check that first and second and third are reported as residing in the same
2979+ // register (cuz they do!), and that the third does not
2980+
2981+ CComPtr<IDxcPixDxilStorage> bfStorage;
2982+ VERIFY_SUCCEEDED (bf->GetStorage (&bfStorage));
2983+ return bfStorage;
2984+ }
2985+
2986+ void RunBitfieldAdjacencyTest (
2987+ IDxcPixDxilStorage *bfStorage,
2988+ std::vector<std::vector<wchar_t const *>> const &adjacentRuns) {
2989+ std::vector<std::set<DWORD>> registersByRun;
2990+ registersByRun.resize (adjacentRuns.size ());
2991+ for (size_t run = 0 ; run < adjacentRuns.size (); ++run) {
2992+ for (auto const &field : adjacentRuns[run]) {
2993+ CComPtr<IDxcPixDxilStorage> fieldStorage;
2994+ VERIFY_SUCCEEDED (bfStorage->AccessField (field, &fieldStorage));
2995+ DWORD reg;
2996+ VERIFY_SUCCEEDED (fieldStorage->GetRegisterNumber (®));
2997+ registersByRun[run].insert (reg);
2998+ }
2999+ }
3000+ for (size_t run = 0 ; run < registersByRun.size (); ++run) {
3001+ {
3002+ // Every field in this run should have the same register number, so this
3003+ // set should be of size 1:
3004+ VERIFY_ARE_EQUAL (1 , registersByRun[run].size ());
3005+ // Every adjacent run should have different register numbers:
3006+ if (run != 0 ) {
3007+ VERIFY_ARE_NOT_EQUAL (*registersByRun[run - 1 ].begin (),
3008+ *registersByRun[run].begin ());
3009+ }
3010+ }
3011+ }
29773012}
29783013
29793014TEST_F (PixDiaTest, DxcPixDxilDebugInfo_BitFields_Simple) {
3015+ if (m_ver.SkipDxilVersion (1 , 5 ))
3016+ return ;
3017+
29803018 const char *hlsl = R"(
29813019struct Bitfields
29823020{
@@ -3000,10 +3038,16 @@ void main()
30003038}
30013039
30023040)" ;
3003- RunSizeAndOffsetTestCase (hlsl, {0 , 17 , 32 , 64 }, {17 , 15 , 3 , 32 });
3041+ auto bfStorage =
3042+ RunSizeAndOffsetTestCase (hlsl, {0 , 17 , 32 , 64 }, {17 , 15 , 3 , 32 });
3043+ RunBitfieldAdjacencyTest (bfStorage,
3044+ {{L" first" , L" second" }, {L" third" }, {L" fourth" }});
30043045}
30053046
30063047TEST_F (PixDiaTest, DxcPixDxilDebugInfo_BitFields_Derived) {
3048+ if (m_ver.SkipDxilVersion (1 , 5 ))
3049+ return ;
3050+
30073051 const char *hlsl = R"(
30083052struct Bitfields
30093053{
@@ -3027,10 +3071,16 @@ void main()
30273071}
30283072
30293073)" ;
3030- RunSizeAndOffsetTestCase (hlsl, {0 , 17 , 32 , 64 }, {17 , 15 , 3 , 32 });
3074+ auto bfStorage =
3075+ RunSizeAndOffsetTestCase (hlsl, {0 , 17 , 32 , 64 }, {17 , 15 , 3 , 32 });
3076+ RunBitfieldAdjacencyTest (bfStorage,
3077+ {{L" first" , L" second" }, {L" third" }, {L" fourth" }});
30313078}
30323079
30333080TEST_F (PixDiaTest, DxcPixDxilDebugInfo_BitFields_Bool) {
3081+ if (m_ver.SkipDxilVersion (1 , 5 ))
3082+ return ;
3083+
30343084 const char *hlsl = R"(
30353085struct Bitfields
30363086{
@@ -3054,17 +3104,58 @@ void main()
30543104}
30553105
30563106)" ;
3057- RunSizeAndOffsetTestCase (hlsl, {0 , 1 , 2 , 32 }, {1 , 1 , 3 , 32 });
3107+ auto bfStorage = RunSizeAndOffsetTestCase (hlsl, {0 , 1 , 2 , 32 }, {1 , 1 , 3 , 32 });
3108+ RunBitfieldAdjacencyTest (bfStorage,
3109+ {{L" first" , L" second" , L" third" }, {L" fourth" }});
30583110}
30593111
30603112TEST_F (PixDiaTest, DxcPixDxilDebugInfo_BitFields_Overlap) {
3113+ if (m_ver.SkipDxilVersion (1 , 5 ))
3114+ return ;
3115+
3116+ const char *hlsl = R"(
3117+ struct Bitfields
3118+ {
3119+ uint32_t first : 20;
3120+ uint32_t second : 20; // should end up in second DWORD
3121+ uint32_t third : 3; // should shader second DWORD
3122+ uint32_t fourth; // should be in third DWORD
3123+ };
3124+
3125+ RWStructuredBuffer<int> UAV: register(u0);
3126+
3127+ [numthreads(1, 1, 1)]
3128+ void main()
3129+ {
3130+ Bitfields bf;
3131+ bf.first = UAV[0];
3132+ bf.second = UAV[1];
3133+ bf.third = UAV[2];
3134+ bf.fourth = UAV[3];
3135+ UAV[16] = bf.first + bf.second + bf.third + bf.fourth; //STOP_HERE
3136+ }
3137+
3138+ )" ;
3139+ auto bfStorage =
3140+ RunSizeAndOffsetTestCase (hlsl, {0 , 32 , 52 , 64 }, {20 , 20 , 3 , 32 });
3141+ // (PIX #58022343): fields that overlap their storage type are not yet
3142+ // reflected properly in terms of their packed offsets as maintained via
3143+ // these PixDxc interfaces based on the dbg.declare data
3144+ // RunBitfieldAdjacencyTest(bfStorage,
3145+ // {{L"first"}, {L"second", L"third"}, {L"fourth"}});
3146+ }
3147+
3148+ TEST_F (PixDiaTest, DxcPixDxilDebugInfo_BitFields_uint64) {
3149+ if (m_ver.SkipDxilVersion (1 , 5 ))
3150+ return ;
3151+
30613152 const char *hlsl = R"(
30623153struct Bitfields
30633154{
3064- unsigned int first : 20;
3065- unsigned int second : 20; // should end up in second DWORD
3066- unsigned int third : 3 ; // should shader second DWORD
3067- unsigned int fourth; // should be in third DWORD
3155+ uint64_t first : 20;
3156+ uint64_t second : 20; // should end up in first uint64 also
3157+ uint64_t third : 24 ; // in first
3158+ uint64_t fourth; // should be in second
30683159};
30693160
30703161RWStructuredBuffer<int> UAV: register(u0);
@@ -3081,7 +3172,10 @@ void main()
30813172}
30823173
30833174)" ;
3084- RunSizeAndOffsetTestCase (hlsl, {0 , 32 , 52 , 64 }, {20 , 20 , 3 , 32 });
3175+ auto bfStorage =
3176+ RunSizeAndOffsetTestCase (hlsl, {0 , 20 , 40 , 64 }, {20 , 20 , 24 , 64 });
3177+ RunBitfieldAdjacencyTest (bfStorage,
3178+ {{L" first" , L" second" , L" third" }, {L" fourth" }});
30853179}
30863180
30873181TEST_F (PixDiaTest, DxcPixDxilDebugInfo_Alignment_ConstInt) {
@@ -3502,9 +3596,10 @@ void ClosestHitShader3(inout RayPayload payload, in BuiltInTriangleIntersectionA
35023596
35033597 // Case: same function called from two places in same top-level function.
35043598 // In this case, we expect the storage for the variable to be in the same
3505- // place for both "instances" of the function: as a thread proceeds through
3506- // the caller, it will write new values into the variable's storage during
3507- // the second or subsequent invocations of the inlined function.
3599+ // place for both "instances" of the function: as a thread proceeds
3600+ // through the caller, it will write new values into the variable's
3601+ // storage during the second or subsequent invocations of the inlined
3602+ // function.
35083603 DWORD instructionOffset =
35093604 AdvanceUntilFunctionEntered (dxilDebugger, 0 , L" ClosestHitShader3" );
35103605 instructionOffset = AdvanceUntilFunctionEntered (
@@ -3550,9 +3645,10 @@ TEST_F(PixDiaTest, DxcPixDxilDebugInfo_VariableScopes_ForScopes) {
35503645
35513646 // Case: same function called from two places in same top-level function.
35523647 // In this case, we expect the storage for the variable to be in the same
3553- // place for both "instances" of the function: as a thread proceeds through
3554- // the caller, it will write new values into the variable's storage during
3555- // the second or subsequent invocations of the inlined function.
3648+ // place for both "instances" of the function: as a thread proceeds
3649+ // through the caller, it will write new values into the variable's
3650+ // storage during the second or subsequent invocations of the inlined
3651+ // function.
35563652 DWORD instructionOffset =
35573653 AdvanceUntilFunctionEntered (dxilDebugger, 0 , L" CSMain" );
35583654
@@ -3597,9 +3693,10 @@ TEST_F(PixDiaTest, DxcPixDxilDebugInfo_VariableScopes_ScopeBraces) {
35973693
35983694 // Case: same function called from two places in same top-level function.
35993695 // In this case, we expect the storage for the variable to be in the same
3600- // place for both "instances" of the function: as a thread proceeds through
3601- // the caller, it will write new values into the variable's storage during
3602- // the second or subsequent invocations of the inlined function.
3696+ // place for both "instances" of the function: as a thread proceeds
3697+ // through the caller, it will write new values into the variable's
3698+ // storage during the second or subsequent invocations of the inlined
3699+ // function.
36033700 DWORD instructionOffset =
36043701 AdvanceUntilFunctionEntered (dxilDebugger, 0 , L" CSMain" );
36053702
@@ -3644,9 +3741,10 @@ TEST_F(PixDiaTest, DxcPixDxilDebugInfo_VariableScopes_Function) {
36443741
36453742 // Case: same function called from two places in same top-level function.
36463743 // In this case, we expect the storage for the variable to be in the same
3647- // place for both "instances" of the function: as a thread proceeds through
3648- // the caller, it will write new values into the variable's storage during
3649- // the second or subsequent invocations of the inlined function.
3744+ // place for both "instances" of the function: as a thread proceeds
3745+ // through the caller, it will write new values into the variable's
3746+ // storage during the second or subsequent invocations of the inlined
3747+ // function.
36503748 DWORD instructionOffset =
36513749 AdvanceUntilFunctionEntered (dxilDebugger, 0 , L" CSMain" );
36523750
@@ -3692,9 +3790,10 @@ void CSMain()
36923790
36933791 // Case: same function called from two places in same top-level function.
36943792 // In this case, we expect the storage for the variable to be in the same
3695- // place for both "instances" of the function: as a thread proceeds through
3696- // the caller, it will write new values into the variable's storage during
3697- // the second or subsequent invocations of the inlined function.
3793+ // place for both "instances" of the function: as a thread proceeds
3794+ // through the caller, it will write new values into the variable's
3795+ // storage during the second or subsequent invocations of the inlined
3796+ // function.
36983797 DWORD instructionOffset =
36993798 AdvanceUntilFunctionEntered (dxilDebugger, 0 , L" CSMain" );
37003799
0 commit comments