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