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