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 "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::NoRedZone, 58 Attribute::NoReturn, 59 Attribute::NoUnwind, 60 Attribute::OptimizeForSize, 61 Attribute::OptimizeNone, 62 Attribute::ReadNone, 63 Attribute::ReadOnly, 64 Attribute::ArgMemOnly, 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 return Builder.Insert(CastInst::Create(Instruction::BitCast, Operand, 98 Builder.getInt8PtrTy())); 99 } 100 101 public: 102 bool runOnModule(Module &M) override { 103 PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M); 104 AttributeMask AttrMask; 105 for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; 106 I = Attribute::AttrKind(I + 1)) { 107 if (!isValidForDXIL(I)) 108 AttrMask.addAttribute(I); 109 } 110 for (auto &F : M.functions()) { 111 F.removeFnAttrs(AttrMask); 112 F.removeRetAttrs(AttrMask); 113 for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx) 114 F.removeParamAttrs(Idx, AttrMask); 115 116 for (auto &BB : F) { 117 IRBuilder<> Builder(&BB); 118 for (auto &I : make_early_inc_range(BB)) { 119 if (I.getOpcode() == Instruction::FNeg) { 120 Builder.SetInsertPoint(&I); 121 Value *In = I.getOperand(0); 122 Value *Zero = ConstantFP::get(In->getType(), -0.0); 123 I.replaceAllUsesWith(Builder.CreateFSub(Zero, In)); 124 I.eraseFromParent(); 125 continue; 126 } 127 // Only insert bitcasts if the IR is using opaque pointers. 128 if (!M.getContext().hasSetOpaquePointersValue()) 129 continue; 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 } 162 } 163 } 164 return true; 165 } 166 167 DXILPrepareModule() : ModulePass(ID) {} 168 169 static char ID; // Pass identification. 170 }; 171 char DXILPrepareModule::ID = 0; 172 173 } // end anonymous namespace 174 175 INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", 176 false, false) 177 INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false, 178 false) 179 180 ModulePass *llvm::createDXILPrepareModulePass() { 181 return new DXILPrepareModule(); 182 } 183