!4870 GlobalValueNumbering

Merge pull request !4870 from zhouyong/my-gvn
This commit is contained in:
openharmony_ci 2023-10-13 03:04:09 +00:00 committed by Gitee
commit 82159cd41e
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
17 changed files with 900 additions and 51 deletions

View File

@ -1544,6 +1544,14 @@ bool GateAccessor::MetaDataEqu(GateRef g1, GateRef g2) const
return GetMetaData(g1) == GetMetaData(g2);
}
bool GateAccessor::MetaDataValueEqu(GateRef g1, GateRef g2) const
{
const GateMetaData *g1Meta = GetMetaData(g1);
const GateMetaData *g2Meta = GetMetaData(g2);
return g1Meta->equal(*g2Meta);
}
bool GateAccessor::IsNop(GateRef g) const
{
return GetMetaData(g)->IsNop();

View File

@ -522,6 +522,7 @@ public:
bool IsProlog(GateRef g) const;
bool IsCFGMerge(GateRef g) const;
bool MetaDataEqu(GateRef g1, GateRef g2) const;
bool MetaDataValueEqu(GateRef g1, GateRef g2) const;
bool IsNop(GateRef g) const;
bool IsRoot(GateRef g) const;
bool HasOuts(GateRef gate) const;

View File

@ -40,6 +40,20 @@ public:
SetKind(GateMetaData::Kind::JSBYTECODE);
}
bool equal(const GateMetaData &other) const override
{
if (!GateMetaData::equal(other)) {
return false;
}
auto cast_other = static_cast<const JSBytecodeMetaData *>(&other);
if (opcode_ == cast_other->opcode_ &&
pcOffset_ == cast_other->pcOffset_ && type_ == cast_other->type_ &&
elementsKinds_ == cast_other->elementsKinds_) {
return true;
}
return false;
}
static const JSBytecodeMetaData* Cast(const GateMetaData* meta)
{
meta->AssertKind(GateMetaData::Kind::JSBYTECODE);

View File

@ -173,6 +173,18 @@ public:
SetKind(GateMetaData::Kind::TYPED_CALL);
}
bool equal(const GateMetaData &other) const override
{
if (!OneParameterMetaData::equal(other)) {
return false;
}
auto cast_other = static_cast<const TypedCallMetaData *>(&other);
if (noGC_ == cast_other->noGC_) {
return true;
}
return false;
}
static const TypedCallMetaData* Cast(const GateMetaData* meta)
{
meta->AssertKind(GateMetaData::Kind::TYPED_CALL);
@ -196,6 +208,19 @@ public:
SetKind(GateMetaData::Kind::TYPED_CALLTARGETCHECK_OP);
}
bool equal(const GateMetaData &other) const override
{
if (!OneParameterMetaData::equal(other)) {
return false;
}
auto cast_other =
static_cast<const TypedCallTargetCheckMetaData *>(&other);
if (checkOp_ == cast_other->checkOp_) {
return true;
}
return false;
}
static const TypedCallTargetCheckMetaData* Cast(const GateMetaData* meta)
{
meta->AssertKind(GateMetaData::Kind::TYPED_CALLTARGETCHECK_OP);
@ -219,6 +244,18 @@ public:
SetKind(GateMetaData::Kind::TYPED_BINARY_OP);
}
bool equal(const GateMetaData &other) const override
{
if (!OneParameterMetaData::equal(other)) {
return false;
}
auto cast_other = static_cast<const TypedBinaryMetaData *>(&other);
if (binOp_ == cast_other->binOp_ && type_ == cast_other->type_) {
return true;
}
return false;
}
static const TypedBinaryMetaData* Cast(const GateMetaData* meta)
{
meta->AssertKind(GateMetaData::Kind::TYPED_BINARY_OP);

View File

@ -47,6 +47,7 @@
#include "ecmascript/compiler/type_mcr_lowering.h"
#include "ecmascript/compiler/value_numbering.h"
#include "ecmascript/compiler/verifier.h"
#include "ecmascript/js_runtime_options.h"
namespace panda::ecmascript::kungfu {
class PassContext;
@ -580,11 +581,14 @@ public:
if (!passOptions->EnableTypeLowering() || !passOptions->EnableValueNumbering()) {
return false;
}
JSRuntimeOptions runtimeOption = data->GetPassContext()->GetEcmaVM()->GetJSOptions();
TimeScope timescope("ValueNumberingPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
Chunk chunk(data->GetNativeAreaAllocator());
bool enableLog = data->GetLog()->EnableMethodCIRLog();
CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk);
ValueNumbering valueNumbering(data->GetCircuit(), &visitor, &chunk);
ValueNumbering valueNumbering(data->GetCircuit(), &visitor, &chunk,
runtimeOption.IsEnableNewValueNumbering(),
runtimeOption.GetTraceValueNumbering());
visitor.AddPass(&valueNumbering);
visitor.VisitGraph();
visitor.PrintLog("value numbering");

View File

@ -134,7 +134,9 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName,
pipeline.RunPass<LaterEliminationPass>();
pipeline.RunPass<EarlyEliminationPass>();
pipeline.RunPass<LCRLoweringPass>();
pipeline.RunPass<ValueNumberingPass>();
pipeline.RunPass<SlowPathLoweringPass>();
pipeline.RunPass<ValueNumberingPass>();
pipeline.RunPass<VerifierPass>();
pipeline.RunPass<GraphLinearizerPass>();
pipeline.RunPass<LLVMIRGenPass>();

View File

@ -107,6 +107,15 @@ public:
: opcode_(opcode), flags_(flags),
statesIn_(statesIn), dependsIn_(dependsIn), valuesIn_(valuesIn) {}
virtual bool equal(const GateMetaData &other) const
{
if (opcode_ == other.opcode_ && kind_ == other.kind_ && flags_ == other.flags_ &&
statesIn_ == other.statesIn_ && dependsIn_ == other.dependsIn_ && valuesIn_ == other.valuesIn_) {
return true;
}
return false;
}
size_t GetStateCount() const
{
return statesIn_;
@ -282,6 +291,18 @@ public:
SetKind(GateMetaData::Kind::IMMUTABLE_BOOL);
}
bool equal(const GateMetaData &other) const override
{
if (!GateMetaData::equal(other)) {
return false;
}
auto cast_other = static_cast<const BoolMetaData *>(&other);
if (value_ == cast_other->value_) {
return true;
}
return false;
}
static const BoolMetaData* Cast(const GateMetaData* meta)
{
meta->AssertKind(GateMetaData::Kind::IMMUTABLE_BOOL);
@ -306,6 +327,18 @@ public:
SetKind(GateMetaData::Kind::IMMUTABLE_ONE_PARAMETER);
}
bool equal(const GateMetaData &other) const override
{
if (!GateMetaData::equal(other)) {
return false;
}
auto cast_other = static_cast<const OneParameterMetaData *>(&other);
if (value_ == cast_other->value_) {
return true;
}
return false;
}
static const OneParameterMetaData* Cast(const GateMetaData* meta)
{
ASSERT(meta->IsOneParameterKind());
@ -341,6 +374,22 @@ public:
}
SetKind(GateMetaData::Kind::MUTABLE_STRING);
}
bool equal(const GateMetaData &other) const override
{
if (!GateMetaData::equal(other)) {
return false;
}
auto cast_other = static_cast<const StringMetaData *>(&other);
if (stringData_.size() != cast_other->GetString().size()) {
return false;
}
if (strncmp(stringData_.data(), cast_other->GetString().data(), stringData_.size()) != 0) {
return false;
}
return true;
}
const ChunkVector<char> &GetString() const
{

View File

@ -101,12 +101,30 @@ host_unittest_action("LoopOptimizationTest") {
]
}
host_unittest_action("GlobalValueNumberingTest") {
module_out_path = module_output_path
sources = [
# test file
"global_value_numbering_test.cpp",
"meta_data_equal_test.cpp",
]
deps = [
"$ark_root/libpandafile:libarkfile_static",
"$js_root:libark_jsruntime_test_set",
"$js_root/ecmascript/compiler:libark_jsoptimizer_set",
sdk_libc_secshared_dep,
]
}
group("host_unittest") {
testonly = true
# deps file
deps = [
":AssemblerTestAction",
":GlobalValueNumberingTestAction",
":LoopOptimizationTestAction",
":TypedArrayLoweringTestAction",
]

View File

@ -0,0 +1,218 @@
/*
* Copyright (c) 2023 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/gate_accessor.h"
#include "ecmascript/compiler/pass.h"
#include "ecmascript/compiler/share_gate_meta_data.h"
#include "ecmascript/compiler/share_opcodes.h"
#include "ecmascript/compiler/value_numbering.h"
#include "ecmascript/compiler/verifier.h"
#include "ecmascript/compiler/ts_hcr_lowering.h"
#include "ecmascript/compiler/type_mcr_lowering.h"
#include "ecmascript/elements.h"
#include "ecmascript/mem/concurrent_marker.h"
#include "ecmascript/mem/native_area_allocator.h"
#include "ecmascript/tests/test_helper.h"
#include "gtest/gtest.h"
#include <cstddef>
#include <vector>
namespace panda::test {
class GlobalValueNumberingTests : public testing::Test {};
using ecmascript::kungfu::Circuit;
using ecmascript::kungfu::CircuitBuilder;
using ecmascript::kungfu::CombinedPassVisitor;
using ecmascript::kungfu::EcmaOpcode;
using ecmascript::kungfu::Environment;
using ecmascript::kungfu::GateAccessor;
using ecmascript::kungfu::GateRef;
using ecmascript::kungfu::PGOSampleType;
using ecmascript::kungfu::ValueNumbering;
using ecmascript::kungfu::Verifier;
HWTEST_F_L0(GlobalValueNumberingTests, AllInputsCheckedTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
auto x = builder.Arguments(1);
auto y = builder.Arguments(2);
auto z = builder.Arguments(3);
auto add1 = builder.Int64Add(x, y);
auto add2 = builder.Int64Add(x, y);
auto add3 = builder.Int64Add(x, z);
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
EXPECT_EQ(valuenumber.VisitGate(add2), add1);
EXPECT_EQ(valuenumber.VisitGate(add3), Circuit::NullGate());
}
HWTEST_F_L0(GlobalValueNumberingTests, DeadNodesTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
auto x = builder.Arguments(1);
auto y = builder.Arguments(2);
auto add1 = builder.Int64Add(x, y);
auto add2 = builder.Int64Add(x, y);
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
acc.DeleteGate(add1);
EXPECT_EQ(valuenumber.VisitGate(add2), Circuit::NullGate());
}
HWTEST_F_L0(GlobalValueNumberingTests, WontReplaceNodeWithItself)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
auto x = builder.Arguments(1);
auto y = builder.Arguments(2);
auto add1 = builder.Int64Add(x, y);
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
}
HWTEST_F_L0(GlobalValueNumberingTests, E2ESimpleAddTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
auto x = builder.Arguments(1);
auto y = builder.Arguments(2);
auto add1 = builder.Int64Add(x, y);
auto add2 = builder.Int64Add(x, y);
auto add3 = builder.Int64Add(add1, add2);
builder.Return(add3);
EXPECT_TRUE(Verifier::Run(&circuit));
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
visitor.AddPass(&valuenumber);
visitor.VisitGraph();
EXPECT_TRUE(Verifier::Run(&circuit));
EXPECT_TRUE(acc.GetValueIn(add3, 0) == acc.GetValueIn(add3, 1));
EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 1);
}
HWTEST_F_L0(GlobalValueNumberingTests, GrowStressTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
std::vector<GateRef> results;
auto x = builder.Arguments(1);
auto y = builder.Arguments(2);
for (int i = 0; i < 10000; i++) {
auto add1 = builder.Int64Add(x, y);
results.push_back(add1);
}
GateRef before = results[0];
for (int i = 1; i < 10000; i++) {
before = builder.Int64Add(before, results[i]);
}
builder.Return(before);
EXPECT_TRUE(Verifier::Run(&circuit));
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
visitor.AddPass(&valuenumber);
visitor.VisitGraph();
EXPECT_TRUE(Verifier::Run(&circuit));
EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 9999);
}
HWTEST_F_L0(GlobalValueNumberingTests, ComplexAddTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
auto x = builder.Arguments(1);
auto y = builder.Arguments(2);
auto add1 = builder.Int64Add(x, y);
auto add2 = builder.Int64Add(x, y);
auto add3 = builder.Int64Add(add1, add2);
auto add4 = builder.Int64Add(x, y);
auto add5 = builder.Int64Add(x, y);
auto add6 = builder.Int64Add(add4, add5);
auto add7 = builder.Int64Add(add3, add6);
builder.Return(add7);
EXPECT_TRUE(Verifier::Run(&circuit));
CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
visitor.AddPass(&valuenumber);
visitor.VisitGraph();
EXPECT_TRUE(Verifier::Run(&circuit));
EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 4);
}
} // namespace panda::test

View File

@ -0,0 +1,213 @@
/*
* Copyright (c) 2023 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/gate_accessor.h"
#include "ecmascript/compiler/share_opcodes.h"
#include "ecmascript/compiler/verifier.h"
#include "ecmascript/compiler/ts_hcr_lowering.h"
#include "ecmascript/compiler/type_mcr_lowering.h"
#include "ecmascript/elements.h"
#include "ecmascript/mem/concurrent_marker.h"
#include "ecmascript/mem/native_area_allocator.h"
#include "ecmascript/tests/test_helper.h"
#include "gtest/gtest.h"
#include <cstddef>
namespace panda::test {
class MetaDataEqualTests : public testing::Test {};
using ecmascript::kungfu::Circuit;
using ecmascript::kungfu::CircuitBuilder;
using ecmascript::kungfu::EcmaOpcode;
using ecmascript::kungfu::ElementsKind;
using ecmascript::kungfu::Environment;
using ecmascript::kungfu::GateAccessor;
using ecmascript::kungfu::GateMetaData;
using ecmascript::kungfu::GateType;
using ecmascript::kungfu::JSBytecodeMetaData;
using ecmascript::kungfu::MachineType;
using ecmascript::kungfu::PGOSampleType;
using ecmascript::kungfu::TypedBinOp;
using ecmascript::kungfu::TypedCallTargetCheckOp;
HWTEST_F_L0(MetaDataEqualTests, StringMetaDataEqualTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
auto stringGate1 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue());
auto stringGate2 = circuit.GetConstantStringGate(MachineType::ARCH, "test2", GateType::NJSValue());
EXPECT_FALSE(acc.MetaDataValueEqu(stringGate1, stringGate2));
auto stringGate3 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue());
EXPECT_TRUE(acc.MetaDataValueEqu(stringGate1, stringGate3));
}
HWTEST_F_L0(MetaDataEqualTests, ConstantMetaDataEqualTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
auto constantValue1 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
auto constantValue2 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
EXPECT_TRUE(acc.MetaDataValueEqu(constantValue1, constantValue2));
auto constantValue3 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
auto constantValue4 = circuit.GetConstantGate(MachineType::I64, 3, GateType::NJSValue());
EXPECT_FALSE(acc.MetaDataValueEqu(constantValue3, constantValue4));
// MetaData is equal, but Gate is not equal
auto constantValue5 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
auto constantValue6 = circuit.GetConstantGate(MachineType::I32, 2, GateType::NJSValue());
EXPECT_TRUE(acc.MetaDataValueEqu(constantValue5, constantValue6));
// MetaData is equal, but Gate is not equal
auto ConstGateNJSValue2 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
auto ConstGateUndefined =
circuit.GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::UndefinedType());
EXPECT_TRUE(acc.MetaDataValueEqu(ConstGateNJSValue2, ConstGateUndefined));
}
HWTEST_F_L0(MetaDataEqualTests, TypeErrorMetaDataEqualTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
auto constantValue1 = circuit.GetConstantGate(MachineType::I64, 2, GateType::NJSValue());
auto stringGate1 = circuit.GetConstantStringGate(MachineType::ARCH, "test1", GateType::NJSValue());
EXPECT_FALSE(acc.MetaDataValueEqu(constantValue1, stringGate1));
EXPECT_FALSE(acc.MetaDataValueEqu(stringGate1, constantValue1));
}
HWTEST_F_L0(MetaDataEqualTests, HCRMetaDataEqualTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
// JSBytecodeMetaData
auto meta = circuit.JSBytecode(0, EcmaOpcode::JEQZ_IMM8, 0, true, false);
auto gate =
circuit.NewGate(meta, MachineType::I64, {Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
auto meta2 = circuit.JSBytecode(0, EcmaOpcode::JEQZ_IMM8, 0, true, false);
auto gate2 =
circuit.NewGate(meta2, MachineType::I64, {Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2));
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta))->SetElementsKind(ElementsKind::NUMBER);
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta2))->SetElementsKind(ElementsKind::NUMBER);
EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2));
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta))->SetType(PGOSampleType::CreateProfileType(0, 0));
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta2))->SetType(PGOSampleType::CreateProfileType(0, 0));
EXPECT_TRUE(acc.MetaDataValueEqu(gate, gate2));
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta))->SetType(PGOSampleType::CreateProfileType(0, 0));
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta2))->SetType(PGOSampleType::CreateProfileType(0, 1));
EXPECT_FALSE(acc.MetaDataValueEqu(gate, gate2));
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta))->SetElementsKind(ElementsKind::NUMBER);
static_cast<JSBytecodeMetaData *>(const_cast<GateMetaData *>(meta2))->SetElementsKind(ElementsKind::HOLE_NUMBER);
EXPECT_FALSE(acc.MetaDataValueEqu(gate, gate2));
}
HWTEST_F_L0(MetaDataEqualTests, MCRMetaDataEqualTest)
{
// construct a circuit
ecmascript::NativeAreaAllocator allocator;
Circuit circuit(&allocator);
ecmascript::Chunk chunk(&allocator);
GateAccessor acc(&circuit);
CircuitBuilder builder(&circuit);
Environment env(0, &builder);
builder.SetEnvironment(&env);
// TypedCallMetaData
auto callGate =
circuit.NewGate(circuit.TypedCall(0, 0, true), MachineType::I64,
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
auto callGate2 =
circuit.NewGate(circuit.TypedCall(0, 0, true), MachineType::I64,
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
EXPECT_TRUE(acc.MetaDataValueEqu(callGate, callGate2));
EXPECT_TRUE(acc.MetaDataValueEqu(callGate2, callGate));
// TypedCallTargetCheckMetaData
auto callGate3 =
circuit.NewGate(circuit.TypedCallTargetCheckOp(0, 0, TypedCallTargetCheckOp::JSCALLTHIS_FAST), MachineType::I64,
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
auto callGate4 =
circuit.NewGate(circuit.TypedCallTargetCheckOp(0, 0, TypedCallTargetCheckOp::JSCALLTHIS_FAST), MachineType::I64,
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
EXPECT_TRUE(acc.MetaDataValueEqu(callGate3, callGate4));
EXPECT_TRUE(acc.MetaDataValueEqu(callGate4, callGate3));
// TypedBinaryMetaData
auto callGate5 = circuit.NewGate(
circuit.TypedBinaryOp(0, TypedBinOp::TYPED_ADD, PGOSampleType::CreateProfileType(0, 1)), MachineType::I64,
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
// TypedBinaryMetaData
auto callGate6 = circuit.NewGate(
circuit.TypedBinaryOp(0, TypedBinOp::TYPED_ADD, PGOSampleType::CreateProfileType(0, 1)), MachineType::I64,
{Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
EXPECT_TRUE(acc.MetaDataValueEqu(callGate5, callGate6));
EXPECT_TRUE(acc.MetaDataValueEqu(callGate6, callGate5));
}
} // namespace panda::test

View File

@ -13,71 +13,169 @@
* limitations under the License.
*/
#include "ecmascript/compiler/value_numbering.h"
#include <cstddef>
namespace panda::ecmascript::kungfu {
GateRef ValueNumbering::VisitGate(GateRef gate)
{
auto opcode = acc_.GetOpCode(gate);
if (opcode != OpCode::CONVERT) {
return Circuit::NullGate();
}
size_t hash = HashCode(gate);
if (entries_.size() == 0) {
entries_.resize(CACHE_LENGTH, Circuit::NullGate());
SetEntry(hash, gate);
auto opcode = acc_.GetOpCode(gate);
if (opcode != OpCode::CONVERT && !useNewGVN_) {
return Circuit::NullGate();
}
GateRef replacement = GetEntry(hash);
if (replacement != Circuit::NullGate() &&
CheckReplacement(gate, replacement)) {
return replacement;
if (entries_ == nullptr) {
InitEntries(entriesLength_);
SetEntry(hash, gate);
entriesSize_++;
return Circuit::NullGate();
}
ASSERT(entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD < entriesLength_);
const size_t mask = entriesLength_ - 1;
size_t dead = entriesLength_;
for (size_t i = hash & mask;; i = (i + 1) & mask) {
GateRef entry = entries_[i];
if (entry == Circuit::NullGate()) {
if (dead != entriesLength_) {
entries_[dead] = gate;
} else {
// Have to insert a new entry.
entries_[i] = gate;
entriesSize_++;
// Resize to keep load factor below 80%
EnsureCapacity();
}
ASSERT(entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD < entriesLength_);
return Circuit::NullGate();
}
if (entry == gate) {
return Circuit::NullGate();
}
// Skip dead entries, but remember their indices so we can reuse them.
if (acc_.IsNop(entry)) {
dead = i;
continue;
}
if (CheckReplacement(gate, entry)) {
optimizedGateCount++;
if (enableLog_) {
LOG_COMPILER(INFO) << "Found a replaceable node, before -> after";
acc_.Print(gate);
acc_.Print(entry);
}
return entry;
}
}
SetEntry(hash, gate);
return Circuit::NullGate();
}
void ValueNumbering::EnsureCapacity()
{
if (entriesSize_ + entriesSize_ / LOAD_FACTOR_THRESHOLD >= entriesLength_) {
Grow();
}
}
void ValueNumbering::Grow()
{
GateRef *const oldEntries = entries_;
size_t const oldSize = entriesLength_;
entriesLength_ *= 2;
InitEntries(entriesLength_);
size_t const mask = entriesLength_ - 1;
for (size_t i = 0; i < oldSize; i++) {
GateRef oldEnrty = oldEntries[i];
if (oldEnrty == Circuit::NullGate() || acc_.IsNop(oldEnrty)) {
continue;
}
for (size_t j = HashCode(oldEnrty) & mask;; j = (j + 1) & mask) {
GateRef entry = entries_[j];
if (entry == oldEnrty) {
break;
}
if (entry == Circuit::NullGate()) {
entries_[j] = oldEnrty;
entriesSize_++;
break;
}
}
}
chunk_->Free(oldEntries);
if (enableLog_) {
LOG_COMPILER(INFO) << "Grow happend";
}
}
void ValueNumbering::InitEntries(size_t initSize)
{
entries_ = chunk_->NewArray<int32_t>(initSize);
for (size_t i = 0; i < initSize; i++) {
entries_[i] = Circuit::NullGate();
}
entriesSize_ = 0;
}
size_t HashCombine(size_t seed, size_t value)
{
// In the meantime, we're not considering 32-bit systems
assert(sizeof(void *) == 8);
const uint64_t m = uint64_t{0xC6A4A7935BD1E995};
const uint32_t r = 47;
value *= m;
value ^= value >> r;
value *= m;
seed ^= value;
seed *= m;
return seed;
}
size_t ValueNumbering::HashCode(GateRef gate)
{
size_t hash = static_cast<size_t>(acc_.GetOpCode(gate));
hash ^= acc_.TryGetValue(gate);
size_t valueCount = acc_.GetNumValueIn(gate);
size_t hash = HashCombine(static_cast<size_t>(acc_.GetOpCode(gate)), valueCount);
for (size_t i = 0; i < valueCount; i++) {
GateRef input = acc_.GetValueIn(gate);
GateRef input = acc_.GetValueIn(gate, i);
auto id = acc_.GetId(input);
hash ^= id;
hash = HashCombine(hash, id);
}
return hash % CACHE_LENGTH;
return hash;
}
// Gates are considered replaceable only when their values are identical
bool ValueNumbering::CheckReplacement(GateRef lhs, GateRef rhs)
{
if (!acc_.MetaDataEqu(lhs, rhs)) {
if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs)) {
if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs))
return false;
size_t valueCount1 = acc_.GetNumIns(lhs);
size_t valueCount2 = acc_.GetNumIns(rhs);
if (valueCount1 != valueCount2)
return false;
for (size_t i = 0; i < valueCount1; i++) {
if (acc_.GetIn(lhs, i) != acc_.GetIn(rhs, i)) {
return false;
}
}
size_t valueCount = acc_.GetNumValueIn(lhs);
for (size_t i = 0; i < valueCount; i++) {
if (acc_.GetValueIn(lhs, i) != acc_.GetValueIn(rhs, i)) {
return false;
}
if (acc_.GetGateType(lhs) != acc_.GetGateType(rhs)) {
return false;
}
if (acc_.HasFrameState(lhs)) {
ASSERT(acc_.HasFrameState(rhs));
if (acc_.GetFrameState(lhs) != acc_.GetFrameState(rhs)) {
return false;
}
if (acc_.GetMachineType(lhs) != acc_.GetMachineType(rhs)) {
return false;
}
auto opcode = acc_.GetOpCode(lhs);
if (opcode == OpCode::CONVERT) {
if (acc_.GetSrcType(lhs) != acc_.GetSrcType(rhs)) {
return false;
}
if (acc_.GetDstType(lhs) != acc_.GetDstType(rhs)) {
return false;
}
if (!acc_.MetaDataValueEqu(lhs, rhs)) {
return false;
}
return true;
}
} // namespace panda::ecmascript::kungfu
} // namespace panda::ecmascript::kungfu

View File

@ -24,29 +24,37 @@
namespace panda::ecmascript::kungfu {
class ValueNumbering : public PassVisitor {
public:
ValueNumbering(Circuit *circuit, RPOVisitor *visitor, Chunk* chunk)
: PassVisitor(circuit, chunk, visitor), entries_(chunk) {}
ValueNumbering(Circuit *circuit, RPOVisitor *visitor, Chunk* chunk, bool useNewGVN, bool enableLog)
: PassVisitor(circuit, chunk, visitor), entries_(nullptr), useNewGVN_(useNewGVN),
enableLog_(enableLog) {}
~ValueNumbering() = default;
GateRef VisitGate(GateRef gate) override;
bool CheckReplacement(GateRef lhs, GateRef rhs);
private:
size_t HashCode(GateRef gate);
GateRef GetEntry(size_t hash)
int GetoptimizedGateCount()
{
ASSERT(hash < entries_.size());
return entries_[hash];
return optimizedGateCount;
}
private:
void Grow();
void EnsureCapacity();
void InitEntries(size_t initSize);
size_t HashCode(GateRef gate);
void SetEntry(size_t hash, GateRef gate)
{
ASSERT(hash < entries_.size());
entries_[hash] = gate;
entries_[hash & (entriesLength_ - 1)] = gate;
}
static const uint32_t CACHE_LENGTH_BIT = 8;
static const uint32_t CACHE_LENGTH = (1U << CACHE_LENGTH_BIT);
ChunkVector<GateRef> entries_;
const uint8_t LOAD_FACTOR_THRESHOLD = 4;
uint32_t entriesLength_ = (1U << CACHE_LENGTH_BIT);
uint32_t entriesSize_ = 0;
GateRef* entries_;
bool useNewGVN_;
int optimizedGateCount = 0;
bool enableLog_ = false;
};
} // panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_VALUE_NUMBERING_H

View File

@ -69,6 +69,7 @@ const std::string PUBLIC_API HELP_OPTION_MSG =
"--compiler-trace-bc: Enable tracing bytecode for aot runtime. Default: 'false'\n"
"--compiler-trace-deopt: Enable tracing deopt for aot runtime. Default: 'false'\n"
"--compiler-trace-inline: Enable tracing inline function for aot runtime. Default: 'false'\n"
"--compiler-trace-value-numbering: Enable tracing value numbering for aot runtime. Default: 'false'\n"
"--compiler-max-inline-bytecodes Set max bytecodes count which aot function can be inlined. Default: '25'\n"
"--compiler-deopt-threshold: Set max count which aot function can occur deoptimization. Default: '10'\n"
"--compiler-stress-deopt: Enable stress deopt for aot compiler. Default: 'false'\n"
@ -173,6 +174,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
{"compiler-trace-bc", required_argument, nullptr, OPTION_COMPILER_TRACE_BC},
{"compiler-trace-deopt", required_argument, nullptr, OPTION_COMPILER_TRACE_DEOPT},
{"compiler-trace-inline", required_argument, nullptr, OPTION_COMPILER_TRACE_INLINE},
{"compiler-trace-value-numbering", required_argument, nullptr, OPTION_COMPILER_TRACE_VALUE_NUMBERING},
{"compiler-max-inline-bytecodes", required_argument, nullptr, OPTION_COMPILER_MAX_INLINE_BYTECODES},
{"compiler-deopt-threshold", required_argument, nullptr, OPTION_COMPILER_DEOPT_THRESHOLD},
{"compiler-stress-deopt", required_argument, nullptr, OPTION_COMPILER_STRESS_DEOPT},
@ -186,6 +188,7 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
{"compiler-opt-early-elimination", required_argument, nullptr, OPTION_COMPILER_OPT_EARLY_ELIMINATION},
{"compiler-opt-later-elimination", required_argument, nullptr, OPTION_COMPILER_OPT_LATER_ELIMINATION},
{"compiler-opt-value-numbering", required_argument, nullptr, OPTION_COMPILER_OPT_VALUE_NUMBERING},
{"compiler-opt-new-value-numbering", required_argument, nullptr, OPTION_COMPILER_OPT_NEW_VALUE_NUMBERING},
{"compiler-opt-inlining", required_argument, nullptr, OPTION_COMPILER_OPT_INLINING},
{"compiler-opt-pgotype", required_argument, nullptr, OPTION_COMPILER_OPT_PGOTYPE},
{"compiler-opt-track-field", required_argument, nullptr, OPTION_COMPILER_OPT_TRACK_FIELD},
@ -373,6 +376,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
return false;
}
break;
case OPTION_COMPILER_TRACE_VALUE_NUMBERING:
ret = ParseBoolParam(&argBool);
if (ret) {
SetTraceValueNumbering(argBool);
} else {
return false;
}
break;
case OPTION_COMPILER_MAX_INLINE_BYTECODES:
ret = ParseUint32Param("max-inline-bytecodes", &argUint32);
if (ret) {
@ -670,6 +681,14 @@ bool JSRuntimeOptions::ParseCommand(const int argc, const char **argv)
return false;
}
break;
case OPTION_COMPILER_OPT_NEW_VALUE_NUMBERING:
ret = ParseBoolParam(&argBool);
if (ret) {
SetEnableNewValueNumbering(argBool);
} else {
return false;
}
break;
case OPTION_COMPILER_OPT_INLINING:
ret = ParseBoolParam(&argBool);
if (ret) {

View File

@ -98,6 +98,7 @@ enum CommandValues {
OPTION_COMPILER_TRACE_BC,
OPTION_COMPILER_TRACE_DEOPT,
OPTION_COMPILER_TRACE_INLINE,
OPTION_COMPILER_TRACE_VALUE_NUMBERING,
OPTION_COMPILER_MAX_INLINE_BYTECODES,
OPTION_COMPILER_DEOPT_THRESHOLD,
OPTION_COMPILER_STRESS_DEOPT,
@ -117,6 +118,7 @@ enum CommandValues {
OPTION_COMPILER_OPT_EARLY_ELIMINATION,
OPTION_COMPILER_OPT_LATER_ELIMINATION,
OPTION_COMPILER_OPT_VALUE_NUMBERING,
OPTION_COMPILER_OPT_NEW_VALUE_NUMBERING,
OPTION_COMPILER_OPT_INLINING,
OPTION_COMPILER_OPT_PGOTYPE,
OPTION_COMPILER_OPT_TRACK_FIELD,
@ -992,6 +994,16 @@ public:
return enableValueNumbering_;
}
void SetEnableNewValueNumbering(bool value)
{
enableNewValueNumbering_ = value;
}
bool IsEnableNewValueNumbering() const
{
return enableNewValueNumbering_;
}
void SetEnableOptInlining(bool value)
{
enableOptInlining_ = value;
@ -1127,6 +1139,16 @@ public:
return traceInline_;
}
void SetTraceValueNumbering(bool value)
{
traceValueNumbering_ = value;
}
bool GetTraceValueNumbering() const
{
return traceValueNumbering_;
}
void SetMaxInlineBytecodes(size_t value)
{
maxInlineBytecodes_ = value;
@ -1316,6 +1338,7 @@ private:
bool enableEarlyElimination_ {true};
bool enableLaterElimination_ {true};
bool enableValueNumbering_ {true};
bool enableNewValueNumbering_ {true};
bool enableOptInlining_ {true};
bool enableOptPGOType_ {true};
bool enableGlobalTypeInfer_ {false};
@ -1337,6 +1360,7 @@ private:
std::string compilerSelectMethods_ {""};
std::string compilerSkipMethods_ {""};
bool traceInline_ {false};
bool traceValueNumbering_{false};
size_t maxInlineBytecodes_ {45};
std::string targetCompilerMode_ {""};
std::string hapPath_ {""};

View File

@ -0,0 +1,18 @@
# Copyright (c) 2023 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.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("global_value_numbering_ts") {
deps = []
}

View File

@ -0,0 +1,21 @@
# Copyright (c) 2023 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.
Hello
Hello
Hello
Hello
1
4
-2
6

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2023 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.
*/
declare function print(n:string):string;
declare function print(n:number):string;
// CMP
//[compiler] Found a replaceable node, before -> after
//[compiler] {"id":212, "op":"ICMP", "MType":"I1, bitfield=0xa, type=NJS_VALUE-GT(M=0, L=0), stamp=10, mark=2, ","in":[[], [], [55, 205], [], []], "out":[213]},
//[compiler] {"id":209, "op":"ICMP", "MType":"I1, bitfield=0xa, type=NJS_VALUE-GT(M=0, L=0), stamp=10, mark=3, ","in":[[], [], [55, 205], [], []], "out":[210]},
//[compiler] {"id":55, "op":"VALUE_SELECTOR", "MType":"I32, bitfield=0x0, type=NJS_VALUE-GT(M=0, L=0), stamp=9, mark=3, ","in":[[16], [], [227, 217], [], []], "out":[215, 212, 209, 206, 102, 88, 94, 97, 99, 85, 83, 80, 71]},
//[compiler] {"id":205, "op":"CONSTANT", "MType":"I32, bitfield=0x1, type=NJS_VALUE-GT(M=0, L=0), stamp=9, mark=3, ","in":[[], [], [], [], []], "out":[227, 224, 221, 215, 212, 209]},
for (var i:number = 0; i < 10; i++) {
if (i <= 1) {
print("Hello");
}
if (i <= 1) {
print("Hello");
}
}
// TypedOperator
//[compiler] Found a replaceable node, before -> after
//[compiler] {"id":669, "op":"FDIV", "MType":"F64, bitfield=0x0, type=NJS_VALUE-GT(M=0, L=0), stamp=10, mark=2, ","in":[[], [], [608, 610], [], []], "out":[670]},
//[compiler] {"id":664, "op":"FDIV", "MType":"F64, bitfield=0x0, type=NJS_VALUE-GT(M=0, L=0), stamp=10, mark=3, ","in":[[], [], [608, 610], [], []], "out":[665]},
function div(a: number, b: number): number {
let sum = 0;
if (a > 0) {
let k = a / b;
sum += k;
}
if (b > 0) {
let k = a / b;
sum += k;
}
return sum;
}
print(div(1,2));
function mul(a: number, b: number): number {
let sum = 0;
if (a > 0) {
let k = a * b;
sum += k;
}
if (b > 0) {
let k = a * b;
sum += k;
}
return sum;
}
print(mul(1,2));
function sub(a: number, b: number): number {
let sum = 0;
if (a > 0) {
let k = a - b;
sum += k;
}
if (b > 0) {
let k = a - b;
sum += k;
}
return sum;
}
print(sub(1,2));
function add(a: number, b: number): number {
let sum = 0;
if (a > 0) {
let k = a + b;
sum += k;
}
if (b > 0) {
let k = a + b;
sum += k;
}
return sum;
}
print(add(1,2));