• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 VisitLoadStatic([[maybe_unused]] GraphVisitor *v, Inst *inst);
116 
117 #include "optimizer/ir/visitor.inc"
118 
119 private:
120     void SetIsApplied(Inst *inst, bool altFormat = false, const char *file = nullptr, int line = 0)
121     {
122         isApplied_ = true;
123         if (altFormat) {
124             COMPILER_LOG(DEBUG, PEEPHOLE) << "Peephole (" << file << ":" << line << ") is applied for " << *inst;
125         } else {
126             COMPILER_LOG(DEBUG, PEEPHOLE) << "Peephole is applied for " << GetOpcodeString(inst->GetOpcode());
127         }
128         GetGraph()->GetEventWriter().EventPeephole(GetOpcodeString(inst->GetOpcode()), inst->GetId(), inst->GetPc());
129         if (g_options.IsCompilerDumpPeepholes()) {
130             std::string name(GetPassName());
131             name += "_" + std::to_string(applyIndex_);
132             GetGraph()->GetPassManager()->DumpGraph(name.c_str());
133             applyIndex_++;
134         }
135     }
136 
137     // This function check that we can merge two Phi instructions in one basic block.
138     static bool IsPhiUnionPossible(PhiInst *phi1, PhiInst *phi2);
139 
140     // Create new instruction instead of current inst
141     static Inst *CreateAndInsertInst(Opcode newOpc, Inst *currInst, Inst *input0, Inst *input1 = nullptr);
142 
143     // Try put constant in second input
144     void TrySwapInputs(Inst *inst);
145 
146     // Try to remove redundant cast
147     void TrySimplifyCastToOperandsType(Inst *inst);
148     void TrySimplifyShifts(Inst *inst);
149     bool TrySimplifyAddSubWithZeroInput(Inst *inst);
150     bool TrySimplifyAddSubWithConstInput(Inst *inst);
151     template <Opcode OPC, int IDX>
152     void TrySimplifyAddSub(Inst *inst, Inst *input0, Inst *input1);
153     bool TrySimplifyAddSubAdd(Inst *inst, Inst *input0, Inst *input1);
154     bool TrySimplifyAddSubSub(Inst *inst, Inst *input0, Inst *input1);
155     bool TrySimplifySubAddAdd(Inst *inst, Inst *input0, Inst *input1);
156     bool TrySimplifyShlShlAdd(Inst *inst);
157     bool TryReassociateShlShlAddSub(Inst *inst);
158     void TrySimplifyNeg(Inst *inst);
159     void TryReplaceDivByShift(Inst *inst);
160     bool TrySimplifyCompareCaseInputInv(Inst *inst, Inst *input);
161     bool TrySimplifyCompareWithBoolInput(Inst *inst, bool *isOsrBlocked);
162     bool TrySimplifyCmpCompareWithZero(Inst *inst, bool *isOsrBlocked);
163     bool TrySimplifyFloatCmpCompare(Inst **input0, Inst **input1, DataType::Type *cmpOpType, Inst *compareInput,
164                                     bool *swap);
165     bool TrySimplifyTestEqualInputs(Inst *inst);
166     void TryRemoveOverflowCheck(Inst *inst);
167     static bool TrySimplifyCompareAndZero(Inst *inst, bool *isOsrBlocked);
168     static bool TrySimplifyCompareAnyType(Inst *inst);
169     static bool TrySimplifyCompareAnyTypeCase1(Inst *inst, Inst *input0, Inst *input1);
170     static bool TrySimplifyCompareAnyTypeCase2(Inst *inst, Inst *input0, Inst *input1);
171     static bool TrySimplifyCompareLenArrayWithZero(Inst *inst);
172     // Try to combine constants when arithmetic operations with constants are repeated
173     template <typename T>
174     static bool TryCombineConst(Inst *inst, ConstantInst *cnst1, T combine, bool *isOsrBlocked);
175     static bool TryCombineAddSubConst(Inst *inst, ConstantInst *cnst1, bool *isOsrBlocked);
176     static bool TryCombineShiftConst(Inst *inst, ConstantInst *cnst1, bool *isOsrBlocked);
177     static bool TryCombineMulConst(Inst *inst, ConstantInst *cnst1, bool *isOsrBlocked);
178 
179     static bool GetInputsOfCompareWithConst(const Inst *inst, Inst **input, ConstantInst **constInput,
180                                             bool *inputsSwapped);
181 
182     static bool CreateCompareInsteadOfXorAdd(Inst *oldInst);
183 
184     bool OptimizeLenArrayForMultiArray(Inst *lenArray, Inst *inst, size_t indexSize);
185     static bool TryEliminatePhi(PhiInst *phi);
186     // It is check can we use this peephole in OSR or not
187     static bool SkipThisPeepholeInOSR(Inst *inst, Inst *newInput);
188 
189     // Table for eliminating 'Compare <CC> <INPUT>, <CONST>'
190     enum InputCode {
191         INPUT_TRUE,   // Result of compare is TRUE whatever the INPUT is
192         INPUT_ORIG,   // Result of compare is equal to the INPUT itself
193         INPUT_INV,    // Result of compare is a negation of the INPUT
194         INPUT_FALSE,  // Result of compare is FALSE whatever the INPUT is
195         INPUT_UNDEF   // Result of compare is undefined
196     };
197     // clang-format off
198     static constexpr std::array<std::array<InputCode, 4>, CC_LAST + 1> VALUES = {{
199         /* CONST < 0  CONST == 0   CONST == 1   CONST > 1        CC    */
200         {INPUT_FALSE, INPUT_INV,   INPUT_ORIG,  INPUT_FALSE}, /* CC_EQ */
201         {INPUT_TRUE,  INPUT_ORIG,  INPUT_INV,   INPUT_TRUE},  /* CC_NE */
202         {INPUT_FALSE, INPUT_FALSE, INPUT_INV,   INPUT_TRUE},  /* CC_LT */
203         {INPUT_FALSE, INPUT_INV,   INPUT_TRUE,  INPUT_TRUE},  /* CC_LE */
204         {INPUT_TRUE,  INPUT_ORIG,  INPUT_FALSE, INPUT_FALSE}, /* CC_GT */
205         {INPUT_TRUE,  INPUT_TRUE,  INPUT_ORIG,  INPUT_FALSE}, /* CC_GE */
206         /* For unsigned comparison 'CONST < 0' equals to 'CONST > 1'   */
207         {INPUT_TRUE,  INPUT_FALSE, INPUT_INV,   INPUT_TRUE},  /* CC_B  */
208         {INPUT_TRUE,  INPUT_INV,   INPUT_TRUE,  INPUT_TRUE},  /* CC_BE */
209         {INPUT_FALSE, INPUT_ORIG,  INPUT_FALSE, INPUT_FALSE}, /* CC_A  */
210         {INPUT_FALSE, INPUT_TRUE,  INPUT_ORIG,  INPUT_FALSE}  /* CC_AE */
211     }};
212     // clang-format on
GetInputCode(const ConstantInst * inst,ConditionCode cc)213     static InputCode GetInputCode(const ConstantInst *inst, ConditionCode cc)
214     {
215         if (inst->GetType() == DataType::INT32) {
216             auto i = std::min<int32_t>(std::max<int32_t>(-1, static_cast<int32_t>(inst->GetInt32Value())), 2U) + 1;
217             return VALUES[cc][i];
218         }
219         if (inst->GetType() == DataType::INT64) {
220             auto i = std::min<int64_t>(std::max<int64_t>(-1, static_cast<int64_t>(inst->GetIntValue())), 2U) + 1;
221             return VALUES[cc][i];
222         }
223         UNREACHABLE();
224         return InputCode::INPUT_UNDEF;
225     }
226     template <typename T>
227     static void EliminateInstPrecedingStore(GraphVisitor *v, Inst *inst);
228     bool TrySimplifyCompareNegation(Inst *inst);
229     bool IsNegationPattern(Inst *inst);
230     bool TrySimplifyNegationPattern(Inst *inst);
231 
232 private:
233     // Each peephole application has own unique index, it will be used in peepholes dumps
234     uint32_t applyIndex_ {0};
235 
236     bool isApplied_ {false};
237 };
238 }  // namespace ark::compiler
239 
240 #endif  // COMPILER_OPTIMIZER_OPTIMIZATIONS_PEEPHOLES_H
241