Files
llvm-project/llvm/lib/Target/DirectX/DXILCBufferAccess.cpp
Justin Bogner c4898f3f22 [HLSL][DirectX] Use a padding type for HLSL buffers. (#167404)
This change drops the use of the "Layout" type and instead uses explicit
padding throughout the compiler to represent types in HLSL buffers.

There are a few parts to this, though it's difficult to split them up as
they're very interdependent:

1. Refactor HLSLBufferLayoutBuilder to allow us to calculate the padding
of arbitrary types.
2. Teach Clang CodeGen to use HLSL specific paths for cbuffers when
generating aggregate copies, array accesses, and structure accesses.
3. Simplify DXILCBufferAccesses such that it directly replaces accesses
with dx.resource.getpointer rather than recalculating the layout.
4. Basic infrastructure for SPIR-V handling, but the implementation
itself will need work in follow ups.

Fixes several issues, including #138996, #144573, and #156084.
Resolves #147352.
2025-11-18 13:38:43 -08:00

93 lines
3.1 KiB
C++

//===- DXILCBufferAccess.cpp - Translate CBuffer Loads --------------------===//
//
// 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 "DXILCBufferAccess.h"
#include "DirectX.h"
#include "llvm/Analysis/DXILResource.h"
#include "llvm/Frontend/HLSL/CBuffer.h"
#include "llvm/Frontend/HLSL/HLSLResource.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/ReplaceConstant.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Transforms/Utils/Local.h"
#define DEBUG_TYPE "dxil-cbuffer-access"
using namespace llvm;
static void replaceUsersOfGlobal(GlobalVariable *Global,
GlobalVariable *HandleGV, size_t Offset) {
for (Use &U : make_early_inc_range(Global->uses())) {
auto UseInst = dyn_cast<Instruction>(U.getUser());
// TODO: Constants? Metadata?
assert(UseInst && "Non-instruction use of cbuffer");
IRBuilder<> Builder(UseInst);
LoadInst *Handle = Builder.CreateLoad(HandleGV->getValueType(), HandleGV,
HandleGV->getName());
Value *Ptr = Builder.CreateIntrinsic(
Global->getType(), Intrinsic::dx_resource_getpointer,
ArrayRef<Value *>{Handle,
ConstantInt::get(Builder.getInt32Ty(), Offset)});
U.set(Ptr);
}
Global->removeFromParent();
}
static bool replaceCBufferAccesses(Module &M) {
std::optional<hlsl::CBufferMetadata> CBufMD = hlsl::CBufferMetadata::get(
M, [](Type *Ty) { return isa<llvm::dxil::PaddingExtType>(Ty); });
if (!CBufMD)
return false;
SmallVector<Constant *> CBufferGlobals;
for (const hlsl::CBufferMapping &Mapping : *CBufMD)
for (const hlsl::CBufferMember &Member : Mapping.Members)
CBufferGlobals.push_back(Member.GV);
convertUsersOfConstantsToInstructions(CBufferGlobals);
for (const hlsl::CBufferMapping &Mapping : *CBufMD)
for (const hlsl::CBufferMember &Member : Mapping.Members)
replaceUsersOfGlobal(Member.GV, Mapping.Handle, Member.Offset);
CBufMD->eraseFromModule();
return true;
}
PreservedAnalyses DXILCBufferAccess::run(Module &M, ModuleAnalysisManager &AM) {
PreservedAnalyses PA;
bool Changed = replaceCBufferAccesses(M);
if (!Changed)
return PreservedAnalyses::all();
return PA;
}
namespace {
class DXILCBufferAccessLegacy : public ModulePass {
public:
bool runOnModule(Module &M) override { return replaceCBufferAccesses(M); }
StringRef getPassName() const override { return "DXIL CBuffer Access"; }
DXILCBufferAccessLegacy() : ModulePass(ID) {}
static char ID; // Pass identification.
};
char DXILCBufferAccessLegacy::ID = 0;
} // end anonymous namespace
INITIALIZE_PASS(DXILCBufferAccessLegacy, DEBUG_TYPE, "DXIL CBuffer Access",
false, false)
ModulePass *llvm::createDXILCBufferAccessLegacyPass() {
return new DXILCBufferAccessLegacy();
}