181ad6265SDimitry Andric //===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric ///
981ad6265SDimitry Andric /// \file This file contains pases and utilities to convert a modern LLVM
1081ad6265SDimitry Andric /// module into a module compatible with the LLVM 3.7-based DirectX Intermediate
1181ad6265SDimitry Andric /// Language (DXIL).
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric
14*0fca6ea1SDimitry Andric #include "DXILMetadata.h"
15*0fca6ea1SDimitry Andric #include "DXILResourceAnalysis.h"
16*0fca6ea1SDimitry Andric #include "DXILShaderFlags.h"
1781ad6265SDimitry Andric #include "DirectX.h"
18bdd1243dSDimitry Andric #include "DirectXIRPasses/PointerTypeAnalysis.h"
1981ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
2081ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
21*0fca6ea1SDimitry Andric #include "llvm/ADT/StringSet.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
2306c3fb27SDimitry Andric #include "llvm/IR/AttributeMask.h"
2481ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h"
2581ad6265SDimitry Andric #include "llvm/IR/Instruction.h"
2681ad6265SDimitry Andric #include "llvm/IR/Module.h"
2781ad6265SDimitry Andric #include "llvm/InitializePasses.h"
2881ad6265SDimitry Andric #include "llvm/Pass.h"
2981ad6265SDimitry Andric #include "llvm/Support/Compiler.h"
30*0fca6ea1SDimitry Andric #include "llvm/Support/VersionTuple.h"
3181ad6265SDimitry Andric
3281ad6265SDimitry Andric #define DEBUG_TYPE "dxil-prepare"
3381ad6265SDimitry Andric
3481ad6265SDimitry Andric using namespace llvm;
3581ad6265SDimitry Andric using namespace llvm::dxil;
3681ad6265SDimitry Andric
3781ad6265SDimitry Andric namespace {
3881ad6265SDimitry Andric
isValidForDXIL(Attribute::AttrKind Attr)3981ad6265SDimitry Andric constexpr bool isValidForDXIL(Attribute::AttrKind Attr) {
4081ad6265SDimitry Andric return is_contained({Attribute::Alignment,
4181ad6265SDimitry Andric Attribute::AlwaysInline,
4281ad6265SDimitry Andric Attribute::Builtin,
4381ad6265SDimitry Andric Attribute::ByVal,
4481ad6265SDimitry Andric Attribute::InAlloca,
4581ad6265SDimitry Andric Attribute::Cold,
4681ad6265SDimitry Andric Attribute::Convergent,
4781ad6265SDimitry Andric Attribute::InlineHint,
4881ad6265SDimitry Andric Attribute::InReg,
4981ad6265SDimitry Andric Attribute::JumpTable,
5081ad6265SDimitry Andric Attribute::MinSize,
5181ad6265SDimitry Andric Attribute::Naked,
5281ad6265SDimitry Andric Attribute::Nest,
5381ad6265SDimitry Andric Attribute::NoAlias,
5481ad6265SDimitry Andric Attribute::NoBuiltin,
5581ad6265SDimitry Andric Attribute::NoCapture,
5681ad6265SDimitry Andric Attribute::NoDuplicate,
5781ad6265SDimitry Andric Attribute::NoImplicitFloat,
5881ad6265SDimitry Andric Attribute::NoInline,
5981ad6265SDimitry Andric Attribute::NonLazyBind,
6081ad6265SDimitry Andric Attribute::NonNull,
6181ad6265SDimitry Andric Attribute::Dereferenceable,
6281ad6265SDimitry Andric Attribute::DereferenceableOrNull,
63bdd1243dSDimitry Andric Attribute::Memory,
6481ad6265SDimitry Andric Attribute::NoRedZone,
6581ad6265SDimitry Andric Attribute::NoReturn,
6681ad6265SDimitry Andric Attribute::NoUnwind,
6781ad6265SDimitry Andric Attribute::OptimizeForSize,
6881ad6265SDimitry Andric Attribute::OptimizeNone,
6981ad6265SDimitry Andric Attribute::ReadNone,
7081ad6265SDimitry Andric Attribute::ReadOnly,
7181ad6265SDimitry Andric Attribute::Returned,
7281ad6265SDimitry Andric Attribute::ReturnsTwice,
7381ad6265SDimitry Andric Attribute::SExt,
7481ad6265SDimitry Andric Attribute::StackAlignment,
7581ad6265SDimitry Andric Attribute::StackProtect,
7681ad6265SDimitry Andric Attribute::StackProtectReq,
7781ad6265SDimitry Andric Attribute::StackProtectStrong,
7881ad6265SDimitry Andric Attribute::SafeStack,
7981ad6265SDimitry Andric Attribute::StructRet,
8081ad6265SDimitry Andric Attribute::SanitizeAddress,
8181ad6265SDimitry Andric Attribute::SanitizeThread,
8281ad6265SDimitry Andric Attribute::SanitizeMemory,
8381ad6265SDimitry Andric Attribute::UWTable,
8481ad6265SDimitry Andric Attribute::ZExt},
8581ad6265SDimitry Andric Attr);
8681ad6265SDimitry Andric }
8781ad6265SDimitry Andric
collectDeadStringAttrs(AttributeMask & DeadAttrs,AttributeSet && AS,const StringSet<> & LiveKeys,bool AllowExperimental)88*0fca6ea1SDimitry Andric static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS,
89*0fca6ea1SDimitry Andric const StringSet<> &LiveKeys,
90*0fca6ea1SDimitry Andric bool AllowExperimental) {
91*0fca6ea1SDimitry Andric for (auto &Attr : AS) {
92*0fca6ea1SDimitry Andric if (!Attr.isStringAttribute())
93*0fca6ea1SDimitry Andric continue;
94*0fca6ea1SDimitry Andric StringRef Key = Attr.getKindAsString();
95*0fca6ea1SDimitry Andric if (LiveKeys.contains(Key))
96*0fca6ea1SDimitry Andric continue;
97*0fca6ea1SDimitry Andric if (AllowExperimental && Key.starts_with("exp-"))
98*0fca6ea1SDimitry Andric continue;
99*0fca6ea1SDimitry Andric DeadAttrs.addAttribute(Key);
100*0fca6ea1SDimitry Andric }
101*0fca6ea1SDimitry Andric }
102*0fca6ea1SDimitry Andric
removeStringFunctionAttributes(Function & F,bool AllowExperimental)103*0fca6ea1SDimitry Andric static void removeStringFunctionAttributes(Function &F,
104*0fca6ea1SDimitry Andric bool AllowExperimental) {
105*0fca6ea1SDimitry Andric AttributeList Attrs = F.getAttributes();
106*0fca6ea1SDimitry Andric const StringSet<> LiveKeys = {"waveops-include-helper-lanes",
107*0fca6ea1SDimitry Andric "fp32-denorm-mode"};
108*0fca6ea1SDimitry Andric // Collect DeadKeys in FnAttrs.
109*0fca6ea1SDimitry Andric AttributeMask DeadAttrs;
110*0fca6ea1SDimitry Andric collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys,
111*0fca6ea1SDimitry Andric AllowExperimental);
112*0fca6ea1SDimitry Andric collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys,
113*0fca6ea1SDimitry Andric AllowExperimental);
114*0fca6ea1SDimitry Andric
115*0fca6ea1SDimitry Andric F.removeFnAttrs(DeadAttrs);
116*0fca6ea1SDimitry Andric F.removeRetAttrs(DeadAttrs);
117*0fca6ea1SDimitry Andric }
118*0fca6ea1SDimitry Andric
cleanModuleFlags(Module & M)119*0fca6ea1SDimitry Andric static void cleanModuleFlags(Module &M) {
120*0fca6ea1SDimitry Andric NamedMDNode *MDFlags = M.getModuleFlagsMetadata();
121*0fca6ea1SDimitry Andric if (!MDFlags)
122*0fca6ea1SDimitry Andric return;
123*0fca6ea1SDimitry Andric
124*0fca6ea1SDimitry Andric SmallVector<llvm::Module::ModuleFlagEntry> FlagEntries;
125*0fca6ea1SDimitry Andric M.getModuleFlagsMetadata(FlagEntries);
126*0fca6ea1SDimitry Andric bool Updated = false;
127*0fca6ea1SDimitry Andric for (auto &Flag : FlagEntries) {
128*0fca6ea1SDimitry Andric // llvm 3.7 only supports behavior up to AppendUnique.
129*0fca6ea1SDimitry Andric if (Flag.Behavior <= Module::ModFlagBehavior::AppendUnique)
130*0fca6ea1SDimitry Andric continue;
131*0fca6ea1SDimitry Andric Flag.Behavior = Module::ModFlagBehavior::Warning;
132*0fca6ea1SDimitry Andric Updated = true;
133*0fca6ea1SDimitry Andric }
134*0fca6ea1SDimitry Andric
135*0fca6ea1SDimitry Andric if (!Updated)
136*0fca6ea1SDimitry Andric return;
137*0fca6ea1SDimitry Andric
138*0fca6ea1SDimitry Andric MDFlags->eraseFromParent();
139*0fca6ea1SDimitry Andric
140*0fca6ea1SDimitry Andric for (auto &Flag : FlagEntries)
141*0fca6ea1SDimitry Andric M.addModuleFlag(Flag.Behavior, Flag.Key->getString(), Flag.Val);
142*0fca6ea1SDimitry Andric }
143*0fca6ea1SDimitry Andric
14481ad6265SDimitry Andric class DXILPrepareModule : public ModulePass {
14581ad6265SDimitry Andric
maybeGenerateBitcast(IRBuilder<> & Builder,PointerTypeMap & PointerTypes,Instruction & Inst,Value * Operand,Type * Ty)14681ad6265SDimitry Andric static Value *maybeGenerateBitcast(IRBuilder<> &Builder,
14781ad6265SDimitry Andric PointerTypeMap &PointerTypes,
14881ad6265SDimitry Andric Instruction &Inst, Value *Operand,
14981ad6265SDimitry Andric Type *Ty) {
15081ad6265SDimitry Andric // Omit bitcasts if the incoming value matches the instruction type.
15181ad6265SDimitry Andric auto It = PointerTypes.find(Operand);
15281ad6265SDimitry Andric if (It != PointerTypes.end())
15381ad6265SDimitry Andric if (cast<TypedPointerType>(It->second)->getElementType() == Ty)
15481ad6265SDimitry Andric return nullptr;
15581ad6265SDimitry Andric // Insert bitcasts where we are removing the instruction.
15681ad6265SDimitry Andric Builder.SetInsertPoint(&Inst);
15781ad6265SDimitry Andric // This code only gets hit in opaque-pointer mode, so the type of the
15881ad6265SDimitry Andric // pointer doesn't matter.
15981ad6265SDimitry Andric PointerType *PtrTy = cast<PointerType>(Operand->getType());
16081ad6265SDimitry Andric return Builder.Insert(
16181ad6265SDimitry Andric CastInst::Create(Instruction::BitCast, Operand,
1625f757f3fSDimitry Andric Builder.getPtrTy(PtrTy->getAddressSpace())));
16381ad6265SDimitry Andric }
16481ad6265SDimitry Andric
16581ad6265SDimitry Andric public:
runOnModule(Module & M)16681ad6265SDimitry Andric bool runOnModule(Module &M) override {
16781ad6265SDimitry Andric PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M);
16881ad6265SDimitry Andric AttributeMask AttrMask;
16981ad6265SDimitry Andric for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;
17081ad6265SDimitry Andric I = Attribute::AttrKind(I + 1)) {
17181ad6265SDimitry Andric if (!isValidForDXIL(I))
17281ad6265SDimitry Andric AttrMask.addAttribute(I);
17381ad6265SDimitry Andric }
174*0fca6ea1SDimitry Andric
175*0fca6ea1SDimitry Andric dxil::ValidatorVersionMD ValVerMD(M);
176*0fca6ea1SDimitry Andric VersionTuple ValVer = ValVerMD.getAsVersionTuple();
177*0fca6ea1SDimitry Andric bool SkipValidation = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;
178*0fca6ea1SDimitry Andric
17981ad6265SDimitry Andric for (auto &F : M.functions()) {
18081ad6265SDimitry Andric F.removeFnAttrs(AttrMask);
18181ad6265SDimitry Andric F.removeRetAttrs(AttrMask);
182*0fca6ea1SDimitry Andric // Only remove string attributes if we are not skipping validation.
183*0fca6ea1SDimitry Andric // This will reserve the experimental attributes when validation version
184*0fca6ea1SDimitry Andric // is 0.0 for experiment mode.
185*0fca6ea1SDimitry Andric removeStringFunctionAttributes(F, SkipValidation);
18681ad6265SDimitry Andric for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
18781ad6265SDimitry Andric F.removeParamAttrs(Idx, AttrMask);
18881ad6265SDimitry Andric
18981ad6265SDimitry Andric for (auto &BB : F) {
19081ad6265SDimitry Andric IRBuilder<> Builder(&BB);
19181ad6265SDimitry Andric for (auto &I : make_early_inc_range(BB)) {
19281ad6265SDimitry Andric if (I.getOpcode() == Instruction::FNeg) {
19381ad6265SDimitry Andric Builder.SetInsertPoint(&I);
19481ad6265SDimitry Andric Value *In = I.getOperand(0);
19581ad6265SDimitry Andric Value *Zero = ConstantFP::get(In->getType(), -0.0);
19681ad6265SDimitry Andric I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
19781ad6265SDimitry Andric I.eraseFromParent();
19881ad6265SDimitry Andric continue;
19981ad6265SDimitry Andric }
20081ad6265SDimitry Andric
20181ad6265SDimitry Andric // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
20281ad6265SDimitry Andric // unmodified as it reserves instruction IDs during contruction.
20381ad6265SDimitry Andric if (auto LI = dyn_cast<LoadInst>(&I)) {
20481ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast(
20581ad6265SDimitry Andric Builder, PointerTypes, I, LI->getPointerOperand(),
20681ad6265SDimitry Andric LI->getType())) {
20781ad6265SDimitry Andric LI->replaceAllUsesWith(
20881ad6265SDimitry Andric Builder.CreateLoad(LI->getType(), NoOpBitcast));
20981ad6265SDimitry Andric LI->eraseFromParent();
21081ad6265SDimitry Andric }
21181ad6265SDimitry Andric continue;
21281ad6265SDimitry Andric }
21381ad6265SDimitry Andric if (auto SI = dyn_cast<StoreInst>(&I)) {
21481ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast(
21581ad6265SDimitry Andric Builder, PointerTypes, I, SI->getPointerOperand(),
21681ad6265SDimitry Andric SI->getValueOperand()->getType())) {
21781ad6265SDimitry Andric
21881ad6265SDimitry Andric SI->replaceAllUsesWith(
21981ad6265SDimitry Andric Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
22081ad6265SDimitry Andric SI->eraseFromParent();
22181ad6265SDimitry Andric }
22281ad6265SDimitry Andric continue;
22381ad6265SDimitry Andric }
22481ad6265SDimitry Andric if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {
22581ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast(
22681ad6265SDimitry Andric Builder, PointerTypes, I, GEP->getPointerOperand(),
2275f757f3fSDimitry Andric GEP->getSourceElementType()))
22881ad6265SDimitry Andric GEP->setOperand(0, NoOpBitcast);
22981ad6265SDimitry Andric continue;
23081ad6265SDimitry Andric }
231bdd1243dSDimitry Andric if (auto *CB = dyn_cast<CallBase>(&I)) {
232bdd1243dSDimitry Andric CB->removeFnAttrs(AttrMask);
233bdd1243dSDimitry Andric CB->removeRetAttrs(AttrMask);
234bdd1243dSDimitry Andric for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
235bdd1243dSDimitry Andric CB->removeParamAttrs(Idx, AttrMask);
236bdd1243dSDimitry Andric continue;
237bdd1243dSDimitry Andric }
23881ad6265SDimitry Andric }
23981ad6265SDimitry Andric }
24081ad6265SDimitry Andric }
241*0fca6ea1SDimitry Andric // Remove flags not for DXIL.
242*0fca6ea1SDimitry Andric cleanModuleFlags(M);
24381ad6265SDimitry Andric return true;
24481ad6265SDimitry Andric }
24581ad6265SDimitry Andric
DXILPrepareModule()24681ad6265SDimitry Andric DXILPrepareModule() : ModulePass(ID) {}
getAnalysisUsage(AnalysisUsage & AU) const247*0fca6ea1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
248*0fca6ea1SDimitry Andric AU.addPreserved<ShaderFlagsAnalysisWrapper>();
249*0fca6ea1SDimitry Andric AU.addPreserved<DXILResourceWrapper>();
250*0fca6ea1SDimitry Andric }
25181ad6265SDimitry Andric static char ID; // Pass identification.
25281ad6265SDimitry Andric };
25381ad6265SDimitry Andric char DXILPrepareModule::ID = 0;
25481ad6265SDimitry Andric
25581ad6265SDimitry Andric } // end anonymous namespace
25681ad6265SDimitry Andric
25781ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
25881ad6265SDimitry Andric false, false)
25981ad6265SDimitry Andric INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
26081ad6265SDimitry Andric false)
26181ad6265SDimitry Andric
createDXILPrepareModulePass()26281ad6265SDimitry Andric ModulePass *llvm::createDXILPrepareModulePass() {
26381ad6265SDimitry Andric return new DXILPrepareModule();
26481ad6265SDimitry Andric }
265