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