16599fdabSChris Bieneman //===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===//
26599fdabSChris Bieneman //
36599fdabSChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46599fdabSChris Bieneman // See https://llvm.org/LICENSE.txt for license information.
56599fdabSChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66599fdabSChris Bieneman //
76599fdabSChris Bieneman //===----------------------------------------------------------------------===//
86599fdabSChris Bieneman ///
96599fdabSChris Bieneman /// \file This file contains pases and utilities to convert a modern LLVM
106599fdabSChris Bieneman /// module into a module compatible with the LLVM 3.7-based DirectX Intermediate
116599fdabSChris Bieneman /// Language (DXIL).
126599fdabSChris Bieneman //===----------------------------------------------------------------------===//
136599fdabSChris Bieneman 
146599fdabSChris Bieneman #include "DirectX.h"
15f5d054cdSChris Bieneman #include "PointerTypeAnalysis.h"
166599fdabSChris Bieneman #include "llvm/ADT/STLExtras.h"
176599fdabSChris Bieneman #include "llvm/ADT/SmallVector.h"
186599fdabSChris Bieneman #include "llvm/CodeGen/Passes.h"
196599fdabSChris Bieneman #include "llvm/IR/IRBuilder.h"
206599fdabSChris Bieneman #include "llvm/IR/Instruction.h"
216599fdabSChris Bieneman #include "llvm/IR/Module.h"
226599fdabSChris Bieneman #include "llvm/InitializePasses.h"
236599fdabSChris Bieneman #include "llvm/Pass.h"
246599fdabSChris Bieneman #include "llvm/Support/Compiler.h"
256599fdabSChris Bieneman 
266599fdabSChris Bieneman #define DEBUG_TYPE "dxil-prepare"
276599fdabSChris Bieneman 
286599fdabSChris Bieneman using namespace llvm;
29f5d054cdSChris Bieneman using namespace llvm::dxil;
306599fdabSChris Bieneman 
316599fdabSChris Bieneman namespace {
326599fdabSChris Bieneman 
isValidForDXIL(Attribute::AttrKind Attr)336599fdabSChris Bieneman constexpr bool isValidForDXIL(Attribute::AttrKind Attr) {
346599fdabSChris Bieneman   return is_contained({Attribute::Alignment,
356599fdabSChris Bieneman                        Attribute::AlwaysInline,
366599fdabSChris Bieneman                        Attribute::Builtin,
376599fdabSChris Bieneman                        Attribute::ByVal,
386599fdabSChris Bieneman                        Attribute::InAlloca,
396599fdabSChris Bieneman                        Attribute::Cold,
406599fdabSChris Bieneman                        Attribute::Convergent,
416599fdabSChris Bieneman                        Attribute::InlineHint,
426599fdabSChris Bieneman                        Attribute::InReg,
436599fdabSChris Bieneman                        Attribute::JumpTable,
446599fdabSChris Bieneman                        Attribute::MinSize,
456599fdabSChris Bieneman                        Attribute::Naked,
466599fdabSChris Bieneman                        Attribute::Nest,
476599fdabSChris Bieneman                        Attribute::NoAlias,
486599fdabSChris Bieneman                        Attribute::NoBuiltin,
496599fdabSChris Bieneman                        Attribute::NoCapture,
506599fdabSChris Bieneman                        Attribute::NoDuplicate,
516599fdabSChris Bieneman                        Attribute::NoImplicitFloat,
526599fdabSChris Bieneman                        Attribute::NoInline,
536599fdabSChris Bieneman                        Attribute::NonLazyBind,
546599fdabSChris Bieneman                        Attribute::NonNull,
556599fdabSChris Bieneman                        Attribute::Dereferenceable,
566599fdabSChris Bieneman                        Attribute::DereferenceableOrNull,
576599fdabSChris Bieneman                        Attribute::NoRedZone,
586599fdabSChris Bieneman                        Attribute::NoReturn,
596599fdabSChris Bieneman                        Attribute::NoUnwind,
606599fdabSChris Bieneman                        Attribute::OptimizeForSize,
616599fdabSChris Bieneman                        Attribute::OptimizeNone,
626599fdabSChris Bieneman                        Attribute::ReadNone,
636599fdabSChris Bieneman                        Attribute::ReadOnly,
646599fdabSChris Bieneman                        Attribute::ArgMemOnly,
656599fdabSChris Bieneman                        Attribute::Returned,
666599fdabSChris Bieneman                        Attribute::ReturnsTwice,
676599fdabSChris Bieneman                        Attribute::SExt,
686599fdabSChris Bieneman                        Attribute::StackAlignment,
696599fdabSChris Bieneman                        Attribute::StackProtect,
706599fdabSChris Bieneman                        Attribute::StackProtectReq,
716599fdabSChris Bieneman                        Attribute::StackProtectStrong,
726599fdabSChris Bieneman                        Attribute::SafeStack,
736599fdabSChris Bieneman                        Attribute::StructRet,
746599fdabSChris Bieneman                        Attribute::SanitizeAddress,
756599fdabSChris Bieneman                        Attribute::SanitizeThread,
766599fdabSChris Bieneman                        Attribute::SanitizeMemory,
776599fdabSChris Bieneman                        Attribute::UWTable,
786599fdabSChris Bieneman                        Attribute::ZExt},
796599fdabSChris Bieneman                       Attr);
806599fdabSChris Bieneman }
816599fdabSChris Bieneman 
826599fdabSChris Bieneman class DXILPrepareModule : public ModulePass {
83f5d054cdSChris Bieneman 
maybeGenerateBitcast(IRBuilder<> & Builder,PointerTypeMap & PointerTypes,Instruction & Inst,Value * Operand,Type * Ty)84f5d054cdSChris Bieneman   static Value *maybeGenerateBitcast(IRBuilder<> &Builder,
85f5d054cdSChris Bieneman                                      PointerTypeMap &PointerTypes,
86f5d054cdSChris Bieneman                                      Instruction &Inst, Value *Operand,
87f5d054cdSChris Bieneman                                      Type *Ty) {
88f5d054cdSChris Bieneman     // Omit bitcasts if the incoming value matches the instruction type.
89f5d054cdSChris Bieneman     auto It = PointerTypes.find(Operand);
90f5d054cdSChris Bieneman     if (It != PointerTypes.end())
91f5d054cdSChris Bieneman       if (cast<TypedPointerType>(It->second)->getElementType() == Ty)
92f5d054cdSChris Bieneman         return nullptr;
93f5d054cdSChris Bieneman     // Insert bitcasts where we are removing the instruction.
94f5d054cdSChris Bieneman     Builder.SetInsertPoint(&Inst);
95f5d054cdSChris Bieneman     // This code only gets hit in opaque-pointer mode, so the type of the
96f5d054cdSChris Bieneman     // pointer doesn't matter.
9704d4130aSChris Bieneman     PointerType *PtrTy = cast<PointerType>(Operand->getType());
9804d4130aSChris Bieneman     return Builder.Insert(
9904d4130aSChris Bieneman         CastInst::Create(Instruction::BitCast, Operand,
10004d4130aSChris Bieneman                          Builder.getInt8PtrTy(PtrTy->getAddressSpace())));
101f5d054cdSChris Bieneman   }
102f5d054cdSChris Bieneman 
1036599fdabSChris Bieneman public:
runOnModule(Module & M)1046599fdabSChris Bieneman   bool runOnModule(Module &M) override {
105f5d054cdSChris Bieneman     PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M);
1066599fdabSChris Bieneman     AttributeMask AttrMask;
1076599fdabSChris Bieneman     for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;
1086599fdabSChris Bieneman          I = Attribute::AttrKind(I + 1)) {
1096599fdabSChris Bieneman       if (!isValidForDXIL(I))
1106599fdabSChris Bieneman         AttrMask.addAttribute(I);
1116599fdabSChris Bieneman     }
1126599fdabSChris Bieneman     for (auto &F : M.functions()) {
1136599fdabSChris Bieneman       F.removeFnAttrs(AttrMask);
1146599fdabSChris Bieneman       F.removeRetAttrs(AttrMask);
115f5d054cdSChris Bieneman       for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
1166599fdabSChris Bieneman         F.removeParamAttrs(Idx, AttrMask);
1176599fdabSChris Bieneman 
1186599fdabSChris Bieneman       for (auto &BB : F) {
1196599fdabSChris Bieneman         IRBuilder<> Builder(&BB);
1206599fdabSChris Bieneman         for (auto &I : make_early_inc_range(BB)) {
1216599fdabSChris Bieneman           if (I.getOpcode() == Instruction::FNeg) {
1226599fdabSChris Bieneman             Builder.SetInsertPoint(&I);
1236599fdabSChris Bieneman             Value *In = I.getOperand(0);
1246599fdabSChris Bieneman             Value *Zero = ConstantFP::get(In->getType(), -0.0);
1256599fdabSChris Bieneman             I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
1266599fdabSChris Bieneman             I.eraseFromParent();
127f5d054cdSChris Bieneman             continue;
128f5d054cdSChris Bieneman           }
129f5d054cdSChris Bieneman           // Only insert bitcasts if the IR is using opaque pointers.
130*12ca031bSpython3kgae           if (M.getContext().supportsTypedPointers())
131f5d054cdSChris Bieneman             continue;
132f5d054cdSChris Bieneman 
133f5d054cdSChris Bieneman           // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
134f5d054cdSChris Bieneman           // unmodified as it reserves instruction IDs during contruction.
135f5d054cdSChris Bieneman           if (auto LI = dyn_cast<LoadInst>(&I)) {
136f5d054cdSChris Bieneman             if (Value *NoOpBitcast = maybeGenerateBitcast(
137f5d054cdSChris Bieneman                     Builder, PointerTypes, I, LI->getPointerOperand(),
138f5d054cdSChris Bieneman                     LI->getType())) {
139f5d054cdSChris Bieneman               LI->replaceAllUsesWith(
140f5d054cdSChris Bieneman                   Builder.CreateLoad(LI->getType(), NoOpBitcast));
141f5d054cdSChris Bieneman               LI->eraseFromParent();
142f5d054cdSChris Bieneman             }
143f5d054cdSChris Bieneman             continue;
144f5d054cdSChris Bieneman           }
145f5d054cdSChris Bieneman           if (auto SI = dyn_cast<StoreInst>(&I)) {
146f5d054cdSChris Bieneman             if (Value *NoOpBitcast = maybeGenerateBitcast(
147f5d054cdSChris Bieneman                     Builder, PointerTypes, I, SI->getPointerOperand(),
148f5d054cdSChris Bieneman                     SI->getValueOperand()->getType())) {
149f5d054cdSChris Bieneman 
150f5d054cdSChris Bieneman               SI->replaceAllUsesWith(
151f5d054cdSChris Bieneman                   Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
152f5d054cdSChris Bieneman               SI->eraseFromParent();
153f5d054cdSChris Bieneman             }
154f5d054cdSChris Bieneman             continue;
155f5d054cdSChris Bieneman           }
156f5d054cdSChris Bieneman           if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {
157f5d054cdSChris Bieneman             if (Value *NoOpBitcast = maybeGenerateBitcast(
158f5d054cdSChris Bieneman                     Builder, PointerTypes, I, GEP->getPointerOperand(),
159f5d054cdSChris Bieneman                     GEP->getResultElementType()))
160f5d054cdSChris Bieneman               GEP->setOperand(0, NoOpBitcast);
161f5d054cdSChris Bieneman             continue;
1626599fdabSChris Bieneman           }
1636599fdabSChris Bieneman         }
1646599fdabSChris Bieneman       }
1656599fdabSChris Bieneman     }
1666599fdabSChris Bieneman     return true;
1676599fdabSChris Bieneman   }
1686599fdabSChris Bieneman 
DXILPrepareModule()1696599fdabSChris Bieneman   DXILPrepareModule() : ModulePass(ID) {}
1706599fdabSChris Bieneman 
1716599fdabSChris Bieneman   static char ID; // Pass identification.
1726599fdabSChris Bieneman };
1736599fdabSChris Bieneman char DXILPrepareModule::ID = 0;
1746599fdabSChris Bieneman 
1756599fdabSChris Bieneman } // end anonymous namespace
1766599fdabSChris Bieneman 
1776599fdabSChris Bieneman INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
1786599fdabSChris Bieneman                       false, false)
1796599fdabSChris Bieneman INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
1806599fdabSChris Bieneman                     false)
1816599fdabSChris Bieneman 
createDXILPrepareModulePass()1826599fdabSChris Bieneman ModulePass *llvm::createDXILPrepareModulePass() {
1836599fdabSChris Bieneman   return new DXILPrepareModule();
1846599fdabSChris Bieneman }
185