LLVM 22.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"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/StringSet.h"
22#include "llvm/CodeGen/Passes.h"
24#include "llvm/IR/IRBuilder.h"
25#include "llvm/IR/Instruction.h"
26#include "llvm/IR/Module.h"
28#include "llvm/Pass.h"
30
31#define DEBUG_TYPE "dxil-prepare"
32
33using namespace llvm;
34using namespace llvm::dxil;
35
36namespace {
37
38constexpr bool isValidForDXIL(Attribute::AttrKind Attr) {
39 return is_contained({Attribute::Alignment,
40 Attribute::AlwaysInline,
41 Attribute::Builtin,
42 Attribute::ByVal,
43 Attribute::InAlloca,
44 Attribute::Cold,
45 Attribute::Convergent,
46 Attribute::InlineHint,
47 Attribute::InReg,
48 Attribute::JumpTable,
49 Attribute::MinSize,
50 Attribute::Naked,
51 Attribute::Nest,
52 Attribute::NoAlias,
53 Attribute::NoBuiltin,
54 Attribute::NoDuplicate,
55 Attribute::NoImplicitFloat,
56 Attribute::NoInline,
57 Attribute::NonLazyBind,
58 Attribute::NonNull,
59 Attribute::Dereferenceable,
60 Attribute::DereferenceableOrNull,
61 Attribute::Memory,
62 Attribute::NoRedZone,
63 Attribute::NoReturn,
64 Attribute::NoUnwind,
65 Attribute::OptimizeForSize,
66 Attribute::OptimizeNone,
67 Attribute::ReadNone,
68 Attribute::ReadOnly,
69 Attribute::Returned,
70 Attribute::ReturnsTwice,
71 Attribute::SExt,
72 Attribute::StackAlignment,
73 Attribute::StackProtect,
74 Attribute::StackProtectReq,
75 Attribute::StackProtectStrong,
76 Attribute::SafeStack,
77 Attribute::StructRet,
78 Attribute::SanitizeAddress,
79 Attribute::SanitizeThread,
80 Attribute::SanitizeMemory,
81 Attribute::UWTable,
82 Attribute::ZExt},
83 Attr);
84}
85
86static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS,
87 const StringSet<> &LiveKeys,
88 bool AllowExperimental) {
89 for (auto &Attr : AS) {
90 if (!Attr.isStringAttribute())
91 continue;
92 StringRef Key = Attr.getKindAsString();
93 if (LiveKeys.contains(Key))
94 continue;
95 if (AllowExperimental && Key.starts_with("exp-"))
96 continue;
97 DeadAttrs.addAttribute(Key);
98 }
99}
100
101static void removeStringFunctionAttributes(Function &F,
102 bool AllowExperimental) {
103 AttributeList Attrs = F.getAttributes();
104 const StringSet<> LiveKeys = {"waveops-include-helper-lanes",
105 "fp32-denorm-mode"};
106 // Collect DeadKeys in FnAttrs.
107 AttributeMask DeadAttrs;
108 collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys,
109 AllowExperimental);
110 collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys,
111 AllowExperimental);
112
113 F.removeFnAttrs(DeadAttrs);
114 F.removeRetAttrs(DeadAttrs);
115}
116
117class DXILPrepareModule : public ModulePass {
118
119 static Value *maybeGenerateBitcast(IRBuilder<> &Builder,
120 PointerTypeMap &PointerTypes,
121 Instruction &Inst, Value *Operand,
122 Type *Ty) {
123 // Omit bitcasts if the incoming value matches the instruction type.
124 auto It = PointerTypes.find(Operand);
125 if (It != PointerTypes.end()) {
126 auto *OpTy = cast<TypedPointerType>(It->second)->getElementType();
127 if (OpTy == Ty)
128 return nullptr;
129 }
130
131 Type *ValTy = Operand->getType();
132 // Also omit the bitcast for matching global array types
133 if (auto *GlobalVar = dyn_cast<GlobalVariable>(Operand))
134 ValTy = GlobalVar->getValueType();
135
136 if (auto *AI = dyn_cast<AllocaInst>(Operand))
137 ValTy = AI->getAllocatedType();
138
139 if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
140 Type *ElTy = ArrTy->getElementType();
141 if (ElTy == Ty)
142 return nullptr;
143 }
144
145 // finally, drill down GEP instructions until we get the array
146 // that is being accessed, and compare element types
147 if (ConstantExpr *GEPInstr = dyn_cast<ConstantExpr>(Operand)) {
148 while (GEPInstr->getOpcode() == Instruction::GetElementPtr) {
149 Value *OpArg = GEPInstr->getOperand(0);
150 if (ConstantExpr *NewGEPInstr = dyn_cast<ConstantExpr>(OpArg)) {
151 GEPInstr = NewGEPInstr;
152 continue;
153 }
154
155 if (auto *GlobalVar = dyn_cast<GlobalVariable>(OpArg))
156 ValTy = GlobalVar->getValueType();
157 if (auto *AI = dyn_cast<AllocaInst>(Operand))
158 ValTy = AI->getAllocatedType();
159 if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {
160 Type *ElTy = ArrTy->getElementType();
161 if (ElTy == Ty)
162 return nullptr;
163 }
164 break;
165 }
166 }
167
168 // Insert bitcasts where we are removing the instruction.
169 Builder.SetInsertPoint(&Inst);
170 // This code only gets hit in opaque-pointer mode, so the type of the
171 // pointer doesn't matter.
172 PointerType *PtrTy = cast<PointerType>(Operand->getType());
173 return Builder.Insert(
174 CastInst::Create(Instruction::BitCast, Operand,
175 Builder.getPtrTy(PtrTy->getAddressSpace())));
176 }
177
178public:
179 bool runOnModule(Module &M) override {
181 AttributeMask AttrMask;
183 I = Attribute::AttrKind(I + 1)) {
184 if (!isValidForDXIL(I))
185 AttrMask.addAttribute(I);
186 }
187
188 const dxil::ModuleMetadataInfo MetadataInfo =
189 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
190 VersionTuple ValVer = MetadataInfo.ValidatorVersion;
191 bool AllowExperimental = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;
192
193 for (auto &F : M.functions()) {
194 F.removeFnAttrs(AttrMask);
195 F.removeRetAttrs(AttrMask);
196 // Only remove string attributes if we are not skipping validation.
197 // This will reserve the experimental attributes when validation version
198 // is 0.0 for experiment mode.
199 removeStringFunctionAttributes(F, AllowExperimental);
200 for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
201 F.removeParamAttrs(Idx, AttrMask);
202
203 for (auto &BB : F) {
204 IRBuilder<> Builder(&BB);
205 for (auto &I : make_early_inc_range(BB)) {
206
207 if (auto *CB = dyn_cast<CallBase>(&I)) {
208 CB->removeFnAttrs(AttrMask);
209 CB->removeRetAttrs(AttrMask);
210 for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
211 CB->removeParamAttrs(Idx, AttrMask);
212 continue;
213 }
214
215 // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
216 // unmodified as it reserves instruction IDs during contruction.
217 if (auto *LI = dyn_cast<LoadInst>(&I)) {
218 if (Value *NoOpBitcast = maybeGenerateBitcast(
219 Builder, PointerTypes, I, LI->getPointerOperand(),
220 LI->getType())) {
221 LI->replaceAllUsesWith(
222 Builder.CreateLoad(LI->getType(), NoOpBitcast));
223 LI->eraseFromParent();
224 }
225 continue;
226 }
227 if (auto *SI = dyn_cast<StoreInst>(&I)) {
228 if (Value *NoOpBitcast = maybeGenerateBitcast(
229 Builder, PointerTypes, I, SI->getPointerOperand(),
230 SI->getValueOperand()->getType())) {
231
232 SI->replaceAllUsesWith(
233 Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
234 SI->eraseFromParent();
235 }
236 continue;
237 }
238 if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {
239 if (Value *NoOpBitcast = maybeGenerateBitcast(
240 Builder, PointerTypes, I, GEP->getPointerOperand(),
241 GEP->getSourceElementType()))
242 GEP->setOperand(0, NoOpBitcast);
243 continue;
244 }
245 }
246 }
247 }
248
249 return true;
250 }
251
252 DXILPrepareModule() : ModulePass(ID) {}
253 void getAnalysisUsage(AnalysisUsage &AU) const override {
255
260 }
261 static char ID; // Pass identification.
262};
263char DXILPrepareModule::ID = 0;
264
265} // end anonymous namespace
266
267INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
268 false, false)
270INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
271 false)
272
274 return new DXILPrepareModule();
275}
#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:55
#define I(x, y, z)
Definition MD5.cpp:58
#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:361
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
Definition Attributes.h:88
@ None
No attributes have been set.
Definition Attributes.h:90
@ EndAttrKinds
Sentinel value useful for loops.
Definition Attributes.h:93
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:1120
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:178
iterator end()
Definition DenseMap.h:81
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2788
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
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
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:45
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:256
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
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:632
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
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1897