Path: blob/main/contrib/llvm-project/llvm/lib/Target/DirectX/DXILPrepare.cpp
35269 views
//===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file This file contains pases and utilities to convert a modern LLVM9/// module into a module compatible with the LLVM 3.7-based DirectX Intermediate10/// Language (DXIL).11//===----------------------------------------------------------------------===//1213#include "DXILMetadata.h"14#include "DXILResourceAnalysis.h"15#include "DXILShaderFlags.h"16#include "DirectX.h"17#include "DirectXIRPasses/PointerTypeAnalysis.h"18#include "llvm/ADT/STLExtras.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/ADT/StringSet.h"21#include "llvm/CodeGen/Passes.h"22#include "llvm/IR/AttributeMask.h"23#include "llvm/IR/IRBuilder.h"24#include "llvm/IR/Instruction.h"25#include "llvm/IR/Module.h"26#include "llvm/InitializePasses.h"27#include "llvm/Pass.h"28#include "llvm/Support/Compiler.h"29#include "llvm/Support/VersionTuple.h"3031#define DEBUG_TYPE "dxil-prepare"3233using namespace llvm;34using namespace llvm::dxil;3536namespace {3738constexpr bool isValidForDXIL(Attribute::AttrKind Attr) {39return is_contained({Attribute::Alignment,40Attribute::AlwaysInline,41Attribute::Builtin,42Attribute::ByVal,43Attribute::InAlloca,44Attribute::Cold,45Attribute::Convergent,46Attribute::InlineHint,47Attribute::InReg,48Attribute::JumpTable,49Attribute::MinSize,50Attribute::Naked,51Attribute::Nest,52Attribute::NoAlias,53Attribute::NoBuiltin,54Attribute::NoCapture,55Attribute::NoDuplicate,56Attribute::NoImplicitFloat,57Attribute::NoInline,58Attribute::NonLazyBind,59Attribute::NonNull,60Attribute::Dereferenceable,61Attribute::DereferenceableOrNull,62Attribute::Memory,63Attribute::NoRedZone,64Attribute::NoReturn,65Attribute::NoUnwind,66Attribute::OptimizeForSize,67Attribute::OptimizeNone,68Attribute::ReadNone,69Attribute::ReadOnly,70Attribute::Returned,71Attribute::ReturnsTwice,72Attribute::SExt,73Attribute::StackAlignment,74Attribute::StackProtect,75Attribute::StackProtectReq,76Attribute::StackProtectStrong,77Attribute::SafeStack,78Attribute::StructRet,79Attribute::SanitizeAddress,80Attribute::SanitizeThread,81Attribute::SanitizeMemory,82Attribute::UWTable,83Attribute::ZExt},84Attr);85}8687static void collectDeadStringAttrs(AttributeMask &DeadAttrs, AttributeSet &&AS,88const StringSet<> &LiveKeys,89bool AllowExperimental) {90for (auto &Attr : AS) {91if (!Attr.isStringAttribute())92continue;93StringRef Key = Attr.getKindAsString();94if (LiveKeys.contains(Key))95continue;96if (AllowExperimental && Key.starts_with("exp-"))97continue;98DeadAttrs.addAttribute(Key);99}100}101102static void removeStringFunctionAttributes(Function &F,103bool AllowExperimental) {104AttributeList Attrs = F.getAttributes();105const StringSet<> LiveKeys = {"waveops-include-helper-lanes",106"fp32-denorm-mode"};107// Collect DeadKeys in FnAttrs.108AttributeMask DeadAttrs;109collectDeadStringAttrs(DeadAttrs, Attrs.getFnAttrs(), LiveKeys,110AllowExperimental);111collectDeadStringAttrs(DeadAttrs, Attrs.getRetAttrs(), LiveKeys,112AllowExperimental);113114F.removeFnAttrs(DeadAttrs);115F.removeRetAttrs(DeadAttrs);116}117118static void cleanModuleFlags(Module &M) {119NamedMDNode *MDFlags = M.getModuleFlagsMetadata();120if (!MDFlags)121return;122123SmallVector<llvm::Module::ModuleFlagEntry> FlagEntries;124M.getModuleFlagsMetadata(FlagEntries);125bool Updated = false;126for (auto &Flag : FlagEntries) {127// llvm 3.7 only supports behavior up to AppendUnique.128if (Flag.Behavior <= Module::ModFlagBehavior::AppendUnique)129continue;130Flag.Behavior = Module::ModFlagBehavior::Warning;131Updated = true;132}133134if (!Updated)135return;136137MDFlags->eraseFromParent();138139for (auto &Flag : FlagEntries)140M.addModuleFlag(Flag.Behavior, Flag.Key->getString(), Flag.Val);141}142143class DXILPrepareModule : public ModulePass {144145static Value *maybeGenerateBitcast(IRBuilder<> &Builder,146PointerTypeMap &PointerTypes,147Instruction &Inst, Value *Operand,148Type *Ty) {149// Omit bitcasts if the incoming value matches the instruction type.150auto It = PointerTypes.find(Operand);151if (It != PointerTypes.end())152if (cast<TypedPointerType>(It->second)->getElementType() == Ty)153return nullptr;154// Insert bitcasts where we are removing the instruction.155Builder.SetInsertPoint(&Inst);156// This code only gets hit in opaque-pointer mode, so the type of the157// pointer doesn't matter.158PointerType *PtrTy = cast<PointerType>(Operand->getType());159return Builder.Insert(160CastInst::Create(Instruction::BitCast, Operand,161Builder.getPtrTy(PtrTy->getAddressSpace())));162}163164public:165bool runOnModule(Module &M) override {166PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M);167AttributeMask AttrMask;168for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;169I = Attribute::AttrKind(I + 1)) {170if (!isValidForDXIL(I))171AttrMask.addAttribute(I);172}173174dxil::ValidatorVersionMD ValVerMD(M);175VersionTuple ValVer = ValVerMD.getAsVersionTuple();176bool SkipValidation = ValVer.getMajor() == 0 && ValVer.getMinor() == 0;177178for (auto &F : M.functions()) {179F.removeFnAttrs(AttrMask);180F.removeRetAttrs(AttrMask);181// Only remove string attributes if we are not skipping validation.182// This will reserve the experimental attributes when validation version183// is 0.0 for experiment mode.184removeStringFunctionAttributes(F, SkipValidation);185for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)186F.removeParamAttrs(Idx, AttrMask);187188for (auto &BB : F) {189IRBuilder<> Builder(&BB);190for (auto &I : make_early_inc_range(BB)) {191if (I.getOpcode() == Instruction::FNeg) {192Builder.SetInsertPoint(&I);193Value *In = I.getOperand(0);194Value *Zero = ConstantFP::get(In->getType(), -0.0);195I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));196I.eraseFromParent();197continue;198}199200// Emtting NoOp bitcast instructions allows the ValueEnumerator to be201// unmodified as it reserves instruction IDs during contruction.202if (auto LI = dyn_cast<LoadInst>(&I)) {203if (Value *NoOpBitcast = maybeGenerateBitcast(204Builder, PointerTypes, I, LI->getPointerOperand(),205LI->getType())) {206LI->replaceAllUsesWith(207Builder.CreateLoad(LI->getType(), NoOpBitcast));208LI->eraseFromParent();209}210continue;211}212if (auto SI = dyn_cast<StoreInst>(&I)) {213if (Value *NoOpBitcast = maybeGenerateBitcast(214Builder, PointerTypes, I, SI->getPointerOperand(),215SI->getValueOperand()->getType())) {216217SI->replaceAllUsesWith(218Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));219SI->eraseFromParent();220}221continue;222}223if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {224if (Value *NoOpBitcast = maybeGenerateBitcast(225Builder, PointerTypes, I, GEP->getPointerOperand(),226GEP->getSourceElementType()))227GEP->setOperand(0, NoOpBitcast);228continue;229}230if (auto *CB = dyn_cast<CallBase>(&I)) {231CB->removeFnAttrs(AttrMask);232CB->removeRetAttrs(AttrMask);233for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)234CB->removeParamAttrs(Idx, AttrMask);235continue;236}237}238}239}240// Remove flags not for DXIL.241cleanModuleFlags(M);242return true;243}244245DXILPrepareModule() : ModulePass(ID) {}246void getAnalysisUsage(AnalysisUsage &AU) const override {247AU.addPreserved<ShaderFlagsAnalysisWrapper>();248AU.addPreserved<DXILResourceWrapper>();249}250static char ID; // Pass identification.251};252char DXILPrepareModule::ID = 0;253254} // end anonymous namespace255256INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",257false, false)258INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,259false)260261ModulePass *llvm::createDXILPrepareModulePass() {262return new DXILPrepareModule();263}264265266