Skip to content

Commit 8e1bca0

Browse files
committed
[DirectX] Add Resource uses to Resource Handle map in DXILResourceMap
When lowering some resource use intrisics to DXIL operations, it needs to know the information of the resource that the intrisics are using. This PR adds Resource uses to Resource Handle map in DXILResourceMap. It helps the resource uses to find the resource information. This PR is also useful to #106188
1 parent cd41803 commit 8e1bca0

File tree

5 files changed

+175
-0
lines changed

5 files changed

+175
-0
lines changed

llvm/include/llvm/Analysis/DXILResource.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@ class ResourceInfo {
264264
class DXILResourceMap {
265265
SmallVector<dxil::ResourceInfo> Resources;
266266
DenseMap<CallInst *, unsigned> CallMap;
267+
// Mapping from Resource use to Resource Handle
268+
DenseMap<CallInst *, CallInst *> ResUseToHandleMap;
267269
unsigned FirstUAV = 0;
268270
unsigned FirstCBuffer = 0;
269271
unsigned FirstSampler = 0;
@@ -335,6 +337,31 @@ class DXILResourceMap {
335337
}
336338

337339
void print(raw_ostream &OS) const;
340+
341+
void updateResourceMap(CallInst *origCallInst, CallInst *newCallInst);
342+
343+
void updateResUseMap(CallInst *origResUse, CallInst *newResUse) {
344+
assert((origResUse != nullptr) && (newResUse != nullptr) &&
345+
(origResUse != newResUse) && "Wrong Inputs");
346+
347+
updateResUseMapCommon(origResUse, newResUse, /*keepOrigResUseInMap=*/false);
348+
}
349+
350+
CallInst *findResHandleByUse(CallInst *resUse) {
351+
auto Pos = ResUseToHandleMap.find(resUse);
352+
assert((Pos != ResUseToHandleMap.end()) &&
353+
"Can't find the resource handle");
354+
355+
return Pos->second;
356+
}
357+
358+
private:
359+
void updateResUseMapCommon(CallInst *origResUse, CallInst *newResUse,
360+
bool keepOrigResUseInMap) {
361+
ResUseToHandleMap.try_emplace(newResUse, findResHandleByUse(origResUse));
362+
if (!keepOrigResUseInMap)
363+
ResUseToHandleMap.erase(origResUse);
364+
}
338365
};
339366

340367
class DXILResourceAnalysis : public AnalysisInfoMixin<DXILResourceAnalysis> {

llvm/lib/Analysis/DXILResource.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,12 @@ DXILResourceMap::DXILResourceMap(
719719
if (Resources.empty() || RI != Resources.back())
720720
Resources.push_back(RI);
721721
CallMap[CI] = Resources.size() - 1;
722+
723+
// Build ResUseToHandleMap
724+
for (auto it = CI->users().begin(); it != CI->users().end(); ++it) {
725+
CallInst *CI_Use = dyn_cast<CallInst>(*it);
726+
ResUseToHandleMap[CI_Use] = CI;
727+
}
722728
}
723729

724730
unsigned Size = Resources.size();
@@ -744,6 +750,47 @@ DXILResourceMap::DXILResourceMap(
744750
}
745751
}
746752

753+
// Parameter origCallInst: original Resource Handle
754+
// Parameter newCallInst: new Resource Handle
755+
//
756+
// This function is needed when origCallInst's lowered to newCallInst.
757+
//
758+
// Because origCallInst and its uses will be replaced by newCallInst and new def
759+
// instructions after lowering. The [origCallInst, resource info] entry in
760+
// CallMap and [origCallInst's use, origCallInst] entries in ResUseToHandleMap
761+
// have to be updated per the changes in lowering.
762+
//
763+
// What this function does are:
764+
// 1. Add [newCallInst, resource info] entry in CallMap
765+
// 2. Remove [origCallInst, resource info] entry in CallMap
766+
// 3. Remap [origCallInst's use, origCallInst] entries to
767+
// [origCallInst's use, newCallInst] entries in ResUseToHandleMap
768+
//
769+
// Remove those entries related to origCallInst in maps is necessary since
770+
// origCallInst's no longer existing after lowering. Moreover, keeping those
771+
// entries in maps will crash DXILResourceMap::print function
772+
//
773+
// FYI:
774+
// Make sure to invoke this function before origCallInst->replaceAllUsesWith()
775+
// and origCallInst->eraseFromParent() since this function needs to visit
776+
// origCallInst and its uses.
777+
//
778+
void DXILResourceMap::updateResourceMap(CallInst *origCallInst,
779+
CallInst *newCallInst) {
780+
assert((origCallInst != nullptr) && (newCallInst != nullptr) &&
781+
(origCallInst != newCallInst));
782+
783+
CallMap.try_emplace(newCallInst, CallMap[origCallInst]);
784+
CallMap.erase(origCallInst);
785+
786+
// Update ResUseToHandleMap since Resource Handle changed
787+
for (auto it = origCallInst->users().begin();
788+
it != origCallInst->users().end(); ++it) {
789+
CallInst *CI_Use = dyn_cast<CallInst>(*it);
790+
ResUseToHandleMap[CI_Use] = newCallInst;
791+
}
792+
}
793+
747794
void DXILResourceMap::print(raw_ostream &OS) const {
748795
for (unsigned I = 0, E = Resources.size(); I != E; ++I) {
749796
OS << "Binding " << I << ":\n";
@@ -756,6 +803,14 @@ void DXILResourceMap::print(raw_ostream &OS) const {
756803
CI->print(OS);
757804
OS << "\n";
758805
}
806+
807+
for (const auto &[ResUse, ResHandle] : ResUseToHandleMap) {
808+
OS << "\n";
809+
OS << "Resource " << CallMap.find(ResHandle)->second;
810+
OS << " is used by ";
811+
ResUse->print(OS);
812+
OS << "\n";
813+
}
759814
}
760815

761816
//===----------------------------------------------------------------------===//

llvm/lib/Target/DirectX/DXILOpLowering.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ class OpLowerer {
249249

250250
removeResourceGlobals(CI);
251251

252+
DRM.updateResourceMap(CI, *OpCall);
253+
252254
CI->replaceAllUsesWith(Cast);
253255
CI->eraseFromParent();
254256
return Error::success();
@@ -295,6 +297,8 @@ class OpLowerer {
295297

296298
removeResourceGlobals(CI);
297299

300+
DRM.updateResourceMap(CI, *OpBind);
301+
298302
CI->replaceAllUsesWith(Cast);
299303
CI->eraseFromParent();
300304

@@ -479,6 +483,9 @@ class OpLowerer {
479483
OpCode::BufferLoad, Args, CI->getName(), NewRetTy);
480484
if (Error E = OpCall.takeError())
481485
return E;
486+
487+
DRM.updateResUseMap(CI, *OpCall);
488+
482489
if (Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
483490
return E;
484491

@@ -547,6 +554,8 @@ class OpLowerer {
547554
if (Error E = OpCall.takeError())
548555
return E;
549556

557+
DRM.updateResUseMap(CI, *OpCall);
558+
550559
CI->eraseFromParent();
551560
return Error::success();
552561
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
; RUN: opt -S -disable-output -disable-output -passes="print<dxil-resource>" < %s 2>&1 | FileCheck %s
2+
3+
define void @test_typedbuffer() {
4+
; RWBuffer<float4> Buf : register(u5, space3)
5+
%uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
6+
@llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
7+
i32 3, i32 5, i32 1, i32 0, i1 false)
8+
; CHECK: Binding [[UAV1:[0-9]+]]:
9+
; CHECK: Symbol: ptr undef
10+
; CHECK: Name: ""
11+
; CHECK: Binding:
12+
; CHECK: Record ID: 0
13+
; CHECK: Space: 3
14+
; CHECK: Lower Bound: 5
15+
; CHECK: Size: 1
16+
; CHECK: Class: UAV
17+
; CHECK: Kind: TypedBuffer
18+
; CHECK: Globally Coherent: 0
19+
; CHECK: HasCounter: 0
20+
; CHECK: IsROV: 0
21+
; CHECK: Element Type: f32
22+
; CHECK: Element Count: 4
23+
24+
; 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)
25+
; 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)
26+
; 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)
27+
28+
%data0 = call <4 x float> @llvm.dx.typedBufferLoad(
29+
target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
30+
call void @llvm.dx.typedBufferStore(
31+
target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1,
32+
i32 2, <4 x float> %data0)
33+
34+
ret void
35+
}
36+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
; 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
2+
; 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
3+
4+
define void @test_typedbuffer() {
5+
; RWBuffer<float4> Buf : register(u5, space3)
6+
%uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
7+
@llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
8+
i32 3, i32 5, i32 1, i32 0, i1 false)
9+
; CHECK: Binding [[UAV1:[0-9]+]]:
10+
; CHECK: Symbol: ptr undef
11+
; CHECK: Name: ""
12+
; CHECK: Binding:
13+
; CHECK: Record ID: 0
14+
; CHECK: Space: 3
15+
; CHECK: Lower Bound: 5
16+
; CHECK: Size: 1
17+
; CHECK: Class: UAV
18+
; CHECK: Kind: TypedBuffer
19+
; CHECK: Globally Coherent: 0
20+
; CHECK: HasCounter: 0
21+
; CHECK: IsROV: 0
22+
; CHECK: Element Type: f32
23+
; CHECK: Element Count: 4
24+
25+
; 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)
26+
; 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)
27+
; 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)
28+
29+
%data0 = call <4 x float> @llvm.dx.typedBufferLoad(
30+
target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i32 0)
31+
call void @llvm.dx.typedBufferStore(
32+
target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1,
33+
i32 2, <4 x float> %data0)
34+
35+
;
36+
;;; After dxil-op-lower, the DXILResourceMap info should be updated.
37+
;
38+
; 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)
39+
; 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)
40+
; 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 15)
41+
;
42+
; CHECK_SM62: Call bound to [[UAV1]]: %uav11 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 1, i32 0, i32 0, i1 false)
43+
; CHECK_SM62-DAG: Resource [[UAV1]] is used by %data02 = call %dx.types.ResRet.f32 @dx.op.bufferLoad.f32(i32 68, %dx.types.Handle %uav11, i32 0, i32 undef)
44+
; CHECK_SM62-DAG: Resource [[UAV1]] is used by call void @dx.op.bufferStore.f32(i32 69, %dx.types.Handle %uav11, i32 2, i32 undef, float %9, float %10, float %11, float %12, i8 15)
45+
46+
ret void
47+
}
48+

0 commit comments

Comments
 (0)