• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/bytecodes.h"
16 #include "ecmascript/compiler/circuit_builder.h"
17 #include "ecmascript/compiler/early_elimination.h"
18 #include "ecmascript/compiler/gate_accessor.h"
19 #include "ecmascript/compiler/graph_editor.h"
20 #include "ecmascript/compiler/loop_analysis.h"
21 #include "ecmascript/compiler/loop_peeling.h"
22 #include "ecmascript/compiler/pass.h"
23 #include "ecmascript/compiler/stub_builder.h"
24 #include "ecmascript/compiler/type.h"
25 #include "ecmascript/compiler/variable_type.h"
26 #include "ecmascript/compiler/verifier.h"
27 #include "ecmascript/compiler/typed_bytecode_lowering.h"
28 #include "ecmascript/compiler/typed_hcr_lowering.h"
29 #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h"
30 #include "ecmascript/mem/chunk.h"
31 #include "ecmascript/mem/native_area_allocator.h"
32 #include "ecmascript/tests/test_helper.h"
33 #include "gtest/gtest-death-test.h"
34 #include "gtest/gtest.h"
35 
36 namespace panda::test {
37 class LoopOptimizationTest : public testing::Test {
38 };
39 using ecmascript::kungfu::Circuit;
40 using ecmascript::kungfu::GateAccessor;
41 using ecmascript::kungfu::GateType;
42 using ecmascript::kungfu::MachineType;
43 using ecmascript::kungfu::CircuitBuilder;
44 using ecmascript::kungfu::Label;
45 using ecmascript::kungfu::OpCode;
46 using ecmascript::kungfu::GateRef;
47 using ecmascript::kungfu::Variable;
48 using ecmascript::kungfu::VariableType;
49 using ecmascript::kungfu::Verifier;
50 using ecmascript::kungfu::LoopAnalysis;
51 using ecmascript::kungfu::Environment;
52 using ecmascript::kungfu::LoopPeeling;
53 using ecmascript::kungfu::EarlyElimination;
54 using ecmascript::kungfu::CombinedPassVisitor;
55 using ecmascript::kungfu::TypedBinOp;
56 using ecmascript::kungfu::PGOTypeRef;
57 using ecmascript::kungfu::PGOSampleType;
58 using ecmascript::kungfu::GraphLinearizer;
HWTEST_F_L0(LoopOptimizationTest,LoopInt32TypedArraySumOptimizationTest)59 HWTEST_F_L0(LoopOptimizationTest, LoopInt32TypedArraySumOptimizationTest)
60 {
61     // construct a circuit
62     ecmascript::NativeAreaAllocator allocator;
63     Circuit circuit(&allocator);
64     ecmascript::Chunk chunk(&allocator);
65     GateAccessor acc(&circuit);
66     CircuitBuilder builder(&circuit);
67     Environment env(0, &builder);
68     // after number speculative runner
69     builder.SetEnvironment(&env);
70     auto array = builder.Arguments(1);
71 
72     DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
73     DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
74 
75     Label loopHead(&env);
76     Label loopBody(&env);
77     Label loopExit(&env);
78     builder.Jump(&loopHead);
79     builder.LoopBegin(&loopHead);
80     auto loopBegin = builder.GetState();
81     EXPECT_TRUE(acc.IsLoopHead(loopBegin));
82     auto loadLength = builder.LoadTypedArrayLength(array, GateType::AnyType());
83     acc.SetMachineType(loadLength, MachineType::I32);
84     acc.SetGateType(loadLength, GateType::NJSValue());
85     auto cmp = builder.TypedBinaryOp<TypedBinOp::TYPED_ADD>(
86         *index, loadLength, GateType::IntType(), GateType::IntType(),
87         GateType::NJSValue(), PGOTypeRef::NoneType());
88     acc.SetMachineType(cmp, MachineType::I1);
89     builder.Branch(cmp, &loopBody, &loopExit);
90     builder.Bind(&loopBody);
91     auto loadElement = builder.LoadElement<ecmascript::kungfu::TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(array, *index);
92     acc.SetMachineType(loadElement, MachineType::I32);
93     acc.SetGateType(loadElement, GateType::NJSValue());
94     auto sumAdd = builder.TypedBinaryOp<TypedBinOp::TYPED_ADD>(
95         *sum, loadElement, GateType::IntType(), GateType::IntType(),
96         GateType::NJSValue(), PGOTypeRef::NoneType());
97     acc.SetMachineType(sumAdd, MachineType::I32);
98     sum = sumAdd;
99     auto indexInc = builder.TypedBinaryOp<TypedBinOp::TYPED_ADD>(
100         *index, builder.Int32(1), GateType::IntType(), GateType::IntType(),
101         GateType::NJSValue(), PGOTypeRef::NoneType());
102     acc.SetMachineType(indexInc, MachineType::I32);
103     index = indexInc;
104     builder.LoopEnd(&loopHead);
105     builder.Bind(&loopExit);
106     builder.LoopExit({&sum});
107     auto convert = builder.ConvertInt32ToTaggedInt(*sum);
108     builder.Return(convert);
109     LoopAnalysis analysis(nullptr, &circuit, &chunk);
110     ecmascript::kungfu::LoopInfo beforeOpt(&chunk, loopBegin);
111     ecmascript::kungfu::LoopInfo afterOpt(&chunk, loopBegin);
112     analysis.CollectLoopBody(&beforeOpt);
113     bool foundLengthBeforeOpt = false;
114     for (auto gate : beforeOpt.loopBodys) {
115         if (acc.GetOpCode(gate) == OpCode::LOAD_TYPED_ARRAY_LENGTH) {
116             foundLengthBeforeOpt = true;
117         }
118     }
119     EXPECT_TRUE(foundLengthBeforeOpt);
120     analysis.PrintLoop(&beforeOpt);
121     LoopPeeling(nullptr, &circuit, false, "LoopInt32TypedArraySumOptimizationTest", &chunk, &beforeOpt).Peel();
122     EXPECT_TRUE(Verifier::Run(&circuit));
123     CombinedPassVisitor visitor(&circuit, false, "LoopInt32TypedArraySumOptimizationTest", &chunk);
124     EarlyElimination earlyElimination(&circuit, &visitor, &chunk);
125     visitor.AddPass(&earlyElimination);
126     visitor.VisitGraph();
127     analysis.CollectLoopBody(&afterOpt);
128     EXPECT_TRUE(Verifier::Run(&circuit));
129     EXPECT_TRUE(beforeOpt.loopBodys.size() > afterOpt.loopBodys.size());
130     bool foundLengthAfterOpt = false;
131     for (auto gate : afterOpt.loopBodys) {
132         if (acc.GetOpCode(gate) == OpCode::LOAD_TYPED_ARRAY_LENGTH) {
133             foundLengthAfterOpt = true;
134         }
135     }
136     EXPECT_FALSE(foundLengthAfterOpt);
137 }
138 
HWTEST_F_L0(LoopOptimizationTest,LoopNumberCalculationOptimizationTest)139 HWTEST_F_L0(LoopOptimizationTest, LoopNumberCalculationOptimizationTest)
140 {
141     // construct a circuit
142     ecmascript::NativeAreaAllocator allocator;
143     Circuit circuit(&allocator);
144     ecmascript::Chunk chunk(&allocator);
145     GateAccessor acc(&circuit);
146     CircuitBuilder builder(&circuit);
147     Environment env(0, &builder);
148     // after slowpath lowering
149     builder.SetEnvironment(&env);
150     auto arg = builder.Arguments(1);
151     acc.SetMachineType(arg, MachineType::I32);
152     DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
153     DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
154 
155     Label loopHead(&env);
156     Label loopBody(&env);
157     Label loopExit(&env);
158     builder.Jump(&loopHead);
159     builder.LoopBegin(&loopHead);
160     auto loopBegin = builder.GetState();
161     auto loopEntry = acc.GetState(loopBegin);
162     auto invariant = builder.Int32Mul(arg, builder.Int32(5));
163     builder.Branch(builder.Int32LessThan(*index, invariant), &loopBody, &loopExit);
164     builder.Bind(&loopBody);
165     auto variant = builder.Int32Add(*sum, builder.Int32(2));
166     sum = variant;
167     index = builder.Int32Add(*index, builder.Int32(1));
168     builder.LoopEnd(&loopHead);
169     builder.Bind(&loopExit);
170     builder.Return(builder.ConvertInt32ToTaggedInt(*sum));
171     EXPECT_TRUE(Verifier::Run(&circuit));
172     std::vector<std::vector<GateRef>> cfg;
173     auto linearizer = GraphLinearizer(&circuit, false, "LoopNumberCalculationOptimizationTest", &chunk, false, false);
174     linearizer.Run(cfg);
175     EXPECT_EQ(acc.GetOpCode(linearizer.GetStateOfSchedulableGate(invariant)), OpCode::IF_BRANCH);
176     EXPECT_EQ(acc.GetOpCode(linearizer.GetStateOfSchedulableGate(variant)), OpCode::LOOP_BACK);
177     std::vector<std::vector<GateRef>> cfg2;
178     auto linearizer2 = GraphLinearizer(&circuit, false, "LoopNumberCalculationOptimizationTest", &chunk, false, true);
179     linearizer2.Run(cfg2);
180     EXPECT_EQ(linearizer2.GetStateOfSchedulableGate(invariant), loopEntry);
181     EXPECT_EQ(acc.GetOpCode(linearizer2.GetStateOfSchedulableGate(variant)), OpCode::LOOP_BACK);
182 }
183 
HWTEST_F_L0(LoopOptimizationTest,LoopLoadConstOptimizationTest)184 HWTEST_F_L0(LoopOptimizationTest, LoopLoadConstOptimizationTest)
185 {
186     // construct a circuit
187     ecmascript::NativeAreaAllocator allocator;
188     Circuit circuit(&allocator);
189     ecmascript::Chunk chunk(&allocator);
190     GateAccessor acc(&circuit);
191     CircuitBuilder builder(&circuit);
192     Environment env(0, &builder);
193     // after slowpath lowering
194     builder.SetEnvironment(&env);
195     auto arg1 = builder.Arguments(1);
196     acc.SetGateType(arg1, GateType::TaggedPointer());
197     auto arg2 = builder.Arguments(2);
198     acc.SetMachineType(arg2, MachineType::ARCH);
199     auto bits = ecmascript::kungfu::LoadStoreAccessor::ToValue(ecmascript::kungfu::MemoryOrder::Default());
200     GateRef invariant = circuit.NewGate(circuit.Load(bits), MachineType::I32,
201         { circuit.GetDependRoot(), arg2 }, GateType::NJSValue());
202 
203     DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0));
204     DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0));
205 
206     Label loopHead(&env);
207     Label loopBody(&env);
208     Label loopExit(&env);
209     builder.Jump(&loopHead);
210     builder.LoopBegin(&loopHead);
211     auto loopBegin = builder.GetState();
212     auto loopEntry = acc.GetState(loopBegin);
213 
214     builder.Branch(builder.Int32LessThan(*index, invariant), &loopBody, &loopExit);
215     builder.Bind(&loopBody);
216     auto variant = builder.Load(VariableType::INT32(), arg1, builder.PtrAdd(arg2, *index));
217     sum = builder.Int32Add(*sum, variant);
218     index = builder.Int32Add(*index, builder.Int32(1));
219     builder.LoopEnd(&loopHead);
220     builder.Bind(&loopExit);
221     builder.Return(builder.ConvertInt32ToTaggedInt(*sum));
222     EXPECT_TRUE(Verifier::Run(&circuit));
223     std::vector<std::vector<GateRef>> cfg;
224     auto linearizer = GraphLinearizer(&circuit, false, "LoopNumberCalculationOptimizationTest", &chunk, false, false);
225     linearizer.Run(cfg);
226     EXPECT_EQ(acc.GetOpCode(linearizer.GetStateOfSchedulableGate(invariant)), OpCode::IF_BRANCH);
227     EXPECT_EQ(acc.GetOpCode(linearizer.GetStateOfSchedulableGate(variant)), OpCode::LOOP_BACK);
228     std::vector<std::vector<GateRef>> cfg2;
229     auto linearizer2 = GraphLinearizer(&circuit, false, "LoopNumberCalculationOptimizationTest", &chunk, false, true);
230     linearizer2.Run(cfg2);
231     EXPECT_EQ(linearizer2.GetStateOfSchedulableGate(invariant), loopEntry);
232     EXPECT_EQ(acc.GetOpCode(linearizer2.GetStateOfSchedulableGate(variant)), OpCode::LOOP_BACK);
233 }
234 } // namespace panda::test
235