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 "DirectX.h" 15 #include "DirectXIRPasses/PointerTypeAnalysis.h" 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include "llvm/CodeGen/Passes.h" 19 #include "llvm/IR/IRBuilder.h" 20 #include "llvm/IR/Instruction.h" 21 #include "llvm/IR/Module.h" 22 #include "llvm/InitializePasses.h" 23 #include "llvm/Pass.h" 24 #include "llvm/Support/Compiler.h" 25 26 #define DEBUG_TYPE "dxil-prepare" 27 28 using namespace llvm; 29 using namespace llvm::dxil; 30 31 namespace { 32 33 constexpr bool isValidForDXIL(Attribute::AttrKind Attr) { 34 return is_contained({Attribute::Alignment, 35 Attribute::AlwaysInline, 36 Attribute::Builtin, 37 Attribute::ByVal, 38 Attribute::InAlloca, 39 Attribute::Cold, 40 Attribute::Convergent, 41 Attribute::InlineHint, 42 Attribute::InReg, 43 Attribute::JumpTable, 44 Attribute::MinSize, 45 Attribute::Naked, 46 Attribute::Nest, 47 Attribute::NoAlias, 48 Attribute::NoBuiltin, 49 Attribute::NoCapture, 50 Attribute::NoDuplicate, 51 Attribute::NoImplicitFloat, 52 Attribute::NoInline, 53 Attribute::NonLazyBind, 54 Attribute::NonNull, 55 Attribute::Dereferenceable, 56 Attribute::DereferenceableOrNull, 57 Attribute::Memory, 58 Attribute::NoRedZone, 59 Attribute::NoReturn, 60 Attribute::NoUnwind, 61 Attribute::OptimizeForSize, 62 Attribute::OptimizeNone, 63 Attribute::ReadNone, 64 Attribute::ReadOnly, 65 Attribute::Returned, 66 Attribute::ReturnsTwice, 67 Attribute::SExt, 68 Attribute::StackAlignment, 69 Attribute::StackProtect, 70 Attribute::StackProtectReq, 71 Attribute::StackProtectStrong, 72 Attribute::SafeStack, 73 Attribute::StructRet, 74 Attribute::SanitizeAddress, 75 Attribute::SanitizeThread, 76 Attribute::SanitizeMemory, 77 Attribute::UWTable, 78 Attribute::ZExt}, 79 Attr); 80 } 81 82 class DXILPrepareModule : public ModulePass { 83 84 static Value *maybeGenerateBitcast(IRBuilder<> &Builder, 85 PointerTypeMap &PointerTypes, 86 Instruction &Inst, Value *Operand, 87 Type *Ty) { 88 // Omit bitcasts if the incoming value matches the instruction type. 89 auto It = PointerTypes.find(Operand); 90 if (It != PointerTypes.end()) 91 if (cast<TypedPointerType>(It->second)->getElementType() == Ty) 92 return nullptr; 93 // Insert bitcasts where we are removing the instruction. 94 Builder.SetInsertPoint(&Inst); 95 // This code only gets hit in opaque-pointer mode, so the type of the 96 // pointer doesn't matter. 97 PointerType *PtrTy = cast<PointerType>(Operand->getType()); 98 return Builder.Insert( 99 CastInst::Create(Instruction::BitCast, Operand, 100 Builder.getInt8PtrTy(PtrTy->getAddressSpace()))); 101 } 102 103 public: 104 bool runOnModule(Module &M) override { 105 PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M); 106 AttributeMask AttrMask; 107 for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; 108 I = Attribute::AttrKind(I + 1)) { 109 if (!isValidForDXIL(I)) 110 AttrMask.addAttribute(I); 111 } 112 for (auto &F : M.functions()) { 113 F.removeFnAttrs(AttrMask); 114 F.removeRetAttrs(AttrMask); 115 for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx) 116 F.removeParamAttrs(Idx, AttrMask); 117 118 for (auto &BB : F) { 119 IRBuilder<> Builder(&BB); 120 for (auto &I : make_early_inc_range(BB)) { 121 if (I.getOpcode() == Instruction::FNeg) { 122 Builder.SetInsertPoint(&I); 123 Value *In = I.getOperand(0); 124 Value *Zero = ConstantFP::get(In->getType(), -0.0); 125 I.replaceAllUsesWith(Builder.CreateFSub(Zero, In)); 126 I.eraseFromParent(); 127 continue; 128 } 129 // Only insert bitcasts if the IR is using opaque pointers. 130 if (M.getContext().supportsTypedPointers()) 131 continue; 132 133 // Emtting NoOp bitcast instructions allows the ValueEnumerator to be 134 // unmodified as it reserves instruction IDs during contruction. 135 if (auto LI = dyn_cast<LoadInst>(&I)) { 136 if (Value *NoOpBitcast = maybeGenerateBitcast( 137 Builder, PointerTypes, I, LI->getPointerOperand(), 138 LI->getType())) { 139 LI->replaceAllUsesWith( 140 Builder.CreateLoad(LI->getType(), NoOpBitcast)); 141 LI->eraseFromParent(); 142 } 143 continue; 144 } 145 if (auto SI = dyn_cast<StoreInst>(&I)) { 146 if (Value *NoOpBitcast = maybeGenerateBitcast( 147 Builder, PointerTypes, I, SI->getPointerOperand(), 148 SI->getValueOperand()->getType())) { 149 150 SI->replaceAllUsesWith( 151 Builder.CreateStore(SI->getValueOperand(), NoOpBitcast)); 152 SI->eraseFromParent(); 153 } 154 continue; 155 } 156 if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) { 157 if (Value *NoOpBitcast = maybeGenerateBitcast( 158 Builder, PointerTypes, I, GEP->getPointerOperand(), 159 GEP->getResultElementType())) 160 GEP->setOperand(0, NoOpBitcast); 161 continue; 162 } 163 if (auto *CB = dyn_cast<CallBase>(&I)) { 164 CB->removeFnAttrs(AttrMask); 165 CB->removeRetAttrs(AttrMask); 166 for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx) 167 CB->removeParamAttrs(Idx, AttrMask); 168 continue; 169 } 170 } 171 } 172 } 173 return true; 174 } 175 176 DXILPrepareModule() : ModulePass(ID) {} 177 178 static char ID; // Pass identification. 179 }; 180 char DXILPrepareModule::ID = 0; 181 182 } // end anonymous namespace 183 184 INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", 185 false, false) 186 INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false, 187 false) 188 189 ModulePass *llvm::createDXILPrepareModulePass() { 190 return new DXILPrepareModule(); 191 } 192