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