brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.9 KiB · 725f2b1 Raw
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