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