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