Simple iterative liveness analysis over SSA.

R=fschneider@google.com
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com//10666026

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@9069 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
vegorov@google.com 2012-06-25 17:07:16 +00:00
parent e63836db88
commit 2f23dc4b60
6 changed files with 236 additions and 4 deletions

View file

@ -63,6 +63,34 @@ class BitVector: public ZoneAllocated {
data_[i / kBitsPerWord] |= (static_cast<uword>(1) << (i % kBitsPerWord));
}
// Add all elements that are in the bitvector from.
bool AddAll(BitVector* from) {
ASSERT(data_length_ == from->data_length_);
bool changed = false;
for (intptr_t i = 0; i < data_length_; i++) {
const uword before = data_[i];
const uword after = data_[i] | from->data_[i];
if (before != after) changed = true;
data_[i] = after;
}
return changed;
}
// From the bitvector gen add those elements that are not in the
// bitvector kill.
bool KillAndAdd(BitVector* kill, BitVector* gen) {
ASSERT(data_length_ == kill->data_length_);
ASSERT(data_length_ == gen->data_length_);
bool changed = false;
for (intptr_t i = 0; i < data_length_; i++) {
const uword before = data_[i];
const uword after = data_[i] | (gen->data_[i] & ~kill->data_[i]);
if (before != after) changed = true;
data_[i] = after;
}
return changed;
}
bool Contains(int i) const {
ASSERT(i >= 0 && i < length());
uword block = data_[i / kBitsPerWord];

View file

@ -52,6 +52,29 @@ TEST_CASE(BitVector) {
iter.Advance();
EXPECT(iter.Done());
}
{ BitVector* a = new BitVector(128);
BitVector* b = new BitVector(128);
BitVector* c = new BitVector(128);
b->Add(0);
b->Add(32);
b->Add(64);
a->AddAll(b);
EXPECT_EQ(true, a->Contains(0));
EXPECT_EQ(true, a->Contains(32));
EXPECT_EQ(true, a->Contains(64));
EXPECT_EQ(false, a->Contains(96));
EXPECT_EQ(false, a->Contains(127));
b->Add(96);
b->Add(127);
c->Add(127);
a->KillAndAdd(c, b);
EXPECT_EQ(true, a->Contains(0));
EXPECT_EQ(true, a->Contains(32));
EXPECT_EQ(true, a->Contains(64));
EXPECT_EQ(true, a->Contains(96));
EXPECT_EQ(false, a->Contains(127));
}
}
} // namespace dart

View file

@ -197,9 +197,12 @@ static bool CompileWithNewCompiler(
optimizer.ApplyICData();
if (FLAG_use_ssa) {
printf("====================================\n");
// Perform register allocation on the SSA graph.
FlowGraphAllocator allocator(block_order);
FlowGraphAllocator allocator(graph_builder.postorder_block_entries(),
graph_builder.current_ssa_temp_index());
allocator.ResolveConstraints();
allocator.AnalyzeLiveness();
// Temporary bailout until we support code generation from SSA form.
graph_builder.Bailout("No SSA code generation support.");

View file

@ -4,12 +4,173 @@
#include "vm/flow_graph_allocator.h"
#include "vm/bit_vector.h"
#include "vm/intermediate_language.h"
#include "vm/flow_graph_compiler.h"
namespace dart {
DEFINE_FLAG(bool, print_ssa_liveness, false,
"Print liveness for ssa variables.");
FlowGraphAllocator::FlowGraphAllocator(
const GrowableArray<BlockEntryInstr*>& postorder,
intptr_t max_ssa_temp_index)
: live_out_(postorder.length()),
kill_(postorder.length()),
gen_(postorder.length()),
live_in_(postorder.length()),
postorder_(postorder),
vreg_count_(max_ssa_temp_index) {
}
void FlowGraphAllocator::ResolveConstraints() {
// TODO(fschneider): Resolve register constraints.
}
static intptr_t ToVirtualRegister(Instruction* instr) {
const Definition* def = instr->AsDefinition();
if (def == NULL) return -1;
return def->ssa_temp_index();
}
void FlowGraphAllocator::ComputeKillAndGenSets() {
const intptr_t block_count = postorder_.length();
for (intptr_t i = 0; i < block_count; i++) {
BlockEntryInstr* block = postorder_[i];
BitVector* kill = kill_[i];
BitVector* live_in = live_in_[i];
if (block->IsJoinEntry()) {
JoinEntryInstr* join = block->AsJoinEntry();
if (join->phis() != NULL) {
for (intptr_t j = 0; j < join->phis()->length(); j++) {
PhiInstr* phi = (*join->phis())[j];
if (phi == NULL) continue;
const intptr_t def = ToVirtualRegister(phi);
if (def >= 0) kill->Add(def);
for (intptr_t k = 0; k < phi->InputCount(); k++) {
Value* val = phi->InputAt(k);
if (!val->IsUse()) continue;
const intptr_t use = ToVirtualRegister(val->AsUse()->definition());
if (use >= 0) {
BlockEntryInstr* pred = block->PredecessorAt(k);
live_out_[pred->postorder_number()]->Add(use);
}
}
}
}
}
Instruction* current = block->StraightLineSuccessor();
// TODO(vegorov): iterate backwards.
while ((current != NULL) && !current->IsBlockEntry()) {
for (intptr_t j = 0; j < current->InputCount(); j++) {
Value* input = current->InputAt(j);
if (!input->IsUse()) continue;
const intptr_t use = ToVirtualRegister(input->AsUse()->definition());
if ((use >= 0) && !kill->Contains(use)) live_in->Add(use);
}
const intptr_t def = ToVirtualRegister(current);
if (def >= 0) kill->Add(def);
current = current->StraightLineSuccessor();
}
UpdateLiveIn(block);
}
}
bool FlowGraphAllocator::UpdateLiveOut(BlockEntryInstr* instr) {
BitVector* live_out = live_out_[instr->postorder_number()];
bool changed = false;
Instruction* last = instr->last_instruction();
for (intptr_t i = 0; i < last->SuccessorCount(); i++) {
BlockEntryInstr* succ = last->SuccessorAt(i);
if (live_out->AddAll(live_in_[succ->postorder_number()])) {
changed = true;
}
}
return changed;
}
bool FlowGraphAllocator::UpdateLiveIn(BlockEntryInstr* instr) {
BitVector* live_out = live_out_[instr->postorder_number()];
BitVector* kill = kill_[instr->postorder_number()];
BitVector* live_in = live_in_[instr->postorder_number()];
return live_in->KillAndAdd(kill, live_out);
}
void FlowGraphAllocator::ComputeLiveInAndLiveOutSets() {
const intptr_t block_count = postorder_.length();
bool changed;
do {
changed = false;
for (intptr_t i = 0; i < block_count; i++) {
BlockEntryInstr* block = postorder_[i];
if (UpdateLiveOut(block) && UpdateLiveIn(block)) {
changed = true;
}
}
} while (changed);
}
void FlowGraphAllocator::AnalyzeLiveness() {
const intptr_t block_count = postorder_.length();
for (intptr_t i = 0; i < block_count; i++) {
live_out_.Add(new BitVector(vreg_count_));
kill_.Add(new BitVector(vreg_count_));
live_in_.Add(new BitVector(vreg_count_));
}
ComputeKillAndGenSets();
ComputeLiveInAndLiveOutSets();
if (FLAG_print_ssa_liveness) {
DumpLiveness();
}
}
static void PrintBitVector(const char* tag, BitVector* v) {
OS::Print("%s:", tag);
for (BitVector::Iterator it(v); !it.Done(); it.Advance()) {
OS::Print(" %d", it.Current());
}
OS::Print("\n");
}
void FlowGraphAllocator::DumpLiveness() {
const intptr_t block_count = postorder_.length();
for (intptr_t i = 0; i < block_count; i++) {
BlockEntryInstr* block = postorder_[i];
OS::Print("block @%d -> ", block->block_id());
Instruction* last = block->last_instruction();
for (intptr_t j = 0; j < last->SuccessorCount(); j++) {
BlockEntryInstr* succ = last->SuccessorAt(j);
OS::Print(" @%d", succ->block_id());
}
OS::Print("\n");
PrintBitVector(" live out", live_out_[i]);
PrintBitVector(" kill", kill_[i]);
PrintBitVector(" live in", live_in_[i]);
}
}
} // namespace dart

View file

@ -12,13 +12,26 @@ namespace dart {
class FlowGraphAllocator : public ValueObject {
public:
explicit FlowGraphAllocator(const GrowableArray<BlockEntryInstr*>& blocks)
: blocks_(blocks) { }
FlowGraphAllocator(const GrowableArray<BlockEntryInstr*>& postorder,
intptr_t max_ssa_temp_index);
void ResolveConstraints();
void AnalyzeLiveness();
private:
const GrowableArray<BlockEntryInstr*>& blocks_;
void ComputeKillAndGenSets();
bool UpdateLiveOut(BlockEntryInstr* instr);
bool UpdateLiveIn(BlockEntryInstr* instr);
void ComputeLiveInAndLiveOutSets();
void DumpLiveness();
GrowableArray<BitVector*> live_out_;
GrowableArray<BitVector*> kill_;
GrowableArray<BitVector*> gen_;
GrowableArray<BitVector*> live_in_;
const GrowableArray<BlockEntryInstr*>& postorder_;
const intptr_t vreg_count_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphAllocator);
};

View file

@ -42,6 +42,10 @@ class FlowGraphBuilder: public ValueObject {
void AddCatchEntry(TargetEntryInstr* entry);
intptr_t current_ssa_temp_index() const {
return current_ssa_temp_index_;
}
private:
void ComputeDominators(GrowableArray<BlockEntryInstr*>* preorder,
GrowableArray<intptr_t>* parent,