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