|  | // 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<BlockEntryInstr*>& 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 InsertRedefinitionsAfterEqualityComparisons(); | 
|  | void Analyze(); | 
|  | void Transform(); | 
|  | // Tries to replace uses of [defn] with a constant, returns true if | 
|  | // successful. 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<PhiInfo> phis_; | 
|  |  | 
|  | // Worklists of blocks and definitions. | 
|  | GrowableArray<BlockEntryInstr*> block_worklist_; | 
|  | DefinitionWorklist definition_worklist_; | 
|  | }; | 
|  |  | 
|  | }  // namespace dart | 
|  |  | 
|  | #endif  // RUNTIME_VM_COMPILER_BACKEND_CONSTANT_PROPAGATOR_H_ |