1fd4e5da5Sopenharmony_ci// Copyright (c) 2017 Google Inc.
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include "source/opt/constants.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include <vector>
18fd4e5da5Sopenharmony_ci
19fd4e5da5Sopenharmony_ci#include "source/opt/ir_context.h"
20fd4e5da5Sopenharmony_ci
21fd4e5da5Sopenharmony_cinamespace spvtools {
22fd4e5da5Sopenharmony_cinamespace opt {
23fd4e5da5Sopenharmony_cinamespace analysis {
24fd4e5da5Sopenharmony_ci
25fd4e5da5Sopenharmony_cifloat Constant::GetFloat() const {
26fd4e5da5Sopenharmony_ci  assert(type()->AsFloat() != nullptr && type()->AsFloat()->width() == 32);
27fd4e5da5Sopenharmony_ci
28fd4e5da5Sopenharmony_ci  if (const FloatConstant* fc = AsFloatConstant()) {
29fd4e5da5Sopenharmony_ci    return fc->GetFloatValue();
30fd4e5da5Sopenharmony_ci  } else {
31fd4e5da5Sopenharmony_ci    assert(AsNullConstant() && "Must be a floating point constant.");
32fd4e5da5Sopenharmony_ci    return 0.0f;
33fd4e5da5Sopenharmony_ci  }
34fd4e5da5Sopenharmony_ci}
35fd4e5da5Sopenharmony_ci
36fd4e5da5Sopenharmony_cidouble Constant::GetDouble() const {
37fd4e5da5Sopenharmony_ci  assert(type()->AsFloat() != nullptr && type()->AsFloat()->width() == 64);
38fd4e5da5Sopenharmony_ci
39fd4e5da5Sopenharmony_ci  if (const FloatConstant* fc = AsFloatConstant()) {
40fd4e5da5Sopenharmony_ci    return fc->GetDoubleValue();
41fd4e5da5Sopenharmony_ci  } else {
42fd4e5da5Sopenharmony_ci    assert(AsNullConstant() && "Must be a floating point constant.");
43fd4e5da5Sopenharmony_ci    return 0.0;
44fd4e5da5Sopenharmony_ci  }
45fd4e5da5Sopenharmony_ci}
46fd4e5da5Sopenharmony_ci
47fd4e5da5Sopenharmony_cidouble Constant::GetValueAsDouble() const {
48fd4e5da5Sopenharmony_ci  assert(type()->AsFloat() != nullptr);
49fd4e5da5Sopenharmony_ci  if (type()->AsFloat()->width() == 32) {
50fd4e5da5Sopenharmony_ci    return GetFloat();
51fd4e5da5Sopenharmony_ci  } else {
52fd4e5da5Sopenharmony_ci    assert(type()->AsFloat()->width() == 64);
53fd4e5da5Sopenharmony_ci    return GetDouble();
54fd4e5da5Sopenharmony_ci  }
55fd4e5da5Sopenharmony_ci}
56fd4e5da5Sopenharmony_ci
57fd4e5da5Sopenharmony_ciuint32_t Constant::GetU32() const {
58fd4e5da5Sopenharmony_ci  assert(type()->AsInteger() != nullptr);
59fd4e5da5Sopenharmony_ci  assert(type()->AsInteger()->width() == 32);
60fd4e5da5Sopenharmony_ci
61fd4e5da5Sopenharmony_ci  if (const IntConstant* ic = AsIntConstant()) {
62fd4e5da5Sopenharmony_ci    return ic->GetU32BitValue();
63fd4e5da5Sopenharmony_ci  } else {
64fd4e5da5Sopenharmony_ci    assert(AsNullConstant() && "Must be an integer constant.");
65fd4e5da5Sopenharmony_ci    return 0u;
66fd4e5da5Sopenharmony_ci  }
67fd4e5da5Sopenharmony_ci}
68fd4e5da5Sopenharmony_ci
69fd4e5da5Sopenharmony_ciuint64_t Constant::GetU64() const {
70fd4e5da5Sopenharmony_ci  assert(type()->AsInteger() != nullptr);
71fd4e5da5Sopenharmony_ci  assert(type()->AsInteger()->width() == 64);
72fd4e5da5Sopenharmony_ci
73fd4e5da5Sopenharmony_ci  if (const IntConstant* ic = AsIntConstant()) {
74fd4e5da5Sopenharmony_ci    return ic->GetU64BitValue();
75fd4e5da5Sopenharmony_ci  } else {
76fd4e5da5Sopenharmony_ci    assert(AsNullConstant() && "Must be an integer constant.");
77fd4e5da5Sopenharmony_ci    return 0u;
78fd4e5da5Sopenharmony_ci  }
79fd4e5da5Sopenharmony_ci}
80fd4e5da5Sopenharmony_ci
81fd4e5da5Sopenharmony_ciint32_t Constant::GetS32() const {
82fd4e5da5Sopenharmony_ci  assert(type()->AsInteger() != nullptr);
83fd4e5da5Sopenharmony_ci  assert(type()->AsInteger()->width() == 32);
84fd4e5da5Sopenharmony_ci
85fd4e5da5Sopenharmony_ci  if (const IntConstant* ic = AsIntConstant()) {
86fd4e5da5Sopenharmony_ci    return ic->GetS32BitValue();
87fd4e5da5Sopenharmony_ci  } else {
88fd4e5da5Sopenharmony_ci    assert(AsNullConstant() && "Must be an integer constant.");
89fd4e5da5Sopenharmony_ci    return 0;
90fd4e5da5Sopenharmony_ci  }
91fd4e5da5Sopenharmony_ci}
92fd4e5da5Sopenharmony_ci
93fd4e5da5Sopenharmony_ciint64_t Constant::GetS64() const {
94fd4e5da5Sopenharmony_ci  assert(type()->AsInteger() != nullptr);
95fd4e5da5Sopenharmony_ci  assert(type()->AsInteger()->width() == 64);
96fd4e5da5Sopenharmony_ci
97fd4e5da5Sopenharmony_ci  if (const IntConstant* ic = AsIntConstant()) {
98fd4e5da5Sopenharmony_ci    return ic->GetS64BitValue();
99fd4e5da5Sopenharmony_ci  } else {
100fd4e5da5Sopenharmony_ci    assert(AsNullConstant() && "Must be an integer constant.");
101fd4e5da5Sopenharmony_ci    return 0;
102fd4e5da5Sopenharmony_ci  }
103fd4e5da5Sopenharmony_ci}
104fd4e5da5Sopenharmony_ci
105fd4e5da5Sopenharmony_ciuint64_t Constant::GetZeroExtendedValue() const {
106fd4e5da5Sopenharmony_ci  const auto* int_type = type()->AsInteger();
107fd4e5da5Sopenharmony_ci  assert(int_type != nullptr);
108fd4e5da5Sopenharmony_ci  const auto width = int_type->width();
109fd4e5da5Sopenharmony_ci  assert(width <= 64);
110fd4e5da5Sopenharmony_ci
111fd4e5da5Sopenharmony_ci  uint64_t value = 0;
112fd4e5da5Sopenharmony_ci  if (const IntConstant* ic = AsIntConstant()) {
113fd4e5da5Sopenharmony_ci    if (width <= 32) {
114fd4e5da5Sopenharmony_ci      value = ic->GetU32BitValue();
115fd4e5da5Sopenharmony_ci    } else {
116fd4e5da5Sopenharmony_ci      value = ic->GetU64BitValue();
117fd4e5da5Sopenharmony_ci    }
118fd4e5da5Sopenharmony_ci  } else {
119fd4e5da5Sopenharmony_ci    assert(AsNullConstant() && "Must be an integer constant.");
120fd4e5da5Sopenharmony_ci  }
121fd4e5da5Sopenharmony_ci  return value;
122fd4e5da5Sopenharmony_ci}
123fd4e5da5Sopenharmony_ci
124fd4e5da5Sopenharmony_ciint64_t Constant::GetSignExtendedValue() const {
125fd4e5da5Sopenharmony_ci  const auto* int_type = type()->AsInteger();
126fd4e5da5Sopenharmony_ci  assert(int_type != nullptr);
127fd4e5da5Sopenharmony_ci  const auto width = int_type->width();
128fd4e5da5Sopenharmony_ci  assert(width <= 64);
129fd4e5da5Sopenharmony_ci
130fd4e5da5Sopenharmony_ci  int64_t value = 0;
131fd4e5da5Sopenharmony_ci  if (const IntConstant* ic = AsIntConstant()) {
132fd4e5da5Sopenharmony_ci    if (width <= 32) {
133fd4e5da5Sopenharmony_ci      // Let the C++ compiler do the sign extension.
134fd4e5da5Sopenharmony_ci      value = int64_t(ic->GetS32BitValue());
135fd4e5da5Sopenharmony_ci    } else {
136fd4e5da5Sopenharmony_ci      value = ic->GetS64BitValue();
137fd4e5da5Sopenharmony_ci    }
138fd4e5da5Sopenharmony_ci  } else {
139fd4e5da5Sopenharmony_ci    assert(AsNullConstant() && "Must be an integer constant.");
140fd4e5da5Sopenharmony_ci  }
141fd4e5da5Sopenharmony_ci  return value;
142fd4e5da5Sopenharmony_ci}
143fd4e5da5Sopenharmony_ci
144fd4e5da5Sopenharmony_ciConstantManager::ConstantManager(IRContext* ctx) : ctx_(ctx) {
145fd4e5da5Sopenharmony_ci  // Populate the constant table with values from constant declarations in the
146fd4e5da5Sopenharmony_ci  // module.  The values of each OpConstant declaration is the identity
147fd4e5da5Sopenharmony_ci  // assignment (i.e., each constant is its own value).
148fd4e5da5Sopenharmony_ci  for (const auto& inst : ctx_->module()->GetConstants()) {
149fd4e5da5Sopenharmony_ci    MapInst(inst);
150fd4e5da5Sopenharmony_ci  }
151fd4e5da5Sopenharmony_ci}
152fd4e5da5Sopenharmony_ci
153fd4e5da5Sopenharmony_ciType* ConstantManager::GetType(const Instruction* inst) const {
154fd4e5da5Sopenharmony_ci  return context()->get_type_mgr()->GetType(inst->type_id());
155fd4e5da5Sopenharmony_ci}
156fd4e5da5Sopenharmony_ci
157fd4e5da5Sopenharmony_cistd::vector<const Constant*> ConstantManager::GetOperandConstants(
158fd4e5da5Sopenharmony_ci    const Instruction* inst) const {
159fd4e5da5Sopenharmony_ci  std::vector<const Constant*> constants;
160fd4e5da5Sopenharmony_ci  constants.reserve(inst->NumInOperands());
161fd4e5da5Sopenharmony_ci  for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
162fd4e5da5Sopenharmony_ci    const Operand* operand = &inst->GetInOperand(i);
163fd4e5da5Sopenharmony_ci    if (operand->type != SPV_OPERAND_TYPE_ID) {
164fd4e5da5Sopenharmony_ci      constants.push_back(nullptr);
165fd4e5da5Sopenharmony_ci    } else {
166fd4e5da5Sopenharmony_ci      uint32_t id = operand->words[0];
167fd4e5da5Sopenharmony_ci      const analysis::Constant* constant = FindDeclaredConstant(id);
168fd4e5da5Sopenharmony_ci      constants.push_back(constant);
169fd4e5da5Sopenharmony_ci    }
170fd4e5da5Sopenharmony_ci  }
171fd4e5da5Sopenharmony_ci  return constants;
172fd4e5da5Sopenharmony_ci}
173fd4e5da5Sopenharmony_ci
174fd4e5da5Sopenharmony_ciuint32_t ConstantManager::FindDeclaredConstant(const Constant* c,
175fd4e5da5Sopenharmony_ci                                               uint32_t type_id) const {
176fd4e5da5Sopenharmony_ci  c = FindConstant(c);
177fd4e5da5Sopenharmony_ci  if (c == nullptr) {
178fd4e5da5Sopenharmony_ci    return 0;
179fd4e5da5Sopenharmony_ci  }
180fd4e5da5Sopenharmony_ci
181fd4e5da5Sopenharmony_ci  for (auto range = const_val_to_id_.equal_range(c);
182fd4e5da5Sopenharmony_ci       range.first != range.second; ++range.first) {
183fd4e5da5Sopenharmony_ci    Instruction* const_def =
184fd4e5da5Sopenharmony_ci        context()->get_def_use_mgr()->GetDef(range.first->second);
185fd4e5da5Sopenharmony_ci    if (type_id == 0 || const_def->type_id() == type_id) {
186fd4e5da5Sopenharmony_ci      return range.first->second;
187fd4e5da5Sopenharmony_ci    }
188fd4e5da5Sopenharmony_ci  }
189fd4e5da5Sopenharmony_ci  return 0;
190fd4e5da5Sopenharmony_ci}
191fd4e5da5Sopenharmony_ci
192fd4e5da5Sopenharmony_cistd::vector<const Constant*> ConstantManager::GetConstantsFromIds(
193fd4e5da5Sopenharmony_ci    const std::vector<uint32_t>& ids) const {
194fd4e5da5Sopenharmony_ci  std::vector<const Constant*> constants;
195fd4e5da5Sopenharmony_ci  for (uint32_t id : ids) {
196fd4e5da5Sopenharmony_ci    if (const Constant* c = FindDeclaredConstant(id)) {
197fd4e5da5Sopenharmony_ci      constants.push_back(c);
198fd4e5da5Sopenharmony_ci    } else {
199fd4e5da5Sopenharmony_ci      return {};
200fd4e5da5Sopenharmony_ci    }
201fd4e5da5Sopenharmony_ci  }
202fd4e5da5Sopenharmony_ci  return constants;
203fd4e5da5Sopenharmony_ci}
204fd4e5da5Sopenharmony_ci
205fd4e5da5Sopenharmony_ciInstruction* ConstantManager::BuildInstructionAndAddToModule(
206fd4e5da5Sopenharmony_ci    const Constant* new_const, Module::inst_iterator* pos, uint32_t type_id) {
207fd4e5da5Sopenharmony_ci  // TODO(1841): Handle id overflow.
208fd4e5da5Sopenharmony_ci  uint32_t new_id = context()->TakeNextId();
209fd4e5da5Sopenharmony_ci  if (new_id == 0) {
210fd4e5da5Sopenharmony_ci    return nullptr;
211fd4e5da5Sopenharmony_ci  }
212fd4e5da5Sopenharmony_ci
213fd4e5da5Sopenharmony_ci  auto new_inst = CreateInstruction(new_id, new_const, type_id);
214fd4e5da5Sopenharmony_ci  if (!new_inst) {
215fd4e5da5Sopenharmony_ci    return nullptr;
216fd4e5da5Sopenharmony_ci  }
217fd4e5da5Sopenharmony_ci  auto* new_inst_ptr = new_inst.get();
218fd4e5da5Sopenharmony_ci  *pos = pos->InsertBefore(std::move(new_inst));
219fd4e5da5Sopenharmony_ci  ++(*pos);
220fd4e5da5Sopenharmony_ci  if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
221fd4e5da5Sopenharmony_ci    context()->get_def_use_mgr()->AnalyzeInstDefUse(new_inst_ptr);
222fd4e5da5Sopenharmony_ci  MapConstantToInst(new_const, new_inst_ptr);
223fd4e5da5Sopenharmony_ci  return new_inst_ptr;
224fd4e5da5Sopenharmony_ci}
225fd4e5da5Sopenharmony_ci
226fd4e5da5Sopenharmony_ciInstruction* ConstantManager::GetDefiningInstruction(
227fd4e5da5Sopenharmony_ci    const Constant* c, uint32_t type_id, Module::inst_iterator* pos) {
228fd4e5da5Sopenharmony_ci  uint32_t decl_id = FindDeclaredConstant(c, type_id);
229fd4e5da5Sopenharmony_ci  if (decl_id == 0) {
230fd4e5da5Sopenharmony_ci    auto iter = context()->types_values_end();
231fd4e5da5Sopenharmony_ci    if (pos == nullptr) pos = &iter;
232fd4e5da5Sopenharmony_ci    return BuildInstructionAndAddToModule(c, pos, type_id);
233fd4e5da5Sopenharmony_ci  } else {
234fd4e5da5Sopenharmony_ci    auto def = context()->get_def_use_mgr()->GetDef(decl_id);
235fd4e5da5Sopenharmony_ci    assert(def != nullptr);
236fd4e5da5Sopenharmony_ci    assert((type_id == 0 || def->type_id() == type_id) &&
237fd4e5da5Sopenharmony_ci           "This constant already has an instruction with a different type.");
238fd4e5da5Sopenharmony_ci    return def;
239fd4e5da5Sopenharmony_ci  }
240fd4e5da5Sopenharmony_ci}
241fd4e5da5Sopenharmony_ci
242fd4e5da5Sopenharmony_cistd::unique_ptr<Constant> ConstantManager::CreateConstant(
243fd4e5da5Sopenharmony_ci    const Type* type, const std::vector<uint32_t>& literal_words_or_ids) const {
244fd4e5da5Sopenharmony_ci  if (literal_words_or_ids.size() == 0) {
245fd4e5da5Sopenharmony_ci    // Constant declared with OpConstantNull
246fd4e5da5Sopenharmony_ci    return MakeUnique<NullConstant>(type);
247fd4e5da5Sopenharmony_ci  } else if (auto* bt = type->AsBool()) {
248fd4e5da5Sopenharmony_ci    assert(literal_words_or_ids.size() == 1 &&
249fd4e5da5Sopenharmony_ci           "Bool constant should be declared with one operand");
250fd4e5da5Sopenharmony_ci    return MakeUnique<BoolConstant>(bt, literal_words_or_ids.front());
251fd4e5da5Sopenharmony_ci  } else if (auto* it = type->AsInteger()) {
252fd4e5da5Sopenharmony_ci    return MakeUnique<IntConstant>(it, literal_words_or_ids);
253fd4e5da5Sopenharmony_ci  } else if (auto* ft = type->AsFloat()) {
254fd4e5da5Sopenharmony_ci    return MakeUnique<FloatConstant>(ft, literal_words_or_ids);
255fd4e5da5Sopenharmony_ci  } else if (auto* vt = type->AsVector()) {
256fd4e5da5Sopenharmony_ci    auto components = GetConstantsFromIds(literal_words_or_ids);
257fd4e5da5Sopenharmony_ci    if (components.empty()) return nullptr;
258fd4e5da5Sopenharmony_ci    // All components of VectorConstant must be of type Bool, Integer or Float.
259fd4e5da5Sopenharmony_ci    if (!std::all_of(components.begin(), components.end(),
260fd4e5da5Sopenharmony_ci                     [](const Constant* c) {
261fd4e5da5Sopenharmony_ci                       if (c->type()->AsBool() || c->type()->AsInteger() ||
262fd4e5da5Sopenharmony_ci                           c->type()->AsFloat()) {
263fd4e5da5Sopenharmony_ci                         return true;
264fd4e5da5Sopenharmony_ci                       } else {
265fd4e5da5Sopenharmony_ci                         return false;
266fd4e5da5Sopenharmony_ci                       }
267fd4e5da5Sopenharmony_ci                     }))
268fd4e5da5Sopenharmony_ci      return nullptr;
269fd4e5da5Sopenharmony_ci    // All components of VectorConstant must be in the same type.
270fd4e5da5Sopenharmony_ci    const auto* component_type = components.front()->type();
271fd4e5da5Sopenharmony_ci    if (!std::all_of(components.begin(), components.end(),
272fd4e5da5Sopenharmony_ci                     [&component_type](const Constant* c) {
273fd4e5da5Sopenharmony_ci                       if (c->type() == component_type) return true;
274fd4e5da5Sopenharmony_ci                       return false;
275fd4e5da5Sopenharmony_ci                     }))
276fd4e5da5Sopenharmony_ci      return nullptr;
277fd4e5da5Sopenharmony_ci    return MakeUnique<VectorConstant>(vt, components);
278fd4e5da5Sopenharmony_ci  } else if (auto* mt = type->AsMatrix()) {
279fd4e5da5Sopenharmony_ci    auto components = GetConstantsFromIds(literal_words_or_ids);
280fd4e5da5Sopenharmony_ci    if (components.empty()) return nullptr;
281fd4e5da5Sopenharmony_ci    return MakeUnique<MatrixConstant>(mt, components);
282fd4e5da5Sopenharmony_ci  } else if (auto* st = type->AsStruct()) {
283fd4e5da5Sopenharmony_ci    auto components = GetConstantsFromIds(literal_words_or_ids);
284fd4e5da5Sopenharmony_ci    if (components.empty()) return nullptr;
285fd4e5da5Sopenharmony_ci    return MakeUnique<StructConstant>(st, components);
286fd4e5da5Sopenharmony_ci  } else if (auto* at = type->AsArray()) {
287fd4e5da5Sopenharmony_ci    auto components = GetConstantsFromIds(literal_words_or_ids);
288fd4e5da5Sopenharmony_ci    if (components.empty()) return nullptr;
289fd4e5da5Sopenharmony_ci    return MakeUnique<ArrayConstant>(at, components);
290fd4e5da5Sopenharmony_ci  } else {
291fd4e5da5Sopenharmony_ci    return nullptr;
292fd4e5da5Sopenharmony_ci  }
293fd4e5da5Sopenharmony_ci}
294fd4e5da5Sopenharmony_ci
295fd4e5da5Sopenharmony_ciconst Constant* ConstantManager::GetConstantFromInst(const Instruction* inst) {
296fd4e5da5Sopenharmony_ci  std::vector<uint32_t> literal_words_or_ids;
297fd4e5da5Sopenharmony_ci
298fd4e5da5Sopenharmony_ci  // Collect the constant defining literals or component ids.
299fd4e5da5Sopenharmony_ci  for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
300fd4e5da5Sopenharmony_ci    literal_words_or_ids.insert(literal_words_or_ids.end(),
301fd4e5da5Sopenharmony_ci                                inst->GetInOperand(i).words.begin(),
302fd4e5da5Sopenharmony_ci                                inst->GetInOperand(i).words.end());
303fd4e5da5Sopenharmony_ci  }
304fd4e5da5Sopenharmony_ci
305fd4e5da5Sopenharmony_ci  switch (inst->opcode()) {
306fd4e5da5Sopenharmony_ci    // OpConstant{True|False} have the value embedded in the opcode. So they
307fd4e5da5Sopenharmony_ci    // are not handled by the for-loop above. Here we add the value explicitly.
308fd4e5da5Sopenharmony_ci    case spv::Op::OpConstantTrue:
309fd4e5da5Sopenharmony_ci      literal_words_or_ids.push_back(true);
310fd4e5da5Sopenharmony_ci      break;
311fd4e5da5Sopenharmony_ci    case spv::Op::OpConstantFalse:
312fd4e5da5Sopenharmony_ci      literal_words_or_ids.push_back(false);
313fd4e5da5Sopenharmony_ci      break;
314fd4e5da5Sopenharmony_ci    case spv::Op::OpConstantNull:
315fd4e5da5Sopenharmony_ci    case spv::Op::OpConstant:
316fd4e5da5Sopenharmony_ci    case spv::Op::OpConstantComposite:
317fd4e5da5Sopenharmony_ci    case spv::Op::OpSpecConstantComposite:
318fd4e5da5Sopenharmony_ci      break;
319fd4e5da5Sopenharmony_ci    default:
320fd4e5da5Sopenharmony_ci      return nullptr;
321fd4e5da5Sopenharmony_ci  }
322fd4e5da5Sopenharmony_ci
323fd4e5da5Sopenharmony_ci  return GetConstant(GetType(inst), literal_words_or_ids);
324fd4e5da5Sopenharmony_ci}
325fd4e5da5Sopenharmony_ci
326fd4e5da5Sopenharmony_cistd::unique_ptr<Instruction> ConstantManager::CreateInstruction(
327fd4e5da5Sopenharmony_ci    uint32_t id, const Constant* c, uint32_t type_id) const {
328fd4e5da5Sopenharmony_ci  uint32_t type =
329fd4e5da5Sopenharmony_ci      (type_id == 0) ? context()->get_type_mgr()->GetId(c->type()) : type_id;
330fd4e5da5Sopenharmony_ci  if (c->AsNullConstant()) {
331fd4e5da5Sopenharmony_ci    return MakeUnique<Instruction>(context(), spv::Op::OpConstantNull, type, id,
332fd4e5da5Sopenharmony_ci                                   std::initializer_list<Operand>{});
333fd4e5da5Sopenharmony_ci  } else if (const BoolConstant* bc = c->AsBoolConstant()) {
334fd4e5da5Sopenharmony_ci    return MakeUnique<Instruction>(
335fd4e5da5Sopenharmony_ci        context(),
336fd4e5da5Sopenharmony_ci        bc->value() ? spv::Op::OpConstantTrue : spv::Op::OpConstantFalse, type,
337fd4e5da5Sopenharmony_ci        id, std::initializer_list<Operand>{});
338fd4e5da5Sopenharmony_ci  } else if (const IntConstant* ic = c->AsIntConstant()) {
339fd4e5da5Sopenharmony_ci    return MakeUnique<Instruction>(
340fd4e5da5Sopenharmony_ci        context(), spv::Op::OpConstant, type, id,
341fd4e5da5Sopenharmony_ci        std::initializer_list<Operand>{
342fd4e5da5Sopenharmony_ci            Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
343fd4e5da5Sopenharmony_ci                    ic->words())});
344fd4e5da5Sopenharmony_ci  } else if (const FloatConstant* fc = c->AsFloatConstant()) {
345fd4e5da5Sopenharmony_ci    return MakeUnique<Instruction>(
346fd4e5da5Sopenharmony_ci        context(), spv::Op::OpConstant, type, id,
347fd4e5da5Sopenharmony_ci        std::initializer_list<Operand>{
348fd4e5da5Sopenharmony_ci            Operand(spv_operand_type_t::SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER,
349fd4e5da5Sopenharmony_ci                    fc->words())});
350fd4e5da5Sopenharmony_ci  } else if (const CompositeConstant* cc = c->AsCompositeConstant()) {
351fd4e5da5Sopenharmony_ci    return CreateCompositeInstruction(id, cc, type_id);
352fd4e5da5Sopenharmony_ci  } else {
353fd4e5da5Sopenharmony_ci    return nullptr;
354fd4e5da5Sopenharmony_ci  }
355fd4e5da5Sopenharmony_ci}
356fd4e5da5Sopenharmony_ci
357fd4e5da5Sopenharmony_cistd::unique_ptr<Instruction> ConstantManager::CreateCompositeInstruction(
358fd4e5da5Sopenharmony_ci    uint32_t result_id, const CompositeConstant* cc, uint32_t type_id) const {
359fd4e5da5Sopenharmony_ci  std::vector<Operand> operands;
360fd4e5da5Sopenharmony_ci  Instruction* type_inst = context()->get_def_use_mgr()->GetDef(type_id);
361fd4e5da5Sopenharmony_ci  uint32_t component_index = 0;
362fd4e5da5Sopenharmony_ci  for (const Constant* component_const : cc->GetComponents()) {
363fd4e5da5Sopenharmony_ci    uint32_t component_type_id = 0;
364fd4e5da5Sopenharmony_ci    if (type_inst && type_inst->opcode() == spv::Op::OpTypeStruct) {
365fd4e5da5Sopenharmony_ci      component_type_id = type_inst->GetSingleWordInOperand(component_index);
366fd4e5da5Sopenharmony_ci    } else if (type_inst && type_inst->opcode() == spv::Op::OpTypeArray) {
367fd4e5da5Sopenharmony_ci      component_type_id = type_inst->GetSingleWordInOperand(0);
368fd4e5da5Sopenharmony_ci    }
369fd4e5da5Sopenharmony_ci    uint32_t id = FindDeclaredConstant(component_const, component_type_id);
370fd4e5da5Sopenharmony_ci
371fd4e5da5Sopenharmony_ci    if (id == 0) {
372fd4e5da5Sopenharmony_ci      // Cannot get the id of the component constant, while all components
373fd4e5da5Sopenharmony_ci      // should have been added to the module prior to the composite constant.
374fd4e5da5Sopenharmony_ci      // Cannot create OpConstantComposite instruction in this case.
375fd4e5da5Sopenharmony_ci      return nullptr;
376fd4e5da5Sopenharmony_ci    }
377fd4e5da5Sopenharmony_ci    operands.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_ID,
378fd4e5da5Sopenharmony_ci                          std::initializer_list<uint32_t>{id});
379fd4e5da5Sopenharmony_ci    component_index++;
380fd4e5da5Sopenharmony_ci  }
381fd4e5da5Sopenharmony_ci  uint32_t type =
382fd4e5da5Sopenharmony_ci      (type_id == 0) ? context()->get_type_mgr()->GetId(cc->type()) : type_id;
383fd4e5da5Sopenharmony_ci  return MakeUnique<Instruction>(context(), spv::Op::OpConstantComposite, type,
384fd4e5da5Sopenharmony_ci                                 result_id, std::move(operands));
385fd4e5da5Sopenharmony_ci}
386fd4e5da5Sopenharmony_ci
387fd4e5da5Sopenharmony_ciconst Constant* ConstantManager::GetConstant(
388fd4e5da5Sopenharmony_ci    const Type* type, const std::vector<uint32_t>& literal_words_or_ids) {
389fd4e5da5Sopenharmony_ci  auto cst = CreateConstant(type, literal_words_or_ids);
390fd4e5da5Sopenharmony_ci  return cst ? RegisterConstant(std::move(cst)) : nullptr;
391fd4e5da5Sopenharmony_ci}
392fd4e5da5Sopenharmony_ci
393fd4e5da5Sopenharmony_ciconst Constant* ConstantManager::GetNullCompositeConstant(const Type* type) {
394fd4e5da5Sopenharmony_ci  std::vector<uint32_t> literal_words_or_id;
395fd4e5da5Sopenharmony_ci
396fd4e5da5Sopenharmony_ci  if (type->AsVector()) {
397fd4e5da5Sopenharmony_ci    const Type* element_type = type->AsVector()->element_type();
398fd4e5da5Sopenharmony_ci    const uint32_t null_id = GetNullConstId(element_type);
399fd4e5da5Sopenharmony_ci    const uint32_t element_count = type->AsVector()->element_count();
400fd4e5da5Sopenharmony_ci    for (uint32_t i = 0; i < element_count; i++) {
401fd4e5da5Sopenharmony_ci      literal_words_or_id.push_back(null_id);
402fd4e5da5Sopenharmony_ci    }
403fd4e5da5Sopenharmony_ci  } else if (type->AsMatrix()) {
404fd4e5da5Sopenharmony_ci    const Type* element_type = type->AsMatrix()->element_type();
405fd4e5da5Sopenharmony_ci    const uint32_t null_id = GetNullConstId(element_type);
406fd4e5da5Sopenharmony_ci    const uint32_t element_count = type->AsMatrix()->element_count();
407fd4e5da5Sopenharmony_ci    for (uint32_t i = 0; i < element_count; i++) {
408fd4e5da5Sopenharmony_ci      literal_words_or_id.push_back(null_id);
409fd4e5da5Sopenharmony_ci    }
410fd4e5da5Sopenharmony_ci  } else if (type->AsStruct()) {
411fd4e5da5Sopenharmony_ci    // TODO (sfricke-lunarg) add proper struct support
412fd4e5da5Sopenharmony_ci    return nullptr;
413fd4e5da5Sopenharmony_ci  } else if (type->AsArray()) {
414fd4e5da5Sopenharmony_ci    const Type* element_type = type->AsArray()->element_type();
415fd4e5da5Sopenharmony_ci    const uint32_t null_id = GetNullConstId(element_type);
416fd4e5da5Sopenharmony_ci    assert(type->AsArray()->length_info().words[0] ==
417fd4e5da5Sopenharmony_ci               analysis::Array::LengthInfo::kConstant &&
418fd4e5da5Sopenharmony_ci           "unexpected array length");
419fd4e5da5Sopenharmony_ci    const uint32_t element_count = type->AsArray()->length_info().words[0];
420fd4e5da5Sopenharmony_ci    for (uint32_t i = 0; i < element_count; i++) {
421fd4e5da5Sopenharmony_ci      literal_words_or_id.push_back(null_id);
422fd4e5da5Sopenharmony_ci    }
423fd4e5da5Sopenharmony_ci  } else {
424fd4e5da5Sopenharmony_ci    return nullptr;
425fd4e5da5Sopenharmony_ci  }
426fd4e5da5Sopenharmony_ci
427fd4e5da5Sopenharmony_ci  return GetConstant(type, literal_words_or_id);
428fd4e5da5Sopenharmony_ci}
429fd4e5da5Sopenharmony_ci
430fd4e5da5Sopenharmony_ciconst Constant* ConstantManager::GetNumericVectorConstantWithWords(
431fd4e5da5Sopenharmony_ci    const Vector* type, const std::vector<uint32_t>& literal_words) {
432fd4e5da5Sopenharmony_ci  const auto* element_type = type->element_type();
433fd4e5da5Sopenharmony_ci  uint32_t words_per_element = 0;
434fd4e5da5Sopenharmony_ci  if (const auto* float_type = element_type->AsFloat())
435fd4e5da5Sopenharmony_ci    words_per_element = float_type->width() / 32;
436fd4e5da5Sopenharmony_ci  else if (const auto* int_type = element_type->AsInteger())
437fd4e5da5Sopenharmony_ci    words_per_element = int_type->width() / 32;
438fd4e5da5Sopenharmony_ci  else if (element_type->AsBool() != nullptr)
439fd4e5da5Sopenharmony_ci    words_per_element = 1;
440fd4e5da5Sopenharmony_ci
441fd4e5da5Sopenharmony_ci  if (words_per_element != 1 && words_per_element != 2) return nullptr;
442fd4e5da5Sopenharmony_ci
443fd4e5da5Sopenharmony_ci  if (words_per_element * type->element_count() !=
444fd4e5da5Sopenharmony_ci      static_cast<uint32_t>(literal_words.size())) {
445fd4e5da5Sopenharmony_ci    return nullptr;
446fd4e5da5Sopenharmony_ci  }
447fd4e5da5Sopenharmony_ci
448fd4e5da5Sopenharmony_ci  std::vector<uint32_t> element_ids;
449fd4e5da5Sopenharmony_ci  for (uint32_t i = 0; i < type->element_count(); ++i) {
450fd4e5da5Sopenharmony_ci    auto first_word = literal_words.begin() + (words_per_element * i);
451fd4e5da5Sopenharmony_ci    std::vector<uint32_t> const_data(first_word,
452fd4e5da5Sopenharmony_ci                                     first_word + words_per_element);
453fd4e5da5Sopenharmony_ci    const analysis::Constant* element_constant =
454fd4e5da5Sopenharmony_ci        GetConstant(element_type, const_data);
455fd4e5da5Sopenharmony_ci    auto element_id = GetDefiningInstruction(element_constant)->result_id();
456fd4e5da5Sopenharmony_ci    element_ids.push_back(element_id);
457fd4e5da5Sopenharmony_ci  }
458fd4e5da5Sopenharmony_ci
459fd4e5da5Sopenharmony_ci  return GetConstant(type, element_ids);
460fd4e5da5Sopenharmony_ci}
461fd4e5da5Sopenharmony_ci
462fd4e5da5Sopenharmony_ciuint32_t ConstantManager::GetFloatConstId(float val) {
463fd4e5da5Sopenharmony_ci  const Constant* c = GetFloatConst(val);
464fd4e5da5Sopenharmony_ci  return GetDefiningInstruction(c)->result_id();
465fd4e5da5Sopenharmony_ci}
466fd4e5da5Sopenharmony_ci
467fd4e5da5Sopenharmony_ciconst Constant* ConstantManager::GetFloatConst(float val) {
468fd4e5da5Sopenharmony_ci  Type* float_type = context()->get_type_mgr()->GetFloatType();
469fd4e5da5Sopenharmony_ci  utils::FloatProxy<float> v(val);
470fd4e5da5Sopenharmony_ci  const Constant* c = GetConstant(float_type, v.GetWords());
471fd4e5da5Sopenharmony_ci  return c;
472fd4e5da5Sopenharmony_ci}
473fd4e5da5Sopenharmony_ci
474fd4e5da5Sopenharmony_ciuint32_t ConstantManager::GetDoubleConstId(double val) {
475fd4e5da5Sopenharmony_ci  const Constant* c = GetDoubleConst(val);
476fd4e5da5Sopenharmony_ci  return GetDefiningInstruction(c)->result_id();
477fd4e5da5Sopenharmony_ci}
478fd4e5da5Sopenharmony_ci
479fd4e5da5Sopenharmony_ciconst Constant* ConstantManager::GetDoubleConst(double val) {
480fd4e5da5Sopenharmony_ci  Type* float_type = context()->get_type_mgr()->GetDoubleType();
481fd4e5da5Sopenharmony_ci  utils::FloatProxy<double> v(val);
482fd4e5da5Sopenharmony_ci  const Constant* c = GetConstant(float_type, v.GetWords());
483fd4e5da5Sopenharmony_ci  return c;
484fd4e5da5Sopenharmony_ci}
485fd4e5da5Sopenharmony_ci
486fd4e5da5Sopenharmony_ciuint32_t ConstantManager::GetSIntConstId(int32_t val) {
487fd4e5da5Sopenharmony_ci  Type* sint_type = context()->get_type_mgr()->GetSIntType();
488fd4e5da5Sopenharmony_ci  const Constant* c = GetConstant(sint_type, {static_cast<uint32_t>(val)});
489fd4e5da5Sopenharmony_ci  return GetDefiningInstruction(c)->result_id();
490fd4e5da5Sopenharmony_ci}
491fd4e5da5Sopenharmony_ci
492fd4e5da5Sopenharmony_ciconst Constant* ConstantManager::GetIntConst(uint64_t val, int32_t bitWidth,
493fd4e5da5Sopenharmony_ci                                             bool isSigned) {
494fd4e5da5Sopenharmony_ci  Type* int_type = context()->get_type_mgr()->GetIntType(bitWidth, isSigned);
495fd4e5da5Sopenharmony_ci
496fd4e5da5Sopenharmony_ci  if (isSigned) {
497fd4e5da5Sopenharmony_ci    // Sign extend the value.
498fd4e5da5Sopenharmony_ci    int32_t num_of_bit_to_ignore = 64 - bitWidth;
499fd4e5da5Sopenharmony_ci    val = static_cast<int64_t>(val << num_of_bit_to_ignore) >>
500fd4e5da5Sopenharmony_ci          num_of_bit_to_ignore;
501fd4e5da5Sopenharmony_ci  } else {
502fd4e5da5Sopenharmony_ci    // Clear the upper bit that are not used.
503fd4e5da5Sopenharmony_ci    uint64_t mask = ((1ull << bitWidth) - 1);
504fd4e5da5Sopenharmony_ci    val &= mask;
505fd4e5da5Sopenharmony_ci  }
506fd4e5da5Sopenharmony_ci
507fd4e5da5Sopenharmony_ci  if (bitWidth <= 32) {
508fd4e5da5Sopenharmony_ci    return GetConstant(int_type, {static_cast<uint32_t>(val)});
509fd4e5da5Sopenharmony_ci  }
510fd4e5da5Sopenharmony_ci
511fd4e5da5Sopenharmony_ci  // If the value is more than 32-bit, we need to split the operands into two
512fd4e5da5Sopenharmony_ci  // 32-bit integers.
513fd4e5da5Sopenharmony_ci  return GetConstant(
514fd4e5da5Sopenharmony_ci      int_type, {static_cast<uint32_t>(val >> 32), static_cast<uint32_t>(val)});
515fd4e5da5Sopenharmony_ci}
516fd4e5da5Sopenharmony_ci
517fd4e5da5Sopenharmony_ciuint32_t ConstantManager::GetUIntConstId(uint32_t val) {
518fd4e5da5Sopenharmony_ci  Type* uint_type = context()->get_type_mgr()->GetUIntType();
519fd4e5da5Sopenharmony_ci  const Constant* c = GetConstant(uint_type, {val});
520fd4e5da5Sopenharmony_ci  return GetDefiningInstruction(c)->result_id();
521fd4e5da5Sopenharmony_ci}
522fd4e5da5Sopenharmony_ci
523fd4e5da5Sopenharmony_ciuint32_t ConstantManager::GetNullConstId(const Type* type) {
524fd4e5da5Sopenharmony_ci  const Constant* c = GetConstant(type, {});
525fd4e5da5Sopenharmony_ci  return GetDefiningInstruction(c)->result_id();
526fd4e5da5Sopenharmony_ci}
527fd4e5da5Sopenharmony_ci
528fd4e5da5Sopenharmony_cistd::vector<const analysis::Constant*> Constant::GetVectorComponents(
529fd4e5da5Sopenharmony_ci    analysis::ConstantManager* const_mgr) const {
530fd4e5da5Sopenharmony_ci  std::vector<const analysis::Constant*> components;
531fd4e5da5Sopenharmony_ci  const analysis::VectorConstant* a = this->AsVectorConstant();
532fd4e5da5Sopenharmony_ci  const analysis::Vector* vector_type = this->type()->AsVector();
533fd4e5da5Sopenharmony_ci  assert(vector_type != nullptr);
534fd4e5da5Sopenharmony_ci  if (a != nullptr) {
535fd4e5da5Sopenharmony_ci    for (uint32_t i = 0; i < vector_type->element_count(); ++i) {
536fd4e5da5Sopenharmony_ci      components.push_back(a->GetComponents()[i]);
537fd4e5da5Sopenharmony_ci    }
538fd4e5da5Sopenharmony_ci  } else {
539fd4e5da5Sopenharmony_ci    const analysis::Type* element_type = vector_type->element_type();
540fd4e5da5Sopenharmony_ci    const analysis::Constant* element_null_const =
541fd4e5da5Sopenharmony_ci        const_mgr->GetConstant(element_type, {});
542fd4e5da5Sopenharmony_ci    for (uint32_t i = 0; i < vector_type->element_count(); ++i) {
543fd4e5da5Sopenharmony_ci      components.push_back(element_null_const);
544fd4e5da5Sopenharmony_ci    }
545fd4e5da5Sopenharmony_ci  }
546fd4e5da5Sopenharmony_ci  return components;
547fd4e5da5Sopenharmony_ci}
548fd4e5da5Sopenharmony_ci
549fd4e5da5Sopenharmony_ci}  // namespace analysis
550fd4e5da5Sopenharmony_ci}  // namespace opt
551fd4e5da5Sopenharmony_ci}  // namespace spvtools
552