| //===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file This file contains pases and utilities to convert a modern LLVM | |
| /// module into a module compatible with the LLVM 3.7-based DirectX Intermediate | |
| /// Language (DXIL). | |
| //===----------------------------------------------------------------------===// | |
| #include "DirectX.h" | |
| #include "DirectXIRPasses/PointerTypeAnalysis.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/IR/IRBuilder.h" | |
| #include "llvm/IR/Instruction.h" | |
| #include "llvm/IR/Module.h" | |
| #include "llvm/InitializePasses.h" | |
| #include "llvm/Pass.h" | |
| #include "llvm/Support/Compiler.h" | |
| #define DEBUG_TYPE "dxil-prepare" | |
| using namespace llvm; | |
| using namespace llvm::dxil; | |
| namespace { | |
| constexpr bool isValidForDXIL(Attribute::AttrKind Attr) { | |
| return is_contained({Attribute::Alignment, | |
| Attribute::AlwaysInline, | |
| Attribute::Builtin, | |
| Attribute::ByVal, | |
| Attribute::InAlloca, | |
| Attribute::Cold, | |
| Attribute::Convergent, | |
| Attribute::InlineHint, | |
| Attribute::InReg, | |
| Attribute::JumpTable, | |
| Attribute::MinSize, | |
| Attribute::Naked, | |
| Attribute::Nest, | |
| Attribute::NoAlias, | |
| Attribute::NoBuiltin, | |
| Attribute::NoCapture, | |
| Attribute::NoDuplicate, | |
| Attribute::NoImplicitFloat, | |
| Attribute::NoInline, | |
| Attribute::NonLazyBind, | |
| Attribute::NonNull, | |
| Attribute::Dereferenceable, | |
| Attribute::DereferenceableOrNull, | |
| Attribute::Memory, | |
| Attribute::NoRedZone, | |
| Attribute::NoReturn, | |
| Attribute::NoUnwind, | |
| Attribute::OptimizeForSize, | |
| Attribute::OptimizeNone, | |
| Attribute::ReadNone, | |
| Attribute::ReadOnly, | |
| Attribute::Returned, | |
| Attribute::ReturnsTwice, | |
| Attribute::SExt, | |
| Attribute::StackAlignment, | |
| Attribute::StackProtect, | |
| Attribute::StackProtectReq, | |
| Attribute::StackProtectStrong, | |
| Attribute::SafeStack, | |
| Attribute::StructRet, | |
| Attribute::SanitizeAddress, | |
| Attribute::SanitizeThread, | |
| Attribute::SanitizeMemory, | |
| Attribute::UWTable, | |
| Attribute::ZExt}, | |
| Attr); | |
| } | |
| class DXILPrepareModule : public ModulePass { | |
| static Value *maybeGenerateBitcast(IRBuilder<> &Builder, | |
| PointerTypeMap &PointerTypes, | |
| Instruction &Inst, Value *Operand, | |
| Type *Ty) { | |
| // Omit bitcasts if the incoming value matches the instruction type. | |
| auto It = PointerTypes.find(Operand); | |
| if (It != PointerTypes.end()) | |
| if (cast<TypedPointerType>(It->second)->getElementType() == Ty) | |
| return nullptr; | |
| // Insert bitcasts where we are removing the instruction. | |
| Builder.SetInsertPoint(&Inst); | |
| // This code only gets hit in opaque-pointer mode, so the type of the | |
| // pointer doesn't matter. | |
| PointerType *PtrTy = cast<PointerType>(Operand->getType()); | |
| return Builder.Insert( | |
| CastInst::Create(Instruction::BitCast, Operand, | |
| Builder.getInt8PtrTy(PtrTy->getAddressSpace()))); | |
| } | |
| public: | |
| bool runOnModule(Module &M) override { | |
| PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M); | |
| AttributeMask AttrMask; | |
| for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds; | |
| I = Attribute::AttrKind(I + 1)) { | |
| if (!isValidForDXIL(I)) | |
| AttrMask.addAttribute(I); | |
| } | |
| for (auto &F : M.functions()) { | |
| F.removeFnAttrs(AttrMask); | |
| F.removeRetAttrs(AttrMask); | |
| for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx) | |
| F.removeParamAttrs(Idx, AttrMask); | |
| for (auto &BB : F) { | |
| IRBuilder<> Builder(&BB); | |
| for (auto &I : make_early_inc_range(BB)) { | |
| if (I.getOpcode() == Instruction::FNeg) { | |
| Builder.SetInsertPoint(&I); | |
| Value *In = I.getOperand(0); | |
| Value *Zero = ConstantFP::get(In->getType(), -0.0); | |
| I.replaceAllUsesWith(Builder.CreateFSub(Zero, In)); | |
| I.eraseFromParent(); | |
| continue; | |
| } | |
| // Only insert bitcasts if the IR is using opaque pointers. | |
| if (M.getContext().supportsTypedPointers()) | |
| continue; | |
| // Emtting NoOp bitcast instructions allows the ValueEnumerator to be | |
| // unmodified as it reserves instruction IDs during contruction. | |
| if (auto LI = dyn_cast<LoadInst>(&I)) { | |
| if (Value *NoOpBitcast = maybeGenerateBitcast( | |
| Builder, PointerTypes, I, LI->getPointerOperand(), | |
| LI->getType())) { | |
| LI->replaceAllUsesWith( | |
| Builder.CreateLoad(LI->getType(), NoOpBitcast)); | |
| LI->eraseFromParent(); | |
| } | |
| continue; | |
| } | |
| if (auto SI = dyn_cast<StoreInst>(&I)) { | |
| if (Value *NoOpBitcast = maybeGenerateBitcast( | |
| Builder, PointerTypes, I, SI->getPointerOperand(), | |
| SI->getValueOperand()->getType())) { | |
| SI->replaceAllUsesWith( | |
| Builder.CreateStore(SI->getValueOperand(), NoOpBitcast)); | |
| SI->eraseFromParent(); | |
| } | |
| continue; | |
| } | |
| if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) { | |
| if (Value *NoOpBitcast = maybeGenerateBitcast( | |
| Builder, PointerTypes, I, GEP->getPointerOperand(), | |
| GEP->getResultElementType())) | |
| GEP->setOperand(0, NoOpBitcast); | |
| continue; | |
| } | |
| if (auto *CB = dyn_cast<CallBase>(&I)) { | |
| CB->removeFnAttrs(AttrMask); | |
| CB->removeRetAttrs(AttrMask); | |
| for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx) | |
| CB->removeParamAttrs(Idx, AttrMask); | |
| continue; | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| DXILPrepareModule() : ModulePass(ID) {} | |
| static char ID; // Pass identification. | |
| }; | |
| char DXILPrepareModule::ID = 0; | |
| } // end anonymous namespace | |
| INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", | |
| false, false) | |
| INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false, | |
| false) | |
| ModulePass *llvm::createDXILPrepareModulePass() { | |
| return new DXILPrepareModule(); | |
| } |