dxcompilerobj.cpp 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455
  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/DxilRootSignature/DxilRootSignature.h"
  29. #include "dxcutil.h"
  30. #include "dxc/Support/dxcfilesystem.h"
  31. #include "dxc/Support/WinIncludes.h"
  32. #include "dxc/DxilContainer/DxilContainerAssembler.h"
  33. #include "dxc/dxcapi.internal.h"
  34. #include "dxc/DXIL/DxilPDB.h"
  35. #include "dxc/Support/dxcapi.use.h"
  36. #include "dxc/Support/Global.h"
  37. #include "dxc/Support/Unicode.h"
  38. #include "dxc/Support/microcom.h"
  39. #include "dxc/Support/FileIOHelper.h"
  40. #include "dxc/Support/dxcapi.impl.h"
  41. #include "dxc/Support/DxcLangExtensionsHelper.h"
  42. #include "dxc/Support/HLSLOptions.h"
  43. #ifdef _WIN32
  44. #include "dxcetw.h"
  45. #endif
  46. #include "dxillib.h"
  47. #include "dxcompileradapter.h"
  48. #include <algorithm>
  49. #include <cfloat>
  50. // SPIRV change starts
  51. #ifdef ENABLE_SPIRV_CODEGEN
  52. #include "clang/SPIRV/EmitSpirvAction.h"
  53. #endif
  54. // SPIRV change ends
  55. #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
  56. #include "clang/Basic/Version.h"
  57. #endif // SUPPORT_QUERY_GIT_COMMIT_INFO
  58. #define CP_UTF16 1200
  59. using namespace llvm;
  60. using namespace clang;
  61. using namespace hlsl;
  62. using std::string;
  63. DEFINE_CROSS_PLATFORM_UUIDOF(IDxcLangExtensions)
  64. // This declaration is used for the locally-linked validator.
  65. HRESULT CreateDxcValidator(_In_ REFIID riid, _Out_ LPVOID *ppv);
  66. // This internal call allows the validator to avoid having to re-deserialize
  67. // the module. It trusts that the caller didn't make any changes and is
  68. // kept internal because the layout of the module class may change based
  69. // on changes across modules, or picking a different compiler version or CRT.
  70. HRESULT RunInternalValidator(_In_ IDxcValidator *pValidator,
  71. _In_ llvm::Module *pModule,
  72. _In_ llvm::Module *pDebugModule,
  73. _In_ IDxcBlob *pShader, UINT32 Flags,
  74. _In_ IDxcOperationResult **ppResult);
  75. static void CreateOperationResultFromOutputs(
  76. IDxcBlob *pResultBlob, dxcutil::DxcArgsFileSystem *msfPtr,
  77. const std::string &warnings, clang::DiagnosticsEngine &diags,
  78. _COM_Outptr_ IDxcOperationResult **ppResult) {
  79. CComPtr<IStream> pErrorStream;
  80. msfPtr->GetStdOutpuHandleStream(&pErrorStream);
  81. dxcutil::CreateOperationResultFromOutputs(pResultBlob, pErrorStream, warnings,
  82. diags.hasErrorOccurred(), ppResult);
  83. }
  84. static void CreateOperationResultFromOutputs(
  85. AbstractMemoryStream *pOutputStream, dxcutil::DxcArgsFileSystem *msfPtr,
  86. const std::string &warnings, clang::DiagnosticsEngine &diags,
  87. _COM_Outptr_ IDxcOperationResult **ppResult) {
  88. CComPtr<IDxcBlob> pResultBlob;
  89. IFT(pOutputStream->QueryInterface(&pResultBlob));
  90. CreateOperationResultFromOutputs(pResultBlob, msfPtr, warnings, diags,
  91. ppResult);
  92. }
  93. static bool ShouldPartBeIncludedInPDB(UINT32 FourCC) {
  94. switch (FourCC) {
  95. case hlsl::DFCC_ShaderDebugName:
  96. case hlsl::DFCC_ShaderHash:
  97. return true;
  98. }
  99. return false;
  100. }
  101. static HRESULT CreateContainerForPDB(IMalloc *pMalloc, IDxcBlob *pOldContainer, IDxcBlob *pDebugBlob, IDxcBlob **ppNewContaner) {
  102. // If the pContainer is not a valid container, give up.
  103. if (!hlsl::IsValidDxilContainer((hlsl::DxilContainerHeader *)pOldContainer->GetBufferPointer(), pOldContainer->GetBufferSize()))
  104. return E_FAIL;
  105. hlsl::DxilContainerHeader *DxilHeader = (hlsl::DxilContainerHeader *)pOldContainer->GetBufferPointer();
  106. hlsl::DxilProgramHeader *ProgramHeader = nullptr;
  107. struct Part {
  108. typedef std::function<HRESULT(IStream *)> WriteProc;
  109. UINT32 uFourCC = 0;
  110. UINT32 uSize = 0;
  111. WriteProc Writer;
  112. Part(UINT32 uFourCC, UINT32 uSize, WriteProc Writer) :
  113. uFourCC(uFourCC),
  114. uSize(uSize),
  115. Writer(Writer)
  116. {}
  117. };
  118. // Compute offset table.
  119. SmallVector<UINT32, 4> OffsetTable;
  120. SmallVector<Part, 4> PartWriters;
  121. UINT32 uTotalPartsSize = 0;
  122. for (unsigned i = 0; i < DxilHeader->PartCount; i++) {
  123. hlsl::DxilPartHeader *PartHeader = GetDxilContainerPart(DxilHeader, i);
  124. if (ShouldPartBeIncludedInPDB(PartHeader->PartFourCC)) {
  125. OffsetTable.push_back(uTotalPartsSize);
  126. uTotalPartsSize += PartHeader->PartSize + sizeof(*PartHeader);
  127. UINT32 uSize = PartHeader->PartSize;
  128. const void *pPartData = PartHeader+1;
  129. Part NewPart(
  130. PartHeader->PartFourCC,
  131. uSize,
  132. [pPartData, uSize](IStream *pStream) {
  133. ULONG uBytesWritten = 0;
  134. IFR(pStream->Write(pPartData, uSize, &uBytesWritten));
  135. return S_OK;
  136. }
  137. );
  138. PartWriters.push_back(NewPart);
  139. }
  140. // Could use any of these. We're mostly after the header version and all that.
  141. if (PartHeader->PartFourCC == hlsl::DFCC_DXIL ||
  142. PartHeader->PartFourCC == hlsl::DFCC_ShaderDebugInfoDXIL)
  143. {
  144. ProgramHeader = (hlsl::DxilProgramHeader *)(PartHeader+1);
  145. }
  146. }
  147. if (!ProgramHeader)
  148. return E_FAIL;
  149. {
  150. static auto AlignByDword = [](UINT32 uSize, UINT32 *pPaddingBytes) {
  151. UINT32 uRem = uSize % sizeof(UINT32);
  152. UINT32 uResult = (uSize/sizeof(UINT32) + (uRem ? 1 : 0)) * sizeof(UINT32);
  153. *pPaddingBytes = uRem ? (sizeof(UINT32)-uRem) : 0;
  154. return uResult;
  155. };
  156. UINT32 uPaddingSize = 0;
  157. UINT32 uPartSize = AlignByDword(sizeof(hlsl::DxilProgramHeader) + pDebugBlob->GetBufferSize(), &uPaddingSize);
  158. OffsetTable.push_back(uTotalPartsSize);
  159. uTotalPartsSize += uPartSize + sizeof(hlsl::DxilPartHeader);
  160. Part NewPart(
  161. hlsl::DFCC_ShaderDebugInfoDXIL,
  162. uPartSize,
  163. [uPartSize, ProgramHeader, pDebugBlob, uPaddingSize](IStream *pStream) {
  164. hlsl::DxilProgramHeader Header = *ProgramHeader;
  165. Header.BitcodeHeader.BitcodeSize = pDebugBlob->GetBufferSize();
  166. Header.BitcodeHeader.BitcodeOffset = sizeof(hlsl::DxilBitcodeHeader);
  167. Header.SizeInUint32 = uPartSize / sizeof(UINT32);
  168. ULONG uBytesWritten = 0;
  169. IFR(pStream->Write(&Header, sizeof(Header), &uBytesWritten));
  170. IFR(pStream->Write(pDebugBlob->GetBufferPointer(), pDebugBlob->GetBufferSize(), &uBytesWritten));
  171. if(uPaddingSize) {
  172. UINT32 uPadding = 0;
  173. assert(uPaddingSize <= sizeof(uPadding) && "Padding size calculation is wrong.");
  174. IFR(pStream->Write(&uPadding, uPaddingSize, &uBytesWritten));
  175. }
  176. return S_OK;
  177. }
  178. );
  179. PartWriters.push_back(NewPart);
  180. }
  181. // Offset the offset table by the offset table itself
  182. for (unsigned i = 0; i < OffsetTable.size(); i++)
  183. OffsetTable[i] += sizeof(hlsl::DxilContainerHeader) + OffsetTable.size() * sizeof(UINT32);
  184. // Create the new header
  185. hlsl::DxilContainerHeader NewDxilHeader = *DxilHeader;
  186. NewDxilHeader.PartCount = OffsetTable.size();
  187. NewDxilHeader.ContainerSizeInBytes =
  188. sizeof(NewDxilHeader) +
  189. OffsetTable.size() * sizeof(UINT32) +
  190. uTotalPartsSize;
  191. // Write it to the result stream
  192. ULONG uSizeWritten = 0;
  193. CComPtr<hlsl::AbstractMemoryStream> pStrippedContainerStream;
  194. IFR(hlsl::CreateMemoryStream(pMalloc, &pStrippedContainerStream));
  195. IFR(pStrippedContainerStream->Write(&NewDxilHeader, sizeof(NewDxilHeader), &uSizeWritten));
  196. // Write offset table
  197. IFR(pStrippedContainerStream->Write(OffsetTable.data(), OffsetTable.size() * sizeof(OffsetTable.data()[0]), &uSizeWritten));
  198. for (unsigned i = 0; i < PartWriters.size(); i++) {
  199. auto &Writer = PartWriters[i];
  200. hlsl::DxilPartHeader PartHeader = {};
  201. PartHeader.PartFourCC = Writer.uFourCC;
  202. PartHeader.PartSize = Writer.uSize;
  203. IFR(pStrippedContainerStream->Write(&PartHeader, sizeof(PartHeader), &uSizeWritten));
  204. IFR(Writer.Writer(pStrippedContainerStream));
  205. }
  206. IFR(pStrippedContainerStream.QueryInterface(ppNewContaner));
  207. return S_OK;
  208. }
  209. #ifdef _WIN32
  210. #pragma fenv_access(on)
  211. struct DefaultFPEnvScope
  212. {
  213. // _controlfp_s is non-standard and <cfenv>.feholdexceptions doesn't work on windows...?
  214. unsigned int previousValue;
  215. DefaultFPEnvScope() {
  216. // _controlfp_s returns the value of the control word as it is after
  217. // the call, not before the call. This is the proper way to get the
  218. // previous value.
  219. errno_t error = _controlfp_s(&previousValue, 0, 0);
  220. IFT(error == 0 ? S_OK : E_FAIL);
  221. // No exceptions, preserve denormals & round to nearest.
  222. unsigned int newValue;
  223. error = _controlfp_s(&newValue, _MCW_EM | _DN_SAVE | _RC_NEAR,
  224. _MCW_EM | _MCW_DN | _MCW_RC);
  225. IFT(error == 0 ? S_OK : E_FAIL);
  226. }
  227. ~DefaultFPEnvScope() {
  228. _clearfp();
  229. unsigned int newValue;
  230. errno_t error = _controlfp_s(&newValue, previousValue, _MCW_EM | _MCW_DN | _MCW_RC);
  231. // During cleanup we can't throw as we might already be handling another one.
  232. DXASSERT_LOCALVAR(error, error == 0, "Failed to restore floating-point environment.");
  233. }
  234. };
  235. #else // _WIN32
  236. struct DefaultFPEnvScope {
  237. DefaultFPEnvScope() {} // Dummy ctor to avoid unused local warning
  238. };
  239. #endif // _WIN32
  240. class HLSLExtensionsCodegenHelperImpl : public HLSLExtensionsCodegenHelper {
  241. private:
  242. CompilerInstance &m_CI;
  243. DxcLangExtensionsHelper &m_langExtensionsHelper;
  244. std::string m_rootSigDefine;
  245. // The metadata format is a root node that has pointers to metadata
  246. // nodes for each define. The metatdata node for a define is a pair
  247. // of (name, value) metadata strings.
  248. //
  249. // Example:
  250. // !hlsl.semdefs = {!0, !1}
  251. // !0 = !{!"FOO", !"BAR"}
  252. // !1 = !{!"BOO", !"HOO"}
  253. void WriteSemanticDefines(llvm::Module *M, const ParsedSemanticDefineList &defines) {
  254. // Create all metadata nodes for each define. Each node is a (name, value) pair.
  255. std::vector<MDNode *> mdNodes;
  256. for (const ParsedSemanticDefine &define : defines) {
  257. MDString *name = MDString::get(M->getContext(), define.Name);
  258. MDString *value = MDString::get(M->getContext(), define.Value);
  259. mdNodes.push_back(MDNode::get(M->getContext(), { name, value }));
  260. }
  261. // Add root node with pointers to all define metadata nodes.
  262. NamedMDNode *Root = M->getOrInsertNamedMetadata(m_langExtensionsHelper.GetSemanticDefineMetadataName());
  263. for (MDNode *node : mdNodes)
  264. Root->addOperand(node);
  265. }
  266. SemanticDefineErrorList GetValidatedSemanticDefines(const ParsedSemanticDefineList &defines, ParsedSemanticDefineList &validated, SemanticDefineErrorList &errors) {
  267. for (const ParsedSemanticDefine &define : defines) {
  268. DxcLangExtensionsHelper::SemanticDefineValidationResult result = m_langExtensionsHelper.ValidateSemanticDefine(define.Name, define.Value);
  269. if (result.HasError())
  270. errors.emplace_back(SemanticDefineError(define.Location, SemanticDefineError::Level::Error, result.Error));
  271. if (result.HasWarning())
  272. errors.emplace_back(SemanticDefineError(define.Location, SemanticDefineError::Level::Warning, result.Warning));
  273. if (!result.HasError())
  274. validated.emplace_back(define);
  275. }
  276. return errors;
  277. }
  278. public:
  279. HLSLExtensionsCodegenHelperImpl(CompilerInstance &CI, DxcLangExtensionsHelper &langExtensionsHelper, StringRef rootSigDefine)
  280. : m_CI(CI), m_langExtensionsHelper(langExtensionsHelper)
  281. , m_rootSigDefine(rootSigDefine)
  282. {}
  283. // Write semantic defines as metadata in the module.
  284. virtual std::vector<SemanticDefineError> WriteSemanticDefines(llvm::Module *M) override {
  285. // Grab the semantic defines seen by the parser.
  286. ParsedSemanticDefineList defines =
  287. CollectSemanticDefinesParsedByCompiler(m_CI, &m_langExtensionsHelper);
  288. // Nothing to do if we have no defines.
  289. SemanticDefineErrorList errors;
  290. if (!defines.size())
  291. return errors;
  292. ParsedSemanticDefineList validated;
  293. GetValidatedSemanticDefines(defines, validated, errors);
  294. WriteSemanticDefines(M, validated);
  295. return errors;
  296. }
  297. virtual std::string GetIntrinsicName(UINT opcode) override {
  298. return m_langExtensionsHelper.GetIntrinsicName(opcode);
  299. }
  300. virtual bool GetDxilOpcode(UINT opcode, OP::OpCode &dxilOpcode) override {
  301. UINT dop = static_cast<UINT>(OP::OpCode::NumOpCodes);
  302. if (m_langExtensionsHelper.GetDxilOpCode(opcode, dop)) {
  303. if (dop < static_cast<UINT>(OP::OpCode::NumOpCodes)) {
  304. dxilOpcode = static_cast<OP::OpCode>(dop);
  305. return true;
  306. }
  307. }
  308. return false;
  309. }
  310. virtual HLSLExtensionsCodegenHelper::CustomRootSignature::Status GetCustomRootSignature(CustomRootSignature *out) override {
  311. // Find macro definition in preprocessor.
  312. Preprocessor &pp = m_CI.getPreprocessor();
  313. MacroInfo *macro = MacroExpander::FindMacroInfo(pp, m_rootSigDefine);
  314. if (!macro)
  315. return CustomRootSignature::NOT_FOUND;
  316. // Combine tokens into single string
  317. MacroExpander expander(pp, MacroExpander::STRIP_QUOTES);
  318. if (!expander.ExpandMacro(macro, &out->RootSignature))
  319. return CustomRootSignature::NOT_FOUND;
  320. // Record source location of root signature macro.
  321. out->EncodedSourceLocation = macro->getDefinitionLoc().getRawEncoding();
  322. return CustomRootSignature::FOUND;
  323. }
  324. };
  325. static void CreateDefineStrings(
  326. _In_count_(defineCount) const DxcDefine *pDefines,
  327. UINT defineCount,
  328. std::vector<std::string> &defines) {
  329. // Not very efficient but also not very important.
  330. for (UINT32 i = 0; i < defineCount; i++) {
  331. CW2A utf8Name(pDefines[i].Name, CP_UTF8);
  332. CW2A utf8Value(pDefines[i].Value, CP_UTF8);
  333. std::string val(utf8Name.m_psz);
  334. val += "=";
  335. val += (pDefines[i].Value) ? utf8Value.m_psz : "1";
  336. defines.push_back(val);
  337. }
  338. }
  339. class DxcCompiler : public IDxcCompiler3,
  340. public IDxcLangExtensions,
  341. public IDxcContainerEvent,
  342. #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
  343. public IDxcVersionInfo2
  344. #else
  345. public IDxcVersionInfo
  346. #endif // SUPPORT_QUERY_GIT_COMMIT_INFO
  347. {
  348. private:
  349. DXC_MICROCOM_TM_REF_FIELDS()
  350. DxcLangExtensionsHelper m_langExtensionsHelper;
  351. CComPtr<IDxcContainerEventsHandler> m_pDxcContainerEventsHandler;
  352. DxcCompilerAdapter m_DxcCompilerAdapter;
  353. public:
  354. DxcCompiler(IMalloc *pMalloc) : m_dwRef(0), m_pMalloc(pMalloc), m_DxcCompilerAdapter(this, pMalloc) {}
  355. DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
  356. DXC_MICROCOM_TM_ALLOC(DxcCompiler)
  357. DXC_LANGEXTENSIONS_HELPER_IMPL(m_langExtensionsHelper)
  358. HRESULT STDMETHODCALLTYPE RegisterDxilContainerEventHandler(IDxcContainerEventsHandler *pHandler, UINT64 *pCookie) override {
  359. DXASSERT(m_pDxcContainerEventsHandler == nullptr, "else events handler is already registered");
  360. *pCookie = 1; // Only one EventsHandler supported
  361. m_pDxcContainerEventsHandler = pHandler;
  362. return S_OK;
  363. };
  364. HRESULT STDMETHODCALLTYPE UnRegisterDxilContainerEventHandler(UINT64 cookie) override {
  365. DXASSERT(m_pDxcContainerEventsHandler != nullptr, "else unregister should not have been called");
  366. m_pDxcContainerEventsHandler.Release();
  367. return S_OK;
  368. }
  369. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
  370. HRESULT hr = DoBasicQueryInterface<
  371. IDxcCompiler3,
  372. IDxcLangExtensions,
  373. IDxcContainerEvent,
  374. IDxcVersionInfo
  375. #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
  376. ,IDxcVersionInfo2
  377. #endif // SUPPORT_QUERY_GIT_COMMIT_INFO
  378. >
  379. (this, iid, ppvObject);
  380. if (FAILED(hr)) {
  381. return DoBasicQueryInterface<IDxcCompiler, IDxcCompiler2>(&m_DxcCompilerAdapter, iid, ppvObject);
  382. }
  383. return hr;
  384. }
  385. // Compile a single entry point to the target shader model with debug information.
  386. HRESULT STDMETHODCALLTYPE Compile(
  387. _In_ const DxcBuffer *pSource, // Source text to compile
  388. _In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  389. _In_ UINT32 argCount, // Number of arguments
  390. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  391. _In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, buffer, and errors
  392. ) override {
  393. if (pSource == nullptr ||
  394. (argCount > 0 && pArguments == nullptr))
  395. return E_INVALIDARG;
  396. if (!(IsEqualIID(riid, __uuidof(IDxcResult)) ||
  397. IsEqualIID(riid, __uuidof(IDxcOperationResult))))
  398. return E_INVALIDARG;
  399. *ppResult = nullptr;
  400. HRESULT hr = S_OK;
  401. CComPtr<IDxcBlobUtf8> utf8Source;
  402. CComPtr<AbstractMemoryStream> pOutputStream;
  403. CComPtr<IDxcOperationResult> pDxcOperationResult;
  404. bool bCompileStarted = false;
  405. bool bPreprocessStarted = false;
  406. DxilShaderHash ShaderHashContent;
  407. DxcThreadMalloc TM(m_pMalloc);
  408. try {
  409. DefaultFPEnvScope fpEnvScope;
  410. IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
  411. // Parse command-line options into DxcOpts
  412. int argCountInt;
  413. IFT(UIntToInt(argCount, &argCountInt));
  414. hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0);
  415. hlsl::options::DxcOpts opts;
  416. std::string warnings;
  417. raw_string_ostream w(warnings);
  418. {
  419. bool finished = false;
  420. CComPtr<AbstractMemoryStream> pOptionErrorStream;
  421. IFT(CreateMemoryStream(m_pMalloc, &pOptionErrorStream));
  422. dxcutil::ReadOptsAndValidate(mainArgs, opts, pOptionErrorStream, &pDxcOperationResult, finished);
  423. if (finished) {
  424. IFT(pDxcOperationResult->QueryInterface(riid, ppResult));
  425. hr = S_OK;
  426. goto Cleanup;
  427. }
  428. if (pOptionErrorStream->GetPtrSize() > 0) {
  429. w << StringRef((const char*)pOptionErrorStream->GetPtr(), (size_t)pOptionErrorStream->GetPtrSize());
  430. }
  431. }
  432. bool isPreprocessing = !opts.Preprocess.empty();
  433. if (isPreprocessing) {
  434. DxcEtw_DXCompilerPreprocess_Start();
  435. bPreprocessStarted = true;
  436. } else {
  437. DxcEtw_DXCompilerCompile_Start();
  438. bCompileStarted = true;
  439. }
  440. CComPtr<DxcResult> pResult = DxcResult::Alloc(m_pMalloc);
  441. IFT(pResult->SetEncoding(opts.DefaultTextCodePage));
  442. DxcOutputObject primaryOutput;
  443. // Formerly API values.
  444. const char *pUtf8SourceName = opts.InputFile.empty() ? "hlsl.hlsl" : opts.InputFile.data();
  445. CA2W pUtf16SourceName(pUtf8SourceName, CP_UTF8);
  446. const char *pUtf8EntryPoint = opts.EntryPoint.empty() ? "main" : opts.EntryPoint.data();
  447. const char *pUtf8OutputName = isPreprocessing
  448. ? opts.Preprocess.data()
  449. : opts.OutputObject.empty()
  450. ? "" : opts.OutputObject.data();
  451. CA2W pUtf16OutputName(isPreprocessing ?
  452. opts.Preprocess.data() : pUtf8OutputName,
  453. CP_UTF8);
  454. LPCWSTR pObjectName = (!isPreprocessing && opts.OutputObject.empty()) ?
  455. nullptr : pUtf16OutputName.m_psz;
  456. IFT(primaryOutput.SetName(pObjectName));
  457. // Wrap source in blob
  458. CComPtr<IDxcBlobEncoding> pSourceEncoding;
  459. IFT(hlsl::DxcCreateBlob(pSource->Ptr, pSource->Size,
  460. true, false, pSource->Encoding != 0, pSource->Encoding,
  461. nullptr, &pSourceEncoding));
  462. #ifdef ENABLE_SPIRV_CODEGEN
  463. // We want to embed the preprocessed source code in the final SPIR-V if
  464. // debug information is enabled. Therefore, we invoke Preprocess() here
  465. // first for such case. Then we invoke the compilation process over the
  466. // preprocessed source code, so that line numbers are consistent with the
  467. // embedded source code.
  468. if (!isPreprocessing && opts.GenSPIRV && opts.DebugInfo) {
  469. CComPtr<IDxcResult> pSrcCodeResult;
  470. std::vector<LPCWSTR> PreprocessArgs;
  471. PreprocessArgs.reserve(argCount + 1);
  472. PreprocessArgs.assign(pArguments, pArguments + argCount);
  473. PreprocessArgs.push_back(L"-P");
  474. PreprocessArgs.push_back(L"preprocessed.hlsl");
  475. IFT(Compile(pSource, PreprocessArgs.data(), PreprocessArgs.size(), pIncludeHandler, IID_PPV_ARGS(&pSrcCodeResult)));
  476. HRESULT status;
  477. IFT(pSrcCodeResult->GetStatus(&status));
  478. if (SUCCEEDED(status)) {
  479. pSourceEncoding.Release();
  480. IFT(pSrcCodeResult->GetOutput(DXC_OUT_HLSL, IID_PPV_ARGS(&pSourceEncoding), nullptr));
  481. }
  482. }
  483. #endif // ENABLE_SPIRV_CODEGEN
  484. // Convert source code encoding
  485. IFC(hlsl::DxcGetBlobAsUtf8(pSourceEncoding, m_pMalloc, &utf8Source));
  486. CComPtr<IDxcBlob> pOutputBlob;
  487. dxcutil::DxcArgsFileSystem *msfPtr =
  488. dxcutil::CreateDxcArgsFileSystem(utf8Source, pUtf16SourceName.m_psz, pIncludeHandler);
  489. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  490. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  491. IFTLLVM(pts.error_code());
  492. IFT(pOutputStream.QueryInterface(&pOutputBlob));
  493. primaryOutput.kind = DXC_OUT_OBJECT;
  494. if (opts.AstDump || opts.OptDump)
  495. primaryOutput.kind = DXC_OUT_TEXT;
  496. else if (isPreprocessing)
  497. primaryOutput.kind = DXC_OUT_HLSL;
  498. IFT(pResult->SetOutputName(DXC_OUT_REFLECTION, opts.OutputReflectionFile));
  499. IFT(pResult->SetOutputName(DXC_OUT_SHADER_HASH, opts.OutputShaderHashFile));
  500. IFT(pResult->SetOutputName(DXC_OUT_ERRORS, opts.OutputWarningsFile));
  501. IFT(pResult->SetOutputName(DXC_OUT_ROOT_SIGNATURE, opts.OutputRootSigFile));
  502. if (opts.DisplayIncludeProcess)
  503. msfPtr->EnableDisplayIncludeProcess();
  504. IFT(msfPtr->RegisterOutputStream(L"output.bc", pOutputStream));
  505. IFT(msfPtr->CreateStdStreams(m_pMalloc));
  506. StringRef Data(utf8Source->GetStringPointer(),
  507. utf8Source->GetStringLength());
  508. // Not very efficient but also not very important.
  509. std::vector<std::string> defines;
  510. CreateDefineStrings(opts.Defines.data(), opts.Defines.size(), defines);
  511. // Setup a compiler instance.
  512. raw_stream_ostream outStream(pOutputStream.p);
  513. llvm::LLVMContext llvmContext; // LLVMContext should outlive CompilerInstance
  514. CompilerInstance compiler;
  515. std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
  516. llvm::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
  517. SetupCompilerForCompile(compiler, &m_langExtensionsHelper, pUtf8SourceName, diagPrinter.get(), defines, opts, pArguments, argCount);
  518. msfPtr->SetupForCompilerInstance(compiler);
  519. // The clang entry point (cc1_main) would now create a compiler invocation
  520. // from arguments, but depending on the Preprocess option, we either compile
  521. // to LLVM bitcode and then package that into a DXBC blob, or preprocess to
  522. // HLSL text.
  523. //
  524. // With the compiler invocation built from command line arguments, the
  525. // next step is to call ExecuteCompilerInvocation, which creates a
  526. // FrontendAction* of EmitBCAction, which is a CodeGenAction, which is an
  527. // ASTFrontendAction. That sets up a BackendConsumer as the ASTConsumer.
  528. compiler.getFrontendOpts().OutputFile = "output.bc";
  529. compiler.WriteDefaultOutputDirectly = true;
  530. compiler.setOutStream(&outStream);
  531. unsigned rootSigMajor = 0;
  532. unsigned rootSigMinor = 0;
  533. // NOTE: this calls the validation component from dxil.dll; the built-in
  534. // validator can be used as a fallback.
  535. bool produceFullContainer = false;
  536. bool needsValidation = false;
  537. if (isPreprocessing) {
  538. // These settings are back-compatible with fxc.
  539. clang::PreprocessorOutputOptions &PPOutOpts =
  540. compiler.getPreprocessorOutputOpts();
  541. PPOutOpts.ShowCPP = 1; // Print normal preprocessed output.
  542. PPOutOpts.ShowComments = 0; // Show comments.
  543. PPOutOpts.ShowLineMarkers = 1; // Show \#line markers.
  544. PPOutOpts.UseLineDirectives = 1; // Use \#line instead of GCC-style \# N.
  545. PPOutOpts.ShowMacroComments = 0; // Show comments, even in macros.
  546. PPOutOpts.ShowMacros = 0; // Print macro definitions.
  547. PPOutOpts.RewriteIncludes = 0; // Preprocess include directives only.
  548. FrontendInputFile file(pUtf8SourceName, IK_HLSL);
  549. clang::PrintPreprocessedAction action;
  550. if (action.BeginSourceFile(compiler, file)) {
  551. action.Execute();
  552. action.EndSourceFile();
  553. }
  554. outStream.flush();
  555. } else {
  556. compiler.getLangOpts().HLSLEntryFunction =
  557. compiler.getCodeGenOpts().HLSLEntryFunction = pUtf8EntryPoint;
  558. compiler.getLangOpts().HLSLProfile =
  559. compiler.getCodeGenOpts().HLSLProfile = opts.TargetProfile;
  560. if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_1") {
  561. rootSigMajor = 1;
  562. rootSigMinor = 1;
  563. } else if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_0") {
  564. rootSigMajor = 1;
  565. rootSigMinor = 0;
  566. }
  567. compiler.getLangOpts().IsHLSLLibrary = opts.IsLibraryProfile();
  568. // Clear entry function if library target
  569. if (compiler.getLangOpts().IsHLSLLibrary)
  570. compiler.getLangOpts().HLSLEntryFunction =
  571. compiler.getCodeGenOpts().HLSLEntryFunction = "";
  572. // NOTE: this calls the validation component from dxil.dll; the built-in
  573. // validator can be used as a fallback.
  574. produceFullContainer = !opts.CodeGenHighLevel && !opts.AstDump && !opts.OptDump && rootSigMajor == 0;
  575. needsValidation = produceFullContainer && !opts.DisableValidation;
  576. if (compiler.getCodeGenOpts().HLSLProfile == "lib_6_x") {
  577. // Currently do not support stripping reflection from offline linking target.
  578. opts.KeepReflectionInDxil = true;
  579. }
  580. if (opts.ValVerMajor != UINT_MAX) {
  581. // user-specified validator version override
  582. compiler.getCodeGenOpts().HLSLValidatorMajorVer = opts.ValVerMajor;
  583. compiler.getCodeGenOpts().HLSLValidatorMinorVer = opts.ValVerMinor;
  584. } else {
  585. // Version from dxil.dll, or internal validator if unavailable
  586. dxcutil::GetValidatorVersion(&compiler.getCodeGenOpts().HLSLValidatorMajorVer,
  587. &compiler.getCodeGenOpts().HLSLValidatorMinorVer);
  588. }
  589. }
  590. if (opts.AstDump) {
  591. clang::ASTDumpAction dumpAction;
  592. // Consider - ASTDumpFilter, ASTDumpLookups
  593. compiler.getFrontendOpts().ASTDumpDecls = true;
  594. FrontendInputFile file(pUtf8SourceName, IK_HLSL);
  595. dumpAction.BeginSourceFile(compiler, file);
  596. dumpAction.Execute();
  597. dumpAction.EndSourceFile();
  598. outStream.flush();
  599. }
  600. else if (opts.OptDump) {
  601. EmitOptDumpAction action(&llvmContext);
  602. FrontendInputFile file(pUtf8SourceName, IK_HLSL);
  603. action.BeginSourceFile(compiler, file);
  604. action.Execute();
  605. action.EndSourceFile();
  606. outStream.flush();
  607. }
  608. else if (rootSigMajor) {
  609. HLSLRootSignatureAction action(
  610. compiler.getCodeGenOpts().HLSLEntryFunction, rootSigMajor,
  611. rootSigMinor);
  612. FrontendInputFile file(pUtf8SourceName, IK_HLSL);
  613. action.BeginSourceFile(compiler, file);
  614. action.Execute();
  615. action.EndSourceFile();
  616. outStream.flush();
  617. // Don't do work to put in a container if an error has occurred
  618. bool compileOK = !compiler.getDiagnostics().hasErrorOccurred();
  619. if (compileOK) {
  620. auto rootSigHandle = action.takeRootSigHandle();
  621. CComPtr<AbstractMemoryStream> pContainerStream;
  622. IFT(CreateMemoryStream(m_pMalloc, &pContainerStream));
  623. SerializeDxilContainerForRootSignature(rootSigHandle.get(),
  624. pContainerStream);
  625. pOutputBlob.Release();
  626. IFT(pContainerStream.QueryInterface(&pOutputBlob));
  627. if (!opts.DisableValidation) {
  628. CComPtr<IDxcBlobEncoding> pValErrors;
  629. // Validation failure communicated through diagnostic error
  630. dxcutil::ValidateRootSignatureInContainer(
  631. pOutputBlob, &compiler.getDiagnostics());
  632. }
  633. }
  634. }
  635. // SPIRV change starts
  636. #ifdef ENABLE_SPIRV_CODEGEN
  637. else if (!isPreprocessing && opts.GenSPIRV) {
  638. // Since SpirvOptions is passed to the SPIR-V CodeGen as a whole
  639. // structure, we need to copy a few non-spirv-specific options into the
  640. // structure.
  641. opts.SpirvOptions.enable16BitTypes = opts.Enable16BitTypes;
  642. opts.SpirvOptions.codeGenHighLevel = opts.CodeGenHighLevel;
  643. opts.SpirvOptions.defaultRowMajor = opts.DefaultRowMajor;
  644. opts.SpirvOptions.disableValidation = opts.DisableValidation;
  645. // Store a string representation of command line options.
  646. if (opts.DebugInfo)
  647. for (auto opt : mainArgs.getArrayRef())
  648. opts.SpirvOptions.clOptions += " " + std::string(opt);
  649. compiler.getCodeGenOpts().SpirvOptions = opts.SpirvOptions;
  650. clang::EmitSpirvAction action;
  651. FrontendInputFile file(pUtf8SourceName, IK_HLSL);
  652. action.BeginSourceFile(compiler, file);
  653. action.Execute();
  654. action.EndSourceFile();
  655. outStream.flush();
  656. }
  657. #endif
  658. // SPIRV change ends
  659. else if (!isPreprocessing) {
  660. EmitBCAction action(&llvmContext);
  661. FrontendInputFile file(pUtf8SourceName, IK_HLSL);
  662. bool compileOK;
  663. if (action.BeginSourceFile(compiler, file)) {
  664. action.Execute();
  665. action.EndSourceFile();
  666. compileOK = !compiler.getDiagnostics().hasErrorOccurred();
  667. }
  668. else {
  669. compileOK = false;
  670. }
  671. outStream.flush();
  672. SerializeDxilFlags SerializeFlags = SerializeDxilFlags::None;
  673. if (opts.EmbedPDBName()) {
  674. SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
  675. }
  676. // If -Qembed_debug specified, embed the debug info.
  677. // Or, if there is no output pointer for the debug blob (such as when called by Compile()),
  678. // embed the debug info and emit a note.
  679. if (opts.EmbedDebugInfo()) {
  680. SerializeFlags |= SerializeDxilFlags::IncludeDebugInfoPart;
  681. }
  682. if (opts.DebugNameForSource) {
  683. // Implies name part
  684. SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
  685. SerializeFlags |= SerializeDxilFlags::DebugNameDependOnSource;
  686. } else if (opts.DebugNameForBinary) {
  687. // Implies name part
  688. SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
  689. }
  690. if (!opts.KeepReflectionInDxil) {
  691. SerializeFlags |= SerializeDxilFlags::StripReflectionFromDxilPart;
  692. }
  693. if (!opts.StripReflection) {
  694. SerializeFlags |= SerializeDxilFlags::IncludeReflectionPart;
  695. }
  696. if (opts.StripRootSignature) {
  697. SerializeFlags |= SerializeDxilFlags::StripRootSignature;
  698. }
  699. // Don't do work to put in a container if an error has occurred
  700. // Do not create a container when there is only a a high-level representation in the module.
  701. if (compileOK && !opts.CodeGenHighLevel) {
  702. HRESULT valHR = S_OK;
  703. CComPtr<AbstractMemoryStream> pReflectionStream;
  704. CComPtr<AbstractMemoryStream> pRootSigStream;
  705. IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pReflectionStream));
  706. IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pRootSigStream));
  707. dxcutil::AssembleInputs inputs(
  708. action.takeModule(), pOutputBlob, m_pMalloc, SerializeFlags,
  709. pOutputStream, opts.IsDebugInfoEnabled(),
  710. opts.GetPDBName(), &compiler.getDiagnostics(),
  711. &ShaderHashContent, pReflectionStream, pRootSigStream);
  712. if (needsValidation) {
  713. valHR = dxcutil::ValidateAndAssembleToContainer(inputs);
  714. } else {
  715. dxcutil::AssembleToContainer(inputs);
  716. }
  717. // Callback after valid DXIL is produced
  718. if (SUCCEEDED(valHR)) {
  719. CComPtr<IDxcBlob> pTargetBlob;
  720. if (m_pDxcContainerEventsHandler != nullptr) {
  721. HRESULT hr = m_pDxcContainerEventsHandler->OnDxilContainerBuilt(pOutputBlob, &pTargetBlob);
  722. if (SUCCEEDED(hr) && pTargetBlob != nullptr) {
  723. std::swap(pOutputBlob, pTargetBlob);
  724. }
  725. }
  726. if (pOutputBlob && produceFullContainer && (SerializeFlags & SerializeDxilFlags::IncludeDebugNamePart) != 0) {
  727. const DxilContainerHeader *pContainer = reinterpret_cast<DxilContainerHeader *>(pOutputBlob->GetBufferPointer());
  728. DXASSERT(IsValidDxilContainer(pContainer, pOutputBlob->GetBufferSize()), "else invalid container generated");
  729. auto it = std::find_if(begin(pContainer), end(pContainer), DxilPartIsType(DFCC_ShaderDebugName));
  730. if (it != end(pContainer)) {
  731. const char *pDebugName;
  732. if (GetDxilShaderDebugName(*it, &pDebugName, nullptr) && pDebugName && *pDebugName) {
  733. IFT(pResult->SetOutputName(DXC_OUT_PDB, pDebugName));
  734. }
  735. }
  736. }
  737. if (pReflectionStream && pReflectionStream->GetPtrSize()) {
  738. CComPtr<IDxcBlob> pReflection;
  739. IFT(pReflectionStream->QueryInterface(&pReflection));
  740. IFT(pResult->SetOutputObject(DXC_OUT_REFLECTION, pReflection));
  741. }
  742. if (pRootSigStream && pRootSigStream->GetPtrSize()) {
  743. CComPtr<IDxcBlob> pRootSignature;
  744. IFT(pRootSigStream->QueryInterface(&pRootSignature));
  745. if (needsValidation) {
  746. CComPtr<IDxcBlobEncoding> pValErrors;
  747. // Validation failure communicated through diagnostic error
  748. dxcutil::ValidateRootSignatureInContainer(pRootSignature, &compiler.getDiagnostics());
  749. }
  750. IFT(pResult->SetOutputObject(DXC_OUT_ROOT_SIGNATURE, pRootSignature));
  751. }
  752. CComPtr<IDxcBlob> pHashBlob;
  753. IFT(hlsl::DxcCreateBlobOnHeapCopy(&ShaderHashContent, (UINT32)sizeof(ShaderHashContent), &pHashBlob));
  754. IFT(pResult->SetOutputObject(DXC_OUT_SHADER_HASH, pHashBlob));
  755. } // SUCCEEDED(valHR)
  756. } // compileOK && !opts.CodeGenHighLevel
  757. }
  758. // Add std err to warnings.
  759. msfPtr->WriteStdErrToStream(w);
  760. CComPtr<IStream> pErrorStream;
  761. msfPtr->GetStdOutpuHandleStream(&pErrorStream);
  762. CComPtr<IDxcBlob> pErrorBlob;
  763. IFT(pErrorStream.QueryInterface(&pErrorBlob));
  764. if (IsBlobNullOrEmpty(pErrorBlob)) {
  765. IFT(pResult->SetOutputString(DXC_OUT_ERRORS, warnings.c_str(), warnings.size()));
  766. } else {
  767. IFT(pResult->SetOutputObject(DXC_OUT_ERRORS, pErrorBlob));
  768. }
  769. bool hasErrorOccurred = compiler.getDiagnostics().hasErrorOccurred();
  770. // SPIRV change starts
  771. #if defined(ENABLE_SPIRV_CODEGEN)
  772. bool writePDB = !opts.GenSPIRV;
  773. #else
  774. bool writePDB = true;
  775. #endif
  776. // SPIRV change ends
  777. if (!hasErrorOccurred) {
  778. if (writePDB && opts.IsDebugInfoEnabled() && !opts.CodeGenHighLevel &&
  779. !opts.OptDump) {
  780. CComPtr<IDxcBlob> pDebugBlob;
  781. IFT(pOutputStream.QueryInterface(&pDebugBlob));
  782. CComPtr<IDxcBlob> pStrippedContainer;
  783. IFT(CreateContainerForPDB(m_pMalloc, pOutputBlob, pDebugBlob, &pStrippedContainer));
  784. pDebugBlob.Release();
  785. IFT(hlsl::pdb::WriteDxilPDB(m_pMalloc, pStrippedContainer, ShaderHashContent.Digest, &pDebugBlob));
  786. IFT(pResult->SetOutputObject(DXC_OUT_PDB, pDebugBlob));
  787. }
  788. }
  789. IFT(primaryOutput.SetObject(pOutputBlob, opts.DefaultTextCodePage));
  790. IFT(pResult->SetOutput(primaryOutput));
  791. IFT(pResult->SetStatusAndPrimaryResult(hasErrorOccurred ? E_FAIL : S_OK, primaryOutput.kind));
  792. IFT(pResult->QueryInterface(riid, ppResult));
  793. hr = S_OK;
  794. } catch (std::bad_alloc &) {
  795. hr = E_OUTOFMEMORY;
  796. } catch (hlsl::Exception &e) {
  797. _Analysis_assume_(DXC_FAILED(e.hr));
  798. CComPtr<IDxcResult> pResult;
  799. hr = e.hr;
  800. if (SUCCEEDED(DxcResult::Create(e.hr, DXC_OUT_NONE, {
  801. DxcOutputObject::ErrorOutput(CP_UTF8,
  802. e.msg.c_str(), e.msg.size())
  803. }, &pResult)) &&
  804. SUCCEEDED(pResult->QueryInterface(riid, ppResult))) {
  805. hr = S_OK;
  806. }
  807. } catch (...) {
  808. hr = E_FAIL;
  809. }
  810. Cleanup:
  811. if (bPreprocessStarted) {
  812. DxcEtw_DXCompilerPreprocess_Stop(hr);
  813. }
  814. if (bCompileStarted) {
  815. DxcEtw_DXCompilerCompile_Stop(hr);
  816. }
  817. return hr;
  818. }
  819. // Disassemble a program.
  820. virtual HRESULT STDMETHODCALLTYPE Disassemble(
  821. _In_ const DxcBuffer *pObject, // Program to disassemble: dxil container or bitcode.
  822. _In_ REFIID riid, _Out_ LPVOID *ppResult // IDxcResult: status, disassembly text, and errors
  823. ) override {
  824. if (pObject == nullptr || ppResult == nullptr)
  825. return E_INVALIDARG;
  826. if (!(IsEqualIID(riid, __uuidof(IDxcResult)) ||
  827. IsEqualIID(riid, __uuidof(IDxcOperationResult))))
  828. return E_INVALIDARG;
  829. *ppResult = nullptr;
  830. CComPtr<IDxcResult> pResult;
  831. HRESULT hr = S_OK;
  832. DxcEtw_DXCompilerDisassemble_Start();
  833. DxcThreadMalloc TM(m_pMalloc);
  834. try {
  835. DefaultFPEnvScope fpEnvScope;
  836. ::llvm::sys::fs::MSFileSystem *msfPtr;
  837. IFT(CreateMSFileSystemForDisk(&msfPtr));
  838. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  839. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  840. IFTLLVM(pts.error_code());
  841. std::string StreamStr;
  842. raw_string_ostream Stream(StreamStr);
  843. CComPtr<IDxcBlobEncoding> pProgram;
  844. IFT(hlsl::DxcCreateBlob(pObject->Ptr, pObject->Size, true, false, false, 0, nullptr, &pProgram))
  845. IFC(dxcutil::Disassemble(pProgram, Stream));
  846. IFT(DxcResult::Create(S_OK, DXC_OUT_DISASSEMBLY, {
  847. DxcOutputObject::StringOutput(DXC_OUT_DISASSEMBLY,
  848. CP_UTF8, StreamStr.c_str(), StreamStr.size(), DxcOutNoName)
  849. }, &pResult));
  850. IFT(pResult->QueryInterface(riid, ppResult));
  851. return S_OK;
  852. } catch (std::bad_alloc &) {
  853. hr = E_OUTOFMEMORY;
  854. } catch (hlsl::Exception &e) {
  855. _Analysis_assume_(DXC_FAILED(e.hr));
  856. hr = e.hr;
  857. if (SUCCEEDED(DxcResult::Create(e.hr, DXC_OUT_NONE, {
  858. DxcOutputObject::ErrorOutput(CP_UTF8,
  859. e.msg.c_str(), e.msg.size())
  860. }, &pResult)) &&
  861. SUCCEEDED(pResult->QueryInterface(riid, ppResult))) {
  862. hr = S_OK;
  863. }
  864. } catch (...) {
  865. hr = E_FAIL;
  866. }
  867. Cleanup:
  868. DxcEtw_DXCompilerDisassemble_Stop(hr);
  869. return hr;
  870. }
  871. void SetupCompilerForCompile(CompilerInstance &compiler,
  872. _In_ DxcLangExtensionsHelper *helper,
  873. _In_ LPCSTR pMainFile, _In_ TextDiagnosticPrinter *diagPrinter,
  874. _In_ std::vector<std::string>& defines,
  875. _In_ hlsl::options::DxcOpts &Opts,
  876. _In_count_(argCount) LPCWSTR *pArguments,
  877. _In_ UINT32 argCount) {
  878. // Setup a compiler instance.
  879. std::shared_ptr<TargetOptions> targetOptions(new TargetOptions);
  880. targetOptions->Triple = "dxil-ms-dx";
  881. targetOptions->DescriptionString = Opts.Enable16BitTypes
  882. ? hlsl::DXIL::kNewLayoutString
  883. : hlsl::DXIL::kLegacyLayoutString;
  884. compiler.HlslLangExtensions = helper;
  885. compiler.getDiagnosticOpts().ShowOptionNames = Opts.ShowOptionNames ? 1 : 0;
  886. compiler.getDiagnosticOpts().Warnings = std::move(Opts.Warnings);
  887. compiler.createDiagnostics(diagPrinter, false);
  888. // don't output warning to stderr/file if "/no-warnings" is present.
  889. compiler.getDiagnostics().setIgnoreAllWarnings(!Opts.OutputWarnings);
  890. compiler.createFileManager();
  891. compiler.createSourceManager(compiler.getFileManager());
  892. compiler.setTarget(
  893. TargetInfo::CreateTargetInfo(compiler.getDiagnostics(), targetOptions));
  894. if (Opts.EnableDX9CompatMode) {
  895. auto const ID = compiler.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Warning, "/Gec flag is a deprecated functionality.");
  896. compiler.getDiagnostics().Report(ID);
  897. }
  898. compiler.getFrontendOpts().Inputs.push_back(FrontendInputFile(pMainFile, IK_HLSL));
  899. // Setup debug information.
  900. if (Opts.IsDebugInfoEnabled()) {
  901. CodeGenOptions &CGOpts = compiler.getCodeGenOpts();
  902. CGOpts.setDebugInfo(CodeGenOptions::FullDebugInfo);
  903. CGOpts.DebugColumnInfo = 1;
  904. CGOpts.DwarfVersion = 4; // Latest version.
  905. // TODO: consider
  906. // DebugPass, DebugCompilationDir, DwarfDebugFlags, SplitDwarfFile
  907. }
  908. clang::PreprocessorOptions &PPOpts(compiler.getPreprocessorOpts());
  909. for (size_t i = 0; i < defines.size(); ++i) {
  910. PPOpts.addMacroDef(defines[i]);
  911. }
  912. PPOpts.IgnoreLineDirectives = Opts.IgnoreLineDirectives;
  913. // fxc compatibility: pre-expand operands before performing token-pasting
  914. PPOpts.ExpandTokPastingArg = Opts.LegacyMacroExpansion;
  915. // Pick additional arguments.
  916. clang::HeaderSearchOptions &HSOpts = compiler.getHeaderSearchOpts();
  917. HSOpts.UseBuiltinIncludes = 0;
  918. // Consider: should we force-include '.' if the source file is relative?
  919. for (const llvm::opt::Arg *A : Opts.Args.filtered(options::OPT_I)) {
  920. const bool IsFrameworkFalse = false;
  921. const bool IgnoreSysRoot = true;
  922. if (dxcutil::IsAbsoluteOrCurDirRelative(A->getValue())) {
  923. HSOpts.AddPath(A->getValue(), frontend::Angled, IsFrameworkFalse, IgnoreSysRoot);
  924. }
  925. else {
  926. std::string s("./");
  927. s += A->getValue();
  928. HSOpts.AddPath(s, frontend::Angled, IsFrameworkFalse, IgnoreSysRoot);
  929. }
  930. }
  931. // Apply root signature option.
  932. unsigned rootSigMinor;
  933. if (Opts.ForceRootSigVer.empty() || Opts.ForceRootSigVer == "rootsig_1_1") {
  934. rootSigMinor = 1;
  935. }
  936. else {
  937. DXASSERT(Opts.ForceRootSigVer == "rootsig_1_0",
  938. "else opts should have been rejected");
  939. rootSigMinor = 0;
  940. }
  941. compiler.getLangOpts().RootSigMajor = 1;
  942. compiler.getLangOpts().RootSigMinor = rootSigMinor;
  943. compiler.getLangOpts().HLSLVersion = (unsigned) Opts.HLSLVersion;
  944. compiler.getLangOpts().EnableDX9CompatMode = Opts.EnableDX9CompatMode;
  945. compiler.getLangOpts().EnableFXCCompatMode = Opts.EnableFXCCompatMode;
  946. compiler.getLangOpts().UseMinPrecision = !Opts.Enable16BitTypes;
  947. // SPIRV change starts
  948. #ifdef ENABLE_SPIRV_CODEGEN
  949. compiler.getLangOpts().SPIRV = Opts.GenSPIRV;
  950. #endif
  951. // SPIRV change ends
  952. if (Opts.WarningAsError)
  953. compiler.getDiagnostics().setWarningsAsErrors(true);
  954. if (Opts.IEEEStrict)
  955. compiler.getCodeGenOpts().UnsafeFPMath = true;
  956. if (Opts.FloatDenormalMode.empty()) {
  957. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Reserve7; // undefined
  958. }
  959. else if (Opts.FloatDenormalMode.equals_lower(StringRef("any"))) {
  960. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Any;
  961. }
  962. else if (Opts.FloatDenormalMode.equals_lower(StringRef("ftz"))) {
  963. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::FTZ;
  964. }
  965. else {
  966. DXASSERT(Opts.FloatDenormalMode.equals_lower(StringRef("preserve")), "else opts should have been rejected");
  967. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Preserve;
  968. }
  969. if (Opts.DisableOptimizations)
  970. compiler.getCodeGenOpts().DisableLLVMOpts = true;
  971. compiler.getCodeGenOpts().OptimizationLevel = Opts.OptLevel;
  972. if (Opts.OptLevel >= 3)
  973. compiler.getCodeGenOpts().UnrollLoops = true;
  974. compiler.getCodeGenOpts().HLSLHighLevel = Opts.CodeGenHighLevel;
  975. compiler.getCodeGenOpts().HLSLResMayAlias = Opts.ResMayAlias;
  976. compiler.getCodeGenOpts().ScanLimit = Opts.ScanLimit;
  977. compiler.getCodeGenOpts().HLSLAllResourcesBound = Opts.AllResourcesBound;
  978. compiler.getCodeGenOpts().HLSLDefaultRowMajor = Opts.DefaultRowMajor;
  979. compiler.getCodeGenOpts().HLSLPreferControlFlow = Opts.PreferFlowControl;
  980. compiler.getCodeGenOpts().HLSLAvoidControlFlow = Opts.AvoidFlowControl;
  981. compiler.getCodeGenOpts().HLSLNotUseLegacyCBufLoad = Opts.NotUseLegacyCBufLoad;
  982. compiler.getCodeGenOpts().HLSLLegacyResourceReservation = Opts.LegacyResourceReservation;
  983. compiler.getCodeGenOpts().HLSLDefines = defines;
  984. compiler.getCodeGenOpts().MainFileName = pMainFile;
  985. // Translate signature packing options
  986. if (Opts.PackPrefixStable)
  987. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::PrefixStable;
  988. else if (Opts.PackOptimized)
  989. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::Optimized;
  990. else
  991. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::Default;
  992. // Constructing vector of wide strings to pass in to codegen. Just passing
  993. // in pArguments will expose ownership of memory to both CodeGenOptions and
  994. // this caller, which can lead to unexpected behavior.
  995. for (UINT32 i = 0; i != Opts.Args.getNumInputArgStrings(); ++i) {
  996. auto arg = Opts.Args.getArgString(i);
  997. if (Opts.InputFile.compare(arg) != 0) {
  998. compiler.getCodeGenOpts().HLSLArguments.emplace_back(arg);
  999. }
  1000. }
  1001. // Overrding default set of loop unroll.
  1002. if (Opts.PreferFlowControl)
  1003. compiler.getCodeGenOpts().UnrollLoops = false;
  1004. if (Opts.AvoidFlowControl)
  1005. compiler.getCodeGenOpts().UnrollLoops = true;
  1006. // always inline for hlsl
  1007. compiler.getCodeGenOpts().setInlining(
  1008. clang::CodeGenOptions::OnlyAlwaysInlining);
  1009. compiler.getCodeGenOpts().HLSLExtensionsCodegen = std::make_shared<HLSLExtensionsCodegenHelperImpl>(compiler, m_langExtensionsHelper, Opts.RootSignatureDefine);
  1010. // AutoBindingSpace also enables automatic binding for libraries if set. UINT_MAX == unset
  1011. compiler.getCodeGenOpts().HLSLDefaultSpace = Opts.AutoBindingSpace;
  1012. // processed export names from -exports option:
  1013. compiler.getCodeGenOpts().HLSLLibraryExports = Opts.Exports;
  1014. // only export shader functions for library
  1015. compiler.getCodeGenOpts().ExportShadersOnly = Opts.ExportShadersOnly;
  1016. if (Opts.DefaultLinkage.empty()) {
  1017. compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::Default;
  1018. } else if (Opts.DefaultLinkage.equals_lower("internal")) {
  1019. compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::Internal;
  1020. } else if (Opts.DefaultLinkage.equals_lower("external")) {
  1021. compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::External;
  1022. }
  1023. }
  1024. // IDxcVersionInfo
  1025. HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) override {
  1026. if (pMajor == nullptr || pMinor == nullptr)
  1027. return E_INVALIDARG;
  1028. *pMajor = DXIL::kDxilMajor;
  1029. *pMinor = DXIL::kDxilMinor;
  1030. return S_OK;
  1031. }
  1032. #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
  1033. HRESULT STDMETHODCALLTYPE GetCommitInfo(_Out_ UINT32 *pCommitCount,
  1034. _Out_ char **pCommitHash) override {
  1035. if (pCommitCount == nullptr || pCommitHash == nullptr)
  1036. return E_INVALIDARG;
  1037. char *const hash = (char *)CoTaskMemAlloc(8 + 1); // 8 is guaranteed by utils/GetCommitInfo.py
  1038. if (hash == nullptr)
  1039. return E_OUTOFMEMORY;
  1040. std::strcpy(hash, getGitCommitHash());
  1041. *pCommitHash = hash;
  1042. *pCommitCount = getGitCommitCount();
  1043. return S_OK;
  1044. }
  1045. #endif // SUPPORT_QUERY_GIT_COMMIT_INFO
  1046. HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) override {
  1047. if (pFlags == nullptr)
  1048. return E_INVALIDARG;
  1049. *pFlags = DxcVersionInfoFlags_None;
  1050. #ifdef _DEBUG
  1051. *pFlags |= DxcVersionInfoFlags_Debug;
  1052. #endif
  1053. return S_OK;
  1054. }
  1055. };
  1056. //////////////////////////////////////////////////////////////
  1057. // legacy IDxcCompiler2 implementation that maps to DxcCompiler
  1058. ULONG STDMETHODCALLTYPE DxcCompilerAdapter::AddRef() {
  1059. return m_pCompilerImpl->AddRef();
  1060. }
  1061. ULONG STDMETHODCALLTYPE DxcCompilerAdapter::Release() {
  1062. return m_pCompilerImpl->Release();
  1063. }
  1064. HRESULT STDMETHODCALLTYPE DxcCompilerAdapter::QueryInterface(REFIID iid, void **ppvObject) {
  1065. return m_pCompilerImpl->QueryInterface(iid, ppvObject);
  1066. }
  1067. // Preprocess source text
  1068. HRESULT STDMETHODCALLTYPE DxcCompilerAdapter::Preprocess(
  1069. _In_ IDxcBlob *pSource, // Source text to preprocess
  1070. _In_opt_z_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  1071. _In_opt_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  1072. _In_ UINT32 argCount, // Number of arguments
  1073. _In_count_(defineCount)
  1074. const DxcDefine *pDefines, // Array of defines
  1075. _In_ UINT32 defineCount, // Number of defines
  1076. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  1077. _COM_Outptr_ IDxcOperationResult **ppResult // Preprocessor output status, buffer, and errors
  1078. ) {
  1079. if (pSource == nullptr || ppResult == nullptr ||
  1080. (defineCount > 0 && pDefines == nullptr) ||
  1081. (argCount > 0 && pArguments == nullptr))
  1082. return E_INVALIDARG;
  1083. *ppResult = nullptr;
  1084. return WrapCompile(
  1085. TRUE,
  1086. pSource, pSourceName,
  1087. nullptr, nullptr,
  1088. pArguments, argCount,
  1089. pDefines, defineCount,
  1090. pIncludeHandler,
  1091. ppResult, nullptr, nullptr);
  1092. }
  1093. // Disassemble a program.
  1094. HRESULT STDMETHODCALLTYPE DxcCompilerAdapter::Disassemble(
  1095. _In_ IDxcBlob *pProgram, // Program to disassemble.
  1096. _COM_Outptr_ IDxcBlobEncoding **ppDisassembly // Disassembly text.
  1097. ) {
  1098. if (pProgram == nullptr || ppDisassembly == nullptr)
  1099. return E_INVALIDARG;
  1100. *ppDisassembly = nullptr;
  1101. HRESULT hr = S_OK;
  1102. DxcThreadMalloc TM(m_pMalloc);
  1103. DxcBuffer buffer = { pProgram->GetBufferPointer(), pProgram->GetBufferSize(), 0 };
  1104. CComPtr<IDxcResult> pResult;
  1105. IFR(m_pCompilerImpl->Disassemble(&buffer, IID_PPV_ARGS(&pResult)));
  1106. IFRBOOL(pResult, E_OUTOFMEMORY);
  1107. IFR(pResult->GetStatus(&hr));
  1108. if (SUCCEEDED(hr)) {
  1109. // Extract disassembly
  1110. IFR(pResult->GetOutput(DXC_OUT_DISASSEMBLY, IID_PPV_ARGS(ppDisassembly), nullptr));
  1111. }
  1112. return hr;
  1113. }
  1114. HRESULT CreateDxcUtils(_In_ REFIID riid, _Out_ LPVOID *ppv);
  1115. HRESULT STDMETHODCALLTYPE DxcCompilerAdapter::CompileWithDebug(
  1116. _In_ IDxcBlob *pSource, // Source text to compile
  1117. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  1118. _In_ LPCWSTR pEntryPoint, // Entry point name
  1119. _In_ LPCWSTR pTargetProfile, // Shader profile to compile
  1120. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  1121. _In_ UINT32 argCount, // Number of arguments
  1122. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  1123. _In_ UINT32 defineCount, // Number of defines
  1124. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  1125. _COM_Outptr_ IDxcOperationResult **ppResult, // Compiler output status, buffer, and errors
  1126. _Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob.
  1127. _COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob
  1128. ) {
  1129. if (pSource == nullptr || ppResult == nullptr ||
  1130. (defineCount > 0 && pDefines == nullptr) ||
  1131. (argCount > 0 && pArguments == nullptr) ||
  1132. pTargetProfile == nullptr)
  1133. return E_INVALIDARG;
  1134. *ppResult = nullptr;
  1135. AssignToOutOpt(nullptr, ppDebugBlobName);
  1136. AssignToOutOpt(nullptr, ppDebugBlob);
  1137. return WrapCompile(
  1138. FALSE,
  1139. pSource, pSourceName,
  1140. pEntryPoint, pTargetProfile,
  1141. pArguments, argCount,
  1142. pDefines, defineCount,
  1143. pIncludeHandler,
  1144. ppResult, ppDebugBlobName, ppDebugBlob);
  1145. }
  1146. HRESULT DxcCompilerAdapter::WrapCompile(
  1147. _In_ BOOL bPreprocess, // Preprocess mode
  1148. _In_ IDxcBlob *pSource, // Source text to compile
  1149. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  1150. _In_ LPCWSTR pEntryPoint, // Entry point name
  1151. _In_ LPCWSTR pTargetProfile, // Shader profile to compile
  1152. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  1153. _In_ UINT32 argCount, // Number of arguments
  1154. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  1155. _In_ UINT32 defineCount, // Number of defines
  1156. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  1157. _COM_Outptr_ IDxcOperationResult **ppResult, // Compiler output status, buffer, and errors
  1158. _Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob.
  1159. _COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob
  1160. ) {
  1161. HRESULT hr = S_OK;
  1162. DxcThreadMalloc TM(m_pMalloc);
  1163. try {
  1164. CComPtr<IDxcUtils> pUtils;
  1165. IFT(CreateDxcUtils(IID_PPV_ARGS(&pUtils)));
  1166. CComPtr<IDxcCompilerArgs> pArgs;
  1167. IFR(pUtils->BuildArguments(
  1168. pSourceName, pEntryPoint, pTargetProfile,
  1169. pArguments, argCount, pDefines, defineCount, &pArgs));
  1170. LPCWSTR PreprocessArgs[] = { L"-P", L"preprocessed.hlsl" };
  1171. if (bPreprocess) {
  1172. IFT(pArgs->AddArguments(PreprocessArgs, _countof(PreprocessArgs)));
  1173. }
  1174. DxcBuffer buffer = { pSource->GetBufferPointer(), pSource->GetBufferSize(), CP_ACP };
  1175. CComPtr<IDxcBlobEncoding> pSourceEncoding;
  1176. if (SUCCEEDED(pSource->QueryInterface(&pSourceEncoding))) {
  1177. BOOL sourceEncodingKnown = false;
  1178. IFT(pSourceEncoding->GetEncoding(&sourceEncodingKnown, &buffer.Encoding));
  1179. }
  1180. CComPtr<AbstractMemoryStream> pOutputStream;
  1181. IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
  1182. // Parse command-line options into DxcOpts
  1183. int argCountInt;
  1184. IFT(UIntToInt(pArgs->GetCount(), &argCountInt));
  1185. hlsl::options::MainArgs mainArgs(argCountInt, pArgs->GetArguments(), 0);
  1186. hlsl::options::DxcOpts opts;
  1187. bool finished = false;
  1188. CComPtr<IDxcOperationResult> pOperationResult;
  1189. dxcutil::ReadOptsAndValidate(mainArgs, opts, pOutputStream, &pOperationResult, finished);
  1190. if (finished) {
  1191. IFT(pOperationResult->QueryInterface(ppResult));
  1192. return S_OK;
  1193. }
  1194. if (pOutputStream->GetPosition() > 0) {
  1195. // Clear existing stream in case it has option spew
  1196. pOutputStream.Release();
  1197. IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
  1198. }
  1199. // To concat out output with compiler errors
  1200. raw_stream_ostream outStream(pOutputStream);
  1201. LPCWSTR EmbedDebugOpt[] = { L"-Qembed_debug" };
  1202. if (opts.DebugInfo && !ppDebugBlob && !opts.EmbedDebug && !opts.StripDebug) {
  1203. // SPIRV change starts
  1204. #if defined(ENABLE_SPIRV_CODEGEN)
  1205. if (!opts.GenSPIRV)
  1206. outStream << "warning: no output provided for debug - embedding PDB in "
  1207. "shader container. Use -Qembed_debug to silence this "
  1208. "warning.\n";
  1209. #else
  1210. outStream << "warning: no output provided for debug - embedding PDB in "
  1211. "shader container. Use -Qembed_debug to silence this "
  1212. "warning.\n";
  1213. #endif
  1214. // SPIRV change ends
  1215. IFT(pArgs->AddArguments(EmbedDebugOpt, _countof(EmbedDebugOpt)));
  1216. }
  1217. CComPtr<DxcResult> pResult = DxcResult::Alloc(m_pMalloc);
  1218. pResult->SetEncoding(opts.DefaultTextCodePage);
  1219. CComPtr<IDxcResult> pImplResult;
  1220. IFR(m_pCompilerImpl->Compile(&buffer, pArgs->GetArguments(), pArgs->GetCount(), pIncludeHandler, IID_PPV_ARGS(&pImplResult)));
  1221. IFRBOOL(pImplResult, E_OUTOFMEMORY);
  1222. IFR(pImplResult->GetStatus(&hr));
  1223. pResult->CopyOutputsFromResult(pImplResult);
  1224. pResult->SetStatusAndPrimaryResult(hr, pImplResult->PrimaryOutput());
  1225. outStream.flush();
  1226. // Insert any warnings generated here
  1227. if (pOutputStream->GetPosition() > 0) {
  1228. CComPtr<IDxcBlobEncoding> pErrorsEncoding;
  1229. if (SUCCEEDED(pResult->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&pErrorsEncoding), nullptr)) &&
  1230. pErrorsEncoding && pErrorsEncoding->GetBufferSize()) {
  1231. CComPtr<IDxcBlobUtf8> pErrorsUtf8;
  1232. IFT(pUtils->GetBlobAsUtf8(pErrorsEncoding, &pErrorsUtf8));
  1233. outStream << pErrorsUtf8->GetStringPointer();
  1234. outStream.flush();
  1235. }
  1236. // Reconstruct result with new error buffer
  1237. CComPtr<IDxcBlobEncoding> pErrorBlob;
  1238. IFT(hlsl::DxcCreateBlob(
  1239. pOutputStream->GetPtr(), pOutputStream->GetPtrSize(),
  1240. false, true, true, DXC_CP_UTF8, nullptr, &pErrorBlob));
  1241. if (pErrorBlob && pErrorBlob->GetBufferSize()) {
  1242. pResult->Output(DXC_OUT_ERRORS)->object.Release();
  1243. pResult->SetOutputObject(DXC_OUT_ERRORS, pErrorBlob);
  1244. }
  1245. }
  1246. // Extract debug blob if present
  1247. CComHeapPtr<wchar_t> pDebugNameOnComHeap;
  1248. CComPtr<IDxcBlob> pDebugBlob;
  1249. if (SUCCEEDED(hr)) {
  1250. CComPtr<IDxcBlobUtf16> pDebugName;
  1251. hr = pResult->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pDebugBlob), &pDebugName);
  1252. if (SUCCEEDED(hr) && ppDebugBlobName && pDebugName) {
  1253. if (!pDebugNameOnComHeap.AllocateBytes(pDebugName->GetBufferSize()))
  1254. return E_OUTOFMEMORY;
  1255. memcpy(pDebugNameOnComHeap.m_pData, pDebugName->GetBufferPointer(), pDebugName->GetBufferSize());
  1256. }
  1257. }
  1258. if (ppDebugBlob && pDebugBlob)
  1259. *ppDebugBlob = pDebugBlob.Detach();
  1260. if (ppDebugBlobName && pDebugNameOnComHeap)
  1261. *ppDebugBlobName = pDebugNameOnComHeap.Detach();
  1262. IFR(pResult.QueryInterface(ppResult));
  1263. hr = S_OK;
  1264. } catch (std::bad_alloc &) {
  1265. hr = E_OUTOFMEMORY;
  1266. } catch (hlsl::Exception &e) {
  1267. _Analysis_assume_(DXC_FAILED(e.hr));
  1268. hr = DxcResult::Create(e.hr, DXC_OUT_NONE, {
  1269. DxcOutputObject::ErrorOutput(CP_UTF8, e.msg.c_str(), e.msg.size())
  1270. }, ppResult);
  1271. } catch (...) {
  1272. hr = E_FAIL;
  1273. }
  1274. return hr;
  1275. }
  1276. //////////////////////////////////////////////////////////////
  1277. HRESULT CreateDxcCompiler(_In_ REFIID riid, _Out_ LPVOID* ppv) {
  1278. *ppv = nullptr;
  1279. try {
  1280. CComPtr<DxcCompiler> result(DxcCompiler::Alloc(DxcGetThreadMallocNoRef()));
  1281. IFROOM(result.p);
  1282. return result.p->QueryInterface(riid, ppv);
  1283. }
  1284. CATCH_CPP_RETURN_HRESULT();
  1285. }