1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#include "ecmascript/compiler/gate_accessor.h"
16#include "ecmascript/compiler/pass.h"
17#include "ecmascript/compiler/share_gate_meta_data.h"
18#include "ecmascript/compiler/share_opcodes.h"
19#include "ecmascript/compiler/value_numbering.h"
20#include "ecmascript/compiler/verifier.h"
21#include "ecmascript/compiler/typed_bytecode_lowering.h"
22#include "ecmascript/compiler/typed_hcr_lowering.h"
23#include "ecmascript/elements.h"
24#include "ecmascript/mem/concurrent_marker.h"
25#include "ecmascript/mem/native_area_allocator.h"
26#include "ecmascript/tests/test_helper.h"
27#include "gtest/gtest.h"
28#include <cstddef>
29#include <vector>
30
31namespace panda::test {
32class GlobalValueNumberingTests : public testing::Test {};
33
34using ecmascript::kungfu::Circuit;
35using ecmascript::kungfu::CircuitBuilder;
36using ecmascript::kungfu::CombinedPassVisitor;
37using ecmascript::kungfu::EcmaOpcode;
38using ecmascript::kungfu::Environment;
39using ecmascript::kungfu::GateAccessor;
40using ecmascript::kungfu::GateRef;
41using ecmascript::kungfu::PGOSampleType;
42using ecmascript::kungfu::ValueNumbering;
43using ecmascript::kungfu::Verifier;
44
45
46HWTEST_F_L0(GlobalValueNumberingTests, AllInputsCheckedTest)
47{
48    // construct a circuit
49    ecmascript::NativeAreaAllocator allocator;
50    Circuit circuit(&allocator);
51    ecmascript::Chunk chunk(&allocator);
52    GateAccessor acc(&circuit);
53    CircuitBuilder builder(&circuit);
54    Environment env(0, &builder);
55    builder.SetEnvironment(&env);
56    auto x = builder.Arguments(1);
57    auto y = builder.Arguments(2);
58    auto z = builder.Arguments(3);
59    auto add1 = builder.Int64Add(x, y);
60    auto add2 = builder.Int64Add(x, y);
61    auto add3 = builder.Int64Add(x, z);
62
63    CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
64    ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
65
66    EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
67    EXPECT_EQ(valuenumber.VisitGate(add2), add1);
68    EXPECT_EQ(valuenumber.VisitGate(add3), Circuit::NullGate());
69}
70
71
72HWTEST_F_L0(GlobalValueNumberingTests, DeadNodesTest)
73{
74    // construct a circuit
75    ecmascript::NativeAreaAllocator allocator;
76    Circuit circuit(&allocator);
77    ecmascript::Chunk chunk(&allocator);
78    GateAccessor acc(&circuit);
79    CircuitBuilder builder(&circuit);
80    Environment env(0, &builder);
81    builder.SetEnvironment(&env);
82    auto x = builder.Arguments(1);
83    auto y = builder.Arguments(2);
84
85    auto add1 = builder.Int64Add(x, y);
86    auto add2 = builder.Int64Add(x, y);
87
88    CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
89    ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
90
91    EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
92    acc.DeleteGate(add1);
93    EXPECT_EQ(valuenumber.VisitGate(add2), Circuit::NullGate());
94}
95
96HWTEST_F_L0(GlobalValueNumberingTests, WontReplaceNodeWithItself)
97{
98    // construct a circuit
99    ecmascript::NativeAreaAllocator allocator;
100    Circuit circuit(&allocator);
101    ecmascript::Chunk chunk(&allocator);
102    GateAccessor acc(&circuit);
103    CircuitBuilder builder(&circuit);
104    Environment env(0, &builder);
105    builder.SetEnvironment(&env);
106    auto x = builder.Arguments(1);
107    auto y = builder.Arguments(2);
108
109    auto add1 = builder.Int64Add(x, y);
110
111    CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
112    ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
113
114    EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
115    EXPECT_EQ(valuenumber.VisitGate(add1), Circuit::NullGate());
116}
117
118
119HWTEST_F_L0(GlobalValueNumberingTests, E2ESimpleAddTest)
120{
121    // construct a circuit
122    ecmascript::NativeAreaAllocator allocator;
123    Circuit circuit(&allocator);
124    ecmascript::Chunk chunk(&allocator);
125    GateAccessor acc(&circuit);
126    CircuitBuilder builder(&circuit);
127    Environment env(0, &builder);
128    builder.SetEnvironment(&env);
129
130    auto x = builder.Arguments(1);
131    auto y = builder.Arguments(2);
132
133
134    auto add1 = builder.Int64Add(x, y);
135    auto add2 = builder.Int64Add(x, y);
136    auto add3 = builder.Int64Add(add1, add2);
137
138    builder.Return(add3);
139    EXPECT_TRUE(Verifier::Run(&circuit));
140    CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
141    ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
142    visitor.AddPass(&valuenumber);
143    visitor.VisitGraph();
144    EXPECT_TRUE(Verifier::Run(&circuit));
145    EXPECT_TRUE(acc.GetValueIn(add3, 0) == acc.GetValueIn(add3, 1));
146    EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 1);
147}
148
149HWTEST_F_L0(GlobalValueNumberingTests, GrowStressTest)
150{
151    // construct a circuit
152    ecmascript::NativeAreaAllocator allocator;
153    Circuit circuit(&allocator);
154    ecmascript::Chunk chunk(&allocator);
155    GateAccessor acc(&circuit);
156    CircuitBuilder builder(&circuit);
157    Environment env(0, &builder);
158    builder.SetEnvironment(&env);
159
160    std::vector<GateRef> results;
161    auto x = builder.Arguments(1);
162    auto y = builder.Arguments(2);
163
164    for (int i = 0; i < 10000; i++) {
165        auto add1 = builder.Int64Add(x, y);
166        results.push_back(add1);
167    }
168
169    GateRef before = results[0];
170    for (int i = 1; i < 10000; i++) {
171        before = builder.Int64Add(before, results[i]);
172    }
173
174    builder.Return(before);
175    EXPECT_TRUE(Verifier::Run(&circuit));
176    CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
177    ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
178    visitor.AddPass(&valuenumber);
179    visitor.VisitGraph();
180    EXPECT_TRUE(Verifier::Run(&circuit));
181    EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 9999);
182}
183
184
185HWTEST_F_L0(GlobalValueNumberingTests, ComplexAddTest)
186{
187    // construct a circuit
188    ecmascript::NativeAreaAllocator allocator;
189    Circuit circuit(&allocator);
190    ecmascript::Chunk chunk(&allocator);
191    GateAccessor acc(&circuit);
192    CircuitBuilder builder(&circuit);
193    Environment env(0, &builder);
194    builder.SetEnvironment(&env);
195
196    auto x = builder.Arguments(1);
197    auto y = builder.Arguments(2);
198
199    auto add1 = builder.Int64Add(x, y);
200    auto add2 = builder.Int64Add(x, y);
201    auto add3 = builder.Int64Add(add1, add2);
202
203    auto add4 = builder.Int64Add(x, y);
204    auto add5 = builder.Int64Add(x, y);
205    auto add6 = builder.Int64Add(add4, add5);
206
207    auto add7 = builder.Int64Add(add3, add6);
208    builder.Return(add7);
209    EXPECT_TRUE(Verifier::Run(&circuit));
210    CombinedPassVisitor visitor(&circuit, false, "ValueNumbering", &chunk);
211    ValueNumbering valuenumber(&circuit, &visitor, &chunk, true, false);
212    visitor.AddPass(&valuenumber);
213    visitor.VisitGraph();
214    EXPECT_TRUE(Verifier::Run(&circuit));
215    EXPECT_EQ(valuenumber.GetoptimizedGateCount(), 4);
216}
217
218} // namespace panda::test