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