| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // DxilPromoteResourcePasses.cpp //
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- // This file is distributed under the University of Illinois Open Source //
- // License. See LICENSE.TXT for details. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
- #include "dxc/DXIL/DxilUtil.h"
- #include "dxc/HLSL/DxilGenerationPass.h"
- #include "dxc/HLSL/HLModule.h"
- #include "llvm/Pass.h"
- #include "llvm/Analysis/AssumptionCache.h"
- #include "llvm/IR/Dominators.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/Instruction.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/LLVMContext.h"
- #include "llvm/IR/Module.h"
- #include "llvm/IR/Operator.h"
- #include "llvm/Transforms/Utils/PromoteMemToReg.h"
- #include "llvm/Transforms/Utils/SSAUpdater.h"
- #include <unordered_set>
- #include <vector>
- using namespace llvm;
- using namespace hlsl;
- // Legalize resource use.
- // Map local or static global resource to global resource.
- // Require inline for static global resource.
- namespace {
- static const StringRef kStaticResourceLibErrorMsg = "static global resource use is disallowed in library exports.";
- class DxilPromoteStaticResources : public ModulePass {
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit DxilPromoteStaticResources()
- : ModulePass(ID) {}
- const char *getPassName() const override {
- return "DXIL Legalize Static Resource Use";
- }
- bool runOnModule(Module &M) override {
- // Promote static global variables.
- return PromoteStaticGlobalResources(M);
- }
- private:
- bool PromoteStaticGlobalResources(Module &M);
- };
- char DxilPromoteStaticResources::ID = 0;
- class DxilPromoteLocalResources : public FunctionPass {
- void getAnalysisUsage(AnalysisUsage &AU) const override;
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit DxilPromoteLocalResources()
- : FunctionPass(ID) {}
- const char *getPassName() const override {
- return "DXIL Legalize Resource Use";
- }
- bool runOnFunction(Function &F) override {
- // Promote local resource first.
- return PromoteLocalResource(F);
- }
- private:
- bool PromoteLocalResource(Function &F);
- };
- char DxilPromoteLocalResources::ID = 0;
- }
- void DxilPromoteLocalResources::getAnalysisUsage(AnalysisUsage &AU) const {
- AU.addRequired<AssumptionCacheTracker>();
- AU.addRequired<DominatorTreeWrapperPass>();
- AU.setPreservesAll();
- }
- bool DxilPromoteLocalResources::PromoteLocalResource(Function &F) {
- bool bModified = false;
- std::vector<AllocaInst *> Allocas;
- DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- AssumptionCache &AC =
- getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
- BasicBlock &BB = F.getEntryBlock();
- unsigned allocaSize = 0;
- while (1) {
- Allocas.clear();
- // Find allocas that are safe to promote, by looking at all instructions in
- // the entry node
- for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I)
- if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) { // Is it an alloca?
- if (dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(AI->getAllocatedType()))) {
- if (isAllocaPromotable(AI))
- Allocas.push_back(AI);
- }
- }
- if (Allocas.empty())
- break;
- // No update.
- // Report error and break.
- if (allocaSize == Allocas.size()) {
- F.getContext().emitError(dxilutil::kResourceMapErrorMsg);
- break;
- }
- allocaSize = Allocas.size();
- PromoteMemToReg(Allocas, *DT, nullptr, &AC);
- bModified = true;
- }
- return bModified;
- }
- FunctionPass *llvm::createDxilPromoteLocalResources() {
- return new DxilPromoteLocalResources();
- }
- INITIALIZE_PASS_BEGIN(DxilPromoteLocalResources,
- "hlsl-dxil-promote-local-resources",
- "DXIL promote local resource use", false, true)
- INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
- INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
- INITIALIZE_PASS_END(DxilPromoteLocalResources,
- "hlsl-dxil-promote-local-resources",
- "DXIL promote local resource use", false, true)
- bool DxilPromoteStaticResources::PromoteStaticGlobalResources(
- Module &M) {
- if (M.GetOrCreateHLModule().GetShaderModel()->IsLib()) {
- // Read/write to global static resource is disallowed for libraries:
- // Resource use needs to be resolved to a single real global resource,
- // but it may not be possible since any external function call may re-enter
- // at any other library export, which could modify the global static
- // between write and read.
- // While it could work for certain cases, describing the boundary at
- // the HLSL level is difficult, so at this point it's better to disallow.
- // example of what could work:
- // After inlining, exported functions must have writes to static globals
- // before reads, and must not have any external function calls between
- // writes and subsequent reads, such that the static global may be
- // optimized away for the exported function.
- for (auto &GV : M.globals()) {
- if (GV.getLinkage() == GlobalVariable::LinkageTypes::InternalLinkage &&
- dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(GV.getType()))) {
- if (!GV.user_empty()) {
- if (Instruction *I = dyn_cast<Instruction>(*GV.user_begin())) {
- dxilutil::EmitErrorOnInstruction(I, kStaticResourceLibErrorMsg);
- break;
- }
- }
- }
- }
- return false;
- }
- bool bModified = false;
- std::set<GlobalVariable *> staticResources;
- for (auto &GV : M.globals()) {
- if (GV.getLinkage() == GlobalVariable::LinkageTypes::InternalLinkage &&
- dxilutil::IsHLSLObjectType(dxilutil::GetArrayEltTy(GV.getType()))) {
- staticResources.insert(&GV);
- }
- }
- SSAUpdater SSA;
- SmallVector<Instruction *, 4> Insts;
- // Make sure every resource load has mapped to global variable.
- while (!staticResources.empty()) {
- bool bUpdated = false;
- for (auto it = staticResources.begin(); it != staticResources.end();) {
- GlobalVariable *GV = *(it++);
- // Build list of instructions to promote.
- for (User *U : GV->users()) {
- if (isa<LoadInst>(U) || isa<StoreInst>(U)) {
- Insts.emplace_back(cast<Instruction>(U));
- } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
- for (User *gepU : GEP->users()) {
- DXASSERT_NOMSG(isa<LoadInst>(gepU) || isa<StoreInst>(gepU));
- if (isa<LoadInst>(gepU) || isa<StoreInst>(gepU))
- Insts.emplace_back(cast<Instruction>(gepU));
- }
- } else {
- DXASSERT(false, "Unhandled user of resource static global");
- }
- }
- LoadAndStorePromoter(Insts, SSA).run(Insts);
- GV->removeDeadConstantUsers();
- if (GV->user_empty()) {
- bUpdated = true;
- staticResources.erase(GV);
- }
- Insts.clear();
- }
- if (!bUpdated) {
- M.getContext().emitError(dxilutil::kResourceMapErrorMsg);
- break;
- }
- bModified = true;
- }
- return bModified;
- }
- ModulePass *llvm::createDxilPromoteStaticResources() {
- return new DxilPromoteStaticResources();
- }
- INITIALIZE_PASS(DxilPromoteStaticResources,
- "hlsl-dxil-promote-static-resources",
- "DXIL promote static resource use", false, false)
|