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" 15*bdd1243dSDimitry 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" 1981ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h" 2081ad6265SDimitry Andric #include "llvm/IR/Instruction.h" 2181ad6265SDimitry Andric #include "llvm/IR/Module.h" 2281ad6265SDimitry Andric #include "llvm/InitializePasses.h" 2381ad6265SDimitry Andric #include "llvm/Pass.h" 2481ad6265SDimitry Andric #include "llvm/Support/Compiler.h" 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric #define DEBUG_TYPE "dxil-prepare" 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric using namespace llvm; 2981ad6265SDimitry Andric using namespace llvm::dxil; 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric namespace { 3281ad6265SDimitry Andric 3381ad6265SDimitry Andric constexpr bool isValidForDXIL(Attribute::AttrKind Attr) { 3481ad6265SDimitry Andric return is_contained({Attribute::Alignment, 3581ad6265SDimitry Andric Attribute::AlwaysInline, 3681ad6265SDimitry Andric Attribute::Builtin, 3781ad6265SDimitry Andric Attribute::ByVal, 3881ad6265SDimitry Andric Attribute::InAlloca, 3981ad6265SDimitry Andric Attribute::Cold, 4081ad6265SDimitry Andric Attribute::Convergent, 4181ad6265SDimitry Andric Attribute::InlineHint, 4281ad6265SDimitry Andric Attribute::InReg, 4381ad6265SDimitry Andric Attribute::JumpTable, 4481ad6265SDimitry Andric Attribute::MinSize, 4581ad6265SDimitry Andric Attribute::Naked, 4681ad6265SDimitry Andric Attribute::Nest, 4781ad6265SDimitry Andric Attribute::NoAlias, 4881ad6265SDimitry Andric Attribute::NoBuiltin, 4981ad6265SDimitry Andric Attribute::NoCapture, 5081ad6265SDimitry Andric Attribute::NoDuplicate, 5181ad6265SDimitry Andric Attribute::NoImplicitFloat, 5281ad6265SDimitry Andric Attribute::NoInline, 5381ad6265SDimitry Andric Attribute::NonLazyBind, 5481ad6265SDimitry Andric Attribute::NonNull, 5581ad6265SDimitry Andric Attribute::Dereferenceable, 5681ad6265SDimitry Andric Attribute::DereferenceableOrNull, 57*bdd1243dSDimitry Andric Attribute::Memory, 5881ad6265SDimitry Andric Attribute::NoRedZone, 5981ad6265SDimitry Andric Attribute::NoReturn, 6081ad6265SDimitry Andric Attribute::NoUnwind, 6181ad6265SDimitry Andric Attribute::OptimizeForSize, 6281ad6265SDimitry Andric Attribute::OptimizeNone, 6381ad6265SDimitry Andric Attribute::ReadNone, 6481ad6265SDimitry Andric Attribute::ReadOnly, 6581ad6265SDimitry Andric Attribute::Returned, 6681ad6265SDimitry Andric Attribute::ReturnsTwice, 6781ad6265SDimitry Andric Attribute::SExt, 6881ad6265SDimitry Andric Attribute::StackAlignment, 6981ad6265SDimitry Andric Attribute::StackProtect, 7081ad6265SDimitry Andric Attribute::StackProtectReq, 7181ad6265SDimitry Andric Attribute::StackProtectStrong, 7281ad6265SDimitry Andric Attribute::SafeStack, 7381ad6265SDimitry Andric Attribute::StructRet, 7481ad6265SDimitry Andric Attribute::SanitizeAddress, 7581ad6265SDimitry Andric Attribute::SanitizeThread, 7681ad6265SDimitry Andric Attribute::SanitizeMemory, 7781ad6265SDimitry Andric Attribute::UWTable, 7881ad6265SDimitry Andric Attribute::ZExt}, 7981ad6265SDimitry Andric Attr); 8081ad6265SDimitry Andric } 8181ad6265SDimitry Andric 8281ad6265SDimitry Andric class DXILPrepareModule : public ModulePass { 8381ad6265SDimitry Andric 8481ad6265SDimitry Andric static Value *maybeGenerateBitcast(IRBuilder<> &Builder, 8581ad6265SDimitry Andric PointerTypeMap &PointerTypes, 8681ad6265SDimitry Andric Instruction &Inst, Value *Operand, 8781ad6265SDimitry Andric Type *Ty) { 8881ad6265SDimitry Andric // Omit bitcasts if the incoming value matches the instruction type. 8981ad6265SDimitry Andric auto It = PointerTypes.find(Operand); 9081ad6265SDimitry Andric if (It != PointerTypes.end()) 9181ad6265SDimitry Andric if (cast<TypedPointerType>(It->second)->getElementType() == Ty) 9281ad6265SDimitry Andric return nullptr; 9381ad6265SDimitry Andric // Insert bitcasts where we are removing the instruction. 9481ad6265SDimitry Andric Builder.SetInsertPoint(&Inst); 9581ad6265SDimitry Andric // This code only gets hit in opaque-pointer mode, so the type of the 9681ad6265SDimitry Andric // pointer doesn't matter. 9781ad6265SDimitry Andric PointerType *PtrTy = cast<PointerType>(Operand->getType()); 9881ad6265SDimitry Andric return Builder.Insert( 9981ad6265SDimitry Andric CastInst::Create(Instruction::BitCast, Operand, 10081ad6265SDimitry Andric Builder.getInt8PtrTy(PtrTy->getAddressSpace()))); 10181ad6265SDimitry Andric } 10281ad6265SDimitry Andric 10381ad6265SDimitry Andric public: 10481ad6265SDimitry Andric bool runOnModule(Module &M) override { 10581ad6265SDimitry Andric PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M); 10681ad6265SDimitry Andric AttributeMask AttrMask; 10781ad6265SDimitry Andric for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; 10881ad6265SDimitry Andric I = Attribute::AttrKind(I + 1)) { 10981ad6265SDimitry Andric if (!isValidForDXIL(I)) 11081ad6265SDimitry Andric AttrMask.addAttribute(I); 11181ad6265SDimitry Andric } 11281ad6265SDimitry Andric for (auto &F : M.functions()) { 11381ad6265SDimitry Andric F.removeFnAttrs(AttrMask); 11481ad6265SDimitry Andric F.removeRetAttrs(AttrMask); 11581ad6265SDimitry Andric for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx) 11681ad6265SDimitry Andric F.removeParamAttrs(Idx, AttrMask); 11781ad6265SDimitry Andric 11881ad6265SDimitry Andric for (auto &BB : F) { 11981ad6265SDimitry Andric IRBuilder<> Builder(&BB); 12081ad6265SDimitry Andric for (auto &I : make_early_inc_range(BB)) { 12181ad6265SDimitry Andric if (I.getOpcode() == Instruction::FNeg) { 12281ad6265SDimitry Andric Builder.SetInsertPoint(&I); 12381ad6265SDimitry Andric Value *In = I.getOperand(0); 12481ad6265SDimitry Andric Value *Zero = ConstantFP::get(In->getType(), -0.0); 12581ad6265SDimitry Andric I.replaceAllUsesWith(Builder.CreateFSub(Zero, In)); 12681ad6265SDimitry Andric I.eraseFromParent(); 12781ad6265SDimitry Andric continue; 12881ad6265SDimitry Andric } 12981ad6265SDimitry Andric // Only insert bitcasts if the IR is using opaque pointers. 13081ad6265SDimitry Andric if (M.getContext().supportsTypedPointers()) 13181ad6265SDimitry Andric continue; 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric // Emtting NoOp bitcast instructions allows the ValueEnumerator to be 13481ad6265SDimitry Andric // unmodified as it reserves instruction IDs during contruction. 13581ad6265SDimitry Andric if (auto LI = dyn_cast<LoadInst>(&I)) { 13681ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast( 13781ad6265SDimitry Andric Builder, PointerTypes, I, LI->getPointerOperand(), 13881ad6265SDimitry Andric LI->getType())) { 13981ad6265SDimitry Andric LI->replaceAllUsesWith( 14081ad6265SDimitry Andric Builder.CreateLoad(LI->getType(), NoOpBitcast)); 14181ad6265SDimitry Andric LI->eraseFromParent(); 14281ad6265SDimitry Andric } 14381ad6265SDimitry Andric continue; 14481ad6265SDimitry Andric } 14581ad6265SDimitry Andric if (auto SI = dyn_cast<StoreInst>(&I)) { 14681ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast( 14781ad6265SDimitry Andric Builder, PointerTypes, I, SI->getPointerOperand(), 14881ad6265SDimitry Andric SI->getValueOperand()->getType())) { 14981ad6265SDimitry Andric 15081ad6265SDimitry Andric SI->replaceAllUsesWith( 15181ad6265SDimitry Andric Builder.CreateStore(SI->getValueOperand(), NoOpBitcast)); 15281ad6265SDimitry Andric SI->eraseFromParent(); 15381ad6265SDimitry Andric } 15481ad6265SDimitry Andric continue; 15581ad6265SDimitry Andric } 15681ad6265SDimitry Andric if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) { 15781ad6265SDimitry Andric if (Value *NoOpBitcast = maybeGenerateBitcast( 15881ad6265SDimitry Andric Builder, PointerTypes, I, GEP->getPointerOperand(), 15981ad6265SDimitry Andric GEP->getResultElementType())) 16081ad6265SDimitry Andric GEP->setOperand(0, NoOpBitcast); 16181ad6265SDimitry Andric continue; 16281ad6265SDimitry Andric } 163*bdd1243dSDimitry Andric if (auto *CB = dyn_cast<CallBase>(&I)) { 164*bdd1243dSDimitry Andric CB->removeFnAttrs(AttrMask); 165*bdd1243dSDimitry Andric CB->removeRetAttrs(AttrMask); 166*bdd1243dSDimitry Andric for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx) 167*bdd1243dSDimitry Andric CB->removeParamAttrs(Idx, AttrMask); 168*bdd1243dSDimitry Andric continue; 169*bdd1243dSDimitry Andric } 17081ad6265SDimitry Andric } 17181ad6265SDimitry Andric } 17281ad6265SDimitry Andric } 17381ad6265SDimitry Andric return true; 17481ad6265SDimitry Andric } 17581ad6265SDimitry Andric 17681ad6265SDimitry Andric DXILPrepareModule() : ModulePass(ID) {} 17781ad6265SDimitry Andric 17881ad6265SDimitry Andric static char ID; // Pass identification. 17981ad6265SDimitry Andric }; 18081ad6265SDimitry Andric char DXILPrepareModule::ID = 0; 18181ad6265SDimitry Andric 18281ad6265SDimitry Andric } // end anonymous namespace 18381ad6265SDimitry Andric 18481ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", 18581ad6265SDimitry Andric false, false) 18681ad6265SDimitry Andric INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false, 18781ad6265SDimitry Andric false) 18881ad6265SDimitry Andric 18981ad6265SDimitry Andric ModulePass *llvm::createDXILPrepareModulePass() { 19081ad6265SDimitry Andric return new DXILPrepareModule(); 19181ad6265SDimitry Andric } 192