• 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.h"
17 #include "ecmascript/compiler/gate_accessor.h"
18 #include "ecmascript/compiler/lcr_gate_meta_data.h"
19 #include "ecmascript/compiler/pass.h"
20 #include "ecmascript/compiler/share_gate_meta_data.h"
21 #include "ecmascript/compiler/share_opcodes.h"
22 #include "ecmascript/compiler/instruction_combine.h"
23 #include "ecmascript/compiler/verifier.h"
24 #include "ecmascript/compiler/gate_matchers.h"
25 #include "ecmascript/elements.h"
26 #include "ecmascript/mem/concurrent_marker.h"
27 #include "ecmascript/mem/machine_code.h"
28 #include "ecmascript/mem/native_area_allocator.h"
29 #include "ecmascript/tests/test_helper.h"
30 #include "gtest/gtest.h"
31 #include <cmath>
32 #include <cstddef>
33 #include <cstdint>
34 #include <vector>
35 
36 namespace panda::test {
37 class InstructionCombineTests : public testing::Test {};
38 using ecmascript::kungfu::Circuit;
39 using ecmascript::kungfu::CircuitBuilder;
40 using ecmascript::kungfu::CombinedPassVisitor;
41 using ecmascript::kungfu::EcmaOpcode;
42 using ecmascript::kungfu::Environment;
43 using ecmascript::kungfu::Float64BinopMatcher;
44 using ecmascript::kungfu::Float64Matcher;
45 using ecmascript::kungfu::GateAccessor;
46 using ecmascript::kungfu::GateRef;
47 using ecmascript::kungfu::InstructionCombine;
48 using ecmascript::kungfu::Int32BinopMatcher;
49 using ecmascript::kungfu::Int64BinopMatcher;
50 using ecmascript::kungfu::OpCode;
51 using ecmascript::kungfu::PGOSampleType;
52 using ecmascript::kungfu::Verifier;
53 // std::numeric_limits<T>::quiet_NaN().
SilenceNaN(T x)54 template <class T> T SilenceNaN(T x)
55 {
56     assert(std::isnan(x));
57     // Do some calculation to make a signalling NaN quiet.
58     return x - x;
59 }
60 
HWTEST_F_L0(InstructionCombineTests,Int64AddTest)61 HWTEST_F_L0(InstructionCombineTests, Int64AddTest)
62 {
63     // construct a circuit
64     ecmascript::NativeAreaAllocator allocator;
65     Circuit circuit(&allocator);
66     ecmascript::Chunk chunk(&allocator);
67     GateAccessor acc(&circuit);
68     CircuitBuilder builder(&circuit);
69     Environment env(0, &builder);
70     builder.SetEnvironment(&env);
71     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
72     InstructionCombine instcombie(&circuit, &visitor, &chunk);
73 
74     // test  x + 0 => x
75     {
76         auto x = builder.Arguments(1);
77         auto const_i64_0 = builder.Int64(0);
78         auto test_x_add_0 = builder.Int64Add(x, const_i64_0);
79         EXPECT_EQ(instcombie.VisitGate(test_x_add_0), x);
80     }
81     // test  1 + 2 => 3
82     {
83         auto const_i64_1 = builder.Int64(1);
84         auto const_i64_2 = builder.Int64(2);
85         auto result = instcombie.VisitGate(builder.Int64Add(const_i64_1, const_i64_2));
86         EXPECT_EQ(acc.IsConstantValue(result, 3), true);
87     }
88     // Test for 64-bit integer wraparound: 9223372036854775807 + 1 => -9223372036854775808
89     {
90         auto const_i64_max = builder.Int64(9223372036854775807);
91         auto const_i64_1 = builder.Int64(1);
92         auto result = instcombie.VisitGate(builder.Int64Add(const_i64_max, const_i64_1));
93 
94         // Cast -9223372036854775808 to uint64_t for comparison
95         EXPECT_EQ(acc.IsConstantValue(result, static_cast<uint64_t>(9223372036854775808ULL)), true);
96     }
97 
98     // test ((y+max)+1)
99     {
100         auto y = builder.Arguments(2);
101         auto const_i64_max = builder.Int64(9223372036854775807);
102         auto const_i64_1 = builder.Int64(1);
103         auto result = instcombie.VisitGate(builder.Int64Add(builder.Int64Add(y, const_i64_max), const_i64_1));
104         Int64BinopMatcher result_m(result, &circuit);
105         EXPECT_EQ(result_m.Left().Gate(), y);
106         EXPECT_EQ(result_m.Right().ResolvedValue(), static_cast<uint64_t>(9223372036854775808ULL));
107     }
108     // test ((z+1)+2) => (z+3)  [z+1] not Owns
109     {
110         auto z = builder.Arguments(3);
111         auto const_i64_1 = builder.Int64(1);
112         auto const_i64_2 = builder.Int64(2);
113         auto z_add_1 = builder.Int64Add(z, const_i64_1);
114         auto intfer = builder.Int64Add(z_add_1, z_add_1);
115         (void)intfer;
116         auto result = instcombie.VisitGate(builder.Int64Add(z_add_1, const_i64_2));
117         EXPECT_EQ(result, Circuit::NullGate());
118     }
119 }
120 
121 
HWTEST_F_L0(InstructionCombineTests,Int32AddTest)122 HWTEST_F_L0(InstructionCombineTests, Int32AddTest)
123 {
124     // construct a circuit
125     ecmascript::NativeAreaAllocator allocator;
126     Circuit circuit(&allocator);
127     ecmascript::Chunk chunk(&allocator);
128     GateAccessor acc(&circuit);
129     CircuitBuilder builder(&circuit);
130     Environment env(0, &builder);
131     builder.SetEnvironment(&env);
132     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
133     InstructionCombine instcombie(&circuit, &visitor, &chunk);
134     // test  x + 0 => x
135     {
136         auto x = builder.Arguments(1);
137         auto const_i32_0 = builder.Int32(0);
138         auto test_x_add_0 = builder.Int32Add(x, const_i32_0);
139         EXPECT_EQ(instcombie.VisitGate(test_x_add_0), x);
140     }
141 
142     // test  1 + 2 => 3
143     {
144         auto const_i32_1 = builder.Int32(1);
145         auto const_i32_2 = builder.Int32(2);
146         auto result = instcombie.VisitGate(builder.Int32Add(const_i32_1, const_i32_2));
147         EXPECT_EQ(acc.IsConstantValue(result, 3), true);
148     }
149 
150     // Test for 32-bit integer wraparound: 2147483647 + 1 => -2147483648
151     {
152         auto const_i32_max = builder.Int32(2147483647);
153         auto const_i32_1 = builder.Int32(1);
154         auto result = instcombie.VisitGate(builder.Int32Add(const_i32_max, const_i32_1));
155 
156         // Check if the result is -2147483648, demonstrating wraparound behavior
157         EXPECT_EQ(acc.IsConstantValue(result, static_cast<uint64_t>(-2147483648)), true);
158     }
159 
160 
161     // test (0 - x) + y => y - x
162     {
163         auto x = builder.Arguments(2);
164         auto y = builder.Arguments(3);
165         auto zero = builder.Int32(0);
166         auto result = instcombie.VisitGate(builder.Int32Add(builder.Int32Sub(zero, x), y));
167         Int32BinopMatcher m(result, &circuit);
168         EXPECT_EQ(m.Left().Gate(), y);
169         EXPECT_EQ(m.Right().Gate(), x);
170         EXPECT_EQ(m.Opcode(), OpCode::SUB);
171     }
172     // test  y + (0 - x) => y - x
173     {
174         auto x = builder.Arguments(4);
175         auto y = builder.Arguments(5);
176         auto zero = builder.Int32(0);
177         auto result = instcombie.VisitGate(builder.Int32Add(y, builder.Int32Sub(zero, x)));
178         Int32BinopMatcher m(result, &circuit);
179         EXPECT_EQ(m.Left().Gate(), y);
180         EXPECT_EQ(m.Right().Gate(), x);
181         EXPECT_EQ(m.Opcode(), OpCode::SUB);
182     }
183 
184     // test ((y+1)+2) => (y+3)  [y+1] Owns
185     {
186         auto y = builder.Arguments(6);
187         auto const_1 = builder.Int32(1);
188         auto const_2 = builder.Int32(2);
189         auto result = instcombie.VisitGate(builder.Int32Add(builder.Int32Add(y, const_1), const_2));
190         Int32BinopMatcher result_m(result, &circuit);
191         EXPECT_EQ(result_m.Left().Gate(), y);
192         EXPECT_EQ(result_m.Right().ResolvedValue(), 3);
193     }
194 
195     // test ((y+max)+1)
196     {
197         auto y = builder.Arguments(6);
198         auto const_1 = builder.Int32(2147483647);
199         auto const_2 = builder.Int32(1);
200         auto result = instcombie.VisitGate(builder.Int32Add(builder.Int32Add(y, const_1), const_2));
201         Int32BinopMatcher result_m(result, &circuit);
202         EXPECT_EQ(result_m.Left().Gate(), y);
203         EXPECT_EQ(result_m.Right().ResolvedValue(), static_cast<uint64_t>(-2147483648));
204     }
205 }
206 
207 
HWTEST_F_L0(InstructionCombineTests,Int64SubTest)208 HWTEST_F_L0(InstructionCombineTests, Int64SubTest)
209 {
210     // construct a circuit
211     ecmascript::NativeAreaAllocator allocator;
212     Circuit circuit(&allocator);
213     ecmascript::Chunk chunk(&allocator);
214     GateAccessor acc(&circuit);
215     CircuitBuilder builder(&circuit);
216     Environment env(0, &builder);
217     builder.SetEnvironment(&env);
218     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
219     InstructionCombine instcombie(&circuit, &visitor, &chunk);
220 
221     // test  x - 0 => x
222     {
223         auto x = builder.Arguments(1);
224         auto const_i64_0 = builder.Int64(0);
225         auto test_x_add_0 = builder.Int64Sub(x, const_i64_0);
226         EXPECT_EQ(instcombie.VisitGate(test_x_add_0), x);
227     }
228     // test  1 - 2 => -1
229     {
230         auto const_i64_1 = builder.Int64(1);
231         auto const_i64_2 = builder.Int64(2);
232         auto result = instcombie.VisitGate(builder.Int64Sub(const_i64_1, const_i64_2));
233         EXPECT_EQ(acc.IsConstantValue(result, (int64_t)-1), true);
234     }
235 
236     // Test for 64-bit integer wraparound subtraction: -9223372036854775808 - 1 => 9223372036854775807
237     {
238         auto const_i64_min = builder.Int64(-9223372036854775807 - 1); // -9223372036854775808
239         auto const_i64_1 = builder.Int64(1);
240         auto result = instcombie.VisitGate(builder.Int64Sub(const_i64_min, const_i64_1));
241 
242         // Expect the result to wrap around to 9223372036854775807
243         // Casting to uint64_t for the comparison
244         EXPECT_EQ(acc.IsConstantValue(result, static_cast<uint64_t>(9223372036854775807)), true);
245     }
246 
247 
248     // test x -x => 0
249     {
250         auto x = builder.Arguments(2);
251         auto result = instcombie.VisitGate(builder.Int64Sub(x, x));
252         EXPECT_EQ(acc.IsConstantValue(result, 0), true);
253     }
254 
255     // test x - k = x + (-k)
256     {
257         auto x = builder.Arguments(3);
258         auto const_1 = builder.Int64(-1);
259         auto result = instcombie.VisitGate(builder.Int64Sub(x, const_1));
260         Int64BinopMatcher m(result, &circuit);
261         EXPECT_EQ(m.Left().Gate(), x);
262         EXPECT_EQ(m.Right().ResolvedValue(), 1);
263         EXPECT_EQ(m.Opcode(), OpCode::ADD);
264     }
265     // Test for x - k = x + (-k) when k is the minimum int64_t value
266     {
267         auto x = builder.Arguments(3);
268         auto const_min = builder.Int64(INT64_MIN); // Minimum int64_t value
269         auto result = instcombie.VisitGate(builder.Int64Sub(x, const_min));
270 
271         // Due to overflow, -k should wrap around to INT64_MIN.
272         // The opcode should be ADD if the subtraction is reinterpreted as addition with -k.
273         Int64BinopMatcher m(result, &circuit);
274         EXPECT_EQ(m.Left().Gate(), x);
275         EXPECT_EQ(m.Right().ResolvedValue(), INT64_MIN); // Here, we expect that -k has wrapped around to INT64_MIN
276         EXPECT_EQ(m.Opcode(), OpCode::ADD);
277     }
278 }
279 
HWTEST_F_L0(InstructionCombineTests,Int32SubTest)280 HWTEST_F_L0(InstructionCombineTests, Int32SubTest)
281 {
282     // construct a circuit
283     ecmascript::NativeAreaAllocator allocator;
284     Circuit circuit(&allocator);
285     ecmascript::Chunk chunk(&allocator);
286     GateAccessor acc(&circuit);
287     CircuitBuilder builder(&circuit);
288     Environment env(0, &builder);
289     builder.SetEnvironment(&env);
290     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
291     InstructionCombine instcombie(&circuit, &visitor, &chunk);
292 
293     // test  x - 0 => x
294     {
295         auto x = builder.Arguments(1);
296         auto const_i32_0 = builder.Int32(0);
297         auto test_x_add_0 = builder.Int32Sub(x, const_i32_0);
298         EXPECT_EQ(instcombie.VisitGate(test_x_add_0), x);
299     }
300     // test  1 - 2 => -1
301     {
302         auto const_i32_1 = builder.Int32(1);
303         auto const_i32_2 = builder.Int32(2);
304         auto result = instcombie.VisitGate(builder.Int32Sub(const_i32_1, const_i32_2));
305         EXPECT_EQ(acc.IsConstantValue(result, (int32_t)-1), true);
306     }
307 
308     // Test for 32-bit integer wraparound subtraction: -2147483648 - 1 => 2147483647
309     {
310         auto const_i32_min = builder.Int32(-2147483647 - 1); // -2147483648
311         auto const_i32_1 = builder.Int32(1);
312         auto result = instcombie.VisitGate(builder.Int32Sub(const_i32_min, const_i32_1));
313 
314         // Expect the result to wrap around to 2147483647
315         // Casting to uint64_t for the comparison, assuming IsConstantValue accepts uint64_t
316         EXPECT_EQ(acc.IsConstantValue(result, static_cast<uint64_t>(2147483647)), true);
317     }
318 
319     // test x -x => 0
320     {
321         auto x = builder.Arguments(2);
322         auto result = instcombie.VisitGate(builder.Int32Sub(x, x));
323         EXPECT_EQ(acc.IsConstantValue(result, 0), true);
324     }
325 
326     // test x - k = x + (-k)
327     {
328         auto x = builder.Arguments(3);
329         auto const_1 = builder.Int32(-1);
330         auto result = instcombie.VisitGate(builder.Int32Sub(x, const_1));
331         Int32BinopMatcher m(result, &circuit);
332         EXPECT_EQ(m.Left().Gate(), x);
333         EXPECT_EQ(m.Right().ResolvedValue(), 1);
334         EXPECT_EQ(m.Opcode(), OpCode::ADD);
335     }
336 
337     // Test for x - k = x + (-k) when k is the minimum int32_t value
338     {
339         auto x = builder.Arguments(3);
340         auto const_min = builder.Int32(INT32_MIN); // Minimum int32_t value
341         auto result = instcombie.VisitGate(builder.Int32Sub(x, const_min));
342 
343         // Due to overflow, -k should wrap around to INT32_MIN.
344         // The opcode should be ADD if the subtraction is reinterpreted as addition with -k.
345         Int32BinopMatcher m(result, &circuit);
346         EXPECT_EQ(m.Left().Gate(), x);
347         EXPECT_EQ(m.Right().ResolvedValue(), INT32_MIN); // Here, we expect that -k has wrapped around to INT32_MIN
348         EXPECT_EQ(m.Opcode(), OpCode::ADD);
349     }
350 }
351 
352 
HWTEST_F_L0(InstructionCombineTests,Int64MulTest)353 HWTEST_F_L0(InstructionCombineTests, Int64MulTest)
354 {
355     // construct a circuit
356     ecmascript::NativeAreaAllocator allocator;
357     Circuit circuit(&allocator);
358     ecmascript::Chunk chunk(&allocator);
359     GateAccessor acc(&circuit);
360     CircuitBuilder b(&circuit);
361     Environment env(0, &b);
362     b.SetEnvironment(&env);
363     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
364     InstructionCombine instcombie(&circuit, &visitor, &chunk);
365 
366     // test  x * 0 => 0
367     {
368         auto x = b.Arguments(1);
369         auto const_0 = b.Int64(0);
370         auto result = b.Int64Mul(x, const_0);
371         EXPECT_EQ(instcombie.VisitGate(result), const_0);
372     }
373     // test  x * 1 => x
374     {
375         auto x = b.Arguments(1);
376         auto const_1 = b.Int64(1);
377         auto result = b.Int64Mul(x, const_1);
378         EXPECT_EQ(instcombie.VisitGate(result), x);
379     }
380 
381     // test  1 * 2 => 2
382     {
383         auto const_1 = b.Int64(1);
384         auto const_2 = b.Int64(2);
385         auto result = instcombie.VisitGate(b.Int64Mul(const_1, const_2));
386         EXPECT_EQ(acc.IsConstantValue(result, (int64_t)2), true);
387     }
388     // Test for 64-bit integer wraparound multiplication: 9223372036854775807 * 2 => -2
389     {
390         auto const_i64_max = b.Int64(9223372036854775807); // Max int64_t value
391         auto const_i64_2 = b.Int64(2);
392         auto result = instcombie.VisitGate(b.Int64Mul(const_i64_max, const_i64_2));
393 
394         // Expect the result to wrap around to -2
395         // Casting to uint64_t for the comparison
396         EXPECT_EQ(acc.IsConstantValue(result, static_cast<uint64_t>(-2)), true);
397     }
398 
399     // test x * -1 => 0 - X
400     {
401         auto x = b.Arguments(2);
402         auto result = instcombie.VisitGate(b.Int64Mul(x, b.Int64(-1)));
403         Int64BinopMatcher m(result, &circuit);
404 
405         EXPECT_EQ(m.Left().ResolvedValue(), 0);
406         EXPECT_EQ(m.Right().Gate(), x);
407         EXPECT_EQ(m.Opcode(), OpCode::SUB);
408     }
409 
410     // test x * 2^n => x << n
411     {
412         auto x = b.Arguments(3);
413         auto const_4 = b.Int64(4);
414         auto result = instcombie.VisitGate(b.Int64Mul(x, const_4));
415         Int64BinopMatcher m(result, &circuit);
416         EXPECT_EQ(m.Left().Gate(), x);
417         EXPECT_EQ(m.Right().ResolvedValue(), 2);
418         EXPECT_EQ(m.Opcode(), OpCode::LSL);
419     }
420 
421     // (x * Int64Constant(a)) * Int64Constant(b)) => x * Int64Constant(a * b)
422     {
423         auto x = b.Arguments(4);
424         auto const_4 = b.Int64(4);
425         auto const_5 = b.Int64(5);
426         auto result = instcombie.VisitGate(b.Int64Mul(b.Int64Mul(x, const_4), const_5));
427         Int64BinopMatcher m(result, &circuit);
428         EXPECT_EQ(m.Left().Gate(), x);
429         EXPECT_EQ(m.Right().ResolvedValue(), 20);
430         EXPECT_EQ(m.Opcode(), OpCode::MUL);
431     }
432     // Test for (x * Int64Constant(a)) * Int64Constant(b)) => x * Int64Constant(a * b) with overflow
433     {
434         auto x = b.Arguments(4);
435         auto const_almost_max = b.Int64(INT64_MAX - 1); // INT64_MAX - 1
436         auto const_3 = b.Int64(3);
437         auto result = instcombie.VisitGate(b.Int64Mul(b.Int64Mul(x, const_almost_max), const_3));
438 
439         // Due to overflow, a * b should wrap around.
440         // The opcode should still be MUL.
441         Int64BinopMatcher m(result, &circuit);
442         EXPECT_EQ(m.Left().Gate(), x);
443         EXPECT_EQ(m.Right().ResolvedValue(), 9223372036854775802);
444 
445         EXPECT_EQ(m.Opcode(), OpCode::MUL);
446     }
447 }
448 
HWTEST_F_L0(InstructionCombineTests,Int32MulTest)449 HWTEST_F_L0(InstructionCombineTests, Int32MulTest)
450 {
451     // construct a circuit
452     ecmascript::NativeAreaAllocator allocator;
453     Circuit circuit(&allocator);
454     ecmascript::Chunk chunk(&allocator);
455     GateAccessor acc(&circuit);
456     CircuitBuilder b(&circuit);
457     Environment env(0, &b);
458     b.SetEnvironment(&env);
459     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
460     InstructionCombine instcombie(&circuit, &visitor, &chunk);
461 
462     // test  x * 0 => 0
463     {
464         auto x = b.Arguments(1);
465         auto const_0 = b.Int32(0);
466         auto result = b.Int32Mul(x, const_0);
467         EXPECT_EQ(instcombie.VisitGate(result), const_0);
468     }
469     // test  x * 1 => x
470     {
471         auto x = b.Arguments(1);
472         auto const_1 = b.Int32(1);
473         auto result = b.Int32Mul(x, const_1);
474         EXPECT_EQ(instcombie.VisitGate(result), x);
475     }
476 
477 
478     // test  1 * 2 => 2
479     {
480         auto const_1 = b.Int32(1);
481         auto const_2 = b.Int32(2);
482         auto result = instcombie.VisitGate(b.Int32Mul(const_1, const_2));
483         EXPECT_NE(result, Circuit::NullGate());
484         EXPECT_EQ(acc.IsConstantValue(result, (int32_t)2), true);
485     }
486 
487     // Test for 32-bit integer wraparound multiplication: 2147483647 * 2 => -2
488     {
489         auto const_i32_max = b.Int32(2147483647); // Max int32_t value
490         auto const_i32_2 = b.Int32(2);
491         auto result = instcombie.VisitGate(b.Int32Mul(const_i32_max, const_i32_2));
492 
493         // Expect the result to wrap around to -2
494         // Casting to uint32_t for the comparison
495         EXPECT_NE(result, Circuit::NullGate());
496         EXPECT_EQ(acc.GetInt32FromConstant(result), -2);
497     }
498 
499 
500     // test x * -1 => 0 - X
501     {
502         auto x = b.Arguments(2);
503         auto result = instcombie.VisitGate(b.Int32Mul(x, b.Int32(-1)));
504         EXPECT_NE(result, Circuit::NullGate());
505         Int32BinopMatcher m(result, &circuit);
506 
507         EXPECT_EQ(m.Left().ResolvedValue(), 0);
508         EXPECT_EQ(m.Right().Gate(), x);
509         EXPECT_EQ(m.Opcode(), OpCode::SUB);
510     }
511 
512     // test x * 2^n => x << n
513     {
514         auto x = b.Arguments(3);
515         auto const_4 = b.Int32(4);
516         auto result = instcombie.VisitGate(b.Int32Mul(x, const_4));
517         EXPECT_NE(result, Circuit::NullGate());
518         Int32BinopMatcher m(result, &circuit);
519         EXPECT_EQ(m.Left().Gate(), x);
520         EXPECT_EQ(m.Right().ResolvedValue(), 2);
521         EXPECT_EQ(m.Opcode(), OpCode::LSL);
522     }
523 
524     // (x * Int32Constant(a)) * Int32Constant(b)) => x * Int32Constant(a * b)
525     {
526         auto x = b.Arguments(4);
527         auto const_4 = b.Int32(4);
528         auto const_5 = b.Int32(5);
529         auto result = instcombie.VisitGate(b.Int32Mul(b.Int32Mul(x, const_4), const_5));
530         EXPECT_NE(result, Circuit::NullGate());
531         Int32BinopMatcher m(result, &circuit);
532         EXPECT_EQ(m.Left().Gate(), x);
533         EXPECT_EQ(m.Right().ResolvedValue(), 20);
534         EXPECT_EQ(m.Opcode(), OpCode::MUL);
535     }
536     // Test for (x * Int32Constant(a)) * Int32Constant(b)) => x * Int32Constant(a * b) with overflow
537     {
538         auto x = b.Arguments(4);
539         auto const_almost_max = b.Int32(INT32_MAX - 1); // INT32_MAX - 1
540         auto const_3 = b.Int32(3);
541         auto result = instcombie.VisitGate(b.Int32Mul(b.Int32Mul(x, const_almost_max), const_3));
542 
543         // Due to overflow, a * b should wrap around.
544         // The opcode should still be MUL.
545         Int32BinopMatcher m(result, &circuit);
546         EXPECT_EQ(m.Left().Gate(), x);
547 
548         EXPECT_EQ(m.Right().ResolvedValue(), static_cast<uint32_t>(2147483642));
549 
550         EXPECT_EQ(m.Opcode(), OpCode::MUL);
551     }
552 }
553 
HWTEST_F_L0(InstructionCombineTests,Int64DivTest)554 HWTEST_F_L0(InstructionCombineTests, Int64DivTest)
555 {
556     // construct a circuit
557     ecmascript::NativeAreaAllocator allocator;
558     Circuit circuit(&allocator);
559     ecmascript::Chunk chunk(&allocator);
560     GateAccessor acc(&circuit);
561     CircuitBuilder b(&circuit);
562     Environment env(0, &b);
563     b.SetEnvironment(&env);
564     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
565     InstructionCombine instcombie(&circuit, &visitor, &chunk);
566 
567     // test  0/x => 0
568     {
569         auto x = b.Arguments(1);
570         auto const_0 = b.Int64(0);
571         auto result = b.Int64Div(const_0, x);
572         EXPECT_EQ(instcombie.VisitGate(result), const_0);
573     }
574 
575 
576     // test  x/0 => 0
577     {
578         auto x = b.Arguments(1);
579         auto const_0 = b.Int64(0);
580         auto result = b.Int64Div(x, const_0);
581         EXPECT_EQ(instcombie.VisitGate(result), const_0);
582     }
583 
584     // test  x / 1 => x
585     {
586         auto x = b.Arguments(1);
587         auto const_1 = b.Int64(1);
588         auto result = b.Int64Div(x, const_1);
589         EXPECT_EQ(instcombie.VisitGate(result), x);
590     }
591 
592     // test  4 / 2 => 4
593     {
594         auto const_4 = b.Int64(4);
595         auto const_2 = b.Int64(2);
596         auto result = instcombie.VisitGate(b.Int64Div(const_4, const_2));
597         EXPECT_NE(result, Circuit::NullGate());
598         EXPECT_EQ(acc.IsConstantValue(result, (int64_t)2), true);
599     }
600 
601     // test x / -1 => 0 - X
602     {
603         auto x = b.Arguments(2);
604         auto result = instcombie.VisitGate(b.Int64Div(x, b.Int64(-1)));
605 
606         EXPECT_NE(result, Circuit::NullGate());
607         Int64BinopMatcher m(result, &circuit);
608 
609         EXPECT_EQ(m.Left().ResolvedValue(), 0);
610         EXPECT_EQ(m.Right().Gate(), x);
611         EXPECT_EQ(m.Opcode(), OpCode::SUB);
612     }
613 
614     // test x / -5 => 0 - x / 5
615     {
616         auto x = b.Arguments(2);
617         auto result = instcombie.VisitGate(b.Int64Div(x, b.Int64(-5)));
618         EXPECT_NE(result, Circuit::NullGate());
619         Int64BinopMatcher m(result, &circuit);
620 
621         EXPECT_EQ(m.Left().ResolvedValue(), 0);
622         EXPECT_EQ(m.Opcode(), OpCode::SUB);
623         Int64BinopMatcher m_right(m.Right().Gate(), &circuit);
624 
625         EXPECT_EQ(m_right.Left().Gate(), x);
626         EXPECT_EQ(m_right.Opcode(), OpCode::SDIV);
627         EXPECT_EQ(m_right.Right().ResolvedValue(), 5);
628     }
629 
630     // test x / -9,223,372,036,854,775,808
631     {
632         auto x = b.Arguments(2);
633         auto result = instcombie.VisitGate(b.Int64Div(x, b.Int64(std::numeric_limits<int64_t>::min())));
634         EXPECT_EQ(result, Circuit::NullGate());
635     }
636 }
637 
HWTEST_F_L0(InstructionCombineTests,Int32DivTest)638 HWTEST_F_L0(InstructionCombineTests, Int32DivTest)
639 {
640     // construct a circuit
641     ecmascript::NativeAreaAllocator allocator;
642     Circuit circuit(&allocator);
643     ecmascript::Chunk chunk(&allocator);
644     GateAccessor acc(&circuit);
645     CircuitBuilder b(&circuit);
646     Environment env(0, &b);
647     b.SetEnvironment(&env);
648     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
649     InstructionCombine instcombie(&circuit, &visitor, &chunk);
650 
651     // test  0/x => 0
652     {
653         auto x = b.Arguments(1);
654         auto const_0 = b.Int32(0);
655         auto result = b.Int32Div(const_0, x);
656         EXPECT_EQ(instcombie.VisitGate(result), const_0);
657     }
658 
659 
660     // test  x/0 => 0
661     {
662         auto x = b.Arguments(1);
663         auto const_0 = b.Int32(0);
664         auto result = b.Int32Div(x, const_0);
665         EXPECT_EQ(instcombie.VisitGate(result), const_0);
666     }
667 
668     // test  x / 1 => x
669     {
670         auto x = b.Arguments(1);
671         auto const_1 = b.Int32(1);
672         auto result = b.Int32Div(x, const_1);
673         EXPECT_EQ(instcombie.VisitGate(result), x);
674     }
675 
676     // test  4 / 2 => 4
677     {
678         auto const_4 = b.Int32(4);
679         auto const_2 = b.Int32(2);
680         auto result = instcombie.VisitGate(b.Int32Div(const_4, const_2));
681 
682         EXPECT_NE(result, Circuit::NullGate());
683         EXPECT_EQ(acc.IsConstantValue(result, (int32_t)2), true);
684     }
685 
686     // test x / -1 => 0 - X
687     {
688         auto x = b.Arguments(2);
689         auto result = instcombie.VisitGate(b.Int32Div(x, b.Int32(-1)));
690         EXPECT_NE(result, Circuit::NullGate());
691         Int32BinopMatcher m(result, &circuit);
692 
693         EXPECT_EQ(m.Left().ResolvedValue(), 0);
694         EXPECT_EQ(m.Right().Gate(), x);
695         EXPECT_EQ(m.Opcode(), OpCode::SUB);
696     }
697 
698     // test x / -5 => 0 - x / 5
699     {
700         auto x = b.Arguments(2);
701         auto result = instcombie.VisitGate(b.Int32Div(x, b.Int32(-5)));
702         EXPECT_NE(result, Circuit::NullGate());
703         Int32BinopMatcher m(result, &circuit);
704 
705         EXPECT_EQ(m.Left().ResolvedValue(), 0);
706         EXPECT_EQ(m.Opcode(), OpCode::SUB);
707         Int32BinopMatcher m_right(m.Right().Gate(), &circuit);
708 
709         EXPECT_EQ(m_right.Left().Gate(), x);
710         EXPECT_EQ(m_right.Opcode(), OpCode::SDIV);
711         EXPECT_EQ(m_right.Right().ResolvedValue(), 5);
712     }
713 }
714 
HWTEST_F_L0(InstructionCombineTests,DoubleBinOptest)715 HWTEST_F_L0(InstructionCombineTests, DoubleBinOptest)
716 {
717     // construct a circuit
718     ecmascript::NativeAreaAllocator allocator;
719     Circuit circuit(&allocator);
720     ecmascript::Chunk chunk(&allocator);
721     GateAccessor acc(&circuit);
722     CircuitBuilder b(&circuit);
723     Environment env(0, &b);
724     b.SetEnvironment(&env);
725     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
726     InstructionCombine instcombie(&circuit, &visitor, &chunk);
727 
728     // test  x op NaN => NaN
729     {
730         auto x = b.Arguments(1);
731         auto nan = b.NanValue();
732         auto zero = b.Double(0);
733         Float64Matcher nan_m(nan, &circuit);
734         EXPECT_EQ(nan_m.HasResolvedValue(), true);
735 
736 
737         EXPECT_EQ(instcombie.VisitGate(b.DoubleAdd(x, nan)), nan);
738         EXPECT_EQ(instcombie.VisitGate(b.DoubleSub(x, nan)), nan);
739         EXPECT_EQ(instcombie.VisitGate(b.DoubleMul(x, nan)), nan);
740         EXPECT_EQ(instcombie.VisitGate(b.DoubleDiv(x, nan)), nan);
741         // x % 0 => NaN
742         EXPECT_EQ(instcombie.VisitGate(b.DoubleMod(x, zero)), nan);
743     }
744     // test  NaN op op => NaN
745     {
746         auto x = b.Arguments(1);
747         auto nan = b.NanValue();
748         EXPECT_EQ(instcombie.VisitGate(b.DoubleAdd(nan, x)), nan);
749         EXPECT_EQ(instcombie.VisitGate(b.DoubleSub(nan, x)), nan);
750         EXPECT_EQ(instcombie.VisitGate(b.DoubleDiv(nan, x)), nan);
751         EXPECT_EQ(instcombie.VisitGate(b.DoubleMod(nan, x)), nan);
752     }
753 
754     // test 10.4 op 5.2 => ?
755     {
756         auto value1 = b.Double(10.1);
757         auto value2 = b.Double(5.2);
758         auto result = instcombie.VisitGate(b.DoubleAdd(value1, value2));
759         EXPECT_NE(result, Circuit::NullGate());
760         EXPECT_EQ(acc.GetOpCode(result), OpCode::CONSTANT);
761 
762         result = instcombie.VisitGate(b.DoubleAdd(value1, value2));
763         EXPECT_NE(result, Circuit::NullGate());
764         EXPECT_EQ(acc.GetOpCode(result), OpCode::CONSTANT);
765 
766         result = instcombie.VisitGate(b.DoubleSub(value1, value2));
767         EXPECT_NE(result, Circuit::NullGate());
768         EXPECT_EQ(acc.GetOpCode(result), OpCode::CONSTANT);
769 
770         result = instcombie.VisitGate(b.DoubleDiv(value1, value2));
771         EXPECT_NE(result, Circuit::NullGate());
772         EXPECT_EQ(acc.GetOpCode(result), OpCode::CONSTANT);
773     }
774 
775     // test x * -1.0 => -0.0 - x
776     {
777         auto x = b.Arguments(1);
778         auto neg_one = b.Double(-1);
779         auto result = instcombie.VisitGate(b.DoubleMul(x, neg_one));
780 
781         EXPECT_NE(result, Circuit::NullGate());
782         Float64BinopMatcher m(result, &circuit);
783         EXPECT_EQ(m.Opcode(), OpCode::SUB);
784         EXPECT_EQ(m.Left().ResolvedValue(), -0.0);
785         EXPECT_EQ(m.Right().Gate(), x);
786     }
787 
788     // test x * -1.0 => -0.0 - x
789     {
790         auto x = b.Arguments(1);
791         auto two = b.Double(2.0);
792         auto result = instcombie.VisitGate(b.DoubleMul(x, two));
793         EXPECT_NE(result, Circuit::NullGate());
794         Float64BinopMatcher m(result, &circuit);
795         EXPECT_EQ(m.Opcode(), OpCode::ADD);
796         EXPECT_EQ(m.Left().Gate(), x);
797         EXPECT_EQ(m.Right().Gate(), x);
798     }
799 }
HWTEST_F_L0(InstructionCombineTests,Int32Modtest)800 HWTEST_F_L0(InstructionCombineTests, Int32Modtest)
801 {
802     // construct a circuit
803     ecmascript::NativeAreaAllocator allocator;
804     Circuit circuit(&allocator);
805     ecmascript::Chunk chunk(&allocator);
806     GateAccessor acc(&circuit);
807     CircuitBuilder b(&circuit);
808     Environment env(0, &b);
809     b.SetEnvironment(&env);
810     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
811     InstructionCombine instcombie(&circuit, &visitor, &chunk);
812     {
813         auto x = b.Arguments(1);
814         auto zero = b.Int32(0);
815         auto one = b.Int32(1);
816         auto neg_one = b.Int32(-1);
817         auto four = b.Int32(4);
818         auto two = b.Int32(2);
819 
820         // 0 % x  => 0
821         // x % 0  => 0
822         // x % 1  => 0
823         // x % -1 => 0
824         // x % x  => 0
825         EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(x, zero)), zero);
826         EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(zero, x)), zero);
827         EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(x, one)), zero);
828         EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(x, neg_one)), zero);
829         EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(x, x)), zero);
830         // 2%4 =>2
831         EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(two, four)), two);
832     }
833 }
834 
HWTEST_F_L0(InstructionCombineTests,Int32AddOverFlowtest)835 HWTEST_F_L0(InstructionCombineTests, Int32AddOverFlowtest)
836 {
837     // construct a circuit
838     ecmascript::NativeAreaAllocator allocator;
839     Circuit circuit(&allocator);
840     ecmascript::Chunk chunk(&allocator);
841     GateAccessor acc(&circuit);
842     CircuitBuilder b(&circuit);
843     Environment env(0, &b);
844     b.SetEnvironment(&env);
845     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
846     InstructionCombine instcombie(&circuit, &visitor, &chunk);
847 
848     // IsFoldable overflow
849     // 2147483647 + 1 =-2147483648
850     {
851         auto add_overflow = b.AddWithOverflow(b.Int32(2147483647), b.Int32(1));
852         auto add_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, add_overflow, b.Int32(0));
853         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, add_overflow, b.Int32(1));
854         EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(add_result)), -2147483648);
855         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(true));
856     }
857 
858     // IsFoldable no overflow
859     {
860         auto add_overflow = b.AddWithOverflow(b.Int32(2147483646), b.Int32(1));
861         auto add_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, add_overflow, b.Int32(0));
862         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, add_overflow, b.Int32(1));
863         EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(add_result)), 2147483647);
864         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
865     }
866 
867 
868     // x add 0 => 0
869     // IsFoldable no overflow
870     {
871         auto x = b.Arguments(1);
872         auto add_overflow = b.AddWithOverflow(x, b.Int32(0));
873         auto add_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, add_overflow, b.Int32(0));
874         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, add_overflow, b.Int32(1));
875         EXPECT_EQ(instcombie.VisitGate(add_result), x);
876         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
877     }
878 }
879 
HWTEST_F_L0(InstructionCombineTests,Int32SubOverFlowTest)880 HWTEST_F_L0(InstructionCombineTests, Int32SubOverFlowTest)
881 {
882     // construct a circuit
883     ecmascript::NativeAreaAllocator allocator;
884     Circuit circuit(&allocator);
885     ecmascript::Chunk chunk(&allocator);
886     GateAccessor acc(&circuit);
887     CircuitBuilder b(&circuit);
888     Environment env(0, &b);
889     b.SetEnvironment(&env);
890     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
891     InstructionCombine instcombie(&circuit, &visitor, &chunk);
892 
893     // IsFoldable overflow
894     // -2147483648 - 1 = 2147483647
895     {
896         auto sub_overflow = b.SubWithOverflow(b.Int32(-2147483648), b.Int32(1));
897         auto sub_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, sub_overflow, b.Int32(0));
898         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, sub_overflow, b.Int32(1));
899         EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(sub_result)), 2147483647);
900         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(true));
901     }
902 
903     // IsFoldable no overflow
904     {
905         auto sub_overflow = b.SubWithOverflow(b.Int32(2147483647), b.Int32(1));
906         auto sub_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, sub_overflow, b.Int32(0));
907         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, sub_overflow, b.Int32(1));
908         EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(sub_result)), 2147483646);
909         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
910     }
911 
912     // x sub 0 => x
913     // IsFoldable no overflow
914     {
915         auto x = b.Arguments(1);
916         auto sub_overflow = b.SubWithOverflow(x, b.Int32(0));
917         auto sub_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, sub_overflow, b.Int32(0));
918         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, sub_overflow, b.Int32(1));
919         EXPECT_EQ(instcombie.VisitGate(sub_result), x);
920         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
921     }
922 }
923 
HWTEST_F_L0(InstructionCombineTests,Int32MulOverFlowTest)924 HWTEST_F_L0(InstructionCombineTests, Int32MulOverFlowTest)
925 {
926     // construct a circuit
927     ecmascript::NativeAreaAllocator allocator;
928     Circuit circuit(&allocator);
929     ecmascript::Chunk chunk(&allocator);
930     GateAccessor acc(&circuit);
931     CircuitBuilder b(&circuit);
932     Environment env(0, &b);
933     b.SetEnvironment(&env);
934     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
935     InstructionCombine instcombie(&circuit, &visitor, &chunk);
936 
937     // IsFoldable overflow
938     // 2147483647 * 2 = -2
939     {
940         auto mul_overflow = b.MulWithOverflow(b.Int32(2147483647), b.Int32(2));
941         auto mul_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, mul_overflow, b.Int32(0));
942         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, mul_overflow, b.Int32(1));
943         EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(mul_result)), -2);
944         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(true));
945     }
946 
947     // IsFoldable no overflow
948     // 1000 * 2 = 2000
949     {
950         auto mul_overflow = b.MulWithOverflow(b.Int32(1000), b.Int32(2));
951         auto mul_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, mul_overflow, b.Int32(0));
952         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, mul_overflow, b.Int32(1));
953         EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(mul_result)), 2000);
954         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
955     }
956 
957     // x * 1 => x
958     // IsFoldable no overflow
959     {
960         auto x = b.Arguments(1);
961         auto mul_overflow = b.MulWithOverflow(x, b.Int32(1));
962         auto mul_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, mul_overflow, b.Int32(0));
963         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, mul_overflow, b.Int32(1));
964         EXPECT_EQ(instcombie.VisitGate(mul_result), x);
965         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
966     }
967 
968     // x * 0 => 0
969     // IsFoldable no overflow
970     {
971         auto x = b.Arguments(1);
972         auto mul_overflow = b.MulWithOverflow(x, b.Int32(0));
973         auto mul_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, mul_overflow, b.Int32(0));
974         auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, mul_overflow, b.Int32(1));
975         EXPECT_EQ(instcombie.VisitGate(mul_result), b.Int32(0));
976         EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
977     }
978 }
979 
HWTEST_F_L0(InstructionCombineTests,Int64_32AndTest)980 HWTEST_F_L0(InstructionCombineTests, Int64_32AndTest)
981 {
982     // construct a circuit
983     ecmascript::NativeAreaAllocator allocator;
984     Circuit circuit(&allocator);
985     ecmascript::Chunk chunk(&allocator);
986     GateAccessor acc(&circuit);
987     CircuitBuilder b(&circuit);
988     Environment env(0, &b);
989     b.SetEnvironment(&env);
990     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
991     InstructionCombine instcombie(&circuit, &visitor, &chunk);
992     {
993         auto x = b.Arguments(1);
994         auto zero = b.Int64(0);
995         auto neg_one = b.Int64(-1);
996         auto Icmp = b.Equal(x, zero);
997         auto one = b.Int64(1);
998         auto two = b.Int64(2);
999         EXPECT_EQ(instcombie.VisitGate(b.Int64And(x, zero)), zero);   // x & 0  => 0
1000         EXPECT_EQ(instcombie.VisitGate(b.Int64And(x, neg_one)), x);   // x & -1 => x
1001         EXPECT_EQ(instcombie.VisitGate(b.Int64And(Icmp, one)), Icmp); // CMP & 1 => CMP
1002         EXPECT_EQ(instcombie.VisitGate(b.Int64And(two, one)), zero);  // K & K  => K
1003         EXPECT_EQ(instcombie.VisitGate(b.Int64And(x, x)), x);         // x & x => x
1004         // (x & 1) & 2 => x & 0
1005         auto result = instcombie.VisitGate(b.Int64And(b.Int64And(x, one), two));
1006         EXPECT_NE(result, Circuit::NullGate());
1007         Int64BinopMatcher m(result, &circuit);
1008         EXPECT_EQ(m.Left().Gate(), x);
1009         EXPECT_EQ(m.Opcode(), OpCode::AND);
1010         EXPECT_EQ(m.Right().Gate(), zero);
1011     }
1012 
1013     {
1014         auto x = b.Arguments(2);
1015         auto zero = b.Int32(0);
1016         auto neg_one = b.Int32(-1);
1017         auto Icmp = b.Equal(x, zero);
1018         auto one = b.Int32(1);
1019         auto two = b.Int32(2);
1020         EXPECT_EQ(instcombie.VisitGate(b.Int32And(x, zero)), zero);   // x & 0  => 0
1021         EXPECT_EQ(instcombie.VisitGate(b.Int32And(x, neg_one)), x);   // x & -1 => x
1022         EXPECT_EQ(instcombie.VisitGate(b.Int32And(Icmp, one)), Icmp); // CMP & 1 => CMP
1023         EXPECT_EQ(instcombie.VisitGate(b.Int32And(two, one)), zero);  // K & K  => K
1024         EXPECT_EQ(instcombie.VisitGate(b.Int32And(x, x)), x);         // x & x => x
1025         // (x & 1) & 2 => x & 0
1026         auto result = instcombie.VisitGate(b.Int32And(b.Int32And(x, one), two));
1027         EXPECT_NE(result, Circuit::NullGate());
1028         Int64BinopMatcher m(result, &circuit);
1029         EXPECT_EQ(m.Left().Gate(), x);
1030         EXPECT_EQ(m.Opcode(), OpCode::AND);
1031         EXPECT_EQ(m.Right().Gate(), zero);
1032     }
1033 }
1034 
HWTEST_F_L0(InstructionCombineTests,Int64_32OrTest)1035 HWTEST_F_L0(InstructionCombineTests, Int64_32OrTest)
1036 {
1037     // construct a circuit
1038     ecmascript::NativeAreaAllocator allocator;
1039     Circuit circuit(&allocator);
1040     ecmascript::Chunk chunk(&allocator);
1041     GateAccessor acc(&circuit);
1042     CircuitBuilder b(&circuit);
1043     Environment env(0, &b);
1044     b.SetEnvironment(&env);
1045     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1046     InstructionCombine instcombie(&circuit, &visitor, &chunk);
1047     {
1048         auto x = b.Arguments(1);
1049         auto zero = b.Int64(0);
1050         auto neg_one = b.Int64(-1);
1051         auto one = b.Int64(1);
1052         auto two = b.Int64(2);
1053         auto three = b.Int64(3);
1054         EXPECT_EQ(instcombie.VisitGate(b.Int64Or(x, zero)), x);          // x | 0  => x
1055         EXPECT_EQ(instcombie.VisitGate(b.Int64Or(x, neg_one)), neg_one); // x | -1 => -1
1056         EXPECT_EQ(instcombie.VisitGate(b.Int64Or(two, one)), three);     // 2 | 1  => 3
1057         EXPECT_EQ(instcombie.VisitGate(b.Int64Or(x, x)), x);             // x | x => x
1058         // (x & K1) | K2 => x | K2 if K2 has ones for every zero bit in K1.
1059         auto result = instcombie.VisitGate(
1060             b.Int64Or(b.Int64And(x, b.Int64(-6148914691236517205L)), b.Int64(6148914691236517205L)));
1061         EXPECT_NE(result, Circuit::NullGate());
1062         Int64BinopMatcher m(result, &circuit);
1063         EXPECT_EQ(m.Left().Gate(), x);
1064         EXPECT_EQ(m.Opcode(), OpCode::OR);
1065         EXPECT_EQ(m.Right().Gate(), b.Int64(6148914691236517205L));
1066     }
1067 
1068     {
1069         auto x = b.Arguments(1);
1070         auto zero = b.Int32(0);
1071         auto neg_one = b.Int32(-1);
1072         auto one = b.Int32(1);
1073         auto two = b.Int32(2);
1074         auto three = b.Int32(3);
1075         EXPECT_EQ(instcombie.VisitGate(b.Int32Or(x, zero)), x);          // x | 0  => x
1076         EXPECT_EQ(instcombie.VisitGate(b.Int32Or(x, neg_one)), neg_one); // x | -1 => -1
1077         EXPECT_EQ(instcombie.VisitGate(b.Int32Or(two, one)), three);     // 2 | 1  => 3
1078         EXPECT_EQ(instcombie.VisitGate(b.Int32Or(x, x)), x);             // x | x => x
1079         // (x & K1) | K2 => x | K2 if K2 has ones for every zero bit in K1.
1080         auto result = instcombie.VisitGate(b.Int32Or(b.Int32And(x, b.Int32(-1431655765)), b.Int32(1431655765)));
1081         EXPECT_NE(result, Circuit::NullGate());
1082         Int32BinopMatcher m(result, &circuit);
1083         EXPECT_EQ(m.Left().Gate(), x);
1084         EXPECT_EQ(m.Opcode(), OpCode::OR);
1085         EXPECT_EQ(m.Right().Gate(), b.Int32(1431655765));
1086     }
1087 }
1088 
HWTEST_F_L0(InstructionCombineTests,Int64_32XOrTest)1089 HWTEST_F_L0(InstructionCombineTests, Int64_32XOrTest)
1090 {
1091     // construct a circuit
1092     ecmascript::NativeAreaAllocator allocator;
1093     Circuit circuit(&allocator);
1094     ecmascript::Chunk chunk(&allocator);
1095     GateAccessor acc(&circuit);
1096     CircuitBuilder b(&circuit);
1097     Environment env(0, &b);
1098     b.SetEnvironment(&env);
1099     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1100     InstructionCombine instcombie(&circuit, &visitor, &chunk);
1101     {
1102         auto x = b.Arguments(1);
1103         auto zero = b.Int64(0);
1104         auto neg_one = b.Int64(-1);
1105         auto one = b.Int64(1);
1106         auto two = b.Int64(2);
1107         auto three = b.Int64(3);
1108         EXPECT_EQ(instcombie.VisitGate(b.Int64Xor(x, zero)), x);      // x ^ 0 => x
1109         EXPECT_EQ(instcombie.VisitGate(b.Int64Xor(two, one)), three); // 2 | 1  => 3
1110         EXPECT_EQ(instcombie.VisitGate(b.Int64Xor(x, x)), zero);      // x ^ x => 0
1111         // (x ^ -1) ^ -1 => x
1112         EXPECT_EQ(instcombie.VisitGate(b.Int64Xor(b.Int64Xor(x, neg_one), neg_one)), x);
1113     }
1114 
1115     {
1116         auto x = b.Arguments(1);
1117         auto zero = b.Int32(0);
1118         auto neg_one = b.Int32(-1);
1119         auto one = b.Int32(1);
1120         auto two = b.Int32(2);
1121         auto three = b.Int32(3);
1122         EXPECT_EQ(instcombie.VisitGate(b.Int32Xor(x, zero)), x);      // x ^ 0 => x
1123         EXPECT_EQ(instcombie.VisitGate(b.Int32Xor(two, one)), three); // 2 | 1  => 3
1124         EXPECT_EQ(instcombie.VisitGate(b.Int32Xor(x, x)), zero);      // x ^ x => 0
1125         // (x ^ -1) ^ -1 => x
1126         EXPECT_EQ(instcombie.VisitGate(b.Int32Xor(b.Int32Xor(x, neg_one), neg_one)), x);
1127     }
1128 }
1129 
HWTEST_F_L0(InstructionCombineTests,Int64_32LsrTest)1130 HWTEST_F_L0(InstructionCombineTests, Int64_32LsrTest)
1131 {
1132     // construct a circuit
1133     ecmascript::NativeAreaAllocator allocator;
1134     Circuit circuit(&allocator);
1135     ecmascript::Chunk chunk(&allocator);
1136     GateAccessor acc(&circuit);
1137     CircuitBuilder b(&circuit);
1138     Environment env(0, &b);
1139     b.SetEnvironment(&env);
1140     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1141     InstructionCombine instcombie(&circuit, &visitor, &chunk);
1142 
1143     {
1144         auto x = b.Arguments(1);
1145         auto zero = b.Int64(0);
1146         auto two = b.Int64(2);
1147         EXPECT_EQ(instcombie.VisitGate(b.Int64LSR(x, zero)), x); // x >>> 0 => x
1148         // (u)-8 >> 2  => 4611686018427387902u
1149         // 8 >> 2  => 2
1150         EXPECT_EQ(instcombie.VisitGate(b.Int64LSR(b.Int64(-8), two)), b.Int64(4611686018427387902u));
1151         EXPECT_EQ(instcombie.VisitGate(b.Int64LSR(b.Int64(8), two)), b.Int64(2));
1152     }
1153 
1154     {
1155         auto x = b.Arguments(1);
1156         auto zero = b.Int32(0);
1157         auto two = b.Int32(2);
1158         EXPECT_EQ(instcombie.VisitGate(b.Int32LSR(x, zero)), x); // x >>> 0 => x
1159         // (u)-8 >> 2  => 1073741822u
1160         // 8 >> 2  => 2
1161         EXPECT_EQ(instcombie.VisitGate(b.Int32LSR(b.Int32(-8), two)), b.Int32(1073741822u));
1162         EXPECT_EQ(instcombie.VisitGate(b.Int32LSR(b.Int32(8), two)), b.Int32(2));
1163         // (x & 1023) >>> 10  => 0
1164         EXPECT_EQ(instcombie.VisitGate(b.Int32LSR(b.Int32And(x, b.Int32(1023)), b.Int32(10))), zero);
1165     }
1166 }
1167 
HWTEST_F_L0(InstructionCombineTests,Int64_32AsrTest)1168 HWTEST_F_L0(InstructionCombineTests, Int64_32AsrTest)
1169 {
1170     // construct a circuit
1171     ecmascript::NativeAreaAllocator allocator;
1172     Circuit circuit(&allocator);
1173     ecmascript::Chunk chunk(&allocator);
1174     GateAccessor acc(&circuit);
1175     CircuitBuilder b(&circuit);
1176     Environment env(0, &b);
1177     b.SetEnvironment(&env);
1178     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1179     InstructionCombine instcombie(&circuit, &visitor, &chunk);
1180     {
1181         auto x = b.Arguments(1);
1182         auto zero = b.Int64(0);
1183         auto two = b.Int64(2);
1184         // x >> 0 => x
1185         EXPECT_EQ(instcombie.VisitGate(b.Int64ASR(x, zero)), x);
1186         // -8 >> 2  => -2
1187         // 8 >> 2  => 2
1188         EXPECT_EQ(instcombie.VisitGate(b.Int64ASR(b.Int64(-8), two)), b.Int64(-2));
1189         EXPECT_EQ(instcombie.VisitGate(b.Int64ASR(b.Int64(8), two)), b.Int64(2));
1190     }
1191     {
1192         auto x = b.Arguments(1);
1193         auto zero = b.Int32(0);
1194         auto two = b.Int32(2);
1195         // x >> 0 => x
1196         EXPECT_EQ(instcombie.VisitGate(b.Int32ASR(x, zero)), x);
1197         // -8 >> 2  => -2
1198         // 8 >> 2  => 2
1199         EXPECT_EQ(instcombie.VisitGate(b.Int32ASR(b.Int32(-8), two)), b.Int32(-2));
1200         EXPECT_EQ(instcombie.VisitGate(b.Int32ASR(b.Int32(8), two)), b.Int32(2));
1201     }
1202 }
1203 
HWTEST_F_L0(InstructionCombineTests,Int64_32LslTest)1204 HWTEST_F_L0(InstructionCombineTests, Int64_32LslTest)
1205 {
1206     // construct a circuit
1207     ecmascript::NativeAreaAllocator allocator;
1208     Circuit circuit(&allocator);
1209     ecmascript::Chunk chunk(&allocator);
1210     GateAccessor acc(&circuit);
1211     CircuitBuilder b(&circuit);
1212     Environment env(0, &b);
1213     b.SetEnvironment(&env);
1214     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1215     InstructionCombine instcombie(&circuit, &visitor, &chunk);
1216     {
1217         auto x = b.Arguments(1);
1218         auto zero = b.Int64(0);
1219         auto two = b.Int64(2);
1220         // x << 0 => x
1221         EXPECT_EQ(instcombie.VisitGate(b.Int64LSL(x, zero)), x);
1222         // 1 << 2  => 4
1223         EXPECT_EQ(instcombie.VisitGate(b.Int64LSL(b.Int64(1), two)), b.Int64(4));
1224     }
1225     {
1226         auto x = b.Arguments(1);
1227         auto zero = b.Int32(0);
1228         auto two = b.Int32(2);
1229         // x << 0 => x
1230         EXPECT_EQ(instcombie.VisitGate(b.Int32LSL(x, zero)), x);
1231         // 1 << 2  => 4
1232         EXPECT_EQ(instcombie.VisitGate(b.Int32LSL(b.Int32(1), two)), b.Int32(4));
1233     }
1234 }
1235 
HWTEST_F_L0(InstructionCombineTests,Int64EqualTest)1236 HWTEST_F_L0(InstructionCombineTests, Int64EqualTest)
1237 {
1238     // construct a circuit
1239     ecmascript::NativeAreaAllocator allocator;
1240     Circuit circuit(&allocator);
1241     ecmascript::Chunk chunk(&allocator);
1242     GateAccessor acc(&circuit);
1243     CircuitBuilder b(&circuit);
1244     Environment env(0, &b);
1245     b.SetEnvironment(&env);
1246     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1247     InstructionCombine instcombie(&circuit, &visitor, &chunk);
1248 
1249     //  Match {EQ ((x or constant1) , constant2)} {((constant1 || constant2) != constant2)} => false
1250     {
1251         auto x = b.Arguments(1);
1252         auto constant1 = b.Int64(5);
1253         auto constant2 = b.Int64(10);
1254         auto result = instcombie.VisitGate(b.Equal(b.Int64Or(x, constant1), constant2));
1255         EXPECT_EQ(result, b.False());
1256     }
1257 
1258     // Taggedalue
1259     {
1260         auto x = b.Arguments(1);
1261         auto constant1 = b.Int64(5);
1262         auto constant2 = b.Int64(10);
1263         auto result = instcombie.VisitGate(b.Equal(b.Int64ToTaggedPtr(b.Int64Or(x, constant1)), constant2));
1264         EXPECT_EQ(result, b.False());
1265     }
1266     // Match {EQ((X or constant1) & constant2, 0)} { (constan2 !=0 && constant1 & constant2 !=0) }=> false
1267     {
1268         auto x = b.Arguments(1);
1269         auto constant1 = b.Int64(15);
1270         auto constant2 = b.Int64(7);
1271         auto zero = b.Int64(0);
1272         auto result = instcombie.VisitGate(b.Equal(b.Int64And(b.Int64Or(x, constant1), constant2), zero));
1273         EXPECT_EQ(result, b.False());
1274     }
1275 }
1276 
HWTEST_F_L0(InstructionCombineTests,ConvertTest)1277 HWTEST_F_L0(InstructionCombineTests, ConvertTest)
1278 {
1279     // construct a circuit
1280     ecmascript::NativeAreaAllocator allocator;
1281     Circuit circuit(&allocator);
1282     ecmascript::Chunk chunk(&allocator);
1283     GateAccessor acc(&circuit);
1284     CircuitBuilder b(&circuit);
1285     Environment env(0, &b);
1286     b.SetEnvironment(&env);
1287     CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1288     InstructionCombine instcombie(&circuit, &visitor, &chunk);
1289     {
1290         auto x = b.Arguments(1);
1291         EXPECT_EQ(instcombie.VisitGate(b.ChangeFloat64ToInt32(b.ChangeInt32ToFloat64(x))), x);
1292     }
1293     {
1294         auto x = b.Arguments(2);
1295         EXPECT_NE(instcombie.VisitGate(b.ChangeInt32ToFloat64(b.ChangeFloat64ToInt32(x))), x);
1296     }
1297     {
1298         auto x = b.Arguments(3);
1299         EXPECT_NE(instcombie.VisitGate(b.Int64ToTaggedPtr(b.ChangeTaggedPointerToInt64(x))), x);
1300     }
1301 }
1302 } // namespace panda::test