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