1 //===- DXILTranslateMetadata.cpp - Pass to emit DXIL metadata ---*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 //===----------------------------------------------------------------------===//
10 
11 #include "DirectX.h"
12 #include "llvm/ADT/Triple.h"
13 #include "llvm/IR/Constants.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/Pass.h"
16 
17 using namespace llvm;
18 
19 static uint32_t ConstMDToUint32(const MDOperand &MDO) {
20   ConstantInt *pConst = mdconst::extract<ConstantInt>(MDO);
21   return (uint32_t)pConst->getZExtValue();
22 }
23 
24 static ConstantAsMetadata *Uint32ToConstMD(unsigned v, LLVMContext &Ctx) {
25   return ConstantAsMetadata::get(
26       Constant::getIntegerValue(IntegerType::get(Ctx, 32), APInt(32, v)));
27 }
28 
29 constexpr StringLiteral ValVerKey = "dx.valver";
30 constexpr unsigned DXILVersionNumFields = 2;
31 
32 static void emitDXILValidatorVersion(Module &M, VersionTuple &ValidatorVer) {
33   NamedMDNode *DXILValidatorVersionMD = M.getNamedMetadata(ValVerKey);
34 
35   // Allow re-writing the validator version, since this can be changed at
36   // later points.
37   if (DXILValidatorVersionMD)
38     M.eraseNamedMetadata(DXILValidatorVersionMD);
39 
40   DXILValidatorVersionMD = M.getOrInsertNamedMetadata(ValVerKey);
41 
42   auto &Ctx = M.getContext();
43   Metadata *MDVals[DXILVersionNumFields];
44   MDVals[0] = Uint32ToConstMD(ValidatorVer.getMajor(), Ctx);
45   MDVals[1] = Uint32ToConstMD(ValidatorVer.getMinor().getValueOr(0), Ctx);
46 
47   DXILValidatorVersionMD->addOperand(MDNode::get(Ctx, MDVals));
48 }
49 
50 static VersionTuple loadDXILValidatorVersion(MDNode *ValVerMD) {
51   if (ValVerMD->getNumOperands() != DXILVersionNumFields)
52     return VersionTuple();
53 
54   unsigned Major = ConstMDToUint32(ValVerMD->getOperand(0));
55   unsigned Minor = ConstMDToUint32(ValVerMD->getOperand(1));
56   return VersionTuple(Major, Minor);
57 }
58 
59 static void cleanModule(Module &M) {
60   M.getOrInsertModuleFlagsMetadata()->eraseFromParent();
61 }
62 
63 namespace {
64 class DXILTranslateMetadata : public ModulePass {
65 public:
66   static char ID; // Pass identification, replacement for typeid
67   explicit DXILTranslateMetadata() : ModulePass(ID), ValidatorVer(1, 0) {}
68 
69   StringRef getPassName() const override { return "DXIL Metadata Emit"; }
70 
71   bool runOnModule(Module &M) override;
72 
73 private:
74   VersionTuple ValidatorVer;
75 };
76 
77 } // namespace
78 
79 bool DXILTranslateMetadata::runOnModule(Module &M) {
80   if (MDNode *ValVerMD = cast_or_null<MDNode>(M.getModuleFlag(ValVerKey))) {
81     auto ValVer = loadDXILValidatorVersion(ValVerMD);
82     if (!ValVer.empty())
83       ValidatorVer = ValVer;
84   }
85   emitDXILValidatorVersion(M, ValidatorVer);
86   cleanModule(M);
87   return false;
88 }
89 
90 char DXILTranslateMetadata::ID = 0;
91 
92 ModulePass *llvm::createDXILTranslateMetadataPass() {
93   return new DXILTranslateMetadata();
94 }
95 
96 INITIALIZE_PASS(DXILTranslateMetadata, "dxil-metadata-emit",
97                 "DXIL Metadata Emit", false, false)
98