40e18905f2
Closes https://github.com/dart-lang/sdk/pull/49478 TEST=Manual GitOrigin-RevId: f4c9c6869dfe73639295e86574a021523b3d374d Change-Id: I134a97caed4eec59d70e9cbca16b7e9a472cf2c1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/251902 Reviewed-by: Michael Thomsen <mit@google.com> Commit-Queue: Alexander Thomas <athom@google.com> Reviewed-by: Aske Simon Christensen <askesc@google.com> Reviewed-by: Kevin Chisholm <kevinjchisholm@google.com> Reviewed-by: Alexander Thomas <athom@google.com>
122 lines
4.2 KiB
C++
122 lines
4.2 KiB
C++
// 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 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_
|