be9bc9c068
This is a version of the Lengauer-Tarjan algorithm that is both simpler and faster. R=srdjan@google.com BUG= TEST= Review URL: https://chromiumcodereview.appspot.com//9729015 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@5737 260f80e4-7a28-3924-810f-c04153c831b5
200 lines
6.0 KiB
C++
200 lines
6.0 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.
|
|
|
|
#include "vm/intermediate_language.h"
|
|
|
|
#include "vm/object.h"
|
|
#include "vm/os.h"
|
|
#include "vm/scopes.h"
|
|
|
|
namespace dart {
|
|
|
|
// ==== Support for visiting flow graphs.
|
|
#define DEFINE_ACCEPT(ShortName, ClassName) \
|
|
void ClassName::Accept(FlowGraphVisitor* visitor) { \
|
|
visitor->Visit##ShortName(this); \
|
|
}
|
|
|
|
FOR_EACH_COMPUTATION(DEFINE_ACCEPT)
|
|
|
|
#undef DEFINE_ACCEPT
|
|
|
|
|
|
Instruction* JoinEntryInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitJoinEntry(this);
|
|
return successor_;
|
|
}
|
|
|
|
|
|
Instruction* TargetEntryInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitTargetEntry(this);
|
|
return successor_;
|
|
}
|
|
|
|
|
|
Instruction* PickTempInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitPickTemp(this);
|
|
return successor_;
|
|
}
|
|
|
|
|
|
Instruction* TuckTempInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitTuckTemp(this);
|
|
return successor_;
|
|
}
|
|
|
|
|
|
Instruction* DoInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitDo(this);
|
|
return successor_;
|
|
}
|
|
|
|
|
|
Instruction* BindInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitBind(this);
|
|
return successor_;
|
|
}
|
|
|
|
|
|
Instruction* ReturnInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitReturn(this);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
Instruction* ThrowInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitThrow(this);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
Instruction* ReThrowInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitReThrow(this);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
Instruction* BranchInstr::Accept(FlowGraphVisitor* visitor) {
|
|
visitor->VisitBranch(this);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// Default implementation of visiting basic blocks. Can be overridden.
|
|
void FlowGraphVisitor::VisitBlocks() {
|
|
for (intptr_t i = 0; i < block_order_.length(); ++i) {
|
|
Instruction* current = block_order_[i]->Accept(this);
|
|
while ((current != NULL) && !current->IsBlockEntry()) {
|
|
current = current->Accept(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ==== Postorder graph traversal.
|
|
void JoinEntryInstr::DiscoverBlocks(
|
|
BlockEntryInstr* current_block,
|
|
GrowableArray<BlockEntryInstr*>* preorder,
|
|
GrowableArray<BlockEntryInstr*>* postorder,
|
|
GrowableArray<intptr_t>* parent) {
|
|
// The global graph entry is a TargetEntryInstr, so we can assume
|
|
// current_block is non-null and preorder array is non-empty.
|
|
ASSERT(current_block != NULL);
|
|
ASSERT(!preorder->is_empty());
|
|
|
|
// 1. Record control-flow-graph basic-block predecessors.
|
|
predecessors_.Add(current_block);
|
|
|
|
// 2. If the block has already been reached by the traversal, we are done.
|
|
if (preorder_number() >= 0) return;
|
|
|
|
// 3. The last entry in the preorder array is the spanning-tree parent.
|
|
intptr_t parent_number = preorder->length() - 1;
|
|
parent->Add(parent_number);
|
|
|
|
// 4. Assign preorder number and add the block entry to the list.
|
|
set_preorder_number(parent_number + 1);
|
|
preorder->Add(this);
|
|
// The preorder and parent arrays are both indexed by preorder block
|
|
// number, so they should stay in lockstep.
|
|
ASSERT(preorder->length() == parent->length());
|
|
|
|
// 5. Iterate straight-line successors until a branch instruction or
|
|
// another basic block entry instruction, and visit that instruction.
|
|
ASSERT(successor_ != NULL);
|
|
Instruction* next = successor_;
|
|
while ((next != NULL) && !next->IsBlockEntry() && !next->IsBranch()) {
|
|
set_last_instruction(next);
|
|
next = next->StraightLineSuccessor();
|
|
}
|
|
if (next != NULL) {
|
|
next->DiscoverBlocks(this, preorder, postorder, parent);
|
|
}
|
|
|
|
// 6. Assign postorder number and add the block entry to the list.
|
|
set_postorder_number(postorder->length());
|
|
postorder->Add(this);
|
|
}
|
|
|
|
|
|
void TargetEntryInstr::DiscoverBlocks(
|
|
BlockEntryInstr* current_block,
|
|
GrowableArray<BlockEntryInstr*>* preorder,
|
|
GrowableArray<BlockEntryInstr*>* postorder,
|
|
GrowableArray<intptr_t>* parent) {
|
|
// 1. Record control-flow-graph basic-block predecessors.
|
|
ASSERT(predecessor_ == NULL);
|
|
predecessor_ = current_block; // Might be NULL (for the graph entry).
|
|
|
|
// 2. There is a single predecessor, so we should only reach this block once.
|
|
ASSERT(preorder_number() == -1);
|
|
|
|
// 3. The last entry in the preorder array is the spanning-tree parent.
|
|
// The global graph entry has no parent, indicated by -1.
|
|
intptr_t parent_number = preorder->length() - 1;
|
|
parent->Add(parent_number);
|
|
|
|
// 4. Assign preorder number and add the block entry to the list.
|
|
set_preorder_number(parent_number + 1);
|
|
preorder->Add(this);
|
|
// The preorder and parent arrays are indexed by preorder block number, so
|
|
// they should stay in lockstep.
|
|
ASSERT(preorder->length() == parent->length());
|
|
|
|
// 5. Iterate straight-line successors until a branch instruction or
|
|
// another basic block entry instruction, and visit that instruction.
|
|
ASSERT(successor_ != NULL);
|
|
Instruction* next = successor_;
|
|
while ((next != NULL) && !next->IsBlockEntry() && !next->IsBranch()) {
|
|
set_last_instruction(next);
|
|
next = next->StraightLineSuccessor();
|
|
}
|
|
if (next != NULL) {
|
|
next->DiscoverBlocks(this, preorder, postorder, parent);
|
|
}
|
|
|
|
// 6. Assign postorder number and add the block entry to the list.
|
|
set_postorder_number(postorder->length());
|
|
postorder->Add(this);
|
|
}
|
|
|
|
|
|
void BranchInstr::DiscoverBlocks(
|
|
BlockEntryInstr* current_block,
|
|
GrowableArray<BlockEntryInstr*>* preorder,
|
|
GrowableArray<BlockEntryInstr*>* postorder,
|
|
GrowableArray<intptr_t>* parent) {
|
|
current_block->set_last_instruction(this);
|
|
// Visit the false successor before the true successor so they appear in
|
|
// true/false order in reverse postorder used as the block ordering in the
|
|
// nonoptimizing compiler.
|
|
ASSERT(true_successor_ != NULL);
|
|
ASSERT(false_successor_ != NULL);
|
|
false_successor_->DiscoverBlocks(current_block, preorder, postorder, parent);
|
|
true_successor_->DiscoverBlocks(current_block, preorder, postorder, parent);
|
|
}
|
|
|
|
|
|
} // namespace dart
|