dxcompilerobj.cpp 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  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 <algorithm>
  48. #include <cfloat>
  49. // SPIRV change starts
  50. #ifdef ENABLE_SPIRV_CODEGEN
  51. #include "clang/SPIRV/EmitSpirvAction.h"
  52. #endif
  53. // SPIRV change ends
  54. #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
  55. #include "clang/Basic/Version.h"
  56. #endif // SUPPORT_QUERY_GIT_COMMIT_INFO
  57. #define CP_UTF16 1200
  58. using namespace llvm;
  59. using namespace clang;
  60. using namespace hlsl;
  61. using std::string;
  62. DEFINE_CROSS_PLATFORM_UUIDOF(IDxcLangExtensions)
  63. // This declaration is used for the locally-linked validator.
  64. HRESULT CreateDxcValidator(_In_ REFIID riid, _Out_ LPVOID *ppv);
  65. // This internal call allows the validator to avoid having to re-deserialize
  66. // the module. It trusts that the caller didn't make any changes and is
  67. // kept internal because the layout of the module class may change based
  68. // on changes across modules, or picking a different compiler version or CRT.
  69. HRESULT RunInternalValidator(_In_ IDxcValidator *pValidator,
  70. _In_ llvm::Module *pModule,
  71. _In_ llvm::Module *pDebugModule,
  72. _In_ IDxcBlob *pShader, UINT32 Flags,
  73. _In_ IDxcOperationResult **ppResult);
  74. static void CreateOperationResultFromOutputs(
  75. IDxcBlob *pResultBlob, dxcutil::DxcArgsFileSystem *msfPtr,
  76. const std::string &warnings, clang::DiagnosticsEngine &diags,
  77. _COM_Outptr_ IDxcOperationResult **ppResult) {
  78. CComPtr<IStream> pErrorStream;
  79. CComPtr<IDxcBlobEncoding> pErrorBlob;
  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. class DxcCompiler : public IDxcCompiler2,
  326. public IDxcLangExtensions,
  327. public IDxcContainerEvent,
  328. #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
  329. public IDxcVersionInfo2
  330. #else
  331. public IDxcVersionInfo
  332. #endif // SUPPORT_QUERY_GIT_COMMIT_INFO
  333. {
  334. private:
  335. DXC_MICROCOM_TM_REF_FIELDS()
  336. DxcLangExtensionsHelper m_langExtensionsHelper;
  337. CComPtr<IDxcContainerEventsHandler> m_pDxcContainerEventsHandler;
  338. void CreateDefineStrings(_In_count_(defineCount) const DxcDefine *pDefines,
  339. UINT defineCount,
  340. std::vector<std::string> &defines) {
  341. // Not very efficient but also not very important.
  342. for (UINT32 i = 0; i < defineCount; i++) {
  343. CW2A utf8Name(pDefines[i].Name, CP_UTF8);
  344. CW2A utf8Value(pDefines[i].Value, CP_UTF8);
  345. std::string val(utf8Name.m_psz);
  346. val += "=";
  347. val += (pDefines[i].Value) ? utf8Value.m_psz : "1";
  348. defines.push_back(val);
  349. }
  350. }
  351. public:
  352. DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL()
  353. DXC_MICROCOM_TM_CTOR(DxcCompiler)
  354. DXC_LANGEXTENSIONS_HELPER_IMPL(m_langExtensionsHelper)
  355. HRESULT STDMETHODCALLTYPE RegisterDxilContainerEventHandler(IDxcContainerEventsHandler *pHandler, UINT64 *pCookie) override {
  356. DXASSERT(m_pDxcContainerEventsHandler == nullptr, "else events handler is already registered");
  357. *pCookie = 1; // Only one EventsHandler supported
  358. m_pDxcContainerEventsHandler = pHandler;
  359. return S_OK;
  360. };
  361. HRESULT STDMETHODCALLTYPE UnRegisterDxilContainerEventHandler(UINT64 cookie) override {
  362. DXASSERT(m_pDxcContainerEventsHandler != nullptr, "else unregister should not have been called");
  363. m_pDxcContainerEventsHandler.Release();
  364. return S_OK;
  365. }
  366. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) override {
  367. return DoBasicQueryInterface<IDxcCompiler,
  368. IDxcCompiler2,
  369. IDxcLangExtensions,
  370. IDxcContainerEvent,
  371. IDxcVersionInfo
  372. #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
  373. ,IDxcVersionInfo2
  374. #endif // SUPPORT_QUERY_GIT_COMMIT_INFO
  375. >
  376. (this, iid, ppvObject);
  377. }
  378. // Compile a single entry point to the target shader model
  379. HRESULT STDMETHODCALLTYPE Compile(
  380. _In_ IDxcBlob *pSource, // Source text to compile
  381. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  382. _In_ LPCWSTR pEntryPoint, // entry point name
  383. _In_ LPCWSTR pTargetProfile, // shader profile to compile
  384. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  385. _In_ UINT32 argCount, // Number of arguments
  386. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  387. _In_ UINT32 defineCount, // Number of defines
  388. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  389. _COM_Outptr_ IDxcOperationResult **ppResult // Compiler output status, buffer, and errors
  390. ) override {
  391. return CompileWithDebug(pSource, pSourceName, pEntryPoint, pTargetProfile,
  392. pArguments, argCount, pDefines, defineCount,
  393. pIncludeHandler, ppResult, nullptr, nullptr);
  394. }
  395. // Compile a single entry point to the target shader model with debug information.
  396. HRESULT STDMETHODCALLTYPE CompileWithDebug(
  397. _In_ IDxcBlob *pSource, // Source text to compile
  398. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  399. _In_ LPCWSTR pEntryPoint, // Entry point name
  400. _In_ LPCWSTR pTargetProfile, // Shader profile to compile
  401. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  402. _In_ UINT32 argCount, // Number of arguments
  403. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  404. _In_ UINT32 defineCount, // Number of defines
  405. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  406. _COM_Outptr_ IDxcOperationResult **ppResult, // Compiler output status, buffer, and errors
  407. _Outptr_opt_result_z_ LPWSTR *ppDebugBlobName,// Suggested file name for debug blob.
  408. _COM_Outptr_opt_ IDxcBlob **ppDebugBlob // Debug blob
  409. ) override {
  410. if (pSource == nullptr || ppResult == nullptr ||
  411. (defineCount > 0 && pDefines == nullptr) ||
  412. (argCount > 0 && pArguments == nullptr) || pEntryPoint == nullptr ||
  413. pTargetProfile == nullptr)
  414. return E_INVALIDARG;
  415. *ppResult = nullptr;
  416. AssignToOutOpt(nullptr, ppDebugBlobName);
  417. AssignToOutOpt(nullptr, ppDebugBlob);
  418. HRESULT hr = S_OK;
  419. CComPtr<IDxcBlobEncoding> utf8Source;
  420. CComPtr<AbstractMemoryStream> pOutputStream;
  421. CComHeapPtr<wchar_t> DebugBlobName;
  422. DxcEtw_DXCompilerCompile_Start();
  423. pSourceName = (pSourceName && *pSourceName) ? pSourceName : L"hlsl.hlsl"; // declared optional, so pick a default
  424. DxcThreadMalloc TM(m_pMalloc);
  425. try {
  426. DefaultFPEnvScope fpEnvScope;
  427. IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
  428. // Parse command-line options into DxcOpts
  429. int argCountInt;
  430. IFT(UIntToInt(argCount, &argCountInt));
  431. hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0);
  432. hlsl::options::DxcOpts opts;
  433. CW2A pUtf8TargetProfile(pTargetProfile, CP_UTF8);
  434. // Set target profile before reading options and validate
  435. opts.TargetProfile = pUtf8TargetProfile.m_psz;
  436. bool finished = false;
  437. dxcutil::ReadOptsAndValidate(mainArgs, opts, pOutputStream, ppResult, finished);
  438. if (finished) {
  439. hr = S_OK;
  440. goto Cleanup;
  441. }
  442. #ifdef ENABLE_SPIRV_CODEGEN
  443. // We want to embed the preprocessed source code in the final SPIR-V if
  444. // debug information is enabled. Therefore, we invoke Preprocess() here
  445. // first for such case. Then we invoke the compilation process over the
  446. // preprocessed source code, so that line numbers are consistent with the
  447. // embedded source code.
  448. CComPtr<IDxcBlob> ppSrcCode;
  449. if (opts.GenSPIRV && opts.DebugInfo) {
  450. CComPtr<IDxcOperationResult> ppSrcCodeResult;
  451. IFT(Preprocess(pSource, pSourceName, pArguments, argCount, pDefines,
  452. defineCount, pIncludeHandler, &ppSrcCodeResult));
  453. HRESULT status;
  454. IFT(ppSrcCodeResult->GetStatus(&status));
  455. if (SUCCEEDED(status)) {
  456. IFT(ppSrcCodeResult->GetResult(&ppSrcCode));
  457. pSource = ppSrcCode;
  458. }
  459. }
  460. #endif // ENABLE_SPIRV_CODEGEN
  461. // Convert source code encoding
  462. IFC(hlsl::DxcGetBlobAsUtf8(pSource, &utf8Source));
  463. CComPtr<IDxcBlob> pOutputBlob;
  464. dxcutil::DxcArgsFileSystem *msfPtr =
  465. dxcutil::CreateDxcArgsFileSystem(utf8Source, pSourceName, pIncludeHandler);
  466. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  467. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  468. IFTLLVM(pts.error_code());
  469. IFT(pOutputStream.QueryInterface(&pOutputBlob));
  470. if (opts.DisplayIncludeProcess)
  471. msfPtr->EnableDisplayIncludeProcess();
  472. // Prepare UTF8-encoded versions of API values.
  473. CW2A pUtf8EntryPoint(pEntryPoint, CP_UTF8);
  474. CW2A utf8SourceName(pSourceName, CP_UTF8);
  475. const char *pUtf8SourceName = utf8SourceName.m_psz;
  476. if (pUtf8SourceName == nullptr) {
  477. if (opts.InputFile.empty()) {
  478. pUtf8SourceName = "input.hlsl";
  479. }
  480. else {
  481. pUtf8SourceName = opts.InputFile.data();
  482. }
  483. }
  484. IFT(msfPtr->RegisterOutputStream(L"output.bc", pOutputStream));
  485. IFT(msfPtr->CreateStdStreams(m_pMalloc));
  486. StringRef Data((LPSTR)utf8Source->GetBufferPointer(),
  487. utf8Source->GetBufferSize());
  488. std::unique_ptr<llvm::MemoryBuffer> pBuffer(
  489. llvm::MemoryBuffer::getMemBufferCopy(Data, pUtf8SourceName));
  490. // Not very efficient but also not very important.
  491. std::vector<std::string> defines;
  492. CreateDefineStrings(pDefines, defineCount, defines);
  493. CreateDefineStrings(opts.Defines.data(), opts.Defines.size(), defines);
  494. // Setup a compiler instance.
  495. std::string warnings;
  496. raw_string_ostream w(warnings);
  497. raw_stream_ostream outStream(pOutputStream.p);
  498. llvm::LLVMContext llvmContext; // LLVMContext should outlive CompilerInstance
  499. CompilerInstance compiler;
  500. std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
  501. llvm::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
  502. SetupCompilerForCompile(compiler, &m_langExtensionsHelper, utf8SourceName, diagPrinter.get(), defines, opts, pArguments, argCount);
  503. msfPtr->SetupForCompilerInstance(compiler);
  504. // The clang entry point (cc1_main) would now create a compiler invocation
  505. // from arguments, but for this path we're exclusively trying to compile
  506. // to LLVM bitcode and then package that into a DXBC blob.
  507. //
  508. // With the compiler invocation built from command line arguments, the
  509. // next step is to call ExecuteCompilerInvocation, which creates a
  510. // FrontendAction* of EmitBCAction, which is a CodeGenAction, which is an
  511. // ASTFrontendAction. That sets up a BackendConsumer as the ASTConsumer.
  512. compiler.getFrontendOpts().OutputFile = "output.bc";
  513. compiler.WriteDefaultOutputDirectly = true;
  514. compiler.setOutStream(&outStream);
  515. compiler.getLangOpts().HLSLEntryFunction =
  516. compiler.getCodeGenOpts().HLSLEntryFunction = pUtf8EntryPoint.m_psz;
  517. compiler.getLangOpts().HLSLProfile =
  518. compiler.getCodeGenOpts().HLSLProfile = pUtf8TargetProfile.m_psz;
  519. unsigned rootSigMajor = 0;
  520. unsigned rootSigMinor = 0;
  521. if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_1") {
  522. rootSigMajor = 1;
  523. rootSigMinor = 1;
  524. } else if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_0") {
  525. rootSigMajor = 1;
  526. rootSigMinor = 0;
  527. }
  528. compiler.getLangOpts().IsHLSLLibrary = opts.IsLibraryProfile();
  529. // Clear entry function if library target
  530. if (compiler.getLangOpts().IsHLSLLibrary)
  531. compiler.getLangOpts().HLSLEntryFunction =
  532. compiler.getCodeGenOpts().HLSLEntryFunction = "";
  533. // NOTE: this calls the validation component from dxil.dll; the built-in
  534. // validator can be used as a fallback.
  535. bool produceFullContainer = !opts.CodeGenHighLevel && !opts.AstDump && !opts.OptDump && rootSigMajor == 0;
  536. bool needsValidation = produceFullContainer && !opts.DisableValidation;
  537. // Disable validation for lib_6_1 and lib_6_2.
  538. if (compiler.getCodeGenOpts().HLSLProfile == "lib_6_1" ||
  539. compiler.getCodeGenOpts().HLSLProfile == "lib_6_2") {
  540. needsValidation = false;
  541. }
  542. if (needsValidation || (opts.CodeGenHighLevel && !opts.DisableValidation)) {
  543. UINT32 majorVer, minorVer;
  544. dxcutil::GetValidatorVersion(&majorVer, &minorVer);
  545. compiler.getCodeGenOpts().HLSLValidatorMajorVer = majorVer;
  546. compiler.getCodeGenOpts().HLSLValidatorMinorVer = minorVer;
  547. }
  548. if (opts.AstDump) {
  549. clang::ASTDumpAction dumpAction;
  550. // Consider - ASTDumpFilter, ASTDumpLookups
  551. compiler.getFrontendOpts().ASTDumpDecls = true;
  552. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  553. dumpAction.BeginSourceFile(compiler, file);
  554. dumpAction.Execute();
  555. dumpAction.EndSourceFile();
  556. outStream.flush();
  557. }
  558. else if (opts.OptDump) {
  559. EmitOptDumpAction action(&llvmContext);
  560. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  561. action.BeginSourceFile(compiler, file);
  562. action.Execute();
  563. action.EndSourceFile();
  564. outStream.flush();
  565. }
  566. else if (rootSigMajor) {
  567. HLSLRootSignatureAction action(
  568. compiler.getCodeGenOpts().HLSLEntryFunction, rootSigMajor,
  569. rootSigMinor);
  570. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  571. action.BeginSourceFile(compiler, file);
  572. action.Execute();
  573. action.EndSourceFile();
  574. outStream.flush();
  575. // Don't do work to put in a container if an error has occurred
  576. bool compileOK = !compiler.getDiagnostics().hasErrorOccurred();
  577. if (compileOK) {
  578. auto rootSigHandle = action.takeRootSigHandle();
  579. CComPtr<AbstractMemoryStream> pContainerStream;
  580. IFT(CreateMemoryStream(m_pMalloc, &pContainerStream));
  581. SerializeDxilContainerForRootSignature(rootSigHandle.get(),
  582. pContainerStream);
  583. pOutputBlob.Release();
  584. IFT(pContainerStream.QueryInterface(&pOutputBlob));
  585. }
  586. }
  587. // SPIRV change starts
  588. #ifdef ENABLE_SPIRV_CODEGEN
  589. else if (opts.GenSPIRV) {
  590. // Since SpirvOptions is passed to the SPIR-V CodeGen as a whole
  591. // structure, we need to copy a few non-spirv-specific options into the
  592. // structure.
  593. opts.SpirvOptions.enable16BitTypes = opts.Enable16BitTypes;
  594. opts.SpirvOptions.codeGenHighLevel = opts.CodeGenHighLevel;
  595. opts.SpirvOptions.defaultRowMajor = opts.DefaultRowMajor;
  596. opts.SpirvOptions.disableValidation = opts.DisableValidation;
  597. // Store a string representation of command line options.
  598. if (opts.DebugInfo)
  599. for (auto opt : mainArgs.getArrayRef())
  600. opts.SpirvOptions.clOptions += " " + std::string(opt);
  601. compiler.getCodeGenOpts().SpirvOptions = opts.SpirvOptions;
  602. clang::EmitSpirvAction action;
  603. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  604. action.BeginSourceFile(compiler, file);
  605. action.Execute();
  606. action.EndSourceFile();
  607. outStream.flush();
  608. }
  609. #endif
  610. // SPIRV change ends
  611. else {
  612. EmitBCAction action(&llvmContext);
  613. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  614. bool compileOK;
  615. if (action.BeginSourceFile(compiler, file)) {
  616. action.Execute();
  617. action.EndSourceFile();
  618. compileOK = !compiler.getDiagnostics().hasErrorOccurred();
  619. }
  620. else {
  621. compileOK = false;
  622. }
  623. outStream.flush();
  624. SerializeDxilFlags SerializeFlags = SerializeDxilFlags::None;
  625. if (opts.EmbedPDBName()) {
  626. SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
  627. }
  628. // If -Qembed_debug specified, embed the debug info.
  629. // Or, if there is no output pointer for the debug blob (such as when called by Compile()),
  630. // embed the debug info and emit a note.
  631. if (opts.EmbedDebugInfo()) {
  632. SerializeFlags |= SerializeDxilFlags::IncludeDebugInfoPart;
  633. } else if (!opts.StripDebug && opts.DebugInfo && !ppDebugBlob) {
  634. w << "warning: no output provided for debug - embedding PDB in shader container. Use -Qembed_debug to silence this warning.\n";
  635. SerializeFlags |= SerializeDxilFlags::IncludeDebugInfoPart;
  636. }
  637. if (opts.DebugNameForSource) {
  638. // Implies name part
  639. SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
  640. SerializeFlags |= SerializeDxilFlags::DebugNameDependOnSource;
  641. } else if (opts.DebugNameForBinary) {
  642. // Implies name part
  643. SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
  644. }
  645. if (opts.StripReflection) {
  646. SerializeFlags |= SerializeDxilFlags::StripReflectionFromDxilPart;
  647. }
  648. // Don't do work to put in a container if an error has occurred
  649. // Do not create a container when there is only a a high-level representation in the module.
  650. if (compileOK && !opts.CodeGenHighLevel) {
  651. HRESULT valHR = S_OK;
  652. if (needsValidation) {
  653. valHR = dxcutil::ValidateAndAssembleToContainer(
  654. action.takeModule(), pOutputBlob, m_pMalloc, SerializeFlags,
  655. pOutputStream, opts.IsDebugInfoEnabled(), opts.GetPDBName(), compiler.getDiagnostics());
  656. } else {
  657. dxcutil::AssembleToContainer(action.takeModule(),
  658. pOutputBlob, m_pMalloc,
  659. SerializeFlags, pOutputStream);
  660. }
  661. // Callback after valid DXIL is produced
  662. if (SUCCEEDED(valHR)) {
  663. CComPtr<IDxcBlob> pTargetBlob;
  664. if (m_pDxcContainerEventsHandler != nullptr) {
  665. HRESULT hr = m_pDxcContainerEventsHandler->OnDxilContainerBuilt(pOutputBlob, &pTargetBlob);
  666. if (SUCCEEDED(hr) && pTargetBlob != nullptr) {
  667. std::swap(pOutputBlob, pTargetBlob);
  668. }
  669. }
  670. if (ppDebugBlobName && produceFullContainer) {
  671. const DxilContainerHeader *pContainer = reinterpret_cast<DxilContainerHeader *>(pOutputBlob->GetBufferPointer());
  672. DXASSERT(IsValidDxilContainer(pContainer, pOutputBlob->GetBufferSize()), "else invalid container generated");
  673. auto it = std::find_if(begin(pContainer), end(pContainer),
  674. DxilPartIsType(DFCC_ShaderDebugName));
  675. if (it != end(pContainer)) {
  676. const char *pDebugName;
  677. if (GetDxilShaderDebugName(*it, &pDebugName, nullptr) && pDebugName && *pDebugName) {
  678. IFTBOOL(Unicode::UTF8BufferToUTF16ComHeap(pDebugName, &DebugBlobName), DXC_E_CONTAINER_INVALID);
  679. }
  680. }
  681. }
  682. }
  683. }
  684. }
  685. // Add std err to warnings.
  686. msfPtr->WriteStdErrToStream(w);
  687. CreateOperationResultFromOutputs(pOutputBlob, msfPtr, warnings,
  688. compiler.getDiagnostics(), ppResult);
  689. // On success, return values. After assigning ppResult, nothing should fail.
  690. HRESULT status;
  691. DXVERIFY_NOMSG(SUCCEEDED((*ppResult)->GetStatus(&status)));
  692. if (SUCCEEDED(status)) {
  693. if (opts.IsDebugInfoEnabled() && ppDebugBlob) {
  694. CComPtr<IDxcBlob> pStrippedContainer;
  695. CComPtr<IDxcBlob> pDebugBitcodeBlob;
  696. DXVERIFY_NOMSG(SUCCEEDED(pOutputStream.QueryInterface(&pDebugBitcodeBlob)));
  697. DXVERIFY_NOMSG(SUCCEEDED(CreateContainerForPDB(m_pMalloc, pOutputBlob, pDebugBitcodeBlob, &pStrippedContainer)));
  698. DXVERIFY_NOMSG(SUCCEEDED((hlsl::pdb::WriteDxilPDB(m_pMalloc, pStrippedContainer, ppDebugBlob))));
  699. }
  700. if (ppDebugBlobName) {
  701. *ppDebugBlobName = DebugBlobName.Detach();
  702. }
  703. }
  704. hr = S_OK;
  705. } catch (std::bad_alloc &) {
  706. hr = E_OUTOFMEMORY;
  707. } catch (hlsl::Exception &e) {
  708. _Analysis_assume_(DXC_FAILED(e.hr));
  709. if (e.hr == DXC_E_ABORT_COMPILATION_ERROR) {
  710. e.hr = S_OK;
  711. CComPtr<IDxcBlobEncoding> pErrorBlob;
  712. IFT(DxcCreateBlobWithEncodingOnHeapCopy(e.msg.c_str(), e.msg.size(),
  713. CP_UTF8, &pErrorBlob));
  714. IFT(DxcOperationResult::CreateFromResultErrorStatus(
  715. nullptr, pErrorBlob, DXC_E_GENERAL_INTERNAL_ERROR, ppResult));
  716. }
  717. hr = e.hr;
  718. } catch (...) {
  719. hr = E_FAIL;
  720. }
  721. Cleanup:
  722. DxcEtw_DXCompilerCompile_Stop(hr);
  723. return hr;
  724. }
  725. // Preprocess source text
  726. HRESULT STDMETHODCALLTYPE Preprocess(
  727. _In_ IDxcBlob *pSource, // Source text to preprocess
  728. _In_opt_ LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and include handlers.
  729. _In_count_(argCount) LPCWSTR *pArguments, // Array of pointers to arguments
  730. _In_ UINT32 argCount, // Number of arguments
  731. _In_count_(defineCount) const DxcDefine *pDefines, // Array of defines
  732. _In_ UINT32 defineCount, // Number of defines
  733. _In_opt_ IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle #include directives (optional)
  734. _COM_Outptr_ IDxcOperationResult **ppResult // Preprocessor output status, buffer, and errors
  735. ) override {
  736. if (pSource == nullptr || ppResult == nullptr ||
  737. (defineCount > 0 && pDefines == nullptr) ||
  738. (argCount > 0 && pArguments == nullptr))
  739. return E_INVALIDARG;
  740. *ppResult = nullptr;
  741. HRESULT hr = S_OK;
  742. DxcEtw_DXCompilerPreprocess_Start();
  743. DxcThreadMalloc TM(m_pMalloc);
  744. CComPtr<IDxcBlobEncoding> utf8Source;
  745. IFC(hlsl::DxcGetBlobAsUtf8(pSource, &utf8Source));
  746. try {
  747. DefaultFPEnvScope fpEnvScope;
  748. CComPtr<AbstractMemoryStream> pOutputStream;
  749. dxcutil::DxcArgsFileSystem *msfPtr = dxcutil::CreateDxcArgsFileSystem(utf8Source, pSourceName, pIncludeHandler);
  750. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  751. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  752. IFTLLVM(pts.error_code());
  753. IFT(CreateMemoryStream(m_pMalloc, &pOutputStream));
  754. int argCountInt;
  755. IFT(UIntToInt(argCount, &argCountInt));
  756. hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0);
  757. hlsl::options::DxcOpts opts;
  758. bool finished;
  759. dxcutil::ReadOptsAndValidate(mainArgs, opts, pOutputStream, ppResult, finished);
  760. if (finished) {
  761. hr = S_OK;
  762. goto Cleanup;
  763. }
  764. // Prepare UTF8-encoded versions of API values.
  765. CW2A utf8SourceName(pSourceName, CP_UTF8);
  766. const char *pUtf8SourceName = utf8SourceName.m_psz;
  767. if (pUtf8SourceName == nullptr) {
  768. if (opts.InputFile.empty()) {
  769. pUtf8SourceName = "input.hlsl";
  770. }
  771. else {
  772. pUtf8SourceName = opts.InputFile.data();
  773. }
  774. }
  775. IFT(msfPtr->RegisterOutputStream(L"output.hlsl", pOutputStream));
  776. IFT(msfPtr->CreateStdStreams(m_pMalloc));
  777. StringRef Data((LPSTR)utf8Source->GetBufferPointer(),
  778. utf8Source->GetBufferSize());
  779. std::unique_ptr<llvm::MemoryBuffer> pBuffer(
  780. llvm::MemoryBuffer::getMemBufferCopy(Data, pUtf8SourceName));
  781. // Not very efficient but also not very important.
  782. std::vector<std::string> defines;
  783. CreateDefineStrings(pDefines, defineCount, defines);
  784. // Setup a compiler instance.
  785. std::string warnings;
  786. raw_string_ostream w(warnings);
  787. raw_stream_ostream outStream(pOutputStream.p);
  788. CompilerInstance compiler;
  789. std::unique_ptr<TextDiagnosticPrinter> diagPrinter =
  790. llvm::make_unique<TextDiagnosticPrinter>(w, &compiler.getDiagnosticOpts());
  791. SetupCompilerForCompile(compiler, &m_langExtensionsHelper, utf8SourceName, diagPrinter.get(), defines, opts, pArguments, argCount);
  792. msfPtr->SetupForCompilerInstance(compiler);
  793. // The clang entry point (cc1_main) would now create a compiler invocation
  794. // from arguments, but for this path we're exclusively trying to preproces
  795. // to text.
  796. compiler.getFrontendOpts().OutputFile = "output.hlsl";
  797. compiler.WriteDefaultOutputDirectly = true;
  798. compiler.setOutStream(&outStream);
  799. // These settings are back-compatible with fxc.
  800. clang::PreprocessorOutputOptions &PPOutOpts =
  801. compiler.getPreprocessorOutputOpts();
  802. PPOutOpts.ShowCPP = 1; // Print normal preprocessed output.
  803. PPOutOpts.ShowComments = 0; // Show comments.
  804. PPOutOpts.ShowLineMarkers = 1; // Show \#line markers.
  805. PPOutOpts.UseLineDirectives = 1; // Use \#line instead of GCC-style \# N.
  806. PPOutOpts.ShowMacroComments = 0; // Show comments, even in macros.
  807. PPOutOpts.ShowMacros = 0; // Print macro definitions.
  808. PPOutOpts.RewriteIncludes = 0; // Preprocess include directives only.
  809. FrontendInputFile file(utf8SourceName.m_psz, IK_HLSL);
  810. clang::PrintPreprocessedAction action;
  811. if (action.BeginSourceFile(compiler, file)) {
  812. action.Execute();
  813. action.EndSourceFile();
  814. }
  815. outStream.flush();
  816. // Add std err to warnings.
  817. msfPtr->WriteStdErrToStream(w);
  818. CreateOperationResultFromOutputs(pOutputStream, msfPtr, warnings,
  819. compiler.getDiagnostics(), ppResult);
  820. hr = S_OK;
  821. }
  822. CATCH_CPP_ASSIGN_HRESULT();
  823. Cleanup:
  824. DxcEtw_DXCompilerPreprocess_Stop(hr);
  825. return hr;
  826. }
  827. // Disassemble a shader.
  828. HRESULT STDMETHODCALLTYPE Disassemble(
  829. _In_ IDxcBlob *pProgram, // Program to disassemble.
  830. _COM_Outptr_ IDxcBlobEncoding** ppDisassembly // Disassembly text.
  831. ) override {
  832. if (pProgram == nullptr || ppDisassembly == nullptr)
  833. return E_INVALIDARG;
  834. *ppDisassembly = nullptr;
  835. HRESULT hr = S_OK;
  836. DxcEtw_DXCompilerDisassemble_Start();
  837. DxcThreadMalloc TM(m_pMalloc);
  838. try {
  839. DefaultFPEnvScope fpEnvScope;
  840. ::llvm::sys::fs::MSFileSystem *msfPtr;
  841. IFT(CreateMSFileSystemForDisk(&msfPtr));
  842. std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr);
  843. ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get());
  844. IFTLLVM(pts.error_code());
  845. std::string StreamStr;
  846. raw_string_ostream Stream(StreamStr);
  847. IFC(dxcutil::Disassemble(pProgram, Stream));
  848. IFT(DxcCreateBlobWithEncodingOnHeapCopy(
  849. StreamStr.c_str(), StreamStr.size(), CP_UTF8, ppDisassembly));
  850. return S_OK;
  851. }
  852. CATCH_CPP_ASSIGN_HRESULT();
  853. Cleanup:
  854. DxcEtw_DXCompilerDisassemble_Stop(hr);
  855. return hr;
  856. }
  857. void SetupCompilerForCompile(CompilerInstance &compiler,
  858. _In_ DxcLangExtensionsHelper *helper,
  859. _In_ LPCSTR pMainFile, _In_ TextDiagnosticPrinter *diagPrinter,
  860. _In_ std::vector<std::string>& defines,
  861. _In_ hlsl::options::DxcOpts &Opts,
  862. _In_count_(argCount) LPCWSTR *pArguments,
  863. _In_ UINT32 argCount) {
  864. // Setup a compiler instance.
  865. std::shared_ptr<TargetOptions> targetOptions(new TargetOptions);
  866. targetOptions->Triple = "dxil-ms-dx";
  867. targetOptions->DescriptionString = Opts.Enable16BitTypes
  868. ? hlsl::DXIL::kNewLayoutString
  869. : hlsl::DXIL::kLegacyLayoutString;
  870. compiler.HlslLangExtensions = helper;
  871. compiler.createDiagnostics(diagPrinter, false);
  872. // don't output warning to stderr/file if "/no-warnings" is present.
  873. compiler.getDiagnostics().setIgnoreAllWarnings(!Opts.OutputWarnings);
  874. compiler.createFileManager();
  875. compiler.createSourceManager(compiler.getFileManager());
  876. compiler.setTarget(
  877. TargetInfo::CreateTargetInfo(compiler.getDiagnostics(), targetOptions));
  878. if (Opts.EnableDX9CompatMode) {
  879. auto const ID = compiler.getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Warning, "/Gec flag is a deprecated functionality.");
  880. compiler.getDiagnostics().Report(ID);
  881. }
  882. compiler.getFrontendOpts().Inputs.push_back(FrontendInputFile(pMainFile, IK_HLSL));
  883. // Setup debug information.
  884. if (Opts.IsDebugInfoEnabled()) {
  885. CodeGenOptions &CGOpts = compiler.getCodeGenOpts();
  886. CGOpts.setDebugInfo(CodeGenOptions::FullDebugInfo);
  887. CGOpts.DebugColumnInfo = 1;
  888. CGOpts.DwarfVersion = 4; // Latest version.
  889. // TODO: consider
  890. // DebugPass, DebugCompilationDir, DwarfDebugFlags, SplitDwarfFile
  891. }
  892. clang::PreprocessorOptions &PPOpts(compiler.getPreprocessorOpts());
  893. for (size_t i = 0; i < defines.size(); ++i) {
  894. PPOpts.addMacroDef(defines[i]);
  895. }
  896. PPOpts.IgnoreLineDirectives = Opts.IgnoreLineDirectives;
  897. // fxc compatibility: pre-expand operands before performing token-pasting
  898. PPOpts.ExpandTokPastingArg = Opts.LegacyMacroExpansion;
  899. // Pick additional arguments.
  900. clang::HeaderSearchOptions &HSOpts = compiler.getHeaderSearchOpts();
  901. HSOpts.UseBuiltinIncludes = 0;
  902. // Consider: should we force-include '.' if the source file is relative?
  903. for (const llvm::opt::Arg *A : Opts.Args.filtered(options::OPT_I)) {
  904. const bool IsFrameworkFalse = false;
  905. const bool IgnoreSysRoot = true;
  906. if (dxcutil::IsAbsoluteOrCurDirRelative(A->getValue())) {
  907. HSOpts.AddPath(A->getValue(), frontend::Angled, IsFrameworkFalse, IgnoreSysRoot);
  908. }
  909. else {
  910. std::string s("./");
  911. s += A->getValue();
  912. HSOpts.AddPath(s, frontend::Angled, IsFrameworkFalse, IgnoreSysRoot);
  913. }
  914. }
  915. // Apply root signature option.
  916. unsigned rootSigMinor;
  917. if (Opts.ForceRootSigVer.empty() || Opts.ForceRootSigVer == "rootsig_1_1") {
  918. rootSigMinor = 1;
  919. }
  920. else {
  921. DXASSERT(Opts.ForceRootSigVer == "rootsig_1_0",
  922. "else opts should have been rejected");
  923. rootSigMinor = 0;
  924. }
  925. compiler.getLangOpts().RootSigMajor = 1;
  926. compiler.getLangOpts().RootSigMinor = rootSigMinor;
  927. compiler.getLangOpts().HLSLVersion = (unsigned) Opts.HLSLVersion;
  928. compiler.getLangOpts().EnableDX9CompatMode = Opts.EnableDX9CompatMode;
  929. compiler.getLangOpts().EnableFXCCompatMode = Opts.EnableFXCCompatMode;
  930. compiler.getLangOpts().UseMinPrecision = !Opts.Enable16BitTypes;
  931. // SPIRV change starts
  932. #ifdef ENABLE_SPIRV_CODEGEN
  933. compiler.getLangOpts().SPIRV = Opts.GenSPIRV;
  934. #endif
  935. // SPIRV change ends
  936. if (Opts.WarningAsError)
  937. compiler.getDiagnostics().setWarningsAsErrors(true);
  938. if (Opts.IEEEStrict)
  939. compiler.getCodeGenOpts().UnsafeFPMath = true;
  940. if (Opts.FloatDenormalMode.empty()) {
  941. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Reserve7; // undefined
  942. }
  943. else if (Opts.FloatDenormalMode.equals_lower(StringRef("any"))) {
  944. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Any;
  945. }
  946. else if (Opts.FloatDenormalMode.equals_lower(StringRef("ftz"))) {
  947. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::FTZ;
  948. }
  949. else {
  950. DXASSERT(Opts.FloatDenormalMode.equals_lower(StringRef("preserve")), "else opts should have been rejected");
  951. compiler.getCodeGenOpts().HLSLFloat32DenormMode = DXIL::Float32DenormMode::Preserve;
  952. }
  953. if (Opts.DisableOptimizations)
  954. compiler.getCodeGenOpts().DisableLLVMOpts = true;
  955. compiler.getCodeGenOpts().OptimizationLevel = Opts.OptLevel;
  956. if (Opts.OptLevel >= 3)
  957. compiler.getCodeGenOpts().UnrollLoops = true;
  958. compiler.getCodeGenOpts().HLSLHighLevel = Opts.CodeGenHighLevel;
  959. compiler.getCodeGenOpts().HLSLResMayAlias = Opts.ResMayAlias;
  960. compiler.getCodeGenOpts().HLSLAllResourcesBound = Opts.AllResourcesBound;
  961. compiler.getCodeGenOpts().HLSLDefaultRowMajor = Opts.DefaultRowMajor;
  962. compiler.getCodeGenOpts().HLSLPreferControlFlow = Opts.PreferFlowControl;
  963. compiler.getCodeGenOpts().HLSLAvoidControlFlow = Opts.AvoidFlowControl;
  964. compiler.getCodeGenOpts().HLSLNotUseLegacyCBufLoad = Opts.NotUseLegacyCBufLoad;
  965. compiler.getCodeGenOpts().HLSLLegacyResourceReservation = Opts.LegacyResourceReservation;
  966. compiler.getCodeGenOpts().HLSLDefines = defines;
  967. compiler.getCodeGenOpts().MainFileName = pMainFile;
  968. // Translate signature packing options
  969. if (Opts.PackPrefixStable)
  970. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::PrefixStable;
  971. else if (Opts.PackOptimized)
  972. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::Optimized;
  973. else
  974. compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = (unsigned)DXIL::PackingStrategy::Default;
  975. // Constructing vector of wide strings to pass in to codegen. Just passing
  976. // in pArguments will expose ownership of memory to both CodeGenOptions and
  977. // this caller, which can lead to unexpected behavior.
  978. for (UINT32 i = 0; i != argCount; ++i) {
  979. compiler.getCodeGenOpts().HLSLArguments.emplace_back(
  980. Unicode::UTF16ToUTF8StringOrThrow(pArguments[i]));
  981. }
  982. // Overrding default set of loop unroll.
  983. if (Opts.PreferFlowControl)
  984. compiler.getCodeGenOpts().UnrollLoops = false;
  985. if (Opts.AvoidFlowControl)
  986. compiler.getCodeGenOpts().UnrollLoops = true;
  987. // always inline for hlsl
  988. compiler.getCodeGenOpts().setInlining(
  989. clang::CodeGenOptions::OnlyAlwaysInlining);
  990. compiler.getCodeGenOpts().HLSLExtensionsCodegen = std::make_shared<HLSLExtensionsCodegenHelperImpl>(compiler, m_langExtensionsHelper, Opts.RootSignatureDefine);
  991. // AutoBindingSpace also enables automatic binding for libraries if set. UINT_MAX == unset
  992. compiler.getCodeGenOpts().HLSLDefaultSpace = Opts.AutoBindingSpace;
  993. // processed export names from -exports option:
  994. compiler.getCodeGenOpts().HLSLLibraryExports = Opts.Exports;
  995. // only export shader functions for library
  996. compiler.getCodeGenOpts().ExportShadersOnly = Opts.ExportShadersOnly;
  997. if (Opts.DefaultLinkage.empty()) {
  998. compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::Default;
  999. } else if (Opts.DefaultLinkage.equals_lower("internal")) {
  1000. compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::Internal;
  1001. } else if (Opts.DefaultLinkage.equals_lower("external")) {
  1002. compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::External;
  1003. }
  1004. }
  1005. // IDxcVersionInfo
  1006. HRESULT STDMETHODCALLTYPE GetVersion(_Out_ UINT32 *pMajor, _Out_ UINT32 *pMinor) override {
  1007. if (pMajor == nullptr || pMinor == nullptr)
  1008. return E_INVALIDARG;
  1009. *pMajor = DXIL::kDxilMajor;
  1010. *pMinor = DXIL::kDxilMinor;
  1011. return S_OK;
  1012. }
  1013. #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO
  1014. HRESULT STDMETHODCALLTYPE GetCommitInfo(_Out_ UINT32 *pCommitCount,
  1015. _Out_ char **pCommitHash) override {
  1016. if (pCommitCount == nullptr || pCommitHash == nullptr)
  1017. return E_INVALIDARG;
  1018. char *const hash = (char *)CoTaskMemAlloc(8 + 1); // 8 is guaranteed by utils/GetCommitInfo.py
  1019. if (hash == nullptr)
  1020. return E_OUTOFMEMORY;
  1021. std::strcpy(hash, getGitCommitHash());
  1022. *pCommitHash = hash;
  1023. *pCommitCount = getGitCommitCount();
  1024. return S_OK;
  1025. }
  1026. #endif // SUPPORT_QUERY_GIT_COMMIT_INFO
  1027. HRESULT STDMETHODCALLTYPE GetFlags(_Out_ UINT32 *pFlags) override {
  1028. if (pFlags == nullptr)
  1029. return E_INVALIDARG;
  1030. *pFlags = DxcVersionInfoFlags_None;
  1031. #ifdef _DEBUG
  1032. *pFlags |= DxcVersionInfoFlags_Debug;
  1033. #endif
  1034. return S_OK;
  1035. }
  1036. };
  1037. HRESULT CreateDxcCompiler(_In_ REFIID riid, _Out_ LPVOID* ppv) {
  1038. *ppv = nullptr;
  1039. try {
  1040. CComPtr<DxcCompiler> result(DxcCompiler::Alloc(DxcGetThreadMallocNoRef()));
  1041. IFROOM(result.p);
  1042. return result.p->QueryInterface(riid, ppv);
  1043. }
  1044. CATCH_CPP_RETURN_HRESULT();
  1045. }