dxcompilerobj.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  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_REF_FIELD(m_dwRef)
  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. void ReadOptsAndValidate(hlsl::options::MainArgs &mainArgs,
  189. hlsl::options::DxcOpts &opts,
  190. AbstractMemoryStream *pOutputStream,
  191. _COM_Outptr_ IDxcOperationResult **ppResult,
  192. bool &finished) {
  193. const llvm::opt::OptTable *table = ::options::getHlslOptTable();
  194. raw_stream_ostream outStream(pOutputStream);
  195. if (0 != hlsl::options::ReadDxcOpts(table, hlsl::options::CompilerFlags,
  196. mainArgs, opts, outStream)) {
  197. CComPtr<IDxcBlob> pErrorBlob;
  198. IFT(pOutputStream->QueryInterface(&pErrorBlob));
  199. CComPtr<IDxcBlobEncoding> pErrorBlobWithEncoding;
  200. outStream.flush();
  201. IFT(DxcCreateBlobWithEncodingSet(pErrorBlob.p, CP_UTF8,
  202. &pErrorBlobWithEncoding));
  203. IFT(DxcOperationResult::CreateFromResultErrorStatus(nullptr, pErrorBlobWithEncoding.p, E_INVALIDARG, ppResult));
  204. finished = true;
  205. return;
  206. }
  207. DXASSERT(!opts.HLSL2015, "else ReadDxcOpts didn't fail for non-isense");
  208. finished = false;
  209. }
  210. public:
  211. DXC_MICROCOM_ADDREF_RELEASE_IMPL(m_dwRef)
  212. DXC_LANGEXTENSIONS_HELPER_IMPL(m_langExtensionsHelper)
  213. __override HRESULT STDMETHODCALLTYPE RegisterDxilContainerEventHandler(IDxcContainerEventsHandler *pHandler, UINT64 *pCookie) {
  214. DXASSERT(m_pDxcContainerEventsHandler == nullptr, "else events handler is already registered");
  215. *pCookie = 1; // Only one EventsHandler supported
  216. m_pDxcContainerEventsHandler = pHandler;
  217. return S_OK;
  218. };
  219. __override HRESULT STDMETHODCALLTYPE UnRegisterDxilContainerEventHandler(UINT64 cookie) {
  220. DXASSERT(m_pDxcContainerEventsHandler != nullptr, "else unregister should not have been called");
  221. m_pDxcContainerEventsHandler.Release();
  222. return S_OK;
  223. }
  224. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) {
  225. return DoBasicQueryInterface<IDxcCompiler,
  226. IDxcCompiler2,
  227. IDxcLangExtensions,
  228. IDxcContainerEvent,
  229. IDxcVersionInfo>
  230. (this, iid, ppvObject);
  231. }
  232. // Compile a single entry point to the target shader model
  233. __override HRESULT STDMETHODCALLTYPE Compile(
  234. _In_ IDxcBlob *pSource, // Source text to compile
  235. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  236. _In_ LPCWSTR pEntryPoint, // entry point name
  237. _In_ LPCWSTR pTargetProfile, // shader profile to compile
  238. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  239. _In_ UINT32 argCount, // Number of arguments
  240. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  241. _In_ UINT32 defineCount, // Number of defines
  242. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  243. _COM_Outptr_ IDxcOperationResult **ppResult // Compiler output status, buffer, and errors
  244. ) {
  245. return CompileWithDebug(pSource, pSourceName, pEntryPoint, pTargetProfile,
  246. pArguments, argCount, pDefines, defineCount,
  247. pIncludeHandler, ppResult, nullptr, nullptr);
  248. }
  249. // Compile a single entry point to the target shader model with debug information.
  250. __override HRESULT STDMETHODCALLTYPE CompileWithDebug(
  251. _In_ IDxcBlob *pSource, // Source text to compile
  252. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  253. _In_ LPCWSTR pEntryPoint, // Entry point name
  254. _In_ LPCWSTR pTargetProfile, // Shader profile to compile
  255. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  256. _In_ UINT32 argCount, // Number of arguments
  257. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  258. _In_ UINT32 defineCount, // Number of defines
  259. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  260. _COM_Outptr_ IDxcOperationResult **ppResult, // Compiler output status, buffer, and errors
  261. _Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob.
  262. _COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob
  263. ) {
  264. if (pSource == nullptr || ppResult == nullptr ||
  265. (defineCount > 0 && pDefines == nullptr) ||
  266. (argCount > 0 && pArguments == nullptr) || pEntryPoint == nullptr ||
  267. pTargetProfile == nullptr)
  268. return E_INVALIDARG;
  269. *ppResult = nullptr;
  270. AssignToOutOpt(nullptr, ppDebugBlobName);
  271. AssignToOutOpt(nullptr, ppDebugBlob);
  272. HRESULT hr = S_OK;
  273. CComPtr<IDxcBlobEncoding> utf8Source;
  274. CComPtr<AbstractMemoryStream> pOutputStream;
  275. CHeapPtr<wchar_t> DebugBlobName;
  276. DxcEtw_DXCompilerCompile_Start();
  277. IFC(hlsl::DxcGetBlobAsUtf8(pSource, &utf8Source));
  278. try {
  279. CComPtr<IMalloc> pMalloc;
  280. CComPtr<IDxcBlob> pOutputBlob;
  281. dxcutil::DxcArgsFileSystem *msfPtr;
  282. IFT(dxcutil::CreateDxcArgsFileSystem(utf8Source, pSourceName, pIncludeHandler, &msfPtr));
  283. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  284. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  285. IFTLLVM(pts.error_code());
  286. IFT(CoGetMalloc(1, &pMalloc));
  287. IFT(CreateMemoryStream(pMalloc, &pOutputStream));
  288. IFT(pOutputStream.QueryInterface(&pOutputBlob));
  289. int argCountInt;
  290. IFT(UIntToInt(argCount, &argCountInt));
  291. hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0);
  292. hlsl::options::DxcOpts opts;
  293. bool finished;
  294. ReadOptsAndValidate(mainArgs, opts, pOutputStream, ppResult, finished);
  295. if (finished) {
  296. hr = S_OK;
  297. goto Cleanup;
  298. }
  299. if (opts.DisplayIncludeProcess)
  300. msfPtr->EnableDisplayIncludeProcess();
  301. // Prepare UTF8-encoded versions of API values.
  302. CW2A pUtf8EntryPoint(pEntryPoint, CP_UTF8);
  303. CW2A pUtf8TargetProfile(pTargetProfile, CP_UTF8);
  304. CW2A utf8SourceName(pSourceName, CP_UTF8);
  305. const char *pUtf8SourceName = utf8SourceName.m_psz;
  306. if (pUtf8SourceName == nullptr) {
  307. if (opts.InputFile.empty()) {
  308. pUtf8SourceName = "input.hlsl";
  309. }
  310. else {
  311. pUtf8SourceName = opts.InputFile.data();
  312. }
  313. }
  314. // Set target profile.
  315. opts.TargetProfile = pUtf8TargetProfile.m_psz;
  316. IFT(msfPtr->RegisterOutputStream(L"output.bc", pOutputStream));
  317. IFT(msfPtr->CreateStdStreams(pMalloc));
  318. StringRef Data((LPSTR)utf8Source->GetBufferPointer(),
  319. utf8Source->GetBufferSize());
  320. std::unique_ptr<llvm::MemoryBuffer> pBuffer(
  321. llvm::MemoryBuffer::getMemBufferCopy(Data, pUtf8SourceName));
  322. // Not very efficient but also not very important.
  323. std::vector<std::string> defines;
  324. CreateDefineStrings(pDefines, defineCount, defines);
  325. CreateDefineStrings(opts.Defines.data(), opts.Defines.size(), defines);
  326. // Setup a compiler instance.
  327. std::string warnings;
  328. raw_string_ostream w(warnings);
  329. raw_stream_ostream outStream(pOutputStream.p);
  330. CompilerInstance compiler;
  331. std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
  332. std::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
  333. SetupCompilerForCompile(compiler, &m_langExtensionsHelper, utf8SourceName, diagPrinter.get(), defines, opts, pArguments, argCount);
  334. msfPtr->SetupForCompilerInstance(compiler);
  335. // The clang entry point (cc1_main) would now create a compiler invocation
  336. // from arguments, but for this path we're exclusively trying to compile
  337. // to LLVM bitcode and then package that into a DXBC blob.
  338. //
  339. // With the compiler invocation built from command line arguments, the
  340. // next step is to call ExecuteCompilerInvocation, which creates a
  341. // FrontendAction* of EmitBCAction, which is a CodeGenAction, which is an
  342. // ASTFrontendAction. That sets up a BackendConsumer as the ASTConsumer.
  343. compiler.getFrontendOpts().OutputFile = "output.bc";
  344. compiler.WriteDefaultOutputDirectly = true;
  345. compiler.setOutStream(&outStream);
  346. compiler.getLangOpts().HLSLEntryFunction =
  347. compiler.getCodeGenOpts().HLSLEntryFunction = pUtf8EntryPoint.m_psz;
  348. compiler.getCodeGenOpts().HLSLProfile = pUtf8TargetProfile.m_psz;
  349. unsigned rootSigMajor = 0;
  350. unsigned rootSigMinor = 0;
  351. if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_1") {
  352. rootSigMajor = 1;
  353. rootSigMinor = 1;
  354. } else if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_0") {
  355. rootSigMajor = 1;
  356. rootSigMinor = 0;
  357. }
  358. compiler.getLangOpts().IsHLSLLibrary = opts.IsLibraryProfile();
  359. // NOTE: this calls the validation component from dxil.dll; the built-in
  360. // validator can be used as a fallback.
  361. bool produceFullContainer = !opts.CodeGenHighLevel && !opts.AstDump && !opts.OptDump && rootSigMajor == 0;
  362. bool needsValidation = produceFullContainer && !opts.DisableValidation &&
  363. !opts.IsLibraryProfile();
  364. if (needsValidation) {
  365. UINT32 majorVer, minorVer;
  366. dxcutil::GetValidatorVersion(&majorVer, &minorVer);
  367. compiler.getCodeGenOpts().HLSLValidatorMajorVer = majorVer;
  368. compiler.getCodeGenOpts().HLSLValidatorMinorVer = minorVer;
  369. }
  370. if (opts.AstDump) {
  371. clang::ASTDumpAction dumpAction;
  372. // Consider - ASTDumpFilter, ASTDumpLookups
  373. compiler.getFrontendOpts().ASTDumpDecls = true;
  374. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  375. dumpAction.BeginSourceFile(compiler, file);
  376. dumpAction.Execute();
  377. dumpAction.EndSourceFile();
  378. outStream.flush();
  379. }
  380. else if (opts.OptDump) {
  381. llvm::LLVMContext llvmContext;
  382. EmitOptDumpAction action(&llvmContext);
  383. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  384. action.BeginSourceFile(compiler, file);
  385. action.Execute();
  386. action.EndSourceFile();
  387. outStream.flush();
  388. }
  389. else if (rootSigMajor) {
  390. HLSLRootSignatureAction action(
  391. compiler.getCodeGenOpts().HLSLEntryFunction, rootSigMajor,
  392. rootSigMinor);
  393. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  394. action.BeginSourceFile(compiler, file);
  395. action.Execute();
  396. action.EndSourceFile();
  397. outStream.flush();
  398. // Don't do work to put in a container if an error has occurred
  399. bool compileOK = !compiler.getDiagnostics().hasErrorOccurred();
  400. if (compileOK) {
  401. auto rootSigHandle = action.takeRootSigHandle();
  402. CComPtr<AbstractMemoryStream> pContainerStream;
  403. IFT(CreateMemoryStream(pMalloc, &pContainerStream));
  404. SerializeDxilContainerForRootSignature(rootSigHandle.get(),
  405. pContainerStream);
  406. pOutputBlob.Release();
  407. IFT(pContainerStream.QueryInterface(&pOutputBlob));
  408. }
  409. }
  410. // SPIRV change starts
  411. #ifdef ENABLE_SPIRV_CODEGEN
  412. else if (opts.GenSPIRV) {
  413. clang::EmitSPIRVAction action;
  414. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  415. action.BeginSourceFile(compiler, file);
  416. action.Execute();
  417. action.EndSourceFile();
  418. outStream.flush();
  419. }
  420. #endif
  421. // SPIRV change ends
  422. else {
  423. llvm::LLVMContext llvmContext;
  424. EmitBCAction action(&llvmContext);
  425. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  426. bool compileOK;
  427. if (action.BeginSourceFile(compiler, file)) {
  428. action.Execute();
  429. action.EndSourceFile();
  430. compileOK = !compiler.getDiagnostics().hasErrorOccurred();
  431. }
  432. else {
  433. compileOK = false;
  434. }
  435. outStream.flush();
  436. SerializeDxilFlags SerializeFlags = SerializeDxilFlags::None;
  437. if (opts.DebugInfo) {
  438. SerializeFlags = SerializeDxilFlags::IncludeDebugNamePart;
  439. // Unless we want to strip it right away, include it in the container.
  440. if (!opts.StripDebug || ppDebugBlob == nullptr) {
  441. SerializeFlags |= SerializeDxilFlags::IncludeDebugInfoPart;
  442. }
  443. }
  444. if (opts.DebugNameForSource) {
  445. SerializeFlags |= SerializeDxilFlags::DebugNameDependOnSource;
  446. }
  447. // Don't do work to put in a container if an error has occurred
  448. // Do not create a container when there is only a a high-level representation in the module.
  449. if (compileOK && !opts.CodeGenHighLevel) {
  450. HRESULT valHR = S_OK;
  451. if (needsValidation) {
  452. valHR = dxcutil::ValidateAndAssembleToContainer(
  453. action.takeModule(), pOutputBlob, pMalloc, SerializeFlags,
  454. pOutputStream, opts.DebugInfo, compiler.getDiagnostics());
  455. } else {
  456. dxcutil::AssembleToContainer(action.takeModule(),
  457. pOutputBlob, pMalloc,
  458. SerializeFlags, pOutputStream);
  459. }
  460. // Callback after valid DXIL is produced
  461. if (SUCCEEDED(valHR)) {
  462. CComPtr<IDxcBlob> pTargetBlob;
  463. if (m_pDxcContainerEventsHandler != nullptr) {
  464. HRESULT hr = m_pDxcContainerEventsHandler->OnDxilContainerBuilt(pOutputBlob, &pTargetBlob);
  465. if (SUCCEEDED(hr) && pTargetBlob != nullptr) {
  466. std::swap(pOutputBlob, pTargetBlob);
  467. }
  468. }
  469. if (ppDebugBlobName && produceFullContainer) {
  470. const DxilContainerHeader *pContainer = reinterpret_cast<DxilContainerHeader *>(pOutputBlob->GetBufferPointer());
  471. DXASSERT(IsValidDxilContainer(pContainer, pOutputBlob->GetBufferSize()), "else invalid container generated");
  472. auto it = std::find_if(begin(pContainer), end(pContainer),
  473. DxilPartIsType(DFCC_ShaderDebugName));
  474. if (it != end(pContainer)) {
  475. const char *pDebugName;
  476. if (GetDxilShaderDebugName(*it, &pDebugName, nullptr) && pDebugName && *pDebugName) {
  477. IFTBOOL(Unicode::UTF8BufferToUTF16ComHeap(pDebugName, &DebugBlobName), DXC_E_CONTAINER_INVALID);
  478. }
  479. }
  480. }
  481. }
  482. }
  483. }
  484. // Add std err to warnings.
  485. msfPtr->WriteStdErrToStream(w);
  486. CreateOperationResultFromOutputs(pOutputBlob, msfPtr, warnings,
  487. compiler.getDiagnostics(), ppResult);
  488. // On success, return values. After assigning ppResult, nothing should fail.
  489. HRESULT status;
  490. DXVERIFY_NOMSG(SUCCEEDED((*ppResult)->GetStatus(&status)));
  491. if (SUCCEEDED(status)) {
  492. if (opts.DebugInfo && ppDebugBlob) {
  493. DXVERIFY_NOMSG(SUCCEEDED(pOutputStream.QueryInterface(ppDebugBlob)));
  494. }
  495. if (ppDebugBlobName) {
  496. *ppDebugBlobName = DebugBlobName.Detach();
  497. }
  498. }
  499. hr = S_OK;
  500. }
  501. CATCH_CPP_ASSIGN_HRESULT();
  502. Cleanup:
  503. DxcEtw_DXCompilerCompile_Stop(hr);
  504. return hr;
  505. }
  506. // Preprocess source text
  507. __override HRESULT STDMETHODCALLTYPE Preprocess(
  508. _In_ IDxcBlob *pSource, // Source text to preprocess
  509. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  510. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  511. _In_ UINT32 argCount, // Number of arguments
  512. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  513. _In_ UINT32 defineCount, // Number of defines
  514. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  515. _COM_Outptr_ IDxcOperationResult **ppResult // Preprocessor output status, buffer, and errors
  516. ) {
  517. if (pSource == nullptr || ppResult == nullptr ||
  518. (defineCount > 0 && pDefines == nullptr) ||
  519. (argCount > 0 && pArguments == nullptr))
  520. return E_INVALIDARG;
  521. *ppResult = nullptr;
  522. HRESULT hr = S_OK;
  523. DxcEtw_DXCompilerPreprocess_Start();
  524. CComPtr<IDxcBlobEncoding> utf8Source;
  525. IFC(hlsl::DxcGetBlobAsUtf8(pSource, &utf8Source));
  526. try {
  527. CComPtr<IMalloc> pMalloc;
  528. CComPtr<AbstractMemoryStream> pOutputStream;
  529. dxcutil::DxcArgsFileSystem *msfPtr;
  530. IFT(dxcutil::CreateDxcArgsFileSystem(utf8Source, pSourceName, pIncludeHandler, &msfPtr));
  531. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  532. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  533. IFTLLVM(pts.error_code());
  534. IFT(CoGetMalloc(1, &pMalloc));
  535. IFT(CreateMemoryStream(pMalloc, &pOutputStream));
  536. const llvm::opt::OptTable *table = ::options::getHlslOptTable();
  537. int argCountInt;
  538. IFT(UIntToInt(argCount, &argCountInt));
  539. hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0);
  540. hlsl::options::DxcOpts opts;
  541. bool finished;
  542. ReadOptsAndValidate(mainArgs, opts, pOutputStream, ppResult, finished);
  543. if (finished) {
  544. hr = S_OK;
  545. goto Cleanup;
  546. }
  547. // Prepare UTF8-encoded versions of API values.
  548. CW2A utf8SourceName(pSourceName, CP_UTF8);
  549. const char *pUtf8SourceName = utf8SourceName.m_psz;
  550. if (pUtf8SourceName == nullptr) {
  551. if (opts.InputFile.empty()) {
  552. pUtf8SourceName = "input.hlsl";
  553. }
  554. else {
  555. pUtf8SourceName = opts.InputFile.data();
  556. }
  557. }
  558. IFT(msfPtr->RegisterOutputStream(L"output.hlsl", pOutputStream));
  559. IFT(msfPtr->CreateStdStreams(pMalloc));
  560. StringRef Data((LPSTR)utf8Source->GetBufferPointer(),
  561. utf8Source->GetBufferSize());
  562. std::unique_ptr<llvm::MemoryBuffer> pBuffer(
  563. llvm::MemoryBuffer::getMemBufferCopy(Data, pUtf8SourceName));
  564. // Not very efficient but also not very important.
  565. std::vector<std::string> defines;
  566. CreateDefineStrings(pDefines, defineCount, defines);
  567. // Setup a compiler instance.
  568. std::string warnings;
  569. raw_string_ostream w(warnings);
  570. raw_stream_ostream outStream(pOutputStream.p);
  571. CompilerInstance compiler;
  572. std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
  573. std::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
  574. SetupCompilerForCompile(compiler, &m_langExtensionsHelper, utf8SourceName, diagPrinter.get(), defines, opts, pArguments, argCount);
  575. msfPtr->SetupForCompilerInstance(compiler);
  576. // The clang entry point (cc1_main) would now create a compiler invocation
  577. // from arguments, but for this path we're exclusively trying to preproces
  578. // to text.
  579. compiler.getFrontendOpts().OutputFile = "output.hlsl";
  580. compiler.WriteDefaultOutputDirectly = true;
  581. compiler.setOutStream(&outStream);
  582. // These settings are back-compatible with fxc.
  583. clang::PreprocessorOutputOptions &PPOutOpts =
  584. compiler.getPreprocessorOutputOpts();
  585. PPOutOpts.ShowCPP = 1; // Print normal preprocessed output.
  586. PPOutOpts.ShowComments = 0; // Show comments.
  587. PPOutOpts.ShowLineMarkers = 1; // Show \#line markers.
  588. PPOutOpts.UseLineDirectives = 1; // Use \#line instead of GCC-style \# N.
  589. PPOutOpts.ShowMacroComments = 0; // Show comments, even in macros.
  590. PPOutOpts.ShowMacros = 0; // Print macro definitions.
  591. PPOutOpts.RewriteIncludes = 0; // Preprocess include directives only.
  592. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  593. clang::PrintPreprocessedAction action;
  594. if (action.BeginSourceFile(compiler, file)) {
  595. action.Execute();
  596. action.EndSourceFile();
  597. }
  598. outStream.flush();
  599. // Add std err to warnings.
  600. msfPtr->WriteStdErrToStream(w);
  601. CreateOperationResultFromOutputs(pOutputStream, msfPtr, warnings,
  602. compiler.getDiagnostics(), ppResult);
  603. hr = S_OK;
  604. }
  605. CATCH_CPP_ASSIGN_HRESULT();
  606. Cleanup:
  607. DxcEtw_DXCompilerPreprocess_Stop(hr);
  608. return hr;
  609. }
  610. // Disassemble a shader.
  611. __override HRESULT STDMETHODCALLTYPE Disassemble(
  612. _In_ IDxcBlob *pProgram, // Program to disassemble.
  613. _COM_Outptr_ IDxcBlobEncoding** ppDisassembly // Disassembly text.
  614. ) {
  615. if (pProgram == nullptr || ppDisassembly == nullptr)
  616. return E_INVALIDARG;
  617. *ppDisassembly = nullptr;
  618. HRESULT hr = S_OK;
  619. DxcEtw_DXCompilerDisassemble_Start();
  620. try {
  621. ::llvm::sys::fs::MSFileSystem *msfPtr;
  622. IFT(CreateMSFileSystemForDisk(&msfPtr));
  623. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  624. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  625. IFTLLVM(pts.error_code());
  626. std::string StreamStr;
  627. raw_string_ostream Stream(StreamStr);
  628. IFC(dxcutil::Disassemble(pProgram, Stream));
  629. IFT(DxcCreateBlobWithEncodingOnHeapCopy(
  630. StreamStr.c_str(), StreamStr.size(), CP_UTF8, ppDisassembly));
  631. return S_OK;
  632. }
  633. CATCH_CPP_ASSIGN_HRESULT();
  634. Cleanup:
  635. DxcEtw_DXCompilerDisassemble_Stop(hr);
  636. return hr;
  637. }
  638. void SetupCompilerForCompile(CompilerInstance &compiler,
  639. _In_ DxcLangExtensionsHelper *helper,
  640. _In_ LPCSTR pMainFile, _In_ TextDiagnosticPrinter *diagPrinter,
  641. _In_ std::vector<std::string>& defines,
  642. _In_ hlsl::options::DxcOpts &Opts,
  643. _In_count_(argCount) LPCWSTR *pArguments,
  644. _In_ UINT32 argCount) {
  645. // Setup a compiler instance.
  646. std::shared_ptr<TargetOptions> targetOptions(new TargetOptions);
  647. targetOptions->Triple = "dxil-ms-dx";
  648. compiler.HlslLangExtensions = helper;
  649. compiler.createDiagnostics(diagPrinter, false);
  650. compiler.createFileManager();
  651. compiler.createSourceManager(compiler.getFileManager());
  652. compiler.setTarget(
  653. TargetInfo::CreateTargetInfo(compiler.getDiagnostics(), targetOptions));
  654. compiler.getFrontendOpts().Inputs.push_back(FrontendInputFile(pMainFile, IK_HLSL));
  655. // Setup debug information.
  656. if (Opts.DebugInfo) {
  657. CodeGenOptions &CGOpts = compiler.getCodeGenOpts();
  658. CGOpts.setDebugInfo(CodeGenOptions::FullDebugInfo);
  659. CGOpts.DebugColumnInfo = 1;
  660. CGOpts.DwarfVersion = 4; // Latest version.
  661. // TODO: consider
  662. // DebugPass, DebugCompilationDir, DwarfDebugFlags, SplitDwarfFile
  663. }
  664. clang::PreprocessorOptions &PPOpts(compiler.getPreprocessorOpts());
  665. for (size_t i = 0; i < defines.size(); ++i) {
  666. PPOpts.addMacroDef(defines[i]);
  667. }
  668. // Pick additional arguments.
  669. clang::HeaderSearchOptions &HSOpts = compiler.getHeaderSearchOpts();
  670. HSOpts.UseBuiltinIncludes = 0;
  671. // Consider: should we force-include '.' if the source file is relative?
  672. for (const llvm::opt::Arg *A : Opts.Args.filtered(options::OPT_I)) {
  673. const bool IsFrameworkFalse = false;
  674. const bool IgnoreSysRoot = true;
  675. if (dxcutil::IsAbsoluteOrCurDirRelative(A->getValue())) {
  676. HSOpts.AddPath(A->getValue(), frontend::Angled, IsFrameworkFalse, IgnoreSysRoot);
  677. }
  678. else {
  679. std::string s("./");
  680. s += A->getValue();
  681. HSOpts.AddPath(s, frontend::Angled, IsFrameworkFalse, IgnoreSysRoot);
  682. }
  683. }
  684. // Apply root signature option.
  685. unsigned rootSigMinor;
  686. if (Opts.ForceRootSigVer.empty() || Opts.ForceRootSigVer == "rootsig_1_1") {
  687. rootSigMinor = 1;
  688. }
  689. else {
  690. DXASSERT(Opts.ForceRootSigVer == "rootsig_1_0",
  691. "else opts should have been rejected");
  692. rootSigMinor = 0;
  693. }
  694. compiler.getLangOpts().RootSigMajor = 1;
  695. compiler.getLangOpts().RootSigMinor = rootSigMinor;
  696. compiler.getLangOpts().HLSL2015 = Opts.HLSL2015;
  697. compiler.getLangOpts().HLSL2016 = Opts.HLSL2016;
  698. compiler.getLangOpts().HLSL2017 = Opts.HLSL2017;
  699. if (Opts.WarningAsError)
  700. compiler.getDiagnostics().setWarningsAsErrors(true);
  701. if (Opts.IEEEStrict)
  702. compiler.getCodeGenOpts().UnsafeFPMath = true;
  703. if (Opts.DisableOptimizations)
  704. compiler.getCodeGenOpts().DisableLLVMOpts = true;
  705. compiler.getCodeGenOpts().OptimizationLevel = Opts.OptLevel;
  706. if (Opts.OptLevel >= 3)
  707. compiler.getCodeGenOpts().UnrollLoops = true;
  708. compiler.getCodeGenOpts().HLSLHighLevel = Opts.CodeGenHighLevel;
  709. compiler.getCodeGenOpts().HLSLAllResourcesBound = Opts.AllResourcesBound;
  710. compiler.getCodeGenOpts().HLSLDefaultRowMajor = Opts.DefaultRowMajor;
  711. compiler.getCodeGenOpts().HLSLPreferControlFlow = Opts.PreferFlowControl;
  712. compiler.getCodeGenOpts().HLSLAvoidControlFlow = Opts.AvoidFlowControl;
  713. compiler.getCodeGenOpts().HLSLNotUseLegacyCBufLoad = Opts.NotUseLegacyCBufLoad;
  714. compiler.getCodeGenOpts().HLSLDefines = defines;
  715. compiler.getCodeGenOpts().MainFileName = pMainFile;
  716. // Translate signature packing options
  717. if (Opts.PackPrefixStable)
  718. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::PrefixStable;
  719. else if (Opts.PackOptimized)
  720. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::Optimized;
  721. else
  722. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::Default;
  723. // Constructing vector of wide strings to pass in to codegen. Just passing
  724. // in pArguments will expose ownership of memory to both CodeGenOptions and
  725. // this caller, which can lead to unexpected behavior.
  726. for (UINT32 i = 0; i != argCount; ++i) {
  727. compiler.getCodeGenOpts().HLSLArguments.emplace_back(
  728. Unicode::UTF16ToUTF8StringOrThrow(pArguments[i]));
  729. }
  730. // Overrding default set of loop unroll.
  731. if (Opts.PreferFlowControl)
  732. compiler.getCodeGenOpts().UnrollLoops = false;
  733. if (Opts.AvoidFlowControl)
  734. compiler.getCodeGenOpts().UnrollLoops = true;
  735. // always inline for hlsl
  736. compiler.getCodeGenOpts().setInlining(
  737. clang::CodeGenOptions::OnlyAlwaysInlining);
  738. compiler.getCodeGenOpts().HLSLExtensionsCodegen = std::make_shared<HLSLExtensionsCodegenHelperImpl>(compiler, m_langExtensionsHelper, Opts.RootSignatureDefine);
  739. }
  740. // IDxcVersionInfo
  741. __override HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) {
  742. if (pMajor == nullptr || pMinor == nullptr)
  743. return E_INVALIDARG;
  744. *pMajor = DXIL::kDxilMajor;
  745. *pMinor = DXIL::kDxilMinor;
  746. return S_OK;
  747. }
  748. __override HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) {
  749. if (pFlags == nullptr)
  750. return E_INVALIDARG;
  751. *pFlags = DxcVersionInfoFlags_None;
  752. #ifdef _DEBUG
  753. *pFlags |= DxcVersionInfoFlags_Debug;
  754. #endif
  755. return S_OK;
  756. }
  757. };
  758. HRESULT CreateDxcCompiler(_In_ REFIID riid, _Out_ LPVOID* ppv) {
  759. CComPtr<DxcCompiler> result = new (std::nothrow) DxcCompiler();
  760. if (result == nullptr) {
  761. *ppv = nullptr;
  762. return E_OUTOFMEMORY;
  763. }
  764. return result.p->QueryInterface(riid, ppv);
  765. }