7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " DirectXIRPasses/PointerTypeAnalysis.h"
10
+ #include " DirectXTargetMachine.h"
10
11
#include " llvm/Analysis/DXILResource.h"
11
12
#include " llvm/AsmParser/Parser.h"
13
+ #include " llvm/CodeGen/CommandFlags.h"
12
14
#include " llvm/IR/Instructions.h"
13
15
#include " llvm/IR/LLVMContext.h"
14
16
#include " llvm/IR/Module.h"
15
17
#include " llvm/IR/Type.h"
16
18
#include " llvm/IR/TypedPointerType.h"
19
+ #include " llvm/MC/TargetRegistry.h"
20
+ #include " llvm/Passes/PassBuilder.h"
17
21
#include " llvm/Support/Casting.h"
22
+ #include " llvm/Support/CodeGen.h"
18
23
#include " llvm/Support/SourceMgr.h"
19
24
#include " llvm/Transforms/Utils/Debugify.h"
20
25
21
26
#include " gmock/gmock.h"
22
27
#include " gtest/gtest.h"
28
+ #include < optional>
23
29
24
30
using ::testing::Contains;
25
31
using ::testing::Pair;
@@ -31,31 +37,153 @@ template <typename T> struct IsA {
31
37
friend bool operator ==(const Value *V, const IsA &) { return isa<T>(V); }
32
38
};
33
39
34
- TEST (UniqueResourceFromUse, TestTrivialUse) {
40
+ namespace {
41
+ class UniqueResourceFromUseTest : public testing ::Test {
42
+ protected:
43
+ PassBuilder *PB;
44
+ ModuleAnalysisManager* MAM;
45
+
46
+ virtual void SetUp () {
47
+ MAM = new ModuleAnalysisManager ();
48
+ PB = new PassBuilder ();
49
+ PB->registerModuleAnalyses (*MAM);
50
+ MAM->registerPass ([&]{ return DXILResourceTypeAnalysis (); });
51
+ MAM->registerPass ([&] { return DXILResourceBindingAnalysis (); });
52
+ }
53
+
54
+ virtual void TearDown () {
55
+ delete PB;
56
+ delete MAM;
57
+ }
58
+ };
59
+
60
+ TEST_F (UniqueResourceFromUseTest, TestTrivialUse) {
35
61
StringRef Assembly = R"(
36
62
define void @main() {
37
63
entry:
38
64
%handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
39
65
call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
66
+ call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
67
+ ret void
68
+ }
69
+
70
+ declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
71
+ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
72
+ )" ;
73
+
74
+ LLVMContext Context;
75
+ SMDiagnostic Error;
76
+ auto M = parseAssemblyString (Assembly, Error, Context);
77
+ ASSERT_TRUE (M) << " Bad assembly?" ;
78
+
79
+ const DXILBindingMap &DBM = MAM->getResult <DXILResourceBindingAnalysis>(*M);
80
+ for (const Function &F : M->functions ()) {
81
+ if (F.getName () != " a.func" ) {
82
+ continue ;
83
+ }
84
+
85
+ unsigned CalledResources = 0 ;
86
+
87
+ for (const User *U : F.users ()) {
88
+ const CallInst *CI = dyn_cast<CallInst>(U);
89
+ ASSERT_TRUE (CI) << " All users of @a.func must be CallInst" ;
90
+
91
+ const Value *Handle = CI->getArgOperand (0 );
92
+
93
+ const auto Bindings = DBM.findByUse (Handle);
94
+ ASSERT_EQ (Bindings.size (), 1u ) << " Handle should resolve into one resource" ;
95
+
96
+ auto Binding = Bindings[0 ].getBinding ();
97
+ EXPECT_EQ (0u , Binding.RecordID );
98
+ EXPECT_EQ (1u , Binding.Space );
99
+ EXPECT_EQ (2u , Binding.LowerBound );
100
+ EXPECT_EQ (3u , Binding.Size );
101
+
102
+ CalledResources++;
103
+ }
104
+
105
+ EXPECT_EQ (2u , CalledResources)
106
+ << " Expected 2 resolved call to create resource" ;
107
+ }
108
+ }
109
+
110
+ TEST_F (UniqueResourceFromUseTest, TestIndirectUse) {
111
+ StringRef Assembly = R"(
112
+ define void @foo() {
113
+ %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
114
+ %handle2 = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %handle)
115
+ %handle3 = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %handle2)
116
+ %handle4 = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %handle3)
117
+ call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle4)
40
118
ret void
41
119
}
42
120
43
121
declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
122
+ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
123
+ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %handle)
124
+ )" ;
125
+
126
+ LLVMContext Context;
127
+ SMDiagnostic Error;
128
+ auto M = parseAssemblyString (Assembly, Error, Context);
129
+ ASSERT_TRUE (M) << " Bad assembly?" ;
130
+
131
+ const DXILBindingMap &DBM = MAM->getResult <DXILResourceBindingAnalysis>(*M);
132
+ for (const Function &F : M->functions ()) {
133
+ if (F.getName () != " a.func" ) {
134
+ continue ;
135
+ }
136
+
137
+ unsigned CalledResources = 0 ;
138
+
139
+ for (const User *U : F.users ()) {
140
+ const CallInst *CI = dyn_cast<CallInst>(U);
141
+ ASSERT_TRUE (CI) << " All users of @a.func must be CallInst" ;
142
+
143
+ const Value *Handle = CI->getArgOperand (0 );
44
144
145
+ const auto Bindings = DBM.findByUse (Handle);
146
+ ASSERT_EQ (Bindings.size (), 1u ) << " Handle should resolve into one resource" ;
147
+
148
+ auto Binding = Bindings[0 ].getBinding ();
149
+ EXPECT_EQ (0u , Binding.RecordID );
150
+ EXPECT_EQ (1u , Binding.Space );
151
+ EXPECT_EQ (2u , Binding.LowerBound );
152
+ EXPECT_EQ (3u , Binding.Size );
153
+
154
+ CalledResources++;
155
+ }
156
+
157
+ EXPECT_EQ (1u , CalledResources)
158
+ << " Expected 1 resolved call to create resource" ;
159
+ }
160
+ }
161
+
162
+ TEST_F (UniqueResourceFromUseTest, TestAmbigousIndirectUse) {
163
+ StringRef Assembly = R"(
164
+ define void @foo() {
165
+ %foo = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 1, i32 1, i32 1, i1 false)
166
+ %bar = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 2, i32 2, i32 2, i32 2, i1 false)
167
+ %baz = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 3, i32 3, i32 3, i32 3, i1 false)
168
+ %bat = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 4, i32 4, i32 4, i32 4, i1 false)
169
+ %a = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %foo, target("dx.RawBuffer", float, 1, 0) %bar)
170
+ %b = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %baz, target("dx.RawBuffer", float, 1, 0) %bat)
171
+ %handle = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %a, target("dx.RawBuffer", float, 1, 0) %b)
172
+ call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
173
+ ret void
174
+ }
175
+
176
+ declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
45
177
declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
178
+ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %x, target("dx.RawBuffer", float, 1, 0) %y)
46
179
)" ;
47
180
48
181
LLVMContext Context;
49
182
SMDiagnostic Error;
50
183
auto M = parseAssemblyString (Assembly, Error, Context);
51
184
ASSERT_TRUE (M) << " Bad assembly?" ;
52
- DebugifyCustomPassManager Passes;
53
- Passes.add (createDXILResourceTypeWrapperPassPass ());
54
- DXILResourceBindingWrapperPass *RBPass = new DXILResourceBindingWrapperPass ();
55
- Passes.add (RBPass);
56
- Passes.run (*M);
57
185
58
- const DXILBindingMap &DBM = RBPass-> getBindingMap ( );
186
+ const DXILBindingMap &DBM = MAM-> getResult <DXILResourceBindingAnalysis>(*M );
59
187
for (const Function &F : M->functions ()) {
60
188
if (F.getName () != " a.func" ) {
61
189
continue ;
@@ -69,20 +197,109 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
69
197
70
198
const Value *Handle = CI->getArgOperand (0 );
71
199
72
- const auto *It = DBM.findByUse (Handle);
73
- ASSERT_TRUE (It != DBM. end () ) << " Handle should resolve into resource " ;
200
+ const auto Bindings = DBM.findByUse (Handle);
201
+ ASSERT_EQ (Bindings. size (), 4u ) << " Handle should resolve into four resources " ;
74
202
75
- const llvm::dxil::ResourceBindingInfo::ResourceBinding &Binding =
76
- It->getBinding ();
203
+ auto Binding = Bindings[0 ].getBinding ();
77
204
EXPECT_EQ (0u , Binding.RecordID );
78
205
EXPECT_EQ (1u , Binding.Space );
206
+ EXPECT_EQ (1u , Binding.LowerBound );
207
+ EXPECT_EQ (1u , Binding.Size );
208
+
209
+ Binding = Bindings[1 ].getBinding ();
210
+ EXPECT_EQ (1u , Binding.RecordID );
211
+ EXPECT_EQ (2u , Binding.Space );
79
212
EXPECT_EQ (2u , Binding.LowerBound );
213
+ EXPECT_EQ (2u , Binding.Size );
214
+
215
+ Binding = Bindings[2 ].getBinding ();
216
+ EXPECT_EQ (2u , Binding.RecordID );
217
+ EXPECT_EQ (3u , Binding.Space );
218
+ EXPECT_EQ (3u , Binding.LowerBound );
80
219
EXPECT_EQ (3u , Binding.Size );
81
220
221
+ Binding = Bindings[3 ].getBinding ();
222
+ EXPECT_EQ (3u , Binding.RecordID );
223
+ EXPECT_EQ (4u , Binding.Space );
224
+ EXPECT_EQ (4u , Binding.LowerBound );
225
+ EXPECT_EQ (4u , Binding.Size );
226
+
227
+ CalledResources++;
228
+ }
229
+
230
+ EXPECT_EQ (1u , CalledResources)
231
+ << " Expected 1 resolved call to create resource" ;
232
+ }
233
+ }
234
+
235
+ TEST_F (UniqueResourceFromUseTest, TestConditionalUse) {
236
+ StringRef Assembly = R"(
237
+ define void @foo(i32 %n) {
238
+ entry:
239
+ %x = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 1, i32 1, i32 1, i1 false)
240
+ %y = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 4, i32 4, i32 4, i32 4, i1 false)
241
+ %cond = icmp eq i32 %n, 0
242
+ br i1 %cond, label %bb.true, label %bb.false
243
+
244
+ bb.true:
245
+ %handle_t = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %x)
246
+ br label %bb.exit
247
+
248
+ bb.false:
249
+ %handle_f = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %y)
250
+ br label %bb.exit
251
+
252
+ bb.exit:
253
+ %handle = phi target("dx.RawBuffer", float, 1, 0) [ %handle_t, %bb.true ], [ %handle_f, %bb.false ]
254
+ call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
255
+ ret void
256
+ }
257
+
258
+ declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
259
+ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
260
+ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %x)
261
+ )" ;
262
+
263
+ LLVMContext Context;
264
+ SMDiagnostic Error;
265
+ auto M = parseAssemblyString (Assembly, Error, Context);
266
+ ASSERT_TRUE (M) << " Bad assembly?" ;
267
+
268
+ const DXILBindingMap &DBM = MAM->getResult <DXILResourceBindingAnalysis>(*M);
269
+ for (const Function &F : M->functions ()) {
270
+ if (F.getName () != " a.func" ) {
271
+ continue ;
272
+ }
273
+
274
+ unsigned CalledResources = 0 ;
275
+
276
+ for (const User *U : F.users ()) {
277
+ const CallInst *CI = dyn_cast<CallInst>(U);
278
+ ASSERT_TRUE (CI) << " All users of @a.func must be CallInst" ;
279
+
280
+ const Value *Handle = CI->getArgOperand (0 );
281
+
282
+ const auto Bindings = DBM.findByUse (Handle);
283
+ ASSERT_EQ (Bindings.size (), 2u ) << " Handle should resolve into four resources" ;
284
+
285
+ auto Binding = Bindings[0 ].getBinding ();
286
+ EXPECT_EQ (0u , Binding.RecordID );
287
+ EXPECT_EQ (1u , Binding.Space );
288
+ EXPECT_EQ (1u , Binding.LowerBound );
289
+ EXPECT_EQ (1u , Binding.Size );
290
+
291
+ Binding = Bindings[1 ].getBinding ();
292
+ EXPECT_EQ (1u , Binding.RecordID );
293
+ EXPECT_EQ (4u , Binding.Space );
294
+ EXPECT_EQ (4u , Binding.LowerBound );
295
+ EXPECT_EQ (4u , Binding.Size );
296
+
82
297
CalledResources++;
83
298
}
84
299
85
300
EXPECT_EQ (1u , CalledResources)
86
- << " Expected exactly 1 resolved call to create resource" ;
301
+ << " Expected 1 resolved call to create resource" ;
87
302
}
88
303
}
304
+
305
+ } // namespace
0 commit comments