LLVM 23.0.0git
DXILPrepare.cpp
Go to the documentation of this file.
1//===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===//
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/// \file This file contains passes and utilities to convert a modern LLVM
10/// module into a module compatible with the LLVM 3.7-based DirectX Intermediate
11/// Language (DXIL).
12//===----------------------------------------------------------------------===//
13
14#include "DXILRootSignature.h"
15#include "DXILShaderFlags.h"
16#include "DirectX.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/StringSet.h"
23#include "llvm/CodeGen/Passes.h"
25#include "llvm/IR/IRBuilder.h"
26#include "llvm/IR/Instruction.h"
27#include "llvm/IR/Module.h"
29#include "llvm/Pass.h"
31
32#define DEBUG_TYPE "dxil-prepare"
33
34using namespace llvm;
35using namespace llvm::dxil;
36
37namespace {
38
39static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS,
40 const StringSet<> &LiveKeys,
41 bool AllowExperimental) {
42 for (auto &Attr : AS) {
43 if (!Attr.isStringAttribute())
44 continue;
45 StringRef Key = Attr.getKindAsString();
46 if (LiveKeys.contains(Key))
47 continue;
48 if (AllowExperimental && Key.starts_with("exp-"))
49 continue;
50 DeadAttrs.addAttribute(Key);
51 }
52}
53
54static void removeStringFunctionAttributes(Function &F,
55 bool AllowExperimental) {
56 AttributeList Attrs = F.getAttributes();
57 const StringSet<> LiveKeys = {"waveops-include-helper-lanes",
58 "fp32-denorm-mode"};
59 // Collect DeadKeys in FnAttrs.
60 AttributeMask DeadAttrs;
61 collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys,
62 AllowExperimental);
63 collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys,
64 AllowExperimental);
65
66 F.removeFnAttrs(DeadAttrs);
67 F.removeRetAttrs(DeadAttrs);
68}
69
70class DXILPrepareModule : public ModulePass {
71
72 static Value *maybeGenerateBitcast(IRBuilder<> &Builder,
73 PointerTypeMap &PointerTypes,
74 Instruction &Inst, Value *Operand,
75 Type *Ty) {
76 // Omit bitcasts if the incoming value matches the instruction type.
77 auto It = PointerTypes.find(Operand);
78 if (It != PointerTypes.end()) {
79 auto *OpTy = cast<TypedPointerType>(It->second)->getElementType();
80 if (OpTy == Ty)
81 return nullptr;
82 }
83
84 Type *ValTy = Operand->getType();
85 // Also omit the bitcast for matching global array types
86 if (auto *GlobalVar = dyn_cast<GlobalVariable>(Operand))
87 ValTy = GlobalVar->getValueType();
88
89 if (auto *AI = dyn_cast<AllocaInst>(Operand))
90 ValTy = AI->getAllocatedType();
91
92 if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
93 Type *ElTy = ArrTy->getElementType();
94 if (ElTy == Ty)
95 return nullptr;
96 }
97
98 // finally, drill down GEP instructions until we get the array
99 // that is being accessed, and compare element types
100 if (ConstantExpr *GEPInstr = dyn_cast<ConstantExpr>(Operand)) {
101 while (GEPInstr->getOpcode() == Instruction::GetElementPtr) {
102 Value *OpArg = GEPInstr->getOperand(0);
103 if (ConstantExpr *NewGEPInstr = dyn_cast<ConstantExpr>(OpArg)) {
104 GEPInstr = NewGEPInstr;
105 continue;
106 }
107
108 if (auto *GlobalVar = dyn_cast<GlobalVariable>(OpArg))
109 ValTy = GlobalVar->getValueType();
110 if (auto *AI = dyn_cast<AllocaInst>(Operand))
111 ValTy = AI->getAllocatedType();
112 if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
113 Type *ElTy = ArrTy->getElementType();
114 if (ElTy == Ty)
115 return nullptr;
116 }
117 break;
118 }
119 }
120
121 // Insert bitcasts where we are removing the instruction.
122 Builder.SetInsertPoint(&Inst);
123 // This code only gets hit in opaque-pointer mode, so the type of the
124 // pointer doesn't matter.
125 PointerType *PtrTy = cast<PointerType>(Operand->getType());
126 return Builder.Insert(
127 CastInst::Create(Instruction::BitCast, Operand,
128 Builder.getPtrTy(PtrTy->getAddressSpace())));
129 }
130
131public:
132 bool runOnModule(Module &M) override {
134 const AttributeMask &AttrMask = getNonDXILAttributeMask();
135
136 const dxil::ModuleMetadataInfo MetadataInfo =
137 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
138 VersionTuple ValVer = MetadataInfo.ValidatorVersion;
139 bool AllowExperimental = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;
140
141 for (auto &F : M.functions()) {
142 F.removeFnAttrs(AttrMask);
143 F.removeRetAttrs(AttrMask);
144 // Only remove string attributes if we are not skipping validation.
145 // This will reserve the experimental attributes when validation version
146 // is 0.0 for experiment mode.
147 removeStringFunctionAttributes(F, AllowExperimental);
148 for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
149 F.removeParamAttrs(Idx, AttrMask);
150
151 for (auto &BB : F) {
152 IRBuilder<> Builder(&BB);
153 for (auto &I : make_early_inc_range(BB)) {
154
155 if (auto *CB = dyn_cast<CallBase>(&I)) {
156 CB->removeFnAttrs(AttrMask);
157 CB->removeRetAttrs(AttrMask);
158 for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
159 CB->removeParamAttrs(Idx, AttrMask);
160 continue;
161 }
162
163 // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
164 // unmodified as it reserves instruction IDs during contruction.
165 if (auto *LI = dyn_cast<LoadInst>(&I)) {
166 if (Value *NoOpBitcast = maybeGenerateBitcast(
167 Builder, PointerTypes, I, LI->getPointerOperand(),
168 LI->getType())) {
169 LI->replaceAllUsesWith(
170 Builder.CreateLoad(LI->getType(), NoOpBitcast));
171 LI->eraseFromParent();
172 }
173 continue;
174 }
175 if (auto *SI = dyn_cast<StoreInst>(&I)) {
176 if (Value *NoOpBitcast = maybeGenerateBitcast(
177 Builder, PointerTypes, I, SI->getPointerOperand(),
178 SI->getValueOperand()->getType())) {
179
180 SI->replaceAllUsesWith(
181 Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
182 SI->eraseFromParent();
183 }
184 continue;
185 }
186 if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
187 if (Value *NoOpBitcast = maybeGenerateBitcast(
188 Builder, PointerTypes, I, GEP->getPointerOperand(),
189 GEP->getSourceElementType()))
190 GEP->setOperand(0, NoOpBitcast);
191 continue;
192 }
193 }
194 }
195 }
196
197 return true;
198 }
199
200 DXILPrepareModule() : ModulePass(ID) {}
201 void getAnalysisUsage(AnalysisUsage &AU) const override {
203
208 }
209 static char ID; // Pass identification.
210};
211char DXILPrepareModule::ID = 0;
212
213} // end anonymous namespace
214
215INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
216 false, false)
218INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
219 false)
220
222 return new DXILPrepareModule();
223}
#define DEBUG_TYPE
Hexagon Common GEP
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file contains some templates that are useful if you are working with the STL at all.
StringSet - A set-like wrapper for the StringMap.
Defines the llvm::VersionTuple class, which represents a version in the form major[....
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
This class stores enough information to efficiently remove some attributes from an existing AttrBuild...
AttributeMask & addAttribute(Attribute::AttrKind Val)
Add an attribute to the mask.
This class holds the attributes for a particular argument, parameter, function, or return value.
Definition Attributes.h:407
static LLVM_ABI CastInst * Create(Instruction::CastOps, Value *S, Type *Ty, const Twine &Name="", InsertPosition InsertBefore=nullptr)
Provides a way to construct any of the CastInst subclasses using an opcode instead of the subclass's ...
A constant value that is initialized with an expression using other constant values.
Definition Constants.h:1310
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:225
iterator end()
Definition DenseMap.h:143
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2868
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
StringSet - A wrapper for StringMap that provides set-like functionality.
Definition StringSet.h:25
bool contains(StringRef key) const
Check if the set contains the given key.
Definition StringSet.h:60
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
Represents a version number in the form major[.minor[.subminor[.build]]].
unsigned getMajor() const
Retrieve the major version number.
std::optional< unsigned > getMinor() const
Retrieve the minor version number, if provided.
Wrapper pass for the legacy pass manager.
Wrapper pass for the legacy pass manager.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
DenseMap< const Value *, Type * > PointerTypeMap
const AttributeMask & getNonDXILAttributeMask()
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
ModulePass * createDXILPrepareModulePass()
Pass to convert modules into DXIL-compatable modules.
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559