Showing with 229 additions and 42 deletions.
  1. +106 −1 src/hir-instructions.cc
  2. +25 −3 src/hir-instructions.h
  3. +49 −0 src/hir.cc
  4. +1 −0 src/hir.h
  5. +28 −14 src/root.cc
  6. +5 −3 src/root.h
  7. +5 −1 src/scope.h
  8. +10 −20 test/test-hir.cc
@@ -9,11 +9,14 @@ namespace internal {
HIRInstruction::HIRInstruction(Type type) :
id(-1),
gcm_visited(0),
gvn_visited(0),
is_live(0),
type_(type),
slot_(NULL),
ast_(NULL),
lir_(NULL),
hashed_(false),
hash_(0),
removed_(false),
pinned_(true),
representation_(kHoleRepresentation) {
@@ -23,11 +26,14 @@ HIRInstruction::HIRInstruction(Type type) :
HIRInstruction::HIRInstruction(Type type, ScopeSlot* slot) :
id(-1),
gcm_visited(0),
gvn_visited(0),
is_live(0),
type_(type),
slot_(slot),
ast_(NULL),
lir_(NULL),
hashed_(false),
hash_(0),
removed_(false),
pinned_(true),
representation_(kHoleRepresentation) {
@@ -40,11 +46,16 @@ void HIRInstruction::Init(HIRGen* g, HIRBlock* block) {
}


inline bool HIRInstruction::HasSideEffects() {
bool HIRInstruction::HasSideEffects() {
return false;
}


bool HIRInstruction::HasGVNSideEffects() {
return HasSideEffects();
}


inline void HIRInstruction::CalculateRepresentation() {
representation_ = kUnknownRepresentation;
}
@@ -95,6 +106,67 @@ void HIRInstruction::RemoveUse(HIRInstruction* i) {
}


uint32_t HIRInstruction::Hash(HIRInstruction* instr) {
// Loop detected
if (instr->hashed_) return instr->hash_;
instr->hashed_ = true;

// Some outstanding hash - just in case of loops
instr->hash_ = 0xffff;

// Jenkins for following sequence
// [type] [hash of input 1] ... [hash of input N]
uint32_t r = instr->type() & 0xff;
r += r << 10;
r ^= r >> 6;

HIRInstructionList::Item* ahead = instr->args()->head();
for (; ahead != NULL; ahead = ahead->next()) {
uint32_t arg_hash = Hash(ahead->value());

while (arg_hash != 0) {
r += arg_hash & 0xff;
r += r << 10;
r ^= r >> 6;
arg_hash = arg_hash >> 8;
}
}

// Shuffle bits
r += r << 3;
r ^= r >> 13;
r += r << 15;

instr->hash_ = r;
return r;
}


int HIRInstruction::Compare(HIRInstruction* a, HIRInstruction* b) {
if (a == b) return 0;

// Types should be equal
if (a->type() != b->type()) return -1;

// Arguments should be equal too
if (a->args()->length() != b->args()->length()) return -1;

HIRInstructionList::Item* ahead = a->args()->head();
HIRInstructionList::Item* bhead = b->args()->head();
for (; ahead != NULL; ahead = ahead->next(), bhead = bhead->next()) {
if (ahead->value() != bhead->value()) return -1;
}

return a->IsGVNEqual(b) ? 0 : 1;
}


bool HIRInstruction::IsGVNEqual(HIRInstruction* to) {
// Default implementation
return true;
}


void HIRInstruction::Print(PrintBuffer* p) {
p->Print("i%d = ", id);

@@ -164,6 +236,14 @@ HIRLiteral::HIRLiteral(AstNode::Type type, ScopeSlot* slot) :
}


bool HIRLiteral::IsGVNEqual(HIRInstruction* to) {
if (!to->Is(HIRInstruction::kLiteral)) return false;
HIRLiteral* lto = HIRLiteral::Cast(to);

return this->root_slot()->is_equal(lto->root_slot());
}


void HIRLiteral::CalculateRepresentation() {
switch (type_) {
case AstNode::kNumber:
@@ -201,6 +281,11 @@ void HIRFunction::Print(PrintBuffer* p) {
}


bool HIRFunction::IsGVNEqual(HIRInstruction* to) {
return this == to;
}


HIRNil::HIRNil() : HIRInstruction(kNil) {
}

@@ -299,12 +384,22 @@ void HIRBinOp::CalculateRepresentation() {
}


bool HIRBinOp::IsGVNEqual(HIRInstruction* to) {
return binop_type_ == HIRBinOp::Cast(to)->binop_type_;
}


HIRLoadContext::HIRLoadContext(ScopeSlot* slot)
: HIRInstruction(kLoadContext),
context_slot_(slot) {
}


bool HIRLoadContext::HasGVNSideEffects() {
return true;
}


HIRStoreContext::HIRStoreContext(ScopeSlot* slot) :
HIRInstruction(kStoreContext),
context_slot_(slot) {
@@ -353,6 +448,11 @@ HIRAllocateObject::HIRAllocateObject(int size)
}


bool HIRAllocateObject::HasGVNSideEffects() {
return true;
}


void HIRAllocateObject::CalculateRepresentation() {
representation_ = kObjectRepresentation;
}
@@ -364,6 +464,11 @@ HIRAllocateArray::HIRAllocateArray(int size)
}


bool HIRAllocateArray::HasGVNSideEffects() {
return true;
}


void HIRAllocateArray::CalculateRepresentation() {
representation_ = kArrayRepresentation;
}
@@ -17,6 +17,7 @@ class HIRPhi;
class LInstruction;

typedef ZoneList<HIRInstruction*> HIRInstructionList;
typedef HashMap<HIRInstruction, HIRInstruction, ZoneObject> HIRInstructionMap;
typedef ZoneList<HIRPhi*> HIRPhiList;

#define HIR_INSTRUCTION_TYPES(V) \
@@ -86,14 +87,20 @@ class HIRInstruction : public ZoneObject {

int id;
int gcm_visited;
int gvn_visited;
int is_live;

virtual void ReplaceArg(HIRInstruction* o, HIRInstruction* n);
virtual bool HasSideEffects();
virtual bool HasGVNSideEffects();
virtual void CalculateRepresentation();
void Remove();
void RemoveUse(HIRInstruction* i);

// GVN hashmap routines
static uint32_t Hash(HIRInstruction* instr);
static int Compare(HIRInstruction* a, HIRInstruction* b);

inline HIRInstruction* AddArg(Type type);
inline HIRInstruction* AddArg(HIRInstruction* instr);
inline bool Is(Type type);
@@ -130,12 +137,17 @@ class HIRInstruction : public ZoneObject {
inline void lir(LInstruction* lir);

protected:
virtual bool IsGVNEqual(HIRInstruction* to);

Type type_;
ScopeSlot* slot_;
AstNode* ast_;
LInstruction* lir_;
HIRBlock* block_;

bool hashed_;
uint32_t hash_;

bool removed_;
bool pinned_;

@@ -187,7 +199,9 @@ class HIRLiteral : public HIRInstruction {

HIR_DEFAULT_METHODS(Literal)

private:
protected:
bool IsGVNEqual(HIRInstruction* to);

AstNode::Type type_;
ScopeSlot* root_slot_;
};
@@ -203,6 +217,9 @@ class HIRFunction : public HIRInstruction {
void Print(PrintBuffer* p);

HIR_DEFAULT_METHODS(Function)

protected:
bool IsGVNEqual(HIRInstruction* to);
};

class HIRNil : public HIRInstruction {
@@ -290,7 +307,9 @@ class HIRBinOp : public HIRInstruction {

HIR_DEFAULT_METHODS(BinOp)

private:
protected:
bool IsGVNEqual(HIRInstruction* to);

BinOp::BinOpType binop_type_;
};

@@ -299,10 +318,11 @@ class HIRLoadContext : public HIRInstruction {
HIRLoadContext(ScopeSlot* slot);

inline ScopeSlot* context_slot();
bool HasGVNSideEffects();

HIR_DEFAULT_METHODS(LoadContext)

private:
protected:
ScopeSlot* context_slot_;
};

@@ -354,6 +374,7 @@ class HIRAllocateObject : public HIRInstruction {
public:
HIRAllocateObject(int size);

bool HasGVNSideEffects();
void CalculateRepresentation();
inline int size();

@@ -367,6 +388,7 @@ class HIRAllocateArray : public HIRInstruction {
public:
HIRAllocateArray(int size);

bool HasGVNSideEffects();
void CalculateRepresentation();
inline int size();

@@ -246,6 +246,55 @@ void HIRGen::EliminateDeadCode(HIRInstruction* instr) {


void HIRGen::GlobalValueNumbering() {
HIRInstructionMap* gvn_ = NULL;
HIRBlock* root_ = NULL;

// For each block
HIRBlockList::Item* bhead = blocks_.head();
for (; bhead != NULL; bhead = bhead->next()) {
HIRBlock* block = bhead->value();

if (root_ != block->root()) {
root_ = block->root();
gvn_ = new HIRInstructionMap();
}

// Visit instructions that wasn't yet visited
HIRInstructionList::Item* ihead = block->instructions()->head();
for (; ihead != NULL; ihead = ihead->next()) {
HIRInstruction* instr = ihead->value();

GlobalValueNumbering(instr, gvn_);
}
}
}


void HIRGen::GlobalValueNumbering(HIRInstruction* instr,
HIRInstructionMap* gvn) {
if (instr->gvn_visited) return;
instr->gvn_visited = 1;

// Instructions with side effects can't be replaced
if (instr->HasGVNSideEffects()) return;

// Process inputs first
HIRInstructionList::Item* ahead = instr->args()->head();
for (; ahead != NULL; ahead = ahead->next()) {
HIRInstruction* arg = ahead->value();
GlobalValueNumbering(arg, gvn);
}

HIRInstruction* copy = gvn->Get(instr);

// If there're already equivalent instruction in GVN, replace current with it
if (copy != NULL) {
Replace(instr, copy);
instr->block()->Remove(instr);
return;
}

gvn->Set(instr, instr);
}


@@ -167,6 +167,7 @@ class HIRGen : public Visitor<HIRInstruction> {
void EliminateDeadCode();
void EliminateDeadCode(HIRInstruction* instr);
void GlobalValueNumbering();
void GlobalValueNumbering(HIRInstruction* instr, HIRInstructionMap* gvn);
void GlobalCodeMotion();
void ScheduleEarly(HIRInstruction* instr, HIRBlock* root);
void ScheduleLate(HIRInstruction* instr);