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