• 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_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 VisitLoadUniqueObject([[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     static PANDA_PUBLIC_API void VisitCallNative(GraphVisitor *v, Inst *inst);
272 
273 #include "visitor.inc"
274 
CheckCommonTypes(Inst * inst1,Inst * inst2)275     static bool CheckCommonTypes(Inst *inst1, Inst *inst2)
276     {
277         if (inst1->GetBasicBlock()->GetGraph()->IsDynamicMethod() &&
278             (inst1->GetType() == DataType::ANY || inst2->GetType() == DataType::ANY)) {
279             return true;
280         }
281         DataType::Type type1 = inst1->GetType();
282         DataType::Type type2 = inst2->GetType();
283         return DataType::GetCommonType(type1) == DataType::GetCommonType(type2);
284     }
285 
286     static void CheckBinaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst, bool isInt = false)
287     {
288         [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst();
289         [[maybe_unused]] auto op2 = inst->GetInputs()[1].GetInst();
290 
291         if (inst->GetOpcode() == Opcode::Div || inst->GetOpcode() == Opcode::Mod) {
292             if (op2->GetOpcode() == Opcode::ZeroCheck) {
293                 op2 = op2->GetInput(0).GetInst();
294             }
295         }
296 
297         if (isInt) {
298             CHECKER_DO_IF_NOT_VISITOR(
299                 v, DataType::GetCommonType(inst->GetType()) == DataType::INT64,
300                 (std::cerr << "Binary instruction type is not a integer", inst->Dump(&std::cerr)));
301         }
302 
303         CHECKER_DO_IF_NOT_VISITOR(
304             v, DataType::IsTypeNumeric(op1->GetType()),
305             (std::cerr << "Binary instruction 1st operand type is not a numeric", inst->Dump(&std::cerr)));
306         CHECKER_DO_IF_NOT_VISITOR(
307             v, DataType::IsTypeNumeric(op2->GetType()),
308             (std::cerr << "Binary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr)));
309         CHECKER_DO_IF_NOT_VISITOR(v, DataType::IsTypeNumeric(inst->GetType()),
310                                   (std::cerr << "Binary instruction type is not a numeric", inst->Dump(&std::cerr)));
311 
312         CHECKER_DO_IF_NOT_VISITOR(v, CheckCommonTypes(op1, op2),
313                                   (std::cerr << "Types of binary instruction operands are not compatible\n",
314                                    op1->Dump(&std::cerr), op2->Dump(&std::cerr), inst->Dump(&std::cerr)));
315         CHECKER_DO_IF_NOT_VISITOR(
316             v, CheckCommonTypes(inst, op1),
317             (std::cerr << "Types of binary instruction result and its operands are not compatible\n",
318              inst->Dump(&std::cerr)));
319     }
320 
CheckBinaryOverflowOperation(GraphVisitor * v,IfInst * inst)321     static void CheckBinaryOverflowOperation(GraphVisitor *v, IfInst *inst)
322     {
323         // Overflow instruction are used only in dynamic methods.
324         // But ASSERT wasn't added because the instructions checks in codegen_test.cpp with default method
325         // NOTE(pishin) add an ASSERT after add assembly tests tests and remove the test from codegen_test.cpp
326         [[maybe_unused]] auto cc = inst->GetCc();
327         CHECKER_DO_IF_NOT_VISITOR(v, (cc == CC_EQ || cc == CC_NE),
328                                   (std::cerr << "overflow instruction are used only CC_EQ or CC_NE"));
329         CheckBinaryOperationTypes(v, inst, true);
330         CHECKER_DO_IF_NOT_VISITOR(v, !DataType::IsLessInt32(inst->GetType()),
331                                   (std::cerr << "overflow instruction have INT32 or INT64 types"));
332     }
333 
CheckBinaryOperationWithShiftedOperandTypes(GraphVisitor * v,Inst * inst,bool rorSupported)334     static void CheckBinaryOperationWithShiftedOperandTypes(GraphVisitor *v, Inst *inst,
335                                                             [[maybe_unused]] bool rorSupported)
336     {
337         CheckBinaryOperationTypes(v, inst, true);
338         [[maybe_unused]] auto instWShift = static_cast<BinaryShiftedRegisterOperation *>(inst);
339         CHECKER_DO_IF_NOT_VISITOR(v,
340                                   instWShift->GetShiftType() != ShiftType::INVALID_SHIFT &&
341                                       (rorSupported || instWShift->GetShiftType() != ShiftType::ROR),
342                                   (std::cerr << "Operation has invalid shift type\n", inst->Dump(&std::cerr)));
343     }
344 
CheckUnaryOperationTypes(GraphVisitor * v,Inst * inst)345     static void CheckUnaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst)
346     {
347         [[maybe_unused]] auto op = inst->GetInput(0).GetInst();
348         CHECKER_DO_IF_NOT_VISITOR(
349             v, CheckCommonTypes(inst, op),
350             (std::cerr << "Types of unary instruction result and its operand are not compatible\n",
351              inst->Dump(&std::cerr), op->Dump(&std::cerr)));
352     }
353 
354     static void CheckTernaryOperationTypes([[maybe_unused]] GraphVisitor *v, Inst *inst, bool isInt = false)
355     {
356         [[maybe_unused]] auto op1 = inst->GetInputs()[0].GetInst();
357         [[maybe_unused]] auto op2 = inst->GetInputs()[1].GetInst();
358         [[maybe_unused]] auto op3 = inst->GetInputs()[1].GetInst();
359 
360         if (isInt) {
361             CHECKER_DO_IF_NOT_VISITOR(
362                 v, DataType::GetCommonType(inst->GetType()) == DataType::INT64,
363                 (std::cerr << "Ternary instruction type is not a integer", inst->Dump(&std::cerr)));
364         }
365 
366         CHECKER_DO_IF_NOT_VISITOR(
367             v, DataType::IsTypeNumeric(op1->GetType()),
368             (std::cerr << "Ternary instruction 1st operand type is not a numeric", inst->Dump(&std::cerr)));
369         CHECKER_DO_IF_NOT_VISITOR(
370             v, DataType::IsTypeNumeric(op2->GetType()),
371             (std::cerr << "Ternary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr)));
372         CHECKER_DO_IF_NOT_VISITOR(
373             v, DataType::IsTypeNumeric(op3->GetType()),
374             (std::cerr << "Ternary instruction 2nd operand type is not a numeric", inst->Dump(&std::cerr)));
375         CHECKER_DO_IF_NOT_VISITOR(v, DataType::IsTypeNumeric(inst->GetType()),
376                                   (std::cerr << "Ternary instruction type is not a numeric", inst->Dump(&std::cerr)));
377 
378         CHECKER_DO_IF_NOT_VISITOR(v, CheckCommonTypes(op1, op2) && CheckCommonTypes(op2, op3),
379                                   (std::cerr << "Types of ternary instruction operands are not compatible\n",
380                                    op1->Dump(&std::cerr), op2->Dump(&std::cerr), op3->Dump(&std::cerr),
381                                    inst->Dump(&std::cerr)));
382         CHECKER_DO_IF_NOT_VISITOR(
383             v, CheckCommonTypes(inst, op1),
384             (std::cerr << "Types of ternary instruction result and its operands are not compatible\n",
385              inst->Dump(&std::cerr)));
386     }
387 
388     static void CheckMemoryInstruction([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst,
389                                        [[maybe_unused]] bool needBarrier = false)
390     {
391         CHECKER_DO_IF_NOT_VISITOR(v,
392                                   DataType::IsTypeNumeric(inst->GetType()) || inst->GetType() == DataType::REFERENCE ||
393                                       inst->GetType() == DataType::ANY,
394                                   (std::cerr << "Memory instruction has wrong type\n", inst->Dump(&std::cerr)));
395         if (inst->IsStore() && (inst->GetInputType(0) != DataType::POINTER) && (inst->GetType() == DataType::ANY)) {
396             CHECKER_DO_IF_NOT_VISITOR(v, needBarrier,
397                                       (std::cerr << "This store should have barrier:\n", inst->Dump(&std::cerr)));
398         }
399     }
400 
CheckObjectTypeDynamic(GraphVisitor * v,Inst * inst,ObjectType type,uint32_t typeId)401     static void CheckObjectTypeDynamic([[maybe_unused]] GraphVisitor *v, Inst *inst, ObjectType type,
402                                        [[maybe_unused]] uint32_t typeId)
403     {
404         // IrToc use LoadObject and StoreObject with ObjectType::MEM_OBJECT for dynamic
405         // We can inline intrinsics with the instruction under the  option --compiler-inline-full-intrinsics=true
406         if (!g_options.IsCompilerInlineFullIntrinsics()) {
407             CHECKER_DO_IF_NOT_VISITOR(
408                 v, type != ObjectType::MEM_OBJECT && type != ObjectType::MEM_STATIC,
409                 (std::cerr << "The object type isn't supported for dynamic\n", inst->Dump(&std::cerr)));
410         }
411         if (type == ObjectType::MEM_DYN_CLASS) {
412             CHECKER_DO_IF_NOT_VISITOR(
413                 v, typeId == TypeIdMixin::MEM_DYN_CLASS_ID,
414                 (std::cerr << "The object type_id for MEM_DYN_CLASS is incorrect\n", inst->Dump(&std::cerr)));
415         } else if (type == ObjectType::MEM_DYN_PROPS) {
416             CHECKER_DO_IF_NOT_VISITOR(
417                 v, typeId == TypeIdMixin::MEM_DYN_PROPS_ID,
418                 (std::cerr << "The object type_id for MEM_DYN_PROPS is incorrect\n", inst->Dump(&std::cerr)));
419         } else if (type == ObjectType::MEM_DYN_PROTO_HOLDER) {
420             CHECKER_DO_IF_NOT_VISITOR(
421                 v, typeId == TypeIdMixin::MEM_DYN_PROTO_HOLDER_ID,
422                 (std::cerr << "The object type_id for MEM_DYN_PROTO_HOLDER is incorrect\n", inst->Dump(&std::cerr)));
423         } else if (type == ObjectType::MEM_DYN_PROTO_CELL) {
424             [[maybe_unused]] Inst *objInst = inst->GetInput(0).GetInst();
425             CHECKER_DO_IF_NOT_VISITOR(
426                 v, typeId == TypeIdMixin::MEM_DYN_PROTO_CELL_ID,
427                 (std::cerr << "The object type_id for MEM_DYN_PROTO_CELL is incorrect\n", inst->Dump(&std::cerr)));
428         } else if (type == ObjectType::MEM_DYN_CHANGE_FIELD) {
429             [[maybe_unused]] Inst *objInst = inst->GetInput(0).GetInst();
430             CHECKER_DO_IF_NOT_VISITOR(
431                 v, typeId == TypeIdMixin::MEM_DYN_CHANGE_FIELD_ID,
432                 (std::cerr << "The object type_id for MEM_DYN_CHANGE_FIELD is incorrect\n", inst->Dump(&std::cerr)));
433         } else if (type == ObjectType::MEM_DYN_GLOBAL) {
434             CHECKER_DO_IF_NOT_VISITOR(
435                 v, typeId == TypeIdMixin::MEM_DYN_GLOBAL_ID,
436                 (std::cerr << "The object type_id for MEM_DYN_GLOBAL is incorrect\n", inst->Dump(&std::cerr)));
437         } else if (type == ObjectType::MEM_DYN_HCLASS) {
438             CHECKER_DO_IF_NOT_VISITOR(
439                 v, typeId == TypeIdMixin::MEM_DYN_HCLASS_ID,
440                 (std::cerr << "The object type_id for MEM_DYN_HCLASS is incorrect\n", inst->Dump(&std::cerr)));
441         } else {
442             CHECKER_DO_IF_NOT_VISITOR(
443                 v,
444                 typeId != TypeIdMixin::MEM_DYN_GLOBAL_ID && typeId != TypeIdMixin::MEM_DYN_CLASS_ID &&
445                     typeId != TypeIdMixin::MEM_DYN_PROPS_ID,
446                 (std::cerr << "The object type_id for MEM_DYN_GLOBAL is incorrect\n", inst->Dump(&std::cerr)));
447         }
448     }
449 
CheckObjectType(GraphVisitor * v,Inst * inst,ObjectType type,uint32_t typeId)450     static void CheckObjectType([[maybe_unused]] GraphVisitor *v, Inst *inst, ObjectType type,
451                                 [[maybe_unused]] uint32_t typeId)
452     {
453         auto graph = inst->GetBasicBlock()->GetGraph();
454         if (!graph->SupportManagedCode()) {
455             return;
456         }
457         if (graph->IsDynamicMethod()) {
458             CheckObjectTypeDynamic(v, inst, type, typeId);
459         } else {
460             CHECKER_DO_IF_NOT_VISITOR(
461                 v, type == ObjectType::MEM_OBJECT || type == ObjectType::MEM_STATIC,
462                 (std::cerr << "The object type isn't supported for static\n", inst->Dump(&std::cerr)));
463         }
464     }
465 
CheckContrlFlowInst(GraphVisitor * v,Inst * inst)466     static void CheckContrlFlowInst([[maybe_unused]] GraphVisitor *v, Inst *inst)
467     {
468         auto block = inst->GetBasicBlock();
469         [[maybe_unused]] auto lastInst = *block->AllInstsSafeReverse().begin();
470         CHECKER_DO_IF_NOT_VISITOR(
471             v, (lastInst == inst),
472             (std::cerr << "Control flow instruction must be last instruction in block\n CF instruction:\n",
473              inst->Dump(&std::cerr), std::cerr << "\n last instruction:\n", lastInst->Dump(&std::cerr)));
474         CHECKER_DO_IF_NOT_VISITOR(v, inst->GetUsers().Empty(),
475                                   (std::cerr << "Control flow instruction has users\n", inst->Dump(&std::cerr)));
476     }
477 
CheckThrows(GraphVisitor * v,Inst * inst,std::initializer_list<Opcode> opcs)478     static void CheckThrows([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst,
479                             [[maybe_unused]] std::initializer_list<Opcode> opcs)
480     {
481 #ifdef COMPILER_DEBUG_CHECKS
482         const auto &inputs = inst->GetInputs();
483         auto ssInput = [&inst](const auto &input) {
484             return input.GetInst()->GetOpcode() == Opcode::SaveState ||
485                    (input.GetInst()->GetOpcode() == Opcode::SaveStateDeoptimize && inst->CanDeoptimize());
486         };
487         bool hasSaveState = std::find_if(inputs.begin(), inputs.end(), ssInput) != inputs.end();
488 
489         bool hasOpc = true;
490         for (auto &node : inst->GetUsers()) {
491             auto opc = node.GetInst()->GetOpcode();
492             hasOpc &= std::find(opcs.begin(), opcs.end(), opc) != opcs.end();
493         }
494 
495         CHECKER_DO_IF_NOT_VISITOR(
496             v, !inst->HasUsers() || hasOpc,
497             (inst->Dump(&std::cerr),
498              std::cerr << "Throw inst doesn't have any users from the list:" << opcs << std::endl));
499         CHECKER_DO_IF_NOT_VISITOR(v, hasSaveState,
500                                   (inst->Dump(&std::cerr), std::cerr << "Throw inst without SaveState" << std::endl));
501 #endif
502     }
503 
CheckSaveStateInput(GraphVisitor * v,Inst * inst)504     static void CheckSaveStateInput([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst)
505     {
506         CHECKER_DO_IF_NOT_VISITOR(
507             v,
508             inst->GetInputsCount() != 0 &&
509                 inst->GetInput(inst->GetInputsCount() - 1).GetInst()->GetOpcode() == Opcode::SaveState,
510             (std::cerr << "Instruction must have SaveState as last input:\n", inst->Dump(&std::cerr)));
511     }
512 
GetPassName()513     std::string GetPassName() const
514     {
515         return passName_;
516     }
517 
IncrementNullPtrInstCounterAndGet()518     int IncrementNullPtrInstCounterAndGet()
519     {
520         return ++nullPtrInstCounter_;
521     }
522 
IncrementLoadUniqueObjectInstCounterAndGet()523     int IncrementLoadUniqueObjectInstCounterAndGet()
524     {
525         return ++loadUniqueObjectInstCounter_;
526     }
527 
528     void PrintFailedMethodAndPass() const;
529     static void PrintFailedMethodAndPassVisitor(GraphVisitor *v);
530 
531 private:
532     Graph *graph_;
533     ArenaAllocator allocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
534     ArenaAllocator localAllocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
535     int nullPtrInstCounter_ = 0;
536     int loadUniqueObjectInstCounter_ = 0;
537     std::string passName_;
538     bool success_ {true};
539 };
540 }  // namespace ark::compiler
541 
542 #undef CHECKER_DO_IF_NOT_VISITOR
543 
544 #endif  // COMPILER_OPTIMIZER_IR_GRAPH_CHECKER_H
545