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 @@ -9,6 +9,7 @@ add_llvm_target(DirectXCodeGen DirectXSubtarget.cpp DirectXTargetMachine.cpp + DxilEmitMetadata.cpp DXILPointerType.cpp DXILPrepare.cpp PointerTypeAnalysis.cpp 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 @@ -23,6 +23,12 @@ /// Pass to convert modules into DXIL-compatable modules ModulePass *createDXILPrepareModulePass(); + +/// Initializer for DxilEmitMetadata. +void initializeDxilEmitMetadataPass(PassRegistry &); + +/// Pass to emit metadata for DXIL. +ModulePass *createDxilEmitMetadataPass(); } // 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 @@ -34,6 +34,7 @@ RegisterTargetMachine X(getTheDirectXTarget()); auto *PR = PassRegistry::getPassRegistry(); initializeDXILPrepareModulePass(*PR); + initializeDxilEmitMetadataPass(*PR); } class DXILTargetObjectFile : public TargetLoweringObjectFile { @@ -85,6 +86,7 @@ CodeGenFileType FileType, bool DisableVerify, MachineModuleInfoWrapperPass *MMIWP) { PM.add(createDXILPrepareModulePass()); + PM.add(createDxilEmitMetadataPass()); switch (FileType) { case CGFT_AssemblyFile: PM.add(createPrintModulePass(Out, "", true)); diff --git a/llvm/lib/Target/DirectX/DxilEmitMetadata.cpp b/llvm/lib/Target/DirectX/DxilEmitMetadata.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/DirectX/DxilEmitMetadata.cpp @@ -0,0 +1,103 @@ +//===- DxilEmitMetadata.cpp - Pass to emit dxil metadata --------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +//===----------------------------------------------------------------------===// + +#include "DirectX.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" + +using namespace llvm; + +namespace { +unsigned ConstMDToUint32(const MDOperand &MDO) { + ConstantInt *pConst = mdconst::extract(MDO); + return (unsigned)pConst->getZExtValue(); +} +ConstantAsMetadata *Uint32ToConstMD(unsigned v, LLVMContext &Ctx) { + return ConstantAsMetadata::get( + Constant::getIntegerValue(IntegerType::get(Ctx, 32), APInt(32, v))); +} +const StringRef ValVerKey = "dx.valver"; +const unsigned DxilVersionNumFields = 2; +const unsigned DxilVersionMajorIdx = 0; // DXIL version major. +const unsigned DxilVersionMinorIdx = 1; // DXIL version minor. + +void emitDxilValidatorVersion(Module &M, VersionTuple &ValidatorVer) { + NamedMDNode *DxilValidatorVersionMD = M.getNamedMetadata(ValVerKey); + + // Allow re-writing the validator version, since this can be changed at + // later points. + if (DxilValidatorVersionMD) + M.eraseNamedMetadata(DxilValidatorVersionMD); + + DxilValidatorVersionMD = M.getOrInsertNamedMetadata(ValVerKey); + + auto &Ctx = M.getContext(); + Metadata *MDVals[DxilVersionNumFields]; + MDVals[DxilVersionMajorIdx] = Uint32ToConstMD(ValidatorVer.getMajor(), Ctx); + MDVals[DxilVersionMinorIdx] = + Uint32ToConstMD(ValidatorVer.getMinor().getValueOr(0), Ctx); + + DxilValidatorVersionMD->addOperand(MDNode::get(Ctx, MDVals)); +} + +VersionTuple loadDxilValidatorVersion(MDNode *ValVerMD) { + if (ValVerMD->getNumOperands() != DxilVersionNumFields) + return VersionTuple(); + + unsigned Major = ConstMDToUint32(ValVerMD->getOperand(DxilVersionMajorIdx)); + unsigned Minor = ConstMDToUint32(ValVerMD->getOperand(DxilVersionMinorIdx)); + return VersionTuple(Major, Minor); +} + +void cleanModule(Module &M) { + M.getOrInsertModuleFlagsMetadata()->eraseFromParent(); +} +} // namespace + +namespace { +class DxilEmitMetadata : public ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + explicit DxilEmitMetadata() : ModulePass(ID), ValidatorVer(1, 0) {} + + StringRef getPassName() const override { return "HLSL DXIL Metadata Emit"; } + + bool runOnModule(Module &M) override; + +private: + VersionTuple ValidatorVer; + void emitDXILVersion(Module &M); +}; + +bool DxilEmitMetadata::runOnModule(Module &M) { + if (MDNode *ValVerMD = cast_or_null(M.getModuleFlag(ValVerKey))) { + auto ValVer = loadDxilValidatorVersion(ValVerMD); + if (!ValVer.empty()) + ValidatorVer = ValVer; + } + emitDxilValidatorVersion(M, ValidatorVer); + cleanModule(M); + return false; +} + +void DxilEmitMetadata::emitDXILVersion(Module &M) {} + +} // namespace + +char DxilEmitMetadata::ID = 0; + +ModulePass *llvm::createDxilEmitMetadataPass() { + return new DxilEmitMetadata(); +} + +INITIALIZE_PASS(DxilEmitMetadata, "dxil-metadata-emit", + "HLSL DXIL Metadata Emit", false, false) diff --git a/llvm/test/CodeGen/DirectX/dxil_ver.ll b/llvm/test/CodeGen/DirectX/dxil_ver.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/dxil_ver.ll @@ -0,0 +1,14 @@ +; RUN: llc %s --filetype=asm -o - | FileCheck %s +target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-pc-shadermodel6.3-library" + +; CHECK:!dx.valver = !{![[valver:[0-9]+]]} +; CHECK:![[valver]] = !{i32 1, i32 1} + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!3} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 6, !"dx.valver", !2} +!2 = !{i32 1, i32 1} +!3 = !{!"clang version 15.0.0 (https://github.com/llvm/llvm-project 71de12113a0661649ecb2f533fba4a2818a1ad68)"} \ No newline at end of file