737888b223
This eases the porting of Irregexp. TEST=ci Bug: https://github.com/dart-lang/sdk/issues/56573 Change-Id: If31a0585ced3eabaf2dac6af04f83d387a8eab5d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/478080 Reviewed-by: Alexander Aprelev <aam@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
355 lines
10 KiB
C++
355 lines
10 KiB
C++
// Copyright (c) 2018, 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_LOOPS_H_
|
|
#define RUNTIME_VM_COMPILER_BACKEND_LOOPS_H_
|
|
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
#error "AOT runtime should not use compiler sources (including header files)"
|
|
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
#include <utility>
|
|
|
|
#include "vm/allocation.h"
|
|
#include "vm/compiler/backend/il.h"
|
|
|
|
namespace dart {
|
|
|
|
// Information on an induction variable in a particular loop.
|
|
//
|
|
// Invariant:
|
|
// offset + mult * def
|
|
// Linear:
|
|
// initial + next * i, for invariant initial and next,
|
|
// and a "normalized" loop index i
|
|
// Wrap-around:
|
|
// initial then next, for invariant initial and any next
|
|
// Periodic:
|
|
// alternate initial and next, for invariant initial and next
|
|
//
|
|
class InductionVar : public ZoneObject {
|
|
public:
|
|
enum Kind {
|
|
kInvariant,
|
|
kLinear,
|
|
kWrapAround,
|
|
kPeriodic,
|
|
};
|
|
|
|
// Strict (exclusive) upper or lower bound on unit stride linear induction:
|
|
// i < U (i++)
|
|
// i > L (i--)
|
|
struct Bound {
|
|
Bound(BranchInstr* b, InductionVar* l) : branch_(b), limit_(l) {}
|
|
BranchInstr* branch_;
|
|
InductionVar* limit_;
|
|
};
|
|
|
|
// Constructor for an invariant.
|
|
InductionVar(int64_t offset, int64_t mult, Definition* def)
|
|
: kind_(kInvariant), offset_(offset), mult_(mult), def_(def), bounds_() {
|
|
ASSERT(mult_ == 0 || def != nullptr);
|
|
}
|
|
|
|
// Constructor for a constant.
|
|
explicit InductionVar(int64_t offset) : InductionVar(offset, 0, nullptr) {}
|
|
|
|
// Constructor for an induction.
|
|
InductionVar(Kind kind, InductionVar* initial, InductionVar* next)
|
|
: kind_(kind), initial_(initial), next_(next), bounds_() {
|
|
ASSERT(IsInvariant(initial));
|
|
switch (kind) {
|
|
case kLinear:
|
|
case kPeriodic:
|
|
ASSERT(IsInvariant(next));
|
|
break;
|
|
case kWrapAround:
|
|
ASSERT(next != nullptr);
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
// Returns true if the other induction is structurally equivalent.
|
|
bool IsEqual(const InductionVar* other) const {
|
|
ASSERT(other != nullptr);
|
|
if (kind_ == other->kind_) {
|
|
switch (kind_) {
|
|
case kInvariant:
|
|
return offset_ == other->offset_ && mult_ == other->mult_ &&
|
|
(mult_ == 0 || def_ == other->def_);
|
|
case kLinear:
|
|
case kWrapAround:
|
|
case kPeriodic:
|
|
return initial_->IsEqual(other->initial_) &&
|
|
next_->IsEqual(other->next_);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Returns true if a fixed difference between this and the other induction
|
|
// can be computed. Sets the output parameter diff on success.
|
|
bool CanComputeDifferenceWith(const InductionVar* other, int64_t* diff) const;
|
|
|
|
// Returns true if this induction in the given loop can be bounded as
|
|
// min <= this <= max by using bounds of more outer loops. On success
|
|
// the output parameters min and max are set, which are always loop
|
|
// invariant expressions inside the given loop.
|
|
bool CanComputeBounds(LoopInfo* loop,
|
|
Instruction* pos,
|
|
InductionVar** min,
|
|
InductionVar** max);
|
|
|
|
// Getters.
|
|
Kind kind() const { return kind_; }
|
|
int64_t offset() const {
|
|
ASSERT(kind_ == kInvariant);
|
|
return offset_;
|
|
}
|
|
int64_t mult() const {
|
|
ASSERT(kind_ == kInvariant);
|
|
return mult_;
|
|
}
|
|
Definition* def() const {
|
|
ASSERT(kind_ == kInvariant);
|
|
return def_;
|
|
}
|
|
InductionVar* initial() const {
|
|
ASSERT(kind_ != kInvariant);
|
|
return initial_;
|
|
}
|
|
InductionVar* next() const {
|
|
ASSERT(kind_ != kInvariant);
|
|
return next_;
|
|
}
|
|
const GrowableArray<Bound>& bounds() { return bounds_; }
|
|
|
|
// For debugging.
|
|
void PrintTo(BaseTextBuffer* f) const;
|
|
const char* ToCString() const;
|
|
|
|
// Returns true if x is invariant.
|
|
static bool IsInvariant(const InductionVar* x) {
|
|
return x != nullptr && x->kind_ == kInvariant;
|
|
}
|
|
|
|
// Returns true if x is a constant (and invariant).
|
|
static bool IsConstant(const InductionVar* x) {
|
|
return x != nullptr && x->kind_ == kInvariant && x->mult_ == 0;
|
|
}
|
|
|
|
// Returns true if x is a constant. Sets the value.
|
|
static bool IsConstant(const InductionVar* x, int64_t* c) {
|
|
if (IsConstant(x)) {
|
|
*c = x->offset_;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Returns true if x is linear.
|
|
static bool IsLinear(const InductionVar* x) {
|
|
return x != nullptr && x->kind_ == kLinear;
|
|
}
|
|
|
|
// Returns true if x is linear with constant stride. Sets the stride.
|
|
static bool IsLinear(const InductionVar* x, int64_t* s) {
|
|
if (IsLinear(x)) {
|
|
return IsConstant(x->next_, s);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Returns true if x is wrap-around.
|
|
static bool IsWrapAround(const InductionVar* x) {
|
|
return x != nullptr && x->kind_ == kWrapAround;
|
|
}
|
|
|
|
// Returns true if x is periodic.
|
|
static bool IsPeriodic(const InductionVar* x) {
|
|
return x != nullptr && x->kind_ == kPeriodic;
|
|
}
|
|
|
|
// Returns true if x is any induction.
|
|
static bool IsInduction(const InductionVar* x) {
|
|
return x != nullptr && x->kind_ != kInvariant;
|
|
}
|
|
|
|
private:
|
|
friend class InductionVarAnalysis;
|
|
|
|
// Induction classification.
|
|
const Kind kind_;
|
|
union {
|
|
struct {
|
|
int64_t offset_;
|
|
int64_t mult_;
|
|
Definition* def_;
|
|
};
|
|
struct {
|
|
InductionVar* initial_;
|
|
InductionVar* next_;
|
|
};
|
|
};
|
|
|
|
bool CanComputeBoundsImpl(LoopInfo* loop,
|
|
Instruction* pos,
|
|
InductionVar** min,
|
|
InductionVar** max);
|
|
|
|
// Bounds on induction.
|
|
GrowableArray<Bound> bounds_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(InductionVar);
|
|
};
|
|
|
|
// Information on a "natural loop" in the flow graph.
|
|
class LoopInfo : public ZoneObject {
|
|
public:
|
|
LoopInfo(intptr_t id, BlockEntryInstr* header, BitVector* blocks);
|
|
|
|
// Merges given blocks to this loop.
|
|
void AddBlocks(BitVector* blocks);
|
|
|
|
// Adds back edge to this loop.
|
|
void AddBackEdge(BlockEntryInstr* block);
|
|
|
|
// Returns true if given block is backedge of this loop.
|
|
bool IsBackEdge(BlockEntryInstr* block) const;
|
|
|
|
// Returns true if given block is alway taken in this loop.
|
|
bool IsAlwaysTaken(BlockEntryInstr* block) const;
|
|
|
|
// Returns true if given definition is a header phi for this loop.
|
|
bool IsHeaderPhi(Definition* def) const;
|
|
|
|
// Returns true if this loop is nested inside given loop.
|
|
bool IsIn(LoopInfo* loop) const;
|
|
|
|
// Returns true if this loop contains given block.
|
|
bool Contains(BlockEntryInstr* block) const;
|
|
|
|
// Returns the nesting depth of this loop.
|
|
intptr_t NestingDepth() const;
|
|
|
|
// Resets induction.
|
|
void ResetInduction();
|
|
|
|
// Assigns induction to a definition.
|
|
void AddInduction(Definition* def, InductionVar* induc);
|
|
|
|
// Looks up induction.
|
|
InductionVar* LookupInduction(Definition* def) const;
|
|
|
|
// Tests if index stays in [0,length) range in this loop at given position.
|
|
bool IsInRange(Instruction* pos, Value* index, Value* length);
|
|
|
|
// Getters.
|
|
intptr_t id() const { return id_; }
|
|
BlockEntryInstr* header() const { return header_; }
|
|
BitVector* blocks() const { return blocks_; }
|
|
const GrowableArray<BlockEntryInstr*>& back_edges() { return back_edges_; }
|
|
ConstraintInstr* limit() const { return limit_; }
|
|
InductionVar* control() const { return control_; }
|
|
LoopInfo* outer() const { return outer_; }
|
|
LoopInfo* inner() const { return inner_; }
|
|
LoopInfo* next() const { return next_; }
|
|
|
|
// For debugging.
|
|
void PrintTo(BaseTextBuffer* f) const;
|
|
const char* ToCString() const;
|
|
|
|
private:
|
|
friend class InductionVar;
|
|
friend class InductionVarAnalysis;
|
|
friend class LoopHierarchy;
|
|
|
|
// Mapping from definition to induction.
|
|
typedef RawPointerKeyValueTrait<Definition, InductionVar*> InductionKV;
|
|
|
|
// Mapping from induction to mapping from instruction to induction pair.
|
|
class MemoVal : public ZoneObject {
|
|
public:
|
|
typedef RawPointerKeyValueTrait<Instruction,
|
|
std::pair<InductionVar*, InductionVar*>>
|
|
PosKV;
|
|
MemoVal() : memo_() {}
|
|
DirectChainedHashMap<PosKV> memo_;
|
|
};
|
|
typedef RawPointerKeyValueTrait<InductionVar, MemoVal*> MemoKV;
|
|
|
|
// Unique id of loop. We use its index in the
|
|
// loop header array for this.
|
|
const intptr_t id_;
|
|
|
|
// Header of loop.
|
|
BlockEntryInstr* header_;
|
|
|
|
// Compact representation of every block in the loop,
|
|
// indexed by its "preorder_number".
|
|
BitVector* blocks_;
|
|
|
|
// Back edges of loop (usually one).
|
|
GrowableArray<BlockEntryInstr*> back_edges_;
|
|
|
|
// Map definition -> induction for this loop.
|
|
DirectChainedHashMap<InductionKV> induction_;
|
|
|
|
// A small, per-loop memoization cache, to avoid costly
|
|
// recomputations while traversing very deeply nested loops.
|
|
DirectChainedHashMap<MemoKV> memo_cache_;
|
|
|
|
// Constraint on a header phi.
|
|
// TODO(ajcbik): very specific to smi range analysis,
|
|
// should we really store it here?
|
|
ConstraintInstr* limit_;
|
|
|
|
// Control induction.
|
|
InductionVar* control_;
|
|
|
|
// Loop hierarchy.
|
|
LoopInfo* outer_;
|
|
LoopInfo* inner_;
|
|
LoopInfo* next_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(LoopInfo);
|
|
};
|
|
|
|
// Information on the loop hierarchy in the flow graph.
|
|
class LoopHierarchy : public ZoneObject {
|
|
public:
|
|
LoopHierarchy(ZoneGrowableArray<BlockEntryInstr*>* headers,
|
|
const GrowableArray<BlockEntryInstr*>& preorder,
|
|
bool print_traces);
|
|
|
|
// Getters.
|
|
const ZoneGrowableArray<BlockEntryInstr*>& headers() const {
|
|
return *headers_;
|
|
}
|
|
LoopInfo* top() const { return top_; }
|
|
|
|
// Returns total number of loops in the hierarchy.
|
|
intptr_t num_loops() const { return headers_->length(); }
|
|
|
|
// Performs induction variable analysis on all loops.
|
|
void ComputeInduction() const;
|
|
|
|
private:
|
|
void Build();
|
|
void Print(LoopInfo* loop) const;
|
|
|
|
ZoneGrowableArray<BlockEntryInstr*>* headers_;
|
|
const GrowableArray<BlockEntryInstr*>& preorder_;
|
|
LoopInfo* top_;
|
|
const bool print_traces_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(LoopHierarchy);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_COMPILER_BACKEND_LOOPS_H_
|