PixTest.cpp 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // PixTest.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides tests for the PIX-specific components //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. // This whole file is win32-only
  12. #ifdef _WIN32
  13. #ifndef UNICODE
  14. #define UNICODE
  15. #endif
  16. #include <memory>
  17. #include <vector>
  18. #include <string>
  19. #include <map>
  20. #include <cassert>
  21. #include <sstream>
  22. #include <algorithm>
  23. #include <cfloat>
  24. #include "dxc/DxilContainer/DxilContainer.h"
  25. #include "dxc/Support/WinIncludes.h"
  26. #include "dxc/dxcapi.h"
  27. #include "dxc/dxcpix.h"
  28. #include <atlfile.h>
  29. #include "dia2.h"
  30. #include "dxc/DXIL/DxilModule.h"
  31. #include "dxc/Test/HLSLTestData.h"
  32. #include "dxc/Test/HlslTestUtils.h"
  33. #include "dxc/Test/DxcTestUtils.h"
  34. #include "llvm/Support/raw_os_ostream.h"
  35. #include "dxc/Support/Global.h"
  36. #include "dxc/Support/dxcapi.use.h"
  37. #include "dxc/Support/microcom.h"
  38. #include "dxc/Support/HLSLOptions.h"
  39. #include "dxc/Support/Unicode.h"
  40. #include <fstream>
  41. #include "llvm/Bitcode/ReaderWriter.h"
  42. #include "llvm/IR/Instructions.h"
  43. #include "llvm/IR/Intrinsics.h"
  44. #include "llvm/IR/IntrinsicInst.h"
  45. #include "llvm/IR/LLVMContext.h"
  46. #include "llvm/IR/Module.h"
  47. #include "llvm/IR/ModuleSlotTracker.h"
  48. #include "llvm/Support/FileSystem.h"
  49. #include "llvm/Support/MemoryBuffer.h"
  50. #include "llvm/Support/MSFileSystem.h"
  51. #include "llvm/Support/Path.h"
  52. #include "llvm/ADT/SmallString.h"
  53. #include "llvm/ADT/StringSwitch.h"
  54. #include <../lib/DxilDia/DxilDiaSession.h>
  55. #include <../lib/DxilDia/DxcPixLiveVariables.h>
  56. #include <../lib/DxilDia/DxcPixLiveVariables_FragmentIterator.h>
  57. #include <dxc/DxilPIXPasses/DxilPIXVirtualRegisters.h>
  58. using namespace std;
  59. using namespace hlsl;
  60. using namespace hlsl_test;
  61. // Aligned to SymTagEnum.
  62. const char *SymTagEnumText[] = {
  63. "Null", // SymTagNull
  64. "Exe", // SymTagExe
  65. "Compiland", // SymTagCompiland
  66. "CompilandDetails", // SymTagCompilandDetails
  67. "CompilandEnv", // SymTagCompilandEnv
  68. "Function", // SymTagFunction
  69. "Block", // SymTagBlock
  70. "Data", // SymTagData
  71. "Annotation", // SymTagAnnotation
  72. "Label", // SymTagLabel
  73. "PublicSymbol", // SymTagPublicSymbol
  74. "UDT", // SymTagUDT
  75. "Enum", // SymTagEnum
  76. "FunctionType", // SymTagFunctionType
  77. "PointerType", // SymTagPointerType
  78. "ArrayType", // SymTagArrayType
  79. "BaseType", // SymTagBaseType
  80. "Typedef", // SymTagTypedef
  81. "BaseClass", // SymTagBaseClass
  82. "Friend", // SymTagFriend
  83. "FunctionArgType", // SymTagFunctionArgType
  84. "FuncDebugStart", // SymTagFuncDebugStart
  85. "FuncDebugEnd", // SymTagFuncDebugEnd
  86. "UsingNamespace", // SymTagUsingNamespace
  87. "VTableShape", // SymTagVTableShape
  88. "VTable", // SymTagVTable
  89. "Custom", // SymTagCustom
  90. "Thunk", // SymTagThunk
  91. "CustomType", // SymTagCustomType
  92. "ManagedType", // SymTagManagedType
  93. "Dimension", // SymTagDimension
  94. "CallSite", // SymTagCallSite
  95. "InlineSite", // SymTagInlineSite
  96. "BaseInterface", // SymTagBaseInterface
  97. "VectorType", // SymTagVectorType
  98. "MatrixType", // SymTagMatrixType
  99. "HLSLType", // SymTagHLSLType
  100. "Caller", // SymTagCaller
  101. "Callee", // SymTagCallee
  102. "Export", // SymTagExport
  103. "HeapAllocationSite", // SymTagHeapAllocationSite
  104. "CoffGroup", // SymTagCoffGroup
  105. };
  106. // Aligned to LocationType.
  107. const char* LocationTypeText[] =
  108. {
  109. "Null",
  110. "Static",
  111. "TLS",
  112. "RegRel",
  113. "ThisRel",
  114. "Enregistered",
  115. "BitField",
  116. "Slot",
  117. "IlRel",
  118. "MetaData",
  119. "Constant",
  120. };
  121. // Aligned to DataKind.
  122. const char* DataKindText[] =
  123. {
  124. "Unknown",
  125. "Local",
  126. "StaticLocal",
  127. "Param",
  128. "ObjectPtr",
  129. "FileStatic",
  130. "Global",
  131. "Member",
  132. "StaticMember",
  133. "Constant",
  134. };
  135. // Aligned to UdtKind.
  136. const char* UdtKindText[] =
  137. {
  138. "Struct",
  139. "Class",
  140. "Union",
  141. "Interface",
  142. };
  143. static std::vector<std::string> Tokenize(const std::string &str,
  144. const char *delimiters) {
  145. std::vector<std::string> tokens;
  146. std::string copy = str;
  147. for (auto i = strtok(&copy[0], delimiters); i != nullptr;
  148. i = strtok(nullptr, delimiters)) {
  149. tokens.push_back(i);
  150. }
  151. return tokens;
  152. }
  153. class PixTest {
  154. public:
  155. BEGIN_TEST_CLASS(PixTest)
  156. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  157. TEST_METHOD_PROPERTY(L"Priority", L"0")
  158. END_TEST_CLASS()
  159. TEST_CLASS_SETUP(InitSupport);
  160. TEST_METHOD(CompileWhenDebugThenDIPresent)
  161. TEST_METHOD(CompileDebugLines)
  162. TEST_METHOD(CompileDebugPDB)
  163. TEST_METHOD(CompileDebugDisasmPDB)
  164. TEST_METHOD(DiaLoadBadBitcodeThenFail)
  165. TEST_METHOD(DiaLoadDebugThenOK)
  166. TEST_METHOD(DiaTableIndexThenOK)
  167. TEST_METHOD(DiaLoadDebugSubrangeNegativeThenOK)
  168. TEST_METHOD(DiaLoadRelocatedBitcode)
  169. TEST_METHOD(DiaLoadBitcodePlusExtraData)
  170. TEST_METHOD(DiaCompileArgs)
  171. TEST_METHOD(PixDebugCompileInfo)
  172. TEST_METHOD(PixStructAnnotation_Simple)
  173. TEST_METHOD(PixStructAnnotation_CopiedStruct)
  174. TEST_METHOD(PixStructAnnotation_MixedSizes)
  175. TEST_METHOD(PixStructAnnotation_StructWithinStruct)
  176. TEST_METHOD(PixStructAnnotation_1DArray)
  177. TEST_METHOD(PixStructAnnotation_2DArray)
  178. TEST_METHOD(PixStructAnnotation_EmbeddedArray)
  179. TEST_METHOD(PixStructAnnotation_FloatN)
  180. TEST_METHOD(PixStructAnnotation_SequentialFloatN)
  181. TEST_METHOD(PixStructAnnotation_EmbeddedFloatN)
  182. TEST_METHOD(PixStructAnnotation_Matrix)
  183. TEST_METHOD(PixStructAnnotation_BigMess)
  184. dxc::DxcDllSupport m_dllSupport;
  185. void CreateBlobPinned(_In_bytecount_(size) LPCVOID data, SIZE_T size,
  186. UINT32 codePage, _Outptr_ IDxcBlobEncoding **ppBlob) {
  187. CComPtr<IDxcLibrary> library;
  188. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  189. IFT(library->CreateBlobWithEncodingFromPinned(data, size, codePage,
  190. ppBlob));
  191. }
  192. void CreateBlobFromFile(LPCWSTR name, _Outptr_ IDxcBlobEncoding **ppBlob) {
  193. CComPtr<IDxcLibrary> library;
  194. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  195. const std::wstring path = hlsl_test::GetPathToHlslDataFile(name);
  196. IFT(library->CreateBlobFromFile(path.c_str(), nullptr, ppBlob));
  197. }
  198. void CreateBlobFromText(_In_z_ const char *pText,
  199. _Outptr_ IDxcBlobEncoding **ppBlob) {
  200. CreateBlobPinned(pText, strlen(pText) + 1, CP_UTF8, ppBlob);
  201. }
  202. HRESULT CreateCompiler(IDxcCompiler **ppResult) {
  203. return m_dllSupport.CreateInstance(CLSID_DxcCompiler, ppResult);
  204. }
  205. HRESULT CreateContainerBuilder(IDxcContainerBuilder **ppResult) {
  206. return m_dllSupport.CreateInstance(CLSID_DxcContainerBuilder, ppResult);
  207. }
  208. template <typename T, typename TDefault, typename TIface>
  209. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  210. TDefault defaultValue, LPCWSTR valueLabel,
  211. HRESULT (__stdcall TIface::*pFn)(T *)) {
  212. T value;
  213. HRESULT hr = (pSymbol->*(pFn))(&value);
  214. if (SUCCEEDED(hr) && value != defaultValue) {
  215. o << L", " << valueLabel << L": " << value;
  216. }
  217. }
  218. template <typename TIface>
  219. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  220. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(BSTR *)) {
  221. CComBSTR value;
  222. HRESULT hr = (pSymbol->*(pFn))(&value);
  223. if (SUCCEEDED(hr) && value.Length()) {
  224. o << L", " << valueLabel << L": " << (LPCWSTR)value;
  225. }
  226. }
  227. template <typename TIface>
  228. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  229. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(VARIANT *)) {
  230. CComVariant value;
  231. HRESULT hr = (pSymbol->*(pFn))(&value);
  232. if (SUCCEEDED(hr) && value.vt != VT_NULL && value.vt != VT_EMPTY) {
  233. if (SUCCEEDED(value.ChangeType(VT_BSTR))) {
  234. o << L", " << valueLabel << L": " << (LPCWSTR)value.bstrVal;
  235. }
  236. }
  237. }
  238. template <typename TIface>
  239. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  240. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(IDiaSymbol **)) {
  241. CComPtr<IDiaSymbol> value;
  242. HRESULT hr = (pSymbol->*(pFn))(&value);
  243. if (SUCCEEDED(hr) && value.p != nullptr) {
  244. DWORD symId;
  245. value->get_symIndexId(&symId);
  246. o << L", " << valueLabel << L": id=" << symId;
  247. }
  248. }
  249. std::wstring GetDebugInfoAsText(_In_ IDiaDataSource* pDataSource) {
  250. CComPtr<IDiaSession> pSession;
  251. CComPtr<IDiaTable> pTable;
  252. CComPtr<IDiaEnumTables> pEnumTables;
  253. std::wstringstream o;
  254. VERIFY_SUCCEEDED(pDataSource->openSession(&pSession));
  255. VERIFY_SUCCEEDED(pSession->getEnumTables(&pEnumTables));
  256. LONG count;
  257. VERIFY_SUCCEEDED(pEnumTables->get_Count(&count));
  258. for (LONG i = 0; i < count; ++i) {
  259. pTable.Release();
  260. ULONG fetched;
  261. VERIFY_SUCCEEDED(pEnumTables->Next(1, &pTable, &fetched));
  262. VERIFY_ARE_EQUAL(fetched, 1);
  263. CComBSTR tableName;
  264. VERIFY_SUCCEEDED(pTable->get_name(&tableName));
  265. o << L"Table: " << (LPWSTR)tableName << std::endl;
  266. LONG rowCount;
  267. IFT(pTable->get_Count(&rowCount));
  268. o << L" Row count: " << rowCount << std::endl;
  269. for (LONG rowIndex = 0; rowIndex < rowCount; ++rowIndex) {
  270. CComPtr<IUnknown> item;
  271. o << L'#' << rowIndex;
  272. IFT(pTable->Item(rowIndex, &item));
  273. CComPtr<IDiaSymbol> pSymbol;
  274. if (SUCCEEDED(item.QueryInterface(&pSymbol))) {
  275. DWORD symTag;
  276. DWORD dataKind;
  277. DWORD locationType;
  278. DWORD registerId;
  279. pSymbol->get_symTag(&symTag);
  280. pSymbol->get_dataKind(&dataKind);
  281. pSymbol->get_locationType(&locationType);
  282. pSymbol->get_registerId(&registerId);
  283. //pSymbol->get_value(&value);
  284. WriteIfValue(pSymbol.p, o, 0, L"symIndexId", &IDiaSymbol::get_symIndexId);
  285. o << L", " << SymTagEnumText[symTag];
  286. if (dataKind != 0) o << L", " << DataKindText[dataKind];
  287. WriteIfValue(pSymbol.p, o, L"name", &IDiaSymbol::get_name);
  288. WriteIfValue(pSymbol.p, o, L"lexicalParent", &IDiaSymbol::get_lexicalParent);
  289. WriteIfValue(pSymbol.p, o, L"type", &IDiaSymbol::get_type);
  290. WriteIfValue(pSymbol.p, o, 0, L"slot", &IDiaSymbol::get_slot);
  291. WriteIfValue(pSymbol.p, o, 0, L"platform", &IDiaSymbol::get_platform);
  292. WriteIfValue(pSymbol.p, o, 0, L"language", &IDiaSymbol::get_language);
  293. WriteIfValue(pSymbol.p, o, 0, L"frontEndMajor", &IDiaSymbol::get_frontEndMajor);
  294. WriteIfValue(pSymbol.p, o, 0, L"frontEndMinor", &IDiaSymbol::get_frontEndMinor);
  295. WriteIfValue(pSymbol.p, o, 0, L"token", &IDiaSymbol::get_token);
  296. WriteIfValue(pSymbol.p, o, L"value", &IDiaSymbol::get_value);
  297. WriteIfValue(pSymbol.p, o, 0, L"code", &IDiaSymbol::get_code);
  298. WriteIfValue(pSymbol.p, o, 0, L"function", &IDiaSymbol::get_function);
  299. WriteIfValue(pSymbol.p, o, 0, L"udtKind", &IDiaSymbol::get_udtKind);
  300. WriteIfValue(pSymbol.p, o, 0, L"hasDebugInfo", &IDiaSymbol::get_hasDebugInfo);
  301. WriteIfValue(pSymbol.p, o, L"compilerName", &IDiaSymbol::get_compilerName);
  302. WriteIfValue(pSymbol.p, o, 0, L"isLocationControlFlowDependent", &IDiaSymbol::get_isLocationControlFlowDependent);
  303. WriteIfValue(pSymbol.p, o, 0, L"numberOfRows", &IDiaSymbol::get_numberOfRows);
  304. WriteIfValue(pSymbol.p, o, 0, L"numberOfColumns", &IDiaSymbol::get_numberOfColumns);
  305. WriteIfValue(pSymbol.p, o, 0, L"length", &IDiaSymbol::get_length);
  306. WriteIfValue(pSymbol.p, o, 0, L"isMatrixRowMajor", &IDiaSymbol::get_isMatrixRowMajor);
  307. WriteIfValue(pSymbol.p, o, 0, L"builtInKind", &IDiaSymbol::get_builtInKind);
  308. WriteIfValue(pSymbol.p, o, 0, L"textureSlot", &IDiaSymbol::get_textureSlot);
  309. WriteIfValue(pSymbol.p, o, 0, L"memorySpaceKind", &IDiaSymbol::get_memorySpaceKind);
  310. WriteIfValue(pSymbol.p, o, 0, L"isHLSLData", &IDiaSymbol::get_isHLSLData);
  311. }
  312. CComPtr<IDiaSourceFile> pSourceFile;
  313. if (SUCCEEDED(item.QueryInterface(&pSourceFile))) {
  314. WriteIfValue(pSourceFile.p, o, 0, L"uniqueId", &IDiaSourceFile::get_uniqueId);
  315. WriteIfValue(pSourceFile.p, o, L"fileName", &IDiaSourceFile::get_fileName);
  316. }
  317. CComPtr<IDiaLineNumber> pLineNumber;
  318. if (SUCCEEDED(item.QueryInterface(&pLineNumber))) {
  319. WriteIfValue(pLineNumber.p, o, L"compiland", &IDiaLineNumber::get_compiland);
  320. //WriteIfValue(pLineNumber.p, o, L"sourceFile", &IDiaLineNumber::get_sourceFile);
  321. WriteIfValue(pLineNumber.p, o, 0, L"lineNumber", &IDiaLineNumber::get_lineNumber);
  322. WriteIfValue(pLineNumber.p, o, 0, L"lineNumberEnd", &IDiaLineNumber::get_lineNumberEnd);
  323. WriteIfValue(pLineNumber.p, o, 0, L"columnNumber", &IDiaLineNumber::get_columnNumber);
  324. WriteIfValue(pLineNumber.p, o, 0, L"columnNumberEnd", &IDiaLineNumber::get_columnNumberEnd);
  325. WriteIfValue(pLineNumber.p, o, 0, L"addressSection", &IDiaLineNumber::get_addressSection);
  326. WriteIfValue(pLineNumber.p, o, 0, L"addressOffset", &IDiaLineNumber::get_addressOffset);
  327. WriteIfValue(pLineNumber.p, o, 0, L"relativeVirtualAddress", &IDiaLineNumber::get_relativeVirtualAddress);
  328. WriteIfValue(pLineNumber.p, o, 0, L"virtualAddress", &IDiaLineNumber::get_virtualAddress);
  329. WriteIfValue(pLineNumber.p, o, 0, L"length", &IDiaLineNumber::get_length);
  330. WriteIfValue(pLineNumber.p, o, 0, L"sourceFileId", &IDiaLineNumber::get_sourceFileId);
  331. WriteIfValue(pLineNumber.p, o, 0, L"statement", &IDiaLineNumber::get_statement);
  332. WriteIfValue(pLineNumber.p, o, 0, L"compilandId", &IDiaLineNumber::get_compilandId);
  333. }
  334. CComPtr<IDiaSectionContrib> pSectionContrib;
  335. if (SUCCEEDED(item.QueryInterface(&pSectionContrib))) {
  336. WriteIfValue(pSectionContrib.p, o, L"compiland", &IDiaSectionContrib::get_compiland);
  337. WriteIfValue(pSectionContrib.p, o, 0, L"addressSection", &IDiaSectionContrib::get_addressSection);
  338. WriteIfValue(pSectionContrib.p, o, 0, L"addressOffset", &IDiaSectionContrib::get_addressOffset);
  339. WriteIfValue(pSectionContrib.p, o, 0, L"relativeVirtualAddress", &IDiaSectionContrib::get_relativeVirtualAddress);
  340. WriteIfValue(pSectionContrib.p, o, 0, L"virtualAddress", &IDiaSectionContrib::get_virtualAddress);
  341. WriteIfValue(pSectionContrib.p, o, 0, L"length", &IDiaSectionContrib::get_length);
  342. WriteIfValue(pSectionContrib.p, o, 0, L"notPaged", &IDiaSectionContrib::get_notPaged);
  343. WriteIfValue(pSectionContrib.p, o, 0, L"code", &IDiaSectionContrib::get_code);
  344. WriteIfValue(pSectionContrib.p, o, 0, L"initializedData", &IDiaSectionContrib::get_initializedData);
  345. WriteIfValue(pSectionContrib.p, o, 0, L"uninitializedData", &IDiaSectionContrib::get_uninitializedData);
  346. WriteIfValue(pSectionContrib.p, o, 0, L"remove", &IDiaSectionContrib::get_remove);
  347. WriteIfValue(pSectionContrib.p, o, 0, L"comdat", &IDiaSectionContrib::get_comdat);
  348. WriteIfValue(pSectionContrib.p, o, 0, L"discardable", &IDiaSectionContrib::get_discardable);
  349. WriteIfValue(pSectionContrib.p, o, 0, L"notCached", &IDiaSectionContrib::get_notCached);
  350. WriteIfValue(pSectionContrib.p, o, 0, L"share", &IDiaSectionContrib::get_share);
  351. WriteIfValue(pSectionContrib.p, o, 0, L"execute", &IDiaSectionContrib::get_execute);
  352. WriteIfValue(pSectionContrib.p, o, 0, L"read", &IDiaSectionContrib::get_read);
  353. WriteIfValue(pSectionContrib.p, o, 0, L"write", &IDiaSectionContrib::get_write);
  354. WriteIfValue(pSectionContrib.p, o, 0, L"dataCrc", &IDiaSectionContrib::get_dataCrc);
  355. WriteIfValue(pSectionContrib.p, o, 0, L"relocationsCrc", &IDiaSectionContrib::get_relocationsCrc);
  356. WriteIfValue(pSectionContrib.p, o, 0, L"compilandId", &IDiaSectionContrib::get_compilandId);
  357. }
  358. CComPtr<IDiaSegment> pSegment;
  359. if (SUCCEEDED(item.QueryInterface(&pSegment))) {
  360. WriteIfValue(pSegment.p, o, 0, L"frame", &IDiaSegment::get_frame);
  361. WriteIfValue(pSegment.p, o, 0, L"offset", &IDiaSegment::get_offset);
  362. WriteIfValue(pSegment.p, o, 0, L"length", &IDiaSegment::get_length);
  363. WriteIfValue(pSegment.p, o, 0, L"read", &IDiaSegment::get_read);
  364. WriteIfValue(pSegment.p, o, 0, L"write", &IDiaSegment::get_write);
  365. WriteIfValue(pSegment.p, o, 0, L"execute", &IDiaSegment::get_execute);
  366. WriteIfValue(pSegment.p, o, 0, L"addressSection", &IDiaSegment::get_addressSection);
  367. WriteIfValue(pSegment.p, o, 0, L"relativeVirtualAddress", &IDiaSegment::get_relativeVirtualAddress);
  368. WriteIfValue(pSegment.p, o, 0, L"virtualAddress", &IDiaSegment::get_virtualAddress);
  369. }
  370. CComPtr<IDiaInjectedSource> pInjectedSource;
  371. if (SUCCEEDED(item.QueryInterface(&pInjectedSource))) {
  372. WriteIfValue(pInjectedSource.p, o, 0, L"crc", &IDiaInjectedSource::get_crc);
  373. WriteIfValue(pInjectedSource.p, o, 0, L"length", &IDiaInjectedSource::get_length);
  374. WriteIfValue(pInjectedSource.p, o, L"filename", &IDiaInjectedSource::get_filename);
  375. WriteIfValue(pInjectedSource.p, o, L"objectFilename", &IDiaInjectedSource::get_objectFilename);
  376. WriteIfValue(pInjectedSource.p, o, L"virtualFilename", &IDiaInjectedSource::get_virtualFilename);
  377. WriteIfValue(pInjectedSource.p, o, 0, L"sourceCompression", &IDiaInjectedSource::get_sourceCompression);
  378. // get_source is also available
  379. }
  380. CComPtr<IDiaFrameData> pFrameData;
  381. if (SUCCEEDED(item.QueryInterface(&pFrameData))) {
  382. }
  383. o << std::endl;
  384. }
  385. }
  386. return o.str();
  387. }
  388. std::wstring GetDebugFileContent(_In_ IDiaDataSource *pDataSource) {
  389. CComPtr<IDiaSession> pSession;
  390. CComPtr<IDiaTable> pTable;
  391. CComPtr<IDiaTable> pSourcesTable;
  392. CComPtr<IDiaEnumTables> pEnumTables;
  393. std::wstringstream o;
  394. VERIFY_SUCCEEDED(pDataSource->openSession(&pSession));
  395. VERIFY_SUCCEEDED(pSession->getEnumTables(&pEnumTables));
  396. ULONG fetched = 0;
  397. while (pEnumTables->Next(1, &pTable, &fetched) == S_OK && fetched == 1) {
  398. CComBSTR name;
  399. IFT(pTable->get_name(&name));
  400. if (wcscmp(name, L"SourceFiles") == 0) {
  401. pSourcesTable = pTable.Detach();
  402. continue;
  403. }
  404. pTable.Release();
  405. }
  406. if (!pSourcesTable) {
  407. return L"cannot find source";
  408. }
  409. // Get source file contents.
  410. // NOTE: "SourceFiles" has the root file first while "InjectedSources" is in
  411. // alphabetical order.
  412. // It is important to keep the root file first for recompilation, so
  413. // iterate "SourceFiles" and look up the corresponding injected
  414. // source.
  415. LONG count;
  416. IFT(pSourcesTable->get_Count(&count));
  417. CComPtr<IDiaSourceFile> pSourceFile;
  418. CComBSTR pName;
  419. CComPtr<IUnknown> pSymbolUnk;
  420. CComPtr<IDiaEnumInjectedSources> pEnumInjectedSources;
  421. CComPtr<IDiaInjectedSource> pInjectedSource;
  422. std::wstring sourceText, sourceFilename;
  423. while (SUCCEEDED(pSourcesTable->Next(1, &pSymbolUnk, &fetched)) &&
  424. fetched == 1) {
  425. sourceText = sourceFilename = L"";
  426. IFT(pSymbolUnk->QueryInterface(&pSourceFile));
  427. IFT(pSourceFile->get_fileName(&pName));
  428. IFT(pSession->findInjectedSource(pName, &pEnumInjectedSources));
  429. if (SUCCEEDED(pEnumInjectedSources->get_Count(&count)) && count == 1) {
  430. IFT(pEnumInjectedSources->Item(0, &pInjectedSource));
  431. DWORD cbData = 0;
  432. std::string tempString;
  433. CComBSTR bstr;
  434. IFT(pInjectedSource->get_filename(&bstr));
  435. IFT(pInjectedSource->get_source(0, &cbData, nullptr));
  436. tempString.resize(cbData);
  437. IFT(pInjectedSource->get_source(
  438. cbData, &cbData, reinterpret_cast<BYTE *>(&tempString[0])));
  439. CA2W tempWString(tempString.data());
  440. o << tempWString.m_psz;
  441. }
  442. pSymbolUnk.Release();
  443. }
  444. return o.str();
  445. }
  446. struct LineNumber { DWORD line; DWORD rva; };
  447. std::vector<LineNumber> ReadLineNumbers(IDiaEnumLineNumbers *pEnumLineNumbers) {
  448. std::vector<LineNumber> lines;
  449. CComPtr<IDiaLineNumber> pLineNumber;
  450. DWORD lineCount;
  451. while (SUCCEEDED(pEnumLineNumbers->Next(1, &pLineNumber, &lineCount)) && lineCount == 1)
  452. {
  453. DWORD line;
  454. DWORD rva;
  455. VERIFY_SUCCEEDED(pLineNumber->get_lineNumber(&line));
  456. VERIFY_SUCCEEDED(pLineNumber->get_relativeVirtualAddress(&rva));
  457. lines.push_back({ line, rva });
  458. pLineNumber.Release();
  459. }
  460. return lines;
  461. }
  462. std::string GetOption(std::string &cmd, char *opt) {
  463. std::string option = cmd.substr(cmd.find(opt));
  464. option = option.substr(option.find_first_of(' '));
  465. option = option.substr(option.find_first_not_of(' '));
  466. return option.substr(0, option.find_first_of(' '));
  467. }
  468. HRESULT CreateDiaSourceForCompile(const char* hlsl,
  469. IDiaDataSource** ppDiaSource)
  470. {
  471. if (!ppDiaSource)
  472. return E_POINTER;
  473. CComPtr<IDxcCompiler> pCompiler;
  474. CComPtr<IDxcOperationResult> pResult;
  475. CComPtr<IDxcBlobEncoding> pSource;
  476. CComPtr<IDxcBlob> pProgram;
  477. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  478. CreateBlobFromText(hlsl, &pSource);
  479. LPCWSTR args[] = { L"/Zi", L"/Qembed_debug" };
  480. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  481. L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pResult));
  482. HRESULT compilationStatus;
  483. VERIFY_SUCCEEDED(pResult->GetStatus(&compilationStatus));
  484. if (FAILED(compilationStatus))
  485. {
  486. CComPtr<IDxcBlobEncoding> pErrros;
  487. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrros));
  488. CA2W errorTextW(static_cast<const char *>(pErrros->GetBufferPointer()), CP_UTF8);
  489. WEX::Logging::Log::Error(errorTextW);
  490. }
  491. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  492. // Disassemble the compiled (stripped) program.
  493. {
  494. CComPtr<IDxcBlobEncoding> pDisassembly;
  495. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembly));
  496. std::string disText = BlobToUtf8(pDisassembly);
  497. CA2W disTextW(disText.c_str(), CP_UTF8);
  498. //WEX::Logging::Log::Comment(disTextW);
  499. }
  500. // CONSIDER: have the dia data source look for the part if passed a whole container.
  501. CComPtr<IDiaDataSource> pDiaSource;
  502. CComPtr<IStream> pProgramStream;
  503. CComPtr<IDxcLibrary> pLib;
  504. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  505. const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
  506. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  507. VERIFY_IS_NOT_NULL(pContainer);
  508. hlsl::DxilPartIterator partIter =
  509. std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer),
  510. hlsl::DxilPartIsType(hlsl::DFCC_ShaderDebugInfoDXIL));
  511. const hlsl::DxilProgramHeader *pProgramHeader =
  512. (const hlsl::DxilProgramHeader *)hlsl::GetDxilPartData(*partIter);
  513. uint32_t bitcodeLength;
  514. const char *pBitcode;
  515. CComPtr<IDxcBlob> pProgramPdb;
  516. hlsl::GetDxilProgramBitcode(pProgramHeader, &pBitcode, &bitcodeLength);
  517. VERIFY_SUCCEEDED(pLib->CreateBlobFromBlob(
  518. pProgram, pBitcode - (char *)pProgram->GetBufferPointer(), bitcodeLength,
  519. &pProgramPdb));
  520. // Disassemble the program with debug information.
  521. {
  522. CComPtr<IDxcBlobEncoding> pDbgDisassembly;
  523. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgramPdb, &pDbgDisassembly));
  524. std::string disText = BlobToUtf8(pDbgDisassembly);
  525. CA2W disTextW(disText.c_str(), CP_UTF8);
  526. //WEX::Logging::Log::Comment(disTextW);
  527. }
  528. // Create a short text dump of debug information.
  529. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pProgramPdb, &pProgramStream));
  530. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  531. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pProgramStream));
  532. *ppDiaSource = pDiaSource.Detach();
  533. return S_OK;
  534. }
  535. CComPtr<IDxcOperationResult> Compile(
  536. const char* hlsl,
  537. const wchar_t* target)
  538. {
  539. CComPtr<IDxcCompiler> pCompiler;
  540. CComPtr<IDxcOperationResult> pResult;
  541. CComPtr<IDxcBlobEncoding> pSource;
  542. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  543. CreateBlobFromText(hlsl, &pSource);
  544. LPCWSTR args[] = { L"/Zi", L"/Od", L"-enable-16bit-types", L"/Qembed_debug" };
  545. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  546. target, args, _countof(args), nullptr, 0, nullptr, &pResult));
  547. HRESULT compilationStatus;
  548. VERIFY_SUCCEEDED(pResult->GetStatus(&compilationStatus));
  549. if (FAILED(compilationStatus))
  550. {
  551. CComPtr<IDxcBlobEncoding> pErrros;
  552. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrros));
  553. CA2W errorTextW(static_cast<const char*>(pErrros->GetBufferPointer()), CP_UTF8);
  554. WEX::Logging::Log::Error(errorTextW);
  555. }
  556. #if 0 //handy for debugging
  557. {
  558. CComPtr<IDxcBlob> pProgram;
  559. CheckOperationSucceeded(pResult, &pProgram);
  560. CComPtr<IDxcLibrary> pLib;
  561. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  562. const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
  563. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  564. VERIFY_IS_NOT_NULL(pContainer);
  565. hlsl::DxilPartIterator partIter =
  566. std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer),
  567. hlsl::DxilPartIsType(hlsl::DFCC_ShaderDebugInfoDXIL));
  568. const hlsl::DxilProgramHeader *pProgramHeader =
  569. (const hlsl::DxilProgramHeader *)hlsl::GetDxilPartData(*partIter);
  570. uint32_t bitcodeLength;
  571. const char *pBitcode;
  572. CComPtr<IDxcBlob> pProgramPdb;
  573. hlsl::GetDxilProgramBitcode(pProgramHeader, &pBitcode, &bitcodeLength);
  574. VERIFY_SUCCEEDED(pLib->CreateBlobFromBlob(
  575. pProgram, pBitcode - (char *)pProgram->GetBufferPointer(),
  576. bitcodeLength, &pProgramPdb));
  577. CComPtr<IDxcBlobEncoding> pDbgDisassembly;
  578. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgramPdb, &pDbgDisassembly));
  579. std::string disText = BlobToUtf8(pDbgDisassembly);
  580. CA2W disTextW(disText.c_str(), CP_UTF8);
  581. WEX::Logging::Log::Comment(disTextW);
  582. }
  583. #endif
  584. return pResult;
  585. }
  586. CComPtr<IDxcBlob> ExtractDxilPart(IDxcBlob *pProgram) {
  587. CComPtr<IDxcLibrary> pLib;
  588. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  589. const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
  590. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  591. VERIFY_IS_NOT_NULL(pContainer);
  592. hlsl::DxilPartIterator partIter =
  593. std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer),
  594. hlsl::DxilPartIsType(hlsl::DFCC_DXIL));
  595. const hlsl::DxilProgramHeader *pProgramHeader =
  596. (const hlsl::DxilProgramHeader *)hlsl::GetDxilPartData(*partIter);
  597. uint32_t bitcodeLength;
  598. const char *pBitcode;
  599. CComPtr<IDxcBlob> pDxilBits;
  600. hlsl::GetDxilProgramBitcode(pProgramHeader, &pBitcode, &bitcodeLength);
  601. VERIFY_SUCCEEDED(pLib->CreateBlobFromBlob(
  602. pProgram, pBitcode - (char *)pProgram->GetBufferPointer(),
  603. bitcodeLength, &pDxilBits));
  604. return pDxilBits;
  605. }
  606. struct ValueLocation
  607. {
  608. int base;
  609. int count;
  610. };
  611. struct PassOutput
  612. {
  613. CComPtr<IDxcBlob> blob;
  614. std::vector<ValueLocation> valueLocations;
  615. };
  616. PassOutput RunAnnotationPasses(IDxcBlob * dxil)
  617. {
  618. CComPtr<IDxcOptimizer> pOptimizer;
  619. VERIFY_SUCCEEDED(
  620. m_dllSupport.CreateInstance(CLSID_DxcOptimizer, &pOptimizer));
  621. std::vector<LPCWSTR> Options;
  622. Options.push_back(L"-opt-mod-passes");
  623. Options.push_back(L"-dxil-dbg-value-to-dbg-declare");
  624. Options.push_back(L"-dxil-annotate-with-virtual-regs");
  625. CComPtr<IDxcBlob> pOptimizedModule;
  626. CComPtr<IDxcBlobEncoding> pText;
  627. VERIFY_SUCCEEDED(pOptimizer->RunOptimizer(
  628. dxil, Options.data(), Options.size(), &pOptimizedModule, &pText));
  629. std::string outputText;
  630. if (pText->GetBufferSize() != 0)
  631. {
  632. outputText = reinterpret_cast<const char*>(pText->GetBufferPointer());
  633. }
  634. auto lines = Tokenize(outputText, "\n");
  635. std::vector<ValueLocation> valueLocations;
  636. for (size_t line = 0; line < lines.size(); ++line) {
  637. if (lines[line] == "Begin - dxil values to virtual register mapping") {
  638. for (++line; line < lines.size(); ++line) {
  639. if (lines[line] == "End - dxil values to virtual register mapping") {
  640. break;
  641. }
  642. auto lineTokens = Tokenize(lines[line], " ");
  643. VERIFY_IS_TRUE(lineTokens.size() >= 2);
  644. if (lineTokens[1] == "dxil")
  645. {
  646. VERIFY_IS_TRUE(lineTokens.size() == 3);
  647. valueLocations.push_back({atoi(lineTokens[2].c_str()), 1});
  648. }
  649. else if (lineTokens[1] == "alloca")
  650. {
  651. VERIFY_IS_TRUE(lineTokens.size() == 4);
  652. valueLocations.push_back(
  653. {atoi(lineTokens[2].c_str()), atoi(lineTokens[3].c_str())});
  654. }
  655. else
  656. {
  657. VERIFY_IS_TRUE(false);
  658. }
  659. }
  660. }
  661. }
  662. return { std::move(pOptimizedModule), std::move(valueLocations) };
  663. }
  664. std::wstring Disassemble(IDxcBlob * pProgram)
  665. {
  666. CComPtr<IDxcCompiler> pCompiler;
  667. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  668. CComPtr<IDxcBlobEncoding> pDbgDisassembly;
  669. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDbgDisassembly));
  670. std::string disText = BlobToUtf8(pDbgDisassembly);
  671. CA2W disTextW(disText.c_str(), CP_UTF8);
  672. return std::wstring(disTextW);
  673. }
  674. CComPtr<IDxcBlob> FindModule(hlsl::DxilFourCC fourCC, IDxcBlob *pSource)
  675. {
  676. const UINT32 BC_C0DE = ((INT32)(INT8)'B' | (INT32)(INT8)'C' << 8 |
  677. (INT32)0xDEC0 << 16); // BC0xc0de in big endian
  678. const char *pBitcode = nullptr;
  679. const hlsl::DxilPartHeader *pDxilPartHeader =
  680. (hlsl::DxilPartHeader *)
  681. pSource->GetBufferPointer(); // Initialize assuming that source is
  682. // starting with DXIL part
  683. if (BC_C0DE == *(UINT32 *)pSource->GetBufferPointer()) {
  684. return pSource;
  685. }
  686. if (hlsl::IsValidDxilContainer(
  687. (hlsl::DxilContainerHeader *)pSource->GetBufferPointer(),
  688. pSource->GetBufferSize())) {
  689. hlsl::DxilContainerHeader *pDxilContainerHeader =
  690. (hlsl::DxilContainerHeader *)pSource->GetBufferPointer();
  691. pDxilPartHeader =
  692. *std::find_if(begin(pDxilContainerHeader), end(pDxilContainerHeader),
  693. hlsl::DxilPartIsType(fourCC));
  694. }
  695. if (fourCC == pDxilPartHeader->PartFourCC) {
  696. UINT32 pBlobSize;
  697. hlsl::DxilProgramHeader *pDxilProgramHeader =
  698. (hlsl::DxilProgramHeader *)(pDxilPartHeader + 1);
  699. hlsl::GetDxilProgramBitcode(pDxilProgramHeader, &pBitcode, &pBlobSize);
  700. UINT32 offset =
  701. (UINT32)(pBitcode - (const char *)pSource->GetBufferPointer());
  702. CComPtr<IDxcLibrary> library;
  703. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  704. CComPtr<IDxcBlob> targetBlob;
  705. library->CreateBlobFromBlob(pSource, offset, pBlobSize, &targetBlob);
  706. return targetBlob;
  707. }
  708. return {};
  709. }
  710. void ReplaceDxilBlobPart(
  711. const void *originalShaderBytecode, SIZE_T originalShaderLength,
  712. IDxcBlob *pNewDxilBlob, IDxcBlob **ppNewShaderOut)
  713. {
  714. CComPtr<IDxcLibrary> pLibrary;
  715. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  716. CComPtr<IDxcBlob> pNewContainer;
  717. // Use the container assembler to build a new container from the
  718. // recently-modified DXIL bitcode. This container will contain new copies of
  719. // things like input signature etc., which will supersede the ones from the
  720. // original compiled shader's container.
  721. {
  722. CComPtr<IDxcAssembler> pAssembler;
  723. IFT(m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  724. CComPtr<IDxcOperationResult> pAssembleResult;
  725. VERIFY_SUCCEEDED(
  726. pAssembler->AssembleToContainer(pNewDxilBlob, &pAssembleResult));
  727. CComPtr<IDxcBlobEncoding> pAssembleErrors;
  728. VERIFY_SUCCEEDED(
  729. pAssembleResult->GetErrorBuffer(&pAssembleErrors));
  730. if (pAssembleErrors && pAssembleErrors->GetBufferSize() != 0) {
  731. OutputDebugStringA(
  732. static_cast<LPCSTR>(pAssembleErrors->GetBufferPointer()));
  733. VERIFY_SUCCEEDED(E_FAIL);
  734. }
  735. VERIFY_SUCCEEDED(pAssembleResult->GetResult(&pNewContainer));
  736. }
  737. // Now copy over the blobs from the original container that won't have been
  738. // invalidated by changing the shader code itself, using the container
  739. // reflection API
  740. {
  741. // Wrap the original code in a container blob
  742. CComPtr<IDxcBlobEncoding> pContainer;
  743. VERIFY_SUCCEEDED(
  744. pLibrary->CreateBlobWithEncodingFromPinned(
  745. static_cast<LPBYTE>(const_cast<void *>(originalShaderBytecode)),
  746. static_cast<UINT32>(originalShaderLength), CP_ACP, &pContainer));
  747. CComPtr<IDxcContainerReflection> pReflection;
  748. IFT(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  749. // Load the reflector from the original shader
  750. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  751. UINT32 partIndex;
  752. if (SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_PrivateData,
  753. &partIndex))) {
  754. CComPtr<IDxcBlob> pPart;
  755. VERIFY_SUCCEEDED(
  756. pReflection->GetPartContent(partIndex, &pPart));
  757. CComPtr<IDxcContainerBuilder> pContainerBuilder;
  758. IFT(m_dllSupport.CreateInstance(CLSID_DxcContainerBuilder,
  759. &pContainerBuilder));
  760. VERIFY_SUCCEEDED(
  761. pContainerBuilder->Load(pNewContainer));
  762. VERIFY_SUCCEEDED(
  763. pContainerBuilder->AddPart(hlsl::DFCC_PrivateData, pPart));
  764. CComPtr<IDxcOperationResult> pBuildResult;
  765. VERIFY_SUCCEEDED(
  766. pContainerBuilder->SerializeContainer(&pBuildResult));
  767. CComPtr<IDxcBlobEncoding> pBuildErrors;
  768. VERIFY_SUCCEEDED(
  769. pBuildResult->GetErrorBuffer(&pBuildErrors));
  770. if (pBuildErrors && pBuildErrors->GetBufferSize() != 0) {
  771. OutputDebugStringA(
  772. reinterpret_cast<LPCSTR>(pBuildErrors->GetBufferPointer()));
  773. VERIFY_SUCCEEDED(E_FAIL);
  774. }
  775. VERIFY_SUCCEEDED(
  776. pBuildResult->GetResult(&pNewContainer));
  777. }
  778. }
  779. *ppNewShaderOut = pNewContainer.Detach();
  780. }
  781. class ModuleAndHangersOn
  782. {
  783. std::unique_ptr<llvm::LLVMContext> llvmContext;
  784. std::unique_ptr<llvm::Module> llvmModule;
  785. DxilModule* dxilModule;
  786. public:
  787. ModuleAndHangersOn(IDxcBlob* pBlob)
  788. {
  789. // Verify we have a valid dxil container.
  790. const DxilContainerHeader *pContainer = IsDxilContainerLike(
  791. pBlob->GetBufferPointer(), pBlob->GetBufferSize());
  792. VERIFY_IS_NOT_NULL(pContainer);
  793. VERIFY_IS_TRUE(IsValidDxilContainer(pContainer, pBlob->GetBufferSize()));
  794. // Get Dxil part from container.
  795. DxilPartIterator it =
  796. std::find_if(begin(pContainer), end(pContainer),
  797. DxilPartIsType(DFCC_ShaderDebugInfoDXIL));
  798. VERIFY_IS_FALSE(it == end(pContainer));
  799. const DxilProgramHeader *pProgramHeader =
  800. reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(*it));
  801. VERIFY_IS_TRUE(IsValidDxilProgramHeader(pProgramHeader, (*it)->PartSize));
  802. // Get a pointer to the llvm bitcode.
  803. const char *pIL;
  804. uint32_t pILLength;
  805. GetDxilProgramBitcode(pProgramHeader, &pIL, &pILLength);
  806. // Parse llvm bitcode into a module.
  807. std::unique_ptr<llvm::MemoryBuffer> pBitcodeBuf(
  808. llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(pIL, pILLength), "",
  809. false));
  810. llvmContext.reset(new llvm::LLVMContext);
  811. llvm::ErrorOr<std::unique_ptr<llvm::Module>> pModule(
  812. llvm::parseBitcodeFile(pBitcodeBuf->getMemBufferRef(),
  813. *llvmContext));
  814. if (std::error_code ec = pModule.getError()) {
  815. VERIFY_FAIL();
  816. }
  817. llvmModule = std::move(pModule.get());
  818. dxilModule =
  819. DxilModule::TryGetDxilModule(llvmModule.get());
  820. }
  821. DxilModule& GetDxilModule()
  822. {
  823. return *dxilModule;
  824. }
  825. };
  826. struct AggregateOffsetAndSize
  827. {
  828. unsigned countOfMembers;
  829. unsigned offset;
  830. unsigned size;
  831. };
  832. struct AllocaWrite {
  833. std::string memberName;
  834. uint32_t regBase;
  835. uint32_t regSize;
  836. uint64_t index;
  837. };
  838. struct TestableResults
  839. {
  840. std::vector<AggregateOffsetAndSize> OffsetAndSizes;
  841. std::vector<AllocaWrite> AllocaWrites;
  842. };
  843. TestableResults TestStructAnnotationCase(const char* hlsl);
  844. void ValidateAllocaWrite(std::vector<AllocaWrite> const& allocaWrites, size_t index, const char* name);
  845. };
  846. bool PixTest::InitSupport() {
  847. if (!m_dllSupport.IsEnabled()) {
  848. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  849. }
  850. return true;
  851. }
  852. TEST_F(PixTest, CompileWhenDebugThenDIPresent) {
  853. // BUG: the first test written was of this form:
  854. // float4 local = 0; return local;
  855. //
  856. // However we get no numbers because of the _wrapper form
  857. // that exports the zero initialization from main into
  858. // a global can't be attributed to any particular location
  859. // within main, and everything in main is eventually folded away.
  860. //
  861. // Making the function do a bit more work by calling an intrinsic
  862. // helps this case.
  863. CComPtr<IDiaDataSource> pDiaSource;
  864. VERIFY_SUCCEEDED(CreateDiaSourceForCompile(
  865. "float4 main(float4 pos : SV_Position) : SV_Target {\r\n"
  866. " float4 local = abs(pos);\r\n"
  867. " return local;\r\n"
  868. "}", &pDiaSource));
  869. std::wstring diaDump = GetDebugInfoAsText(pDiaSource).c_str();
  870. //WEX::Logging::Log::Comment(GetDebugInfoAsText(pDiaSource).c_str());
  871. // Very basic tests - we have basic symbols, line numbers, and files with sources.
  872. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"symIndexId: 5, CompilandEnv, name: hlslTarget, lexicalParent: id=2, value: ps_6_0"));
  873. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"lineNumber: 2"));
  874. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"length: 99, filename: source.hlsl"));
  875. std::wstring diaFileContent = GetDebugFileContent(pDiaSource).c_str();
  876. VERIFY_IS_NOT_NULL(wcsstr(diaFileContent.c_str(), L"loat4 main(float4 pos : SV_Position) : SV_Target"));
  877. #if SUPPORT_FXC_PDB
  878. // Now, fake it by loading from a .pdb!
  879. VERIFY_SUCCEEDED(CoInitializeEx(0, COINITBASE_MULTITHREADED));
  880. const wchar_t path[] = L"path-to-fxc-blob.bin";
  881. pDiaSource.Release();
  882. pProgramStream.Release();
  883. CComPtr<IDxcBlobEncoding> fxcBlob;
  884. CComPtr<IDxcBlob> pdbBlob;
  885. VERIFY_SUCCEEDED(pLib->CreateBlobFromFile(path, nullptr, &fxcBlob));
  886. std::string s = DumpParts(fxcBlob);
  887. CA2W sW(s.c_str(), CP_UTF8);
  888. WEX::Logging::Log::Comment(sW);
  889. VERIFY_SUCCEEDED(CreateDiaSourceFromDxbcBlob(pLib, fxcBlob, &pDiaSource));
  890. WEX::Logging::Log::Comment(GetDebugInfoAsText(pDiaSource).c_str());
  891. #endif
  892. }
  893. TEST_F(PixTest, CompileDebugDisasmPDB) {
  894. const char *hlsl = R"(
  895. [RootSignature("")]
  896. float main(float pos : A) : SV_Target {
  897. float x = abs(pos);
  898. float y = sin(pos);
  899. float z = x + y;
  900. return z;
  901. }
  902. )";
  903. CComPtr<IDxcLibrary> pLib;
  904. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  905. CComPtr<IDxcCompiler> pCompiler;
  906. CComPtr<IDxcCompiler2> pCompiler2;
  907. CComPtr<IDxcOperationResult> pResult;
  908. CComPtr<IDxcBlobEncoding> pSource;
  909. CComPtr<IDxcBlob> pProgram;
  910. CComPtr<IDxcBlob> pPdbBlob;
  911. WCHAR *pDebugName = nullptr;
  912. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  913. VERIFY_SUCCEEDED(pCompiler.QueryInterface(&pCompiler2));
  914. CreateBlobFromText(hlsl, &pSource);
  915. LPCWSTR args[] = { L"/Zi", L"/Qembed_debug" };
  916. VERIFY_SUCCEEDED(pCompiler2->CompileWithDebug(pSource, L"source.hlsl", L"main",
  917. L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pResult, &pDebugName, &pPdbBlob));
  918. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  919. // Test that disassembler can consume a PDB container
  920. CComPtr<IDxcBlobEncoding> pDisasm;
  921. VERIFY_SUCCEEDED(pCompiler->Disassemble(pPdbBlob, &pDisasm));
  922. }
  923. // Test that the new PDB format still works with Dia
  924. TEST_F(PixTest, CompileDebugPDB) {
  925. const char *hlsl = R"(
  926. [RootSignature("")]
  927. float main(float pos : A) : SV_Target {
  928. float x = abs(pos);
  929. float y = sin(pos);
  930. float z = x + y;
  931. return z;
  932. }
  933. )";
  934. CComPtr<IDxcLibrary> pLib;
  935. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  936. CComPtr<IDxcCompiler> pCompiler;
  937. CComPtr<IDxcCompiler2> pCompiler2;
  938. CComPtr<IDxcOperationResult> pResult;
  939. CComPtr<IDxcBlobEncoding> pSource;
  940. CComPtr<IDxcBlob> pProgram;
  941. CComPtr<IDxcBlob> pPdbBlob;
  942. WCHAR *pDebugName = nullptr;
  943. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  944. VERIFY_SUCCEEDED(pCompiler.QueryInterface(&pCompiler2));
  945. CreateBlobFromText(hlsl, &pSource);
  946. LPCWSTR args[] = { L"/Zi", L"/Qembed_debug" };
  947. VERIFY_SUCCEEDED(pCompiler2->CompileWithDebug(pSource, L"source.hlsl", L"main",
  948. L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pResult, &pDebugName, &pPdbBlob));
  949. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  950. CComPtr<IDiaDataSource> pDiaSource;
  951. CComPtr<IStream> pProgramStream;
  952. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pPdbBlob, &pProgramStream));
  953. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  954. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pProgramStream));
  955. // Test that IDxcContainerReflection can consume a PDB container
  956. CComPtr<IDxcContainerReflection> pReflection;
  957. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  958. VERIFY_SUCCEEDED(pReflection->Load(pPdbBlob));
  959. UINT32 uDebugInfoIndex = 0;
  960. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &uDebugInfoIndex));
  961. }
  962. TEST_F(PixTest, CompileDebugLines) {
  963. CComPtr<IDiaDataSource> pDiaSource;
  964. VERIFY_SUCCEEDED(
  965. CreateDiaSourceForCompile(
  966. "float main(float pos : A) : SV_Target {\r\n"
  967. " float x = abs(pos);\r\n"
  968. " float y = sin(pos);\r\n"
  969. " float z = x + y;\r\n"
  970. " return z;\r\n"
  971. "}", &pDiaSource));
  972. const uint32_t numExpectedVAs = 18;
  973. const uint32_t numExpectedLineEntries = 6;
  974. auto verifyLines = [=](const std::vector<LineNumber> lines) {
  975. VERIFY_ARE_EQUAL(lines.size(), numExpectedLineEntries);
  976. // loadInput
  977. VERIFY_ARE_EQUAL(lines[0].line, 1);
  978. VERIFY_ARE_EQUAL(lines[0].rva, 4);
  979. // abs
  980. VERIFY_ARE_EQUAL(lines[1].line, 2);
  981. VERIFY_ARE_EQUAL(lines[1].rva, 7);
  982. // sin
  983. VERIFY_ARE_EQUAL(lines[2].line, 3);
  984. VERIFY_ARE_EQUAL(lines[2].rva, 10);
  985. // fadd
  986. VERIFY_ARE_EQUAL(lines[3].line, 4);
  987. VERIFY_ARE_EQUAL(lines[3].rva, 13);
  988. // storeOutput
  989. VERIFY_ARE_EQUAL(lines[4].line, 5);
  990. VERIFY_ARE_EQUAL(lines[4].rva, 16);
  991. // ret
  992. VERIFY_ARE_EQUAL(lines[5].line, 5);
  993. VERIFY_ARE_EQUAL(lines[5].rva, 17);
  994. };
  995. CComPtr<IDiaSession> pSession;
  996. CComPtr<IDiaEnumLineNumbers> pEnumLineNumbers;
  997. // Verify lines are ok when getting one RVA at a time.
  998. std::vector<LineNumber> linesOneByOne;
  999. VERIFY_SUCCEEDED(pDiaSource->openSession(&pSession));
  1000. for (int i = 0; i < numExpectedVAs; ++i) {
  1001. VERIFY_SUCCEEDED(pSession->findLinesByRVA(i, 1, &pEnumLineNumbers));
  1002. std::vector<LineNumber> lines = ReadLineNumbers(pEnumLineNumbers);
  1003. std::copy(lines.begin(), lines.end(), std::back_inserter(linesOneByOne));
  1004. pEnumLineNumbers.Release();
  1005. }
  1006. verifyLines(linesOneByOne);
  1007. // Verify lines are ok when getting all RVAs at once.
  1008. std::vector<LineNumber> linesAllAtOnce;
  1009. pEnumLineNumbers.Release();
  1010. VERIFY_SUCCEEDED(pSession->findLinesByRVA(0, numExpectedVAs, &pEnumLineNumbers));
  1011. linesAllAtOnce = ReadLineNumbers(pEnumLineNumbers);
  1012. verifyLines(linesAllAtOnce);
  1013. // Verify lines are ok when getting all lines through enum tables.
  1014. std::vector<LineNumber> linesFromTable;
  1015. pEnumLineNumbers.Release();
  1016. CComPtr<IDiaEnumTables> pTables;
  1017. CComPtr<IDiaTable> pTable;
  1018. VERIFY_SUCCEEDED(pSession->getEnumTables(&pTables));
  1019. DWORD celt;
  1020. while (SUCCEEDED(pTables->Next(1, &pTable, &celt)) && celt == 1)
  1021. {
  1022. if (SUCCEEDED(pTable->QueryInterface(&pEnumLineNumbers))) {
  1023. linesFromTable = ReadLineNumbers(pEnumLineNumbers);
  1024. break;
  1025. }
  1026. pTable.Release();
  1027. }
  1028. verifyLines(linesFromTable);
  1029. // Verify lines are ok when getting by address.
  1030. std::vector<LineNumber> linesByAddr;
  1031. pEnumLineNumbers.Release();
  1032. VERIFY_SUCCEEDED(pSession->findLinesByAddr(0, 0, numExpectedVAs, &pEnumLineNumbers));
  1033. linesByAddr = ReadLineNumbers(pEnumLineNumbers);
  1034. verifyLines(linesByAddr);
  1035. // Verify findFileById.
  1036. CComPtr<IDiaSourceFile> pFile;
  1037. VERIFY_SUCCEEDED(pSession->findFileById(0, &pFile));
  1038. CComBSTR pName;
  1039. VERIFY_SUCCEEDED(pFile->get_fileName(&pName));
  1040. VERIFY_ARE_EQUAL_WSTR(pName, L"source.hlsl");
  1041. }
  1042. TEST_F(PixTest, DiaLoadBadBitcodeThenFail) {
  1043. CComPtr<IDxcBlob> pBadBitcode;
  1044. CComPtr<IDiaDataSource> pDiaSource;
  1045. CComPtr<IStream> pStream;
  1046. CComPtr<IDxcLibrary> pLib;
  1047. Utf8ToBlob(m_dllSupport, "badcode", &pBadBitcode);
  1048. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1049. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pBadBitcode, &pStream));
  1050. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  1051. VERIFY_FAILED(pDiaSource->loadDataFromIStream(pStream));
  1052. }
  1053. static void CompileAndGetDebugPart(dxc::DxcDllSupport &dllSupport, const char *source, wchar_t *profile, IDxcBlob **ppDebugPart) {
  1054. CComPtr<IDxcBlob> pContainer;
  1055. CComPtr<IDxcLibrary> pLib;
  1056. CComPtr<IDxcContainerReflection> pReflection;
  1057. UINT32 index;
  1058. std::vector<LPCWSTR> args;
  1059. args.push_back(L"/Zi");
  1060. args.push_back(L"/Qembed_debug");
  1061. VerifyCompileOK(dllSupport, source, profile, args, &pContainer);
  1062. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1063. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  1064. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  1065. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &index));
  1066. VERIFY_SUCCEEDED(pReflection->GetPartContent(index, ppDebugPart));
  1067. }
  1068. static void CompileTestAndLoadDiaSource(dxc::DxcDllSupport &dllSupport, const char *source, wchar_t *profile, IDiaDataSource **ppDataSource) {
  1069. CComPtr<IDxcBlob> pDebugContent;
  1070. CComPtr<IStream> pStream;
  1071. CComPtr<IDiaDataSource> pDiaSource;
  1072. CComPtr<IDxcLibrary> pLib;
  1073. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1074. CompileAndGetDebugPart(dllSupport, source, profile, &pDebugContent);
  1075. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pDebugContent, &pStream));
  1076. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  1077. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pStream));
  1078. if (ppDataSource) {
  1079. *ppDataSource = pDiaSource.Detach();
  1080. }
  1081. }
  1082. static const char EmptyCompute[] = "[numthreads(8,8,1)] void main() { }";
  1083. static void CompileTestAndLoadDia(dxc::DxcDllSupport &dllSupport, IDiaDataSource **ppDataSource) {
  1084. CompileTestAndLoadDiaSource(dllSupport, EmptyCompute, L"cs_6_0", ppDataSource);
  1085. }
  1086. TEST_F(PixTest, DiaLoadDebugSubrangeNegativeThenOK) {
  1087. static const char source[] = R"(
  1088. SamplerState samp0 : register(s0);
  1089. Texture2DArray tex0 : register(t0);
  1090. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1091. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1092. }
  1093. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1094. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1095. Texture2DArray textures[] = {
  1096. tex0,
  1097. };
  1098. return foo(textures, index, samp0, uvw);
  1099. }
  1100. )";
  1101. CComPtr<IDiaDataSource> pDiaDataSource;
  1102. CComPtr<IDiaSession> pDiaSession;
  1103. CompileTestAndLoadDiaSource(m_dllSupport, source, L"ps_6_0", &pDiaDataSource);
  1104. VERIFY_SUCCEEDED(pDiaDataSource->openSession(&pDiaSession));
  1105. }
  1106. TEST_F(PixTest, DiaLoadRelocatedBitcode) {
  1107. static const char source[] = R"(
  1108. SamplerState samp0 : register(s0);
  1109. Texture2DArray tex0 : register(t0);
  1110. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1111. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1112. }
  1113. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1114. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1115. Texture2DArray textures[] = {
  1116. tex0,
  1117. };
  1118. return foo(textures, index, samp0, uvw);
  1119. }
  1120. )";
  1121. CComPtr<IDxcBlob> pPart;
  1122. CComPtr<IDiaDataSource> pDiaSource;
  1123. CComPtr<IStream> pStream;
  1124. CComPtr<IDxcLibrary> pLib;
  1125. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1126. CompileAndGetDebugPart(m_dllSupport, source, L"ps_6_0", &pPart);
  1127. const char *pPartData = (char *)pPart->GetBufferPointer();
  1128. const size_t uPartSize = pPart->GetBufferSize();
  1129. // Get program header
  1130. const hlsl::DxilProgramHeader *programHeader = (hlsl::DxilProgramHeader *)pPartData;
  1131. const char *pBitcode = nullptr;
  1132. uint32_t uBitcodeSize = 0;
  1133. hlsl::GetDxilProgramBitcode(programHeader, &pBitcode, &uBitcodeSize);
  1134. VERIFY_IS_TRUE(uBitcodeSize % sizeof(UINT32) == 0);
  1135. size_t uNewGapSize = 4 * 10; // Size of some bytes between program header and bitcode
  1136. size_t uNewSuffixeBytes = 4 * 10; // Size of some random bytes after the program
  1137. hlsl::DxilProgramHeader newProgramHeader = {};
  1138. memcpy(&newProgramHeader, programHeader, sizeof(newProgramHeader));
  1139. newProgramHeader.BitcodeHeader.BitcodeOffset = uNewGapSize + sizeof(newProgramHeader.BitcodeHeader);
  1140. unsigned uNewSizeInBytes = sizeof(newProgramHeader) + uNewGapSize + uBitcodeSize + uNewSuffixeBytes;
  1141. VERIFY_IS_TRUE(uNewSizeInBytes % sizeof(UINT32) == 0);
  1142. newProgramHeader.SizeInUint32 = uNewSizeInBytes / sizeof(UINT32);
  1143. llvm::SmallVector<char, 0> buffer;
  1144. llvm::raw_svector_ostream OS(buffer);
  1145. // Write the header
  1146. OS.write((char *)&newProgramHeader, sizeof(newProgramHeader));
  1147. // Write some garbage between the header and the bitcode
  1148. for (unsigned i = 0; i < uNewGapSize; i++) {
  1149. OS.write(0xFF);
  1150. }
  1151. // Write the actual bitcode
  1152. OS.write(pBitcode, uBitcodeSize);
  1153. // Write some garbage after the bitcode
  1154. for (unsigned i = 0; i < uNewSuffixeBytes; i++) {
  1155. OS.write(0xFF);
  1156. }
  1157. OS.flush();
  1158. // Try to load this new program, make sure dia is still okay.
  1159. CComPtr<IDxcBlobEncoding> pNewProgramBlob;
  1160. VERIFY_SUCCEEDED(pLib->CreateBlobWithEncodingFromPinned(buffer.data(), buffer.size(), CP_ACP, &pNewProgramBlob));
  1161. CComPtr<IStream> pNewProgramStream;
  1162. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pNewProgramBlob, &pNewProgramStream));
  1163. CComPtr<IDiaDataSource> pDiaDataSource;
  1164. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaDataSource));
  1165. VERIFY_SUCCEEDED(pDiaDataSource->loadDataFromIStream(pNewProgramStream));
  1166. }
  1167. TEST_F(PixTest, DiaCompileArgs) {
  1168. static const char source[] = R"(
  1169. SamplerState samp0 : register(s0);
  1170. Texture2DArray tex0 : register(t0);
  1171. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1172. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1173. }
  1174. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1175. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1176. Texture2DArray textures[] = {
  1177. tex0,
  1178. };
  1179. return foo(textures, index, samp0, uvw);
  1180. }
  1181. )";
  1182. CComPtr<IDxcBlob> pPart;
  1183. CComPtr<IDiaDataSource> pDiaSource;
  1184. CComPtr<IStream> pStream;
  1185. CComPtr<IDxcLibrary> pLib;
  1186. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1187. const WCHAR *FlagList[] = {
  1188. L"/Zi",
  1189. L"-Zpr",
  1190. L"/Qembed_debug",
  1191. L"/Fd", L"F:\\my dir\\",
  1192. L"-Fo", L"F:\\my dir\\file.dxc",
  1193. };
  1194. const WCHAR *DefineList[] = {
  1195. L"MY_SPECIAL_DEFINE",
  1196. L"MY_OTHER_SPECIAL_DEFINE=\"MY_STRING\"",
  1197. };
  1198. std::vector<LPCWSTR> args;
  1199. for (unsigned i = 0; i < _countof(FlagList); i++) {
  1200. args.push_back(FlagList[i]);
  1201. }
  1202. for (unsigned i = 0; i < _countof(DefineList); i++) {
  1203. args.push_back(L"/D");
  1204. args.push_back(DefineList[i]);
  1205. }
  1206. auto CompileAndGetDebugPart = [&args](dxc::DxcDllSupport &dllSupport, const char *source, wchar_t *profile, IDxcBlob **ppDebugPart) {
  1207. CComPtr<IDxcBlob> pContainer;
  1208. CComPtr<IDxcLibrary> pLib;
  1209. CComPtr<IDxcContainerReflection> pReflection;
  1210. UINT32 index;
  1211. VerifyCompileOK(dllSupport, source, profile, args, &pContainer);
  1212. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1213. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  1214. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  1215. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &index));
  1216. VERIFY_SUCCEEDED(pReflection->GetPartContent(index, ppDebugPart));
  1217. };
  1218. CompileAndGetDebugPart(m_dllSupport, source, L"ps_6_0", &pPart);
  1219. CComPtr<IStream> pNewProgramStream;
  1220. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pPart, &pNewProgramStream));
  1221. CComPtr<IDiaDataSource> pDiaDataSource;
  1222. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaDataSource));
  1223. VERIFY_SUCCEEDED(pDiaDataSource->loadDataFromIStream(pNewProgramStream));
  1224. CComPtr<IDiaSession> pSession;
  1225. VERIFY_SUCCEEDED(pDiaDataSource->openSession(&pSession));
  1226. CComPtr<IDiaEnumTables> pEnumTables;
  1227. VERIFY_SUCCEEDED(pSession->getEnumTables(&pEnumTables));
  1228. CComPtr<IDiaTable> pSymbolTable;
  1229. LONG uCount = 0;
  1230. VERIFY_SUCCEEDED(pEnumTables->get_Count(&uCount));
  1231. for (int i = 0; i < uCount; i++) {
  1232. CComPtr<IDiaTable> pTable;
  1233. VARIANT index = {};
  1234. index.vt = VT_I4;
  1235. index.intVal = i;
  1236. VERIFY_SUCCEEDED(pEnumTables->Item(index, &pTable));
  1237. CComBSTR pName;
  1238. VERIFY_SUCCEEDED(pTable->get_name(&pName));
  1239. if (pName == "Symbols") {
  1240. pSymbolTable = pTable;
  1241. break;
  1242. }
  1243. }
  1244. std::wstring Args;
  1245. std::wstring Entry;
  1246. std::wstring Target;
  1247. std::vector<std::wstring> Defines;
  1248. std::vector<std::wstring> Flags;
  1249. auto ReadNullSeparatedTokens = [](BSTR Str) -> std::vector<std::wstring> {
  1250. std::vector<std::wstring> Result;
  1251. while (*Str) {
  1252. Result.push_back(std::wstring(Str));
  1253. Str += wcslen(Str)+1;
  1254. }
  1255. return Result;
  1256. };
  1257. VERIFY_SUCCEEDED(pSymbolTable->get_Count(&uCount));
  1258. for (int i = 0; i < uCount; i++) {
  1259. CComPtr<IUnknown> pSymbolUnk;
  1260. CComPtr<IDiaSymbol> pSymbol;
  1261. CComVariant pValue;
  1262. CComBSTR pName;
  1263. VERIFY_SUCCEEDED(pSymbolTable->Item(i, &pSymbolUnk));
  1264. VERIFY_SUCCEEDED(pSymbolUnk->QueryInterface(&pSymbol));
  1265. VERIFY_SUCCEEDED(pSymbol->get_name(&pName));
  1266. VERIFY_SUCCEEDED(pSymbol->get_value(&pValue));
  1267. if (pName == "hlslTarget") {
  1268. if (pValue.vt == VT_BSTR)
  1269. Target = pValue.bstrVal;
  1270. }
  1271. else if (pName == "hlslEntry") {
  1272. if (pValue.vt == VT_BSTR)
  1273. Entry = pValue.bstrVal;
  1274. }
  1275. else if (pName == "hlslFlags") {
  1276. if (pValue.vt == VT_BSTR)
  1277. Flags = ReadNullSeparatedTokens(pValue.bstrVal);
  1278. }
  1279. else if (pName == "hlslArguments") {
  1280. if (pValue.vt == VT_BSTR)
  1281. Args = pValue.bstrVal;
  1282. }
  1283. else if (pName == "hlslDefines") {
  1284. if (pValue.vt == VT_BSTR)
  1285. Defines = ReadNullSeparatedTokens(pValue.bstrVal);
  1286. }
  1287. }
  1288. auto VectorContains = [](std::vector<std::wstring> &Tokens, std::wstring Sub) {
  1289. for (unsigned i = 0; i < Tokens.size(); i++) {
  1290. if (Tokens[i].find(Sub) != std::wstring::npos)
  1291. return true;
  1292. }
  1293. return false;
  1294. };
  1295. VERIFY_IS_TRUE(Target == L"ps_6_0");
  1296. VERIFY_IS_TRUE(Entry == L"main");
  1297. VERIFY_IS_TRUE(_countof(FlagList) == Flags.size());
  1298. for (unsigned i = 0; i < _countof(FlagList); i++) {
  1299. VERIFY_IS_TRUE(Flags[i] == FlagList[i]);
  1300. }
  1301. for (unsigned i = 0; i < _countof(DefineList); i++) {
  1302. VERIFY_IS_TRUE(VectorContains(Defines, DefineList[i]));
  1303. }
  1304. }
  1305. TEST_F(PixTest, DiaLoadBitcodePlusExtraData) {
  1306. // Test that dia doesn't crash when bitcode has unused extra data at the end
  1307. static const char source[] = R"(
  1308. SamplerState samp0 : register(s0);
  1309. Texture2DArray tex0 : register(t0);
  1310. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1311. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1312. }
  1313. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1314. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1315. Texture2DArray textures[] = {
  1316. tex0,
  1317. };
  1318. return foo(textures, index, samp0, uvw);
  1319. }
  1320. )";
  1321. CComPtr<IDxcBlob> pPart;
  1322. CComPtr<IDiaDataSource> pDiaSource;
  1323. CComPtr<IStream> pStream;
  1324. CComPtr<IDxcLibrary> pLib;
  1325. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1326. CompileAndGetDebugPart(m_dllSupport, source, L"ps_6_0", &pPart);
  1327. const char *pPartData = (char *)pPart->GetBufferPointer();
  1328. const size_t uPartSize = pPart->GetBufferSize();
  1329. // Get program header
  1330. const hlsl::DxilProgramHeader *programHeader = (hlsl::DxilProgramHeader *)pPartData;
  1331. const char *pBitcode = nullptr;
  1332. uint32_t uBitcodeSize = 0;
  1333. hlsl::GetDxilProgramBitcode(programHeader, &pBitcode, &uBitcodeSize);
  1334. llvm::SmallVector<char, 0> buffer;
  1335. llvm::raw_svector_ostream OS(buffer);
  1336. // Write the bitcode
  1337. OS.write(pBitcode, uBitcodeSize);
  1338. for (unsigned i = 0; i < 12; i++) {
  1339. OS.write(0xFF);
  1340. }
  1341. OS.flush();
  1342. // Try to load this new program, make sure dia is still okay.
  1343. CComPtr<IDxcBlobEncoding> pNewProgramBlob;
  1344. VERIFY_SUCCEEDED(pLib->CreateBlobWithEncodingFromPinned(buffer.data(), buffer.size(), CP_ACP, &pNewProgramBlob));
  1345. CComPtr<IStream> pNewProgramStream;
  1346. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pNewProgramBlob, &pNewProgramStream));
  1347. CComPtr<IDiaDataSource> pDiaDataSource;
  1348. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaDataSource));
  1349. VERIFY_SUCCEEDED(pDiaDataSource->loadDataFromIStream(pNewProgramStream));
  1350. }
  1351. TEST_F(PixTest, DiaLoadDebugThenOK) {
  1352. CompileTestAndLoadDia(m_dllSupport, nullptr);
  1353. }
  1354. TEST_F(PixTest, DiaTableIndexThenOK) {
  1355. CComPtr<IDiaDataSource> pDiaSource;
  1356. CComPtr<IDiaSession> pDiaSession;
  1357. CComPtr<IDiaEnumTables> pEnumTables;
  1358. CComPtr<IDiaTable> pTable;
  1359. VARIANT vtIndex;
  1360. CompileTestAndLoadDia(m_dllSupport, &pDiaSource);
  1361. VERIFY_SUCCEEDED(pDiaSource->openSession(&pDiaSession));
  1362. VERIFY_SUCCEEDED(pDiaSession->getEnumTables(&pEnumTables));
  1363. vtIndex.vt = VT_EMPTY;
  1364. VERIFY_FAILED(pEnumTables->Item(vtIndex, &pTable));
  1365. vtIndex.vt = VT_I4;
  1366. vtIndex.intVal = 1;
  1367. VERIFY_SUCCEEDED(pEnumTables->Item(vtIndex, &pTable));
  1368. VERIFY_IS_NOT_NULL(pTable.p);
  1369. pTable.Release();
  1370. vtIndex.vt = VT_UI4;
  1371. vtIndex.uintVal = 1;
  1372. VERIFY_SUCCEEDED(pEnumTables->Item(vtIndex, &pTable));
  1373. VERIFY_IS_NOT_NULL(pTable.p);
  1374. pTable.Release();
  1375. vtIndex.uintVal = 100;
  1376. VERIFY_FAILED(pEnumTables->Item(vtIndex, &pTable));
  1377. }
  1378. TEST_F(PixTest, PixDebugCompileInfo) {
  1379. static const char source[] = R"(
  1380. SamplerState samp0 : register(s0);
  1381. Texture2DArray tex0 : register(t0);
  1382. float4 foo(Texture2DArray textures[], int idx, SamplerState samplerState, float3 uvw) {
  1383. return textures[NonUniformResourceIndex(idx)].Sample(samplerState, uvw);
  1384. }
  1385. [RootSignature( "DescriptorTable(SRV(t0)), DescriptorTable(Sampler(s0)) " )]
  1386. float4 main(int index : INDEX, float3 uvw : TEXCOORD) : SV_Target {
  1387. Texture2DArray textures[] = {
  1388. tex0,
  1389. };
  1390. return foo(textures, index, samp0, uvw);
  1391. }
  1392. )";
  1393. CComPtr<IDxcBlob> pPart;
  1394. CComPtr<IDiaDataSource> pDiaSource;
  1395. CComPtr<IStream> pStream;
  1396. CComPtr<IDxcLibrary> pLib;
  1397. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1398. const WCHAR *FlagList[] = {
  1399. L"/Zi", L"-Zpr", L"/Qembed_debug", L"/Fd",
  1400. L"F:\\my dir\\", L"-Fo", L"F:\\my dir\\file.dxc",
  1401. };
  1402. const WCHAR *DefineList[] = {
  1403. L"MY_SPECIAL_DEFINE",
  1404. L"MY_OTHER_SPECIAL_DEFINE=\"MY_STRING\"",
  1405. };
  1406. std::vector<LPCWSTR> args;
  1407. for (unsigned i = 0; i < _countof(FlagList); i++) {
  1408. args.push_back(FlagList[i]);
  1409. }
  1410. for (unsigned i = 0; i < _countof(DefineList); i++) {
  1411. args.push_back(L"/D");
  1412. args.push_back(DefineList[i]);
  1413. }
  1414. auto CompileAndGetDebugPart = [&args](dxc::DxcDllSupport &dllSupport,
  1415. const char *source, wchar_t *profile,
  1416. IDxcBlob **ppDebugPart) {
  1417. CComPtr<IDxcBlob> pContainer;
  1418. CComPtr<IDxcLibrary> pLib;
  1419. CComPtr<IDxcContainerReflection> pReflection;
  1420. UINT32 index;
  1421. VerifyCompileOK(dllSupport, source, profile, args, &pContainer);
  1422. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1423. VERIFY_SUCCEEDED(
  1424. dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  1425. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  1426. VERIFY_SUCCEEDED(
  1427. pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &index));
  1428. VERIFY_SUCCEEDED(pReflection->GetPartContent(index, ppDebugPart));
  1429. };
  1430. constexpr wchar_t *profile = L"ps_6_0";
  1431. CompileAndGetDebugPart(m_dllSupport, source, profile, &pPart);
  1432. CComPtr<IStream> pNewProgramStream;
  1433. VERIFY_SUCCEEDED(
  1434. pLib->CreateStreamFromBlobReadOnly(pPart, &pNewProgramStream));
  1435. CComPtr<IDiaDataSource> pDiaDataSource;
  1436. VERIFY_SUCCEEDED(
  1437. m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaDataSource));
  1438. VERIFY_SUCCEEDED(pDiaDataSource->loadDataFromIStream(pNewProgramStream));
  1439. CComPtr<IDiaSession> pSession;
  1440. VERIFY_SUCCEEDED(pDiaDataSource->openSession(&pSession));
  1441. CComPtr<IDxcPixDxilDebugInfoFactory> factory;
  1442. VERIFY_SUCCEEDED(pSession->QueryInterface(IID_PPV_ARGS(&factory)));
  1443. CComPtr<IDxcPixCompilationInfo> compilationInfo;
  1444. VERIFY_SUCCEEDED(factory->NewDxcPixCompilationInfo(&compilationInfo));
  1445. CComBSTR arguments;
  1446. VERIFY_SUCCEEDED(compilationInfo->GetArguments(&arguments));
  1447. for (unsigned i = 0; i < _countof(FlagList); i++) {
  1448. VERIFY_IS_TRUE(nullptr != wcsstr(arguments, FlagList[i]));
  1449. }
  1450. CComBSTR macros;
  1451. VERIFY_SUCCEEDED(compilationInfo->GetMacroDefinitions(&macros));
  1452. for (unsigned i = 0; i < _countof(DefineList); i++) {
  1453. std::wstring MacroDef = std::wstring(L"-D") + DefineList[i];
  1454. VERIFY_IS_TRUE(nullptr != wcsstr(macros, MacroDef.c_str()));
  1455. }
  1456. CComBSTR entryPointFile;
  1457. VERIFY_SUCCEEDED(compilationInfo->GetEntryPointFile(&entryPointFile));
  1458. VERIFY_ARE_EQUAL(std::wstring(L"source.hlsl"), std::wstring(entryPointFile));
  1459. CComBSTR entryPointFunction;
  1460. VERIFY_SUCCEEDED(compilationInfo->GetEntryPoint(&entryPointFunction));
  1461. VERIFY_ARE_EQUAL(std::wstring(L"main"), std::wstring(entryPointFunction));
  1462. CComBSTR hlslTarget;
  1463. VERIFY_SUCCEEDED(compilationInfo->GetHlslTarget(&hlslTarget));
  1464. VERIFY_ARE_EQUAL(std::wstring(profile), std::wstring(hlslTarget));
  1465. }
  1466. // This function lives in lib\DxilPIXPasses\DxilAnnotateWithVirtualRegister.cpp
  1467. // Declared here so we can test it.
  1468. uint32_t CountStructMembers(llvm::Type const* pType);
  1469. PixTest::TestableResults PixTest::TestStructAnnotationCase(const char* hlsl)
  1470. {
  1471. auto pOperationResult = Compile(hlsl, L"as_6_5");
  1472. CComPtr<IDxcBlob> pBlob;
  1473. CheckOperationSucceeded(pOperationResult, &pBlob);
  1474. CComPtr<IDxcBlob> pDxil = FindModule(DFCC_ShaderDebugInfoDXIL, pBlob);
  1475. PassOutput passOutput = RunAnnotationPasses(pDxil);
  1476. auto pAnnotated = passOutput.blob;
  1477. CComPtr<IDxcBlob> pAnnotatedContainer;
  1478. ReplaceDxilBlobPart(
  1479. pBlob->GetBufferPointer(),
  1480. pBlob->GetBufferSize(),
  1481. pAnnotated,
  1482. &pAnnotatedContainer);
  1483. ModuleAndHangersOn moduleEtc(pAnnotatedContainer);
  1484. llvm::Function *entryFunction = moduleEtc.GetDxilModule().GetEntryFunction();
  1485. PixTest::TestableResults ret;
  1486. // For every dbg.declare, run the member iterator and record what it finds:
  1487. for (auto& block : entryFunction->getBasicBlockList())
  1488. {
  1489. for (auto& instruction : block.getInstList())
  1490. {
  1491. if (auto* dbgDeclare = llvm::dyn_cast<llvm::DbgDeclareInst>(&instruction))
  1492. {
  1493. llvm::Value* Address = dbgDeclare->getAddress();
  1494. auto* AddressAsAlloca = llvm::dyn_cast<llvm::AllocaInst>(Address);
  1495. auto* Expression = dbgDeclare->getExpression();
  1496. std::unique_ptr<dxil_debug_info::MemberIterator> iterator = dxil_debug_info::CreateMemberIterator(
  1497. dbgDeclare,
  1498. moduleEtc.GetDxilModule().GetModule()->getDataLayout(),
  1499. AddressAsAlloca,
  1500. Expression);
  1501. unsigned int startingBit = 0;
  1502. unsigned int coveredBits = 0;
  1503. unsigned int memberIndex = 0;
  1504. while (iterator->Next(&memberIndex))
  1505. {
  1506. if (memberIndex == 0)
  1507. {
  1508. startingBit = iterator->OffsetInBits(memberIndex);
  1509. coveredBits = iterator->SizeInBits(memberIndex);
  1510. }
  1511. else
  1512. {
  1513. coveredBits = std::max<unsigned int>( coveredBits, iterator->OffsetInBits(memberIndex) + iterator->SizeInBits(memberIndex));
  1514. }
  1515. }
  1516. // memberIndex is now the count of members in this aggregate type
  1517. ret.OffsetAndSizes.push_back({ memberIndex, startingBit, coveredBits });
  1518. // Use this independent count of number of struct members to test the
  1519. // function that operates on the alloca type:
  1520. llvm::Type *pAllocaTy = AddressAsAlloca->getType()->getElementType();
  1521. if (auto *AT = llvm::dyn_cast<llvm::ArrayType>(pAllocaTy))
  1522. {
  1523. // This is the case where a struct is passed to a function, and in
  1524. // these tests there should be only one struct behind the pointer.
  1525. VERIFY_ARE_EQUAL(AT->getNumElements(), 1);
  1526. pAllocaTy = AT->getArrayElementType();
  1527. }
  1528. if (auto* ST = llvm::dyn_cast<llvm::StructType>(pAllocaTy))
  1529. {
  1530. uint32_t countOfMembers = CountStructMembers(ST);
  1531. // memberIndex might be greater, because the fragment iterator also includes contained derived types as
  1532. // fragments, in addition to the members of that contained derived types. CountStructMembers only counts
  1533. // the leaf-node types.
  1534. VERIFY_ARE_EQUAL(countOfMembers, memberIndex);
  1535. }
  1536. else if (pAllocaTy->isFloatingPointTy() || pAllocaTy->isIntegerTy())
  1537. {
  1538. // If there's only one member in the struct in the pass-to-function (by pointer)
  1539. // case, then the underlying type will have been reduced to the contained type.
  1540. VERIFY_ARE_EQUAL(1, memberIndex);
  1541. }
  1542. else
  1543. {
  1544. VERIFY_IS_TRUE(false);
  1545. }
  1546. }
  1547. }
  1548. }
  1549. // The member iterator should find a solid run of bits that is exactly covered
  1550. // by exactly one of the members found by the annotation pass:
  1551. for (auto const& cover : ret.OffsetAndSizes)
  1552. {
  1553. bool found = false;
  1554. for (auto const& valueLocation : passOutput.valueLocations)
  1555. {
  1556. constexpr unsigned int eightBitsPerByte = 8;
  1557. if (valueLocation.base * eightBitsPerByte == cover.offset)
  1558. {
  1559. VERIFY_IS_FALSE(found);
  1560. found = true;
  1561. VERIFY_ARE_EQUAL(valueLocation.count, cover.countOfMembers);
  1562. }
  1563. }
  1564. VERIFY_IS_TRUE(found);
  1565. }
  1566. // For every store operation to the struct alloca, check that the annotation pass correctly determined which alloca
  1567. for (auto& block : entryFunction->getBasicBlockList()) {
  1568. for (auto& instruction : block.getInstList()) {
  1569. if (auto* store =
  1570. llvm::dyn_cast<llvm::StoreInst>(&instruction)) {
  1571. if (auto* pGEP = llvm::dyn_cast<llvm::GetElementPtrInst>(store->getPointerOperand()))
  1572. {
  1573. ret.AllocaWrites.push_back({});
  1574. auto& NewAllocaWrite = ret.AllocaWrites.back();
  1575. llvm::Value* pPointerOperand = pGEP->getPointerOperand();
  1576. if (auto* pGEP2 = llvm::dyn_cast<llvm::GetElementPtrInst>(pPointerOperand))
  1577. {
  1578. auto *pMemberIndex = llvm::dyn_cast<llvm::ConstantInt>(
  1579. pGEP->getOperand(2));
  1580. uint64_t memberIndex = pMemberIndex->getLimitedValue();
  1581. // Until we have debugging info for floatN, matrixNxM etc., we can't get the name:
  1582. // auto *secondPointer = pGEP2->getPointerOperandType();
  1583. // auto* pStruct =
  1584. // llvm::dyn_cast<llvm::StructType>(secondPointer->getVectorElementType());
  1585. NewAllocaWrite.memberName =
  1586. "member" + std::to_string(memberIndex);
  1587. }
  1588. else
  1589. {
  1590. NewAllocaWrite.memberName = pGEP->getName();
  1591. }
  1592. llvm::Value* index;
  1593. if (pix_dxil::PixAllocaRegWrite::FromInst(
  1594. store,
  1595. &NewAllocaWrite.regBase,
  1596. &NewAllocaWrite.regSize,
  1597. &index)) {
  1598. auto* asInt = llvm::dyn_cast<llvm::ConstantInt>(index);
  1599. NewAllocaWrite.index = asInt->getLimitedValue();
  1600. }
  1601. }
  1602. }
  1603. }
  1604. }
  1605. return ret;
  1606. }
  1607. void PixTest::ValidateAllocaWrite(std::vector<AllocaWrite> const &allocaWrites,
  1608. size_t index, const char *name) {
  1609. VERIFY_ARE_EQUAL(index, allocaWrites[index].index);
  1610. #if DBG
  1611. // Compilation may add a prefix to the struct member name:
  1612. VERIFY_IS_TRUE(0 == strncmp(name, allocaWrites[index].memberName.c_str(), strlen(name)));
  1613. #endif
  1614. }
  1615. TEST_F(PixTest, PixStructAnnotation_Simple) {
  1616. const char *hlsl = R"(
  1617. struct smallPayload
  1618. {
  1619. uint dummy;
  1620. };
  1621. [numthreads(1, 1, 1)]
  1622. void main()
  1623. {
  1624. smallPayload p;
  1625. p.dummy = 42;
  1626. DispatchMesh(1, 1, 1, p);
  1627. }
  1628. )";
  1629. auto Testables = TestStructAnnotationCase(hlsl);
  1630. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1631. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes[0].countOfMembers);
  1632. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1633. VERIFY_ARE_EQUAL(32, Testables.OffsetAndSizes[0].size);
  1634. VERIFY_ARE_EQUAL(1, Testables.AllocaWrites.size());
  1635. ValidateAllocaWrite(Testables.AllocaWrites, 0, "dummy");
  1636. }
  1637. TEST_F(PixTest, PixStructAnnotation_CopiedStruct) {
  1638. const char *hlsl = R"(
  1639. struct smallPayload
  1640. {
  1641. uint dummy;
  1642. };
  1643. [numthreads(1, 1, 1)]
  1644. void main()
  1645. {
  1646. smallPayload p;
  1647. p.dummy = 42;
  1648. smallPayload p2 = p;
  1649. DispatchMesh(1, 1, 1, p2);
  1650. }
  1651. )";
  1652. auto Testables = TestStructAnnotationCase(hlsl);
  1653. VERIFY_ARE_EQUAL(2, Testables.OffsetAndSizes.size());
  1654. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes[0].countOfMembers);
  1655. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1656. VERIFY_ARE_EQUAL(32, Testables.OffsetAndSizes[0].size);
  1657. VERIFY_ARE_EQUAL(2, Testables.AllocaWrites.size());
  1658. // The values in the copy don't have stable names:
  1659. ValidateAllocaWrite(Testables.AllocaWrites, 0, "");
  1660. }
  1661. TEST_F(PixTest, PixStructAnnotation_MixedSizes) {
  1662. const char *hlsl = R"(
  1663. struct smallPayload
  1664. {
  1665. bool b1;
  1666. uint16_t sixteen;
  1667. uint32_t thirtytwo;
  1668. uint64_t sixtyfour;
  1669. };
  1670. [numthreads(1, 1, 1)]
  1671. void main()
  1672. {
  1673. smallPayload p;
  1674. p.b1 = true;
  1675. p.sixteen = 16;
  1676. p.thirtytwo = 32;
  1677. p.sixtyfour = 64;
  1678. DispatchMesh(1, 1, 1, p);
  1679. }
  1680. )";
  1681. auto Testables = TestStructAnnotationCase(hlsl);
  1682. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1683. VERIFY_ARE_EQUAL(4, Testables.OffsetAndSizes[0].countOfMembers);
  1684. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1685. // 16+16 to place "thirtytwo" at its natural alignment:
  1686. VERIFY_ARE_EQUAL(32+16+16+64+32, Testables.OffsetAndSizes[0].size);
  1687. VERIFY_ARE_EQUAL(4, Testables.AllocaWrites.size());
  1688. ValidateAllocaWrite(Testables.AllocaWrites, 0, "b1");
  1689. ValidateAllocaWrite(Testables.AllocaWrites, 1, "sixteen");
  1690. ValidateAllocaWrite(Testables.AllocaWrites, 2, "thirtytwo");
  1691. ValidateAllocaWrite(Testables.AllocaWrites, 3, "sixtyfour");
  1692. }
  1693. TEST_F(PixTest, PixStructAnnotation_StructWithinStruct) {
  1694. const char *hlsl = R"(
  1695. struct Contained
  1696. {
  1697. uint32_t one;
  1698. uint32_t two;
  1699. };
  1700. struct smallPayload
  1701. {
  1702. uint32_t before;
  1703. Contained contained;
  1704. uint32_t after;
  1705. };
  1706. [numthreads(1, 1, 1)]
  1707. void main()
  1708. {
  1709. smallPayload p;
  1710. p.before = 0xb4;
  1711. p.contained.one = 1;
  1712. p.contained.two = 2;
  1713. p.after = 3;
  1714. DispatchMesh(1, 1, 1, p);
  1715. }
  1716. )";
  1717. auto Testables = TestStructAnnotationCase(hlsl);
  1718. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1719. VERIFY_ARE_EQUAL(4, Testables.OffsetAndSizes[0].countOfMembers);
  1720. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1721. VERIFY_ARE_EQUAL(4*32, Testables.OffsetAndSizes[0].size);
  1722. ValidateAllocaWrite(Testables.AllocaWrites, 0, "before");
  1723. ValidateAllocaWrite(Testables.AllocaWrites, 1, "one");
  1724. ValidateAllocaWrite(Testables.AllocaWrites, 2, "two");
  1725. ValidateAllocaWrite(Testables.AllocaWrites, 3, "after");
  1726. }
  1727. TEST_F(PixTest, PixStructAnnotation_1DArray) {
  1728. const char* hlsl = R"(
  1729. struct smallPayload
  1730. {
  1731. uint32_t Array[2];
  1732. };
  1733. [numthreads(1, 1, 1)]
  1734. void main()
  1735. {
  1736. smallPayload p;
  1737. p.Array[0] = 250;
  1738. p.Array[1] = 251;
  1739. DispatchMesh(1, 1, 1, p);
  1740. }
  1741. )";
  1742. auto Testables = TestStructAnnotationCase(hlsl);
  1743. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1744. VERIFY_ARE_EQUAL(2, Testables.OffsetAndSizes[0].countOfMembers);
  1745. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1746. VERIFY_ARE_EQUAL(2 * 32, Testables.OffsetAndSizes[0].size);
  1747. }
  1748. TEST_F(PixTest, PixStructAnnotation_2DArray) {
  1749. const char *hlsl = R"(
  1750. struct smallPayload
  1751. {
  1752. uint32_t TwoDArray[2][3];
  1753. };
  1754. [numthreads(1, 1, 1)]
  1755. void main()
  1756. {
  1757. smallPayload p;
  1758. p.TwoDArray[0][0] = 250;
  1759. p.TwoDArray[0][1] = 251;
  1760. p.TwoDArray[0][2] = 252;
  1761. p.TwoDArray[1][0] = 253;
  1762. p.TwoDArray[1][1] = 254;
  1763. p.TwoDArray[1][2] = 255;
  1764. DispatchMesh(1, 1, 1, p);
  1765. }
  1766. )";
  1767. auto Testables = TestStructAnnotationCase(hlsl);
  1768. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1769. VERIFY_ARE_EQUAL(6, Testables.OffsetAndSizes[0].countOfMembers);
  1770. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1771. VERIFY_ARE_EQUAL(2 * 3 * 32, Testables.OffsetAndSizes[0].size);
  1772. }
  1773. TEST_F(PixTest, PixStructAnnotation_EmbeddedArray) {
  1774. const char *hlsl = R"(
  1775. struct Contained
  1776. {
  1777. uint32_t array[3];
  1778. };
  1779. struct smallPayload
  1780. {
  1781. uint32_t before;
  1782. Contained contained;
  1783. uint32_t after;
  1784. };
  1785. [numthreads(1, 1, 1)]
  1786. void main()
  1787. {
  1788. smallPayload p;
  1789. p.before = 0xb4;
  1790. p.contained.array[0] = 0;
  1791. p.contained.array[1] = 1;
  1792. p.contained.array[2] = 2;
  1793. p.after = 3;
  1794. DispatchMesh(1, 1, 1, p);
  1795. }
  1796. )";
  1797. auto Testables = TestStructAnnotationCase(hlsl);
  1798. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1799. VERIFY_ARE_EQUAL(5, Testables.OffsetAndSizes[0].countOfMembers);
  1800. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1801. VERIFY_ARE_EQUAL(5 * 32, Testables.OffsetAndSizes[0].size);
  1802. ValidateAllocaWrite(Testables.AllocaWrites, 0, "before");
  1803. ValidateAllocaWrite(Testables.AllocaWrites, 1, "array");
  1804. ValidateAllocaWrite(Testables.AllocaWrites, 2, "array");
  1805. ValidateAllocaWrite(Testables.AllocaWrites, 3, "array");
  1806. ValidateAllocaWrite(Testables.AllocaWrites, 4, "after");
  1807. }
  1808. TEST_F(PixTest, PixStructAnnotation_FloatN) {
  1809. const char *hlsl = R"(
  1810. struct smallPayload
  1811. {
  1812. float2 f2;
  1813. };
  1814. [numthreads(1, 1, 1)]
  1815. void main()
  1816. {
  1817. smallPayload p;
  1818. p.f2 = float2(1,2);
  1819. DispatchMesh(1, 1, 1, p);
  1820. }
  1821. )";
  1822. auto Testables = TestStructAnnotationCase(hlsl);
  1823. // Can't test this until dbg.declare instructions are emitted when structs contain pointers-to-pointers
  1824. // VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1825. // VERIFY_ARE_EQUAL(2, Testables.OffsetAndSizes[0].countOfMembers);
  1826. // VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1827. // VERIFY_ARE_EQUAL(32 + 32, Testables.OffsetAndSizes[0].size);
  1828. VERIFY_ARE_EQUAL(2, Testables.AllocaWrites.size());
  1829. ValidateAllocaWrite(Testables.AllocaWrites, 0, "member0"); // "memberN" until dbg.declare works
  1830. ValidateAllocaWrite(Testables.AllocaWrites, 1, "member1"); // "memberN" until dbg.declare works
  1831. }
  1832. TEST_F(PixTest, PixStructAnnotation_SequentialFloatN) {
  1833. const char *hlsl = R"(
  1834. struct smallPayload
  1835. {
  1836. float3 color;
  1837. float3 dir;
  1838. };
  1839. [numthreads(1, 1, 1)]
  1840. void main()
  1841. {
  1842. smallPayload p;
  1843. p.color = float3(1,2,3);
  1844. p.dir = float3(4,5,6);
  1845. DispatchMesh(1, 1, 1, p);
  1846. }
  1847. )";
  1848. auto Testables = TestStructAnnotationCase(hlsl);
  1849. // Can't test this until dbg.declare instructions are emitted when structs contain pointers-to-pointers
  1850. // VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1851. // VERIFY_ARE_EQUAL(2, Testables.OffsetAndSizes[0].countOfMembers);
  1852. // VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1853. // VERIFY_ARE_EQUAL(32 + 32, Testables.OffsetAndSizes[0].size);
  1854. VERIFY_ARE_EQUAL(6, Testables.AllocaWrites.size());
  1855. ValidateAllocaWrite(Testables.AllocaWrites, 0, "member0"); // "memberN" until dbg.declare works
  1856. ValidateAllocaWrite(Testables.AllocaWrites, 1, "member1"); // "memberN" until dbg.declare works
  1857. ValidateAllocaWrite(Testables.AllocaWrites, 2, "member2"); // "memberN" until dbg.declare works
  1858. ValidateAllocaWrite(Testables.AllocaWrites, 3, "member0"); // "memberN" until dbg.declare works
  1859. ValidateAllocaWrite(Testables.AllocaWrites, 4, "member1"); // "memberN" until dbg.declare works
  1860. ValidateAllocaWrite(Testables.AllocaWrites, 5, "member2"); // "memberN" until dbg.declare works
  1861. }
  1862. TEST_F(PixTest, PixStructAnnotation_EmbeddedFloatN) {
  1863. const char *hlsl = R"(
  1864. struct Embedded
  1865. {
  1866. float2 f2;
  1867. };
  1868. struct smallPayload
  1869. {
  1870. uint32_t i32;
  1871. Embedded e;
  1872. };
  1873. [numthreads(1, 1, 1)]
  1874. void main()
  1875. {
  1876. smallPayload p;
  1877. p.i32 = 32;
  1878. p.e.f2 = float2(1,2);
  1879. DispatchMesh(1, 1, 1, p);
  1880. }
  1881. )";
  1882. auto Testables = TestStructAnnotationCase(hlsl);
  1883. // Can't test this until dbg.declare instructions are emitted when structs
  1884. // contain pointers-to-pointers
  1885. //VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1886. //VERIFY_ARE_EQUAL(2, Testables.OffsetAndSizes[0].countOfMembers);
  1887. //VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1888. //VERIFY_ARE_EQUAL(32 + 32, Testables.OffsetAndSizes[0].size);
  1889. VERIFY_ARE_EQUAL(3, Testables.AllocaWrites.size());
  1890. ValidateAllocaWrite(Testables.AllocaWrites, 0, "");
  1891. ValidateAllocaWrite(Testables.AllocaWrites, 1, "member0");
  1892. ValidateAllocaWrite(Testables.AllocaWrites, 2, "member1");
  1893. }
  1894. TEST_F(PixTest, PixStructAnnotation_Matrix) {
  1895. const char *hlsl = R"(
  1896. struct smallPayload
  1897. {
  1898. float4x4 mat;
  1899. };
  1900. [numthreads(1, 1, 1)]
  1901. void main()
  1902. {
  1903. smallPayload p;
  1904. p.mat = float4x4( 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15, 16);
  1905. DispatchMesh(1, 1, 1, p);
  1906. }
  1907. )";
  1908. auto Testables = TestStructAnnotationCase(hlsl);
  1909. // Can't test member iterator until dbg.declare instructions are emitted when structs
  1910. // contain pointers-to-pointers
  1911. VERIFY_ARE_EQUAL(16, Testables.AllocaWrites.size());
  1912. for (int i = 0; i < 16; ++i)
  1913. {
  1914. ValidateAllocaWrite(Testables.AllocaWrites, i, "");
  1915. }
  1916. }
  1917. TEST_F(PixTest, PixStructAnnotation_BigMess) {
  1918. const char *hlsl = R"(
  1919. struct BigStruct
  1920. {
  1921. uint64_t bigInt;
  1922. double bigDouble;
  1923. };
  1924. struct EmbeddedStruct
  1925. {
  1926. uint32_t OneInt;
  1927. uint32_t TwoDArray[2][2];
  1928. };
  1929. struct smallPayload
  1930. {
  1931. uint dummy;
  1932. uint vertexCount;
  1933. uint primitiveCount;
  1934. EmbeddedStruct embeddedStruct;
  1935. #ifdef PAYLOAD_MATRICES
  1936. float4x4 mat;
  1937. #endif
  1938. uint64_t bigOne;
  1939. half littleOne;
  1940. BigStruct bigStruct[2];
  1941. uint lastCheck;
  1942. };
  1943. [numthreads(1, 1, 1)]
  1944. void main()
  1945. {
  1946. smallPayload p;
  1947. // Adding enough instructions to make the shader interesting to debug:
  1948. p.dummy = 42;
  1949. p.vertexCount = 3;
  1950. p.primitiveCount = 1;
  1951. p.embeddedStruct.OneInt = 123;
  1952. p.embeddedStruct.TwoDArray[0][0] = 252;
  1953. p.embeddedStruct.TwoDArray[0][1] = 253;
  1954. p.embeddedStruct.TwoDArray[1][0] = 254;
  1955. p.embeddedStruct.TwoDArray[1][1] = 255;
  1956. #ifdef PAYLOAD_MATRICES
  1957. p.mat = float4x4( 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15, 16);
  1958. #endif
  1959. p.bigOne = 123456789;
  1960. p.littleOne = 1.0;
  1961. p.bigStruct[0].bigInt = 10;
  1962. p.bigStruct[0].bigDouble = 2.0;
  1963. p.bigStruct[1].bigInt = 20;
  1964. p.bigStruct[1].bigDouble = 4.0;
  1965. p.lastCheck = 27;
  1966. DispatchMesh(1, 1, 1, p);
  1967. }
  1968. )";
  1969. auto Testables = TestStructAnnotationCase(hlsl);
  1970. VERIFY_ARE_EQUAL(1, Testables.OffsetAndSizes.size());
  1971. VERIFY_ARE_EQUAL(15, Testables.OffsetAndSizes[0].countOfMembers);
  1972. VERIFY_ARE_EQUAL(0, Testables.OffsetAndSizes[0].offset);
  1973. constexpr uint32_t BigStructBitSize = 64 * 2;
  1974. constexpr uint32_t EmbeddedStructBitSize = 32 * 5;
  1975. VERIFY_ARE_EQUAL(3 * 32 + EmbeddedStructBitSize + 64 + 16 +16/*alignment for next field*/ + BigStructBitSize*2 + 32, Testables.OffsetAndSizes[0].size);
  1976. }
  1977. #endif