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"
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 // An atomic on a float allocation exchanges the bit pattern as an
194 // integer, so the pointer element type does not match the value
195 // type. Typed pointers need a cast to keep the two in agreement.
196 if (auto *RMW = dyn_cast<AtomicRMWInst>(&I)) {
197 if (Value *NoOpBitcast = maybeGenerateBitcast(
198 Builder, PointerTypes, I, RMW->getPointerOperand(),
199 RMW->getValOperand()->getType()))
201 NoOpBitcast);
202 continue;
203 }
204 if (auto *CmpXchg = dyn_cast<AtomicCmpXchgInst>(&I)) {
205 if (Value *NoOpBitcast = maybeGenerateBitcast(
206 Builder, PointerTypes, I, CmpXchg->getPointerOperand(),
207 CmpXchg->getNewValOperand()->getType()))
208 CmpXchg->setOperand(AtomicCmpXchgInst::getPointerOperandIndex(),
209 NoOpBitcast);
210 continue;
211 }
212 }
213 }
214 }
215
216 return true;
217 }
218
219 DXILPrepareModule() : ModulePass(ID) {}
220 void getAnalysisUsage(AnalysisUsage &AU) const override {
222
227 }
228 static char ID; // Pass identification.
229};
230char DXILPrepareModule::ID = 0;
231
232} // end anonymous namespace
233
234INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
235 false, false)
237INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
238 false)
239
241 return new DXILPrepareModule();
242}
#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.
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:410
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
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:767
iterator end()
Definition DenseMap.h:687
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2918
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:68
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: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.
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
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
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:267