Skip to content

Commit 392daa1

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 900b636 commit 392daa1

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
@@ -203,6 +203,8 @@ class OpLowerer {
203203

204204
Value *Cast = createTmpHandleCast(*OpCall, CI->getType());
205205

206+
DRM.updateResourceMap(CI, *OpCall);
207+
206208
CI->replaceAllUsesWith(Cast);
207209
CI->eraseFromParent();
208210
return Error::success();
@@ -247,6 +249,8 @@ class OpLowerer {
247249

248250
Value *Cast = createTmpHandleCast(*OpAnnotate, CI->getType());
249251

252+
DRM.updateResourceMap(CI, *OpBind);
253+
250254
CI->replaceAllUsesWith(Cast);
251255
CI->eraseFromParent();
252256

@@ -411,6 +415,9 @@ class OpLowerer {
411415
OpCode::BufferLoad, Args, CI->getName(), NewRetTy);
412416
if (Error E = OpCall.takeError())
413417
return E;
418+
419+
DRM.updateResUseMap(CI, *OpCall);
420+
414421
if (Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
415422
return E;
416423

@@ -455,6 +462,8 @@ class OpLowerer {
455462
if (Error E = OpCall.takeError())
456463
return E;
457464

465+
DRM.updateResUseMap(CI, *OpCall);
466+
458467
CI->eraseFromParent();
459468
return Error::success();
460469
});
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 218, %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)