Coverage Report

Created: 2026-04-01 02:40

/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
}