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
36namespace panda::test {
37class InstructionCombineTests : public testing::Test {};
38using ecmascript::kungfu::Circuit;
39using ecmascript::kungfu::CircuitBuilder;
40using ecmascript::kungfu::CombinedPassVisitor;
41using ecmascript::kungfu::EcmaOpcode;
42using ecmascript::kungfu::Environment;
43using ecmascript::kungfu::Float64BinopMatcher;
44using ecmascript::kungfu::Float64Matcher;
45using ecmascript::kungfu::GateAccessor;
46using ecmascript::kungfu::GateRef;
47using ecmascript::kungfu::InstructionCombine;
48using ecmascript::kungfu::Int32BinopMatcher;
49using ecmascript::kungfu::Int64BinopMatcher;
50using ecmascript::kungfu::OpCode;
51using ecmascript::kungfu::PGOSampleType;
52using ecmascript::kungfu::Verifier;
53// std::numeric_limits<T>::quiet_NaN().
54template <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
61HWTEST_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
122HWTEST_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
208HWTEST_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
280HWTEST_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
353HWTEST_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
449HWTEST_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
554HWTEST_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
631HWTEST_F_L0(InstructionCombineTests, Int32DivTest)
632{
633    // construct a circuit
634    ecmascript::NativeAreaAllocator allocator;
635    Circuit circuit(&allocator);
636    ecmascript::Chunk chunk(&allocator);
637    GateAccessor acc(&circuit);
638    CircuitBuilder b(&circuit);
639    Environment env(0, &b);
640    b.SetEnvironment(&env);
641    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
642    InstructionCombine instcombie(&circuit, &visitor, &chunk);
643
644    // test  0/x => 0
645    {
646        auto x = b.Arguments(1);
647        auto const_0 = b.Int32(0);
648        auto result = b.Int32Div(const_0, x);
649        EXPECT_EQ(instcombie.VisitGate(result), const_0);
650    }
651
652
653    // test  x/0 => 0
654    {
655        auto x = b.Arguments(1);
656        auto const_0 = b.Int32(0);
657        auto result = b.Int32Div(x, const_0);
658        EXPECT_EQ(instcombie.VisitGate(result), const_0);
659    }
660
661    // test  x / 1 => x
662    {
663        auto x = b.Arguments(1);
664        auto const_1 = b.Int32(1);
665        auto result = b.Int32Div(x, const_1);
666        EXPECT_EQ(instcombie.VisitGate(result), x);
667    }
668
669    // test  4 / 2 => 4
670    {
671        auto const_4 = b.Int32(4);
672        auto const_2 = b.Int32(2);
673        auto result = instcombie.VisitGate(b.Int32Div(const_4, const_2));
674
675        EXPECT_NE(result, Circuit::NullGate());
676        EXPECT_EQ(acc.IsConstantValue(result, (int32_t)2), true);
677    }
678
679    // test x / -1 => 0 - X
680    {
681        auto x = b.Arguments(2);
682        auto result = instcombie.VisitGate(b.Int32Div(x, b.Int32(-1)));
683        EXPECT_NE(result, Circuit::NullGate());
684        Int32BinopMatcher m(result, &circuit);
685
686        EXPECT_EQ(m.Left().ResolvedValue(), 0);
687        EXPECT_EQ(m.Right().Gate(), x);
688        EXPECT_EQ(m.Opcode(), OpCode::SUB);
689    }
690
691    // test x / -5 => 0 - x / 5
692    {
693        auto x = b.Arguments(2);
694        auto result = instcombie.VisitGate(b.Int32Div(x, b.Int32(-5)));
695        EXPECT_NE(result, Circuit::NullGate());
696        Int32BinopMatcher m(result, &circuit);
697
698        EXPECT_EQ(m.Left().ResolvedValue(), 0);
699        EXPECT_EQ(m.Opcode(), OpCode::SUB);
700        Int32BinopMatcher m_right(m.Right().Gate(), &circuit);
701
702        EXPECT_EQ(m_right.Left().Gate(), x);
703        EXPECT_EQ(m_right.Opcode(), OpCode::SDIV);
704        EXPECT_EQ(m_right.Right().ResolvedValue(), 5);
705    }
706}
707
708HWTEST_F_L0(InstructionCombineTests, DoubleBinOptest)
709{
710    // construct a circuit
711    ecmascript::NativeAreaAllocator allocator;
712    Circuit circuit(&allocator);
713    ecmascript::Chunk chunk(&allocator);
714    GateAccessor acc(&circuit);
715    CircuitBuilder b(&circuit);
716    Environment env(0, &b);
717    b.SetEnvironment(&env);
718    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
719    InstructionCombine instcombie(&circuit, &visitor, &chunk);
720
721    // test  x op NaN => NaN
722    {
723        auto x = b.Arguments(1);
724        auto nan = b.NanValue();
725        auto zero = b.Double(0);
726        Float64Matcher nan_m(nan, &circuit);
727        EXPECT_EQ(nan_m.HasResolvedValue(), true);
728
729
730        EXPECT_EQ(instcombie.VisitGate(b.DoubleAdd(x, nan)), nan);
731        EXPECT_EQ(instcombie.VisitGate(b.DoubleSub(x, nan)), nan);
732        EXPECT_EQ(instcombie.VisitGate(b.DoubleMul(x, nan)), nan);
733        EXPECT_EQ(instcombie.VisitGate(b.DoubleDiv(x, nan)), nan);
734        // x % 0 => NaN
735        EXPECT_EQ(instcombie.VisitGate(b.DoubleMod(x, zero)), nan);
736    }
737    // test  NaN op op => NaN
738    {
739        auto x = b.Arguments(1);
740        auto nan = b.NanValue();
741        EXPECT_EQ(instcombie.VisitGate(b.DoubleAdd(nan, x)), nan);
742        EXPECT_EQ(instcombie.VisitGate(b.DoubleSub(nan, x)), nan);
743        EXPECT_EQ(instcombie.VisitGate(b.DoubleDiv(nan, x)), nan);
744        EXPECT_EQ(instcombie.VisitGate(b.DoubleMod(nan, x)), nan);
745    }
746
747    // test 10.4 op 5.2 => ?
748    {
749        auto value1 = b.Double(10.1);
750        auto value2 = b.Double(5.2);
751        auto result = instcombie.VisitGate(b.DoubleAdd(value1, value2));
752        EXPECT_NE(result, Circuit::NullGate());
753        EXPECT_EQ(acc.GetOpCode(result), OpCode::CONSTANT);
754
755        result = instcombie.VisitGate(b.DoubleAdd(value1, value2));
756        EXPECT_NE(result, Circuit::NullGate());
757        EXPECT_EQ(acc.GetOpCode(result), OpCode::CONSTANT);
758
759        result = instcombie.VisitGate(b.DoubleSub(value1, value2));
760        EXPECT_NE(result, Circuit::NullGate());
761        EXPECT_EQ(acc.GetOpCode(result), OpCode::CONSTANT);
762
763        result = instcombie.VisitGate(b.DoubleDiv(value1, value2));
764        EXPECT_NE(result, Circuit::NullGate());
765        EXPECT_EQ(acc.GetOpCode(result), OpCode::CONSTANT);
766    }
767
768    // test x * -1.0 => -0.0 - x
769    {
770        auto x = b.Arguments(1);
771        auto neg_one = b.Double(-1);
772        auto result = instcombie.VisitGate(b.DoubleMul(x, neg_one));
773
774        EXPECT_NE(result, Circuit::NullGate());
775        Float64BinopMatcher m(result, &circuit);
776        EXPECT_EQ(m.Opcode(), OpCode::SUB);
777        EXPECT_EQ(m.Left().ResolvedValue(), -0.0);
778        EXPECT_EQ(m.Right().Gate(), x);
779    }
780
781    // test x * -1.0 => -0.0 - x
782    {
783        auto x = b.Arguments(1);
784        auto two = b.Double(2.0);
785        auto result = instcombie.VisitGate(b.DoubleMul(x, two));
786        EXPECT_NE(result, Circuit::NullGate());
787        Float64BinopMatcher m(result, &circuit);
788        EXPECT_EQ(m.Opcode(), OpCode::ADD);
789        EXPECT_EQ(m.Left().Gate(), x);
790        EXPECT_EQ(m.Right().Gate(), x);
791    }
792}
793HWTEST_F_L0(InstructionCombineTests, Int32Modtest)
794{
795    // construct a circuit
796    ecmascript::NativeAreaAllocator allocator;
797    Circuit circuit(&allocator);
798    ecmascript::Chunk chunk(&allocator);
799    GateAccessor acc(&circuit);
800    CircuitBuilder b(&circuit);
801    Environment env(0, &b);
802    b.SetEnvironment(&env);
803    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
804    InstructionCombine instcombie(&circuit, &visitor, &chunk);
805    {
806        auto x = b.Arguments(1);
807        auto zero = b.Int32(0);
808        auto one = b.Int32(1);
809        auto neg_one = b.Int32(-1);
810        auto four = b.Int32(4);
811        auto two = b.Int32(2);
812
813        // 0 % x  => 0
814        // x % 0  => 0
815        // x % 1  => 0
816        // x % -1 => 0
817        // x % x  => 0
818        EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(x, zero)), zero);
819        EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(zero, x)), zero);
820        EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(x, one)), zero);
821        EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(x, neg_one)), zero);
822        EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(x, x)), zero);
823        // 2%4 =>2
824        EXPECT_EQ(instcombie.VisitGate(b.Int32Mod(two, four)), two);
825    }
826}
827
828HWTEST_F_L0(InstructionCombineTests, Int32AddOverFlowtest)
829{
830    // construct a circuit
831    ecmascript::NativeAreaAllocator allocator;
832    Circuit circuit(&allocator);
833    ecmascript::Chunk chunk(&allocator);
834    GateAccessor acc(&circuit);
835    CircuitBuilder b(&circuit);
836    Environment env(0, &b);
837    b.SetEnvironment(&env);
838    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
839    InstructionCombine instcombie(&circuit, &visitor, &chunk);
840
841    // IsFoldable overflow
842    // 2147483647 + 1 =-2147483648
843    {
844        auto add_overflow = b.AddWithOverflow(b.Int32(2147483647), b.Int32(1));
845        auto add_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, add_overflow, b.Int32(0));
846        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, add_overflow, b.Int32(1));
847        EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(add_result)), -2147483648);
848        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(true));
849    }
850
851    // IsFoldable no overflow
852    {
853        auto add_overflow = b.AddWithOverflow(b.Int32(2147483646), b.Int32(1));
854        auto add_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, add_overflow, b.Int32(0));
855        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, add_overflow, b.Int32(1));
856        EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(add_result)), 2147483647);
857        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
858    }
859
860
861    // x add 0 => 0
862    // IsFoldable no overflow
863    {
864        auto x = b.Arguments(1);
865        auto add_overflow = b.AddWithOverflow(x, b.Int32(0));
866        auto add_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, add_overflow, b.Int32(0));
867        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, add_overflow, b.Int32(1));
868        EXPECT_EQ(instcombie.VisitGate(add_result), x);
869        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
870    }
871}
872
873HWTEST_F_L0(InstructionCombineTests, Int32SubOverFlowTest)
874{
875    // construct a circuit
876    ecmascript::NativeAreaAllocator allocator;
877    Circuit circuit(&allocator);
878    ecmascript::Chunk chunk(&allocator);
879    GateAccessor acc(&circuit);
880    CircuitBuilder b(&circuit);
881    Environment env(0, &b);
882    b.SetEnvironment(&env);
883    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
884    InstructionCombine instcombie(&circuit, &visitor, &chunk);
885
886    // IsFoldable overflow
887    // -2147483648 - 1 = 2147483647
888    {
889        auto sub_overflow = b.SubWithOverflow(b.Int32(-2147483648), b.Int32(1));
890        auto sub_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, sub_overflow, b.Int32(0));
891        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, sub_overflow, b.Int32(1));
892        EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(sub_result)), 2147483647);
893        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(true));
894    }
895
896    // IsFoldable no overflow
897    {
898        auto sub_overflow = b.SubWithOverflow(b.Int32(2147483647), b.Int32(1));
899        auto sub_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, sub_overflow, b.Int32(0));
900        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, sub_overflow, b.Int32(1));
901        EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(sub_result)), 2147483646);
902        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
903    }
904
905    // x sub 0 => x
906    // IsFoldable no overflow
907    {
908        auto x = b.Arguments(1);
909        auto sub_overflow = b.SubWithOverflow(x, b.Int32(0));
910        auto sub_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, sub_overflow, b.Int32(0));
911        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, sub_overflow, b.Int32(1));
912        EXPECT_EQ(instcombie.VisitGate(sub_result), x);
913        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
914    }
915}
916
917HWTEST_F_L0(InstructionCombineTests, Int32MulOverFlowTest)
918{
919    // construct a circuit
920    ecmascript::NativeAreaAllocator allocator;
921    Circuit circuit(&allocator);
922    ecmascript::Chunk chunk(&allocator);
923    GateAccessor acc(&circuit);
924    CircuitBuilder b(&circuit);
925    Environment env(0, &b);
926    b.SetEnvironment(&env);
927    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
928    InstructionCombine instcombie(&circuit, &visitor, &chunk);
929
930    // IsFoldable overflow
931    // 2147483647 * 2 = -2
932    {
933        auto mul_overflow = b.MulWithOverflow(b.Int32(2147483647), b.Int32(2));
934        auto mul_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, mul_overflow, b.Int32(0));
935        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, mul_overflow, b.Int32(1));
936        EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(mul_result)), -2);
937        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(true));
938    }
939
940    // IsFoldable no overflow
941    // 1000 * 2 = 2000
942    {
943        auto mul_overflow = b.MulWithOverflow(b.Int32(1000), b.Int32(2));
944        auto mul_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, mul_overflow, b.Int32(0));
945        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, mul_overflow, b.Int32(1));
946        EXPECT_EQ(acc.GetInt32FromConstant(instcombie.VisitGate(mul_result)), 2000);
947        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
948    }
949
950    // x * 1 => x
951    // IsFoldable no overflow
952    {
953        auto x = b.Arguments(1);
954        auto mul_overflow = b.MulWithOverflow(x, b.Int32(1));
955        auto mul_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, mul_overflow, b.Int32(0));
956        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, mul_overflow, b.Int32(1));
957        EXPECT_EQ(instcombie.VisitGate(mul_result), x);
958        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
959    }
960
961    // x * 0 => 0
962    // IsFoldable no overflow
963    {
964        auto x = b.Arguments(1);
965        auto mul_overflow = b.MulWithOverflow(x, b.Int32(0));
966        auto mul_result = b.ExtractValue(ecmascript::kungfu::MachineType::I32, mul_overflow, b.Int32(0));
967        auto is_over = b.ExtractValue(ecmascript::kungfu::MachineType::I1, mul_overflow, b.Int32(1));
968        EXPECT_EQ(instcombie.VisitGate(mul_result), b.Int32(0));
969        EXPECT_EQ(instcombie.VisitGate(is_over), b.Boolean(false));
970    }
971}
972
973HWTEST_F_L0(InstructionCombineTests, Int64_32AndTest)
974{
975    // construct a circuit
976    ecmascript::NativeAreaAllocator allocator;
977    Circuit circuit(&allocator);
978    ecmascript::Chunk chunk(&allocator);
979    GateAccessor acc(&circuit);
980    CircuitBuilder b(&circuit);
981    Environment env(0, &b);
982    b.SetEnvironment(&env);
983    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
984    InstructionCombine instcombie(&circuit, &visitor, &chunk);
985    {
986        auto x = b.Arguments(1);
987        auto zero = b.Int64(0);
988        auto neg_one = b.Int64(-1);
989        auto Icmp = b.Equal(x, zero);
990        auto one = b.Int64(1);
991        auto two = b.Int64(2);
992        EXPECT_EQ(instcombie.VisitGate(b.Int64And(x, zero)), zero);   // x & 0  => 0
993        EXPECT_EQ(instcombie.VisitGate(b.Int64And(x, neg_one)), x);   // x & -1 => x
994        EXPECT_EQ(instcombie.VisitGate(b.Int64And(Icmp, one)), Icmp); // CMP & 1 => CMP
995        EXPECT_EQ(instcombie.VisitGate(b.Int64And(two, one)), zero);  // K & K  => K
996        EXPECT_EQ(instcombie.VisitGate(b.Int64And(x, x)), x);         // x & x => x
997        // (x & 1) & 2 => x & 0
998        auto result = instcombie.VisitGate(b.Int64And(b.Int64And(x, one), two));
999        EXPECT_NE(result, Circuit::NullGate());
1000        Int64BinopMatcher m(result, &circuit);
1001        EXPECT_EQ(m.Left().Gate(), x);
1002        EXPECT_EQ(m.Opcode(), OpCode::AND);
1003        EXPECT_EQ(m.Right().Gate(), zero);
1004    }
1005
1006    {
1007        auto x = b.Arguments(2);
1008        auto zero = b.Int32(0);
1009        auto neg_one = b.Int32(-1);
1010        auto Icmp = b.Equal(x, zero);
1011        auto one = b.Int32(1);
1012        auto two = b.Int32(2);
1013        EXPECT_EQ(instcombie.VisitGate(b.Int32And(x, zero)), zero);   // x & 0  => 0
1014        EXPECT_EQ(instcombie.VisitGate(b.Int32And(x, neg_one)), x);   // x & -1 => x
1015        EXPECT_EQ(instcombie.VisitGate(b.Int32And(Icmp, one)), Icmp); // CMP & 1 => CMP
1016        EXPECT_EQ(instcombie.VisitGate(b.Int32And(two, one)), zero);  // K & K  => K
1017        EXPECT_EQ(instcombie.VisitGate(b.Int32And(x, x)), x);         // x & x => x
1018        // (x & 1) & 2 => x & 0
1019        auto result = instcombie.VisitGate(b.Int32And(b.Int32And(x, one), two));
1020        EXPECT_NE(result, Circuit::NullGate());
1021        Int64BinopMatcher m(result, &circuit);
1022        EXPECT_EQ(m.Left().Gate(), x);
1023        EXPECT_EQ(m.Opcode(), OpCode::AND);
1024        EXPECT_EQ(m.Right().Gate(), zero);
1025    }
1026}
1027
1028HWTEST_F_L0(InstructionCombineTests, Int64_32OrTest)
1029{
1030    // construct a circuit
1031    ecmascript::NativeAreaAllocator allocator;
1032    Circuit circuit(&allocator);
1033    ecmascript::Chunk chunk(&allocator);
1034    GateAccessor acc(&circuit);
1035    CircuitBuilder b(&circuit);
1036    Environment env(0, &b);
1037    b.SetEnvironment(&env);
1038    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1039    InstructionCombine instcombie(&circuit, &visitor, &chunk);
1040    {
1041        auto x = b.Arguments(1);
1042        auto zero = b.Int64(0);
1043        auto neg_one = b.Int64(-1);
1044        auto one = b.Int64(1);
1045        auto two = b.Int64(2);
1046        auto three = b.Int64(3);
1047        EXPECT_EQ(instcombie.VisitGate(b.Int64Or(x, zero)), x);          // x | 0  => x
1048        EXPECT_EQ(instcombie.VisitGate(b.Int64Or(x, neg_one)), neg_one); // x | -1 => -1
1049        EXPECT_EQ(instcombie.VisitGate(b.Int64Or(two, one)), three);     // 2 | 1  => 3
1050        EXPECT_EQ(instcombie.VisitGate(b.Int64Or(x, x)), x);             // x | x => x
1051        // (x & K1) | K2 => x | K2 if K2 has ones for every zero bit in K1.
1052        auto result = instcombie.VisitGate(
1053            b.Int64Or(b.Int64And(x, b.Int64(-6148914691236517205L)), b.Int64(6148914691236517205L)));
1054        EXPECT_NE(result, Circuit::NullGate());
1055        Int64BinopMatcher m(result, &circuit);
1056        EXPECT_EQ(m.Left().Gate(), x);
1057        EXPECT_EQ(m.Opcode(), OpCode::OR);
1058        EXPECT_EQ(m.Right().Gate(), b.Int64(6148914691236517205L));
1059    }
1060
1061    {
1062        auto x = b.Arguments(1);
1063        auto zero = b.Int32(0);
1064        auto neg_one = b.Int32(-1);
1065        auto one = b.Int32(1);
1066        auto two = b.Int32(2);
1067        auto three = b.Int32(3);
1068        EXPECT_EQ(instcombie.VisitGate(b.Int32Or(x, zero)), x);          // x | 0  => x
1069        EXPECT_EQ(instcombie.VisitGate(b.Int32Or(x, neg_one)), neg_one); // x | -1 => -1
1070        EXPECT_EQ(instcombie.VisitGate(b.Int32Or(two, one)), three);     // 2 | 1  => 3
1071        EXPECT_EQ(instcombie.VisitGate(b.Int32Or(x, x)), x);             // x | x => x
1072        // (x & K1) | K2 => x | K2 if K2 has ones for every zero bit in K1.
1073        auto result = instcombie.VisitGate(b.Int32Or(b.Int32And(x, b.Int32(-1431655765)), b.Int32(1431655765)));
1074        EXPECT_NE(result, Circuit::NullGate());
1075        Int32BinopMatcher m(result, &circuit);
1076        EXPECT_EQ(m.Left().Gate(), x);
1077        EXPECT_EQ(m.Opcode(), OpCode::OR);
1078        EXPECT_EQ(m.Right().Gate(), b.Int32(1431655765));
1079    }
1080}
1081
1082HWTEST_F_L0(InstructionCombineTests, Int64_32XOrTest)
1083{
1084    // construct a circuit
1085    ecmascript::NativeAreaAllocator allocator;
1086    Circuit circuit(&allocator);
1087    ecmascript::Chunk chunk(&allocator);
1088    GateAccessor acc(&circuit);
1089    CircuitBuilder b(&circuit);
1090    Environment env(0, &b);
1091    b.SetEnvironment(&env);
1092    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1093    InstructionCombine instcombie(&circuit, &visitor, &chunk);
1094    {
1095        auto x = b.Arguments(1);
1096        auto zero = b.Int64(0);
1097        auto neg_one = b.Int64(-1);
1098        auto one = b.Int64(1);
1099        auto two = b.Int64(2);
1100        auto three = b.Int64(3);
1101        EXPECT_EQ(instcombie.VisitGate(b.Int64Xor(x, zero)), x);      // x ^ 0 => x
1102        EXPECT_EQ(instcombie.VisitGate(b.Int64Xor(two, one)), three); // 2 | 1  => 3
1103        EXPECT_EQ(instcombie.VisitGate(b.Int64Xor(x, x)), zero);      // x ^ x => 0
1104        // (x ^ -1) ^ -1 => x
1105        EXPECT_EQ(instcombie.VisitGate(b.Int64Xor(b.Int64Xor(x, neg_one), neg_one)), x);
1106    }
1107
1108    {
1109        auto x = b.Arguments(1);
1110        auto zero = b.Int32(0);
1111        auto neg_one = b.Int32(-1);
1112        auto one = b.Int32(1);
1113        auto two = b.Int32(2);
1114        auto three = b.Int32(3);
1115        EXPECT_EQ(instcombie.VisitGate(b.Int32Xor(x, zero)), x);      // x ^ 0 => x
1116        EXPECT_EQ(instcombie.VisitGate(b.Int32Xor(two, one)), three); // 2 | 1  => 3
1117        EXPECT_EQ(instcombie.VisitGate(b.Int32Xor(x, x)), zero);      // x ^ x => 0
1118        // (x ^ -1) ^ -1 => x
1119        EXPECT_EQ(instcombie.VisitGate(b.Int32Xor(b.Int32Xor(x, neg_one), neg_one)), x);
1120    }
1121}
1122
1123HWTEST_F_L0(InstructionCombineTests, Int64_32LsrTest)
1124{
1125    // construct a circuit
1126    ecmascript::NativeAreaAllocator allocator;
1127    Circuit circuit(&allocator);
1128    ecmascript::Chunk chunk(&allocator);
1129    GateAccessor acc(&circuit);
1130    CircuitBuilder b(&circuit);
1131    Environment env(0, &b);
1132    b.SetEnvironment(&env);
1133    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1134    InstructionCombine instcombie(&circuit, &visitor, &chunk);
1135
1136    {
1137        auto x = b.Arguments(1);
1138        auto zero = b.Int64(0);
1139        auto two = b.Int64(2);
1140        EXPECT_EQ(instcombie.VisitGate(b.Int64LSR(x, zero)), x); // x >>> 0 => x
1141        // (u)-8 >> 2  => 4611686018427387902u
1142        // 8 >> 2  => 2
1143        EXPECT_EQ(instcombie.VisitGate(b.Int64LSR(b.Int64(-8), two)), b.Int64(4611686018427387902u));
1144        EXPECT_EQ(instcombie.VisitGate(b.Int64LSR(b.Int64(8), two)), b.Int64(2));
1145    }
1146
1147    {
1148        auto x = b.Arguments(1);
1149        auto zero = b.Int32(0);
1150        auto two = b.Int32(2);
1151        EXPECT_EQ(instcombie.VisitGate(b.Int32LSR(x, zero)), x); // x >>> 0 => x
1152        // (u)-8 >> 2  => 1073741822u
1153        // 8 >> 2  => 2
1154        EXPECT_EQ(instcombie.VisitGate(b.Int32LSR(b.Int32(-8), two)), b.Int32(1073741822u));
1155        EXPECT_EQ(instcombie.VisitGate(b.Int32LSR(b.Int32(8), two)), b.Int32(2));
1156        // (x & 1023) >>> 10  => 0
1157        EXPECT_EQ(instcombie.VisitGate(b.Int32LSR(b.Int32And(x, b.Int32(1023)), b.Int32(10))), zero);
1158    }
1159}
1160
1161HWTEST_F_L0(InstructionCombineTests, Int64_32AsrTest)
1162{
1163    // construct a circuit
1164    ecmascript::NativeAreaAllocator allocator;
1165    Circuit circuit(&allocator);
1166    ecmascript::Chunk chunk(&allocator);
1167    GateAccessor acc(&circuit);
1168    CircuitBuilder b(&circuit);
1169    Environment env(0, &b);
1170    b.SetEnvironment(&env);
1171    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1172    InstructionCombine instcombie(&circuit, &visitor, &chunk);
1173    {
1174        auto x = b.Arguments(1);
1175        auto zero = b.Int64(0);
1176        auto two = b.Int64(2);
1177        // x >> 0 => x
1178        EXPECT_EQ(instcombie.VisitGate(b.Int64ASR(x, zero)), x);
1179        // -8 >> 2  => -2
1180        // 8 >> 2  => 2
1181        EXPECT_EQ(instcombie.VisitGate(b.Int64ASR(b.Int64(-8), two)), b.Int64(-2));
1182        EXPECT_EQ(instcombie.VisitGate(b.Int64ASR(b.Int64(8), two)), b.Int64(2));
1183    }
1184    {
1185        auto x = b.Arguments(1);
1186        auto zero = b.Int32(0);
1187        auto two = b.Int32(2);
1188        // x >> 0 => x
1189        EXPECT_EQ(instcombie.VisitGate(b.Int32ASR(x, zero)), x);
1190        // -8 >> 2  => -2
1191        // 8 >> 2  => 2
1192        EXPECT_EQ(instcombie.VisitGate(b.Int32ASR(b.Int32(-8), two)), b.Int32(-2));
1193        EXPECT_EQ(instcombie.VisitGate(b.Int32ASR(b.Int32(8), two)), b.Int32(2));
1194    }
1195}
1196
1197HWTEST_F_L0(InstructionCombineTests, Int64_32LslTest)
1198{
1199    // construct a circuit
1200    ecmascript::NativeAreaAllocator allocator;
1201    Circuit circuit(&allocator);
1202    ecmascript::Chunk chunk(&allocator);
1203    GateAccessor acc(&circuit);
1204    CircuitBuilder b(&circuit);
1205    Environment env(0, &b);
1206    b.SetEnvironment(&env);
1207    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1208    InstructionCombine instcombie(&circuit, &visitor, &chunk);
1209    {
1210        auto x = b.Arguments(1);
1211        auto zero = b.Int64(0);
1212        auto two = b.Int64(2);
1213        // x << 0 => x
1214        EXPECT_EQ(instcombie.VisitGate(b.Int64LSL(x, zero)), x);
1215        // 1 << 2  => 4
1216        EXPECT_EQ(instcombie.VisitGate(b.Int64LSL(b.Int64(1), two)), b.Int64(4));
1217    }
1218    {
1219        auto x = b.Arguments(1);
1220        auto zero = b.Int32(0);
1221        auto two = b.Int32(2);
1222        // x << 0 => x
1223        EXPECT_EQ(instcombie.VisitGate(b.Int32LSL(x, zero)), x);
1224        // 1 << 2  => 4
1225        EXPECT_EQ(instcombie.VisitGate(b.Int32LSL(b.Int32(1), two)), b.Int32(4));
1226    }
1227}
1228
1229HWTEST_F_L0(InstructionCombineTests, Int64EqualTest)
1230{
1231    // construct a circuit
1232    ecmascript::NativeAreaAllocator allocator;
1233    Circuit circuit(&allocator);
1234    ecmascript::Chunk chunk(&allocator);
1235    GateAccessor acc(&circuit);
1236    CircuitBuilder b(&circuit);
1237    Environment env(0, &b);
1238    b.SetEnvironment(&env);
1239    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1240    InstructionCombine instcombie(&circuit, &visitor, &chunk);
1241
1242    //  Match {EQ ((x or constant1) , constant2)} {((constant1 || constant2) != constant2)} => false
1243    {
1244        auto x = b.Arguments(1);
1245        auto constant1 = b.Int64(5);
1246        auto constant2 = b.Int64(10);
1247        auto result = instcombie.VisitGate(b.Equal(b.Int64Or(x, constant1), constant2));
1248        EXPECT_EQ(result, b.False());
1249    }
1250
1251    // Taggedalue
1252    {
1253        auto x = b.Arguments(1);
1254        auto constant1 = b.Int64(5);
1255        auto constant2 = b.Int64(10);
1256        auto result = instcombie.VisitGate(b.Equal(b.Int64ToTaggedPtr(b.Int64Or(x, constant1)), constant2));
1257        EXPECT_EQ(result, b.False());
1258    }
1259    // Match {EQ((X or constant1) & constant2, 0)} { (constan2 !=0 && constant1 & constant2 !=0) }=> false
1260    {
1261        auto x = b.Arguments(1);
1262        auto constant1 = b.Int64(15);
1263        auto constant2 = b.Int64(7);
1264        auto zero = b.Int64(0);
1265        auto result = instcombie.VisitGate(b.Equal(b.Int64And(b.Int64Or(x, constant1), constant2), zero));
1266        EXPECT_EQ(result, b.False());
1267    }
1268}
1269
1270HWTEST_F_L0(InstructionCombineTests, ConvertTest)
1271{
1272    // construct a circuit
1273    ecmascript::NativeAreaAllocator allocator;
1274    Circuit circuit(&allocator);
1275    ecmascript::Chunk chunk(&allocator);
1276    GateAccessor acc(&circuit);
1277    CircuitBuilder b(&circuit);
1278    Environment env(0, &b);
1279    b.SetEnvironment(&env);
1280    CombinedPassVisitor visitor(&circuit, false, "InstCombie", &chunk);
1281    InstructionCombine instcombie(&circuit, &visitor, &chunk);
1282    {
1283        auto x = b.Arguments(1);
1284        EXPECT_EQ(instcombie.VisitGate(b.ChangeFloat64ToInt32(b.ChangeInt32ToFloat64(x))), x);
1285    }
1286
1287    {
1288        auto x = b.Arguments(2);
1289        EXPECT_EQ(instcombie.VisitGate(b.ChangeInt32ToFloat64(b.ChangeFloat64ToInt32(x))), x);
1290    }
1291}
1292} // namespace panda::test