• 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_IR_GRAPH_CHECKER_H
17 #define COMPILER_OPTIMIZER_IR_GRAPH_CHECKER_H
18 
19 #include "compiler_options.h"
20 #include "graph.h"
21 #include "graph_visitor.h"
22 #include "graph_checker_macros.h"
23 #include "optimizer/analysis/dominators_tree.h"
24 #include "optimizer/analysis/rpo.h"
25 #include "optimizer/analysis/loop_analyzer.h"
26 #include "optimizer/code_generator/registers_description.h"
27 #include "optimizer/optimizations/cleanup.h"
28 #include "optimizer/optimizations/memory_coalescing.h"
29 #include <iostream>
30 
31 // CC-OFFNXT(G.PRE.02) should be with define
32 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
33 #define CHECKER_DO_IF_NOT_VISITOR(visitor, cond, func) \
34     CHECKER_DO_IF_NOT_VISITOR_INTERNAL(visitor, GraphChecker *, cond, func)
35 
36 namespace ark::compiler {
37 inline std::ostream &operator<<(std::ostream &os, const std::initializer_list<Opcode> &opcs)
38 {
39     os << "[ ";
40     for (auto opc : opcs) {
41         os << GetOpcodeString(opc) << " ";
42     }
43     os << "]";
44     return os;
45 }
46 
47 class GraphChecker : public GraphVisitor {
48 public:
49     explicit GraphChecker(Graph *graph, const char *passName);
50     PANDA_PUBLIC_API explicit GraphChecker(Graph *graph);
51 
~GraphChecker()52     ~GraphChecker() override
53     {
54         GetGraph()->GetPassManager()->SetCheckMode(false);
55     }
56 
57     NO_COPY_SEMANTIC(GraphChecker);
58     NO_MOVE_SEMANTIC(GraphChecker);
59 
60     PANDA_PUBLIC_API bool Check();
61 
GetStatus()62     bool GetStatus() const
63     {
64         return success_;
65     }
66 
SetStatus(bool status)67     void SetStatus(bool status)
68     {
69         success_ = status;
70     }
71 
72 private:
73     void PreCloneChecks(Graph *graph);
74     void UserInputCheck(Graph *graph);
75     void CheckBlock(BasicBlock *block);
76     void CheckDomTree();
77     void CheckLoopAnalysis();
78     void CheckStartBlock();
79     void CheckEndBlock();
80     void CheckControlFlow(BasicBlock *block);
81     void CheckDataFlow(BasicBlock *block);
82     void CheckUserOfInt32(BasicBlock *block, Inst *inst, User &user);
83     void CheckInstUsers(Inst *inst, [[maybe_unused]] BasicBlock *block);
84     void CheckPhiInputs(Inst *phiInst);
85     void CheckInstsRegisters(BasicBlock *block);
86     void CheckPhisRegisters(BasicBlock *block);
87     void CheckNoLowLevel(BasicBlock *block);
88     void CheckLoops();
89     void CheckGraph();
90     bool HasOuterInfiniteLoop();
91     bool CheckInstHasInput(Inst *inst, Inst *input);
92     bool CheckInstHasUser(Inst *inst, Inst *user);
93     void CheckCallReturnInlined();
94     void CheckSaveStateCaller(SaveStateInst *savestate);
95     bool FindCaller(Inst *caller, BasicBlock *domBlock, ArenaStack<Inst *> *inlinedCalls);
96     void CheckSpillFillHolder(Inst *inst);
97     bool CheckInstRegUsageSaved(const Inst *inst, Register reg) const;
98     void MarkBlocksInLoop(Loop *loop, Marker mrk);
99     bool CheckBlockHasPredecessor(BasicBlock *block, BasicBlock *predecessor);
100     bool CheckBlockHasSuccessor(BasicBlock *block, BasicBlock *successor);
101     bool BlockContainsInstruction(BasicBlock *block, Opcode opcode);
102     void CheckLoopHasSafePoint(Loop *loop);
103     void CheckBlockEdges(const BasicBlock &block);
104     void CheckTryBeginBlock(const BasicBlock &block);
105     void CheckJump(const BasicBlock &block);
106     bool IsTryCatchDomination(const BasicBlock *inputBlock, const BasicBlock *userBlock) const;
107     void CheckInputType(Inst *inst);
108 #ifdef COMPILER_DEBUG_CHECKS
109     bool NeedCheckSaveState();
110     void PrepareUsers(Inst *inst, ArenaVector<User *> *users);
111     bool IsPhiSafeToSkipObjectCheck(Inst *inst, Marker visited);
112     bool IsPhiUserSafeToSkipObjectCheck(Inst *inst, Marker visited);
113     void CheckSaveStateInputs(Inst *inst, ArenaVector<User *> *users);
114 #endif  // COMPILER_DEBUG_CHECKS
115     void CheckSaveStateInputs();
116     void CheckSaveStatesWithRuntimeCallUsers();
117     void CheckSaveStatesWithRuntimeCallUsers(BasicBlock *block, SaveStateInst *ss);
118     void CheckSaveStateOsrRec(const Inst *inst, const Inst *user, BasicBlock *block, Marker visited);
119 
GetGraph()120     Graph *GetGraph() const
121     {
122         return graph_;
123     }
124 
GetAllocator()125     ArenaAllocator *GetAllocator()
126     {
127         return &allocator_;
128     }
129 
GetLocalAllocator()130     ArenaAllocator *GetLocalAllocator()
131     {
132         return &localAllocator_;
133     }
134 
GetBlocksToVisit()135     const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override
136     {
137         return GetGraph()->GetBlocksRPO();
138     }
139 
140     /*
141      * Visitors to check instructions types
142      */
143     static PANDA_PUBLIC_API void VisitMov([[maybe_unused]] GraphVisitor *v, Inst *inst);
144     static PANDA_PUBLIC_API void VisitNeg([[maybe_unused]] GraphVisitor *v, Inst *inst);
145     static PANDA_PUBLIC_API void VisitAbs([[maybe_unused]] GraphVisitor *v, Inst *inst);
146     static PANDA_PUBLIC_API void VisitSqrt([[maybe_unused]] GraphVisitor *v, Inst *inst);
147     static PANDA_PUBLIC_API void VisitAddI([[maybe_unused]] GraphVisitor *v, Inst *inst);
148     static PANDA_PUBLIC_API void VisitSubI([[maybe_unused]] GraphVisitor *v, Inst *inst);
149     static PANDA_PUBLIC_API void VisitMulI([[maybe_unused]] GraphVisitor *v, Inst *inst);
150     static PANDA_PUBLIC_API void VisitDivI([[maybe_unused]] GraphVisitor *v, Inst *inst);
151     static PANDA_PUBLIC_API void VisitModI([[maybe_unused]] GraphVisitor *v, Inst *inst);
152     static PANDA_PUBLIC_API void VisitAndI([[maybe_unused]] GraphVisitor *v, Inst *inst);
153     static PANDA_PUBLIC_API void VisitOrI([[maybe_unused]] GraphVisitor *v, Inst *inst);
154     static PANDA_PUBLIC_API void VisitXorI([[maybe_unused]] GraphVisitor *v, Inst *inst);
155     static PANDA_PUBLIC_API void VisitShlI([[maybe_unused]] GraphVisitor *v, Inst *inst);
156     static PANDA_PUBLIC_API void VisitShrI([[maybe_unused]] GraphVisitor *v, Inst *inst);
157     static PANDA_PUBLIC_API void VisitAShlI([[maybe_unused]] GraphVisitor *v, Inst *inst);
158     static PANDA_PUBLIC_API void VisitNot([[maybe_unused]] GraphVisitor *v, Inst *inst);
159     static PANDA_PUBLIC_API void VisitAdd([[maybe_unused]] GraphVisitor *v, Inst *inst);
160     static PANDA_PUBLIC_API void VisitSub([[maybe_unused]] GraphVisitor *v, Inst *inst);
161     static PANDA_PUBLIC_API void VisitMul([[maybe_unused]] GraphVisitor *v, Inst *inst);
162     static PANDA_PUBLIC_API void VisitDiv([[maybe_unused]] GraphVisitor *v, Inst *inst);
163     static PANDA_PUBLIC_API void VisitMod([[maybe_unused]] GraphVisitor *v, Inst *inst);
164     static PANDA_PUBLIC_API void VisitMin([[maybe_unused]] GraphVisitor *v, Inst *inst);
165     static PANDA_PUBLIC_API void VisitMax([[maybe_unused]] GraphVisitor *v, Inst *inst);
166     static PANDA_PUBLIC_API void VisitShl([[maybe_unused]] GraphVisitor *v, Inst *inst);
167     static PANDA_PUBLIC_API void VisitShr([[maybe_unused]] GraphVisitor *v, Inst *inst);
168     static PANDA_PUBLIC_API void VisitAShr([[maybe_unused]] GraphVisitor *v, Inst *inst);
169     static PANDA_PUBLIC_API void VisitAnd([[maybe_unused]] GraphVisitor *v, Inst *inst);
170     static PANDA_PUBLIC_API void VisitOr([[maybe_unused]] GraphVisitor *v, Inst *inst);
171     static PANDA_PUBLIC_API void VisitXor([[maybe_unused]] GraphVisitor *v, Inst *inst);
172     static PANDA_PUBLIC_API void VisitLoadArray([[maybe_unused]] GraphVisitor *v, Inst *inst);
173     static PANDA_PUBLIC_API void VisitLoadArrayI([[maybe_unused]] GraphVisitor *v, Inst *inst);
174     static PANDA_PUBLIC_API void VisitLoadArrayPair([[maybe_unused]] GraphVisitor *v, Inst *inst);
175     static PANDA_PUBLIC_API void VisitLoadObjectPair([[maybe_unused]] GraphVisitor *v, Inst *inst);
176     static PANDA_PUBLIC_API void VisitLoadArrayPairI([[maybe_unused]] GraphVisitor *v, Inst *inst);
177     static PANDA_PUBLIC_API void VisitLoadPairPart([[maybe_unused]] GraphVisitor *v, Inst *inst);
178     static PANDA_PUBLIC_API void VisitStore([[maybe_unused]] GraphVisitor *v, Inst *inst);
179     static PANDA_PUBLIC_API void VisitStoreI([[maybe_unused]] GraphVisitor *v, Inst *inst);
180     static PANDA_PUBLIC_API void VisitStoreArrayPair([[maybe_unused]] GraphVisitor *v, Inst *inst);
181     static PANDA_PUBLIC_API void VisitStoreObjectPair([[maybe_unused]] GraphVisitor *v, Inst *inst);
182     static PANDA_PUBLIC_API void VisitStoreArrayPairI([[maybe_unused]] GraphVisitor *v, Inst *inst);
183     static PANDA_PUBLIC_API void VisitStoreArray([[maybe_unused]] GraphVisitor *v, Inst *inst);
184     static PANDA_PUBLIC_API void VisitStoreArrayI([[maybe_unused]] GraphVisitor *v, Inst *inst);
185     static PANDA_PUBLIC_API void VisitStoreStatic([[maybe_unused]] GraphVisitor *v, Inst *inst);
186     static PANDA_PUBLIC_API void VisitUnresolvedStoreStatic([[maybe_unused]] GraphVisitor *v, Inst *inst);
187     static PANDA_PUBLIC_API void VisitStoreObject([[maybe_unused]] GraphVisitor *v, Inst *inst);
188     static PANDA_PUBLIC_API void VisitStoreObjectDynamic([[maybe_unused]] GraphVisitor *v, Inst *inst);
189     static PANDA_PUBLIC_API void VisitStoreResolvedObjectField([[maybe_unused]] GraphVisitor *v, Inst *inst);
190     static PANDA_PUBLIC_API void VisitFillConstArray([[maybe_unused]] GraphVisitor *v, Inst *inst);
191     static PANDA_PUBLIC_API void VisitStoreResolvedObjectFieldStatic([[maybe_unused]] GraphVisitor *v, Inst *inst);
192     static PANDA_PUBLIC_API void VisitLoadStatic([[maybe_unused]] GraphVisitor *v, Inst *inst);
193     static PANDA_PUBLIC_API void VisitLoadClass([[maybe_unused]] GraphVisitor *v, Inst *inst);
194     static PANDA_PUBLIC_API void VisitLoadAndInitClass([[maybe_unused]] GraphVisitor *v, Inst *inst);
195     static PANDA_PUBLIC_API void VisitUnresolvedLoadAndInitClass([[maybe_unused]] GraphVisitor *v, Inst *inst);
196     static PANDA_PUBLIC_API void VisitGetInstanceClass([[maybe_unused]] GraphVisitor *v, Inst *inst);
197     static PANDA_PUBLIC_API void VisitNewObject([[maybe_unused]] GraphVisitor *v, Inst *inst);
198     static PANDA_PUBLIC_API void VisitInitObject([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
199     static PANDA_PUBLIC_API void VisitInitClass([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
200     static PANDA_PUBLIC_API void VisitIntrinsic([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
201     static PANDA_PUBLIC_API void VisitLoadRuntimeClass([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
202     static PANDA_PUBLIC_API void VisitLoadObject([[maybe_unused]] GraphVisitor *v, Inst *inst);
203     static PANDA_PUBLIC_API void VisitConstant([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
204     static PANDA_PUBLIC_API void VisitNullPtr([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
205     static PANDA_PUBLIC_API void VisitLoadUndefined([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
206     static PANDA_PUBLIC_API void VisitPhi([[maybe_unused]] GraphVisitor *v, Inst *inst);
207     static PANDA_PUBLIC_API void VisitParameter([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
208     static PANDA_PUBLIC_API void VisitCompare([[maybe_unused]] GraphVisitor *v, Inst *inst);
209     static PANDA_PUBLIC_API void VisitCast([[maybe_unused]] GraphVisitor *v, Inst *inst);
210     static PANDA_PUBLIC_API void VisitCmp([[maybe_unused]] GraphVisitor *v, Inst *inst);
211     static PANDA_PUBLIC_API void VisitMonitor([[maybe_unused]] GraphVisitor *v, Inst *inst);
212     static PANDA_PUBLIC_API void VisitReturn([[maybe_unused]] GraphVisitor *v, Inst *inst);
213     static PANDA_PUBLIC_API void VisitReturnVoid([[maybe_unused]] GraphVisitor *v, Inst *inst);
214     static PANDA_PUBLIC_API void VisitNullCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
215     static PANDA_PUBLIC_API void VisitBoundsCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
216     static PANDA_PUBLIC_API void VisitBoundsCheckI([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
217     static PANDA_PUBLIC_API void VisitRefTypeCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
218     static PANDA_PUBLIC_API void VisitNegativeCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
219     static PANDA_PUBLIC_API void VisitNotPositiveCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
220     static PANDA_PUBLIC_API void VisitZeroCheck([[maybe_unused]] GraphVisitor *v, Inst *inst);
221     static PANDA_PUBLIC_API void VisitDeoptimizeIf([[maybe_unused]] GraphVisitor *v, Inst *inst);
222     static PANDA_PUBLIC_API void VisitLenArray([[maybe_unused]] GraphVisitor *v, Inst *inst);
223     static PANDA_PUBLIC_API void VisitCallVirtual([[maybe_unused]] GraphVisitor *v, Inst *inst);
224     static PANDA_PUBLIC_API void VisitCallDynamic([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
225     static PANDA_PUBLIC_API void VisitSaveState([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
226     static PANDA_PUBLIC_API void VisitSafePoint([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
227     static PANDA_PUBLIC_API void VisitSaveStateOsr([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
228     static PANDA_PUBLIC_API void VisitThrow([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
229     static PANDA_PUBLIC_API void VisitCheckCast([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
230     static PANDA_PUBLIC_API void VisitIsInstance([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
231     static PANDA_PUBLIC_API void VisitSelect([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
232     static PANDA_PUBLIC_API void VisitSelectWithReference([[maybe_unused]] GraphVisitor *v,
233                                                           [[maybe_unused]] Inst *inst);
234     static PANDA_PUBLIC_API void VisitSelectImm([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
235     static PANDA_PUBLIC_API void VisitSelectImmWithReference([[maybe_unused]] GraphVisitor *v,
236                                                              [[maybe_unused]] Inst *inst);
237     static PANDA_PUBLIC_API void VisitSelectImmNotReference([[maybe_unused]] GraphVisitor *v,
238                                                             [[maybe_unused]] Inst *inst);
239     static PANDA_PUBLIC_API void VisitIf([[maybe_unused]] GraphVisitor *v, Inst *inst);
240     static PANDA_PUBLIC_API void VisitIfImm([[maybe_unused]] GraphVisitor *v, Inst *inst);
241     static PANDA_PUBLIC_API void VisitTry([[maybe_unused]] GraphVisitor *v, Inst *inst);
242     static PANDA_PUBLIC_API void VisitNOP([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
243     static PANDA_PUBLIC_API void VisitAndNot([[maybe_unused]] GraphVisitor *v, Inst *inst);
244     static PANDA_PUBLIC_API void VisitOrNot([[maybe_unused]] GraphVisitor *v, Inst *inst);
245     static PANDA_PUBLIC_API void VisitXorNot([[maybe_unused]] GraphVisitor *v, Inst *inst);
246     static PANDA_PUBLIC_API void VisitMNeg([[maybe_unused]] GraphVisitor *v, Inst *inst);
247     static PANDA_PUBLIC_API void VisitMAdd([[maybe_unused]] GraphVisitor *v, Inst *inst);
248     static PANDA_PUBLIC_API void VisitMSub([[maybe_unused]] GraphVisitor *v, Inst *inst);
249     static PANDA_PUBLIC_API void VisitAddSR(GraphVisitor *v, Inst *inst);
250     static PANDA_PUBLIC_API void VisitSubSR(GraphVisitor *v, Inst *inst);
251     static PANDA_PUBLIC_API void VisitAndSR(GraphVisitor *v, Inst *inst);
252     static PANDA_PUBLIC_API void VisitOrSR(GraphVisitor *v, Inst *inst);
253     static PANDA_PUBLIC_API void VisitXorSR(GraphVisitor *v, Inst *inst);
254     static PANDA_PUBLIC_API void VisitAndNotSR(GraphVisitor *v, Inst *inst);
255     static PANDA_PUBLIC_API void VisitOrNotSR(GraphVisitor *v, Inst *inst);
256     static PANDA_PUBLIC_API void VisitXorNotSR(GraphVisitor *v, Inst *inst);
257     static PANDA_PUBLIC_API void VisitNegSR([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
258     static PANDA_PUBLIC_API void VisitCompareAnyType(GraphVisitor *v, Inst *inst);
259     static PANDA_PUBLIC_API void VisitCastAnyTypeValue(GraphVisitor *v, Inst *inst);
260     static PANDA_PUBLIC_API void VisitCastValueToAnyType(GraphVisitor *v, Inst *inst);
261     static PANDA_PUBLIC_API void VisitAnyTypeCheck(GraphVisitor *v, Inst *inst);
262     static PANDA_PUBLIC_API void VisitHclassCheck(GraphVisitor *v, Inst *inst);
263     static PANDA_PUBLIC_API void VisitBitcast(GraphVisitor *v, Inst *inst);
264     static PANDA_PUBLIC_API void VisitAddOverflow([[maybe_unused]] GraphVisitor *v, Inst *inst);
265     static PANDA_PUBLIC_API void VisitSubOverflow([[maybe_unused]] GraphVisitor *v, Inst *inst);
266     static PANDA_PUBLIC_API void VisitLoadString(GraphVisitor *v, Inst *inst);
267     static PANDA_PUBLIC_API void VisitLoadType(GraphVisitor *v, Inst *inst);
268     static PANDA_PUBLIC_API void VisitLoadUnresolvedType(GraphVisitor *v, Inst *inst);
269     static PANDA_PUBLIC_API void VisitLoadFromConstantPool(GraphVisitor *v, Inst *inst);
270     static PANDA_PUBLIC_API void VisitLoadImmediate([[maybe_unused]] GraphVisitor *v, Inst *inst);
271 
272 #include "visitor.inc"
273 
CheckCommonTypes(Inst * inst1,Inst * inst2)274     static bool CheckCommonTypes(Inst *inst1, Inst *inst2)
275     {
276         if (inst1->GetBasicBlock()->GetGraph()->IsDynamicMethod() &&
277             (inst1->GetType() == DataType::ANY || inst2->GetType() == DataType::ANY)) {
278             return true;
279         }
280         DataType::Type type1 = inst1->GetType();
281         DataType::Type type2 = inst2->GetType();
282         return DataType::GetCommonType(type1) == DataType::GetCommonType(type2);
283     }
284 
285     static void CheckBinaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst, bool isInt = false)
286     {
287         [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst();
288         [[maybe_unused]] auto op2 = inst->GetInputs()[1].GetInst();
289 
290         if (inst->GetOpcode() == Opcode::Div || inst->GetOpcode() == Opcode::Mod) {
291             if (op2->GetOpcode() == Opcode::ZeroCheck) {
292                 op2 = op2->GetInput(0).GetInst();
293             }
294         }
295 
296         if (isInt) {
297             CHECKER_DO_IF_NOT_VISITOR(
298                 v, DataType::GetCommonType(inst->GetType()) == DataType::INT64,
299                 (std::cerr << "Binary instruction type is not a integer", inst->Dump(&std::cerr)));
300         }
301 
302         CHECKER_DO_IF_NOT_VISITOR(
303             v, DataType::IsTypeNumeric(op1->GetType()),
304             (std::cerr << "Binary instruction 1st operand type is not a numeric", inst->Dump(&std::cerr)));
305         CHECKER_DO_IF_NOT_VISITOR(
306             v, DataType::IsTypeNumeric(op2->GetType()),
307             (std::cerr << "Binary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr)));
308         CHECKER_DO_IF_NOT_VISITOR(v, DataType::IsTypeNumeric(inst->GetType()),
309                                   (std::cerr << "Binary instruction type is not a numeric", inst->Dump(&std::cerr)));
310 
311         CHECKER_DO_IF_NOT_VISITOR(v, CheckCommonTypes(op1, op2),
312                                   (std::cerr << "Types of binary instruction operands are not compatible\n",
313                                    op1->Dump(&std::cerr), op2->Dump(&std::cerr), inst->Dump(&std::cerr)));
314         CHECKER_DO_IF_NOT_VISITOR(
315             v, CheckCommonTypes(inst, op1),
316             (std::cerr << "Types of binary instruction result and its operands are not compatible\n",
317              inst->Dump(&std::cerr)));
318     }
319 
CheckBinaryOverflowOperation(GraphVisitor * v,IfInst * inst)320     static void CheckBinaryOverflowOperation(GraphVisitor *v, IfInst *inst)
321     {
322         // Overflow instruction are used only in dynamic methods.
323         // But ASSERT wasn't added because the instructions checks in codegen_test.cpp with default method
324         // NOTE(pishin) add an ASSERT after add assembly tests tests and remove the test from codegen_test.cpp
325         [[maybe_unused]] auto cc = inst->GetCc();
326         CHECKER_DO_IF_NOT_VISITOR(v, (cc == CC_EQ || cc == CC_NE),
327                                   (std::cerr << "overflow instruction are used only CC_EQ or CC_NE"));
328         CheckBinaryOperationTypes(v, inst, true);
329         CHECKER_DO_IF_NOT_VISITOR(v, !DataType::IsLessInt32(inst->GetType()),
330                                   (std::cerr << "overflow instruction have INT32 or INT64 types"));
331     }
332 
CheckBinaryOperationWithShiftedOperandTypes(GraphVisitor * v,Inst * inst,bool rorSupported)333     static void CheckBinaryOperationWithShiftedOperandTypes(GraphVisitor *v, Inst *inst,
334                                                             [[maybe_unused]] bool rorSupported)
335     {
336         CheckBinaryOperationTypes(v, inst, true);
337         [[maybe_unused]] auto instWShift = static_cast<BinaryShiftedRegisterOperation *>(inst);
338         CHECKER_DO_IF_NOT_VISITOR(v,
339                                   instWShift->GetShiftType() != ShiftType::INVALID_SHIFT &&
340                                       (rorSupported || instWShift->GetShiftType() != ShiftType::ROR),
341                                   (std::cerr << "Operation has invalid shift type\n", inst->Dump(&std::cerr)));
342     }
343 
CheckUnaryOperationTypes(GraphVisitor * v,Inst * inst)344     static void CheckUnaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst)
345     {
346         [[maybe_unused]] auto op = inst->GetInput(0).GetInst();
347         CHECKER_DO_IF_NOT_VISITOR(
348             v, CheckCommonTypes(inst, op),
349             (std::cerr << "Types of unary instruction result and its operand are not compatible\n",
350              inst->Dump(&std::cerr), op->Dump(&std::cerr)));
351     }
352 
353     static void CheckTernaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst, bool isInt = false)
354     {
355         [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst();
356         [[maybe_unused]] auto op2 = inst->GetInputs()[1].GetInst();
357         [[maybe_unused]] auto op3 = inst->GetInputs()[1].GetInst();
358 
359         if (isInt) {
360             CHECKER_DO_IF_NOT_VISITOR(
361                 v, DataType::GetCommonType(inst->GetType()) == DataType::INT64,
362                 (std::cerr << "Ternary instruction type is not a integer", inst->Dump(&std::cerr)));
363         }
364 
365         CHECKER_DO_IF_NOT_VISITOR(
366             v, DataType::IsTypeNumeric(op1->GetType()),
367             (std::cerr << "Ternary instruction 1st operand type is not a numeric", inst->Dump(&std::cerr)));
368         CHECKER_DO_IF_NOT_VISITOR(
369             v, DataType::IsTypeNumeric(op2->GetType()),
370             (std::cerr << "Ternary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr)));
371         CHECKER_DO_IF_NOT_VISITOR(
372             v, DataType::IsTypeNumeric(op3->GetType()),
373             (std::cerr << "Ternary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr)));
374         CHECKER_DO_IF_NOT_VISITOR(v, DataType::IsTypeNumeric(inst->GetType()),
375                                   (std::cerr << "Ternary instruction type is not a numeric", inst->Dump(&std::cerr)));
376 
377         CHECKER_DO_IF_NOT_VISITOR(v, CheckCommonTypes(op1, op2) && CheckCommonTypes(op2, op3),
378                                   (std::cerr << "Types of ternary instruction operands are not compatible\n",
379                                    op1->Dump(&std::cerr), op2->Dump(&std::cerr), op3->Dump(&std::cerr),
380                                    inst->Dump(&std::cerr)));
381         CHECKER_DO_IF_NOT_VISITOR(
382             v, CheckCommonTypes(inst, op1),
383             (std::cerr << "Types of ternary instruction result and its operands are not compatible\n",
384              inst->Dump(&std::cerr)));
385     }
386 
387     static void CheckMemoryInstruction([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst,
388                                        [[maybe_unused]] bool needBarrier = false)
389     {
390         CHECKER_DO_IF_NOT_VISITOR(v,
391                                   DataType::IsTypeNumeric(inst->GetType()) || inst->GetType() == DataType::REFERENCE ||
392                                       inst->GetType() == DataType::ANY,
393                                   (std::cerr << "Memory instruction has wrong type\n", inst->Dump(&std::cerr)));
394         if (inst->IsStore() && (inst->GetInputType(0) != DataType::POINTER) && (inst->GetType() == DataType::ANY)) {
395             CHECKER_DO_IF_NOT_VISITOR(v, needBarrier,
396                                       (std::cerr << "This store should have barrier:\n", inst->Dump(&std::cerr)));
397         }
398     }
399 
CheckObjectTypeDynamic(GraphVisitor * v,Inst * inst,ObjectType type,uint32_t typeId)400     static void CheckObjectTypeDynamic([[maybe_unused]] GraphVisitor *v, Inst *inst, ObjectType type,
401                                        [[maybe_unused]] uint32_t typeId)
402     {
403         // IrToc use LoadObject and StoreObject with ObjectType::MEM_OBJECT for dynamic
404         // We can inline intrinsics with the instruction under the  option --compiler-inline-full-intrinsics=true
405         if (!g_options.IsCompilerInlineFullIntrinsics()) {
406             CHECKER_DO_IF_NOT_VISITOR(
407                 v, type != ObjectType::MEM_OBJECT && type != ObjectType::MEM_STATIC,
408                 (std::cerr << "The object type isn't supported for dynamic\n", inst->Dump(&std::cerr)));
409         }
410         if (type == ObjectType::MEM_DYN_CLASS) {
411             CHECKER_DO_IF_NOT_VISITOR(
412                 v, typeId == TypeIdMixin::MEM_DYN_CLASS_ID,
413                 (std::cerr << "The object type_id for MEM_DYN_CLASS is incorrect\n", inst->Dump(&std::cerr)));
414         } else if (type == ObjectType::MEM_DYN_PROPS) {
415             CHECKER_DO_IF_NOT_VISITOR(
416                 v, typeId == TypeIdMixin::MEM_DYN_PROPS_ID,
417                 (std::cerr << "The object type_id for MEM_DYN_PROPS is incorrect\n", inst->Dump(&std::cerr)));
418         } else if (type == ObjectType::MEM_DYN_PROTO_HOLDER) {
419             CHECKER_DO_IF_NOT_VISITOR(
420                 v, typeId == TypeIdMixin::MEM_DYN_PROTO_HOLDER_ID,
421                 (std::cerr << "The object type_id for MEM_DYN_PROTO_HOLDER is incorrect\n", inst->Dump(&std::cerr)));
422         } else if (type == ObjectType::MEM_DYN_PROTO_CELL) {
423             [[maybe_unused]] Inst *objInst = inst->GetInput(0).GetInst();
424             CHECKER_DO_IF_NOT_VISITOR(
425                 v, typeId == TypeIdMixin::MEM_DYN_PROTO_CELL_ID,
426                 (std::cerr << "The object type_id for MEM_DYN_PROTO_CELL is incorrect\n", inst->Dump(&std::cerr)));
427         } else if (type == ObjectType::MEM_DYN_CHANGE_FIELD) {
428             [[maybe_unused]] Inst *objInst = inst->GetInput(0).GetInst();
429             CHECKER_DO_IF_NOT_VISITOR(
430                 v, typeId == TypeIdMixin::MEM_DYN_CHANGE_FIELD_ID,
431                 (std::cerr << "The object type_id for MEM_DYN_CHANGE_FIELD is incorrect\n", inst->Dump(&std::cerr)));
432         } else if (type == ObjectType::MEM_DYN_GLOBAL) {
433             CHECKER_DO_IF_NOT_VISITOR(
434                 v, typeId == TypeIdMixin::MEM_DYN_GLOBAL_ID,
435                 (std::cerr << "The object type_id for MEM_DYN_GLOBAL is incorrect\n", inst->Dump(&std::cerr)));
436         } else if (type == ObjectType::MEM_DYN_HCLASS) {
437             CHECKER_DO_IF_NOT_VISITOR(
438                 v, typeId == TypeIdMixin::MEM_DYN_HCLASS_ID,
439                 (std::cerr << "The object type_id for MEM_DYN_HCLASS is incorrect\n", inst->Dump(&std::cerr)));
440         } else {
441             CHECKER_DO_IF_NOT_VISITOR(
442                 v,
443                 typeId != TypeIdMixin::MEM_DYN_GLOBAL_ID && typeId != TypeIdMixin::MEM_DYN_CLASS_ID &&
444                     typeId != TypeIdMixin::MEM_DYN_PROPS_ID,
445                 (std::cerr << "The object type_id for MEM_DYN_GLOBAL is incorrect\n", inst->Dump(&std::cerr)));
446         }
447     }
448 
CheckObjectType(GraphVisitor * v,Inst * inst,ObjectType type,uint32_t typeId)449     static void CheckObjectType([[maybe_unused]] GraphVisitor *v, Inst *inst, ObjectType type,
450                                 [[maybe_unused]] uint32_t typeId)
451     {
452         auto graph = inst->GetBasicBlock()->GetGraph();
453         if (!graph->SupportManagedCode()) {
454             return;
455         }
456         if (graph->IsDynamicMethod()) {
457             CheckObjectTypeDynamic(v, inst, type, typeId);
458         } else {
459             CHECKER_DO_IF_NOT_VISITOR(
460                 v, type == ObjectType::MEM_OBJECT || type == ObjectType::MEM_STATIC,
461                 (std::cerr << "The object type isn't supported for static\n", inst->Dump(&std::cerr)));
462         }
463     }
464 
CheckContrlFlowInst(GraphVisitor * v,Inst * inst)465     static void CheckContrlFlowInst([[maybe_unused]] GraphVisitor *v, Inst *inst)
466     {
467         auto block = inst->GetBasicBlock();
468         [[maybe_unused]] auto lastInst = *block->AllInstsSafeReverse().begin();
469         CHECKER_DO_IF_NOT_VISITOR(
470             v, (lastInst == inst),
471             (std::cerr << "Control flow instruction must be last instruction in block\n CF instruction:\n",
472              inst->Dump(&std::cerr), std::cerr << "\n last instruction:\n", lastInst->Dump(&std::cerr)));
473         CHECKER_DO_IF_NOT_VISITOR(v, inst->GetUsers().Empty(),
474                                   (std::cerr << "Control flow instruction has users\n", inst->Dump(&std::cerr)));
475     }
476 
CheckThrows(GraphVisitor * v,Inst * inst,std::initializer_list<Opcode> opcs)477     static void CheckThrows([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst,
478                             [[maybe_unused]] std::initializer_list<Opcode> opcs)
479     {
480 #ifdef COMPILER_DEBUG_CHECKS
481         const auto &inputs = inst->GetInputs();
482         auto ssInput = [&inst](const auto &input) {
483             return input.GetInst()->GetOpcode() == Opcode::SaveState ||
484                    (input.GetInst()->GetOpcode() == Opcode::SaveStateDeoptimize && inst->CanDeoptimize());
485         };
486         bool hasSaveState = std::find_if(inputs.begin(), inputs.end(), ssInput) != inputs.end();
487 
488         bool hasOpc = true;
489         for (auto &node : inst->GetUsers()) {
490             auto opc = node.GetInst()->GetOpcode();
491             hasOpc &= std::find(opcs.begin(), opcs.end(), opc) != opcs.end();
492         }
493 
494         CHECKER_DO_IF_NOT_VISITOR(
495             v, !inst->HasUsers() || hasOpc,
496             (inst->Dump(&std::cerr),
497              std::cerr << "Throw inst doesn't have any users from the list:" << opcs << std::endl));
498         CHECKER_DO_IF_NOT_VISITOR(v, hasSaveState,
499                                   (inst->Dump(&std::cerr), std::cerr << "Throw inst without SaveState" << std::endl));
500 #endif
501     }
502 
CheckSaveStateInput(GraphVisitor * v,Inst * inst)503     static void CheckSaveStateInput([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst)
504     {
505         CHECKER_DO_IF_NOT_VISITOR(
506             v,
507             inst->GetInputsCount() != 0 &&
508                 inst->GetInput(inst->GetInputsCount() - 1).GetInst()->GetOpcode() == Opcode::SaveState,
509             (std::cerr << "Instruction must have SaveState as last input:\n", inst->Dump(&std::cerr)));
510     }
511 
GetPassName()512     std::string GetPassName() const
513     {
514         return passName_;
515     }
516 
IncrementNullPtrInstCounterAndGet()517     int IncrementNullPtrInstCounterAndGet()
518     {
519         return ++nullPtrInstCounter_;
520     }
521 
IncrementLoadUndefinedInstCounterAndGet()522     int IncrementLoadUndefinedInstCounterAndGet()
523     {
524         return ++loadUndefinedInstCounter_;
525     }
526 
527     void PrintFailedMethodAndPass() const;
528     static void PrintFailedMethodAndPassVisitor(GraphVisitor *v);
529 
530 private:
531     Graph *graph_;
532     ArenaAllocator allocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
533     ArenaAllocator localAllocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
534     int nullPtrInstCounter_ = 0;
535     int loadUndefinedInstCounter_ = 0;
536     std::string passName_;
537     bool success_ {true};
538 };
539 }  // namespace ark::compiler
540 
541 #undef CHECKER_DO_IF_NOT_VISITOR
542 
543 #endif  // COMPILER_OPTIMIZER_IR_GRAPH_CHECKER_H
544