[llvm] Lower llvm.dx.rawBufferLoad to dxil ops (PR #116845)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 19 10:32:00 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Zhengxing li (lizhengxing)
<details>
<summary>Changes</summary>
It's the draft PR of llvm.dx.rawbufferload.
There are 3 commits.
The DXILResourceMap change: [[[DirectX] Add Resource uses to Resource Handle map in DXILResourceMap · lizhengxing/llvm-project@<!-- -->392daa1](https://github.com/lizhengxing/llvm-project/commit/392daa10503f89a2f081ec2df2fea5ea5db980f6)](https://github.com/llvm/llvm-project/pull/116845/commits/8e1bca0aa7269bcb210d2e5e1a95e7d8375ba162)
The Raw Buffer Load change: [[Lower llvm.dx.rawbufferload to dxil ops · lizhengxing/llvm-project@<!-- -->731703f](https://github.com/lizhengxing/llvm-project/commit/731703f8130d47d5d2e3b89ff413ef7d4d38523e)](https://github.com/llvm/llvm-project/pull/116845/commits/27c361bd7cf21506e46b074c59a57bbd6c60ceb1)
I separate the DXILResourceMap change in the Raw Buffer Load PR to the third commit. [[Changes in DXILResourceMap for lowering llvm.dx.rawbufferload to dxil… · lizhengxing/llvm-project@<!-- -->5abec9d](https://github.com/lizhengxing/llvm-project/commit/5abec9db0adc2203355478e524dcc651336c3f40)](https://github.com/llvm/llvm-project/pull/116845/commits/3a8f3a1996ed2c87aae08632fcb4fc08893cfae1)
---
Patch is 30.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/116845.diff
8 Files Affected:
- (modified) llvm/include/llvm/Analysis/DXILResource.h (+32)
- (modified) llvm/include/llvm/IR/IntrinsicsDirectX.td (+3)
- (modified) llvm/lib/Analysis/DXILResource.cpp (+69)
- (modified) llvm/lib/Target/DirectX/DXIL.td (+11)
- (modified) llvm/lib/Target/DirectX/DXILOpLowering.cpp (+199)
- (added) llvm/test/Analysis/DXILResource/resource-map.ll (+36)
- (added) llvm/test/CodeGen/DirectX/DXILResource/dxil-resource-map.ll (+48)
- (added) llvm/test/CodeGen/DirectX/RawBufferLoad.ll (+192)
``````````diff
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 6b577c02f05450..7f64688fba183a 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -264,6 +264,8 @@ class ResourceInfo {
class DXILResourceMap {
SmallVector<dxil::ResourceInfo> Resources;
DenseMap<CallInst *, unsigned> CallMap;
+ // Mapping from Resource use to Resource Handle
+ DenseMap<CallInst *, CallInst *> ResUseToHandleMap;
unsigned FirstUAV = 0;
unsigned FirstCBuffer = 0;
unsigned FirstSampler = 0;
@@ -335,6 +337,36 @@ class DXILResourceMap {
}
void print(raw_ostream &OS) const;
+
+ void updateResourceMap(CallInst *origCallInst, CallInst *newCallInst);
+
+ // Update ResUseMap with multiple new resource uses
+ void updateResUseMap(CallInst *origResUse,
+ std::vector<Value *> &multiNewResUse);
+
+ // Update ResUseMap with single new resource use
+ void updateResUseMap(CallInst *origResUse, CallInst *newResUse) {
+ assert((origResUse != nullptr) && (newResUse != nullptr) &&
+ (origResUse != newResUse) && "Wrong Inputs");
+
+ updateResUseMapCommon(origResUse, newResUse, /*keepOrigResUseInMap=*/false);
+ }
+
+ CallInst *findResHandleByUse(CallInst *resUse) {
+ auto Pos = ResUseToHandleMap.find(resUse);
+ assert((Pos != ResUseToHandleMap.end()) &&
+ "Can't find the resource handle");
+
+ return Pos->second;
+ }
+
+private:
+ void updateResUseMapCommon(CallInst *origResUse, CallInst *newResUse,
+ bool keepOrigResUseInMap) {
+ ResUseToHandleMap.try_emplace(newResUse, findResHandleByUse(origResUse));
+ if (!keepOrigResUseInMap)
+ ResUseToHandleMap.erase(origResUse);
+ }
};
class DXILResourceAnalysis : public AnalysisInfoMixin<DXILResourceAnalysis> {
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 48a9595f844f05..d8be8d002a0917 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -27,6 +27,9 @@ def int_dx_handle_fromBinding
[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty],
[IntrNoMem]>;
+def int_dx_rawBufferLoad
+ : DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_i32_ty, llvm_i32_ty]>;
+
def int_dx_typedBufferLoad
: DefaultAttrsIntrinsic<[llvm_any_ty], [llvm_any_ty, llvm_i32_ty],
[IntrReadMem]>;
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 2802480481690d..be4fad8a84a171 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -719,6 +719,12 @@ DXILResourceMap::DXILResourceMap(
if (Resources.empty() || RI != Resources.back())
Resources.push_back(RI);
CallMap[CI] = Resources.size() - 1;
+
+ // Build ResUseToHandleMap
+ for (auto it = CI->users().begin(); it != CI->users().end(); ++it) {
+ CallInst *CI_Use = dyn_cast<CallInst>(*it);
+ ResUseToHandleMap[CI_Use] = CI;
+ }
}
unsigned Size = Resources.size();
@@ -744,6 +750,61 @@ DXILResourceMap::DXILResourceMap(
}
}
+// Parameter origCallInst: original Resource Handle
+// Parameter newCallInst: new Resource Handle
+//
+// This function is needed when origCallInst's lowered to newCallInst.
+//
+// Because origCallInst and its uses will be replaced by newCallInst and new def
+// instructions after lowering. The [origCallInst, resource info] entry in
+// CallMap and [origCallInst's use, origCallInst] entries in ResUseToHandleMap
+// have to be updated per the changes in lowering.
+//
+// What this function does are:
+// 1. Add [newCallInst, resource info] entry in CallMap
+// 2. Remove [origCallInst, resource info] entry in CallMap
+// 3. Remap [origCallInst's use, origCallInst] entries to
+// [origCallInst's use, newCallInst] entries in ResUseToHandleMap
+//
+// Remove those entries related to origCallInst in maps is necessary since
+// origCallInst's no longer existing after lowering. Moreover, keeping those
+// entries in maps will crash DXILResourceMap::print function
+//
+// FYI:
+// Make sure to invoke this function before origCallInst->replaceAllUsesWith()
+// and origCallInst->eraseFromParent() since this function needs to visit
+// origCallInst and its uses.
+//
+void DXILResourceMap::updateResourceMap(CallInst *origCallInst,
+ CallInst *newCallInst) {
+ assert((origCallInst != nullptr) && (newCallInst != nullptr) &&
+ (origCallInst != newCallInst));
+
+ CallMap.try_emplace(newCallInst, CallMap[origCallInst]);
+ CallMap.erase(origCallInst);
+
+ // Update ResUseToHandleMap since Resource Handle changed
+ for (auto it = origCallInst->users().begin();
+ it != origCallInst->users().end(); ++it) {
+ CallInst *CI_Use = dyn_cast<CallInst>(*it);
+ ResUseToHandleMap[CI_Use] = newCallInst;
+ }
+}
+
+ void DXILResourceMap::updateResUseMap(CallInst *origResUse,
+ std::vector<Value *> &multiNewResUse) {
+ assert((origResUse != nullptr) && "Wrong Inputs");
+
+ for (int i = 0; i < multiNewResUse.size(); ++i) {
+ CallInst *newResUse = dyn_cast<CallInst>(multiNewResUse[i]);
+ assert(newResUse != nullptr);
+
+ bool keepOrigResUseInMap =
+ i == (multiNewResUse.size() - 1) ? false : true;
+ updateResUseMapCommon(origResUse, newResUse, keepOrigResUseInMap);
+ }
+ }
+
void DXILResourceMap::print(raw_ostream &OS) const {
for (unsigned I = 0, E = Resources.size(); I != E; ++I) {
OS << "Binding " << I << ":\n";
@@ -756,6 +817,14 @@ void DXILResourceMap::print(raw_ostream &OS) const {
CI->print(OS);
OS << "\n";
}
+
+ for (const auto &[ResUse, ResHandle] : ResUseToHandleMap) {
+ OS << "\n";
+ OS << "Resource " << CallMap.find(ResHandle)->second;
+ OS << " is used by ";
+ ResUse->print(OS);
+ OS << "\n";
+ }
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index 1a8e110491cc87..a638371d6031ad 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -854,6 +854,17 @@ def AnnotateHandle : DXILOp<216, annotateHandle> {
let stages = [Stages<DXIL1_6, [all_stages]>];
}
+def RawBufferLoad : DXILOp<139, rawBufferLoad> {
+ let Doc = "reads from a ByteAddressBuffer or StructuredBuffer";
+ // Handle, Coord0, Coord1, mask, alignment
+ let arguments = [HandleTy, Int32Ty, Int32Ty, Int8Ty, Int32Ty];
+ let result = OverloadTy;
+ let overloads =
+ [Overloads<DXIL1_0,
+ [ResRetHalfTy, ResRetFloatTy, ResRetInt16Ty, ResRetInt32Ty]>];
+ let stages = [Stages<DXIL1_0, [all_stages]>];
+}
+
def CreateHandleFromBinding : DXILOp<217, createHandleFromBinding> {
let Doc = "create resource handle from binding";
let arguments = [ResBindTy, Int32Ty, Int1Ty];
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 9f124394363a38..d2b6f05fc936bd 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -249,6 +249,8 @@ class OpLowerer {
removeResourceGlobals(CI);
+ DRM.updateResourceMap(CI, *OpCall);
+
CI->replaceAllUsesWith(Cast);
CI->eraseFromParent();
return Error::success();
@@ -295,6 +297,8 @@ class OpLowerer {
removeResourceGlobals(CI);
+ DRM.updateResourceMap(CI, *OpBind);
+
CI->replaceAllUsesWith(Cast);
CI->eraseFromParent();
@@ -479,6 +483,9 @@ class OpLowerer {
OpCode::BufferLoad, Args, CI->getName(), NewRetTy);
if (Error E = OpCall.takeError())
return E;
+
+ DRM.updateResUseMap(CI, *OpCall);
+
if (Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
return E;
@@ -547,6 +554,8 @@ class OpLowerer {
if (Error E = OpCall.takeError())
return E;
+ DRM.updateResUseMap(CI, *OpCall);
+
CI->eraseFromParent();
return Error::success();
});
@@ -619,6 +628,193 @@ class OpLowerer {
});
}
+ Value *GenerateRawBufLd(Value *handle, Value *bufIdx, Value *offset, Type *Ty,
+ IRBuilder<> &Builder, unsigned NumComponents,
+ Constant *alignment) {
+ if (bufIdx == nullptr) {
+ // This is actually a byte address buffer load with a struct template
+ // type. The call takes only one coordinates for the offset.
+ bufIdx = offset;
+ offset = UndefValue::get(offset->getType());
+ }
+
+ // NumComponents 1: mask = 1 // Mask_X;
+ // NumComponents 2: mask = 3 // Mask_X | Mask_Y
+ // NumComponents 3: mask = 7 // Mask_X | Mask_Y | Mask_Z
+ // NumComponents 4: mask = 15 // Mask_X | Mask_Y | Mask_Z | Mask_W
+ assert((NumComponents) > 0 && (NumComponents < 5));
+ Constant *mask =
+ ConstantInt::get(Builder.getInt8Ty(), ((1 << NumComponents) - 1));
+
+ Value *Args[] = {handle, bufIdx, offset, mask, alignment};
+ Type *NewRetTy = OpBuilder.getResRetType(Ty->getScalarType());
+ Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
+ OpCode::RawBufferLoad, Args, "", NewRetTy); // TODO: Need name argument?
+ if (Error E = OpCall.takeError())
+ return nullptr;
+
+ return *OpCall;
+ }
+
+ void TranslateRawBufVecLd(Type *Ty, unsigned ElemCount, IRBuilder<> &Builder,
+ Value *handle, Value *bufIdx, Value *baseOffset,
+ const DataLayout &DL, std::vector<Value *> &bufLds,
+ unsigned baseAlign, bool isScalarTy) {
+ Type *VecEltTy = Ty->getScalarType();
+
+ unsigned EltSize = DL.getTypeAllocSize(VecEltTy);
+ unsigned alignment = std::min(baseAlign, EltSize);
+ Constant *alignmentVal =
+ ConstantInt::get(M.getContext(), APInt(32, alignment));
+
+ if (baseOffset == nullptr) {
+ baseOffset = ConstantInt::get(Builder.getInt32Ty(), 0);
+ }
+
+ std::vector<Value *> elts(ElemCount);
+ unsigned rest = (ElemCount % 4);
+ for (unsigned i = 0; i < ElemCount - rest; i += 4) {
+ Value *bufLd = GenerateRawBufLd(handle, bufIdx, baseOffset, Ty, Builder,
+ 4, alignmentVal);
+ bufLds.emplace_back(bufLd);
+
+ baseOffset = Builder.CreateAdd(
+ baseOffset, ConstantInt::get(Builder.getInt32Ty(), 4 * EltSize));
+ }
+
+ if (rest) {
+ Value *bufLd = GenerateRawBufLd(handle, bufIdx, baseOffset, Ty, Builder,
+ rest, alignmentVal);
+ bufLds.emplace_back(bufLd);
+ }
+ }
+
+ Error replaceMultiResRetsUses(CallInst *Intrin,
+ std::vector<Value *> &bufLds) {
+ IRBuilder<> &IRB = OpBuilder.getIRB();
+
+ // TODO: HasCheckBit????
+
+ Type *OldTy = Intrin->getType();
+
+ // For scalars, we just extract the first element.
+ if (!isa<FixedVectorType>(OldTy)) {
+ CallInst *Op = dyn_cast<CallInst>(bufLds[0]);
+ assert(Op != nullptr);
+ Value *EVI = IRB.CreateExtractValue(Op, 0);
+
+ Intrin->replaceAllUsesWith(EVI);
+ DRM.updateResUseMap(Intrin, Op);
+ Intrin->eraseFromParent();
+
+ return Error::success();
+ }
+
+ const auto *VecTy = cast<FixedVectorType>(OldTy);
+ const unsigned N = VecTy->getNumElements();
+
+ std::vector<Value *> Extracts(N);
+
+ // The users of the operation should all be scalarized, so we attempt to
+ // replace the extractelements with extractvalues directly.
+ for (Use &U : make_early_inc_range(Intrin->uses())) {
+ if (auto *EEI = dyn_cast<ExtractElementInst>(U.getUser())) {
+ if (auto *IndexOp = dyn_cast<ConstantInt>(EEI->getIndexOperand())) {
+ size_t IndexVal = IndexOp->getZExtValue();
+ assert(IndexVal < N && "Index into buffer load out of range");
+ if (!Extracts[IndexVal]) {
+ CallInst *Op = dyn_cast<CallInst>(bufLds[IndexVal / 4]);
+ assert(Op != nullptr);
+ Extracts[IndexVal] = IRB.CreateExtractValue(Op, IndexVal % 4);
+ }
+ EEI->replaceAllUsesWith(Extracts[IndexVal]);
+ EEI->eraseFromParent();
+ } else {
+ // Need to handle DynamicAccesses here???
+ }
+ }
+ }
+
+ // If there's a dynamic access we need to round trip through stack memory so
+ // that we don't leave vectors around.
+ //
+ // TODO: dynamic access for rawbuffer??????
+ //
+
+ // If we still have uses, then we're not fully scalarized and need to
+ // recreate the vector. This should only happen for things like exported
+ // functions from libraries.
+ if (!Intrin->use_empty()) {
+ for (int I = 0, E = N; I != E; ++I)
+ if (!Extracts[I]) {
+ CallInst *Op = dyn_cast<CallInst>(bufLds[I / 4]);
+ assert(Op != nullptr);
+ Extracts[I] = IRB.CreateExtractValue(Op, I % 4);
+ }
+
+ Value *Vec = UndefValue::get(OldTy);
+ for (int I = 0, E = N; I != E; ++I)
+ Vec = IRB.CreateInsertElement(Vec, Extracts[I], I);
+
+ Intrin->replaceAllUsesWith(Vec);
+ }
+
+ // TODO:
+ // Remove the dx.op.rawbufferload without any uses now?
+
+ DRM.updateResUseMap(Intrin, bufLds);
+ Intrin->eraseFromParent();
+
+ return Error::success();
+ }
+
+ [[nodiscard]] bool lowerRawBufferLoad(Function &F) {
+ IRBuilder<> &IRB = OpBuilder.getIRB();
+
+ return replaceFunction(F, [&](CallInst *CI) -> Error {
+ IRB.SetInsertPoint(CI);
+
+ auto *It = DRM.find(DRM.findResHandleByUse(CI));
+ assert(It != DRM.end() && "Resource not in map?");
+ dxil::ResourceInfo &RI = *It;
+
+ ResourceKind RCKind = RI.getResourceKind();
+ assert((RCKind == dxil::ResourceKind::StructuredBuffer) ||
+ (RCKind == dxil::ResourceKind::RawBuffer));
+
+ Type *Ty = CI->getType();
+ std::vector<Value *> bufLds;
+ // TODO: Need check Bool type load???
+
+ unsigned numComponents = 1;
+ if (Ty->isVectorTy()) {
+ numComponents = dyn_cast<FixedVectorType>(Ty)->getNumElements();
+ }
+
+ Value *Handle =
+ createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType());
+ Value *bufIdx = CI->getArgOperand(1);
+ Value *baseOffset = CI->getArgOperand(2);
+
+ bool isScalarTy = !Ty->isVectorTy();
+
+ if (RCKind == dxil::ResourceKind::StructuredBuffer) {
+ TranslateRawBufVecLd(Ty, numComponents, IRB, Handle, bufIdx, baseOffset,
+ F.getDataLayout(), bufLds,
+ /*baseAlign (in bytes)*/ 8, isScalarTy);
+ } else {
+ TranslateRawBufVecLd(Ty, numComponents, IRB, Handle, bufIdx, baseOffset,
+ F.getDataLayout(), bufLds,
+ /*baseAlign (in bytes)*/ 4, isScalarTy);
+ }
+
+ if (Error E = replaceMultiResRetsUses(CI, bufLds))
+ return E;
+
+ return Error::success();
+ });
+ }
+
bool lowerIntrinsics() {
bool Updated = false;
bool HasErrors = false;
@@ -638,6 +834,9 @@ class OpLowerer {
case Intrinsic::dx_handle_fromBinding:
HasErrors |= lowerHandleFromBinding(F);
break;
+ case Intrinsic::dx_rawBufferLoad:
+ HasErrors |= lowerRawBufferLoad(F);
+ break;
case Intrinsic::dx_typedBufferLoad:
HasErrors |= lowerTypedBufferLoad(F, /*HasCheckBit=*/false);
break;
diff --git a/llvm/test/Analysis/DXILResource/resource-map.ll b/llvm/test/Analysis/DXILResource/resource-map.ll
new file mode 100644
index 00000000000000..65255d4c942e53
--- /dev/null
+++ b/llvm/test/Analysis/DXILResource/resource-map.ll
@@ -0,0 +1,36 @@
+; RUN: opt -S -disable-output -disable-output -passes="print<dxil-resource>" < %s 2>&1 | FileCheck %s
+
+define void @test_typedbuffer() {
+ ; RWBuffer<float4> Buf : register(u5, space3)
+ %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
+ @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
+ i32 3, i32 5, i32 1, i32 0, i1 false)
+ ; CHECK: Binding [[UAV1:[0-9]+]]:
+ ; CHECK: Symbol: ptr undef
+ ; CHECK: Name: ""
+ ; CHECK: Binding:
+ ; CHECK: Record ID: 0
+ ; CHECK: Space: 3
+ ; CHECK: Lower Bound: 5
+ ; CHECK: Size: 1
+ ; CHECK: Class: UAV
+ ; CHECK: Kind: TypedBuffer
+ ; CHECK: Globally Coherent: 0
+ ; CHECK: HasCounter: 0
+ ; CHECK: IsROV: 0
+ ; CHECK: Element Type: f32
+ ; CHECK: Element Count: 4
+
+ ; CHECK: Call bound to [[UAV1]]: %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
+ ; CHECK-DAG: Resource [[UAV1]] is used by %data0 = call <4 x float> @llvm.dx.typedBufferLoad.v4f32.tdx.TypedBuffer_v4f32_1_0_0t(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
+ ; CHECK-DAG: Resource [[UAV1]] is used by call void @llvm.dx.typedBufferStore.tdx.TypedBuffer_v4f32_1_0_0t.v4f32(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 2, <4 x float> %data0)
+
+ %data0 = call <4 x float> @llvm.dx.typedBufferLoad(
+ target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
+ call void @llvm.dx.typedBufferStore(
+ target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1,
+ i32 2, <4 x float> %data0)
+
+ ret void
+}
+
diff --git a/llvm/test/CodeGen/DirectX/DXILResource/dxil-resource-map.ll b/llvm/test/CodeGen/DirectX/DXILResource/dxil-resource-map.ll
new file mode 100644
index 00000000000000..ac5f3d16145974
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/DXILResource/dxil-resource-map.ll
@@ -0,0 +1,48 @@
+; RUN: opt -S -disable-output -disable-output -passes="print<dxil-resource>,dxil-op-lower,print<dxil-resource>" -mtriple=dxil-pc-shadermodel6.6-compute < %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK_SM66
+; RUN: opt -S -disable-output -disable-output -passes="print<dxil-resource>,dxil-op-lower,print<dxil-resource>" -mtriple=dxil-pc-shadermodel6.2-compute < %s 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK_SM62
+
+define void @test_typedbuffer() {
+ ; RWBuffer<float4> Buf : register(u5, space3)
+ %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
+ @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
+ i32 3, i32 5, i32 1, i32 0, i1 false)
+ ; CHECK: Binding [[UAV1:[0-9]+]]:
+ ; CHECK: Symbol: ptr undef
+ ; CHECK: Name: ""
+ ; CHECK: Binding:
+ ; CHECK: Record ID: 0
+ ; CHECK: Space: 3
+ ; CHECK: Lower Bound: 5
+ ; CHECK: Size: 1
+ ; CHECK: Class: UAV
+ ; CHECK: Kind: TypedBuffer
+ ; CHECK: Globally Coherent: 0
+ ; CHECK: HasCounter: 0
+ ; CHECK: IsROV: 0
+ ; CHECK: Element Type: f32
+ ; CHECK: Element Count: 4
+
+ ; CHECK: Call bound to [[UAV1]]: %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.handle.fromBinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false)
+ ; CHECK-DAG: Resource [[UAV1]] is used by %data0 = call <4 x float> @llvm.dx.typedBufferLoad.v4f32.tdx.TypedBuffer_v4f32_1_0_0t(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
+ ; CHECK-DAG: Resource [[UAV1]] is used by call void @llvm.dx.typedBufferStore.tdx.TypedBuffer_v4f32_1_0_0t.v4f32(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 2, <4 x float> %data0)
+
+ %data0 = call <4 x float> @llvm.dx.typedBufferLoad(
+ target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
+ call void @llvm.dx.typedBufferStore(
+ target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1,
+ i32 2, <4 x float> %data0)
+
+ ;
+ ;;; After dxil-op-lower, the DXILResourceMap info should be updated.
+ ;
+ ; CHECK_SM66: Call bound to [[UAV1]]: %uav11 = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, %dx.types.ResBind { i32 5, i32 5, i32 3, i8 1 }, i32 0, i1 false)
+ ; CHECK_SM66-DAG: Resource [[UAV1]] is used by %data02 = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %uav1_annot, i32 0, i32 undef)
+ ; CHECK_SM66-DAG: Resource [[UAV1]] is used by call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %uav1_annot, i32 2, i32 undef, float %9, float %10, float %11, float %12, i8 1...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/116845
More information about the llvm-commits
mailing list