Coverage Report

Created: 2025-12-31 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-tools/source/opt/eliminate_dead_constant_pass.cpp
Line
Count
Source
1
// Copyright (c) 2016 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/eliminate_dead_constant_pass.h"
16
17
#include <algorithm>
18
#include <unordered_map>
19
#include <unordered_set>
20
#include <vector>
21
22
#include "source/opt/def_use_manager.h"
23
#include "source/opt/log.h"
24
#include "source/opt/reflect.h"
25
26
namespace spvtools {
27
namespace opt {
28
29
0
Pass::Status EliminateDeadConstantPass::Process() {
30
0
  std::unordered_set<Instruction*> working_list;
31
  // Traverse all the instructions to get the initial set of dead constants as
32
  // working list and count number of real uses for constants. Uses in
33
  // annotation instructions do not count.
34
0
  std::unordered_map<Instruction*, size_t> use_counts;
35
0
  std::vector<Instruction*> constants = context()->GetConstants();
36
0
  for (auto* c : constants) {
37
0
    uint32_t const_id = c->result_id();
38
0
    size_t count = 0;
39
0
    context()->get_def_use_mgr()->ForEachUse(
40
0
        const_id, [&count](Instruction* user, uint32_t index) {
41
0
          (void)index;
42
0
          spv::Op op = user->opcode();
43
0
          if (!(IsAnnotationInst(op) || IsDebug1Inst(op) || IsDebug2Inst(op) ||
44
0
                IsDebug3Inst(op))) {
45
0
            ++count;
46
0
          }
47
0
        });
48
0
    use_counts[c] = count;
49
0
    if (!count) {
50
0
      working_list.insert(c);
51
0
    }
52
0
  }
53
54
  // Start from the constants with 0 uses, back trace through the def-use chain
55
  // to find all dead constants.
56
0
  std::unordered_set<Instruction*> dead_consts;
57
0
  while (!working_list.empty()) {
58
0
    Instruction* inst = *working_list.begin();
59
    // Back propagate if the instruction contains IDs in its operands.
60
0
    switch (inst->opcode()) {
61
0
      case spv::Op::OpConstantComposite:
62
0
      case spv::Op::OpSpecConstantComposite:
63
0
      case spv::Op::OpSpecConstantOp:
64
0
        for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
65
          // SpecConstantOp instruction contains 'opcode' as its operand. Need
66
          // to exclude such operands when decreasing uses.
67
0
          if (inst->GetInOperand(i).type != SPV_OPERAND_TYPE_ID) {
68
0
            continue;
69
0
          }
70
0
          uint32_t operand_id = inst->GetSingleWordInOperand(i);
71
0
          Instruction* def_inst =
72
0
              context()->get_def_use_mgr()->GetDef(operand_id);
73
          // If the use_count does not have any count for the def_inst,
74
          // def_inst must not be a constant, and should be ignored here.
75
0
          if (!use_counts.count(def_inst)) {
76
0
            continue;
77
0
          }
78
          // The number of uses should never be less then 0, so it can not be
79
          // less than 1 before it decreases.
80
0
          SPIRV_ASSERT(consumer(), use_counts[def_inst] > 0);
81
0
          --use_counts[def_inst];
82
0
          if (!use_counts[def_inst]) {
83
0
            working_list.insert(def_inst);
84
0
          }
85
0
        }
86
0
        break;
87
0
      default:
88
0
        break;
89
0
    }
90
0
    dead_consts.insert(inst);
91
0
    working_list.erase(inst);
92
0
  }
93
94
  // Turn all dead instructions and uses of them to nop
95
0
  for (auto* dc : dead_consts) {
96
0
    context()->KillDef(dc->result_id());
97
0
  }
98
0
  return dead_consts.empty() ? Status::SuccessWithoutChange
99
0
                             : Status::SuccessWithChange;
100
0
}
101
102
}  // namespace opt
103
}  // namespace spvtools