/home/runner/work/DirectXShaderCompiler/DirectXShaderCompiler/tools/clang/tools/dxcompiler/dxcompilerobj.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
12 | | #include "clang/Basic/Diagnostic.h" |
13 | | #include "clang/Basic/FileManager.h" |
14 | | #include "clang/Basic/SourceManager.h" |
15 | | #include "clang/Basic/TargetInfo.h" |
16 | | #include "clang/Basic/TargetOptions.h" |
17 | | #include "clang/CodeGen/CodeGenAction.h" |
18 | | #include "clang/Frontend/ASTUnit.h" |
19 | | #include "clang/Frontend/CompilerInstance.h" |
20 | | #include "clang/Frontend/FrontendActions.h" |
21 | | #include "clang/Frontend/FrontendDiagnostic.h" |
22 | | #include "clang/Frontend/TextDiagnosticPrinter.h" |
23 | | #include "clang/Lex/HLSLMacroExpander.h" |
24 | | #include "clang/Lex/Preprocessor.h" |
25 | | #include "clang/Sema/SemaHLSL.h" |
26 | | #include "llvm/Bitcode/ReaderWriter.h" |
27 | | #include "llvm/IR/LLVMContext.h" |
28 | | #include "llvm/Support/TimeProfiler.h" |
29 | | #include "llvm/Support/Timer.h" |
30 | | #include "llvm/Transforms/Utils/Cloning.h" |
31 | | |
32 | | #include "dxc/DXIL/DxilModule.h" |
33 | | #include "dxc/DXIL/DxilPDB.h" |
34 | | #include "dxc/DxcBindingTable/DxcBindingTable.h" |
35 | | #include "dxc/DxilContainer/DxilContainerAssembler.h" |
36 | | #include "dxc/DxilRootSignature/DxilRootSignature.h" |
37 | | #include "dxc/HLSL/HLSLExtensionsCodegenHelper.h" |
38 | | #include "dxc/Support/Path.h" |
39 | | #include "dxc/Support/WinIncludes.h" |
40 | | #include "dxc/Support/dxcfilesystem.h" |
41 | | #include "dxc/dxcapi.internal.h" |
42 | | #include "dxcutil.h" |
43 | | |
44 | | #include "dxc/Support/DxcLangExtensionsHelper.h" |
45 | | #include "dxc/Support/FileIOHelper.h" |
46 | | #include "dxc/Support/Global.h" |
47 | | #include "dxc/Support/HLSLOptions.h" |
48 | | #include "dxc/Support/Unicode.h" |
49 | | #include "dxc/Support/dxcapi.impl.h" |
50 | | #include "dxc/Support/dxcapi.use.h" |
51 | | #include "dxc/Support/microcom.h" |
52 | | |
53 | | #ifdef _WIN32 |
54 | | #include "dxcetw.h" |
55 | | #endif |
56 | | #include "dxcompileradapter.h" |
57 | | #include "dxcshadersourceinfo.h" |
58 | | #include "dxcversion.inc" |
59 | | #include <algorithm> |
60 | | #include <cfloat> |
61 | | |
62 | | // SPIRV change starts |
63 | | #ifdef ENABLE_SPIRV_CODEGEN |
64 | | #include "clang/SPIRV/EmitSpirvAction.h" |
65 | | #include "clang/SPIRV/FeatureManager.h" |
66 | | #endif |
67 | | // SPIRV change ends |
68 | | |
69 | | #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO |
70 | | #include "clang/Basic/Version.h" |
71 | | #endif // SUPPORT_QUERY_GIT_COMMIT_INFO |
72 | | |
73 | | #ifdef ENABLE_METAL_CODEGEN |
74 | | #include "metal_irconverter.h" |
75 | | #endif |
76 | | |
77 | | #define CP_UTF16 1200 |
78 | | |
79 | | using namespace llvm; |
80 | | using namespace clang; |
81 | | using namespace hlsl; |
82 | | using std::string; |
83 | | |
84 | 28.8k | static bool ShouldBeCopiedIntoPDB(UINT32 FourCC) { |
85 | 28.8k | switch (FourCC) { |
86 | 3.90k | case hlsl::DFCC_ShaderDebugName: |
87 | 7.80k | case hlsl::DFCC_ShaderHash: |
88 | 7.80k | return true; |
89 | 28.8k | } |
90 | 21.0k | return false; |
91 | 28.8k | } |
92 | | |
93 | | static HRESULT CreateContainerForPDB(IMalloc *pMalloc, IDxcBlob *pOldContainer, |
94 | | IDxcBlob *pDebugBlob, |
95 | | IDxcVersionInfo *pVersionInfo, |
96 | | const hlsl::DxilSourceInfo *pSourceInfo, |
97 | | AbstractMemoryStream *pReflectionStream, |
98 | 3.90k | IDxcBlob **ppNewContainer) { |
99 | | // If the pContainer is not a valid container, give up. |
100 | 3.90k | if (!hlsl::IsValidDxilContainer( |
101 | 3.90k | (hlsl::DxilContainerHeader *)pOldContainer->GetBufferPointer(), |
102 | 3.90k | pOldContainer->GetBufferSize())) |
103 | 0 | return E_FAIL; |
104 | | |
105 | 3.90k | hlsl::DxilContainerHeader *DxilHeader = |
106 | 3.90k | (hlsl::DxilContainerHeader *)pOldContainer->GetBufferPointer(); |
107 | 3.90k | hlsl::DxilProgramHeader *ProgramHeader = nullptr; |
108 | | |
109 | 3.90k | std::unique_ptr<DxilContainerWriter> containerWriter( |
110 | 3.90k | NewDxilContainerWriter(false)); |
111 | 3.90k | std::unique_ptr<DxilPartWriter> pDxilVersionWriter( |
112 | 3.90k | NewVersionWriter(pVersionInfo)); |
113 | | |
114 | 32.7k | for (unsigned i = 0; i < DxilHeader->PartCount; i++28.8k ) { |
115 | 28.8k | hlsl::DxilPartHeader *PartHeader = GetDxilContainerPart(DxilHeader, i); |
116 | 28.8k | if (ShouldBeCopiedIntoPDB(PartHeader->PartFourCC)) { |
117 | 7.80k | UINT32 uSize = PartHeader->PartSize; |
118 | 7.80k | const void *pPartData = PartHeader + 1; |
119 | 7.80k | containerWriter->AddPart( |
120 | 7.80k | PartHeader->PartFourCC, uSize, |
121 | 7.80k | [pPartData, uSize](AbstractMemoryStream *pStream) { |
122 | 7.80k | ULONG uBytesWritten = 0; |
123 | 7.80k | IFR(pStream->Write(pPartData, uSize, &uBytesWritten)); |
124 | 7.80k | return S_OK; |
125 | 7.80k | }); |
126 | 7.80k | } |
127 | | |
128 | | // Could use any of these. We're mostly after the header version and all |
129 | | // that. |
130 | 28.8k | if (PartHeader->PartFourCC == hlsl::DFCC_DXIL || |
131 | 28.8k | PartHeader->PartFourCC == hlsl::DFCC_ShaderDebugInfoDXIL24.9k ) { |
132 | 4.56k | ProgramHeader = (hlsl::DxilProgramHeader *)(PartHeader + 1); |
133 | 4.56k | } |
134 | 28.8k | } |
135 | | |
136 | 3.90k | if (!ProgramHeader) |
137 | 0 | return E_FAIL; |
138 | | |
139 | 3.90k | if (pSourceInfo) { |
140 | 3.89k | const UINT32 uPartSize = pSourceInfo->AlignedSizeInBytes; |
141 | | |
142 | 3.89k | containerWriter->AddPart(hlsl::DFCC_ShaderSourceInfo, uPartSize, |
143 | 3.89k | [pSourceInfo](IStream *pStream) { |
144 | 3.89k | ULONG uBytesWritten = 0; |
145 | 3.89k | pStream->Write(pSourceInfo, |
146 | 3.89k | pSourceInfo->AlignedSizeInBytes, |
147 | 3.89k | &uBytesWritten); |
148 | 3.89k | return S_OK; |
149 | 3.89k | }); |
150 | 3.89k | } |
151 | | |
152 | 3.90k | if (pReflectionStream) { |
153 | 16 | const hlsl::DxilPartHeader *pReflectionPartHeader = |
154 | 16 | (const hlsl::DxilPartHeader *)pReflectionStream->GetPtr(); |
155 | | |
156 | 16 | containerWriter->AddPart( |
157 | 16 | hlsl::DFCC_ShaderStatistics, pReflectionPartHeader->PartSize, |
158 | 16 | [pReflectionPartHeader](IStream *pStream) { |
159 | 16 | ULONG uBytesWritten = 0; |
160 | 16 | pStream->Write(pReflectionPartHeader + 1, |
161 | 16 | pReflectionPartHeader->PartSize, &uBytesWritten); |
162 | 16 | return S_OK; |
163 | 16 | }); |
164 | 16 | } |
165 | | |
166 | 3.90k | if (pVersionInfo) { |
167 | 3.90k | containerWriter->AddPart( |
168 | 3.90k | hlsl::DFCC_CompilerVersion, pDxilVersionWriter->size(), |
169 | 3.90k | [&pDxilVersionWriter](AbstractMemoryStream *pStream) { |
170 | 3.90k | pDxilVersionWriter->write(pStream); |
171 | 3.90k | return S_OK; |
172 | 3.90k | }); |
173 | 3.90k | } |
174 | | |
175 | 3.90k | if (pDebugBlob) { |
176 | 3.88k | static auto AlignByDword = [](UINT32 uSize, UINT32 *pPaddingBytes) { |
177 | 3.88k | UINT32 uRem = uSize % sizeof(UINT32); |
178 | 3.88k | UINT32 uResult = |
179 | 3.88k | (uSize / sizeof(UINT32) + (uRem ? 10 : 0)) * sizeof(UINT32); |
180 | 3.88k | *pPaddingBytes = uRem ? (sizeof(UINT32) - uRem)0 : 0; |
181 | 3.88k | return uResult; |
182 | 3.88k | }; |
183 | | |
184 | 3.88k | UINT32 uPaddingSize = 0; |
185 | 3.88k | UINT32 uPartSize = AlignByDword(sizeof(hlsl::DxilProgramHeader) + |
186 | 3.88k | pDebugBlob->GetBufferSize(), |
187 | 3.88k | &uPaddingSize); |
188 | | |
189 | 3.88k | containerWriter->AddPart( |
190 | 3.88k | hlsl::DFCC_ShaderDebugInfoDXIL, uPartSize, |
191 | 3.88k | [uPartSize, ProgramHeader, pDebugBlob, uPaddingSize](IStream *pStream) { |
192 | 3.88k | hlsl::DxilProgramHeader Header = *ProgramHeader; |
193 | 3.88k | Header.BitcodeHeader.BitcodeSize = pDebugBlob->GetBufferSize(); |
194 | 3.88k | Header.BitcodeHeader.BitcodeOffset = sizeof(hlsl::DxilBitcodeHeader); |
195 | 3.88k | Header.SizeInUint32 = uPartSize / sizeof(UINT32); |
196 | | |
197 | 3.88k | ULONG uBytesWritten = 0; |
198 | 3.88k | IFR(pStream->Write(&Header, sizeof(Header), &uBytesWritten)); |
199 | 3.88k | IFR(pStream->Write(pDebugBlob->GetBufferPointer(), |
200 | 3.88k | pDebugBlob->GetBufferSize(), &uBytesWritten)); |
201 | 3.88k | if (uPaddingSize) { |
202 | 0 | UINT32 uPadding = 0; |
203 | 0 | assert(uPaddingSize <= sizeof(uPadding) && |
204 | 0 | "Padding size calculation is wrong."); |
205 | 0 | IFR(pStream->Write(&uPadding, uPaddingSize, &uBytesWritten)); |
206 | 0 | } |
207 | 3.88k | return S_OK; |
208 | 3.88k | }); |
209 | 3.88k | } |
210 | | |
211 | 3.90k | CComPtr<hlsl::AbstractMemoryStream> pStrippedContainerStream; |
212 | 3.90k | IFR(hlsl::CreateMemoryStream(pMalloc, &pStrippedContainerStream)); |
213 | | |
214 | 3.90k | containerWriter->write(pStrippedContainerStream); |
215 | 3.90k | IFR(pStrippedContainerStream.QueryInterface(ppNewContainer)); |
216 | | |
217 | 3.90k | return S_OK; |
218 | 3.90k | } |
219 | | |
220 | | #ifdef _WIN32 |
221 | | |
222 | | #pragma fenv_access(on) |
223 | | |
224 | | struct DefaultFPEnvScope { |
225 | | // _controlfp_s is non-standard and <cfenv>.feholdexceptions doesn't work on |
226 | | // windows...? |
227 | | unsigned int previousValue; |
228 | | DefaultFPEnvScope() { |
229 | | // _controlfp_s returns the value of the control word as it is after |
230 | | // the call, not before the call. This is the proper way to get the |
231 | | // previous value. |
232 | | errno_t error = _controlfp_s(&previousValue, 0, 0); |
233 | | IFT(error == 0 ? S_OK : E_FAIL); |
234 | | // No exceptions, preserve denormals & round to nearest. |
235 | | unsigned int newValue; |
236 | | error = _controlfp_s(&newValue, _MCW_EM | _DN_SAVE | _RC_NEAR, |
237 | | _MCW_EM | _MCW_DN | _MCW_RC); |
238 | | IFT(error == 0 ? S_OK : E_FAIL); |
239 | | } |
240 | | ~DefaultFPEnvScope() { |
241 | | _clearfp(); |
242 | | unsigned int newValue; |
243 | | errno_t error = |
244 | | _controlfp_s(&newValue, previousValue, _MCW_EM | _MCW_DN | _MCW_RC); |
245 | | // During cleanup we can't throw as we might already be handling another |
246 | | // one. |
247 | | DXASSERT_LOCALVAR(error, error == 0, |
248 | | "Failed to restore floating-point environment."); |
249 | | } |
250 | | }; |
251 | | |
252 | | #else // _WIN32 |
253 | | |
254 | | struct DefaultFPEnvScope { |
255 | 33.7k | DefaultFPEnvScope() {} // Dummy ctor to avoid unused local warning |
256 | | }; |
257 | | |
258 | | #endif // _WIN32 |
259 | | |
260 | | class HLSLExtensionsCodegenHelperImpl : public HLSLExtensionsCodegenHelper { |
261 | | private: |
262 | | CompilerInstance &m_CI; |
263 | | DxcLangExtensionsHelper &m_langExtensionsHelper; |
264 | | std::string m_rootSigDefine; |
265 | | |
266 | | // The metadata format is a root node that has pointers to metadata |
267 | | // nodes for each define. The metatdata node for a define is a pair |
268 | | // of (name, value) metadata strings. |
269 | | // |
270 | | // Example: |
271 | | // !hlsl.semdefs = {!0, !1} |
272 | | // !0 = !{!"FOO", !"BAR"} |
273 | | // !1 = !{!"BOO", !"HOO"} |
274 | | void WriteSemanticDefines(llvm::Module *M, |
275 | 54 | const ParsedSemanticDefineList &defines) { |
276 | | // Create all metadata nodes for each define. Each node is a (name, value) |
277 | | // pair. |
278 | 54 | std::vector<MDNode *> mdNodes; |
279 | 54 | const std::string enableStr("_ENABLE_"); |
280 | 54 | const std::string disableStr("_DISABLE_"); |
281 | 54 | const std::string selectStr("_SELECT_"); |
282 | | |
283 | 54 | auto &optToggles = m_CI.getCodeGenOpts().HLSLOptimizationToggles.Toggles; |
284 | 54 | auto &optSelects = m_CI.getCodeGenOpts().HLSLOptimizationToggles.Selects; |
285 | | |
286 | 54 | const llvm::SmallVector<std::string, 2> &semDefPrefixes = |
287 | 54 | m_langExtensionsHelper.GetSemanticDefines(); |
288 | | |
289 | | // Add semantic defines to mdNodes and also to codeGenOpts |
290 | 82 | for (const ParsedSemanticDefine &define : defines) { |
291 | 82 | MDString *name = MDString::get(M->getContext(), define.Name); |
292 | 82 | MDString *value = MDString::get(M->getContext(), define.Value); |
293 | 82 | mdNodes.push_back(MDNode::get(M->getContext(), {name, value})); |
294 | | |
295 | | // Find index for end of matching semantic define prefix |
296 | 82 | size_t prefixPos = 0; |
297 | 82 | for (auto prefix : semDefPrefixes) { |
298 | 82 | if (IsMacroMatch(define.Name, prefix)) { |
299 | 82 | prefixPos = prefix.length() - 1; |
300 | 82 | break; |
301 | 82 | } |
302 | 82 | } |
303 | | |
304 | | // Add semantic defines to option flag equivalents |
305 | | // Convert define-style '_' into option-style '-' and lowercase everything |
306 | 82 | if (!define.Name.compare(prefixPos, enableStr.length(), enableStr)) { |
307 | 2 | std::string optName = |
308 | 2 | define.Name.substr(prefixPos + enableStr.length()); |
309 | 2 | std::replace(optName.begin(), optName.end(), '_', '-'); |
310 | 2 | optToggles[StringRef(optName).lower()] = true; |
311 | 80 | } else if (!define.Name.compare(prefixPos, disableStr.length(), |
312 | 80 | disableStr)) { |
313 | 4 | std::string optName = |
314 | 4 | define.Name.substr(prefixPos + disableStr.length()); |
315 | 4 | std::replace(optName.begin(), optName.end(), '_', '-'); |
316 | 4 | optToggles[StringRef(optName).lower()] = false; |
317 | 76 | } else if (!define.Name.compare(prefixPos, selectStr.length(), |
318 | 76 | selectStr)) { |
319 | 0 | std::string optName = |
320 | 0 | define.Name.substr(prefixPos + selectStr.length()); |
321 | 0 | std::replace(optName.begin(), optName.end(), '_', '-'); |
322 | 0 | optSelects[StringRef(optName).lower()] = define.Value; |
323 | 0 | } |
324 | 82 | } |
325 | | |
326 | | // Add root node with pointers to all define metadata nodes. |
327 | 54 | NamedMDNode *Root = M->getOrInsertNamedMetadata( |
328 | 54 | m_langExtensionsHelper.GetSemanticDefineMetadataName()); |
329 | 54 | for (MDNode *node : mdNodes) |
330 | 82 | Root->addOperand(node); |
331 | 54 | } |
332 | | |
333 | | SemanticDefineErrorList |
334 | | GetValidatedSemanticDefines(const ParsedSemanticDefineList &defines, |
335 | | ParsedSemanticDefineList &validated, |
336 | 54 | SemanticDefineErrorList &errors) { |
337 | 84 | for (const ParsedSemanticDefine &define : defines) { |
338 | 84 | DxcLangExtensionsHelper::SemanticDefineValidationResult result = |
339 | 84 | m_langExtensionsHelper.ValidateSemanticDefine(define.Name, |
340 | 84 | define.Value); |
341 | 84 | if (result.HasError()) |
342 | 2 | errors.emplace_back(SemanticDefineError( |
343 | 2 | define.Location, SemanticDefineError::Level::Error, result.Error)); |
344 | 84 | if (result.HasWarning()) |
345 | 2 | errors.emplace_back(SemanticDefineError( |
346 | 2 | define.Location, SemanticDefineError::Level::Warning, |
347 | 2 | result.Warning)); |
348 | 84 | if (!result.HasError()) |
349 | 82 | validated.emplace_back(define); |
350 | 84 | } |
351 | | |
352 | 54 | return errors; |
353 | 54 | } |
354 | | |
355 | | public: |
356 | | HLSLExtensionsCodegenHelperImpl(CompilerInstance &CI, |
357 | | DxcLangExtensionsHelper &langExtensionsHelper, |
358 | | StringRef rootSigDefine) |
359 | 25.5k | : m_CI(CI), m_langExtensionsHelper(langExtensionsHelper), |
360 | 25.5k | m_rootSigDefine(rootSigDefine) {} |
361 | | |
362 | | // Write semantic defines as metadata in the module. |
363 | 20.0k | virtual void WriteSemanticDefines(llvm::Module *M) override { |
364 | | // Grab the semantic defines seen by the parser. |
365 | 20.0k | ParsedSemanticDefineList defines = |
366 | 20.0k | CollectSemanticDefinesParsedByCompiler(m_CI, &m_langExtensionsHelper); |
367 | | |
368 | | // Nothing to do if we have no defines. |
369 | 20.0k | SemanticDefineErrorList errors; |
370 | 20.0k | if (!defines.size()) |
371 | 19.9k | return; |
372 | | |
373 | 54 | ParsedSemanticDefineList validated; |
374 | 54 | GetValidatedSemanticDefines(defines, validated, errors); |
375 | 54 | WriteSemanticDefines(M, validated); |
376 | | |
377 | 54 | auto &Diags = m_CI.getDiagnostics(); |
378 | 54 | for (const auto &error : errors) { |
379 | 4 | clang::DiagnosticsEngine::Level level = clang::DiagnosticsEngine::Error; |
380 | 4 | if (error.IsWarning()) |
381 | 2 | level = clang::DiagnosticsEngine::Warning; |
382 | 4 | unsigned DiagID = Diags.getCustomDiagID(level, "%0"); |
383 | 4 | Diags.Report(clang::SourceLocation::getFromRawEncoding(error.Location()), |
384 | 4 | DiagID) |
385 | 4 | << error.Message(); |
386 | 4 | } |
387 | 54 | } |
388 | | // Update CodeGenOption based on HLSLOptimizationToggles. |
389 | 20.0k | void UpdateCodeGenOptions(clang::CodeGenOptions &CGO) override { |
390 | 20.0k | auto &CodeGenOpts = m_CI.getCodeGenOpts(); |
391 | 20.0k | CGO.HLSLEnableLifetimeMarkers &= |
392 | 20.0k | CodeGenOpts.HLSLOptimizationToggles.IsEnabled( |
393 | 20.0k | hlsl::options::TOGGLE_LIFETIME_MARKERS); |
394 | 20.0k | } |
395 | 20.0k | virtual bool IsOptionEnabled(hlsl::options::Toggle toggle) override { |
396 | 20.0k | return m_CI.getCodeGenOpts().HLSLOptimizationToggles.IsEnabled(toggle); |
397 | 20.0k | } |
398 | | |
399 | 66 | virtual std::string GetIntrinsicName(UINT opcode) override { |
400 | 66 | return m_langExtensionsHelper.GetIntrinsicName(opcode); |
401 | 66 | } |
402 | | |
403 | 6 | virtual bool GetDxilOpcode(UINT opcode, OP::OpCode &dxilOpcode) override { |
404 | 6 | UINT dop = static_cast<UINT>(OP::OpCode::NumOpCodes); |
405 | 6 | if (m_langExtensionsHelper.GetDxilOpCode(opcode, dop)) { |
406 | 6 | if (dop < static_cast<UINT>(OP::OpCode::NumOpCodes)) { |
407 | 6 | dxilOpcode = static_cast<OP::OpCode>(dop); |
408 | 6 | return true; |
409 | 6 | } |
410 | 6 | } |
411 | 0 | return false; |
412 | 6 | } |
413 | | |
414 | | virtual HLSLExtensionsCodegenHelper::CustomRootSignature::Status |
415 | 20.0k | GetCustomRootSignature(CustomRootSignature *out) override { |
416 | | // Find macro definition in preprocessor. |
417 | 20.0k | Preprocessor &pp = m_CI.getPreprocessor(); |
418 | 20.0k | MacroInfo *macro = MacroExpander::FindMacroInfo(pp, m_rootSigDefine); |
419 | 20.0k | if (!macro) |
420 | 20.0k | return CustomRootSignature::NOT_FOUND; |
421 | | |
422 | | // Combine tokens into single string |
423 | 0 | MacroExpander expander(pp, MacroExpander::STRIP_QUOTES); |
424 | 0 | if (!expander.ExpandMacro(macro, &out->RootSignature)) |
425 | 0 | return CustomRootSignature::NOT_FOUND; |
426 | | |
427 | | // Record source location of root signature macro. |
428 | 0 | out->EncodedSourceLocation = macro->getDefinitionLoc().getRawEncoding(); |
429 | |
|
430 | 0 | return CustomRootSignature::FOUND; |
431 | 0 | } |
432 | | }; |
433 | | |
434 | | static void CreateDefineStrings(const DxcDefine *pDefines, UINT defineCount, |
435 | 25.5k | std::vector<std::string> &defines) { |
436 | | // Not very efficient but also not very important. |
437 | 33.6k | for (UINT32 i = 0; i < defineCount; i++8.04k ) { |
438 | 8.04k | CW2A utf8Name(pDefines[i].Name); |
439 | 8.04k | CW2A utf8Value(pDefines[i].Value); |
440 | 8.04k | std::string val(utf8Name.m_psz); |
441 | 8.04k | val += "="; |
442 | 8.04k | val += (pDefines[i].Value) ? utf8Value.m_psz7.27k : "1"774 ; |
443 | 8.04k | defines.push_back(val); |
444 | 8.04k | } |
445 | 25.5k | } |
446 | | |
447 | | static HRESULT ErrorWithString(const std::string &error, REFIID riid, |
448 | 30 | void **ppResult) { |
449 | 30 | CComPtr<IDxcResult> pResult; |
450 | 30 | IFT(DxcResult::Create( |
451 | 30 | E_FAIL, DXC_OUT_NONE, |
452 | 30 | {DxcOutputObject::ErrorOutput(CP_UTF8, error.data(), error.size())}, |
453 | 30 | &pResult)); |
454 | 30 | IFT(pResult->QueryInterface(riid, ppResult)); |
455 | 30 | return S_OK; |
456 | 30 | } |
457 | | |
458 | | class DxcCompiler : public IDxcCompiler3, |
459 | | public IDxcLangExtensions3, |
460 | | public IDxcContainerEvent, |
461 | | public IDxcVersionInfo3, |
462 | | #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO |
463 | | public IDxcVersionInfo2 |
464 | | #else |
465 | | public IDxcVersionInfo |
466 | | #endif // SUPPORT_QUERY_GIT_COMMIT_INFO |
467 | | { |
468 | | private: |
469 | | DXC_MICROCOM_TM_REF_FIELDS() |
470 | | DxcLangExtensionsHelper m_langExtensionsHelper; |
471 | | CComPtr<IDxcContainerEventsHandler> m_pDxcContainerEventsHandler; |
472 | | DxcCompilerAdapter m_DxcCompilerAdapter; |
473 | | |
474 | | public: |
475 | | DxcCompiler(IMalloc *pMalloc) |
476 | 36.5k | : m_dwRef(0), m_pMalloc(pMalloc), m_DxcCompilerAdapter(this, pMalloc) {} |
477 | | DXC_MICROCOM_TM_ADDREF_RELEASE_IMPL() |
478 | | DXC_MICROCOM_TM_ALLOC(DxcCompiler) |
479 | | DXC_LANGEXTENSIONS_HELPER_IMPL(m_langExtensionsHelper) |
480 | | |
481 | | HRESULT STDMETHODCALLTYPE RegisterDxilContainerEventHandler( |
482 | 0 | IDxcContainerEventsHandler *pHandler, UINT64 *pCookie) override { |
483 | 0 | DXASSERT(m_pDxcContainerEventsHandler == nullptr, |
484 | 0 | "else events handler is already registered"); |
485 | 0 | *pCookie = 1; // Only one EventsHandler supported |
486 | 0 | m_pDxcContainerEventsHandler = pHandler; |
487 | 0 | return S_OK; |
488 | 0 | }; |
489 | | HRESULT STDMETHODCALLTYPE |
490 | 0 | UnRegisterDxilContainerEventHandler(UINT64 cookie) override { |
491 | 0 | DXASSERT(m_pDxcContainerEventsHandler != nullptr, |
492 | 0 | "else unregister should not have been called"); |
493 | 0 | m_pDxcContainerEventsHandler.Release(); |
494 | 0 | return S_OK; |
495 | 0 | } |
496 | | |
497 | | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, |
498 | 67.4k | void **ppvObject) override { |
499 | 67.4k | HRESULT hr = DoBasicQueryInterface<IDxcCompiler3, IDxcLangExtensions, |
500 | 67.4k | IDxcLangExtensions2, IDxcLangExtensions3, |
501 | 67.4k | IDxcContainerEvent, IDxcVersionInfo |
502 | 67.4k | #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO |
503 | 67.4k | , |
504 | 67.4k | IDxcVersionInfo2 |
505 | 67.4k | #endif // SUPPORT_QUERY_GIT_COMMIT_INFO |
506 | 67.4k | , |
507 | 67.4k | IDxcVersionInfo3>(this, iid, ppvObject); |
508 | 67.4k | if (FAILED(hr)) { |
509 | 38.3k | return DoBasicQueryInterface<IDxcCompiler, IDxcCompiler2>( |
510 | 38.3k | &m_DxcCompilerAdapter, iid, ppvObject); |
511 | 38.3k | } |
512 | 29.0k | return hr; |
513 | 67.4k | } |
514 | | |
515 | | // Compile a single entry point to the target shader model with debug |
516 | | // information. |
517 | | HRESULT STDMETHODCALLTYPE Compile( |
518 | | const DxcBuffer *pSource, // Source text to compile |
519 | | LPCWSTR *pArguments, // Array of pointers to arguments |
520 | | UINT32 argCount, // Number of arguments |
521 | | IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle |
522 | | // #include directives (optional) |
523 | | REFIID riid, LPVOID *ppResult // IDxcResult: status, buffer, and errors |
524 | 25.5k | ) override { |
525 | 25.5k | llvm::TimeTraceScope TimeScope("Compile", StringRef("")); |
526 | 25.5k | if (pSource == nullptr || ppResult == nullptr || |
527 | 25.5k | (argCount > 0 && pArguments == nullptr)) |
528 | 0 | return E_INVALIDARG; |
529 | 25.5k | if (!(IsEqualIID(riid, __uuidof(IDxcResult)) || |
530 | 25.5k | IsEqualIID(riid, 0 __uuidof0 (IDxcOperationResult)))) |
531 | 0 | return E_INVALIDARG; |
532 | | |
533 | 25.5k | *ppResult = nullptr; |
534 | | |
535 | 25.5k | HRESULT hr = S_OK; |
536 | 25.5k | CComPtr<IDxcBlobUtf8> utf8Source; |
537 | 25.5k | CComPtr<AbstractMemoryStream> pOutputStream; |
538 | 25.5k | CComPtr<IDxcOperationResult> pDxcOperationResult; |
539 | 25.5k | bool bCompileStarted = false; |
540 | 25.5k | bool bPreprocessStarted = false; |
541 | 25.5k | DxilShaderHash ShaderHashContent; |
542 | 25.5k | DxcThreadMalloc TM(m_pMalloc); |
543 | | |
544 | 25.5k | try { |
545 | 25.5k | DefaultFPEnvScope fpEnvScope; |
546 | | |
547 | 25.5k | IFT(CreateMemoryStream(m_pMalloc, &pOutputStream)); |
548 | | |
549 | | // Parse command-line options into DxcOpts |
550 | 25.5k | int argCountInt; |
551 | 25.5k | IFT(UIntToInt(argCount, &argCountInt)); |
552 | 25.5k | hlsl::options::MainArgs mainArgs(argCountInt, pArguments, 0); |
553 | 25.5k | hlsl::options::DxcOpts opts; |
554 | 25.5k | std::string warnings; |
555 | 25.5k | raw_string_ostream w(warnings); |
556 | 25.5k | { |
557 | 25.5k | bool finished = false; |
558 | 25.5k | CComPtr<AbstractMemoryStream> pOptionErrorStream; |
559 | 25.5k | IFT(CreateMemoryStream(m_pMalloc, &pOptionErrorStream)); |
560 | 25.5k | dxcutil::ReadOptsAndValidate(mainArgs, opts, pOptionErrorStream, |
561 | 25.5k | &pDxcOperationResult, finished); |
562 | 25.5k | if (finished) { |
563 | 0 | IFT(pDxcOperationResult->QueryInterface(riid, ppResult)); |
564 | 0 | hr = S_OK; |
565 | 0 | goto Cleanup; |
566 | 0 | } |
567 | 25.5k | if (pOptionErrorStream->GetPtrSize() > 0) { |
568 | 8 | w << StringRef((const char *)pOptionErrorStream->GetPtr(), |
569 | 8 | (size_t)pOptionErrorStream->GetPtrSize()); |
570 | 8 | } |
571 | 25.5k | } |
572 | | |
573 | 0 | bool isPreprocessing = !opts.Preprocess.empty(); |
574 | 25.5k | if (isPreprocessing) { |
575 | 256 | DxcEtw_DXCompilerPreprocess_Start(); |
576 | 256 | bPreprocessStarted = true; |
577 | 25.3k | } else { |
578 | 25.3k | DxcEtw_DXCompilerCompile_Start(); |
579 | 25.3k | bCompileStarted = true; |
580 | 25.3k | } |
581 | | |
582 | 25.5k | CComPtr<DxcResult> pResult = DxcResult::Alloc(m_pMalloc); |
583 | 25.5k | IFT(pResult->SetEncoding(opts.DefaultTextCodePage)); |
584 | 25.5k | DxcOutputObject primaryOutput; |
585 | | |
586 | | // Formerly API values. |
587 | 25.5k | const char *pUtf8SourceName = |
588 | 25.5k | opts.InputFile.empty() ? "hlsl.hlsl"16 : opts.InputFile.data()25.5k ; |
589 | | |
590 | 25.5k | CA2W pWideSourceName(pUtf8SourceName); |
591 | 25.5k | const char *pUtf8EntryPoint = |
592 | 25.5k | opts.EntryPoint.empty() ? "main"1.57k : opts.EntryPoint.data()23.9k ; |
593 | 25.5k | const char *pUtf8OutputName = isPreprocessing ? opts.Preprocess.data()256 |
594 | 25.5k | : opts.OutputObject.empty()25.3k |
595 | 25.3k | ? ""25.1k |
596 | 25.3k | : opts.OutputObject.data()176 ; |
597 | 25.5k | CA2W pWideOutputName(isPreprocessing ? opts.Preprocess.data()256 |
598 | 25.5k | : pUtf8OutputName25.3k ); |
599 | 25.5k | LPCWSTR pObjectName = (!isPreprocessing && opts.OutputObject.empty()25.3k ) |
600 | 25.5k | ? nullptr25.1k |
601 | 25.5k | : pWideOutputName.m_psz432 ; |
602 | 25.5k | IFT(primaryOutput.SetName(pObjectName)); |
603 | | |
604 | | // Wrap source in blob |
605 | 25.5k | CComPtr<IDxcBlobEncoding> pSourceEncoding; |
606 | 25.5k | IFT(hlsl::DxcCreateBlob(pSource->Ptr, pSource->Size, true, false, |
607 | 25.5k | pSource->Encoding != 0, pSource->Encoding, |
608 | 25.5k | nullptr, &pSourceEncoding)); |
609 | | |
610 | 25.5k | #ifdef ENABLE_SPIRV_CODEGEN |
611 | | // We want to embed the original source code in the final SPIR-V if |
612 | | // debug information is enabled. But the compiled source requires |
613 | | // pre-seeding with #line directives. We invoke Preprocess() here |
614 | | // first for such case. Then we invoke the compilation process over the |
615 | | // preprocessed source code. |
616 | 25.5k | if (!isPreprocessing && opts.GenSPIRV25.3k && opts.DebugInfo3.23k ) { |
617 | | // Convert source code encoding |
618 | 182 | CComPtr<IDxcBlobUtf8> pOrigUtf8Source; |
619 | 182 | IFC(hlsl::DxcGetBlobAsUtf8(pSourceEncoding, m_pMalloc, |
620 | 182 | &pOrigUtf8Source)); |
621 | 182 | opts.SpirvOptions.origSource.assign( |
622 | 182 | static_cast<const char *>(pOrigUtf8Source->GetStringPointer()), |
623 | 182 | pOrigUtf8Source->GetStringLength()); |
624 | | |
625 | 182 | CComPtr<IDxcResult> pSrcCodeResult; |
626 | 182 | std::vector<LPCWSTR> PreprocessArgs; |
627 | 182 | PreprocessArgs.reserve(argCount + 1); |
628 | 182 | PreprocessArgs.assign(pArguments, pArguments + argCount); |
629 | 182 | PreprocessArgs.push_back(L"-P"); |
630 | 182 | PreprocessArgs.push_back(L"-Fi"); |
631 | 182 | PreprocessArgs.push_back(L"preprocessed.hlsl"); |
632 | 182 | IFT(Compile(pSource, PreprocessArgs.data(), PreprocessArgs.size(), |
633 | 182 | pIncludeHandler, IID_PPV_ARGS(&pSrcCodeResult))); |
634 | 182 | HRESULT status; |
635 | 182 | IFT(pSrcCodeResult->GetStatus(&status)); |
636 | 182 | if (SUCCEEDED(status)) { |
637 | 180 | pSourceEncoding.Release(); |
638 | 180 | IFT(pSrcCodeResult->GetOutput( |
639 | 180 | DXC_OUT_HLSL, IID_PPV_ARGS(&pSourceEncoding), nullptr)); |
640 | 180 | } |
641 | 182 | } |
642 | 25.5k | #endif // ENABLE_SPIRV_CODEGEN |
643 | | |
644 | | // Convert source code encoding |
645 | 25.5k | IFC(hlsl::DxcGetBlobAsUtf8(pSourceEncoding, m_pMalloc, &utf8Source, |
646 | 25.5k | opts.DefaultTextCodePage)); |
647 | | |
648 | 25.5k | CComPtr<IDxcBlob> pOutputBlob; |
649 | 25.5k | dxcutil::DxcArgsFileSystem *msfPtr = dxcutil::CreateDxcArgsFileSystem( |
650 | 25.5k | utf8Source, pWideSourceName.m_psz, pIncludeHandler, |
651 | 25.5k | opts.DefaultTextCodePage); |
652 | 25.5k | std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr); |
653 | | |
654 | 25.5k | ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get()); |
655 | 25.5k | IFTLLVM(pts.error_code()); |
656 | | |
657 | 25.5k | IFT(pOutputStream.QueryInterface(&pOutputBlob)); |
658 | | |
659 | 25.5k | primaryOutput.kind = DXC_OUT_OBJECT; |
660 | 25.5k | if (opts.AstDump || opts.OptDump25.3k || opts.DumpDependencies25.3k || |
661 | 25.5k | opts.VerifyDiagnostics25.3k ) |
662 | 928 | primaryOutput.kind = DXC_OUT_TEXT; |
663 | 24.6k | else if (isPreprocessing) |
664 | 256 | primaryOutput.kind = DXC_OUT_HLSL; |
665 | | |
666 | 25.5k | IFT(pResult->SetOutputName(DXC_OUT_REFLECTION, |
667 | 25.5k | opts.OutputReflectionFile)); |
668 | 25.5k | IFT(pResult->SetOutputName(DXC_OUT_SHADER_HASH, |
669 | 25.5k | opts.OutputShaderHashFile)); |
670 | 25.5k | IFT(pResult->SetOutputName(DXC_OUT_ERRORS, opts.OutputWarningsFile)); |
671 | 25.5k | IFT(pResult->SetOutputName(DXC_OUT_ROOT_SIGNATURE, |
672 | 25.5k | opts.OutputRootSigFile)); |
673 | | |
674 | 25.5k | if (opts.DisplayIncludeProcess) |
675 | 8 | msfPtr->EnableDisplayIncludeProcess(); |
676 | | |
677 | 25.5k | IFT(msfPtr->RegisterOutputStream(L"output.bc", pOutputStream)); |
678 | 25.5k | IFT(msfPtr->CreateStdStreams(m_pMalloc)); |
679 | | |
680 | 25.5k | StringRef Data(utf8Source->GetStringPointer(), |
681 | 25.5k | utf8Source->GetStringLength()); |
682 | | |
683 | | // Not very efficient but also not very important. |
684 | 25.5k | std::vector<std::string> defines; |
685 | 25.5k | CreateDefineStrings(opts.Defines.data(), opts.Defines.size(), defines); |
686 | | |
687 | | // Setup a compiler instance. |
688 | 25.5k | raw_stream_ostream outStream(pOutputStream.p); |
689 | 25.5k | llvm::LLVMContext |
690 | 25.5k | llvmContext; // LLVMContext should outlive CompilerInstance |
691 | 25.5k | std::unique_ptr<llvm::Module> debugModule; |
692 | 25.5k | CComPtr<AbstractMemoryStream> pReflectionStream; |
693 | 25.5k | CompilerInstance compiler; |
694 | 25.5k | std::unique_ptr<TextDiagnosticPrinter> diagPrinter = |
695 | 25.5k | llvm::make_unique<TextDiagnosticPrinter>( |
696 | 25.5k | w, &compiler.getDiagnosticOpts()); |
697 | 25.5k | SetupCompilerForCompile(compiler, &m_langExtensionsHelper, |
698 | 25.5k | pUtf8SourceName, diagPrinter.get(), defines, opts, |
699 | 25.5k | pArguments, argCount); |
700 | 25.5k | msfPtr->SetupForCompilerInstance(compiler); |
701 | | |
702 | | // The clang entry point (cc1_main) would now create a compiler invocation |
703 | | // from arguments, but depending on the Preprocess option, we either |
704 | | // compile to LLVM bitcode and then package that into a DXBC blob, or |
705 | | // preprocess to HLSL text. |
706 | | // |
707 | | // With the compiler invocation built from command line arguments, the |
708 | | // next step is to call ExecuteCompilerInvocation, which creates a |
709 | | // FrontendAction* of EmitBCAction, which is a CodeGenAction, which is an |
710 | | // ASTFrontendAction. That sets up a BackendConsumer as the ASTConsumer. |
711 | 25.5k | compiler.getFrontendOpts().OutputFile = "output.bc"; |
712 | 25.5k | compiler.WriteDefaultOutputDirectly = true; |
713 | 25.5k | compiler.setOutStream(&outStream); |
714 | | |
715 | 25.5k | unsigned rootSigMajor = 0; |
716 | 25.5k | unsigned rootSigMinor = 0; |
717 | 25.5k | bool produceFullContainer = false; |
718 | 25.5k | bool needsValidation = false; |
719 | 25.5k | bool validateRootSigContainer = false; |
720 | | |
721 | 25.5k | if (isPreprocessing) { |
722 | 256 | TimeTraceScope TimeScope("PreprocessAction", StringRef("")); |
723 | | // These settings are back-compatible with fxc. |
724 | 256 | clang::PreprocessorOutputOptions &PPOutOpts = |
725 | 256 | compiler.getPreprocessorOutputOpts(); |
726 | 256 | PPOutOpts.ShowCPP = 1; // Print normal preprocessed output. |
727 | 256 | PPOutOpts.ShowComments = 0; // Show comments. |
728 | 256 | PPOutOpts.ShowLineMarkers = 1; // Show \#line markers. |
729 | 256 | PPOutOpts.UseLineDirectives = |
730 | 256 | 1; // Use \#line instead of GCC-style \# N. |
731 | 256 | PPOutOpts.ShowMacroComments = 0; // Show comments, even in macros. |
732 | 256 | PPOutOpts.ShowMacros = 0; // Print macro definitions. |
733 | 256 | PPOutOpts.RewriteIncludes = 0; // Preprocess include directives only. |
734 | | |
735 | 256 | FrontendInputFile file(pUtf8SourceName, IK_HLSL); |
736 | 256 | clang::PrintPreprocessedAction action; |
737 | 256 | if (action.BeginSourceFile(compiler, file)) { |
738 | 256 | action.Execute(); |
739 | 256 | action.EndSourceFile(); |
740 | 256 | } |
741 | 256 | outStream.flush(); |
742 | 25.3k | } else { |
743 | 25.3k | compiler.getLangOpts().HLSLEntryFunction = |
744 | 25.3k | compiler.getCodeGenOpts().HLSLEntryFunction = pUtf8EntryPoint; |
745 | | |
746 | | // Parse and apply |
747 | 25.3k | if (opts.BindingTableDefine.size()) { |
748 | | // Just pass the define for now because preprocessor is not available |
749 | | // yet. |
750 | 32 | struct BindingTableParserImpl |
751 | 32 | : public CodeGenOptions::BindingTableParserType { |
752 | 32 | CompilerInstance &compiler; |
753 | 32 | std::string define; |
754 | 32 | BindingTableParserImpl(CompilerInstance &compiler, StringRef define) |
755 | 32 | : compiler(compiler), define(define.str()) {} |
756 | | |
757 | 32 | bool Parse(llvm::raw_ostream &os, |
758 | 32 | hlsl::DxcBindingTable *outBindingTable) override { |
759 | 32 | Preprocessor &pp = compiler.getPreprocessor(); |
760 | 32 | MacroInfo *macro = MacroExpander::FindMacroInfo(pp, define); |
761 | 32 | if (!macro) { |
762 | 2 | os << Twine("Binding table define'") + define + "' not found."; |
763 | 2 | os.flush(); |
764 | 2 | return false; |
765 | 2 | } |
766 | | |
767 | 30 | std::string bindingTableStr; |
768 | | // Combine tokens into single string |
769 | 30 | MacroExpander expander(pp, MacroExpander::STRIP_QUOTES); |
770 | 30 | if (!expander.ExpandMacro(macro, &bindingTableStr)) { |
771 | 0 | os << Twine("Binding table define'") + define + |
772 | 0 | "' failed to expand."; |
773 | 0 | os.flush(); |
774 | 0 | return false; |
775 | 0 | } |
776 | 30 | return hlsl::ParseBindingTable(define, StringRef(bindingTableStr), |
777 | 30 | os, outBindingTable); |
778 | 30 | } |
779 | 32 | }; |
780 | | |
781 | 32 | compiler.getCodeGenOpts().BindingTableParser.reset( |
782 | 32 | new BindingTableParserImpl(compiler, opts.BindingTableDefine)); |
783 | 25.2k | } else if (opts.ImportBindingTable.size()) { |
784 | 40 | hlsl::options::StringRefWide wstrRef(opts.ImportBindingTable); |
785 | 40 | CComPtr<IDxcBlob> pBlob; |
786 | 40 | std::string error; |
787 | 40 | llvm::raw_string_ostream os(error); |
788 | 40 | if (!pIncludeHandler) { |
789 | 2 | os << Twine("Binding table binding file '") + |
790 | 2 | opts.ImportBindingTable + |
791 | 2 | "' specified, but no include handler was given."; |
792 | 2 | os.flush(); |
793 | 2 | return ErrorWithString(error, riid, ppResult); |
794 | 38 | } else if (SUCCEEDED(pIncludeHandler->LoadSource(wstrRef, &pBlob))) { |
795 | 38 | bool succ = hlsl::ParseBindingTable( |
796 | 38 | opts.ImportBindingTable, |
797 | 38 | StringRef((const char *)pBlob->GetBufferPointer(), |
798 | 38 | pBlob->GetBufferSize()), |
799 | 38 | os, &compiler.getCodeGenOpts().HLSLBindingTable); |
800 | | |
801 | 38 | if (!succ) { |
802 | 28 | os.flush(); |
803 | 28 | return ErrorWithString(error, riid, ppResult); |
804 | 28 | } |
805 | 38 | } else { |
806 | 0 | os << Twine("Could not load binding table file '") + |
807 | 0 | opts.ImportBindingTable + "'."; |
808 | 0 | os.flush(); |
809 | 0 | return ErrorWithString(error, riid, ppResult); |
810 | 0 | } |
811 | 40 | } |
812 | | |
813 | 25.2k | if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_1") { |
814 | 6 | rootSigMajor = 1; |
815 | 6 | rootSigMinor = 1; |
816 | 25.2k | } else if (compiler.getCodeGenOpts().HLSLProfile == "rootsig_1_0") { |
817 | 10 | rootSigMajor = 1; |
818 | 10 | rootSigMinor = 0; |
819 | 10 | } |
820 | 25.2k | compiler.getLangOpts().IsHLSLLibrary = opts.IsLibraryProfile(); |
821 | | |
822 | 25.2k | if (compiler.getLangOpts().IsHLSLLibrary && opts.GenMetal3.86k ) |
823 | 0 | return ErrorWithString("Shader libraries unsupported in Metal (yet)", |
824 | 0 | riid, ppResult); |
825 | | |
826 | | // Clear entry function if library target |
827 | 25.2k | if (compiler.getLangOpts().IsHLSLLibrary) |
828 | 3.86k | compiler.getLangOpts().HLSLEntryFunction = |
829 | 3.86k | compiler.getCodeGenOpts().HLSLEntryFunction = ""; |
830 | | |
831 | 25.2k | produceFullContainer = opts.ProduceFullContainer(); |
832 | 25.2k | needsValidation = opts.NeedsValidation(); |
833 | | |
834 | 25.2k | if (compiler.getCodeGenOpts().HLSLProfile == "lib_6_x") { |
835 | | // Currently do not support stripping reflection from offline linking |
836 | | // target. |
837 | 296 | opts.KeepReflectionInDxil = true; |
838 | 296 | } |
839 | | |
840 | 25.2k | if (opts.ValVerMajor != UINT_MAX) { |
841 | | // user-specified validator version override |
842 | 480 | compiler.getCodeGenOpts().HLSLValidatorMajorVer = opts.ValVerMajor; |
843 | 480 | compiler.getCodeGenOpts().HLSLValidatorMinorVer = opts.ValVerMinor; |
844 | 24.7k | } else { |
845 | 24.7k | dxcutil::GetValidatorVersion( |
846 | 24.7k | &compiler.getCodeGenOpts().HLSLValidatorMajorVer, |
847 | 24.7k | &compiler.getCodeGenOpts().HLSLValidatorMinorVer); |
848 | 24.7k | } |
849 | | |
850 | | // Root signature-only container validation is only supported on 1.5 and |
851 | | // above. |
852 | 25.2k | validateRootSigContainer = |
853 | 25.2k | DXIL::CompareVersions( |
854 | 25.2k | compiler.getCodeGenOpts().HLSLValidatorMajorVer, |
855 | 25.2k | compiler.getCodeGenOpts().HLSLValidatorMinorVer, 1, 5) >= 0; |
856 | 25.2k | } |
857 | | |
858 | 25.5k | compiler.getTarget().adjust(compiler.getLangOpts()); |
859 | | |
860 | 25.5k | if (opts.AstDump) { |
861 | 212 | TimeTraceScope TimeScope("DumpAST", StringRef("")); |
862 | 212 | clang::ASTDumpAction dumpAction; |
863 | | // Consider - ASTDumpFilter, ASTDumpLookups |
864 | 212 | compiler.getFrontendOpts().ASTDumpDecls = true; |
865 | 212 | FrontendInputFile file(pUtf8SourceName, IK_HLSL); |
866 | 212 | dumpAction.BeginSourceFile(compiler, file); |
867 | 212 | dumpAction.Execute(); |
868 | 212 | dumpAction.EndSourceFile(); |
869 | 212 | outStream.flush(); |
870 | 25.3k | } else if (opts.DumpDependencies) { |
871 | 6 | TimeTraceScope TimeScope("DumpDependencies", StringRef("")); |
872 | 6 | auto dependencyCollector = std::make_shared<DependencyCollector>(); |
873 | 6 | compiler.addDependencyCollector(dependencyCollector); |
874 | 6 | compiler.createPreprocessor(clang::TranslationUnitKind::TU_Complete); |
875 | | |
876 | 6 | clang::PreprocessOnlyAction preprocessAction; |
877 | 6 | FrontendInputFile file(pUtf8SourceName, IK_HLSL); |
878 | 6 | preprocessAction.BeginSourceFile(compiler, file); |
879 | 6 | preprocessAction.Execute(); |
880 | 6 | preprocessAction.EndSourceFile(); |
881 | | |
882 | 6 | outStream << (opts.OutputObject.empty() ? opts.InputFile |
883 | 6 | : opts.OutputObject0 ); |
884 | 6 | bool firstDependency = true; |
885 | 42 | for (auto &dependency : dependencyCollector->getDependencies()) { |
886 | 42 | if (firstDependency) { |
887 | 6 | outStream << ": " << dependency; |
888 | 6 | firstDependency = false; |
889 | 6 | continue; |
890 | 6 | } |
891 | 36 | outStream << " \\\n " << dependency; |
892 | 36 | } |
893 | 6 | outStream << "\n"; |
894 | 6 | outStream.flush(); |
895 | 25.3k | } else if (opts.OptDump) { |
896 | 26 | EmitOptDumpAction action(&llvmContext); |
897 | 26 | FrontendInputFile file(pUtf8SourceName, IK_HLSL); |
898 | 26 | action.BeginSourceFile(compiler, file); |
899 | 26 | action.Execute(); |
900 | 26 | action.EndSourceFile(); |
901 | 26 | outStream.flush(); |
902 | 25.2k | } else if (rootSigMajor) { |
903 | 16 | HLSLRootSignatureAction action( |
904 | 16 | compiler.getCodeGenOpts().HLSLEntryFunction, rootSigMajor, |
905 | 16 | rootSigMinor); |
906 | 16 | FrontendInputFile file(pUtf8SourceName, IK_HLSL); |
907 | 16 | action.BeginSourceFile(compiler, file); |
908 | 16 | action.Execute(); |
909 | 16 | action.EndSourceFile(); |
910 | 16 | outStream.flush(); |
911 | | // Don't do work to put in a container if an error has occurred |
912 | 16 | bool compileOK = !compiler.getDiagnostics().hasErrorOccurred(); |
913 | 16 | if (compileOK) { |
914 | 16 | auto rootSigHandle = action.takeRootSigHandle(); |
915 | | |
916 | 16 | CComPtr<AbstractMemoryStream> pContainerStream; |
917 | 16 | IFT(CreateMemoryStream(m_pMalloc, &pContainerStream)); |
918 | 16 | SerializeDxilContainerForRootSignature(rootSigHandle.get(), |
919 | 16 | pContainerStream); |
920 | | |
921 | 16 | pOutputBlob.Release(); |
922 | 16 | IFT(pContainerStream.QueryInterface(&pOutputBlob)); |
923 | 16 | if (validateRootSigContainer && !opts.DisableValidation) { |
924 | 16 | CComPtr<IDxcBlobEncoding> pValErrors; |
925 | | // Validation failure communicated through diagnostic error |
926 | 16 | dxcutil::ValidateRootSignatureInContainer( |
927 | 16 | pOutputBlob, &compiler.getDiagnostics()); |
928 | 16 | } |
929 | 16 | } |
930 | 25.2k | } else if (opts.VerifyDiagnostics) { |
931 | 684 | SyntaxOnlyAction action; |
932 | 684 | FrontendInputFile file(pUtf8SourceName, IK_HLSL); |
933 | 684 | if (action.BeginSourceFile(compiler, file)) { |
934 | 684 | action.Execute(); |
935 | 684 | action.EndSourceFile(); |
936 | 684 | } |
937 | 684 | } |
938 | | // SPIRV change starts |
939 | 24.5k | #ifdef ENABLE_SPIRV_CODEGEN |
940 | 24.5k | else if (!isPreprocessing && opts.GenSPIRV24.3k ) { |
941 | | // Since SpirvOptions is passed to the SPIR-V CodeGen as a whole |
942 | | // structure, we need to copy a few non-spirv-specific options into the |
943 | | // structure. |
944 | 3.21k | opts.SpirvOptions.enable16BitTypes = opts.Enable16BitTypes; |
945 | 3.21k | opts.SpirvOptions.codeGenHighLevel = opts.CodeGenHighLevel; |
946 | 3.21k | opts.SpirvOptions.defaultRowMajor = opts.DefaultRowMajor; |
947 | 3.21k | opts.SpirvOptions.disableValidation = opts.DisableValidation; |
948 | 3.21k | opts.SpirvOptions.IEEEStrict = opts.IEEEStrict; |
949 | | // Save a string representation of command line options and |
950 | | // input file name. |
951 | 3.21k | if (opts.DebugInfo) { |
952 | 182 | opts.SpirvOptions.inputFile = opts.InputFile; |
953 | 1.72k | for (auto opt : mainArgs.getArrayRef()) { |
954 | 1.72k | if (opts.InputFile.compare(opt) != 0) { |
955 | 1.54k | opts.SpirvOptions.clOptions += " " + std::string(opt); |
956 | 1.54k | } |
957 | 1.72k | } |
958 | 182 | } |
959 | | |
960 | 3.21k | compiler.getCodeGenOpts().SpirvOptions = opts.SpirvOptions; |
961 | 3.21k | clang::EmitSpirvAction action; |
962 | 3.21k | FrontendInputFile file(pUtf8SourceName, IK_HLSL); |
963 | 3.21k | action.BeginSourceFile(compiler, file); |
964 | 3.21k | action.Execute(); |
965 | 3.21k | action.EndSourceFile(); |
966 | 3.21k | outStream.flush(); |
967 | 3.21k | } |
968 | 21.3k | #endif |
969 | | // SPIRV change ends |
970 | 21.3k | else if (!isPreprocessing) { |
971 | 21.1k | EmitBCAction action(&llvmContext); |
972 | 21.1k | FrontendInputFile file(pUtf8SourceName, IK_HLSL); |
973 | 21.1k | bool compileOK; |
974 | 21.1k | TimeTraceScope TimeScope("Compile Action", StringRef("")); |
975 | 21.1k | if (action.BeginSourceFile(compiler, file)) { |
976 | 21.1k | action.Execute(); |
977 | 21.1k | action.EndSourceFile(); |
978 | 21.1k | compileOK = !compiler.getDiagnostics().hasErrorOccurred(); |
979 | 21.1k | } else { |
980 | 0 | compileOK = false; |
981 | 0 | } |
982 | 21.1k | outStream.flush(); |
983 | | |
984 | 21.1k | SerializeDxilFlags SerializeFlags = |
985 | 21.1k | hlsl::options::ComputeSerializeDxilFlags(opts); |
986 | 21.1k | CComPtr<IDxcBlob> pRootSignatureBlob = nullptr; |
987 | 21.1k | CComPtr<IDxcBlob> pPrivateBlob = nullptr; |
988 | 21.1k | if (!opts.RootSignatureSource.empty()) { |
989 | 4 | hlsl::options::StringRefWide wstrRef(opts.RootSignatureSource); |
990 | 4 | std::string error; |
991 | 4 | llvm::raw_string_ostream os(error); |
992 | 4 | if (!pIncludeHandler) { |
993 | 0 | os << Twine("Root Signature file '") + opts.RootSignatureSource + |
994 | 0 | "' specified, but no include handler was given."; |
995 | 0 | os.flush(); |
996 | 0 | return ErrorWithString(error, riid, ppResult); |
997 | 4 | } else if (SUCCEEDED(pIncludeHandler->LoadSource( |
998 | 4 | wstrRef, &pRootSignatureBlob))) { |
999 | 4 | } else { |
1000 | 0 | os << Twine("Could not load root signature file '") + |
1001 | 0 | opts.RootSignatureSource + "'."; |
1002 | 0 | os.flush(); |
1003 | 0 | return ErrorWithString(error, riid, ppResult); |
1004 | 0 | } |
1005 | 4 | } |
1006 | 21.1k | if (!opts.PrivateSource.empty()) { |
1007 | 2 | hlsl::options::StringRefWide wstrRef(opts.PrivateSource); |
1008 | 2 | std::string error; |
1009 | 2 | llvm::raw_string_ostream os(error); |
1010 | 2 | if (!pIncludeHandler) { |
1011 | 0 | os << Twine("Private file '") + opts.PrivateSource + |
1012 | 0 | "' specified, but no include handler was given."; |
1013 | 0 | os.flush(); |
1014 | 0 | return ErrorWithString(error, riid, ppResult); |
1015 | 2 | } else if (SUCCEEDED( |
1016 | 2 | pIncludeHandler->LoadSource(wstrRef, &pPrivateBlob))) { |
1017 | 2 | } else { |
1018 | 0 | os << Twine("Could not load root signature file '") + |
1019 | 0 | opts.PrivateSource + "'."; |
1020 | 0 | os.flush(); |
1021 | 0 | return ErrorWithString(error, riid, ppResult); |
1022 | 0 | } |
1023 | 2 | } |
1024 | | |
1025 | | // Don't do work to put in a container if an error has occurred |
1026 | | // Do not create a container when there is only a a high-level |
1027 | | // representation in the module. |
1028 | 21.1k | if (compileOK && !opts.CodeGenHighLevel18.7k ) { |
1029 | 18.3k | TimeTraceScope TimeScope("AssembleAndWriteContainer", StringRef("")); |
1030 | 18.3k | HRESULT valHR = S_OK; |
1031 | 18.3k | CComPtr<AbstractMemoryStream> pRootSigStream; |
1032 | 18.3k | IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), |
1033 | 18.3k | &pReflectionStream)); |
1034 | 18.3k | IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pRootSigStream)); |
1035 | | |
1036 | 18.3k | std::unique_ptr<llvm::Module> serializeModule(action.takeModule()); |
1037 | | |
1038 | | // Clone and save the copy. |
1039 | 18.3k | if (opts.GenerateFullDebugInfo()) { |
1040 | 3.89k | debugModule.reset(llvm::CloneModule(serializeModule.get())); |
1041 | 3.89k | } |
1042 | | |
1043 | 18.3k | dxcutil::AssembleInputs inputs( |
1044 | 18.3k | std::move(serializeModule), pOutputBlob, m_pMalloc, |
1045 | 18.3k | SerializeFlags, pOutputStream, 0, opts.GetPDBName(), |
1046 | 18.3k | &compiler.getDiagnostics(), &ShaderHashContent, pReflectionStream, |
1047 | 18.3k | pRootSigStream, pRootSignatureBlob, pPrivateBlob); |
1048 | | |
1049 | 18.3k | inputs.pVersionInfo = static_cast<IDxcVersionInfo *>(this); |
1050 | | |
1051 | 18.3k | if (needsValidation) { |
1052 | 17.7k | valHR = dxcutil::ValidateAndAssembleToContainer(inputs); |
1053 | 17.7k | } else { |
1054 | 648 | dxcutil::AssembleToContainer(inputs); |
1055 | 648 | } |
1056 | | |
1057 | | // Callback after valid DXIL is produced |
1058 | 18.3k | if (SUCCEEDED(valHR)) { |
1059 | 18.1k | CComPtr<IDxcBlob> pTargetBlob; |
1060 | 18.1k | if (m_pDxcContainerEventsHandler != nullptr) { |
1061 | 0 | HRESULT hr = m_pDxcContainerEventsHandler->OnDxilContainerBuilt( |
1062 | 0 | pOutputBlob, &pTargetBlob); |
1063 | 0 | if (SUCCEEDED(hr) && pTargetBlob != nullptr) { |
1064 | 0 | std::swap(pOutputBlob, pTargetBlob); |
1065 | 0 | } |
1066 | 0 | } |
1067 | | |
1068 | 18.1k | if (pOutputBlob && produceFullContainer && |
1069 | 18.1k | (SerializeFlags & SerializeDxilFlags::IncludeDebugNamePart) != |
1070 | 18.1k | 0) { |
1071 | 7.11k | const DxilContainerHeader *pContainer = |
1072 | 7.11k | reinterpret_cast<DxilContainerHeader *>( |
1073 | 7.11k | pOutputBlob->GetBufferPointer()); |
1074 | 7.11k | DXASSERT(IsValidDxilContainer(pContainer, |
1075 | 7.11k | pOutputBlob->GetBufferSize()), |
1076 | 7.11k | "else invalid container generated"); |
1077 | 7.11k | auto it = std::find_if(begin(pContainer), end(pContainer), |
1078 | 7.11k | DxilPartIsType(DFCC_ShaderDebugName)); |
1079 | 7.11k | if (it != end(pContainer)) { |
1080 | 7.11k | const char *pDebugName; |
1081 | 7.11k | if (GetDxilShaderDebugName(*it, &pDebugName, nullptr) && |
1082 | 7.11k | pDebugName && *pDebugName) { |
1083 | 7.11k | IFT(pResult->SetOutputName(DXC_OUT_PDB, pDebugName)); |
1084 | 7.11k | } |
1085 | 7.11k | } |
1086 | 7.11k | } |
1087 | | |
1088 | | // Skip reflection generation here when targeting metal, this is |
1089 | | // handled below. |
1090 | 18.1k | if (!opts.GenMetal && pReflectionStream && |
1091 | 18.1k | pReflectionStream->GetPtrSize()) { |
1092 | 18.1k | CComPtr<IDxcBlob> pReflection; |
1093 | 18.1k | IFT(pReflectionStream->QueryInterface(&pReflection)); |
1094 | 18.1k | IFT(pResult->SetOutputObject(DXC_OUT_REFLECTION, pReflection)); |
1095 | 18.1k | } |
1096 | 18.1k | if (pRootSigStream && pRootSigStream->GetPtrSize()) { |
1097 | 3.36k | CComPtr<IDxcBlob> pRootSignature; |
1098 | 3.36k | IFT(pRootSigStream->QueryInterface(&pRootSignature)); |
1099 | 3.36k | if (validateRootSigContainer && needsValidation) { |
1100 | 3.36k | CComPtr<IDxcBlobEncoding> pValErrors; |
1101 | | // Validation failure communicated through diagnostic error |
1102 | 3.36k | dxcutil::ValidateRootSignatureInContainer( |
1103 | 3.36k | pRootSignature, &compiler.getDiagnostics()); |
1104 | 3.36k | } |
1105 | 3.36k | IFT(pResult->SetOutputObject(DXC_OUT_ROOT_SIGNATURE, |
1106 | 3.36k | pRootSignature)); |
1107 | 3.36k | } |
1108 | 18.1k | CComPtr<IDxcBlob> pHashBlob; |
1109 | 18.1k | IFT(hlsl::DxcCreateBlobOnHeapCopy(&ShaderHashContent, |
1110 | 18.1k | (UINT32)sizeof(ShaderHashContent), |
1111 | 18.1k | &pHashBlob)); |
1112 | 18.1k | IFT(pResult->SetOutputObject(DXC_OUT_SHADER_HASH, pHashBlob)); |
1113 | 18.1k | } // SUCCEEDED(valHR) |
1114 | | #ifdef ENABLE_METAL_CODEGEN |
1115 | | // This is a bit hacky because we don't currently have a good way to |
1116 | | // disassemble AIR. |
1117 | | if (opts.GenMetal && produceFullContainer && |
1118 | | !opts.OutputObject.empty()) { |
1119 | | IRCompiler *MetalCompiler = IRCompilerCreate(); |
1120 | | IRCompilerSetEntryPointName( |
1121 | | MetalCompiler, |
1122 | | compiler.getCodeGenOpts().HLSLEntryFunction.c_str()); |
1123 | | |
1124 | | IRObject *DXILObj = IRObjectCreateFromDXIL( |
1125 | | static_cast<const uint8_t *>(pOutputBlob->GetBufferPointer()), |
1126 | | pOutputBlob->GetBufferSize(), IRBytecodeOwnershipNone); |
1127 | | |
1128 | | // Compile DXIL to Metal IR: |
1129 | | IRError *Error = nullptr; |
1130 | | IRObject *AIR = IRCompilerAllocCompileAndLink(MetalCompiler, NULL, |
1131 | | DXILObj, &Error); |
1132 | | |
1133 | | if (!AIR) { |
1134 | | IRObjectDestroy(DXILObj); |
1135 | | IRCompilerDestroy(MetalCompiler); |
1136 | | IRErrorDestroy(Error); |
1137 | | return ErrorWithString( |
1138 | | "Error occurred in Metal Shader Conversion", riid, ppResult); |
1139 | | } |
1140 | | |
1141 | | IRMetalLibBinary *MetalLib = IRMetalLibBinaryCreate(); |
1142 | | IRShaderStage Stage = IRShaderStageInvalid; |
1143 | | const ShaderModel *SM = hlsl::ShaderModel::GetByName( |
1144 | | compiler.getLangOpts().HLSLProfile); |
1145 | | switch (SM->GetKind()) { |
1146 | | case DXIL::ShaderKind::Vertex: |
1147 | | Stage = IRShaderStageVertex; |
1148 | | break; |
1149 | | case DXIL::ShaderKind::Pixel: |
1150 | | Stage = IRShaderStageFragment; |
1151 | | break; |
1152 | | case DXIL::ShaderKind::Hull: |
1153 | | Stage = IRShaderStageHull; |
1154 | | break; |
1155 | | case DXIL::ShaderKind::Domain: |
1156 | | Stage = IRShaderStageDomain; |
1157 | | break; |
1158 | | case DXIL::ShaderKind::Mesh: |
1159 | | Stage = IRShaderStageMesh; |
1160 | | break; |
1161 | | case DXIL::ShaderKind::Amplification: |
1162 | | Stage = IRShaderStageAmplification; |
1163 | | break; |
1164 | | case DXIL::ShaderKind::Geometry: |
1165 | | Stage = IRShaderStageGeometry; |
1166 | | break; |
1167 | | case DXIL::ShaderKind::Compute: |
1168 | | Stage = IRShaderStageCompute; |
1169 | | break; |
1170 | | } |
1171 | | assert(Stage != IRShaderStageInvalid && |
1172 | | "Library targets not supported for Metal (yet)."); |
1173 | | IRObjectGetMetalLibBinary(AIR, Stage, MetalLib); |
1174 | | size_t MetalLibSize = IRMetalLibGetBytecodeSize(MetalLib); |
1175 | | std::unique_ptr<uint8_t[]> MetalLibBytes = |
1176 | | std::unique_ptr<uint8_t[]>(new uint8_t[MetalLibSize]); |
1177 | | IRMetalLibGetBytecode(MetalLib, MetalLibBytes.get()); |
1178 | | |
1179 | | if (!opts.OutputReflectionFile.empty()) { |
1180 | | IRShaderReflection *Reflection = IRShaderReflectionCreate(); |
1181 | | IRObjectGetReflection(AIR, Stage, Reflection); |
1182 | | const char *RawJSON = |
1183 | | IRShaderReflectionCopyJSONString(Reflection); |
1184 | | IFT(pResult->SetOutputString(DXC_OUT_REFLECTION, RawJSON, |
1185 | | strlen(RawJSON))); |
1186 | | IRShaderReflectionDestroy(Reflection); |
1187 | | } |
1188 | | |
1189 | | // Store the metallib to custom format or disk, or use to create a |
1190 | | // MTLLibrary. |
1191 | | |
1192 | | CComPtr<IDxcBlob> MetalBlob; |
1193 | | IFT(hlsl::DxcCreateBlobOnHeapCopy( |
1194 | | MetalLibBytes.get(), (uint32_t)MetalLibSize, &MetalBlob)); |
1195 | | std::swap(pOutputBlob, MetalBlob); |
1196 | | |
1197 | | IRMetalLibBinaryDestroy(MetalLib); |
1198 | | IRObjectDestroy(DXILObj); |
1199 | | IRObjectDestroy(AIR); |
1200 | | IRCompilerDestroy(MetalCompiler); |
1201 | | } |
1202 | | #endif |
1203 | 18.3k | } // compileOK && !opts.CodeGenHighLevel |
1204 | 21.1k | } |
1205 | | |
1206 | 25.5k | std::string remarks; |
1207 | 25.5k | raw_string_ostream r(remarks); |
1208 | 25.5k | msfPtr->WriteStdOutToStream(r); |
1209 | 25.5k | CComPtr<IStream> pErrorStream; |
1210 | 25.5k | msfPtr->GetStdErrorHandleStream(&pErrorStream); |
1211 | 25.5k | CComPtr<IDxcBlob> pErrorBlob; |
1212 | 25.5k | IFT(pErrorStream.QueryInterface(&pErrorBlob)); |
1213 | 25.5k | if (IsBlobNullOrEmpty(pErrorBlob)) { |
1214 | | // Add std err to warnings. |
1215 | 25.5k | IFT(pResult->SetOutputString(DXC_OUT_ERRORS, warnings.c_str(), |
1216 | 25.5k | warnings.size())); |
1217 | | // Add std out to remarks. |
1218 | 25.5k | IFT(pResult->SetOutputString(DXC_OUT_REMARKS, remarks.c_str(), |
1219 | 25.5k | remarks.size())); |
1220 | 25.5k | } else { |
1221 | 20 | IFT(pResult->SetOutputObject(DXC_OUT_ERRORS, pErrorBlob)); |
1222 | 20 | } |
1223 | | |
1224 | 25.5k | bool hasErrorOccurred = compiler.getDiagnostics().hasErrorOccurred(); |
1225 | | |
1226 | 25.5k | bool writePDB = opts.GeneratePDB() && produceFullContainer4.31k ; |
1227 | | |
1228 | | // SPIRV change starts |
1229 | 25.5k | #if defined(ENABLE_SPIRV_CODEGEN) |
1230 | 25.5k | writePDB &= !opts.GenSPIRV; |
1231 | 25.5k | #endif |
1232 | | // SPIRV change ends |
1233 | | |
1234 | 25.5k | if (!hasErrorOccurred && writePDB21.9k ) { |
1235 | 3.90k | CComPtr<IDxcBlob> pStrippedContainer; |
1236 | 3.90k | { |
1237 | | // Create the shader source information for PDB |
1238 | 3.90k | hlsl::SourceInfoWriter debugSourceInfoWriter; |
1239 | 3.90k | const hlsl::DxilSourceInfo *pSourceInfo = nullptr; |
1240 | 3.90k | if (!opts.SourceInDebugModule) { // If we are using old PDB format |
1241 | | // where sources are in debug module, |
1242 | | // do not generate source info at all |
1243 | 3.89k | debugSourceInfoWriter.Write(opts.TargetProfile, opts.EntryPoint, |
1244 | 3.89k | compiler.getCodeGenOpts(), |
1245 | 3.89k | compiler.getSourceManager()); |
1246 | 3.89k | pSourceInfo = debugSourceInfoWriter.GetPart(); |
1247 | 3.89k | } |
1248 | | |
1249 | 3.90k | CComPtr<IDxcBlob> pDebugProgramBlob; |
1250 | 3.90k | CComPtr<AbstractMemoryStream> pReflectionInPdb; |
1251 | | // Don't include the debug part if using source only PDB |
1252 | 3.90k | if (opts.SourceOnlyDebug) { |
1253 | 16 | assert(pSourceInfo); |
1254 | 16 | pReflectionInPdb = pReflectionStream; |
1255 | 3.88k | } else { |
1256 | 3.88k | if (!opts.SourceInDebugModule) { |
1257 | | // Strip out the source related metadata |
1258 | 3.88k | debugModule->GetOrCreateDxilModule() |
1259 | 3.88k | .StripShaderSourcesAndCompileOptions( |
1260 | 3.88k | /* bReplaceWithDummyData */ true); |
1261 | 3.88k | } |
1262 | 3.88k | CComPtr<AbstractMemoryStream> pDebugBlobStorage; |
1263 | 3.88k | IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), |
1264 | 3.88k | &pDebugBlobStorage)); |
1265 | 3.88k | raw_stream_ostream outStream(pDebugBlobStorage.p); |
1266 | 3.88k | WriteBitcodeToFile(debugModule.get(), outStream, true); |
1267 | 3.88k | outStream.flush(); |
1268 | 3.88k | IFT(pDebugBlobStorage.QueryInterface(&pDebugProgramBlob)); |
1269 | 3.88k | } |
1270 | | |
1271 | 3.90k | IFT(CreateContainerForPDB(m_pMalloc, pOutputBlob, pDebugProgramBlob, |
1272 | 3.90k | static_cast<IDxcVersionInfo *>(this), |
1273 | 3.90k | pSourceInfo, pReflectionInPdb, |
1274 | 3.90k | &pStrippedContainer)); |
1275 | 3.90k | } |
1276 | | |
1277 | | // Create the final PDB Blob |
1278 | 0 | CComPtr<IDxcBlob> pPdbBlob; |
1279 | 3.90k | IFT(hlsl::pdb::WriteDxilPDB(m_pMalloc, pStrippedContainer, |
1280 | 3.90k | ShaderHashContent.Digest, &pPdbBlob)); |
1281 | 3.90k | IFT(pResult->SetOutputObject(DXC_OUT_PDB, pPdbBlob)); |
1282 | | |
1283 | | // If option Qpdb_in_private given, add the PDB to the DXC_OUT_OBJECT |
1284 | | // container output as a DFCC_PrivateData part. |
1285 | 3.90k | if (opts.PdbInPrivate) { |
1286 | 2 | CComPtr<IDxcBlobEncoding> pContainerBlob; |
1287 | 2 | hlsl::DxcCreateBlobWithEncodingFromPinned( |
1288 | 2 | pOutputBlob->GetBufferPointer(), pOutputBlob->GetBufferSize(), |
1289 | 2 | CP_ACP, &pContainerBlob); |
1290 | | |
1291 | 2 | CComPtr<IDxcContainerBuilder> pContainerBuilder; |
1292 | 2 | DxcCreateInstance2(this->m_pMalloc, CLSID_DxcContainerBuilder, |
1293 | 2 | IID_PPV_ARGS(&pContainerBuilder)); |
1294 | 2 | IFT(pContainerBuilder->Load(pOutputBlob)); |
1295 | 2 | IFT(pContainerBuilder->AddPart(hlsl::DFCC_PrivateData, pPdbBlob)); |
1296 | | |
1297 | 2 | CComPtr<IDxcOperationResult> pReserializeResult; |
1298 | 2 | IFT(pContainerBuilder->SerializeContainer(&pReserializeResult)); |
1299 | | |
1300 | 2 | CComPtr<IDxcBlob> pNewOutput; |
1301 | 2 | IFT(pReserializeResult->GetResult(&pNewOutput)); |
1302 | 2 | pOutputBlob = pNewOutput; |
1303 | 2 | } // PDB in private |
1304 | 3.90k | } // Write PDB |
1305 | | |
1306 | 25.5k | IFT(primaryOutput.SetObject(pOutputBlob, opts.DefaultTextCodePage)); |
1307 | 25.5k | IFT(pResult->SetOutput(primaryOutput)); |
1308 | | |
1309 | | // It is possible for errors to occur, but the diagnostic or AST consumers |
1310 | | // can recover from them, or translate them to mean something different. |
1311 | | // This happens with the `-verify` flag where an error may be expected. |
1312 | | // The correct way to identify errors in this case is to query the |
1313 | | // DiagnosticClient for the number of errors. |
1314 | 25.5k | unsigned NumErrors = |
1315 | 25.5k | compiler.getDiagnostics().getClient()->getNumErrors(); |
1316 | 25.5k | IFT(pResult->SetStatusAndPrimaryResult(NumErrors > 0 ? E_FAIL : S_OK, |
1317 | 25.5k | primaryOutput.kind)); |
1318 | 25.5k | IFT(pResult->QueryInterface(riid, ppResult)); |
1319 | | |
1320 | 25.5k | hr = S_OK; |
1321 | 25.5k | } catch (std::bad_alloc &) { |
1322 | 0 | hr = E_OUTOFMEMORY; |
1323 | 0 | } catch (hlsl::Exception &e) { |
1324 | 0 | assert(DXC_FAILED(e.hr)); |
1325 | 0 | CComPtr<IDxcResult> pResult; |
1326 | 0 | hr = e.hr; |
1327 | 0 | std::string msg("Internal Compiler error: "); |
1328 | 0 | msg += e.msg; |
1329 | 0 | if (SUCCEEDED(DxcResult::Create( |
1330 | 0 | e.hr, DXC_OUT_NONE, |
1331 | 0 | {DxcOutputObject::ErrorOutput(CP_UTF8, msg.c_str(), msg.size())}, |
1332 | 0 | &pResult)) && |
1333 | 0 | SUCCEEDED(pResult->QueryInterface(riid, ppResult))) { |
1334 | 0 | hr = S_OK; |
1335 | 0 | } |
1336 | 0 | } catch (...) { |
1337 | 0 | hr = E_FAIL; |
1338 | 0 | } |
1339 | 25.5k | Cleanup: |
1340 | 25.5k | if (bPreprocessStarted) { |
1341 | 256 | DxcEtw_DXCompilerPreprocess_Stop(hr); |
1342 | 256 | } |
1343 | 25.5k | if (bCompileStarted) { |
1344 | 25.2k | DxcEtw_DXCompilerCompile_Stop(hr); |
1345 | 25.2k | } |
1346 | 25.5k | return hr; |
1347 | 25.5k | } |
1348 | | |
1349 | | // Disassemble a program. |
1350 | | virtual HRESULT STDMETHODCALLTYPE Disassemble( |
1351 | | const DxcBuffer |
1352 | | *pObject, // Program to disassemble: dxil container or bitcode. |
1353 | | REFIID riid, |
1354 | | LPVOID *ppResult // IDxcResult: status, disassembly text, and errors |
1355 | 8.17k | ) override { |
1356 | 8.17k | if (pObject == nullptr || ppResult == nullptr) |
1357 | 0 | return E_INVALIDARG; |
1358 | 8.17k | if (!(IsEqualIID(riid, __uuidof(IDxcResult)) || |
1359 | 8.17k | IsEqualIID(riid, 0 __uuidof0 (IDxcOperationResult)))) |
1360 | 0 | return E_INVALIDARG; |
1361 | | |
1362 | 8.17k | *ppResult = nullptr; |
1363 | 8.17k | CComPtr<IDxcResult> pResult; |
1364 | | |
1365 | 8.17k | HRESULT hr = S_OK; |
1366 | 8.17k | DxcEtw_DXCompilerDisassemble_Start(); |
1367 | 8.17k | DxcThreadMalloc TM(m_pMalloc); |
1368 | 8.17k | try { |
1369 | 8.17k | DefaultFPEnvScope fpEnvScope; |
1370 | | |
1371 | 8.17k | ::llvm::sys::fs::MSFileSystem *msfPtr; |
1372 | 8.17k | IFT(CreateMSFileSystemForDisk(&msfPtr)); |
1373 | 8.17k | std::unique_ptr<::llvm::sys::fs::MSFileSystem> msf(msfPtr); |
1374 | | |
1375 | 8.17k | ::llvm::sys::fs::AutoPerThreadSystem pts(msf.get()); |
1376 | 8.17k | IFTLLVM(pts.error_code()); |
1377 | | |
1378 | 8.17k | std::string StreamStr; |
1379 | 8.17k | raw_string_ostream Stream(StreamStr); |
1380 | | |
1381 | 8.17k | CComPtr<IDxcBlobEncoding> pProgram; |
1382 | 8.17k | IFT(hlsl::DxcCreateBlob(pObject->Ptr, pObject->Size, true, false, false, |
1383 | 8.17k | 0, nullptr, &pProgram)) |
1384 | 8.17k | IFC(dxcutil::Disassemble(pProgram, Stream)); |
1385 | | |
1386 | 8.15k | IFT(DxcResult::Create(S_OK, DXC_OUT_DISASSEMBLY, |
1387 | 8.15k | {DxcOutputObject::StringOutput( |
1388 | 8.15k | DXC_OUT_DISASSEMBLY, CP_UTF8, StreamStr.c_str(), |
1389 | 8.15k | StreamStr.size(), DxcOutNoName)}, |
1390 | 8.15k | &pResult)); |
1391 | 8.15k | IFT(pResult->QueryInterface(riid, ppResult)); |
1392 | | |
1393 | 8.15k | return S_OK; |
1394 | 8.15k | } catch (std::bad_alloc &) { |
1395 | 0 | hr = E_OUTOFMEMORY; |
1396 | 0 | } catch (hlsl::Exception &e) { |
1397 | 0 | assert(DXC_FAILED(e.hr)); |
1398 | 0 | hr = e.hr; |
1399 | 0 | if (SUCCEEDED( |
1400 | 0 | DxcResult::Create(e.hr, DXC_OUT_NONE, |
1401 | 0 | {DxcOutputObject::ErrorOutput( |
1402 | 0 | CP_UTF8, e.msg.c_str(), e.msg.size())}, |
1403 | 0 | &pResult)) && |
1404 | 0 | SUCCEEDED(pResult->QueryInterface(riid, ppResult))) { |
1405 | 0 | hr = S_OK; |
1406 | 0 | } |
1407 | 6 | } catch (...) { |
1408 | 6 | hr = E_FAIL; |
1409 | 6 | } |
1410 | 22 | Cleanup: |
1411 | 22 | DxcEtw_DXCompilerDisassemble_Stop(hr); |
1412 | 22 | return hr; |
1413 | 8.17k | } |
1414 | | |
1415 | | void SetupCompilerForCompile(CompilerInstance &compiler, |
1416 | | DxcLangExtensionsHelper *helper, |
1417 | | LPCSTR pMainFile, |
1418 | | TextDiagnosticPrinter *diagPrinter, |
1419 | | std::vector<std::string> &defines, |
1420 | | hlsl::options::DxcOpts &Opts, |
1421 | 25.5k | LPCWSTR *pArguments, UINT32 argCount) { |
1422 | | // Setup a compiler instance. |
1423 | 25.5k | std::shared_ptr<TargetOptions> targetOptions(new TargetOptions); |
1424 | 25.5k | targetOptions->Triple = "dxil-ms-dx"; |
1425 | 25.5k | if (helper) { |
1426 | 25.5k | targetOptions->Triple = helper->GetTargetTriple(); |
1427 | 25.5k | } |
1428 | 25.5k | targetOptions->DescriptionString = Opts.Enable16BitTypes |
1429 | 25.5k | ? hlsl::DXIL::kNewLayoutString1.45k |
1430 | 25.5k | : hlsl::DXIL::kLegacyLayoutString24.1k ; |
1431 | 25.5k | compiler.HlslLangExtensions = helper; |
1432 | 25.5k | compiler.getDiagnosticOpts().ShowOptionNames = Opts.ShowOptionNames ? 125.5k : 02 ; |
1433 | 25.5k | compiler.getDiagnosticOpts().Warnings = std::move(Opts.Warnings); |
1434 | 25.5k | compiler.getDiagnosticOpts().VerifyDiagnostics = Opts.VerifyDiagnostics; |
1435 | 25.5k | compiler.createDiagnostics(diagPrinter, false); |
1436 | | // don't output warning to stderr/file if "/no-warnings" is present. |
1437 | 25.5k | compiler.getDiagnostics().setIgnoreAllWarnings(!Opts.OutputWarnings); |
1438 | 25.5k | if (Opts.DiagnosticsFormat.equals_lower("msvc") || |
1439 | 25.5k | Opts.DiagnosticsFormat.equals_lower("msvc-fallback")25.5k ) |
1440 | 4 | compiler.getDiagnosticOpts().setFormat(DiagnosticOptions::MSVC); |
1441 | 25.5k | else if (Opts.DiagnosticsFormat.equals_lower("vi")) |
1442 | 2 | compiler.getDiagnosticOpts().setFormat(DiagnosticOptions::Vi); |
1443 | 25.5k | else if (!Opts.DiagnosticsFormat.equals_lower("clang")) { |
1444 | 2 | auto const ID = compiler.getDiagnostics().getCustomDiagID( |
1445 | 2 | clang::DiagnosticsEngine::Warning, |
1446 | 2 | "invalid option %0 to -fdiagnostics-format: supported values are " |
1447 | 2 | "clang, msvc, msvc-fallback, and vi"); |
1448 | 2 | compiler.getDiagnostics().Report(ID) << Opts.DiagnosticsFormat; |
1449 | 2 | } |
1450 | 25.5k | compiler.createFileManager(); |
1451 | 25.5k | compiler.createSourceManager(compiler.getFileManager()); |
1452 | 25.5k | compiler.setTarget( |
1453 | 25.5k | TargetInfo::CreateTargetInfo(compiler.getDiagnostics(), targetOptions)); |
1454 | 25.5k | if (Opts.EnableDX9CompatMode) { |
1455 | 76 | auto const ID = compiler.getDiagnostics().getCustomDiagID( |
1456 | 76 | clang::DiagnosticsEngine::Warning, |
1457 | 76 | "/Gec flag is a deprecated functionality."); |
1458 | 76 | compiler.getDiagnostics().Report(ID); |
1459 | 76 | } |
1460 | | |
1461 | 25.5k | compiler.getFrontendOpts().Inputs.push_back( |
1462 | 25.5k | FrontendInputFile(pMainFile, IK_HLSL)); |
1463 | 25.5k | compiler.getFrontendOpts().ShowTimers = Opts.TimeReport ? 14 : 025.5k ; |
1464 | | // Setup debug information. |
1465 | 25.5k | if (Opts.GenerateFullDebugInfo()) { |
1466 | 4.30k | CodeGenOptions &CGOpts = compiler.getCodeGenOpts(); |
1467 | | // HLSL Change - begin |
1468 | 4.30k | CGOpts.setDebugInfo(CodeGenOptions::FullDebugInfo); |
1469 | 4.30k | CGOpts.HLSLEmbedSourcesInModule = true; |
1470 | | // HLSL Change - end |
1471 | | // CGOpts.setDebugInfo(CodeGenOptions::FullDebugInfo); // HLSL change |
1472 | 4.30k | CGOpts.DebugColumnInfo = 1; |
1473 | 4.30k | CGOpts.DwarfVersion = 4; // Latest version. |
1474 | | // TODO: consider |
1475 | | // DebugPass, DebugCompilationDir, DwarfDebugFlags, SplitDwarfFile |
1476 | 21.2k | } else if (!Opts.ForceDisableLocTracking) { |
1477 | 21.2k | CodeGenOptions &CGOpts = compiler.getCodeGenOpts(); |
1478 | 21.2k | CGOpts.setDebugInfo(CodeGenOptions::LocTrackingOnly); |
1479 | 21.2k | CGOpts.DebugColumnInfo = 1; |
1480 | 21.2k | } |
1481 | | |
1482 | 25.5k | clang::PreprocessorOptions &PPOpts(compiler.getPreprocessorOpts()); |
1483 | 33.6k | for (size_t i = 0; i < defines.size(); ++i8.04k ) { |
1484 | 8.04k | PPOpts.addMacroDef(defines[i]); |
1485 | 8.04k | } |
1486 | | |
1487 | 25.5k | PPOpts.IgnoreLineDirectives = Opts.IgnoreLineDirectives; |
1488 | | // fxc compatibility: pre-expand operands before performing token-pasting |
1489 | 25.5k | PPOpts.ExpandTokPastingArg = Opts.LegacyMacroExpansion; |
1490 | | |
1491 | | // Pick additional arguments. |
1492 | 25.5k | clang::HeaderSearchOptions &HSOpts = compiler.getHeaderSearchOpts(); |
1493 | 25.5k | HSOpts.UseBuiltinIncludes = 0; |
1494 | | // Consider: should we force-include '.' if the source file is relative? |
1495 | 25.5k | for (const llvm::opt::Arg *A : Opts.Args.filtered(options::OPT_I)) { |
1496 | 246 | const bool IsFrameworkFalse = false; |
1497 | 246 | const bool IgnoreSysRoot = true; |
1498 | 246 | if (dxcutil::IsAbsoluteOrCurDirRelative(A->getValue())) { |
1499 | 226 | HSOpts.AddPath(A->getValue(), frontend::Angled, IsFrameworkFalse, |
1500 | 226 | IgnoreSysRoot); |
1501 | 226 | } else { |
1502 | 20 | std::string s("./"); |
1503 | 20 | s += A->getValue(); |
1504 | 20 | HSOpts.AddPath(s, frontend::Angled, IsFrameworkFalse, IgnoreSysRoot); |
1505 | 20 | } |
1506 | 246 | } |
1507 | | |
1508 | | // Apply root signature option. |
1509 | 25.5k | unsigned rootSigMinor; |
1510 | 25.5k | if (Opts.ForceRootSigVer.empty() || Opts.ForceRootSigVer == "rootsig_1_1"928 ) { |
1511 | 25.1k | rootSigMinor = 1; |
1512 | 25.1k | } else { |
1513 | 444 | DXASSERT(Opts.ForceRootSigVer == "rootsig_1_0", |
1514 | 444 | "else opts should have been rejected"); |
1515 | 444 | rootSigMinor = 0; |
1516 | 444 | } |
1517 | 25.5k | compiler.getLangOpts().RootSigMajor = 1; |
1518 | 25.5k | compiler.getLangOpts().RootSigMinor = rootSigMinor; |
1519 | 25.5k | compiler.getLangOpts().HLSLVersion = Opts.HLSLVersion; |
1520 | 25.5k | compiler.getLangOpts().EnableDX9CompatMode = Opts.EnableDX9CompatMode; |
1521 | 25.5k | compiler.getLangOpts().EnableFXCCompatMode = Opts.EnableFXCCompatMode; |
1522 | | |
1523 | 25.5k | compiler.getLangOpts().UseMinPrecision = !Opts.Enable16BitTypes; |
1524 | | |
1525 | 25.5k | compiler.getLangOpts().EnablePayloadAccessQualifiers = |
1526 | 25.5k | Opts.EnablePayloadQualifiers; |
1527 | 25.5k | compiler.getLangOpts().HLSLProfile = compiler.getCodeGenOpts().HLSLProfile = |
1528 | 25.5k | Opts.TargetProfile; |
1529 | 25.5k | const ShaderModel *SM = hlsl::ShaderModel::GetByName( |
1530 | 25.5k | compiler.getLangOpts().HLSLProfile.c_str()); |
1531 | 25.5k | if (SM->IsSM69Plus()) |
1532 | 1.17k | compiler.getLangOpts().MaxHLSLVectorLength = DXIL::kSM69MaxVectorLength; |
1533 | 24.3k | else |
1534 | 24.3k | compiler.getLangOpts().MaxHLSLVectorLength = |
1535 | 24.3k | DXIL::kDefaultMaxVectorLength; |
1536 | | |
1537 | | // Enable dumping implicit top level decls either if it was specifically |
1538 | | // requested or if we are not dumping the ast from the command line. That |
1539 | | // allows us to dump implicit AST nodes in the debugger. |
1540 | 25.5k | compiler.getLangOpts().DumpImplicitTopLevelDecls = |
1541 | 25.5k | Opts.AstDumpImplicit || !Opts.AstDump25.5k ; |
1542 | 25.5k | compiler.getLangOpts().HLSLDefaultRowMajor = Opts.DefaultRowMajor; |
1543 | | |
1544 | | // SPIRV change starts |
1545 | 25.5k | #ifdef ENABLE_SPIRV_CODEGEN |
1546 | 25.5k | compiler.getLangOpts().SPIRV = Opts.GenSPIRV; |
1547 | 25.5k | llvm::Optional<spv_target_env> spirvTargetEnv = |
1548 | 25.5k | spirv::FeatureManager::stringToSpvEnvironment( |
1549 | 25.5k | Opts.SpirvOptions.targetEnv); |
1550 | | |
1551 | | // If we do not have a valid target environment, the error will be handled |
1552 | | // later. |
1553 | 25.5k | if (spirvTargetEnv.hasValue()) { |
1554 | 25.5k | VersionTuple spirvVersion = |
1555 | 25.5k | spirv::FeatureManager::getSpirvVersion(spirvTargetEnv.getValue()); |
1556 | 25.5k | compiler.getLangOpts().SpirvMajorVersion = spirvVersion.getMajor(); |
1557 | 25.5k | assert(spirvVersion.getMinor().hasValue() && |
1558 | 25.5k | "There must always be a major and minor version number when " |
1559 | 25.5k | "targeting SPIR-V."); |
1560 | 25.5k | compiler.getLangOpts().SpirvMinorVersion = |
1561 | 25.5k | spirvVersion.getMinor().getValue(); |
1562 | 25.5k | } |
1563 | 25.5k | #endif |
1564 | | // SPIRV change ends |
1565 | | |
1566 | 25.5k | if (Opts.WarningAsError) |
1567 | 52 | compiler.getDiagnostics().setWarningsAsErrors(true); |
1568 | | |
1569 | 25.5k | if (Opts.IEEEStrict) |
1570 | 30 | compiler.getCodeGenOpts().UnsafeFPMath = true; |
1571 | | |
1572 | 25.5k | if (Opts.FloatDenormalMode.empty()) { |
1573 | 25.5k | compiler.getCodeGenOpts().HLSLFloat32DenormMode = |
1574 | 25.5k | DXIL::Float32DenormMode::Reserve7; // undefined |
1575 | 25.5k | } else if (18 Opts.FloatDenormalMode.equals_lower(StringRef("any"))18 ) { |
1576 | 2 | compiler.getCodeGenOpts().HLSLFloat32DenormMode = |
1577 | 2 | DXIL::Float32DenormMode::Any; |
1578 | 16 | } else if (Opts.FloatDenormalMode.equals_lower(StringRef("ftz"))) { |
1579 | 10 | compiler.getCodeGenOpts().HLSLFloat32DenormMode = |
1580 | 10 | DXIL::Float32DenormMode::FTZ; |
1581 | 10 | } else { |
1582 | 6 | DXASSERT(Opts.FloatDenormalMode.equals_lower(StringRef("preserve")), |
1583 | 6 | "else opts should have been rejected"); |
1584 | 6 | compiler.getCodeGenOpts().HLSLFloat32DenormMode = |
1585 | 6 | DXIL::Float32DenormMode::Preserve; |
1586 | 6 | } |
1587 | | |
1588 | 25.5k | if (Opts.DisableOptimizations) |
1589 | 1.54k | compiler.getCodeGenOpts().DisableLLVMOpts = true; |
1590 | | |
1591 | 25.5k | compiler.getCodeGenOpts().OptimizationLevel = Opts.OptLevel; |
1592 | 25.5k | if (Opts.OptLevel >= 3) |
1593 | 23.3k | compiler.getCodeGenOpts().UnrollLoops = true; |
1594 | | |
1595 | 25.5k | compiler.getCodeGenOpts().HLSLHighLevel = Opts.CodeGenHighLevel; |
1596 | 25.5k | compiler.getCodeGenOpts().HLSLAllowPreserveValues = |
1597 | 25.5k | Opts.AllowPreserveValues; |
1598 | 25.5k | compiler.getCodeGenOpts().HLSLOnlyWarnOnUnrollFail = |
1599 | 25.5k | Opts.EnableFXCCompatMode; |
1600 | 25.5k | compiler.getCodeGenOpts().HLSLResMayAlias = Opts.ResMayAlias; |
1601 | 25.5k | compiler.getCodeGenOpts().ScanLimit = Opts.ScanLimit; |
1602 | 25.5k | compiler.getCodeGenOpts().HLSLOptimizationToggles = Opts.OptToggles; |
1603 | 25.5k | compiler.getCodeGenOpts().HLSLAllResourcesBound = Opts.AllResourcesBound; |
1604 | 25.5k | compiler.getCodeGenOpts().HLSLIgnoreOptSemDefs = Opts.IgnoreOptSemDefs; |
1605 | 25.5k | compiler.getCodeGenOpts().HLSLIgnoreSemDefs = Opts.IgnoreSemDefs; |
1606 | 25.5k | compiler.getCodeGenOpts().HLSLOverrideSemDefs = Opts.OverrideSemDefs; |
1607 | 25.5k | compiler.getCodeGenOpts().HLSLPreferControlFlow = Opts.PreferFlowControl; |
1608 | 25.5k | compiler.getCodeGenOpts().HLSLAvoidControlFlow = Opts.AvoidFlowControl; |
1609 | 25.5k | compiler.getCodeGenOpts().HLSLLegacyResourceReservation = |
1610 | 25.5k | Opts.LegacyResourceReservation; |
1611 | 25.5k | compiler.getCodeGenOpts().HLSLDefines = defines; |
1612 | 25.5k | compiler.getCodeGenOpts().HLSLPreciseOutputs = Opts.PreciseOutputs; |
1613 | 25.5k | compiler.getCodeGenOpts().MainFileName = pMainFile; |
1614 | 25.5k | compiler.getCodeGenOpts().HLSLPrintBeforeAll = Opts.PrintBeforeAll; |
1615 | 25.5k | compiler.getCodeGenOpts().HLSLPrintBefore = Opts.PrintBefore; |
1616 | 25.5k | compiler.getCodeGenOpts().HLSLPrintAfterAll = Opts.PrintAfterAll; |
1617 | 25.5k | compiler.getCodeGenOpts().HLSLPrintAfter = Opts.PrintAfter; |
1618 | 25.5k | compiler.getCodeGenOpts().HLSLForceZeroStoreLifetimes = |
1619 | 25.5k | Opts.ForceZeroStoreLifetimes; |
1620 | 25.5k | compiler.getCodeGenOpts().HLSLEnableLifetimeMarkers = |
1621 | 25.5k | Opts.EnableLifetimeMarkers; |
1622 | 25.5k | compiler.getCodeGenOpts().HLSLEnablePayloadAccessQualifiers = |
1623 | 25.5k | Opts.EnablePayloadQualifiers; |
1624 | | |
1625 | | // Translate signature packing options |
1626 | 25.5k | if (Opts.PackPrefixStable) |
1627 | 12 | compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = |
1628 | 12 | (unsigned)DXIL::PackingStrategy::PrefixStable; |
1629 | 25.5k | else if (Opts.PackOptimized) |
1630 | 16 | compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = |
1631 | 16 | (unsigned)DXIL::PackingStrategy::Optimized; |
1632 | 25.5k | else |
1633 | 25.5k | compiler.getCodeGenOpts().HLSLSignaturePackingStrategy = |
1634 | 25.5k | (unsigned)DXIL::PackingStrategy::Default; |
1635 | | |
1636 | | // Constructing vector of strings to pass in to codegen. Just passing |
1637 | | // in pArguments will expose ownership of memory to both CodeGenOptions and |
1638 | | // this caller, which can lead to unexpected behavior. |
1639 | 25.5k | { |
1640 | | // Find all args that are of Option::InputClass and record their indices |
1641 | | // in a set. If there are multiple Option::InputClass arguments, exclude |
1642 | | // all of them. We only use the last one and there's no point recording |
1643 | | // the rest of them. |
1644 | | // |
1645 | | // This list is used to populate the argument list in debug module and |
1646 | | // PDB, which are for recompiling. The input filenames are not needed for |
1647 | | // it and should be excluded. |
1648 | 25.5k | llvm::DenseSet<unsigned> InputArgIndices; |
1649 | 128k | for (llvm::opt::Arg *arg : Opts.Args.getArgs()) { |
1650 | 128k | if (arg->getOption().getKind() == llvm::opt::Option::InputClass) |
1651 | 25.5k | InputArgIndices.insert(arg->getIndex()); |
1652 | 128k | } |
1653 | 218k | for (unsigned i = 0; i < Opts.Args.getNumInputArgStrings(); ++i192k ) { |
1654 | 192k | if (InputArgIndices.count(i) == |
1655 | 192k | 0) { // Only include this arg if it's not in the set of |
1656 | | // Option::InputClass args. |
1657 | 166k | StringRef argStr = Opts.Args.getArgString(i); |
1658 | 166k | compiler.getCodeGenOpts().HLSLArguments.emplace_back(argStr); |
1659 | 166k | } |
1660 | 192k | } |
1661 | 25.5k | } |
1662 | | |
1663 | | // Overrding default set of loop unroll. |
1664 | 25.5k | if (Opts.PreferFlowControl) |
1665 | 8 | compiler.getCodeGenOpts().UnrollLoops = false; |
1666 | 25.5k | if (Opts.AvoidFlowControl) |
1667 | 8 | compiler.getCodeGenOpts().UnrollLoops = true; |
1668 | | |
1669 | 25.5k | clang::CodeGenOptions::InliningMethod Inlining = |
1670 | 25.5k | clang::CodeGenOptions::OnlyAlwaysInlining; |
1671 | 25.5k | if (Opts.NewInlining) |
1672 | 14 | Inlining = clang::CodeGenOptions::NormalInlining; |
1673 | 25.5k | compiler.getCodeGenOpts().setInlining(Inlining); |
1674 | | |
1675 | 25.5k | compiler.getCodeGenOpts().HLSLExtensionsCodegen = |
1676 | 25.5k | std::make_shared<HLSLExtensionsCodegenHelperImpl>( |
1677 | 25.5k | compiler, m_langExtensionsHelper, Opts.RootSignatureDefine); |
1678 | | |
1679 | | // AutoBindingSpace also enables automatic binding for libraries if set. |
1680 | | // UINT_MAX == unset |
1681 | 25.5k | compiler.getCodeGenOpts().HLSLDefaultSpace = Opts.AutoBindingSpace; |
1682 | | |
1683 | | // processed export names from -exports option: |
1684 | 25.5k | compiler.getCodeGenOpts().HLSLLibraryExports = Opts.Exports; |
1685 | | |
1686 | | // only export shader functions for library |
1687 | 25.5k | compiler.getCodeGenOpts().ExportShadersOnly = Opts.ExportShadersOnly; |
1688 | 25.5k | compiler.getLangOpts().ExportShadersOnly = Opts.ExportShadersOnly; |
1689 | | |
1690 | 25.5k | if (Opts.DefaultLinkage.empty()) { |
1691 | 24.9k | compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::Default; |
1692 | 24.9k | } else if (590 Opts.DefaultLinkage.equals_lower("internal")590 ) { |
1693 | 8 | compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::Internal; |
1694 | 582 | } else if (Opts.DefaultLinkage.equals_lower("external")) { |
1695 | 582 | compiler.getCodeGenOpts().DefaultLinkage = DXIL::DefaultLinkage::External; |
1696 | 582 | } |
1697 | 25.5k | compiler.getLangOpts().DefaultLinkage = |
1698 | 25.5k | compiler.getCodeGenOpts().DefaultLinkage; |
1699 | 25.5k | } |
1700 | | |
1701 | | // IDxcVersionInfo |
1702 | | HRESULT STDMETHODCALLTYPE GetVersion(UINT32 *pMajor, |
1703 | 14.9k | UINT32 *pMinor) override { |
1704 | 14.9k | if (pMajor == nullptr || pMinor == nullptr) |
1705 | 0 | return E_INVALIDARG; |
1706 | 14.9k | *pMajor = DXIL::kDxilMajor; |
1707 | 14.9k | *pMinor = DXIL::kDxilMinor; |
1708 | 14.9k | return S_OK; |
1709 | 14.9k | } |
1710 | | HRESULT STDMETHODCALLTYPE GetCustomVersionString( |
1711 | | char **pVersionString // Custom version string for compiler. (Must be |
1712 | | // CoTaskMemFree()'d!) |
1713 | 6.72k | ) override { |
1714 | 6.72k | size_t size = strlen(RC_FILE_VERSION); |
1715 | 6.72k | char *const result = (char *)CoTaskMemAlloc(size + 1); |
1716 | 6.72k | if (result == nullptr) |
1717 | 0 | return E_OUTOFMEMORY; |
1718 | 6.72k | std::strcpy(result, RC_FILE_VERSION); |
1719 | 6.72k | *pVersionString = result; |
1720 | 6.72k | return S_OK; |
1721 | 6.72k | } |
1722 | | |
1723 | | #ifdef SUPPORT_QUERY_GIT_COMMIT_INFO |
1724 | | HRESULT STDMETHODCALLTYPE GetCommitInfo(UINT32 *pCommitCount, |
1725 | 6.72k | char **pCommitHash) override { |
1726 | 6.72k | if (pCommitCount == nullptr || pCommitHash == nullptr) |
1727 | 0 | return E_INVALIDARG; |
1728 | | |
1729 | 6.72k | char *const hash = (char *)CoTaskMemAlloc( |
1730 | 6.72k | 8 + 1); // 8 is guaranteed by utils/GetCommitInfo.py |
1731 | 6.72k | if (hash == nullptr) |
1732 | 0 | return E_OUTOFMEMORY; |
1733 | 6.72k | std::strcpy(hash, getGitCommitHash()); |
1734 | | |
1735 | 6.72k | *pCommitHash = hash; |
1736 | 6.72k | *pCommitCount = getGitCommitCount(); |
1737 | | |
1738 | 6.72k | return S_OK; |
1739 | 6.72k | } |
1740 | | #endif // SUPPORT_QUERY_GIT_COMMIT_INFO |
1741 | | |
1742 | 7.79k | HRESULT STDMETHODCALLTYPE GetFlags(UINT32 *pFlags) override { |
1743 | 7.79k | if (pFlags == nullptr) |
1744 | 0 | return E_INVALIDARG; |
1745 | 7.79k | *pFlags = DxcVersionInfoFlags_None; |
1746 | | #ifndef NDEBUG |
1747 | | *pFlags |= DxcVersionInfoFlags_Debug; |
1748 | | #endif |
1749 | 7.79k | return S_OK; |
1750 | 7.79k | } |
1751 | | }; |
1752 | | |
1753 | | ////////////////////////////////////////////////////////////// |
1754 | | // legacy IDxcCompiler2 implementation that maps to DxcCompiler |
1755 | 38.3k | ULONG STDMETHODCALLTYPE DxcCompilerAdapter::AddRef() { |
1756 | 38.3k | return m_pCompilerImpl->AddRef(); |
1757 | 38.3k | } |
1758 | 38.3k | ULONG STDMETHODCALLTYPE DxcCompilerAdapter::Release() { |
1759 | 38.3k | return m_pCompilerImpl->Release(); |
1760 | 38.3k | } |
1761 | | HRESULT STDMETHODCALLTYPE DxcCompilerAdapter::QueryInterface(REFIID iid, |
1762 | 10.2k | void **ppvObject) { |
1763 | 10.2k | return m_pCompilerImpl->QueryInterface(iid, ppvObject); |
1764 | 10.2k | } |
1765 | | |
1766 | | // Preprocess source text |
1767 | | HRESULT STDMETHODCALLTYPE DxcCompilerAdapter::Preprocess( |
1768 | | IDxcBlob *pSource, // Source text to preprocess |
1769 | | LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and |
1770 | | // include handlers. |
1771 | | LPCWSTR *pArguments, // Array of pointers to arguments |
1772 | | UINT32 argCount, // Number of arguments |
1773 | | const DxcDefine *pDefines, // Array of defines |
1774 | | UINT32 defineCount, // Number of defines |
1775 | | IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle |
1776 | | // #include directives (optional) |
1777 | | IDxcOperationResult * |
1778 | | *ppResult // Preprocessor output status, buffer, and errors |
1779 | 74 | ) { |
1780 | 74 | if (pSource == nullptr || ppResult == nullptr || |
1781 | 74 | (defineCount > 0 && pDefines == nullptr4 ) || |
1782 | 74 | (argCount > 0 && pArguments == nullptr70 )) |
1783 | 0 | return E_INVALIDARG; |
1784 | 74 | *ppResult = nullptr; |
1785 | | |
1786 | 74 | return WrapCompile(TRUE, pSource, pSourceName, nullptr, nullptr, pArguments, |
1787 | 74 | argCount, pDefines, defineCount, pIncludeHandler, ppResult, |
1788 | 74 | nullptr, nullptr); |
1789 | 74 | } |
1790 | | |
1791 | | // Disassemble a program. |
1792 | | HRESULT STDMETHODCALLTYPE DxcCompilerAdapter::Disassemble( |
1793 | | IDxcBlob *pProgram, // Program to disassemble. |
1794 | | IDxcBlobEncoding **ppDisassembly // Disassembly text. |
1795 | 8.17k | ) { |
1796 | 8.17k | if (pProgram == nullptr || ppDisassembly == nullptr) |
1797 | 0 | return E_INVALIDARG; |
1798 | | |
1799 | 8.17k | *ppDisassembly = nullptr; |
1800 | | |
1801 | 8.17k | HRESULT hr = S_OK; |
1802 | 8.17k | DxcThreadMalloc TM(m_pMalloc); |
1803 | | |
1804 | 8.17k | DxcBuffer buffer = {pProgram->GetBufferPointer(), pProgram->GetBufferSize(), |
1805 | 8.17k | 0}; |
1806 | 8.17k | CComPtr<IDxcResult> pResult; |
1807 | 8.17k | IFR(m_pCompilerImpl->Disassemble(&buffer, IID_PPV_ARGS(&pResult))); |
1808 | 8.15k | IFRBOOL(pResult, E_OUTOFMEMORY); |
1809 | | |
1810 | 8.15k | IFR(pResult->GetStatus(&hr)); |
1811 | 8.15k | if (SUCCEEDED(hr)) { |
1812 | | // Extract disassembly |
1813 | 8.15k | IFR(pResult->GetOutput(DXC_OUT_DISASSEMBLY, IID_PPV_ARGS(ppDisassembly), |
1814 | 8.15k | nullptr)); |
1815 | 8.15k | } |
1816 | 8.15k | return hr; |
1817 | 8.15k | } |
1818 | | |
1819 | | HRESULT CreateDxcUtils(REFIID riid, LPVOID *ppv); |
1820 | | |
1821 | | HRESULT STDMETHODCALLTYPE DxcCompilerAdapter::CompileWithDebug( |
1822 | | IDxcBlob *pSource, // Source text to compile |
1823 | | LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and |
1824 | | // include handlers. |
1825 | | LPCWSTR pEntryPoint, // Entry point name |
1826 | | LPCWSTR pTargetProfile, // Shader profile to compile |
1827 | | LPCWSTR *pArguments, // Array of pointers to arguments |
1828 | | UINT32 argCount, // Number of arguments |
1829 | | const DxcDefine *pDefines, // Array of defines |
1830 | | UINT32 defineCount, // Number of defines |
1831 | | IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle |
1832 | | // #include directives (optional) |
1833 | | IDxcOperationResult * |
1834 | | *ppResult, // Compiler output status, buffer, and errors |
1835 | | LPWSTR *ppDebugBlobName, // Suggested file name for debug blob. |
1836 | | IDxcBlob **ppDebugBlob // Debug blob |
1837 | 25.3k | ) { |
1838 | 25.3k | if (pSource == nullptr || ppResult == nullptr25.3k || |
1839 | 25.3k | (25.3k defineCount > 025.3k && pDefines == nullptr2.12k ) || |
1840 | 25.3k | (25.3k argCount > 025.3k && pArguments == nullptr23.5k ) || pTargetProfile == nullptr25.3k ) |
1841 | 6 | return E_INVALIDARG; |
1842 | | |
1843 | 25.3k | *ppResult = nullptr; |
1844 | 25.3k | AssignToOutOpt(nullptr, ppDebugBlobName); |
1845 | 25.3k | AssignToOutOpt(nullptr, ppDebugBlob); |
1846 | | |
1847 | 25.3k | return WrapCompile(FALSE, pSource, pSourceName, pEntryPoint, pTargetProfile, |
1848 | 25.3k | pArguments, argCount, pDefines, defineCount, |
1849 | 25.3k | pIncludeHandler, ppResult, ppDebugBlobName, ppDebugBlob); |
1850 | 25.3k | } |
1851 | | |
1852 | | HRESULT DxcCompilerAdapter::WrapCompile( |
1853 | | BOOL bPreprocess, // Preprocess mode |
1854 | | IDxcBlob *pSource, // Source text to compile |
1855 | | LPCWSTR pSourceName, // Optional file name for pSource. Used in errors and |
1856 | | // include handlers. |
1857 | | LPCWSTR pEntryPoint, // Entry point name |
1858 | | LPCWSTR pTargetProfile, // Shader profile to compile |
1859 | | LPCWSTR *pArguments, // Array of pointers to arguments |
1860 | | UINT32 argCount, // Number of arguments |
1861 | | const DxcDefine *pDefines, // Array of defines |
1862 | | UINT32 defineCount, // Number of defines |
1863 | | IDxcIncludeHandler *pIncludeHandler, // user-provided interface to handle |
1864 | | // #include directives (optional) |
1865 | | IDxcOperationResult * |
1866 | | *ppResult, // Compiler output status, buffer, and errors |
1867 | | LPWSTR *ppDebugBlobName, // Suggested file name for debug blob. |
1868 | | IDxcBlob **ppDebugBlob // Debug blob |
1869 | 25.4k | ) { |
1870 | 25.4k | HRESULT hr = S_OK; |
1871 | 25.4k | DxcThreadMalloc TM(m_pMalloc); |
1872 | | |
1873 | 25.4k | try { |
1874 | 25.4k | CComPtr<IDxcUtils> pUtils; |
1875 | 25.4k | IFT(CreateDxcUtils(IID_PPV_ARGS(&pUtils))); |
1876 | 25.4k | CComPtr<IDxcCompilerArgs> pArgs; |
1877 | 25.4k | IFR(pUtils->BuildArguments(pSourceName, pEntryPoint, pTargetProfile, |
1878 | 25.4k | pArguments, argCount, pDefines, defineCount, |
1879 | 25.4k | &pArgs)); |
1880 | | |
1881 | 25.4k | LPCWSTR PreprocessArgs[] = {L"-P", L"-Fi", L"preprocessed.hlsl"}; |
1882 | 25.4k | if (bPreprocess) { |
1883 | 74 | IFT(pArgs->AddArguments(PreprocessArgs, _countof(PreprocessArgs))); |
1884 | 74 | } |
1885 | | |
1886 | 25.4k | DxcBuffer buffer = {pSource->GetBufferPointer(), pSource->GetBufferSize(), |
1887 | 25.4k | CP_ACP}; |
1888 | 25.4k | CComPtr<IDxcBlobEncoding> pSourceEncoding; |
1889 | 25.4k | if (SUCCEEDED(pSource->QueryInterface(&pSourceEncoding))) { |
1890 | 25.4k | BOOL sourceEncodingKnown = false; |
1891 | 25.4k | IFT(pSourceEncoding->GetEncoding(&sourceEncodingKnown, &buffer.Encoding)); |
1892 | 25.4k | } |
1893 | | |
1894 | 25.4k | CComPtr<AbstractMemoryStream> pOutputStream; |
1895 | 25.4k | IFT(CreateMemoryStream(m_pMalloc, &pOutputStream)); |
1896 | | |
1897 | | // Parse command-line options into DxcOpts |
1898 | 25.4k | int argCountInt; |
1899 | 25.4k | IFT(UIntToInt(pArgs->GetCount(), &argCountInt)); |
1900 | 25.4k | hlsl::options::MainArgs mainArgs(argCountInt, pArgs->GetArguments(), 0); |
1901 | 25.4k | hlsl::options::DxcOpts opts; |
1902 | 25.4k | bool finished = false; |
1903 | 25.4k | CComPtr<IDxcOperationResult> pOperationResult; |
1904 | 25.4k | dxcutil::ReadOptsAndValidate(mainArgs, opts, pOutputStream, |
1905 | 25.4k | &pOperationResult, finished); |
1906 | 25.4k | if (!opts.TimeTrace.empty()) |
1907 | 10 | llvm::timeTraceProfilerInitialize(opts.TimeTraceGranularity); |
1908 | 25.4k | if (finished) { |
1909 | 24 | IFT(pOperationResult->QueryInterface(ppResult)); |
1910 | 24 | return S_OK; |
1911 | 24 | } |
1912 | | |
1913 | 25.3k | if (pOutputStream->GetPosition() > 0) { |
1914 | | // Clear existing stream in case it has option spew |
1915 | 4 | pOutputStream.Release(); |
1916 | 4 | IFT(CreateMemoryStream(m_pMalloc, &pOutputStream)); |
1917 | 4 | } |
1918 | | |
1919 | | // To concat out output with compiler errors |
1920 | 25.3k | raw_stream_ostream outStream(pOutputStream); |
1921 | | |
1922 | 25.3k | LPCWSTR EmbedDebugOpt[] = {L"-Qembed_debug"}; |
1923 | 25.3k | if (opts.DebugInfo && !ppDebugBlob4.11k && !opts.EmbedDebug900 && |
1924 | 25.3k | !opts.StripDebug588 ) { |
1925 | | // SPIRV change starts |
1926 | 578 | #if defined(ENABLE_SPIRV_CODEGEN) |
1927 | 578 | if (!opts.GenSPIRV) |
1928 | 396 | outStream << "warning: no output provided for debug - embedding PDB in " |
1929 | 396 | "shader container. Use -Qembed_debug to silence this " |
1930 | 396 | "warning.\n"; |
1931 | | #else |
1932 | | outStream << "warning: no output provided for debug - embedding PDB in " |
1933 | | "shader container. Use -Qembed_debug to silence this " |
1934 | | "warning.\n"; |
1935 | | #endif |
1936 | | // SPIRV change ends |
1937 | 578 | IFT(pArgs->AddArguments(EmbedDebugOpt, _countof(EmbedDebugOpt))); |
1938 | 578 | } |
1939 | | |
1940 | 25.3k | CComPtr<DxcResult> pResult = DxcResult::Alloc(m_pMalloc); |
1941 | 25.3k | pResult->SetEncoding(opts.DefaultTextCodePage); |
1942 | | |
1943 | 25.3k | CComPtr<IDxcResult> pImplResult; |
1944 | 25.3k | IFR(m_pCompilerImpl->Compile(&buffer, pArgs->GetArguments(), |
1945 | 25.3k | pArgs->GetCount(), pIncludeHandler, |
1946 | 25.3k | IID_PPV_ARGS(&pImplResult))); |
1947 | 25.3k | IFRBOOL(pImplResult, E_OUTOFMEMORY); |
1948 | 25.3k | IFR(pImplResult->GetStatus(&hr)); |
1949 | | |
1950 | 25.3k | pResult->CopyOutputsFromResult(pImplResult); |
1951 | 25.3k | pResult->SetStatusAndPrimaryResult(hr, pImplResult->PrimaryOutput()); |
1952 | | |
1953 | 25.3k | if (opts.TimeReport) { |
1954 | 4 | std::string TimeReport; |
1955 | 4 | raw_string_ostream OS(TimeReport); |
1956 | 4 | llvm::TimerGroup::printAll(OS); |
1957 | 4 | IFT(pResult->SetOutputString(DXC_OUT_TIME_REPORT, TimeReport.c_str(), |
1958 | 4 | TimeReport.size())); |
1959 | 4 | } |
1960 | | |
1961 | 25.3k | if (llvm::timeTraceProfilerEnabled()) { |
1962 | 10 | std::string TimeTrace; |
1963 | 10 | raw_string_ostream OS(TimeTrace); |
1964 | 10 | llvm::timeTraceProfilerWrite(OS); |
1965 | 10 | llvm::timeTraceProfilerCleanup(); |
1966 | 10 | IFT(pResult->SetOutputString(DXC_OUT_TIME_TRACE, TimeTrace.c_str(), |
1967 | 10 | TimeTrace.size())); |
1968 | 10 | } |
1969 | | |
1970 | 25.3k | outStream.flush(); |
1971 | | |
1972 | | // Insert any warnings generated here |
1973 | 25.3k | if (pOutputStream->GetPosition() > 0) { |
1974 | 396 | CComPtr<IDxcBlobEncoding> pErrorsEncoding; |
1975 | 396 | if (SUCCEEDED(pResult->GetOutput( |
1976 | 396 | DXC_OUT_ERRORS, IID_PPV_ARGS(&pErrorsEncoding), nullptr)) && |
1977 | 396 | pErrorsEncoding && pErrorsEncoding->GetBufferSize()) { |
1978 | 86 | CComPtr<IDxcBlobUtf8> pErrorsUtf8; |
1979 | 86 | IFT(pUtils->GetBlobAsUtf8(pErrorsEncoding, &pErrorsUtf8)); |
1980 | 86 | outStream << pErrorsUtf8->GetStringPointer(); |
1981 | 86 | outStream.flush(); |
1982 | 86 | } |
1983 | | // Reconstruct result with new error buffer |
1984 | 396 | CComPtr<IDxcBlobEncoding> pErrorBlob; |
1985 | 396 | IFT(hlsl::DxcCreateBlob(pOutputStream->GetPtr(), |
1986 | 396 | pOutputStream->GetPtrSize(), false, true, true, |
1987 | 396 | DXC_CP_UTF8, nullptr, &pErrorBlob)); |
1988 | 396 | if (pErrorBlob && pErrorBlob->GetBufferSize()) { |
1989 | 396 | pResult->Output(DXC_OUT_ERRORS)->object.Release(); |
1990 | 396 | pResult->SetOutputObject(DXC_OUT_ERRORS, pErrorBlob); |
1991 | 396 | } |
1992 | 396 | } |
1993 | | |
1994 | | // Extract debug blob if present |
1995 | 25.3k | CComHeapPtr<wchar_t> pDebugNameOnComHeap; |
1996 | 25.3k | CComPtr<IDxcBlob> pDebugBlob; |
1997 | 25.3k | if (SUCCEEDED(hr)) { |
1998 | 22.3k | CComPtr<IDxcBlobWide> pDebugName; |
1999 | 22.3k | hr = pResult->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pDebugBlob), |
2000 | 22.3k | &pDebugName); |
2001 | 22.3k | if (SUCCEEDED(hr) && ppDebugBlobName3.89k && pDebugName3.21k ) { |
2002 | 3.21k | if (!pDebugNameOnComHeap.AllocateBytes(pDebugName->GetBufferSize())) |
2003 | 0 | return E_OUTOFMEMORY; |
2004 | 3.21k | memcpy(pDebugNameOnComHeap.m_pData, pDebugName->GetBufferPointer(), |
2005 | 3.21k | pDebugName->GetBufferSize()); |
2006 | 3.21k | } |
2007 | 22.3k | } |
2008 | | |
2009 | 25.3k | if (ppDebugBlob && pDebugBlob10.1k ) |
2010 | 3.21k | *ppDebugBlob = pDebugBlob.Detach(); |
2011 | 25.3k | if (ppDebugBlobName && pDebugNameOnComHeap10.1k ) |
2012 | 3.21k | *ppDebugBlobName = pDebugNameOnComHeap.Detach(); |
2013 | | |
2014 | 25.3k | IFR(pResult.QueryInterface(ppResult)); |
2015 | 25.3k | hr = S_OK; |
2016 | 25.3k | } catch (std::bad_alloc &) { |
2017 | 0 | hr = E_OUTOFMEMORY; |
2018 | 0 | } catch (hlsl::Exception &e) { |
2019 | 0 | assert(DXC_FAILED(e.hr)); |
2020 | 0 | hr = DxcResult::Create( |
2021 | 0 | e.hr, DXC_OUT_NONE, |
2022 | 0 | {DxcOutputObject::ErrorOutput(CP_UTF8, e.msg.c_str(), e.msg.size())}, |
2023 | 0 | ppResult); |
2024 | 0 | } catch (...) { |
2025 | 0 | hr = E_FAIL; |
2026 | 0 | } |
2027 | 25.3k | return hr; |
2028 | 25.4k | } |
2029 | | ////////////////////////////////////////////////////////////// |
2030 | | |
2031 | 36.5k | HRESULT CreateDxcCompiler(REFIID riid, LPVOID *ppv) { |
2032 | 36.5k | *ppv = nullptr; |
2033 | 36.5k | try { |
2034 | 36.5k | CComPtr<DxcCompiler> result(DxcCompiler::Alloc(DxcGetThreadMallocNoRef())); |
2035 | 36.5k | IFROOM(result.p); |
2036 | 36.5k | return result.p->QueryInterface(riid, ppv); |
2037 | 36.5k | } |
2038 | 36.5k | CATCH_CPP_RETURN_HRESULT(); |
2039 | 0 | } |