• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 
16 #ifndef COMPILER_OPTIMIZER_OPTIMIZATIONS_PEEPHOLES_H
17 #define COMPILER_OPTIMIZER_OPTIMIZATIONS_PEEPHOLES_H
18 
19 #include "optimizer/ir/graph.h"
20 #include "optimizer/pass.h"
21 
22 #include "compiler_logger.h"
23 #include "compiler_options.h"
24 #include "optimizer/ir/analysis.h"
25 #include "optimizer/ir/graph_visitor.h"
26 
27 namespace ark::compiler {
28 
29 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
30 #define PEEPHOLE_IS_APPLIED(visitor, inst) (visitor)->SetIsApplied((inst), true, __FILE__, __LINE__)
31 
32 // NOLINTNEXTLINE(fuchsia-multiple-inheritance)
33 class PANDA_PUBLIC_API Peepholes : public Optimization, public GraphVisitor {
34     using Optimization::Optimization;
35 
36 public:
Peepholes(Graph * graph)37     explicit Peepholes(Graph *graph) : Optimization(graph) {}
38 
39     NO_MOVE_SEMANTIC(Peepholes);
40     NO_COPY_SEMANTIC(Peepholes);
41     ~Peepholes() override = default;
42 
43     bool RunImpl() override;
44 
GetPassName()45     const char *GetPassName() const override
46     {
47         return "Peepholes";
48     }
49 
IsApplied()50     bool IsApplied() const
51     {
52         return isApplied_;
53     }
54 
IsEnable()55     bool IsEnable() const override
56     {
57         return g_options.IsCompilerPeepholes();
58     }
59 
60     void InvalidateAnalyses() override;
61 
GetBlocksToVisit()62     const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override
63     {
64         return GetGraph()->GetBlocksRPO();
65     }
66 #include "intrinsics_peephole.inl.h"
67 
68     static void VisitSafePoint([[maybe_unused]] GraphVisitor *v, Inst *inst);
69     static void VisitNeg([[maybe_unused]] GraphVisitor *v, Inst *inst);
70     static void VisitAbs([[maybe_unused]] GraphVisitor *v, Inst *inst);
71     static void VisitNot([[maybe_unused]] GraphVisitor *v, Inst *inst);
72     static void VisitAdd([[maybe_unused]] GraphVisitor *v, Inst *inst);
73     static void VisitAddFinalize([[maybe_unused]] GraphVisitor *v, Inst *inst, Inst *input0, Inst *input1);
74     static void VisitSub([[maybe_unused]] GraphVisitor *v, Inst *inst);
75     static void VisitSubFinalize([[maybe_unused]] GraphVisitor *v, Inst *inst, Inst *input0, Inst *input1);
76     static void VisitMulOneConst([[maybe_unused]] GraphVisitor *v, Inst *inst, Inst *input0, Inst *input1);
77     static void VisitMul([[maybe_unused]] GraphVisitor *v, Inst *inst);
78     static void VisitDiv([[maybe_unused]] GraphVisitor *v, Inst *inst);
79     static void VisitMin([[maybe_unused]] GraphVisitor *v, Inst *inst);
80     static void VisitMax([[maybe_unused]] GraphVisitor *v, Inst *inst);
81     static void VisitMod([[maybe_unused]] GraphVisitor *v, Inst *inst);
82     static void VisitShl([[maybe_unused]] GraphVisitor *v, Inst *inst);
83     static void VisitShr([[maybe_unused]] GraphVisitor *v, Inst *inst);
84     static void VisitAShr([[maybe_unused]] GraphVisitor *v, Inst *inst);
85     static void VisitAnd([[maybe_unused]] GraphVisitor *v, Inst *inst);
86     static void VisitOr([[maybe_unused]] GraphVisitor *v, Inst *inst);
87     static void VisitXor([[maybe_unused]] GraphVisitor *v, Inst *inst);
88     static void VisitCmp(GraphVisitor *v, Inst *inst);
89     static void VisitCompare([[maybe_unused]] GraphVisitor *v, Inst *inst);
90     static void VisitIf(GraphVisitor *v, Inst *inst);
91     static void VisitCast([[maybe_unused]] GraphVisitor *v, Inst *inst);
92     static void VisitCastCase1([[maybe_unused]] GraphVisitor *v, Inst *inst);
93     static void VisitCastCase2([[maybe_unused]] GraphVisitor *v, Inst *inst);
94     static void VisitCastCase3([[maybe_unused]] GraphVisitor *v, Inst *inst);
95     static void VisitLenArray(GraphVisitor *v, Inst *inst);
96     static void VisitPhi([[maybe_unused]] GraphVisitor *v, Inst *inst);
97     static void VisitSqrt([[maybe_unused]] GraphVisitor *v, Inst *inst);
98     static void VisitIsInstance(GraphVisitor *v, Inst *inst);
99     static void VisitCastAnyTypeValue(GraphVisitor *v, Inst *inst);
100     static void VisitCastValueToAnyType(GraphVisitor *v, Inst *inst);
101     static void VisitCompareAnyType(GraphVisitor *v, Inst *inst);
102     static void VisitStore([[maybe_unused]] GraphVisitor *v, Inst *inst);
103     static void VisitStoreObject([[maybe_unused]] GraphVisitor *v, Inst *inst);
104     static void VisitStoreStatic([[maybe_unused]] GraphVisitor *v, Inst *inst);
105     static void VisitAddOverflowCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
106     static void VisitSubOverflowCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
107     static void VisitNegOverflowAndZeroCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
108     static void VisitGetInstanceClass([[maybe_unused]] GraphVisitor *v, Inst *inst);
109     static void VisitLoadAndInitClass([[maybe_unused]] GraphVisitor *v, Inst *inst);
110     static void VisitInitClass([[maybe_unused]] GraphVisitor *v, Inst *inst);
111     static void VisitIntrinsic([[maybe_unused]] GraphVisitor *v, Inst *inst);
112     static void VisitLoadClass([[maybe_unused]] GraphVisitor *v, Inst *inst);
113     static void VisitLoadConstantPool([[maybe_unused]] GraphVisitor *v, Inst *inst);
114     static void VisitLoadFromConstantPool([[maybe_unused]] GraphVisitor *v, Inst *inst);
115     static void VisitLoadObject([[maybe_unused]] GraphVisitor *v, Inst *inst);
116     static void VisitLoadStatic([[maybe_unused]] GraphVisitor *v, Inst *inst);
117 
118 #include "optimizer/ir/visitor.inc"
119 
120 private:
121     void SetIsApplied(Inst *inst, bool altFormat = false, const char *file = nullptr, int line = 0)
122     {
123         isApplied_ = true;
124         if (altFormat) {
125             COMPILER_LOG(DEBUG, PEEPHOLE) << "Peephole (" << file << ":" << line << ") is applied for " << *inst;
126         } else {
127             COMPILER_LOG(DEBUG, PEEPHOLE) << "Peephole is applied for " << GetOpcodeString(inst->GetOpcode());
128         }
129         GetGraph()->GetEventWriter().EventPeephole(GetOpcodeString(inst->GetOpcode()), inst->GetId(), inst->GetPc());
130         if (g_options.IsCompilerDumpPeepholes()) {
131             std::string name(GetPassName());
132             name += "_" + std::to_string(applyIndex_);
133             GetGraph()->GetPassManager()->DumpGraph(name.c_str());
134             applyIndex_++;
135         }
136     }
137 
138     // This function check that we can merge two Phi instructions in one basic block.
139     static bool IsPhiUnionPossible(PhiInst *phi1, PhiInst *phi2);
140 
141     // Create new instruction instead of current inst
142     static Inst *CreateAndInsertInst(Opcode newOpc, Inst *currInst, Inst *input0, Inst *input1 = nullptr);
143 
144     // Try put constant in second input
145     void TrySwapInputs(Inst *inst);
146 
147     // Try to remove redundant cast
148     void TrySimplifyCastToOperandsType(Inst *inst);
149     void TrySimplifyShifts(Inst *inst);
150     bool TrySimplifyAddSubWithZeroInput(Inst *inst);
151     bool TrySimplifyAddSubWithConstInput(Inst *inst);
152     template <Opcode OPC, int IDX>
153     void TrySimplifyAddSub(Inst *inst, Inst *input0, Inst *input1);
154     bool TrySimplifyAddSubAdd(Inst *inst, Inst *input0, Inst *input1);
155     bool TrySimplifyAddSubSub(Inst *inst, Inst *input0, Inst *input1);
156     bool TrySimplifySubAddAdd(Inst *inst, Inst *input0, Inst *input1);
157     bool TrySimplifyShlShlAdd(Inst *inst);
158     bool TryReassociateShlShlAddSub(Inst *inst);
159     void TrySimplifyNeg(Inst *inst);
160     void TryReplaceDivByShift(Inst *inst);
161     bool TrySimplifyCompareCaseInputInv(Inst *inst, Inst *input);
162     bool TrySimplifyCompareWithBoolInput(Inst *inst, bool *isOsrBlocked);
163     bool TrySimplifyCmpCompareWithZero(Inst *inst, bool *isOsrBlocked);
164     bool TrySimplifyFloatCmpCompare(Inst **input0, Inst **input1, DataType::Type *cmpOpType, Inst *compareInput,
165                                     bool *swap);
166     bool TrySimplifyTestEqualInputs(Inst *inst);
167     void TryRemoveOverflowCheck(Inst *inst);
168     static bool TrySimplifyCompareAndZero(Inst *inst, bool *isOsrBlocked);
169     static bool TrySimplifyCompareAnyType(Inst *inst);
170     static bool TrySimplifyCompareAnyTypeCase1(Inst *inst, Inst *input0, Inst *input1);
171     static bool TrySimplifyCompareAnyTypeCase2(Inst *inst, Inst *input0, Inst *input1);
172     static bool TrySimplifyCompareLenArrayWithZero(Inst *inst);
173     // Try to combine constants when arithmetic operations with constants are repeated
174     template <typename T>
175     static bool TryCombineConst(Inst *inst, ConstantInst *cnst1, T combine, bool *isOsrBlocked);
176     static bool TryCombineAddSubConst(Inst *inst, ConstantInst *cnst1, bool *isOsrBlocked);
177     static bool TryCombineShiftConst(Inst *inst, ConstantInst *cnst1, bool *isOsrBlocked);
178     static bool TryCombineMulConst(Inst *inst, ConstantInst *cnst1, bool *isOsrBlocked);
179 
180     static bool GetInputsOfCompareWithConst(const Inst *inst, Inst **input, ConstantInst **constInput,
181                                             bool *inputsSwapped);
182 
183     static bool CreateCompareInsteadOfXorAdd(Inst *oldInst);
184 
185     bool OptimizeLenArrayForMultiArray(Inst *lenArray, Inst *inst, size_t indexSize);
186     static bool TryEliminatePhi(PhiInst *phi);
187     // It is check can we use this peephole in OSR or not
188     static bool SkipThisPeepholeInOSR(Inst *inst, Inst *newInput);
189 
190     // Table for eliminating 'Compare <CC> <INPUT>, <CONST>'
191     enum InputCode {
192         INPUT_TRUE,   // Result of compare is TRUE whatever the INPUT is
193         INPUT_ORIG,   // Result of compare is equal to the INPUT itself
194         INPUT_INV,    // Result of compare is a negation of the INPUT
195         INPUT_FALSE,  // Result of compare is FALSE whatever the INPUT is
196         INPUT_UNDEF   // Result of compare is undefined
197     };
198     // clang-format off
199     static constexpr std::array<std::array<InputCode, 4>, CC_LAST + 1> VALUES = {{
200         /* CONST < 0  CONST == 0   CONST == 1   CONST > 1        CC    */
201         {INPUT_FALSE, INPUT_INV,   INPUT_ORIG,  INPUT_FALSE}, /* CC_EQ */
202         {INPUT_TRUE,  INPUT_ORIG,  INPUT_INV,   INPUT_TRUE},  /* CC_NE */
203         {INPUT_FALSE, INPUT_FALSE, INPUT_INV,   INPUT_TRUE},  /* CC_LT */
204         {INPUT_FALSE, INPUT_INV,   INPUT_TRUE,  INPUT_TRUE},  /* CC_LE */
205         {INPUT_TRUE,  INPUT_ORIG,  INPUT_FALSE, INPUT_FALSE}, /* CC_GT */
206         {INPUT_TRUE,  INPUT_TRUE,  INPUT_ORIG,  INPUT_FALSE}, /* CC_GE */
207         /* For unsigned comparison 'CONST < 0' equals to 'CONST > 1'   */
208         {INPUT_TRUE,  INPUT_FALSE, INPUT_INV,   INPUT_TRUE},  /* CC_B  */
209         {INPUT_TRUE,  INPUT_INV,   INPUT_TRUE,  INPUT_TRUE},  /* CC_BE */
210         {INPUT_FALSE, INPUT_ORIG,  INPUT_FALSE, INPUT_FALSE}, /* CC_A  */
211         {INPUT_FALSE, INPUT_TRUE,  INPUT_ORIG,  INPUT_FALSE}  /* CC_AE */
212     }};
213     // clang-format on
GetInputCode(const ConstantInst * inst,ConditionCode cc)214     static InputCode GetInputCode(const ConstantInst *inst, ConditionCode cc)
215     {
216         if (inst->GetType() == DataType::INT32) {
217             auto i = std::min<int32_t>(std::max<int32_t>(-1, static_cast<int32_t>(inst->GetInt32Value())), 2U) + 1;
218             return VALUES[cc][i];
219         }
220         if (inst->GetType() == DataType::INT64) {
221             auto i = std::min<int64_t>(std::max<int64_t>(-1, static_cast<int64_t>(inst->GetIntValue())), 2U) + 1;
222             return VALUES[cc][i];
223         }
224         UNREACHABLE();
225         return InputCode::INPUT_UNDEF;
226     }
227     template <typename T>
228     static void EliminateInstPrecedingStore(GraphVisitor *v, Inst *inst);
229     bool TrySimplifyCompareNegation(Inst *inst);
230     bool IsNegationPattern(Inst *inst);
231     bool TrySimplifyNegationPattern(Inst *inst);
232     static bool TryOptimizeBoxedLoadStoreObject(Inst *inst);
233     static bool TryOptimizeXorChain(Inst *inst);
234 
235 private:
236     // Each peephole application has own unique index, it will be used in peepholes dumps
237     uint32_t applyIndex_ {0};
238 
239     bool isApplied_ {false};
240 };
241 }  // namespace ark::compiler
242 
243 #endif  // COMPILER_OPTIMIZER_OPTIMIZATIONS_PEEPHOLES_H
244