CompilerTest.cpp 104 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // CompilerTest.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 compiler API. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #ifndef UNICODE
  12. #define UNICODE
  13. #endif
  14. #include <memory>
  15. #include <vector>
  16. #include <string>
  17. #include <map>
  18. #include <cassert>
  19. #include <sstream>
  20. #include <algorithm>
  21. #include <cfloat>
  22. #include "dxc/DxilContainer/DxilContainer.h"
  23. #include "dxc/Support/WinIncludes.h"
  24. #include "dxc/dxcapi.h"
  25. #ifdef _WIN32
  26. #include <atlfile.h>
  27. #include "dia2.h"
  28. #endif
  29. #include "HLSLTestData.h"
  30. #include "HlslTestUtils.h"
  31. #include "DxcTestUtils.h"
  32. #include "llvm/Support/raw_os_ostream.h"
  33. #include "dxc/Support/Global.h"
  34. #include "dxc/Support/dxcapi.use.h"
  35. #include "dxc/Support/microcom.h"
  36. #include "dxc/Support/HLSLOptions.h"
  37. #include "dxc/Support/Unicode.h"
  38. #include <fstream>
  39. #include "llvm/Support/FileSystem.h"
  40. #include "llvm/Support/MSFileSystem.h"
  41. #include "llvm/Support/Path.h"
  42. #include "llvm/ADT/SmallString.h"
  43. #include "llvm/ADT/StringSwitch.h"
  44. using namespace std;
  45. using namespace hlsl_test;
  46. // Aligned to SymTagEnum.
  47. const char *SymTagEnumText[] =
  48. {
  49. "Null", // SymTagNull
  50. "Exe", // SymTagExe
  51. "Compiland", // SymTagCompiland
  52. "CompilandDetails", // SymTagCompilandDetails
  53. "CompilandEnv", // SymTagCompilandEnv
  54. "Function", // SymTagFunction
  55. "Block", // SymTagBlock
  56. "Data", // SymTagData
  57. "Annotation", // SymTagAnnotation
  58. "Label", // SymTagLabel
  59. "PublicSymbol", // SymTagPublicSymbol
  60. "UDT", // SymTagUDT
  61. "Enum", // SymTagEnum
  62. "FunctionType", // SymTagFunctionType
  63. "PointerType", // SymTagPointerType
  64. "ArrayType", // SymTagArrayType
  65. "BaseType", // SymTagBaseType
  66. "Typedef", // SymTagTypedef
  67. "BaseClass", // SymTagBaseClass
  68. "Friend", // SymTagFriend
  69. "FunctionArgType", // SymTagFunctionArgType
  70. "FuncDebugStart", // SymTagFuncDebugStart
  71. "FuncDebugEnd", // SymTagFuncDebugEnd
  72. "UsingNamespace", // SymTagUsingNamespace
  73. "VTableShape", // SymTagVTableShape
  74. "VTable", // SymTagVTable
  75. "Custom", // SymTagCustom
  76. "Thunk", // SymTagThunk
  77. "CustomType", // SymTagCustomType
  78. "ManagedType", // SymTagManagedType
  79. "Dimension", // SymTagDimension
  80. "CallSite", // SymTagCallSite
  81. "InlineSite", // SymTagInlineSite
  82. "BaseInterface", // SymTagBaseInterface
  83. "VectorType", // SymTagVectorType
  84. "MatrixType", // SymTagMatrixType
  85. "HLSLType", // SymTagHLSLType
  86. "Caller", // SymTagCaller
  87. "Callee", // SymTagCallee
  88. "Export", // SymTagExport
  89. "HeapAllocationSite", // SymTagHeapAllocationSite
  90. "CoffGroup", // SymTagCoffGroup
  91. };
  92. // Aligned to LocationType.
  93. const char *LocationTypeText[] =
  94. {
  95. "Null",
  96. "Static",
  97. "TLS",
  98. "RegRel",
  99. "ThisRel",
  100. "Enregistered",
  101. "BitField",
  102. "Slot",
  103. "IlRel",
  104. "MetaData",
  105. "Constant",
  106. };
  107. // Aligned to DataKind.
  108. const char *DataKindText[] =
  109. {
  110. "Unknown",
  111. "Local",
  112. "StaticLocal",
  113. "Param",
  114. "ObjectPtr",
  115. "FileStatic",
  116. "Global",
  117. "Member",
  118. "StaticMember",
  119. "Constant",
  120. };
  121. // Aligned to UdtKind.
  122. const char *UdtKindText[] =
  123. {
  124. "Struct",
  125. "Class",
  126. "Union",
  127. "Interface",
  128. };
  129. class TestIncludeHandler : public IDxcIncludeHandler {
  130. DXC_MICROCOM_REF_FIELD(m_dwRef)
  131. public:
  132. DXC_MICROCOM_ADDREF_RELEASE_IMPL(m_dwRef)
  133. dxc::DxcDllSupport &m_dllSupport;
  134. HRESULT m_defaultErrorCode = E_FAIL;
  135. TestIncludeHandler(dxc::DxcDllSupport &dllSupport) : m_dwRef(0), m_dllSupport(dllSupport), callIndex(0) { }
  136. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject) override {
  137. return DoBasicQueryInterface<IDxcIncludeHandler>(this, iid, ppvObject);
  138. }
  139. struct LoadSourceCallInfo {
  140. std::wstring Filename; // Filename as written in #include statement
  141. LoadSourceCallInfo(LPCWSTR pFilename) :
  142. Filename(pFilename) { }
  143. };
  144. std::vector<LoadSourceCallInfo> CallInfos;
  145. std::wstring GetAllFileNames() const {
  146. std::wstringstream s;
  147. for (size_t i = 0; i < CallInfos.size(); ++i) {
  148. s << CallInfos[i].Filename << ';';
  149. }
  150. return s.str();
  151. }
  152. struct LoadSourceCallResult {
  153. HRESULT hr;
  154. std::string source;
  155. UINT32 codePage;
  156. LoadSourceCallResult() : hr(E_FAIL), codePage(0) { }
  157. LoadSourceCallResult(const char *pSource, UINT32 codePage = CP_UTF8) : hr(S_OK), source(pSource), codePage(codePage) { }
  158. };
  159. std::vector<LoadSourceCallResult> CallResults;
  160. size_t callIndex;
  161. HRESULT STDMETHODCALLTYPE LoadSource(
  162. _In_ LPCWSTR pFilename, // Filename as written in #include statement
  163. _COM_Outptr_ IDxcBlob **ppIncludeSource // Resultant source object for included file
  164. ) override {
  165. CallInfos.push_back(LoadSourceCallInfo(pFilename));
  166. *ppIncludeSource = nullptr;
  167. if (callIndex >= CallResults.size()) {
  168. return m_defaultErrorCode;
  169. }
  170. if (FAILED(CallResults[callIndex].hr)) {
  171. return CallResults[callIndex++].hr;
  172. }
  173. MultiByteStringToBlob(m_dllSupport, CallResults[callIndex].source,
  174. CallResults[callIndex].codePage, ppIncludeSource);
  175. return CallResults[callIndex++].hr;
  176. }
  177. };
  178. #ifdef _WIN32
  179. class CompilerTest {
  180. #else
  181. class CompilerTest : public ::testing::Test {
  182. #endif
  183. public:
  184. BEGIN_TEST_CLASS(CompilerTest)
  185. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  186. TEST_METHOD_PROPERTY(L"Priority", L"0")
  187. END_TEST_CLASS()
  188. TEST_CLASS_SETUP(InitSupport);
  189. TEST_METHOD(CompileWhenDebugThenDIPresent)
  190. TEST_METHOD(CompileDebugLines)
  191. TEST_METHOD(CompileWhenDefinesThenApplied)
  192. TEST_METHOD(CompileWhenDefinesManyThenApplied)
  193. TEST_METHOD(CompileWhenEmptyThenFails)
  194. TEST_METHOD(CompileWhenIncorrectThenFails)
  195. TEST_METHOD(CompileWhenWorksThenDisassembleWorks)
  196. TEST_METHOD(CompileWhenDebugWorksThenStripDebug)
  197. TEST_METHOD(CompileWhenWorksThenAddRemovePrivate)
  198. TEST_METHOD(CompileThenAddCustomDebugName)
  199. TEST_METHOD(CompileWithRootSignatureThenStripRootSignature)
  200. TEST_METHOD(CompileWhenIncludeThenLoadInvoked)
  201. TEST_METHOD(CompileWhenIncludeThenLoadUsed)
  202. TEST_METHOD(CompileWhenIncludeAbsoluteThenLoadAbsolute)
  203. TEST_METHOD(CompileWhenIncludeLocalThenLoadRelative)
  204. TEST_METHOD(CompileWhenIncludeSystemThenLoadNotRelative)
  205. TEST_METHOD(CompileWhenIncludeSystemMissingThenLoadAttempt)
  206. TEST_METHOD(CompileWhenIncludeFlagsThenIncludeUsed)
  207. TEST_METHOD(CompileWhenIncludeMissingThenFail)
  208. TEST_METHOD(CompileWhenIncludeHasPathThenOK)
  209. TEST_METHOD(CompileWhenIncludeEmptyThenOK)
  210. TEST_METHOD(CompileWhenODumpThenPassConfig)
  211. TEST_METHOD(CompileWhenODumpThenOptimizerMatch)
  212. TEST_METHOD(CompileWhenVdThenProducesDxilContainer)
  213. #if _ITERATOR_DEBUG_LEVEL==0
  214. // CompileWhenNoMemThenOOM can properly detect leaks only when debug iterators are disabled
  215. TEST_METHOD(CompileWhenNoMemThenOOM)
  216. #endif
  217. TEST_METHOD(CompileWhenShaderModelMismatchAttributeThenFail)
  218. TEST_METHOD(CompileBadHlslThenFail)
  219. TEST_METHOD(CompileLegacyShaderModelThenFail)
  220. TEST_METHOD(CompileWhenRecursiveAlbeitStaticTermThenFail)
  221. TEST_METHOD(CompileWhenRecursiveThenFail)
  222. TEST_METHOD(CompileHlsl2015ThenFail)
  223. TEST_METHOD(CompileHlsl2016ThenOK)
  224. TEST_METHOD(CompileHlsl2017ThenOK)
  225. TEST_METHOD(CompileHlsl2018ThenOK)
  226. TEST_METHOD(CompileHlsl2019ThenFail)
  227. TEST_METHOD(DiaLoadBadBitcodeThenFail)
  228. TEST_METHOD(DiaLoadDebugThenOK)
  229. TEST_METHOD(DiaTableIndexThenOK)
  230. TEST_METHOD(CodeGenAttributeAtVertex)
  231. TEST_METHOD(CodeGenAttributeAtVertexNoOpt)
  232. TEST_METHOD(CodeGenBarycentrics)
  233. TEST_METHOD(CodeGenBarycentrics1)
  234. TEST_METHOD(CodeGenBarycentricsThreeSV)
  235. TEST_METHOD(CodeGenBitCast16Bits)
  236. TEST_METHOD(CodeGenCbuffer64Types)
  237. TEST_METHOD(CodeGenCbufferHalf)
  238. TEST_METHOD(CodeGenCbufferHalfStruct)
  239. TEST_METHOD(CodeGenCbufferInt16)
  240. TEST_METHOD(CodeGenCbufferInt16Struct)
  241. TEST_METHOD(CodeGenDataLayoutHalf)
  242. TEST_METHOD(CodeGenEnum3)
  243. TEST_METHOD(CodeGenFloatingPointEnvironment)
  244. TEST_METHOD(CodeGenFixedWidthTypes)
  245. TEST_METHOD(CodeGenFixedWidthTypes16Bit)
  246. TEST_METHOD(CodeGenFunctionAttribute)
  247. TEST_METHOD(CodeGenInclude)
  248. TEST_METHOD(CodeGenInt16Op)
  249. TEST_METHOD(CodeGenInt16OpBits)
  250. TEST_METHOD(CodeGenLibCsEntry)
  251. TEST_METHOD(CodeGenLibCsEntry2)
  252. TEST_METHOD(CodeGenLibCsEntry3)
  253. TEST_METHOD(CodeGenLibEntries)
  254. TEST_METHOD(CodeGenLibEntries2)
  255. TEST_METHOD(CodeGenLibNoAlias)
  256. TEST_METHOD(CodeGenLibResource)
  257. TEST_METHOD(CodeGenLibUnusedFunc)
  258. TEST_METHOD(CodeGenMultiUAVLoad2)
  259. TEST_METHOD(CodeGenMultiUAVLoad4)
  260. TEST_METHOD(CodeGenMultiUAVLoad5)
  261. TEST_METHOD(CodeGenMultiUAVLoad6)
  262. TEST_METHOD(CodeGenMultiUAVLoad7)
  263. TEST_METHOD(CodeGenRaw_Buf2)
  264. TEST_METHOD(CodeGenRaw_Buf4)
  265. TEST_METHOD(CodeGenRaw_Buf5)
  266. TEST_METHOD(CodeGenSignaturePackingByWidth)
  267. TEST_METHOD(CodeGenStruct_Buf2)
  268. TEST_METHOD(CodeGenStruct_Buf3)
  269. TEST_METHOD(CodeGenStruct_Buf4)
  270. TEST_METHOD(CodeGenStruct_Buf5)
  271. TEST_METHOD(CodeGenStruct_Buf6)
  272. TEST_METHOD(CodeGenStruct_Buf_New_Layout)
  273. TEST_METHOD(CodeGenUav_Typed_Load_Store3)
  274. TEST_METHOD(CodeGenUint64_2)
  275. TEST_METHOD(CodeGenLiterals_Exact_Precision_Mod)
  276. TEST_METHOD(CodeGenTypedBufferHalf)
  277. TEST_METHOD(CodeGenRootSigProfile)
  278. TEST_METHOD(CodeGenRootSigProfile2)
  279. TEST_METHOD(CodeGenRootSigProfile5)
  280. TEST_METHOD(PreprocessWhenValidThenOK)
  281. TEST_METHOD(PreprocessWhenExpandTokenPastingOperandThenAccept)
  282. TEST_METHOD(WhenSigMismatchPCFunctionThenFail)
  283. TEST_METHOD(CodeGenSamples)
  284. TEST_METHOD(ViewID)
  285. TEST_METHOD(SubobjectCodeGenErrors)
  286. TEST_METHOD(DebugInfo)
  287. TEST_METHOD(QuickTest)
  288. BEGIN_TEST_METHOD(ManualFileCheckTest)
  289. TEST_METHOD_PROPERTY(L"Ignore", L"true")
  290. END_TEST_METHOD()
  291. // Batch directories
  292. TEST_METHOD(CodeGenBatch)
  293. dxc::DxcDllSupport m_dllSupport;
  294. VersionSupportInfo m_ver;
  295. void CreateBlobPinned(_In_bytecount_(size) LPCVOID data, SIZE_T size,
  296. UINT32 codePage, _Outptr_ IDxcBlobEncoding **ppBlob) {
  297. CComPtr<IDxcLibrary> library;
  298. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  299. IFT(library->CreateBlobWithEncodingFromPinned(data, size, codePage,
  300. ppBlob));
  301. }
  302. void CreateBlobFromFile(LPCWSTR name, _Outptr_ IDxcBlobEncoding **ppBlob) {
  303. CComPtr<IDxcLibrary> library;
  304. IFT(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &library));
  305. const std::wstring path = hlsl_test::GetPathToHlslDataFile(name);
  306. IFT(library->CreateBlobFromFile(path.c_str(), nullptr, ppBlob));
  307. }
  308. void CreateBlobFromText(_In_z_ const char *pText,
  309. _Outptr_ IDxcBlobEncoding **ppBlob) {
  310. CreateBlobPinned(pText, strlen(pText), CP_UTF8, ppBlob);
  311. }
  312. HRESULT CreateCompiler(IDxcCompiler **ppResult) {
  313. return m_dllSupport.CreateInstance(CLSID_DxcCompiler, ppResult);
  314. }
  315. #ifdef _WIN32 // No ContainerBuilder support yet
  316. HRESULT CreateContainerBuilder(IDxcContainerBuilder **ppResult) {
  317. return m_dllSupport.CreateInstance(CLSID_DxcContainerBuilder, ppResult);
  318. }
  319. #endif
  320. template <typename T, typename TDefault, typename TIface>
  321. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  322. TDefault defaultValue, LPCWSTR valueLabel,
  323. HRESULT (__stdcall TIface::*pFn)(T *)) {
  324. T value;
  325. HRESULT hr = (pSymbol->*(pFn))(&value);
  326. if (SUCCEEDED(hr) && value != defaultValue) {
  327. o << L", " << valueLabel << L": " << value;
  328. }
  329. }
  330. #ifdef _WIN32 // exclude dia stuff
  331. template <typename TIface>
  332. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  333. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(BSTR *)) {
  334. CComBSTR value;
  335. HRESULT hr = (pSymbol->*(pFn))(&value);
  336. if (SUCCEEDED(hr) && value.Length()) {
  337. o << L", " << valueLabel << L": " << (LPCWSTR)value;
  338. }
  339. }
  340. template <typename TIface>
  341. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  342. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(VARIANT *)) {
  343. CComVariant value;
  344. HRESULT hr = (pSymbol->*(pFn))(&value);
  345. if (SUCCEEDED(hr) && value.vt != VT_NULL && value.vt != VT_EMPTY) {
  346. if (SUCCEEDED(value.ChangeType(VT_BSTR))) {
  347. o << L", " << valueLabel << L": " << (LPCWSTR)value.bstrVal;
  348. }
  349. }
  350. }
  351. template <typename TIface>
  352. void WriteIfValue(TIface *pSymbol, std::wstringstream &o,
  353. LPCWSTR valueLabel, HRESULT(__stdcall TIface::*pFn)(IDiaSymbol **)) {
  354. CComPtr<IDiaSymbol> value;
  355. HRESULT hr = (pSymbol->*(pFn))(&value);
  356. if (SUCCEEDED(hr) && value.p != nullptr) {
  357. DWORD symId;
  358. value->get_symIndexId(&symId);
  359. o << L", " << valueLabel << L": id=" << symId;
  360. }
  361. }
  362. std::wstring GetDebugInfoAsText(_In_ IDiaDataSource* pDataSource) {
  363. CComPtr<IDiaSession> pSession;
  364. CComPtr<IDiaTable> pTable;
  365. CComPtr<IDiaEnumTables> pEnumTables;
  366. std::wstringstream o;
  367. VERIFY_SUCCEEDED(pDataSource->openSession(&pSession));
  368. VERIFY_SUCCEEDED(pSession->getEnumTables(&pEnumTables));
  369. LONG count;
  370. VERIFY_SUCCEEDED(pEnumTables->get_Count(&count));
  371. for (LONG i = 0; i < count; ++i) {
  372. pTable.Release();
  373. ULONG fetched;
  374. VERIFY_SUCCEEDED(pEnumTables->Next(1, &pTable, &fetched));
  375. VERIFY_ARE_EQUAL(fetched, 1);
  376. CComBSTR tableName;
  377. VERIFY_SUCCEEDED(pTable->get_name(&tableName));
  378. o << L"Table: " << (LPWSTR)tableName << std::endl;
  379. LONG rowCount;
  380. IFT(pTable->get_Count(&rowCount));
  381. o << L" Row count: " << rowCount << std::endl;
  382. for (LONG rowIndex = 0; rowIndex < rowCount; ++rowIndex) {
  383. CComPtr<IUnknown> item;
  384. o << L'#' << rowIndex;
  385. IFT(pTable->Item(rowIndex, &item));
  386. CComPtr<IDiaSymbol> pSymbol;
  387. if (SUCCEEDED(item.QueryInterface(&pSymbol))) {
  388. DWORD symTag;
  389. DWORD dataKind;
  390. DWORD locationType;
  391. DWORD registerId;
  392. pSymbol->get_symTag(&symTag);
  393. pSymbol->get_dataKind(&dataKind);
  394. pSymbol->get_locationType(&locationType);
  395. pSymbol->get_registerId(&registerId);
  396. //pSymbol->get_value(&value);
  397. WriteIfValue(pSymbol.p, o, 0, L"symIndexId", &IDiaSymbol::get_symIndexId);
  398. o << L", " << SymTagEnumText[symTag];
  399. if (dataKind != 0) o << L", " << DataKindText[dataKind];
  400. WriteIfValue(pSymbol.p, o, L"name", &IDiaSymbol::get_name);
  401. WriteIfValue(pSymbol.p, o, L"lexicalParent", &IDiaSymbol::get_lexicalParent);
  402. WriteIfValue(pSymbol.p, o, L"type", &IDiaSymbol::get_type);
  403. WriteIfValue(pSymbol.p, o, 0, L"slot", &IDiaSymbol::get_slot);
  404. WriteIfValue(pSymbol.p, o, 0, L"platform", &IDiaSymbol::get_platform);
  405. WriteIfValue(pSymbol.p, o, 0, L"language", &IDiaSymbol::get_language);
  406. WriteIfValue(pSymbol.p, o, 0, L"frontEndMajor", &IDiaSymbol::get_frontEndMajor);
  407. WriteIfValue(pSymbol.p, o, 0, L"frontEndMinor", &IDiaSymbol::get_frontEndMinor);
  408. WriteIfValue(pSymbol.p, o, 0, L"token", &IDiaSymbol::get_token);
  409. WriteIfValue(pSymbol.p, o, L"value", &IDiaSymbol::get_value);
  410. WriteIfValue(pSymbol.p, o, 0, L"code", &IDiaSymbol::get_code);
  411. WriteIfValue(pSymbol.p, o, 0, L"function", &IDiaSymbol::get_function);
  412. WriteIfValue(pSymbol.p, o, 0, L"udtKind", &IDiaSymbol::get_udtKind);
  413. WriteIfValue(pSymbol.p, o, 0, L"hasDebugInfo", &IDiaSymbol::get_hasDebugInfo);
  414. WriteIfValue(pSymbol.p, o, L"compilerName", &IDiaSymbol::get_compilerName);
  415. WriteIfValue(pSymbol.p, o, 0, L"isLocationControlFlowDependent", &IDiaSymbol::get_isLocationControlFlowDependent);
  416. WriteIfValue(pSymbol.p, o, 0, L"numberOfRows", &IDiaSymbol::get_numberOfRows);
  417. WriteIfValue(pSymbol.p, o, 0, L"numberOfColumns", &IDiaSymbol::get_numberOfColumns);
  418. WriteIfValue(pSymbol.p, o, 0, L"length", &IDiaSymbol::get_length);
  419. WriteIfValue(pSymbol.p, o, 0, L"isMatrixRowMajor", &IDiaSymbol::get_isMatrixRowMajor);
  420. WriteIfValue(pSymbol.p, o, 0, L"builtInKind", &IDiaSymbol::get_builtInKind);
  421. WriteIfValue(pSymbol.p, o, 0, L"textureSlot", &IDiaSymbol::get_textureSlot);
  422. WriteIfValue(pSymbol.p, o, 0, L"memorySpaceKind", &IDiaSymbol::get_memorySpaceKind);
  423. WriteIfValue(pSymbol.p, o, 0, L"isHLSLData", &IDiaSymbol::get_isHLSLData);
  424. }
  425. CComPtr<IDiaSourceFile> pSourceFile;
  426. if (SUCCEEDED(item.QueryInterface(&pSourceFile))) {
  427. WriteIfValue(pSourceFile.p, o, 0, L"uniqueId", &IDiaSourceFile::get_uniqueId);
  428. WriteIfValue(pSourceFile.p, o, L"fileName", &IDiaSourceFile::get_fileName);
  429. }
  430. CComPtr<IDiaLineNumber> pLineNumber;
  431. if (SUCCEEDED(item.QueryInterface(&pLineNumber))) {
  432. WriteIfValue(pLineNumber.p, o, L"compiland", &IDiaLineNumber::get_compiland);
  433. //WriteIfValue(pLineNumber.p, o, L"sourceFile", &IDiaLineNumber::get_sourceFile);
  434. WriteIfValue(pLineNumber.p, o, 0, L"lineNumber", &IDiaLineNumber::get_lineNumber);
  435. WriteIfValue(pLineNumber.p, o, 0, L"lineNumberEnd", &IDiaLineNumber::get_lineNumberEnd);
  436. WriteIfValue(pLineNumber.p, o, 0, L"columnNumber", &IDiaLineNumber::get_columnNumber);
  437. WriteIfValue(pLineNumber.p, o, 0, L"columnNumberEnd", &IDiaLineNumber::get_columnNumberEnd);
  438. WriteIfValue(pLineNumber.p, o, 0, L"addressSection", &IDiaLineNumber::get_addressSection);
  439. WriteIfValue(pLineNumber.p, o, 0, L"addressOffset", &IDiaLineNumber::get_addressOffset);
  440. WriteIfValue(pLineNumber.p, o, 0, L"relativeVirtualAddress", &IDiaLineNumber::get_relativeVirtualAddress);
  441. WriteIfValue(pLineNumber.p, o, 0, L"virtualAddress", &IDiaLineNumber::get_virtualAddress);
  442. WriteIfValue(pLineNumber.p, o, 0, L"length", &IDiaLineNumber::get_length);
  443. WriteIfValue(pLineNumber.p, o, 0, L"sourceFileId", &IDiaLineNumber::get_sourceFileId);
  444. WriteIfValue(pLineNumber.p, o, 0, L"statement", &IDiaLineNumber::get_statement);
  445. WriteIfValue(pLineNumber.p, o, 0, L"compilandId", &IDiaLineNumber::get_compilandId);
  446. }
  447. CComPtr<IDiaSectionContrib> pSectionContrib;
  448. if (SUCCEEDED(item.QueryInterface(&pSectionContrib))) {
  449. WriteIfValue(pSectionContrib.p, o, L"compiland", &IDiaSectionContrib::get_compiland);
  450. WriteIfValue(pSectionContrib.p, o, 0, L"addressSection", &IDiaSectionContrib::get_addressSection);
  451. WriteIfValue(pSectionContrib.p, o, 0, L"addressOffset", &IDiaSectionContrib::get_addressOffset);
  452. WriteIfValue(pSectionContrib.p, o, 0, L"relativeVirtualAddress", &IDiaSectionContrib::get_relativeVirtualAddress);
  453. WriteIfValue(pSectionContrib.p, o, 0, L"virtualAddress", &IDiaSectionContrib::get_virtualAddress);
  454. WriteIfValue(pSectionContrib.p, o, 0, L"length", &IDiaSectionContrib::get_length);
  455. WriteIfValue(pSectionContrib.p, o, 0, L"notPaged", &IDiaSectionContrib::get_notPaged);
  456. WriteIfValue(pSectionContrib.p, o, 0, L"code", &IDiaSectionContrib::get_code);
  457. WriteIfValue(pSectionContrib.p, o, 0, L"initializedData", &IDiaSectionContrib::get_initializedData);
  458. WriteIfValue(pSectionContrib.p, o, 0, L"uninitializedData", &IDiaSectionContrib::get_uninitializedData);
  459. WriteIfValue(pSectionContrib.p, o, 0, L"remove", &IDiaSectionContrib::get_remove);
  460. WriteIfValue(pSectionContrib.p, o, 0, L"comdat", &IDiaSectionContrib::get_comdat);
  461. WriteIfValue(pSectionContrib.p, o, 0, L"discardable", &IDiaSectionContrib::get_discardable);
  462. WriteIfValue(pSectionContrib.p, o, 0, L"notCached", &IDiaSectionContrib::get_notCached);
  463. WriteIfValue(pSectionContrib.p, o, 0, L"share", &IDiaSectionContrib::get_share);
  464. WriteIfValue(pSectionContrib.p, o, 0, L"execute", &IDiaSectionContrib::get_execute);
  465. WriteIfValue(pSectionContrib.p, o, 0, L"read", &IDiaSectionContrib::get_read);
  466. WriteIfValue(pSectionContrib.p, o, 0, L"write", &IDiaSectionContrib::get_write);
  467. WriteIfValue(pSectionContrib.p, o, 0, L"dataCrc", &IDiaSectionContrib::get_dataCrc);
  468. WriteIfValue(pSectionContrib.p, o, 0, L"relocationsCrc", &IDiaSectionContrib::get_relocationsCrc);
  469. WriteIfValue(pSectionContrib.p, o, 0, L"compilandId", &IDiaSectionContrib::get_compilandId);
  470. }
  471. CComPtr<IDiaSegment> pSegment;
  472. if (SUCCEEDED(item.QueryInterface(&pSegment))) {
  473. WriteIfValue(pSegment.p, o, 0, L"frame", &IDiaSegment::get_frame);
  474. WriteIfValue(pSegment.p, o, 0, L"offset", &IDiaSegment::get_offset);
  475. WriteIfValue(pSegment.p, o, 0, L"length", &IDiaSegment::get_length);
  476. WriteIfValue(pSegment.p, o, 0, L"read", &IDiaSegment::get_read);
  477. WriteIfValue(pSegment.p, o, 0, L"write", &IDiaSegment::get_write);
  478. WriteIfValue(pSegment.p, o, 0, L"execute", &IDiaSegment::get_execute);
  479. WriteIfValue(pSegment.p, o, 0, L"addressSection", &IDiaSegment::get_addressSection);
  480. WriteIfValue(pSegment.p, o, 0, L"relativeVirtualAddress", &IDiaSegment::get_relativeVirtualAddress);
  481. WriteIfValue(pSegment.p, o, 0, L"virtualAddress", &IDiaSegment::get_virtualAddress);
  482. }
  483. CComPtr<IDiaInjectedSource> pInjectedSource;
  484. if (SUCCEEDED(item.QueryInterface(&pInjectedSource))) {
  485. WriteIfValue(pInjectedSource.p, o, 0, L"crc", &IDiaInjectedSource::get_crc);
  486. WriteIfValue(pInjectedSource.p, o, 0, L"length", &IDiaInjectedSource::get_length);
  487. WriteIfValue(pInjectedSource.p, o, L"filename", &IDiaInjectedSource::get_filename);
  488. WriteIfValue(pInjectedSource.p, o, L"objectFilename", &IDiaInjectedSource::get_objectFilename);
  489. WriteIfValue(pInjectedSource.p, o, L"virtualFilename", &IDiaInjectedSource::get_virtualFilename);
  490. WriteIfValue(pInjectedSource.p, o, 0, L"sourceCompression", &IDiaInjectedSource::get_sourceCompression);
  491. // get_source is also available
  492. }
  493. CComPtr<IDiaFrameData> pFrameData;
  494. if (SUCCEEDED(item.QueryInterface(&pFrameData))) {
  495. }
  496. o << std::endl;
  497. }
  498. }
  499. return o.str();
  500. }
  501. std::wstring GetDebugFileContent(_In_ IDiaDataSource *pDataSource) {
  502. CComPtr<IDiaSession> pSession;
  503. CComPtr<IDiaTable> pTable;
  504. CComPtr<IDiaTable> pSourcesTable;
  505. CComPtr<IDiaEnumTables> pEnumTables;
  506. std::wstringstream o;
  507. VERIFY_SUCCEEDED(pDataSource->openSession(&pSession));
  508. VERIFY_SUCCEEDED(pSession->getEnumTables(&pEnumTables));
  509. ULONG fetched = 0;
  510. while (pEnumTables->Next(1, &pTable, &fetched) == S_OK && fetched == 1) {
  511. CComBSTR name;
  512. IFT(pTable->get_name(&name));
  513. if (wcscmp(name, L"SourceFiles") == 0) {
  514. pSourcesTable = pTable.Detach();
  515. continue;
  516. }
  517. pTable.Release();
  518. }
  519. if (!pSourcesTable) {
  520. return L"cannot find source";
  521. }
  522. // Get source file contents.
  523. // NOTE: "SourceFiles" has the root file first while "InjectedSources" is in
  524. // alphabetical order.
  525. // It is important to keep the root file first for recompilation, so
  526. // iterate "SourceFiles" and look up the corresponding injected
  527. // source.
  528. LONG count;
  529. IFT(pSourcesTable->get_Count(&count));
  530. CComPtr<IDiaSourceFile> pSourceFile;
  531. CComBSTR pName;
  532. CComPtr<IUnknown> pSymbolUnk;
  533. CComPtr<IDiaEnumInjectedSources> pEnumInjectedSources;
  534. CComPtr<IDiaInjectedSource> pInjectedSource;
  535. std::wstring sourceText, sourceFilename;
  536. while (SUCCEEDED(pSourcesTable->Next(1, &pSymbolUnk, &fetched)) &&
  537. fetched == 1) {
  538. sourceText = sourceFilename = L"";
  539. IFT(pSymbolUnk->QueryInterface(&pSourceFile));
  540. IFT(pSourceFile->get_fileName(&pName));
  541. IFT(pSession->findInjectedSource(pName, &pEnumInjectedSources));
  542. if (SUCCEEDED(pEnumInjectedSources->get_Count(&count)) && count == 1) {
  543. IFT(pEnumInjectedSources->Item(0, &pInjectedSource));
  544. DWORD cbData = 0;
  545. std::string tempString;
  546. CComBSTR bstr;
  547. IFT(pInjectedSource->get_filename(&bstr));
  548. IFT(pInjectedSource->get_source(0, &cbData, nullptr));
  549. tempString.resize(cbData);
  550. IFT(pInjectedSource->get_source(
  551. cbData, &cbData, reinterpret_cast<BYTE *>(&tempString[0])));
  552. CA2W tempWString(tempString.data());
  553. o << tempWString.m_psz;
  554. }
  555. pSymbolUnk.Release();
  556. }
  557. return o.str();
  558. }
  559. struct LineNumber { DWORD line; DWORD rva; };
  560. std::vector<LineNumber> ReadLineNumbers(IDiaEnumLineNumbers *pEnumLineNumbers) {
  561. std::vector<LineNumber> lines;
  562. CComPtr<IDiaLineNumber> pLineNumber;
  563. DWORD lineCount;
  564. while (SUCCEEDED(pEnumLineNumbers->Next(1, &pLineNumber, &lineCount)) && lineCount == 1)
  565. {
  566. DWORD line;
  567. DWORD rva;
  568. VERIFY_SUCCEEDED(pLineNumber->get_lineNumber(&line));
  569. VERIFY_SUCCEEDED(pLineNumber->get_relativeVirtualAddress(&rva));
  570. lines.push_back({ line, rva });
  571. pLineNumber.Release();
  572. }
  573. return lines;
  574. }
  575. #endif // _WIN32 - exclude dia stuff
  576. std::string GetOption(std::string &cmd, char *opt) {
  577. std::string option = cmd.substr(cmd.find(opt));
  578. option = option.substr(option.find_first_of(' '));
  579. option = option.substr(option.find_first_not_of(' '));
  580. return option.substr(0, option.find_first_of(' '));
  581. }
  582. void CodeGenTest(std::wstring name) {
  583. CComPtr<IDxcCompiler> pCompiler;
  584. CComPtr<IDxcOperationResult> pResult;
  585. CComPtr<IDxcBlobEncoding> pSource;
  586. name.insert(0, L"..\\CodeGenHLSL\\");
  587. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  588. CreateBlobFromFile(name.c_str(), &pSource);
  589. std::string cmdLine = GetFirstLine(name.c_str());
  590. llvm::StringRef argsRef = cmdLine;
  591. llvm::SmallVector<llvm::StringRef, 8> splitArgs;
  592. argsRef.split(splitArgs, " ");
  593. hlsl::options::MainArgs argStrings(splitArgs);
  594. std::string errorString;
  595. llvm::raw_string_ostream errorStream(errorString);
  596. hlsl::options::DxcOpts opts;
  597. IFT(ReadDxcOpts(hlsl::options::getHlslOptTable(), /*flagsToInclude*/ 0,
  598. argStrings, opts, errorStream));
  599. std::wstring entry =
  600. Unicode::UTF8ToUTF16StringOrThrow(opts.EntryPoint.str().c_str());
  601. std::wstring profile =
  602. Unicode::UTF8ToUTF16StringOrThrow(opts.TargetProfile.str().c_str());
  603. std::vector<std::wstring> argLists;
  604. CopyArgsToWStrings(opts.Args, hlsl::options::CoreOption, argLists);
  605. std::vector<LPCWSTR> args;
  606. args.reserve(argLists.size());
  607. for (const std::wstring &a : argLists)
  608. args.push_back(a.data());
  609. VERIFY_SUCCEEDED(pCompiler->Compile(
  610. pSource, name.c_str(), entry.c_str(), profile.c_str(), args.data(), args.size(),
  611. opts.Defines.data(), opts.Defines.size(), nullptr, &pResult));
  612. VERIFY_IS_NOT_NULL(pResult, L"Failed to compile - pResult NULL");
  613. HRESULT result;
  614. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  615. if (FAILED(result)) {
  616. CComPtr<IDxcBlobEncoding> pErr;
  617. IFT(pResult->GetErrorBuffer(&pErr));
  618. std::string errString(BlobToUtf8(pErr));
  619. CA2W errStringW(errString.c_str(), CP_UTF8);
  620. WEX::Logging::Log::Comment(L"Failed to compile - errors follow");
  621. WEX::Logging::Log::Comment(errStringW);
  622. }
  623. VERIFY_SUCCEEDED(result);
  624. CComPtr<IDxcBlob> pProgram;
  625. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  626. if (opts.IsRootSignatureProfile())
  627. return;
  628. CComPtr<IDxcBlobEncoding> pDisassembleBlob;
  629. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembleBlob));
  630. std::string disassembleString(BlobToUtf8(pDisassembleBlob));
  631. VERIFY_ARE_NOT_EQUAL(0U, disassembleString.size());
  632. }
  633. void CodeGenTestCheckFullPath(LPCWSTR fullPath) {
  634. FileRunTestResult t = FileRunTestResult::RunFromFileCommands(fullPath);
  635. if (t.RunResult != 0) {
  636. CA2W commentWide(t.ErrorMessage.c_str(), CP_UTF8);
  637. WEX::Logging::Log::Comment(commentWide);
  638. WEX::Logging::Log::Error(L"Run result is not zero");
  639. }
  640. }
  641. void CodeGenTestCheck(LPCWSTR name, bool implicitDir = true) {
  642. std::wstring path = name;
  643. if (implicitDir) {
  644. path.insert(0, L"..\\CodeGenHLSL\\");
  645. path = hlsl_test::GetPathToHlslDataFile(path.c_str());
  646. }
  647. CodeGenTestCheckFullPath(path.c_str());
  648. }
  649. void CodeGenTestCheckBatchDir(std::wstring suitePath, bool implicitDir = true) {
  650. using namespace llvm;
  651. using namespace WEX::TestExecution;
  652. if (implicitDir) suitePath.insert(0, L"..\\CodeGenHLSL\\");
  653. ::llvm::sys::fs::MSFileSystem *msfPtr;
  654. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  655. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  656. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  657. IFTLLVM(pts.error_code());
  658. CW2A pUtf8Filename(suitePath.c_str());
  659. if (!llvm::sys::path::is_absolute(pUtf8Filename.m_psz)) {
  660. suitePath = hlsl_test::GetPathToHlslDataFile(suitePath.c_str());
  661. }
  662. CW2A utf8SuitePath(suitePath.c_str());
  663. unsigned numTestsRun = 0;
  664. std::error_code EC;
  665. llvm::SmallString<128> DirNative;
  666. llvm::sys::path::native(utf8SuitePath.m_psz, DirNative);
  667. for (llvm::sys::fs::recursive_directory_iterator Dir(DirNative, EC), DirEnd;
  668. Dir != DirEnd && !EC; Dir.increment(EC)) {
  669. // Check whether this entry has an extension typically associated with
  670. // headers.
  671. if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
  672. .Cases(".hlsl", ".ll", true).Default(false))
  673. continue;
  674. StringRef filename = Dir->path();
  675. CA2W wRelPath(filename.data());
  676. WEX::Logging::Log::StartGroup(wRelPath);
  677. CodeGenTestCheck(wRelPath, /*implicitDir*/ false);
  678. WEX::Logging::Log::EndGroup(wRelPath);
  679. numTestsRun++;
  680. }
  681. VERIFY_IS_GREATER_THAN(numTestsRun, (unsigned)0, L"No test files found in batch directory.");
  682. }
  683. std::string VerifyCompileFailed(LPCSTR pText, LPCWSTR pTargetProfile, LPCSTR pErrorMsg) {
  684. return VerifyCompileFailed(pText, pTargetProfile, pErrorMsg, L"main");
  685. }
  686. std::string VerifyCompileFailed(LPCSTR pText, LPCWSTR pTargetProfile, LPCSTR pErrorMsg, LPCWSTR pEntryPoint) {
  687. CComPtr<IDxcCompiler> pCompiler;
  688. CComPtr<IDxcOperationResult> pResult;
  689. CComPtr<IDxcBlobEncoding> pSource;
  690. CComPtr<IDxcBlobEncoding> pErrors;
  691. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  692. CreateBlobFromText(pText, &pSource);
  693. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", pEntryPoint,
  694. pTargetProfile, nullptr, 0, nullptr, 0, nullptr, &pResult));
  695. HRESULT status;
  696. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  697. VERIFY_FAILED(status);
  698. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  699. if (pErrorMsg && *pErrorMsg) {
  700. CheckOperationResultMsgs(pResult, &pErrorMsg, 1, false, false);
  701. }
  702. return BlobToUtf8(pErrors);
  703. }
  704. void VerifyOperationSucceeded(IDxcOperationResult *pResult) {
  705. HRESULT result;
  706. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  707. if (FAILED(result)) {
  708. CComPtr<IDxcBlobEncoding> pErrors;
  709. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  710. CA2W errorsWide(BlobToUtf8(pErrors).c_str(), CP_UTF8);
  711. WEX::Logging::Log::Comment(errorsWide);
  712. }
  713. VERIFY_SUCCEEDED(result);
  714. }
  715. std::string VerifyOperationFailed(IDxcOperationResult *pResult) {
  716. HRESULT result;
  717. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  718. VERIFY_FAILED(result);
  719. CComPtr<IDxcBlobEncoding> pErrors;
  720. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  721. return BlobToUtf8(pErrors);
  722. }
  723. #ifdef _WIN32 // - exclude dia stuff
  724. HRESULT CreateDiaSourceForCompile(const char *hlsl, IDiaDataSource **ppDiaSource)
  725. {
  726. if (!ppDiaSource)
  727. return E_POINTER;
  728. CComPtr<IDxcCompiler> pCompiler;
  729. CComPtr<IDxcOperationResult> pResult;
  730. CComPtr<IDxcBlobEncoding> pSource;
  731. CComPtr<IDxcBlob> pProgram;
  732. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  733. CreateBlobFromText(hlsl, &pSource);
  734. LPCWSTR args[] = { L"/Zi" };
  735. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  736. L"ps_6_0", args, _countof(args), nullptr, 0, nullptr, &pResult));
  737. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  738. // Disassemble the compiled (stripped) program.
  739. {
  740. CComPtr<IDxcBlobEncoding> pDisassembly;
  741. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembly));
  742. std::string disText = BlobToUtf8(pDisassembly);
  743. CA2W disTextW(disText.c_str(), CP_UTF8);
  744. //WEX::Logging::Log::Comment(disTextW);
  745. }
  746. // CONSIDER: have the dia data source look for the part if passed a whole container.
  747. CComPtr<IDiaDataSource> pDiaSource;
  748. CComPtr<IStream> pProgramStream;
  749. CComPtr<IDxcLibrary> pLib;
  750. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  751. const hlsl::DxilContainerHeader *pContainer = hlsl::IsDxilContainerLike(
  752. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  753. VERIFY_IS_NOT_NULL(pContainer);
  754. hlsl::DxilPartIterator partIter =
  755. std::find_if(hlsl::begin(pContainer), hlsl::end(pContainer),
  756. hlsl::DxilPartIsType(hlsl::DFCC_ShaderDebugInfoDXIL));
  757. const hlsl::DxilProgramHeader *pProgramHeader =
  758. (const hlsl::DxilProgramHeader *)hlsl::GetDxilPartData(*partIter);
  759. uint32_t bitcodeLength;
  760. const char *pBitcode;
  761. CComPtr<IDxcBlob> pProgramPdb;
  762. hlsl::GetDxilProgramBitcode(pProgramHeader, &pBitcode, &bitcodeLength);
  763. VERIFY_SUCCEEDED(pLib->CreateBlobFromBlob(
  764. pProgram, pBitcode - (char *)pProgram->GetBufferPointer(), bitcodeLength,
  765. &pProgramPdb));
  766. // Disassemble the program with debug information.
  767. {
  768. CComPtr<IDxcBlobEncoding> pDbgDisassembly;
  769. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgramPdb, &pDbgDisassembly));
  770. std::string disText = BlobToUtf8(pDbgDisassembly);
  771. CA2W disTextW(disText.c_str(), CP_UTF8);
  772. //WEX::Logging::Log::Comment(disTextW);
  773. }
  774. // Create a short text dump of debug information.
  775. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pProgramPdb, &pProgramStream));
  776. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  777. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pProgramStream));
  778. *ppDiaSource = pDiaSource.Detach();
  779. return S_OK;
  780. }
  781. #endif // _WIN32 - exclude dia stuff
  782. };
  783. // Useful for debugging.
  784. #if SUPPORT_FXC_PDB
  785. #include <d3dcompiler.h>
  786. #pragma comment(lib, "d3dcompiler.lib")
  787. HRESULT GetBlobPdb(IDxcBlob *pBlob, IDxcBlob **ppDebugInfo) {
  788. return D3DGetBlobPart(pBlob->GetBufferPointer(), pBlob->GetBufferSize(),
  789. D3D_BLOB_PDB, 0, (ID3DBlob **)ppDebugInfo);
  790. }
  791. std::string FourCCStr(uint32_t val) {
  792. std::stringstream o;
  793. char c[5];
  794. c[0] = val & 0xFF;
  795. c[1] = (val & 0xFF00) >> 8;
  796. c[2] = (val & 0xFF0000) >> 16;
  797. c[3] = (val & 0xFF000000) >> 24;
  798. c[4] = '\0';
  799. o << c << " (" << std::hex << val << std::dec << ")";
  800. return o.str();
  801. }
  802. std::string DumpParts(IDxcBlob *pBlob) {
  803. std::stringstream o;
  804. hlsl::DxilContainerHeader *pContainer = (hlsl::DxilContainerHeader *)pBlob->GetBufferPointer();
  805. o << "Container:" << std::endl
  806. << " Size: " << pContainer->ContainerSizeInBytes << std::endl
  807. << " FourCC: " << FourCCStr(pContainer->HeaderFourCC) << std::endl
  808. << " Part count: " << pContainer->PartCount << std::endl;
  809. for (uint32_t i = 0; i < pContainer->PartCount; ++i) {
  810. hlsl::DxilPartHeader *pPart = hlsl::GetDxilContainerPart(pContainer, i);
  811. o << "Part " << i << std::endl
  812. << " FourCC: " << FourCCStr(pPart->PartFourCC) << std::endl
  813. << " Size: " << pPart->PartSize << std::endl;
  814. }
  815. return o.str();
  816. }
  817. HRESULT CreateDiaSourceFromDxbcBlob(IDxcLibrary *pLib, IDxcBlob *pDxbcBlob,
  818. IDiaDataSource **ppDiaSource) {
  819. HRESULT hr = S_OK;
  820. CComPtr<IDxcBlob> pdbBlob;
  821. CComPtr<IStream> pPdbStream;
  822. CComPtr<IDiaDataSource> pDiaSource;
  823. IFR(GetBlobPdb(pDxbcBlob, &pdbBlob));
  824. IFR(pLib->CreateStreamFromBlobReadOnly(pdbBlob, &pPdbStream));
  825. IFR(CoCreateInstance(CLSID_DiaSource, NULL, CLSCTX_INPROC_SERVER,
  826. __uuidof(IDiaDataSource), (void **)&pDiaSource));
  827. IFR(pDiaSource->loadDataFromIStream(pPdbStream));
  828. *ppDiaSource = pDiaSource.Detach();
  829. return hr;
  830. }
  831. #endif
  832. bool CompilerTest::InitSupport() {
  833. if (!m_dllSupport.IsEnabled()) {
  834. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  835. m_ver.Initialize(m_dllSupport);
  836. }
  837. return true;
  838. }
  839. #if _WIN32 // - exclude dia stuff
  840. TEST_F(CompilerTest, CompileWhenDebugThenDIPresent) {
  841. // BUG: the first test written was of this form:
  842. // float4 local = 0; return local;
  843. //
  844. // However we get no numbers because of the _wrapper form
  845. // that exports the zero initialization from main into
  846. // a global can't be attributed to any particular location
  847. // within main, and everything in main is eventually folded away.
  848. //
  849. // Making the function do a bit more work by calling an intrinsic
  850. // helps this case.
  851. CComPtr<IDiaDataSource> pDiaSource;
  852. VERIFY_SUCCEEDED(CreateDiaSourceForCompile(
  853. "float4 main(float4 pos : SV_Position) : SV_Target {\r\n"
  854. " float4 local = abs(pos);\r\n"
  855. " return local;\r\n"
  856. "}", &pDiaSource));
  857. std::wstring diaDump = GetDebugInfoAsText(pDiaSource).c_str();
  858. //WEX::Logging::Log::Comment(GetDebugInfoAsText(pDiaSource).c_str());
  859. // Very basic tests - we have basic symbols, line numbers, and files with sources.
  860. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"symIndexId: 5, CompilandEnv, name: hlslTarget, lexicalParent: id=2, value: ps_6_0"));
  861. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"lineNumber: 2"));
  862. VERIFY_IS_NOT_NULL(wcsstr(diaDump.c_str(), L"length: 99, filename: source.hlsl"));
  863. std::wstring diaFileContent = GetDebugFileContent(pDiaSource).c_str();
  864. VERIFY_IS_NOT_NULL(wcsstr(diaFileContent.c_str(), L"loat4 main(float4 pos : SV_Position) : SV_Target"));
  865. #if SUPPORT_FXC_PDB
  866. // Now, fake it by loading from a .pdb!
  867. VERIFY_SUCCEEDED(CoInitializeEx(0, COINITBASE_MULTITHREADED));
  868. const wchar_t path[] = L"path-to-fxc-blob.bin";
  869. pDiaSource.Release();
  870. pProgramStream.Release();
  871. CComPtr<IDxcBlobEncoding> fxcBlob;
  872. CComPtr<IDxcBlob> pdbBlob;
  873. VERIFY_SUCCEEDED(pLib->CreateBlobFromFile(path, nullptr, &fxcBlob));
  874. std::string s = DumpParts(fxcBlob);
  875. CA2W sW(s.c_str(), CP_UTF8);
  876. WEX::Logging::Log::Comment(sW);
  877. VERIFY_SUCCEEDED(CreateDiaSourceFromDxbcBlob(pLib, fxcBlob, &pDiaSource));
  878. WEX::Logging::Log::Comment(GetDebugInfoAsText(pDiaSource).c_str());
  879. #endif
  880. }
  881. TEST_F(CompilerTest, CompileDebugLines) {
  882. CComPtr<IDiaDataSource> pDiaSource;
  883. VERIFY_SUCCEEDED(CreateDiaSourceForCompile(
  884. "float main(float pos : A) : SV_Target {\r\n"
  885. " float x = abs(pos);\r\n"
  886. " float y = sin(pos);\r\n"
  887. " float z = x + y;\r\n"
  888. " return z;\r\n"
  889. "}", &pDiaSource));
  890. static constexpr uint32_t numExpectedRVAs = 10;
  891. auto verifyLines = [=](const std::vector<LineNumber> lines) {
  892. VERIFY_ARE_EQUAL(lines.size(), numExpectedRVAs);
  893. // 0: loadInput
  894. VERIFY_ARE_EQUAL(lines[0].rva, 0);
  895. VERIFY_ARE_EQUAL(lines[0].line, 1);
  896. // 1: dbg.value
  897. VERIFY_ARE_EQUAL(lines[1].rva, 1);
  898. VERIFY_ARE_EQUAL(lines[1].line, 1);
  899. // 2: abs
  900. VERIFY_ARE_EQUAL(lines[2].rva, 2);
  901. VERIFY_ARE_EQUAL(lines[2].line, 2);
  902. // 3: dbg.value
  903. VERIFY_ARE_EQUAL(lines[3].rva, 3);
  904. VERIFY_ARE_EQUAL(lines[3].line, 2);
  905. // 4: sin
  906. VERIFY_ARE_EQUAL(lines[4].rva, 4);
  907. VERIFY_ARE_EQUAL(lines[4].line, 3);
  908. // 5: dbg.value
  909. VERIFY_ARE_EQUAL(lines[5].rva, 5);
  910. VERIFY_ARE_EQUAL(lines[5].line, 3);
  911. // 6: fadd
  912. VERIFY_ARE_EQUAL(lines[6].rva, 6);
  913. VERIFY_ARE_EQUAL(lines[6].line, 4);
  914. // 7: dbg.value
  915. VERIFY_ARE_EQUAL(lines[7].rva, 7);
  916. VERIFY_ARE_EQUAL(lines[7].line, 4);
  917. // 8: storeOutput
  918. VERIFY_ARE_EQUAL(lines[8].rva, 8);
  919. VERIFY_ARE_EQUAL(lines[8].line, 5);
  920. // 9: ret
  921. VERIFY_ARE_EQUAL(lines[9].rva, 9);
  922. VERIFY_ARE_EQUAL(lines[9].line, 5);
  923. };
  924. CComPtr<IDiaSession> pSession;
  925. CComPtr<IDiaEnumLineNumbers> pEnumLineNumbers;
  926. // Verify lines are ok when getting one RVA at a time.
  927. std::vector<LineNumber> linesOneByOne;
  928. VERIFY_SUCCEEDED(pDiaSource->openSession(&pSession));
  929. for (int i = 0; i < numExpectedRVAs; ++i) {
  930. VERIFY_SUCCEEDED(pSession->findLinesByRVA(i, 1, &pEnumLineNumbers));
  931. std::vector<LineNumber> lines = ReadLineNumbers(pEnumLineNumbers);
  932. std::copy(lines.begin(), lines.end(), std::back_inserter(linesOneByOne));
  933. pEnumLineNumbers.Release();
  934. }
  935. verifyLines(linesOneByOne);
  936. // Verify lines are ok when getting all RVAs at once.
  937. std::vector<LineNumber> linesAllAtOnce;
  938. pEnumLineNumbers.Release();
  939. VERIFY_SUCCEEDED(pSession->findLinesByRVA(0, numExpectedRVAs, &pEnumLineNumbers));
  940. linesAllAtOnce = ReadLineNumbers(pEnumLineNumbers);
  941. verifyLines(linesAllAtOnce);
  942. // Verify lines are ok when getting all lines through enum tables.
  943. std::vector<LineNumber> linesFromTable;
  944. pEnumLineNumbers.Release();
  945. CComPtr<IDiaEnumTables> pTables;
  946. CComPtr<IDiaTable> pTable;
  947. VERIFY_SUCCEEDED(pSession->getEnumTables(&pTables));
  948. DWORD celt;
  949. while (SUCCEEDED(pTables->Next(1, &pTable, &celt)) && celt == 1)
  950. {
  951. if (SUCCEEDED(pTable->QueryInterface(&pEnumLineNumbers))) {
  952. linesFromTable = ReadLineNumbers(pEnumLineNumbers);
  953. break;
  954. }
  955. pTable.Release();
  956. }
  957. verifyLines(linesFromTable);
  958. // Verify lines are ok when getting by address.
  959. std::vector<LineNumber> linesByAddr;
  960. pEnumLineNumbers.Release();
  961. VERIFY_SUCCEEDED(pSession->findLinesByAddr(0, 0, numExpectedRVAs, &pEnumLineNumbers));
  962. linesByAddr = ReadLineNumbers(pEnumLineNumbers);
  963. verifyLines(linesByAddr);
  964. // Verify findFileById.
  965. CComPtr<IDiaSourceFile> pFile;
  966. VERIFY_SUCCEEDED(pSession->findFileById(0, &pFile));
  967. CComBSTR pName;
  968. VERIFY_SUCCEEDED(pFile->get_fileName(&pName));
  969. VERIFY_ARE_EQUAL_WSTR(pName, L"source.hlsl");
  970. }
  971. #endif // _WIN32 - exclude dia stuff
  972. TEST_F(CompilerTest, CompileWhenDefinesThenApplied) {
  973. CComPtr<IDxcCompiler> pCompiler;
  974. CComPtr<IDxcOperationResult> pResult;
  975. CComPtr<IDxcBlobEncoding> pSource;
  976. DxcDefine defines[] = {{L"F4", L"float4"}};
  977. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  978. CreateBlobFromText("F4 main() : SV_Target { return 0; }", &pSource);
  979. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  980. L"ps_6_0", nullptr, 0, defines,
  981. _countof(defines), nullptr, &pResult));
  982. }
  983. TEST_F(CompilerTest, CompileWhenDefinesManyThenApplied) {
  984. CComPtr<IDxcCompiler> pCompiler;
  985. CComPtr<IDxcOperationResult> pResult;
  986. CComPtr<IDxcBlobEncoding> pSource;
  987. LPCWSTR args[] = {L"/DVAL1=1", L"/DVAL2=2", L"/DVAL3=3", L"/DVAL4=2",
  988. L"/DVAL5=4", L"/DNVAL1", L"/DNVAL2", L"/DNVAL3",
  989. L"/DNVAL4", L"/DNVAL5", L"/DCVAL1=1", L"/DCVAL2=2",
  990. L"/DCVAL3=3", L"/DCVAL4=2", L"/DCVAL5=4", L"/DCVALNONE="};
  991. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  992. CreateBlobFromText("float4 main() : SV_Target {\r\n"
  993. "#ifndef VAL1\r\n"
  994. "#error VAL1 not defined\r\n"
  995. "#endif\r\n"
  996. "#ifndef NVAL5\r\n"
  997. "#error NVAL5 not defined\r\n"
  998. "#endif\r\n"
  999. "#ifndef CVALNONE\r\n"
  1000. "#error CVALNONE not defined\r\n"
  1001. "#endif\r\n"
  1002. "return 0; }",
  1003. &pSource);
  1004. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1005. L"ps_6_0", args, _countof(args), nullptr,
  1006. 0, nullptr, &pResult));
  1007. HRESULT compileStatus;
  1008. VERIFY_SUCCEEDED(pResult->GetStatus(&compileStatus));
  1009. if (FAILED(compileStatus)) {
  1010. CComPtr<IDxcBlobEncoding> pErrors;
  1011. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  1012. OutputDebugStringA((LPCSTR)pErrors->GetBufferPointer());
  1013. }
  1014. VERIFY_SUCCEEDED(compileStatus);
  1015. }
  1016. TEST_F(CompilerTest, CompileWhenEmptyThenFails) {
  1017. CComPtr<IDxcCompiler> pCompiler;
  1018. CComPtr<IDxcOperationResult> pResult;
  1019. CComPtr<IDxcBlobEncoding> pSource;
  1020. CComPtr<IDxcBlobEncoding> pSourceBad;
  1021. LPCWSTR pProfile = L"ps_6_0";
  1022. LPCWSTR pEntryPoint = L"main";
  1023. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1024. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  1025. CreateBlobFromText("float4 main() : SV_Target { return undef; }", &pSourceBad);
  1026. // correct version
  1027. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", pEntryPoint,
  1028. pProfile, nullptr, 0, nullptr, 0, nullptr,
  1029. &pResult));
  1030. pResult.Release();
  1031. // correct version with compilation errors
  1032. VERIFY_SUCCEEDED(pCompiler->Compile(pSourceBad, L"source.hlsl", pEntryPoint,
  1033. pProfile, nullptr, 0, nullptr, 0, nullptr,
  1034. &pResult));
  1035. pResult.Release();
  1036. // null source
  1037. VERIFY_FAILED(pCompiler->Compile(nullptr, L"source.hlsl", pEntryPoint, pProfile,
  1038. nullptr, 0, nullptr, 0, nullptr, &pResult));
  1039. // null profile
  1040. VERIFY_FAILED(pCompiler->Compile(pSourceBad, L"source.hlsl", pEntryPoint,
  1041. nullptr, nullptr, 0, nullptr, 0, nullptr,
  1042. &pResult));
  1043. // null source name succeeds
  1044. VERIFY_SUCCEEDED(pCompiler->Compile(pSourceBad, nullptr, pEntryPoint, pProfile,
  1045. nullptr, 0, nullptr, 0, nullptr, &pResult));
  1046. pResult.Release();
  1047. // empty source name (as opposed to null) also suceeds
  1048. VERIFY_SUCCEEDED(pCompiler->Compile(pSourceBad, L"", pEntryPoint, pProfile,
  1049. nullptr, 0, nullptr, 0, nullptr,
  1050. &pResult));
  1051. pResult.Release();
  1052. // null result
  1053. VERIFY_FAILED(pCompiler->Compile(pSource, L"source.hlsl", pEntryPoint,
  1054. pProfile, nullptr, 0, nullptr, 0, nullptr,
  1055. nullptr));
  1056. }
  1057. TEST_F(CompilerTest, CompileWhenIncorrectThenFails) {
  1058. CComPtr<IDxcCompiler> pCompiler;
  1059. CComPtr<IDxcOperationResult> pResult;
  1060. CComPtr<IDxcBlobEncoding> pSource;
  1061. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1062. CreateBlobFromText("float4_undefined main() : SV_Target { return 0; }",
  1063. &pSource);
  1064. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main", L"ps_6_0",
  1065. nullptr, 0, nullptr, 0, nullptr,
  1066. &pResult));
  1067. HRESULT result;
  1068. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  1069. VERIFY_FAILED(result);
  1070. CComPtr<IDxcBlobEncoding> pErrorBuffer;
  1071. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrorBuffer));
  1072. std::string errorString(BlobToUtf8(pErrorBuffer));
  1073. VERIFY_ARE_NOT_EQUAL(0U, errorString.size());
  1074. // Useful for examining actual error message:
  1075. // CA2W errorStringW(errorString.c_str(), CP_UTF8);
  1076. // WEX::Logging::Log::Comment(errorStringW.m_psz);
  1077. }
  1078. TEST_F(CompilerTest, CompileWhenWorksThenDisassembleWorks) {
  1079. CComPtr<IDxcCompiler> pCompiler;
  1080. CComPtr<IDxcOperationResult> pResult;
  1081. CComPtr<IDxcBlobEncoding> pSource;
  1082. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1083. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  1084. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1085. L"ps_6_0", nullptr, 0, nullptr, 0,
  1086. nullptr, &pResult));
  1087. HRESULT result;
  1088. VERIFY_SUCCEEDED(pResult->GetStatus(&result));
  1089. VERIFY_SUCCEEDED(result);
  1090. CComPtr<IDxcBlob> pProgram;
  1091. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1092. CComPtr<IDxcBlobEncoding> pDisassembleBlob;
  1093. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembleBlob));
  1094. std::string disassembleString(BlobToUtf8(pDisassembleBlob));
  1095. VERIFY_ARE_NOT_EQUAL(0U, disassembleString.size());
  1096. // Useful for examining disassembly:
  1097. // CA2W disassembleStringW(disassembleString.c_str(), CP_UTF8);
  1098. // WEX::Logging::Log::Comment(disassembleStringW.m_psz);
  1099. }
  1100. #ifdef _WIN32 // Container builder unsupported
  1101. TEST_F(CompilerTest, CompileWhenDebugWorksThenStripDebug) {
  1102. CComPtr<IDxcCompiler> pCompiler;
  1103. CComPtr<IDxcOperationResult> pResult;
  1104. CComPtr<IDxcBlobEncoding> pSource;
  1105. CComPtr<IDxcBlob> pProgram;
  1106. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1107. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target {\r\n"
  1108. " float4 local = abs(pos);\r\n"
  1109. " return local;\r\n"
  1110. "}",
  1111. &pSource);
  1112. LPCWSTR args[] = {L"/Zi"};
  1113. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1114. L"ps_6_0", args, _countof(args), nullptr,
  1115. 0, nullptr, &pResult));
  1116. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1117. // Check if it contains debug blob
  1118. hlsl::DxilContainerHeader *pHeader =
  1119. (hlsl::DxilContainerHeader *)(pProgram->GetBufferPointer());
  1120. hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
  1121. pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL);
  1122. VERIFY_IS_NOT_NULL(pPartHeader);
  1123. // Check debug info part does not exist after strip debug info
  1124. CComPtr<IDxcBlob> pNewProgram;
  1125. CComPtr<IDxcContainerBuilder> pBuilder;
  1126. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  1127. VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
  1128. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL));
  1129. pResult.Release();
  1130. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  1131. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  1132. pHeader = (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
  1133. pPartHeader = hlsl::GetDxilPartByType(
  1134. pHeader, hlsl::DxilFourCC::DFCC_ShaderDebugInfoDXIL);
  1135. VERIFY_IS_NULL(pPartHeader);
  1136. }
  1137. TEST_F(CompilerTest, CompileWhenWorksThenAddRemovePrivate) {
  1138. CComPtr<IDxcCompiler> pCompiler;
  1139. CComPtr<IDxcOperationResult> pResult;
  1140. CComPtr<IDxcBlobEncoding> pSource;
  1141. CComPtr<IDxcBlob> pProgram;
  1142. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1143. CreateBlobFromText("float4 main() : SV_Target {\r\n"
  1144. " return 0;\r\n"
  1145. "}",
  1146. &pSource);
  1147. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1148. L"ps_6_0", nullptr, 0, nullptr, 0,
  1149. nullptr, &pResult));
  1150. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1151. // Append private data blob
  1152. CComPtr<IDxcContainerBuilder> pBuilder;
  1153. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  1154. std::string privateTxt("private data");
  1155. CComPtr<IDxcBlobEncoding> pPrivate;
  1156. CreateBlobFromText(privateTxt.c_str(), &pPrivate);
  1157. VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
  1158. VERIFY_SUCCEEDED(pBuilder->AddPart(hlsl::DxilFourCC::DFCC_PrivateData, pPrivate));
  1159. pResult.Release();
  1160. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  1161. CComPtr<IDxcBlob> pNewProgram;
  1162. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  1163. hlsl::DxilContainerHeader *pContainerHeader =
  1164. (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
  1165. hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
  1166. pContainerHeader, hlsl::DxilFourCC::DFCC_PrivateData);
  1167. VERIFY_IS_NOT_NULL(pPartHeader);
  1168. // compare data
  1169. std::string privatePart((const char *)(pPartHeader + 1), privateTxt.size());
  1170. VERIFY_IS_TRUE(strcmp(privatePart.c_str(), privateTxt.c_str()) == 0);
  1171. // Remove private data blob
  1172. pBuilder.Release();
  1173. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  1174. VERIFY_SUCCEEDED(pBuilder->Load(pNewProgram));
  1175. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_PrivateData));
  1176. pResult.Release();
  1177. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  1178. pNewProgram.Release();
  1179. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  1180. pContainerHeader =
  1181. (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
  1182. pPartHeader = hlsl::GetDxilPartByType(
  1183. pContainerHeader, hlsl::DxilFourCC::DFCC_PrivateData);
  1184. VERIFY_IS_NULL(pPartHeader);
  1185. }
  1186. TEST_F(CompilerTest, CompileThenAddCustomDebugName) {
  1187. // container builders prior to 1.3 did not support adding debug name parts
  1188. if (m_ver.SkipDxilVersion(1, 3)) return;
  1189. CComPtr<IDxcCompiler> pCompiler;
  1190. CComPtr<IDxcOperationResult> pResult;
  1191. CComPtr<IDxcBlobEncoding> pSource;
  1192. CComPtr<IDxcBlob> pProgram;
  1193. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1194. CreateBlobFromText("float4 main() : SV_Target {\r\n"
  1195. " return 0;\r\n"
  1196. "}",
  1197. &pSource);
  1198. LPCWSTR args[] = { L"/Zi", L"/Zss" };
  1199. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1200. L"ps_6_0", args, _countof(args), nullptr, 0,
  1201. nullptr, &pResult));
  1202. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1203. // Append private data blob
  1204. CComPtr<IDxcContainerBuilder> pBuilder;
  1205. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  1206. const char pNewName[] = "MyOwnUniqueName.lld";
  1207. //include null terminator:
  1208. size_t nameBlobPartSize = sizeof(hlsl::DxilShaderDebugName) + _countof(pNewName);
  1209. // round up to four-byte size:
  1210. size_t allocatedSize = (nameBlobPartSize + 3) & ~3;
  1211. auto pNameBlobContent = reinterpret_cast<hlsl::DxilShaderDebugName*>(malloc(allocatedSize));
  1212. ZeroMemory(pNameBlobContent, allocatedSize); //just to make sure trailing nulls are nulls.
  1213. pNameBlobContent->Flags = 0;
  1214. pNameBlobContent->NameLength = _countof(pNewName) - 1; //this is not supposed to include null terminator
  1215. memcpy(pNameBlobContent + 1, pNewName, _countof(pNewName));
  1216. CComPtr<IDxcBlobEncoding> pDebugName;
  1217. CreateBlobPinned(pNameBlobContent, allocatedSize, CP_UTF8, &pDebugName);
  1218. VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
  1219. // should fail since it already exists:
  1220. VERIFY_FAILED(pBuilder->AddPart(hlsl::DxilFourCC::DFCC_ShaderDebugName, pDebugName));
  1221. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_ShaderDebugName));
  1222. VERIFY_SUCCEEDED(pBuilder->AddPart(hlsl::DxilFourCC::DFCC_ShaderDebugName, pDebugName));
  1223. pResult.Release();
  1224. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  1225. CComPtr<IDxcBlob> pNewProgram;
  1226. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  1227. hlsl::DxilContainerHeader *pContainerHeader =
  1228. (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
  1229. hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
  1230. pContainerHeader, hlsl::DxilFourCC::DFCC_ShaderDebugName);
  1231. VERIFY_IS_NOT_NULL(pPartHeader);
  1232. // compare data
  1233. VERIFY_IS_TRUE(memcmp(pPartHeader + 1, pNameBlobContent, allocatedSize) == 0);
  1234. free(pNameBlobContent);
  1235. // Remove private data blob
  1236. pBuilder.Release();
  1237. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  1238. VERIFY_SUCCEEDED(pBuilder->Load(pNewProgram));
  1239. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_ShaderDebugName));
  1240. pResult.Release();
  1241. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  1242. pNewProgram.Release();
  1243. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  1244. pContainerHeader =
  1245. (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
  1246. pPartHeader = hlsl::GetDxilPartByType(
  1247. pContainerHeader, hlsl::DxilFourCC::DFCC_ShaderDebugName);
  1248. VERIFY_IS_NULL(pPartHeader);
  1249. }
  1250. TEST_F(CompilerTest, CompileWithRootSignatureThenStripRootSignature) {
  1251. CComPtr<IDxcCompiler> pCompiler;
  1252. CComPtr<IDxcOperationResult> pResult;
  1253. CComPtr<IDxcBlobEncoding> pSource;
  1254. CComPtr<IDxcBlob> pProgram;
  1255. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1256. CreateBlobFromText("[RootSignature(\"\")] \r\n"
  1257. "float4 main(float a : A) : SV_Target {\r\n"
  1258. " return a;\r\n"
  1259. "}",
  1260. &pSource);
  1261. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1262. L"ps_6_0", nullptr, 0, nullptr,
  1263. 0, nullptr, &pResult));
  1264. VERIFY_IS_NOT_NULL(pResult);
  1265. HRESULT status;
  1266. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  1267. VERIFY_SUCCEEDED(status);
  1268. VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
  1269. VERIFY_IS_NOT_NULL(pProgram);
  1270. hlsl::DxilContainerHeader *pContainerHeader =
  1271. (hlsl::DxilContainerHeader *)(pProgram->GetBufferPointer());
  1272. hlsl::DxilPartHeader *pPartHeader = hlsl::GetDxilPartByType(
  1273. pContainerHeader, hlsl::DxilFourCC::DFCC_RootSignature);
  1274. VERIFY_IS_NOT_NULL(pPartHeader);
  1275. // Remove root signature
  1276. CComPtr<IDxcBlob> pNewProgram;
  1277. CComPtr<IDxcContainerBuilder> pBuilder;
  1278. VERIFY_SUCCEEDED(CreateContainerBuilder(&pBuilder));
  1279. VERIFY_SUCCEEDED(pBuilder->Load(pProgram));
  1280. VERIFY_SUCCEEDED(pBuilder->RemovePart(hlsl::DxilFourCC::DFCC_RootSignature));
  1281. pResult.Release();
  1282. VERIFY_SUCCEEDED(pBuilder->SerializeContainer(&pResult));
  1283. VERIFY_SUCCEEDED(pResult->GetResult(&pNewProgram));
  1284. pContainerHeader = (hlsl::DxilContainerHeader *)(pNewProgram->GetBufferPointer());
  1285. pPartHeader = hlsl::GetDxilPartByType(pContainerHeader,
  1286. hlsl::DxilFourCC::DFCC_RootSignature);
  1287. VERIFY_IS_NULL(pPartHeader);
  1288. }
  1289. #endif // Container builder unsupported
  1290. TEST_F(CompilerTest, CompileWhenIncludeThenLoadInvoked) {
  1291. CComPtr<IDxcCompiler> pCompiler;
  1292. CComPtr<IDxcOperationResult> pResult;
  1293. CComPtr<IDxcBlobEncoding> pSource;
  1294. CComPtr<TestIncludeHandler> pInclude;
  1295. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1296. CreateBlobFromText(
  1297. "#include \"helper.h\"\r\n"
  1298. "float4 main() : SV_Target { return 0; }", &pSource);
  1299. pInclude = new TestIncludeHandler(m_dllSupport);
  1300. pInclude->CallResults.emplace_back("");
  1301. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1302. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1303. VerifyOperationSucceeded(pResult);
  1304. VERIFY_ARE_EQUAL_WSTR(L"./helper.h;", pInclude->GetAllFileNames().c_str());
  1305. }
  1306. TEST_F(CompilerTest, CompileWhenIncludeThenLoadUsed) {
  1307. CComPtr<IDxcCompiler> pCompiler;
  1308. CComPtr<IDxcOperationResult> pResult;
  1309. CComPtr<IDxcBlobEncoding> pSource;
  1310. CComPtr<TestIncludeHandler> pInclude;
  1311. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1312. CreateBlobFromText(
  1313. "#include \"helper.h\"\r\n"
  1314. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1315. pInclude = new TestIncludeHandler(m_dllSupport);
  1316. pInclude->CallResults.emplace_back("#define ZERO 0");
  1317. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1318. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1319. VerifyOperationSucceeded(pResult);
  1320. VERIFY_ARE_EQUAL_WSTR(L"./helper.h;", pInclude->GetAllFileNames().c_str());
  1321. }
  1322. TEST_F(CompilerTest, CompileWhenIncludeAbsoluteThenLoadAbsolute) {
  1323. CComPtr<IDxcCompiler> pCompiler;
  1324. CComPtr<IDxcOperationResult> pResult;
  1325. CComPtr<IDxcBlobEncoding> pSource;
  1326. CComPtr<TestIncludeHandler> pInclude;
  1327. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1328. #ifdef _WIN32 // OS-specific root
  1329. CreateBlobFromText(
  1330. "#include \"C:\\helper.h\"\r\n"
  1331. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1332. #else
  1333. CreateBlobFromText(
  1334. "#include \"/helper.h\"\n"
  1335. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1336. #endif
  1337. pInclude = new TestIncludeHandler(m_dllSupport);
  1338. pInclude->CallResults.emplace_back("#define ZERO 0");
  1339. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1340. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1341. VerifyOperationSucceeded(pResult);
  1342. #ifdef _WIN32 // OS-specific root
  1343. VERIFY_ARE_EQUAL_WSTR(L"C:\\helper.h;", pInclude->GetAllFileNames().c_str());
  1344. #else
  1345. VERIFY_ARE_EQUAL_WSTR(L"/helper.h;", pInclude->GetAllFileNames().c_str());
  1346. #endif
  1347. }
  1348. TEST_F(CompilerTest, CompileWhenIncludeLocalThenLoadRelative) {
  1349. CComPtr<IDxcCompiler> pCompiler;
  1350. CComPtr<IDxcOperationResult> pResult;
  1351. CComPtr<IDxcBlobEncoding> pSource;
  1352. CComPtr<TestIncludeHandler> pInclude;
  1353. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1354. CreateBlobFromText(
  1355. "#include \"..\\helper.h\"\r\n"
  1356. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1357. pInclude = new TestIncludeHandler(m_dllSupport);
  1358. pInclude->CallResults.emplace_back("#define ZERO 0");
  1359. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1360. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1361. VerifyOperationSucceeded(pResult);
  1362. #ifdef _WIN32 // OS-specific directory dividers
  1363. VERIFY_ARE_EQUAL_WSTR(L"./..\\helper.h;", pInclude->GetAllFileNames().c_str());
  1364. #else
  1365. VERIFY_ARE_EQUAL_WSTR(L"./../helper.h;", pInclude->GetAllFileNames().c_str());
  1366. #endif
  1367. }
  1368. TEST_F(CompilerTest, CompileWhenIncludeSystemThenLoadNotRelative) {
  1369. CComPtr<IDxcCompiler> pCompiler;
  1370. CComPtr<IDxcOperationResult> pResult;
  1371. CComPtr<IDxcBlobEncoding> pSource;
  1372. CComPtr<TestIncludeHandler> pInclude;
  1373. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1374. CreateBlobFromText(
  1375. "#include \"subdir/other/file.h\"\r\n"
  1376. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1377. LPCWSTR args[] = {
  1378. L"-Ifoo"
  1379. };
  1380. pInclude = new TestIncludeHandler(m_dllSupport);
  1381. pInclude->CallResults.emplace_back("#include <helper.h>");
  1382. pInclude->CallResults.emplace_back("#define ZERO 0");
  1383. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1384. L"ps_6_0", args, _countof(args), nullptr, 0, pInclude, &pResult));
  1385. VerifyOperationSucceeded(pResult);
  1386. #ifdef _WIN32 // OS-specific directory dividers
  1387. VERIFY_ARE_EQUAL_WSTR(L"./subdir/other/file.h;./foo\\helper.h;", pInclude->GetAllFileNames().c_str());
  1388. #else
  1389. VERIFY_ARE_EQUAL_WSTR(L"./subdir/other/file.h;./foo/helper.h;", pInclude->GetAllFileNames().c_str());
  1390. #endif
  1391. }
  1392. TEST_F(CompilerTest, CompileWhenIncludeSystemMissingThenLoadAttempt) {
  1393. CComPtr<IDxcCompiler> pCompiler;
  1394. CComPtr<IDxcOperationResult> pResult;
  1395. CComPtr<IDxcBlobEncoding> pSource;
  1396. CComPtr<TestIncludeHandler> pInclude;
  1397. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1398. CreateBlobFromText(
  1399. "#include \"subdir/other/file.h\"\r\n"
  1400. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1401. pInclude = new TestIncludeHandler(m_dllSupport);
  1402. pInclude->CallResults.emplace_back("#include <helper.h>");
  1403. pInclude->CallResults.emplace_back("#define ZERO 0");
  1404. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1405. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1406. std::string failLog(VerifyOperationFailed(pResult));
  1407. VERIFY_ARE_NOT_EQUAL(std::string::npos, failLog.find("<angled>")); // error message should prompt to use <angled> rather than "quotes"
  1408. VERIFY_ARE_EQUAL_WSTR(L"./subdir/other/file.h;./subdir/other/helper.h;", pInclude->GetAllFileNames().c_str());
  1409. }
  1410. TEST_F(CompilerTest, CompileWhenIncludeFlagsThenIncludeUsed) {
  1411. CComPtr<IDxcCompiler> pCompiler;
  1412. CComPtr<IDxcOperationResult> pResult;
  1413. CComPtr<IDxcBlobEncoding> pSource;
  1414. CComPtr<TestIncludeHandler> pInclude;
  1415. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1416. CreateBlobFromText(
  1417. "#include <helper.h>\r\n"
  1418. "float4 main() : SV_Target { return ZERO; }", &pSource);
  1419. pInclude = new TestIncludeHandler(m_dllSupport);
  1420. pInclude->CallResults.emplace_back("#define ZERO 0");
  1421. #ifdef _WIN32 // OS-specific root
  1422. LPCWSTR args[] = { L"-I\\\\server\\share" };
  1423. #else
  1424. LPCWSTR args[] = { L"-I/server/share" };
  1425. #endif
  1426. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1427. L"ps_6_0", args, _countof(args), nullptr, 0, pInclude, &pResult));
  1428. VerifyOperationSucceeded(pResult);
  1429. #ifdef _WIN32 // OS-specific root
  1430. VERIFY_ARE_EQUAL_WSTR(L"\\\\server\\share\\helper.h;", pInclude->GetAllFileNames().c_str());
  1431. #else
  1432. VERIFY_ARE_EQUAL_WSTR(L"/server/share/helper.h;", pInclude->GetAllFileNames().c_str());
  1433. #endif
  1434. }
  1435. TEST_F(CompilerTest, CompileWhenIncludeMissingThenFail) {
  1436. CComPtr<IDxcCompiler> pCompiler;
  1437. CComPtr<IDxcOperationResult> pResult;
  1438. CComPtr<IDxcBlobEncoding> pSource;
  1439. CComPtr<TestIncludeHandler> pInclude;
  1440. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1441. CreateBlobFromText(
  1442. "#include \"file.h\"\r\n"
  1443. "float4 main() : SV_Target { return 0; }", &pSource);
  1444. pInclude = new TestIncludeHandler(m_dllSupport);
  1445. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1446. L"ps_6_0", nullptr, 0, nullptr, 0, pInclude, &pResult));
  1447. HRESULT hr;
  1448. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1449. VERIFY_FAILED(hr);
  1450. }
  1451. TEST_F(CompilerTest, CompileWhenIncludeHasPathThenOK) {
  1452. CComPtr<IDxcCompiler> pCompiler;
  1453. LPCWSTR Source = L"c:\\temp\\OddIncludes\\main.hlsl";
  1454. LPCWSTR Args[] = { L"/I", L"c:\\temp" };
  1455. LPCWSTR ArgsUp[] = { L"/I", L"c:\\Temp" };
  1456. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1457. bool useUpValues[] = { false, true };
  1458. for (bool useUp : useUpValues) {
  1459. CComPtr<IDxcOperationResult> pResult;
  1460. CComPtr<IDxcBlobEncoding> pSource;
  1461. #if TEST_ON_DISK
  1462. CComPtr<IDxcLibrary> pLibrary;
  1463. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  1464. VERIFY_SUCCEEDED(pLibrary->CreateIncludeHandler(&pInclude));
  1465. VERIFY_SUCCEEDED(pLibrary->CreateBlobFromFile(Source, nullptr, &pSource));
  1466. #else
  1467. CComPtr<TestIncludeHandler> pInclude;
  1468. pInclude = new TestIncludeHandler(m_dllSupport);
  1469. pInclude->CallResults.emplace_back("// Empty");
  1470. CreateBlobFromText("#include \"include.hlsl\"\r\n"
  1471. "float4 main() : SV_Target { return 0; }",
  1472. &pSource);
  1473. #endif
  1474. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, Source, L"main",
  1475. L"ps_6_0", useUp ? ArgsUp : Args, _countof(Args), nullptr, 0, pInclude, &pResult));
  1476. HRESULT hr;
  1477. VERIFY_SUCCEEDED(pResult->GetStatus(&hr));
  1478. VERIFY_SUCCEEDED(hr);
  1479. }
  1480. }
  1481. TEST_F(CompilerTest, CompileWhenIncludeEmptyThenOK) {
  1482. CComPtr<IDxcCompiler> pCompiler;
  1483. CComPtr<IDxcOperationResult> pResult;
  1484. CComPtr<IDxcBlobEncoding> pSource;
  1485. CComPtr<TestIncludeHandler> pInclude;
  1486. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1487. CreateBlobFromText("#include \"empty.h\"\r\n"
  1488. "float4 main() : SV_Target { return 0; }",
  1489. &pSource);
  1490. pInclude = new TestIncludeHandler(m_dllSupport);
  1491. pInclude->CallResults.emplace_back("", CP_ACP); // An empty file would get detected as ACP code page
  1492. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1493. L"ps_6_0", nullptr, 0, nullptr, 0,
  1494. pInclude, &pResult));
  1495. VerifyOperationSucceeded(pResult);
  1496. VERIFY_ARE_EQUAL_WSTR(L"./empty.h;", pInclude->GetAllFileNames().c_str());
  1497. }
  1498. static const char EmptyCompute[] = "[numthreads(8,8,1)] void main() { }";
  1499. TEST_F(CompilerTest, CompileWhenODumpThenPassConfig) {
  1500. CComPtr<IDxcCompiler> pCompiler;
  1501. CComPtr<IDxcOperationResult> pResult;
  1502. CComPtr<IDxcBlobEncoding> pSource;
  1503. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1504. CreateBlobFromText(EmptyCompute, &pSource);
  1505. LPCWSTR Args[] = { L"/Odump" };
  1506. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1507. L"cs_6_0", Args, _countof(Args), nullptr, 0, nullptr, &pResult));
  1508. VerifyOperationSucceeded(pResult);
  1509. CComPtr<IDxcBlob> pResultBlob;
  1510. VERIFY_SUCCEEDED(pResult->GetResult(&pResultBlob));
  1511. string passes((char *)pResultBlob->GetBufferPointer(), pResultBlob->GetBufferSize());
  1512. VERIFY_ARE_NOT_EQUAL(string::npos, passes.find("inline"));
  1513. }
  1514. TEST_F(CompilerTest, CompileWhenVdThenProducesDxilContainer) {
  1515. CComPtr<IDxcCompiler> pCompiler;
  1516. CComPtr<IDxcOperationResult> pResult;
  1517. CComPtr<IDxcBlobEncoding> pSource;
  1518. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1519. CreateBlobFromText(EmptyCompute, &pSource);
  1520. LPCWSTR Args[] = { L"/Vd" };
  1521. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1522. L"cs_6_0", Args, _countof(Args), nullptr, 0, nullptr, &pResult));
  1523. VerifyOperationSucceeded(pResult);
  1524. CComPtr<IDxcBlob> pResultBlob;
  1525. VERIFY_SUCCEEDED(pResult->GetResult(&pResultBlob));
  1526. VERIFY_IS_TRUE(hlsl::IsValidDxilContainer(reinterpret_cast<hlsl::DxilContainerHeader *>(pResultBlob->GetBufferPointer()), pResultBlob->GetBufferSize()));
  1527. }
  1528. TEST_F(CompilerTest, CompileWhenODumpThenOptimizerMatch) {
  1529. LPCWSTR OptLevels[] = { L"/Od", L"/O1", L"/O2" };
  1530. CComPtr<IDxcCompiler> pCompiler;
  1531. CComPtr<IDxcOptimizer> pOptimizer;
  1532. CComPtr<IDxcAssembler> pAssembler;
  1533. CComPtr<IDxcValidator> pValidator;
  1534. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  1535. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  1536. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcOptimizer, &pOptimizer));
  1537. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
  1538. for (LPCWSTR OptLevel : OptLevels) {
  1539. CComPtr<IDxcOperationResult> pResult;
  1540. CComPtr<IDxcBlobEncoding> pSource;
  1541. CComPtr<IDxcBlob> pHighLevelBlob;
  1542. CComPtr<IDxcBlob> pOptimizedModule;
  1543. CComPtr<IDxcBlob> pAssembledBlob;
  1544. // Could use EmptyCompute and cs_6_0, but there is an issue where properties
  1545. // don't round-trip properly at high-level, so validation fails because
  1546. // dimensions are set to zero. Workaround by using pixel shader instead.
  1547. LPCWSTR Target = L"ps_6_0";
  1548. CreateBlobFromText("float4 main() : SV_Target { return 0; }", &pSource);
  1549. LPCWSTR Args[2] = { OptLevel, L"/Odump" };
  1550. // Get the passes for this optimization level.
  1551. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1552. Target, Args, _countof(Args), nullptr, 0, nullptr, &pResult));
  1553. VerifyOperationSucceeded(pResult);
  1554. CComPtr<IDxcBlob> pResultBlob;
  1555. VERIFY_SUCCEEDED(pResult->GetResult(&pResultBlob));
  1556. string passes((char *)pResultBlob->GetBufferPointer(), pResultBlob->GetBufferSize());
  1557. // Get wchar_t version and prepend hlsl-hlensure, to do a split high-level/opt compilation pass.
  1558. CA2W passesW(passes.c_str(), CP_UTF8);
  1559. std::vector<LPCWSTR> Options;
  1560. SplitPassList(passesW.m_psz, Options);
  1561. // Now compile directly.
  1562. pResult.Release();
  1563. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1564. Target, Args, 1, nullptr, 0, nullptr, &pResult));
  1565. VerifyOperationSucceeded(pResult);
  1566. // Now compile via a high-level compile followed by the optimization passes.
  1567. pResult.Release();
  1568. Args[_countof(Args)-1] = L"/fcgl";
  1569. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1570. Target, Args, _countof(Args), nullptr, 0, nullptr, &pResult));
  1571. VerifyOperationSucceeded(pResult);
  1572. VERIFY_SUCCEEDED(pResult->GetResult(&pHighLevelBlob));
  1573. VERIFY_SUCCEEDED(pOptimizer->RunOptimizer(pHighLevelBlob, Options.data(),
  1574. Options.size(), &pOptimizedModule,
  1575. nullptr));
  1576. string text = DisassembleProgram(m_dllSupport, pOptimizedModule);
  1577. WEX::Logging::Log::Comment(L"Final program:");
  1578. WEX::Logging::Log::Comment(CA2W(text.c_str()));
  1579. // At the very least, the module should be valid.
  1580. pResult.Release();
  1581. VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pOptimizedModule, &pResult));
  1582. VerifyOperationSucceeded(pResult);
  1583. VERIFY_SUCCEEDED(pResult->GetResult(&pAssembledBlob));
  1584. pResult.Release();
  1585. VERIFY_SUCCEEDED(pValidator->Validate(pAssembledBlob, DxcValidatorFlags_Default, &pResult));
  1586. VerifyOperationSucceeded(pResult);
  1587. }
  1588. }
  1589. static const UINT CaptureStacks = 0; // Set to 1 to enable captures
  1590. static const UINT StackFrameCount = 12;
  1591. struct InstrumentedHeapMalloc : public IMalloc {
  1592. private:
  1593. HANDLE m_Handle; // Heap handle.
  1594. ULONG m_RefCount = 0; // Reference count. Used for reference leaks, not for lifetime.
  1595. ULONG m_AllocCount = 0; // Total # of alloc and realloc requests.
  1596. ULONG m_AllocSize = 0; // Total # of alloc and realloc bytes.
  1597. ULONG m_Size = 0; // Current # of alloc'ed bytes.
  1598. ULONG m_FailAlloc = 0; // If nonzero, the alloc/realloc call to fail.
  1599. // Each allocation also tracks the following information:
  1600. // - allocation callstack
  1601. // - deallocation callstack
  1602. // - prior/next blocks in a list of allocated blocks
  1603. LIST_ENTRY AllocList;
  1604. struct PtrData {
  1605. LIST_ENTRY Entry;
  1606. LPVOID AllocFrames[CaptureStacks ? StackFrameCount * CaptureStacks : 1];
  1607. LPVOID FreeFrames[CaptureStacks ? StackFrameCount * CaptureStacks : 1];
  1608. UINT64 AllocAtCount;
  1609. DWORD AllocFrameCount;
  1610. DWORD FreeFrameCount;
  1611. SIZE_T Size;
  1612. PtrData *Self;
  1613. };
  1614. PtrData *DataFromPtr(void *p) {
  1615. if (p == nullptr) return nullptr;
  1616. PtrData *R = ((PtrData *)p) - 1;
  1617. if (R != R->Self) {
  1618. VERIFY_FAIL(); // p is invalid or underrun
  1619. }
  1620. return R;
  1621. }
  1622. public:
  1623. InstrumentedHeapMalloc() : m_Handle(nullptr) {
  1624. ResetCounts();
  1625. }
  1626. ~InstrumentedHeapMalloc() {
  1627. if (m_Handle)
  1628. HeapDestroy(m_Handle);
  1629. }
  1630. void ResetHeap() {
  1631. if (m_Handle) {
  1632. HeapDestroy(m_Handle);
  1633. m_Handle = nullptr;
  1634. }
  1635. m_Handle = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
  1636. }
  1637. ULONG GetRefCount() const { return m_RefCount; }
  1638. ULONG GetAllocCount() const { return m_AllocCount; }
  1639. ULONG GetAllocSize() const { return m_AllocSize; }
  1640. ULONG GetSize() const { return m_Size; }
  1641. void ResetCounts() {
  1642. m_RefCount = m_AllocCount = m_AllocSize = m_Size = 0;
  1643. AllocList.Blink = AllocList.Flink = &AllocList;
  1644. }
  1645. void SetFailAlloc(ULONG index) {
  1646. m_FailAlloc = index;
  1647. }
  1648. ULONG STDMETHODCALLTYPE AddRef() {
  1649. return ++m_RefCount;
  1650. }
  1651. ULONG STDMETHODCALLTYPE Release() {
  1652. if (m_RefCount == 0) VERIFY_FAIL();
  1653. return --m_RefCount;
  1654. }
  1655. STDMETHODIMP QueryInterface(REFIID iid, void** ppvObject) {
  1656. return DoBasicQueryInterface<IMalloc>(this, iid, ppvObject);
  1657. }
  1658. virtual void *STDMETHODCALLTYPE Alloc(_In_ SIZE_T cb) {
  1659. ++m_AllocCount;
  1660. if (m_FailAlloc && m_AllocCount >= m_FailAlloc) {
  1661. return nullptr; // breakpoint for i failure - m_FailAlloc == 1+VAL
  1662. }
  1663. m_AllocSize += cb;
  1664. m_Size += cb;
  1665. PtrData *P = (PtrData *)HeapAlloc(m_Handle, HEAP_ZERO_MEMORY, sizeof(PtrData) + cb);
  1666. P->Entry.Flink = AllocList.Flink;
  1667. P->Entry.Blink = &AllocList;
  1668. AllocList.Flink->Blink = &(P->Entry);
  1669. AllocList.Flink = &(P->Entry);
  1670. // breakpoint for i failure on NN alloc - m_FailAlloc == 1+VAL && m_AllocCount == NN
  1671. // breakpoint for happy path for NN alloc - m_AllocCount == NN
  1672. P->AllocAtCount = m_AllocCount;
  1673. if (CaptureStacks)
  1674. P->AllocFrameCount = CaptureStackBackTrace(1, StackFrameCount, P->AllocFrames, nullptr);
  1675. P->Size = cb;
  1676. P->Self = P;
  1677. return P + 1;
  1678. }
  1679. virtual void *STDMETHODCALLTYPE Realloc(_In_opt_ void *pv, _In_ SIZE_T cb) {
  1680. SIZE_T priorSize = pv == nullptr ? (SIZE_T)0 : GetSize(pv);
  1681. void *R = Alloc(cb);
  1682. if (!R)
  1683. return nullptr;
  1684. SIZE_T copySize = std::min(cb, priorSize);
  1685. memcpy(R, pv, copySize);
  1686. Free(pv);
  1687. return R;
  1688. }
  1689. virtual void STDMETHODCALLTYPE Free(_In_opt_ void *pv) {
  1690. if (!pv)
  1691. return;
  1692. PtrData *P = DataFromPtr(pv);
  1693. if (P->FreeFrameCount)
  1694. VERIFY_FAIL(); // double-free detected
  1695. m_Size -= P->Size;
  1696. P->Entry.Flink->Blink = P->Entry.Blink;
  1697. P->Entry.Blink->Flink = P->Entry.Flink;
  1698. if (CaptureStacks)
  1699. P->FreeFrameCount =
  1700. CaptureStackBackTrace(1, StackFrameCount, P->FreeFrames, nullptr);
  1701. }
  1702. virtual SIZE_T STDMETHODCALLTYPE GetSize(
  1703. /* [annotation][in] */
  1704. _In_opt_ _Post_writable_byte_size_(return) void *pv)
  1705. {
  1706. if (pv == nullptr) return 0;
  1707. return DataFromPtr(pv)->Size;
  1708. }
  1709. virtual int STDMETHODCALLTYPE DidAlloc(
  1710. _In_opt_ void *pv) {
  1711. return -1; // don't know
  1712. }
  1713. virtual void STDMETHODCALLTYPE HeapMinimize(void) {}
  1714. void DumpLeaks() {
  1715. PtrData *ptr = (PtrData*)AllocList.Flink;;
  1716. PtrData *end = (PtrData*)AllocList.Blink;;
  1717. WEX::Logging::Log::Comment(FormatToWString(L"Leaks total size: %d", (signed int)m_Size).data());
  1718. while (ptr != end) {
  1719. WEX::Logging::Log::Comment(FormatToWString(L"Memory leak at 0x0%X, size %d, alloc# %d", ptr + 1, ptr->Size, ptr->AllocAtCount).data());
  1720. ptr = (PtrData*)ptr->Entry.Flink;
  1721. }
  1722. }
  1723. };
  1724. #if _ITERATOR_DEBUG_LEVEL==0
  1725. // CompileWhenNoMemThenOOM can properly detect leaks only when debug iterators are disabled
  1726. TEST_F(CompilerTest, CompileWhenNoMemThenOOM) {
  1727. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  1728. CComPtr<IDxcBlobEncoding> pSource;
  1729. CreateBlobFromText(EmptyCompute, &pSource);
  1730. InstrumentedHeapMalloc InstrMalloc;
  1731. CComPtr<IDxcCompiler> pCompiler;
  1732. CComPtr<IDxcOperationResult> pResult;
  1733. ULONG allocCount = 0;
  1734. ULONG allocSize = 0;
  1735. ULONG initialRefCount;
  1736. InstrMalloc.ResetHeap();
  1737. VERIFY_IS_TRUE(m_dllSupport.HasCreateWithMalloc());
  1738. // Verify a simple object creation.
  1739. initialRefCount = InstrMalloc.GetRefCount();
  1740. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance2(&InstrMalloc, CLSID_DxcCompiler, &pCompiler));
  1741. pCompiler.Release();
  1742. VERIFY_IS_TRUE(0 == InstrMalloc.GetSize());
  1743. VERIFY_ARE_EQUAL(initialRefCount, InstrMalloc.GetRefCount());
  1744. InstrMalloc.ResetCounts();
  1745. InstrMalloc.ResetHeap();
  1746. // First time, run to completion and capture stats.
  1747. initialRefCount = InstrMalloc.GetRefCount();
  1748. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance2(&InstrMalloc, CLSID_DxcCompiler, &pCompiler));
  1749. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1750. L"cs_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  1751. allocCount = InstrMalloc.GetAllocCount();
  1752. allocSize = InstrMalloc.GetAllocSize();
  1753. HRESULT hrWithMemory;
  1754. VERIFY_SUCCEEDED(pResult->GetStatus(&hrWithMemory));
  1755. VERIFY_SUCCEEDED(hrWithMemory);
  1756. pCompiler.Release();
  1757. pResult.Release();
  1758. VERIFY_IS_TRUE(allocSize > allocCount);
  1759. // Ensure that after all resources are released, there are no outstanding
  1760. // allocations or references.
  1761. //
  1762. // First leak is in ((InstrumentedHeapMalloc::PtrData *)InstrMalloc.AllocList.Flink)
  1763. if (InstrMalloc.GetSize() != 0) {
  1764. WEX::Logging::Log::Comment(L"Memory leak(s) detected");
  1765. InstrMalloc.DumpLeaks();
  1766. VERIFY_IS_TRUE(0 == InstrMalloc.GetSize());
  1767. }
  1768. VERIFY_ARE_EQUAL(initialRefCount, InstrMalloc.GetRefCount());
  1769. // In Debug, without /D_ITERATOR_DEBUG_LEVEL=0, debug iterators will be used;
  1770. // this causes a problem where std::string is specified as noexcept, and yet
  1771. // a sentinel is allocated that may fail and throw.
  1772. if (m_ver.SkipOutOfMemoryTest()) return;
  1773. // Now, fail each allocation and make sure we get an error.
  1774. for (ULONG i = 0; i <= allocCount; ++i) {
  1775. // LogCommentFmt(L"alloc fail %u", i);
  1776. bool isLast = i == allocCount;
  1777. InstrMalloc.ResetCounts();
  1778. InstrMalloc.ResetHeap();
  1779. InstrMalloc.SetFailAlloc(i + 1);
  1780. HRESULT hrOp = m_dllSupport.CreateInstance2(&InstrMalloc, CLSID_DxcCompiler, &pCompiler);
  1781. if (SUCCEEDED(hrOp)) {
  1782. hrOp = pCompiler->Compile(pSource, L"source.hlsl", L"main", L"cs_6_0",
  1783. nullptr, 0, nullptr, 0, nullptr, &pResult);
  1784. if (SUCCEEDED(hrOp)) {
  1785. pResult->GetStatus(&hrOp);
  1786. }
  1787. }
  1788. if (FAILED(hrOp)) {
  1789. // This is true in *almost* every case. When the OOM happens during stream
  1790. // handling, there is no specific error set; by the time it's detected,
  1791. // it propagates as E_FAIL.
  1792. //VERIFY_ARE_EQUAL(hrOp, E_OUTOFMEMORY);
  1793. VERIFY_IS_TRUE(hrOp == E_OUTOFMEMORY || hrOp == E_FAIL);
  1794. }
  1795. if (isLast)
  1796. VERIFY_SUCCEEDED(hrOp);
  1797. else
  1798. VERIFY_FAILED(hrOp);
  1799. pCompiler.Release();
  1800. pResult.Release();
  1801. if (InstrMalloc.GetSize() != 0) {
  1802. WEX::Logging::Log::Comment(FormatToWString(L"Memory leak(s) detected, allocCount = %d", i).data());
  1803. InstrMalloc.DumpLeaks();
  1804. VERIFY_IS_TRUE(0 == InstrMalloc.GetSize());
  1805. }
  1806. VERIFY_ARE_EQUAL(initialRefCount, InstrMalloc.GetRefCount());
  1807. }
  1808. }
  1809. #endif
  1810. TEST_F(CompilerTest, CompileWhenShaderModelMismatchAttributeThenFail) {
  1811. CComPtr<IDxcCompiler> pCompiler;
  1812. CComPtr<IDxcOperationResult> pResult;
  1813. CComPtr<IDxcBlobEncoding> pSource;
  1814. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1815. CreateBlobFromText(EmptyCompute, &pSource);
  1816. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1817. L"ps_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  1818. std::string failLog(VerifyOperationFailed(pResult));
  1819. VERIFY_ARE_NOT_EQUAL(string::npos, failLog.find("attribute numthreads only valid for CS"));
  1820. }
  1821. TEST_F(CompilerTest, CompileBadHlslThenFail) {
  1822. CComPtr<IDxcCompiler> pCompiler;
  1823. CComPtr<IDxcOperationResult> pResult;
  1824. CComPtr<IDxcBlobEncoding> pSource;
  1825. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1826. CreateBlobFromText(
  1827. "bad hlsl", &pSource);
  1828. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1829. L"ps_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  1830. HRESULT status;
  1831. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  1832. VERIFY_FAILED(status);
  1833. }
  1834. TEST_F(CompilerTest, CompileLegacyShaderModelThenFail) {
  1835. VerifyCompileFailed(
  1836. "float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", L"ps_5_1", nullptr);
  1837. }
  1838. TEST_F(CompilerTest, CompileWhenRecursiveAlbeitStaticTermThenFail) {
  1839. // This shader will compile under fxc because if execution is
  1840. // simulated statically, it does terminate. dxc changes this behavior
  1841. // to avoid imposing the requirement on the compiler.
  1842. const char ShaderText[] =
  1843. "static int i = 10;\r\n"
  1844. "float4 f(); // Forward declaration\r\n"
  1845. "float4 g() { if (i > 10) { i--; return f(); } else return 0; } // Recursive call to 'f'\r\n"
  1846. "float4 f() { return g(); } // First call to 'g'\r\n"
  1847. "float4 VS() : SV_Position{\r\n"
  1848. " return f(); // First call to 'f'\r\n"
  1849. "}\r\n";
  1850. VerifyCompileFailed(ShaderText, L"vs_6_0", "recursive functions not allowed", L"VS");
  1851. }
  1852. TEST_F(CompilerTest, CompileWhenRecursiveThenFail) {
  1853. const char ShaderTextSimple[] =
  1854. "float4 f(); // Forward declaration\r\n"
  1855. "float4 g() { return f(); } // Recursive call to 'f'\r\n"
  1856. "float4 f() { return g(); } // First call to 'g'\r\n"
  1857. "float4 main() : SV_Position{\r\n"
  1858. " return f(); // First call to 'f'\r\n"
  1859. "}\r\n";
  1860. VerifyCompileFailed(ShaderTextSimple, L"vs_6_0", "recursive functions not allowed");
  1861. const char ShaderTextIndirect[] =
  1862. "float4 f(); // Forward declaration\r\n"
  1863. "float4 g() { return f(); } // Recursive call to 'f'\r\n"
  1864. "float4 f() { return g(); } // First call to 'g'\r\n"
  1865. "float4 main() : SV_Position{\r\n"
  1866. " return f(); // First call to 'f'\r\n"
  1867. "}\r\n";
  1868. VerifyCompileFailed(ShaderTextIndirect, L"vs_6_0", "recursive functions not allowed");
  1869. const char ShaderTextSelf[] =
  1870. "float4 main() : SV_Position{\r\n"
  1871. " return main();\r\n"
  1872. "}\r\n";
  1873. VerifyCompileFailed(ShaderTextSelf, L"vs_6_0", "recursive functions not allowed");
  1874. const char ShaderTextMissing[] =
  1875. "float4 mainz() : SV_Position{\r\n"
  1876. " return 1;\r\n"
  1877. "}\r\n";
  1878. VerifyCompileFailed(ShaderTextMissing, L"vs_6_0", "missing entry point definition");
  1879. }
  1880. TEST_F(CompilerTest, CompileHlsl2015ThenFail) {
  1881. CComPtr<IDxcCompiler> pCompiler;
  1882. CComPtr<IDxcOperationResult> pResult;
  1883. CComPtr<IDxcBlobEncoding> pSource;
  1884. CComPtr<IDxcBlobEncoding> pErrors;
  1885. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1886. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  1887. LPCWSTR args[2] = { L"-HV", L"2015" };
  1888. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1889. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  1890. HRESULT status;
  1891. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  1892. VERIFY_ARE_EQUAL(status, E_INVALIDARG);
  1893. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  1894. LPCSTR pErrorMsg = "HLSL Version 2015 is only supported for language services";
  1895. CheckOperationResultMsgs(pResult, &pErrorMsg, 1, false, false);
  1896. }
  1897. TEST_F(CompilerTest, CompileHlsl2016ThenOK) {
  1898. CComPtr<IDxcCompiler> pCompiler;
  1899. CComPtr<IDxcOperationResult> pResult;
  1900. CComPtr<IDxcBlobEncoding> pSource;
  1901. CComPtr<IDxcBlobEncoding> pErrors;
  1902. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1903. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  1904. LPCWSTR args[2] = { L"-HV", L"2016" };
  1905. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1906. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  1907. HRESULT status;
  1908. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  1909. VERIFY_SUCCEEDED(status);
  1910. }
  1911. TEST_F(CompilerTest, CompileHlsl2017ThenOK) {
  1912. CComPtr<IDxcCompiler> pCompiler;
  1913. CComPtr<IDxcOperationResult> pResult;
  1914. CComPtr<IDxcBlobEncoding> pSource;
  1915. CComPtr<IDxcBlobEncoding> pErrors;
  1916. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1917. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  1918. LPCWSTR args[2] = { L"-HV", L"2017" };
  1919. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1920. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  1921. HRESULT status;
  1922. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  1923. VERIFY_SUCCEEDED(status);
  1924. }
  1925. TEST_F(CompilerTest, CompileHlsl2018ThenOK) {
  1926. CComPtr<IDxcCompiler> pCompiler;
  1927. CComPtr<IDxcOperationResult> pResult;
  1928. CComPtr<IDxcBlobEncoding> pSource;
  1929. CComPtr<IDxcBlobEncoding> pErrors;
  1930. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1931. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  1932. LPCWSTR args[2] = { L"-HV", L"2018" };
  1933. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1934. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  1935. HRESULT status;
  1936. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  1937. VERIFY_SUCCEEDED(status);
  1938. }
  1939. TEST_F(CompilerTest, CompileHlsl2019ThenFail) {
  1940. CComPtr<IDxcCompiler> pCompiler;
  1941. CComPtr<IDxcOperationResult> pResult;
  1942. CComPtr<IDxcBlobEncoding> pSource;
  1943. CComPtr<IDxcBlobEncoding> pErrors;
  1944. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  1945. CreateBlobFromText("float4 main(float4 pos : SV_Position) : SV_Target { return pos; }", &pSource);
  1946. LPCWSTR args[2] = { L"-HV", L"2019" };
  1947. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  1948. L"ps_6_0", args, 2, nullptr, 0, nullptr, &pResult));
  1949. HRESULT status;
  1950. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  1951. VERIFY_ARE_EQUAL(status, E_INVALIDARG);
  1952. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&pErrors));
  1953. LPCSTR pErrorMsg = "Unknown HLSL version";
  1954. CheckOperationResultMsgs(pResult, &pErrorMsg, 1, false, false);
  1955. }
  1956. #ifdef _WIN32 // - exclude dia stuff
  1957. TEST_F(CompilerTest, DiaLoadBadBitcodeThenFail) {
  1958. CComPtr<IDxcBlob> pBadBitcode;
  1959. CComPtr<IDiaDataSource> pDiaSource;
  1960. CComPtr<IStream> pStream;
  1961. CComPtr<IDxcLibrary> pLib;
  1962. Utf8ToBlob(m_dllSupport, "badcode", &pBadBitcode);
  1963. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1964. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pBadBitcode, &pStream));
  1965. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  1966. VERIFY_FAILED(pDiaSource->loadDataFromIStream(pStream));
  1967. }
  1968. static void CompileTestAndLoadDia(dxc::DxcDllSupport &dllSupport, IDiaDataSource **ppDataSource) {
  1969. CComPtr<IDxcBlob> pContainer;
  1970. CComPtr<IDxcBlob> pDebugContent;
  1971. CComPtr<IDiaDataSource> pDiaSource;
  1972. CComPtr<IStream> pStream;
  1973. CComPtr<IDxcLibrary> pLib;
  1974. CComPtr<IDxcContainerReflection> pReflection;
  1975. UINT32 index;
  1976. VerifyCompileOK(dllSupport, EmptyCompute, L"cs_6_0", L"/Zi", &pContainer);
  1977. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcLibrary, &pLib));
  1978. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
  1979. VERIFY_SUCCEEDED(pReflection->Load(pContainer));
  1980. VERIFY_SUCCEEDED(pReflection->FindFirstPartKind(hlsl::DFCC_ShaderDebugInfoDXIL, &index));
  1981. VERIFY_SUCCEEDED(pReflection->GetPartContent(index, &pDebugContent));
  1982. VERIFY_SUCCEEDED(pLib->CreateStreamFromBlobReadOnly(pDebugContent, &pStream));
  1983. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcDiaDataSource, &pDiaSource));
  1984. VERIFY_SUCCEEDED(pDiaSource->loadDataFromIStream(pStream));
  1985. if (ppDataSource) {
  1986. *ppDataSource = pDiaSource.Detach();
  1987. }
  1988. }
  1989. TEST_F(CompilerTest, DiaLoadDebugThenOK) {
  1990. CompileTestAndLoadDia(m_dllSupport, nullptr);
  1991. }
  1992. TEST_F(CompilerTest, DiaTableIndexThenOK) {
  1993. CComPtr<IDiaDataSource> pDiaSource;
  1994. CComPtr<IDiaSession> pDiaSession;
  1995. CComPtr<IDiaEnumTables> pEnumTables;
  1996. CComPtr<IDiaTable> pTable;
  1997. VARIANT vtIndex;
  1998. CompileTestAndLoadDia(m_dllSupport, &pDiaSource);
  1999. VERIFY_SUCCEEDED(pDiaSource->openSession(&pDiaSession));
  2000. VERIFY_SUCCEEDED(pDiaSession->getEnumTables(&pEnumTables));
  2001. vtIndex.vt = VT_EMPTY;
  2002. VERIFY_FAILED(pEnumTables->Item(vtIndex, &pTable));
  2003. vtIndex.vt = VT_I4;
  2004. vtIndex.intVal = 1;
  2005. VERIFY_SUCCEEDED(pEnumTables->Item(vtIndex, &pTable));
  2006. VERIFY_IS_NOT_NULL(pTable.p);
  2007. pTable.Release();
  2008. vtIndex.vt = VT_UI4;
  2009. vtIndex.uintVal = 1;
  2010. VERIFY_SUCCEEDED(pEnumTables->Item(vtIndex, &pTable));
  2011. VERIFY_IS_NOT_NULL(pTable.p);
  2012. pTable.Release();
  2013. vtIndex.uintVal = 100;
  2014. VERIFY_FAILED(pEnumTables->Item(vtIndex, &pTable));
  2015. }
  2016. #endif // _WIN32 - exclude dia stuff
  2017. TEST_F(CompilerTest, CodeGenAttributeAtVertex) {
  2018. if (m_ver.SkipDxilVersion(1,1)) return;
  2019. CodeGenTestCheck(L"attributeAtVertex.hlsl");
  2020. }
  2021. TEST_F(CompilerTest, CodeGenAttributeAtVertexNoOpt) {
  2022. if (m_ver.SkipDxilVersion(1,1)) return;
  2023. CodeGenTestCheck(L"attributeAtVertexNoOpt.hlsl");
  2024. }
  2025. TEST_F(CompilerTest, CodeGenBarycentrics) {
  2026. if (m_ver.SkipDxilVersion(1,1)) return;
  2027. CodeGenTestCheck(L"barycentrics.hlsl");
  2028. }
  2029. TEST_F(CompilerTest, CodeGenBarycentrics1) {
  2030. if (m_ver.SkipDxilVersion(1,1)) return;
  2031. CodeGenTestCheck(L"barycentrics1.hlsl");
  2032. }
  2033. TEST_F(CompilerTest, CodeGenBarycentricsThreeSV) {
  2034. if (m_ver.SkipDxilVersion(1,1)) return;
  2035. CodeGenTestCheck(L"barycentricsThreeSV.hlsl");
  2036. }
  2037. TEST_F(CompilerTest, CodeGenBitCast16Bits) {
  2038. if (m_ver.SkipDxilVersion(1, 2)) return;
  2039. CodeGenTestCheck(L"bitcast_16bits.hlsl");
  2040. }
  2041. TEST_F(CompilerTest, CodeGenCbuffer64Types) {
  2042. if (m_ver.SkipDxilVersion(1, 2)) return;
  2043. CodeGenTestCheck(L"cbuffer64Types.hlsl");
  2044. }
  2045. TEST_F(CompilerTest, CodeGenCbufferHalf) {
  2046. if (m_ver.SkipDxilVersion(1, 2)) return;
  2047. CodeGenTestCheck(L"cbufferHalf.hlsl");
  2048. }
  2049. TEST_F(CompilerTest, CodeGenCbufferHalfStruct) {
  2050. if (m_ver.SkipDxilVersion(1, 2)) return;
  2051. CodeGenTestCheck(L"cbufferHalf-struct.hlsl");
  2052. }
  2053. TEST_F(CompilerTest, CodeGenCbufferInt16) {
  2054. if (m_ver.SkipDxilVersion(1, 2)) return;
  2055. CodeGenTestCheck(L"cbufferInt16.hlsl");
  2056. }
  2057. TEST_F(CompilerTest, CodeGenCbufferInt16Struct) {
  2058. if (m_ver.SkipDxilVersion(1, 2)) return;
  2059. CodeGenTestCheck(L"cbufferInt16-struct.hlsl");
  2060. }
  2061. TEST_F(CompilerTest, CodeGenDataLayoutHalf) {
  2062. if (m_ver.SkipDxilVersion(1, 2)) return;
  2063. CodeGenTestCheck(L"dataLayoutHalf.hlsl");
  2064. }
  2065. TEST_F(CompilerTest, CodeGenEnum3) {
  2066. if (m_ver.SkipDxilVersion(1,1)) return;
  2067. CodeGenTestCheck(L"enum3.hlsl");
  2068. }
  2069. #ifdef _WIN32
  2070. #pragma fenv_access(on)
  2071. #pragma optimize("", off)
  2072. #pragma warning(disable : 4723)
  2073. // Define test state as something weird that we can verify was restored
  2074. static const unsigned int fpTestState =
  2075. (_MCW_EM & (~_EM_ZERODIVIDE)) | // throw on div by zero
  2076. _DN_FLUSH_OPERANDS_SAVE_RESULTS | // denorm flush operands & save results
  2077. _RC_UP; // round up
  2078. static const unsigned int fpTestMask = _MCW_EM | _MCW_DN | _MCW_RC;
  2079. struct FPTestScope
  2080. {
  2081. // _controlfp_s is non-standard and <cfenv> doesn't have a function to enable exceptions
  2082. unsigned int fpSavedState;
  2083. FPTestScope() {
  2084. VERIFY_IS_TRUE(_controlfp_s(&fpSavedState, 0, 0) == 0);
  2085. unsigned int newValue;
  2086. VERIFY_IS_TRUE(_controlfp_s(&newValue, fpTestState, fpTestMask) == 0);
  2087. }
  2088. ~FPTestScope() {
  2089. unsigned int newValue;
  2090. errno_t error = _controlfp_s(&newValue, fpSavedState, fpTestMask);
  2091. DXASSERT_LOCALVAR(error, error == 0, "Failed to restore floating-point environment.");
  2092. }
  2093. };
  2094. void VerifyDivByZeroThrows() {
  2095. bool bCaughtExpectedException = false;
  2096. __try {
  2097. float one = 1.0;
  2098. float zero = 0.0;
  2099. float val = one / zero;
  2100. (void)val;
  2101. } __except(EXCEPTION_EXECUTE_HANDLER) {
  2102. bCaughtExpectedException = true;
  2103. }
  2104. VERIFY_IS_TRUE(bCaughtExpectedException);
  2105. }
  2106. TEST_F(CompilerTest, CodeGenFloatingPointEnvironment) {
  2107. unsigned int fpOriginal;
  2108. VERIFY_IS_TRUE(_controlfp_s(&fpOriginal, 0, 0) == 0);
  2109. {
  2110. FPTestScope fpTestScope;
  2111. // Get state before/after compilation, making sure it's our test state,
  2112. // and that it is restored after the compile.
  2113. unsigned int fpBeforeCompile;
  2114. VERIFY_IS_TRUE(_controlfp_s(&fpBeforeCompile, 0, 0) == 0);
  2115. VERIFY_ARE_EQUAL((fpBeforeCompile & fpTestMask), fpTestState);
  2116. CodeGenTestCheck(L"fpexcept.hlsl");
  2117. // Verify excpetion environment was restored
  2118. unsigned int fpAfterCompile;
  2119. VERIFY_IS_TRUE(_controlfp_s(&fpAfterCompile, 0, 0) == 0);
  2120. VERIFY_ARE_EQUAL((fpBeforeCompile & fpTestMask), (fpAfterCompile & fpTestMask));
  2121. // Make sure round up is set
  2122. VERIFY_ARE_EQUAL(rint(12.25), 13);
  2123. // Make sure we actually enabled div-by-zero exception
  2124. VerifyDivByZeroThrows();
  2125. }
  2126. // Verify original state has been restored
  2127. unsigned int fpLocal;
  2128. VERIFY_IS_TRUE(_controlfp_s(&fpLocal, 0, 0) == 0);
  2129. VERIFY_ARE_EQUAL(fpLocal, fpOriginal);
  2130. }
  2131. #pragma optimize("", on)
  2132. #else // _WIN32
  2133. // Only implemented on Win32
  2134. TEST_F(CompilerTest, CodeGenFloatingPointEnvironment) {
  2135. VERIFY_IS_TRUE(true);
  2136. }
  2137. #endif // _WIN32
  2138. TEST_F(CompilerTest, CodeGenFixedWidthTypes) {
  2139. if (m_ver.SkipDxilVersion(1, 2)) return;
  2140. CodeGenTestCheck(L"fixedWidth.hlsl");
  2141. }
  2142. TEST_F(CompilerTest, CodeGenFixedWidthTypes16Bit) {
  2143. if (m_ver.SkipDxilVersion(1, 2)) return;
  2144. CodeGenTestCheck(L"fixedWidth16Bit.hlsl");
  2145. }
  2146. TEST_F(CompilerTest, CodeGenFunctionAttribute) {
  2147. if (m_ver.SkipDxilVersion(1, 2)) return;
  2148. CodeGenTestCheck(L"functionAttribute.hlsl");
  2149. }
  2150. TEST_F(CompilerTest, CodeGenInclude) {
  2151. CodeGenTestCheck(L"Include.hlsl");
  2152. }
  2153. TEST_F(CompilerTest, CodeGenInt16Op) {
  2154. if (m_ver.SkipDxilVersion(1, 2)) return;
  2155. CodeGenTestCheck(L"int16Op.hlsl");
  2156. }
  2157. TEST_F(CompilerTest, CodeGenInt16OpBits) {
  2158. if (m_ver.SkipDxilVersion(1, 2)) return;
  2159. CodeGenTestCheck(L"int16OpBits.hlsl");
  2160. }
  2161. TEST_F(CompilerTest, CodeGenLibCsEntry) {
  2162. CodeGenTestCheck(L"lib_cs_entry.hlsl");
  2163. }
  2164. TEST_F(CompilerTest, CodeGenLibCsEntry2) {
  2165. CodeGenTestCheck(L"lib_cs_entry2.hlsl");
  2166. }
  2167. TEST_F(CompilerTest, CodeGenLibCsEntry3) {
  2168. CodeGenTestCheck(L"lib_cs_entry3.hlsl");
  2169. }
  2170. TEST_F(CompilerTest, CodeGenLibEntries) {
  2171. CodeGenTestCheck(L"lib_entries.hlsl");
  2172. }
  2173. TEST_F(CompilerTest, CodeGenLibEntries2) {
  2174. CodeGenTestCheck(L"lib_entries2.hlsl");
  2175. }
  2176. TEST_F(CompilerTest, CodeGenLibNoAlias) {
  2177. CodeGenTestCheck(L"lib_no_alias.hlsl");
  2178. }
  2179. TEST_F(CompilerTest, CodeGenLibResource) {
  2180. CodeGenTestCheck(L"lib_resource.hlsl");
  2181. }
  2182. TEST_F(CompilerTest, CodeGenLibUnusedFunc) {
  2183. CodeGenTestCheck(L"lib_unused_func.hlsl");
  2184. }
  2185. TEST_F(CompilerTest, CodeGenMultiUAVLoad2) {
  2186. if (m_ver.SkipDxilVersion(1,1)) return;
  2187. CodeGenTestCheck(L"multiUAVLoad2.hlsl");
  2188. }
  2189. TEST_F(CompilerTest, CodeGenMultiUAVLoad4) {
  2190. if (m_ver.SkipDxilVersion(1,1)) return;
  2191. CodeGenTestCheck(L"multiUAVLoad4.hlsl");
  2192. }
  2193. TEST_F(CompilerTest, CodeGenMultiUAVLoad5) {
  2194. if (m_ver.SkipDxilVersion(1,1)) return;
  2195. CodeGenTestCheck(L"multiUAVLoad5.hlsl");
  2196. }
  2197. TEST_F(CompilerTest, CodeGenMultiUAVLoad6) {
  2198. if (m_ver.SkipDxilVersion(1,1)) return;
  2199. CodeGenTestCheck(L"multiUAVLoad6.hlsl");
  2200. }
  2201. TEST_F(CompilerTest, CodeGenMultiUAVLoad7) {
  2202. if (m_ver.SkipDxilVersion(1,1)) return;
  2203. CodeGenTestCheck(L"multiUAVLoad7.hlsl");
  2204. }
  2205. TEST_F(CompilerTest, CodeGenRaw_Buf2) {
  2206. if (m_ver.SkipDxilVersion(1, 2)) return;
  2207. CodeGenTestCheck(L"raw_buf2.hlsl");
  2208. }
  2209. TEST_F(CompilerTest, CodeGenRaw_Buf4) {
  2210. if (m_ver.SkipDxilVersion(1, 2)) return;
  2211. CodeGenTestCheck(L"raw_buf4.hlsl");
  2212. }
  2213. TEST_F(CompilerTest, CodeGenRaw_Buf5) {
  2214. if (m_ver.SkipDxilVersion(1, 2)) return;
  2215. CodeGenTestCheck(L"raw_buf5.hlsl");
  2216. }
  2217. TEST_F(CompilerTest, CodeGenSignaturePackingByWidth) {
  2218. if (m_ver.SkipDxilVersion(1, 2)) return;
  2219. CodeGenTestCheck(L"signature_packing_by_width.hlsl");
  2220. }
  2221. TEST_F(CompilerTest, CodeGenStruct_Buf2) {
  2222. if (m_ver.SkipDxilVersion(1, 2)) return;
  2223. CodeGenTestCheck(L"struct_buf2.hlsl");
  2224. }
  2225. TEST_F(CompilerTest, CodeGenStruct_Buf3) {
  2226. if (m_ver.SkipDxilVersion(1, 2)) return;
  2227. CodeGenTestCheck(L"struct_buf3.hlsl");
  2228. }
  2229. TEST_F(CompilerTest, CodeGenStruct_Buf4) {
  2230. if (m_ver.SkipDxilVersion(1, 2)) return;
  2231. CodeGenTestCheck(L"struct_buf4.hlsl");
  2232. }
  2233. TEST_F(CompilerTest, CodeGenStruct_Buf5) {
  2234. if (m_ver.SkipDxilVersion(1, 2)) return;
  2235. CodeGenTestCheck(L"struct_buf5.hlsl");
  2236. }
  2237. TEST_F(CompilerTest, CodeGenStruct_Buf6) {
  2238. if (m_ver.SkipDxilVersion(1, 2)) return;
  2239. CodeGenTestCheck(L"struct_buf6.hlsl");
  2240. }
  2241. TEST_F(CompilerTest, CodeGenStruct_Buf_New_Layout) {
  2242. if (m_ver.SkipDxilVersion(1, 2)) return;
  2243. CodeGenTestCheck(L"struct_buf_new_layout.hlsl");
  2244. }
  2245. TEST_F(CompilerTest, CodeGenUav_Typed_Load_Store3) {
  2246. if (m_ver.SkipDxilVersion(1,2)) return;
  2247. CodeGenTestCheck(L"uav_typed_load_store3.hlsl");
  2248. }
  2249. TEST_F(CompilerTest, CodeGenUint64_2) {
  2250. if (m_ver.SkipDxilVersion(1,1)) return;
  2251. CodeGenTestCheck(L"uint64_2.hlsl");
  2252. }
  2253. TEST_F(CompilerTest, CodeGenLiterals_Exact_Precision_Mod) {
  2254. if (m_ver.SkipDxilVersion(1, 2)) return;
  2255. CodeGenTestCheck(L"literals_exact_precision_Mod.hlsl");
  2256. }
  2257. TEST_F(CompilerTest, CodeGenTypedBufferHalf) {
  2258. if (m_ver.SkipDxilVersion(1, 2)) return;
  2259. CodeGenTestCheck(L"typed_buffer_half.hlsl");
  2260. }
  2261. TEST_F(CompilerTest, CodeGenRootSigProfile) {
  2262. CodeGenTest(L"rootSigProfile.hlsl");
  2263. }
  2264. TEST_F(CompilerTest, CodeGenRootSigProfile2) {
  2265. // TODO: Verify the result when reflect the structures.
  2266. CodeGenTest(L"rootSigProfile2.hlsl");
  2267. }
  2268. TEST_F(CompilerTest, CodeGenRootSigProfile5) {
  2269. CodeGenTest(L"rootSigProfile5.hlsl");
  2270. }
  2271. TEST_F(CompilerTest, CodeGenSamples){
  2272. CodeGenTestCheckBatchDir(L"Samples");
  2273. }
  2274. TEST_F(CompilerTest, PreprocessWhenValidThenOK) {
  2275. CComPtr<IDxcCompiler> pCompiler;
  2276. CComPtr<IDxcOperationResult> pResult;
  2277. CComPtr<IDxcBlobEncoding> pSource;
  2278. DxcDefine defines[2];
  2279. defines[0].Name = L"MYDEF";
  2280. defines[0].Value = L"int";
  2281. defines[1].Name = L"MYOTHERDEF";
  2282. defines[1].Value = L"123";
  2283. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2284. CreateBlobFromText(
  2285. "// First line\r\n"
  2286. "MYDEF g_int = MYOTHERDEF;\r\n"
  2287. "#define FOO BAR\r\n"
  2288. "int FOO;", &pSource);
  2289. VERIFY_SUCCEEDED(pCompiler->Preprocess(pSource, L"file.hlsl", nullptr, 0,
  2290. defines, _countof(defines), nullptr,
  2291. &pResult));
  2292. HRESULT hrOp;
  2293. VERIFY_SUCCEEDED(pResult->GetStatus(&hrOp));
  2294. VERIFY_SUCCEEDED(hrOp);
  2295. CComPtr<IDxcBlob> pOutText;
  2296. VERIFY_SUCCEEDED(pResult->GetResult(&pOutText));
  2297. std::string text(BlobToUtf8(pOutText));
  2298. VERIFY_ARE_EQUAL_STR(
  2299. "#line 1 \"file.hlsl\"\n"
  2300. "\n"
  2301. "int g_int = 123;\n"
  2302. "\n"
  2303. "int BAR;\n", text.c_str());
  2304. }
  2305. TEST_F(CompilerTest, PreprocessWhenExpandTokenPastingOperandThenAccept) {
  2306. // Tests that we can turn on fxc's behavior (pre-expanding operands before
  2307. // performing token-pasting) using -flegacy-macro-expansion
  2308. CComPtr<IDxcCompiler> pCompiler;
  2309. CComPtr<IDxcOperationResult> pResult;
  2310. CComPtr<IDxcBlobEncoding> pSource;
  2311. LPCWSTR expandOption = L"-flegacy-macro-expansion";
  2312. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2313. CreateBlobFromText(R"(
  2314. #define SET_INDEX0 10
  2315. #define BINDING_INDEX0 5
  2316. #define SET(INDEX) SET_INDEX##INDEX
  2317. #define BINDING(INDEX) BINDING_INDEX##INDEX
  2318. #define SET_BIND(NAME,SET,BIND) resource_set_##SET##_bind_##BIND##_##NAME
  2319. #define RESOURCE(NAME,INDEX) SET_BIND(NAME, SET(INDEX), BINDING(INDEX))
  2320. Texture2D<float4> resource_set_10_bind_5_tex;
  2321. float4 main() : SV_Target{
  2322. return RESOURCE(tex, 0)[uint2(1, 2)];
  2323. }
  2324. )",
  2325. &pSource);
  2326. VERIFY_SUCCEEDED(pCompiler->Preprocess(pSource, L"file.hlsl", &expandOption,
  2327. 1, nullptr, 0, nullptr, &pResult));
  2328. HRESULT hrOp;
  2329. VERIFY_SUCCEEDED(pResult->GetStatus(&hrOp));
  2330. VERIFY_SUCCEEDED(hrOp);
  2331. CComPtr<IDxcBlob> pOutText;
  2332. VERIFY_SUCCEEDED(pResult->GetResult(&pOutText));
  2333. std::string text(BlobToUtf8(pOutText));
  2334. VERIFY_ARE_EQUAL_STR(R"(#line 1 "file.hlsl"
  2335. #line 12 "file.hlsl"
  2336. Texture2D<float4> resource_set_10_bind_5_tex;
  2337. float4 main() : SV_Target{
  2338. return resource_set_10_bind_5_tex[uint2(1, 2)];
  2339. }
  2340. )",
  2341. text.c_str());
  2342. }
  2343. TEST_F(CompilerTest, WhenSigMismatchPCFunctionThenFail) {
  2344. CComPtr<IDxcCompiler> pCompiler;
  2345. CComPtr<IDxcOperationResult> pResult;
  2346. CComPtr<IDxcBlobEncoding> pSource;
  2347. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2348. CreateBlobFromText(
  2349. "struct PSSceneIn \n\
  2350. { \n\
  2351. float4 pos : SV_Position; \n\
  2352. float2 tex : TEXCOORD0; \n\
  2353. float3 norm : NORMAL; \n\
  2354. }; \n"
  2355. "struct HSPerPatchData { \n\
  2356. float edges[ 3 ] : SV_TessFactor; \n\
  2357. float inside : SV_InsideTessFactor; \n\
  2358. float foo : FOO; \n\
  2359. }; \n"
  2360. "HSPerPatchData HSPerPatchFunc( InputPatch< PSSceneIn, 3 > points, \n\
  2361. OutputPatch<PSSceneIn, 3> outpoints) { \n\
  2362. HSPerPatchData d = (HSPerPatchData)0; \n\
  2363. d.edges[ 0 ] = points[0].tex.x + outpoints[0].tex.x; \n\
  2364. d.edges[ 1 ] = 1; \n\
  2365. d.edges[ 2 ] = 1; \n\
  2366. d.inside = 1; \n\
  2367. return d; \n\
  2368. } \n"
  2369. "[domain(\"tri\")] \n\
  2370. [partitioning(\"fractional_odd\")] \n\
  2371. [outputtopology(\"triangle_cw\")] \n\
  2372. [patchconstantfunc(\"HSPerPatchFunc\")] \n\
  2373. [outputcontrolpoints(3)] \n"
  2374. "void main(const uint id : SV_OutputControlPointID, \n\
  2375. const InputPatch< PSSceneIn, 3 > points ) { \n\
  2376. } \n"
  2377. , &pSource);
  2378. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main",
  2379. L"hs_6_0", nullptr, 0, nullptr, 0, nullptr, &pResult));
  2380. std::string failLog(VerifyOperationFailed(pResult));
  2381. VERIFY_ARE_NOT_EQUAL(string::npos, failLog.find(
  2382. "Signature element SV_Position, referred to by patch constant function, is not found in corresponding hull shader output."));
  2383. }
  2384. TEST_F(CompilerTest, ViewID) {
  2385. if (m_ver.SkipDxilVersion(1,1)) return;
  2386. CodeGenTestCheckBatchDir(L"viewid");
  2387. }
  2388. TEST_F(CompilerTest, SubobjectCodeGenErrors) {
  2389. struct SubobjectErrorTestCase {
  2390. const char *shaderText;
  2391. const char *expectedError;
  2392. };
  2393. SubobjectErrorTestCase testCases[] = {
  2394. { "GlobalRootSignature grs;", "1:1: error: subobject needs to be initialized" },
  2395. { "StateObjectConfig soc;", "1:1: error: subobject needs to be initialized" },
  2396. { "LocalRootSignature lrs;", "1:1: error: subobject needs to be initialized" },
  2397. { "SubobjectToExportsAssociation sea;", "1:1: error: subobject needs to be initialized" },
  2398. { "RaytracingShaderConfig rsc;", "1:1: error: subobject needs to be initialized" },
  2399. { "RaytracingPipelineConfig rpc;", "1:1: error: subobject needs to be initialized" },
  2400. { "TriangleHitGroup hitGt;", "1:1: error: subobject needs to be initialized" },
  2401. { "ProceduralPrimitiveHitGroup hitGt;", "1:1: error: subobject needs to be initialized" },
  2402. { "GlobalRootSignature grs2 = {\"\"};", "1:29: error: empty string not expected here" },
  2403. { "LocalRootSignature lrs2 = {\"\"};", "1:28: error: empty string not expected here" },
  2404. { "SubobjectToExportsAssociation sea2 = { \"\", \"x\" };", "1:40: error: empty string not expected here" },
  2405. { "string s; SubobjectToExportsAssociation sea4 = { \"x\", s };", "1:55: error: cannot convert to constant string" },
  2406. { "extern int v; RaytracingPipelineConfig rpc2 = { v + 16 };", "1:49: error: cannot convert to constant unsigned int" },
  2407. { "string s; TriangleHitGroup trHitGt2_8 = { s, \"foo\" };", "1:43: error: cannot convert to constant string" },
  2408. { "string s; ProceduralPrimitiveHitGroup ppHitGt2_8 = { s, \"\", s };", "1:54: error: cannot convert to constant string" },
  2409. { "ProceduralPrimitiveHitGroup ppHitGt2_9 = { \"a\", \"b\", \"\"};", "1:54: error: empty string not expected here" }
  2410. };
  2411. for (unsigned i = 0; i < _countof(testCases); i++) {
  2412. CComPtr<IDxcCompiler> pCompiler;
  2413. CComPtr<IDxcOperationResult> pResult;
  2414. CComPtr<IDxcBlobEncoding> pSource;
  2415. VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
  2416. CreateBlobFromText(testCases[i].shaderText, &pSource);
  2417. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"", L"lib_6_4", nullptr, 0, nullptr, 0, nullptr, &pResult));
  2418. std::string failLog(VerifyOperationFailed(pResult));
  2419. VERIFY_ARE_NOT_EQUAL(string::npos, failLog.find(testCases[i].expectedError));
  2420. }
  2421. }
  2422. TEST_F(CompilerTest, DebugInfo) {
  2423. CodeGenTestCheckBatchDir(L"debug");
  2424. }
  2425. TEST_F(CompilerTest, QuickTest) {
  2426. CodeGenTestCheckBatchDir(L"quick-test");
  2427. }
  2428. #ifdef _WIN32
  2429. TEST_F(CompilerTest, ManualFileCheckTest) {
  2430. #else
  2431. TEST_F(CompilerTest, DISABLED_ManualFileCheckTest) {
  2432. #endif
  2433. using namespace llvm;
  2434. using namespace WEX::TestExecution;
  2435. WEX::Common::String value;
  2436. VERIFY_SUCCEEDED(RuntimeParameters::TryGetValue(L"InputPath", value));
  2437. std::wstring path = value;
  2438. if (!llvm::sys::path::is_absolute(CW2A(path.c_str()).m_psz)) {
  2439. path = hlsl_test::GetPathToHlslDataFile(path.c_str());
  2440. }
  2441. bool isDirectory;
  2442. {
  2443. // Temporarily setup the filesystem for testing whether the path is a directory.
  2444. // If it is, CodeGenTestCheckBatchDir will create its own instance.
  2445. llvm::sys::fs::MSFileSystem *msfPtr;
  2446. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  2447. std::unique_ptr<llvm::sys::fs::MSFileSystem> msf(msfPtr);
  2448. llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  2449. IFTLLVM(pts.error_code());
  2450. isDirectory = llvm::sys::fs::is_directory(CW2A(path.c_str()).m_psz);
  2451. }
  2452. if (isDirectory) {
  2453. CodeGenTestCheckBatchDir(path, /*implicitDir*/ false);
  2454. } else {
  2455. CodeGenTestCheck(path.c_str(), /*implicitDir*/ false);
  2456. }
  2457. }
  2458. TEST_F(CompilerTest, CodeGenBatch) {
  2459. CodeGenTestCheckBatchDir(L"batch");
  2460. }