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 "source/opt/ir_context.h"
16 
17 #include <algorithm>
18 #include <memory>
19 #include <string>
20 #include <utility>
21 
22 #include "OpenCLDebugInfo100.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "source/opt/pass.h"
26 #include "test/opt/pass_fixture.h"
27 #include "test/opt/pass_utils.h"
28 
29 static const uint32_t kDebugDeclareOperandVariableIndex = 5;
30 static const uint32_t kDebugValueOperandValueIndex = 5;
31 
32 namespace spvtools {
33 namespace opt {
34 namespace {
35 
36 using Analysis = IRContext::Analysis;
37 using ::testing::Each;
38 using ::testing::UnorderedElementsAre;
39 
40 class NoopPassPreservesNothing : public Pass {
41  public:
NoopPassPreservesNothing(Status s)42   NoopPassPreservesNothing(Status s) : Pass(), status_to_return_(s) {}
43 
name() const44   const char* name() const override { return "noop-pass"; }
Process()45   Status Process() override { return status_to_return_; }
46 
47  private:
48   Status status_to_return_;
49 };
50 
51 class NoopPassPreservesAll : public Pass {
52  public:
NoopPassPreservesAll(Status s)53   NoopPassPreservesAll(Status s) : Pass(), status_to_return_(s) {}
54 
name() const55   const char* name() const override { return "noop-pass"; }
Process()56   Status Process() override { return status_to_return_; }
57 
GetPreservedAnalyses()58   Analysis GetPreservedAnalyses() override {
59     return Analysis(IRContext::kAnalysisEnd - 1);
60   }
61 
62  private:
63   Status status_to_return_;
64 };
65 
66 class NoopPassPreservesFirst : public Pass {
67  public:
NoopPassPreservesFirst(Status s)68   NoopPassPreservesFirst(Status s) : Pass(), status_to_return_(s) {}
69 
name() const70   const char* name() const override { return "noop-pass"; }
Process()71   Status Process() override { return status_to_return_; }
72 
GetPreservedAnalyses()73   Analysis GetPreservedAnalyses() override { return IRContext::kAnalysisBegin; }
74 
75  private:
76   Status status_to_return_;
77 };
78 
79 using IRContextTest = PassTest<::testing::Test>;
80 
TEST_F(IRContextTest,IndividualValidAfterBuild)81 TEST_F(IRContextTest, IndividualValidAfterBuild) {
82   std::unique_ptr<Module> module(new Module());
83   IRContext localContext(SPV_ENV_UNIVERSAL_1_2, std::move(module),
84                          spvtools::MessageConsumer());
85 
86   for (Analysis i = IRContext::kAnalysisBegin; i < IRContext::kAnalysisEnd;
87        i <<= 1) {
88     localContext.BuildInvalidAnalyses(i);
89     EXPECT_TRUE(localContext.AreAnalysesValid(i));
90   }
91 }
92 
TEST_F(IRContextTest,AllValidAfterBuild)93 TEST_F(IRContextTest, AllValidAfterBuild) {
94   std::unique_ptr<Module> module = MakeUnique<Module>();
95   IRContext localContext(SPV_ENV_UNIVERSAL_1_2, std::move(module),
96                          spvtools::MessageConsumer());
97 
98   Analysis built_analyses = IRContext::kAnalysisNone;
99   for (Analysis i = IRContext::kAnalysisBegin; i < IRContext::kAnalysisEnd;
100        i <<= 1) {
101     localContext.BuildInvalidAnalyses(i);
102     built_analyses |= i;
103   }
104   EXPECT_TRUE(localContext.AreAnalysesValid(built_analyses));
105 }
106 
TEST_F(IRContextTest,AllValidAfterPassNoChange)107 TEST_F(IRContextTest, AllValidAfterPassNoChange) {
108   std::unique_ptr<Module> module = MakeUnique<Module>();
109   IRContext localContext(SPV_ENV_UNIVERSAL_1_2, std::move(module),
110                          spvtools::MessageConsumer());
111 
112   Analysis built_analyses = IRContext::kAnalysisNone;
113   for (Analysis i = IRContext::kAnalysisBegin; i < IRContext::kAnalysisEnd;
114        i <<= 1) {
115     localContext.BuildInvalidAnalyses(i);
116     built_analyses |= i;
117   }
118 
119   NoopPassPreservesNothing pass(Pass::Status::SuccessWithoutChange);
120   Pass::Status s = pass.Run(&localContext);
121   EXPECT_EQ(s, Pass::Status::SuccessWithoutChange);
122   EXPECT_TRUE(localContext.AreAnalysesValid(built_analyses));
123 }
124 
TEST_F(IRContextTest,NoneValidAfterPassWithChange)125 TEST_F(IRContextTest, NoneValidAfterPassWithChange) {
126   std::unique_ptr<Module> module = MakeUnique<Module>();
127   IRContext localContext(SPV_ENV_UNIVERSAL_1_2, std::move(module),
128                          spvtools::MessageConsumer());
129 
130   for (Analysis i = IRContext::kAnalysisBegin; i < IRContext::kAnalysisEnd;
131        i <<= 1) {
132     localContext.BuildInvalidAnalyses(i);
133   }
134 
135   NoopPassPreservesNothing pass(Pass::Status::SuccessWithChange);
136   Pass::Status s = pass.Run(&localContext);
137   EXPECT_EQ(s, Pass::Status::SuccessWithChange);
138   for (Analysis i = IRContext::kAnalysisBegin; i < IRContext::kAnalysisEnd;
139        i <<= 1) {
140     EXPECT_FALSE(localContext.AreAnalysesValid(i));
141   }
142 }
143 
TEST_F(IRContextTest,AllPreservedAfterPassWithChange)144 TEST_F(IRContextTest, AllPreservedAfterPassWithChange) {
145   std::unique_ptr<Module> module = MakeUnique<Module>();
146   IRContext localContext(SPV_ENV_UNIVERSAL_1_2, std::move(module),
147                          spvtools::MessageConsumer());
148 
149   for (Analysis i = IRContext::kAnalysisBegin; i < IRContext::kAnalysisEnd;
150        i <<= 1) {
151     localContext.BuildInvalidAnalyses(i);
152   }
153 
154   NoopPassPreservesAll pass(Pass::Status::SuccessWithChange);
155   Pass::Status s = pass.Run(&localContext);
156   EXPECT_EQ(s, Pass::Status::SuccessWithChange);
157   for (Analysis i = IRContext::kAnalysisBegin; i < IRContext::kAnalysisEnd;
158        i <<= 1) {
159     EXPECT_TRUE(localContext.AreAnalysesValid(i));
160   }
161 }
162 
TEST_F(IRContextTest,PreserveFirstOnlyAfterPassWithChange)163 TEST_F(IRContextTest, PreserveFirstOnlyAfterPassWithChange) {
164   std::unique_ptr<Module> module = MakeUnique<Module>();
165   IRContext localContext(SPV_ENV_UNIVERSAL_1_2, std::move(module),
166                          spvtools::MessageConsumer());
167 
168   for (Analysis i = IRContext::kAnalysisBegin; i < IRContext::kAnalysisEnd;
169        i <<= 1) {
170     localContext.BuildInvalidAnalyses(i);
171   }
172 
173   NoopPassPreservesFirst pass(Pass::Status::SuccessWithChange);
174   Pass::Status s = pass.Run(&localContext);
175   EXPECT_EQ(s, Pass::Status::SuccessWithChange);
176   EXPECT_TRUE(localContext.AreAnalysesValid(IRContext::kAnalysisBegin));
177   for (Analysis i = IRContext::kAnalysisBegin << 1; i < IRContext::kAnalysisEnd;
178        i <<= 1) {
179     EXPECT_FALSE(localContext.AreAnalysesValid(i));
180   }
181 }
182 
TEST_F(IRContextTest,KillMemberName)183 TEST_F(IRContextTest, KillMemberName) {
184   const std::string text = R"(
185               OpCapability Shader
186           %1 = OpExtInstImport "GLSL.std.450"
187                OpMemoryModel Logical GLSL450
188                OpEntryPoint Fragment %2 "main"
189                OpExecutionMode %2 OriginUpperLeft
190                OpSource GLSL 430
191                OpName %3 "stuff"
192                OpMemberName %3 0 "refZ"
193                OpMemberDecorate %3 0 Offset 0
194                OpDecorate %3 Block
195           %4 = OpTypeFloat 32
196           %3 = OpTypeStruct %4
197           %5 = OpTypeVoid
198           %6 = OpTypeFunction %5
199           %2 = OpFunction %5 None %6
200           %7 = OpLabel
201                OpReturn
202                OpFunctionEnd
203 )";
204 
205   std::unique_ptr<IRContext> context =
206       BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
207 
208   // Build the decoration manager.
209   context->get_decoration_mgr();
210 
211   // Delete the OpTypeStruct.  Should delete the OpName, OpMemberName, and
212   // OpMemberDecorate associated with it.
213   context->KillDef(3);
214 
215   // Make sure all of the name are removed.
216   for (auto& inst : context->debugs2()) {
217     EXPECT_EQ(inst.opcode(), SpvOpNop);
218   }
219 
220   // Make sure all of the decorations are removed.
221   for (auto& inst : context->annotations()) {
222     EXPECT_EQ(inst.opcode(), SpvOpNop);
223   }
224 }
225 
TEST_F(IRContextTest,KillGroupDecoration)226 TEST_F(IRContextTest, KillGroupDecoration) {
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                OpDecorate %3 Restrict
235           %3 = OpDecorationGroup
236                OpGroupDecorate %3 %4 %5
237           %6 = OpTypeFloat 32
238           %7 = OpTypePointer Function %6
239           %8 = OpTypeStruct %6
240           %9 = OpTypeVoid
241          %10 = OpTypeFunction %9
242           %2 = OpFunction %9 None %10
243          %11 = OpLabel
244           %4 = OpVariable %7 Function
245           %5 = OpVariable %7 Function
246                OpReturn
247                OpFunctionEnd
248 )";
249 
250   std::unique_ptr<IRContext> context =
251       BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
252 
253   // Build the decoration manager.
254   context->get_decoration_mgr();
255 
256   // Delete the second variable.
257   context->KillDef(5);
258 
259   // The three decorations instructions should still be there.  The first two
260   // should be the same, but the third should have %5 removed.
261 
262   // Check the OpDecorate instruction
263   auto inst = context->annotation_begin();
264   EXPECT_EQ(inst->opcode(), SpvOpDecorate);
265   EXPECT_EQ(inst->GetSingleWordInOperand(0), 3);
266 
267   // Check the OpDecorationGroup Instruction
268   ++inst;
269   EXPECT_EQ(inst->opcode(), SpvOpDecorationGroup);
270   EXPECT_EQ(inst->result_id(), 3);
271 
272   // Check that %5 is no longer part of the group.
273   ++inst;
274   EXPECT_EQ(inst->opcode(), SpvOpGroupDecorate);
275   EXPECT_EQ(inst->NumInOperands(), 2);
276   EXPECT_EQ(inst->GetSingleWordInOperand(0), 3);
277   EXPECT_EQ(inst->GetSingleWordInOperand(1), 4);
278 
279   // Check that we are at the end.
280   ++inst;
281   EXPECT_EQ(inst, context->annotation_end());
282 }
283 
TEST_F(IRContextTest,TakeNextUniqueIdIncrementing)284 TEST_F(IRContextTest, TakeNextUniqueIdIncrementing) {
285   const uint32_t NUM_TESTS = 1000;
286   IRContext localContext(SPV_ENV_UNIVERSAL_1_2, nullptr);
287   for (uint32_t i = 1; i < NUM_TESTS; ++i)
288     EXPECT_EQ(i, localContext.TakeNextUniqueId());
289 }
290 
TEST_F(IRContextTest,KillGroupDecorationWitNoDecorations)291 TEST_F(IRContextTest, KillGroupDecorationWitNoDecorations) {
292   const std::string text = R"(
293                OpCapability Shader
294           %1 = OpExtInstImport "GLSL.std.450"
295                OpMemoryModel Logical GLSL450
296                OpEntryPoint Fragment %2 "main"
297                OpExecutionMode %2 OriginUpperLeft
298                OpSource GLSL 430
299           %3 = OpDecorationGroup
300                OpGroupDecorate %3 %4 %5
301           %6 = OpTypeFloat 32
302           %7 = OpTypePointer Function %6
303           %8 = OpTypeStruct %6
304           %9 = OpTypeVoid
305          %10 = OpTypeFunction %9
306           %2 = OpFunction %9 None %10
307          %11 = OpLabel
308           %4 = OpVariable %7 Function
309           %5 = OpVariable %7 Function
310                OpReturn
311                OpFunctionEnd
312 )";
313 
314   std::unique_ptr<IRContext> context =
315       BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
316 
317   // Build the decoration manager.
318   context->get_decoration_mgr();
319 
320   // Delete the second variable.
321   context->KillDef(5);
322 
323   // The two decoration instructions should still be there.  The first one
324   // should be the same, but the second should have %5 removed.
325 
326   // Check the OpDecorationGroup Instruction
327   auto inst = context->annotation_begin();
328   EXPECT_EQ(inst->opcode(), SpvOpDecorationGroup);
329   EXPECT_EQ(inst->result_id(), 3);
330 
331   // Check that %5 is no longer part of the group.
332   ++inst;
333   EXPECT_EQ(inst->opcode(), SpvOpGroupDecorate);
334   EXPECT_EQ(inst->NumInOperands(), 2);
335   EXPECT_EQ(inst->GetSingleWordInOperand(0), 3);
336   EXPECT_EQ(inst->GetSingleWordInOperand(1), 4);
337 
338   // Check that we are at the end.
339   ++inst;
340   EXPECT_EQ(inst, context->annotation_end());
341 }
342 
TEST_F(IRContextTest,KillDecorationGroup)343 TEST_F(IRContextTest, KillDecorationGroup) {
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 = OpDecorationGroup
352                OpGroupDecorate %3 %4 %5
353           %6 = OpTypeFloat 32
354           %7 = OpTypePointer Function %6
355           %8 = OpTypeStruct %6
356           %9 = OpTypeVoid
357          %10 = OpTypeFunction %9
358           %2 = OpFunction %9 None %10
359          %11 = OpLabel
360           %4 = OpVariable %7 Function
361           %5 = OpVariable %7 Function
362                OpReturn
363                OpFunctionEnd
364 )";
365 
366   std::unique_ptr<IRContext> context =
367       BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
368 
369   // Build the decoration manager.
370   context->get_decoration_mgr();
371 
372   // Delete the second variable.
373   context->KillDef(3);
374 
375   // Check the OpDecorationGroup Instruction is still there.
376   EXPECT_TRUE(context->annotations().empty());
377 }
378 
TEST_F(IRContextTest,KillFunctionFromDebugFunction)379 TEST_F(IRContextTest, KillFunctionFromDebugFunction) {
380   const std::string text = R"(
381                OpCapability Shader
382           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
383                OpMemoryModel Logical GLSL450
384                OpEntryPoint Fragment %2 "main"
385                OpExecutionMode %2 OriginUpperLeft
386           %3 = OpString "ps.hlsl"
387           %4 = OpString "foo"
388                OpSource HLSL 600
389        %void = OpTypeVoid
390           %6 = OpTypeFunction %void
391           %7 = OpExtInst %void %1 DebugSource %3
392           %8 = OpExtInst %void %1 DebugCompilationUnit 1 4 %7 HLSL
393           %9 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %void
394          %10 = OpExtInst %void %1 DebugFunction %4 %9 %7 1 1 %8 %4 FlagIsProtected|FlagIsPrivate 1 %11
395           %2 = OpFunction %void None %6
396          %12 = OpLabel
397                OpReturn
398                OpFunctionEnd
399          %11 = OpFunction %void None %6
400          %13 = OpLabel
401                OpReturn
402                OpFunctionEnd
403 )";
404 
405   std::unique_ptr<IRContext> context =
406       BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
407 
408   // Delete the second variable.
409   context->KillDef(11);
410 
411   // Get DebugInfoNone id.
412   uint32_t debug_info_none_id = 0;
413   for (auto it = context->ext_inst_debuginfo_begin();
414        it != context->ext_inst_debuginfo_end(); ++it) {
415     if (it->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
416       debug_info_none_id = it->result_id();
417     }
418   }
419   EXPECT_NE(0, debug_info_none_id);
420 
421   // Check the Function operand of DebugFunction is DebugInfoNone.
422   const uint32_t kDebugFunctionOperandFunctionIndex = 13;
423   bool checked = false;
424   for (auto it = context->ext_inst_debuginfo_begin();
425        it != context->ext_inst_debuginfo_end(); ++it) {
426     if (it->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
427       EXPECT_FALSE(checked);
428       EXPECT_EQ(it->GetOperand(kDebugFunctionOperandFunctionIndex).words[0],
429                 debug_info_none_id);
430       checked = true;
431     }
432   }
433   EXPECT_TRUE(checked);
434 }
435 
TEST_F(IRContextTest,KillVariableFromDebugGlobalVariable)436 TEST_F(IRContextTest, KillVariableFromDebugGlobalVariable) {
437   const std::string text = R"(
438                OpCapability Shader
439           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
440                OpMemoryModel Logical GLSL450
441                OpEntryPoint Fragment %2 "main"
442                OpExecutionMode %2 OriginUpperLeft
443           %3 = OpString "ps.hlsl"
444           %4 = OpString "foo"
445           %5 = OpString "int"
446                OpSource HLSL 600
447        %uint = OpTypeInt 32 0
448     %uint_32 = OpConstant %uint 32
449 %_ptr_Private_uint = OpTypePointer Private %uint
450        %void = OpTypeVoid
451          %10 = OpTypeFunction %void
452          %11 = OpVariable %_ptr_Private_uint Private
453          %12 = OpExtInst %void %1 DebugSource %3
454          %13 = OpExtInst %void %1 DebugCompilationUnit 1 4 %12 HLSL
455          %14 = OpExtInst %void %1 DebugTypeBasic %5 %uint_32 Signed
456          %15 = OpExtInst %void %1 DebugGlobalVariable %4 %14 %12 1 12 %13 %4 %11 FlagIsDefinition
457           %2 = OpFunction %void None %10
458          %16 = OpLabel
459                OpReturn
460                OpFunctionEnd
461 )";
462 
463   std::unique_ptr<IRContext> context =
464       BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
465 
466   // Delete the second variable.
467   context->KillDef(11);
468 
469   // Get DebugInfoNone id.
470   uint32_t debug_info_none_id = 0;
471   for (auto it = context->ext_inst_debuginfo_begin();
472        it != context->ext_inst_debuginfo_end(); ++it) {
473     if (it->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
474       debug_info_none_id = it->result_id();
475     }
476   }
477   EXPECT_NE(0, debug_info_none_id);
478 
479   // Check the Function operand of DebugFunction is DebugInfoNone.
480   const uint32_t kDebugGlobalVariableOperandVariableIndex = 11;
481   bool checked = false;
482   for (auto it = context->ext_inst_debuginfo_begin();
483        it != context->ext_inst_debuginfo_end(); ++it) {
484     if (it->GetOpenCL100DebugOpcode() ==
485         OpenCLDebugInfo100DebugGlobalVariable) {
486       EXPECT_FALSE(checked);
487       EXPECT_EQ(
488           it->GetOperand(kDebugGlobalVariableOperandVariableIndex).words[0],
489           debug_info_none_id);
490       checked = true;
491     }
492   }
493   EXPECT_TRUE(checked);
494 }
495 
TEST_F(IRContextTest,BasicVisitFromEntryPoint)496 TEST_F(IRContextTest, BasicVisitFromEntryPoint) {
497   // Make sure we visit the entry point, and the function it calls.
498   // Do not visit Dead or Exported.
499   const std::string text = R"(
500                OpCapability Shader
501                OpMemoryModel Logical GLSL450
502                OpEntryPoint Fragment %10 "main"
503                OpName %10 "main"
504                OpName %Dead "Dead"
505                OpName %11 "Constant"
506                OpName %ExportedFunc "ExportedFunc"
507                OpDecorate %ExportedFunc LinkageAttributes "ExportedFunc" Export
508        %void = OpTypeVoid
509           %6 = OpTypeFunction %void
510          %10 = OpFunction %void None %6
511          %14 = OpLabel
512          %15 = OpFunctionCall %void %11
513          %16 = OpFunctionCall %void %11
514                OpReturn
515                OpFunctionEnd
516          %11 = OpFunction %void None %6
517          %18 = OpLabel
518                OpReturn
519                OpFunctionEnd
520        %Dead = OpFunction %void None %6
521          %19 = OpLabel
522                OpReturn
523                OpFunctionEnd
524 %ExportedFunc = OpFunction %void None %7
525          %20 = OpLabel
526          %21 = OpFunctionCall %void %11
527                OpReturn
528                OpFunctionEnd
529 )";
530   // clang-format on
531 
532   std::unique_ptr<IRContext> localContext =
533       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
534                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
535   EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n"
536                                    << text << std::endl;
537   std::vector<uint32_t> processed;
538   Pass::ProcessFunction mark_visited = [&processed](Function* fp) {
539     processed.push_back(fp->result_id());
540     return false;
541   };
542   localContext->ProcessEntryPointCallTree(mark_visited);
543   EXPECT_THAT(processed, UnorderedElementsAre(10, 11));
544 }
545 
TEST_F(IRContextTest,BasicVisitReachable)546 TEST_F(IRContextTest, BasicVisitReachable) {
547   // Make sure we visit the entry point, exported function, and the function
548   // they call. Do not visit Dead.
549   const std::string text = R"(
550                OpCapability Shader
551                OpMemoryModel Logical GLSL450
552                OpEntryPoint Fragment %10 "main"
553                OpName %10 "main"
554                OpName %Dead "Dead"
555                OpName %11 "Constant"
556                OpName %12 "ExportedFunc"
557                OpName %13 "Constant2"
558                OpDecorate %12 LinkageAttributes "ExportedFunc" Export
559        %void = OpTypeVoid
560           %6 = OpTypeFunction %void
561          %10 = OpFunction %void None %6
562          %14 = OpLabel
563          %15 = OpFunctionCall %void %11
564          %16 = OpFunctionCall %void %11
565                OpReturn
566                OpFunctionEnd
567          %11 = OpFunction %void None %6
568          %18 = OpLabel
569                OpReturn
570                OpFunctionEnd
571        %Dead = OpFunction %void None %6
572          %19 = OpLabel
573                OpReturn
574                OpFunctionEnd
575          %12 = OpFunction %void None %6
576          %20 = OpLabel
577          %21 = OpFunctionCall %void %13
578                OpReturn
579                OpFunctionEnd
580          %13 = OpFunction %void None %6
581          %22 = OpLabel
582                OpReturn
583                OpFunctionEnd
584 )";
585   // clang-format on
586 
587   std::unique_ptr<IRContext> localContext =
588       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
589                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
590   EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n"
591                                    << text << std::endl;
592 
593   std::vector<uint32_t> processed;
594   Pass::ProcessFunction mark_visited = [&processed](Function* fp) {
595     processed.push_back(fp->result_id());
596     return false;
597   };
598   localContext->ProcessReachableCallTree(mark_visited);
599   EXPECT_THAT(processed, UnorderedElementsAre(10, 11, 12, 13));
600 }
601 
TEST_F(IRContextTest,BasicVisitOnlyOnce)602 TEST_F(IRContextTest, BasicVisitOnlyOnce) {
603   // Make sure we visit %12 only once, even if it is called from two different
604   // functions.
605   const std::string text = R"(
606                OpCapability Shader
607                OpMemoryModel Logical GLSL450
608                OpEntryPoint Fragment %10 "main"
609                OpName %10 "main"
610                OpName %Dead "Dead"
611                OpName %11 "Constant"
612                OpName %12 "ExportedFunc"
613                OpDecorate %12 LinkageAttributes "ExportedFunc" Export
614        %void = OpTypeVoid
615           %6 = OpTypeFunction %void
616          %10 = OpFunction %void None %6
617          %14 = OpLabel
618          %15 = OpFunctionCall %void %11
619          %16 = OpFunctionCall %void %12
620                OpReturn
621                OpFunctionEnd
622          %11 = OpFunction %void None %6
623          %18 = OpLabel
624          %19 = OpFunctionCall %void %12
625                OpReturn
626                OpFunctionEnd
627        %Dead = OpFunction %void None %6
628          %20 = OpLabel
629                OpReturn
630                OpFunctionEnd
631          %12 = OpFunction %void None %6
632          %21 = OpLabel
633                OpReturn
634                OpFunctionEnd
635 )";
636   // clang-format on
637 
638   std::unique_ptr<IRContext> localContext =
639       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
640                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
641   EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n"
642                                    << text << std::endl;
643 
644   std::vector<uint32_t> processed;
645   Pass::ProcessFunction mark_visited = [&processed](Function* fp) {
646     processed.push_back(fp->result_id());
647     return false;
648   };
649   localContext->ProcessReachableCallTree(mark_visited);
650   EXPECT_THAT(processed, UnorderedElementsAre(10, 11, 12));
651 }
652 
TEST_F(IRContextTest,BasicDontVisitExportedVariable)653 TEST_F(IRContextTest, BasicDontVisitExportedVariable) {
654   // Make sure we only visit functions and not exported variables.
655   const std::string text = R"(
656                OpCapability Shader
657                OpMemoryModel Logical GLSL450
658                OpEntryPoint Fragment %10 "main"
659                OpExecutionMode %10 OriginUpperLeft
660                OpSource GLSL 150
661                OpName %10 "main"
662                OpName %12 "export_var"
663                OpDecorate %12 LinkageAttributes "export_var" Export
664        %void = OpTypeVoid
665           %6 = OpTypeFunction %void
666       %float = OpTypeFloat 32
667   %float_1 = OpConstant %float 1
668          %12 = OpVariable %float Output
669          %10 = OpFunction %void None %6
670          %14 = OpLabel
671                OpStore %12 %float_1
672                OpReturn
673                OpFunctionEnd
674 )";
675   // clang-format on
676 
677   std::unique_ptr<IRContext> localContext =
678       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
679                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
680   EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n"
681                                    << text << std::endl;
682 
683   std::vector<uint32_t> processed;
684   Pass::ProcessFunction mark_visited = [&processed](Function* fp) {
685     processed.push_back(fp->result_id());
686     return false;
687   };
688   localContext->ProcessReachableCallTree(mark_visited);
689   EXPECT_THAT(processed, UnorderedElementsAre(10));
690 }
691 
TEST_F(IRContextTest,IdBoundTestAtLimit)692 TEST_F(IRContextTest, IdBoundTestAtLimit) {
693   const std::string text = R"(
694 OpCapability Shader
695 OpCapability Linkage
696 OpMemoryModel Logical GLSL450
697 %1 = OpTypeVoid
698 %2 = OpTypeFunction %1
699 %3 = OpFunction %1 None %2
700 %4 = OpLabel
701 OpReturn
702 OpFunctionEnd)";
703 
704   std::unique_ptr<IRContext> context =
705       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
706                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
707   uint32_t current_bound = context->module()->id_bound();
708   context->set_max_id_bound(current_bound);
709   uint32_t next_id_bound = context->TakeNextId();
710   EXPECT_EQ(next_id_bound, 0);
711   EXPECT_EQ(current_bound, context->module()->id_bound());
712   next_id_bound = context->TakeNextId();
713   EXPECT_EQ(next_id_bound, 0);
714 }
715 
TEST_F(IRContextTest,IdBoundTestBelowLimit)716 TEST_F(IRContextTest, IdBoundTestBelowLimit) {
717   const std::string text = R"(
718 OpCapability Shader
719 OpCapability Linkage
720 OpMemoryModel Logical GLSL450
721 %1 = OpTypeVoid
722 %2 = OpTypeFunction %1
723 %3 = OpFunction %1 None %2
724 %4 = OpLabel
725 OpReturn
726 OpFunctionEnd)";
727 
728   std::unique_ptr<IRContext> context =
729       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
730                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
731   uint32_t current_bound = context->module()->id_bound();
732   context->set_max_id_bound(current_bound + 100);
733   uint32_t next_id_bound = context->TakeNextId();
734   EXPECT_EQ(next_id_bound, current_bound);
735   EXPECT_EQ(current_bound + 1, context->module()->id_bound());
736   next_id_bound = context->TakeNextId();
737   EXPECT_EQ(next_id_bound, current_bound + 1);
738 }
739 
TEST_F(IRContextTest,IdBoundTestNearLimit)740 TEST_F(IRContextTest, IdBoundTestNearLimit) {
741   const std::string text = R"(
742 OpCapability Shader
743 OpCapability Linkage
744 OpMemoryModel Logical GLSL450
745 %1 = OpTypeVoid
746 %2 = OpTypeFunction %1
747 %3 = OpFunction %1 None %2
748 %4 = OpLabel
749 OpReturn
750 OpFunctionEnd)";
751 
752   std::unique_ptr<IRContext> context =
753       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
754                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
755   uint32_t current_bound = context->module()->id_bound();
756   context->set_max_id_bound(current_bound + 1);
757   uint32_t next_id_bound = context->TakeNextId();
758   EXPECT_EQ(next_id_bound, current_bound);
759   EXPECT_EQ(current_bound + 1, context->module()->id_bound());
760   next_id_bound = context->TakeNextId();
761   EXPECT_EQ(next_id_bound, 0);
762 }
763 
TEST_F(IRContextTest,IdBoundTestUIntMax)764 TEST_F(IRContextTest, IdBoundTestUIntMax) {
765   const std::string text = R"(
766 OpCapability Shader
767 OpCapability Linkage
768 OpMemoryModel Logical GLSL450
769 %1 = OpTypeVoid
770 %2 = OpTypeFunction %1
771 %3 = OpFunction %1 None %2
772 %4294967294 = OpLabel ; ID is UINT_MAX-1
773 OpReturn
774 OpFunctionEnd)";
775 
776   std::unique_ptr<IRContext> context =
777       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
778                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
779   uint32_t current_bound = context->module()->id_bound();
780 
781   // Expecting |BuildModule| to preserve the numeric ids.
782   EXPECT_EQ(current_bound, std::numeric_limits<uint32_t>::max());
783 
784   context->set_max_id_bound(current_bound);
785   uint32_t next_id_bound = context->TakeNextId();
786   EXPECT_EQ(next_id_bound, 0);
787   EXPECT_EQ(current_bound, context->module()->id_bound());
788 }
789 
TEST_F(IRContextTest,CfgAndDomAnalysis)790 TEST_F(IRContextTest, CfgAndDomAnalysis) {
791   const std::string text = R"(
792 OpCapability Shader
793 OpCapability Linkage
794 OpMemoryModel Logical GLSL450
795 %1 = OpTypeVoid
796 %2 = OpTypeFunction %1
797 %3 = OpFunction %1 None %2
798 %4 = OpLabel
799 OpReturn
800 OpFunctionEnd)";
801 
802   std::unique_ptr<IRContext> ctx =
803       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
804                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
805 
806   // Building the dominator analysis should build the CFG.
807   ASSERT_TRUE(ctx->module()->begin() != ctx->module()->end());
808   ctx->GetDominatorAnalysis(&*ctx->module()->begin());
809 
810   EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisCFG));
811   EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisDominatorAnalysis));
812 
813   // Invalidating the CFG analysis should invalidate the dominator analysis.
814   ctx->InvalidateAnalyses(IRContext::kAnalysisCFG);
815   EXPECT_FALSE(ctx->AreAnalysesValid(IRContext::kAnalysisCFG));
816   EXPECT_FALSE(ctx->AreAnalysesValid(IRContext::kAnalysisDominatorAnalysis));
817 }
818 
TEST_F(IRContextTest,AsanErrorTest)819 TEST_F(IRContextTest, AsanErrorTest) {
820   std::string shader = R"(
821                OpCapability Shader
822           %1 = OpExtInstImport "GLSL.std.450"
823                OpMemoryModel Logical GLSL450
824                OpEntryPoint Fragment %4 "main"
825                OpExecutionMode %4 OriginUpperLeft
826                OpSource ESSL 310
827                OpName %4 "main"
828                OpName %8 "x"
829                OpName %10 "y"
830                OpDecorate %8 RelaxedPrecision
831                OpDecorate %10 RelaxedPrecision
832                OpDecorate %11 RelaxedPrecision
833           %2 = OpTypeVoid
834           %3 = OpTypeFunction %2
835           %6 = OpTypeInt 32 1
836           %7 = OpTypePointer Function %6
837           %9 = OpConstant %6 1
838           %4 = OpFunction %2 None %3
839           %5 = OpLabel
840           %8 = OpVariable %7 Function
841          %10 = OpVariable %7 Function
842                OpStore %8 %9
843          %11 = OpLoad %6 %8
844 	       OpBranch %20
845 	 %20 = OpLabel
846 	 %21 = OpPhi %6 %11 %5
847          OpStore %10 %21
848          OpReturn
849          OpFunctionEnd
850   )";
851 
852   const auto env = SPV_ENV_UNIVERSAL_1_3;
853   const auto consumer = nullptr;
854   const auto context = BuildModule(
855       env, consumer, shader, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
856 
857   opt::Function* fun =
858       context->cfg()->block(5)->GetParent();  // Computes the CFG analysis
859   opt::DominatorAnalysis* dom = nullptr;
860   dom = context->GetDominatorAnalysis(fun);  // Computes the dominator analysis,
861                                              // which depends on the CFG
862                                              // analysis
863   context->InvalidateAnalysesExceptFor(
864       opt::IRContext::Analysis::kAnalysisDominatorAnalysis);  // Invalidates the
865                                                               // CFG analysis
866   dom = context->GetDominatorAnalysis(
867       fun);  // Recompute the CFG analysis because the Dominator tree uses it.
868   auto bb = dom->ImmediateDominator(5);
869   std::cout
870       << bb->id();  // Make sure asan does not complain about use after free.
871 }
872 
TEST_F(IRContextTest,DebugInstructionReplaceSingleUse)873 TEST_F(IRContextTest, DebugInstructionReplaceSingleUse) {
874   const std::string text = R"(
875 OpCapability Shader
876 OpCapability Linkage
877 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
878 OpMemoryModel Logical GLSL450
879 %2 = OpString "test"
880 %3 = OpTypeVoid
881 %4 = OpTypeFunction %3
882 %5 = OpTypeFloat 32
883 %6 = OpTypePointer Function %5
884 %7 = OpConstant %5 0
885 %8 = OpTypeInt 32 0
886 %9 = OpConstant %8 32
887 %10 = OpExtInst %3 %1 DebugExpression
888 %11 = OpExtInst %3 %1 DebugSource %2
889 %12 = OpExtInst %3 %1 DebugCompilationUnit 1 4 %11 HLSL
890 %13 = OpExtInst %3 %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %3
891 %14 = OpExtInst %3 %1 DebugFunction %2 %13 %11 0 0 %12 %2 FlagIsProtected|FlagIsPrivate 0 %17
892 %15 = OpExtInst %3 %1 DebugTypeBasic %2 %9 Float
893 %16 = OpExtInst %3 %1 DebugLocalVariable %2 %15 %11 0 0 %14 FlagIsLocal
894 %17 = OpFunction %3 None %4
895 %18 = OpLabel
896 %19 = OpExtInst %3 %1 DebugScope %14
897 %20 = OpVariable %6 Function
898 %26 = OpVariable %6 Function
899 OpBranch %21
900 %21 = OpLabel
901 %22 = OpPhi %5 %7 %18
902 OpBranch %23
903 %23 = OpLabel
904 OpLine %2 0 0
905 OpStore %20 %7
906 %24 = OpExtInst %3 %1 DebugValue %16 %22 %10
907 %25 = OpExtInst %3 %1 DebugDeclare %16 %26 %10
908 OpReturn
909 OpFunctionEnd)";
910 
911   std::unique_ptr<IRContext> ctx =
912       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
913                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
914   ctx->BuildInvalidAnalyses(IRContext::kAnalysisDebugInfo);
915   NoopPassPreservesAll pass(Pass::Status::SuccessWithChange);
916   pass.Run(ctx.get());
917   EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisDebugInfo));
918 
919   auto* dbg_value = ctx->get_def_use_mgr()->GetDef(24);
920   EXPECT_TRUE(dbg_value->GetSingleWordOperand(kDebugValueOperandValueIndex) ==
921               22);
922   EXPECT_TRUE(ctx->ReplaceAllUsesWith(22, 7));
923   dbg_value = ctx->get_def_use_mgr()->GetDef(24);
924   EXPECT_TRUE(dbg_value->GetSingleWordOperand(kDebugValueOperandValueIndex) ==
925               7);
926 
927   auto* dbg_decl = ctx->get_def_use_mgr()->GetDef(25);
928   EXPECT_TRUE(
929       dbg_decl->GetSingleWordOperand(kDebugDeclareOperandVariableIndex) == 26);
930   EXPECT_TRUE(ctx->ReplaceAllUsesWith(26, 20));
931   dbg_decl = ctx->get_def_use_mgr()->GetDef(25);
932   EXPECT_TRUE(
933       dbg_decl->GetSingleWordOperand(kDebugDeclareOperandVariableIndex) == 20);
934 }
935 
TEST_F(IRContextTest,DebugInstructionReplaceAllUses)936 TEST_F(IRContextTest, DebugInstructionReplaceAllUses) {
937   const std::string text = R"(
938 OpCapability Shader
939 OpCapability Linkage
940 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
941 OpMemoryModel Logical GLSL450
942 %2 = OpString "test"
943 %3 = OpTypeVoid
944 %4 = OpTypeFunction %3
945 %5 = OpTypeFloat 32
946 %6 = OpTypePointer Function %5
947 %7 = OpConstant %5 0
948 %8 = OpTypeInt 32 0
949 %9 = OpConstant %8 32
950 %10 = OpExtInst %3 %1 DebugExpression
951 %11 = OpExtInst %3 %1 DebugSource %2
952 %12 = OpExtInst %3 %1 DebugCompilationUnit 1 4 %11 HLSL
953 %13 = OpExtInst %3 %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %3
954 %14 = OpExtInst %3 %1 DebugFunction %2 %13 %11 0 0 %12 %2 FlagIsProtected|FlagIsPrivate 0 %17
955 %15 = OpExtInst %3 %1 DebugTypeBasic %2 %9 Float
956 %16 = OpExtInst %3 %1 DebugLocalVariable %2 %15 %11 0 0 %14 FlagIsLocal
957 %27 = OpExtInst %3 %1 DebugLocalVariable %2 %15 %11 1 0 %14 FlagIsLocal
958 %17 = OpFunction %3 None %4
959 %18 = OpLabel
960 %19 = OpExtInst %3 %1 DebugScope %14
961 %20 = OpVariable %6 Function
962 %26 = OpVariable %6 Function
963 OpBranch %21
964 %21 = OpLabel
965 %22 = OpPhi %5 %7 %18
966 OpBranch %23
967 %23 = OpLabel
968 OpLine %2 0 0
969 OpStore %20 %7
970 %24 = OpExtInst %3 %1 DebugValue %16 %22 %10
971 %25 = OpExtInst %3 %1 DebugDeclare %16 %26 %10
972 %28 = OpExtInst %3 %1 DebugValue %27 %22 %10
973 %29 = OpExtInst %3 %1 DebugDeclare %27 %26 %10
974 OpReturn
975 OpFunctionEnd)";
976 
977   std::unique_ptr<IRContext> ctx =
978       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
979                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
980   ctx->BuildInvalidAnalyses(IRContext::kAnalysisDebugInfo);
981   NoopPassPreservesAll pass(Pass::Status::SuccessWithChange);
982   pass.Run(ctx.get());
983   EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisDebugInfo));
984 
985   auto* dbg_value0 = ctx->get_def_use_mgr()->GetDef(24);
986   auto* dbg_value1 = ctx->get_def_use_mgr()->GetDef(28);
987   EXPECT_TRUE(dbg_value0->GetSingleWordOperand(kDebugValueOperandValueIndex) ==
988               22);
989   EXPECT_TRUE(dbg_value1->GetSingleWordOperand(kDebugValueOperandValueIndex) ==
990               22);
991   EXPECT_TRUE(ctx->ReplaceAllUsesWith(22, 7));
992   dbg_value0 = ctx->get_def_use_mgr()->GetDef(24);
993   dbg_value1 = ctx->get_def_use_mgr()->GetDef(28);
994   EXPECT_TRUE(dbg_value0->GetSingleWordOperand(kDebugValueOperandValueIndex) ==
995               7);
996   EXPECT_TRUE(dbg_value1->GetSingleWordOperand(kDebugValueOperandValueIndex) ==
997               7);
998 
999   auto* dbg_decl0 = ctx->get_def_use_mgr()->GetDef(25);
1000   auto* dbg_decl1 = ctx->get_def_use_mgr()->GetDef(29);
1001   EXPECT_TRUE(
1002       dbg_decl0->GetSingleWordOperand(kDebugDeclareOperandVariableIndex) == 26);
1003   EXPECT_TRUE(
1004       dbg_decl1->GetSingleWordOperand(kDebugDeclareOperandVariableIndex) == 26);
1005   EXPECT_TRUE(ctx->ReplaceAllUsesWith(26, 20));
1006   dbg_decl0 = ctx->get_def_use_mgr()->GetDef(25);
1007   dbg_decl1 = ctx->get_def_use_mgr()->GetDef(29);
1008   EXPECT_TRUE(
1009       dbg_decl0->GetSingleWordOperand(kDebugDeclareOperandVariableIndex) == 20);
1010   EXPECT_TRUE(
1011       dbg_decl1->GetSingleWordOperand(kDebugDeclareOperandVariableIndex) == 20);
1012 }
1013 
TEST_F(IRContextTest,DebugInstructionReplaceDebugScopeAndDebugInlinedAt)1014 TEST_F(IRContextTest, DebugInstructionReplaceDebugScopeAndDebugInlinedAt) {
1015   const std::string text = R"(
1016 OpCapability Shader
1017 OpCapability Linkage
1018 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
1019 OpMemoryModel Logical GLSL450
1020 %2 = OpString "test"
1021 %3 = OpTypeVoid
1022 %4 = OpTypeFunction %3
1023 %5 = OpTypeFloat 32
1024 %6 = OpTypePointer Function %5
1025 %7 = OpConstant %5 0
1026 %8 = OpTypeInt 32 0
1027 %9 = OpConstant %8 32
1028 %10 = OpExtInst %3 %1 DebugExpression
1029 %11 = OpExtInst %3 %1 DebugSource %2
1030 %12 = OpExtInst %3 %1 DebugCompilationUnit 1 4 %11 HLSL
1031 %13 = OpExtInst %3 %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %3
1032 %14 = OpExtInst %3 %1 DebugFunction %2 %13 %11 0 0 %12 %2 FlagIsProtected|FlagIsPrivate 0 %17
1033 %15 = OpExtInst %3 %1 DebugInfoNone
1034 %16 = OpExtInst %3 %1 DebugFunction %2 %13 %11 10 10 %12 %2 FlagIsProtected|FlagIsPrivate 0 %15
1035 %25 = OpExtInst %3 %1 DebugInlinedAt 0 %14
1036 %26 = OpExtInst %3 %1 DebugInlinedAt 2 %14
1037 %17 = OpFunction %3 None %4
1038 %18 = OpLabel
1039 %19 = OpExtInst %3 %1 DebugScope %14
1040 %20 = OpVariable %6 Function
1041 OpBranch %21
1042 %21 = OpLabel
1043 %24 = OpExtInst %3 %1 DebugScope %16
1044 %22 = OpPhi %5 %7 %18
1045 OpBranch %23
1046 %23 = OpLabel
1047 %27 = OpExtInst %3 %1 DebugScope %16 %25
1048 OpLine %2 0 0
1049 %28 = OpFAdd %5 %7 %7
1050 OpStore %20 %28
1051 OpReturn
1052 OpFunctionEnd)";
1053 
1054   std::unique_ptr<IRContext> ctx =
1055       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1056                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1057   ctx->BuildInvalidAnalyses(IRContext::kAnalysisDebugInfo);
1058   NoopPassPreservesAll pass(Pass::Status::SuccessWithChange);
1059   pass.Run(ctx.get());
1060   EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisDebugInfo));
1061 
1062   auto* inst0 = ctx->get_def_use_mgr()->GetDef(20);
1063   auto* inst1 = ctx->get_def_use_mgr()->GetDef(22);
1064   auto* inst2 = ctx->get_def_use_mgr()->GetDef(28);
1065   EXPECT_EQ(inst0->GetDebugScope().GetLexicalScope(), 14);
1066   EXPECT_EQ(inst1->GetDebugScope().GetLexicalScope(), 16);
1067   EXPECT_EQ(inst2->GetDebugScope().GetLexicalScope(), 16);
1068   EXPECT_EQ(inst2->GetDebugInlinedAt(), 25);
1069 
1070   EXPECT_TRUE(ctx->ReplaceAllUsesWith(14, 12));
1071   EXPECT_TRUE(ctx->ReplaceAllUsesWith(16, 14));
1072   EXPECT_TRUE(ctx->ReplaceAllUsesWith(25, 26));
1073   EXPECT_EQ(inst0->GetDebugScope().GetLexicalScope(), 12);
1074   EXPECT_EQ(inst1->GetDebugScope().GetLexicalScope(), 14);
1075   EXPECT_EQ(inst2->GetDebugScope().GetLexicalScope(), 14);
1076   EXPECT_EQ(inst2->GetDebugInlinedAt(), 26);
1077 }
1078 
TEST_F(IRContextTest,AddDebugValueAfterReplaceUse)1079 TEST_F(IRContextTest, AddDebugValueAfterReplaceUse) {
1080   const std::string text = R"(
1081 OpCapability Shader
1082 OpCapability Linkage
1083 %1 = OpExtInstImport "OpenCL.DebugInfo.100"
1084 OpMemoryModel Logical GLSL450
1085 %2 = OpString "test"
1086 %3 = OpTypeVoid
1087 %4 = OpTypeFunction %3
1088 %5 = OpTypeFloat 32
1089 %6 = OpTypePointer Function %5
1090 %7 = OpConstant %5 0
1091 %8 = OpTypeInt 32 0
1092 %9 = OpConstant %8 32
1093 %10 = OpExtInst %3 %1 DebugExpression
1094 %11 = OpExtInst %3 %1 DebugSource %2
1095 %12 = OpExtInst %3 %1 DebugCompilationUnit 1 4 %11 HLSL
1096 %13 = OpExtInst %3 %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %3
1097 %14 = OpExtInst %3 %1 DebugFunction %2 %13 %11 0 0 %12 %2 FlagIsProtected|FlagIsPrivate 0 %17
1098 %15 = OpExtInst %3 %1 DebugTypeBasic %2 %9 Float
1099 %16 = OpExtInst %3 %1 DebugLocalVariable %2 %15 %11 0 0 %14 FlagIsLocal
1100 %17 = OpFunction %3 None %4
1101 %18 = OpLabel
1102 %19 = OpExtInst %3 %1 DebugScope %14
1103 %20 = OpVariable %6 Function
1104 %26 = OpVariable %6 Function
1105 OpBranch %21
1106 %21 = OpLabel
1107 %27 = OpExtInst %3 %1 DebugScope %14
1108 %22 = OpPhi %5 %7 %18
1109 OpBranch %23
1110 %23 = OpLabel
1111 %28 = OpExtInst %3 %1 DebugScope %14
1112 OpLine %2 0 0
1113 OpStore %20 %7
1114 %24 = OpExtInst %3 %1 DebugValue %16 %22 %10
1115 %25 = OpExtInst %3 %1 DebugDeclare %16 %26 %10
1116 OpReturn
1117 OpFunctionEnd)";
1118 
1119   std::unique_ptr<IRContext> ctx =
1120       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
1121                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1122   ctx->BuildInvalidAnalyses(IRContext::kAnalysisDebugInfo);
1123   NoopPassPreservesAll pass(Pass::Status::SuccessWithChange);
1124   pass.Run(ctx.get());
1125   EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisDebugInfo));
1126 
1127   // Replace all uses of result it '26' with '20'
1128   auto* dbg_decl = ctx->get_def_use_mgr()->GetDef(25);
1129   EXPECT_EQ(dbg_decl->GetSingleWordOperand(kDebugDeclareOperandVariableIndex),
1130             26);
1131   EXPECT_TRUE(ctx->ReplaceAllUsesWith(26, 20));
1132   dbg_decl = ctx->get_def_use_mgr()->GetDef(25);
1133   EXPECT_EQ(dbg_decl->GetSingleWordOperand(kDebugDeclareOperandVariableIndex),
1134             20);
1135 
1136   // No DebugValue should be added because result id '26' is not used for
1137   // DebugDeclare.
1138   ctx->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible(dbg_decl, 26, 22,
1139                                                              dbg_decl, nullptr);
1140   EXPECT_EQ(dbg_decl->NextNode()->opcode(), SpvOpReturn);
1141 
1142   // DebugValue should be added because result id '20' is used for DebugDeclare.
1143   ctx->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible(dbg_decl, 20, 22,
1144                                                              dbg_decl, nullptr);
1145   EXPECT_EQ(dbg_decl->NextNode()->GetOpenCL100DebugOpcode(),
1146             OpenCLDebugInfo100DebugValue);
1147 
1148   // Replace all uses of result it '20' with '26'
1149   EXPECT_EQ(dbg_decl->GetSingleWordOperand(kDebugDeclareOperandVariableIndex),
1150             20);
1151   EXPECT_TRUE(ctx->ReplaceAllUsesWith(20, 26));
1152   EXPECT_EQ(dbg_decl->GetSingleWordOperand(kDebugDeclareOperandVariableIndex),
1153             26);
1154 
1155   // No DebugValue should be added because result id '20' is not used for
1156   // DebugDeclare.
1157   ctx->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible(dbg_decl, 20, 7,
1158                                                              dbg_decl, nullptr);
1159   Instruction* dbg_value = dbg_decl->NextNode();
1160   EXPECT_EQ(dbg_value->GetOpenCL100DebugOpcode(), OpenCLDebugInfo100DebugValue);
1161   EXPECT_EQ(dbg_value->GetSingleWordOperand(kDebugValueOperandValueIndex), 22);
1162 
1163   // DebugValue should be added because result id '26' is used for DebugDeclare.
1164   ctx->get_debug_info_mgr()->AddDebugValueIfVarDeclIsVisible(dbg_decl, 26, 7,
1165                                                              dbg_decl, nullptr);
1166   dbg_value = dbg_decl->NextNode();
1167   EXPECT_EQ(dbg_value->GetOpenCL100DebugOpcode(), OpenCLDebugInfo100DebugValue);
1168   EXPECT_EQ(dbg_value->GetSingleWordOperand(kDebugValueOperandValueIndex), 7);
1169 }
1170 
1171 }  // namespace
1172 }  // namespace opt
1173 }  // namespace spvtools
1174