Skip to content

Commit bf7741b

Browse files
committed
[DirectX] ForwardHandle needs to check if globals were stored on allocas
fixes #140819 SROA pass is making it so that some globals get loaded into stack allocations. This means we find an alloca where we use to expect a load and now need to walk an alloca -> store -> maybe load chain before we find the global. Doing so fixes All but two instances of #137715 And fixes every instance of `Load of "8.sroa.0" is not a global resource handle we are currently seeing in the DML shaders.
1 parent a719091 commit bf7741b

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

llvm/lib/Target/DirectX/DXILForwardHandleAccesses.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,48 @@ static bool forwardHandleAccesses(Function &F, DominatorTree &DT) {
8787

8888
for (LoadInst *LI : LoadsToProcess) {
8989
Value *V = LI->getPointerOperand();
90-
auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand());
90+
auto *GV = dyn_cast<GlobalVariable>(V);
9191

9292
// If we didn't find the global, we may need to walk through a level of
9393
// indirection. This generally happens at -O0.
94-
if (!GV)
94+
if (!GV) {
9595
if (auto *NestedLI = dyn_cast<LoadInst>(V)) {
9696
BasicBlock::iterator BBI(NestedLI);
9797
Value *Loaded = FindAvailableLoadedValue(
9898
NestedLI, NestedLI->getParent(), BBI, 0, nullptr, nullptr);
9999
GV = dyn_cast_or_null<GlobalVariable>(Loaded);
100+
} else if (auto *NestedAlloca = dyn_cast<AllocaInst>(V)) {
101+
for (auto &Use : NestedAlloca->uses()) {
102+
auto *Store = dyn_cast<StoreInst>(Use.getUser());
103+
if (!Store)
104+
continue;
105+
106+
Value *StoredVal = Store->getValueOperand();
107+
if (!StoredVal)
108+
continue;
109+
110+
// Try direct global match
111+
GV = dyn_cast<GlobalVariable>(StoredVal);
112+
if (GV)
113+
break;
114+
115+
// If it's a load, check its source
116+
if (auto *Load = dyn_cast<LoadInst>(StoredVal)) {
117+
GV = dyn_cast<GlobalVariable>(Load->getPointerOperand());
118+
if (GV)
119+
break;
120+
121+
// Try to find available loaded value
122+
BasicBlock::iterator BBI(Load);
123+
Value *Loaded = FindAvailableLoadedValue(Load, Load->getParent(),
124+
BBI, 0, nullptr, nullptr);
125+
GV = dyn_cast<GlobalVariable>(Loaded);
126+
if (GV)
127+
break;
128+
}
129+
}
100130
}
131+
}
101132

102133
auto It = HandleMap.find(GV);
103134
if (It == HandleMap.end()) {
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -S -dxil-forward-handle-accesses %s | FileCheck %s
3+
4+
%"class.hlsl::RWStructuredBuffer" = type { target("dx.RawBuffer", i32, 1, 0) }
5+
@_ZL4dest = internal unnamed_addr global %"class.hlsl::RWStructuredBuffer" poison, align 4
6+
@.str = private unnamed_addr constant [5 x i8] c"dest\00", align 1
7+
8+
9+
; NOTE: intent of this test is to confirm load target("dx.RawBuffer", i32, 1, 0)
10+
; is replaced with call @llvm.dx.resource.getpointer
11+
define void @CSMain() local_unnamed_addr {
12+
; CHECK-LABEL: define void @CSMain() local_unnamed_addr {
13+
; CHECK-NEXT: [[ENTRY:.*:]]
14+
; CHECK-NEXT: [[AGG_TMP_I1_SROA_0:%.*]] = alloca target("dx.RawBuffer", i32, 1, 0), align 8
15+
; CHECK-NEXT: [[TMP0:%.*]] = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false, ptr nonnull @.str)
16+
; CHECK-NEXT: store target("dx.RawBuffer", i32, 1, 0) [[TMP0]], ptr @_ZL4dest, align 4
17+
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @llvm.dx.thread.id(i32 0)
18+
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr @_ZL4dest, align 4
19+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[AGG_TMP_I1_SROA_0]])
20+
; CHECK-NEXT: store i32 [[TMP2]], ptr [[AGG_TMP_I1_SROA_0]], align 8
21+
; CHECK-NEXT: [[TMP3:%.*]] = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) [[TMP0]], i32 [[TMP1]])
22+
; CHECK-NEXT: store i32 0, ptr [[TMP3]], align 4
23+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[AGG_TMP_I1_SROA_0]])
24+
; CHECK-NEXT: ret void
25+
;
26+
entry:
27+
%agg.tmp.i1.sroa.0 = alloca target("dx.RawBuffer", i32, 1, 0), align 8
28+
%0 = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false, ptr nonnull @.str)
29+
store target("dx.RawBuffer", i32, 1, 0) %0, ptr @_ZL4dest, align 4
30+
%1 = tail call i32 @llvm.dx.thread.id(i32 0)
31+
%2 = load i32, ptr @_ZL4dest, align 4
32+
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %agg.tmp.i1.sroa.0)
33+
store i32 %2, ptr %agg.tmp.i1.sroa.0, align 8
34+
%agg.tmp.i1.sroa.0.0.agg.tmp.i1.sroa.0.0.agg.tmp.i1.sroa.0.0.agg.tmp.i1.sroa.0.0. = load target("dx.RawBuffer", i32, 1, 0), ptr %agg.tmp.i1.sroa.0, align 8
35+
%3 = tail call noundef nonnull align 4 dereferenceable(4) ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0) %agg.tmp.i1.sroa.0.0.agg.tmp.i1.sroa.0.0.agg.tmp.i1.sroa.0.0.agg.tmp.i1.sroa.0.0., i32 %1)
36+
store i32 0, ptr %3, align 4
37+
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %agg.tmp.i1.sroa.0)
38+
ret void
39+
}

0 commit comments

Comments
 (0)