mirror of
https://github.com/dart-lang/sdk
synced 2024-09-18 20:41:24 +00:00
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:
parent
e63836db88
commit
2f23dc4b60
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue