DxilModuleTest.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // Copyright (C) Microsoft Corporation. All rights reserved. //
  4. // DxilModuleTest.cpp //
  5. // //
  6. // Provides unit tests for DxilModule. //
  7. // //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "CompilationResult.h"
  10. #include "HlslTestUtils.h"
  11. #include "DxcTestUtils.h"
  12. #include "dxc/Support/microcom.h"
  13. #include "dxc/dxcapi.internal.h"
  14. #include "dxc/HLSL/HLOperationLowerExtension.h"
  15. #include "dxc/HlslIntrinsicOp.h"
  16. #include "dxc/DXIL/DxilOperations.h"
  17. #include "dxc/DXIL/DxilInstructions.h"
  18. #include "dxc/DxilContainer/DxilContainer.h"
  19. #include "dxc/DXIL/DxilModule.h"
  20. #include "llvm/Support/Regex.h"
  21. #include "llvm/Support/MSFileSystem.h"
  22. #include "llvm/Support/FileSystem.h"
  23. #include "llvm/Support/MemoryBuffer.h"
  24. #include "llvm/Support/ErrorOr.h"
  25. #include "llvm/Bitcode/ReaderWriter.h"
  26. #include "llvm/IR/LLVMContext.h"
  27. #include "llvm/IR/InstIterator.h"
  28. using namespace hlsl;
  29. using namespace llvm;
  30. ///////////////////////////////////////////////////////////////////////////////
  31. // DxilModule unit tests.
  32. #ifdef _WIN32
  33. class DxilModuleTest {
  34. #else
  35. class DxilModuleTest : public ::testing::Test {
  36. #endif
  37. public:
  38. BEGIN_TEST_CLASS(DxilModuleTest)
  39. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  40. TEST_METHOD_PROPERTY(L"Priority", L"0")
  41. END_TEST_CLASS()
  42. TEST_CLASS_SETUP(InitSupport);
  43. dxc::DxcDllSupport m_dllSupport;
  44. // Basic loading tests.
  45. TEST_METHOD(LoadDxilModule_1_0)
  46. TEST_METHOD(LoadDxilModule_1_1)
  47. TEST_METHOD(LoadDxilModule_1_2)
  48. // Precise query tests.
  49. TEST_METHOD(Precise1)
  50. TEST_METHOD(Precise2)
  51. TEST_METHOD(Precise3)
  52. TEST_METHOD(Precise4)
  53. TEST_METHOD(Precise5)
  54. TEST_METHOD(Precise6)
  55. TEST_METHOD(Precise7)
  56. TEST_METHOD(CSGetNumThreads)
  57. TEST_METHOD(MSGetNumThreads)
  58. TEST_METHOD(ASGetNumThreads)
  59. };
  60. bool DxilModuleTest::InitSupport() {
  61. if (!m_dllSupport.IsEnabled()) {
  62. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  63. }
  64. return true;
  65. }
  66. ///////////////////////////////////////////////////////////////////////////////
  67. // Compilation and dxil module loading support.
  68. namespace {
  69. class Compiler {
  70. public:
  71. Compiler(dxc::DxcDllSupport &dll)
  72. : m_dllSupport(dll)
  73. , m_msf(CreateMSFileSystem())
  74. , m_pts(m_msf.get())
  75. {
  76. m_ver.Initialize(m_dllSupport);
  77. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  78. }
  79. bool SkipDxil_Test(unsigned major, unsigned minor) {
  80. return m_ver.SkipDxilVersion(major, minor);
  81. }
  82. IDxcOperationResult *Compile(const char *program, LPCWSTR shaderModel = L"ps_6_0") {
  83. return Compile(program, shaderModel, {}, {});
  84. }
  85. IDxcOperationResult *Compile(const char *program, LPCWSTR shaderModel, const std::vector<LPCWSTR> &arguments, const std::vector<DxcDefine> defs ) {
  86. Utf8ToBlob(m_dllSupport, program, &pCodeBlob);
  87. VERIFY_SUCCEEDED(pCompiler->Compile(pCodeBlob, L"hlsl.hlsl", L"main",
  88. shaderModel,
  89. const_cast<LPCWSTR *>(arguments.data()), arguments.size(),
  90. defs.data(), defs.size(),
  91. nullptr, &pCompileResult));
  92. return pCompileResult;
  93. }
  94. std::string Disassemble() {
  95. CComPtr<IDxcBlob> pBlob;
  96. CheckOperationSucceeded(pCompileResult, &pBlob);
  97. return DisassembleProgram(m_dllSupport, pBlob);
  98. }
  99. DxilModule &GetDxilModule() {
  100. // Make sure we compiled successfully.
  101. CComPtr<IDxcBlob> pBlob;
  102. CheckOperationSucceeded(pCompileResult, &pBlob);
  103. // Verify we have a valid dxil container.
  104. const DxilContainerHeader *pContainer =
  105. IsDxilContainerLike(pBlob->GetBufferPointer(), pBlob->GetBufferSize());
  106. VERIFY_IS_NOT_NULL(pContainer);
  107. VERIFY_IS_TRUE(IsValidDxilContainer(pContainer, pBlob->GetBufferSize()));
  108. // Get Dxil part from container.
  109. DxilPartIterator it = std::find_if(begin(pContainer), end(pContainer), DxilPartIsType(DFCC_DXIL));
  110. VERIFY_IS_FALSE(it == end(pContainer));
  111. const DxilProgramHeader *pProgramHeader =
  112. reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(*it));
  113. VERIFY_IS_TRUE(IsValidDxilProgramHeader(pProgramHeader, (*it)->PartSize));
  114. // Get a pointer to the llvm bitcode.
  115. const char *pIL;
  116. uint32_t pILLength;
  117. GetDxilProgramBitcode(pProgramHeader, &pIL, &pILLength);
  118. // Parse llvm bitcode into a module.
  119. std::unique_ptr<llvm::MemoryBuffer> pBitcodeBuf(
  120. llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(pIL, pILLength), "", false));
  121. llvm::ErrorOr<std::unique_ptr<llvm::Module>>
  122. pModule(llvm::parseBitcodeFile(pBitcodeBuf->getMemBufferRef(), m_llvmContext));
  123. if (std::error_code ec = pModule.getError()) {
  124. VERIFY_FAIL();
  125. }
  126. m_module = std::move(pModule.get());
  127. // Grab the dxil module;
  128. DxilModule *DM = DxilModule::TryGetDxilModule(m_module.get());
  129. VERIFY_IS_NOT_NULL(DM);
  130. return *DM;
  131. }
  132. private:
  133. static ::llvm::sys::fs::MSFileSystem *CreateMSFileSystem() {
  134. ::llvm::sys::fs::MSFileSystem *msfPtr;
  135. VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
  136. return msfPtr;
  137. }
  138. dxc::DxcDllSupport &m_dllSupport;
  139. VersionSupportInfo m_ver;
  140. CComPtr<IDxcCompiler> pCompiler;
  141. CComPtr<IDxcBlobEncoding> pCodeBlob;
  142. CComPtr<IDxcOperationResult> pCompileResult;
  143. llvm::LLVMContext m_llvmContext;
  144. std::unique_ptr<llvm::Module> m_module;
  145. std::unique_ptr<::llvm::sys::fs::MSFileSystem> m_msf;
  146. ::llvm::sys::fs::AutoPerThreadSystem m_pts;
  147. };
  148. }
  149. ///////////////////////////////////////////////////////////////////////////////
  150. // Unit Test Implementation
  151. TEST_F(DxilModuleTest, LoadDxilModule_1_0) {
  152. Compiler c(m_dllSupport);
  153. c.Compile(
  154. "float4 main() : SV_Target {\n"
  155. " return 0;\n"
  156. "}\n"
  157. ,
  158. L"ps_6_0"
  159. );
  160. // Basic sanity check on dxil version in dxil module.
  161. DxilModule &DM = c.GetDxilModule();
  162. unsigned vMajor, vMinor;
  163. DM.GetDxilVersion(vMajor, vMinor);
  164. VERIFY_IS_TRUE(vMajor == 1);
  165. VERIFY_IS_TRUE(vMinor == 0);
  166. }
  167. TEST_F(DxilModuleTest, LoadDxilModule_1_1) {
  168. Compiler c(m_dllSupport);
  169. if (c.SkipDxil_Test(1,1)) return;
  170. c.Compile(
  171. "float4 main() : SV_Target {\n"
  172. " return 0;\n"
  173. "}\n"
  174. ,
  175. L"ps_6_1"
  176. );
  177. // Basic sanity check on dxil version in dxil module.
  178. DxilModule &DM = c.GetDxilModule();
  179. unsigned vMajor, vMinor;
  180. DM.GetDxilVersion(vMajor, vMinor);
  181. VERIFY_IS_TRUE(vMajor == 1);
  182. VERIFY_IS_TRUE(vMinor == 1);
  183. }
  184. TEST_F(DxilModuleTest, LoadDxilModule_1_2) {
  185. Compiler c(m_dllSupport);
  186. if (c.SkipDxil_Test(1,2)) return;
  187. c.Compile(
  188. "float4 main() : SV_Target {\n"
  189. " return 0;\n"
  190. "}\n"
  191. ,
  192. L"ps_6_2"
  193. );
  194. // Basic sanity check on dxil version in dxil module.
  195. DxilModule &DM = c.GetDxilModule();
  196. unsigned vMajor, vMinor;
  197. DM.GetDxilVersion(vMajor, vMinor);
  198. VERIFY_IS_TRUE(vMajor == 1);
  199. VERIFY_IS_TRUE(vMinor == 2);
  200. }
  201. TEST_F(DxilModuleTest, Precise1) {
  202. Compiler c(m_dllSupport);
  203. c.Compile(
  204. "precise float main(float x : X, float y : Y) : SV_Target {\n"
  205. " return sqrt(x) + y;\n"
  206. "}\n"
  207. );
  208. // Make sure sqrt and add are marked precise.
  209. DxilModule &DM = c.GetDxilModule();
  210. Function *F = DM.GetEntryFunction();
  211. int numChecks = 0;
  212. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
  213. Instruction *Inst = &*I;
  214. if (DxilInst_Sqrt(Inst)) {
  215. numChecks++;
  216. VERIFY_IS_TRUE(DM.IsPrecise(Inst));
  217. }
  218. else if (LlvmInst_FAdd(Inst)) {
  219. numChecks++;
  220. VERIFY_IS_TRUE(DM.IsPrecise(Inst));
  221. }
  222. }
  223. VERIFY_ARE_EQUAL(numChecks, 2);
  224. }
  225. TEST_F(DxilModuleTest, Precise2) {
  226. Compiler c(m_dllSupport);
  227. c.Compile(
  228. "float main(float x : X, float y : Y) : SV_Target {\n"
  229. " return sqrt(x) + y;\n"
  230. "}\n"
  231. );
  232. // Make sure sqrt and add are not marked precise.
  233. DxilModule &DM = c.GetDxilModule();
  234. Function *F = DM.GetEntryFunction();
  235. int numChecks = 0;
  236. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
  237. Instruction *Inst = &*I;
  238. if (DxilInst_Sqrt(Inst)) {
  239. numChecks++;
  240. VERIFY_IS_FALSE(DM.IsPrecise(Inst));
  241. }
  242. else if (LlvmInst_FAdd(Inst)) {
  243. numChecks++;
  244. VERIFY_IS_FALSE(DM.IsPrecise(Inst));
  245. }
  246. }
  247. VERIFY_ARE_EQUAL(numChecks, 2);
  248. }
  249. TEST_F(DxilModuleTest, Precise3) {
  250. // TODO: Enable this test when precise metadata is inserted for Gis.
  251. if (const bool GisIsBroken = true) return;
  252. Compiler c(m_dllSupport);
  253. c.Compile(
  254. "float main(float x : X, float y : Y) : SV_Target {\n"
  255. " return sqrt(x) + y;\n"
  256. "}\n",
  257. L"ps_6_0",
  258. { L"/Gis" }, {}
  259. );
  260. // Make sure sqrt and add are marked precise.
  261. DxilModule &DM = c.GetDxilModule();
  262. Function *F = DM.GetEntryFunction();
  263. int numChecks = 0;
  264. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
  265. Instruction *Inst = &*I;
  266. if (DxilInst_Sqrt(Inst)) {
  267. numChecks++;
  268. VERIFY_IS_TRUE(DM.IsPrecise(Inst));
  269. }
  270. else if (LlvmInst_FAdd(Inst)) {
  271. numChecks++;
  272. VERIFY_IS_TRUE(DM.IsPrecise(Inst));
  273. }
  274. }
  275. VERIFY_ARE_EQUAL(numChecks, 2);
  276. }
  277. TEST_F(DxilModuleTest, Precise4) {
  278. Compiler c(m_dllSupport);
  279. c.Compile(
  280. "float main(float x : X, float y : Y) : SV_Target {\n"
  281. " precise float sx = 1 / sqrt(x);\n"
  282. " return sx + y;\n"
  283. "}\n"
  284. );
  285. // Make sure sqrt and div are marked precise, and add is not.
  286. DxilModule &DM = c.GetDxilModule();
  287. Function *F = DM.GetEntryFunction();
  288. int numChecks = 0;
  289. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
  290. Instruction *Inst = &*I;
  291. if (DxilInst_Sqrt(Inst)) {
  292. numChecks++;
  293. VERIFY_IS_TRUE(DM.IsPrecise(Inst));
  294. }
  295. else if (LlvmInst_FDiv(Inst)) {
  296. numChecks++;
  297. VERIFY_IS_TRUE(DM.IsPrecise(Inst));
  298. }
  299. else if (LlvmInst_FAdd(Inst)) {
  300. numChecks++;
  301. VERIFY_IS_FALSE(DM.IsPrecise(Inst));
  302. }
  303. }
  304. VERIFY_ARE_EQUAL(numChecks, 3);
  305. }
  306. TEST_F(DxilModuleTest, Precise5) {
  307. Compiler c(m_dllSupport);
  308. c.Compile(
  309. "float C[10];\n"
  310. "float main(float x : X, float y : Y, int i : I) : SV_Target {\n"
  311. " float A[2];\n"
  312. " A[0] = x;\n"
  313. " A[1] = y;\n"
  314. " return A[i] + C[i];\n"
  315. "}\n"
  316. );
  317. // Make sure load and extract value are not reported as precise.
  318. DxilModule &DM = c.GetDxilModule();
  319. Function *F = DM.GetEntryFunction();
  320. int numChecks = 0;
  321. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
  322. Instruction *Inst = &*I;
  323. if (LlvmInst_ExtractValue(Inst)) {
  324. numChecks++;
  325. VERIFY_IS_FALSE(DM.IsPrecise(Inst));
  326. }
  327. else if (LlvmInst_Load(Inst)) {
  328. numChecks++;
  329. VERIFY_IS_FALSE(DM.IsPrecise(Inst));
  330. }
  331. else if (LlvmInst_FAdd(Inst)) {
  332. numChecks++;
  333. VERIFY_IS_FALSE(DM.IsPrecise(Inst));
  334. }
  335. }
  336. VERIFY_ARE_EQUAL(numChecks, 3);
  337. }
  338. TEST_F(DxilModuleTest, Precise6) {
  339. Compiler c(m_dllSupport);
  340. c.Compile(
  341. "precise float2 main(float2 x : A, float2 y : B) : SV_Target {\n"
  342. " return sqrt(x * y);\n"
  343. "}\n"
  344. );
  345. // Make sure sqrt and mul are marked precise.
  346. DxilModule &DM = c.GetDxilModule();
  347. Function *F = DM.GetEntryFunction();
  348. int numChecks = 0;
  349. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
  350. Instruction *Inst = &*I;
  351. if (DxilInst_Sqrt(Inst)) {
  352. numChecks++;
  353. VERIFY_IS_TRUE(DM.IsPrecise(Inst));
  354. }
  355. else if (LlvmInst_FMul(Inst)) {
  356. numChecks++;
  357. VERIFY_IS_TRUE(DM.IsPrecise(Inst));
  358. }
  359. }
  360. VERIFY_ARE_EQUAL(numChecks, 4);
  361. }
  362. TEST_F(DxilModuleTest, Precise7) {
  363. Compiler c(m_dllSupport);
  364. c.Compile(
  365. "float2 main(float2 x : A, float2 y : B) : SV_Target {\n"
  366. " return sqrt(x * y);\n"
  367. "}\n"
  368. );
  369. // Make sure sqrt and mul are not marked precise.
  370. DxilModule &DM = c.GetDxilModule();
  371. Function *F = DM.GetEntryFunction();
  372. int numChecks = 0;
  373. for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
  374. Instruction *Inst = &*I;
  375. if (DxilInst_Sqrt(Inst)) {
  376. numChecks++;
  377. VERIFY_IS_FALSE(DM.IsPrecise(Inst));
  378. }
  379. else if (LlvmInst_FMul(Inst)) {
  380. numChecks++;
  381. VERIFY_IS_FALSE(DM.IsPrecise(Inst));
  382. }
  383. }
  384. VERIFY_ARE_EQUAL(numChecks, 4);
  385. }
  386. TEST_F(DxilModuleTest, CSGetNumThreads) {
  387. Compiler c(m_dllSupport);
  388. c.Compile(
  389. "[numthreads(8, 4, 2)]\n"
  390. "void main() {\n"
  391. "}\n"
  392. ,
  393. L"cs_6_0"
  394. );
  395. DxilModule &DM = c.GetDxilModule();
  396. VERIFY_ARE_EQUAL(8, DM.GetNumThreads(0));
  397. VERIFY_ARE_EQUAL(4, DM.GetNumThreads(1));
  398. VERIFY_ARE_EQUAL(2, DM.GetNumThreads(2));
  399. }
  400. TEST_F(DxilModuleTest, MSGetNumThreads) {
  401. Compiler c(m_dllSupport);
  402. if (c.SkipDxil_Test(1,5)) return;
  403. c.Compile(
  404. "struct MeshPerVertex { float4 pos : SV_Position; };\n"
  405. "[numthreads(8, 4, 2)]\n"
  406. "[outputtopology(\"triangle\")]\n"
  407. "void main(\n"
  408. " out indices uint3 primIndices[1]\n"
  409. ") {\n"
  410. " SetMeshOutputCounts(0, 0);\n"
  411. "}\n"
  412. ,
  413. L"ms_6_5"
  414. );
  415. DxilModule &DM = c.GetDxilModule();
  416. VERIFY_ARE_EQUAL(8, DM.GetNumThreads(0));
  417. VERIFY_ARE_EQUAL(4, DM.GetNumThreads(1));
  418. VERIFY_ARE_EQUAL(2, DM.GetNumThreads(2));
  419. }
  420. TEST_F(DxilModuleTest, ASGetNumThreads) {
  421. Compiler c(m_dllSupport);
  422. if (c.SkipDxil_Test(1,5)) return;
  423. c.Compile(
  424. "struct Payload { uint i; };\n"
  425. "[numthreads(8, 4, 2)]\n"
  426. "void main() {\n"
  427. " Payload pld = {0};\n"
  428. " DispatchMesh(1, 1, 1, pld);\n"
  429. "}\n"
  430. ,
  431. L"as_6_5"
  432. );
  433. DxilModule &DM = c.GetDxilModule();
  434. VERIFY_ARE_EQUAL(8, DM.GetNumThreads(0));
  435. VERIFY_ARE_EQUAL(4, DM.GetNumThreads(1));
  436. VERIFY_ARE_EQUAL(2, DM.GetNumThreads(2));
  437. }