diff --git a/llvm/lib/MC/MCDXContainerWriter.cpp b/llvm/lib/MC/MCDXContainerWriter.cpp --- a/llvm/lib/MC/MCDXContainerWriter.cpp +++ b/llvm/lib/MC/MCDXContainerWriter.cpp @@ -65,6 +65,10 @@ PartOffsets.push_back(PartOffset); PartOffset += sizeof(dxbc::PartHeader) + SectionSize; PartOffset = alignTo(PartOffset, Align(4ul)); + // The DXIL part also writes a program header, so we need to include its + // size when computing the offset for a part after the DXIL part. + if (Sec.getName() == "DXIL") + PartOffset += sizeof(dxbc::ProgramHeader); } assert(PartOffset < std::numeric_limits::max() && "Part data too large for DXContainer"); diff --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt --- a/llvm/lib/Target/DirectX/CMakeLists.txt +++ b/llvm/lib/Target/DirectX/CMakeLists.txt @@ -17,6 +17,7 @@ DirectXRegisterInfo.cpp DirectXSubtarget.cpp DirectXTargetMachine.cpp + DXContainerGlobals.cpp DXILMetadata.cpp DXILOpBuilder.cpp DXILOpLowering.cpp diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp @@ -0,0 +1,71 @@ +//===- DXContainerGlobals.cpp - DXContainer global generator pass ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// DXContainerGlobalsPass implementation. +// +//===----------------------------------------------------------------------===// + +#include "DXILShaderFlags.h" +#include "DirectX.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/Constants.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; +using namespace llvm::dxil; + +namespace { +class DXContainerGlobals : public llvm::ModulePass { + +public: + static char ID; // Pass identification, replacement for typeid + DXContainerGlobals() : ModulePass(ID) { + initializeDXContainerGlobalsPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { + return "DXContainer Global Emitter"; + } + + bool runOnModule(Module &M) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + AU.addRequired(); + } +}; + +} // namespace + +bool DXContainerGlobals::runOnModule(Module &M) { + const uint64_t Flags = + (uint64_t)(getAnalysis().getShaderFlags()); + + Constant *FlagsConstant = ConstantInt::get(M.getContext(), APInt(64, Flags)); + auto *GV = new llvm::GlobalVariable(M, FlagsConstant->getType(), true, + GlobalValue::PrivateLinkage, + FlagsConstant, "dx.sfi0"); + GV->setSection("SFI0"); + GV->setAlignment(Align(4)); + appendToCompilerUsed(M, {GV}); + return true; +} + +char DXContainerGlobals::ID = 0; +INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals", + "DXContainer Global Emitter", false, true) +INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper) +INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals", + "DXContainer Global Emitter", false, true) + +ModulePass *llvm::createDXContainerGlobalsPass() { + return new DXContainerGlobals(); +} diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.h b/llvm/lib/Target/DirectX/DXILShaderFlags.h --- a/llvm/lib/Target/DirectX/DXILShaderFlags.h +++ b/llvm/lib/Target/DirectX/DXILShaderFlags.h @@ -73,6 +73,26 @@ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); }; +/// Wrapper pass for the legacy pass manager. +/// +/// This is required because the passes that will depend on this are codegen +/// passes which run through the legacy pass manager. +class ShaderFlagsAnalysisWrapper : public ModulePass { + ComputedShaderFlags Flags; + +public: + static char ID; + + ShaderFlagsAnalysisWrapper() : ModulePass(ID) {} + + const ComputedShaderFlags &getShaderFlags() { return Flags; } + + bool runOnModule(Module &M) override { + Flags = ComputedShaderFlags::computeFlags(M); + return false; + } +}; + } // namespace dxil } // namespace llvm diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp --- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp +++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp @@ -71,3 +71,8 @@ Flags.print(OS); return PreservedAnalyses::all(); } + +char ShaderFlagsAnalysisWrapper::ID = 0; + +INITIALIZE_PASS(ShaderFlagsAnalysisWrapper, "dx-shader-flag-analysis", + "DXIL Shader Flag Analysis", true, true) diff --git a/llvm/lib/Target/DirectX/DirectX.h b/llvm/lib/Target/DirectX/DirectX.h --- a/llvm/lib/Target/DirectX/DirectX.h +++ b/llvm/lib/Target/DirectX/DirectX.h @@ -49,6 +49,14 @@ /// Initializer for DXILPrettyPrinter. void initializeDXILPrettyPrinterPass(PassRegistry &); +/// Initializer for dxil::ShaderFlagsAnalysisWrapper pass. +void initializeShaderFlagsAnalysisWrapperPass(PassRegistry &); + +/// Initializer for DXContainerGlobals pass. +void initializeDXContainerGlobalsPass(PassRegistry &); + +/// Pass for generating DXContainer part globals. +ModulePass *createDXContainerGlobalsPass(); } // namespace llvm #endif // LLVM_LIB_TARGET_DIRECTX_DIRECTX_H diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp --- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp +++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp @@ -43,6 +43,7 @@ initializeDXILOpLoweringLegacyPass(*PR); initializeDXILTranslateMetadataPass(*PR); initializeDXILResourceWrapperPass(*PR); + initializeShaderFlagsAnalysisWrapperPass(*PR); } class DXILTargetObjectFile : public TargetLoweringObjectFile { @@ -126,6 +127,9 @@ if (TargetPassConfig::willCompleteCodeGenPipeline()) { PM.add(createDXILEmbedderPass()); + // We embed the other DXContainer globals after embedding DXIL so that the + // globals don't pollute the DXIL. + PM.add(createDXContainerGlobalsPass()); } switch (FileType) { case CGFT_AssemblyFile: diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll --- a/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll +++ b/llvm/test/CodeGen/DirectX/ShaderFlags/double-extensions.ll @@ -1,4 +1,5 @@ ; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s +; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC target triple = "dxil-pc-shadermodel6.7-library" @@ -11,3 +12,14 @@ %res = fdiv double %a, %b ret double %res } + + +; DXC: - Name: SFI0 +; DXC-NEXT: Size: 16 +; DXC-NEXT: Flags: +; DXC-NEXT: Doubles: true +; DXC-NOT: {{[A-Za-z]+: +true}} +; DXC: DX11_1_DoubleExtensions: true +; DXC-NOT: {{[A-Za-z]+: +true}} +; DXC: NextUnusedBit: false +; DXC: ... diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll --- a/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll +++ b/llvm/test/CodeGen/DirectX/ShaderFlags/doubles.ll @@ -1,4 +1,5 @@ ; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s +; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC target triple = "dxil-pc-shadermodel6.7-library" @@ -10,3 +11,11 @@ %sum = fadd double %a, %b ret double %sum } + +; DXC: - Name: SFI0 +; DXC-NEXT: Size: 16 +; DXC-NEXT: Flags: +; DXC-NEXT: Doubles: true +; DXC-NOT: {{[A-Za-z]+: +true}} +; DXC: NextUnusedBit: false +; DXC: ... diff --git a/llvm/test/CodeGen/DirectX/embed-dxil.ll b/llvm/test/CodeGen/DirectX/embed-dxil.ll --- a/llvm/test/CodeGen/DirectX/embed-dxil.ll +++ b/llvm/test/CodeGen/DirectX/embed-dxil.ll @@ -9,7 +9,10 @@ } ; CHECK: @dx.dxil = private constant [[BC_TYPE:\[[0-9]+ x i8\]]] c"BC\C0\DE{{[^"]+}}", section "DXIL", align 4 -; CHECK: @llvm.compiler.used = appending global [1 x ptr] [ptr @dx.dxil], section "llvm.metadata" + +; The dxil global should be the first here because we generate it before the +; other globals. If it isn't the first here, that's probably a bug. +; CHECK: @llvm.compiler.used = appending global {{\[[0-9]+ x ptr\]}} [ptr @dx.dxil ; This is using regex matches on some sizes, offsets and fields. These are all ; going to change as the DirectX backend continues to evolve and implement more @@ -41,3 +44,6 @@ ; DXC-NEXT: DXILMinorVersion: [[#]] ; DXC-NEXT: DXILSize: [[#SIZE - 32]] ; DXC-NEXT: DXIL: [ 0x42, 0x43, 0xC0, 0xDE, +; DXC: - Name: SFI0 +; DXC-NEXT: Size: 16 +; DXC-NOT: Flags: