LLVM 20.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 pases 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
15#include "DXILShaderFlags.h"
16#include "DirectX.h"
18#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"
32
33#define DEBUG_TYPE "dxil-prepare"
34
35using namespace llvm;
36using namespace llvm::dxil;
37
38namespace {
39
40constexpr bool isValidForDXIL(Attribute::AttrKind Attr) {
41 return is_contained({Attribute::Alignment,
42 Attribute::AlwaysInline,
43 Attribute::Builtin,
44 Attribute::ByVal,
45 Attribute::InAlloca,
46 Attribute::Cold,
47 Attribute::Convergent,
48 Attribute::InlineHint,
49 Attribute::InReg,
50 Attribute::JumpTable,
51 Attribute::MinSize,
52 Attribute::Naked,
53 Attribute::Nest,
54 Attribute::NoAlias,
55 Attribute::NoBuiltin,
56 Attribute::NoCapture,
57 Attribute::NoDuplicate,
58 Attribute::NoImplicitFloat,
59 Attribute::NoInline,
60 Attribute::NonLazyBind,
61 Attribute::NonNull,
62 Attribute::Dereferenceable,
63 Attribute::DereferenceableOrNull,
64 Attribute::Memory,
65 Attribute::NoRedZone,
66 Attribute::NoReturn,
67 Attribute::NoUnwind,
68 Attribute::OptimizeForSize,
69 Attribute::OptimizeNone,
70 Attribute::ReadNone,
71 Attribute::ReadOnly,
72 Attribute::Returned,
73 Attribute::ReturnsTwice,
74 Attribute::SExt,
75 Attribute::StackAlignment,
76 Attribute::StackProtect,
77 Attribute::StackProtectReq,
78 Attribute::StackProtectStrong,
79 Attribute::SafeStack,
80 Attribute::StructRet,
81 Attribute::SanitizeAddress,
82 Attribute::SanitizeThread,
83 Attribute::SanitizeMemory,
84 Attribute::UWTable,
85 Attribute::ZExt},
86 Attr);
87}
88
89static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS,
90 const StringSet<> &LiveKeys,
91 bool AllowExperimental) {
92 for (auto &Attr : AS) {
93 if (!Attr.isStringAttribute())
94 continue;
95 StringRef Key = Attr.getKindAsString();
96 if (LiveKeys.contains(Key))
97 continue;
98 if (AllowExperimental && Key.starts_with("exp-"))
99 continue;
100 DeadAttrs.addAttribute(Key);
101 }
102}
103
104static void removeStringFunctionAttributes(Function &F,
105 bool AllowExperimental) {
106 AttributeList Attrs = F.getAttributes();
107 const StringSet<> LiveKeys = {"waveops-include-helper-lanes",
108 "fp32-denorm-mode"};
109 // Collect DeadKeys in FnAttrs.
110 AttributeMask DeadAttrs;
111 collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys,
112 AllowExperimental);
113 collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys,
114 AllowExperimental);
115
116 F.removeFnAttrs(DeadAttrs);
117 F.removeRetAttrs(DeadAttrs);
118}
119
120static void cleanModuleFlags(Module &M) {
121 NamedMDNode *MDFlags = M.getModuleFlagsMetadata();
122 if (!MDFlags)
123 return;
124
126 M.getModuleFlagsMetadata(FlagEntries);
127 bool Updated = false;
128 for (auto &Flag : FlagEntries) {
129 // llvm 3.7 only supports behavior up to AppendUnique.
130 if (Flag.Behavior <= Module::ModFlagBehavior::AppendUnique)
131 continue;
132 Flag.Behavior = Module::ModFlagBehavior::Warning;
133 Updated = true;
134 }
135
136 if (!Updated)
137 return;
138
139 MDFlags->eraseFromParent();
140
141 for (auto &Flag : FlagEntries)
142 M.addModuleFlag(Flag.Behavior, Flag.Key->getString(), Flag.Val);
143}
144
145class DXILPrepareModule : public ModulePass {
146
147 static Value *maybeGenerateBitcast(IRBuilder<> &Builder,
148 PointerTypeMap &PointerTypes,
149 Instruction &Inst, Value *Operand,
150 Type *Ty) {
151 // Omit bitcasts if the incoming value matches the instruction type.
152 auto It = PointerTypes.find(Operand);
153 if (It != PointerTypes.end())
154 if (cast<TypedPointerType>(It->second)->getElementType() == Ty)
155 return nullptr;
156 // Insert bitcasts where we are removing the instruction.
157 Builder.SetInsertPoint(&Inst);
158 // This code only gets hit in opaque-pointer mode, so the type of the
159 // pointer doesn't matter.
160 PointerType *PtrTy = cast<PointerType>(Operand->getType());
161 return Builder.Insert(
162 CastInst::Create(Instruction::BitCast, Operand,
163 Builder.getPtrTy(PtrTy->getAddressSpace())));
164 }
165
166public:
167 bool runOnModule(Module &M) override {
169 AttributeMask AttrMask;
171 I = Attribute::AttrKind(I + 1)) {
172 if (!isValidForDXIL(I))
173 AttrMask.addAttribute(I);
174 }
175
176 const dxil::ModuleMetadataInfo MetadataInfo =
177 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
178 VersionTuple ValVer = MetadataInfo.ValidatorVersion;
179 bool SkipValidation = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;
180
181 for (auto &F : M.functions()) {
182 F.removeFnAttrs(AttrMask);
183 F.removeRetAttrs(AttrMask);
184 // Only remove string attributes if we are not skipping validation.
185 // This will reserve the experimental attributes when validation version
186 // is 0.0 for experiment mode.
187 removeStringFunctionAttributes(F, SkipValidation);
188 for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
189 F.removeParamAttrs(Idx, AttrMask);
190
191 for (auto &BB : F) {
192 IRBuilder<> Builder(&BB);
193 for (auto &I : make_early_inc_range(BB)) {
194 if (I.getOpcode() == Instruction::FNeg) {
195 Builder.SetInsertPoint(&I);
196 Value *In = I.getOperand(0);
197 Value *Zero = ConstantFP::get(In->getType(), -0.0);
198 I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
199 I.eraseFromParent();
200 continue;
201 }
202
203 // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
204 // unmodified as it reserves instruction IDs during contruction.
205 if (auto LI = dyn_cast<LoadInst>(&I)) {
206 if (Value *NoOpBitcast = maybeGenerateBitcast(
207 Builder, PointerTypes, I, LI->getPointerOperand(),
208 LI->getType())) {
209 LI->replaceAllUsesWith(
210 Builder.CreateLoad(LI->getType(), NoOpBitcast));
211 LI->eraseFromParent();
212 }
213 continue;
214 }
215 if (auto SI = dyn_cast<StoreInst>(&I)) {
216 if (Value *NoOpBitcast = maybeGenerateBitcast(
217 Builder, PointerTypes, I, SI->getPointerOperand(),
218 SI->getValueOperand()->getType())) {
219
220 SI->replaceAllUsesWith(
221 Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
222 SI->eraseFromParent();
223 }
224 continue;
225 }
226 if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {
227 if (Value *NoOpBitcast = maybeGenerateBitcast(
228 Builder, PointerTypes, I, GEP->getPointerOperand(),
229 GEP->getSourceElementType()))
230 GEP->setOperand(0, NoOpBitcast);
231 continue;
232 }
233 if (auto *CB = dyn_cast<CallBase>(&I)) {
234 CB->removeFnAttrs(AttrMask);
235 CB->removeRetAttrs(AttrMask);
236 for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
237 CB->removeParamAttrs(Idx, AttrMask);
238 continue;
239 }
240 }
241 }
242 }
243 // Remove flags not for DXIL.
244 cleanModuleFlags(M);
245 return true;
246 }
247
248 DXILPrepareModule() : ModulePass(ID) {}
249 void getAnalysisUsage(AnalysisUsage &AU) const override {
255 }
256 static char ID; // Pass identification.
257};
258char DXILPrepareModule::ID = 0;
259
260} // end anonymous namespace
261
262INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
263 false, false)
265INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
266 false)
267
269 return new DXILPrepareModule();
270}
#define DEBUG_TYPE
Definition: DXILPrepare.cpp:33
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
bool End
Definition: ELF_riscv.cpp:480
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:55
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:57
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:52
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
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.
AttributeMask & addAttribute(Attribute::AttrKind Val)
Add an attribute to the mask.
Definition: AttributeMask.h:44
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
Definition: Attributes.h:86
@ None
No attributes have been set.
Definition: Attributes.h:88
@ EndAttrKinds
Sentinel value useful for loops.
Definition: Attributes.h:91
static 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 ...
The legacy pass manager's analysis pass to compute DXIL resource information.
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:156
iterator end()
Definition: DenseMap.h:84
Value * CreateFSub(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)
Definition: IRBuilder.h:1583
InstTy * Insert(InstTy *I, const Twine &Name="") const
Insert and return the specified instruction.
Definition: IRBuilder.h:142
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Definition: IRBuilder.h:1813
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Definition: IRBuilder.h:1826
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Definition: IRBuilder.h:566
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition: IRBuilder.h:177
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2697
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:251
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
A tuple of MDNodes.
Definition: Metadata.h:1731
void eraseFromParent()
Drop all references and remove the node from parent module.
Definition: Metadata.cpp:1438
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:98
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
StringSet - A wrapper for StringMap that provides set-like functionality.
Definition: StringSet.h:23
bool contains(StringRef key) const
Check if the set contains the given key.
Definition: StringSet.h:55
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:74
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]]].
Definition: VersionTuple.h:29
unsigned getMajor() const
Retrieve the major version number.
Definition: VersionTuple.h:71
std::optional< unsigned > getMinor() const
Retrieve the minor version number, if provided.
Definition: VersionTuple.h:74
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.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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:657
ModulePass * createDXILPrepareModulePass()
Pass to convert modules into DXIL-compatable modules.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1903