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(Val: Operand); |
91 | if (It != PointerTypes.end()) |
92 | if (cast<TypedPointerType>(Val: 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>(Val: Operand->getType()); |
99 | return Builder.Insert( |
100 | I: CastInst::Create(Instruction::BitCast, S: Operand, |
101 | Ty: Builder.getPtrTy(AddrSpace: 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(Val: I); |
112 | } |
113 | for (auto &F : M.functions()) { |
114 | F.removeFnAttrs(Attrs: AttrMask); |
115 | F.removeRetAttrs(Attrs: AttrMask); |
116 | for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx) |
117 | F.removeParamAttrs(ArgNo: Idx, Attrs: AttrMask); |
118 | |
119 | for (auto &BB : F) { |
120 | IRBuilder<> Builder(&BB); |
121 | for (auto &I : make_early_inc_range(Range&: BB)) { |
122 | if (I.getOpcode() == Instruction::FNeg) { |
123 | Builder.SetInsertPoint(&I); |
124 | Value *In = I.getOperand(i: 0); |
125 | Value *Zero = ConstantFP::get(Ty: In->getType(), V: -0.0); |
126 | I.replaceAllUsesWith(V: Builder.CreateFSub(L: Zero, R: 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>(Val: &I)) { |
134 | if (Value *NoOpBitcast = maybeGenerateBitcast( |
135 | Builder, PointerTypes, Inst&: I, Operand: LI->getPointerOperand(), |
136 | Ty: LI->getType())) { |
137 | LI->replaceAllUsesWith( |
138 | V: Builder.CreateLoad(Ty: LI->getType(), Ptr: NoOpBitcast)); |
139 | LI->eraseFromParent(); |
140 | } |
141 | continue; |
142 | } |
143 | if (auto SI = dyn_cast<StoreInst>(Val: &I)) { |
144 | if (Value *NoOpBitcast = maybeGenerateBitcast( |
145 | Builder, PointerTypes, Inst&: I, Operand: SI->getPointerOperand(), |
146 | Ty: SI->getValueOperand()->getType())) { |
147 | |
148 | SI->replaceAllUsesWith( |
149 | V: Builder.CreateStore(Val: SI->getValueOperand(), Ptr: NoOpBitcast)); |
150 | SI->eraseFromParent(); |
151 | } |
152 | continue; |
153 | } |
154 | if (auto GEP = dyn_cast<GetElementPtrInst>(Val: &I)) { |
155 | if (Value *NoOpBitcast = maybeGenerateBitcast( |
156 | Builder, PointerTypes, Inst&: I, Operand: GEP->getPointerOperand(), |
157 | Ty: GEP->getSourceElementType())) |
158 | GEP->setOperand(i_nocapture: 0, Val_nocapture: NoOpBitcast); |
159 | continue; |
160 | } |
161 | if (auto *CB = dyn_cast<CallBase>(Val: &I)) { |
162 | CB->removeFnAttrs(AttrsToRemove: AttrMask); |
163 | CB->removeRetAttrs(AttrsToRemove: AttrMask); |
164 | for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx) |
165 | CB->removeParamAttrs(ArgNo: Idx, AttrsToRemove: 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 | |