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"
26#include "llvm/IR/IRBuilder.h"
27#include "llvm/IR/Instruction.h"
28#include "llvm/IR/Module.h"
30#include "llvm/Pass.h"
32
33#define DEBUG_TYPE "dxil-prepare"
34
35using namespace llvm;
36using namespace llvm::dxil;
37
38namespace {
39
40static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS,
41 const StringSet<> &LiveKeys,
42 bool AllowExperimental) {
43 for (auto &Attr : AS) {
44 if (!Attr.isStringAttribute())
45 continue;
46 StringRef Key = Attr.getKindAsString();
47 if (LiveKeys.contains(Key))
48 continue;
49 if (AllowExperimental && Key.starts_with("exp-"))
50 continue;
51 DeadAttrs.addAttribute(Key);
52 }
53}
54
55static void removeStringFunctionAttributes(Function &F,
56 bool AllowExperimental) {
57 AttributeList Attrs = F.getAttributes();
58 const StringSet<> LiveKeys = {"waveops-include-helper-lanes",
59 "fp32-denorm-mode"};
60 // Collect DeadKeys in FnAttrs.
61 AttributeMask DeadAttrs;
62 collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys,
63 AllowExperimental);
64 collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys,
65 AllowExperimental);
66
67 F.removeFnAttrs(DeadAttrs);
68 F.removeRetAttrs(DeadAttrs);
69}
70
71class DXILPrepareModule : public ModulePass {
72
73 static Value *maybeGenerateBitcast(IRBuilder<> &Builder,
74 PointerTypeMap &PointerTypes,
75 Instruction &Inst, Value *Operand,
76 Type *Ty) {
77 // Omit bitcasts if the incoming value matches the instruction type.
78 auto It = PointerTypes.find(Operand);
79 if (It != PointerTypes.end()) {
80 auto *OpTy = cast<TypedPointerType>(It->second)->getElementType();
81 if (OpTy == Ty)
82 return nullptr;
83 }
84
85 Type *ValTy = Operand->getType();
86 // Also omit the bitcast for matching global array types
87 if (auto *GlobalVar = dyn_cast<GlobalVariable>(Operand))
88 ValTy = GlobalVar->getValueType();
89
90 if (auto *AI = dyn_cast<AllocaInst>(Operand))
91 ValTy = AI->getAllocatedType();
92
93 if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
94 Type *ElTy = ArrTy->getElementType();
95 if (ElTy == Ty)
96 return nullptr;
97 }
98
99 // finally, drill down GEP instructions until we get the array
100 // that is being accessed, and compare element types
101 if (ConstantExpr *GEPInstr = dyn_cast<ConstantExpr>(Operand)) {
102 while (GEPInstr->getOpcode() == Instruction::GetElementPtr) {
103 Value *OpArg = GEPInstr->getOperand(0);
104 if (ConstantExpr *NewGEPInstr = dyn_cast<ConstantExpr>(OpArg)) {
105 GEPInstr = NewGEPInstr;
106 continue;
107 }
108
109 if (auto *GlobalVar = dyn_cast<GlobalVariable>(OpArg))
110 ValTy = GlobalVar->getValueType();
111 if (auto *AI = dyn_cast<AllocaInst>(Operand))
112 ValTy = AI->getAllocatedType();
113 if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
114 Type *ElTy = ArrTy->getElementType();
115 if (ElTy == Ty)
116 return nullptr;
117 }
118 break;
119 }
120 }
121
122 // Insert bitcasts where we are removing the instruction.
123 Builder.SetInsertPoint(&Inst);
124 // This code only gets hit in opaque-pointer mode, so the type of the
125 // pointer doesn't matter.
126 PointerType *PtrTy = cast<PointerType>(Operand->getType());
127 return Builder.Insert(
128 CastInst::Create(Instruction::BitCast, Operand,
129 Builder.getPtrTy(PtrTy->getAddressSpace())));
130 }
131
132public:
133 bool runOnModule(Module &M) override {
135 const AttributeMask &AttrMask = getNonDXILAttributeMask();
136
137 const dxil::ModuleMetadataInfo MetadataInfo =
138 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
139 VersionTuple ValVer = MetadataInfo.ValidatorVersion;
140 bool AllowExperimental = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;
141
142 for (auto &F : M.functions()) {
143 F.removeFnAttrs(AttrMask);
144 F.removeRetAttrs(AttrMask);
145 // Only remove string attributes if we are not skipping validation.
146 // This will reserve the experimental attributes when validation version
147 // is 0.0 for experiment mode.
148 removeStringFunctionAttributes(F, AllowExperimental);
149 for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
150 F.removeParamAttrs(Idx, AttrMask);
151
152 for (auto &BB : F) {
153 IRBuilder<> Builder(&BB);
154 for (auto &I : make_early_inc_range(BB)) {
155
156 if (auto *CB = dyn_cast<CallBase>(&I)) {
157 CB->removeFnAttrs(AttrMask);
158 CB->removeRetAttrs(AttrMask);
159 for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
160 CB->removeParamAttrs(Idx, AttrMask);
161 continue;
162 }
163
164 // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
165 // unmodified as it reserves instruction IDs during contruction.
166 if (auto *LI = dyn_cast<LoadInst>(&I)) {
167 if (Value *NoOpBitcast = maybeGenerateBitcast(
168 Builder, PointerTypes, I, LI->getPointerOperand(),
169 LI->getType())) {
170 LI->replaceAllUsesWith(
171 Builder.CreateLoad(LI->getType(), NoOpBitcast));
172 LI->eraseFromParent();
173 }
174 continue;
175 }
176 if (auto *SI = dyn_cast<StoreInst>(&I)) {
177 if (Value *NoOpBitcast = maybeGenerateBitcast(
178 Builder, PointerTypes, I, SI->getPointerOperand(),
179 SI->getValueOperand()->getType())) {
180
181 SI->replaceAllUsesWith(
182 Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
183 SI->eraseFromParent();
184 }
185 continue;
186 }
187 if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
188 if (Value *NoOpBitcast = maybeGenerateBitcast(
189 Builder, PointerTypes, I, GEP->getPointerOperand(),
190 GEP->getSourceElementType()))
191 GEP->setOperand(0, NoOpBitcast);
192 continue;
193 }
194 // An atomic on a float allocation exchanges the bit pattern as an
195 // integer, so the pointer element type does not match the value
196 // type. Typed pointers need a cast to keep the two in agreement.
197 if (auto *RMW = dyn_cast<AtomicRMWInst>(&I)) {
198 if (Value *NoOpBitcast = maybeGenerateBitcast(
199 Builder, PointerTypes, I, RMW->getPointerOperand(),
200 RMW->getValOperand()->getType()))
202 NoOpBitcast);
203 continue;
204 }
205 if (auto *CmpXchg = dyn_cast<AtomicCmpXchgInst>(&I)) {
206 if (Value *NoOpBitcast = maybeGenerateBitcast(
207 Builder, PointerTypes, I, CmpXchg->getPointerOperand(),
208 CmpXchg->getNewValOperand()->getType()))
209 CmpXchg->setOperand(AtomicCmpXchgInst::getPointerOperandIndex(),
210 NoOpBitcast);
211 continue;
212 }
213 }
214 }
215 }
216
217 return true;
218 }
219
220 DXILPrepareModule() : ModulePass(ID) {}
221 void getAnalysisUsage(AnalysisUsage &AU) const override {
223
229 }
230 static char ID; // Pass identification.
231};
232char DXILPrepareModule::ID = 0;
233
234} // end anonymous namespace
235
236INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
237 false, false)
239INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
240 false)
241
243 return new DXILPrepareModule();
244}
#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: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
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:2909
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
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