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 @@ -12,6 +12,7 @@ DXILOpLowering.cpp DXILPointerType.cpp DXILPrepare.cpp + DXILTranslateMetadata.cpp PointerTypeAnalysis.cpp LINK_COMPONENTS diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp @@ -0,0 +1,97 @@ +//===- DXILTranslateMetadata.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; + +static uint32_t ConstMDToUint32(const MDOperand &MDO) { + ConstantInt *pConst = mdconst::extract(MDO); + return (uint32_t)pConst->getZExtValue(); +} + +static ConstantAsMetadata *Uint32ToConstMD(unsigned v, LLVMContext &Ctx) { + return ConstantAsMetadata::get( + Constant::getIntegerValue(IntegerType::get(Ctx, 32), APInt(32, v))); +} + +constexpr StringLiteral ValVerKey = "dx.valver"; +constexpr unsigned DXILVersionNumFields = 2; + +static 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[0] = Uint32ToConstMD(ValidatorVer.getMajor(), Ctx); + MDVals[1] = Uint32ToConstMD(ValidatorVer.getMinor().getValueOr(0), Ctx); + + DXILValidatorVersionMD->addOperand(MDNode::get(Ctx, MDVals)); +} + +static VersionTuple loadDXILValidatorVersion(MDNode *ValVerMD) { + if (ValVerMD->getNumOperands() != DXILVersionNumFields) + return VersionTuple(); + + unsigned Major = ConstMDToUint32(ValVerMD->getOperand(0)); + unsigned Minor = ConstMDToUint32(ValVerMD->getOperand(1)); + return VersionTuple(Major, Minor); +} + +static void cleanModule(Module &M) { + M.getOrInsertModuleFlagsMetadata()->eraseFromParent(); +} + +namespace { +class DXILTranslateMetadata : public ModulePass { +public: + static char ID; // Pass identification, replacement for typeid + explicit DXILTranslateMetadata() : ModulePass(ID), ValidatorVer(1, 0) {} + + StringRef getPassName() const override { return "DXIL Metadata Emit"; } + + bool runOnModule(Module &M) override; + +private: + VersionTuple ValidatorVer; +}; + +} // namespace + +bool DXILTranslateMetadata::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; +} + +char DXILTranslateMetadata::ID = 0; + +ModulePass *llvm::createDXILTranslateMetadataPass() { + return new DXILTranslateMetadata(); +} + +INITIALIZE_PASS(DXILTranslateMetadata, "dxil-metadata-emit", + "DXIL Metadata Emit", false, false) 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 @@ -30,6 +30,11 @@ /// Pass to lowering LLVM intrinsic call to DXIL op function call. ModulePass *createDXILOpLoweringLegacyPass(); +/// Initializer for DXILTranslateMetadata. +void initializeDXILTranslateMetadataPass(PassRegistry &); + +/// Pass to emit metadata for DXIL. +ModulePass *createDXILTranslateMetadataPass(); } // 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 @@ -35,6 +35,7 @@ auto *PR = PassRegistry::getPassRegistry(); initializeDXILPrepareModulePass(*PR); initializeDXILOpLoweringLegacyPass(*PR); + initializeDXILTranslateMetadataPass(*PR); } class DXILTargetObjectFile : public TargetLoweringObjectFile { @@ -87,6 +88,7 @@ MachineModuleInfoWrapperPass *MMIWP) { PM.add(createDXILOpLoweringLegacyPass()); PM.add(createDXILPrepareModulePass()); + PM.add(createDXILTranslateMetadataPass()); switch (FileType) { case CGFT_AssemblyFile: PM.add(createPrintModulePass(Out, "", true)); 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: opt -S -dxil-metadata-emit < %s | 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)"}