/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/compiler/circuit_optimizer.h" namespace panda::ecmascript::kungfu { ValueLattice::ValueLattice() : value_(0), status_(LatticeStatus::TOP) { } ValueLattice::ValueLattice(LatticeStatus status) : value_(0), status_(status) { } ValueLattice::ValueLattice(uint64_t value) : value_(value), status_(LatticeStatus::MID) { } bool ValueLattice::IsTop() const { return GetStatus() == LatticeStatus::TOP; } bool ValueLattice::IsMid() const { return GetStatus() == LatticeStatus::MID; } bool ValueLattice::IsBot() const { return GetStatus() == LatticeStatus::BOT; } LatticeStatus ValueLattice::GetStatus() const { return status_; } std::optional ValueLattice::GetValue() const { if (IsTop() || IsBot()) { return std::nullopt; } return value_; } ValueLattice ValueLattice::Meet(const ValueLattice &other) { if (this->IsTop()) { return other; } if (other.IsTop()) { return *this; } if (this->IsBot() || other.IsBot()) { return ValueLattice(LatticeStatus::BOT); } // both are single if (this->GetValue().value() != other.GetValue().value()) { return ValueLattice(LatticeStatus::BOT); } return *this; } bool ValueLattice::operator==(const ValueLattice &other) const { if (this->IsTop() && other.IsTop()) { return true; } if (this->IsBot() && other.IsBot()) { return true; } if (this->IsMid() && other.IsMid()) { return this->GetValue().value() == other.GetValue().value(); } return false; } bool ValueLattice::operator!=(const ValueLattice &other) const { return !(*this == other); } bool ValueLattice::operator<(const ValueLattice &other) const { if (this->IsMid() && other.IsTop()) { return true; } if (this->IsBot() && other.IsMid()) { return true; } if (this->IsBot() && other.IsTop()) { return true; } return false; } bool ValueLattice::operator>(const ValueLattice &other) const { return !(*this < other); } bool ValueLattice::operator<=(const ValueLattice &other) const { return (*this < other) || (*this == other); } bool ValueLattice::operator>=(const ValueLattice &other) const { return (*this > other) || (*this == other); } ValueLattice ValueLattice::Implies(const ValueLattice &other) const { if (!this->IsTop()) { return other; } return ValueLattice(LatticeStatus::TOP); } void ValueLattice::Print(std::ostream &os) const { if (IsTop()) { os << "TOP"; } else { if (IsBot()) { os << "BOT"; } else { os << GetValue().value(); } } } ReachabilityLattice::ReachabilityLattice() : reachable_(false) { } ReachabilityLattice::ReachabilityLattice(bool reachable) : reachable_(reachable) { } bool ReachabilityLattice::IsReachable() const { return reachable_; } bool ReachabilityLattice::IsUnreachable() const { return !reachable_; } bool ReachabilityLattice::operator==(const ReachabilityLattice &other) const { return this->IsReachable() == other.IsReachable(); } bool ReachabilityLattice::operator!=(const ReachabilityLattice &other) const { return !(*this == other); } ReachabilityLattice ReachabilityLattice::operator+(const ReachabilityLattice &other) const { return ReachabilityLattice(this->IsReachable() || other.IsReachable()); } ReachabilityLattice ReachabilityLattice::operator*(const ReachabilityLattice &other) const { return ReachabilityLattice(this->IsReachable() && other.IsReachable()); } ValueLattice ReachabilityLattice::Implies(const ValueLattice &other) const { if (this->IsReachable()) { return other; } return ValueLattice(LatticeStatus::TOP); } void ReachabilityLattice::Print(std::ostream &os) const { if (this->IsReachable()) { os << "reachable"; } else { os << "unreachable"; } } void LatticeUpdateRule::Initialize(Circuit *circuit, std::function valueLattice, std::function reachabilityLattice) { circuit_ = circuit; acc_ = GateAccessor(circuit); valueLatticeMap_ = std::move(valueLattice); reachabilityLatticeMap_ = std::move(reachabilityLattice); } bool LatticeUpdateRule::UpdateValueLattice(GateRef gate, const ValueLattice &valueLattice) { if (valueLatticeMap_(gate) != valueLattice) { valueLatticeMap_(gate) = valueLattice; return true; } return false; } bool LatticeUpdateRule::UpdateReachabilityLattice(GateRef gate, const ReachabilityLattice &reachabilityLattice) { if (reachabilityLatticeMap_(gate) != reachabilityLattice) { reachabilityLatticeMap_(gate) = reachabilityLattice; return true; } return false; } uint64_t LatticeUpdateRuleSCCP::RunBoolArithmetic(bool valueA, bool valueB, OpCode op) { switch (op) { case OpCode::ADD: return (valueA + valueB); case OpCode::SUB: return (valueA - valueB); case OpCode::MUL: return (valueA * valueB); case OpCode::AND: return (valueA & valueB); case OpCode::XOR: return (valueA ^ valueB); case OpCode::OR: return (valueA | valueB); default: LOG_COMPILER(ERROR) << "unexpected op!"; return 0; } return 0; } template uint64_t LatticeUpdateRuleSCCP::RunFixedPointArithmetic(T valueA, T valueB, OpCode op) { static_assert(std::is_unsigned::value, "T should be an unsigned type"); using make_signed_t = typename std::make_signed::type; switch (op) { case OpCode::ADD: return (valueA + valueB); case OpCode::SUB: return (valueA - valueB); case OpCode::MUL: return (valueA * valueB); case OpCode::SDIV: return (static_cast(valueA) / static_cast(valueB)); case OpCode::UDIV: return (valueA / valueB); case OpCode::SMOD: return (static_cast(valueA) % static_cast(valueB)); case OpCode::UMOD: return (valueA % valueB); case OpCode::AND: return (valueA & valueB); case OpCode::XOR: return (valueA ^ valueB); case OpCode::OR: return (valueA | valueB); case OpCode::LSL: return (valueA << valueB); case OpCode::LSR: return (valueA >> valueB); case OpCode::ASR: return (static_cast(valueA) >> static_cast(valueB)); default: LOG_COMPILER(ERROR) << "unexpected op!"; return 0; } return 0; } template double LatticeUpdateRuleSCCP::RunFloatingPointArithmetic(T valueA, T valueB, OpCode op) { switch (op) { case OpCode::ADD: return (valueA + valueB); case OpCode::SUB: return (valueA - valueB); case OpCode::MUL: return (valueA * valueB); case OpCode::FDIV: return (valueA / valueB); case OpCode::FMOD: return fmod(valueA, valueB); default: LOG_COMPILER(ERROR) << "unexpected op!"; return 0; } return 0; } uint64_t LatticeUpdateRuleSCCP::RunBasicArithmetic(ValueLattice operandA, ValueLattice operandB, OpCode op, MachineType machineType) { auto valueA = operandA.GetValue().value(); auto valueB = operandB.GetValue().value(); if (machineType == MachineType::I1) { return static_cast(RunBoolArithmetic(static_cast(valueA), static_cast(valueB), op)); } else if (machineType == MachineType::I8) { return static_cast(RunFixedPointArithmetic(static_cast(valueA), static_cast(valueB), op)); } else if (machineType == MachineType::I16) { return static_cast(RunFixedPointArithmetic(static_cast(valueA), static_cast(valueB), op)); } else if (machineType == MachineType::I32) { return static_cast(RunFixedPointArithmetic(static_cast(valueA), static_cast(valueB), op)); } else if (machineType == MachineType::I64) { return RunFixedPointArithmetic(static_cast(valueA), static_cast(valueB), op); } else if (machineType == MachineType::F32) { float valueA_ = base::bit_cast(static_cast(valueA)); float valueB_ = base::bit_cast(static_cast(valueB)); return base::bit_cast(RunFloatingPointArithmetic(valueA_, valueB_, op)); } else if (machineType == MachineType::F64) { double valueA_ = base::bit_cast(static_cast(valueA)); double valueB_ = base::bit_cast(static_cast(valueB)); return base::bit_cast(RunFloatingPointArithmetic(valueA_, valueB_, op)); } else { LOG_COMPILER(ERROR) << "unexpected machineType!"; } return 0; } uint64_t LatticeUpdateRuleSCCP::RunFCompareArithmetic(ValueLattice operandA, ValueLattice operandB, FCmpCondition cond, MachineType machineType) { auto valueA = operandA.GetValue().value(); auto valueB = operandB.GetValue().value(); if (machineType == MachineType::F32) { float valueA_ = base::bit_cast(static_cast(valueA)); float valueB_ = base::bit_cast(static_cast(valueB)); return base::bit_cast(RunFloatingPointCompare(valueA_, valueB_, cond)); } else if (machineType == MachineType::F64) { double valueA_ = base::bit_cast(static_cast(valueA)); double valueB_ = base::bit_cast(static_cast(valueB)); return base::bit_cast(RunFloatingPointCompare(valueA_, valueB_, cond)); } else { LOG_COMPILER(ERROR) << "unexpected machineType!"; } return 0; } uint64_t LatticeUpdateRuleSCCP::RunICompareArithmetic(ValueLattice operandA, ValueLattice operandB, ICmpCondition cond, MachineType machineType) { auto valueA = operandA.GetValue().value(); auto valueB = operandB.GetValue().value(); if (machineType == MachineType::I1) { return static_cast(RunBoolCompare(static_cast(valueA), static_cast(valueB), cond)); } else if (machineType == MachineType::I8) { return static_cast(RunFixedPointCompare(static_cast(valueA), static_cast(valueB), cond)); } else if (machineType == MachineType::I16) { return static_cast(RunFixedPointCompare(static_cast(valueA), static_cast(valueB), cond)); } else if (machineType == MachineType::I32) { return static_cast(RunFixedPointCompare(static_cast(valueA), static_cast(valueB), cond)); } else if (machineType == MachineType::I64) { return RunFixedPointCompare(static_cast(valueA), static_cast(valueB), cond); } else { LOG_COMPILER(ERROR) << "unexpected machineType!"; } return 0; } uint64_t LatticeUpdateRuleSCCP::RunBoolCompare(bool valueA, bool valueB, ICmpCondition cond) { switch (cond) { case ICmpCondition::EQ: return (valueA == valueB ? 1 : 0); case ICmpCondition::NE: return (valueA != valueB ? 1 : 0); default: LOG_COMPILER(ERROR) << "unexpected cond!"; return 0; } } template uint64_t LatticeUpdateRuleSCCP::RunFixedPointCompare(T valueA, T valueB, ICmpCondition cond) { static_assert(std::is_unsigned::value, "T should be an unsigned type"); using make_signed_t = typename std::make_signed::type; switch (cond) { case ICmpCondition::SLT: return (static_cast(valueA) < static_cast(valueB)); case ICmpCondition::SLE: return (static_cast(valueA) <= static_cast(valueB)); case ICmpCondition::SGT: return (static_cast(valueA) > static_cast(valueB)); case ICmpCondition::SGE: return (static_cast(valueA) >= static_cast(valueB)); case ICmpCondition::ULT: return (valueA < valueB); case ICmpCondition::ULE: return (valueA <= valueB); case ICmpCondition::UGT: return (valueA > valueB); case ICmpCondition::UGE: return (valueA >= valueB); case ICmpCondition::NE: return (valueA == valueB ? 1 : 0); case ICmpCondition::EQ: return (valueA != valueB ? 1 : 0); default: UNREACHABLE(); } } template uint64_t LatticeUpdateRuleSCCP::RunFloatingPointCompare(T valueA, T valueB, FCmpCondition cond) { switch (cond) { case FCmpCondition::OLT: return (valueA < valueB); case FCmpCondition::OLE: return (valueA <= valueB); case FCmpCondition::OGT: return (valueA > valueB); case FCmpCondition::OGE: return (valueA >= valueB); case FCmpCondition::ONE: return (valueA != valueB ? 1 : 0); case FCmpCondition::OEQ: return (valueA == valueB ? 1 : 0); default: LOG_COMPILER(ERROR) << "unexpected cond!"; return 0; } return 0; } bool LatticeUpdateRuleSCCP::Run(GateRef gate) { const std::map> functionTable = { {OpCode::CIRCUIT_ROOT, [&]() -> bool { return RunCircuitRoot(gate); }}, {OpCode::STATE_ENTRY, [&]() -> bool { return RunStateEntry(gate); }}, {OpCode::DEPEND_ENTRY, [&]() -> bool { return RunDependEntry(gate); }}, {OpCode::RETURN_LIST, [&]() -> bool { return RunReturnList(gate); }}, {OpCode::ARG_LIST, [&]() -> bool { return RunArgList(gate); }}, {OpCode::RETURN, [&]() -> bool { return RunReturn(gate); }}, {OpCode::RETURN_VOID, [&]() -> bool { return RunReturnVoid(gate); }}, {OpCode::THROW, [&]() -> bool { return RunThrow(gate); }}, {OpCode::ORDINARY_BLOCK, [&]() -> bool { return RunOrdinaryBlock(gate); }}, {OpCode::IF_BRANCH, [&]() -> bool { return RunIfBranch(gate); }}, {OpCode::SWITCH_BRANCH, [&]() -> bool { return RunSwitchBranch(gate); }}, {OpCode::IF_TRUE, [&]() -> bool { return RunIfTrue(gate); }}, {OpCode::IF_FALSE, [&]() -> bool { return RunIfFalse(gate); }}, {OpCode::SWITCH_CASE, [&]() -> bool { return RunSwitchCase(gate); }}, {OpCode::DEFAULT_CASE, [&]() -> bool { return RunDefaultCase(gate); }}, {OpCode::MERGE, [&]() -> bool { return RunMerge(gate); }}, {OpCode::LOOP_BEGIN, [&]() -> bool { return RunLoopBegin(gate); }}, {OpCode::LOOP_BACK, [&]() -> bool { return RunLoopBack(gate); }}, {OpCode::VALUE_SELECTOR, [&]() -> bool { return RunValueSelector(gate); }}, {OpCode::DEPEND_SELECTOR, [&]() -> bool { return RunDependSelector(gate); }}, {OpCode::DEPEND_RELAY, [&]() -> bool { return RunDependRelay(gate); }}, {OpCode::DEPEND_AND, [&]() -> bool { return RunDependAnd(gate); }}, {OpCode::JS_BYTECODE, [&]() -> bool { return RunJSBytecode(gate); }}, {OpCode::IF_SUCCESS, [&]() -> bool { return RunIfSuccess(gate); }}, {OpCode::IF_EXCEPTION, [&]() -> bool { return RunIfException(gate); }}, {OpCode::GET_EXCEPTION, [&]() -> bool { return RunGetException(gate); }}, {OpCode::RUNTIME_CALL, [&]() -> bool { return RunRuntimeCall(gate); }}, {OpCode::NOGC_RUNTIME_CALL, [&]() -> bool { return RunNoGCRuntimeCall(gate); }}, {OpCode::BYTECODE_CALL, [&]() -> bool { return RunBytecodeCall(gate); }}, {OpCode::BUILTINS_CALL, [&]() -> bool { return RunBuiltinsCall(gate); }}, {OpCode::BUILTINS_CALL_WITH_ARGV, [&]() -> bool { return RunBuiltinsCallWithArgv(gate); }}, {OpCode::DEBUGGER_BYTECODE_CALL, [&]() -> bool { return RunDebuggerBytecodeCall(gate); }}, {OpCode::CALL, [&]() -> bool { return RunCall(gate); }}, {OpCode::RUNTIME_CALL_WITH_ARGV, [&]() -> bool { return RunRuntimeCallWithArgv(gate); }}, {OpCode::ALLOCA, [&]() -> bool { return RunAlloca(gate); }}, {OpCode::ARG, [&]() -> bool { return RunArg(gate); }}, {OpCode::CONST_DATA, [&]() -> bool { return RunConstData(gate); }}, {OpCode::RELOCATABLE_DATA, [&]() -> bool { return RunRelocatableData(gate); }}, {OpCode::CONSTANT, [&]() -> bool { return RunConstant(gate); }}, {OpCode::ZEXT, [&]() -> bool { return RunZExtToIntOrArch(gate); }}, {OpCode::SEXT, [&]() -> bool { return RunSExtToIntOrArch(gate); }}, {OpCode::TRUNC, [&]() -> bool { return RunTruncToInt(gate); }}, {OpCode::REV, [&]() -> bool { return RunRev(gate); }}, {OpCode::ADD, [&]() -> bool { return RunAdd(gate); }}, {OpCode::SUB, [&]() -> bool { return RunSub(gate); }}, {OpCode::MUL, [&]() -> bool { return RunMul(gate); }}, {OpCode::EXP, [&]() -> bool { return RunExp(gate); }}, {OpCode::SDIV, [&]() -> bool { return RunSDiv(gate); }}, {OpCode::SMOD, [&]() -> bool { return RunSMod(gate); }}, {OpCode::UDIV, [&]() -> bool { return RunUDiv(gate); }}, {OpCode::UMOD, [&]() -> bool { return RunUMod(gate); }}, {OpCode::FDIV, [&]() -> bool { return RunFDiv(gate); }}, {OpCode::FMOD, [&]() -> bool { return RunFMod(gate); }}, {OpCode::AND, [&]() -> bool { return RunAnd(gate); }}, {OpCode::XOR, [&]() -> bool { return RunXor(gate); }}, {OpCode::OR, [&]() -> bool { return RunOr(gate); }}, {OpCode::LSL, [&]() -> bool { return RunLSL(gate); }}, {OpCode::LSR, [&]() -> bool { return RunLSR(gate); }}, {OpCode::ASR, [&]() -> bool { return RunASR(gate); }}, {OpCode::ICMP, [&]() -> bool { return RunIcmp(gate); }}, {OpCode::FCMP, [&]() -> bool { return RunFcmp(gate); }}, {OpCode::LOAD, [&]() -> bool { return RunLoad(gate); }}, {OpCode::STORE, [&]() -> bool { return RunStore(gate); }}, {OpCode::TAGGED_TO_INT64, [&]() -> bool { return RunTaggedToInt64(gate); }}, {OpCode::INT64_TO_TAGGED, [&]() -> bool { return RunInt64ToTagged(gate); }}, {OpCode::SIGNED_INT_TO_FLOAT, [&]() -> bool { return RunSignedIntToFloat(gate); }}, {OpCode::UNSIGNED_INT_TO_FLOAT, [&]() -> bool { return RunUnsignedIntToFloat(gate); }}, {OpCode::FLOAT_TO_SIGNED_INT, [&]() -> bool { return RunFloatToSignedInt(gate); }}, {OpCode::UNSIGNED_FLOAT_TO_INT, [&]() -> bool { return RunUnsignedFloatToInt(gate); }}, {OpCode::BITCAST, [&]() -> bool { return RunBitCast(gate); }}, }; return functionTable.at(acc_.GetOpCode(gate))(); } bool LatticeUpdateRuleSCCP::RunCircuitRoot([[maybe_unused]] GateRef gate) { return false; } bool LatticeUpdateRuleSCCP::RunStateEntry(GateRef gate) { return UpdateReachabilityLattice(gate, ReachabilityLattice(true)); } bool LatticeUpdateRuleSCCP::RunDependEntry(GateRef gate) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } bool LatticeUpdateRuleSCCP::RunFrameStateEntry([[maybe_unused]] GateRef gate) { return false; } bool LatticeUpdateRuleSCCP::RunReturnList([[maybe_unused]] GateRef gate) { return false; } bool LatticeUpdateRuleSCCP::RunThrowList([[maybe_unused]] GateRef gate) { return false; } bool LatticeUpdateRuleSCCP::RunConstantList([[maybe_unused]] GateRef gate) { return false; } bool LatticeUpdateRuleSCCP::RunAllocaList([[maybe_unused]] GateRef gate) { return false; } bool LatticeUpdateRuleSCCP::RunArgList([[maybe_unused]] GateRef gate) { return false; } bool LatticeUpdateRuleSCCP::RunReturn(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunReturnVoid(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunThrow(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunOrdinaryBlock(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunIfBranch(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunSwitchBranch(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunIfTrue(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); const bool predicateMayBeTrue = valueLatticeMap_(acc_.GetIn(previousState, 1)) <= ValueLattice(1); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState) * ReachabilityLattice(predicateMayBeTrue)); } bool LatticeUpdateRuleSCCP::RunIfFalse(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); const bool predicateMayBeFalse = valueLatticeMap_(acc_.GetIn(previousState, 1)) <= ValueLattice(0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState) * ReachabilityLattice(predicateMayBeFalse)); } bool LatticeUpdateRuleSCCP::RunSwitchCase(GateRef gate) { const bool valueMayMatch = valueLatticeMap_(acc_.GetIn(acc_.GetIn(gate, 0), 1)) <= ValueLattice(acc_.TryGetValue(gate)); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(acc_.GetIn(gate, 0)) * ReachabilityLattice(valueMayMatch)); } bool LatticeUpdateRuleSCCP::RunDefaultCase(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunMerge(GateRef gate) { ReachabilityLattice reachable; for (const auto &input : acc_.ConstIns(gate)) { reachable = reachable + reachabilityLatticeMap_(input); } return UpdateReachabilityLattice(gate, reachable); } bool LatticeUpdateRuleSCCP::RunLoopBegin(GateRef gate) { ReachabilityLattice reachable; for (const auto &input : acc_.ConstIns(gate)) { reachable = reachable + reachabilityLatticeMap_(input); } return UpdateReachabilityLattice(gate, reachable); } bool LatticeUpdateRuleSCCP::RunLoopBack(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunValueSelector(GateRef gate) { const auto relatedState = acc_.GetIn(gate, 0); ValueLattice value; size_t cnt = 0; for (const auto &input : acc_.ConstIns(gate)) { if (cnt > 0) { value = value.Meet(reachabilityLatticeMap_( acc_.GetIn(relatedState, cnt - 1)).Implies(valueLatticeMap_(input))); } cnt++; } return UpdateValueLattice(gate, value); } bool LatticeUpdateRuleSCCP::RunDependSelector(GateRef gate) { const auto relatedState = acc_.GetIn(gate, 0); ValueLattice value; size_t cnt = 0; for (const auto &input : acc_.ConstIns(gate)) { if (cnt > 0) { value = value.Meet(reachabilityLatticeMap_( acc_.GetIn(relatedState, cnt - 1)).Implies(valueLatticeMap_(input))); } cnt++; } if (!value.IsTop()) { value = ValueLattice(LatticeStatus::BOT); } return UpdateValueLattice(gate, value); } bool LatticeUpdateRuleSCCP::RunDependRelay(GateRef gate) { const auto relatedState = acc_.GetIn(gate, 0); ValueLattice value = valueLatticeMap_(acc_.GetIn(gate, 1)); if (!value.IsTop()) { value = ValueLattice(LatticeStatus::BOT); } return UpdateValueLattice(gate, reachabilityLatticeMap_(relatedState).Implies(value)); } bool LatticeUpdateRuleSCCP::RunDependAnd(GateRef gate) { ValueLattice value = ValueLattice(LatticeStatus::BOT); for (const auto &input : acc_.ConstIns(gate)) { if (valueLatticeMap_(input).IsTop()) { value = ValueLattice(LatticeStatus::TOP); } } return UpdateValueLattice(gate, value); } bool LatticeUpdateRuleSCCP::RunJSBytecode(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)) || UpdateValueLattice(gate, reachabilityLatticeMap_(gate).Implies(ValueLattice(LatticeStatus::BOT))); } bool LatticeUpdateRuleSCCP::RunIfSuccess(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunIfException(GateRef gate) { const auto previousState = acc_.GetIn(gate, 0); return UpdateReachabilityLattice(gate, reachabilityLatticeMap_(previousState)); } bool LatticeUpdateRuleSCCP::RunGetException(GateRef gate) { return UpdateValueLattice(gate, valueLatticeMap_(acc_.GetIn(gate, 0)).Implies( ValueLattice(LatticeStatus::BOT))); } bool LatticeUpdateRuleSCCP::RunRuntimeCall(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunNoGCRuntimeCall(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunBytecodeCall(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunDebuggerBytecodeCall(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunBuiltinsCall(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunBuiltinsCallWithArgv(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunCall(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunRuntimeCallWithArgv(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunAlloca(GateRef gate) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } bool LatticeUpdateRuleSCCP::RunArg(GateRef gate) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } bool LatticeUpdateRuleSCCP::RunMutableData(GateRef gate) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } bool LatticeUpdateRuleSCCP::RunConstData(GateRef gate) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } bool LatticeUpdateRuleSCCP::RunRelocatableData(GateRef gate) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } bool LatticeUpdateRuleSCCP::RunConstant(GateRef gate) { const auto constantValue = ValueLattice(acc_.GetConstantValue(gate)); return UpdateValueLattice(gate, constantValue); } bool LatticeUpdateRuleSCCP::RunZExtToIntOrArch(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunSExtToIntOrArch(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunTruncToInt(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunRev(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); if (operandA.IsMid()) { return UpdateValueLattice(gate, ValueLattice(operandA.GetValue().value())); } return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunAdd(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::ADD, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunSub(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::SUB, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunMul(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if ((operandA.IsMid() && operandA.GetValue().value() == 0) || (operandB.IsMid() && operandB.GetValue().value() == 0)) { return UpdateValueLattice(gate, ValueLattice(0)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::MUL, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunExp(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto fastPow = [](uint64_t a, uint64_t b) { uint64_t result = 1; uint64_t power = a; while (b) { if (b & 1) { result = result * power; } power = power * power; b >>= 1; } return result; }; return UpdateValueLattice(gate, ValueLattice(fastPow(operandA.GetValue().value(), operandB.GetValue().value()))); } bool LatticeUpdateRuleSCCP::RunSDiv(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::SDIV, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunSMod(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::SMOD, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunUDiv(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::UDIV, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunUMod(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::UMOD, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunFDiv(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::FDIV, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunFMod(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::FMOD, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunAnd(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::AND, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunXor(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::XOR, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunOr(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::OR, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunLSL(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::LSL, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunLSR(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::LSR, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunASR(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunBasicArithmetic(operandA, operandB, OpCode::ASR, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunIcmp(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); ICmpCondition cond = acc_.GetICmpCondition(gate); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunICompareArithmetic(operandA, operandB, cond, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunFcmp(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); const ValueLattice &operandB = valueLatticeMap_(acc_.GetIn(gate, 1)); FCmpCondition cond = acc_.GetFCmpCondition(gate); if (operandA.IsTop() || operandB.IsTop()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::TOP)); } if (operandA.IsBot() || operandB.IsBot()) { return UpdateValueLattice(gate, ValueLattice(LatticeStatus::BOT)); } auto machineType = acc_.GetMachineType(gate); auto value = RunFCompareArithmetic(operandA, operandB, cond, machineType); return UpdateValueLattice(gate, ValueLattice(value)); } bool LatticeUpdateRuleSCCP::RunLoad(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunStore(GateRef gate) { return LatticeUpdateRuleSCCP::RunDependAnd(gate); } bool LatticeUpdateRuleSCCP::RunTaggedToInt64(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunInt64ToTagged(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunSignedIntToFloat(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunUnsignedIntToFloat(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunFloatToSignedInt(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunUnsignedFloatToInt(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } bool LatticeUpdateRuleSCCP::RunBitCast(GateRef gate) { const ValueLattice &operandA = valueLatticeMap_(acc_.GetIn(gate, 0)); return UpdateValueLattice(gate, operandA); } void SubgraphRewriteRule::Initialize(Circuit *circuit) { circuit_ = circuit; acc_ = GateAccessor(circuit); } bool SubgraphRewriteRuleCP::Run(GateRef gate) { const std::map> functionTable = { {OpCode::ADD, [&]() -> bool { return RunAdd(gate); }}, {OpCode::SUB, [&]() -> bool { return RunSub(gate); }}, }; if (!functionTable.count(acc_.GetOpCode(gate))) { return false; } return functionTable.at(acc_.GetOpCode(gate))(); } bool SubgraphRewriteRuleCP::RunAdd(GateRef gate) { GateAccessor acc(circuit_); const auto &operandA = acc_.GetIn(gate, 0); const auto &operandB = acc_.GetIn(gate, 1); if (acc_.GetOpCode(operandA) == OpCode::CONSTANT && acc_.GetOpCode(operandB) == OpCode::CONSTANT) { acc_.DeleteIn(gate, 0); acc_.DeleteIn(gate, 1); const auto valueA = acc_.GetConstantValue(operandA); const auto valueB = acc_.GetConstantValue(operandB); acc_.SetMetaData(gate, circuit_->Constant(valueA + valueB)); return true; } return false; } bool SubgraphRewriteRuleCP::RunSub(GateRef gate) { GateAccessor acc(circuit_); const auto &operandA = acc_.GetIn(gate, 0); const auto &operandB = acc_.GetIn(gate, 1); if (acc_.GetOpCode(operandA) == OpCode::CONSTANT && acc_.GetOpCode(operandB) == OpCode::CONSTANT) { acc_.DeleteIn(gate, 0); acc_.DeleteIn(gate, 1); const auto valueA = acc_.GetConstantValue(operandA); const auto valueB = acc_.GetConstantValue(operandB); acc_.SetMetaData(gate, circuit_->Constant(valueA - valueB)); return true; } return false; } LatticeEquationsSystemSolverFramework::LatticeEquationsSystemSolverFramework(LatticeUpdateRule *latticeUpdateRule) : circuit_(nullptr), acc_(nullptr), latticeUpdateRule_(latticeUpdateRule) { } bool LatticeEquationsSystemSolverFramework::Run(Circuit *circuit, bool enableLogging) { circuit_ = circuit; acc_ = GateAccessor(circuit); auto valueLatticeMapFunction = [&](GateRef gate) -> ValueLattice & { return valueLatticesMap_[gate]; }; auto reachabilityLatticeMapFunction = [&](GateRef gate) -> ReachabilityLattice & { return reachabilityLatticesMap_[gate]; }; latticeUpdateRule_->Initialize(circuit_, valueLatticeMapFunction, reachabilityLatticeMapFunction); std::deque workList; std::set workSet; std::vector gates; circuit_->GetAllGates(gates); for (auto gate : gates) { workList.push_back(gate); workSet.insert(gate); } while (!workList.empty()) { const auto gate = workList.front(); workList.pop_front(); workSet.erase(gate); if (latticeUpdateRule_->Run(gate) || acc_.GetMetaData(gate)->IsCFGMerge()) { for (const auto &output : acc_.ConstUses(gate)) { if (!workSet.count(output)) { workList.push_back(output); // work queue workSet.insert(output); } } } } if (enableLogging) { circuit_->GetAllGates(gates); for (auto gate : gates) { if (valueLatticesMap_.count(gate)) { if (valueLatticesMap_.at(gate).IsTop()) { std::cerr << "[Top]"; } else if (valueLatticesMap_.at(gate).IsBot()) { std::cerr << "[Bot]"; } else { std::cerr << "[" << valueLatticesMap_.at(gate).GetValue().value() << "]"; } } if (reachabilityLatticesMap_.count(gate)) { if (reachabilityLatticesMap_.at(gate).IsReachable()) { std::cerr << "[Reachable]"; } else { std::cerr << "[Unreachable]"; } } std::cerr << " "; acc_.Print(gate); } } return true; } const ValueLattice &LatticeEquationsSystemSolverFramework::GetValueLattice(GateRef gate) const { return valueLatticesMap_.at(gate); } const ReachabilityLattice &LatticeEquationsSystemSolverFramework::GetReachabilityLattice(GateRef gate) const { return reachabilityLatticesMap_.at(gate); } SubGraphRewriteFramework::SubGraphRewriteFramework(SubgraphRewriteRule *subgraphRewriteRule) : circuit_(nullptr), acc_(nullptr), subgraphRewriteRule_(subgraphRewriteRule) { } bool SubGraphRewriteFramework::Run(Circuit *circuit, bool enableLogging) { circuit_ = circuit; acc_ = GateAccessor(circuit); subgraphRewriteRule_->Initialize(circuit_); std::deque workList; std::set workSet; std::vector gates; circuit_->GetAllGates(gates); for (auto gate : gates) { workList.push_back(gate); workSet.insert(gate); } while (!workList.empty()) { const auto gate = workList.front(); workList.pop_front(); workSet.erase(gate); if (subgraphRewriteRule_->Run(gate)) { for (const auto &output : acc_.ConstUses(gate)) { if (!workSet.count(output)) { workList.push_front(output); // work stack workSet.insert(output); } } } } if (enableLogging) { circuit_->GetAllGates(gates); for (auto gate : gates) { acc_.Print(gate); } } return true; } PartitionNode::PartitionNode() : gate_(Circuit::NullGate()) { } PartitionNode::PartitionNode(GateRef gate) : gate_(gate) { } std::shared_ptr PartitionNode::GetPrev() const { return prev_.lock(); } std::shared_ptr PartitionNode::GetNext() const { return next_.lock(); } std::shared_ptr PartitionNode::GetBelong() const { return belong_.lock(); } GateRef PartitionNode::GetGate() const { return gate_; } void PartitionNode::SetPrev(std::shared_ptr prev) { prev_ = prev; } void PartitionNode::SetNext(std::shared_ptr next) { next_ = next; } void PartitionNode::SetBelong(std::shared_ptr belong) { belong_ = belong; } bool PartitionNode::ExistUseByIndex(uint32_t index) const { return indexToUses_.count(index) > 0; } void PartitionNode::SetUseByIndex(uint32_t index, std::shared_ptr node) { if (!ExistUseByIndex(index)) { indexToUses_.emplace(index, std::vector>(0)); } indexToUses_[index].emplace_back(node); } void PartitionNode::GetUsesVector(std::vector>>> &uses) const { for (const auto &p : indexToUses_) { uses.emplace_back(p); } } Partition::Partition() : isTouched_(false), onWorkList_(false), size_(0) { } std::shared_ptr Partition::GetHead() const { return head_.lock(); } void Partition::SetHead(std::shared_ptr head) { head_ = head; } void Partition::SetTouched() { isTouched_ = true; } void Partition::SetNotTouched() { isTouched_ = false; } void Partition::SetOnWorkList() { onWorkList_ = true; } void Partition::SetNotOnWorkList() { onWorkList_ = false; } bool Partition::IsTouched() const { return isTouched_; } bool Partition::IsOnWorkList() const { return onWorkList_; } uint32_t Partition::GetSize() const { return size_; } void Partition::SizeUp() { ++size_; } void Partition::SizeDown() { --size_; } void Partition::AddTouchedNode(std::shared_ptr node) { touched_.emplace_back(node); } void Partition::CleanTouchedNode() { touched_.clear(); } size_t Partition::GetTouchedSize() const { return touched_.size(); } void Partition::Insert(std::shared_ptr node) { if (this->GetHead() != nullptr) { this->GetHead()->SetPrev(node); } node->SetPrev(nullptr); node->SetNext(this->GetHead()); this->SetHead(node); this->SizeUp(); } void Partition::Delete(std::shared_ptr node) { if (node->GetPrev() != nullptr) { node->GetPrev()->SetNext(node->GetNext()); } else { this->SetHead(node->GetNext()); } if (node->GetNext() != nullptr) { node->GetNext()->SetPrev(node->GetPrev()); } node->SetPrev(nullptr); node->SetNext(nullptr); this->SizeDown(); } std::shared_ptr Partition::SplitByTouched() { for (auto node : touched_) { this->Delete(node); } auto newPartition = std::make_shared(Partition()); for (auto node : touched_) { newPartition->Insert(node); node->SetBelong(newPartition); } return newPartition; } void Partition::MergeUses(std::map>> &indexToUses) const { std::vector>>> uses; for (auto defNode = this->GetHead(); defNode != nullptr; defNode = defNode->GetNext()) { uses.clear(); defNode->GetUsesVector(uses); for (const auto &use : uses) { auto index = use.first; const auto &useNodes = use.second; if (indexToUses.count(index) == 0) { indexToUses.emplace(index, std::vector>(0)); } for (auto useNode : useNodes) { indexToUses[index].emplace_back(useNode); } } } } GlobalValueNumbering::GlobalValueNumbering(Circuit *circuit, bool enableLog) : acc_(GateAccessor(circuit)), enableLog_(enableLog) { } void GlobalValueNumbering::GetPartitionNodes(std::vector> &pNodes) { std::vector gates; std::map> gateToNode; acc_.GetAllGates(gates); for (auto gate : gates) { auto node = std::make_shared(PartitionNode(gate)); pNodes.emplace_back(node); gateToNode[gate] = node; } for (auto gate : gates) { size_t count = acc_.GetNumIns(gate); auto node = gateToNode[gate]; for (size_t i = 0; i < count; ++i) { GateRef r = acc_.GetIn(gate, i); auto defNode = gateToNode[r]; defNode->SetUseByIndex(i, node); } } } void GlobalValueNumbering::SplitByOpCode(const std::vector> &nodes, std::vector> &partitions) { std::map, std::shared_ptr> opToPartition; for (auto node : nodes) { auto op = OpCode(acc_.GetOpCode(node->GetGate())); auto bit = acc_.TryGetValue(node->GetGate()); auto mt = acc_.GetMachineType(node->GetGate()); auto gt = acc_.GetGateType(node->GetGate()).Value(); auto tp = std::make_tuple(op, bit, mt, gt); if (opToPartition.count(tp) == 0) { auto p = std::make_shared(Partition()); opToPartition[tp] = p; partitions.emplace_back(p); } auto p = opToPartition[tp]; node->SetBelong(p); p->Insert(node); } } void GlobalValueNumbering::TrySplit(std::queue> &workList, std::vector> &partitions) { auto curPartition = workList.front(); workList.pop(); curPartition->SetNotOnWorkList(); std::vector> touchedPartition; std::map>> indexToUses; curPartition->MergeUses(indexToUses); for (const auto &use : indexToUses) { const auto &useNodes = use.second; for (auto useNode : useNodes) { if (!useNode->GetBelong()->IsTouched()) { useNode->GetBelong()->SetTouched(); touchedPartition.emplace_back(useNode->GetBelong()); } useNode->GetBelong()->AddTouchedNode(useNode); } for (auto partition : touchedPartition) { if (partition->GetSize() != static_cast(partition->GetTouchedSize())) { auto newPartition = partition->SplitByTouched(); if (partition->IsOnWorkList() || partition->GetSize() > newPartition->GetSize()) { workList.push(newPartition); newPartition->SetOnWorkList(); } else { workList.push(partition); partition->SetOnWorkList(); } partitions.emplace_back(newPartition); } partition->CleanTouchedNode(); } for (auto partition : touchedPartition) { partition->SetNotTouched(); } touchedPartition.clear(); } } void GlobalValueNumbering::EliminateRedundantGates(const std::vector> &partitions) { if (IsLogEnabled()) { Print(partitions); } for (auto partition : partitions) { std::map>> indexToUses; partition->MergeUses(indexToUses); auto kingNode = partition->GetHead(); for (const auto &uses : indexToUses) { auto index = uses.first; const auto &useNodes = uses.second; for (auto useNode : useNodes) { acc_.ReplaceIn(useNode->GetGate(), index, kingNode->GetGate()); } } } for (auto partition : partitions) { auto kingNode = partition->GetHead(); for (auto node = kingNode->GetNext(); node != nullptr; node = node->GetNext()) { acc_.DeleteGate(node->GetGate()); } } } void GlobalValueNumbering::Run() { std::vector> pNodes; GetPartitionNodes(pNodes); std::vector> partitions; SplitByOpCode(pNodes, partitions); std::queue> workList; for (auto p : partitions) { workList.push(p); p->SetOnWorkList(); } while (!workList.empty()) { TrySplit(workList, partitions); } EliminateRedundantGates(partitions); } void GlobalValueNumbering::Print(const std::vector> &partitions) { for (auto partition : partitions) { auto kingNode = partition->GetHead(); std::string log = "[global-value-numbering] replace ["; bool noGateReplaced = true; for (auto node = kingNode->GetNext(); node != nullptr; node = node->GetNext()) { if (noGateReplaced) { noGateReplaced = false; } else { log += ", "; } log += std::to_string(acc_.GetId(node->GetGate())); } if (noGateReplaced) { continue; } log += "] with " + GateMetaData::Str(acc_.GetOpCode(kingNode->GetGate())) + " " + std::to_string(acc_.GetId(kingNode->GetGate())); LOG_COMPILER(INFO) << log; } } } // namespace panda::ecmascript::kungfu