181ad6265SDimitry Andric //===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric /// 981ad6265SDimitry Andric /// \file This file contains pases and utilities to convert a modern LLVM 1081ad6265SDimitry Andric /// module into a module compatible with the LLVM 3.7-based DirectX Intermediate 1181ad6265SDimitry Andric /// Language (DXIL). 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include "DirectX.h" 15bdd1243dSDimitry Andric #include "DirectXIRPasses/PointerTypeAnalysis.h" 1681ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h" 1781ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 1881ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h" 1906c3fb27SDimitry Andric #include "llvm/IR/AttributeMask.h" 2081ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h" 2181ad6265SDimitry Andric #include "llvm/IR/Instruction.h" 2281ad6265SDimitry Andric #include "llvm/IR/Module.h" 2381ad6265SDimitry Andric #include "llvm/InitializePasses.h" 2481ad6265SDimitry Andric #include "llvm/Pass.h" 2581ad6265SDimitry Andric #include "llvm/Support/Compiler.h" 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric #define DEBUG_TYPE "dxil-prepare" 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric using namespace llvm; 3081ad6265SDimitry Andric using namespace llvm::dxil; 3181ad6265SDimitry Andric 3281ad6265SDimitry Andric namespace { 3381ad6265SDimitry Andric 3481ad6265SDimitry Andric constexpr bool isValidForDXIL(Attribute::AttrKind Attr) { 3581ad6265SDimitry Andric return is_contained({Attribute::Alignment, 3681ad6265SDimitry Andric Attribute::AlwaysInline, 3781ad6265SDimitry Andric Attribute::Builtin, 3881ad6265SDimitry Andric Attribute::ByVal, 3981ad6265SDimitry Andric Attribute::InAlloca, 4081ad6265SDimitry Andric Attribute::Cold, 4181ad6265SDimitry Andric Attribute::Convergent, 4281ad6265SDimitry Andric Attribute::InlineHint, 4381ad6265SDimitry Andric Attribute::InReg, 4481ad6265SDimitry Andric Attribute::JumpTable, 4581ad6265SDimitry Andric Attribute::MinSize, 4681ad6265SDimitry Andric Attribute::Naked, 4781ad6265SDimitry Andric Attribute::Nest, 4881ad6265SDimitry Andric Attribute::NoAlias, 4981ad6265SDimitry Andric Attribute::NoBuiltin, 5081ad6265SDimitry Andric Attribute::NoCapture, 5181ad6265SDimitry Andric Attribute::NoDuplicate, 5281ad6265SDimitry Andric Attribute::NoImplicitFloat, 5381ad6265SDimitry Andric Attribute::NoInline, 5481ad6265SDimitry Andric Attribute::NonLazyBind, 5581ad6265SDimitry Andric Attribute::NonNull, 5681ad6265SDimitry Andric Attribute::Dereferenceable, 5781ad6265SDimitry Andric Attribute::DereferenceableOrNull, 58bdd1243dSDimitry Andric Attribute::Memory, 5981ad6265SDimitry Andric Attribute::NoRedZone, 6081ad6265SDimitry Andric Attribute::NoReturn, 6181ad6265SDimitry Andric Attribute::NoUnwind, 6281ad6265SDimitry Andric Attribute::OptimizeForSize, 6381ad6265SDimitry Andric Attribute::OptimizeNone, 6481ad6265SDimitry Andric Attribute::ReadNone, 6581ad6265SDimitry Andric Attribute::ReadOnly, 6681ad6265SDimitry Andric Attribute::Returned, 6781ad6265SDimitry Andric Attribute::ReturnsTwice, 6881ad6265SDimitry Andric Attribute::SExt, 6981ad6265SDimitry Andric Attribute::StackAlignment, 7081ad6265SDimitry Andric Attribute::StackProtect, 7181ad6265SDimitry Andric Attribute::StackProtectReq, 7281ad6265SDimitry Andric Attribute::StackProtectStrong, 7381ad6265SDimitry Andric Attribute::SafeStack, 7481ad6265SDimitry Andric Attribute::StructRet, 7581ad6265SDimitry Andric Attribute::SanitizeAddress, 7681ad6265SDimitry Andric Attribute::SanitizeThread, 7781ad6265SDimitry Andric Attribute::SanitizeMemory, 7881ad6265SDimitry Andric Attribute::UWTable, 7981ad6265SDimitry Andric Attribute::ZExt}, 8081ad6265SDimitry Andric Attr); 8181ad6265SDimitry Andric } 8281ad6265SDimitry Andric 8381ad6265SDimitry Andric class DXILPrepareModule : public ModulePass { 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric static Value *maybeGenerateBitcast(IRBuilder<> &Builder, 8681ad6265SDimitry Andric PointerTypeMap &PointerTypes, 8781ad6265SDimitry Andric Instruction &Inst, Value *Operand, 8881ad6265SDimitry Andric Type *Ty) { 8981ad6265SDimitry Andric // Omit bitcasts if the incoming value matches the instruction type. 9081ad6265SDimitry Andric auto It = PointerTypes.find(Operand); 9181ad6265SDimitry Andric if (It != PointerTypes.end()) 9281ad6265SDimitry Andric if (cast<TypedPointerType>(It->second)->getElementType() == Ty) 9381ad6265SDimitry Andric return nullptr; 9481ad6265SDimitry Andric // Insert bitcasts where we are removing the instruction. 9581ad6265SDimitry Andric Builder.SetInsertPoint(&Inst); 9681ad6265SDimitry Andric // This code only gets hit in opaque-pointer mode, so the type of the 9781ad6265SDimitry Andric // pointer doesn't matter. 9881ad6265SDimitry Andric PointerType *PtrTy = cast<PointerType>(Operand->getType()); 9981ad6265SDimitry Andric return Builder.Insert( 10081ad6265SDimitry Andric CastInst::Create(Instruction::BitCast, Operand, 101*5f757f3fSDimitry Andric Builder.getPtrTy(PtrTy->getAddressSpace()))); 10281ad6265SDimitry Andric } 10381ad6265SDimitry Andric 10481ad6265SDimitry Andric public: 10581ad6265SDimitry Andric bool runOnModule(Module &M) override { 10681ad6265SDimitry Andric PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M); 10781ad6265SDimitry Andric AttributeMask AttrMask; 10881ad6265SDimitry Andric for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; 10981ad6265SDimitry Andric I = Attribute::AttrKind(I + 1)) { 11081ad6265SDimitry Andric if (!isValidForDXIL(I)) 11181ad6265SDimitry Andric AttrMask.addAttribute(I); 11281ad6265SDimitry Andric } 11381ad6265SDimitry Andric for (auto &F : M.functions()) { 11481ad6265SDimitry Andric F.removeFnAttrs(AttrMask); 11581ad6265SDimitry Andric F.removeRetAttrs(AttrMask); 11681ad6265SDimitry Andric for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx) 11781ad6265SDimitry Andric F.removeParamAttrs(Idx, AttrMask); 11881ad6265SDimitry Andric 11981ad6265SDimitry Andric for (auto &BB : F) { 12081ad6265SDimitry Andric IRBuilder<> Builder(&BB); 12181ad6265SDimitry Andric for (auto &I : make_early_inc_range(BB)) { 12281ad6265SDimitry Andric if (I.getOpcode() == Instruction::FNeg) { 12381ad6265SDimitry Andric Builder.SetInsertPoint(&I); 12481ad6265SDimitry Andric Value *In = I.getOperand(0); 12581ad6265SDimitry Andric Value *Zero = ConstantFP::get(In->getType(), -0.0); 12681ad6265SDimitry Andric I.replaceAllUsesWith(Builder.CreateFSub(Zero, In)); 12781ad6265SDimitry Andric I.eraseFromParent(); 12881ad6265SDimitry Andric continue; 12981ad6265SDimitry Andric } 13081ad6265SDimitry Andric 13181ad6265SDimitry Andric // Emtting NoOp bitcast instructions allows the ValueEnumerator to be 13281ad6265SDimitry Andric // unmodified as it reserves instruction IDs during contruction. 13381ad6265SDimitry Andric if (auto LI = dyn_cast<LoadInst>(&I)) { 13481ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast( 13581ad6265SDimitry Andric Builder, PointerTypes, I, LI->getPointerOperand(), 13681ad6265SDimitry Andric LI->getType())) { 13781ad6265SDimitry Andric LI->replaceAllUsesWith( 13881ad6265SDimitry Andric Builder.CreateLoad(LI->getType(), NoOpBitcast)); 13981ad6265SDimitry Andric LI->eraseFromParent(); 14081ad6265SDimitry Andric } 14181ad6265SDimitry Andric continue; 14281ad6265SDimitry Andric } 14381ad6265SDimitry Andric if (auto SI = dyn_cast<StoreInst>(&I)) { 14481ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast( 14581ad6265SDimitry Andric Builder, PointerTypes, I, SI->getPointerOperand(), 14681ad6265SDimitry Andric SI->getValueOperand()->getType())) { 14781ad6265SDimitry Andric 14881ad6265SDimitry Andric SI->replaceAllUsesWith( 14981ad6265SDimitry Andric Builder.CreateStore(SI->getValueOperand(), NoOpBitcast)); 15081ad6265SDimitry Andric SI->eraseFromParent(); 15181ad6265SDimitry Andric } 15281ad6265SDimitry Andric continue; 15381ad6265SDimitry Andric } 15481ad6265SDimitry Andric if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) { 15581ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast( 15681ad6265SDimitry Andric Builder, PointerTypes, I, GEP->getPointerOperand(), 157*5f757f3fSDimitry Andric GEP->getSourceElementType())) 15881ad6265SDimitry Andric GEP->setOperand(0, NoOpBitcast); 15981ad6265SDimitry Andric continue; 16081ad6265SDimitry Andric } 161bdd1243dSDimitry Andric if (auto *CB = dyn_cast<CallBase>(&I)) { 162bdd1243dSDimitry Andric CB->removeFnAttrs(AttrMask); 163bdd1243dSDimitry Andric CB->removeRetAttrs(AttrMask); 164bdd1243dSDimitry Andric for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx) 165bdd1243dSDimitry Andric CB->removeParamAttrs(Idx, AttrMask); 166bdd1243dSDimitry Andric continue; 167bdd1243dSDimitry Andric } 16881ad6265SDimitry Andric } 16981ad6265SDimitry Andric } 17081ad6265SDimitry Andric } 17181ad6265SDimitry Andric return true; 17281ad6265SDimitry Andric } 17381ad6265SDimitry Andric 17481ad6265SDimitry Andric DXILPrepareModule() : ModulePass(ID) {} 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric static char ID; // Pass identification. 17781ad6265SDimitry Andric }; 17881ad6265SDimitry Andric char DXILPrepareModule::ID = 0; 17981ad6265SDimitry Andric 18081ad6265SDimitry Andric } // end anonymous namespace 18181ad6265SDimitry Andric 18281ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", 18381ad6265SDimitry Andric false, false) 18481ad6265SDimitry Andric INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false, 18581ad6265SDimitry Andric false) 18681ad6265SDimitry Andric 18781ad6265SDimitry Andric ModulePass *llvm::createDXILPrepareModulePass() { 18881ad6265SDimitry Andric return new DXILPrepareModule(); 18981ad6265SDimitry Andric } 190