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