14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci#include "ecmascript/compiler/value_numbering.h" 164514f5e3Sopenharmony_ci#include <cstddef> 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu { 194514f5e3Sopenharmony_ci 204514f5e3Sopenharmony_ciGateRef ValueNumbering::VisitGate(GateRef gate) 214514f5e3Sopenharmony_ci{ 224514f5e3Sopenharmony_ci size_t hash = HashCode(gate); 234514f5e3Sopenharmony_ci auto opcode = acc_.GetOpCode(gate); 244514f5e3Sopenharmony_ci if (opcode != OpCode::CONVERT && !useNewGVN_) { 254514f5e3Sopenharmony_ci return Circuit::NullGate(); 264514f5e3Sopenharmony_ci } 274514f5e3Sopenharmony_ci if (acc_.GetStateCount(gate) > 0 || acc_.GetDependCount(gate) > 0) { 284514f5e3Sopenharmony_ci return Circuit::NullGate(); 294514f5e3Sopenharmony_ci } 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_ci if (entries_ == nullptr) { 324514f5e3Sopenharmony_ci InitEntries(entriesLength_); 334514f5e3Sopenharmony_ci SetEntry(hash, gate); 344514f5e3Sopenharmony_ci entriesSize_++; 354514f5e3Sopenharmony_ci return Circuit::NullGate(); 364514f5e3Sopenharmony_ci } 374514f5e3Sopenharmony_ci ASSERT(entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD < entriesLength_ && entriesLength_ >= 1); 384514f5e3Sopenharmony_ci const size_t mask = entriesLength_ - 1; 394514f5e3Sopenharmony_ci size_t dead = entriesLength_; 404514f5e3Sopenharmony_ci for (size_t i = hash & mask;; i = (i + 1) & mask) { 414514f5e3Sopenharmony_ci GateRef entry = entries_[i]; 424514f5e3Sopenharmony_ci if (entry == Circuit::NullGate()) { 434514f5e3Sopenharmony_ci if (dead != entriesLength_) { 444514f5e3Sopenharmony_ci entries_[dead] = gate; 454514f5e3Sopenharmony_ci } else { 464514f5e3Sopenharmony_ci // Have to insert a new entry. 474514f5e3Sopenharmony_ci entries_[i] = gate; 484514f5e3Sopenharmony_ci entriesSize_++; 494514f5e3Sopenharmony_ci // Resize to keep load factor below 80% 504514f5e3Sopenharmony_ci EnsureCapacity(); 514514f5e3Sopenharmony_ci } 524514f5e3Sopenharmony_ci ASSERT(entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD < entriesLength_); 534514f5e3Sopenharmony_ci return Circuit::NullGate(); 544514f5e3Sopenharmony_ci } 554514f5e3Sopenharmony_ci 564514f5e3Sopenharmony_ci if (entry == gate) { 574514f5e3Sopenharmony_ci return Circuit::NullGate(); 584514f5e3Sopenharmony_ci } 594514f5e3Sopenharmony_ci 604514f5e3Sopenharmony_ci // Skip dead entries, but remember their indices so we can reuse them. 614514f5e3Sopenharmony_ci if (acc_.IsNop(entry)) { 624514f5e3Sopenharmony_ci dead = i; 634514f5e3Sopenharmony_ci continue; 644514f5e3Sopenharmony_ci } 654514f5e3Sopenharmony_ci 664514f5e3Sopenharmony_ci if (CheckReplacement(gate, entry)) { 674514f5e3Sopenharmony_ci optimizedGateCount++; 684514f5e3Sopenharmony_ci if (enableLog_) { 694514f5e3Sopenharmony_ci LOG_COMPILER(INFO) << "Found a replaceable node, before -> after"; 704514f5e3Sopenharmony_ci acc_.Print(gate); 714514f5e3Sopenharmony_ci acc_.Print(entry); 724514f5e3Sopenharmony_ci } 734514f5e3Sopenharmony_ci return entry; 744514f5e3Sopenharmony_ci } 754514f5e3Sopenharmony_ci } 764514f5e3Sopenharmony_ci return Circuit::NullGate(); 774514f5e3Sopenharmony_ci} 784514f5e3Sopenharmony_ci 794514f5e3Sopenharmony_civoid ValueNumbering::EnsureCapacity() 804514f5e3Sopenharmony_ci{ 814514f5e3Sopenharmony_ci if (entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD >= entriesLength_) { 824514f5e3Sopenharmony_ci Grow(); 834514f5e3Sopenharmony_ci } 844514f5e3Sopenharmony_ci} 854514f5e3Sopenharmony_ci 864514f5e3Sopenharmony_civoid ValueNumbering::Grow() 874514f5e3Sopenharmony_ci{ 884514f5e3Sopenharmony_ci GateRef *const oldEntries = entries_; 894514f5e3Sopenharmony_ci size_t const oldSize = entriesLength_; 904514f5e3Sopenharmony_ci entriesLength_ *= 2; // 2 : entriesLength 914514f5e3Sopenharmony_ci InitEntries(entriesLength_); 924514f5e3Sopenharmony_ci ASSERT(entriesLength_ > 0); 934514f5e3Sopenharmony_ci size_t const mask = entriesLength_ - 1; 944514f5e3Sopenharmony_ci 954514f5e3Sopenharmony_ci for (size_t i = 0; i < oldSize; i++) { 964514f5e3Sopenharmony_ci GateRef oldEnrty = oldEntries[i]; 974514f5e3Sopenharmony_ci if (oldEnrty == Circuit::NullGate() || acc_.IsNop(oldEnrty)) { 984514f5e3Sopenharmony_ci continue; 994514f5e3Sopenharmony_ci } 1004514f5e3Sopenharmony_ci for (size_t j = HashCode(oldEnrty) & mask;; j = (j + 1) & mask) { 1014514f5e3Sopenharmony_ci GateRef entry = entries_[j]; 1024514f5e3Sopenharmony_ci if (entry == oldEnrty) { 1034514f5e3Sopenharmony_ci break; 1044514f5e3Sopenharmony_ci } 1054514f5e3Sopenharmony_ci if (entry == Circuit::NullGate()) { 1064514f5e3Sopenharmony_ci entries_[j] = oldEnrty; 1074514f5e3Sopenharmony_ci entriesSize_++; 1084514f5e3Sopenharmony_ci break; 1094514f5e3Sopenharmony_ci } 1104514f5e3Sopenharmony_ci } 1114514f5e3Sopenharmony_ci } 1124514f5e3Sopenharmony_ci chunk_->Free(oldEntries); 1134514f5e3Sopenharmony_ci if (enableLog_) { 1144514f5e3Sopenharmony_ci LOG_COMPILER(INFO) << "Grow happend"; 1154514f5e3Sopenharmony_ci } 1164514f5e3Sopenharmony_ci} 1174514f5e3Sopenharmony_ci 1184514f5e3Sopenharmony_civoid ValueNumbering::InitEntries(size_t initSize) 1194514f5e3Sopenharmony_ci{ 1204514f5e3Sopenharmony_ci entries_ = chunk_->NewArray<int32_t>(initSize); 1214514f5e3Sopenharmony_ci for (size_t i = 0; i < initSize; i++) { 1224514f5e3Sopenharmony_ci entries_[i] = Circuit::NullGate(); 1234514f5e3Sopenharmony_ci } 1244514f5e3Sopenharmony_ci entriesSize_ = 0; 1254514f5e3Sopenharmony_ci} 1264514f5e3Sopenharmony_ci 1274514f5e3Sopenharmony_ci 1284514f5e3Sopenharmony_cisize_t HashCombine(size_t seed, size_t value) 1294514f5e3Sopenharmony_ci{ 1304514f5e3Sopenharmony_ci // In the meantime, we're not considering 32-bit systems 1314514f5e3Sopenharmony_ci assert(sizeof(void *) == 8); // 8 : make sure the void* pointer is 8 bytes in size 1324514f5e3Sopenharmony_ci const uint64_t m = uint64_t{0xC6A4A7935BD1E995}; 1334514f5e3Sopenharmony_ci const uint32_t r = 47; 1344514f5e3Sopenharmony_ci 1354514f5e3Sopenharmony_ci value *= m; 1364514f5e3Sopenharmony_ci value ^= value >> r; 1374514f5e3Sopenharmony_ci value *= m; 1384514f5e3Sopenharmony_ci 1394514f5e3Sopenharmony_ci seed ^= value; 1404514f5e3Sopenharmony_ci seed *= m; 1414514f5e3Sopenharmony_ci return seed; 1424514f5e3Sopenharmony_ci} 1434514f5e3Sopenharmony_ci 1444514f5e3Sopenharmony_cisize_t ValueNumbering::HashCode(GateRef gate) 1454514f5e3Sopenharmony_ci{ 1464514f5e3Sopenharmony_ci size_t valueCount = acc_.GetNumValueIn(gate); 1474514f5e3Sopenharmony_ci size_t hash = HashCombine(static_cast<size_t>(acc_.GetOpCode(gate)), valueCount); 1484514f5e3Sopenharmony_ci for (size_t i = 0; i < valueCount; i++) { 1494514f5e3Sopenharmony_ci GateRef input = acc_.GetValueIn(gate, i); 1504514f5e3Sopenharmony_ci auto id = acc_.GetId(input); 1514514f5e3Sopenharmony_ci hash = HashCombine(hash, id); 1524514f5e3Sopenharmony_ci } 1534514f5e3Sopenharmony_ci return hash; 1544514f5e3Sopenharmony_ci} 1554514f5e3Sopenharmony_ci 1564514f5e3Sopenharmony_ci// Gates are considered replaceable only when their values are identical 1574514f5e3Sopenharmony_cibool ValueNumbering::CheckReplacement(GateRef lhs, GateRef rhs) 1584514f5e3Sopenharmony_ci{ 1594514f5e3Sopenharmony_ci if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs)) 1604514f5e3Sopenharmony_ci return false; 1614514f5e3Sopenharmony_ci 1624514f5e3Sopenharmony_ci size_t valueCount1 = acc_.GetNumIns(lhs); 1634514f5e3Sopenharmony_ci size_t valueCount2 = acc_.GetNumIns(rhs); 1644514f5e3Sopenharmony_ci if (valueCount1 != valueCount2) 1654514f5e3Sopenharmony_ci return false; 1664514f5e3Sopenharmony_ci for (size_t i = 0; i < valueCount1; i++) { 1674514f5e3Sopenharmony_ci if (acc_.GetIn(lhs, i) != acc_.GetIn(rhs, i)) { 1684514f5e3Sopenharmony_ci return false; 1694514f5e3Sopenharmony_ci } 1704514f5e3Sopenharmony_ci } 1714514f5e3Sopenharmony_ci 1724514f5e3Sopenharmony_ci if (acc_.GetGateType(lhs) != acc_.GetGateType(rhs)) { 1734514f5e3Sopenharmony_ci return false; 1744514f5e3Sopenharmony_ci } 1754514f5e3Sopenharmony_ci 1764514f5e3Sopenharmony_ci if (acc_.GetMachineType(lhs) != acc_.GetMachineType(rhs)) { 1774514f5e3Sopenharmony_ci return false; 1784514f5e3Sopenharmony_ci } 1794514f5e3Sopenharmony_ci 1804514f5e3Sopenharmony_ci if (!acc_.MetaDataValueEqu(lhs, rhs)) { 1814514f5e3Sopenharmony_ci return false; 1824514f5e3Sopenharmony_ci } 1834514f5e3Sopenharmony_ci 1844514f5e3Sopenharmony_ci return true; 1854514f5e3Sopenharmony_ci} 1864514f5e3Sopenharmony_ci} // namespace panda::ecmascript::kungfu