LinkerTest.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // LinkerTest.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 "llvm/ADT/ArrayRef.h"
  14. #include "dxc/Test/CompilationResult.h"
  15. #include "dxc/Test/HLSLTestData.h"
  16. #include "llvm/Support/ManagedStatic.h"
  17. #include <fstream>
  18. #include "WexTestClass.h"
  19. #include "dxc/Test/HlslTestUtils.h"
  20. #include "dxc/Test/DxcTestUtils.h"
  21. #include "dxc/dxcapi.h"
  22. #include "dxc/DxilContainer/DxilContainer.h"
  23. using namespace std;
  24. using namespace hlsl;
  25. using namespace llvm;
  26. // The test fixture.
  27. class LinkerTest
  28. {
  29. public:
  30. BEGIN_TEST_CLASS(LinkerTest)
  31. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  32. TEST_METHOD_PROPERTY(L"Priority", L"0")
  33. END_TEST_CLASS()
  34. TEST_CLASS_SETUP(InitSupport);
  35. TEST_METHOD(RunLinkResource);
  36. TEST_METHOD(RunLinkResourceWithBinding);
  37. TEST_METHOD(RunLinkAllProfiles);
  38. TEST_METHOD(RunLinkFailNoDefine);
  39. TEST_METHOD(RunLinkFailReDefine);
  40. TEST_METHOD(RunLinkGlobalInit);
  41. TEST_METHOD(RunLinkNoAlloca);
  42. TEST_METHOD(RunLinkMatArrayParam);
  43. TEST_METHOD(RunLinkMatParam);
  44. TEST_METHOD(RunLinkMatParamToLib);
  45. TEST_METHOD(RunLinkResRet);
  46. TEST_METHOD(RunLinkToLib);
  47. TEST_METHOD(RunLinkToLibExport);
  48. TEST_METHOD(RunLinkToLibExportShadersOnly);
  49. TEST_METHOD(RunLinkFailReDefineGlobal);
  50. TEST_METHOD(RunLinkFailProfileMismatch);
  51. TEST_METHOD(RunLinkFailEntryNoProps);
  52. TEST_METHOD(RunLinkFailSelectRes);
  53. TEST_METHOD(RunLinkToLibWithUnresolvedFunctions);
  54. TEST_METHOD(RunLinkToLibWithUnresolvedFunctionsExports);
  55. TEST_METHOD(RunLinkToLibWithExportNamesSwapped);
  56. TEST_METHOD(RunLinkToLibWithExportCollision);
  57. TEST_METHOD(RunLinkToLibWithUnusedExport);
  58. TEST_METHOD(RunLinkToLibWithNoExports);
  59. TEST_METHOD(RunLinkWithPotentialIntrinsicNameCollisions);
  60. TEST_METHOD(RunLinkWithValidatorVersion);
  61. TEST_METHOD(RunLinkWithTempReg);
  62. TEST_METHOD(RunLinkToLibWithGlobalCtor);
  63. TEST_METHOD(LinkSm63ToSm66);
  64. TEST_METHOD(RunLinkWithRootSig);
  65. dxc::DxcDllSupport m_dllSupport;
  66. VersionSupportInfo m_ver;
  67. void CreateLinker(IDxcLinker **pResultLinker) {
  68. VERIFY_SUCCEEDED(
  69. m_dllSupport.CreateInstance(CLSID_DxcLinker, pResultLinker));
  70. }
  71. void Compile(LPCWSTR filename, IDxcBlob **pResultBlob,
  72. llvm::ArrayRef<LPCWSTR> pArguments = {}, LPCWSTR pEntry = L"",
  73. LPCWSTR pShaderTarget = L"lib_6_x") {
  74. std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(filename);
  75. CComPtr<IDxcBlobEncoding> pSource;
  76. CComPtr<IDxcLibrary> pLibrary;
  77. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  78. VERIFY_SUCCEEDED(
  79. pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource));
  80. CComPtr<IDxcIncludeHandler> pIncludeHandler;
  81. VERIFY_SUCCEEDED(pLibrary->CreateIncludeHandler(&pIncludeHandler));
  82. CComPtr<IDxcCompiler> pCompiler;
  83. CComPtr<IDxcOperationResult> pResult;
  84. CComPtr<IDxcBlob> pProgram;
  85. VERIFY_SUCCEEDED(
  86. m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  87. VERIFY_SUCCEEDED(pCompiler->Compile(pSource, fullPath.c_str(), pEntry, pShaderTarget,
  88. const_cast<LPCWSTR*>(pArguments.data()), pArguments.size(),
  89. nullptr, 0,
  90. pIncludeHandler, &pResult));
  91. CheckOperationSucceeded(pResult, pResultBlob);
  92. }
  93. void CompileLib(LPCWSTR filename, IDxcBlob **pResultBlob,
  94. llvm::ArrayRef<LPCWSTR> pArguments = {},
  95. LPCWSTR pShaderTarget = L"lib_6_x") {
  96. Compile(filename, pResultBlob, pArguments, L"", pShaderTarget);
  97. }
  98. void AssembleLib(LPCWSTR filename, IDxcBlob **pResultBlob) {
  99. std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(filename);
  100. CComPtr<IDxcLibrary> pLibrary;
  101. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcLibrary, &pLibrary));
  102. CComPtr<IDxcBlobEncoding> pSource;
  103. VERIFY_SUCCEEDED(pLibrary->CreateBlobFromFile(fullPath.c_str(), nullptr, &pSource));
  104. CComPtr<IDxcAssembler> pAssembler;
  105. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcAssembler, &pAssembler));
  106. CComPtr<IDxcOperationResult> pResult;
  107. VERIFY_SUCCEEDED(pAssembler->AssembleToContainer(pSource, &pResult));
  108. CheckOperationSucceeded(pResult, pResultBlob);
  109. }
  110. void RegisterDxcModule(LPCWSTR pLibName, IDxcBlob *pBlob,
  111. IDxcLinker *pLinker) {
  112. VERIFY_SUCCEEDED(pLinker->RegisterLibrary(pLibName, pBlob));
  113. }
  114. void Link(LPCWSTR pEntryName, LPCWSTR pShaderModel, IDxcLinker *pLinker,
  115. ArrayRef<LPCWSTR> libNames, llvm::ArrayRef<LPCSTR> pCheckMsgs,
  116. llvm::ArrayRef<LPCSTR> pCheckNotMsgs,
  117. llvm::ArrayRef<LPCWSTR> pArguments = {},
  118. bool bRegEx = false) {
  119. CComPtr<IDxcOperationResult> pResult;
  120. VERIFY_SUCCEEDED(pLinker->Link(pEntryName, pShaderModel, libNames.data(),
  121. libNames.size(),
  122. pArguments.data(), pArguments.size(),
  123. &pResult));
  124. CComPtr<IDxcBlob> pProgram;
  125. CheckOperationSucceeded(pResult, &pProgram);
  126. CComPtr<IDxcCompiler> pCompiler;
  127. CComPtr<IDxcBlobEncoding> pDisassembly;
  128. VERIFY_SUCCEEDED(
  129. m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
  130. VERIFY_SUCCEEDED(pCompiler->Disassemble(pProgram, &pDisassembly));
  131. std::string IR = BlobToUtf8(pDisassembly);
  132. CheckMsgs(IR.c_str(), IR.size(), pCheckMsgs.data(), pCheckMsgs.size(), bRegEx);
  133. CheckNotMsgs(IR.c_str(), IR.size(), pCheckNotMsgs.data(), pCheckNotMsgs.size(), bRegEx);
  134. }
  135. void LinkCheckMsg(LPCWSTR pEntryName, LPCWSTR pShaderModel, IDxcLinker *pLinker,
  136. ArrayRef<LPCWSTR> libNames, llvm::ArrayRef<LPCSTR> pErrorMsgs,
  137. llvm::ArrayRef<LPCWSTR> pArguments = {}) {
  138. CComPtr<IDxcOperationResult> pResult;
  139. VERIFY_SUCCEEDED(pLinker->Link(pEntryName, pShaderModel,
  140. libNames.data(), libNames.size(),
  141. pArguments.data(), pArguments.size(),
  142. &pResult));
  143. CheckOperationResultMsgs(pResult, pErrorMsgs.data(), pErrorMsgs.size(),
  144. false, false);
  145. }
  146. };
  147. bool LinkerTest::InitSupport() {
  148. if (!m_dllSupport.IsEnabled()) {
  149. VERIFY_SUCCEEDED(m_dllSupport.Initialize());
  150. m_ver.Initialize(m_dllSupport);
  151. }
  152. return true;
  153. }
  154. TEST_F(LinkerTest, RunLinkResource) {
  155. CComPtr<IDxcBlob> pResLib;
  156. CompileLib(L"..\\CodeGenHLSL\\lib_resource2.hlsl", &pResLib);
  157. CComPtr<IDxcBlob> pEntryLib;
  158. CompileLib(L"..\\CodeGenHLSL\\lib_cs_entry.hlsl", &pEntryLib);
  159. CComPtr<IDxcLinker> pLinker;
  160. CreateLinker(&pLinker);
  161. LPCWSTR libName = L"entry";
  162. RegisterDxcModule(libName, pEntryLib, pLinker);
  163. LPCWSTR libResName = L"res";
  164. RegisterDxcModule(libResName, pResLib, pLinker);
  165. Link(L"entry", L"cs_6_0", pLinker, {libResName, libName}, {} ,{});
  166. }
  167. TEST_F(LinkerTest, RunLinkResourceWithBinding) {
  168. // These two libraries both have a ConstantBuffer resource named g_buf.
  169. // These are explicitly bound to different slots, and the types don't match.
  170. // This test runs a pass to rename resources to prevent merging of resource globals.
  171. // Then tests linking these, which requires dxil op overload renaming
  172. // because of a typename collision between the two libraries.
  173. CComPtr<IDxcBlob> pLib1;
  174. CompileLib(L"..\\CodeGenHLSL\\lib_res_bound1.hlsl", &pLib1);
  175. CComPtr<IDxcBlob> pLib2;
  176. CompileLib(L"..\\CodeGenHLSL\\lib_res_bound2.hlsl", &pLib2);
  177. LPCWSTR optOptions[] = {
  178. L"-dxil-rename-resources,prefix=lib1",
  179. L"-dxil-rename-resources,prefix=lib2",
  180. };
  181. CComPtr<IDxcOptimizer> pOptimizer;
  182. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcOptimizer, &pOptimizer));
  183. CComPtr<IDxcContainerReflection> pContainerReflection;
  184. VERIFY_SUCCEEDED(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pContainerReflection));
  185. UINT32 partIdx = 0;
  186. VERIFY_SUCCEEDED(pContainerReflection->Load(pLib1));
  187. VERIFY_SUCCEEDED(pContainerReflection->FindFirstPartKind(DXC_PART_DXIL, &partIdx));
  188. CComPtr<IDxcBlob> pLib1Module;
  189. VERIFY_SUCCEEDED(pContainerReflection->GetPartContent(partIdx, &pLib1Module));
  190. CComPtr<IDxcBlob> pLib1ModuleRenamed;
  191. VERIFY_SUCCEEDED(pOptimizer->RunOptimizer(pLib1Module, &optOptions[0], 1, &pLib1ModuleRenamed, nullptr));
  192. pLib1Module.Release();
  193. pLib1.Release();
  194. AssembleToContainer(m_dllSupport, pLib1ModuleRenamed, &pLib1);
  195. VERIFY_SUCCEEDED(pContainerReflection->Load(pLib2));
  196. VERIFY_SUCCEEDED(pContainerReflection->FindFirstPartKind(DXC_PART_DXIL, &partIdx));
  197. CComPtr<IDxcBlob> pLib2Module;
  198. VERIFY_SUCCEEDED(pContainerReflection->GetPartContent(partIdx, &pLib2Module));
  199. CComPtr<IDxcBlob> pLib2ModuleRenamed;
  200. VERIFY_SUCCEEDED(pOptimizer->RunOptimizer(pLib2Module, &optOptions[1], 1, &pLib2ModuleRenamed, nullptr));
  201. pLib2Module.Release();
  202. pLib2.Release();
  203. AssembleToContainer(m_dllSupport, pLib2ModuleRenamed, &pLib2);
  204. CComPtr<IDxcLinker> pLinker;
  205. CreateLinker(&pLinker);
  206. LPCWSTR lib1Name = L"lib1";
  207. RegisterDxcModule(lib1Name, pLib1, pLinker);
  208. LPCWSTR lib2Name = L"lib2";
  209. RegisterDxcModule(lib2Name, pLib2, pLinker);
  210. Link(L"main", L"cs_6_0", pLinker, {lib1Name, lib2Name}, {} ,{});
  211. }
  212. TEST_F(LinkerTest, RunLinkAllProfiles) {
  213. CComPtr<IDxcLinker> pLinker;
  214. CreateLinker(&pLinker);
  215. LPCWSTR libName = L"entry";
  216. LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
  217. CComPtr<IDxcBlob> pEntryLib;
  218. CompileLib(L"..\\CodeGenHLSL\\lib_entries2.hlsl", &pEntryLib, option);
  219. RegisterDxcModule(libName, pEntryLib, pLinker);
  220. Link(L"vs_main", L"vs_6_0", pLinker, {libName}, {},{});
  221. Link(L"hs_main", L"hs_6_0", pLinker, {libName}, {},{});
  222. Link(L"ds_main", L"ds_6_0", pLinker, {libName}, {},{});
  223. Link(L"gs_main", L"gs_6_0", pLinker, {libName}, {},{});
  224. Link(L"ps_main", L"ps_6_0", pLinker, {libName}, {},{});
  225. CComPtr<IDxcBlob> pResLib;
  226. CompileLib(L"..\\CodeGenHLSL\\lib_resource2.hlsl", &pResLib);
  227. LPCWSTR libResName = L"res";
  228. RegisterDxcModule(libResName, pResLib, pLinker);
  229. Link(L"cs_main", L"cs_6_0", pLinker, {libName, libResName}, {},{});
  230. }
  231. TEST_F(LinkerTest, RunLinkFailNoDefine) {
  232. CComPtr<IDxcBlob> pEntryLib;
  233. CompileLib(L"..\\CodeGenHLSL\\lib_cs_entry.hlsl", &pEntryLib);
  234. CComPtr<IDxcLinker> pLinker;
  235. CreateLinker(&pLinker);
  236. LPCWSTR libName = L"entry";
  237. RegisterDxcModule(libName, pEntryLib, pLinker);
  238. LinkCheckMsg(L"entry", L"cs_6_0", pLinker, {libName},
  239. {"Cannot find definition of function"});
  240. }
  241. TEST_F(LinkerTest, RunLinkFailReDefine) {
  242. CComPtr<IDxcBlob> pEntryLib;
  243. CompileLib(L"..\\CodeGenHLSL\\lib_cs_entry.hlsl", &pEntryLib);
  244. CComPtr<IDxcLinker> pLinker;
  245. CreateLinker(&pLinker);
  246. LPCWSTR libName = L"entry";
  247. RegisterDxcModule(libName, pEntryLib, pLinker);
  248. LPCWSTR libName2 = L"entry2";
  249. RegisterDxcModule(libName2, pEntryLib, pLinker);
  250. LinkCheckMsg(L"entry", L"cs_6_0", pLinker, {libName, libName2},
  251. {"Definition already exists for function"});
  252. }
  253. TEST_F(LinkerTest, RunLinkGlobalInit) {
  254. CComPtr<IDxcBlob> pEntryLib;
  255. CompileLib(L"..\\CodeGenHLSL\\lib_global.hlsl", &pEntryLib, {}, L"lib_6_3");
  256. CComPtr<IDxcLinker> pLinker;
  257. CreateLinker(&pLinker);
  258. LPCWSTR libName = L"entry";
  259. RegisterDxcModule(libName, pEntryLib, pLinker);
  260. Link(L"test", L"ps_6_0", pLinker, {libName},
  261. // Make sure cbuffer load is generated.
  262. {"dx.op.cbufferLoad"},{});
  263. }
  264. TEST_F(LinkerTest, RunLinkFailReDefineGlobal) {
  265. LPCWSTR option[] = { L"-default-linkage", L"external" };
  266. CComPtr<IDxcBlob> pEntryLib;
  267. CompileLib(L"..\\CodeGenHLSL\\lib_global2.hlsl", &pEntryLib, option, L"lib_6_3");
  268. CComPtr<IDxcBlob> pLib0;
  269. CompileLib(L"..\\CodeGenHLSL\\lib_global3.hlsl", &pLib0, option, L"lib_6_3");
  270. CComPtr<IDxcBlob> pLib1;
  271. CompileLib(L"..\\CodeGenHLSL\\lib_global4.hlsl", &pLib1, option, L"lib_6_3");
  272. CComPtr<IDxcLinker> pLinker;
  273. CreateLinker(&pLinker);
  274. LPCWSTR libName = L"entry";
  275. RegisterDxcModule(libName, pEntryLib, pLinker);
  276. LPCWSTR libName1 = L"lib0";
  277. RegisterDxcModule(libName1, pLib0, pLinker);
  278. LPCWSTR libName2 = L"lib1";
  279. RegisterDxcModule(libName2, pLib1, pLinker);
  280. LinkCheckMsg(L"entry", L"cs_6_0", pLinker, {libName, libName1, libName2},
  281. {"Definition already exists for global variable", "Resource already exists"});
  282. }
  283. TEST_F(LinkerTest, RunLinkFailProfileMismatch) {
  284. CComPtr<IDxcBlob> pEntryLib;
  285. CompileLib(L"..\\CodeGenHLSL\\lib_global.hlsl", &pEntryLib);
  286. CComPtr<IDxcLinker> pLinker;
  287. CreateLinker(&pLinker);
  288. LPCWSTR libName = L"entry";
  289. RegisterDxcModule(libName, pEntryLib, pLinker);
  290. LinkCheckMsg(L"test", L"cs_6_0", pLinker, {libName},
  291. {"Profile mismatch between entry function and target profile"});
  292. }
  293. TEST_F(LinkerTest, RunLinkFailEntryNoProps) {
  294. CComPtr<IDxcBlob> pEntryLib;
  295. CompileLib(L"..\\CodeGenHLSL\\lib_global.hlsl", &pEntryLib);
  296. CComPtr<IDxcLinker> pLinker;
  297. CreateLinker(&pLinker);
  298. LPCWSTR libName = L"entry";
  299. RegisterDxcModule(libName, pEntryLib, pLinker);
  300. LinkCheckMsg(L"\01?update@@YAXXZ", L"cs_6_0", pLinker, {libName},
  301. {"Cannot find function property for entry function"});
  302. }
  303. TEST_F(LinkerTest, RunLinkNoAlloca) {
  304. CComPtr<IDxcBlob> pEntryLib;
  305. CompileLib(L"..\\CodeGenHLSL\\lib_no_alloca.hlsl", &pEntryLib);
  306. CComPtr<IDxcBlob> pLib;
  307. CompileLib(L"..\\CodeGenHLSL\\lib_no_alloca.h", &pLib);
  308. CComPtr<IDxcLinker> pLinker;
  309. CreateLinker(&pLinker);
  310. LPCWSTR libName = L"ps_main";
  311. RegisterDxcModule(libName, pEntryLib, pLinker);
  312. LPCWSTR libName2 = L"test";
  313. RegisterDxcModule(libName2, pLib, pLinker);
  314. Link(L"ps_main", L"ps_6_0", pLinker, {libName, libName2}, {}, {"alloca"});
  315. }
  316. TEST_F(LinkerTest, RunLinkMatArrayParam) {
  317. CComPtr<IDxcBlob> pEntryLib;
  318. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_entry.hlsl", &pEntryLib);
  319. CComPtr<IDxcBlob> pLib;
  320. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_cast.hlsl", &pLib);
  321. CComPtr<IDxcLinker> pLinker;
  322. CreateLinker(&pLinker);
  323. LPCWSTR libName = L"ps_main";
  324. RegisterDxcModule(libName, pEntryLib, pLinker);
  325. LPCWSTR libName2 = L"test";
  326. RegisterDxcModule(libName2, pLib, pLinker);
  327. Link(L"main", L"ps_6_0", pLinker, {libName, libName2},
  328. {"alloca [24 x float]", "getelementptr [12 x float], [12 x float]*"},
  329. {});
  330. }
  331. TEST_F(LinkerTest, RunLinkMatParam) {
  332. CComPtr<IDxcBlob> pEntryLib;
  333. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_entry2.hlsl", &pEntryLib);
  334. CComPtr<IDxcBlob> pLib;
  335. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_cast2.hlsl", &pLib);
  336. CComPtr<IDxcLinker> pLinker;
  337. CreateLinker(&pLinker);
  338. LPCWSTR libName = L"ps_main";
  339. RegisterDxcModule(libName, pEntryLib, pLinker);
  340. LPCWSTR libName2 = L"test";
  341. RegisterDxcModule(libName2, pLib, pLinker);
  342. Link(L"main", L"ps_6_0", pLinker, {libName, libName2},
  343. {"alloca [12 x float]"},
  344. {});
  345. }
  346. TEST_F(LinkerTest, RunLinkMatParamToLib) {
  347. CComPtr<IDxcBlob> pEntryLib;
  348. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_entry2.hlsl", &pEntryLib);
  349. CComPtr<IDxcLinker> pLinker;
  350. CreateLinker(&pLinker);
  351. LPCWSTR libName = L"ps_main";
  352. RegisterDxcModule(libName, pEntryLib, pLinker);
  353. Link(L"", L"lib_6_3", pLinker, {libName},
  354. // The bitcast cannot be removed because user function call use it as
  355. // argument.
  356. {"bitcast <12 x float>\\* %.* to %class\\.matrix\\.float\\.4\\.3\\*"}, {}, {}, true);
  357. }
  358. TEST_F(LinkerTest, RunLinkResRet) {
  359. CComPtr<IDxcBlob> pEntryLib;
  360. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_out_param_res.hlsl", &pEntryLib);
  361. CComPtr<IDxcBlob> pLib;
  362. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_out_param_res_imp.hlsl", &pLib);
  363. CComPtr<IDxcLinker> pLinker;
  364. CreateLinker(&pLinker);
  365. LPCWSTR libName = L"ps_main";
  366. RegisterDxcModule(libName, pEntryLib, pLinker);
  367. LPCWSTR libName2 = L"test";
  368. RegisterDxcModule(libName2, pLib, pLinker);
  369. Link(L"test", L"ps_6_0", pLinker, {libName, libName2}, {}, {"alloca"});
  370. }
  371. TEST_F(LinkerTest, RunLinkToLib) {
  372. LPCWSTR option[] = {L"-Zi", L"-Qembed_debug"};
  373. CComPtr<IDxcBlob> pEntryLib;
  374. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_entry2.hlsl",
  375. &pEntryLib, option);
  376. CComPtr<IDxcBlob> pLib;
  377. CompileLib(
  378. L"..\\CodeGenHLSL\\linker\\lib_mat_cast2.hlsl",
  379. &pLib, option);
  380. CComPtr<IDxcLinker> pLinker;
  381. CreateLinker(&pLinker);
  382. LPCWSTR libName = L"ps_main";
  383. RegisterDxcModule(libName, pEntryLib, pLinker);
  384. LPCWSTR libName2 = L"test";
  385. RegisterDxcModule(libName2, pLib, pLinker);
  386. Link(L"", L"lib_6_3", pLinker, {libName, libName2}, {"!llvm.dbg.cu"}, {}, option);
  387. }
  388. TEST_F(LinkerTest, RunLinkToLibExport) {
  389. CComPtr<IDxcBlob> pEntryLib;
  390. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_entry2.hlsl",
  391. &pEntryLib);
  392. CComPtr<IDxcBlob> pLib;
  393. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_cast2.hlsl",
  394. &pLib);
  395. CComPtr<IDxcLinker> pLinker;
  396. CreateLinker(&pLinker);
  397. LPCWSTR libName = L"ps_main";
  398. RegisterDxcModule(libName, pEntryLib, pLinker);
  399. LPCWSTR libName2 = L"test";
  400. RegisterDxcModule(libName2, pLib, pLinker);
  401. Link(L"", L"lib_6_3", pLinker, {libName, libName2},
  402. { "@\"\\01?renamed_test@@","@\"\\01?cloned_test@@","@main" },
  403. { "@\"\\01?mat_test", "@renamed_test", "@cloned_test" },
  404. {L"-exports", L"renamed_test,cloned_test=\\01?mat_test@@YA?AV?$vector@M$02@@V?$vector@M$03@@0AIAV?$matrix@M$03$02@@@Z;main"});
  405. }
  406. TEST_F(LinkerTest, RunLinkToLibExportShadersOnly) {
  407. CComPtr<IDxcBlob> pEntryLib;
  408. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_entry2.hlsl",
  409. &pEntryLib);
  410. CComPtr<IDxcBlob> pLib;
  411. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_cast2.hlsl",
  412. &pLib);
  413. CComPtr<IDxcLinker> pLinker;
  414. CreateLinker(&pLinker);
  415. LPCWSTR libName = L"ps_main";
  416. RegisterDxcModule(libName, pEntryLib, pLinker);
  417. LPCWSTR libName2 = L"test";
  418. RegisterDxcModule(libName2, pLib, pLinker);
  419. Link(L"", L"lib_6_3", pLinker, {libName, libName2},
  420. { "@main" },
  421. { "@\"\\01?mat_test" },
  422. {L"-export-shaders-only"});
  423. }
  424. TEST_F(LinkerTest, RunLinkFailSelectRes) {
  425. if (m_ver.SkipDxilVersion(1, 3)) return;
  426. CComPtr<IDxcBlob> pEntryLib;
  427. CompileLib(L"..\\CodeGenHLSL\\lib_select_res_entry.hlsl", &pEntryLib);
  428. CComPtr<IDxcBlob> pLib;
  429. CompileLib(L"..\\CodeGenHLSL\\lib_select_res.hlsl", &pLib);
  430. CComPtr<IDxcLinker> pLinker;
  431. CreateLinker(&pLinker);
  432. LPCWSTR libName = L"main";
  433. RegisterDxcModule(libName, pEntryLib, pLinker);
  434. LPCWSTR libName2 = L"test";
  435. RegisterDxcModule(libName2, pLib, pLinker);
  436. LinkCheckMsg(L"main", L"ps_6_0", pLinker, {libName, libName2},
  437. {"local resource not guaranteed to map to unique global resource"});
  438. }
  439. TEST_F(LinkerTest, RunLinkToLibWithUnresolvedFunctions) {
  440. LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
  441. CComPtr<IDxcBlob> pLib1;
  442. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func1.hlsl",
  443. &pLib1, option);
  444. CComPtr<IDxcBlob> pLib2;
  445. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func2.hlsl",
  446. &pLib2, option);
  447. CComPtr<IDxcLinker> pLinker;
  448. CreateLinker(&pLinker);
  449. LPCWSTR libName1 = L"lib1";
  450. RegisterDxcModule(libName1, pLib1, pLinker);
  451. LPCWSTR libName2 = L"lib2";
  452. RegisterDxcModule(libName2, pLib2, pLinker);
  453. Link(L"", L"lib_6_3", pLinker, { libName1, libName2 }, {
  454. "declare float @\"\\01?external_fn1@@YAMXZ\"()",
  455. "declare float @\"\\01?external_fn2@@YAMXZ\"()",
  456. "declare float @\"\\01?external_fn@@YAMXZ\"()",
  457. "define float @\"\\01?lib1_fn@@YAMXZ\"()",
  458. "define float @\"\\01?lib2_fn@@YAMXZ\"()",
  459. "define float @\"\\01?call_lib1@@YAMXZ\"()",
  460. "define float @\"\\01?call_lib2@@YAMXZ\"()"
  461. }, {"declare float @\"\\01?unused_fn1", "declare float @\"\\01?unused_fn2"});
  462. }
  463. TEST_F(LinkerTest, RunLinkToLibWithUnresolvedFunctionsExports) {
  464. LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
  465. CComPtr<IDxcBlob> pLib1;
  466. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func1.hlsl",
  467. &pLib1, option);
  468. CComPtr<IDxcBlob> pLib2;
  469. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func2.hlsl",
  470. &pLib2, option);
  471. CComPtr<IDxcLinker> pLinker;
  472. CreateLinker(&pLinker);
  473. LPCWSTR libName1 = L"lib1";
  474. RegisterDxcModule(libName1, pLib1, pLinker);
  475. LPCWSTR libName2 = L"lib2";
  476. RegisterDxcModule(libName2, pLib2, pLinker);
  477. Link(L"", L"lib_6_3", pLinker, { libName1, libName2 },
  478. { "declare float @\"\\01?external_fn1@@YAMXZ\"()",
  479. "declare float @\"\\01?external_fn2@@YAMXZ\"()",
  480. "declare float @\"\\01?external_fn@@YAMXZ\"()",
  481. "define float @\"\\01?renamed_lib1@@YAMXZ\"()",
  482. "define float @\"\\01?call_lib2@@YAMXZ\"()"
  483. },
  484. { "float @\"\\01?unused_fn1", "float @\"\\01?unused_fn2",
  485. "float @\"\\01?lib1_fn", "float @\"\\01?lib2_fn",
  486. "float @\"\\01?call_lib1"
  487. },
  488. { L"-exports", L"renamed_lib1=call_lib1",
  489. L"-exports", L"call_lib2"
  490. });
  491. }
  492. TEST_F(LinkerTest, RunLinkToLibWithExportNamesSwapped) {
  493. LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
  494. CComPtr<IDxcBlob> pLib1;
  495. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func1.hlsl",
  496. &pLib1, option);
  497. CComPtr<IDxcBlob> pLib2;
  498. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func2.hlsl",
  499. &pLib2, option);
  500. CComPtr<IDxcLinker> pLinker;
  501. CreateLinker(&pLinker);
  502. LPCWSTR libName1 = L"lib1";
  503. RegisterDxcModule(libName1, pLib1, pLinker);
  504. LPCWSTR libName2 = L"lib2";
  505. RegisterDxcModule(libName2, pLib2, pLinker);
  506. Link(L"", L"lib_6_3", pLinker, { libName1, libName2 },
  507. { "declare float @\"\\01?external_fn1@@YAMXZ\"()",
  508. "declare float @\"\\01?external_fn2@@YAMXZ\"()",
  509. "declare float @\"\\01?external_fn@@YAMXZ\"()",
  510. "define float @\"\\01?call_lib1@@YAMXZ\"()",
  511. "define float @\"\\01?call_lib2@@YAMXZ\"()"
  512. },
  513. { "float @\"\\01?unused_fn1", "float @\"\\01?unused_fn2",
  514. "float @\"\\01?lib1_fn", "float @\"\\01?lib2_fn"
  515. },
  516. { L"-exports", L"call_lib2=call_lib1;call_lib1=call_lib2" });
  517. }
  518. TEST_F(LinkerTest, RunLinkToLibWithExportCollision) {
  519. LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
  520. CComPtr<IDxcBlob> pLib1;
  521. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func1.hlsl",
  522. &pLib1, option);
  523. CComPtr<IDxcBlob> pLib2;
  524. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func2.hlsl",
  525. &pLib2, option);
  526. CComPtr<IDxcLinker> pLinker;
  527. CreateLinker(&pLinker);
  528. LPCWSTR libName1 = L"lib1";
  529. RegisterDxcModule(libName1, pLib1, pLinker);
  530. LPCWSTR libName2 = L"lib2";
  531. RegisterDxcModule(libName2, pLib2, pLinker);
  532. LinkCheckMsg(L"", L"lib_6_3", pLinker, { libName1, libName2 },
  533. { "Export name collides with another export: \\01?call_lib2@@YAMXZ"
  534. },
  535. { L"-exports", L"call_lib2=call_lib1;call_lib2" });
  536. }
  537. TEST_F(LinkerTest, RunLinkToLibWithUnusedExport) {
  538. LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
  539. CComPtr<IDxcBlob> pLib1;
  540. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func1.hlsl",
  541. &pLib1, option);
  542. CComPtr<IDxcBlob> pLib2;
  543. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func2.hlsl",
  544. &pLib2, option);
  545. CComPtr<IDxcLinker> pLinker;
  546. CreateLinker(&pLinker);
  547. LPCWSTR libName1 = L"lib1";
  548. RegisterDxcModule(libName1, pLib1, pLinker);
  549. LPCWSTR libName2 = L"lib2";
  550. RegisterDxcModule(libName2, pLib2, pLinker);
  551. LinkCheckMsg(L"", L"lib_6_3", pLinker, { libName1, libName2 },
  552. { "Could not find target for export: call_lib"
  553. },
  554. { L"-exports", L"call_lib2=call_lib;call_lib1" });
  555. }
  556. TEST_F(LinkerTest, RunLinkToLibWithNoExports) {
  557. LPCWSTR option[] = { L"-Zi", L"-Qembed_debug" };
  558. CComPtr<IDxcBlob> pLib1;
  559. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func1.hlsl",
  560. &pLib1, option);
  561. CComPtr<IDxcBlob> pLib2;
  562. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_unresolved_func2.hlsl",
  563. &pLib2, option);
  564. CComPtr<IDxcLinker> pLinker;
  565. CreateLinker(&pLinker);
  566. LPCWSTR libName1 = L"lib1";
  567. RegisterDxcModule(libName1, pLib1, pLinker);
  568. LPCWSTR libName2 = L"lib2";
  569. RegisterDxcModule(libName2, pLib2, pLinker);
  570. LinkCheckMsg(L"", L"lib_6_3", pLinker, { libName1, libName2 },
  571. { "Library has no functions to export"
  572. },
  573. { L"-exports", L"call_lib2=call_lib" });
  574. }
  575. TEST_F(LinkerTest, RunLinkWithPotentialIntrinsicNameCollisions) {
  576. LPCWSTR option[] = { L"-Zi", L"-Qembed_debug", L"-default-linkage", L"external" };
  577. CComPtr<IDxcBlob> pLib1;
  578. CompileLib(L"..\\CodeGenHLSL\\linker\\createHandle_multi.hlsl",
  579. &pLib1, option, L"lib_6_3");
  580. CComPtr<IDxcBlob> pLib2;
  581. CompileLib(L"..\\CodeGenHLSL\\linker\\createHandle_multi2.hlsl",
  582. &pLib2, option, L"lib_6_3");
  583. CComPtr<IDxcLinker> pLinker;
  584. CreateLinker(&pLinker);
  585. LPCWSTR libName1 = L"lib1";
  586. RegisterDxcModule(libName1, pLib1, pLinker);
  587. LPCWSTR libName2 = L"lib2";
  588. RegisterDxcModule(libName2, pLib2, pLinker);
  589. Link(L"", L"lib_6_3", pLinker, { libName1, libName2 }, {
  590. "declare %dx.types.Handle @\"dx.op.createHandleForLib.class.Texture2D<vector<float, 4> >\"(i32, %\"class.Texture2D<vector<float, 4> >\")",
  591. "declare %dx.types.Handle @\"dx.op.createHandleForLib.class.Texture2D<float>\"(i32, %\"class.Texture2D<float>\")"
  592. }, { });
  593. }
  594. TEST_F(LinkerTest, RunLinkWithValidatorVersion) {
  595. if (m_ver.SkipDxilVersion(1, 4)) return;
  596. CComPtr<IDxcBlob> pEntryLib;
  597. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_entry2.hlsl",
  598. &pEntryLib, {});
  599. CComPtr<IDxcBlob> pLib;
  600. CompileLib(
  601. L"..\\CodeGenHLSL\\linker\\lib_mat_cast2.hlsl",
  602. &pLib, {});
  603. CComPtr<IDxcLinker> pLinker;
  604. CreateLinker(&pLinker);
  605. LPCWSTR libName = L"ps_main";
  606. RegisterDxcModule(libName, pEntryLib, pLinker);
  607. LPCWSTR libName2 = L"test";
  608. RegisterDxcModule(libName2, pLib, pLinker);
  609. Link(L"", L"lib_6_3", pLinker, {libName, libName2},
  610. {"!dx.valver = !{(![0-9]+)}.*\n\\1 = !{i32 1, i32 3}"},
  611. {}, {L"-validator-version", L"1.3"}, /*regex*/ true);
  612. }
  613. TEST_F(LinkerTest, RunLinkWithTempReg) {
  614. // TempRegLoad/TempRegStore not normally usable from HLSL.
  615. // This assembly library exposes these through overloaded wrapper functions
  616. // void sreg(uint index, <type> value) to store register, overloaded for uint, int, and float
  617. // uint ureg(uint index) to load register as uint
  618. // int ireg(int index) to load register as int
  619. // float freg(uint index) to load register as float
  620. // This test verifies this scenario works, by assembling this library,
  621. // compiling a library with an entry point that uses sreg/ureg,
  622. // then linking these to a final standard vs_6_0 DXIL shader.
  623. CComPtr<IDxcBlob> pTempRegLib;
  624. AssembleLib(L"..\\HLSLFileCheck\\dxil\\linker\\TempReg.ll", &pTempRegLib);
  625. CComPtr<IDxcBlob> pEntryLib;
  626. CompileLib(L"..\\HLSLFileCheck\\dxil\\linker\\use-TempReg.hlsl", &pEntryLib, {}, L"lib_6_3");
  627. CComPtr<IDxcLinker> pLinker;
  628. CreateLinker(&pLinker);
  629. LPCWSTR libName = L"entry";
  630. RegisterDxcModule(libName, pEntryLib, pLinker);
  631. LPCWSTR libResName = L"TempReg";
  632. RegisterDxcModule(libResName, pTempRegLib, pLinker);
  633. Link(L"main", L"vs_6_0", pLinker, {libResName, libName}, {
  634. "call void @dx.op.tempRegStore.i32",
  635. "call i32 @dx.op.tempRegLoad.i32"
  636. } ,{});
  637. }
  638. TEST_F(LinkerTest, RunLinkToLibWithGlobalCtor) {
  639. CComPtr<IDxcBlob> pLib0;
  640. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_static_cb_init.hlsl", &pLib0, {});
  641. CComPtr<IDxcBlob> pLib1;
  642. CompileLib(L"..\\CodeGenHLSL\\linker\\lib_use_static_cb_init.hlsl", &pLib1,
  643. {});
  644. CComPtr<IDxcLinker> pLinker;
  645. CreateLinker(&pLinker);
  646. LPCWSTR libName = L"foo";
  647. RegisterDxcModule(libName, pLib0, pLinker);
  648. LPCWSTR libName2 = L"bar";
  649. RegisterDxcModule(libName2, pLib1, pLinker);
  650. // Make sure global_ctors created for lib to lib.
  651. Link(L"", L"lib_6_3", pLinker, {libName, libName2},
  652. {"@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ "
  653. "i32, void ()*, i8* } { i32 65535, void ()* "
  654. "@foo._GLOBAL__sub_I_lib_static_cb_init.hlsl, i8* null }]"},
  655. {},
  656. {});
  657. }
  658. TEST_F(LinkerTest, LinkSm63ToSm66) {
  659. if (m_ver.SkipDxilVersion(1, 6)) return;
  660. CComPtr<IDxcBlob> pLib0;
  661. CompileLib(L"..\\CodeGenHLSL\\linker\\link_to_sm66.hlsl", &pLib0, {}, L"lib_6_3");
  662. CComPtr<IDxcLinker> pLinker;
  663. CreateLinker(&pLinker);
  664. LPCWSTR libName = L"foo";
  665. RegisterDxcModule(libName, pLib0, pLinker);
  666. // Make sure add annotateHandle when link lib_6_3 to ps_6_6.
  667. Link(L"ps_main", L"ps_6_6", pLinker, {libName},
  668. {"call %dx.types.Handle @dx.op.annotateHandle\\(i32 216, %dx.types.Handle "
  669. "%(.*), %dx.types.ResourceProperties { i32 13, i32 4 }\\)"},
  670. {}, {}, true);
  671. }
  672. TEST_F(LinkerTest, RunLinkWithRootSig) {
  673. CComPtr<IDxcBlob> pLib0;
  674. CompileLib(L"..\\CodeGenHLSL\\linker\\link_with_root_sig.hlsl", &pLib0, {},
  675. L"lib_6_x");
  676. CComPtr<IDxcLinker> pLinker;
  677. CreateLinker(&pLinker);
  678. LPCWSTR libName = L"foo";
  679. RegisterDxcModule(libName, pLib0, pLinker);
  680. LPCWSTR pEntryName = L"vs_main";
  681. LPCWSTR pShaderModel = L"vs_6_6";
  682. LPCWSTR libNames[] = {libName};
  683. CComPtr<IDxcOperationResult> pResult;
  684. VERIFY_SUCCEEDED(pLinker->Link(pEntryName, pShaderModel, libNames,
  685. 1, {}, 0, &pResult));
  686. CComPtr<IDxcBlob> pLinkedProgram;
  687. CheckOperationSucceeded(pResult, &pLinkedProgram);
  688. VERIFY_IS_TRUE(pLinkedProgram);
  689. CComPtr<IDxcBlob> pProgram;
  690. Compile(L"..\\CodeGenHLSL\\linker\\link_with_root_sig.hlsl", &pProgram, {},
  691. pEntryName, pShaderModel);
  692. VERIFY_IS_TRUE(pProgram);
  693. const DxilContainerHeader *pLinkedContainer = IsDxilContainerLike(
  694. pLinkedProgram->GetBufferPointer(), pLinkedProgram->GetBufferSize());
  695. VERIFY_IS_TRUE(pLinkedContainer);
  696. const DxilContainerHeader *pContainer = IsDxilContainerLike(
  697. pProgram->GetBufferPointer(), pProgram->GetBufferSize());
  698. VERIFY_IS_TRUE(pContainer);
  699. const DxilPartHeader *pLinkedRSPart =
  700. GetDxilPartByType(pLinkedContainer, DFCC_RootSignature);
  701. VERIFY_IS_TRUE(pLinkedRSPart);
  702. const DxilPartHeader *pRSPart =
  703. GetDxilPartByType(pContainer, DFCC_RootSignature);
  704. VERIFY_IS_TRUE(pRSPart);
  705. VERIFY_IS_TRUE(pRSPart->PartSize == pLinkedRSPart->PartSize);
  706. const uint8_t *pRS = (const uint8_t *)GetDxilPartData(pRSPart);
  707. const uint8_t *pLinkedRS = (const uint8_t *)GetDxilPartData(pLinkedRSPart);
  708. for (unsigned i = 0; i < pLinkedRSPart->PartSize; i++) {
  709. VERIFY_IS_TRUE(pRS[i] == pLinkedRS[i]);
  710. }
  711. }