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