DxilModuleTest.cpp 12 KB

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