Coverage Report

Created: 2025-07-04 07:23

/src/shaderc/third_party/spirv-tools/source/opt/pass.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2017 The Khronos Group Inc.
2
// Copyright (c) 2017 Valve Corporation
3
// Copyright (c) 2017 LunarG Inc.
4
//
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
//     http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
17
#include "source/opt/pass.h"
18
19
#include "source/opt/ir_builder.h"
20
#include "source/opt/iterator.h"
21
22
namespace spvtools {
23
namespace opt {
24
namespace {
25
constexpr uint32_t kTypePointerTypeIdInIdx = 1;
26
}  // namespace
27
28
79.8k
Pass::Pass() : consumer_(nullptr), context_(nullptr), already_run_(false) {}
29
30
71.2k
Pass::Status Pass::Run(IRContext* ctx) {
31
71.2k
  if (already_run_) {
32
0
    return Status::Failure;
33
0
  }
34
71.2k
  already_run_ = true;
35
36
71.2k
  context_ = ctx;
37
71.2k
  Pass::Status status = Process();
38
71.2k
  context_ = nullptr;
39
40
71.2k
  if (status == Status::SuccessWithChange) {
41
12.2k
    ctx->InvalidateAnalysesExceptFor(GetPreservedAnalyses());
42
12.2k
  }
43
71.2k
  if (!(status == Status::Failure || ctx->IsConsistent()))
44
0
    assert(false && "An analysis in the context is out of date.");
45
71.2k
  return status;
46
71.2k
}
47
48
13.2k
uint32_t Pass::GetPointeeTypeId(const Instruction* ptrInst) const {
49
13.2k
  const uint32_t ptrTypeId = ptrInst->type_id();
50
13.2k
  const Instruction* ptrTypeInst = get_def_use_mgr()->GetDef(ptrTypeId);
51
13.2k
  return ptrTypeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx);
52
13.2k
}
53
54
0
Instruction* Pass::GetBaseType(uint32_t ty_id) {
55
0
  Instruction* ty_inst = get_def_use_mgr()->GetDef(ty_id);
56
0
  if (ty_inst->opcode() == spv::Op::OpTypeMatrix) {
57
0
    uint32_t vty_id = ty_inst->GetSingleWordInOperand(0);
58
0
    ty_inst = get_def_use_mgr()->GetDef(vty_id);
59
0
  }
60
0
  if (ty_inst->opcode() == spv::Op::OpTypeVector) {
61
0
    uint32_t cty_id = ty_inst->GetSingleWordInOperand(0);
62
0
    ty_inst = get_def_use_mgr()->GetDef(cty_id);
63
0
  }
64
0
  return ty_inst;
65
0
}
66
67
0
bool Pass::IsFloat(uint32_t ty_id, uint32_t width) {
68
0
  Instruction* ty_inst = GetBaseType(ty_id);
69
0
  if (ty_inst->opcode() != spv::Op::OpTypeFloat) return false;
70
0
  return ty_inst->GetSingleWordInOperand(0) == width;
71
0
}
72
73
0
uint32_t Pass::GetNullId(uint32_t type_id) {
74
0
  if (IsFloat(type_id, 16)) context()->AddCapability(spv::Capability::Float16);
75
0
  analysis::TypeManager* type_mgr = context()->get_type_mgr();
76
0
  analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
77
0
  const analysis::Type* type = type_mgr->GetType(type_id);
78
0
  const analysis::Constant* null_const = const_mgr->GetConstant(type, {});
79
0
  Instruction* null_inst =
80
0
      const_mgr->GetDefiningInstruction(null_const, type_id);
81
0
  return null_inst->result_id();
82
0
}
83
84
uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id,
85
0
                            Instruction* insertion_position) {
86
0
  analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
87
88
0
  uint32_t original_type_id = object_to_copy->type_id();
89
0
  if (original_type_id == new_type_id) {
90
0
    return object_to_copy->result_id();
91
0
  }
92
93
0
  InstructionBuilder ir_builder(
94
0
      context(), insertion_position,
95
0
      IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDefUse);
96
97
0
  Instruction* original_type = get_def_use_mgr()->GetDef(original_type_id);
98
0
  Instruction* new_type = get_def_use_mgr()->GetDef(new_type_id);
99
100
0
  if (new_type->opcode() != original_type->opcode()) {
101
0
    return 0;
102
0
  }
103
104
0
  switch (original_type->opcode()) {
105
0
    case spv::Op::OpTypeArray: {
106
0
      uint32_t original_element_type_id =
107
0
          original_type->GetSingleWordInOperand(0);
108
0
      uint32_t new_element_type_id = new_type->GetSingleWordInOperand(0);
109
110
0
      std::vector<uint32_t> element_ids;
111
0
      uint32_t length_id = original_type->GetSingleWordInOperand(1);
112
0
      const analysis::Constant* length_const =
113
0
          const_mgr->FindDeclaredConstant(length_id);
114
0
      assert(length_const->AsIntConstant());
115
0
      uint32_t array_length = length_const->AsIntConstant()->GetU32();
116
0
      for (uint32_t i = 0; i < array_length; i++) {
117
0
        Instruction* extract = ir_builder.AddCompositeExtract(
118
0
            original_element_type_id, object_to_copy->result_id(), {i});
119
0
        uint32_t new_id =
120
0
            GenerateCopy(extract, new_element_type_id, insertion_position);
121
0
        if (new_id == 0) {
122
0
          return 0;
123
0
        }
124
0
        element_ids.push_back(new_id);
125
0
      }
126
127
0
      return ir_builder.AddCompositeConstruct(new_type_id, element_ids)
128
0
          ->result_id();
129
0
    }
130
0
    case spv::Op::OpTypeStruct: {
131
0
      std::vector<uint32_t> element_ids;
132
0
      for (uint32_t i = 0; i < original_type->NumInOperands(); i++) {
133
0
        uint32_t orig_member_type_id = original_type->GetSingleWordInOperand(i);
134
0
        uint32_t new_member_type_id = new_type->GetSingleWordInOperand(i);
135
0
        Instruction* extract = ir_builder.AddCompositeExtract(
136
0
            orig_member_type_id, object_to_copy->result_id(), {i});
137
0
        uint32_t new_id =
138
0
            GenerateCopy(extract, new_member_type_id, insertion_position);
139
0
        if (new_id == 0) {
140
0
          return 0;
141
0
        }
142
0
        element_ids.push_back(new_id);
143
0
      }
144
0
      return ir_builder.AddCompositeConstruct(new_type_id, element_ids)
145
0
          ->result_id();
146
0
    }
147
0
    default:
148
      // If we do not have an aggregate type, then we have a problem.  Either we
149
      // found multiple instances of the same type, or we are copying to an
150
      // incompatible type.  Either way the code is illegal. Leave the code as
151
      // is and let the caller deal with it.
152
0
      return 0;
153
0
  }
154
0
}
155
156
}  // namespace opt
157
}  // namespace spvtools