DxilModuleTest.cpp 12 KB

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