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