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/instruction_combine.h" 16#include "ecmascript/compiler/circuit_builder-inl.h" 17#include "ecmascript/compiler/gate_matchers.h" 18 19namespace panda::ecmascript::kungfu { 20 21GateRef InstructionCombine::ReplaceOld(GateRef gate, GateRef newGate) 22{ 23 acc_.UpdateAllUses(gate, newGate); 24 return newGate; 25} 26 27 28GateRef InstructionCombine::VisitGate(GateRef gate) 29{ 30 OpCode op = acc_.GetOpCode(gate); 31 GateRef result = Circuit::NullGate(); 32 ; 33 switch (op) { 34 case OpCode::ADD: 35 result = VisitADD(gate); 36 break; 37 case OpCode::SUB: 38 result = VisitSUB(gate); 39 break; 40 case OpCode::MUL: 41 result = VisitMUL(gate); 42 break; 43 case OpCode::SDIV: 44 result = VisitSDIV(gate); 45 break; 46 case OpCode::FDIV: 47 result = VisitFDIV(gate); 48 break; 49 case OpCode::SMOD: 50 result = VisitSMOD(gate); 51 break; 52 case OpCode::AND: 53 result = VisitAND(gate); 54 break; 55 case OpCode::OR: 56 result = VisitOR(gate); 57 break; 58 case OpCode::XOR: 59 result = VisitXOR(gate); 60 break; 61 case OpCode::ASR: 62 result = VisitASR(gate); 63 break; 64 case OpCode::LSL: 65 result = VisitLSL(gate); 66 break; 67 case OpCode::LSR: 68 result = VisitLSR(gate); 69 break; 70 case OpCode::ICMP: 71 result = VisitICMP(gate); 72 break; 73 case OpCode::REV: 74 result = VisitREV(gate); 75 break; 76 case OpCode::IF_BRANCH: 77 result = VisitBranch(gate); 78 break; 79 case OpCode::EXTRACT_VALUE: 80 return VisitExtractValue(gate); 81 case OpCode::TAGGED_TO_INT64: 82 case OpCode::INT64_TO_TAGGED: 83 case OpCode::SIGNED_INT_TO_FLOAT: 84 case OpCode::FLOAT_TO_SIGNED_INT: 85 case OpCode::UNSIGNED_FLOAT_TO_INT: 86 case OpCode::BITCAST: 87 case OpCode::ZEXT: 88 case OpCode::SEXT: 89 case OpCode::TRUNC: 90 case OpCode::FEXT: 91 case OpCode::FTRUNC: 92 return VisitConvert(gate); 93 break; 94 default: 95 break; 96 } 97 if (enableLog_ && result != Circuit::NullGate()) { 98 LOG_COMPILER(INFO) << "InstructionCombine opt befor -> afert"; 99 acc_.Print(gate); 100 acc_.Print(result); 101 } 102 return result; 103} 104 105// Wait for the implementation of constant folding and partial redundancy elimination. 106// The Convert-related IR operations need refactoring for more effective optimization. 107// 1. Merge or differentiate the functionalities of SignIntToFloat and Bitcast 108// as both handle Int-to-Float conversions. Int32ToFloat32 also exhibits similar behavior. 109// 2. Clarify the roles of TruncFloatToInt64 and FTrunc, ensuring they are distinct or unified. 110// 3. Standardize naming conventions for operations that are inverse or similar to each other 111// to avoid confusion. ex: ChangeTaggedPointerToInt64 and Int64ToTaggedPtr perform similar functions, 112// yet their names are significantly different 113// 4. ................. 114GateRef InstructionCombine::VisitConvert(GateRef gate) 115{ 116 // For the meanings of the following Opcodes, please refer to 117 // UNARY_ARITHMETIC_METHOD_LIST_WITH_BITWIDTH 118 switch (acc_.GetOpCode(gate)) { 119 case OpCode::TAGGED_TO_INT64: 120 { 121 GateMatcher in(acc_.GetValueIn(gate, 0), circuit_); 122 if (in.IsInt64ToTagged()) { 123 return in.ValueIn(0); 124 } 125 break; 126 } 127 case OpCode::INT64_TO_TAGGED: 128 { 129 GateMatcher in(acc_.GetValueIn(gate, 0), circuit_); 130 if (in.IsTaggedToInt64()) { 131 return in.ValueIn(0); 132 } 133 break; 134 } 135 case OpCode::SIGNED_INT_TO_FLOAT: 136 { 137 GateMatcher in(acc_.GetValueIn(gate, 0), circuit_); 138 if (in.IsFloatToSignedInt()) { 139 return in.ValueIn(0); 140 } 141 break; 142 } 143 case OpCode::FLOAT_TO_SIGNED_INT: 144 { 145 GateMatcher in(acc_.GetValueIn(gate, 0), circuit_); 146 if (in.IsSignedIntToFloat()) { 147 return in.ValueIn(0); 148 } 149 break; 150 } 151 case OpCode::UNSIGNED_FLOAT_TO_INT: 152 break; 153 case OpCode::BITCAST: 154 case OpCode::ZEXT: 155 case OpCode::SEXT: 156 case OpCode::TRUNC: 157 case OpCode::FEXT: 158 case OpCode::FTRUNC: 159 break; 160 default: 161 break; 162 } 163 return Circuit::NullGate(); 164} 165 166GateRef InstructionCombine::VisitBranch(GateRef gate) 167{ 168 (void)gate; 169 return Circuit::NullGate(); 170} 171 172GateRef InstructionCombine::VisitREV(GateRef gate) 173{ 174 // REV Constant => Constant 175 auto revValue = acc_.GetValueIn(gate, 0); 176 if (acc_.GetOpCode(revValue) == OpCode::CONSTANT && acc_.GetMachineType(revValue) == I1) { 177 if (acc_.GetConstantValue(revValue) == 0) { 178 return builder_.True(); 179 } else { 180 return builder_.False(); 181 } 182 } 183 return Circuit::NullGate(); 184} 185 186GateRef InstructionCombine::VisitICMP(GateRef gate) 187{ 188 Int64BinopMatcher m(gate, circuit_); 189 // Match {EQ ((x or constant1) , constant2)} {((constant1 | constant2) != constant2)} => false 190 GateRef result = Circuit::NullGate(); 191 if (m.ConditionValue() == static_cast<uint64_t>(ICmpCondition::EQ) && m.Right().HasResolvedValue()) { 192 // In essence, it's all about comparing I64, so we can optimize further 193 // Subsequently, considering whether it can be automated within the gateMatcher 194 if (m.Left().Opcode() == OpCode::INT64_TO_TAGGED) { 195 m.SetLeft(m.Left().InputAt(0), circuit_); 196 } 197 198 if (m.Left().IsOr()) { 199 Int64BinopMatcher cmpLeft(m.Left().Gate(), circuit_); 200 if (cmpLeft.Right().HasResolvedValue()) { 201 uint64_t constant1 = static_cast<uint64_t>(cmpLeft.Right().ResolvedValue()); 202 uint64_t constant2 = static_cast<uint64_t>(m.Right().ResolvedValue()); 203 bool flag = ((constant1 | constant2) != constant2); 204 result = flag ? builder_.False() : Circuit::NullGate(); 205 } 206 } 207 208 if (result != Circuit::NullGate()) { 209 return result; 210 } 211 212 // Match {EQ((X or constant1) & constant2, 0)} { (constan2 !=0 && constant1 & constant2 !=0) }=> false 213 if (m.Left().IsAnd() && m.Right().ResolvedValue() == 0) { 214 Int64BinopMatcher andOp(m.Left().Gate(), circuit_); 215 if (andOp.Left().IsOr() && andOp.Right().HasResolvedValue() && andOp.Right().ResolvedValue() != 0) { 216 // The awkwardness in writing it this way is simply to reduce cyclomatic complexity. 217 Int64BinopMatcher orOp(andOp.Left().Gate(), circuit_); 218 auto constant2 = andOp.Right().ResolvedValue(); 219 auto constant1 = orOp.Right().HasResolvedValue() ? orOp.Right().ResolvedValue() : 0; 220 bool flag = (constant1 & constant2) != 0; 221 result = flag ? builder_.False() : Circuit::NullGate(); 222 } 223 } 224 if (result != Circuit::NullGate()) { 225 return result; 226 } 227 } 228 229 return Circuit::NullGate(); 230} 231 232GateRef InstructionCombine::VisitADD(GateRef gate) 233{ 234 auto machineType = acc_.GetMachineType(gate); 235 switch (machineType) { 236 case MachineType::I32: 237 return ReduceInt32Add(gate); 238 case MachineType::I64: 239 return ReduceInt64Add(gate); 240 case MachineType::F64: 241 return ReduceDoubleAdd(gate); 242 default: 243 break; 244 } 245 return Circuit::NullGate(); 246} 247 248GateRef InstructionCombine::VisitSUB(GateRef gate) 249{ 250 auto machineType = acc_.GetMachineType(gate); 251 switch (machineType) { 252 case MachineType::I32: 253 return ReduceInt32Sub(gate); 254 case MachineType::I64: 255 return ReduceInt64Sub(gate); 256 case MachineType::F64: 257 return ReduceDoubleSub(gate); 258 default: 259 break; 260 } 261 return Circuit::NullGate(); 262} 263 264GateRef InstructionCombine::VisitMUL(GateRef gate) 265{ 266 auto machineType = acc_.GetMachineType(gate); 267 switch (machineType) { 268 case MachineType::I32: 269 return ReduceInt32Mul(gate); 270 case MachineType::I64: 271 return ReduceInt64Mul(gate); 272 case MachineType::F64: 273 return ReduceDoubleMul(gate); 274 default: 275 break; 276 } 277 return Circuit::NullGate(); 278} 279 280GateRef InstructionCombine::VisitSDIV(GateRef gate) 281{ 282 auto machineType = acc_.GetMachineType(gate); 283 switch (machineType) { 284 case MachineType::I32: 285 return ReduceInt32Div(gate); 286 case MachineType::I64: 287 return ReduceInt64Div(gate); 288 default: 289 break; 290 } 291 return Circuit::NullGate(); 292} 293 294GateRef InstructionCombine::VisitFDIV(GateRef gate) 295{ 296 auto machineType = acc_.GetMachineType(gate); 297 switch (machineType) { 298 case MachineType::F64: 299 return ReduceDoubleDiv(gate); 300 default: 301 break; 302 } 303 return Circuit::NullGate(); 304} 305 306GateRef InstructionCombine::VisitSMOD(GateRef gate) 307{ 308 auto machineType = acc_.GetMachineType(gate); 309 switch (machineType) { 310 case MachineType::I32: 311 return ReduceInt32Mod(gate); 312 case MachineType::F64: 313 return ReduceDoubleMod(gate); 314 default: 315 break; 316 } 317 return Circuit::NullGate(); 318} 319 320 321GateRef InstructionCombine::VisitAND(GateRef gate) 322{ 323 auto machineType = acc_.GetMachineType(gate); 324 switch (machineType) { 325 case MachineType::I32: 326 return ReduceWord32And(gate); 327 case MachineType::I64: 328 return ReduceWord64And(gate); 329 default: 330 break; 331 } 332 return Circuit::NullGate(); 333} 334 335GateRef InstructionCombine::VisitOR(GateRef gate) 336{ 337 auto machineType = acc_.GetMachineType(gate); 338 switch (machineType) { 339 case MachineType::I32: 340 return ReduceWord32Or(gate); 341 case MachineType::I64: 342 return ReduceWord64Or(gate); 343 default: 344 break; 345 } 346 return Circuit::NullGate(); 347} 348 349GateRef InstructionCombine::VisitXOR(GateRef gate) 350{ 351 auto machineType = acc_.GetMachineType(gate); 352 switch (machineType) { 353 case MachineType::I32: 354 return ReduceWord32Xor(gate); 355 case MachineType::I64: 356 return ReduceWord64Xor(gate); 357 default: 358 break; 359 } 360 return Circuit::NullGate(); 361} 362 363GateRef InstructionCombine::VisitLSR(GateRef gate) 364{ 365 auto machineType = acc_.GetMachineType(gate); 366 switch (machineType) { 367 case MachineType::I32: 368 return ReduceWord32Lsr(gate); 369 case MachineType::I64: 370 return ReduceWord64Lsr(gate); 371 default: 372 break; 373 } 374 return Circuit::NullGate(); 375} 376 377GateRef InstructionCombine::VisitASR(GateRef gate) 378{ 379 auto machineType = acc_.GetMachineType(gate); 380 switch (machineType) { 381 case MachineType::I32: 382 return ReduceWord32Asr(gate); 383 case MachineType::I64: 384 return ReduceWord64Asr(gate); 385 default: 386 break; 387 } 388 return Circuit::NullGate(); 389} 390 391 392GateRef InstructionCombine::VisitLSL(GateRef gate) 393{ 394 auto machineType = acc_.GetMachineType(gate); 395 switch (machineType) { 396 case MachineType::I32: 397 return ReduceWord32Lsl(gate); 398 case MachineType::I64: 399 return ReduceWord64Lsl(gate); 400 default: 401 break; 402 } 403 return Circuit::NullGate(); 404} 405 406 407GateRef InstructionCombine::VisitExtractValue(GateRef gate) 408{ 409 Int32BinopMatcher n(gate, circuit_); 410 int32_t index = n.Right().ResolvedValue(); 411 int32_t val; 412 assert(index == 0 || index == 1); 413 switch (n.Left().Opcode()) { 414 case OpCode::ADD_WITH_OVERFLOW: 415 { 416 Int32BinopMatcher m(n.Left().Gate(), circuit_); 417 if (m.IsFoldable()) { 418 bool ovf = base::SignedAddOverflow32(m.Left().ResolvedValue(), m.Right().ResolvedValue(), &val); 419 return index == 0 ? builder_.Int32(val) : builder_.Boolean(ovf); 420 } 421 if (m.Right().Is(0)) { 422 return (index == 0 ? m.Left().Gate() : builder_.Boolean(false)); 423 } 424 break; 425 } 426 case OpCode::SUB_WITH_OVERFLOW: 427 { 428 Int32BinopMatcher m(n.Left().Gate(), circuit_); 429 if (m.IsFoldable()) { 430 bool ovf = base::SignedSubOverflow32(m.Left().ResolvedValue(), m.Right().ResolvedValue(), &val); 431 return index == 0 ? builder_.Int32(val) : builder_.Boolean(ovf); 432 } 433 if (m.Right().Is(0)) { 434 return (index == 0 ? m.Left().Gate() : builder_.Boolean(false)); 435 } 436 break; 437 } 438 case OpCode::MUL_WITH_OVERFLOW: 439 { 440 Int32BinopMatcher m(n.Left().Gate(), circuit_); 441 if (m.IsFoldable()) { 442 bool ovf = base::SignedMulOverflow32(m.Left().ResolvedValue(), m.Right().ResolvedValue(), &val); 443 return index == 0 ? builder_.Int32(val) : builder_.Boolean(ovf); 444 } 445 if (m.Right().Is(0)) { 446 return (index == 0 ? builder_.Int32(0) : builder_.Boolean(false)); 447 } 448 if (m.Right().Is(1)) { 449 return (index == 0 ? m.Left().Gate() : builder_.Boolean(false)); 450 } 451 break; 452 } 453 default: 454 break; 455 } 456 return Circuit::NullGate(); 457} 458 459GateRef InstructionCombine::ReduceInt64Add(GateRef gate) 460{ 461 Int64BinopMatcher m(gate, circuit_); 462 463 if (m.Right().Is(0)) { 464 return m.Left().Gate(); 465 } 466 467 if (m.IsFoldable()) { 468 return builder_.Int64(base::AddWithWraparound(m.Right().ResolvedValue(), m.Left().ResolvedValue())); 469 } 470 471 // (x + Int64Constant(a)) + Int64Constant(b) => x + Int64Constant(a + b) 472 if (m.Right().HasResolvedValue() && m.Left().IsmInt64Add()) { 473 Int64BinopMatcher mLeft(m.Left().Gate(), circuit_); 474 if (mLeft.Right().HasResolvedValue() && m.OwnsInput(m.Left().Gate())) { 475 acc_.ReplaceValueIn(gate, mLeft.Left().Gate(), 0); 476 acc_.ReplaceValueIn(gate, builder_.Int64(base::AddWithWraparound( 477 m.Right().ResolvedValue(), mLeft.Right().ResolvedValue())), 1); 478 return gate; 479 } 480 } 481 482 return Circuit::NullGate(); 483} 484 485GateRef InstructionCombine::ReduceInt32Add(GateRef gate) 486{ 487 Int32BinopMatcher m(gate, circuit_); 488 // x + 0 => x 489 if (m.Right().Is(0)) { 490 return m.Left().Gate(); 491 } 492 493 if (m.IsFoldable()) { 494 return builder_.Int32(base::AddWithWraparound(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 495 } 496 497 if (m.Left().IsmInt32Sub()) { 498 Int32BinopMatcher mleft(m.Left().Gate(), circuit_); 499 // (0 - x) + y => y - x 500 if (mleft.Left().Is(0)) { 501 auto newGate = builder_.Int32Sub(m.Right().Gate(), mleft.Right().Gate()); 502 return ReplaceOld(gate, newGate); 503 } 504 } 505 506 if (m.Right().IsmInt32Sub()) { 507 Int32BinopMatcher mright(m.Right().Gate(), circuit_); 508 // y + (0 - x) => y - x 509 if (mright.Left().Is(0)) { 510 auto newGate = builder_.Int32Sub(m.Left().Gate(), mright.Right().Gate()); 511 return ReplaceOld(gate, newGate); 512 } 513 } 514 // (x + Int32Constant(a)) + Int32Constant(b)) => x + Int32Constant(a + b) 515 if (m.Right().HasResolvedValue() && m.Left().IsmInt32Add()) { 516 Int32BinopMatcher mleft(m.Left().Gate(), circuit_); 517 if (mleft.Right().HasResolvedValue() && m.OwnsInput(m.Left().Gate())) { 518 acc_.ReplaceValueIn(gate, mleft.Left().Gate(), 0); 519 acc_.ReplaceValueIn(gate, builder_.Int32(base::AddWithWraparound( 520 mleft.Right().ResolvedValue(), m.Right().ResolvedValue())), 1); 521 return gate; 522 } 523 } 524 return Circuit::NullGate(); 525} 526 527GateRef InstructionCombine::ReduceInt64Sub(GateRef gate) 528{ 529 Int64BinopMatcher m(gate, circuit_); 530 // x - 0 => x 531 if (m.Right().Is(0)) { 532 return (m.Left().Gate()); 533 } 534 if (m.IsFoldable()) { 535 return builder_.Int64(base::SubWithWraparound(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 536 } 537 // x - x => 0 538 if (m.LeftEqualsRight()) { 539 return builder_.Int64(0); 540 } 541 // x - K => x + -K 542 if (m.Right().HasResolvedValue()) { 543 auto newGate = 544 builder_.Int64Add(m.Left().Gate(), builder_.Int64(base::NegateWithWraparound(m.Right().ResolvedValue()))); 545 return ReplaceOld(gate, newGate); 546 } 547 return Circuit::NullGate(); 548} 549 550GateRef InstructionCombine::ReduceInt32Sub(GateRef gate) 551{ 552 Int32BinopMatcher m(gate, circuit_); 553 // x - 0 => x 554 if (m.Right().Is(0)) { 555 return (m.Left().Gate()); 556 } 557 if (m.IsFoldable()) { 558 return builder_.Int32(base::SubWithWraparound(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 559 } 560 // x - x => 0 561 if (m.LeftEqualsRight()) { 562 return builder_.Int32(0); 563 } 564 // x - K => x + -K 565 if (m.Right().HasResolvedValue()) { 566 auto newGate = 567 builder_.Int32Add(m.Left().Gate(), builder_.Int32(base::NegateWithWraparound(m.Right().ResolvedValue()))); 568 return ReplaceOld(gate, newGate); 569 } 570 return Circuit::NullGate(); 571} 572 573GateRef InstructionCombine::ReduceInt64Mul(GateRef gate) 574{ 575 Int64BinopMatcher m(gate, circuit_); 576 // x * 0 => 0 577 if (m.Right().Is(0)) { 578 return m.Right().Gate(); 579 } 580 // x * 1 => x 581 if (m.Right().Is(1)) { 582 return m.Left().Gate(); 583 } 584 // K * K => K (K stands for arbitrary constants) 585 if (m.IsFoldable()) { 586 return builder_.Int64(base::MulWithWraparound(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 587 } 588 // x * -1 => 0 - x 589 if (m.Right().Is(-1)) { 590 auto newGate = builder_.Int64Sub(builder_.Int64(0), m.Left().Gate()); 591 return ReplaceOld(gate, newGate); 592 } 593 // x * 2^n => x << n 594 if (m.Right().IsPowerOf2()) { 595 auto newGate = builder_.Int64LSL(m.Left().Gate(), builder_.Int64( 596 base::WhichPowerOfTwo(m.Right().ResolvedValue()))); 597 return ReplaceOld(gate, newGate); 598 } 599 600 // (x * Int64Constant(a)) * Int64Constant(b)) => x * Int64Constant(a * b) 601 if (m.Right().HasResolvedValue() && m.Left().IsmInt64Mul()) { 602 Int64BinopMatcher n(m.Left().Gate(), circuit_); 603 if (n.Right().HasResolvedValue() && m.OwnsInput(m.Left().Gate())) { 604 acc_.ReplaceValueIn(gate, n.Left().Gate(), 0); 605 acc_.ReplaceValueIn( 606 gate, builder_.Int64(base::MulWithWraparound(n.Right().ResolvedValue(), m.Right().ResolvedValue())), 1); 607 return gate; 608 } 609 } 610 611 return Circuit::NullGate(); 612} 613 614GateRef InstructionCombine::ReduceInt32Mul(GateRef gate) 615{ 616 Int32BinopMatcher m(gate, circuit_); 617 // x * 0 => 0 618 if (m.Right().Is(0)) { 619 return m.Right().Gate(); 620 } 621 // x * 1 => x 622 if (m.Right().Is(1)) { 623 return m.Left().Gate(); 624 } 625 // K * K => K (K stands for arbitrary constants) 626 if (m.IsFoldable()) { 627 return builder_.Int32(base::MulWithWraparound(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 628 } 629 // x * -1 => 0 - x 630 if (m.Right().Is(-1)) { 631 auto newGate = builder_.Int32Sub(builder_.Int32(0), m.Left().Gate()); 632 return ReplaceOld(gate, newGate); 633 } 634 // x * 2^n => x << n 635 if (m.Right().IsPowerOf2()) { 636 auto newGate = builder_.Int32LSL(m.Left().Gate(), builder_.Int32( 637 base::WhichPowerOfTwo(m.Right().ResolvedValue()))); 638 return ReplaceOld(gate, newGate); 639 } 640 641 // (x * Int32Constant(a)) * Int32Constant(b)) => x * Int32Constant(a * b) 642 if (m.Right().HasResolvedValue() && m.Left().IsmInt32Mul()) { 643 Int32BinopMatcher n(m.Left().Gate(), circuit_); 644 if (n.Right().HasResolvedValue() && m.OwnsInput(m.Left().Gate())) { 645 acc_.ReplaceValueIn(gate, n.Left().Gate(), 0); 646 acc_.ReplaceValueIn( 647 gate, builder_.Int32(base::MulWithWraparound(n.Right().ResolvedValue(), m.Right().ResolvedValue())), 1); 648 return gate; 649 } 650 } 651 652 return Circuit::NullGate(); 653} 654 655 656GateRef InstructionCombine::ReduceInt64Div(GateRef gate) 657{ 658 Int64BinopMatcher m(gate, circuit_); 659 // 0 / x => 0 660 if (m.Left().Is(0)) { 661 return m.Left().Gate(); 662 } 663 // x / 0 => 0 664 if (m.Right().Is(0)) { 665 return m.Right().Gate(); 666 } 667 // x / 1 => x 668 if (m.Right().Is(1)) { 669 return m.Left().Gate(); 670 } 671 // K / K => K 672 if (m.IsFoldable()) { 673 return builder_.Int64(base::SignedDiv64(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 674 } 675 // x / -1 => 0 - x 676 if (m.Right().Is(-1)) { 677 auto newGate = builder_.Int64Sub(builder_.Int64(0), m.Left().Gate()); 678 return ReplaceOld(gate, newGate); 679 } 680 681 // x/-K => 0-(x/K) 682 if (m.Right().HasResolvedValue()) { 683 int64_t const divisor = m.Right().ResolvedValue(); 684 if (divisor < 0) { 685 auto newDiv = builder_.Int64Div(m.Left().Gate(), builder_.Int64(abs(m.Right().ResolvedValue()))); 686 auto newGate = builder_.Int64Sub(builder_.Int64(0), newDiv); 687 return ReplaceOld(gate, newGate); 688 } 689 } 690 return Circuit::NullGate(); 691} 692 693GateRef InstructionCombine::ReduceInt32Div(GateRef gate) 694{ 695 Int32BinopMatcher m(gate, circuit_); 696 // 0 / x => 0 697 if (m.Left().Is(0)) { 698 return m.Left().Gate(); 699 } 700 // x / 0 => 0 701 if (m.Right().Is(0)) { 702 return m.Right().Gate(); 703 } 704 // x / 1 => x 705 if (m.Right().Is(1)) { 706 return m.Left().Gate(); 707 } 708 // K / K => K 709 if (m.IsFoldable()) { 710 return builder_.Int32(base::SignedDiv32(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 711 } 712 // x / -1 => 0 - x 713 if (m.Right().Is(-1)) { 714 auto newGate = builder_.Int32Sub(builder_.Int32(0), m.Left().Gate()); 715 return ReplaceOld(gate, newGate); 716 } 717 718 // x/-K => 0-(x/K) 719 if (m.Right().HasResolvedValue()) { 720 int32_t const divisor = m.Right().ResolvedValue(); 721 if (divisor < 0) { 722 auto newDiv = builder_.Int32Div(m.Left().Gate(), builder_.Int32(abs(m.Right().ResolvedValue()))); 723 auto newGate = builder_.Int32Sub(builder_.Int32(0), newDiv); 724 return ReplaceOld(gate, newGate); 725 } 726 } 727 return Circuit::NullGate(); 728} 729 730GateRef InstructionCombine::ReduceDoubleAdd(GateRef gate) 731{ 732 Float64BinopMatcher m(gate, circuit_); 733 // x + NaN => NaN 734 if (m.Right().IsNaN()) { 735 return builder_.NanValue(); 736 } 737 // NaN + x => NaN 738 if (m.Left().IsNaN()) { 739 return builder_.NanValue(); 740 } 741 // K + K => K (K stands for arbitrary constants) 742 if (m.IsFoldable()) { 743 return builder_.Double(m.Left().ResolvedValue() + m.Right().ResolvedValue()); 744 } 745 return Circuit::NullGate(); 746} 747GateRef InstructionCombine::ReduceDoubleSub(GateRef gate) 748{ 749 Float64BinopMatcher m(gate, circuit_); 750 // x - NaN => NaN 751 if (m.Right().IsNaN()) { 752 return builder_.NanValue(); 753 } 754 // NaN - x => NaN 755 if (m.Left().IsNaN()) { 756 return builder_.NanValue(); 757 } 758 // L - R => (L - R) 759 if (m.IsFoldable()) { 760 return builder_.Double(m.Left().ResolvedValue() - m.Right().ResolvedValue()); 761 } 762 return Circuit::NullGate(); 763} 764 765GateRef InstructionCombine::ReduceDoubleMul(GateRef gate) 766{ 767 Float64BinopMatcher m(gate, circuit_); 768 if (m.Right().Is(-1)) { // x * -1.0 => -0.0 - x 769 auto newGate = builder_.DoubleSub(builder_.Double(-0.0), m.Left().Gate()); 770 return ReplaceOld(gate, newGate); 771 } 772 if (m.Right().IsNaN()) { // x * NaN => NaN 773 return builder_.NanValue(); 774 } 775 if (m.IsFoldable()) { // K * K => K (K stands for arbitrary constants) 776 return builder_.Double(m.Left().ResolvedValue() * m.Right().ResolvedValue()); 777 } 778 if (m.Right().Is(2)) { // x * 2.0 => x + x 779 auto newGate = builder_.DoubleAdd(m.Left().Gate(), m.Left().Gate()); 780 return ReplaceOld(gate, newGate); 781 } 782 return Circuit::NullGate(); 783} 784 785GateRef InstructionCombine::ReduceDoubleDiv(GateRef gate) 786{ 787 Float64BinopMatcher m(gate, circuit_); 788 789 if (m.Right().IsNaN()) { // x / NaN => NaN 790 return builder_.NanValue(); 791 } 792 if (m.Left().IsNaN()) { // NaN / x => NaN 793 return builder_.NanValue(); 794 } 795 if (m.IsFoldable()) { // K / K => K (K stands for arbitrary constants) 796 return builder_.Double(base::Divide(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 797 } 798 799 return Circuit::NullGate(); 800} 801 802GateRef InstructionCombine::ReduceInt32Mod(GateRef gate) 803{ 804 Int32BinopMatcher m(gate, circuit_); 805 // 0 % x => 0 806 if (m.Left().Is(0)) { 807 return m.Left().Gate(); 808 } 809 // x % 0 => 0 810 if (m.Right().Is(0)) { 811 return m.Right().Gate(); 812 } 813 // x % 1 => 0 814 if (m.Right().Is(1)) { 815 return builder_.Int32(0); 816 } 817 // x % -1 => 0 818 if (m.Right().Is(-1)) { 819 return builder_.Int32(0); 820 } 821 // x % x => 0 822 if (m.LeftEqualsRight()) { 823 return builder_.Int32(0); 824 } 825 // K % K => K (K stands for arbitrary constants) 826 if (m.IsFoldable()) { 827 return builder_.Int32(base::SignedMod32(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 828 } 829 830 return Circuit::NullGate(); 831} 832 833GateRef InstructionCombine::ReduceDoubleMod(GateRef gate) 834{ 835 Float64BinopMatcher m(gate, circuit_); 836 if (m.Right().Is(0)) { // x % 0 => NaN 837 return builder_.NanValue(); 838 } 839 if (m.Right().IsNaN()) { // x % NaN => NaN 840 return builder_.NanValue(); 841 } 842 if (m.Left().IsNaN()) { // NaN % x => NaN 843 return builder_.NanValue(); 844 } 845 return Circuit::NullGate(); 846} 847 848 849GateRef InstructionCombine::ReduceWord64And(GateRef gate) 850{ 851 Int64BinopMatcher m(gate, circuit_); 852 // x & 0 => 0 853 if (m.Right().Is(0)) { 854 return m.Right().Gate(); 855 } 856 // x & -1 => x 857 if (m.Right().Is(-1)) { 858 return m.Left().Gate(); 859 } 860 // CMP & 1 => CMP 861 if (m.Left().IsIcmp() && m.Right().Is(1)) { 862 return m.Left().Gate(); 863 } 864 // K & K => K (K stands for arbitrary constants) 865 if (m.IsFoldable()) { 866 return builder_.Int64(static_cast<uint64_t>(m.Left().ResolvedValue()) & 867 static_cast<uint64_t>(m.Right().ResolvedValue())); 868 } 869 // x & x => x 870 if (m.LeftEqualsRight()) { 871 return m.Left().Gate(); 872 } 873 // (x & K) & K => x & K 874 if (m.Left().IsmInt64And() && m.Right().HasResolvedValue()) { 875 Int64BinopMatcher mleft(m.Left().Gate(), circuit_); 876 if (mleft.Right().HasResolvedValue()) { 877 auto newGate = builder_.Int64And( 878 mleft.Left().Gate(), builder_.Int64(static_cast<uint64_t>(m.Right().ResolvedValue()) & 879 static_cast<uint64_t>(mleft.Right().ResolvedValue()))); 880 return ReplaceOld(gate, newGate); 881 } 882 } 883 return Circuit::NullGate(); 884} 885 886GateRef InstructionCombine::ReduceWord32And(GateRef gate) 887{ 888 Int32BinopMatcher m(gate, circuit_); 889 // x & 0 => 0 890 if (m.Right().Is(0)) { 891 return m.Right().Gate(); 892 } 893 // x & -1 => x 894 if (m.Right().Is(-1)) { 895 return m.Left().Gate(); 896 } 897 // CMP & 1 => CMP 898 if (m.Left().IsIcmp() && m.Right().Is(1)) { 899 return m.Left().Gate(); 900 } 901 // K & K => K (K stands for arbitrary constants) 902 if (m.IsFoldable()) { 903 return builder_.Int32(static_cast<uint32_t>(m.Left().ResolvedValue()) & 904 static_cast<uint32_t>(m.Right().ResolvedValue())); 905 } 906 // x & x => x 907 if (m.LeftEqualsRight()) { 908 return m.Left().Gate(); 909 } 910 // (x & K) & K => x & K 911 if (m.Left().IsmInt32And() && m.Right().HasResolvedValue()) { 912 Int32BinopMatcher mleft(m.Left().Gate(), circuit_); 913 if (mleft.Right().HasResolvedValue()) { 914 auto newGate = builder_.Int32And( 915 mleft.Left().Gate(), builder_.Int32(static_cast<uint32_t>(m.Right().ResolvedValue()) & 916 static_cast<uint32_t>(mleft.Right().ResolvedValue()))); 917 return ReplaceOld(gate, newGate); 918 } 919 } 920 return Circuit::NullGate(); 921} 922 923GateRef InstructionCombine::ReduceWord64Or(GateRef gate) 924{ 925 Int64BinopMatcher m(gate, circuit_); 926 // x | 0 => x 927 if (m.Right().Is(0)) { 928 return m.Left().Gate(); 929 } 930 // x | -1 => -1 931 if (m.Right().Is(-1)) { 932 return m.Right().Gate(); 933 } 934 // K | K => K (K stands for arbitrary constants) 935 if (m.IsFoldable()) { 936 return builder_.Int64(static_cast<uint64_t>(m.Left().ResolvedValue()) | 937 static_cast<uint64_t>(m.Right().ResolvedValue())); 938 } 939 // x | x => x 940 if (m.LeftEqualsRight()) { 941 return m.Left().Gate(); 942 } 943 944 // (x & K1) | K2 => x | K2 if K2 has ones for every zero bit in K1. 945 if (m.Right().HasResolvedValue() && m.Left().IsmInt64And()) { 946 Int64BinopMatcher mand(m.Left().Gate(), circuit_); 947 if (mand.Right().HasResolvedValue()) { 948 if ((m.Right().ResolvedValue() | mand.Right().ResolvedValue()) == -1) { 949 acc_.ReplaceValueIn(gate, mand.Left().Gate(), 0); 950 return gate; 951 } 952 } 953 } 954 return Circuit::NullGate(); 955} 956 957GateRef InstructionCombine::ReduceWord32Or(GateRef gate) 958{ 959 Int32BinopMatcher m(gate, circuit_); 960 // x | 0 => x 961 if (m.Right().Is(0)) { 962 return m.Left().Gate(); 963 } 964 // x | -1 => -1 965 if (m.Right().Is(-1)) { 966 return m.Right().Gate(); 967 } 968 // K | K => K (K stands for arbitrary constants) 969 if (m.IsFoldable()) { 970 return builder_.Int32(static_cast<uint32_t>(m.Left().ResolvedValue()) | 971 static_cast<uint32_t>(m.Right().ResolvedValue())); 972 } 973 // x | x => x 974 if (m.LeftEqualsRight()) { 975 return m.Left().Gate(); 976 } 977 978 // (x & K1) | K2 => x | K2 if K2 has ones for every zero bit in K1. 979 if (m.Right().HasResolvedValue() && m.Left().IsmInt32And()) { 980 Int32BinopMatcher mand(m.Left().Gate(), circuit_); 981 if (mand.Right().HasResolvedValue()) { 982 if ((m.Right().ResolvedValue() | mand.Right().ResolvedValue()) == -1) { 983 acc_.ReplaceValueIn(gate, mand.Left().Gate(), 0); 984 return gate; 985 } 986 } 987 } 988 989 return Circuit::NullGate(); 990} 991 992GateRef InstructionCombine::ReduceWord64Xor(GateRef gate) 993{ 994 Int64BinopMatcher m(gate, circuit_); 995 // x ^ 0 => x 996 if (m.Right().Is(0)) { 997 return m.Left().Gate(); 998 } 999 // K ^ K => K (K stands for arbitrary constants) 1000 if (m.IsFoldable()) { 1001 return builder_.Int64(m.Left().ResolvedValue() ^ m.Right().ResolvedValue()); 1002 } 1003 if (m.LeftEqualsRight()) { 1004 return builder_.Int64(0); // x ^ x => 0 1005 } 1006 // (x ^ -1) ^ -1 => x 1007 if (m.Left().IsmInt64Xor() && m.Right().Is(-1)) { 1008 Int64BinopMatcher mleft(m.Left().Gate(), circuit_); 1009 if (mleft.Right().Is(-1)) { 1010 return mleft.Left().Gate(); 1011 } 1012 } 1013 return Circuit::NullGate(); 1014} 1015 1016GateRef InstructionCombine::ReduceWord32Xor(GateRef gate) 1017{ 1018 Int32BinopMatcher m(gate, circuit_); 1019 // x ^ 0 => x 1020 if (m.Right().Is(0)) { 1021 return m.Left().Gate(); 1022 } 1023 // K ^ K => K (K stands for arbitrary constants) 1024 if (m.IsFoldable()) { 1025 return builder_.Int32(m.Left().ResolvedValue() ^ m.Right().ResolvedValue()); 1026 } 1027 if (m.LeftEqualsRight()) { 1028 return builder_.Int32(0); // x ^ x => 0 1029 } 1030 // (x ^ -1) ^ -1 => x 1031 if (m.Left().IsmInt32Xor() && m.Right().Is(-1)) { 1032 Int32BinopMatcher mleft(m.Left().Gate(), circuit_); 1033 if (mleft.Right().Is(-1)) { 1034 return mleft.Left().Gate(); 1035 } 1036 } 1037 return Circuit::NullGate(); 1038} 1039GateRef InstructionCombine::ReduceWord64Lsr(GateRef gate) 1040{ 1041 Uint64BinopMatcher m(gate, circuit_); 1042 1043 // x >>> 0 => x 1044 if (m.Right().Is(0)) { 1045 return m.Left().Gate(); 1046 } 1047 if (m.IsFoldable()) { 1048 // 63: The '63' here is used as a mask to limit the shift amount to 0-63 bits, preventing overflow. 1049 return builder_.Int64(m.Left().ResolvedValue() >> (m.Right().ResolvedValue() & 63)); 1050 } 1051 return Circuit::NullGate(); 1052} 1053 1054GateRef InstructionCombine::ReduceWord32Lsr(GateRef gate) 1055{ 1056 Uint32BinopMatcher m(gate, circuit_); 1057 // x >>> 0 => x 1058 if (m.Right().Is(0)) { 1059 return m.Left().Gate(); 1060 } 1061 if (m.IsFoldable()) { 1062 // 31: The '31' here is used as a mask to limit the shift amount to 0-31 bits, preventing overflow. 1063 return builder_.Int32(m.Left().ResolvedValue() >> (m.Right().ResolvedValue() & 31)); 1064 } 1065 // (m >>> s) == 0 implies ((x & m) >>> s) == 0 1066 if (m.Left().IsmInt32And() && m.Right().HasResolvedValue()) { 1067 Uint32BinopMatcher mleft(m.Left().Gate(), circuit_); 1068 if (mleft.Right().HasResolvedValue()) { 1069 uint32_t shift = m.Right().ResolvedValue() & 31; 1070 uint32_t mask = mleft.Right().ResolvedValue(); 1071 if ((mask >> shift) == 0) { 1072 return builder_.Int32(0); 1073 } 1074 } 1075 } 1076 return Circuit::NullGate(); 1077} 1078 1079GateRef InstructionCombine::ReduceWord64Asr(GateRef gate) 1080{ 1081 Int64BinopMatcher m(gate, circuit_); 1082 // x >> 0 => x 1083 if (m.Right().Is(0)) { 1084 return m.Left().Gate(); 1085 } 1086 if (m.IsFoldable()) { 1087 // 63: The '63' here is used as a mask to limit the shift amount to 0-63 bits, preventing overflow. 1088 return builder_.Int64(m.Left().ResolvedValue() >> (m.Right().ResolvedValue() & 63)); 1089 } 1090 return Circuit::NullGate(); 1091} 1092 1093GateRef InstructionCombine::ReduceWord32Asr(GateRef gate) 1094{ 1095 Int32BinopMatcher m(gate, circuit_); 1096 // x >> 0 => x 1097 if (m.Right().Is(0)) { 1098 return m.Left().Gate(); 1099 } 1100 if (m.IsFoldable()) { 1101 // 31: The '31' here is used as a mask to limit the shift amount to 0-31 bits, preventing overflow. 1102 return builder_.Int32(m.Left().ResolvedValue() >> (m.Right().ResolvedValue() & 31)); 1103 } 1104 if (m.Left().IsmInt32LSL()) { 1105 Int32BinopMatcher mleft(m.Left().Gate(), circuit_); 1106 if (mleft.Left().IsIcmp()) { 1107 // Check if the right shift amount is 31 (logical shift by 31 bits). 1108 if (m.Right().Is(31) && mleft.Right().Is(31)) { 1109 auto newGate = builder_.Int32Sub(builder_.Int32(0), mleft.Left().Gate()); 1110 return ReplaceOld(gate, newGate); 1111 } 1112 } else if (mleft.Left().IsLoad()) { 1113 // Check if the right shift amount is 24 (logical shift by 24 bits). 1114 if (m.Right().Is(24) && mleft.Right().Is(24) && 1115 acc_.GetMachineType(mleft.Left().Gate()) == MachineType::I8) { 1116 return mleft.Left().Gate(); 1117 } 1118 } 1119 } 1120 return Circuit::NullGate(); 1121} 1122 1123GateRef InstructionCombine::ReduceWord64Lsl(GateRef gate) 1124{ 1125 Int64BinopMatcher m(gate, circuit_); 1126 // x << 0 => x 1127 if (m.Right().Is(0)) { 1128 return m.Left().Gate(); 1129 } 1130 if (m.IsFoldable()) { 1131 return builder_.Int64(base::ShlWithWraparound(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 1132 } 1133 // Check if the right shift amount is in the range of 1 to 63 bits (inclusive). 1134 if (m.Right().IsInRange(1, 63) && (m.Left().IsmInt64ASR() || m.Left().IsmInt64LSR())) { 1135 Int64BinopMatcher mleft(m.Left().Gate(), circuit_); 1136 // (x >>> K) << K => x & ~(2^K - 1) 1137 // (x >> K) << K => x & ~(2^K - 1) 1138 if (mleft.Right().Is(m.Right().ResolvedValue())) { 1139 auto newGate = builder_.Int64And( 1140 mleft.Left().Gate(), builder_.Int64(std::numeric_limits<uint64_t>::max() << m.Right().ResolvedValue())); 1141 return ReplaceOld(gate, newGate); 1142 } 1143 } 1144 return Circuit::NullGate(); 1145} 1146GateRef InstructionCombine::ReduceWord32Lsl(GateRef gate) 1147{ 1148 Int32BinopMatcher m(gate, circuit_); 1149 // x << 0 => x 1150 if (m.Right().Is(0)) { 1151 return m.Left().Gate(); 1152 } 1153 if (m.IsFoldable()) { 1154 return builder_.Int32(base::ShlWithWraparound(m.Left().ResolvedValue(), m.Right().ResolvedValue())); 1155 } 1156 1157 // Check if the right shift amount is in the range of 1 to 31 bits (inclusive). 1158 if (m.Right().IsInRange(1, 31) && (m.Left().IsmInt32ASR() || m.Left().IsmInt32LSR())) { 1159 Int64BinopMatcher mleft(m.Left().Gate(), circuit_); 1160 // (x >>> K) << K => x & ~(2^K - 1) 1161 // (x >> K) << K => x & ~(2^K - 1) 1162 if (mleft.Right().Is(m.Right().ResolvedValue())) { 1163 auto newGate = builder_.Int32And( 1164 mleft.Left().Gate(), builder_.Int32(std::numeric_limits<uint64_t>::max() << m.Right().ResolvedValue())); 1165 return ReplaceOld(gate, newGate); 1166 } 1167 } 1168 return Circuit::NullGate(); 1169} 1170 1171} // namespace panda::ecmascript::kungfu