// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_COMPILER_BACKEND_CONSTANT_PROPAGATOR_H_ #define RUNTIME_VM_COMPILER_BACKEND_CONSTANT_PROPAGATOR_H_ #if defined(DART_PRECOMPILED_RUNTIME) #error "AOT runtime should not use compiler sources (including header files)" #endif // defined(DART_PRECOMPILED_RUNTIME) #include "vm/compiler/backend/flow_graph.h" #include "vm/compiler/backend/il.h" namespace dart { // Sparse conditional constant propagation and unreachable code elimination. // Assumes that use lists are computed and preserves them. class ConstantPropagator : public FlowGraphVisitor { public: ConstantPropagator(FlowGraph* graph, const GrowableArray& ignored); static void Optimize(FlowGraph* graph); // (1) Visit branches to optimize away unreachable blocks discovered by range // analysis. // (2) Eliminate branches that have the same true- and false-target: For // example, this occurs after expressions like // // if (a == null || b == null) { // ... // } // // where b is known to be null. static void OptimizeBranches(FlowGraph* graph); // Used to initialize the abstract value of definitions. static ObjectPtr Unknown() { return Object::unknown_constant().ptr(); } private: void Analyze(); void Transform(); // Tries to replace uses of [defn] with a constant, returns true if // successfull. The [value] is used as a temporary handle. bool TransformDefinition(Definition* defn); void EliminateRedundantBranches(); void SetReachable(BlockEntryInstr* block); bool SetValue(Definition* definition, const Object& value); // Phi might be viewed as redundant based on current reachability of // predecessor blocks (i.e. the same definition is flowing from all // reachable predecessors). We can use this information to constant // fold phi(x) == x and phi(x) != x comparisons. Definition* UnwrapPhi(Definition* defn); void MarkUnwrappedPhi(Definition* defn); // Assign the join (least upper bound) of a pair of abstract values to the // first one. void Join(Object* left, const Object& right); bool IsUnknown(const Object& value) { return value.ptr() == unknown_.ptr(); } bool IsNonConstant(const Object& value) { return value.ptr() == non_constant_.ptr(); } bool IsConstant(const Object& value) { return !IsNonConstant(value) && !IsUnknown(value); } void VisitBinaryIntegerOp(BinaryIntegerOpInstr* binary_op); void VisitUnaryIntegerOp(UnaryIntegerOpInstr* unary_op); virtual void VisitBlocks() { UNREACHABLE(); } #define DECLARE_VISIT(type, attrs) virtual void Visit##type(type##Instr* instr); FOR_EACH_INSTRUCTION(DECLARE_VISIT) #undef DECLARE_VISIT // Structure tracking visit counts for phis. Used to detect infinite loops. struct PhiInfo { PhiInstr* phi; intptr_t visit_count; }; // Returns PhiInfo associated with the given phi. Note that this // pointer can be invalidated by subsequent call to GetPhiInfo and // thus should not be stored anywhere. PhiInfo* GetPhiInfo(PhiInstr* phi); FlowGraph* graph_; // Sentinels for unknown constant and non-constant values. const Object& unknown_; const Object& non_constant_; // Temporary handle used in [TransformDefinition]. Object& constant_value_; // Analysis results. For each block, a reachability bit. Indexed by // preorder number. BitVector* reachable_; // Bitvector of phis that were "unwrapped" into one of their inputs // when visiting one of their uses. These uses of these phis // should be revisited if reachability of the predecessor blocks // changes even if that does not change constant value of the phi. BitVector* unwrapped_phis_; // List of visited phis indexed by their id (stored as pass specific id on // a phi instruction). GrowableArray phis_; // Worklists of blocks and definitions. GrowableArray block_worklist_; DefinitionWorklist definition_worklist_; }; } // namespace dart #endif // RUNTIME_VM_COMPILER_BACKEND_CONSTANT_PROPAGATOR_H_