/src/spirv-tools/source/opt/constants.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 2.88M | float Constant::GetFloat() const { |
26 | 2.88M | assert(type()->AsFloat() != nullptr && type()->AsFloat()->width() == 32); |
27 | | |
28 | 2.88M | if (const FloatConstant* fc = AsFloatConstant()) { |
29 | 2.45M | return fc->GetFloatValue(); |
30 | 2.45M | } else { |
31 | 426k | assert(AsNullConstant() && "Must be a floating point constant."); |
32 | 426k | return 0.0f; |
33 | 426k | } |
34 | 2.88M | } |
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 | 1.88k | double Constant::GetValueAsDouble() const { |
48 | 1.88k | assert(type()->AsFloat() != nullptr); |
49 | 1.88k | if (type()->AsFloat()->width() == 32) { |
50 | 1.88k | return GetFloat(); |
51 | 1.88k | } else { |
52 | 0 | assert(type()->AsFloat()->width() == 64); |
53 | 0 | return GetDouble(); |
54 | 0 | } |
55 | 1.88k | } |
56 | | |
57 | 837k | uint32_t Constant::GetU32() const { |
58 | 837k | assert(type()->AsInteger() != nullptr); |
59 | 837k | assert(type()->AsInteger()->width() == 32); |
60 | | |
61 | 837k | if (const IntConstant* ic = AsIntConstant()) { |
62 | 837k | return ic->GetU32BitValue(); |
63 | 837k | } else { |
64 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
65 | 0 | return 0u; |
66 | 0 | } |
67 | 837k | } |
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 | 30 | int32_t Constant::GetS32() const { |
82 | 30 | assert(type()->AsInteger() != nullptr); |
83 | 30 | assert(type()->AsInteger()->width() == 32); |
84 | | |
85 | 30 | if (const IntConstant* ic = AsIntConstant()) { |
86 | 30 | return ic->GetS32BitValue(); |
87 | 30 | } else { |
88 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
89 | 0 | return 0; |
90 | 0 | } |
91 | 30 | } |
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 | 4.76M | uint64_t Constant::GetZeroExtendedValue() const { |
106 | 4.76M | const auto* int_type = type()->AsInteger(); |
107 | 4.76M | assert(int_type != nullptr); |
108 | 4.76M | const auto width = int_type->width(); |
109 | 4.76M | assert(width <= 64); |
110 | | |
111 | 4.76M | uint64_t value = 0; |
112 | 4.76M | if (const IntConstant* ic = AsIntConstant()) { |
113 | 4.76M | if (width <= 32) { |
114 | 4.76M | value = ic->GetU32BitValue(); |
115 | 4.76M | } else { |
116 | 0 | value = ic->GetU64BitValue(); |
117 | 0 | } |
118 | 4.76M | } else { |
119 | 24 | assert(AsNullConstant() && "Must be an integer constant."); |
120 | 24 | } |
121 | 4.76M | return value; |
122 | 4.76M | } |
123 | | |
124 | 1.61M | int64_t Constant::GetSignExtendedValue() const { |
125 | 1.61M | const auto* int_type = type()->AsInteger(); |
126 | 1.61M | assert(int_type != nullptr); |
127 | 1.61M | const auto width = int_type->width(); |
128 | 1.61M | assert(width <= 64); |
129 | | |
130 | 1.61M | int64_t value = 0; |
131 | 1.61M | if (const IntConstant* ic = AsIntConstant()) { |
132 | 1.61M | if (width <= 32) { |
133 | | // Let the C++ compiler do the sign extension. |
134 | 1.61M | value = int64_t(ic->GetS32BitValue()); |
135 | 1.61M | } else { |
136 | 0 | value = ic->GetS64BitValue(); |
137 | 0 | } |
138 | 1.61M | } else { |
139 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
140 | 0 | } |
141 | 1.61M | return value; |
142 | 1.61M | } |
143 | | |
144 | 18.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 | 224k | for (const auto& inst : ctx_->module()->GetConstants()) { |
149 | 224k | MapInst(inst); |
150 | 224k | } |
151 | 18.0k | } |
152 | | |
153 | 2.69M | Type* ConstantManager::GetType(const Instruction* inst) const { |
154 | 2.69M | return context()->get_type_mgr()->GetType(inst->type_id()); |
155 | 2.69M | } |
156 | | |
157 | | std::vector<const Constant*> ConstantManager::GetOperandConstants( |
158 | 21.2M | const Instruction* inst) const { |
159 | 21.2M | std::vector<const Constant*> constants; |
160 | 21.2M | constants.reserve(inst->NumInOperands()); |
161 | 55.5M | for (uint32_t i = 0; i < inst->NumInOperands(); i++) { |
162 | 34.3M | const Operand* operand = &inst->GetInOperand(i); |
163 | 34.3M | if (operand->type != SPV_OPERAND_TYPE_ID) { |
164 | 1.37M | constants.push_back(nullptr); |
165 | 32.9M | } else { |
166 | 32.9M | uint32_t id = operand->words[0]; |
167 | 32.9M | const analysis::Constant* constant = FindDeclaredConstant(id); |
168 | 32.9M | constants.push_back(constant); |
169 | 32.9M | } |
170 | 34.3M | } |
171 | 21.2M | return constants; |
172 | 21.2M | } |
173 | | |
174 | | uint32_t ConstantManager::FindDeclaredConstant(const Constant* c, |
175 | 7.49M | uint32_t type_id) const { |
176 | 7.49M | c = FindConstant(c); |
177 | 7.49M | if (c == nullptr) { |
178 | 0 | return 0; |
179 | 0 | } |
180 | | |
181 | 7.49M | for (auto range = const_val_to_id_.equal_range(c); |
182 | 7.49M | range.first != range.second; ++range.first) { |
183 | 7.10M | Instruction* const_def = |
184 | 7.10M | context()->get_def_use_mgr()->GetDef(range.first->second); |
185 | 7.10M | if (type_id == 0 || const_def->type_id() == type_id) { |
186 | 7.10M | return range.first->second; |
187 | 7.10M | } |
188 | 7.10M | } |
189 | 390k | return 0; |
190 | 7.49M | } |
191 | | |
192 | | std::vector<const Constant*> ConstantManager::GetConstantsFromIds( |
193 | 566k | const std::vector<uint32_t>& ids) const { |
194 | 566k | std::vector<const Constant*> constants; |
195 | 1.54M | for (uint32_t id : ids) { |
196 | 1.54M | if (const Constant* c = FindDeclaredConstant(id)) { |
197 | 1.54M | constants.push_back(c); |
198 | 1.54M | } else { |
199 | 604 | return {}; |
200 | 604 | } |
201 | 1.54M | } |
202 | 565k | return constants; |
203 | 566k | } |
204 | | |
205 | | Instruction* ConstantManager::BuildInstructionAndAddToModule( |
206 | 390k | const Constant* new_const, Module::inst_iterator* pos, uint32_t type_id) { |
207 | | // TODO(1841): Handle id overflow. |
208 | 390k | uint32_t new_id = context()->TakeNextId(); |
209 | 390k | if (new_id == 0) { |
210 | 0 | return nullptr; |
211 | 0 | } |
212 | | |
213 | 390k | auto new_inst = CreateInstruction(new_id, new_const, type_id); |
214 | 390k | if (!new_inst) { |
215 | 0 | return nullptr; |
216 | 0 | } |
217 | 390k | auto* new_inst_ptr = new_inst.get(); |
218 | 390k | *pos = pos->InsertBefore(std::move(new_inst)); |
219 | 390k | ++(*pos); |
220 | 390k | if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse)) |
221 | 390k | context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inst_ptr); |
222 | 390k | MapConstantToInst(new_const, new_inst_ptr); |
223 | 390k | return new_inst_ptr; |
224 | 390k | } |
225 | | |
226 | | Instruction* ConstantManager::GetDefiningInstruction( |
227 | 6.49M | const Constant* c, uint32_t type_id, Module::inst_iterator* pos) { |
228 | 6.49M | uint32_t decl_id = FindDeclaredConstant(c, type_id); |
229 | 6.49M | if (decl_id == 0) { |
230 | 390k | auto iter = context()->types_values_end(); |
231 | 390k | if (pos == nullptr) pos = &iter; |
232 | 390k | return BuildInstructionAndAddToModule(c, pos, type_id); |
233 | 6.09M | } else { |
234 | 6.09M | auto def = context()->get_def_use_mgr()->GetDef(decl_id); |
235 | 6.09M | assert(def != nullptr); |
236 | 6.09M | assert((type_id == 0 || def->type_id() == type_id) && |
237 | 6.09M | "This constant already has an instruction with a different type."); |
238 | 6.09M | return def; |
239 | 6.09M | } |
240 | 6.49M | } |
241 | | |
242 | | std::unique_ptr<Constant> ConstantManager::CreateConstant( |
243 | 7.91M | const Type* type, const std::vector<uint32_t>& literal_words_or_ids) const { |
244 | 7.91M | if (literal_words_or_ids.size() == 0) { |
245 | | // Constant declared with OpConstantNull |
246 | 216k | return MakeUnique<NullConstant>(type); |
247 | 7.69M | } else if (auto* bt = type->AsBool()) { |
248 | 952k | assert(literal_words_or_ids.size() == 1 && |
249 | 952k | "Bool constant should be declared with one operand"); |
250 | 952k | return MakeUnique<BoolConstant>(bt, literal_words_or_ids.front()); |
251 | 6.74M | } else if (auto* it = type->AsInteger()) { |
252 | 3.80M | return MakeUnique<IntConstant>(it, literal_words_or_ids); |
253 | 3.80M | } else if (auto* ft = type->AsFloat()) { |
254 | 2.37M | return MakeUnique<FloatConstant>(ft, literal_words_or_ids); |
255 | 2.37M | } else if (auto* vt = type->AsVector()) { |
256 | 561k | auto components = GetConstantsFromIds(literal_words_or_ids); |
257 | 561k | if (components.empty()) return nullptr; |
258 | | // All components of VectorConstant must be of type Bool, Integer or Float. |
259 | 561k | if (!std::all_of(components.begin(), components.end(), |
260 | 1.51M | [](const Constant* c) { |
261 | 1.51M | if (c->type()->AsBool() || c->type()->AsInteger() || |
262 | 1.51M | c->type()->AsFloat()) { |
263 | 1.51M | return true; |
264 | 1.51M | } else { |
265 | 0 | return false; |
266 | 0 | } |
267 | 1.51M | })) |
268 | 0 | return nullptr; |
269 | | // All components of VectorConstant must be in the same type. |
270 | 561k | const auto* component_type = components.front()->type(); |
271 | 561k | if (!std::all_of(components.begin(), components.end(), |
272 | 1.51M | [&component_type](const Constant* c) { |
273 | 1.51M | if (c->type() == component_type) return true; |
274 | 0 | return false; |
275 | 1.51M | })) |
276 | 0 | return nullptr; |
277 | 561k | return MakeUnique<VectorConstant>(vt, components); |
278 | 561k | } else if (auto* mt = type->AsMatrix()) { |
279 | 46 | auto components = GetConstantsFromIds(literal_words_or_ids); |
280 | 46 | if (components.empty()) return nullptr; |
281 | 35 | return MakeUnique<MatrixConstant>(mt, components); |
282 | 4.32k | } else if (auto* st = type->AsStruct()) { |
283 | 2.67k | auto components = GetConstantsFromIds(literal_words_or_ids); |
284 | 2.67k | if (components.empty()) return nullptr; |
285 | 2.63k | return MakeUnique<StructConstant>(st, components); |
286 | 2.67k | } else if (auto* at = type->AsArray()) { |
287 | 1.64k | auto components = GetConstantsFromIds(literal_words_or_ids); |
288 | 1.64k | if (components.empty()) return nullptr; |
289 | 1.53k | return MakeUnique<ArrayConstant>(at, components); |
290 | 1.64k | } else { |
291 | 0 | return nullptr; |
292 | 0 | } |
293 | 7.91M | } |
294 | | |
295 | 1.44M | const Constant* ConstantManager::GetConstantFromInst(const Instruction* inst) { |
296 | 1.44M | std::vector<uint32_t> literal_words_or_ids; |
297 | | |
298 | | // Collect the constant defining literals or component ids. |
299 | 2.97M | for (uint32_t i = 0; i < inst->NumInOperands(); i++) { |
300 | 1.52M | literal_words_or_ids.insert(literal_words_or_ids.end(), |
301 | 1.52M | inst->GetInOperand(i).words.begin(), |
302 | 1.52M | inst->GetInOperand(i).words.end()); |
303 | 1.52M | } |
304 | | |
305 | 1.44M | switch (inst->opcode()) { |
306 | | // OpConstant{True|False} have the value embedded in the opcode. So they |
307 | | // are not handled by the for-loop above. Here we add the value explicitly. |
308 | 7.73k | case spv::Op::OpConstantTrue: |
309 | 7.73k | literal_words_or_ids.push_back(true); |
310 | 7.73k | break; |
311 | 4.97k | case spv::Op::OpConstantFalse: |
312 | 4.97k | literal_words_or_ids.push_back(false); |
313 | 4.97k | break; |
314 | 1.94k | case spv::Op::OpConstantNull: |
315 | 1.38M | case spv::Op::OpConstant: |
316 | 1.41M | case spv::Op::OpConstantComposite: |
317 | 1.41M | case spv::Op::OpSpecConstantComposite: |
318 | 1.41M | break; |
319 | 26.6k | default: |
320 | 26.6k | return nullptr; |
321 | 1.44M | } |
322 | | |
323 | 1.42M | return GetConstant(GetType(inst), literal_words_or_ids); |
324 | 1.44M | } |
325 | | |
326 | | std::unique_ptr<Instruction> ConstantManager::CreateInstruction( |
327 | 390k | uint32_t id, const Constant* c, uint32_t type_id) const { |
328 | 390k | uint32_t type = |
329 | 390k | (type_id == 0) ? context()->get_type_mgr()->GetId(c->type()) : type_id; |
330 | 390k | if (c->AsNullConstant()) { |
331 | 211 | return MakeUnique<Instruction>(context(), spv::Op::OpConstantNull, type, id, |
332 | 211 | std::initializer_list<Operand>{}); |
333 | 390k | } else if (const BoolConstant* bc = c->AsBoolConstant()) { |
334 | 7.14k | return MakeUnique<Instruction>( |
335 | 7.14k | context(), |
336 | 7.14k | bc->value() ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse, type, |
337 | 7.14k | id, std::initializer_list<Operand>{}); |
338 | 382k | } else if (const IntConstant* ic = c->AsIntConstant()) { |
339 | 203k | return MakeUnique<Instruction>( |
340 | 203k | context(), spv::Op::OpConstant, type, id, |
341 | 203k | std::initializer_list<Operand>{ |
342 | 203k | Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, |
343 | 203k | ic->words())}); |
344 | 203k | } else if (const FloatConstant* fc = c->AsFloatConstant()) { |
345 | 87.8k | return MakeUnique<Instruction>( |
346 | 87.8k | context(), spv::Op::OpConstant, type, id, |
347 | 87.8k | std::initializer_list<Operand>{ |
348 | 87.8k | Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, |
349 | 87.8k | fc->words())}); |
350 | 91.7k | } else if (const CompositeConstant* cc = c->AsCompositeConstant()) { |
351 | 91.7k | return CreateCompositeInstruction(id, cc, type_id); |
352 | 91.7k | } else { |
353 | 0 | return nullptr; |
354 | 0 | } |
355 | 390k | } |
356 | | |
357 | | std::unique_ptr<Instruction> ConstantManager::CreateCompositeInstruction( |
358 | 91.7k | uint32_t result_id, const CompositeConstant* cc, uint32_t type_id) const { |
359 | 91.7k | std::vector<Operand> operands; |
360 | 91.7k | Instruction* type_inst = context()->get_def_use_mgr()->GetDef(type_id); |
361 | 91.7k | uint32_t component_index = 0; |
362 | 241k | for (const Constant* component_const : cc->GetComponents()) { |
363 | 241k | uint32_t component_type_id = 0; |
364 | 241k | if (type_inst && type_inst->opcode() == spv::Op::OpTypeStruct) { |
365 | 2.10k | component_type_id = type_inst->GetSingleWordInOperand(component_index); |
366 | 239k | } else if (type_inst && type_inst->opcode() == spv::Op::OpTypeArray) { |
367 | 1 | component_type_id = type_inst->GetSingleWordInOperand(0); |
368 | 1 | } |
369 | 241k | uint32_t id = FindDeclaredConstant(component_const, component_type_id); |
370 | | |
371 | 241k | if (id == 0) { |
372 | | // Cannot get the id of the component constant, while all components |
373 | | // should have been added to the module prior to the composite constant. |
374 | | // Cannot create OpConstantComposite instruction in this case. |
375 | 0 | return nullptr; |
376 | 0 | } |
377 | 241k | operands.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_ID, |
378 | 241k | std::initializer_list<uint32_t>{id}); |
379 | 241k | component_index++; |
380 | 241k | } |
381 | 91.7k | uint32_t type = |
382 | 91.7k | (type_id == 0) ? context()->get_type_mgr()->GetId(cc->type()) : type_id; |
383 | 91.7k | return MakeUnique<Instruction>(context(), spv::Op::OpConstantComposite, type, |
384 | 91.7k | result_id, std::move(operands)); |
385 | 91.7k | } |
386 | | |
387 | | const Constant* ConstantManager::GetConstant( |
388 | 7.91M | const Type* type, const std::vector<uint32_t>& literal_words_or_ids) { |
389 | 7.91M | auto cst = CreateConstant(type, literal_words_or_ids); |
390 | 7.91M | return cst ? RegisterConstant(std::move(cst)) : nullptr; |
391 | 7.91M | } |
392 | | |
393 | 1 | const Constant* ConstantManager::GetNullCompositeConstant(const Type* type) { |
394 | 1 | std::vector<uint32_t> literal_words_or_id; |
395 | | |
396 | 1 | if (type->AsVector()) { |
397 | 1 | const Type* element_type = type->AsVector()->element_type(); |
398 | 1 | const uint32_t null_id = GetNullConstId(element_type); |
399 | 1 | const uint32_t element_count = type->AsVector()->element_count(); |
400 | 3 | for (uint32_t i = 0; i < element_count; i++) { |
401 | 2 | literal_words_or_id.push_back(null_id); |
402 | 2 | } |
403 | 1 | } else if (type->AsMatrix()) { |
404 | 0 | const Type* element_type = type->AsMatrix()->element_type(); |
405 | 0 | const uint32_t null_id = GetNullConstId(element_type); |
406 | 0 | const uint32_t element_count = type->AsMatrix()->element_count(); |
407 | 0 | for (uint32_t i = 0; i < element_count; i++) { |
408 | 0 | literal_words_or_id.push_back(null_id); |
409 | 0 | } |
410 | 0 | } else if (type->AsStruct()) { |
411 | | // TODO (sfricke-lunarg) add proper struct support |
412 | 0 | return nullptr; |
413 | 0 | } else if (type->AsArray()) { |
414 | 0 | const Type* element_type = type->AsArray()->element_type(); |
415 | 0 | const uint32_t null_id = GetNullConstId(element_type); |
416 | 0 | assert(type->AsArray()->length_info().words[0] == |
417 | 0 | analysis::Array::LengthInfo::kConstant && |
418 | 0 | "unexpected array length"); |
419 | 0 | const uint32_t element_count = type->AsArray()->length_info().words[0]; |
420 | 0 | for (uint32_t i = 0; i < element_count; i++) { |
421 | 0 | literal_words_or_id.push_back(null_id); |
422 | 0 | } |
423 | 0 | } else { |
424 | 0 | return nullptr; |
425 | 0 | } |
426 | | |
427 | 1 | return GetConstant(type, literal_words_or_id); |
428 | 1 | } |
429 | | |
430 | | const Constant* ConstantManager::GetNumericVectorConstantWithWords( |
431 | 37 | const Vector* type, const std::vector<uint32_t>& literal_words) { |
432 | 37 | const auto* element_type = type->element_type(); |
433 | 37 | uint32_t words_per_element = 0; |
434 | 37 | if (const auto* float_type = element_type->AsFloat()) |
435 | 1 | words_per_element = float_type->width() / 32; |
436 | 36 | else if (const auto* int_type = element_type->AsInteger()) |
437 | 36 | words_per_element = int_type->width() / 32; |
438 | 0 | else if (element_type->AsBool() != nullptr) |
439 | 0 | words_per_element = 1; |
440 | | |
441 | 37 | if (words_per_element != 1 && words_per_element != 2) return nullptr; |
442 | | |
443 | 37 | if (words_per_element * type->element_count() != |
444 | 37 | static_cast<uint32_t>(literal_words.size())) { |
445 | 2 | return nullptr; |
446 | 2 | } |
447 | | |
448 | 35 | std::vector<uint32_t> element_ids; |
449 | 107 | for (uint32_t i = 0; i < type->element_count(); ++i) { |
450 | 72 | auto first_word = literal_words.begin() + (words_per_element * i); |
451 | 72 | std::vector<uint32_t> const_data(first_word, |
452 | 72 | first_word + words_per_element); |
453 | 72 | const analysis::Constant* element_constant = |
454 | 72 | GetConstant(element_type, const_data); |
455 | 72 | auto element_id = GetDefiningInstruction(element_constant)->result_id(); |
456 | 72 | element_ids.push_back(element_id); |
457 | 72 | } |
458 | | |
459 | 35 | return GetConstant(type, element_ids); |
460 | 37 | } |
461 | | |
462 | 0 | uint32_t ConstantManager::GetFloatConstId(float val) { |
463 | 0 | const Constant* c = GetFloatConst(val); |
464 | 0 | return GetDefiningInstruction(c)->result_id(); |
465 | 0 | } |
466 | | |
467 | 200 | const Constant* ConstantManager::GetFloatConst(float val) { |
468 | 200 | Type* float_type = context()->get_type_mgr()->GetFloatType(); |
469 | 200 | utils::FloatProxy<float> v(val); |
470 | 200 | const Constant* c = GetConstant(float_type, v.GetWords()); |
471 | 200 | return c; |
472 | 200 | } |
473 | | |
474 | 0 | uint32_t ConstantManager::GetDoubleConstId(double val) { |
475 | 0 | const Constant* c = GetDoubleConst(val); |
476 | 0 | return GetDefiningInstruction(c)->result_id(); |
477 | 0 | } |
478 | | |
479 | 0 | const Constant* ConstantManager::GetDoubleConst(double val) { |
480 | 0 | Type* float_type = context()->get_type_mgr()->GetDoubleType(); |
481 | 0 | utils::FloatProxy<double> v(val); |
482 | 0 | const Constant* c = GetConstant(float_type, v.GetWords()); |
483 | 0 | return c; |
484 | 0 | } |
485 | | |
486 | 0 | uint32_t ConstantManager::GetSIntConstId(int32_t val) { |
487 | 0 | Type* sint_type = context()->get_type_mgr()->GetSIntType(); |
488 | 0 | const Constant* c = GetConstant(sint_type, {static_cast<uint32_t>(val)}); |
489 | 0 | return GetDefiningInstruction(c)->result_id(); |
490 | 0 | } |
491 | | |
492 | | const Constant* ConstantManager::GetIntConst(uint64_t val, int32_t bitWidth, |
493 | 1.14k | bool isSigned) { |
494 | 1.14k | Type* int_type = context()->get_type_mgr()->GetIntType(bitWidth, isSigned); |
495 | | |
496 | 1.14k | if (isSigned) { |
497 | | // Sign extend the value. |
498 | 1.11k | int32_t num_of_bit_to_ignore = 64 - bitWidth; |
499 | 1.11k | val = static_cast<int64_t>(val << num_of_bit_to_ignore) >> |
500 | 1.11k | num_of_bit_to_ignore; |
501 | 1.11k | } else if (bitWidth < 64) { |
502 | | // Clear the upper bit that are not used. |
503 | 35 | uint64_t mask = ((1ull << bitWidth) - 1); |
504 | 35 | val &= mask; |
505 | 35 | } |
506 | | |
507 | 1.14k | if (bitWidth <= 32) { |
508 | 1.14k | return GetConstant(int_type, {static_cast<uint32_t>(val)}); |
509 | 1.14k | } |
510 | | |
511 | | // If the value is more than 32-bit, we need to split the operands into two |
512 | | // 32-bit integers. |
513 | 0 | return GetConstant( |
514 | 0 | int_type, {static_cast<uint32_t>(val), static_cast<uint32_t>(val >> 32)}); |
515 | 1.14k | } |
516 | | |
517 | 0 | uint32_t ConstantManager::GetUIntConstId(uint32_t val) { |
518 | 0 | Type* uint_type = context()->get_type_mgr()->GetUIntType(); |
519 | 0 | const Constant* c = GetConstant(uint_type, {val}); |
520 | 0 | return GetDefiningInstruction(c)->result_id(); |
521 | 0 | } |
522 | | |
523 | 1 | uint32_t ConstantManager::GetNullConstId(const Type* type) { |
524 | 1 | const Constant* c = GetConstant(type, {}); |
525 | 1 | return GetDefiningInstruction(c)->result_id(); |
526 | 1 | } |
527 | | |
528 | | const Constant* ConstantManager::GenerateIntegerConstant( |
529 | 2.12M | const analysis::Integer* integer_type, uint64_t result) { |
530 | 2.12M | assert(integer_type != nullptr); |
531 | | |
532 | 2.12M | std::vector<uint32_t> words; |
533 | 2.12M | if (integer_type->width() == 64) { |
534 | | // In the 64-bit case, two words are needed to represent the value. |
535 | 0 | words = {static_cast<uint32_t>(result), |
536 | 0 | static_cast<uint32_t>(result >> 32)}; |
537 | 2.12M | } else { |
538 | | // In all other cases, only a single word is needed. |
539 | 2.12M | assert(integer_type->width() <= 32); |
540 | 2.12M | if (integer_type->IsSigned()) { |
541 | 2.11M | result = utils::SignExtendValue(result, integer_type->width()); |
542 | 2.11M | } else { |
543 | 7.21k | result = utils::ZeroExtendValue(result, integer_type->width()); |
544 | 7.21k | } |
545 | 2.12M | words = {static_cast<uint32_t>(result)}; |
546 | 2.12M | } |
547 | 2.12M | return GetConstant(integer_type, words); |
548 | 2.12M | } |
549 | | |
550 | | std::vector<const analysis::Constant*> Constant::GetVectorComponents( |
551 | 337k | analysis::ConstantManager* const_mgr) const { |
552 | 337k | std::vector<const analysis::Constant*> components; |
553 | 337k | const analysis::VectorConstant* a = this->AsVectorConstant(); |
554 | 337k | const analysis::Vector* vector_type = this->type()->AsVector(); |
555 | 337k | assert(vector_type != nullptr); |
556 | 337k | if (a != nullptr) { |
557 | 1.15M | for (uint32_t i = 0; i < vector_type->element_count(); ++i) { |
558 | 919k | components.push_back(a->GetComponents()[i]); |
559 | 919k | } |
560 | 230k | } else { |
561 | 106k | const analysis::Type* element_type = vector_type->element_type(); |
562 | 106k | const analysis::Constant* element_null_const = |
563 | 106k | const_mgr->GetConstant(element_type, {}); |
564 | 533k | for (uint32_t i = 0; i < vector_type->element_count(); ++i) { |
565 | 426k | components.push_back(element_null_const); |
566 | 426k | } |
567 | 106k | } |
568 | 337k | return components; |
569 | 337k | } |
570 | | |
571 | | } // namespace analysis |
572 | | } // namespace opt |
573 | | } // namespace spvtools |