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