2
0

DxilModuleTest.cpp 12 KB

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