llvm-project/llvm/lib/Target/DirectX/DXILResourceImplicitBinding.cpp
Helena Kotas 74ad4baef0
[HLSL] Move DXILResourceImplicitBinding pass closer to DXIL Resource Analysis (#140981)
Moving `DXILResourceImplicitBinding` pass and the associated `DXILResourceBindingAnalysis` lower in the llc pipeline to just before the DXIL Resource Analysis, which is where its results are first needed, and adjusting the set of analyses it preserves.

The reason for this change is that I will soon be adding `DXILResourceBindingAnalysis` dependency to `DXILPostOptimizationValidation` pass and bringing this closer to where it is needed avoid unnecessary churn to preserved analysis setting in preceding passes.
2025-05-29 10:12:09 -07:00

191 lines
6.2 KiB
C++

//===- DXILResourceImplicitBinding.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "DXILResourceImplicitBinding.h"
#include "DirectX.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/DXILResource.h"
#include "llvm/IR/Analysis.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include <cstdint>
#define DEBUG_TYPE "dxil-resource-implicit-binding"
using namespace llvm;
using namespace llvm::dxil;
namespace {
static void diagnoseImplicitBindingNotFound(CallInst *ImplBindingCall) {
Function *F = ImplBindingCall->getFunction();
LLVMContext &Context = F->getParent()->getContext();
// FIXME: include the name of the resource in the error message
// (llvm/llvm-project#137868)
Context.diagnose(
DiagnosticInfoGenericWithLoc("resource cannot be allocated", *F,
ImplBindingCall->getDebugLoc(), DS_Error));
}
static bool assignBindings(Module &M, DXILResourceBindingInfo &DRBI,
DXILResourceTypeMap &DRTM) {
struct ImplicitBindingCall {
int OrderID;
CallInst *Call;
ImplicitBindingCall(int OrderID, CallInst *Call)
: OrderID(OrderID), Call(Call) {}
};
SmallVector<ImplicitBindingCall> Calls;
SmallVector<Function *> FunctionsToMaybeRemove;
// collect all of the llvm.dx.resource.handlefromImplicitbinding calls
for (Function &F : M.functions()) {
if (!F.isDeclaration())
continue;
if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefromimplicitbinding)
continue;
for (User *U : F.users()) {
if (CallInst *CI = dyn_cast<CallInst>(U)) {
int OrderID = cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
Calls.emplace_back(OrderID, CI);
}
}
FunctionsToMaybeRemove.emplace_back(&F);
}
// sort all the collected implicit bindings by OrderID
llvm::stable_sort(
Calls, [](auto &LHS, auto &RHS) { return LHS.OrderID < RHS.OrderID; });
// iterate over sorted calls, find binding for each new OrderID and replace
// each call with dx_resource_handlefrombinding using the new binding
int LastOrderID = -1;
llvm::TargetExtType *HandleTy = nullptr;
ConstantInt *RegSlotOp = nullptr;
bool AllBindingsAssigned = true;
bool Changed = false;
for (ImplicitBindingCall &IB : Calls) {
IRBuilder<> Builder(IB.Call);
if (IB.OrderID != LastOrderID) {
LastOrderID = IB.OrderID;
HandleTy = cast<TargetExtType>(IB.Call->getType());
ResourceTypeInfo &RTI = DRTM[HandleTy];
uint32_t Space =
cast<ConstantInt>(IB.Call->getArgOperand(1))->getZExtValue();
int32_t Size =
cast<ConstantInt>(IB.Call->getArgOperand(2))->getZExtValue();
std::optional<uint32_t> RegSlot =
DRBI.findAvailableBinding(RTI.getResourceClass(), Space, Size);
if (!RegSlot) {
diagnoseImplicitBindingNotFound(IB.Call);
AllBindingsAssigned = false;
continue;
}
RegSlotOp = ConstantInt::get(Builder.getInt32Ty(), RegSlot.value());
}
if (!RegSlotOp)
continue;
auto *NewCall = Builder.CreateIntrinsic(
HandleTy, Intrinsic::dx_resource_handlefrombinding,
{IB.Call->getOperand(1), /* space */
RegSlotOp, /* register slot */
IB.Call->getOperand(2), /* size */
IB.Call->getOperand(3), /* index */
IB.Call->getOperand(4), /* non-uniform flag */
IB.Call->getOperand(5)}); /* name */
IB.Call->replaceAllUsesWith(NewCall);
IB.Call->eraseFromParent();
Changed = true;
}
for (Function *F : FunctionsToMaybeRemove) {
if (F->user_empty()) {
F->eraseFromParent();
Changed = true;
}
}
DRBI.setHasImplicitBinding(!AllBindingsAssigned);
return Changed;
}
} // end anonymous namespace
PreservedAnalyses DXILResourceImplicitBinding::run(Module &M,
ModuleAnalysisManager &AM) {
DXILResourceBindingInfo &DRBI = AM.getResult<DXILResourceBindingAnalysis>(M);
DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
if (!DRBI.hasImplicitBinding())
return PreservedAnalyses::all();
if (!assignBindings(M, DRBI, DRTM))
return PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserve<DXILResourceBindingAnalysis>();
PA.preserve<DXILResourceTypeAnalysis>();
return PA;
}
namespace {
class DXILResourceImplicitBindingLegacy : public ModulePass {
public:
DXILResourceImplicitBindingLegacy() : ModulePass(ID) {}
bool runOnModule(Module &M) override {
DXILResourceTypeMap &DRTM =
getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
DXILResourceBindingInfo &DRBI =
getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
if (DRBI.hasImplicitBinding())
return assignBindings(M, DRBI, DRTM);
return false;
}
static char ID; // Pass identification.
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.addRequired<DXILResourceTypeWrapperPass>();
AU.addRequired<DXILResourceBindingWrapperPass>();
AU.addPreserved<DXILResourceTypeWrapperPass>();
AU.addPreserved<DXILResourceBindingWrapperPass>();
}
};
char DXILResourceImplicitBindingLegacy::ID = 0;
} // end anonymous namespace
INITIALIZE_PASS_BEGIN(DXILResourceImplicitBindingLegacy, DEBUG_TYPE,
"DXIL Resource Implicit Binding", false, false)
INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
INITIALIZE_PASS_END(DXILResourceImplicitBindingLegacy, DEBUG_TYPE,
"DXIL Resource Implicit Binding", false, false)
ModulePass *llvm::createDXILResourceImplicitBindingLegacyPass() {
return new DXILResourceImplicitBindingLegacy();
}