/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 |