1 /*
2 * Copyright (c) 2022 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
16 #include <random>
17
18 #include "ecmascript/compiler/circuit_optimizer.h"
19 #include "ecmascript/compiler/early_elimination.h"
20 #include "ecmascript/compiler/verifier.h"
21 #include "ecmascript/mem/native_area_allocator.h"
22 #include "ecmascript/tests/test_helper.h"
23
24 namespace panda::test {
25 class CircuitOptimizerTests : public testing::Test {
26 };
27
28 using ecmascript::kungfu::Circuit;
29 using ecmascript::kungfu::OpCode;
30 using ecmascript::kungfu::GateType;
31 using ecmascript::kungfu::MachineType;
32 using ecmascript::kungfu::GateAccessor;
33 using ecmascript::kungfu::GateRef;
34
HWTEST_F_L0(CircuitOptimizerTests,TestLatticeEquationsSystemSolverFramework)35 HWTEST_F_L0(CircuitOptimizerTests, TestLatticeEquationsSystemSolverFramework)
36 {
37 // construct a circuit
38 ecmascript::NativeAreaAllocator allocator;
39 Circuit circuit(&allocator);
40 GateAccessor acc(&circuit);
41 auto n = circuit.NewArg(MachineType::I64, 0, GateType::NJSValue(),
42 acc.GetArgRoot());
43 auto constantA = circuit.GetConstantGate(MachineType::I64, 1, GateType::NJSValue());
44 auto constantB = circuit.GetConstantGate(MachineType::I64,
45 2, GateType::NJSValue()); // 2: idx 2
46 auto constantC = circuit.GetConstantGate(MachineType::I64, 1, GateType::NJSValue());
47 auto constantD = circuit.GetConstantGate(MachineType::I64, 0, GateType::NJSValue());
48 auto loopBegin = circuit.NewGate(circuit.LoopBegin(),
49 MachineType::NOVALUE,
50 { acc.GetStateRoot(), Circuit::NullGate() },
51 GateType::Empty());
52 auto selectorA = circuit.NewGate(circuit.ValueSelector(2), // 2: valuesIn
53 MachineType::I64,
54 { loopBegin, constantA, Circuit::NullGate() },
55 GateType::NJSValue());
56 auto selectorB = circuit.NewGate(circuit.ValueSelector(2), // 2: valuesIn
57 MachineType::I64,
58 { loopBegin, n, Circuit::NullGate() },
59 GateType::NJSValue());
60 auto newX = circuit.NewGate(circuit.Sub(),
61 MachineType::I64,
62 {constantB, selectorA},
63 GateType::NJSValue());
64 acc.NewIn(selectorA, 2, newX);
65 acc.NewIn(selectorB,
66 2,
67 circuit.NewGate(circuit.Sub(),
68 MachineType::I64,
69 {selectorB, constantC},
70 GateType::NJSValue()));
71 auto predicate = circuit.NewGate(circuit.Icmp(
72 static_cast<uint64_t>(ecmascript::kungfu::ICmpCondition::NE)),
73 MachineType::I1,
74 {selectorB, constantD},
75 GateType::NJSValue());
76 auto ifBranch = circuit.NewGate(circuit.IfBranch(),
77 {loopBegin, predicate});
78 auto ifTrue = circuit.NewGate(circuit.IfTrue(),
79 {ifBranch});
80 auto ifFalse = circuit.NewGate(circuit.IfFalse(),
81 {ifBranch});
82 auto loopBack = circuit.NewGate(circuit.LoopBack(),
83 {ifTrue});
84 acc.NewIn(loopBegin, 1, loopBack);
85 auto ret = circuit.NewGate(circuit.Return(),
86 { ifFalse,
87 acc.GetDependRoot(),
88 newX,
89 acc.GetReturnRoot() });
90 // verify the circuit
91 {
92 auto verifyResult = ecmascript::kungfu::Verifier::Run(&circuit);
93 EXPECT_EQ(verifyResult, true);
94 }
95 {
96 ecmascript::kungfu::LatticeUpdateRuleSCCP rule;
97 ecmascript::kungfu::LatticeEquationsSystemSolverFramework solver(&rule);
98 // optimize the circuit
99 auto optimizeResult = solver.Run(&circuit, false);
100 EXPECT_EQ(optimizeResult, true);
101 // check optimization result (returned value is constant 1)
102 EXPECT_TRUE(solver.GetReachabilityLattice(ret).IsReachable());
103 EXPECT_TRUE(solver.GetValueLattice(acc.GetIn(ret, 2)).GetValue() == 1);
104 }
105 {
106 // modify the initial value of x to 2
107 acc.SetMetaData(constantA, circuit.Constant(2));
108 }
109 {
110 ecmascript::kungfu::LatticeUpdateRuleSCCP rule;
111 ecmascript::kungfu::LatticeEquationsSystemSolverFramework solver(&rule);
112 // optimize the circuit
113 auto optimizeResult = solver.Run(&circuit, false);
114 EXPECT_EQ(optimizeResult, true);
115 // check optimization result (returned value is not constant)
116 EXPECT_TRUE(solver.GetReachabilityLattice(ret).IsReachable());
117 EXPECT_TRUE(solver.GetValueLattice(acc.GetIn(ret, 2)).IsBot());
118 }
119 {
120 // set the initial value of n to fixed value 0 (instead of function argument)
121 acc.SetMetaData(n, circuit.Constant(0));
122 }
123 {
124 ecmascript::kungfu::LatticeUpdateRuleSCCP rule;
125 ecmascript::kungfu::LatticeEquationsSystemSolverFramework solver(&rule);
126 // optimize the circuit
127 auto optimizeResult = solver.Run(&circuit, false);
128 EXPECT_EQ(optimizeResult, true);
129 // check optimization result (returned value is constant 0)
130 EXPECT_TRUE(solver.GetReachabilityLattice(ret).IsReachable());
131 EXPECT_TRUE(solver.GetValueLattice(acc.GetIn(ret, 2)).GetValue() == 0);
132 }
133 }
134
HWTEST_F_L0(CircuitOptimizerTests,TestSubgraphRewriteFramework)135 HWTEST_F_L0(CircuitOptimizerTests, TestSubgraphRewriteFramework)
136 {
137 ecmascript::NativeAreaAllocator allocator;
138 Circuit circuit(&allocator);
139 GateAccessor acc(&circuit);
140 const uint64_t numOfConstants = 100;
141 const uint64_t numOfUses = 10;
142 std::random_device randomDevice;
143 std::mt19937_64 rng(randomDevice());
144 std::multimap<uint64_t, GateRef> constantsSet;
145 for (uint64_t iter = 0; iter < numOfUses; iter++) {
146 for (uint64_t idx = 0; idx < numOfConstants; idx++) {
147 constantsSet.insert(
148 std::make_pair(rng(),
149 circuit.GetConstantGate(MachineType::I64,
150 idx,
151 GateType::NJSValue())));
152 }
153 }
154 while (constantsSet.size() > 1) {
155 const auto elementA = constantsSet.begin();
156 const auto operandA = elementA->second;
157 constantsSet.erase(elementA);
158 const auto elementB = constantsSet.begin();
159 const auto operandB = elementB->second;
160 constantsSet.erase(elementB);
161 constantsSet.insert(
162 std::make_pair(rng(),
163 circuit.NewGate(circuit.Add(),
164 MachineType::I64,
165 {operandA,
166 operandB},
167 GateType::NJSValue())));
168 }
169 auto ret = circuit.NewGate(circuit.Return(),
170 { acc.GetStateRoot(),
171 acc.GetDependRoot(),
172 constantsSet.begin()->second,
173 acc.GetReturnRoot() });
174 ecmascript::kungfu::SubgraphRewriteRuleCP rule;
175 ecmascript::kungfu::SubGraphRewriteFramework rewriter(&rule);
176 rewriter.Run(&circuit);
177 auto returnValue = acc.GetIn(ret, 2);
178 EXPECT_TRUE(acc.GetOpCode(returnValue) == OpCode::CONSTANT);
179 EXPECT_TRUE(acc.GetConstantValue(returnValue) == (numOfUses) * (numOfConstants) * (numOfConstants - 1) / 2);
180 }
181
HWTEST_F_L0(CircuitOptimizerTests,TestLatticeUpdateRuleSCCP)182 HWTEST_F_L0(CircuitOptimizerTests, TestLatticeUpdateRuleSCCP)
183 {
184 ecmascript::NativeAreaAllocator allocator;
185 Circuit circuit(&allocator);
186 GateAccessor acc(&circuit);
187 auto constantA = circuit.NewGate(circuit.Constant(-8848),
188 MachineType::I32,
189 GateType::NJSValue());
190 auto constantB = circuit.NewGate(circuit.Constant(4),
191 MachineType::I32,
192 GateType::NJSValue());
193 auto newX = circuit.NewGate(circuit.Sdiv(),
194 MachineType::I32,
195 {constantA, constantB},
196 GateType::NJSValue());
197 auto ret = circuit.NewGate(circuit.Return(),
198 { acc.GetStateRoot(),
199 circuit.GetDependRoot(),
200 newX,
201 acc.GetReturnRoot()});
202 {
203 int32_t x = -8848;
204 int32_t y = 4;
205 ecmascript::kungfu::LatticeUpdateRuleSCCP rule;
206 ecmascript::kungfu::LatticeEquationsSystemSolverFramework solver(&rule);
207 // optimize the circuit
208 auto optimizeResult = solver.Run(&circuit, false);
209 EXPECT_EQ(optimizeResult, true);
210 // check optimization result (returned value is constant -2212)
211 EXPECT_TRUE(solver.GetReachabilityLattice(ret).IsReachable());
212 EXPECT_EQ(solver.GetValueLattice(acc.GetIn(ret, 2)).GetValue(),
213 ecmascript::base::bit_cast<uint32_t>(x / y));
214 }
215 {
216 acc.SetMetaData(newX, circuit.Udiv());
217 uint32_t x = -8848;
218 uint32_t y = 4;
219 ecmascript::kungfu::LatticeUpdateRuleSCCP rule;
220 ecmascript::kungfu::LatticeEquationsSystemSolverFramework solver(&rule);
221 // optimize the circuit
222 auto optimizeResult = solver.Run(&circuit, false);
223 EXPECT_EQ(optimizeResult, true);
224 // check optimization result (returned value is constant 1073739612)
225 EXPECT_TRUE(solver.GetReachabilityLattice(ret).IsReachable());
226 EXPECT_EQ(solver.GetValueLattice(acc.GetIn(ret, 2)).GetValue(), x / y);
227 }
228 {
229 // modify the initial type of constantA to int8_t
230 acc.SetMachineType(constantA, MachineType::I8);
231 // modify the initial value of constantA to 200
232 acc.SetMetaData(constantA, circuit.Constant(200));
233 // modify the initial type of constantB to int8_t
234 acc.SetMachineType(constantB, MachineType::I8);
235 // modify the initial value of constantB to 200
236 acc.SetMetaData(constantB, circuit.Constant(200));
237 acc.SetMachineType(newX, MachineType::I8);
238 acc.SetMetaData(newX, circuit.Add());
239 ecmascript::kungfu::LatticeUpdateRuleSCCP rule;
240 ecmascript::kungfu::LatticeEquationsSystemSolverFramework solver(&rule);
241 // optimize the circuit
242 auto optimizeResult = solver.Run(&circuit, false);
243 EXPECT_EQ(optimizeResult, true);
244 // check optimization result (returned value is constant 144)
245 EXPECT_TRUE(solver.GetReachabilityLattice(ret).IsReachable());
246 EXPECT_EQ(solver.GetValueLattice(acc.GetIn(ret, 2)).GetValue(), 144);
247 }
248 {
249 float x = 9.6;
250 float y = 6.9;
251 // modify the initial type of constantA to float
252 acc.SetMachineType(constantA, MachineType::F32);
253 // modify the initial value of constantA to 9.6
254 acc.SetMetaData(constantA, circuit.Constant(ecmascript::base::bit_cast<uint32_t>(x)));
255 // modify the initial type of constantB to float
256 acc.SetMachineType(constantB, MachineType::F32);
257 // modify the initial value of constantB to 6.9
258 acc.SetMetaData(constantB, circuit.Constant(ecmascript::base::bit_cast<uint32_t>(y)));
259 acc.SetMachineType(newX, MachineType::F32);
260 acc.SetMetaData(newX, circuit.Fmod());
261 ecmascript::kungfu::LatticeUpdateRuleSCCP rule;
262 ecmascript::kungfu::LatticeEquationsSystemSolverFramework solver(&rule);
263 // optimize the circuit
264 auto optimizeResult = solver.Run(&circuit, false);
265 EXPECT_EQ(optimizeResult, true);
266 // check optimization result (returned value is constant 2.7)
267 EXPECT_TRUE(solver.GetReachabilityLattice(ret).IsReachable());
268 EXPECT_EQ(ecmascript::base::bit_cast<double>(solver.GetValueLattice(acc.GetIn(ret, 2)).GetValue().value()),
269 fmod(x, y));
270 }
271 }
272
HWTEST_F_L0(CircuitOptimizerTests,TestSmallSizeGlobalValueNumbering)273 HWTEST_F_L0(CircuitOptimizerTests, TestSmallSizeGlobalValueNumbering) {
274 // construct a circuit
275 ecmascript::NativeAreaAllocator allocator;
276 Circuit circuit(&allocator);
277 GateAccessor acc(&circuit);
278 auto constantA = circuit.NewGate(circuit.Constant(1),
279 MachineType::I64, GateType::NJSValue());
280 auto constantB = circuit.NewGate(circuit.Constant(1),
281 MachineType::I64, GateType::NJSValue());
282 auto argA = circuit.NewArg(MachineType::I64, 1,
283 GateType::NJSValue(),
284 acc.GetArgRoot());
285 auto argB = circuit.NewArg(MachineType::I64, 2,
286 GateType::NJSValue(),
287 acc.GetArgRoot());
288
289 auto add1 = circuit.NewGate(circuit.Add(),
290 MachineType::I64,
291 {constantA, argA},
292 GateType::NJSValue());
293
294 auto add2 = circuit.NewGate(circuit.Add(),
295 MachineType::I64,
296 { constantB, argA },
297 GateType::NJSValue());
298
299 auto add3 = circuit.NewGate(circuit.Add(),
300 MachineType::I64,
301 { constantA, argB },
302 GateType::NJSValue());
303 ecmascript::kungfu::GlobalValueNumbering(&circuit, false).Run();
304 EXPECT_FALSE(acc.GetMetaData(add3)->IsNop());
305 EXPECT_FALSE(acc.GetMetaData(argA)->IsNop());
306 EXPECT_FALSE(acc.GetMetaData(argB)->IsNop());
307 EXPECT_TRUE(acc.GetMetaData(constantA)->IsNop() || acc.GetMetaData(constantB)->IsNop());
308 EXPECT_FALSE(acc.GetMetaData(constantA)->IsNop() && acc.GetMetaData(constantB)->IsNop());
309 EXPECT_TRUE(acc.GetMetaData(add1)->IsNop() || acc.GetMetaData(add2)->IsNop());
310 EXPECT_FALSE(acc.GetMetaData(add1)->IsNop() && acc.GetMetaData(add2)->IsNop());
311 }
312
HWTEST_F_L0(CircuitOptimizerTests,TestMultiLevelGlobalValueNumbering)313 HWTEST_F_L0(CircuitOptimizerTests, TestMultiLevelGlobalValueNumbering) {
314 ecmascript::NativeAreaAllocator allocator;
315 Circuit circuit(&allocator);
316 GateAccessor acc(&circuit);
317 std::random_device randomDevice;
318 std::mt19937_64 rng(randomDevice());
319 std::vector<GateRef> args;
320 for (uint32_t i = 0; i < 5; ++i) {
321 args.push_back(circuit.NewArg(MachineType::I64, i, GateType::NJSValue(),
322 acc.GetArgRoot()));
323 }
324 std::map<GateRef, std::vector<GateRef>> addToAdds;
325 std::map<GateRef, GateRef> addToAdd;
326 std::map<std::pair<GateRef, GateRef>, GateRef> pairToAdd;
327 std::vector<GateRef> adds;
328 for (uint32_t i = 0; i < 50; ++i) {
329 std::pair<GateRef, GateRef> p(args[rng() % 5], args[rng() % 5]);
330 auto add = circuit.NewGate(circuit.Add(),
331 MachineType::I64,
332 {p.first, p.second},
333 GateType::NJSValue());
334 adds.push_back(add);
335 if (pairToAdd.count(p) == 0) {
336 pairToAdd[p] = add;
337 addToAdds[add] = std::vector<GateRef>(0);
338 }
339 addToAdd[add] = pairToAdd[p];
340 addToAdds[addToAdd[add]].emplace_back(add);
341 }
342 std::map<GateRef, std::vector<GateRef>> subToSubs;
343 std::map<GateRef, GateRef> subToSub;
344 std::map<std::pair<GateRef, GateRef>, GateRef> pairToSub;
345 std::vector<GateRef> subs;
346 for (uint32_t i = 0; i < 50; ++i) {
347 std::pair<GateRef, GateRef> p(adds[rng() % 5], adds[rng() % 5]);
348 auto sub = circuit.NewGate(circuit.Sub(),
349 MachineType::I64,
350 {p.first, p.second},
351 GateType::NJSValue());
352 subs.push_back(sub);
353 // remove redundant adds.
354 std::pair<GateRef, GateRef> np(addToAdd[p.first], addToAdd[p.second]);
355 if (pairToSub.count(np) == 0) {
356 pairToSub[np] = sub;
357 subToSubs[sub] = std::vector<GateRef>(0);
358 }
359 subToSub[sub] = pairToSub[np];
360 subToSubs[subToSub[sub]].emplace_back(sub);
361 }
362 ecmascript::kungfu::GlobalValueNumbering(&circuit, false).Run();
363 std::map<GateRef, GateRef> gateToKing;
364 for (const auto &p : addToAdds) {
365 uint32_t cnt = 0;
366 GateRef kingGate;
367 for (auto gate : p.second) {
368 if (acc.GetOpCode(gate) != OpCode::NOP) {
369 cnt++;
370 kingGate = gate;
371 }
372 }
373 EXPECT_TRUE(cnt == 1);
374 for (auto gate : p.second) {
375 gateToKing[gate] = kingGate;
376 }
377 }
378 for (const auto &p : subToSubs) {
379 uint32_t cnt = 0;
380 GateRef kingGate;
381 for (auto gate : p.second) {
382 if (acc.GetOpCode(gate) != OpCode::NOP) {
383 cnt++;
384 kingGate = gate;
385 }
386 }
387 EXPECT_TRUE(cnt == 1);
388 for (auto gate : p.second) {
389 gateToKing[gate] = kingGate;
390 }
391 }
392 std::vector<GateRef> gates;
393 acc.GetAllGates(gates);
394 for (auto gate : gates) {
395 if (acc.GetOpCode(gate) == OpCode::NOP) {
396 continue;
397 }
398 std::vector<GateRef> ins;
399 for (auto in : ins) {
400 EXPECT_TRUE(in == gateToKing[in]);
401 }
402 }
403 }
404
HWTEST_F_L0(CircuitOptimizerTests,TestSmallWorldGlobalValueNumbering)405 HWTEST_F_L0(CircuitOptimizerTests, TestSmallWorldGlobalValueNumbering) {
406 ecmascript::NativeAreaAllocator allocator;
407 Circuit circuit(&allocator);
408 GateAccessor acc(&circuit);
409 std::random_device randomDevice;
410 std::mt19937_64 rng(randomDevice());
411 std::vector<GateRef> args;
412 for (uint32_t i = 0; i < 3; ++i) {
413 args.push_back(circuit.NewArg(MachineType::I64, i,
414 GateType::NJSValue(), acc.GetArgRoot()));
415 }
416 std::map<GateRef, std::vector<GateRef>> addToAdds;
417 std::map<GateRef, GateRef> addToAdd;
418 std::map<std::pair<GateRef, GateRef>, GateRef> pairToAdd;
419 std::vector<GateRef> adds;
420 std::vector<GateRef> toBeSelect;
421 for (uint32_t i = 0; i < 10; ++i) {
422 std::pair<GateRef, GateRef> p(args[rng() % 3], args[rng() % 3]);
423 auto add = circuit.NewGate(circuit.Add(),
424 MachineType::I64,
425 {p.first, p.second},
426 GateType::NJSValue());
427 adds.emplace_back(add);
428 toBeSelect.emplace_back(add);
429 toBeSelect.emplace_back(add);
430 if (pairToAdd.count(p) == 0) {
431 pairToAdd[p] = add;
432 addToAdds[add] = std::vector<GateRef>(0);
433 }
434 addToAdd[add] = pairToAdd[p];
435 addToAdds[addToAdd[add]].emplace_back(add);
436 }
437 for (uint32_t i = 0; i < 1000; ++i) {
438 std::pair<GateRef, GateRef> p(toBeSelect[rng() % toBeSelect.size()], toBeSelect[rng() % toBeSelect.size()]);
439 auto add = circuit.NewGate(circuit.Add(), MachineType::I64,
440 {p.first, p.second},
441 GateType::NJSValue());
442 adds.emplace_back(add);
443 toBeSelect.emplace_back(add);
444 toBeSelect.emplace_back(add);
445 toBeSelect.emplace_back(p.first);
446 toBeSelect.emplace_back(p.second);
447
448 std::pair<GateRef, GateRef> np(addToAdd[p.first], addToAdd[p.second]);
449 if (pairToAdd.count(np) == 0) {
450 pairToAdd[np] = add;
451 addToAdds[add] = std::vector<GateRef>(0);
452 }
453 addToAdd[add] = pairToAdd[np];
454 addToAdds[addToAdd[add]].emplace_back(add);
455 }
456 ecmascript::kungfu::GlobalValueNumbering(&circuit, false).Run();
457 std::map<GateRef, GateRef> gateToKing;
458 for (const auto &p : addToAdds) {
459 uint32_t cnt = 0;
460 GateRef kingGate;
461 for (auto gate : p.second) {
462 if (acc.GetOpCode(gate) != OpCode::NOP) {
463 cnt++;
464 kingGate = gate;
465 }
466 }
467 EXPECT_TRUE(cnt == 1);
468 for (auto gate : p.second) {
469 gateToKing[gate] = kingGate;
470 }
471 }
472 std::vector<GateRef> gates;
473 acc.GetAllGates(gates);
474 for (auto gate : gates) {
475 if (acc.GetOpCode(gate) == OpCode::NOP) {
476 continue;
477 }
478 std::vector<GateRef> ins;
479 for (auto in : ins) {
480 EXPECT_TRUE(in == gateToKing[in]);
481 }
482 }
483 }
484
HWTEST_F_L0(CircuitOptimizerTests,TestEarlyElimination)485 HWTEST_F_L0(CircuitOptimizerTests, TestEarlyElimination) {
486 // construct a circuit
487 ecmascript::NativeAreaAllocator allocator;
488 Circuit circuit(&allocator);
489 GateAccessor acc(&circuit);
490 auto receiver = circuit.NewArg(MachineType::I64, 1,
491 GateType::AnyType(),
492 acc.GetArgRoot());
493 auto index = circuit.NewGate(circuit.Constant(1),
494 MachineType::I64, GateType::NJSValue());
495 auto load0 = circuit.NewGate(circuit.LoadElement(0),
496 MachineType::ANYVALUE,
497 { acc.GetStateRoot(), acc.GetDependRoot(), receiver, index },
498 GateType::AnyType());
499 auto load1 = circuit.NewGate(circuit.LoadElement(0),
500 MachineType::ANYVALUE,
501 { load0, load0, receiver, index },
502 GateType::AnyType());
503 ecmascript::kungfu::EarlyElimination(&circuit, false, "test", &allocator).Run();
504 EXPECT_FALSE(acc.GetMetaData(load0)->IsNop());
505 EXPECT_TRUE(acc.GetMetaData(load1)->IsNop());
506 }
507
HWTEST_F_L0(CircuitOptimizerTests,TestNotEarlyElimination)508 HWTEST_F_L0(CircuitOptimizerTests, TestNotEarlyElimination) {
509 // construct a circuit
510 ecmascript::NativeAreaAllocator allocator;
511 Circuit circuit(&allocator);
512 GateAccessor acc(&circuit);
513 auto receiver = circuit.NewArg(MachineType::I64, 1,
514 GateType::AnyType(),
515 acc.GetArgRoot());
516 auto index = circuit.NewGate(circuit.Constant(1),
517 MachineType::I64, GateType::NJSValue());
518 auto load0 = circuit.NewGate(circuit.LoadElement(0),
519 MachineType::ANYVALUE,
520 { acc.GetStateRoot(), acc.GetDependRoot(), receiver, index },
521 GateType::AnyType());
522 auto store = circuit.NewGate(circuit.StoreElement(0),
523 MachineType::NOVALUE,
524 { load0, load0, receiver, index, index },
525 GateType::AnyType());
526 auto load1 = circuit.NewGate(circuit.LoadElement(0),
527 MachineType::ANYVALUE,
528 { store, store, receiver, index },
529 GateType::AnyType());
530 ecmascript::kungfu::EarlyElimination(&circuit, false, "test", &allocator).Run();
531 EXPECT_FALSE(acc.GetMetaData(load0)->IsNop());
532 EXPECT_FALSE(acc.GetMetaData(load1)->IsNop());
533 }
534
HWTEST_F_L0(CircuitOptimizerTests,TestMergeEarlyElimination)535 HWTEST_F_L0(CircuitOptimizerTests, TestMergeEarlyElimination) {
536 // construct a circuit
537 ecmascript::NativeAreaAllocator allocator;
538 Circuit circuit(&allocator);
539 GateAccessor acc(&circuit);
540 auto receiver = circuit.NewArg(MachineType::I64, 1,
541 GateType::AnyType(),
542 acc.GetArgRoot());
543 auto index = circuit.NewGate(circuit.Constant(1),
544 MachineType::I64, GateType::NJSValue());
545 auto condition = circuit.NewGate(circuit.Constant(1),
546 MachineType::I1, GateType::NJSValue());
547 auto load0 = circuit.NewGate(circuit.LoadElement(0),
548 MachineType::ANYVALUE,
549 { acc.GetStateRoot(), acc.GetDependRoot(), receiver, index },
550 GateType::AnyType());
551 auto ifBranch = circuit.NewGate(circuit.IfBranch(), {load0, condition});
552 auto ifTrue = circuit.NewGate(circuit.IfTrue(), {ifBranch});
553 auto ifFalse = circuit.NewGate(circuit.IfFalse(), {ifBranch});
554 auto ifTrueDepend = circuit.NewGate(circuit.DependRelay(), { ifTrue, load0 });
555 auto ifFalseDepend = circuit.NewGate(circuit.DependRelay(), { ifFalse, load0 });
556 auto load1 = circuit.NewGate(circuit.LoadElement(0),
557 MachineType::ANYVALUE,
558 { ifTrue, ifTrueDepend, receiver, index },
559 GateType::AnyType());
560 auto load2 = circuit.NewGate(circuit.LoadElement(0),
561 MachineType::ANYVALUE,
562 { ifFalse, ifFalseDepend, receiver, index },
563 GateType::AnyType());
564 auto merge = circuit.NewGate(circuit.Merge(2), {load1, load2});
565 auto dependSelector = circuit.NewGate(circuit.DependSelector(2),
566 {merge, load1, load2});
567 auto load3 = circuit.NewGate(circuit.LoadElement(0),
568 MachineType::ANYVALUE,
569 { merge, dependSelector, receiver, index },
570 GateType::AnyType());
571 ecmascript::kungfu::EarlyElimination(&circuit, false, "test", &allocator).Run();
572 EXPECT_FALSE(acc.GetMetaData(load0)->IsNop());
573 EXPECT_TRUE(acc.GetMetaData(load1)->IsNop());
574 EXPECT_TRUE(acc.GetMetaData(load2)->IsNop());
575 EXPECT_TRUE(acc.GetMetaData(load3)->IsNop());
576 }
577 } // namespace panda::test