xref: /aosp_15_r20/art/compiler/optimizing/graph_checker.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <ostream>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "base/arena_bit_vector.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
26*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker class CodeGenerator;
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker // A control-flow graph visitor performing various checks.
33*795d594fSAndroid Build Coastguard Worker class GraphChecker final : public HGraphDelegateVisitor {
34*795d594fSAndroid Build Coastguard Worker  public:
35*795d594fSAndroid Build Coastguard Worker   explicit GraphChecker(HGraph* graph,
36*795d594fSAndroid Build Coastguard Worker                         CodeGenerator* codegen = nullptr,
37*795d594fSAndroid Build Coastguard Worker                         const char* dump_prefix = "art::GraphChecker: ")
HGraphDelegateVisitor(graph)38*795d594fSAndroid Build Coastguard Worker       : HGraphDelegateVisitor(graph),
39*795d594fSAndroid Build Coastguard Worker         errors_(graph->GetAllocator()->Adapter(kArenaAllocGraphChecker)),
40*795d594fSAndroid Build Coastguard Worker         dump_prefix_(dump_prefix),
41*795d594fSAndroid Build Coastguard Worker         allocator_(graph->GetArenaStack()),
42*795d594fSAndroid Build Coastguard Worker         seen_ids_(&allocator_, graph->GetCurrentInstructionId(), false, kArenaAllocGraphChecker),
43*795d594fSAndroid Build Coastguard Worker         uses_per_instruction_(allocator_.Adapter(kArenaAllocGraphChecker)),
44*795d594fSAndroid Build Coastguard Worker         instructions_per_block_(allocator_.Adapter(kArenaAllocGraphChecker)),
45*795d594fSAndroid Build Coastguard Worker         phis_per_block_(allocator_.Adapter(kArenaAllocGraphChecker)),
46*795d594fSAndroid Build Coastguard Worker         codegen_(codegen) {}
47*795d594fSAndroid Build Coastguard Worker 
48*795d594fSAndroid Build Coastguard Worker   // Check the whole graph. The pass_change parameter indicates whether changes
49*795d594fSAndroid Build Coastguard Worker   // may have occurred during the just executed pass. The default value is
50*795d594fSAndroid Build Coastguard Worker   // conservatively "true" (something may have changed). The last_size parameter
51*795d594fSAndroid Build Coastguard Worker   // and return value pass along the observed graph sizes.
52*795d594fSAndroid Build Coastguard Worker   size_t Run(bool pass_change = true, size_t last_size = 0);
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker   void VisitBasicBlock(HBasicBlock* block) override;
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker   void VisitInstruction(HInstruction* instruction) override;
57*795d594fSAndroid Build Coastguard Worker   void VisitPhi(HPhi* phi) override;
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker   void VisitArraySet(HArraySet* instruction) override;
60*795d594fSAndroid Build Coastguard Worker   void VisitInstanceFieldSet(HInstanceFieldSet* instruction) override;
61*795d594fSAndroid Build Coastguard Worker   void VisitStaticFieldSet(HStaticFieldSet* instruction) override;
62*795d594fSAndroid Build Coastguard Worker   void VisitBinaryOperation(HBinaryOperation* op) override;
63*795d594fSAndroid Build Coastguard Worker   void VisitBooleanNot(HBooleanNot* instruction) override;
64*795d594fSAndroid Build Coastguard Worker   void VisitBoundType(HBoundType* instruction) override;
65*795d594fSAndroid Build Coastguard Worker   void VisitBoundsCheck(HBoundsCheck* check) override;
66*795d594fSAndroid Build Coastguard Worker   void VisitCheckCast(HCheckCast* check) override;
67*795d594fSAndroid Build Coastguard Worker   void VisitCondition(HCondition* op) override;
68*795d594fSAndroid Build Coastguard Worker   void VisitConstant(HConstant* instruction) override;
69*795d594fSAndroid Build Coastguard Worker   void VisitDeoptimize(HDeoptimize* instruction) override;
70*795d594fSAndroid Build Coastguard Worker   void VisitIf(HIf* instruction) override;
71*795d594fSAndroid Build Coastguard Worker   void VisitInstanceOf(HInstanceOf* check) override;
72*795d594fSAndroid Build Coastguard Worker   void VisitInvoke(HInvoke* invoke) override;
73*795d594fSAndroid Build Coastguard Worker   void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) override;
74*795d594fSAndroid Build Coastguard Worker   void VisitLoadClass(HLoadClass* load) override;
75*795d594fSAndroid Build Coastguard Worker   void VisitLoadException(HLoadException* load) override;
76*795d594fSAndroid Build Coastguard Worker   void VisitMonitorOperation(HMonitorOperation* monitor_operation) override;
77*795d594fSAndroid Build Coastguard Worker   void VisitNeg(HNeg* instruction) override;
78*795d594fSAndroid Build Coastguard Worker   void VisitPackedSwitch(HPackedSwitch* instruction) override;
79*795d594fSAndroid Build Coastguard Worker   void VisitReturn(HReturn* ret) override;
80*795d594fSAndroid Build Coastguard Worker   void VisitReturnVoid(HReturnVoid* ret) override;
81*795d594fSAndroid Build Coastguard Worker   void VisitSelect(HSelect* instruction) override;
82*795d594fSAndroid Build Coastguard Worker   void VisitTryBoundary(HTryBoundary* try_boundary) override;
83*795d594fSAndroid Build Coastguard Worker   void VisitTypeConversion(HTypeConversion* instruction) override;
84*795d594fSAndroid Build Coastguard Worker 
85*795d594fSAndroid Build Coastguard Worker   void VisitVecOperation(HVecOperation* instruction) override;
86*795d594fSAndroid Build Coastguard Worker 
87*795d594fSAndroid Build Coastguard Worker   void CheckTypeCheckBitstringInput(HTypeCheckInstruction* check,
88*795d594fSAndroid Build Coastguard Worker                                     size_t input_pos,
89*795d594fSAndroid Build Coastguard Worker                                     bool check_value,
90*795d594fSAndroid Build Coastguard Worker                                     uint32_t expected_value,
91*795d594fSAndroid Build Coastguard Worker                                     const char* name);
92*795d594fSAndroid Build Coastguard Worker   void HandleTypeCheckInstruction(HTypeCheckInstruction* instruction);
93*795d594fSAndroid Build Coastguard Worker   void HandleLoop(HBasicBlock* loop_header);
94*795d594fSAndroid Build Coastguard Worker   void HandleBooleanInput(HInstruction* instruction, size_t input_index);
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker   template <typename GetWriteBarrierKind>
97*795d594fSAndroid Build Coastguard Worker   void CheckWriteBarrier(HInstruction* instruction, GetWriteBarrierKind&& get_write_barrier_kind);
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker   // Was the last visit of the graph valid?
IsValid()100*795d594fSAndroid Build Coastguard Worker   bool IsValid() const {
101*795d594fSAndroid Build Coastguard Worker     return errors_.empty();
102*795d594fSAndroid Build Coastguard Worker   }
103*795d594fSAndroid Build Coastguard Worker 
104*795d594fSAndroid Build Coastguard Worker   // Get the list of detected errors.
GetErrors()105*795d594fSAndroid Build Coastguard Worker   const ArenaVector<std::string>& GetErrors() const {
106*795d594fSAndroid Build Coastguard Worker     return errors_;
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker   // Print detected errors on output stream `os`.
Dump(std::ostream & os)110*795d594fSAndroid Build Coastguard Worker   void Dump(std::ostream& os) const {
111*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0, e = errors_.size(); i < e; ++i) {
112*795d594fSAndroid Build Coastguard Worker       os << dump_prefix_ << errors_[i] << std::endl;
113*795d594fSAndroid Build Coastguard Worker     }
114*795d594fSAndroid Build Coastguard Worker   }
115*795d594fSAndroid Build Coastguard Worker 
116*795d594fSAndroid Build Coastguard Worker  private:
117*795d594fSAndroid Build Coastguard Worker   // Report a new error.
AddError(const std::string & error)118*795d594fSAndroid Build Coastguard Worker   void AddError(const std::string& error) {
119*795d594fSAndroid Build Coastguard Worker     errors_.push_back(error);
120*795d594fSAndroid Build Coastguard Worker   }
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker   // The block currently visited.
123*795d594fSAndroid Build Coastguard Worker   HBasicBlock* current_block_ = nullptr;
124*795d594fSAndroid Build Coastguard Worker   // Errors encountered while checking the graph.
125*795d594fSAndroid Build Coastguard Worker   ArenaVector<std::string> errors_;
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker   void VisitReversePostOrder();
128*795d594fSAndroid Build Coastguard Worker 
129*795d594fSAndroid Build Coastguard Worker   // Checks that the graph's flags are set correctly.
130*795d594fSAndroid Build Coastguard Worker   void CheckGraphFlags();
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker   // Checks if `instruction` is in its block's instruction/phi list. To do so, it searches
133*795d594fSAndroid Build Coastguard Worker   // instructions_per_block_/phis_per_block_ which are set versions of that. If the set to
134*795d594fSAndroid Build Coastguard Worker   // check hasn't been populated yet, it does so now.
135*795d594fSAndroid Build Coastguard Worker   bool ContainedInItsBlockList(HInstruction* instruction);
136*795d594fSAndroid Build Coastguard Worker 
137*795d594fSAndroid Build Coastguard Worker   // String displayed before dumped errors.
138*795d594fSAndroid Build Coastguard Worker   const char* const dump_prefix_;
139*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator_;
140*795d594fSAndroid Build Coastguard Worker   ArenaBitVector seen_ids_;
141*795d594fSAndroid Build Coastguard Worker 
142*795d594fSAndroid Build Coastguard Worker   // As part of VisitInstruction, we verify that the instruction's input_record is present in the
143*795d594fSAndroid Build Coastguard Worker   // corresponding input's GetUses. If an instruction is used in many places (e.g. 200K+ uses), the
144*795d594fSAndroid Build Coastguard Worker   // linear search through GetUses is too slow. We can use bookkeeping to search in a set, instead
145*795d594fSAndroid Build Coastguard Worker   // of a list.
146*795d594fSAndroid Build Coastguard Worker   ScopedArenaSafeMap<int, ScopedArenaSet<const art::HUseListNode<art::HInstruction*>*>>
147*795d594fSAndroid Build Coastguard Worker       uses_per_instruction_;
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker   // Extra bookkeeping to increase GraphChecker's speed while asking if an instruction is contained
150*795d594fSAndroid Build Coastguard Worker   // in a list of instructions/phis.
151*795d594fSAndroid Build Coastguard Worker   ScopedArenaSafeMap<HBasicBlock*, ScopedArenaHashSet<HInstruction*>> instructions_per_block_;
152*795d594fSAndroid Build Coastguard Worker   ScopedArenaSafeMap<HBasicBlock*, ScopedArenaHashSet<HInstruction*>> phis_per_block_;
153*795d594fSAndroid Build Coastguard Worker 
154*795d594fSAndroid Build Coastguard Worker   // Used to access target information.
155*795d594fSAndroid Build Coastguard Worker   CodeGenerator* codegen_;
156*795d594fSAndroid Build Coastguard Worker 
157*795d594fSAndroid Build Coastguard Worker   struct FlagInfo {
158*795d594fSAndroid Build Coastguard Worker     bool seen_try_boundary = false;
159*795d594fSAndroid Build Coastguard Worker     bool seen_monitor_operation = false;
160*795d594fSAndroid Build Coastguard Worker     bool seen_loop = false;
161*795d594fSAndroid Build Coastguard Worker     bool seen_irreducible_loop = false;
162*795d594fSAndroid Build Coastguard Worker     bool seen_SIMD = false;
163*795d594fSAndroid Build Coastguard Worker     bool seen_bounds_checks = false;
164*795d594fSAndroid Build Coastguard Worker     bool seen_always_throwing_invokes = false;
165*795d594fSAndroid Build Coastguard Worker   };
166*795d594fSAndroid Build Coastguard Worker   FlagInfo flag_info_;
167*795d594fSAndroid Build Coastguard Worker 
168*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(GraphChecker);
169*795d594fSAndroid Build Coastguard Worker };
170*795d594fSAndroid Build Coastguard Worker 
171*795d594fSAndroid Build Coastguard Worker }  // namespace art
172*795d594fSAndroid Build Coastguard Worker 
173*795d594fSAndroid Build Coastguard Worker #endif  // ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_
174