/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 | 232 | float Constant::GetFloat() const { |
26 | 232 | assert(type()->AsFloat() != nullptr && type()->AsFloat()->width() == 32); |
27 | | |
28 | 232 | if (const FloatConstant* fc = AsFloatConstant()) { |
29 | 232 | return fc->GetFloatValue(); |
30 | 232 | } else { |
31 | 0 | assert(AsNullConstant() && "Must be a floating point constant."); |
32 | 0 | return 0.0f; |
33 | 0 | } |
34 | 232 | } |
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 | 108 | uint32_t Constant::GetU32() const { |
58 | 108 | assert(type()->AsInteger() != nullptr); |
59 | 108 | assert(type()->AsInteger()->width() == 32); |
60 | | |
61 | 108 | if (const IntConstant* ic = AsIntConstant()) { |
62 | 108 | return ic->GetU32BitValue(); |
63 | 108 | } else { |
64 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
65 | 0 | return 0u; |
66 | 0 | } |
67 | 108 | } |
68 | | |
69 | 44 | uint64_t Constant::GetU64() const { |
70 | 44 | assert(type()->AsInteger() != nullptr); |
71 | 44 | assert(type()->AsInteger()->width() == 64); |
72 | | |
73 | 44 | if (const IntConstant* ic = AsIntConstant()) { |
74 | 44 | return ic->GetU64BitValue(); |
75 | 44 | } else { |
76 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
77 | 0 | return 0u; |
78 | 0 | } |
79 | 44 | } |
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 | 3.47k | uint64_t Constant::GetZeroExtendedValue() const { |
106 | 3.47k | const auto* int_type = type()->AsInteger(); |
107 | 3.47k | assert(int_type != nullptr); |
108 | 3.47k | const auto width = int_type->width(); |
109 | 3.47k | assert(width <= 64); |
110 | | |
111 | 3.47k | uint64_t value = 0; |
112 | 3.47k | if (const IntConstant* ic = AsIntConstant()) { |
113 | 3.47k | if (width <= 32) { |
114 | 3.47k | value = ic->GetU32BitValue(); |
115 | 3.47k | } else { |
116 | 0 | value = ic->GetU64BitValue(); |
117 | 0 | } |
118 | 3.47k | } else { |
119 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
120 | 0 | } |
121 | 3.47k | return value; |
122 | 3.47k | } |
123 | | |
124 | 2.04k | int64_t Constant::GetSignExtendedValue() const { |
125 | 2.04k | const auto* int_type = type()->AsInteger(); |
126 | 2.04k | assert(int_type != nullptr); |
127 | 2.04k | const auto width = int_type->width(); |
128 | 2.04k | assert(width <= 64); |
129 | | |
130 | 2.04k | int64_t value = 0; |
131 | 2.04k | if (const IntConstant* ic = AsIntConstant()) { |
132 | 2.04k | if (width <= 32) { |
133 | | // Let the C++ compiler do the sign extension. |
134 | 2.04k | value = int64_t(ic->GetS32BitValue()); |
135 | 2.04k | } else { |
136 | 4 | value = ic->GetS64BitValue(); |
137 | 4 | } |
138 | 2.04k | } else { |
139 | 0 | assert(AsNullConstant() && "Must be an integer constant."); |
140 | 0 | } |
141 | 2.04k | return value; |
142 | 2.04k | } |
143 | | |
144 | 228 | 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 | 2.89k | for (const auto& inst : ctx_->module()->GetConstants()) { |
149 | 2.89k | MapInst(inst); |
150 | 2.89k | } |
151 | 228 | } |
152 | | |
153 | 5.03k | Type* ConstantManager::GetType(const Instruction* inst) const { |
154 | 5.03k | return context()->get_type_mgr()->GetType(inst->type_id()); |
155 | 5.03k | } |
156 | | |
157 | | std::vector<const Constant*> ConstantManager::GetOperandConstants( |
158 | 62.9k | const Instruction* inst) const { |
159 | 62.9k | std::vector<const Constant*> constants; |
160 | 62.9k | constants.reserve(inst->NumInOperands()); |
161 | 198k | for (uint32_t i = 0; i < inst->NumInOperands(); i++) { |
162 | 135k | const Operand* operand = &inst->GetInOperand(i); |
163 | 135k | if (operand->type != SPV_OPERAND_TYPE_ID) { |
164 | 17.9k | constants.push_back(nullptr); |
165 | 117k | } else { |
166 | 117k | uint32_t id = operand->words[0]; |
167 | 117k | const analysis::Constant* constant = FindDeclaredConstant(id); |
168 | 117k | constants.push_back(constant); |
169 | 117k | } |
170 | 135k | } |
171 | 62.9k | return constants; |
172 | 62.9k | } |
173 | | |
174 | | uint32_t ConstantManager::FindDeclaredConstant(const Constant* c, |
175 | 1.43k | uint32_t type_id) const { |
176 | 1.43k | c = FindConstant(c); |
177 | 1.43k | if (c == nullptr) { |
178 | 0 | return 0; |
179 | 0 | } |
180 | | |
181 | 1.43k | for (auto range = const_val_to_id_.equal_range(c); |
182 | 1.43k | range.first != range.second; ++range.first) { |
183 | 1.31k | Instruction* const_def = |
184 | 1.31k | context()->get_def_use_mgr()->GetDef(range.first->second); |
185 | 1.31k | if (type_id == 0 || const_def->type_id() == type_id) { |
186 | 1.31k | return range.first->second; |
187 | 1.31k | } |
188 | 1.31k | } |
189 | 124 | return 0; |
190 | 1.43k | } |
191 | | |
192 | | std::vector<const Constant*> ConstantManager::GetConstantsFromIds( |
193 | 598 | const std::vector<uint32_t>& ids) const { |
194 | 598 | std::vector<const Constant*> constants; |
195 | 1.73k | for (uint32_t id : ids) { |
196 | 1.73k | if (const Constant* c = FindDeclaredConstant(id)) { |
197 | 1.73k | constants.push_back(c); |
198 | 1.73k | } else { |
199 | 0 | return {}; |
200 | 0 | } |
201 | 1.73k | } |
202 | 598 | return constants; |
203 | 598 | } |
204 | | |
205 | | Instruction* ConstantManager::BuildInstructionAndAddToModule( |
206 | 124 | const Constant* new_const, Module::inst_iterator* pos, uint32_t type_id) { |
207 | | // TODO(1841): Handle id overflow. |
208 | 124 | uint32_t new_id = context()->TakeNextId(); |
209 | 124 | if (new_id == 0) { |
210 | 0 | return nullptr; |
211 | 0 | } |
212 | | |
213 | 124 | auto new_inst = CreateInstruction(new_id, new_const, type_id); |
214 | 124 | if (!new_inst) { |
215 | 0 | return nullptr; |
216 | 0 | } |
217 | 124 | auto* new_inst_ptr = new_inst.get(); |
218 | 124 | *pos = pos->InsertBefore(std::move(new_inst)); |
219 | 124 | ++(*pos); |
220 | 124 | if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse)) |
221 | 124 | context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inst_ptr); |
222 | 124 | MapConstantToInst(new_const, new_inst_ptr); |
223 | 124 | return new_inst_ptr; |
224 | 124 | } |
225 | | |
226 | | Instruction* ConstantManager::GetDefiningInstruction( |
227 | 952 | const Constant* c, uint32_t type_id, Module::inst_iterator* pos) { |
228 | 952 | uint32_t decl_id = FindDeclaredConstant(c, type_id); |
229 | 952 | if (decl_id == 0) { |
230 | 124 | auto iter = context()->types_values_end(); |
231 | 124 | if (pos == nullptr) pos = &iter; |
232 | 124 | return BuildInstructionAndAddToModule(c, pos, type_id); |
233 | 828 | } else { |
234 | 828 | auto def = context()->get_def_use_mgr()->GetDef(decl_id); |
235 | 828 | assert(def != nullptr); |
236 | 828 | assert((type_id == 0 || def->type_id() == type_id) && |
237 | 828 | "This constant already has an instruction with a different type."); |
238 | 828 | return def; |
239 | 828 | } |
240 | 952 | } |
241 | | |
242 | | std::unique_ptr<Constant> ConstantManager::CreateConstant( |
243 | 5.66k | const Type* type, const std::vector<uint32_t>& literal_words_or_ids) const { |
244 | 5.66k | if (literal_words_or_ids.size() == 0) { |
245 | | // Constant declared with OpConstantNull |
246 | 0 | return MakeUnique<NullConstant>(type); |
247 | 5.66k | } else if (auto* bt = type->AsBool()) { |
248 | 190 | assert(literal_words_or_ids.size() == 1 && |
249 | 190 | "Bool constant should be declared with one operand"); |
250 | 190 | return MakeUnique<BoolConstant>(bt, literal_words_or_ids.front()); |
251 | 5.47k | } else if (auto* it = type->AsInteger()) { |
252 | 3.56k | return MakeUnique<IntConstant>(it, literal_words_or_ids); |
253 | 3.56k | } else if (auto* ft = type->AsFloat()) { |
254 | 1.31k | return MakeUnique<FloatConstant>(ft, literal_words_or_ids); |
255 | 1.31k | } else if (auto* vt = type->AsVector()) { |
256 | 468 | auto components = GetConstantsFromIds(literal_words_or_ids); |
257 | 468 | if (components.empty()) return nullptr; |
258 | | // All components of VectorConstant must be of type Bool, Integer or Float. |
259 | 468 | if (!std::all_of(components.begin(), components.end(), |
260 | 1.34k | [](const Constant* c) { |
261 | 1.34k | if (c->type()->AsBool() || c->type()->AsInteger() || |
262 | 1.34k | c->type()->AsFloat()) { |
263 | 1.34k | return true; |
264 | 1.34k | } else { |
265 | 0 | return false; |
266 | 0 | } |
267 | 1.34k | })) |
268 | 0 | return nullptr; |
269 | | // All components of VectorConstant must be in the same type. |
270 | 468 | const auto* component_type = components.front()->type(); |
271 | 468 | if (!std::all_of(components.begin(), components.end(), |
272 | 1.34k | [&component_type](const Constant* c) { |
273 | 1.34k | if (c->type() == component_type) return true; |
274 | 0 | return false; |
275 | 1.34k | })) |
276 | 0 | return nullptr; |
277 | 468 | return MakeUnique<VectorConstant>(vt, components); |
278 | 468 | } else if (auto* mt = type->AsMatrix()) { |
279 | 18 | auto components = GetConstantsFromIds(literal_words_or_ids); |
280 | 18 | if (components.empty()) return nullptr; |
281 | 18 | return MakeUnique<MatrixConstant>(mt, components); |
282 | 112 | } else if (auto* st = type->AsStruct()) { |
283 | 104 | auto components = GetConstantsFromIds(literal_words_or_ids); |
284 | 104 | if (components.empty()) return nullptr; |
285 | 104 | return MakeUnique<StructConstant>(st, components); |
286 | 104 | } else if (auto* at = type->AsArray()) { |
287 | 8 | auto components = GetConstantsFromIds(literal_words_or_ids); |
288 | 8 | if (components.empty()) return nullptr; |
289 | 8 | return MakeUnique<ArrayConstant>(at, components); |
290 | 8 | } else { |
291 | 0 | return nullptr; |
292 | 0 | } |
293 | 5.66k | } |
294 | | |
295 | 4.94k | const Constant* ConstantManager::GetConstantFromInst(const Instruction* inst) { |
296 | 4.94k | std::vector<uint32_t> literal_words_or_ids; |
297 | | |
298 | | // Collect the constant defining literals or component ids. |
299 | 10.7k | for (uint32_t i = 0; i < inst->NumInOperands(); i++) { |
300 | 5.85k | literal_words_or_ids.insert(literal_words_or_ids.end(), |
301 | 5.85k | inst->GetInOperand(i).words.begin(), |
302 | 5.85k | inst->GetInOperand(i).words.end()); |
303 | 5.85k | } |
304 | | |
305 | 4.94k | 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 | 16 | case spv::Op::OpConstantTrue: |
309 | 16 | literal_words_or_ids.push_back(true); |
310 | 16 | break; |
311 | 12 | case spv::Op::OpConstantFalse: |
312 | 12 | literal_words_or_ids.push_back(false); |
313 | 12 | break; |
314 | 0 | case spv::Op::OpConstantNull: |
315 | 4.39k | case spv::Op::OpConstant: |
316 | 4.88k | case spv::Op::OpConstantComposite: |
317 | 4.88k | case spv::Op::OpSpecConstantComposite: |
318 | 4.88k | case spv::Op::OpSpecConstantCompositeReplicateEXT: |
319 | 4.88k | break; |
320 | 36 | default: |
321 | 36 | return nullptr; |
322 | 4.94k | } |
323 | | |
324 | 4.91k | return GetConstant(GetType(inst), literal_words_or_ids); |
325 | 4.94k | } |
326 | | |
327 | | std::unique_ptr<Instruction> ConstantManager::CreateInstruction( |
328 | 124 | uint32_t id, const Constant* c, uint32_t type_id) const { |
329 | 124 | uint32_t type = |
330 | 124 | (type_id == 0) ? context()->get_type_mgr()->GetId(c->type()) : type_id; |
331 | 124 | if (c->AsNullConstant()) { |
332 | 0 | return MakeUnique<Instruction>(context(), spv::Op::OpConstantNull, type, id, |
333 | 0 | std::initializer_list<Operand>{}); |
334 | 124 | } else if (const BoolConstant* bc = c->AsBoolConstant()) { |
335 | 52 | return MakeUnique<Instruction>( |
336 | 52 | context(), |
337 | 52 | bc->value() ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse, type, |
338 | 52 | id, std::initializer_list<Operand>{}); |
339 | 72 | } else if (const IntConstant* ic = c->AsIntConstant()) { |
340 | 18 | return MakeUnique<Instruction>( |
341 | 18 | context(), spv::Op::OpConstant, type, id, |
342 | 18 | std::initializer_list<Operand>{ |
343 | 18 | Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, |
344 | 18 | ic->words())}); |
345 | 54 | } else if (const FloatConstant* fc = c->AsFloatConstant()) { |
346 | 0 | return MakeUnique<Instruction>( |
347 | 0 | context(), spv::Op::OpConstant, type, id, |
348 | 0 | std::initializer_list<Operand>{ |
349 | 0 | Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, |
350 | 0 | fc->words())}); |
351 | 54 | } else if (const CompositeConstant* cc = c->AsCompositeConstant()) { |
352 | 54 | return CreateCompositeInstruction(id, cc, type_id); |
353 | 54 | } else { |
354 | 0 | return nullptr; |
355 | 0 | } |
356 | 124 | } |
357 | | |
358 | | std::unique_ptr<Instruction> ConstantManager::CreateCompositeInstruction( |
359 | 54 | uint32_t result_id, const CompositeConstant* cc, uint32_t type_id) const { |
360 | 54 | std::vector<Operand> operands; |
361 | 54 | Instruction* type_inst = context()->get_def_use_mgr()->GetDef(type_id); |
362 | 54 | uint32_t component_index = 0; |
363 | 180 | for (const Constant* component_const : cc->GetComponents()) { |
364 | 180 | uint32_t component_type_id = 0; |
365 | 180 | if (type_inst && type_inst->opcode() == spv::Op::OpTypeStruct) { |
366 | 144 | component_type_id = type_inst->GetSingleWordInOperand(component_index); |
367 | 144 | } else if (type_inst && type_inst->opcode() == spv::Op::OpTypeArray) { |
368 | 0 | component_type_id = type_inst->GetSingleWordInOperand(0); |
369 | 0 | } |
370 | 180 | uint32_t id = FindDeclaredConstant(component_const, component_type_id); |
371 | | |
372 | 180 | 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 | 180 | operands.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_ID, |
379 | 180 | std::initializer_list<uint32_t>{id}); |
380 | 180 | component_index++; |
381 | 180 | } |
382 | 54 | uint32_t type = |
383 | 54 | (type_id == 0) ? context()->get_type_mgr()->GetId(cc->type()) : type_id; |
384 | 54 | return MakeUnique<Instruction>(context(), spv::Op::OpConstantComposite, type, |
385 | 54 | result_id, std::move(operands)); |
386 | 54 | } |
387 | | |
388 | | const Constant* ConstantManager::GetConstant( |
389 | 5.66k | const Type* type, const std::vector<uint32_t>& literal_words_or_ids) { |
390 | 5.66k | auto cst = CreateConstant(type, literal_words_or_ids); |
391 | 5.66k | return cst ? RegisterConstant(std::move(cst)) : nullptr; |
392 | 5.66k | } |
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 | 0 | const Vector* type, const std::vector<uint32_t>& literal_words) { |
433 | 0 | const auto* element_type = type->element_type(); |
434 | 0 | uint32_t words_per_element = 0; |
435 | 0 | if (const auto* float_type = element_type->AsFloat()) |
436 | 0 | words_per_element = float_type->width() / 32; |
437 | 0 | else if (const auto* int_type = element_type->AsInteger()) |
438 | 0 | words_per_element = int_type->width() / 32; |
439 | 0 | else if (element_type->AsBool() != nullptr) |
440 | 0 | words_per_element = 1; |
441 | |
|
442 | 0 | if (words_per_element != 1 && words_per_element != 2) return nullptr; |
443 | | |
444 | 0 | if (words_per_element * type->element_count() != |
445 | 0 | static_cast<uint32_t>(literal_words.size())) { |
446 | 0 | return nullptr; |
447 | 0 | } |
448 | | |
449 | 0 | std::vector<uint32_t> element_ids; |
450 | 0 | for (uint32_t i = 0; i < type->element_count(); ++i) { |
451 | 0 | auto first_word = literal_words.begin() + (words_per_element * i); |
452 | 0 | std::vector<uint32_t> const_data(first_word, |
453 | 0 | first_word + words_per_element); |
454 | 0 | const analysis::Constant* element_constant = |
455 | 0 | GetConstant(element_type, const_data); |
456 | 0 | auto element_id = GetDefiningInstruction(element_constant)->result_id(); |
457 | 0 | element_ids.push_back(element_id); |
458 | 0 | } |
459 | |
|
460 | 0 | return GetConstant(type, element_ids); |
461 | 0 | } |
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 | 0 | const Constant* ConstantManager::GetFloatConst(float val) { |
471 | 0 | Type* float_type = context()->get_type_mgr()->GetFloatType(); |
472 | 0 | utils::FloatProxy<float> v(val); |
473 | 0 | const Constant* c = GetConstant(float_type, v.GetWords()); |
474 | 0 | return c; |
475 | 0 | } |
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 | 80 | bool isSigned) { |
499 | 80 | Type* int_type = context()->get_type_mgr()->GetIntType(bitWidth, isSigned); |
500 | | |
501 | 80 | if (isSigned) { |
502 | | // Sign extend the value. |
503 | 80 | int32_t num_of_bit_to_ignore = 64 - bitWidth; |
504 | 80 | val = static_cast<int64_t>(val << num_of_bit_to_ignore) >> |
505 | 80 | num_of_bit_to_ignore; |
506 | 80 | } 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 | 80 | if (bitWidth <= 32) { |
513 | 80 | return GetConstant(int_type, {static_cast<uint32_t>(val)}); |
514 | 80 | } |
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 | 80 | } |
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 | 162 | const analysis::Integer* integer_type, uint64_t result) { |
535 | 162 | assert(integer_type != nullptr); |
536 | | |
537 | 162 | std::vector<uint32_t> words; |
538 | 162 | 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 | 162 | } else { |
543 | | // In all other cases, only a single word is needed. |
544 | 162 | assert(integer_type->width() <= 32); |
545 | 162 | if (integer_type->IsSigned()) { |
546 | 162 | result = utils::SignExtendValue(result, integer_type->width()); |
547 | 162 | } else { |
548 | 0 | result = utils::ZeroExtendValue(result, integer_type->width()); |
549 | 0 | } |
550 | 162 | words = {static_cast<uint32_t>(result)}; |
551 | 162 | } |
552 | 162 | return GetConstant(integer_type, words); |
553 | 162 | } |
554 | | |
555 | | std::vector<const analysis::Constant*> Constant::GetVectorComponents( |
556 | 0 | analysis::ConstantManager* const_mgr) const { |
557 | 0 | std::vector<const analysis::Constant*> components; |
558 | 0 | const analysis::VectorConstant* a = this->AsVectorConstant(); |
559 | 0 | const analysis::Vector* vector_type = this->type()->AsVector(); |
560 | 0 | assert(vector_type != nullptr); |
561 | 0 | if (a != nullptr) { |
562 | 0 | for (uint32_t i = 0; i < vector_type->element_count(); ++i) { |
563 | 0 | components.push_back(a->GetComponents()[i]); |
564 | 0 | } |
565 | 0 | } 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 | 0 | return components; |
574 | 0 | } |
575 | | |
576 | | } // namespace analysis |
577 | | } // namespace opt |
578 | | } // namespace spvtools |