@@ -728,6 +728,144 @@ class PixTest {
728728 std::vector<std::string> lines;
729729 };
730730
731+ std::string ExtractBracedSubstring (std::string const &line) {
732+ auto open = line.find (' {' );
733+ auto close = line.find (' }' );
734+ if (open != std::string::npos && close != std::string::npos &&
735+ open + 1 < close) {
736+ return line.substr (open + 1 , close - open - 1 );
737+ }
738+ return " " ;
739+ }
740+
741+ int ExtractMetaInt32Value (std::string const &token) {
742+ if (token.substr (0 , 5 ) == " i32 " ) {
743+ return atoi (token.c_str () + 5 );
744+ }
745+ return -1 ;
746+ }
747+
748+ std::map<int , std::pair<int , int >>
749+ MetaDataKeyToRegisterNumber (std::vector<std::string> const &lines) {
750+ // Find lines of the exemplary form
751+ // "!249 = !{i32 0, i32 20}" (in the case of a DXIL value)
752+ // "!196 = !{i32 1, i32 5, i32 1}" (in the case of a DXIL alloca reg)
753+ // The first i32 is a tag indicating what type of metadata this is.
754+ // It doesn't matter if we parse poorly and find some data that don't match
755+ // this pattern, as long as we do find all the data that do match (we won't
756+ // be looking up the non-matchers in the resultant map anyway).
757+
758+ constexpr char *valueMetaDataAssignment = " = !{i32 0, " ;
759+ constexpr char *allocaMetaDataAssignment = " = !{i32 1, " ;
760+
761+ std::map<int , std::pair<int , int >> ret;
762+ for (auto const &line : lines) {
763+ if (line[0 ] == ' !' ) {
764+ if (line.find (valueMetaDataAssignment) != std::string::npos ||
765+ line.find (allocaMetaDataAssignment) != std::string::npos) {
766+ int key = atoi (line.c_str () + 1 );
767+ if (key != 0 ) {
768+ std::string bitInBraces = ExtractBracedSubstring (line);
769+ if (bitInBraces != " " ) {
770+ auto tokens = Tokenize (bitInBraces.c_str (), " ," );
771+ if (tokens.size () == 2 ) {
772+ auto value = ExtractMetaInt32Value (tokens[1 ]);
773+ if (value != -1 ) {
774+ ret[key] = {value, 1 };
775+ }
776+ }
777+ if (tokens.size () == 3 ) {
778+ auto value0 = ExtractMetaInt32Value (tokens[1 ]);
779+ if (value0 != -1 ) {
780+ auto value1 = ExtractMetaInt32Value (tokens[2 ]);
781+ if (value1 != -1 ) {
782+ ret[key] = {value0, value1};
783+ }
784+ }
785+ }
786+ }
787+ }
788+ }
789+ }
790+ }
791+ return ret;
792+ }
793+
794+ std::string ExtractValueName (std::string const &line) {
795+ auto foundEquals = line.find (' =' );
796+ if (foundEquals != std::string::npos && foundEquals > 4 ) {
797+ return line.substr (2 , foundEquals - 3 );
798+ }
799+ return " " ;
800+ }
801+
802+ using DxilRegisterToNameMap = std::map<std::pair<int , int >, std::string>;
803+
804+ void CheckForAndInsertMapEntryIfFound (
805+ DxilRegisterToNameMap ®isterToNameMap,
806+ std::map<int , std::pair<int , int >> const &metaDataKeyToValue,
807+ std::string const &line, char const *tag, size_t tagLength) {
808+ auto foundAlloca = line.find (tag);
809+ if (foundAlloca != std::string::npos) {
810+ auto valueName = ExtractValueName (line);
811+ if (valueName != " " ) {
812+ int key = atoi (line.c_str () + foundAlloca + tagLength);
813+ auto foundKey = metaDataKeyToValue.find (key);
814+ if (foundKey != metaDataKeyToValue.end ()) {
815+ registerToNameMap[foundKey->second ] = valueName;
816+ }
817+ }
818+ }
819+ }
820+
821+ // Here's some exemplary DXIL to help understand what's going on:
822+ //
823+ // %5 = alloca [1 x float], i32 0, !pix-alloca-reg !196
824+ // %25 = call float @dx.op.loadInput.f32(...), !pix-dxil-reg !255
825+ //
826+ // The %5 is an alloca name, and the %25 is a regular llvm value.
827+ // The meta-data tags !pix-alloca-reg and !pix-dxil-reg denote this,
828+ // and provide keys !196 and !255 respectively.
829+ // Those keys are then given values later on in the DXIL like this:
830+ //
831+ // !196 = !{i32 1, i32 5, i32 1} (5 is the base alloca, 1 is the offset into
832+ // it) !255 = !{i32 0, i32 23}
833+ //
834+ // So the task is first to find all of those key/value pairs and make a map
835+ // from e.g. !196 to, e.g., (5,1), and then to find all of the alloca and reg
836+ // tags and look up the keys in said map to build the map we're actually
837+ // looking for, with key->values like e.g. "%5"->(5,1) and "%25"->(23)
838+
839+ DxilRegisterToNameMap BuildDxilRegisterToNameMap (char const *disassembly) {
840+ DxilRegisterToNameMap ret;
841+
842+ auto lines = Tokenize (disassembly, " \n " );
843+
844+ auto metaDataKeyToValue = MetaDataKeyToRegisterNumber (lines);
845+
846+ for (auto const &line : lines) {
847+ if (line[0 ] == ' !' ) {
848+ // Stop searching for values when we've run into the metadata region of
849+ // the disassembly
850+ break ;
851+ }
852+ const char allocaTag[] = " !pix-alloca-reg !" ;
853+ CheckForAndInsertMapEntryIfFound (ret, metaDataKeyToValue, line, allocaTag,
854+ _countof (allocaTag) - 1 );
855+ const char valueTag[] = " !pix-dxil-reg !" ;
856+ CheckForAndInsertMapEntryIfFound (ret, metaDataKeyToValue, line, valueTag,
857+ _countof (valueTag) - 1 );
858+ }
859+ return ret;
860+ }
861+
862+ static std::string ToString (std::wstring from)
863+ {
864+ std::string ret;
865+ ret.assign (from.data (), from.data () + from.size ());
866+ return ret;
867+ }
868+
731869 PassOutput RunAnnotationPasses (IDxcBlob * dxil, int startingLineNumber = 0 )
732870 {
733871 CComPtr<IDxcOptimizer> pOptimizer;
@@ -752,39 +890,18 @@ class PixTest {
752890 outputText = reinterpret_cast <const char *>(pText->GetBufferPointer ());
753891 }
754892
755- auto lines = Tokenize (outputText, " \n " );
893+ auto disasm = ToString ( Disassemble (pOptimizedModule) );
756894
757- std::vector<ValueLocation> valueLocations ;
895+ auto registerToName = BuildDxilRegisterToNameMap (disasm. c_str ()) ;
758896
759- for (size_t line = 0 ; line < lines.size (); ++line) {
760- if (lines[line] == " Begin - dxil values to virtual register mapping" ) {
761- for (++line; line < lines.size (); ++line) {
762- if (lines[line] == " End - dxil values to virtual register mapping" ) {
763- break ;
764- }
897+ std::vector<ValueLocation> valueLocations;
765898
766- auto lineTokens = Tokenize (lines[line], " " );
767- VERIFY_IS_TRUE (lineTokens.size () >= 2 );
768- if (lineTokens[1 ] == " dxil" )
769- {
770- VERIFY_IS_TRUE (lineTokens.size () == 3 );
771- valueLocations.push_back ({atoi (lineTokens[2 ].c_str ()), 1 });
772- }
773- else if (lineTokens[1 ] == " alloca" )
774- {
775- VERIFY_IS_TRUE (lineTokens.size () == 4 );
776- valueLocations.push_back (
777- {atoi (lineTokens[2 ].c_str ()), atoi (lineTokens[3 ].c_str ())});
778- }
779- else
780- {
781- VERIFY_IS_TRUE (false );
782- }
783- }
784- }
899+ for (auto const & r2n : registerToName)
900+ {
901+ valueLocations.push_back ({r2n.first .first , r2n.first .second });
785902 }
786903
787- return { std::move (pOptimizedModule), std::move (valueLocations), std::move (lines ) };
904+ return { std::move (pOptimizedModule), std::move (valueLocations), Tokenize (outputText. c_str (), " \n " ) };
788905 }
789906
790907 std::wstring Disassemble (IDxcBlob * pProgram)
@@ -2126,10 +2243,10 @@ PixTest::TestableResults PixTest::TestStructAnnotationCase(
21262243 for (ValueLocation const &valueLocation :
21272244 passOutput.valueLocations ) // For each allocas and dxil values
21282245 {
2129- if (CurRegIdx == valueLocation.base ) {
2246+ if (CurRegIdx == valueLocation.base &&
2247+ valueLocation.count == cover.countOfMembers ) {
21302248 VERIFY_IS_FALSE (found);
21312249 found = true ;
2132- VERIFY_ARE_EQUAL (valueLocation.count , cover.countOfMembers );
21332250 }
21342251 }
21352252 VERIFY_IS_TRUE (found);
0 commit comments