dxcompilerobj.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // dxcompilerobj.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. // Implements the DirectX Compiler. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "clang/Basic/Diagnostic.h"
  12. #include "clang/Basic/FileManager.h"
  13. #include "clang/Basic/SourceManager.h"
  14. #include "clang/Basic/TargetOptions.h"
  15. #include "clang/Basic/TargetInfo.h"
  16. #include "clang/Frontend/CompilerInstance.h"
  17. #include "clang/Lex/Preprocessor.h"
  18. #include "clang/Lex/HLSLMacroExpander.h"
  19. #include "clang/Frontend/ASTUnit.h"
  20. #include "clang/Frontend/TextDiagnosticPrinter.h"
  21. #include "clang/Sema/SemaHLSL.h"
  22. #include "llvm/Bitcode/ReaderWriter.h"
  23. #include "clang/Frontend/FrontendActions.h"
  24. #include "clang/CodeGen/CodeGenAction.h"
  25. #include "llvm/IR/LLVMContext.h"
  26. #include "dxc/Support/WinIncludes.h"
  27. #include "dxc/HLSL/HLSLExtensionsCodegenHelper.h"
  28. #include "dxc/HLSL/DxilRootSignature.h"
  29. #include "dxcutil.h"
  30. #include "dxc/Support/dxcfilesystem.h"
  31. // SPIRV change starts
  32. #ifdef ENABLE_SPIRV_CODEGEN
  33. #include "clang/SPIRV/EmitSPIRVAction.h"
  34. #endif
  35. // SPIRV change ends
  36. #include "dxc/Support/WinIncludes.h"
  37. #include "dxc/HLSL/DxilContainer.h"
  38. #include "dxc/dxcapi.internal.h"
  39. #include "dxc/Support/dxcapi.use.h"
  40. #include "dxc/Support/Global.h"
  41. #include "dxc/Support/Unicode.h"
  42. #include "dxc/Support/microcom.h"
  43. #include "dxc/Support/FileIOHelper.h"
  44. #include "dxc/Support/dxcapi.impl.h"
  45. #include "dxc/Support/DxcLangExtensionsHelper.h"
  46. #include "dxc/Support/HLSLOptions.h"
  47. #include "dxcetw.h"
  48. #include "dxillib.h"
  49. #include <algorithm>
  50. #define CP_UTF16 1200
  51. using namespace llvm;
  52. using namespace clang;
  53. using namespace hlsl;
  54. using std::string;
  55. // This declaration is used for the locally-linked validator.
  56. HRESULT CreateDxcValidator(_In_ REFIID riid, _Out_ LPVOID *ppv);
  57. // This internal call allows the validator to avoid having to re-deserialize
  58. // the module. It trusts that the caller didn't make any changes and is
  59. // kept internal because the layout of the module class may change based
  60. // on changes across modules, or picking a different compiler version or CRT.
  61. HRESULT RunInternalValidator(_In_ IDxcValidator *pValidator,
  62. _In_ llvm::Module *pModule,
  63. _In_ llvm::Module *pDebugModule,
  64. _In_ IDxcBlob *pShader, UINT32 Flags,
  65. _In_ IDxcOperationResult **ppResult);
  66. static void CreateOperationResultFromOutputs(
  67. IDxcBlob *pResultBlob, dxcutil::DxcArgsFileSystem *msfPtr,
  68. const std::string &warnings, clang::DiagnosticsEngine &diags,
  69. _COM_Outptr_ IDxcOperationResult **ppResult) {
  70. CComPtr<IStream> pErrorStream;
  71. CComPtr<IDxcBlobEncoding> pErrorBlob;
  72. msfPtr->GetStdOutpuHandleStream(&pErrorStream);
  73. dxcutil::CreateOperationResultFromOutputs(pResultBlob, pErrorStream, warnings,
  74. diags.hasErrorOccurred(), ppResult);
  75. }
  76. static void CreateOperationResultFromOutputs(
  77. AbstractMemoryStream *pOutputStream, dxcutil::DxcArgsFileSystem *msfPtr,
  78. const std::string &warnings, clang::DiagnosticsEngine &diags,
  79. _COM_Outptr_ IDxcOperationResult **ppResult) {
  80. CComPtr<IDxcBlob> pResultBlob;
  81. IFT(pOutputStream->QueryInterface(&pResultBlob));
  82. CreateOperationResultFromOutputs(pResultBlob, msfPtr, warnings, diags,
  83. ppResult);
  84. }
  85. class HLSLExtensionsCodegenHelperImpl : public HLSLExtensionsCodegenHelper {
  86. private:
  87. CompilerInstance &m_CI;
  88. DxcLangExtensionsHelper &m_langExtensionsHelper;
  89. std::string m_rootSigDefine;
  90. // The metadata format is a root node that has pointers to metadata
  91. // nodes for each define. The metatdata node for a define is a pair
  92. // of (name, value) metadata strings.
  93. //
  94. // Example:
  95. // !hlsl.semdefs = {!0, !1}
  96. // !0 = !{!"FOO", !"BAR"}
  97. // !1 = !{!"BOO", !"HOO"}
  98. void WriteSemanticDefines(llvm::Module *M, const ParsedSemanticDefineList &defines) {
  99. // Create all metadata nodes for each define. Each node is a (name, value) pair.
  100. std::vector<MDNode *> mdNodes;
  101. for (const ParsedSemanticDefine &define : defines) {
  102. MDString *name = MDString::get(M->getContext(), define.Name);
  103. MDString *value = MDString::get(M->getContext(), define.Value);
  104. mdNodes.push_back(MDNode::get(M->getContext(), { name, value }));
  105. }
  106. // Add root node with pointers to all define metadata nodes.
  107. NamedMDNode *Root = M->getOrInsertNamedMetadata(m_langExtensionsHelper.GetSemanticDefineMetadataName());
  108. for (MDNode *node : mdNodes)
  109. Root->addOperand(node);
  110. }
  111. SemanticDefineErrorList GetValidatedSemanticDefines(const ParsedSemanticDefineList &defines, ParsedSemanticDefineList &validated, SemanticDefineErrorList &errors) {
  112. for (const ParsedSemanticDefine &define : defines) {
  113. DxcLangExtensionsHelper::SemanticDefineValidationResult result = m_langExtensionsHelper.ValidateSemanticDefine(define.Name, define.Value);
  114. if (result.HasError())
  115. errors.emplace_back(SemanticDefineError(define.Location, SemanticDefineError::Level::Error, result.Error));
  116. if (result.HasWarning())
  117. errors.emplace_back(SemanticDefineError(define.Location, SemanticDefineError::Level::Warning, result.Warning));
  118. if (!result.HasError())
  119. validated.emplace_back(define);
  120. }
  121. return errors;
  122. }
  123. public:
  124. HLSLExtensionsCodegenHelperImpl(CompilerInstance &CI, DxcLangExtensionsHelper &langExtensionsHelper, StringRef rootSigDefine)
  125. : m_CI(CI), m_langExtensionsHelper(langExtensionsHelper)
  126. , m_rootSigDefine(rootSigDefine)
  127. {}
  128. // Write semantic defines as metadata in the module.
  129. virtual std::vector<SemanticDefineError> WriteSemanticDefines(llvm::Module *M) override {
  130. // Grab the semantic defines seen by the parser.
  131. ParsedSemanticDefineList defines =
  132. CollectSemanticDefinesParsedByCompiler(m_CI, &m_langExtensionsHelper);
  133. // Nothing to do if we have no defines.
  134. SemanticDefineErrorList errors;
  135. if (!defines.size())
  136. return errors;
  137. ParsedSemanticDefineList validated;
  138. GetValidatedSemanticDefines(defines, validated, errors);
  139. WriteSemanticDefines(M, validated);
  140. return errors;
  141. }
  142. virtual std::string GetIntrinsicName(UINT opcode) override {
  143. return m_langExtensionsHelper.GetIntrinsicName(opcode);
  144. }
  145. virtual bool GetDxilOpcode(UINT opcode, OP::OpCode &dxilOpcode) override {
  146. UINT dop = static_cast<UINT>(OP::OpCode::NumOpCodes);
  147. if (m_langExtensionsHelper.GetDxilOpCode(opcode, dop)) {
  148. if (dop < static_cast<UINT>(OP::OpCode::NumOpCodes)) {
  149. dxilOpcode = static_cast<OP::OpCode>(dop);
  150. return true;
  151. }
  152. }
  153. return false;
  154. }
  155. virtual HLSLExtensionsCodegenHelper::CustomRootSignature::Status GetCustomRootSignature(CustomRootSignature *out) {
  156. // Find macro definition in preprocessor.
  157. Preprocessor &pp = m_CI.getPreprocessor();
  158. MacroInfo *macro = MacroExpander::FindMacroInfo(pp, m_rootSigDefine);
  159. if (!macro)
  160. return CustomRootSignature::NOT_FOUND;
  161. // Combine tokens into single string
  162. MacroExpander expander(pp, MacroExpander::STRIP_QUOTES);
  163. if (!expander.ExpandMacro(macro, &out->RootSignature))
  164. return CustomRootSignature::NOT_FOUND;
  165. // Record source location of root signature macro.
  166. out->EncodedSourceLocation = macro->getDefinitionLoc().getRawEncoding();
  167. return CustomRootSignature::FOUND;
  168. }
  169. };
  170. class DxcCompiler : public IDxcCompiler2, public IDxcLangExtensions, public IDxcContainerEvent, public IDxcVersionInfo {
  171. private:
  172. DXC_MICROCOM_TM_REF_FIELDS()
  173. DxcLangExtensionsHelper m_langExtensionsHelper;
  174. CComPtr<IDxcContainerEventsHandler> m_pDxcContainerEventsHandler;
  175. void CreateDefineStrings(_In_count_(defineCount) const DxcDefine *pDefines,
  176. UINT defineCount,
  177. std::vector<std::string> &defines) {
  178. // Not very efficient but also not very important.
  179. for (UINT32 i = 0; i < defineCount; i++) {
  180. CW2A utf8Name(pDefines[i].Name, CP_UTF8);
  181. CW2A utf8Value(pDefines[i].Value, CP_UTF8);
  182. std::string val(utf8Name.m_psz);
  183. val += "=";
  184. val += (pDefines[i].Value) ? utf8Value.m_psz : "1";
  185. defines.push_back(val);
  186. }
  187. }
  188. public:
  189. DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
  190. DXC_MICROCOM_TM_CTOR(DxcCompiler)
  191. DXC_LANGEXTENSIONS_HELPER_IMPL(m_langExtensionsHelper)
  192. __override HRESULT STDMETHODCALLTYPE RegisterDxilContainerEventHandler(IDxcContainerEventsHandler *pHandler, UINT64 *pCookie) {
  193. DXASSERT(m_pDxcContainerEventsHandler == nullptr, "else events handler is already registered");
  194. *pCookie = 1; // Only one EventsHandler supported
  195. m_pDxcContainerEventsHandler = pHandler;
  196. return S_OK;
  197. };
  198. __override HRESULT STDMETHODCALLTYPE UnRegisterDxilContainerEventHandler(UINT64 cookie) {
  199. DXASSERT(m_pDxcContainerEventsHandler != nullptr, "else unregister should not have been called");
  200. m_pDxcContainerEventsHandler.Release();
  201. return S_OK;
  202. }
  203. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
  204. return DoBasicQueryInterface<IDxcCompiler,
  205. IDxcCompiler2,
  206. IDxcLangExtensions,
  207. IDxcContainerEvent,
  208. IDxcVersionInfo>
  209. (this, iid, ppvObject);
  210. }
  211. // Compile a single entry point to the target shader model
  212. __override HRESULT STDMETHODCALLTYPE Compile(
  213. _In_ IDxcBlob *pSource, // Source text to compile
  214. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  215. _In_ LPCWSTR pEntryPoint, // entry point name
  216. _In_ LPCWSTR pTargetProfile, // shader profile to compile
  217. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  218. _In_ UINT32 argCount, // Number of arguments
  219. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  220. _In_ UINT32 defineCount, // Number of defines
  221. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  222. _COM_Outptr_ IDxcOperationResult **ppResult // Compiler output status, buffer, and errors
  223. ) {
  224. return CompileWithDebug(pSource, pSourceName, pEntryPoint, pTargetProfile,
  225. pArguments, argCount, pDefines, defineCount,
  226. pIncludeHandler, ppResult, nullptr, nullptr);
  227. }
  228. // Compile a single entry point to the target shader model with debug information.
  229. __override HRESULT STDMETHODCALLTYPE CompileWithDebug(
  230. _In_ IDxcBlob *pSource, // Source text to compile
  231. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  232. _In_ LPCWSTR pEntryPoint, // Entry point name
  233. _In_ LPCWSTR pTargetProfile, // Shader profile to compile
  234. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  235. _In_ UINT32 argCount, // Number of arguments
  236. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  237. _In_ UINT32 defineCount, // Number of defines
  238. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  239. _COM_Outptr_ IDxcOperationResult **ppResult, // Compiler output status, buffer, and errors
  240. _Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob.
  241. _COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob
  242. ) {
  243. if (pSource == nullptr || ppResult == nullptr ||
  244. (defineCount > 0 && pDefines == nullptr) ||
  245. (argCount > 0 && pArguments == nullptr) || pEntryPoint == nullptr ||
  246. pTargetProfile == nullptr)
  247. return E_INVALIDARG;
  248. *ppResult = nullptr;
  249. AssignToOutOpt(nullptr, ppDebugBlobName);
  250. AssignToOutOpt(nullptr, ppDebugBlob);
  251. HRESULT hr = S_OK;
  252. CComPtr<IDxcBlobEncoding> utf8Source;
  253. CComPtr<AbstractMemoryStream> pOutputStream;
  254. CHeapPtr<wchar_t> DebugBlobName;
  255. DxcEtw_DXCompilerCompile_Start();
  256. pSourceName = (pSourceName && *pSourceName) ? pSourceName : L"hlsl.hlsl"; // declared optional, so pick a default
  257. DxcThreadMalloc TM(m_pMalloc);
  258. IFC(hlsl::DxcGetBlobAsUtf8(pSource, &utf8Source));
  259. try {
  260. CComPtr<IDxcBlob> pOutputBlob;
  261. dxcutil::DxcArgsFileSystem *msfPtr =
  262. dxcutil::CreateDxcArgsFileSystem(utf8Source, pSourceName, pIncludeHandler);
  263. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  264. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  265. IFTLLVM(pts.error_code());
  266. IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
  267. IFT(pOutputStream.QueryInterface(&pOutputBlob));
  268. int argCountInt;
  269. IFT(UIntToInt(argCount, &argCountInt));
  270. hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0);
  271. hlsl::options::DxcOpts opts;
  272. CW2A pUtf8TargetProfile(pTargetProfile, CP_UTF8);
  273. // Set target profile before reading options and validate
  274. opts.TargetProfile = pUtf8TargetProfile.m_psz;
  275. bool finished;
  276. dxcutil::ReadOptsAndValidate(mainArgs, opts, pOutputStream, ppResult, finished);
  277. if (finished) {
  278. hr = S_OK;
  279. goto Cleanup;
  280. }
  281. if (opts.DisplayIncludeProcess)
  282. msfPtr->EnableDisplayIncludeProcess();
  283. // Prepare UTF8-encoded versions of API values.
  284. CW2A pUtf8EntryPoint(pEntryPoint, CP_UTF8);
  285. CW2A utf8SourceName(pSourceName, CP_UTF8);
  286. const char *pUtf8SourceName = utf8SourceName.m_psz;
  287. if (pUtf8SourceName == nullptr) {
  288. if (opts.InputFile.empty()) {
  289. pUtf8SourceName = "input.hlsl";
  290. }
  291. else {
  292. pUtf8SourceName = opts.InputFile.data();
  293. }
  294. }
  295. IFT(msfPtr->RegisterOutputStream(L"output.bc", pOutputStream));
  296. IFT(msfPtr->CreateStdStreams(m_pMalloc));
  297. StringRef Data((LPSTR)utf8Source->GetBufferPointer(),
  298. utf8Source->GetBufferSize());
  299. std::unique_ptr<llvm::MemoryBuffer> pBuffer(
  300. llvm::MemoryBuffer::getMemBufferCopy(Data, pUtf8SourceName));
  301. // Not very efficient but also not very important.
  302. std::vector<std::string> defines;
  303. CreateDefineStrings(pDefines, defineCount, defines);
  304. CreateDefineStrings(opts.Defines.data(), opts.Defines.size(), defines);
  305. // Setup a compiler instance.
  306. std::string warnings;
  307. raw_string_ostream w(warnings);
  308. raw_stream_ostream outStream(pOutputStream.p);
  309. llvm::LLVMContext llvmContext; // LLVMContext should outlive CompilerInstance
  310. CompilerInstance compiler;
  311. std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
  312. std::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
  313. SetupCompilerForCompile(compiler, &m_langExtensionsHelper, utf8SourceName, diagPrinter.get(), defines, opts, pArguments, argCount);
  314. msfPtr->SetupForCompilerInstance(compiler);
  315. // The clang entry point (cc1_main) would now create a compiler invocation
  316. // from arguments, but for this path we're exclusively trying to compile
  317. // to LLVM bitcode and then package that into a DXBC blob.
  318. //
  319. // With the compiler invocation built from command line arguments, the
  320. // next step is to call ExecuteCompilerInvocation, which creates a
  321. // FrontendAction* of EmitBCAction, which is a CodeGenAction, which is an
  322. // ASTFrontendAction. That sets up a BackendConsumer as the ASTConsumer.
  323. compiler.getFrontendOpts().OutputFile = "output.bc";
  324. compiler.WriteDefaultOutputDirectly = true;
  325. compiler.setOutStream(&outStream);
  326. compiler.getLangOpts().HLSLEntryFunction =
  327. compiler.getCodeGenOpts().HLSLEntryFunction = pUtf8EntryPoint.m_psz;
  328. compiler.getLangOpts().HLSLProfile =
  329. compiler.getCodeGenOpts().HLSLProfile = pUtf8TargetProfile.m_psz;
  330. unsigned rootSigMajor = 0;
  331. unsigned rootSigMinor = 0;
  332. if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_1") {
  333. rootSigMajor = 1;
  334. rootSigMinor = 1;
  335. } else if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_0") {
  336. rootSigMajor = 1;
  337. rootSigMinor = 0;
  338. }
  339. compiler.getLangOpts().IsHLSLLibrary = opts.IsLibraryProfile();
  340. // NOTE: this calls the validation component from dxil.dll; the built-in
  341. // validator can be used as a fallback.
  342. bool produceFullContainer = !opts.CodeGenHighLevel && !opts.AstDump && !opts.OptDump && rootSigMajor == 0;
  343. bool needsValidation = produceFullContainer && !opts.DisableValidation &&
  344. !opts.IsLibraryProfile();
  345. if (needsValidation || (opts.CodeGenHighLevel && !opts.DisableValidation)) {
  346. UINT32 majorVer, minorVer;
  347. dxcutil::GetValidatorVersion(&majorVer, &minorVer);
  348. compiler.getCodeGenOpts().HLSLValidatorMajorVer = majorVer;
  349. compiler.getCodeGenOpts().HLSLValidatorMinorVer = minorVer;
  350. }
  351. if (opts.AstDump) {
  352. clang::ASTDumpAction dumpAction;
  353. // Consider - ASTDumpFilter, ASTDumpLookups
  354. compiler.getFrontendOpts().ASTDumpDecls = true;
  355. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  356. dumpAction.BeginSourceFile(compiler, file);
  357. dumpAction.Execute();
  358. dumpAction.EndSourceFile();
  359. outStream.flush();
  360. }
  361. else if (opts.OptDump) {
  362. EmitOptDumpAction action(&llvmContext);
  363. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  364. action.BeginSourceFile(compiler, file);
  365. action.Execute();
  366. action.EndSourceFile();
  367. outStream.flush();
  368. }
  369. else if (rootSigMajor) {
  370. HLSLRootSignatureAction action(
  371. compiler.getCodeGenOpts().HLSLEntryFunction, rootSigMajor,
  372. rootSigMinor);
  373. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  374. action.BeginSourceFile(compiler, file);
  375. action.Execute();
  376. action.EndSourceFile();
  377. outStream.flush();
  378. // Don't do work to put in a container if an error has occurred
  379. bool compileOK = !compiler.getDiagnostics().hasErrorOccurred();
  380. if (compileOK) {
  381. auto rootSigHandle = action.takeRootSigHandle();
  382. CComPtr<AbstractMemoryStream> pContainerStream;
  383. IFT(CreateMemoryStream(m_pMalloc, &pContainerStream));
  384. SerializeDxilContainerForRootSignature(rootSigHandle.get(),
  385. pContainerStream);
  386. pOutputBlob.Release();
  387. IFT(pContainerStream.QueryInterface(&pOutputBlob));
  388. }
  389. }
  390. // SPIRV change starts
  391. #ifdef ENABLE_SPIRV_CODEGEN
  392. else if (opts.GenSPIRV) {
  393. clang::EmitSPIRVOptions spirvOpts;
  394. spirvOpts.codeGenHighLevel = opts.CodeGenHighLevel;
  395. spirvOpts.disableValidation = opts.DisableValidation;
  396. spirvOpts.invertY = opts.VkInvertY;
  397. spirvOpts.useGlLayout = opts.VkUseGlLayout;
  398. spirvOpts.useDxLayout = opts.VkUseDxLayout;
  399. spirvOpts.enableReflect = opts.SpvEnableReflect;
  400. spirvOpts.ignoreUnusedResources = opts.VkIgnoreUnusedResources;
  401. spirvOpts.defaultRowMajor = opts.DefaultRowMajor;
  402. spirvOpts.stageIoOrder = opts.VkStageIoOrder;
  403. spirvOpts.bShift = opts.VkBShift;
  404. spirvOpts.tShift = opts.VkTShift;
  405. spirvOpts.sShift = opts.VkSShift;
  406. spirvOpts.uShift = opts.VkUShift;
  407. spirvOpts.allowedExtensions = opts.SpvExtensions;
  408. spirvOpts.targetEnv = opts.SpvTargetEnv;
  409. spirvOpts.enable16BitTypes = opts.Enable16BitTypes;
  410. spirvOpts.enableDebugInfo = opts.DebugInfo;
  411. clang::EmitSPIRVAction action(spirvOpts);
  412. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  413. action.BeginSourceFile(compiler, file);
  414. action.Execute();
  415. action.EndSourceFile();
  416. outStream.flush();
  417. }
  418. #endif
  419. // SPIRV change ends
  420. else {
  421. EmitBCAction action(&llvmContext);
  422. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  423. bool compileOK;
  424. if (action.BeginSourceFile(compiler, file)) {
  425. action.Execute();
  426. action.EndSourceFile();
  427. compileOK = !compiler.getDiagnostics().hasErrorOccurred();
  428. }
  429. else {
  430. compileOK = false;
  431. }
  432. outStream.flush();
  433. SerializeDxilFlags SerializeFlags = SerializeDxilFlags::None;
  434. if (opts.DebugInfo) {
  435. SerializeFlags = SerializeDxilFlags::IncludeDebugNamePart;
  436. // Unless we want to strip it right away, include it in the container.
  437. if (!opts.StripDebug || ppDebugBlob == nullptr) {
  438. SerializeFlags |= SerializeDxilFlags::IncludeDebugInfoPart;
  439. }
  440. }
  441. if (opts.DebugNameForSource) {
  442. SerializeFlags |= SerializeDxilFlags::DebugNameDependOnSource;
  443. }
  444. // Don't do work to put in a container if an error has occurred
  445. // Do not create a container when there is only a a high-level representation in the module.
  446. if (compileOK && !opts.CodeGenHighLevel) {
  447. HRESULT valHR = S_OK;
  448. if (needsValidation) {
  449. valHR = dxcutil::ValidateAndAssembleToContainer(
  450. action.takeModule(), pOutputBlob, m_pMalloc, SerializeFlags,
  451. pOutputStream, opts.DebugInfo, compiler.getDiagnostics());
  452. } else {
  453. dxcutil::AssembleToContainer(action.takeModule(),
  454. pOutputBlob, m_pMalloc,
  455. SerializeFlags, pOutputStream);
  456. }
  457. // Callback after valid DXIL is produced
  458. if (SUCCEEDED(valHR)) {
  459. CComPtr<IDxcBlob> pTargetBlob;
  460. if (m_pDxcContainerEventsHandler != nullptr) {
  461. HRESULT hr = m_pDxcContainerEventsHandler->OnDxilContainerBuilt(pOutputBlob, &pTargetBlob);
  462. if (SUCCEEDED(hr) && pTargetBlob != nullptr) {
  463. std::swap(pOutputBlob, pTargetBlob);
  464. }
  465. }
  466. if (ppDebugBlobName && produceFullContainer) {
  467. const DxilContainerHeader *pContainer = reinterpret_cast<DxilContainerHeader *>(pOutputBlob->GetBufferPointer());
  468. DXASSERT(IsValidDxilContainer(pContainer, pOutputBlob->GetBufferSize()), "else invalid container generated");
  469. auto it = std::find_if(begin(pContainer), end(pContainer),
  470. DxilPartIsType(DFCC_ShaderDebugName));
  471. if (it != end(pContainer)) {
  472. const char *pDebugName;
  473. if (GetDxilShaderDebugName(*it, &pDebugName, nullptr) && pDebugName && *pDebugName) {
  474. IFTBOOL(Unicode::UTF8BufferToUTF16ComHeap(pDebugName, &DebugBlobName), DXC_E_CONTAINER_INVALID);
  475. }
  476. }
  477. }
  478. }
  479. }
  480. }
  481. // Add std err to warnings.
  482. msfPtr->WriteStdErrToStream(w);
  483. CreateOperationResultFromOutputs(pOutputBlob, msfPtr, warnings,
  484. compiler.getDiagnostics(), ppResult);
  485. // On success, return values. After assigning ppResult, nothing should fail.
  486. HRESULT status;
  487. DXVERIFY_NOMSG(SUCCEEDED((*ppResult)->GetStatus(&status)));
  488. if (SUCCEEDED(status)) {
  489. if (opts.DebugInfo && ppDebugBlob) {
  490. DXVERIFY_NOMSG(SUCCEEDED(pOutputStream.QueryInterface(ppDebugBlob)));
  491. }
  492. if (ppDebugBlobName) {
  493. *ppDebugBlobName = DebugBlobName.Detach();
  494. }
  495. }
  496. hr = S_OK;
  497. } catch (std::bad_alloc &) {
  498. hr = E_OUTOFMEMORY;
  499. } catch (hlsl::Exception &e) {
  500. _Analysis_assume_(DXC_FAILED(e.hr));
  501. if (e.hr == DXC_E_ABORT_COMPILATION_ERROR) {
  502. e.hr = S_OK;
  503. CComPtr<IDxcBlobEncoding> pErrorBlob;
  504. IFT(DxcCreateBlobWithEncodingOnHeapCopy(e.msg.c_str(), e.msg.size(),
  505. CP_UTF8, &pErrorBlob));
  506. IFT(DxcOperationResult::CreateFromResultErrorStatus(
  507. nullptr, pErrorBlob, DXC_E_GENERAL_INTERNAL_ERROR, ppResult));
  508. }
  509. hr = e.hr;
  510. } catch (...) {
  511. hr = E_FAIL;
  512. }
  513. Cleanup:
  514. DxcEtw_DXCompilerCompile_Stop(hr);
  515. return hr;
  516. }
  517. // Preprocess source text
  518. __override HRESULT STDMETHODCALLTYPE Preprocess(
  519. _In_ IDxcBlob *pSource, // Source text to preprocess
  520. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  521. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  522. _In_ UINT32 argCount, // Number of arguments
  523. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  524. _In_ UINT32 defineCount, // Number of defines
  525. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  526. _COM_Outptr_ IDxcOperationResult **ppResult // Preprocessor output status, buffer, and errors
  527. ) {
  528. if (pSource == nullptr || ppResult == nullptr ||
  529. (defineCount > 0 && pDefines == nullptr) ||
  530. (argCount > 0 && pArguments == nullptr))
  531. return E_INVALIDARG;
  532. *ppResult = nullptr;
  533. HRESULT hr = S_OK;
  534. DxcEtw_DXCompilerPreprocess_Start();
  535. DxcThreadMalloc TM(m_pMalloc);
  536. CComPtr<IDxcBlobEncoding> utf8Source;
  537. IFC(hlsl::DxcGetBlobAsUtf8(pSource, &utf8Source));
  538. try {
  539. CComPtr<AbstractMemoryStream> pOutputStream;
  540. dxcutil::DxcArgsFileSystem *msfPtr = dxcutil::CreateDxcArgsFileSystem(utf8Source, pSourceName, pIncludeHandler);
  541. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  542. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  543. IFTLLVM(pts.error_code());
  544. IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
  545. const llvm::opt::OptTable *table = ::options::getHlslOptTable();
  546. int argCountInt;
  547. IFT(UIntToInt(argCount, &argCountInt));
  548. hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0);
  549. hlsl::options::DxcOpts opts;
  550. bool finished;
  551. dxcutil::ReadOptsAndValidate(mainArgs, opts, pOutputStream, ppResult, finished);
  552. if (finished) {
  553. hr = S_OK;
  554. goto Cleanup;
  555. }
  556. // Prepare UTF8-encoded versions of API values.
  557. CW2A utf8SourceName(pSourceName, CP_UTF8);
  558. const char *pUtf8SourceName = utf8SourceName.m_psz;
  559. if (pUtf8SourceName == nullptr) {
  560. if (opts.InputFile.empty()) {
  561. pUtf8SourceName = "input.hlsl";
  562. }
  563. else {
  564. pUtf8SourceName = opts.InputFile.data();
  565. }
  566. }
  567. IFT(msfPtr->RegisterOutputStream(L"output.hlsl", pOutputStream));
  568. IFT(msfPtr->CreateStdStreams(m_pMalloc));
  569. StringRef Data((LPSTR)utf8Source->GetBufferPointer(),
  570. utf8Source->GetBufferSize());
  571. std::unique_ptr<llvm::MemoryBuffer> pBuffer(
  572. llvm::MemoryBuffer::getMemBufferCopy(Data, pUtf8SourceName));
  573. // Not very efficient but also not very important.
  574. std::vector<std::string> defines;
  575. CreateDefineStrings(pDefines, defineCount, defines);
  576. // Setup a compiler instance.
  577. std::string warnings;
  578. raw_string_ostream w(warnings);
  579. raw_stream_ostream outStream(pOutputStream.p);
  580. CompilerInstance compiler;
  581. std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
  582. std::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
  583. SetupCompilerForCompile(compiler, &m_langExtensionsHelper, utf8SourceName, diagPrinter.get(), defines, opts, pArguments, argCount);
  584. msfPtr->SetupForCompilerInstance(compiler);
  585. // The clang entry point (cc1_main) would now create a compiler invocation
  586. // from arguments, but for this path we're exclusively trying to preproces
  587. // to text.
  588. compiler.getFrontendOpts().OutputFile = "output.hlsl";
  589. compiler.WriteDefaultOutputDirectly = true;
  590. compiler.setOutStream(&outStream);
  591. // These settings are back-compatible with fxc.
  592. clang::PreprocessorOutputOptions &PPOutOpts =
  593. compiler.getPreprocessorOutputOpts();
  594. PPOutOpts.ShowCPP = 1; // Print normal preprocessed output.
  595. PPOutOpts.ShowComments = 0; // Show comments.
  596. PPOutOpts.ShowLineMarkers = 1; // Show \#line markers.
  597. PPOutOpts.UseLineDirectives = 1; // Use \#line instead of GCC-style \# N.
  598. PPOutOpts.ShowMacroComments = 0; // Show comments, even in macros.
  599. PPOutOpts.ShowMacros = 0; // Print macro definitions.
  600. PPOutOpts.RewriteIncludes = 0; // Preprocess include directives only.
  601. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  602. clang::PrintPreprocessedAction action;
  603. if (action.BeginSourceFile(compiler, file)) {
  604. action.Execute();
  605. action.EndSourceFile();
  606. }
  607. outStream.flush();
  608. // Add std err to warnings.
  609. msfPtr->WriteStdErrToStream(w);
  610. CreateOperationResultFromOutputs(pOutputStream, msfPtr, warnings,
  611. compiler.getDiagnostics(), ppResult);
  612. hr = S_OK;
  613. }
  614. CATCH_CPP_ASSIGN_HRESULT();
  615. Cleanup:
  616. DxcEtw_DXCompilerPreprocess_Stop(hr);
  617. return hr;
  618. }
  619. // Disassemble a shader.
  620. __override HRESULT STDMETHODCALLTYPE Disassemble(
  621. _In_ IDxcBlob *pProgram, // Program to disassemble.
  622. _COM_Outptr_ IDxcBlobEncoding** ppDisassembly // Disassembly text.
  623. ) {
  624. if (pProgram == nullptr || ppDisassembly == nullptr)
  625. return E_INVALIDARG;
  626. *ppDisassembly = nullptr;
  627. HRESULT hr = S_OK;
  628. DxcEtw_DXCompilerDisassemble_Start();
  629. DxcThreadMalloc TM(m_pMalloc);
  630. try {
  631. ::llvm::sys::fs::MSFileSystem *msfPtr;
  632. IFT(CreateMSFileSystemForDisk(&msfPtr));
  633. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  634. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  635. IFTLLVM(pts.error_code());
  636. std::string StreamStr;
  637. raw_string_ostream Stream(StreamStr);
  638. IFC(dxcutil::Disassemble(pProgram, Stream));
  639. IFT(DxcCreateBlobWithEncodingOnHeapCopy(
  640. StreamStr.c_str(), StreamStr.size(), CP_UTF8, ppDisassembly));
  641. return S_OK;
  642. }
  643. CATCH_CPP_ASSIGN_HRESULT();
  644. Cleanup:
  645. DxcEtw_DXCompilerDisassemble_Stop(hr);
  646. return hr;
  647. }
  648. void SetupCompilerForCompile(CompilerInstance &compiler,
  649. _In_ DxcLangExtensionsHelper *helper,
  650. _In_ LPCSTR pMainFile, _In_ TextDiagnosticPrinter *diagPrinter,
  651. _In_ std::vector<std::string>& defines,
  652. _In_ hlsl::options::DxcOpts &Opts,
  653. _In_count_(argCount) LPCWSTR *pArguments,
  654. _In_ UINT32 argCount) {
  655. // Setup a compiler instance.
  656. std::shared_ptr<TargetOptions> targetOptions(new TargetOptions);
  657. targetOptions->Triple = "dxil-ms-dx";
  658. targetOptions->DescriptionString = Opts.Enable16BitTypes
  659. ? hlsl::DXIL::kNewLayoutString
  660. : hlsl::DXIL::kLegacyLayoutString;
  661. compiler.HlslLangExtensions = helper;
  662. compiler.createDiagnostics(diagPrinter, false);
  663. compiler.createFileManager();
  664. compiler.createSourceManager(compiler.getFileManager());
  665. compiler.setTarget(
  666. TargetInfo::CreateTargetInfo(compiler.getDiagnostics(), targetOptions));
  667. compiler.getFrontendOpts().Inputs.push_back(FrontendInputFile(pMainFile, IK_HLSL));
  668. // Setup debug information.
  669. if (Opts.DebugInfo) {
  670. CodeGenOptions &CGOpts = compiler.getCodeGenOpts();
  671. CGOpts.setDebugInfo(CodeGenOptions::FullDebugInfo);
  672. CGOpts.DebugColumnInfo = 1;
  673. CGOpts.DwarfVersion = 4; // Latest version.
  674. // TODO: consider
  675. // DebugPass, DebugCompilationDir, DwarfDebugFlags, SplitDwarfFile
  676. }
  677. clang::PreprocessorOptions &PPOpts(compiler.getPreprocessorOpts());
  678. for (size_t i = 0; i < defines.size(); ++i) {
  679. PPOpts.addMacroDef(defines[i]);
  680. }
  681. PPOpts.IgnoreLineDirectives = Opts.IgnoreLineDirectives;
  682. // fxc compatibility: pre-expand operands before performing token-pasting
  683. PPOpts.ExpandTokPastingArg = Opts.LegacyMacroExpansion;
  684. // Pick additional arguments.
  685. clang::HeaderSearchOptions &HSOpts = compiler.getHeaderSearchOpts();
  686. HSOpts.UseBuiltinIncludes = 0;
  687. // Consider: should we force-include '.' if the source file is relative?
  688. for (const llvm::opt::Arg *A : Opts.Args.filtered(options::OPT_I)) {
  689. const bool IsFrameworkFalse = false;
  690. const bool IgnoreSysRoot = true;
  691. if (dxcutil::IsAbsoluteOrCurDirRelative(A->getValue())) {
  692. HSOpts.AddPath(A->getValue(), frontend::Angled, IsFrameworkFalse, IgnoreSysRoot);
  693. }
  694. else {
  695. std::string s("./");
  696. s += A->getValue();
  697. HSOpts.AddPath(s, frontend::Angled, IsFrameworkFalse, IgnoreSysRoot);
  698. }
  699. }
  700. // Apply root signature option.
  701. unsigned rootSigMinor;
  702. if (Opts.ForceRootSigVer.empty() || Opts.ForceRootSigVer == "rootsig_1_1") {
  703. rootSigMinor = 1;
  704. }
  705. else {
  706. DXASSERT(Opts.ForceRootSigVer == "rootsig_1_0",
  707. "else opts should have been rejected");
  708. rootSigMinor = 0;
  709. }
  710. compiler.getLangOpts().RootSigMajor = 1;
  711. compiler.getLangOpts().RootSigMinor = rootSigMinor;
  712. compiler.getLangOpts().HLSLVersion = (unsigned) Opts.HLSLVersion;
  713. compiler.getLangOpts().UseMinPrecision = !Opts.Enable16BitTypes;
  714. // SPIRV change starts
  715. #ifdef ENABLE_SPIRV_CODEGEN
  716. compiler.getLangOpts().SPIRV = Opts.GenSPIRV;
  717. #endif
  718. // SPIRV change ends
  719. if (Opts.WarningAsError)
  720. compiler.getDiagnostics().setWarningsAsErrors(true);
  721. if (Opts.IEEEStrict)
  722. compiler.getCodeGenOpts().UnsafeFPMath = true;
  723. if (Opts.FloatDenormalMode.empty()) {
  724. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Reserve7; // undefined
  725. }
  726. else if (Opts.FloatDenormalMode.equals_lower(StringRef("any"))) {
  727. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Any;
  728. }
  729. else if (Opts.FloatDenormalMode.equals_lower(StringRef("ftz"))) {
  730. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::FTZ;
  731. }
  732. else {
  733. DXASSERT(Opts.FloatDenormalMode.equals_lower(StringRef("preserve")), "else opts should have been rejected");
  734. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Preserve;
  735. }
  736. if (Opts.DisableOptimizations)
  737. compiler.getCodeGenOpts().DisableLLVMOpts = true;
  738. compiler.getCodeGenOpts().OptimizationLevel = Opts.OptLevel;
  739. if (Opts.OptLevel >= 3)
  740. compiler.getCodeGenOpts().UnrollLoops = true;
  741. compiler.getCodeGenOpts().HLSLHighLevel = Opts.CodeGenHighLevel;
  742. compiler.getCodeGenOpts().HLSLAllResourcesBound = Opts.AllResourcesBound;
  743. compiler.getCodeGenOpts().HLSLDefaultRowMajor = Opts.DefaultRowMajor;
  744. compiler.getCodeGenOpts().HLSLPreferControlFlow = Opts.PreferFlowControl;
  745. compiler.getCodeGenOpts().HLSLAvoidControlFlow = Opts.AvoidFlowControl;
  746. compiler.getCodeGenOpts().HLSLNotUseLegacyCBufLoad = Opts.NotUseLegacyCBufLoad;
  747. compiler.getCodeGenOpts().HLSLDefines = defines;
  748. compiler.getCodeGenOpts().MainFileName = pMainFile;
  749. // Translate signature packing options
  750. if (Opts.PackPrefixStable)
  751. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::PrefixStable;
  752. else if (Opts.PackOptimized)
  753. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::Optimized;
  754. else
  755. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::Default;
  756. // Constructing vector of wide strings to pass in to codegen. Just passing
  757. // in pArguments will expose ownership of memory to both CodeGenOptions and
  758. // this caller, which can lead to unexpected behavior.
  759. for (UINT32 i = 0; i != argCount; ++i) {
  760. compiler.getCodeGenOpts().HLSLArguments.emplace_back(
  761. Unicode::UTF16ToUTF8StringOrThrow(pArguments[i]));
  762. }
  763. // Overrding default set of loop unroll.
  764. if (Opts.PreferFlowControl)
  765. compiler.getCodeGenOpts().UnrollLoops = false;
  766. if (Opts.AvoidFlowControl)
  767. compiler.getCodeGenOpts().UnrollLoops = true;
  768. // always inline for hlsl
  769. compiler.getCodeGenOpts().setInlining(
  770. clang::CodeGenOptions::OnlyAlwaysInlining);
  771. compiler.getCodeGenOpts().HLSLExtensionsCodegen = std::make_shared<HLSLExtensionsCodegenHelperImpl>(compiler, m_langExtensionsHelper, Opts.RootSignatureDefine);
  772. }
  773. // IDxcVersionInfo
  774. __override HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) {
  775. if (pMajor == nullptr || pMinor == nullptr)
  776. return E_INVALIDARG;
  777. *pMajor = DXIL::kDxilMajor;
  778. *pMinor = DXIL::kDxilMinor;
  779. return S_OK;
  780. }
  781. __override HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) {
  782. if (pFlags == nullptr)
  783. return E_INVALIDARG;
  784. *pFlags = DxcVersionInfoFlags_None;
  785. #ifdef _DEBUG
  786. *pFlags |= DxcVersionInfoFlags_Debug;
  787. #endif
  788. return S_OK;
  789. }
  790. };
  791. HRESULT CreateDxcCompiler(_In_ REFIID riid, _Out_ LPVOID* ppv) {
  792. *ppv = nullptr;
  793. try {
  794. CComPtr<DxcCompiler> result(DxcCompiler::Alloc(DxcGetThreadMallocNoRef()));
  795. IFROOM(result.p);
  796. return result.p->QueryInterface(riid, ppv);
  797. }
  798. CATCH_CPP_RETURN_HRESULT();
  799. }