/src/spirv-tools/source/opt/constants.cpp
Line | Count | Source |
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/constants.h" |
16 | | |
17 | | #include <vector> |
18 | | |
19 | | #include "source/opt/ir_context.h" |
20 | | |
21 | | namespace spvtools { |
22 | | namespace opt { |
23 | | namespace analysis { |
24 | | |
25 | 134k | float Constant::GetFloat() const { |
26 | 134k | assert(type()->AsFloat() != nullptr && type()->AsFloat()->width() == 32); |
27 | | |
28 | 134k | if (const FloatConstant* fc = AsFloatConstant()) { |
29 | 133k | return fc->GetFloatValue(); |
30 | 133k | } else { |
31 | 1.45k | assert(AsNullConstant() && "Must be a floating point constant."); |
32 | 1.45k | return 0.0f; |
33 | 1.45k | } |
34 | 134k | } |
35 | | |
36 | 0 | double Constant::GetDouble() const { |
37 | 0 | assert(type()->AsFloat() != nullptr && type()->AsFloat()->width() == 64); |
38 | | |
39 | 0 | if (const FloatConstant* fc = AsFloatConstant()) { |
40 | 0 | return fc->GetDoubleValue(); |
41 | 0 | } else { |
42 | 0 | assert(AsNullConstant() && "Must be a floating point constant."); |
43 | 0 | return 0.0; |
44 | 0 | } |
45 | 0 | } |
46 | | |
47 | 4.21k | double Constant::GetValueAsDouble() const { |
48 | 4.21k | assert(type()->AsFloat() != nullptr); |
49 | 4.21k | if (type()->AsFloat()->width() == 32) { |
50 | 4.21k | return GetFloat(); |
51 | 4.21k | } else { |
52 | 0 | assert(type()->AsFloat()->width() == 64); |
53 | 0 | return GetDouble(); |
54 | 0 | } |
55 | 4.21k | } |
56 | | |
57 | 26.6k | uint32_t Constant::GetU32() const { |
58 | 26.6k | assert(type()->AsInteger() != nullptr); |
59 | 26.6k | assert(type()->AsInteger()->width() == 32); |
60 | | |
61 | 26.6k | if (const IntConstant* ic = AsIntConstant()) { |
62 | 26.5k | return ic->GetU32BitValue(); |
63 | 26.5k | } else { |
64 | 8 | assert(AsNullConstant() && "Must be an integer constant."); |
65 | 8 | return 0u; |
66 | 8 | } |
67 | 26.6k | } |
68 | | |
69 | 0 | uint64_t Constant::GetU64() const { |
70 | 0 | assert(type()->AsInteger() != nullptr); |
71 | 0 | assert(type()->AsInteger()->width() == 64); |
72 | | |
73 | 0 | if (const IntConstant* ic = AsIntConstant()) { |
74 | 0 | return ic->GetU64BitValue(); |
75 | 0 | } else { |
76 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
77 | 0 | return 0u; |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | 0 | int32_t Constant::GetS32() const { |
82 | 0 | assert(type()->AsInteger() != nullptr); |
83 | 0 | assert(type()->AsInteger()->width() == 32); |
84 | | |
85 | 0 | if (const IntConstant* ic = AsIntConstant()) { |
86 | 0 | return ic->GetS32BitValue(); |
87 | 0 | } else { |
88 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
89 | 0 | return 0; |
90 | 0 | } |
91 | 0 | } |
92 | | |
93 | 0 | int64_t Constant::GetS64() const { |
94 | 0 | assert(type()->AsInteger() != nullptr); |
95 | 0 | assert(type()->AsInteger()->width() == 64); |
96 | | |
97 | 0 | if (const IntConstant* ic = AsIntConstant()) { |
98 | 0 | return ic->GetS64BitValue(); |
99 | 0 | } else { |
100 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
101 | 0 | return 0; |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | 461k | uint64_t Constant::GetZeroExtendedValue() const { |
106 | 461k | const auto* int_type = type()->AsInteger(); |
107 | 461k | assert(int_type != nullptr); |
108 | 461k | const auto width = int_type->width(); |
109 | 461k | assert(width <= 64); |
110 | | |
111 | 461k | uint64_t value = 0; |
112 | 461k | if (const IntConstant* ic = AsIntConstant()) { |
113 | 460k | if (width <= 32) { |
114 | 460k | value = ic->GetU32BitValue(); |
115 | 460k | } else { |
116 | 0 | value = ic->GetU64BitValue(); |
117 | 0 | } |
118 | 460k | } else { |
119 | 288 | assert(AsNullConstant() && "Must be an integer constant."); |
120 | 288 | } |
121 | 461k | return value; |
122 | 461k | } |
123 | | |
124 | 238k | int64_t Constant::GetSignExtendedValue() const { |
125 | 238k | const auto* int_type = type()->AsInteger(); |
126 | 238k | assert(int_type != nullptr); |
127 | 238k | const auto width = int_type->width(); |
128 | 238k | assert(width <= 64); |
129 | | |
130 | 238k | int64_t value = 0; |
131 | 238k | if (const IntConstant* ic = AsIntConstant()) { |
132 | 237k | if (width <= 32) { |
133 | | // Let the C++ compiler do the sign extension. |
134 | 237k | value = int64_t(ic->GetS32BitValue()); |
135 | 237k | } else { |
136 | 0 | value = ic->GetS64BitValue(); |
137 | 0 | } |
138 | 237k | } else { |
139 | 469 | assert(AsNullConstant() && "Must be an integer constant."); |
140 | 469 | } |
141 | 238k | return value; |
142 | 238k | } |
143 | | |
144 | 12.0k | ConstantManager::ConstantManager(IRContext* ctx) : ctx_(ctx) { |
145 | | // Populate the constant table with values from constant declarations in the |
146 | | // module. The values of each OpConstant declaration is the identity |
147 | | // assignment (i.e., each constant is its own value). |
148 | 265k | for (const auto& inst : ctx_->module()->GetConstants()) { |
149 | 265k | MapInst(inst); |
150 | 265k | } |
151 | 12.0k | } |
152 | | |
153 | 755k | Type* ConstantManager::GetType(const Instruction* inst) const { |
154 | 755k | return context()->get_type_mgr()->GetType(inst->type_id()); |
155 | 755k | } |
156 | | |
157 | | std::vector<const Constant*> ConstantManager::GetOperandConstants( |
158 | 5.02M | const Instruction* inst) const { |
159 | 5.02M | std::vector<const Constant*> constants; |
160 | 5.02M | constants.reserve(inst->NumInOperands()); |
161 | 14.8M | for (uint32_t i = 0; i < inst->NumInOperands(); i++) { |
162 | 9.82M | const Operand* operand = &inst->GetInOperand(i); |
163 | 9.82M | if (operand->type != SPV_OPERAND_TYPE_ID) { |
164 | 1.18M | constants.push_back(nullptr); |
165 | 8.64M | } else { |
166 | 8.64M | uint32_t id = operand->words[0]; |
167 | 8.64M | const analysis::Constant* constant = FindDeclaredConstant(id); |
168 | 8.64M | constants.push_back(constant); |
169 | 8.64M | } |
170 | 9.82M | } |
171 | 5.02M | return constants; |
172 | 5.02M | } |
173 | | |
174 | | uint32_t ConstantManager::FindDeclaredConstant(const Constant* c, |
175 | 536k | uint32_t type_id) const { |
176 | 536k | if (c == nullptr) { |
177 | 0 | return 0; |
178 | 0 | } |
179 | 536k | c = FindConstant(c); |
180 | 536k | if (c == nullptr) { |
181 | 0 | return 0; |
182 | 0 | } |
183 | | |
184 | 536k | for (auto range = const_val_to_id_.equal_range(c); |
185 | 536k | range.first != range.second; ++range.first) { |
186 | 473k | Instruction* const_def = |
187 | 473k | context()->get_def_use_mgr()->GetDef(range.first->second); |
188 | 473k | if (type_id == 0 || const_def->type_id() == type_id) { |
189 | 473k | return range.first->second; |
190 | 473k | } |
191 | 473k | } |
192 | 63.0k | return 0; |
193 | 536k | } |
194 | | |
195 | | std::vector<const Constant*> ConstantManager::GetConstantsFromIds( |
196 | 84.7k | const std::vector<uint32_t>& ids) const { |
197 | 84.7k | std::vector<const Constant*> constants; |
198 | 273k | for (uint32_t id : ids) { |
199 | 273k | if (const Constant* c = FindDeclaredConstant(id)) { |
200 | 273k | constants.push_back(c); |
201 | 273k | } else { |
202 | 5 | return {}; |
203 | 5 | } |
204 | 273k | } |
205 | 84.7k | return constants; |
206 | 84.7k | } |
207 | | |
208 | | Instruction* ConstantManager::BuildInstructionAndAddToModule( |
209 | 62.9k | const Constant* new_const, Module::inst_iterator* pos, uint32_t type_id) { |
210 | 62.9k | if (new_const == nullptr) { |
211 | 0 | return nullptr; |
212 | 0 | } |
213 | 62.9k | uint32_t new_id = context()->TakeNextId(); |
214 | 62.9k | if (new_id == 0) { |
215 | 0 | return nullptr; |
216 | 0 | } |
217 | | |
218 | 62.9k | auto new_inst = CreateInstruction(new_id, new_const, type_id); |
219 | 62.9k | if (!new_inst) { |
220 | 0 | return nullptr; |
221 | 0 | } |
222 | 62.9k | auto* new_inst_ptr = new_inst.get(); |
223 | 62.9k | *pos = pos->InsertBefore(std::move(new_inst)); |
224 | 62.9k | ++(*pos); |
225 | 62.9k | if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse)) |
226 | 62.9k | context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inst_ptr); |
227 | 62.9k | MapConstantToInst(new_const, new_inst_ptr); |
228 | 62.9k | return new_inst_ptr; |
229 | 62.9k | } |
230 | | |
231 | | Instruction* ConstantManager::GetDefiningInstruction( |
232 | 398k | const Constant* c, uint32_t type_id, Module::inst_iterator* pos) { |
233 | 398k | if (c == nullptr) { |
234 | 0 | return nullptr; |
235 | 0 | } |
236 | 398k | uint32_t decl_id = FindDeclaredConstant(c, type_id); |
237 | 398k | if (decl_id == 0) { |
238 | 62.9k | auto iter = context()->types_values_end(); |
239 | 62.9k | if (pos == nullptr) pos = &iter; |
240 | 62.9k | return BuildInstructionAndAddToModule(c, pos, type_id); |
241 | 335k | } else { |
242 | 335k | auto def = context()->get_def_use_mgr()->GetDef(decl_id); |
243 | 335k | assert(def != nullptr); |
244 | 335k | assert((type_id == 0 || def->type_id() == type_id) && |
245 | 335k | "This constant already has an instruction with a different type."); |
246 | 335k | return def; |
247 | 335k | } |
248 | 398k | } |
249 | | |
250 | | std::unique_ptr<Constant> ConstantManager::CreateConstant( |
251 | 932k | const Type* type, const std::vector<uint32_t>& literal_words_or_ids) const { |
252 | 932k | if (literal_words_or_ids.size() == 0) { |
253 | | // Constant declared with OpConstantNull |
254 | 3.86k | return MakeUnique<NullConstant>(type); |
255 | 928k | } else if (auto* bt = type->AsBool()) { |
256 | 111k | assert(literal_words_or_ids.size() == 1 && |
257 | 111k | "Bool constant should be declared with one operand"); |
258 | 111k | return MakeUnique<BoolConstant>(bt, literal_words_or_ids.front()); |
259 | 816k | } else if (auto* it = type->AsInteger()) { |
260 | 595k | return MakeUnique<IntConstant>(it, literal_words_or_ids); |
261 | 595k | } else if (auto* ft = type->AsFloat()) { |
262 | 136k | return MakeUnique<FloatConstant>(ft, literal_words_or_ids); |
263 | 136k | } else if (auto* vt = type->AsVector()) { |
264 | 77.1k | auto components = GetConstantsFromIds(literal_words_or_ids); |
265 | 77.1k | if (components.empty()) return nullptr; |
266 | | // All components of VectorConstant must be of type Bool, Integer or Float. |
267 | 77.1k | if (!std::all_of(components.begin(), components.end(), |
268 | 235k | [](const Constant* c) { |
269 | 235k | if (c->type()->AsBool() || c->type()->AsInteger() || |
270 | 235k | c->type()->AsFloat()) { |
271 | 235k | return true; |
272 | 235k | } else { |
273 | 0 | return false; |
274 | 0 | } |
275 | 235k | })) |
276 | 0 | return nullptr; |
277 | | // All components of VectorConstant must be in the same type. |
278 | 77.1k | const auto* component_type = components.front()->type(); |
279 | 77.1k | if (!std::all_of(components.begin(), components.end(), |
280 | 235k | [&component_type](const Constant* c) { |
281 | 235k | if (c->type() == component_type) return true; |
282 | 0 | return false; |
283 | 235k | })) |
284 | 0 | return nullptr; |
285 | 77.1k | return MakeUnique<VectorConstant>(vt, components); |
286 | 77.1k | } else if (auto* mt = type->AsMatrix()) { |
287 | 232 | auto components = GetConstantsFromIds(literal_words_or_ids); |
288 | 232 | if (components.empty()) return nullptr; |
289 | 232 | return MakeUnique<MatrixConstant>(mt, components); |
290 | 7.41k | } else if (auto* st = type->AsStruct()) { |
291 | 6.50k | auto components = GetConstantsFromIds(literal_words_or_ids); |
292 | 6.50k | if (components.empty()) return nullptr; |
293 | 6.50k | return MakeUnique<StructConstant>(st, components); |
294 | 6.50k | } else if (auto* at = type->AsArray()) { |
295 | 909 | auto components = GetConstantsFromIds(literal_words_or_ids); |
296 | 909 | if (components.empty()) return nullptr; |
297 | 909 | return MakeUnique<ArrayConstant>(at, components); |
298 | 909 | } else if (auto* tt = type->AsTensorARM()) { |
299 | 0 | auto components = GetConstantsFromIds(literal_words_or_ids); |
300 | 0 | if (components.empty()) return nullptr; |
301 | 0 | return MakeUnique<TensorConstant>(tt, components); |
302 | 0 | } else { |
303 | 0 | return nullptr; |
304 | 0 | } |
305 | 932k | } |
306 | | |
307 | 628k | const Constant* ConstantManager::GetConstantFromInst(const Instruction* inst) { |
308 | 628k | std::vector<uint32_t> literal_words_or_ids; |
309 | | |
310 | | // Collect the constant defining literals or component ids. |
311 | 1.37M | for (uint32_t i = 0; i < inst->NumInOperands(); i++) { |
312 | 743k | literal_words_or_ids.insert(literal_words_or_ids.end(), |
313 | 743k | inst->GetInOperand(i).words.begin(), |
314 | 743k | inst->GetInOperand(i).words.end()); |
315 | 743k | } |
316 | | |
317 | 628k | const Type* type = GetType(inst); |
318 | | |
319 | 628k | switch (inst->opcode()) { |
320 | | // OpConstant{True|False} have the value embedded in the opcode. So they |
321 | | // are not handled by the for-loop above. Here we add the value explicitly. |
322 | 6.11k | case spv::Op::OpConstantTrue: |
323 | 6.11k | literal_words_or_ids.push_back(true); |
324 | 6.11k | break; |
325 | 5.92k | case spv::Op::OpConstantFalse: |
326 | 5.92k | literal_words_or_ids.push_back(false); |
327 | 5.92k | break; |
328 | 1.09k | case spv::Op::OpConstantNull: |
329 | 537k | case spv::Op::OpConstant: |
330 | 567k | case spv::Op::OpConstantComposite: |
331 | 567k | case spv::Op::OpSpecConstantComposite: |
332 | 567k | break; |
333 | | // Replicated composite constant instructions have a single operand for the |
334 | | // value. We need to replicate it as many times as there are components. |
335 | 0 | case spv::Op::OpConstantCompositeReplicateEXT: |
336 | 0 | case spv::Op::OpSpecConstantCompositeReplicateEXT: { |
337 | 0 | uint32_t value = literal_words_or_ids[0]; |
338 | 0 | uint64_t component_count = type->NumberOfComponents(); |
339 | 0 | if (const auto* tensor_type = type->AsTensorARM()) { |
340 | | // TensorARM shape is stored as an ID, so resolve the outer |
341 | | // dimension here instead of using Type::NumberOfComponents(). |
342 | 0 | if (!tensor_type->is_shaped()) { |
343 | 0 | return nullptr; |
344 | 0 | } |
345 | 0 | const auto* shape_inst = |
346 | 0 | context()->get_def_use_mgr()->GetDef(tensor_type->shape_id()); |
347 | 0 | if (!shape_inst) { |
348 | 0 | return nullptr; |
349 | 0 | } |
350 | 0 | const auto* shape_cst = GetConstantFromInst(shape_inst); |
351 | 0 | if (!shape_cst || !shape_cst->AsArrayConstant()) { |
352 | 0 | return nullptr; |
353 | 0 | } |
354 | 0 | const auto& shape_components = |
355 | 0 | shape_cst->AsArrayConstant()->GetComponents(); |
356 | 0 | if (shape_components.empty()) { |
357 | 0 | return nullptr; |
358 | 0 | } |
359 | 0 | const auto* outer_dim_cst = shape_components.front()->AsIntConstant(); |
360 | 0 | if (!outer_dim_cst) { |
361 | 0 | return nullptr; |
362 | 0 | } |
363 | 0 | component_count = outer_dim_cst->GetZeroExtendedValue(); |
364 | 0 | } |
365 | | // Cooperative matrix types have no component count and no constant |
366 | | // class. Do not turn an empty component list into a null constant. |
367 | 0 | if (component_count == 0) { |
368 | 0 | return nullptr; |
369 | 0 | } |
370 | 0 | literal_words_or_ids.assign(static_cast<size_t>(component_count), value); |
371 | 0 | break; |
372 | 0 | } |
373 | 49.1k | default: |
374 | 49.1k | return nullptr; |
375 | 628k | } |
376 | | |
377 | 579k | return GetConstant(type, literal_words_or_ids); |
378 | 628k | } |
379 | | |
380 | | std::unique_ptr<Instruction> ConstantManager::CreateInstruction( |
381 | 62.9k | uint32_t id, const Constant* c, uint32_t type_id) const { |
382 | 62.9k | uint32_t type = |
383 | 62.9k | (type_id == 0) ? context()->get_type_mgr()->GetId(c->type()) : type_id; |
384 | 62.9k | if (c->AsNullConstant()) { |
385 | 512 | return MakeUnique<Instruction>(context(), spv::Op::OpConstantNull, type, id, |
386 | 512 | std::initializer_list<Operand>{}); |
387 | 62.4k | } else if (const BoolConstant* bc = c->AsBoolConstant()) { |
388 | 6.79k | return MakeUnique<Instruction>( |
389 | 6.79k | context(), |
390 | 6.79k | bc->value() ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse, type, |
391 | 6.79k | id, std::initializer_list<Operand>{}); |
392 | 55.6k | } else if (const IntConstant* ic = c->AsIntConstant()) { |
393 | 32.4k | return MakeUnique<Instruction>( |
394 | 32.4k | context(), spv::Op::OpConstant, type, id, |
395 | 32.4k | std::initializer_list<Operand>{ |
396 | 32.4k | Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, |
397 | 32.4k | ic->words())}); |
398 | 32.4k | } else if (const FloatConstant* fc = c->AsFloatConstant()) { |
399 | 12.5k | return MakeUnique<Instruction>( |
400 | 12.5k | context(), spv::Op::OpConstant, type, id, |
401 | 12.5k | std::initializer_list<Operand>{ |
402 | 12.5k | Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, |
403 | 12.5k | fc->words())}); |
404 | 12.5k | } else if (const CompositeConstant* cc = c->AsCompositeConstant()) { |
405 | 10.6k | return CreateCompositeInstruction(id, cc, type_id); |
406 | 10.6k | } else { |
407 | 0 | return nullptr; |
408 | 0 | } |
409 | 62.9k | } |
410 | | |
411 | | std::unique_ptr<Instruction> ConstantManager::CreateCompositeInstruction( |
412 | 10.6k | uint32_t result_id, const CompositeConstant* cc, uint32_t type_id) const { |
413 | 10.6k | std::vector<Operand> operands; |
414 | 10.6k | Instruction* type_inst = context()->get_def_use_mgr()->GetDef(type_id); |
415 | 10.6k | uint32_t component_index = 0; |
416 | 28.5k | for (const Constant* component_const : cc->GetComponents()) { |
417 | 28.5k | uint32_t component_type_id = 0; |
418 | 28.5k | if (type_inst && type_inst->opcode() == spv::Op::OpTypeStruct) { |
419 | 6.62k | component_type_id = type_inst->GetSingleWordInOperand(component_index); |
420 | 21.9k | } else if (type_inst && type_inst->opcode() == spv::Op::OpTypeArray) { |
421 | 185 | component_type_id = type_inst->GetSingleWordInOperand(0); |
422 | 21.7k | } else if (type_inst && type_inst->opcode() == spv::Op::OpTypeTensorARM) { |
423 | 0 | component_type_id = |
424 | 0 | context()->get_type_mgr()->GetId(component_const->type()); |
425 | 0 | if (component_type_id == 0) { |
426 | 0 | return nullptr; |
427 | 0 | } |
428 | 0 | } |
429 | 28.5k | uint32_t id = FindDeclaredConstant(component_const, component_type_id); |
430 | | |
431 | 28.5k | if (id == 0) { |
432 | | // Cannot get the id of the component constant, while all components |
433 | | // should have been added to the module prior to the composite constant. |
434 | | // Cannot create OpConstantComposite instruction in this case. |
435 | 0 | return nullptr; |
436 | 0 | } |
437 | 28.5k | operands.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_ID, |
438 | 28.5k | std::initializer_list<uint32_t>{id}); |
439 | 28.5k | component_index++; |
440 | 28.5k | } |
441 | 10.6k | uint32_t type = |
442 | 10.6k | (type_id == 0) ? context()->get_type_mgr()->GetId(cc->type()) : type_id; |
443 | 10.6k | return MakeUnique<Instruction>(context(), spv::Op::OpConstantComposite, type, |
444 | 10.6k | result_id, std::move(operands)); |
445 | 10.6k | } |
446 | | |
447 | | const Constant* ConstantManager::GetConstant( |
448 | 932k | const Type* type, const std::vector<uint32_t>& literal_words_or_ids) { |
449 | 932k | if (type == nullptr) { |
450 | 0 | return nullptr; |
451 | 0 | } |
452 | 932k | auto cst = CreateConstant(type, literal_words_or_ids); |
453 | 932k | return cst ? RegisterConstant(std::move(cst)) : nullptr; |
454 | 932k | } |
455 | | |
456 | 3 | const Constant* ConstantManager::GetNullCompositeConstant(const Type* type) { |
457 | 3 | if (type == nullptr) { |
458 | 0 | return nullptr; |
459 | 0 | } |
460 | 3 | std::vector<uint32_t> literal_words_or_id; |
461 | | |
462 | 3 | if (type->AsVector()) { |
463 | 3 | const Type* element_type = type->AsVector()->element_type(); |
464 | 3 | const uint32_t null_id = GetNullConstId(element_type); |
465 | 3 | const uint32_t element_count = type->AsVector()->element_count(); |
466 | 9 | for (uint32_t i = 0; i < element_count; i++) { |
467 | 6 | literal_words_or_id.push_back(null_id); |
468 | 6 | } |
469 | 3 | } else if (type->AsMatrix()) { |
470 | 0 | const Type* element_type = type->AsMatrix()->element_type(); |
471 | 0 | const uint32_t null_id = GetNullConstId(element_type); |
472 | 0 | const uint32_t element_count = type->AsMatrix()->element_count(); |
473 | 0 | for (uint32_t i = 0; i < element_count; i++) { |
474 | 0 | literal_words_or_id.push_back(null_id); |
475 | 0 | } |
476 | 0 | } else if (type->AsStruct()) { |
477 | | // TODO (sfricke-lunarg) add proper struct support |
478 | 0 | return nullptr; |
479 | 0 | } else if (type->AsArray()) { |
480 | 0 | const Type* element_type = type->AsArray()->element_type(); |
481 | 0 | const uint32_t null_id = GetNullConstId(element_type); |
482 | 0 | assert(type->AsArray()->length_info().words[0] == |
483 | 0 | analysis::Array::LengthInfo::kConstant && |
484 | 0 | "unexpected array length"); |
485 | 0 | const uint32_t element_count = type->AsArray()->length_info().words[0]; |
486 | 0 | for (uint32_t i = 0; i < element_count; i++) { |
487 | 0 | literal_words_or_id.push_back(null_id); |
488 | 0 | } |
489 | 0 | } else if (type->AsTensorARM()) { |
490 | 0 | auto ttype = type->AsTensorARM(); |
491 | 0 | assert(ttype->is_shaped() && "Only shaped tensors are composites"); |
492 | 0 | const auto* shape_inst = |
493 | 0 | context()->get_def_use_mgr()->GetDef(ttype->shape_id()); |
494 | 0 | if (!shape_inst) { |
495 | 0 | return nullptr; |
496 | 0 | } |
497 | 0 | const auto* shape_cst = GetConstantFromInst(shape_inst); |
498 | 0 | if (!shape_cst || !shape_cst->AsArrayConstant()) { |
499 | 0 | return nullptr; |
500 | 0 | } |
501 | 0 | const auto& shape_components = |
502 | 0 | shape_cst->AsArrayConstant()->GetComponents(); |
503 | 0 | if (shape_components.empty()) { |
504 | 0 | return nullptr; |
505 | 0 | } |
506 | 0 | const auto* outer_dim_cst = shape_components.front()->AsIntConstant(); |
507 | 0 | if (!outer_dim_cst) { |
508 | 0 | return nullptr; |
509 | 0 | } |
510 | 0 | const uint64_t element_count = outer_dim_cst->GetZeroExtendedValue(); |
511 | 0 | std::vector<const Constant*> components; |
512 | 0 | components.reserve(static_cast<size_t>(element_count)); |
513 | |
|
514 | 0 | if (shape_components.size() == 1) { |
515 | 0 | const Constant* element_null = GetConstant(ttype->element_type(), {}); |
516 | 0 | for (uint64_t i = 0; i < element_count; i++) { |
517 | 0 | components.push_back(element_null); |
518 | 0 | } |
519 | 0 | return RegisterConstant( |
520 | 0 | MakeUnique<TensorConstant>(ttype, std::move(components))); |
521 | 0 | } |
522 | | |
523 | 0 | const Constant* rank_cst = nullptr; |
524 | 0 | if (ttype->rank_id() != 0) { |
525 | 0 | const auto* rank_inst = |
526 | 0 | context()->get_def_use_mgr()->GetDef(ttype->rank_id()); |
527 | 0 | if (rank_inst) { |
528 | 0 | rank_cst = GetConstantFromInst(rank_inst); |
529 | 0 | } |
530 | 0 | } |
531 | 0 | uint64_t rank_value = shape_components.size(); |
532 | 0 | if (rank_cst && rank_cst->AsIntConstant()) { |
533 | 0 | rank_value = rank_cst->AsIntConstant()->GetZeroExtendedValue(); |
534 | 0 | } |
535 | 0 | if (rank_value <= 1) { |
536 | 0 | const Constant* element_null = GetConstant(ttype->element_type(), {}); |
537 | 0 | for (uint64_t i = 0; i < element_count; i++) { |
538 | 0 | components.push_back(element_null); |
539 | 0 | } |
540 | 0 | return RegisterConstant( |
541 | 0 | MakeUnique<TensorConstant>(ttype, std::move(components))); |
542 | 0 | } |
543 | | |
544 | 0 | const uint64_t inner_rank = rank_value - 1; |
545 | 0 | const auto* rank_int_type = |
546 | 0 | rank_cst ? rank_cst->type()->AsInteger() : nullptr; |
547 | 0 | if (!rank_int_type) { |
548 | 0 | rank_int_type = outer_dim_cst->type()->AsInteger(); |
549 | 0 | } |
550 | 0 | if (!rank_int_type) { |
551 | 0 | return nullptr; |
552 | 0 | } |
553 | 0 | const Constant* inner_rank_cst = |
554 | 0 | GenerateIntegerConstant(rank_int_type, inner_rank); |
555 | 0 | const uint32_t inner_rank_id = |
556 | 0 | GetDefiningInstruction(inner_rank_cst)->result_id(); |
557 | |
|
558 | 0 | const Type* shape_elem_type = shape_components[1]->type(); |
559 | 0 | const auto* shape_elem_int = shape_elem_type->AsInteger(); |
560 | 0 | if (!shape_elem_int) { |
561 | 0 | return nullptr; |
562 | 0 | } |
563 | 0 | const Constant* inner_shape_len_cst = |
564 | 0 | GenerateIntegerConstant(shape_elem_int, inner_rank); |
565 | 0 | const uint32_t inner_shape_len_id = |
566 | 0 | GetDefiningInstruction(inner_shape_len_cst)->result_id(); |
567 | 0 | Array::LengthInfo inner_shape_len_info{ |
568 | 0 | inner_shape_len_id, |
569 | 0 | {Array::LengthInfo::kConstant, static_cast<uint32_t>(inner_rank)}}; |
570 | 0 | Array inner_shape_type(shape_elem_type, inner_shape_len_info); |
571 | 0 | const Type* inner_shape_reg_type = |
572 | 0 | context()->get_type_mgr()->GetRegisteredType(&inner_shape_type); |
573 | 0 | if (!inner_shape_reg_type) { |
574 | 0 | return nullptr; |
575 | 0 | } |
576 | 0 | std::vector<uint32_t> inner_shape_ids; |
577 | 0 | inner_shape_ids.reserve(shape_components.size() - 1); |
578 | 0 | for (size_t i = 1; i < shape_components.size(); ++i) { |
579 | 0 | inner_shape_ids.push_back( |
580 | 0 | GetDefiningInstruction(shape_components[i])->result_id()); |
581 | 0 | } |
582 | 0 | const Constant* inner_shape_cst = |
583 | 0 | GetConstant(inner_shape_reg_type, inner_shape_ids); |
584 | 0 | const uint32_t inner_shape_id = |
585 | 0 | GetDefiningInstruction(inner_shape_cst)->result_id(); |
586 | |
|
587 | 0 | TensorARM inner_tensor_type(ttype->element_type(), inner_rank_id, |
588 | 0 | inner_shape_id); |
589 | 0 | const Type* inner_tensor_reg_type = |
590 | 0 | context()->get_type_mgr()->GetRegisteredType(&inner_tensor_type); |
591 | 0 | if (!inner_tensor_reg_type) { |
592 | 0 | return nullptr; |
593 | 0 | } |
594 | 0 | const Constant* inner_null_tensor = |
595 | 0 | GetNullCompositeConstant(inner_tensor_reg_type); |
596 | 0 | if (!inner_null_tensor) { |
597 | 0 | return nullptr; |
598 | 0 | } |
599 | 0 | for (uint64_t i = 0; i < element_count; i++) { |
600 | 0 | components.push_back(inner_null_tensor); |
601 | 0 | } |
602 | 0 | return RegisterConstant( |
603 | 0 | MakeUnique<TensorConstant>(ttype, std::move(components))); |
604 | 0 | } else { |
605 | 0 | return nullptr; |
606 | 0 | } |
607 | | |
608 | 3 | return GetConstant(type, literal_words_or_id); |
609 | 3 | } |
610 | | |
611 | | const Constant* ConstantManager::GetNumericVectorConstantWithWords( |
612 | 149 | const Vector* type, const std::vector<uint32_t>& literal_words) { |
613 | 149 | const auto* element_type = type->element_type(); |
614 | 149 | uint32_t words_per_element = 0; |
615 | 149 | if (const auto* float_type = element_type->AsFloat()) |
616 | 1 | words_per_element = float_type->width() / 32; |
617 | 148 | else if (const auto* int_type = element_type->AsInteger()) |
618 | 148 | words_per_element = int_type->width() / 32; |
619 | 0 | else if (element_type->AsBool() != nullptr) |
620 | 0 | words_per_element = 1; |
621 | | |
622 | 149 | if (words_per_element != 1 && words_per_element != 2) return nullptr; |
623 | | |
624 | 149 | if (words_per_element * type->element_count() != |
625 | 149 | static_cast<uint32_t>(literal_words.size())) { |
626 | 0 | return nullptr; |
627 | 0 | } |
628 | | |
629 | 149 | std::vector<uint32_t> element_ids; |
630 | 741 | for (uint32_t i = 0; i < type->element_count(); ++i) { |
631 | 592 | auto first_word = literal_words.begin() + (words_per_element * i); |
632 | 592 | std::vector<uint32_t> const_data(first_word, |
633 | 592 | first_word + words_per_element); |
634 | 592 | const analysis::Constant* element_constant = |
635 | 592 | GetConstant(element_type, const_data); |
636 | 592 | if (!element_constant) { |
637 | 0 | return nullptr; |
638 | 0 | } |
639 | 592 | Instruction* element_inst = GetDefiningInstruction(element_constant); |
640 | 592 | if (!element_inst) { |
641 | 0 | return nullptr; |
642 | 0 | } |
643 | 592 | element_ids.push_back(element_inst->result_id()); |
644 | 592 | } |
645 | | |
646 | 149 | return GetConstant(type, element_ids); |
647 | 149 | } |
648 | | |
649 | 0 | uint32_t ConstantManager::GetFloatConstId(float val) { |
650 | 0 | const Constant* c = GetFloatConst(val); |
651 | 0 | Instruction* inst = GetDefiningInstruction(c); |
652 | 0 | if (inst == nullptr) return 0; |
653 | 0 | return inst->result_id(); |
654 | 0 | } |
655 | | |
656 | 590 | const Constant* ConstantManager::GetFloatConst(float val) { |
657 | 590 | Type* float_type = context()->get_type_mgr()->GetFloatType(); |
658 | 590 | utils::FloatProxy<float> v(val); |
659 | 590 | const Constant* c = GetConstant(float_type, v.GetWords()); |
660 | 590 | return c; |
661 | 590 | } |
662 | | |
663 | 0 | uint32_t ConstantManager::GetDoubleConstId(double val) { |
664 | 0 | const Constant* c = GetDoubleConst(val); |
665 | 0 | Instruction* inst = GetDefiningInstruction(c); |
666 | 0 | if (inst == nullptr) return 0; |
667 | 0 | return inst->result_id(); |
668 | 0 | } |
669 | | |
670 | 0 | const Constant* ConstantManager::GetDoubleConst(double val) { |
671 | 0 | Type* float_type = context()->get_type_mgr()->GetDoubleType(); |
672 | 0 | utils::FloatProxy<double> v(val); |
673 | 0 | const Constant* c = GetConstant(float_type, v.GetWords()); |
674 | 0 | return c; |
675 | 0 | } |
676 | | |
677 | 0 | uint32_t ConstantManager::GetSIntConstId(int32_t val) { |
678 | 0 | Type* sint_type = context()->get_type_mgr()->GetSIntType(); |
679 | 0 | const Constant* c = GetConstant(sint_type, {static_cast<uint32_t>(val)}); |
680 | 0 | if (!c) { |
681 | 0 | return 0; |
682 | 0 | } |
683 | 0 | Instruction* inst = GetDefiningInstruction(c); |
684 | 0 | if (!inst) { |
685 | 0 | return 0; |
686 | 0 | } |
687 | 0 | return inst->result_id(); |
688 | 0 | } |
689 | | |
690 | | const Constant* ConstantManager::GetIntConst(uint64_t val, int32_t bitWidth, |
691 | 701 | bool isSigned) { |
692 | 701 | Type* int_type = context()->get_type_mgr()->GetIntType(bitWidth, isSigned); |
693 | | |
694 | 701 | if (isSigned) { |
695 | | // Sign extend the value. |
696 | 554 | int32_t num_of_bit_to_ignore = 64 - bitWidth; |
697 | 554 | val = static_cast<int64_t>(val << num_of_bit_to_ignore) >> |
698 | 554 | num_of_bit_to_ignore; |
699 | 554 | } else if (bitWidth < 64) { |
700 | | // Clear the upper bit that are not used. |
701 | 147 | uint64_t mask = ((1ull << bitWidth) - 1); |
702 | 147 | val &= mask; |
703 | 147 | } |
704 | | |
705 | 701 | if (bitWidth <= 32) { |
706 | 701 | return GetConstant(int_type, {static_cast<uint32_t>(val)}); |
707 | 701 | } |
708 | | |
709 | | // If the value is more than 32-bit, we need to split the operands into two |
710 | | // 32-bit integers. |
711 | 0 | return GetConstant( |
712 | 0 | int_type, {static_cast<uint32_t>(val), static_cast<uint32_t>(val >> 32)}); |
713 | 701 | } |
714 | | |
715 | 0 | uint32_t ConstantManager::GetUIntConstId(uint32_t val) { |
716 | 0 | Type* uint_type = context()->get_type_mgr()->GetUIntType(); |
717 | 0 | const Constant* c = GetConstant(uint_type, {val}); |
718 | 0 | if (!c) { |
719 | 0 | return 0; |
720 | 0 | } |
721 | 0 | Instruction* inst = GetDefiningInstruction(c); |
722 | 0 | if (!inst) { |
723 | 0 | return 0; |
724 | 0 | } |
725 | 0 | return inst->result_id(); |
726 | 0 | } |
727 | | |
728 | 1.89k | uint32_t ConstantManager::GetNullConstId(const Type* type) { |
729 | 1.89k | const Constant* c = GetConstant(type, {}); |
730 | 1.89k | if (!c) { |
731 | 0 | return 0; |
732 | 0 | } |
733 | 1.89k | Instruction* inst = GetDefiningInstruction(c); |
734 | 1.89k | if (!inst) { |
735 | 0 | return 0; |
736 | 0 | } |
737 | 1.89k | return inst->result_id(); |
738 | 1.89k | } |
739 | | |
740 | | const Constant* ConstantManager::GenerateIntegerConstant( |
741 | 78.3k | const analysis::Integer* integer_type, uint64_t result) { |
742 | 78.3k | assert(integer_type != nullptr); |
743 | | |
744 | 78.3k | std::vector<uint32_t> words; |
745 | 78.3k | if (integer_type->width() == 64) { |
746 | | // In the 64-bit case, two words are needed to represent the value. |
747 | 0 | words = {static_cast<uint32_t>(result), |
748 | 0 | static_cast<uint32_t>(result >> 32)}; |
749 | 78.3k | } else { |
750 | | // In all other cases, only a single word is needed. |
751 | 78.3k | assert(integer_type->width() <= 32); |
752 | 78.3k | if (integer_type->IsSigned()) { |
753 | 77.5k | result = utils::SignExtendValue(result, integer_type->width()); |
754 | 77.5k | } else { |
755 | 792 | result = utils::ZeroExtendValue(result, integer_type->width()); |
756 | 792 | } |
757 | 78.3k | words = {static_cast<uint32_t>(result)}; |
758 | 78.3k | } |
759 | 78.3k | return GetConstant(integer_type, words); |
760 | 78.3k | } |
761 | | |
762 | | std::vector<const analysis::Constant*> Constant::GetVectorComponents( |
763 | 28.5k | analysis::ConstantManager* const_mgr) const { |
764 | 28.5k | std::vector<const analysis::Constant*> components; |
765 | 28.5k | const analysis::VectorConstant* a = this->AsVectorConstant(); |
766 | 28.5k | const analysis::Vector* vector_type = this->type()->AsVector(); |
767 | 28.5k | assert(vector_type != nullptr); |
768 | 28.5k | if (a != nullptr) { |
769 | 112k | for (uint32_t i = 0; i < vector_type->element_count(); ++i) { |
770 | 84.8k | components.push_back(a->GetComponents()[i]); |
771 | 84.8k | } |
772 | 28.1k | } else { |
773 | 422 | const analysis::Type* element_type = vector_type->element_type(); |
774 | 422 | const analysis::Constant* element_null_const = |
775 | 422 | const_mgr->GetConstant(element_type, {}); |
776 | 1.68k | for (uint32_t i = 0; i < vector_type->element_count(); ++i) { |
777 | 1.26k | components.push_back(element_null_const); |
778 | 1.26k | } |
779 | 422 | } |
780 | 28.5k | return components; |
781 | 28.5k | } |
782 | | |
783 | | } // namespace analysis |
784 | | } // namespace opt |
785 | | } // namespace spvtools |