1 /**
2  * Copyright (c) 2021-2022 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 <iostream>
20 #include "compiler_options.h"
21 #include "graph.h"
22 #include "graph_visitor.h"
23 #include "optimizer/analysis/dominators_tree.h"
24 #include "optimizer/analysis/rpo.h"
25 #include "optimizer/analysis/loop_analyzer.h"
26 #include "optimizer/optimizations/cleanup.h"
27 
28 namespace panda::compiler {
operator <<(std::ostream &os, const std::initializer_list<Opcode> &opcs)29 inline std::ostream &operator<<(std::ostream &os, const std::initializer_list<Opcode> &opcs)
30 {
31     os << "[ ";
32     for (auto opc : opcs) {
33         os << GetOpcodeString(opc) << " ";
34     }
35     os << "]";
36     return os;
37 }
38 
39 class GraphChecker : public GraphVisitor {
40 public:
41     explicit GraphChecker(Graph *graph);
42     ~GraphChecker() override
43     {
44         GetGraph()->GetPassManager()->SetCheckMode(false);
45     }
46 
47     NO_COPY_SEMANTIC(GraphChecker);
48     NO_MOVE_SEMANTIC(GraphChecker);
49 
50     void Check();
51 
52 private:
53     void PreCloneChecks(Graph *graph);
54     void UserInputCheck(Graph *graph);
55     void CheckBlock(BasicBlock *block);
56     void CheckDomTree();
57     void CheckLoopAnalysis();
58     void CheckStartBlock();
59     void CheckEndBlock();
60     void CheckControlFlow(BasicBlock *block);
61     void CheckDataFlow(BasicBlock *block);
62     void CheckPhiInputs(Inst *phi_inst);
63     void CheckInstsRegisters(BasicBlock *block);
64     void CheckPhisRegisters(BasicBlock *block);
65     void CheckNoLowLevel(BasicBlock *block);
66     void CheckLoops();
67     void CheckGraph();
68     bool HasOuterInfiniteLoop();
69     bool CheckInstHasInput(Inst *inst, Inst *input);
70     bool CheckInstHasUser(Inst *inst, Inst *user);
71     void CheckCallReturnInlined();
72     void CheckSpillFillHolder(Inst *inst);
73     bool CheckInstRegUsageSaved(const Inst *inst, Register reg) const;
74     void MarkBlocksInLoop(Loop *loop, Marker mrk);
75     bool CheckBlockHasPredecessor(BasicBlock *block, BasicBlock *predecessor);
76     bool CheckBlockHasSuccessor(BasicBlock *block, BasicBlock *successor);
77     void CheckLoopHasSafePoint(Loop *loop);
78     void CheckBlockEdges(const BasicBlock &block);
79     void CheckTryBeginBlock(const BasicBlock &block);
80     void CheckJump(const BasicBlock &block);
81     bool IsTryCatchDomination(const BasicBlock *input_block, const BasicBlock *user_block) const;
82 #ifndef NDEBUG
83     bool NeedCheckSaveState();
84 #endif  // !NDEBUG
85     void CheckSaveStateInputs();
86     void CheckObjectRec(const Inst *object, const Inst *user, const BasicBlock *block, Inst *start_from,
87                         Marker visited) const;
88     void FindObjectInSaveState(const Inst *object, Inst *ss) const;
89     void CheckSaveStatesWithRuntimeCallUsers();
90     void CheckSaveStateOsrRec(const Inst *inst, const Inst *user, BasicBlock *block, Marker visited);
91 
GetGraph() const92     Graph *GetGraph() const
93     {
94         return graph_;
95     }
96 
GetAllocator()97     ArenaAllocator *GetAllocator()
98     {
99         return &allocator_;
100     }
101 
GetLocalAllocator()102     ArenaAllocator *GetLocalAllocator()
103     {
104         return &local_allocator_;
105     }
106 
107     const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override
108     {
109         return GetGraph()->GetBlocksRPO();
110     }
111 
112     /*
113      * Visitors to check instructions types
114      */
115     static void VisitReturn([[maybe_unused]] GraphVisitor *v, Inst *inst);
116     static void VisitIf([[maybe_unused]] GraphVisitor *v, Inst *inst);
117     static void VisitIfImm([[maybe_unused]] GraphVisitor *v, Inst *inst);
118 #include "visitor.inc"
119 
CheckCommonTypes(Inst *inst1, Inst *inst2)120     static bool CheckCommonTypes(Inst *inst1, Inst *inst2)
121     {
122         if (inst1->GetBasicBlock()->GetGraph()->IsDynamicMethod() &&
123             (inst1->GetType() == DataType::ANY || inst2->GetType() == DataType::ANY)) {
124             return true;
125         }
126         DataType::Type type1 = inst1->GetType();
127         DataType::Type type2 = inst2->GetType();
128         return DataType::GetCommonType(type1) == DataType::GetCommonType(type2);
129     }
130 private:
131     Graph *graph_;
132     ArenaAllocator allocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
133     ArenaAllocator local_allocator_ {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
134     int null_ptr_inst_counter_ = 0;
135 };
136 }  // namespace panda::compiler
137 
138 #endif  // COMPILER_OPTIMIZER_IR_GRAPH_CHECKER_H
139