ValidationTest.cpp 70 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // ValidationTest.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. // //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include <memory>
  11. #include <vector>
  12. #include <string>
  13. #include <algorithm>
  14. #include "llvm/ADT/StringRef.h"
  15. #include "llvm/Support/Regex.h"
  16. #include "llvm/ADT/ArrayRef.h"
  17. #include <atlbase.h>
  18. #include "WexTestClass.h"
  19. #include "DxcTestUtils.h"
  20. #include "HlslTestUtils.h"
  21. using namespace std;
  22. void CheckOperationSucceeded(IDxcOperationResult *pResult, IDxcBlob **ppBlob) {
  23. HRESULT status;
  24. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  25. VERIFY_SUCCEEDED(status);
  26. VERIFY_SUCCEEDED(pResult->GetResult(ppBlob));
  27. }
  28. std::string DisassembleProgram(dxc::DxcDllSupport &dllSupport,
  29. IDxcBlob *pProgram) {
  30. CComPtr<IDxcCompiler> pCompiler;
  31. CComPtr<IDxcBlobEncoding> pDisassembly;
  32. if (!dllSupport.IsEnabled()) {
  33. VERIFY_SUCCEEDED(dllSupport.Initialize());
  34. }
  35. VERIFY_SUCCEEDED(dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  36. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembly));
  37. return BlobToUtf8(pDisassembly);
  38. }
  39. class ValidationTest
  40. {
  41. public:
  42. BEGIN_TEST_CLASS(ValidationTest)
  43. TEST_METHOD_PROPERTY(L"Priority", L"0")
  44. END_TEST_CLASS()
  45. TEST_METHOD(WhenCorrectThenOK);
  46. TEST_METHOD(WhenMisalignedThenFail);
  47. TEST_METHOD(WhenEmptyFileThenFail);
  48. TEST_METHOD(WhenIncorrectMagicThenFail);
  49. TEST_METHOD(WhenIncorrectTargetTripleThenFail);
  50. TEST_METHOD(WhenIncorrectModelThenFail);
  51. TEST_METHOD(WhenIncorrectPSThenFail);
  52. TEST_METHOD(WhenWaveAffectsGradientThenFail);
  53. TEST_METHOD(WhenMultipleModulesThenFail);
  54. TEST_METHOD(WhenUnexpectedEOFThenFail);
  55. TEST_METHOD(WhenUnknownBlocksThenFail);
  56. TEST_METHOD(LoadOutputControlPointNotInPatchConstantFunction);
  57. TEST_METHOD(StorePatchControlNotInPatchConstantFunction);
  58. TEST_METHOD(OutputControlPointIDInPatchConstantFunction);
  59. TEST_METHOD(GsVertexIDOutOfBound)
  60. TEST_METHOD(StreamIDOutOfBound)
  61. TEST_METHOD(SignatureStreamIDForNonGS)
  62. TEST_METHOD(TypedUAVStoreFullMask0)
  63. TEST_METHOD(TypedUAVStoreFullMask1)
  64. TEST_METHOD(Recursive)
  65. TEST_METHOD(Recursive2)
  66. TEST_METHOD(UserDefineFunction)
  67. TEST_METHOD(ResourceRangeOverlap0)
  68. TEST_METHOD(ResourceRangeOverlap1)
  69. TEST_METHOD(ResourceRangeOverlap2)
  70. TEST_METHOD(ResourceRangeOverlap3)
  71. TEST_METHOD(CBufferOverlap0)
  72. TEST_METHOD(CBufferOverlap1)
  73. TEST_METHOD(ControlFlowHint)
  74. TEST_METHOD(ControlFlowHint1)
  75. TEST_METHOD(ControlFlowHint2)
  76. TEST_METHOD(SemanticLength1)
  77. TEST_METHOD(SemanticLength64)
  78. TEST_METHOD(PullModelPosition)
  79. TEST_METHOD(StructBufStrideAlign)
  80. TEST_METHOD(StructBufStrideOutOfBound)
  81. TEST_METHOD(StructBufGlobalCoherentAndCounter)
  82. TEST_METHOD(StructBufLoadCoordinates)
  83. TEST_METHOD(StructBufStoreCoordinates)
  84. TEST_METHOD(TypedBufRetType)
  85. TEST_METHOD(VsInputSemantic)
  86. TEST_METHOD(VsOutputSemantic)
  87. TEST_METHOD(HsInputSemantic)
  88. TEST_METHOD(HsOutputSemantic)
  89. TEST_METHOD(PatchConstSemantic)
  90. TEST_METHOD(DsInputSemantic)
  91. TEST_METHOD(DsOutputSemantic)
  92. TEST_METHOD(GsInputSemantic)
  93. TEST_METHOD(GsOutputSemantic)
  94. TEST_METHOD(PsInputSemantic)
  95. TEST_METHOD(PsOutputSemantic)
  96. TEST_METHOD(ArrayOfSVTarget)
  97. TEST_METHOD(InfiniteLog)
  98. TEST_METHOD(InfiniteAsin)
  99. TEST_METHOD(InfiniteAcos)
  100. TEST_METHOD(InfiniteDdxDdy)
  101. TEST_METHOD(IDivByZero)
  102. TEST_METHOD(UDivByZero)
  103. TEST_METHOD(UnusedMetadata)
  104. TEST_METHOD(MemoryOutOfBound)
  105. TEST_METHOD(AddrSpaceCast)
  106. TEST_METHOD(PtrBitCast)
  107. TEST_METHOD(MinPrecisionBitCast)
  108. TEST_METHOD(StructBitCast)
  109. TEST_METHOD(MultiDimArray)
  110. TEST_METHOD(NoFunctionParam)
  111. TEST_METHOD(I8Type)
  112. TEST_METHOD(EmptyStructInBuffer)
  113. TEST_METHOD(BigStructInBuffer)
  114. TEST_METHOD(AddUint64Odd)
  115. TEST_METHOD(ClipCullMaxComponents)
  116. TEST_METHOD(ClipCullMaxRows)
  117. TEST_METHOD(DuplicateSysValue)
  118. TEST_METHOD(SemTargetMax)
  119. TEST_METHOD(SemTargetIndexMatchesRow)
  120. TEST_METHOD(SemTargetCol0)
  121. TEST_METHOD(SemIndexMax)
  122. TEST_METHOD(SemTessFactorIndexMax)
  123. TEST_METHOD(SemInsideTessFactorIndexMax)
  124. TEST_METHOD(SemShouldBeAllocated)
  125. TEST_METHOD(SemShouldNotBeAllocated)
  126. TEST_METHOD(SemComponentOrder)
  127. TEST_METHOD(SemComponentOrder2)
  128. TEST_METHOD(SemComponentOrder3)
  129. TEST_METHOD(SemIndexConflictArbSV)
  130. TEST_METHOD(SemIndexConflictTessfactors)
  131. TEST_METHOD(SemIndexConflictTessfactors2)
  132. TEST_METHOD(SemRowOutOfRange)
  133. TEST_METHOD(SemPackOverlap)
  134. TEST_METHOD(SemPackOverlap2)
  135. TEST_METHOD(SemMultiDepth)
  136. TEST_METHOD(WhenInstrDisallowedThenFail);
  137. TEST_METHOD(WhenDepthNotFloatThenFail);
  138. TEST_METHOD(BarrierFail);
  139. TEST_METHOD(CBufferLegacyOutOfBoundFail);
  140. TEST_METHOD(CsThreadSizeFail);
  141. TEST_METHOD(DeadLoopFail);
  142. TEST_METHOD(EvalFail);
  143. TEST_METHOD(GetDimCalcLODFail);
  144. TEST_METHOD(HsAttributeFail);
  145. TEST_METHOD(InnerCoverageFail);
  146. TEST_METHOD(InterpChangeFail);
  147. TEST_METHOD(InterpOnIntFail);
  148. TEST_METHOD(InvalidSigCompTyFail);
  149. TEST_METHOD(MultiStream2Fail);
  150. TEST_METHOD(PhiTGSMFail);
  151. TEST_METHOD(ReducibleFail);
  152. TEST_METHOD(SampleBiasFail);
  153. TEST_METHOD(SamplerKindFail);
  154. TEST_METHOD(SemaOverlapFail);
  155. TEST_METHOD(SigOutOfRangeFail);
  156. TEST_METHOD(SigOverlapFail);
  157. TEST_METHOD(SimpleHs1Fail);
  158. TEST_METHOD(SimpleHs3Fail);
  159. TEST_METHOD(SimpleHs4Fail);
  160. TEST_METHOD(SimpleDs1Fail);
  161. TEST_METHOD(SimpleGs1Fail);
  162. TEST_METHOD(UavBarrierFail);
  163. TEST_METHOD(UndefValueFail);
  164. TEST_METHOD(UpdateCounterFail);
  165. TEST_METHOD(WhenSmUnknownThenFail);
  166. TEST_METHOD(WhenSmLegacyThenFail);
  167. TEST_METHOD(WhenMetaFlagsUsageDeclThenOK);
  168. TEST_METHOD(WhenMetaFlagsUsageThenFail);
  169. dxc::DxcDllSupport m_dllSupport;
  170. void TestCheck(LPCWSTR name) {
  171. std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(name);
  172. FileRunTestResult t = FileRunTestResult::RunFromFileCommands(fullPath.c_str());
  173. if (t.RunResult != 0) {
  174. CA2W commentWide(t.ErrorMessage.c_str(), CP_UTF8);
  175. WEX::Logging::Log::Comment(commentWide);
  176. WEX::Logging::Log::Error(L"Run result is not zero");
  177. }
  178. }
  179. bool CheckOperationResultMsg(IDxcOperationResult *pResult,
  180. const char *pErrorMsg, bool maySucceedAnyway,
  181. bool bRegex) {
  182. HRESULT status;
  183. VERIFY_SUCCEEDED(pResult->GetStatus(&status));
  184. if (pErrorMsg == nullptr) {
  185. VERIFY_SUCCEEDED(status);
  186. }
  187. else {
  188. if (SUCCEEDED(status) && maySucceedAnyway) {
  189. return false;
  190. }
  191. //VERIFY_FAILED(status);
  192. CComPtr<IDxcBlobEncoding> text;
  193. VERIFY_SUCCEEDED(pResult->GetErrorBuffer(&text));
  194. if (bRegex) {
  195. llvm::Regex RE(pErrorMsg);
  196. std::string reErrors;
  197. VERIFY_IS_TRUE(RE.isValid(reErrors));
  198. VERIFY_IS_TRUE(RE.match(llvm::StringRef((const char *)text->GetBufferPointer(), text->GetBufferSize())));
  199. } else {
  200. const char *pStart = (const char *)text->GetBufferPointer();
  201. const char *pEnd = pStart + text->GetBufferSize();
  202. const char *pMatch = std::search(pStart, pEnd, pErrorMsg, pErrorMsg + strlen(pErrorMsg));
  203. if (pEnd == pMatch) {
  204. WEX::Logging::Log::Comment(WEX::Common::String().Format(
  205. L"Unable to find '%S' in text:\r\n%.*S", pErrorMsg, (pEnd - pStart),
  206. pStart));
  207. }
  208. VERIFY_ARE_NOT_EQUAL(pEnd, pMatch);
  209. }
  210. }
  211. return true;
  212. }
  213. void CheckValidationMsg(IDxcBlob *pBlob, const char *pErrorMsg, bool bRegex = false) {
  214. CComPtr<IDxcValidator> pValidator;
  215. CComPtr<IDxcOperationResult> pResult;
  216. if (!m_dllSupport.IsEnabled()) {
  217. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  218. }
  219. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcValidator, &pValidator));
  220. VERIFY_SUCCEEDED(pValidator->Validate(pBlob, DxcValidatorFlags_Default, &pResult));
  221. CheckOperationResultMsg(pResult, pErrorMsg, false, bRegex);
  222. }
  223. void CheckValidationMsg(const char *pBlob, size_t blobSize, const char *pErrorMsg, bool bRegex = false) {
  224. if (!m_dllSupport.IsEnabled()) {
  225. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  226. }
  227. CComPtr<IDxcLibrary> pLibrary;
  228. CComPtr<IDxcBlobEncoding> pBlobEncoding; // Encoding doesn't actually matter, it's binary.
  229. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  230. VERIFY_SUCCEEDED(pLibrary->CreateBlobWithEncodingFromPinned((LPBYTE)pBlob, blobSize, CP_UTF8, &pBlobEncoding));
  231. CheckValidationMsg(pBlobEncoding, pErrorMsg, bRegex);
  232. }
  233. void CompileSource(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
  234. IDxcBlob **pResultBlob) {
  235. CComPtr<IDxcCompiler> pCompiler;
  236. CComPtr<IDxcOperationResult> pResult;
  237. CComPtr<IDxcBlob> pProgram;
  238. if (!m_dllSupport.IsEnabled()) {
  239. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  240. }
  241. CA2W shWide(pShaderModel, CP_UTF8);
  242. VERIFY_SUCCEEDED(
  243. m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  244. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main",
  245. shWide, nullptr, 0, nullptr, 0, nullptr,
  246. &pResult));
  247. VERIFY_SUCCEEDED(pResult->GetResult(pResultBlob));
  248. }
  249. void CompileSource(LPCSTR pSource, LPCSTR pShaderModel,
  250. IDxcBlob **pResultBlob) {
  251. if (!m_dllSupport.IsEnabled()) {
  252. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  253. }
  254. CComPtr<IDxcBlobEncoding> pSourceBlob;
  255. Utf8ToBlob(m_dllSupport, pSource, &pSourceBlob);
  256. CompileSource(pSourceBlob, pShaderModel, pResultBlob);
  257. }
  258. void DisassembleProgram(IDxcBlob *pProgram, std::string *text) {
  259. *text = ::DisassembleProgram(m_dllSupport, pProgram);
  260. }
  261. void RewriteAssemblyCheckMsg(LPCSTR pSource, LPCSTR pShaderModel,
  262. llvm::ArrayRef<LPCSTR> pLookFors, llvm::ArrayRef<LPCSTR> pReplacements,
  263. llvm::ArrayRef<LPCSTR> pErrorMsgs, bool bRegex = false) {
  264. CComPtr<IDxcBlob> pText;
  265. CComPtr<IDxcBlobEncoding> pSourceBlob;
  266. if (!m_dllSupport.IsEnabled()) {
  267. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  268. }
  269. Utf8ToBlob(m_dllSupport, pSource, &pSourceBlob);
  270. RewriteAssemblyToText(pSourceBlob, pShaderModel, pLookFors, pReplacements, &pText, bRegex);
  271. CComPtr<IDxcAssembler> pAssembler;
  272. CComPtr<IDxcOperationResult> pAssembleResult;
  273. VERIFY_SUCCEEDED(
  274. m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  275. VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pText, &pAssembleResult));
  276. for (auto pErrorMsg : pErrorMsgs) {
  277. if (!CheckOperationResultMsg(pAssembleResult, pErrorMsg, true, bRegex)) {
  278. // Assembly succeeded, try validation.
  279. CComPtr<IDxcBlob> pBlob;
  280. VERIFY_SUCCEEDED(pAssembleResult->GetResult(&pBlob));
  281. CheckValidationMsg(pBlob, pErrorMsg, bRegex);
  282. }
  283. }
  284. }
  285. void RewriteAssemblyToText(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
  286. llvm::ArrayRef<LPCSTR> pLookFors, llvm::ArrayRef<LPCSTR> pReplacements,
  287. IDxcBlob **pBlob, bool bRegex = false) {
  288. CComPtr<IDxcBlob> pProgram;
  289. std::string disassembly;
  290. CompileSource(pSource, pShaderModel, &pProgram);
  291. DisassembleProgram(pProgram, &disassembly);
  292. for (unsigned i = 0; i < pLookFors.size(); ++i) {
  293. LPCSTR pLookFor = pLookFors[i];
  294. LPCSTR pReplacement = pReplacements[i];
  295. if (pLookFor && *pLookFor) {
  296. if (bRegex) {
  297. llvm::Regex RE(pLookFor);
  298. std::string reErrors;
  299. VERIFY_IS_TRUE(RE.isValid(reErrors));
  300. std::string replaced = RE.sub(pReplacement, disassembly, &reErrors);
  301. VERIFY_ARE_NOT_EQUAL(disassembly, replaced);
  302. VERIFY_IS_TRUE(reErrors.empty());
  303. disassembly = std::move(replaced);
  304. } else {
  305. bool found = false;
  306. size_t pos = 0;
  307. size_t lookForLen = strlen(pLookFor);
  308. size_t replaceLen = strlen(pReplacement);
  309. for (;;) {
  310. pos = disassembly.find(pLookFor, pos);
  311. if (pos == std::string::npos)
  312. break;
  313. found = true; // at least once
  314. disassembly.replace(pos, lookForLen, pReplacement);
  315. pos += replaceLen;
  316. }
  317. VERIFY_IS_TRUE(found);
  318. }
  319. }
  320. }
  321. Utf8ToBlob(m_dllSupport, disassembly.c_str(), pBlob);
  322. }
  323. void RewriteAssemblyCheckMsg(LPCWSTR name, LPCSTR pShaderModel,
  324. llvm::ArrayRef<LPCSTR> pLookFors, llvm::ArrayRef<LPCSTR> pReplacements,
  325. llvm::ArrayRef<LPCSTR> pErrorMsgs, bool bRegex = false) {
  326. std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(name);
  327. CComPtr<IDxcLibrary> pLibrary;
  328. CComPtr<IDxcBlobEncoding> pSource;
  329. if (!m_dllSupport.IsEnabled()) {
  330. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  331. }
  332. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  333. VERIFY_SUCCEEDED(
  334. pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource));
  335. CComPtr<IDxcBlob> pText;
  336. RewriteAssemblyToText(pSource, pShaderModel, pLookFors, pReplacements, &pText, bRegex);
  337. CComPtr<IDxcAssembler> pAssembler;
  338. CComPtr<IDxcOperationResult> pAssembleResult;
  339. VERIFY_SUCCEEDED(
  340. m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  341. VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pText, &pAssembleResult));
  342. for (auto pErrorMsg : pErrorMsgs) {
  343. if (!CheckOperationResultMsg(pAssembleResult, pErrorMsg, true, bRegex)) {
  344. // Assembly succeeded, try validation.
  345. CComPtr<IDxcBlob> pBlob;
  346. VERIFY_SUCCEEDED(pAssembleResult->GetResult(&pBlob));
  347. CheckValidationMsg(pBlob, pErrorMsg, bRegex);
  348. }
  349. }
  350. }
  351. };
  352. TEST_F(ValidationTest, WhenCorrectThenOK) {
  353. CComPtr<IDxcBlob> pProgram;
  354. CompileSource("float4 main() : SV_Target { return 1; }", "ps_6_0", &pProgram);
  355. CheckValidationMsg(pProgram, nullptr);
  356. }
  357. // Lots of these going on below for simplicity in setting up payloads.
  358. //
  359. // warning C4838: conversion from 'int' to 'const char' requires a narrowing conversion
  360. // warning C4309: 'initializing': truncation of constant value
  361. #pragma warning(disable: 4838)
  362. #pragma warning(disable: 4309)
  363. TEST_F(ValidationTest, WhenMisalignedThenFail) {
  364. // Bitcode size must 4-byte aligned
  365. const char blob[] = {
  366. 'B', 'C',
  367. };
  368. CheckValidationMsg(blob, _countof(blob), "Invalid bitcode size");
  369. }
  370. TEST_F(ValidationTest, WhenEmptyFileThenFail) {
  371. // No blocks after signature.
  372. const char blob[] = {
  373. 'B', 'C', 0xc0, 0xde
  374. };
  375. CheckValidationMsg(blob, _countof(blob), "Malformed IR file");
  376. }
  377. TEST_F(ValidationTest, WhenIncorrectMagicThenFail) {
  378. // Signature isn't 'B', 'C', 0xC0 0xDE
  379. const char blob[] = {
  380. 'B', 'C', 0xc0, 0xdd
  381. };
  382. CheckValidationMsg(blob, _countof(blob), "Invalid bitcode signature");
  383. }
  384. TEST_F(ValidationTest, WhenIncorrectTargetTripleThenFail) {
  385. const char blob[] = {
  386. 'B', 'C', 0xc0, 0xde
  387. };
  388. CheckValidationMsg(blob, _countof(blob), "Malformed IR file");
  389. }
  390. TEST_F(ValidationTest, WhenMultipleModulesThenFail) {
  391. const char blob[] = {
  392. 'B', 'C', 0xc0, 0xde,
  393. 0x21, 0x0c, 0x00, 0x00, // Enter sub-block, BlockID = 8, Code Size=3, padding x2
  394. 0x00, 0x00, 0x00, 0x00, // NumWords = 0
  395. 0x08, 0x00, 0x00, 0x00, // End-of-block, padding
  396. // At this point, this is valid bitcode (but missing required DXIL metadata)
  397. // Trigger the case we're looking for now
  398. 0x21, 0x0c, 0x00, 0x00, // Enter sub-block, BlockID = 8, Code Size=3, padding x2
  399. };
  400. CheckValidationMsg(blob, _countof(blob), "Unused bits in buffer");
  401. }
  402. TEST_F(ValidationTest, WhenUnexpectedEOFThenFail) {
  403. // Importantly, this is testing the usage of report_fatal_error during deserialization.
  404. const char blob[] = {
  405. 'B', 'C', 0xc0, 0xde,
  406. 0x21, 0x0c, 0x00, 0x00, // Enter sub-block, BlockID = 8, Code Size=3, padding x2
  407. 0x00, 0x00, 0x00, 0x00, // NumWords = 0
  408. };
  409. CheckValidationMsg(blob, _countof(blob), "Invalid record");
  410. }
  411. TEST_F(ValidationTest, WhenUnknownBlocksThenFail) {
  412. const char blob[] = {
  413. 'B', 'C', 0xc0, 0xde, // Signature
  414. 0x31, 0x00, 0x00, 0x00 // Enter sub-block, BlockID != 8
  415. };
  416. CheckValidationMsg(blob, _countof(blob), "Unrecognized block found");
  417. }
  418. TEST_F(ValidationTest, WhenInstrDisallowedThenFail) {
  419. RewriteAssemblyCheckMsg(
  420. L"..\\CodeGenHLSL\\abs2.hlsl", "ps_6_0",
  421. {
  422. "target triple = \"dxil-ms-dx\"",
  423. "ret void",
  424. "dx.op.loadInput.i32(i32 4, i32 0, i32 0, i8 3, i32 undef)",
  425. "!\"ps\", i32 6, i32 0",
  426. },
  427. {
  428. "target triple = \"dxil-ms-dx\"\n%dx.types.wave_t = type { i8* }",
  429. "unreachable",
  430. "dx.op.loadInput.i32(i32 4, i32 0, i32 0, i8 3, i32 undef)\n%wave_local = alloca %dx.types.wave_t",
  431. "!\"vs\", i32 6, i32 0",
  432. },
  433. {"Semantic 'SV_Target' is invalid as vs Output",
  434. "Declaration '%dx.types.wave_t = type { i8* }' uses a reserved prefix",
  435. "Instructions must be of an allowed type",
  436. }
  437. );
  438. }
  439. TEST_F(ValidationTest, WhenDepthNotFloatThenFail) {
  440. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\IntegerDepth2.hlsl", "ps_6_0",
  441. {
  442. "!\"SV_Depth\", i8 9",
  443. },
  444. {
  445. "!\"SV_Depth\", i8 4",
  446. },
  447. {
  448. "SV_Depth must be float",
  449. });
  450. }
  451. TEST_F(ValidationTest, BarrierFail) {
  452. RewriteAssemblyCheckMsg(
  453. L"..\\CodeGenHLSL\\barrier.hlsl", "cs_6_0",
  454. {"dx.op.barrier(i32 82, i32 8)",
  455. "dx.op.barrier(i32 82, i32 9)",
  456. "dx.op.barrier(i32 82, i32 11)",
  457. "%class.RWStructuredBuffer = type { %class.matrix.float.2.2 }\n",
  458. "call i32 @dx.op.flattenedThreadIdInGroup.i32(i32 98)",
  459. },
  460. {"dx.op.barrier(i32 82, i32 15)",
  461. "dx.op.barrier(i32 82, i32 0)",
  462. "dx.op.barrier(i32 82, i32 %rem)",
  463. "%class.RWStructuredBuffer = type { %class.matrix.float.2.2 }\n"
  464. "@dx.typevar.8 = external addrspace(1) constant %class.RWStructuredBuffer\n"
  465. "@\"internalGV\" = internal global [64 x <4 x float>] undef\n",
  466. "call i32 @dx.op.flattenedThreadIdInGroup.i32(i32 98)\n"
  467. "%load = load %class.RWStructuredBuffer, %class.RWStructuredBuffer addrspace(1)* @dx.typevar.8",
  468. },
  469. {"Internal declaration 'internalGV' is unused",
  470. "External declaration 'dx.typevar.8' is unused",
  471. "Vector type '<4 x float>' is not allowed",
  472. "Mode of Barrier must be an immediate constant",
  473. "sync must include some form of memory barrier - _u (UAV) and/or _g (Thread Group Shared Memory)",
  474. "sync can't specify both _ugroup and _uglobal. If both are needed, just specify _uglobal"
  475. });
  476. }
  477. TEST_F(ValidationTest, CBufferLegacyOutOfBoundFail) {
  478. RewriteAssemblyCheckMsg(
  479. L"..\\CodeGenHLSL\\cbuffer1.50.hlsl", "ps_6_0",
  480. "cbufferLoadLegacy.f32(i32 61, %dx.types.Handle %Foo2_buffer, i32 0)",
  481. "cbufferLoadLegacy.f32(i32 61, %dx.types.Handle %Foo2_buffer, i32 6)",
  482. "Cbuffer access out of bound");
  483. }
  484. TEST_F(ValidationTest, CsThreadSizeFail) {
  485. RewriteAssemblyCheckMsg(
  486. L"..\\CodeGenHLSL\\share_mem1.hlsl", "cs_6_0",
  487. {"!{i32 8, i32 8, i32 1",
  488. "[256 x float]"},
  489. {"!{i32 1025, i32 1025, i32 1025",
  490. "[64000000 x float]"},
  491. {"Declared Thread Group X size 1025 outside valid range",
  492. "Declared Thread Group Y size 1025 outside valid range",
  493. "Declared Thread Group Z size 1025 outside valid range",
  494. "Declared Thread Group Count 1076890625 (X*Y*Z) is beyond the valid maximum",
  495. "Total Thread Group Shared Memory storage is 256000000, exceeded 32768",
  496. });
  497. }
  498. TEST_F(ValidationTest, DeadLoopFail) {
  499. RewriteAssemblyCheckMsg(
  500. L"..\\CodeGenHLSL\\loop1.hlsl", "ps_6_0",
  501. {"br i1 %exitcond, label %for.end.loopexit, label %for.body, !llvm.loop !([0-9]+)",
  502. "%add.lcssa = phi float \\[ %add, %for.body \\]",
  503. "!dx.entryPoints = !\\{!([0-9]+)\\}",
  504. "\\[ %add.lcssa, %for.end.loopexit \\]"
  505. },
  506. {"br label %for.body",
  507. "",
  508. "!dx.entryPoints = !\\{!\\1\\}\n!dx.unused = !\\{!\\1\\}",
  509. "[ 0.000000e+00, %for.end.loopexit ]"
  510. },
  511. {"Loop must have break",
  512. "Named metadata 'dx.unused' is unknown",
  513. },
  514. /*bRegex*/true);
  515. }
  516. TEST_F(ValidationTest, EvalFail) {
  517. RewriteAssemblyCheckMsg(
  518. L"..\\CodeGenHLSL\\Eval.hlsl", "ps_6_0",
  519. "!\"A\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 4",
  520. "!\"A\", i8 9, i8 0, !\\1, i8 0, i32 1, i8 4",
  521. "Interpolation mode on A used with eval_\\* instruction must be ",
  522. /*bRegex*/true);
  523. }
  524. TEST_F(ValidationTest, GetDimCalcLODFail) {
  525. RewriteAssemblyCheckMsg(
  526. L"..\\CodeGenHLSL\\GetDimCalcLOD.hlsl", "ps_6_0",
  527. {"extractvalue %dx.types.Dimensions %2, 1",
  528. "float 1.000000e+00, i1 true"
  529. },
  530. {"extractvalue %dx.types.Dimensions %2, 2",
  531. "float undef, i1 true"
  532. },
  533. {"GetDimensions used undef dimension z on TextureCube",
  534. "coord uninitialized"});
  535. }
  536. TEST_F(ValidationTest, HsAttributeFail) {
  537. RewriteAssemblyCheckMsg(
  538. L"..\\CodeGenHLSL\\hsAttribute.hlsl", "hs_6_0",
  539. {"i32 3, i32 3, i32 2, i32 3, i32 3, float 6.400000e+01"
  540. },
  541. {"i32 36, i32 36, i32 0, i32 0, i32 0, float 6.500000e+01"
  542. },
  543. {"HS input control point count must be [1..32]. 36 specified",
  544. "Invalid Tessellator Domain specified. Must be isoline, tri or quad",
  545. "Invalid Tessellator Partitioning specified",
  546. "Invalid Tessellator Output Primitive specified",
  547. "Hull Shader MaxTessFactor must be [1.000000..64.000000]. 65.000000 specified",
  548. "output control point count must be [0..32]. 36 specified"});
  549. }
  550. TEST_F(ValidationTest, InnerCoverageFail) {
  551. RewriteAssemblyCheckMsg(
  552. L"..\\CodeGenHLSL\\InnerCoverage2.hlsl", "ps_6_0",
  553. {"dx.op.coverage.i32(i32 93)",
  554. "declare i32 @dx.op.coverage.i32(i32)"
  555. },
  556. {"dx.op.coverage.i32(i32 93)\n %inner = call i32 @dx.op.innercoverage.i32(i32 94)",
  557. "declare i32 @dx.op.coverage.i32(i32)\n"
  558. "declare i32 @dx.op.innercoverage.i32(i32)"
  559. },
  560. "InnerCoverage and Coverage are mutually exclusive.");
  561. }
  562. TEST_F(ValidationTest, InterpChangeFail) {
  563. RewriteAssemblyCheckMsg(
  564. L"..\\CodeGenHLSL\\interpChange.hlsl", "ps_6_0",
  565. "i32 1, i8 0, null}",
  566. "i32 0, i8 2, null}",
  567. "interpolation mode that differs from another element packed",
  568. /*bRegex*/true);
  569. }
  570. TEST_F(ValidationTest, InterpOnIntFail) {
  571. RewriteAssemblyCheckMsg(
  572. L"..\\CodeGenHLSL\\interpOnInt2.hlsl", "ps_6_0",
  573. "!\"A\", i8 5, i8 0, !([0-9]+), i8 1",
  574. "!\"A\", i8 5, i8 0, !\\1, i8 2",
  575. "signature element A specifies invalid interpolation mode for integer component type",
  576. /*bRegex*/true);
  577. }
  578. TEST_F(ValidationTest, InvalidSigCompTyFail) {
  579. RewriteAssemblyCheckMsg(
  580. L"..\\CodeGenHLSL\\abs2.hlsl", "ps_6_0",
  581. "!\"A\", i8 4",
  582. "!\"A\", i8 0",
  583. "A specifies unrecognized or invalid component type");
  584. }
  585. TEST_F(ValidationTest, MultiStream2Fail) {
  586. RewriteAssemblyCheckMsg(
  587. L"..\\CodeGenHLSL\\multiStreamGS.hlsl", "gs_6_0",
  588. "i32 1, i32 12, i32 7, i32 1, i32 1",
  589. "i32 1, i32 12, i32 7, i32 2, i32 1",
  590. "Multiple GS output streams are used but 'XXX' is not pointlist");
  591. }
  592. TEST_F(ValidationTest, PhiTGSMFail) {
  593. RewriteAssemblyCheckMsg(
  594. L"..\\CodeGenHLSL\\phiTGSM.hlsl", "cs_6_0",
  595. "ret void",
  596. "%arrayPhi = phi i32 addrspace(3)* [ %arrayidx, %if.then ], [ %arrayidx2, %if.else ]\n"
  597. "%phiAtom = atomicrmw add i32 addrspace(3)* %arrayPhi, i32 1 seq_cst\n"
  598. "ret void",
  599. "TGSM pointers must originate from an unambiguous TGSM global variable");
  600. }
  601. TEST_F(ValidationTest, ReducibleFail) {
  602. RewriteAssemblyCheckMsg(
  603. L"..\\CodeGenHLSL\\reducible.hlsl", "ps_6_0",
  604. {"%conv\n"
  605. " br label %if.end",
  606. "to float\n"
  607. " br label %if.end"
  608. },
  609. {"%conv\n"
  610. " br i1 %cmp.i0, label %if.else, label %if.end",
  611. "to float\n"
  612. " br i1 %cmp.i0, label %if.then, label %if.end"
  613. },
  614. "Execution flow must be reducible");
  615. }
  616. TEST_F(ValidationTest, SampleBiasFail) {
  617. RewriteAssemblyCheckMsg(
  618. L"..\\CodeGenHLSL\\sampleBias.hlsl", "ps_6_0",
  619. {"float -1.600000e+01"
  620. },
  621. {"float 1.800000e+01"
  622. },
  623. "bias amount for sample_b must be in the range [-16.000000,15.990000]");
  624. }
  625. TEST_F(ValidationTest, SamplerKindFail) {
  626. RewriteAssemblyCheckMsg(
  627. L"..\\CodeGenHLSL\\samplerKind.hlsl", "ps_6_0",
  628. {"uav1_UAV_2d = call %dx.types.Handle @dx.op.createHandle(i32 59, i8 1",
  629. "g_txDiffuse_texture_2d = call %dx.types.Handle @dx.op.createHandle(i32 59, i8 0",
  630. "\"g_samLinear\", i32 0, i32 0, i32 1, i32 0",
  631. "\"g_samLinearC\", i32 0, i32 1, i32 1, i32 1",
  632. },
  633. {"uav1_UAV_2d = call %dx.types.Handle @dx.op.createHandle(i32 59, i8 0",
  634. "g_txDiffuse_texture_2d = call %dx.types.Handle @dx.op.createHandle(i32 59, i8 1",
  635. "\"g_samLinear\", i32 0, i32 0, i32 1, i32 3",
  636. "\"g_samLinearC\", i32 0, i32 1, i32 1, i32 3",
  637. },
  638. {"Invalid sampler mode",
  639. "require sampler declared in comparison mode",
  640. "requires sampler declared in default mode",
  641. "should on srv resource"});
  642. }
  643. TEST_F(ValidationTest, SemaOverlapFail) {
  644. RewriteAssemblyCheckMsg(
  645. L"..\\CodeGenHLSL\\semaOverlap1.hlsl", "ps_6_0",
  646. {"!([0-9]+) = !\\{i32 0, !\"A\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 4, i32 0, i8 0, null\\}\n"
  647. "!([0-9]+) = !\\{i32 0\\}\n"
  648. "!([0-9]+) = !\\{i32 1, !\"A\", i8 9, i8 0, !([0-9]+)",
  649. },
  650. {"!\\1 = !\\{i32 0, !\"A\", i8 9, i8 0, !\\2, i8 2, i32 1, i8 4, i32 0, i8 0, null\\}\n"
  651. "!\\3 = !\\{i32 0\\}\n"
  652. "!\\4 = !\\{i32 1, !\"A\", i8 9, i8 0, !\\2",
  653. },
  654. {"Semantic 'A' overlap at 0"},
  655. /*bRegex*/true);
  656. }
  657. TEST_F(ValidationTest, SigOutOfRangeFail) {
  658. RewriteAssemblyCheckMsg(
  659. L"..\\CodeGenHLSL\\semaOverlap1.hlsl", "ps_6_0",
  660. {"i32 1, i8 0, null}",
  661. },
  662. {"i32 8000, i8 0, null}",
  663. },
  664. {"signature element A at location (8000,0) size (1,4) is out of range"});
  665. }
  666. TEST_F(ValidationTest, SigOverlapFail) {
  667. RewriteAssemblyCheckMsg(
  668. L"..\\CodeGenHLSL\\semaOverlap1.hlsl", "ps_6_0",
  669. {"i32 1, i8 0, null}",
  670. },
  671. {"i32 0, i8 0, null}",
  672. },
  673. {"signature element A at location (0,0) size (1,4) overlaps another signature element"});
  674. }
  675. TEST_F(ValidationTest, SimpleHs1Fail) {
  676. RewriteAssemblyCheckMsg(
  677. L"..\\CodeGenHLSL\\SimpleHs1.hlsl", "hs_6_0",
  678. {"i32 3, i32 3, i32 2, i32 3, i32 3, float 6.400000e+01}",
  679. "\"SV_TessFactor\", i8 9, i8 25",
  680. "\"SV_InsideTessFactor\", i8 9, i8 26",
  681. },
  682. {"i32 3, i32 3000, i32 2, i32 3, i32 3, float 6.400000e+01}",
  683. "\"TessFactor\", i8 9, i8 0",
  684. "\"InsideTessFactor\", i8 9, i8 0",
  685. },
  686. {"output control point count must be [0..32]. 3000 specified",
  687. "Required TessFactor for domain not found declared anywhere in Patch Constant data",
  688. // TODO: enable this after support pass thru hull shader.
  689. //"For pass thru hull shader, input control point count must match output control point count",
  690. //"Total number of scalars across all HS output control points must not exceed",
  691. });
  692. }
  693. TEST_F(ValidationTest, SimpleHs3Fail) {
  694. RewriteAssemblyCheckMsg(
  695. L"..\\CodeGenHLSL\\SimpleHs3.hlsl", "hs_6_0",
  696. {
  697. "i32 3, i32 3, i32 2, i32 3, i32 3, float 6.400000e+01}",
  698. },
  699. {
  700. "i32 3, i32 3, i32 2, i32 3, i32 2, float 6.400000e+01}",
  701. },
  702. {"Hull Shader declared with Tri Domain must specify output primitive "
  703. "point, triangle_cw or triangle_ccw. Line output is not compatible with "
  704. "the Tri domain"});
  705. }
  706. TEST_F(ValidationTest, SimpleHs4Fail) {
  707. RewriteAssemblyCheckMsg(
  708. L"..\\CodeGenHLSL\\SimpleHs4.hlsl", "hs_6_0",
  709. {
  710. "i32 2, i32 2, i32 1, i32 3, i32 2, float 6.400000e+01}",
  711. },
  712. {
  713. "i32 2, i32 2, i32 1, i32 3, i32 3, float 6.400000e+01}",
  714. },
  715. {"Hull Shader declared with IsoLine Domain must specify output primitive "
  716. "point or line. Triangle_cw or triangle_ccw output are not compatible "
  717. "with the IsoLine Domain"});
  718. }
  719. TEST_F(ValidationTest, SimpleDs1Fail) {
  720. RewriteAssemblyCheckMsg(
  721. L"..\\CodeGenHLSL\\SimpleDs1.hlsl", "ds_6_0",
  722. {"!{i32 2, i32 3}"
  723. },
  724. {"!{i32 4, i32 36}"
  725. },
  726. {"DS input control point count must be [0..32]. 36 specified",
  727. "Invalid Tessellator Domain specified. Must be isoline, tri or quad",
  728. "DomainLocation component index out of bounds for the domain"});
  729. }
  730. TEST_F(ValidationTest, SimpleGs1Fail) {
  731. RewriteAssemblyCheckMsg(
  732. L"..\\CodeGenHLSL\\SimpleGs1.hlsl", "gs_6_0",
  733. {"!{i32 1, i32 3, i32 1, i32 5, i32 1}",
  734. "i8 4, i32 1, i8 4, i32 1, i8 0, null}"
  735. },
  736. {"!{i32 5, i32 1025, i32 1, i32 0, i32 33}",
  737. "i8 4, i32 1, i8 4, i32 1, i8 0, !100}\n"
  738. "!100 = !{i32 0, i32 5}"
  739. },
  740. {"GS output vertex count must be [0..1024]. 1025 specified",
  741. "GS instance count must be [1..32]. 33 specified",
  742. "GS output primitive topology unrecognized",
  743. "GS input primitive unrecognized",
  744. "Stream index (5) must between 0 and 3"});
  745. }
  746. TEST_F(ValidationTest, UavBarrierFail) {
  747. RewriteAssemblyCheckMsg(
  748. L"..\\CodeGenHLSL\\uavBarrier.hlsl", "ps_6_0",
  749. {"dx.op.barrier(i32 82, i32 2)",
  750. "textureLoad.f32(i32 68, %dx.types.Handle %uav1_UAV_2d, i32 undef",
  751. "i32 undef, i32 undef, i32 undef, i32 undef)",
  752. "float %add9.i3, i8 15)",
  753. },
  754. {"dx.op.barrier(i32 82, i32 9)",
  755. "textureLoad.f32(i32 68, %dx.types.Handle %uav1_UAV_2d, i32 1",
  756. "i32 1, i32 2, i32 undef, i32 undef)",
  757. "float undef, i8 7)",
  758. },
  759. {"uav load don't support offset",
  760. "uav load don't support mipLevel/sampleIndex",
  761. "store on typed uav must write to all four components of the UAV",
  762. "sync in a non-Compute Shader must only sync UAV (sync_uglobal)"});
  763. }
  764. TEST_F(ValidationTest, UndefValueFail) {
  765. RewriteAssemblyCheckMsg(
  766. L"..\\CodeGenHLSL\\UndefValue.hlsl", "ps_6_0",
  767. {"fadd fast float %([0-9]+)"
  768. },
  769. {"fadd fast float undef"
  770. },
  771. {"Instructions should not read uninitialized value"},
  772. /*bRegex*/ true);
  773. }
  774. TEST_F(ValidationTest, UpdateCounterFail) {
  775. RewriteAssemblyCheckMsg(
  776. L"..\\CodeGenHLSL\\UpdateCounter2.hlsl", "ps_6_0",
  777. {"%2 = call i32 @dx.op.bufferUpdateCounter(i32 72, %dx.types.Handle %buf2_UAV_structbuf, i8 1)",
  778. "%3 = call i32 @dx.op.bufferUpdateCounter(i32 72, %dx.types.Handle %buf2_UAV_structbuf, i8 1)"
  779. },
  780. {"%2 = call i32 @dx.op.bufferUpdateCounter(i32 72, %dx.types.Handle %buf2_UAV_structbuf, i8 -1)",
  781. "%3 = call i32 @dx.op.bufferUpdateCounter(i32 72, %dx.types.Handle %buf2_UAV_structbuf, i8 1)\n"
  782. "%srvUpdate = call i32 @dx.op.bufferUpdateCounter(i32 72, %dx.types.Handle %buf1_texture_buf, i8 undef)"
  783. },
  784. {"BufferUpdateCounter valid only on UAV",
  785. "BufferUpdateCounter valid only on structured buffers",
  786. "inc of BufferUpdateCounter must be an immediate constant",
  787. "RWStructuredBuffers may increment or decrement their counters, but not both"});
  788. }
  789. TEST_F(ValidationTest, WhenIncorrectModelThenFail) {
  790. TestCheck(L"val-failures.hlsl");
  791. }
  792. TEST_F(ValidationTest, WhenIncorrectPSThenFail) {
  793. TestCheck(L"val-failures-ps.hlsl");
  794. }
  795. TEST_F(ValidationTest, WhenSmUnknownThenFail) {
  796. RewriteAssemblyCheckMsg("float4 main() : SV_Target { return 1; }", "ps_6_0",
  797. {"{!\"ps\", i32 6, i32 0}"},
  798. {"{!\"ps\", i32 1, i32 2}"},
  799. "Unknown shader model 'ps_1_2'");
  800. }
  801. TEST_F(ValidationTest, WhenSmLegacyThenFail) {
  802. RewriteAssemblyCheckMsg("float4 main() : SV_Target { return 1; }", "ps_6_0",
  803. "{!\"ps\", i32 6, i32 0}", "{!\"ps\", i32 5, i32 1}",
  804. "Unknown shader model 'ps_5_1'");
  805. }
  806. TEST_F(ValidationTest, WhenMetaFlagsUsageDeclThenOK) {
  807. RewriteAssemblyCheckMsg(
  808. "uint u; float4 main() : SV_Target { uint64_t n = u; n *= u; return (uint)(n >> 32); }", "ps_6_0",
  809. "1048576", "1048577", // inhibit optimization, which should work fine
  810. nullptr);
  811. }
  812. TEST_F(ValidationTest, GsVertexIDOutOfBound) {
  813. RewriteAssemblyCheckMsg(
  814. L"..\\CodeGenHLSL\\SimpleGs1.hlsl", "gs_6_0",
  815. "dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 2, i32 0)",
  816. "dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 2, i32 1)",
  817. "expect VertexID between 0~1, got 1");
  818. }
  819. TEST_F(ValidationTest, StreamIDOutOfBound) {
  820. RewriteAssemblyCheckMsg(
  821. L"..\\CodeGenHLSL\\SimpleGs1.hlsl", "gs_6_0",
  822. "dx.op.emitStream(i32 99, i8 0)",
  823. "dx.op.emitStream(i32 99, i8 1)",
  824. "expect StreamID between 0 , got 1");
  825. }
  826. TEST_F(ValidationTest, SignatureStreamIDForNonGS) {
  827. RewriteAssemblyCheckMsg(
  828. L"..\\CodeGenHLSL\\abs1.hlsl", "ps_6_0",
  829. ", i8 0, i32 1, i8 4, i32 0, i8 0, null}",
  830. ", i8 0, i32 1, i8 4, i32 0, i8 0, !19}\n!19 = !{i32 0, i32 1}",
  831. "Stream index (1) must between 0 and 0");
  832. }
  833. TEST_F(ValidationTest, TypedUAVStoreFullMask0) {
  834. RewriteAssemblyCheckMsg(
  835. L"..\\CodeGenHLSL\\uav_typed_store.hlsl", "ps_6_0",
  836. "float 2.000000e+00, i8 15)",
  837. "float 2.000000e+00, i8 undef)",
  838. "Mask of TextureStore must be an immediate constant");
  839. }
  840. TEST_F(ValidationTest, TypedUAVStoreFullMask1) {
  841. RewriteAssemblyCheckMsg(
  842. L"..\\CodeGenHLSL\\uav_typed_store.hlsl", "ps_6_0",
  843. "float 3.000000e+00, i8 15)",
  844. "float 3.000000e+00, i8 undef)",
  845. "Mask of BufferStore must be an immediate constant");
  846. }
  847. TEST_F(ValidationTest, Recursive) {
  848. TestCheck(L"..\\CodeGenHLSL\\recursive.hlsl");
  849. }
  850. TEST_F(ValidationTest, Recursive2) {
  851. TestCheck(L"..\\CodeGenHLSL\\recursive2.hlsl");
  852. }
  853. TEST_F(ValidationTest, UserDefineFunction) {
  854. TestCheck(L"..\\CodeGenHLSL\\recursive2.hlsl");
  855. }
  856. TEST_F(ValidationTest, ResourceRangeOverlap0) {
  857. RewriteAssemblyCheckMsg(
  858. L"..\\CodeGenHLSL\\resource_overlap.hlsl", "ps_6_0",
  859. "!\"B\", i32 0, i32 1",
  860. "!\"B\", i32 0, i32 0",
  861. "Resource B with base 0 size 1 overlap");
  862. }
  863. TEST_F(ValidationTest, ResourceRangeOverlap1) {
  864. RewriteAssemblyCheckMsg(
  865. L"..\\CodeGenHLSL\\resource_overlap.hlsl", "ps_6_0",
  866. "!\"s1\", i32 0, i32 1",
  867. "!\"s1\", i32 0, i32 0",
  868. "Resource s1 with base 0 size 1 overlap");
  869. }
  870. TEST_F(ValidationTest, ResourceRangeOverlap2) {
  871. RewriteAssemblyCheckMsg(
  872. L"..\\CodeGenHLSL\\resource_overlap.hlsl", "ps_6_0",
  873. "!\"uav2\", i32 0, i32 0",
  874. "!\"uav2\", i32 0, i32 3",
  875. "Resource uav2 with base 3 size 1 overlap");
  876. }
  877. TEST_F(ValidationTest, ResourceRangeOverlap3) {
  878. RewriteAssemblyCheckMsg(
  879. L"..\\CodeGenHLSL\\resource_overlap.hlsl", "ps_6_0",
  880. "!\"srv2\", i32 0, i32 1",
  881. "!\"srv2\", i32 0, i32 0",
  882. "Resource srv2 with base 0 size 1 overlap");
  883. }
  884. TEST_F(ValidationTest, CBufferOverlap0) {
  885. RewriteAssemblyCheckMsg(
  886. L"..\\CodeGenHLSL\\cbufferOffset.hlsl", "ps_6_0",
  887. "i32 6, !\"g2\", i32 3, i32 0",
  888. "i32 6, !\"g2\", i32 3, i32 8",
  889. "CBuffer Foo1 has offset overlaps at 16");
  890. }
  891. TEST_F(ValidationTest, CBufferOverlap1) {
  892. RewriteAssemblyCheckMsg(
  893. L"..\\CodeGenHLSL\\cbufferOffset.hlsl", "ps_6_0",
  894. " = !{i32 32, !",
  895. " = !{i32 16, !",
  896. "CBuffer Foo1 size insufficient for element at offset 16");
  897. }
  898. TEST_F(ValidationTest, ControlFlowHint) {
  899. RewriteAssemblyCheckMsg(
  900. L"..\\CodeGenHLSL\\if1.hlsl", "ps_6_0",
  901. "!\"dx.controlflow.hints\", i32 1",
  902. "!\"dx.controlflow.hints\", i32 5",
  903. "Attribute forcecase only works for switch");
  904. }
  905. TEST_F(ValidationTest, ControlFlowHint1) {
  906. RewriteAssemblyCheckMsg(
  907. L"..\\CodeGenHLSL\\if1.hlsl", "ps_6_0",
  908. "!\"dx.controlflow.hints\", i32 1",
  909. "!\"dx.controlflow.hints\", i32 1, i32 2",
  910. "Can't use branch and flatten attributes together");
  911. }
  912. TEST_F(ValidationTest, ControlFlowHint2) {
  913. RewriteAssemblyCheckMsg(
  914. L"..\\CodeGenHLSL\\if1.hlsl", "ps_6_0",
  915. "!\"dx.controlflow.hints\", i32 1",
  916. "!\"dx.controlflow.hints\", i32 3",
  917. "Invalid control flow hint");
  918. }
  919. TEST_F(ValidationTest, SemanticLength1) {
  920. RewriteAssemblyCheckMsg(
  921. L"..\\CodeGenHLSL\\binary1.hlsl", "ps_6_0",
  922. "!\"C\"",
  923. "!\"\"",
  924. "Semantic length must be at least 1 and at most 64");
  925. }
  926. TEST_F(ValidationTest, SemanticLength64) {
  927. RewriteAssemblyCheckMsg(
  928. L"..\\CodeGenHLSL\\binary1.hlsl", "ps_6_0",
  929. "!\"C\"",
  930. "!\"CSESESESESESESESESESESESESESESESESESESESESESESESESESESESESESESESE\"",
  931. "Semantic length must be at least 1 and at most 64");
  932. }
  933. TEST_F(ValidationTest, PullModelPosition) {
  934. RewriteAssemblyCheckMsg(
  935. L"..\\CodeGenHLSL\\eval.hlsl", "ps_6_0",
  936. "!\"A\", i8 9, i8 0",
  937. "!\"SV_Position\", i8 9, i8 3",
  938. "does not support pull-model evaluation of position");
  939. }
  940. TEST_F(ValidationTest, StructBufGlobalCoherentAndCounter) {
  941. RewriteAssemblyCheckMsg(
  942. L"..\\CodeGenHLSL\\struct_buf1.hlsl", "ps_6_0",
  943. "!\"buf2\", i32 0, i32 0, i32 1, i32 12, i1 false, i1 false",
  944. "!\"buf2\", i32 0, i32 0, i32 1, i32 12, i1 true, i1 true",
  945. "globallycoherent cannot be used with append/consume buffers'buf2'");
  946. }
  947. TEST_F(ValidationTest, StructBufStrideAlign) {
  948. RewriteAssemblyCheckMsg(
  949. L"..\\CodeGenHLSL\\struct_buf1.hlsl", "ps_6_0",
  950. "= !{i32 1, i32 52}",
  951. "= !{i32 1, i32 50}",
  952. "structured buffer element size must be a multiple of 4 bytes (actual size 50 bytes)");
  953. }
  954. TEST_F(ValidationTest, StructBufStrideOutOfBound) {
  955. RewriteAssemblyCheckMsg(
  956. L"..\\CodeGenHLSL\\struct_buf1.hlsl", "ps_6_0",
  957. "= !{i32 1, i32 52}",
  958. "= !{i32 1, i32 2052}",
  959. "structured buffer elements cannot be larger than 2048 bytes (actual size 2052 bytes)");
  960. }
  961. TEST_F(ValidationTest, StructBufLoadCoordinates) {
  962. RewriteAssemblyCheckMsg(
  963. L"..\\CodeGenHLSL\\struct_buf1.hlsl", "ps_6_0",
  964. "bufferLoad.f32(i32 70, %dx.types.Handle %buf1_texture_structbuf, i32 1, i32 8)",
  965. "bufferLoad.f32(i32 70, %dx.types.Handle %buf1_texture_structbuf, i32 1, i32 undef)",
  966. "structured buffer require 2 coordinates");
  967. }
  968. TEST_F(ValidationTest, StructBufStoreCoordinates) {
  969. RewriteAssemblyCheckMsg(
  970. L"..\\CodeGenHLSL\\struct_buf1.hlsl", "ps_6_0",
  971. "bufferStore.f32(i32 71, %dx.types.Handle %buf2_UAV_structbuf, i32 0, i32 0",
  972. "bufferStore.f32(i32 71, %dx.types.Handle %buf2_UAV_structbuf, i32 0, i32 undef",
  973. "structured buffer require 2 coordinates");
  974. }
  975. TEST_F(ValidationTest, TypedBufRetType) {
  976. RewriteAssemblyCheckMsg(
  977. L"..\\CodeGenHLSL\\sample5.hlsl", "ps_6_0",
  978. "%class.Texture2D = type { <4 x float>",
  979. "%class.Texture2D = type { <4 x double>",
  980. "elements of typed buffers and textures must fit in four 32-bit quantities");
  981. }
  982. TEST_F(ValidationTest, VsInputSemantic) {
  983. RewriteAssemblyCheckMsg(
  984. L"..\\CodeGenHLSL\\clip_planes.hlsl", "vs_6_0",
  985. "!\"POSITION\", i8 9, i8 0",
  986. "!\"SV_Target\", i8 9, i8 16",
  987. "Semantic 'SV_Target' is invalid as vs Input");
  988. }
  989. TEST_F(ValidationTest, VsOutputSemantic) {
  990. RewriteAssemblyCheckMsg(
  991. L"..\\CodeGenHLSL\\clip_planes.hlsl", "vs_6_0",
  992. "!\"NORMAL\", i8 9, i8 0",
  993. "!\"SV_Target\", i8 9, i8 16",
  994. "Semantic 'SV_Target' is invalid as vs Output");
  995. }
  996. TEST_F(ValidationTest, HsInputSemantic) {
  997. RewriteAssemblyCheckMsg(
  998. L"..\\CodeGenHLSL\\SimpleHs1.hlsl", "hs_6_0",
  999. "!\"TEXCOORD\", i8 9, i8 0",
  1000. "!\"VertexID\", i8 4, i8 1",
  1001. "Semantic 'VertexID' is invalid as hs Input");
  1002. }
  1003. TEST_F(ValidationTest, HsOutputSemantic) {
  1004. RewriteAssemblyCheckMsg(
  1005. L"..\\CodeGenHLSL\\SimpleHs1.hlsl", "hs_6_0",
  1006. "!\"TEXCOORD\", i8 9, i8 0",
  1007. "!\"VertexID\", i8 4, i8 1",
  1008. "Semantic 'VertexID' is invalid as hs Output");
  1009. }
  1010. TEST_F(ValidationTest, PatchConstSemantic) {
  1011. RewriteAssemblyCheckMsg(
  1012. L"..\\CodeGenHLSL\\SimpleHs1.hlsl", "hs_6_0",
  1013. "!\"SV_TessFactor\", i8 9, i8 25",
  1014. "!\"VertexID\", i8 4, i8 1",
  1015. "Semantic 'VertexID' is invalid as hs PatchConstant");
  1016. }
  1017. TEST_F(ValidationTest, DsInputSemantic) {
  1018. RewriteAssemblyCheckMsg(
  1019. L"..\\CodeGenHLSL\\SimpleDs1.hlsl", "ds_6_0",
  1020. "!\"TEXCOORD\", i8 9, i8 0",
  1021. "!\"VertexID\", i8 4, i8 1",
  1022. "Semantic 'VertexID' is invalid as ds Input");
  1023. }
  1024. TEST_F(ValidationTest, DsOutputSemantic) {
  1025. RewriteAssemblyCheckMsg(
  1026. L"..\\CodeGenHLSL\\SimpleDs1.hlsl", "ds_6_0",
  1027. "!\"TEXCOORD\", i8 9, i8 0",
  1028. "!\"VertexID\", i8 4, i8 1",
  1029. "Semantic 'VertexID' is invalid as ds Output");
  1030. }
  1031. TEST_F(ValidationTest, GsInputSemantic) {
  1032. RewriteAssemblyCheckMsg(
  1033. L"..\\CodeGenHLSL\\SimpleGs1.hlsl", "gs_6_0",
  1034. "!\"POSSIZE\", i8 9, i8 0",
  1035. "!\"VertexID\", i8 4, i8 1",
  1036. "Semantic 'VertexID' is invalid as gs Input");
  1037. }
  1038. TEST_F(ValidationTest, GsOutputSemantic) {
  1039. RewriteAssemblyCheckMsg(
  1040. L"..\\CodeGenHLSL\\SimpleGs1.hlsl", "gs_6_0",
  1041. "!\"TEXCOORD\", i8 9, i8 0",
  1042. "!\"VertexID\", i8 4, i8 1",
  1043. "Semantic 'VertexID' is invalid as gs Output");
  1044. }
  1045. TEST_F(ValidationTest, PsInputSemantic) {
  1046. RewriteAssemblyCheckMsg(
  1047. L"..\\CodeGenHLSL\\abs2.hlsl", "ps_6_0",
  1048. "!\"A\", i8 4, i8 0",
  1049. "!\"VertexID\", i8 4, i8 1",
  1050. "Semantic 'VertexID' is invalid as ps Input");
  1051. }
  1052. TEST_F(ValidationTest, PsOutputSemantic) {
  1053. RewriteAssemblyCheckMsg(
  1054. L"..\\CodeGenHLSL\\abs2.hlsl", "ps_6_0",
  1055. "!\"SV_Target\", i8 9, i8 16",
  1056. "!\"VertexID\", i8 4, i8 1",
  1057. "Semantic 'VertexID' is invalid as ps Output");
  1058. }
  1059. TEST_F(ValidationTest, ArrayOfSVTarget) {
  1060. RewriteAssemblyCheckMsg(
  1061. L"..\\CodeGenHLSL\\targetArray.hlsl", "ps_6_0",
  1062. "i32 6, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1",
  1063. "i32 6, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 2",
  1064. "Pixel shader output registers are not indexable.",
  1065. /*bRegex*/true);
  1066. }
  1067. TEST_F(ValidationTest, InfiniteLog) {
  1068. RewriteAssemblyCheckMsg(
  1069. L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
  1070. "op.unary.f32\\(i32 23, float %[0-9+]\\)",
  1071. "op.unary.f32(i32 23, float 0x7FF0000000000000)",
  1072. "No indefinite logarithm",
  1073. /*bRegex*/true);
  1074. }
  1075. TEST_F(ValidationTest, InfiniteAsin) {
  1076. RewriteAssemblyCheckMsg(
  1077. L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
  1078. "op.unary.f32(i32 16, float %1)",
  1079. "op.unary.f32(i32 16, float 0x7FF0000000000000)",
  1080. "No indefinite arcsine");
  1081. }
  1082. TEST_F(ValidationTest, InfiniteAcos) {
  1083. RewriteAssemblyCheckMsg(
  1084. L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
  1085. "op.unary.f32(i32 15, float %1)",
  1086. "op.unary.f32(i32 15, float 0x7FF0000000000000)",
  1087. "No indefinite arccosine");
  1088. }
  1089. TEST_F(ValidationTest, InfiniteDdxDdy) {
  1090. RewriteAssemblyCheckMsg(
  1091. L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
  1092. "op.unary.f32\\(i32 85, float %[0-9]+\\)",
  1093. "op.unary.f32(i32 85, float 0x7FF0000000000000)",
  1094. "No indefinite derivative calculation",
  1095. /*bRegex*/true);
  1096. }
  1097. TEST_F(ValidationTest, IDivByZero) {
  1098. RewriteAssemblyCheckMsg(
  1099. L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
  1100. "sdiv i32 %6, %7",
  1101. "sdiv i32 %6, 0",
  1102. "No signed integer division by zero");
  1103. }
  1104. TEST_F(ValidationTest, UDivByZero) {
  1105. RewriteAssemblyCheckMsg(
  1106. L"..\\CodeGenHLSL\\intrinsic_val_imm.hlsl", "ps_6_0",
  1107. "udiv i32 %3, %4",
  1108. "udiv i32 %3, 0",
  1109. "No unsigned integer division by zero");
  1110. }
  1111. TEST_F(ValidationTest, UnusedMetadata) {
  1112. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\loop2.hlsl", "ps_6_0",
  1113. ", !llvm.loop ",
  1114. ", !llvm.loop2 ",
  1115. "All metadata must be used by dxil");
  1116. }
  1117. TEST_F(ValidationTest, MemoryOutOfBound) {
  1118. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\targetArray.hlsl", "ps_6_0",
  1119. "getelementptr [4 x float], [4 x float]* %7, i32 0, i32 3",
  1120. "getelementptr [4 x float], [4 x float]* %7, i32 0, i32 10",
  1121. "Access to out-of-bounds memory is disallowed");
  1122. }
  1123. TEST_F(ValidationTest, AddrSpaceCast) {
  1124. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
  1125. "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
  1126. " store float %10, float* %11, align 4",
  1127. "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
  1128. " %X = addrspacecast float* %11 to float addrspace(1)* \n"
  1129. " store float %10, float addrspace(1)* %X, align 4",
  1130. "generic address space");
  1131. }
  1132. TEST_F(ValidationTest, PtrBitCast) {
  1133. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
  1134. "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
  1135. " store float %10, float* %11, align 4",
  1136. "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
  1137. " %X = bitcast float* %11 to double* \n"
  1138. " store float %10, float* %11, align 4",
  1139. "Pointer type bitcast must be have same size");
  1140. }
  1141. TEST_F(ValidationTest, MinPrecisionBitCast) {
  1142. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
  1143. "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
  1144. " store float %10, float* %11, align 4",
  1145. "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
  1146. " %X = bitcast float* %11 to [2 x half]* \n"
  1147. " store float %10, float* %11, align 4",
  1148. "Bitcast on minprecison types is not allowed");
  1149. }
  1150. TEST_F(ValidationTest, StructBitCast) {
  1151. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
  1152. "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
  1153. " store float %10, float* %11, align 4",
  1154. "%11 = getelementptr [4 x float], [4 x float]* %0, i32 0, i32 0\n"
  1155. " %X = bitcast float* %11 to %dx.types.Handle* \n"
  1156. " store float %10, float* %11, align 4",
  1157. "Bitcast on struct types is not allowed");
  1158. }
  1159. TEST_F(ValidationTest, MultiDimArray) {
  1160. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
  1161. "%0 = alloca [4 x float]",
  1162. "%0 = alloca [4 x float]\n"
  1163. " %md = alloca [2 x [4 x float]]",
  1164. "Only one dimension allowed for array type");
  1165. }
  1166. TEST_F(ValidationTest, NoFunctionParam) {
  1167. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\abs2.hlsl", "ps_6_0",
  1168. {"define void @main\\(\\)", "void \\(\\)\\* @main, !([0-9]+)\\}(.*)!\\1 = !\\{!([0-9]+)\\}", "void \\(\\)\\* @main"},
  1169. {"define void @main(<4 x i32> %mainArg)", "void (<4 x i32>)* @main, !\\1}\\2!\\1 = !{!\\3, !\\3}", "void (<4 x i32>)* @main"},
  1170. "with parameter is not permitted",
  1171. /*bRegex*/true);
  1172. }
  1173. TEST_F(ValidationTest, I8Type) {
  1174. RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\staticGlobals.hlsl", "ps_6_0",
  1175. "%([0-9]+) = alloca \\[4 x float\\]",
  1176. "%\\1 = alloca [4 x float]\n"
  1177. " %m8 = alloca i8",
  1178. "I8 can only used as immediate value for intrinsic",
  1179. /*bRegex*/true);
  1180. }
  1181. TEST_F(ValidationTest, EmptyStructInBuffer) {
  1182. TestCheck(L"..\\CodeGenHLSL\\EmptyStructInBuffer.hlsl");
  1183. }
  1184. TEST_F(ValidationTest, BigStructInBuffer) {
  1185. TestCheck(L"..\\CodeGenHLSL\\BigStructInBuffer.hlsl");
  1186. }
  1187. TEST_F(ValidationTest, AddUint64Odd) {
  1188. TestCheck(L"..\\CodeGenHLSL\\AddUint64Odd.hlsl");
  1189. }
  1190. TEST_F(ValidationTest, WhenWaveAffectsGradientThenFail) {
  1191. TestCheck(L"val-wave-failures-ps.hlsl");
  1192. }
  1193. TEST_F(ValidationTest, WhenMetaFlagsUsageThenFail) {
  1194. RewriteAssemblyCheckMsg(
  1195. "uint u; float4 main() : SV_Target { uint64_t n = u; n *= u; return (uint)(n >> 32); }", "ps_6_0",
  1196. "1048576", "0", // remove the int64 flag
  1197. "Flags must match usage");
  1198. }
  1199. TEST_F(ValidationTest, StorePatchControlNotInPatchConstantFunction) {
  1200. RewriteAssemblyCheckMsg(
  1201. "struct PSSceneIn \
  1202. { \
  1203. float4 pos : SV_Position; \
  1204. float2 tex : TEXCOORD0; \
  1205. float3 norm : NORMAL; \
  1206. }; \
  1207. \
  1208. struct HSPerVertexData \
  1209. { \
  1210. PSSceneIn v; \
  1211. }; \
  1212. struct HSPerPatchData \
  1213. { \
  1214. float edges[ 3 ] : SV_TessFactor; \
  1215. float inside : SV_InsideTessFactor; \
  1216. }; \
  1217. HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 3 > points, \
  1218. OutputPatch<HSPerVertexData, 3> outpoints) \
  1219. { \
  1220. HSPerPatchData d; \
  1221. \
  1222. d.edges[ 0 ] = points[0].tex.x + outpoints[0].v.tex.x; \
  1223. d.edges[ 1 ] = 1; \
  1224. d.edges[ 2 ] = 1; \
  1225. d.inside = 1; \
  1226. \
  1227. return d; \
  1228. }\
  1229. [domain(\"tri\")]\
  1230. [partitioning(\"fractional_odd\")]\
  1231. [outputtopology(\"triangle_cw\")]\
  1232. [patchconstantfunc(\"HSPerPatchFunc\")]\
  1233. [outputcontrolpoints(3)]\
  1234. HSPerVertexData main( const uint id : SV_OutputControlPointID,\
  1235. const InputPatch< PSSceneIn, 3 > points )\
  1236. {\
  1237. HSPerVertexData v;\
  1238. \
  1239. v.v = points[ id ];\
  1240. \
  1241. return v;\
  1242. }\
  1243. ",
  1244. "hs_6_0",
  1245. "dx.op.storeOutput.f32(i32 5",
  1246. "dx.op.storePatchConstant.f32(i32 108",
  1247. "opcode 'StorePatchConstant' should only used in 'PatchConstant function'");
  1248. }
  1249. TEST_F(ValidationTest, LoadOutputControlPointNotInPatchConstantFunction) {
  1250. RewriteAssemblyCheckMsg(
  1251. "struct PSSceneIn \
  1252. { \
  1253. float4 pos : SV_Position; \
  1254. float2 tex : TEXCOORD0; \
  1255. float3 norm : NORMAL; \
  1256. }; \
  1257. \
  1258. struct HSPerVertexData \
  1259. { \
  1260. PSSceneIn v; \
  1261. }; \
  1262. struct HSPerPatchData \
  1263. { \
  1264. float edges[ 3 ] : SV_TessFactor; \
  1265. float inside : SV_InsideTessFactor; \
  1266. }; \
  1267. HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 3 > points, \
  1268. OutputPatch<HSPerVertexData, 3> outpoints) \
  1269. { \
  1270. HSPerPatchData d; \
  1271. \
  1272. d.edges[ 0 ] = points[0].tex.x + outpoints[0].v.tex.x; \
  1273. d.edges[ 1 ] = 1; \
  1274. d.edges[ 2 ] = 1; \
  1275. d.inside = 1; \
  1276. \
  1277. return d; \
  1278. }\
  1279. [domain(\"tri\")]\
  1280. [partitioning(\"fractional_odd\")]\
  1281. [outputtopology(\"triangle_cw\")]\
  1282. [patchconstantfunc(\"HSPerPatchFunc\")]\
  1283. [outputcontrolpoints(3)]\
  1284. HSPerVertexData main( const uint id : SV_OutputControlPointID,\
  1285. const InputPatch< PSSceneIn, 3 > points )\
  1286. {\
  1287. HSPerVertexData v;\
  1288. \
  1289. v.v = points[ id ];\
  1290. \
  1291. return v;\
  1292. }\
  1293. ",
  1294. "hs_6_0",
  1295. "dx.op.loadInput.f32(i32 4",
  1296. "dx.op.loadOutputControlPoint.f32(i32 105",
  1297. "opcode 'LoadOutputControlPoint' should only used in 'PatchConstant function'");
  1298. }
  1299. TEST_F(ValidationTest, OutputControlPointIDInPatchConstantFunction) {
  1300. RewriteAssemblyCheckMsg(
  1301. "struct PSSceneIn \
  1302. { \
  1303. float4 pos : SV_Position; \
  1304. float2 tex : TEXCOORD0; \
  1305. float3 norm : NORMAL; \
  1306. }; \
  1307. \
  1308. struct HSPerVertexData \
  1309. { \
  1310. PSSceneIn v; \
  1311. }; \
  1312. struct HSPerPatchData \
  1313. { \
  1314. float edges[ 3 ] : SV_TessFactor; \
  1315. float inside : SV_InsideTessFactor; \
  1316. }; \
  1317. HSPerPatchData HSPerPatchFunc( const InputPatch< PSSceneIn, 3 > points, \
  1318. OutputPatch<HSPerVertexData, 3> outpoints) \
  1319. { \
  1320. HSPerPatchData d; \
  1321. \
  1322. d.edges[ 0 ] = points[0].tex.x + outpoints[0].v.tex.x; \
  1323. d.edges[ 1 ] = 1; \
  1324. d.edges[ 2 ] = 1; \
  1325. d.inside = 1; \
  1326. \
  1327. return d; \
  1328. }\
  1329. [domain(\"tri\")]\
  1330. [partitioning(\"fractional_odd\")]\
  1331. [outputtopology(\"triangle_cw\")]\
  1332. [patchconstantfunc(\"HSPerPatchFunc\")]\
  1333. [outputcontrolpoints(3)]\
  1334. HSPerVertexData main( const uint id : SV_OutputControlPointID,\
  1335. const InputPatch< PSSceneIn, 3 > points )\
  1336. {\
  1337. HSPerVertexData v;\
  1338. \
  1339. v.v = points[ id ];\
  1340. \
  1341. return v;\
  1342. }\
  1343. ",
  1344. "hs_6_0",
  1345. "ret void",
  1346. "call i32 @dx.op.outputControlPointID.i32(i32 109)\n ret void",
  1347. "opcode 'OutputControlPointID' should only used in 'hull function'");
  1348. }
  1349. TEST_F(ValidationTest, ClipCullMaxComponents) {
  1350. RewriteAssemblyCheckMsg(" \
  1351. struct VSOut { \
  1352. float3 clip0 : SV_ClipDistance; \
  1353. float3 clip1 : SV_ClipDistance1; \
  1354. float cull0 : SV_CullDistance; \
  1355. float cull1 : SV_CullDistance1; \
  1356. float cull2 : CullDistance2; \
  1357. }; \
  1358. VSOut main() { \
  1359. VSOut Out; \
  1360. Out.clip0 = 0.1; \
  1361. Out.clip1 = 0.2; \
  1362. Out.cull0 = 0.3; \
  1363. Out.cull1 = 0.4; \
  1364. Out.cull2 = 0.5; \
  1365. return Out; \
  1366. } \
  1367. ",
  1368. "vs_6_0",
  1369. "!{i32 4, !\"CullDistance\", i8 9, i8 0,",
  1370. "!{i32 4, !\"SV_CullDistance\", i8 9, i8 7,",
  1371. "ClipDistance and CullDistance use more than the maximum of 8 components combined.");
  1372. }
  1373. TEST_F(ValidationTest, ClipCullMaxRows) {
  1374. RewriteAssemblyCheckMsg(" \
  1375. struct VSOut { \
  1376. float3 clip0 : SV_ClipDistance; \
  1377. float3 clip1 : SV_ClipDistance1; \
  1378. float2 cull0 : CullDistance; \
  1379. }; \
  1380. VSOut main() { \
  1381. VSOut Out; \
  1382. Out.clip0 = 0.1; \
  1383. Out.clip1 = 0.2; \
  1384. Out.cull0 = 0.3; \
  1385. return Out; \
  1386. } \
  1387. ",
  1388. "vs_6_0",
  1389. "!{i32 2, !\"CullDistance\", i8 9, i8 0,",
  1390. "!{i32 2, !\"SV_CullDistance\", i8 9, i8 7,",
  1391. "ClipDistance and CullDistance occupy more than the maximum of 2 rows combined.");
  1392. }
  1393. TEST_F(ValidationTest, DuplicateSysValue) {
  1394. RewriteAssemblyCheckMsg(" \
  1395. float4 main(uint vid : SV_VertexID, uint iid : SV_InstanceID) : SV_Position { \
  1396. return (float4)0 + vid + iid; \
  1397. } \
  1398. ",
  1399. "vs_6_0",
  1400. "!{i32 1, !\"SV_InstanceID\", i8 5, i8 2,",
  1401. "!{i32 1, !\"\", i8 5, i8 1,",
  1402. //"System value SV_VertexID appears more than once in the same signature.");
  1403. "Semantic 'SV_VertexID' overlap at 0");
  1404. }
  1405. TEST_F(ValidationTest, SemTargetMax) {
  1406. RewriteAssemblyCheckMsg(" \
  1407. float4 main(float4 col : COLOR) : SV_Target7 { return col; } \
  1408. ",
  1409. "ps_6_0",
  1410. "!{i32 0, !\"SV_Target\", i8 9, i8 16, ![0-9]+, i8 0, i32 1, i8 4, i32 7, i8 0, null}",
  1411. "!{i32 0, !\"SV_Target\", i8 9, i8 16, !101, i8 0, i32 1, i8 4, i32 8, i8 0, null}\n!101 = !{i32 8}",
  1412. "SV_Target semantic index exceeds maximum \\(7\\)",
  1413. /*bRegex*/true);
  1414. }
  1415. TEST_F(ValidationTest, SemTargetIndexMatchesRow) {
  1416. RewriteAssemblyCheckMsg(" \
  1417. float4 main(float4 col : COLOR) : SV_Target7 { return col; } \
  1418. ",
  1419. "ps_6_0",
  1420. "!{i32 0, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 4, i32 7, i8 0, null}",
  1421. "!{i32 0, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 1, i8 4, i32 6, i8 0, null}",
  1422. "SV_Target semantic index must match packed row location",
  1423. /*bRegex*/true);
  1424. }
  1425. TEST_F(ValidationTest, SemTargetCol0) {
  1426. RewriteAssemblyCheckMsg(" \
  1427. float3 main(float4 col : COLOR) : SV_Target7 { return col.xyz; } \
  1428. ",
  1429. "ps_6_0",
  1430. "!{i32 0, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 3, i32 7, i8 0, null}",
  1431. "!{i32 0, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 1, i8 3, i32 7, i8 1, null}",
  1432. "SV_Target packed location must start at column 0",
  1433. /*bRegex*/true);
  1434. }
  1435. TEST_F(ValidationTest, SemIndexMax) {
  1436. RewriteAssemblyCheckMsg(" \
  1437. float4 main(uint vid : SV_VertexID, uint iid : SV_InstanceID) : SV_Position { \
  1438. return (float4)0 + vid + iid; \
  1439. } \
  1440. ",
  1441. "vs_6_0",
  1442. "!{i32 0, !\"SV_VertexID\", i8 5, i8 1, ![0-9]+, i8 0, i32 1, i8 1, i32 0, i8 0, null}",
  1443. "!{i32 0, !\"SV_VertexID\", i8 5, i8 1, !101, i8 0, i32 1, i8 1, i32 0, i8 0, null}\n!101 = !{i32 1}",
  1444. "SV_VertexID semantic index exceeds maximum \\(0\\)",
  1445. /*bRegex*/true);
  1446. }
  1447. TEST_F(ValidationTest, SemTessFactorIndexMax) {
  1448. RewriteAssemblyCheckMsg(" \
  1449. struct Vertex { \
  1450. float4 pos : SV_Position; \
  1451. }; \
  1452. struct PatchConstant { \
  1453. float edges[ 3 ] : SV_TessFactor; \
  1454. float inside : SV_InsideTessFactor; \
  1455. }; \
  1456. PatchConstant PCMain( InputPatch<Vertex, 3> patch) { \
  1457. PatchConstant PC; \
  1458. PC.edges = (float[3])patch[1].pos.xyz; \
  1459. PC.inside = patch[1].pos.w; \
  1460. return PC; \
  1461. } \
  1462. [domain(\"tri\")] \
  1463. [partitioning(\"fractional_odd\")] \
  1464. [outputtopology(\"triangle_cw\")] \
  1465. [patchconstantfunc(\"PCMain\")] \
  1466. [outputcontrolpoints(3)] \
  1467. Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) { \
  1468. Vertex Out = patch[id]; \
  1469. Out.pos.w += 0.25; \
  1470. return Out; \
  1471. } \
  1472. ",
  1473. "hs_6_0",
  1474. "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, ![0-9]+, i8 0, i32 3, i8 1, i32 0, i8 3, null}",
  1475. "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !101, i8 0, i32 2, i8 1, i32 0, i8 3, null}\n!101 = !{i32 0, i32 1}",
  1476. "TessFactor rows, columns \\(2, 1\\) invalid for domain Tri. Expected 3 rows and 1 column.",
  1477. /*bRegex*/true);
  1478. }
  1479. TEST_F(ValidationTest, SemInsideTessFactorIndexMax) {
  1480. RewriteAssemblyCheckMsg(" \
  1481. struct Vertex { \
  1482. float4 pos : SV_Position; \
  1483. }; \
  1484. struct PatchConstant { \
  1485. float edges[ 3 ] : SV_TessFactor; \
  1486. float inside : SV_InsideTessFactor; \
  1487. }; \
  1488. PatchConstant PCMain( InputPatch<Vertex, 3> patch) { \
  1489. PatchConstant PC; \
  1490. PC.edges = (float[3])patch[1].pos.xyz; \
  1491. PC.inside = patch[1].pos.w; \
  1492. return PC; \
  1493. } \
  1494. [domain(\"tri\")] \
  1495. [partitioning(\"fractional_odd\")] \
  1496. [outputtopology(\"triangle_cw\")] \
  1497. [patchconstantfunc(\"PCMain\")] \
  1498. [outputcontrolpoints(3)] \
  1499. Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) { \
  1500. Vertex Out = patch[id]; \
  1501. Out.pos.w += 0.25; \
  1502. return Out; \
  1503. } \
  1504. ",
  1505. "hs_6_0",
  1506. "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !([0-9]+), i8 0, i32 1, i8 1, i32 3, i8 0, null}",
  1507. "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !\\1, i8 0, i32 2, i8 1, i32 3, i8 0, null}",
  1508. "InsideTessFactor rows, columns \\(2, 1\\) invalid for domain Tri. Expected 1 rows and 1 column.",
  1509. /*bRegex*/true);
  1510. }
  1511. TEST_F(ValidationTest, SemShouldBeAllocated) {
  1512. RewriteAssemblyCheckMsg(" \
  1513. struct Vertex { \
  1514. float4 pos : SV_Position; \
  1515. }; \
  1516. struct PatchConstant { \
  1517. float edges[ 3 ] : SV_TessFactor; \
  1518. float inside : SV_InsideTessFactor; \
  1519. }; \
  1520. PatchConstant PCMain( InputPatch<Vertex, 3> patch) { \
  1521. PatchConstant PC; \
  1522. PC.edges = (float[3])patch[1].pos.xyz; \
  1523. PC.inside = patch[1].pos.w; \
  1524. return PC; \
  1525. } \
  1526. [domain(\"tri\")] \
  1527. [partitioning(\"fractional_odd\")] \
  1528. [outputtopology(\"triangle_cw\")] \
  1529. [patchconstantfunc(\"PCMain\")] \
  1530. [outputcontrolpoints(3)] \
  1531. Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) { \
  1532. Vertex Out = patch[id]; \
  1533. Out.pos.w += 0.25; \
  1534. return Out; \
  1535. } \
  1536. ",
  1537. "hs_6_0",
  1538. "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 3, null}",
  1539. "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !\\1, i8 0, i32 3, i8 1, i32 -1, i8 -1, null}",
  1540. "PatchConstant Semantic 'SV_TessFactor' should have a valid packing location",
  1541. /*bRegex*/true);
  1542. }
  1543. TEST_F(ValidationTest, SemShouldNotBeAllocated) {
  1544. RewriteAssemblyCheckMsg(" \
  1545. float4 main(float4 col : COLOR, out uint coverage : SV_Coverage) : SV_Target7 { coverage = 7; return col; } \
  1546. ",
  1547. "ps_6_0",
  1548. "!\"SV_Coverage\", i8 5, i8 14, !([0-9]+), i8 0, i32 1, i8 1, i32 -1, i8 -1, null}",
  1549. "!\"SV_Coverage\", i8 5, i8 14, !\\1, i8 0, i32 1, i8 1, i32 2, i8 0, null}",
  1550. "Output Semantic 'SV_Coverage' should have a packing location of -1",
  1551. /*bRegex*/true);
  1552. }
  1553. TEST_F(ValidationTest, SemComponentOrder) {
  1554. RewriteAssemblyCheckMsg(" \
  1555. void main( \
  1556. float2 f2in : f2in, \
  1557. float3 f3in : f3in, \
  1558. uint vid : SV_VertexID, \
  1559. uint iid : SV_InstanceID, \
  1560. out float4 pos : SV_Position, \
  1561. out float2 f2out : f2out, \
  1562. out float3 f3out : f3out, \
  1563. out float2 ClipDistance : SV_ClipDistance, \
  1564. out float CullDistance : SV_CullDistance) \
  1565. { \
  1566. pos = float4(f3in, f2in.x); \
  1567. ClipDistance = f2in.x; \
  1568. CullDistance = f2in.y; \
  1569. } \
  1570. ",
  1571. "vs_6_0",
  1572. "= !{i32 1, !\"f2out\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 2, i32 2, i8 0, null}\n"
  1573. "!([0-9]+) = !{i32 2, !\"f3out\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 3, i32 1, i8 0, null}\n"
  1574. "!([0-9]+) = !{i32 3, !\"SV_ClipDistance\", i8 9, i8 6, !([0-9]+), i8 2, i32 1, i8 2, i32 3, i8 0, null}\n"
  1575. "!([0-9]+) = !{i32 4, !\"SV_CullDistance\", i8 9, i8 7, !([0-9]+), i8 2, i32 1, i8 1, i32 3, i8 2, null}\n",
  1576. "= !{i32 1, !\"f2out\", i8 9, i8 0, !\\1, i8 2, i32 1, i8 2, i32 2, i8 2, null}\n"
  1577. "!\\2 = !{i32 2, !\"f3out\", i8 9, i8 0, !\\3, i8 2, i32 1, i8 3, i32 1, i8 1, null}\n"
  1578. "!\\4 = !{i32 3, !\"SV_ClipDistance\", i8 9, i8 6, !\\5, i8 2, i32 1, i8 2, i32 2, i8 0, null}\n"
  1579. "!\\6 = !{i32 4, !\"SV_CullDistance\", i8 9, i8 7, !\\7, i8 2, i32 1, i8 1, i32 1, i8 0, null}\n",
  1580. "signature element SV_ClipDistance at location \\(2,0\\) size \\(1,2\\) violates component ordering rule \\(arb < sv < sgv\\).\n"
  1581. "signature element SV_CullDistance at location \\(1,0\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).",
  1582. /*bRegex*/true);
  1583. }
  1584. TEST_F(ValidationTest, SemComponentOrder2) {
  1585. RewriteAssemblyCheckMsg(" \
  1586. float4 main( \
  1587. float4 col : Color, \
  1588. uint2 val : Value, \
  1589. uint pid : SV_PrimitiveID, \
  1590. bool ff : SV_IsFrontFace) : SV_Target \
  1591. { \
  1592. return col; \
  1593. } \
  1594. ",
  1595. "ps_6_0",
  1596. "= !{i32 1, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 2, i32 1, i8 0, null}\n"
  1597. "!([0-9]+) = !{i32 2, !\"SV_PrimitiveID\", i8 5, i8 10, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 2, null}\n"
  1598. "!([0-9]+) = !{i32 3, !\"SV_IsFrontFace\", i8 1, i8 13, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 3, null}\n",
  1599. "= !{i32 1, !\"Value\", i8 5, i8 0, !\\1, i8 1, i32 1, i8 2, i32 1, i8 2, null}\n"
  1600. "!\\2 = !{i32 2, !\"SV_PrimitiveID\", i8 5, i8 10, !\\3, i8 1, i32 1, i8 1, i32 1, i8 0, null}\n"
  1601. "!\\4 = !{i32 3, !\"SV_IsFrontFace\", i8 1, i8 13, !\\5, i8 1, i32 1, i8 1, i32 1, i8 1, null}\n",
  1602. "signature element SV_PrimitiveID at location \\(1,0\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).\n"
  1603. "signature element SV_IsFrontFace at location \\(1,1\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).",
  1604. /*bRegex*/true);
  1605. }
  1606. TEST_F(ValidationTest, SemComponentOrder3) {
  1607. RewriteAssemblyCheckMsg(" \
  1608. float4 main( \
  1609. float4 col : Color, \
  1610. uint val : Value, \
  1611. uint pid : SV_PrimitiveID, \
  1612. bool ff : SV_IsFrontFace, \
  1613. uint vpid : ViewPortArrayIndex) : SV_Target \
  1614. { \
  1615. return col; \
  1616. } \
  1617. ",
  1618. "ps_6_0",
  1619. "= !{i32 1, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 0, null}\n"
  1620. "!([0-9]+) = !{i32 2, !\"SV_PrimitiveID\", i8 5, i8 10, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 2, null}\n"
  1621. "!([0-9]+) = !{i32 3, !\"SV_IsFrontFace\", i8 1, i8 13, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 3, null}\n"
  1622. "!([0-9]+) = !{i32 4, !\"ViewPortArrayIndex\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 1, i32 1, i8 1, null}\n",
  1623. "= !{i32 1, !\"Value\", i8 5, i8 0, !\\1, i8 1, i32 1, i8 1, i32 1, i8 1, null}\n"
  1624. "!\\2 = !{i32 2, !\"SV_PrimitiveID\", i8 5, i8 10, !\\3, i8 1, i32 1, i8 1, i32 1, i8 0, null}\n"
  1625. "!\\4 = !{i32 3, !\"SV_IsFrontFace\", i8 1, i8 13, !\\5, i8 1, i32 1, i8 1, i32 1, i8 2, null}\n"
  1626. "!\\6 = !{i32 4, !\"ViewPortArrayIndex\", i8 5, i8 0, !\\7, i8 1, i32 1, i8 1, i32 1, i8 3, null}\n",
  1627. "signature element SV_PrimitiveID at location \\(1,0\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).\n"
  1628. "signature element ViewPortArrayIndex at location \\(1,3\\) size \\(1,1\\) violates component ordering rule \\(arb < sv < sgv\\).",
  1629. /*bRegex*/true);
  1630. }
  1631. TEST_F(ValidationTest, SemIndexConflictArbSV) {
  1632. RewriteAssemblyCheckMsg(" \
  1633. void main( \
  1634. float4 inpos : Position, \
  1635. uint iid : SV_InstanceID, \
  1636. out float4 pos : SV_Position, \
  1637. out uint id[2] : Array, \
  1638. out uint vpid : SV_ViewPortArrayIndex, \
  1639. out float2 ClipDistance : SV_ClipDistance, \
  1640. out float CullDistance : SV_CullDistance) \
  1641. { \
  1642. pos = inpos; \
  1643. ClipDistance = inpos.x; \
  1644. CullDistance = inpos.y; \
  1645. vpid = iid; \
  1646. id[0] = iid; \
  1647. id[1] = iid + 1; \
  1648. } \
  1649. ",
  1650. "vs_6_0",
  1651. "!{i32 2, !\"SV_ViewportArrayIndex\", i8 5, i8 5, !([0-9]+), i8 1, i32 1, i8 1, i32 3, i8 0, null}",
  1652. "!{i32 2, !\"SV_ViewportArrayIndex\", i8 5, i8 5, !\\1, i8 1, i32 1, i8 1, i32 1, i8 3, null}",
  1653. "signature element SV_ViewportArrayIndex at location \\(1,3\\) size \\(1,1\\) has an indexing conflict with another signature element packed into the same row.",
  1654. /*bRegex*/true);
  1655. }
  1656. TEST_F(ValidationTest, SemIndexConflictTessfactors) {
  1657. RewriteAssemblyCheckMsg(" \
  1658. struct Vertex { \
  1659. float4 pos : SV_Position; \
  1660. }; \
  1661. struct PatchConstant { \
  1662. float edges[ 4 ] : SV_TessFactor; \
  1663. float inside[ 2 ] : SV_InsideTessFactor; \
  1664. }; \
  1665. PatchConstant PCMain( InputPatch<Vertex, 4> patch) { \
  1666. PatchConstant PC; \
  1667. PC.edges = (float[4])patch[1].pos; \
  1668. PC.inside = (float[2])patch[1].pos.xy; \
  1669. return PC; \
  1670. } \
  1671. [domain(\"quad\")] \
  1672. [partitioning(\"fractional_odd\")] \
  1673. [outputtopology(\"triangle_cw\")] \
  1674. [patchconstantfunc(\"PCMain\")] \
  1675. [outputcontrolpoints(4)] \
  1676. Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) { \
  1677. Vertex Out = patch[id]; \
  1678. Out.pos.w += 0.25; \
  1679. return Out; \
  1680. } \
  1681. ",
  1682. "hs_6_0",
  1683. //!{i32 0, !"SV_TessFactor", i8 9, i8 25, !23, i8 0, i32 4, i8 1, i32 0, i8 3, null}
  1684. "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !([0-9]+), i8 0, i32 2, i8 1, i32 4, i8 3, null}",
  1685. "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !\\1, i8 0, i32 2, i8 1, i32 0, i8 2, null}",
  1686. "signature element SV_InsideTessFactor at location \\(0,2\\) size \\(2,1\\) has an indexing conflict with another signature element packed into the same row.",
  1687. /*bRegex*/true);
  1688. }
  1689. TEST_F(ValidationTest, SemIndexConflictTessfactors2) {
  1690. RewriteAssemblyCheckMsg(" \
  1691. struct Vertex { \
  1692. float4 pos : SV_Position; \
  1693. }; \
  1694. struct PatchConstant { \
  1695. float edges[ 4 ] : SV_TessFactor; \
  1696. float inside[ 2 ] : SV_InsideTessFactor; \
  1697. float arb [ 3 ] : Arb; \
  1698. }; \
  1699. PatchConstant PCMain( InputPatch<Vertex, 4> patch) { \
  1700. PatchConstant PC; \
  1701. PC.edges = (float[4])patch[1].pos; \
  1702. PC.inside = (float[2])patch[1].pos.xy; \
  1703. PC.arb[0] = 1; PC.arb[1] = 2; PC.arb[2] = 3; \
  1704. return PC; \
  1705. } \
  1706. [domain(\"quad\")] \
  1707. [partitioning(\"fractional_odd\")] \
  1708. [outputtopology(\"triangle_cw\")] \
  1709. [patchconstantfunc(\"PCMain\")] \
  1710. [outputcontrolpoints(4)] \
  1711. Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) { \
  1712. Vertex Out = patch[id]; \
  1713. Out.pos.w += 0.25; \
  1714. return Out; \
  1715. } \
  1716. ",
  1717. "hs_6_0",
  1718. "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
  1719. "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 2, i8 0, null}",
  1720. "signature element Arb at location \\(2,0\\) size \\(3,1\\) has an indexing conflict with another signature element packed into the same row.",
  1721. /*bRegex*/true);
  1722. }
  1723. TEST_F(ValidationTest, SemRowOutOfRange) {
  1724. RewriteAssemblyCheckMsg(" \
  1725. struct Vertex { \
  1726. float4 pos : SV_Position; \
  1727. }; \
  1728. struct PatchConstant { \
  1729. float edges[ 4 ] : SV_TessFactor; \
  1730. float inside[ 2 ] : SV_InsideTessFactor; \
  1731. float arb [ 3 ] : Arb; \
  1732. }; \
  1733. PatchConstant PCMain( InputPatch<Vertex, 4> patch) { \
  1734. PatchConstant PC; \
  1735. PC.edges = (float[4])patch[1].pos; \
  1736. PC.inside = (float[2])patch[1].pos.xy; \
  1737. PC.arb[0] = 1; PC.arb[1] = 2; PC.arb[2] = 3; \
  1738. return PC; \
  1739. } \
  1740. [domain(\"quad\")] \
  1741. [partitioning(\"fractional_odd\")] \
  1742. [outputtopology(\"triangle_cw\")] \
  1743. [patchconstantfunc(\"PCMain\")] \
  1744. [outputcontrolpoints(4)] \
  1745. Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) { \
  1746. Vertex Out = patch[id]; \
  1747. Out.pos.w += 0.25; \
  1748. return Out; \
  1749. } \
  1750. ",
  1751. "hs_6_0",
  1752. "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
  1753. "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 31, i8 0, null}",
  1754. "signature element Arb at location \\(31,0\\) size \\(3,1\\) is out of range.",
  1755. /*bRegex*/true);
  1756. }
  1757. TEST_F(ValidationTest, SemPackOverlap) {
  1758. RewriteAssemblyCheckMsg(" \
  1759. struct Vertex { \
  1760. float4 pos : SV_Position; \
  1761. }; \
  1762. struct PatchConstant { \
  1763. float edges[ 4 ] : SV_TessFactor; \
  1764. float inside[ 2 ] : SV_InsideTessFactor; \
  1765. float arb [ 3 ] : Arb; \
  1766. }; \
  1767. PatchConstant PCMain( InputPatch<Vertex, 4> patch) { \
  1768. PatchConstant PC; \
  1769. PC.edges = (float[4])patch[1].pos; \
  1770. PC.inside = (float[2])patch[1].pos.xy; \
  1771. PC.arb[0] = 1; PC.arb[1] = 2; PC.arb[2] = 3; \
  1772. return PC; \
  1773. } \
  1774. [domain(\"quad\")] \
  1775. [partitioning(\"fractional_odd\")] \
  1776. [outputtopology(\"triangle_cw\")] \
  1777. [patchconstantfunc(\"PCMain\")] \
  1778. [outputcontrolpoints(4)] \
  1779. Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) { \
  1780. Vertex Out = patch[id]; \
  1781. Out.pos.w += 0.25; \
  1782. return Out; \
  1783. } \
  1784. ",
  1785. "hs_6_0",
  1786. "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
  1787. "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 1, i8 3, null}",
  1788. "signature element Arb at location \\(1,3\\) size \\(3,1\\) overlaps another signature element.",
  1789. /*bRegex*/true);
  1790. }
  1791. TEST_F(ValidationTest, SemPackOverlap2) {
  1792. RewriteAssemblyCheckMsg(" \
  1793. void main( \
  1794. float4 inpos : Position, \
  1795. uint iid : SV_InstanceID, \
  1796. out float4 pos : SV_Position, \
  1797. out uint id[2] : Array, \
  1798. out uint3 value : Value, \
  1799. out float2 ClipDistance : SV_ClipDistance, \
  1800. out float CullDistance : SV_CullDistance) \
  1801. { \
  1802. pos = inpos; \
  1803. ClipDistance = inpos.x; \
  1804. CullDistance = inpos.y; \
  1805. value = iid; \
  1806. id[0] = iid; \
  1807. id[1] = iid + 1; \
  1808. } \
  1809. ",
  1810. "vs_6_0",
  1811. {"!{i32 1, !\"Array\", i8 5, i8 0, !([0-9]+), i8 1, i32 2, i8 1, i32 1, i8 0, null}(.*)"
  1812. "!\\1 = !{i32 0, i32 1}\n",
  1813. "= !{i32 2, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 3, i32 1, i8 1, null}"},
  1814. {"!{i32 1, !\"Array\", i8 5, i8 0, !\\1, i8 1, i32 2, i8 1, i32 1, i8 1, null}\\2"
  1815. "!\\1 = !{i32 0, i32 1}\n",
  1816. "= !{i32 2, !\"Value\", i8 5, i8 0, !\\1, i8 1, i32 1, i8 3, i32 2, i8 0, null}"},
  1817. "signature element Value at location \\(2,0\\) size \\(1,3\\) overlaps another signature element.",
  1818. /*bRegex*/true);
  1819. }
  1820. TEST_F(ValidationTest, SemMultiDepth) {
  1821. RewriteAssemblyCheckMsg(" \
  1822. float4 main(float4 f4 : Input, out float d0 : SV_Depth, out float d1 : SV_Target) : SV_Target1 \
  1823. { d0 = f4.z; d1 = f4.w; return f4; } \
  1824. ",
  1825. "ps_6_0",
  1826. {"!{i32 1, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 1, i32 0, i8 0, null}"},
  1827. {"!{i32 1, !\"SV_DepthGreaterEqual\", i8 9, i8 19, !\\1, i8 0, i32 1, i8 1, i32 -1, i8 -1, null}"},
  1828. "Pixel Shader only allows one type of depth semantic to be declared",
  1829. /*bRegex*/true);
  1830. }
  1831. // TODO: reject non-zero padding