1 // Copyright (c) 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <string>
16
17 #include "gmock/gmock.h"
18 #include "source/opt/build_module.h"
19 #include "source/opt/value_number_table.h"
20 #include "test/opt/assembly_builder.h"
21 #include "test/opt/pass_fixture.h"
22
23 namespace spvtools {
24 namespace opt {
25 namespace {
26
27 using ::testing::HasSubstr;
28 using ::testing::MatchesRegex;
29 using ValueTableTest = PassTest<::testing::Test>;
30
TEST_F(ValueTableTest,SameInstructionSameValue)31 TEST_F(ValueTableTest, SameInstructionSameValue) {
32 const std::string text = R"(
33 OpCapability Shader
34 %1 = OpExtInstImport "GLSL.std.450"
35 OpMemoryModel Logical GLSL450
36 OpEntryPoint Fragment %2 "main"
37 OpExecutionMode %2 OriginUpperLeft
38 OpSource GLSL 430
39 %3 = OpTypeVoid
40 %4 = OpTypeFunction %3
41 %5 = OpTypeFloat 32
42 %6 = OpTypePointer Function %5
43 %2 = OpFunction %3 None %4
44 %7 = OpLabel
45 %8 = OpVariable %6 Function
46 %9 = OpLoad %5 %8
47 %10 = OpFAdd %5 %9 %9
48 OpReturn
49 OpFunctionEnd
50 )";
51 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
52 ValueNumberTable vtable(context.get());
53 Instruction* inst = context->get_def_use_mgr()->GetDef(10);
54 EXPECT_EQ(vtable.GetValueNumber(inst), vtable.GetValueNumber(inst));
55 }
56
TEST_F(ValueTableTest,DifferentInstructionSameValue)57 TEST_F(ValueTableTest, DifferentInstructionSameValue) {
58 const std::string text = R"(
59 OpCapability Shader
60 %1 = OpExtInstImport "GLSL.std.450"
61 OpMemoryModel Logical GLSL450
62 OpEntryPoint Fragment %2 "main"
63 OpExecutionMode %2 OriginUpperLeft
64 OpSource GLSL 430
65 %3 = OpTypeVoid
66 %4 = OpTypeFunction %3
67 %5 = OpTypeFloat 32
68 %6 = OpTypePointer Function %5
69 %2 = OpFunction %3 None %4
70 %7 = OpLabel
71 %8 = OpVariable %6 Function
72 %9 = OpLoad %5 %8
73 %10 = OpFAdd %5 %9 %9
74 %11 = OpFAdd %5 %9 %9
75 OpReturn
76 OpFunctionEnd
77 )";
78 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
79 ValueNumberTable vtable(context.get());
80 Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
81 Instruction* inst2 = context->get_def_use_mgr()->GetDef(11);
82 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
83 }
84
TEST_F(ValueTableTest,SameValueDifferentBlock)85 TEST_F(ValueTableTest, SameValueDifferentBlock) {
86 const std::string text = R"(
87 OpCapability Shader
88 %1 = OpExtInstImport "GLSL.std.450"
89 OpMemoryModel Logical GLSL450
90 OpEntryPoint Fragment %2 "main"
91 OpExecutionMode %2 OriginUpperLeft
92 OpSource GLSL 430
93 %3 = OpTypeVoid
94 %4 = OpTypeFunction %3
95 %5 = OpTypeFloat 32
96 %6 = OpTypePointer Function %5
97 %2 = OpFunction %3 None %4
98 %7 = OpLabel
99 %8 = OpVariable %6 Function
100 %9 = OpLoad %5 %8
101 %10 = OpFAdd %5 %9 %9
102 OpBranch %11
103 %11 = OpLabel
104 %12 = OpFAdd %5 %9 %9
105 OpReturn
106 OpFunctionEnd
107 )";
108 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
109 ValueNumberTable vtable(context.get());
110 Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
111 Instruction* inst2 = context->get_def_use_mgr()->GetDef(12);
112 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
113 }
114
TEST_F(ValueTableTest,DifferentValue)115 TEST_F(ValueTableTest, DifferentValue) {
116 const std::string text = R"(
117 OpCapability Shader
118 %1 = OpExtInstImport "GLSL.std.450"
119 OpMemoryModel Logical GLSL450
120 OpEntryPoint Fragment %2 "main"
121 OpExecutionMode %2 OriginUpperLeft
122 OpSource GLSL 430
123 %3 = OpTypeVoid
124 %4 = OpTypeFunction %3
125 %5 = OpTypeFloat 32
126 %6 = OpTypePointer Function %5
127 %2 = OpFunction %3 None %4
128 %7 = OpLabel
129 %8 = OpVariable %6 Function
130 %9 = OpLoad %5 %8
131 %10 = OpFAdd %5 %9 %9
132 %11 = OpFAdd %5 %9 %10
133 OpReturn
134 OpFunctionEnd
135 )";
136 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
137 ValueNumberTable vtable(context.get());
138 Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
139 Instruction* inst2 = context->get_def_use_mgr()->GetDef(11);
140 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
141 }
142
TEST_F(ValueTableTest,DifferentValueDifferentBlock)143 TEST_F(ValueTableTest, DifferentValueDifferentBlock) {
144 const std::string text = R"(
145 OpCapability Shader
146 %1 = OpExtInstImport "GLSL.std.450"
147 OpMemoryModel Logical GLSL450
148 OpEntryPoint Fragment %2 "main"
149 OpExecutionMode %2 OriginUpperLeft
150 OpSource GLSL 430
151 %3 = OpTypeVoid
152 %4 = OpTypeFunction %3
153 %5 = OpTypeFloat 32
154 %6 = OpTypePointer Function %5
155 %2 = OpFunction %3 None %4
156 %7 = OpLabel
157 %8 = OpVariable %6 Function
158 %9 = OpLoad %5 %8
159 %10 = OpFAdd %5 %9 %9
160 OpBranch %11
161 %11 = OpLabel
162 %12 = OpFAdd %5 %9 %10
163 OpReturn
164 OpFunctionEnd
165 )";
166 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
167 ValueNumberTable vtable(context.get());
168 Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
169 Instruction* inst2 = context->get_def_use_mgr()->GetDef(12);
170 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
171 }
172
TEST_F(ValueTableTest,SameLoad)173 TEST_F(ValueTableTest, SameLoad) {
174 const std::string text = R"(
175 OpCapability Shader
176 %1 = OpExtInstImport "GLSL.std.450"
177 OpMemoryModel Logical GLSL450
178 OpEntryPoint Fragment %2 "main"
179 OpExecutionMode %2 OriginUpperLeft
180 OpSource GLSL 430
181 %3 = OpTypeVoid
182 %4 = OpTypeFunction %3
183 %5 = OpTypeFloat 32
184 %6 = OpTypePointer Function %5
185 %2 = OpFunction %3 None %4
186 %7 = OpLabel
187 %8 = OpVariable %6 Function
188 %9 = OpLoad %5 %8
189 OpReturn
190 OpFunctionEnd
191 )";
192 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
193 ValueNumberTable vtable(context.get());
194 Instruction* inst = context->get_def_use_mgr()->GetDef(9);
195 EXPECT_EQ(vtable.GetValueNumber(inst), vtable.GetValueNumber(inst));
196 }
197
198 // Two different loads, even from the same memory, must given different value
199 // numbers if the memory is not read-only.
TEST_F(ValueTableTest,DifferentFunctionLoad)200 TEST_F(ValueTableTest, DifferentFunctionLoad) {
201 const std::string text = R"(
202 OpCapability Shader
203 %1 = OpExtInstImport "GLSL.std.450"
204 OpMemoryModel Logical GLSL450
205 OpEntryPoint Fragment %2 "main"
206 OpExecutionMode %2 OriginUpperLeft
207 OpSource GLSL 430
208 %3 = OpTypeVoid
209 %4 = OpTypeFunction %3
210 %5 = OpTypeFloat 32
211 %6 = OpTypePointer Function %5
212 %2 = OpFunction %3 None %4
213 %7 = OpLabel
214 %8 = OpVariable %6 Function
215 %9 = OpLoad %5 %8
216 %10 = OpLoad %5 %8
217 OpReturn
218 OpFunctionEnd
219 )";
220 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
221 ValueNumberTable vtable(context.get());
222 Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
223 Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
224 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
225 }
226
TEST_F(ValueTableTest,DifferentUniformLoad)227 TEST_F(ValueTableTest, DifferentUniformLoad) {
228 const std::string text = R"(
229 OpCapability Shader
230 %1 = OpExtInstImport "GLSL.std.450"
231 OpMemoryModel Logical GLSL450
232 OpEntryPoint Fragment %2 "main"
233 OpExecutionMode %2 OriginUpperLeft
234 OpSource GLSL 430
235 %3 = OpTypeVoid
236 %4 = OpTypeFunction %3
237 %5 = OpTypeFloat 32
238 %6 = OpTypePointer Uniform %5
239 %8 = OpVariable %6 Uniform
240 %2 = OpFunction %3 None %4
241 %7 = OpLabel
242 %9 = OpLoad %5 %8
243 %10 = OpLoad %5 %8
244 OpReturn
245 OpFunctionEnd
246 )";
247 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
248 ValueNumberTable vtable(context.get());
249 Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
250 Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
251 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
252 }
253
TEST_F(ValueTableTest,DifferentInputLoad)254 TEST_F(ValueTableTest, DifferentInputLoad) {
255 const std::string text = R"(
256 OpCapability Shader
257 %1 = OpExtInstImport "GLSL.std.450"
258 OpMemoryModel Logical GLSL450
259 OpEntryPoint Fragment %2 "main"
260 OpExecutionMode %2 OriginUpperLeft
261 OpSource GLSL 430
262 %3 = OpTypeVoid
263 %4 = OpTypeFunction %3
264 %5 = OpTypeFloat 32
265 %6 = OpTypePointer Input %5
266 %8 = OpVariable %6 Input
267 %2 = OpFunction %3 None %4
268 %7 = OpLabel
269 %9 = OpLoad %5 %8
270 %10 = OpLoad %5 %8
271 OpReturn
272 OpFunctionEnd
273 )";
274 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
275 ValueNumberTable vtable(context.get());
276 Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
277 Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
278 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
279 }
280
TEST_F(ValueTableTest,DifferentUniformConstantLoad)281 TEST_F(ValueTableTest, DifferentUniformConstantLoad) {
282 const std::string text = R"(
283 OpCapability Shader
284 %1 = OpExtInstImport "GLSL.std.450"
285 OpMemoryModel Logical GLSL450
286 OpEntryPoint Fragment %2 "main"
287 OpExecutionMode %2 OriginUpperLeft
288 OpSource GLSL 430
289 %3 = OpTypeVoid
290 %4 = OpTypeFunction %3
291 %5 = OpTypeFloat 32
292 %6 = OpTypePointer UniformConstant %5
293 %8 = OpVariable %6 UniformConstant
294 %2 = OpFunction %3 None %4
295 %7 = OpLabel
296 %9 = OpLoad %5 %8
297 %10 = OpLoad %5 %8
298 OpReturn
299 OpFunctionEnd
300 )";
301 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
302 ValueNumberTable vtable(context.get());
303 Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
304 Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
305 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
306 }
307
TEST_F(ValueTableTest,DifferentPushConstantLoad)308 TEST_F(ValueTableTest, DifferentPushConstantLoad) {
309 const std::string text = R"(
310 OpCapability Shader
311 %1 = OpExtInstImport "GLSL.std.450"
312 OpMemoryModel Logical GLSL450
313 OpEntryPoint Fragment %2 "main"
314 OpExecutionMode %2 OriginUpperLeft
315 OpSource GLSL 430
316 %3 = OpTypeVoid
317 %4 = OpTypeFunction %3
318 %5 = OpTypeFloat 32
319 %6 = OpTypePointer PushConstant %5
320 %8 = OpVariable %6 PushConstant
321 %2 = OpFunction %3 None %4
322 %7 = OpLabel
323 %9 = OpLoad %5 %8
324 %10 = OpLoad %5 %8
325 OpReturn
326 OpFunctionEnd
327 )";
328 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
329 ValueNumberTable vtable(context.get());
330 Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
331 Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
332 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
333 }
334
TEST_F(ValueTableTest,SameCall)335 TEST_F(ValueTableTest, SameCall) {
336 const std::string text = R"(
337 OpCapability Shader
338 %1 = OpExtInstImport "GLSL.std.450"
339 OpMemoryModel Logical GLSL450
340 OpEntryPoint Fragment %2 "main"
341 OpExecutionMode %2 OriginUpperLeft
342 OpSource GLSL 430
343 %3 = OpTypeVoid
344 %4 = OpTypeFunction %3
345 %5 = OpTypeFloat 32
346 %6 = OpTypeFunction %5
347 %7 = OpTypePointer Function %5
348 %8 = OpVariable %7 Private
349 %2 = OpFunction %3 None %4
350 %9 = OpLabel
351 %10 = OpFunctionCall %5 %11
352 OpReturn
353 OpFunctionEnd
354 %11 = OpFunction %5 None %6
355 %12 = OpLabel
356 %13 = OpLoad %5 %8
357 OpReturnValue %13
358 OpFunctionEnd
359 )";
360 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
361 ValueNumberTable vtable(context.get());
362 Instruction* inst = context->get_def_use_mgr()->GetDef(10);
363 EXPECT_EQ(vtable.GetValueNumber(inst), vtable.GetValueNumber(inst));
364 }
365
366 // Function calls should be given a new value number, even if they are the same.
TEST_F(ValueTableTest,DifferentCall)367 TEST_F(ValueTableTest, DifferentCall) {
368 const std::string text = R"(
369 OpCapability Shader
370 %1 = OpExtInstImport "GLSL.std.450"
371 OpMemoryModel Logical GLSL450
372 OpEntryPoint Fragment %2 "main"
373 OpExecutionMode %2 OriginUpperLeft
374 OpSource GLSL 430
375 %3 = OpTypeVoid
376 %4 = OpTypeFunction %3
377 %5 = OpTypeFloat 32
378 %6 = OpTypeFunction %5
379 %7 = OpTypePointer Function %5
380 %8 = OpVariable %7 Private
381 %2 = OpFunction %3 None %4
382 %9 = OpLabel
383 %10 = OpFunctionCall %5 %11
384 %12 = OpFunctionCall %5 %11
385 OpReturn
386 OpFunctionEnd
387 %11 = OpFunction %5 None %6
388 %13 = OpLabel
389 %14 = OpLoad %5 %8
390 OpReturnValue %14
391 OpFunctionEnd
392 )";
393 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
394 ValueNumberTable vtable(context.get());
395 Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
396 Instruction* inst2 = context->get_def_use_mgr()->GetDef(12);
397 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
398 }
399
400 // It is possible to have two instruction that compute the same numerical value,
401 // but with different types. They should have different value numbers.
TEST_F(ValueTableTest,DifferentTypes)402 TEST_F(ValueTableTest, DifferentTypes) {
403 const std::string text = R"(
404 OpCapability Shader
405 %1 = OpExtInstImport "GLSL.std.450"
406 OpMemoryModel Logical GLSL450
407 OpEntryPoint Fragment %2 "main"
408 OpExecutionMode %2 OriginUpperLeft
409 OpSource GLSL 430
410 %3 = OpTypeVoid
411 %4 = OpTypeFunction %3
412 %5 = OpTypeInt 32 0
413 %6 = OpTypeInt 32 1
414 %7 = OpTypePointer Function %5
415 %2 = OpFunction %3 None %4
416 %8 = OpLabel
417 %9 = OpVariable %7 Function
418 %10 = OpLoad %5 %9
419 %11 = OpIAdd %5 %10 %10
420 %12 = OpIAdd %6 %10 %10
421 OpReturn
422 OpFunctionEnd
423 )";
424 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
425 ValueNumberTable vtable(context.get());
426 Instruction* inst1 = context->get_def_use_mgr()->GetDef(11);
427 Instruction* inst2 = context->get_def_use_mgr()->GetDef(12);
428 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
429 }
430
TEST_F(ValueTableTest,CopyObject)431 TEST_F(ValueTableTest, CopyObject) {
432 const std::string text = R"(
433 OpCapability Shader
434 %1 = OpExtInstImport "GLSL.std.450"
435 OpMemoryModel Logical GLSL450
436 OpEntryPoint Fragment %2 "main"
437 OpExecutionMode %2 OriginUpperLeft
438 OpSource GLSL 430
439 %3 = OpTypeVoid
440 %4 = OpTypeFunction %3
441 %5 = OpTypeFloat 32
442 %6 = OpTypePointer Function %5
443 %2 = OpFunction %3 None %4
444 %7 = OpLabel
445 %8 = OpVariable %6 Function
446 %9 = OpLoad %5 %8
447 %10 = OpCopyObject %5 %9
448 OpReturn
449 OpFunctionEnd
450 )";
451 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
452 ValueNumberTable vtable(context.get());
453 Instruction* inst1 = context->get_def_use_mgr()->GetDef(9);
454 Instruction* inst2 = context->get_def_use_mgr()->GetDef(10);
455 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
456 }
457
TEST_F(ValueTableTest,CopyObjectWitDecoration)458 TEST_F(ValueTableTest, CopyObjectWitDecoration) {
459 const std::string text = R"(
460 OpCapability Shader
461 %1 = OpExtInstImport "GLSL.std.450"
462 OpMemoryModel Logical GLSL450
463 OpEntryPoint Fragment %2 "main"
464 OpExecutionMode %2 OriginUpperLeft
465 OpSource GLSL 430
466 OpDecorate %3 NonUniformEXT
467 %4 = OpTypeVoid
468 %5 = OpTypeFunction %4
469 %6 = OpTypeFloat 32
470 %7 = OpTypePointer Function %6
471 %2 = OpFunction %4 None %5
472 %8 = OpLabel
473 %9 = OpVariable %7 Function
474 %10 = OpLoad %6 %9
475 %3 = OpCopyObject %6 %10
476 OpReturn
477 OpFunctionEnd
478 )";
479 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
480 ValueNumberTable vtable(context.get());
481 Instruction* inst1 = context->get_def_use_mgr()->GetDef(10);
482 Instruction* inst2 = context->get_def_use_mgr()->GetDef(3);
483 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
484 }
485
486 // Test that a phi where the operands have the same value assigned that value
487 // to the result of the phi.
TEST_F(ValueTableTest,PhiTest1)488 TEST_F(ValueTableTest, PhiTest1) {
489 const std::string text = R"(
490 OpCapability Shader
491 %1 = OpExtInstImport "GLSL.std.450"
492 OpMemoryModel Logical GLSL450
493 OpEntryPoint Fragment %2 "main"
494 OpExecutionMode %2 OriginUpperLeft
495 OpSource GLSL 430
496 %3 = OpTypeVoid
497 %4 = OpTypeFunction %3
498 %5 = OpTypeFloat 32
499 %6 = OpTypePointer Uniform %5
500 %7 = OpTypeBool
501 %8 = OpConstantTrue %7
502 %9 = OpVariable %6 Uniform
503 %2 = OpFunction %3 None %4
504 %10 = OpLabel
505 OpBranchConditional %8 %11 %12
506 %11 = OpLabel
507 %13 = OpLoad %5 %9
508 OpBranch %14
509 %12 = OpLabel
510 %15 = OpLoad %5 %9
511 OpBranch %14
512 %14 = OpLabel
513 %16 = OpPhi %5 %13 %11 %15 %12
514 OpReturn
515 OpFunctionEnd
516 )";
517 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
518 ValueNumberTable vtable(context.get());
519 Instruction* inst1 = context->get_def_use_mgr()->GetDef(13);
520 Instruction* inst2 = context->get_def_use_mgr()->GetDef(15);
521 Instruction* phi = context->get_def_use_mgr()->GetDef(16);
522 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
523 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi));
524 }
525
TEST_F(ValueTableTest,PhiTest1WithDecoration)526 TEST_F(ValueTableTest, PhiTest1WithDecoration) {
527 const std::string text = R"(
528 OpCapability Shader
529 %1 = OpExtInstImport "GLSL.std.450"
530 OpMemoryModel Logical GLSL450
531 OpEntryPoint Fragment %2 "main"
532 OpExecutionMode %2 OriginUpperLeft
533 OpSource GLSL 430
534 OpDecorate %3 NonUniformEXT
535 %4 = OpTypeVoid
536 %5 = OpTypeFunction %5
537 %6 = OpTypeFloat 32
538 %7 = OpTypePointer Uniform %6
539 %8 = OpTypeBool
540 %9 = OpConstantTrue %8
541 %10 = OpVariable %7 Uniform
542 %2 = OpFunction %4 None %5
543 %11 = OpLabel
544 OpBranchConditional %9 %12 %13
545 %12 = OpLabel
546 %14 = OpLoad %6 %10
547 OpBranch %15
548 %13 = OpLabel
549 %16 = OpLoad %6 %10
550 OpBranch %15
551 %15 = OpLabel
552 %3 = OpPhi %6 %14 %12 %16 %13
553 OpReturn
554 OpFunctionEnd
555 )";
556 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
557 ValueNumberTable vtable(context.get());
558 Instruction* inst1 = context->get_def_use_mgr()->GetDef(14);
559 Instruction* inst2 = context->get_def_use_mgr()->GetDef(16);
560 Instruction* phi = context->get_def_use_mgr()->GetDef(3);
561 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
562 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi));
563 }
564
565 // When the values for the inputs to a phi do not match, then the phi should
566 // have its own value number.
TEST_F(ValueTableTest,PhiTest2)567 TEST_F(ValueTableTest, PhiTest2) {
568 const std::string text = R"(
569 OpCapability Shader
570 %1 = OpExtInstImport "GLSL.std.450"
571 OpMemoryModel Logical GLSL450
572 OpEntryPoint Fragment %2 "main"
573 OpExecutionMode %2 OriginUpperLeft
574 OpSource GLSL 430
575 %3 = OpTypeVoid
576 %4 = OpTypeFunction %3
577 %5 = OpTypeFloat 32
578 %6 = OpTypePointer Uniform %5
579 %7 = OpTypeBool
580 %8 = OpConstantTrue %7
581 %9 = OpVariable %6 Uniform
582 %10 = OpVariable %6 Uniform
583 %2 = OpFunction %3 None %4
584 %11 = OpLabel
585 OpBranchConditional %8 %12 %13
586 %12 = OpLabel
587 %14 = OpLoad %5 %9
588 OpBranch %15
589 %13 = OpLabel
590 %16 = OpLoad %5 %10
591 OpBranch %15
592 %15 = OpLabel
593 %17 = OpPhi %14 %12 %16 %13
594 OpReturn
595 OpFunctionEnd
596 )";
597 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
598 ValueNumberTable vtable(context.get());
599 Instruction* inst1 = context->get_def_use_mgr()->GetDef(14);
600 Instruction* inst2 = context->get_def_use_mgr()->GetDef(16);
601 Instruction* phi = context->get_def_use_mgr()->GetDef(17);
602 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
603 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi));
604 EXPECT_NE(vtable.GetValueNumber(inst2), vtable.GetValueNumber(phi));
605 }
606
607 // Test that a phi node in a loop header gets a new value because one of its
608 // inputs comes from later in the loop.
TEST_F(ValueTableTest,PhiLoopTest)609 TEST_F(ValueTableTest, PhiLoopTest) {
610 const std::string text = R"(
611 OpCapability Shader
612 %1 = OpExtInstImport "GLSL.std.450"
613 OpMemoryModel Logical GLSL450
614 OpEntryPoint Fragment %2 "main"
615 OpExecutionMode %2 OriginUpperLeft
616 OpSource GLSL 430
617 %3 = OpTypeVoid
618 %4 = OpTypeFunction %3
619 %5 = OpTypeFloat 32
620 %6 = OpTypePointer Uniform %5
621 %7 = OpTypeBool
622 %8 = OpConstantTrue %7
623 %9 = OpVariable %6 Uniform
624 %10 = OpVariable %6 Uniform
625 %2 = OpFunction %3 None %4
626 %11 = OpLabel
627 %12 = OpLoad %5 %9
628 OpSelectionMerge %13 None
629 OpBranchConditional %8 %14 %13
630 %14 = OpLabel
631 %15 = OpPhi %5 %12 %11 %16 %14
632 %16 = OpLoad %5 %9
633 OpLoopMerge %17 %14 None
634 OpBranchConditional %8 %14 %17
635 %17 = OpLabel
636 OpBranch %13
637 %13 = OpLabel
638 %18 = OpPhi %5 %12 %11 %16 %17
639 OpReturn
640 OpFunctionEnd
641 )";
642 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
643 ValueNumberTable vtable(context.get());
644 Instruction* inst1 = context->get_def_use_mgr()->GetDef(12);
645 Instruction* inst2 = context->get_def_use_mgr()->GetDef(16);
646 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
647
648 Instruction* phi1 = context->get_def_use_mgr()->GetDef(15);
649 EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi1));
650
651 Instruction* phi2 = context->get_def_use_mgr()->GetDef(18);
652 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi2));
653 EXPECT_NE(vtable.GetValueNumber(phi1), vtable.GetValueNumber(phi2));
654 }
655
656 // Test to make sure that OpPhi instructions with no in operands are handled
657 // correctly.
TEST_F(ValueTableTest,EmptyPhiTest)658 TEST_F(ValueTableTest, EmptyPhiTest) {
659 const std::string text = R"(
660 OpCapability Shader
661 %1 = OpExtInstImport "GLSL.std.450"
662 OpMemoryModel Logical GLSL450
663 OpEntryPoint Fragment %2 "main"
664 OpExecutionMode %2 OriginUpperLeft
665 OpSource GLSL 430
666 %void = OpTypeVoid
667 %4 = OpTypeFunction %void
668 %bool = OpTypeBool
669 %true = OpConstantTrue %bool
670 %2 = OpFunction %void None %4
671 %7 = OpLabel
672 OpSelectionMerge %8 None
673 OpBranchConditional %true %9 %8
674 %9 = OpLabel
675 OpKill
676 %8 = OpLabel
677 %10 = OpPhi %bool
678 OpReturn
679 OpFunctionEnd
680 )";
681 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
682 ValueNumberTable vtable(context.get());
683 Instruction* inst = context->get_def_use_mgr()->GetDef(10);
684 vtable.GetValueNumber(inst);
685 }
686
TEST_F(ValueTableTest,RedundantSampledImageLoad)687 TEST_F(ValueTableTest, RedundantSampledImageLoad) {
688 const std::string text = R"(
689 OpCapability Shader
690 %1 = OpExtInstImport "GLSL.std.450"
691 OpMemoryModel Logical GLSL450
692 OpEntryPoint Fragment %main "main" %gl_FragColor
693 OpExecutionMode %main OriginLowerLeft
694 OpSource GLSL 330
695 OpName %main "main"
696 OpName %tex0 "tex0"
697 OpName %gl_FragColor "gl_FragColor"
698 OpDecorate %tex0 Location 0
699 OpDecorate %tex0 DescriptorSet 0
700 OpDecorate %tex0 Binding 0
701 OpDecorate %gl_FragColor Location 0
702 %void = OpTypeVoid
703 %6 = OpTypeFunction %void
704 %float = OpTypeFloat 32
705 %v4float = OpTypeVector %float 4
706 %9 = OpTypeImage %float 2D 0 0 0 1 Unknown
707 %10 = OpTypeSampledImage %9
708 %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10
709 %tex0 = OpVariable %_ptr_UniformConstant_10 UniformConstant
710 %_ptr_Output_v4float = OpTypePointer Output %v4float
711 %13 = OpConstantNull %v4float
712 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
713 %14 = OpUndef %v4float
714 %main = OpFunction %void None %6
715 %15 = OpLabel
716 %16 = OpLoad %10 %tex0
717 %17 = OpImageSampleProjImplicitLod %v4float %16 %13
718 %18 = OpImageSampleProjImplicitLod %v4float %16 %13
719 %19 = OpFAdd %v4float %18 %17
720 OpStore %gl_FragColor %19
721 OpReturn
722 OpFunctionEnd
723 )";
724 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
725 ValueNumberTable vtable(context.get());
726 Instruction* load1 = context->get_def_use_mgr()->GetDef(17);
727 Instruction* load2 = context->get_def_use_mgr()->GetDef(18);
728 EXPECT_EQ(vtable.GetValueNumber(load1), vtable.GetValueNumber(load2));
729 }
730
TEST_F(ValueTableTest,DifferentDebugLocalVariableSameValue)731 TEST_F(ValueTableTest, DifferentDebugLocalVariableSameValue) {
732 const std::string text = R"(
733 OpCapability Shader
734 %1 = OpExtInstImport "GLSL.std.450"
735 %2 = OpExtInstImport "OpenCL.DebugInfo.100"
736 OpMemoryModel Logical GLSL450
737 OpEntryPoint Fragment %3 "main"
738 OpExecutionMode %3 OriginUpperLeft
739 OpSource GLSL 430
740 %4 = OpString "test"
741 %5 = OpTypeVoid
742 %6 = OpTypeFunction %5
743 %7 = OpTypeInt 32 0
744 %8 = OpConstant %7 32
745 %9 = OpExtInst %5 %2 DebugSource %4
746 %10 = OpExtInst %5 %2 DebugCompilationUnit 1 4 %9 HLSL
747 %11 = OpExtInst %5 %2 DebugTypeBasic %4 %8 Float
748 %12 = OpExtInst %5 %2 DebugLocalVariable %4 %11 %9 0 0 %10 FlagIsLocal
749 %13 = OpExtInst %5 %2 DebugLocalVariable %4 %11 %9 0 0 %10 FlagIsLocal
750 %3 = OpFunction %5 None %6
751 %14 = OpLabel
752 OpReturn
753 OpFunctionEnd
754 )";
755 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
756 ValueNumberTable vtable(context.get());
757 Instruction* inst1 = context->get_def_use_mgr()->GetDef(12);
758 Instruction* inst2 = context->get_def_use_mgr()->GetDef(13);
759 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
760 }
761
TEST_F(ValueTableTest,DifferentDebugValueSameValue)762 TEST_F(ValueTableTest, DifferentDebugValueSameValue) {
763 const std::string text = R"(
764 OpCapability Shader
765 %1 = OpExtInstImport "GLSL.std.450"
766 %2 = OpExtInstImport "OpenCL.DebugInfo.100"
767 OpMemoryModel Logical GLSL450
768 OpEntryPoint Fragment %3 "main"
769 OpExecutionMode %3 OriginUpperLeft
770 OpSource GLSL 430
771 %4 = OpString "test"
772 %5 = OpTypeVoid
773 %6 = OpTypeFunction %5
774 %7 = OpTypeInt 32 0
775 %8 = OpConstant %7 32
776 %9 = OpExtInst %5 %2 DebugSource %4
777 %10 = OpExtInst %5 %2 DebugCompilationUnit 1 4 %9 HLSL
778 %11 = OpExtInst %5 %2 DebugTypeBasic %4 %8 Float
779 %12 = OpExtInst %5 %2 DebugLocalVariable %4 %11 %9 0 0 %10 FlagIsLocal
780 %13 = OpExtInst %5 %2 DebugExpression
781 %3 = OpFunction %5 None %6
782 %14 = OpLabel
783 %15 = OpExtInst %5 %2 DebugValue %12 %8 %13
784 %16 = OpExtInst %5 %2 DebugValue %12 %8 %13
785 OpReturn
786 OpFunctionEnd
787 )";
788 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
789 ValueNumberTable vtable(context.get());
790 Instruction* inst1 = context->get_def_use_mgr()->GetDef(15);
791 Instruction* inst2 = context->get_def_use_mgr()->GetDef(16);
792 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
793 }
794
TEST_F(ValueTableTest,DifferentDebugDeclareSameValue)795 TEST_F(ValueTableTest, DifferentDebugDeclareSameValue) {
796 const std::string text = R"(
797 OpCapability Shader
798 %1 = OpExtInstImport "GLSL.std.450"
799 %2 = OpExtInstImport "OpenCL.DebugInfo.100"
800 OpMemoryModel Logical GLSL450
801 OpEntryPoint Fragment %3 "main"
802 OpExecutionMode %3 OriginUpperLeft
803 OpSource GLSL 430
804 %4 = OpString "test"
805 %void = OpTypeVoid
806 %6 = OpTypeFunction %void
807 %uint = OpTypeInt 32 0
808 %_ptr_Function_uint = OpTypePointer Function %uint
809 %uint_32 = OpConstant %uint 32
810 %10 = OpExtInst %void %2 DebugSource %4
811 %11 = OpExtInst %void %2 DebugCompilationUnit 1 4 %10 HLSL
812 %12 = OpExtInst %void %2 DebugTypeBasic %4 %uint_32 Float
813 %13 = OpExtInst %void %2 DebugLocalVariable %4 %12 %10 0 0 %11 FlagIsLocal
814 %14 = OpExtInst %void %2 DebugExpression
815 %3 = OpFunction %void None %6
816 %15 = OpLabel
817 %16 = OpVariable %_ptr_Function_uint Function
818 %17 = OpExtInst %void %2 DebugDeclare %13 %16 %14
819 %18 = OpExtInst %void %2 DebugDeclare %13 %16 %14
820 OpReturn
821 OpFunctionEnd
822 )";
823 auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
824 ValueNumberTable vtable(context.get());
825 Instruction* inst1 = context->get_def_use_mgr()->GetDef(17);
826 Instruction* inst2 = context->get_def_use_mgr()->GetDef(18);
827 EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2));
828 }
829
830 } // namespace
831 } // namespace opt
832 } // namespace spvtools
833