LLVM 24.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"
17#include "DirectX.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/StringSet.h"
24#include "llvm/CodeGen/Passes.h"
25#include "llvm/IR/Analysis.h"
27#include "llvm/IR/IRBuilder.h"
28#include "llvm/IR/Instruction.h"
29#include "llvm/IR/Module.h"
30#include "llvm/IR/PassManager.h"
32#include "llvm/Pass.h"
34
35#define DEBUG_TYPE "dxil-prepare"
36
37using namespace llvm;
38using namespace llvm::dxil;
39
40namespace {
41
42static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS,
43 const StringSet<> &LiveKeys,
44 bool AllowExperimental) {
45 for (auto &Attr : AS) {
46 if (!Attr.isStringAttribute())
47 continue;
48 StringRef Key = Attr.getKindAsString();
49 if (LiveKeys.contains(Key))
50 continue;
51 if (AllowExperimental && Key.starts_with("exp-"))
52 continue;
53 DeadAttrs.addAttribute(Key);
54 }
55}
56
57static void removeStringFunctionAttributes(Function &F,
58 bool AllowExperimental) {
59 AttributeList Attrs = F.getAttributes();
60 const StringSet<> LiveKeys = {"waveops-include-helper-lanes",
61 "fp32-denorm-mode"};
62 // Collect DeadKeys in FnAttrs.
63 AttributeMask DeadAttrs;
64 collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys,
65 AllowExperimental);
66 collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys,
67 AllowExperimental);
68
69 F.removeFnAttrs(DeadAttrs);
70 F.removeRetAttrs(DeadAttrs);
71}
72
73class DXILPrepareModuleLegacy : public ModulePass {
74public:
75 DXILPrepareModuleLegacy() : ModulePass(ID) {}
76 void getAnalysisUsage(AnalysisUsage &AU) const override {
78
84 }
85 bool runOnModule(Module &M) override;
86 static char ID; // Pass identification.
87};
88char DXILPrepareModuleLegacy::ID = 0;
89
90} // end anonymous namespace
91
93 PointerTypeMap &PointerTypes,
94 Instruction &Inst, Value *Operand,
95 Type *Ty) {
96 // Omit bitcasts if the incoming value matches the instruction type.
97 auto It = PointerTypes.find(Operand);
98 if (It != PointerTypes.end()) {
99 auto *OpTy = cast<TypedPointerType>(It->second)->getElementType();
100 if (OpTy == Ty)
101 return nullptr;
102 }
103
104 Type *ValTy = Operand->getType();
105 // Also omit the bitcast for matching global array types
106 if (auto *GlobalVar = dyn_cast<GlobalVariable>(Operand))
107 ValTy = GlobalVar->getValueType();
108
109 if (auto *AI = dyn_cast<AllocaInst>(Operand))
110 ValTy = AI->getAllocatedType();
111
112 if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
113 Type *ElTy = ArrTy->getElementType();
114 if (ElTy == Ty)
115 return nullptr;
116 }
117
118 // finally, drill down GEP instructions until we get the array
119 // that is being accessed, and compare element types
120 if (ConstantExpr *GEPInstr = dyn_cast<ConstantExpr>(Operand)) {
121 while (GEPInstr->getOpcode() == Instruction::GetElementPtr) {
122 Value *OpArg = GEPInstr->getOperand(0);
123 if (ConstantExpr *NewGEPInstr = dyn_cast<ConstantExpr>(OpArg)) {
124 GEPInstr = NewGEPInstr;
125 continue;
126 }
127
128 if (auto *GlobalVar = dyn_cast<GlobalVariable>(OpArg))
129 ValTy = GlobalVar->getValueType();
130 if (auto *AI = dyn_cast<AllocaInst>(Operand))
131 ValTy = AI->getAllocatedType();
132 if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
133 Type *ElTy = ArrTy->getElementType();
134 if (ElTy == Ty)
135 return nullptr;
136 }
137 break;
138 }
139 }
140
141 // Insert bitcasts where we are removing the instruction.
142 Builder.SetInsertPoint(&Inst);
143 // This code only gets hit in opaque-pointer mode, so the type of the
144 // pointer doesn't matter.
145 PointerType *PtrTy = cast<PointerType>(Operand->getType());
146 return Builder.Insert(
147 CastInst::Create(Instruction::BitCast, Operand,
148 Builder.getPtrTy(PtrTy->getAddressSpace())));
149}
150
151static bool prepareModule(
152 Module &M,
153 function_ref<dxil::ModuleMetadataInfo &()> GetModuleMetadataInfo) {
155 const AttributeMask &AttrMask = getNonDXILAttributeMask();
156
157 const dxil::ModuleMetadataInfo MetadataInfo = GetModuleMetadataInfo();
158 VersionTuple ValVer = MetadataInfo.ValidatorVersion;
159 bool AllowExperimental = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;
160
161 for (auto &F : M.functions()) {
162 F.removeFnAttrs(AttrMask);
163 F.removeRetAttrs(AttrMask);
164 // Only remove string attributes if we are not skipping validation.
165 // This will reserve the experimental attributes when validation version
166 // is 0.0 for experiment mode.
167 removeStringFunctionAttributes(F, AllowExperimental);
168 for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
169 F.removeParamAttrs(Idx, AttrMask);
170
171 for (auto &BB : F) {
172 IRBuilder<> Builder(&BB);
173 for (auto &I : make_early_inc_range(BB)) {
174
175 if (auto *CB = dyn_cast<CallBase>(&I)) {
176 CB->removeFnAttrs(AttrMask);
177 CB->removeRetAttrs(AttrMask);
178 for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
179 CB->removeParamAttrs(Idx, AttrMask);
180 continue;
181 }
182
183 // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
184 // unmodified as it reserves instruction IDs during contruction.
185 if (auto *LI = dyn_cast<LoadInst>(&I)) {
186 if (Value *NoOpBitcast = maybeGenerateBitcast(
187 Builder, PointerTypes, I, LI->getPointerOperand(),
188 LI->getType())) {
189 LI->replaceAllUsesWith(
190 Builder.CreateLoad(LI->getType(), NoOpBitcast));
191 LI->eraseFromParent();
192 }
193 continue;
194 }
195 if (auto *SI = dyn_cast<StoreInst>(&I)) {
196 if (Value *NoOpBitcast = maybeGenerateBitcast(
197 Builder, PointerTypes, I, SI->getPointerOperand(),
198 SI->getValueOperand()->getType())) {
199
200 SI->replaceAllUsesWith(
201 Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
202 SI->eraseFromParent();
203 }
204 continue;
205 }
206 if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
207 if (Value *NoOpBitcast = maybeGenerateBitcast(
208 Builder, PointerTypes, I, GEP->getPointerOperand(),
209 GEP->getSourceElementType()))
210 GEP->setOperand(0, NoOpBitcast);
211 continue;
212 }
213 // An atomic on a float allocation exchanges the bit pattern as an
214 // integer, so the pointer element type does not match the value
215 // type. Typed pointers need a cast to keep the two in agreement.
216 if (auto *RMW = dyn_cast<AtomicRMWInst>(&I)) {
217 if (Value *NoOpBitcast = maybeGenerateBitcast(
218 Builder, PointerTypes, I, RMW->getPointerOperand(),
219 RMW->getValOperand()->getType()))
221 NoOpBitcast);
222 continue;
223 }
224 if (auto *CmpXchg = dyn_cast<AtomicCmpXchgInst>(&I)) {
225 if (Value *NoOpBitcast = maybeGenerateBitcast(
226 Builder, PointerTypes, I, CmpXchg->getPointerOperand(),
227 CmpXchg->getNewValOperand()->getType()))
228 CmpXchg->setOperand(AtomicCmpXchgInst::getPointerOperandIndex(),
229 NoOpBitcast);
230 continue;
231 }
232 }
233 }
234 }
235
236 return true;
237}
238
239bool DXILPrepareModuleLegacy::runOnModule(Module &M) {
240 return prepareModule(M, [&]() -> dxil::ModuleMetadataInfo & {
241 return getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
242 });
243}
244
247 bool Changed = prepareModule(M, [&]() -> dxil::ModuleMetadataInfo & {
248 return MAM.getResult<DXILMetadataAnalysis>(M);
249 });
250 if (!Changed)
251 return PreservedAnalyses::all();
254 .preserve<DXILResourceAnalysis>()
255 .preserve<RootSignatureAnalysis>()
256 .preserve<SignatureAnalysis>()
257 .preserve<ShaderFlagsAnalysis>();
258}
259
260INITIALIZE_PASS_BEGIN(DXILPrepareModuleLegacy, DEBUG_TYPE,
261 "DXIL Prepare Module", false, false)
263INITIALIZE_PASS_END(DXILPrepareModuleLegacy, DEBUG_TYPE, "DXIL Prepare Module",
265
267 return new DXILPrepareModuleLegacy();
268}
static bool prepareModule(Module &M, function_ref< dxil::ModuleMetadataInfo &()> GetModuleMetadataInfo)
static Value * maybeGenerateBitcast(IRBuilder<> &Builder, PointerTypeMap &PointerTypes, Instruction &Inst, Value *Operand, Type *Ty)
#define DEBUG_TYPE
Hexagon Common GEP
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
ModuleAnalysisManager MAM
#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.
static unsigned getPointerOperandIndex()
static unsigned getPointerOperandIndex()
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:406
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:1316
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:766
iterator end()
Definition DenseMap.h:686
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2949
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:253
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
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:27
bool contains(StringRef key) const
Check if the set contains the given key.
Definition StringSet.h:62
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:257
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.
An efficient, type-erasing, non-owning reference to a callable.
Pass manager infrastructure for declaring and invalidating analyses.
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:649
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
ModulePass * createDXILPrepareModuleLegacyPass()
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:320
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39