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