195 lines · cpp
1//===- DXILWriterPass.cpp - Bitcode writing pass --------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// DXILWriterPass implementation.10//11//===----------------------------------------------------------------------===//12 13#include "DXILWriterPass.h"14#include "DXILBitcodeWriter.h"15#include "llvm/ADT/DenseMap.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Analysis/ModuleSummaryAnalysis.h"19#include "llvm/IR/Constants.h"20#include "llvm/IR/DerivedTypes.h"21#include "llvm/IR/GlobalVariable.h"22#include "llvm/IR/IntrinsicInst.h"23#include "llvm/IR/Intrinsics.h"24#include "llvm/IR/LLVMContext.h"25#include "llvm/IR/Module.h"26#include "llvm/IR/PassManager.h"27#include "llvm/InitializePasses.h"28#include "llvm/Pass.h"29#include "llvm/Support/Alignment.h"30#include "llvm/Transforms/Utils/ModuleUtils.h"31 32using namespace llvm;33using namespace llvm::dxil;34 35namespace {36class WriteDXILPass : public llvm::ModulePass {37 raw_ostream &OS; // raw_ostream to print on38 39public:40 static char ID; // Pass identification, replacement for typeid41 WriteDXILPass() : ModulePass(ID), OS(dbgs()) {42 initializeWriteDXILPassPass(*PassRegistry::getPassRegistry());43 }44 45 explicit WriteDXILPass(raw_ostream &o) : ModulePass(ID), OS(o) {46 initializeWriteDXILPassPass(*PassRegistry::getPassRegistry());47 }48 49 StringRef getPassName() const override { return "Bitcode Writer"; }50 51 bool runOnModule(Module &M) override {52 WriteDXILToFile(M, OS);53 return false;54 }55 void getAnalysisUsage(AnalysisUsage &AU) const override {56 AU.setPreservesAll();57 }58};59 60static void legalizeLifetimeIntrinsics(Module &M) {61 LLVMContext &Ctx = M.getContext();62 Type *I64Ty = IntegerType::get(Ctx, 64);63 Type *PtrTy = PointerType::get(Ctx, 0);64 Intrinsic::ID LifetimeIIDs[2] = {Intrinsic::lifetime_start,65 Intrinsic::lifetime_end};66 for (Intrinsic::ID &IID : LifetimeIIDs) {67 Function *F = M.getFunction(Intrinsic::getName(IID, {PtrTy}, &M));68 if (!F)69 continue;70 71 // Get or insert an LLVM 3.7-compliant lifetime intrinsic function of the72 // form `void @llvm.lifetime.[start/end](i64, ptr)` with the NoUnwind73 // attribute74 AttributeList Attr;75 Attr = Attr.addFnAttribute(Ctx, Attribute::NoUnwind);76 FunctionCallee LifetimeCallee = M.getOrInsertFunction(77 Intrinsic::getBaseName(IID), Attr, Type::getVoidTy(Ctx), I64Ty, PtrTy);78 79 // Replace all calls to lifetime intrinsics with calls to the80 // LLVM 3.7-compliant version of the lifetime intrinsic81 for (User *U : make_early_inc_range(F->users())) {82 CallInst *CI = dyn_cast<CallInst>(U);83 assert(CI &&84 "Expected user of a lifetime intrinsic function to be a CallInst");85 86 // LLVM 3.7 lifetime intrinics require an i8* operand, so we insert87 // a bitcast to ensure that is the case88 Value *PtrOperand = CI->getArgOperand(0);89 PointerType *PtrOpPtrTy = cast<PointerType>(PtrOperand->getType());90 Value *NoOpBitCast = CastInst::Create(Instruction::BitCast, PtrOperand,91 PtrOpPtrTy, "", CI->getIterator());92 93 // LLVM 3.7 lifetime intrinsics have an explicit size operand, whose value94 // we can obtain from the pointer operand which must be an AllocaInst (as95 // of https://github.com/llvm/llvm-project/pull/149310)96 AllocaInst *AI = dyn_cast<AllocaInst>(PtrOperand);97 assert(AI &&98 "The pointer operand of a lifetime intrinsic call must be an "99 "AllocaInst");100 std::optional<TypeSize> AllocSize =101 AI->getAllocationSize(CI->getDataLayout());102 assert(AllocSize.has_value() &&103 "Expected the allocation size of AllocaInst to be known");104 CallInst *NewCI = CallInst::Create(105 LifetimeCallee,106 {ConstantInt::get(I64Ty, AllocSize.value().getFixedValue()),107 NoOpBitCast},108 "", CI->getIterator());109 for (Attribute ParamAttr : CI->getParamAttributes(0))110 NewCI->addParamAttr(1, ParamAttr);111 112 CI->eraseFromParent();113 }114 115 F->eraseFromParent();116 }117}118 119static void removeLifetimeIntrinsics(Module &M) {120 Intrinsic::ID LifetimeIIDs[2] = {Intrinsic::lifetime_start,121 Intrinsic::lifetime_end};122 for (Intrinsic::ID &IID : LifetimeIIDs) {123 Function *F = M.getFunction(Intrinsic::getBaseName(IID));124 if (!F)125 continue;126 127 for (User *U : make_early_inc_range(F->users())) {128 CallInst *CI = dyn_cast<CallInst>(U);129 assert(CI && "Expected user of lifetime function to be a CallInst");130 BitCastInst *BCI = dyn_cast<BitCastInst>(CI->getArgOperand(1));131 assert(BCI && "Expected pointer operand of CallInst to be a BitCastInst");132 CI->eraseFromParent();133 BCI->eraseFromParent();134 }135 F->eraseFromParent();136 }137}138 139class EmbedDXILPass : public llvm::ModulePass {140public:141 static char ID; // Pass identification, replacement for typeid142 EmbedDXILPass() : ModulePass(ID) {143 initializeEmbedDXILPassPass(*PassRegistry::getPassRegistry());144 }145 146 StringRef getPassName() const override { return "DXIL Embedder"; }147 148 bool runOnModule(Module &M) override {149 std::string Data;150 llvm::raw_string_ostream OS(Data);151 152 // Perform late legalization of lifetime intrinsics that would otherwise153 // fail the Module Verifier if performed in an earlier pass154 legalizeLifetimeIntrinsics(M);155 156 WriteDXILToFile(M, OS);157 158 // We no longer need lifetime intrinsics after bitcode serialization, so we159 // simply remove them to keep the Module Verifier happy after our160 // not-so-legal legalizations161 removeLifetimeIntrinsics(M);162 163 Constant *ModuleConstant =164 ConstantDataArray::get(M.getContext(), arrayRefFromStringRef(Data));165 auto *GV = new llvm::GlobalVariable(M, ModuleConstant->getType(), true,166 GlobalValue::PrivateLinkage,167 ModuleConstant, "dx.dxil");168 GV->setSection("DXIL");169 GV->setAlignment(Align(4));170 appendToCompilerUsed(M, {GV});171 return true;172 }173 174 void getAnalysisUsage(AnalysisUsage &AU) const override {175 AU.setPreservesAll();176 }177};178} // namespace179 180char WriteDXILPass::ID = 0;181INITIALIZE_PASS_BEGIN(WriteDXILPass, "dxil-write-bitcode", "Write Bitcode",182 false, true)183INITIALIZE_PASS_DEPENDENCY(ModuleSummaryIndexWrapperPass)184INITIALIZE_PASS_END(WriteDXILPass, "dxil-write-bitcode", "Write Bitcode", false,185 true)186 187ModulePass *llvm::createDXILWriterPass(raw_ostream &Str) {188 return new WriteDXILPass(Str);189}190 191char EmbedDXILPass::ID = 0;192INITIALIZE_PASS(EmbedDXILPass, "dxil-embed", "Embed DXIL", false, true)193 194ModulePass *llvm::createDXILEmbedderPass() { return new EmbedDXILPass(); }195