xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/DirectX/DXILPrepare.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
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 
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 
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 
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 
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:
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 
24681ad6265SDimitry Andric   DXILPrepareModule() : ModulePass(ID) {}
247*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 
26281ad6265SDimitry Andric ModulePass *llvm::createDXILPrepareModulePass() {
26381ad6265SDimitry Andric   return new DXILPrepareModule();
26481ad6265SDimitry Andric }
265