brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · d6fa65f Raw
276 lines · cpp
1//===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===//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/// \file This file contains passes and utilities to convert a modern LLVM10/// module into a module compatible with the LLVM 3.7-based DirectX Intermediate11/// Language (DXIL).12//===----------------------------------------------------------------------===//13 14#include "DXILRootSignature.h"15#include "DXILShaderFlags.h"16#include "DirectX.h"17#include "DirectXIRPasses/PointerTypeAnalysis.h"18#include "llvm/ADT/STLExtras.h"19#include "llvm/ADT/StringSet.h"20#include "llvm/Analysis/DXILMetadataAnalysis.h"21#include "llvm/Analysis/DXILResource.h"22#include "llvm/CodeGen/Passes.h"23#include "llvm/IR/AttributeMask.h"24#include "llvm/IR/IRBuilder.h"25#include "llvm/IR/Instruction.h"26#include "llvm/IR/Module.h"27#include "llvm/InitializePasses.h"28#include "llvm/Pass.h"29#include "llvm/Support/VersionTuple.h"30 31#define DEBUG_TYPE "dxil-prepare"32 33using namespace llvm;34using namespace llvm::dxil;35 36namespace {37 38constexpr bool isValidForDXIL(Attribute::AttrKind Attr) {39  return is_contained({Attribute::Alignment,40                       Attribute::AlwaysInline,41                       Attribute::Builtin,42                       Attribute::ByVal,43                       Attribute::InAlloca,44                       Attribute::Cold,45                       Attribute::Convergent,46                       Attribute::InlineHint,47                       Attribute::InReg,48                       Attribute::JumpTable,49                       Attribute::MinSize,50                       Attribute::Naked,51                       Attribute::Nest,52                       Attribute::NoAlias,53                       Attribute::NoBuiltin,54                       Attribute::NoDuplicate,55                       Attribute::NoImplicitFloat,56                       Attribute::NoInline,57                       Attribute::NonLazyBind,58                       Attribute::NonNull,59                       Attribute::Dereferenceable,60                       Attribute::DereferenceableOrNull,61                       Attribute::Memory,62                       Attribute::NoRedZone,63                       Attribute::NoReturn,64                       Attribute::NoUnwind,65                       Attribute::OptimizeForSize,66                       Attribute::OptimizeNone,67                       Attribute::ReadNone,68                       Attribute::ReadOnly,69                       Attribute::Returned,70                       Attribute::ReturnsTwice,71                       Attribute::SExt,72                       Attribute::StackAlignment,73                       Attribute::StackProtect,74                       Attribute::StackProtectReq,75                       Attribute::StackProtectStrong,76                       Attribute::SafeStack,77                       Attribute::StructRet,78                       Attribute::SanitizeAddress,79                       Attribute::SanitizeThread,80                       Attribute::SanitizeMemory,81                       Attribute::UWTable,82                       Attribute::ZExt},83                      Attr);84}85 86static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS,87                                   const StringSet<> &LiveKeys,88                                   bool AllowExperimental) {89  for (auto &Attr : AS) {90    if (!Attr.isStringAttribute())91      continue;92    StringRef Key = Attr.getKindAsString();93    if (LiveKeys.contains(Key))94      continue;95    if (AllowExperimental && Key.starts_with("exp-"))96      continue;97    DeadAttrs.addAttribute(Key);98  }99}100 101static void removeStringFunctionAttributes(Function &F,102                                           bool AllowExperimental) {103  AttributeList Attrs = F.getAttributes();104  const StringSet<> LiveKeys = {"waveops-include-helper-lanes",105                                "fp32-denorm-mode"};106  // Collect DeadKeys in FnAttrs.107  AttributeMask DeadAttrs;108  collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys,109                         AllowExperimental);110  collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys,111                         AllowExperimental);112 113  F.removeFnAttrs(DeadAttrs);114  F.removeRetAttrs(DeadAttrs);115}116 117class DXILPrepareModule : public ModulePass {118 119  static Value *maybeGenerateBitcast(IRBuilder<> &Builder,120                                     PointerTypeMap &PointerTypes,121                                     Instruction &Inst, Value *Operand,122                                     Type *Ty) {123    // Omit bitcasts if the incoming value matches the instruction type.124    auto It = PointerTypes.find(Operand);125    if (It != PointerTypes.end()) {126      auto *OpTy = cast<TypedPointerType>(It->second)->getElementType();127      if (OpTy == Ty)128        return nullptr;129    }130 131    Type *ValTy = Operand->getType();132    // Also omit the bitcast for matching global array types133    if (auto *GlobalVar = dyn_cast<GlobalVariable>(Operand))134      ValTy = GlobalVar->getValueType();135 136    if (auto *AI = dyn_cast<AllocaInst>(Operand))137      ValTy = AI->getAllocatedType();138 139    if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {140      Type *ElTy = ArrTy->getElementType();141      if (ElTy == Ty)142        return nullptr;143    }144 145    // finally, drill down GEP instructions until we get the array146    // that is being accessed, and compare element types147    if (ConstantExpr *GEPInstr = dyn_cast<ConstantExpr>(Operand)) {148      while (GEPInstr->getOpcode() == Instruction::GetElementPtr) {149        Value *OpArg = GEPInstr->getOperand(0);150        if (ConstantExpr *NewGEPInstr = dyn_cast<ConstantExpr>(OpArg)) {151          GEPInstr = NewGEPInstr;152          continue;153        }154 155        if (auto *GlobalVar = dyn_cast<GlobalVariable>(OpArg))156          ValTy = GlobalVar->getValueType();157        if (auto *AI = dyn_cast<AllocaInst>(Operand))158          ValTy = AI->getAllocatedType();159        if (auto *ArrTy = dyn_cast<ArrayType>(ValTy)) {160          Type *ElTy = ArrTy->getElementType();161          if (ElTy == Ty)162            return nullptr;163        }164        break;165      }166    }167 168    // Insert bitcasts where we are removing the instruction.169    Builder.SetInsertPoint(&Inst);170    // This code only gets hit in opaque-pointer mode, so the type of the171    // pointer doesn't matter.172    PointerType *PtrTy = cast<PointerType>(Operand->getType());173    return Builder.Insert(174        CastInst::Create(Instruction::BitCast, Operand,175                         Builder.getPtrTy(PtrTy->getAddressSpace())));176  }177 178public:179  bool runOnModule(Module &M) override {180    PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M);181    AttributeMask AttrMask;182    for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;183         I = Attribute::AttrKind(I + 1)) {184      if (!isValidForDXIL(I))185        AttrMask.addAttribute(I);186    }187 188    const dxil::ModuleMetadataInfo MetadataInfo =189        getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();190    VersionTuple ValVer = MetadataInfo.ValidatorVersion;191    bool AllowExperimental = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;192 193    for (auto &F : M.functions()) {194      F.removeFnAttrs(AttrMask);195      F.removeRetAttrs(AttrMask);196      // Only remove string attributes if we are not skipping validation.197      // This will reserve the experimental attributes when validation version198      // is 0.0 for experiment mode.199      removeStringFunctionAttributes(F, AllowExperimental);200      for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)201        F.removeParamAttrs(Idx, AttrMask);202 203      for (auto &BB : F) {204        IRBuilder<> Builder(&BB);205        for (auto &I : make_early_inc_range(BB)) {206 207          if (auto *CB = dyn_cast<CallBase>(&I)) {208            CB->removeFnAttrs(AttrMask);209            CB->removeRetAttrs(AttrMask);210            for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)211              CB->removeParamAttrs(Idx, AttrMask);212            continue;213          }214 215          // Emtting NoOp bitcast instructions allows the ValueEnumerator to be216          // unmodified as it reserves instruction IDs during contruction.217          if (auto *LI = dyn_cast<LoadInst>(&I)) {218            if (Value *NoOpBitcast = maybeGenerateBitcast(219                    Builder, PointerTypes, I, LI->getPointerOperand(),220                    LI->getType())) {221              LI->replaceAllUsesWith(222                  Builder.CreateLoad(LI->getType(), NoOpBitcast));223              LI->eraseFromParent();224            }225            continue;226          }227          if (auto *SI = dyn_cast<StoreInst>(&I)) {228            if (Value *NoOpBitcast = maybeGenerateBitcast(229                    Builder, PointerTypes, I, SI->getPointerOperand(),230                    SI->getValueOperand()->getType())) {231 232              SI->replaceAllUsesWith(233                  Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));234              SI->eraseFromParent();235            }236            continue;237          }238          if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {239            if (Value *NoOpBitcast = maybeGenerateBitcast(240                    Builder, PointerTypes, I, GEP->getPointerOperand(),241                    GEP->getSourceElementType()))242              GEP->setOperand(0, NoOpBitcast);243            continue;244          }245        }246      }247    }248 249    return true;250  }251 252  DXILPrepareModule() : ModulePass(ID) {}253  void getAnalysisUsage(AnalysisUsage &AU) const override {254    AU.addRequired<DXILMetadataAnalysisWrapperPass>();255 256    AU.addPreserved<DXILMetadataAnalysisWrapperPass>();257    AU.addPreserved<DXILResourceWrapperPass>();258    AU.addPreserved<RootSignatureAnalysisWrapper>();259    AU.addPreserved<ShaderFlagsAnalysisWrapper>();260  }261  static char ID; // Pass identification.262};263char DXILPrepareModule::ID = 0;264 265} // end anonymous namespace266 267INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",268                      false, false)269INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass)270INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,271                    false)272 273ModulePass *llvm::createDXILPrepareModulePass() {274  return new DXILPrepareModule();275}276