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 14 #include "DXILResourceAnalysis.h" 15 #include "DXILShaderFlags.h" 16 #include "DirectX.h" 17 #include "DirectXIRPasses/PointerTypeAnalysis.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/SmallVector.h" 20 #include "llvm/ADT/StringSet.h" 21 #include "llvm/Analysis/DXILMetadataAnalysis.h" 22 #include "llvm/Analysis/DXILResource.h" 23 #include "llvm/CodeGen/Passes.h" 24 #include "llvm/IR/AttributeMask.h" 25 #include "llvm/IR/IRBuilder.h" 26 #include "llvm/IR/Instruction.h" 27 #include "llvm/IR/Module.h" 28 #include "llvm/InitializePasses.h" 29 #include "llvm/Pass.h" 30 #include "llvm/Support/Compiler.h" 31 #include "llvm/Support/VersionTuple.h" 32 33 #define DEBUG_TYPE "dxil-prepare" 34 35 using namespace llvm; 36 using namespace llvm::dxil; 37 38 namespace { 39 40 constexpr 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::NoDuplicate, 57 Attribute::NoImplicitFloat, 58 Attribute::NoInline, 59 Attribute::NonLazyBind, 60 Attribute::NonNull, 61 Attribute::Dereferenceable, 62 Attribute::DereferenceableOrNull, 63 Attribute::Memory, 64 Attribute::NoRedZone, 65 Attribute::NoReturn, 66 Attribute::NoUnwind, 67 Attribute::OptimizeForSize, 68 Attribute::OptimizeNone, 69 Attribute::ReadNone, 70 Attribute::ReadOnly, 71 Attribute::Returned, 72 Attribute::ReturnsTwice, 73 Attribute::SExt, 74 Attribute::StackAlignment, 75 Attribute::StackProtect, 76 Attribute::StackProtectReq, 77 Attribute::StackProtectStrong, 78 Attribute::SafeStack, 79 Attribute::StructRet, 80 Attribute::SanitizeAddress, 81 Attribute::SanitizeThread, 82 Attribute::SanitizeMemory, 83 Attribute::UWTable, 84 Attribute::ZExt}, 85 Attr); 86 } 87 88 static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS, 89 const StringSet<> &LiveKeys, 90 bool AllowExperimental) { 91 for (auto &Attr : AS) { 92 if (!Attr.isStringAttribute()) 93 continue; 94 StringRef Key = Attr.getKindAsString(); 95 if (LiveKeys.contains(Key)) 96 continue; 97 if (AllowExperimental && Key.starts_with("exp-")) 98 continue; 99 DeadAttrs.addAttribute(Key); 100 } 101 } 102 103 static void removeStringFunctionAttributes(Function &F, 104 bool AllowExperimental) { 105 AttributeList Attrs = F.getAttributes(); 106 const StringSet<> LiveKeys = {"waveops-include-helper-lanes", 107 "fp32-denorm-mode"}; 108 // Collect DeadKeys in FnAttrs. 109 AttributeMask DeadAttrs; 110 collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys, 111 AllowExperimental); 112 collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys, 113 AllowExperimental); 114 115 F.removeFnAttrs(DeadAttrs); 116 F.removeRetAttrs(DeadAttrs); 117 } 118 119 static void cleanModuleFlags(Module &M) { 120 NamedMDNode *MDFlags = M.getModuleFlagsMetadata(); 121 if (!MDFlags) 122 return; 123 124 SmallVector<llvm::Module::ModuleFlagEntry> FlagEntries; 125 M.getModuleFlagsMetadata(FlagEntries); 126 bool Updated = false; 127 for (auto &Flag : FlagEntries) { 128 // llvm 3.7 only supports behavior up to AppendUnique. 129 if (Flag.Behavior <= Module::ModFlagBehavior::AppendUnique) 130 continue; 131 Flag.Behavior = Module::ModFlagBehavior::Warning; 132 Updated = true; 133 } 134 135 if (!Updated) 136 return; 137 138 MDFlags->eraseFromParent(); 139 140 for (auto &Flag : FlagEntries) 141 M.addModuleFlag(Flag.Behavior, Flag.Key->getString(), Flag.Val); 142 } 143 144 class DXILPrepareModule : public ModulePass { 145 146 static Value *maybeGenerateBitcast(IRBuilder<> &Builder, 147 PointerTypeMap &PointerTypes, 148 Instruction &Inst, Value *Operand, 149 Type *Ty) { 150 // Omit bitcasts if the incoming value matches the instruction type. 151 auto It = PointerTypes.find(Operand); 152 if (It != PointerTypes.end()) 153 if (cast<TypedPointerType>(It->second)->getElementType() == Ty) 154 return nullptr; 155 // Insert bitcasts where we are removing the instruction. 156 Builder.SetInsertPoint(&Inst); 157 // This code only gets hit in opaque-pointer mode, so the type of the 158 // pointer doesn't matter. 159 PointerType *PtrTy = cast<PointerType>(Operand->getType()); 160 return Builder.Insert( 161 CastInst::Create(Instruction::BitCast, Operand, 162 Builder.getPtrTy(PtrTy->getAddressSpace()))); 163 } 164 165 public: 166 bool runOnModule(Module &M) override { 167 PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M); 168 AttributeMask AttrMask; 169 for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; 170 I = Attribute::AttrKind(I + 1)) { 171 if (!isValidForDXIL(I)) 172 AttrMask.addAttribute(I); 173 } 174 175 const dxil::ModuleMetadataInfo MetadataInfo = 176 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata(); 177 VersionTuple ValVer = MetadataInfo.ValidatorVersion; 178 bool SkipValidation = ValVer.getMajor() == 0 && ValVer.getMinor() == 0; 179 180 for (auto &F : M.functions()) { 181 F.removeFnAttrs(AttrMask); 182 F.removeRetAttrs(AttrMask); 183 // Only remove string attributes if we are not skipping validation. 184 // This will reserve the experimental attributes when validation version 185 // is 0.0 for experiment mode. 186 removeStringFunctionAttributes(F, SkipValidation); 187 for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx) 188 F.removeParamAttrs(Idx, AttrMask); 189 190 for (auto &BB : F) { 191 IRBuilder<> Builder(&BB); 192 for (auto &I : make_early_inc_range(BB)) { 193 if (I.getOpcode() == Instruction::FNeg) { 194 Builder.SetInsertPoint(&I); 195 Value *In = I.getOperand(0); 196 Value *Zero = ConstantFP::get(In->getType(), -0.0); 197 I.replaceAllUsesWith(Builder.CreateFSub(Zero, In)); 198 I.eraseFromParent(); 199 continue; 200 } 201 202 // Emtting NoOp bitcast instructions allows the ValueEnumerator to be 203 // unmodified as it reserves instruction IDs during contruction. 204 if (auto LI = dyn_cast<LoadInst>(&I)) { 205 if (Value *NoOpBitcast = maybeGenerateBitcast( 206 Builder, PointerTypes, I, LI->getPointerOperand(), 207 LI->getType())) { 208 LI->replaceAllUsesWith( 209 Builder.CreateLoad(LI->getType(), NoOpBitcast)); 210 LI->eraseFromParent(); 211 } 212 continue; 213 } 214 if (auto SI = dyn_cast<StoreInst>(&I)) { 215 if (Value *NoOpBitcast = maybeGenerateBitcast( 216 Builder, PointerTypes, I, SI->getPointerOperand(), 217 SI->getValueOperand()->getType())) { 218 219 SI->replaceAllUsesWith( 220 Builder.CreateStore(SI->getValueOperand(), NoOpBitcast)); 221 SI->eraseFromParent(); 222 } 223 continue; 224 } 225 if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) { 226 if (Value *NoOpBitcast = maybeGenerateBitcast( 227 Builder, PointerTypes, I, GEP->getPointerOperand(), 228 GEP->getSourceElementType())) 229 GEP->setOperand(0, NoOpBitcast); 230 continue; 231 } 232 if (auto *CB = dyn_cast<CallBase>(&I)) { 233 CB->removeFnAttrs(AttrMask); 234 CB->removeRetAttrs(AttrMask); 235 for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx) 236 CB->removeParamAttrs(Idx, AttrMask); 237 continue; 238 } 239 } 240 } 241 } 242 // Remove flags not for DXIL. 243 cleanModuleFlags(M); 244 return true; 245 } 246 247 DXILPrepareModule() : ModulePass(ID) {} 248 void getAnalysisUsage(AnalysisUsage &AU) const override { 249 AU.addRequired<DXILMetadataAnalysisWrapperPass>(); 250 AU.addPreserved<ShaderFlagsAnalysisWrapper>(); 251 AU.addPreserved<DXILResourceMDWrapper>(); 252 AU.addPreserved<DXILMetadataAnalysisWrapperPass>(); 253 AU.addPreserved<DXILResourceBindingWrapperPass>(); 254 } 255 static char ID; // Pass identification. 256 }; 257 char DXILPrepareModule::ID = 0; 258 259 } // end anonymous namespace 260 261 INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", 262 false, false) 263 INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass) 264 INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false, 265 false) 266 267 ModulePass *llvm::createDXILPrepareModulePass() { 268 return new DXILPrepareModule(); 269 } 270