14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci#include "ecmascript/compiler/bytecodes.h" 164514f5e3Sopenharmony_ci#include "ecmascript/compiler/circuit_builder.h" 174514f5e3Sopenharmony_ci#include "ecmascript/compiler/early_elimination.h" 184514f5e3Sopenharmony_ci#include "ecmascript/compiler/gate_accessor.h" 194514f5e3Sopenharmony_ci#include "ecmascript/compiler/graph_editor.h" 204514f5e3Sopenharmony_ci#include "ecmascript/compiler/loop_analysis.h" 214514f5e3Sopenharmony_ci#include "ecmascript/compiler/loop_peeling.h" 224514f5e3Sopenharmony_ci#include "ecmascript/compiler/pass.h" 234514f5e3Sopenharmony_ci#include "ecmascript/compiler/stub_builder.h" 244514f5e3Sopenharmony_ci#include "ecmascript/compiler/type.h" 254514f5e3Sopenharmony_ci#include "ecmascript/compiler/variable_type.h" 264514f5e3Sopenharmony_ci#include "ecmascript/compiler/verifier.h" 274514f5e3Sopenharmony_ci#include "ecmascript/compiler/typed_bytecode_lowering.h" 284514f5e3Sopenharmony_ci#include "ecmascript/compiler/typed_hcr_lowering.h" 294514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/types/pgo_profiler_type.h" 304514f5e3Sopenharmony_ci#include "ecmascript/mem/chunk.h" 314514f5e3Sopenharmony_ci#include "ecmascript/mem/native_area_allocator.h" 324514f5e3Sopenharmony_ci#include "ecmascript/tests/test_helper.h" 334514f5e3Sopenharmony_ci#include "gtest/gtest-death-test.h" 344514f5e3Sopenharmony_ci#include "gtest/gtest.h" 354514f5e3Sopenharmony_ci 364514f5e3Sopenharmony_cinamespace panda::test { 374514f5e3Sopenharmony_ciclass LoopOptimizationTest : public testing::Test { 384514f5e3Sopenharmony_ci}; 394514f5e3Sopenharmony_ciusing ecmascript::kungfu::Circuit; 404514f5e3Sopenharmony_ciusing ecmascript::kungfu::GateAccessor; 414514f5e3Sopenharmony_ciusing ecmascript::kungfu::GateType; 424514f5e3Sopenharmony_ciusing ecmascript::kungfu::MachineType; 434514f5e3Sopenharmony_ciusing ecmascript::kungfu::CircuitBuilder; 444514f5e3Sopenharmony_ciusing ecmascript::kungfu::Label; 454514f5e3Sopenharmony_ciusing ecmascript::kungfu::OpCode; 464514f5e3Sopenharmony_ciusing ecmascript::kungfu::GateRef; 474514f5e3Sopenharmony_ciusing ecmascript::kungfu::Variable; 484514f5e3Sopenharmony_ciusing ecmascript::kungfu::VariableType; 494514f5e3Sopenharmony_ciusing ecmascript::kungfu::Verifier; 504514f5e3Sopenharmony_ciusing ecmascript::kungfu::LoopAnalysis; 514514f5e3Sopenharmony_ciusing ecmascript::kungfu::Environment; 524514f5e3Sopenharmony_ciusing ecmascript::kungfu::LoopPeeling; 534514f5e3Sopenharmony_ciusing ecmascript::kungfu::EarlyElimination; 544514f5e3Sopenharmony_ciusing ecmascript::kungfu::CombinedPassVisitor; 554514f5e3Sopenharmony_ciusing ecmascript::kungfu::TypedBinOp; 564514f5e3Sopenharmony_ciusing ecmascript::kungfu::PGOTypeRef; 574514f5e3Sopenharmony_ciusing ecmascript::kungfu::PGOSampleType; 584514f5e3Sopenharmony_ciusing ecmascript::kungfu::GraphLinearizer; 594514f5e3Sopenharmony_ciusing ecmascript::kungfu::ParamType; 604514f5e3Sopenharmony_ciHWTEST_F_L0(LoopOptimizationTest, LoopInt32TypedArraySumOptimizationTest) 614514f5e3Sopenharmony_ci{ 624514f5e3Sopenharmony_ci // construct a circuit 634514f5e3Sopenharmony_ci ecmascript::NativeAreaAllocator allocator; 644514f5e3Sopenharmony_ci Circuit circuit(&allocator); 654514f5e3Sopenharmony_ci ecmascript::Chunk chunk(&allocator); 664514f5e3Sopenharmony_ci GateAccessor acc(&circuit); 674514f5e3Sopenharmony_ci CircuitBuilder builder(&circuit); 684514f5e3Sopenharmony_ci Environment env(0, &builder); 694514f5e3Sopenharmony_ci // after number speculative runner 704514f5e3Sopenharmony_ci builder.SetEnvironment(&env); 714514f5e3Sopenharmony_ci auto array = builder.Arguments(1); 724514f5e3Sopenharmony_ci 734514f5e3Sopenharmony_ci DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0)); 744514f5e3Sopenharmony_ci DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0)); 754514f5e3Sopenharmony_ci 764514f5e3Sopenharmony_ci Label loopHead(&env); 774514f5e3Sopenharmony_ci Label loopBody(&env); 784514f5e3Sopenharmony_ci Label loopExit(&env); 794514f5e3Sopenharmony_ci builder.Jump(&loopHead); 804514f5e3Sopenharmony_ci builder.LoopBegin(&loopHead); 814514f5e3Sopenharmony_ci auto loopBegin = builder.GetState(); 824514f5e3Sopenharmony_ci EXPECT_TRUE(acc.IsLoopHead(loopBegin)); 834514f5e3Sopenharmony_ci auto loadLength = builder.LoadTypedArrayLength(array, ParamType::AnyType()); 844514f5e3Sopenharmony_ci acc.SetMachineType(loadLength, MachineType::I32); 854514f5e3Sopenharmony_ci acc.SetGateType(loadLength, GateType::NJSValue()); 864514f5e3Sopenharmony_ci auto cmp = builder.TypedBinaryOp<TypedBinOp::TYPED_ADD>(*index, loadLength, ParamType::IntType()); 874514f5e3Sopenharmony_ci acc.SetMachineType(cmp, MachineType::I1); 884514f5e3Sopenharmony_ci builder.Branch(cmp, &loopBody, &loopExit); 894514f5e3Sopenharmony_ci builder.Bind(&loopBody); 904514f5e3Sopenharmony_ci auto loadElement = builder.LoadElement<ecmascript::kungfu::TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(array, *index); 914514f5e3Sopenharmony_ci acc.SetMachineType(loadElement, MachineType::I32); 924514f5e3Sopenharmony_ci acc.SetGateType(loadElement, GateType::NJSValue()); 934514f5e3Sopenharmony_ci auto sumAdd = builder.TypedBinaryOp<TypedBinOp::TYPED_ADD>(*sum, loadElement, ParamType::IntType()); 944514f5e3Sopenharmony_ci acc.SetMachineType(sumAdd, MachineType::I32); 954514f5e3Sopenharmony_ci sum = sumAdd; 964514f5e3Sopenharmony_ci auto indexInc = builder.TypedBinaryOp<TypedBinOp::TYPED_ADD>(*index, builder.Int32(1), ParamType::IntType()); 974514f5e3Sopenharmony_ci acc.SetMachineType(indexInc, MachineType::I32); 984514f5e3Sopenharmony_ci index = indexInc; 994514f5e3Sopenharmony_ci builder.LoopEnd(&loopHead); 1004514f5e3Sopenharmony_ci builder.Bind(&loopExit); 1014514f5e3Sopenharmony_ci builder.LoopExit({&sum}); 1024514f5e3Sopenharmony_ci auto convert = builder.ConvertInt32ToTaggedInt(*sum); 1034514f5e3Sopenharmony_ci builder.Return(convert); 1044514f5e3Sopenharmony_ci LoopAnalysis analysis(nullptr, &circuit, &chunk); 1054514f5e3Sopenharmony_ci ecmascript::kungfu::LoopInfo beforeOpt(&chunk, loopBegin); 1064514f5e3Sopenharmony_ci ecmascript::kungfu::LoopInfo afterOpt(&chunk, loopBegin); 1074514f5e3Sopenharmony_ci analysis.CollectLoopBody(&beforeOpt); 1084514f5e3Sopenharmony_ci bool foundLengthBeforeOpt = false; 1094514f5e3Sopenharmony_ci for (auto gate : beforeOpt.loopBodys) { 1104514f5e3Sopenharmony_ci if (acc.GetOpCode(gate) == OpCode::LOAD_TYPED_ARRAY_LENGTH) { 1114514f5e3Sopenharmony_ci foundLengthBeforeOpt = true; 1124514f5e3Sopenharmony_ci } 1134514f5e3Sopenharmony_ci } 1144514f5e3Sopenharmony_ci EXPECT_TRUE(foundLengthBeforeOpt); 1154514f5e3Sopenharmony_ci analysis.PrintLoop(&beforeOpt); 1164514f5e3Sopenharmony_ci LoopPeeling(nullptr, &circuit, false, "LoopInt32TypedArraySumOptimizationTest", &chunk, &beforeOpt).Peel(); 1174514f5e3Sopenharmony_ci EXPECT_TRUE(Verifier::Run(&circuit)); 1184514f5e3Sopenharmony_ci CombinedPassVisitor visitor(&circuit, false, "LoopInt32TypedArraySumOptimizationTest", &chunk); 1194514f5e3Sopenharmony_ci EarlyElimination earlyElimination(&circuit, &visitor, &chunk, true, true); 1204514f5e3Sopenharmony_ci visitor.AddPass(&earlyElimination); 1214514f5e3Sopenharmony_ci visitor.VisitGraph(); 1224514f5e3Sopenharmony_ci analysis.CollectLoopBody(&afterOpt); 1234514f5e3Sopenharmony_ci EXPECT_TRUE(Verifier::Run(&circuit)); 1244514f5e3Sopenharmony_ci EXPECT_TRUE(beforeOpt.loopBodys.size() > afterOpt.loopBodys.size()); 1254514f5e3Sopenharmony_ci bool foundLengthAfterOpt = false; 1264514f5e3Sopenharmony_ci for (auto gate : afterOpt.loopBodys) { 1274514f5e3Sopenharmony_ci if (acc.GetOpCode(gate) == OpCode::LOAD_TYPED_ARRAY_LENGTH) { 1284514f5e3Sopenharmony_ci foundLengthAfterOpt = true; 1294514f5e3Sopenharmony_ci } 1304514f5e3Sopenharmony_ci } 1314514f5e3Sopenharmony_ci EXPECT_FALSE(foundLengthAfterOpt); 1324514f5e3Sopenharmony_ci} 1334514f5e3Sopenharmony_ci 1344514f5e3Sopenharmony_ciHWTEST_F_L0(LoopOptimizationTest, LoopNumberCalculationOptimizationTest) 1354514f5e3Sopenharmony_ci{ 1364514f5e3Sopenharmony_ci // construct a circuit 1374514f5e3Sopenharmony_ci ecmascript::NativeAreaAllocator allocator; 1384514f5e3Sopenharmony_ci Circuit circuit(&allocator); 1394514f5e3Sopenharmony_ci ecmascript::Chunk chunk(&allocator); 1404514f5e3Sopenharmony_ci GateAccessor acc(&circuit); 1414514f5e3Sopenharmony_ci CircuitBuilder builder(&circuit); 1424514f5e3Sopenharmony_ci Environment env(0, &builder); 1434514f5e3Sopenharmony_ci // after slowpath lowering 1444514f5e3Sopenharmony_ci builder.SetEnvironment(&env); 1454514f5e3Sopenharmony_ci auto arg = builder.Arguments(1); 1464514f5e3Sopenharmony_ci acc.SetMachineType(arg, MachineType::I32); 1474514f5e3Sopenharmony_ci DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0)); 1484514f5e3Sopenharmony_ci DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0)); 1494514f5e3Sopenharmony_ci 1504514f5e3Sopenharmony_ci Label loopHead(&env); 1514514f5e3Sopenharmony_ci Label loopBody(&env); 1524514f5e3Sopenharmony_ci Label loopExit(&env); 1534514f5e3Sopenharmony_ci builder.Jump(&loopHead); 1544514f5e3Sopenharmony_ci builder.LoopBegin(&loopHead); 1554514f5e3Sopenharmony_ci auto loopBegin = builder.GetState(); 1564514f5e3Sopenharmony_ci auto loopEntry = acc.GetState(loopBegin); 1574514f5e3Sopenharmony_ci auto invariant = builder.Int32Mul(arg, builder.Int32(5)); 1584514f5e3Sopenharmony_ci builder.Branch(builder.Int32LessThan(*index, invariant), &loopBody, &loopExit); 1594514f5e3Sopenharmony_ci builder.Bind(&loopBody); 1604514f5e3Sopenharmony_ci auto variant = builder.Int32Add(*sum, builder.Int32(2)); 1614514f5e3Sopenharmony_ci sum = variant; 1624514f5e3Sopenharmony_ci index = builder.Int32Add(*index, builder.Int32(1)); 1634514f5e3Sopenharmony_ci builder.LoopEnd(&loopHead); 1644514f5e3Sopenharmony_ci builder.Bind(&loopExit); 1654514f5e3Sopenharmony_ci builder.Return(builder.ConvertInt32ToTaggedInt(*sum)); 1664514f5e3Sopenharmony_ci EXPECT_TRUE(Verifier::Run(&circuit)); 1674514f5e3Sopenharmony_ci std::vector<std::vector<GateRef>> cfg; 1684514f5e3Sopenharmony_ci auto linearizer = GraphLinearizer(&circuit, false, "LoopNumberCalculationOptimizationTest", &chunk, false, false); 1694514f5e3Sopenharmony_ci linearizer.Run(cfg); 1704514f5e3Sopenharmony_ci EXPECT_EQ(acc.GetOpCode(linearizer.GetStateOfSchedulableGate(invariant)), OpCode::IF_BRANCH); 1714514f5e3Sopenharmony_ci EXPECT_EQ(acc.GetOpCode(linearizer.GetStateOfSchedulableGate(variant)), OpCode::LOOP_BACK); 1724514f5e3Sopenharmony_ci std::vector<std::vector<GateRef>> cfg2; 1734514f5e3Sopenharmony_ci auto linearizer2 = GraphLinearizer(&circuit, false, "LoopNumberCalculationOptimizationTest", &chunk, false, true); 1744514f5e3Sopenharmony_ci linearizer2.Run(cfg2); 1754514f5e3Sopenharmony_ci EXPECT_EQ(linearizer2.GetStateOfSchedulableGate(invariant), loopEntry); 1764514f5e3Sopenharmony_ci EXPECT_EQ(acc.GetOpCode(linearizer2.GetStateOfSchedulableGate(variant)), OpCode::LOOP_BACK); 1774514f5e3Sopenharmony_ci} 1784514f5e3Sopenharmony_ci 1794514f5e3Sopenharmony_ciHWTEST_F_L0(LoopOptimizationTest, LoopLoadConstOptimizationTest) 1804514f5e3Sopenharmony_ci{ 1814514f5e3Sopenharmony_ci // construct a circuit 1824514f5e3Sopenharmony_ci ecmascript::NativeAreaAllocator allocator; 1834514f5e3Sopenharmony_ci Circuit circuit(&allocator); 1844514f5e3Sopenharmony_ci ecmascript::Chunk chunk(&allocator); 1854514f5e3Sopenharmony_ci GateAccessor acc(&circuit); 1864514f5e3Sopenharmony_ci CircuitBuilder builder(&circuit); 1874514f5e3Sopenharmony_ci Environment env(0, &builder); 1884514f5e3Sopenharmony_ci // after slowpath lowering 1894514f5e3Sopenharmony_ci builder.SetEnvironment(&env); 1904514f5e3Sopenharmony_ci auto arg1 = builder.Arguments(1); 1914514f5e3Sopenharmony_ci acc.SetGateType(arg1, GateType::TaggedPointer()); 1924514f5e3Sopenharmony_ci auto arg2 = builder.Arguments(2); 1934514f5e3Sopenharmony_ci acc.SetMachineType(arg2, MachineType::ARCH); 1944514f5e3Sopenharmony_ci auto bits = ecmascript::kungfu::LoadStoreAccessor::ToValue(ecmascript::kungfu::MemoryAttribute::Default()); 1954514f5e3Sopenharmony_ci GateRef invariant = circuit.NewGate(circuit.Load(bits), MachineType::I32, 1964514f5e3Sopenharmony_ci { circuit.GetDependRoot(), arg2 }, GateType::NJSValue()); 1974514f5e3Sopenharmony_ci 1984514f5e3Sopenharmony_ci DEFVALUE(index, (&builder), VariableType::INT32(), builder.Int32(0)); 1994514f5e3Sopenharmony_ci DEFVALUE(sum, (&builder), VariableType::INT32(), builder.Int32(0)); 2004514f5e3Sopenharmony_ci 2014514f5e3Sopenharmony_ci Label loopHead(&env); 2024514f5e3Sopenharmony_ci Label loopBody(&env); 2034514f5e3Sopenharmony_ci Label loopExit(&env); 2044514f5e3Sopenharmony_ci builder.Jump(&loopHead); 2054514f5e3Sopenharmony_ci builder.LoopBegin(&loopHead); 2064514f5e3Sopenharmony_ci auto loopBegin = builder.GetState(); 2074514f5e3Sopenharmony_ci auto loopEntry = acc.GetState(loopBegin); 2084514f5e3Sopenharmony_ci 2094514f5e3Sopenharmony_ci builder.Branch(builder.Int32LessThan(*index, invariant), &loopBody, &loopExit); 2104514f5e3Sopenharmony_ci builder.Bind(&loopBody); 2114514f5e3Sopenharmony_ci auto variant = builder.Load(VariableType::INT32(), arg1, builder.PtrAdd(arg2, *index)); 2124514f5e3Sopenharmony_ci sum = builder.Int32Add(*sum, variant); 2134514f5e3Sopenharmony_ci index = builder.Int32Add(*index, builder.Int32(1)); 2144514f5e3Sopenharmony_ci builder.LoopEnd(&loopHead); 2154514f5e3Sopenharmony_ci builder.Bind(&loopExit); 2164514f5e3Sopenharmony_ci builder.Return(builder.ConvertInt32ToTaggedInt(*sum)); 2174514f5e3Sopenharmony_ci EXPECT_TRUE(Verifier::Run(&circuit)); 2184514f5e3Sopenharmony_ci std::vector<std::vector<GateRef>> cfg; 2194514f5e3Sopenharmony_ci auto linearizer = GraphLinearizer(&circuit, false, "LoopNumberCalculationOptimizationTest", &chunk, false, false); 2204514f5e3Sopenharmony_ci linearizer.Run(cfg); 2214514f5e3Sopenharmony_ci EXPECT_EQ(acc.GetOpCode(linearizer.GetStateOfSchedulableGate(invariant)), OpCode::IF_BRANCH); 2224514f5e3Sopenharmony_ci EXPECT_EQ(acc.GetOpCode(linearizer.GetStateOfSchedulableGate(variant)), OpCode::LOOP_BACK); 2234514f5e3Sopenharmony_ci std::vector<std::vector<GateRef>> cfg2; 2244514f5e3Sopenharmony_ci auto linearizer2 = GraphLinearizer(&circuit, false, "LoopNumberCalculationOptimizationTest", &chunk, false, true); 2254514f5e3Sopenharmony_ci linearizer2.Run(cfg2); 2264514f5e3Sopenharmony_ci EXPECT_EQ(linearizer2.GetStateOfSchedulableGate(invariant), loopEntry); 2274514f5e3Sopenharmony_ci EXPECT_EQ(acc.GetOpCode(linearizer2.GetStateOfSchedulableGate(variant)), OpCode::LOOP_BACK); 2284514f5e3Sopenharmony_ci} 2294514f5e3Sopenharmony_ci} // namespace panda::test 230