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