Revision: 2643
Author: [email protected]
Date: Fri Aug 7 00:15:31 2009
Log: Add support for (some) assignment expressions to the CFG builder and
fast-mode compiler.
1. We avoid generating a useless temporary for assignments with
nontrivial right-hand sides. Instead of translating id = expr into:
...
tmp = <last expr instruction>
id = tmp
we generate directly
...
id = <last expr instruction>
by passing a data destination ('hint') down the AST. The semantics is
to use the destination as a result location if a temp is needed. It
may be ignored. NULL indicates I don't care and you should generate a
temp.
2. We correctly handle assignments as subexpressions. When building
the CFG for an expression we accumulate the assigned variables and we
emit a move to a fresh temporary if a value in a variable is in
jeopardy of being overwritten.
Review URL: http://codereview.chromium.org/165056
http://code.google.com/p/v8/source/detail?r=2643
Modified:
/branches/bleeding_edge/src/arm/cfg-arm.cc
/branches/bleeding_edge/src/cfg.cc
/branches/bleeding_edge/src/cfg.h
/branches/bleeding_edge/src/ia32/cfg-ia32.cc
/branches/bleeding_edge/src/x64/cfg-x64.cc
=======================================
--- /branches/bleeding_edge/src/arm/cfg-arm.cc Thu Aug 6 04:14:48 2009
+++ /branches/bleeding_edge/src/arm/cfg-arm.cc Fri Aug 7 00:15:31 2009
@@ -106,28 +106,33 @@
__ RecordPosition(pos_);
}
}
+
+
+void MoveInstr::Compile(MacroAssembler* masm) {
+ location()->Move(masm, value());
+}
void BinaryOpInstr::Compile(MacroAssembler* masm) {
// The right-hand value should not be on the stack---if it is a
// compiler-generated temporary it is in the accumulator.
- ASSERT(!val1_->is_on_stack());
+ ASSERT(!value1()->is_on_stack());
Comment cmnt(masm, "[ BinaryOpInstr");
// We can overwrite one of the operands if it is a temporary.
OverwriteMode mode = NO_OVERWRITE;
- if (val0_->is_temporary()) {
+ if (value0()->is_temporary()) {
mode = OVERWRITE_LEFT;
- } else if (val1_->is_temporary()) {
+ } else if (value1()->is_temporary()) {
mode = OVERWRITE_RIGHT;
}
// Move left to r1 and right to r0.
- val0_->Get(masm, r1);
- val1_->Get(masm, r0);
- GenericBinaryOpStub stub(op_, mode);
+ value0()->Get(masm, r1);
+ value1()->Get(masm, r0);
+ GenericBinaryOpStub stub(op(), mode);
__ CallStub(&stub);
- loc_->Set(masm, r0);
+ location()->Set(masm, r0);
}
@@ -165,6 +170,12 @@
return MemOperand(r0);
}
}
+
+
+void Constant::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ __ mov(ip, Operand(handle_));
+ __ str(ip, ToMemOperand(loc));
+}
void SlotLocation::Get(MacroAssembler* masm, Register reg) {
@@ -181,6 +192,18 @@
__ ldr(ip, ToMemOperand(this));
__ push(ip); // Push will not destroy ip.
}
+
+
+void SlotLocation::Move(MacroAssembler* masm, Value* value) {
+ // Double dispatch.
+ value->MoveToSlot(masm, this);
+}
+
+
+void SlotLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ __ ldr(ip, ToMemOperand(this));
+ __ str(ip, ToMemOperand(loc));
+}
void TempLocation::Get(MacroAssembler* masm, Register reg) {
@@ -191,9 +214,8 @@
case STACK:
__ pop(reg);
break;
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
- break;
}
}
@@ -206,9 +228,8 @@
case STACK:
__ push(reg);
break;
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
- break;
}
}
@@ -219,13 +240,38 @@
__ push(r0);
break;
case STACK:
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
+ }
+}
+
+
+void TempLocation::Move(MacroAssembler* masm, Value* value) {
+ switch (where_) {
+ case ACCUMULATOR:
+ value->Get(masm, r0);
+ case STACK:
+ value->Push(masm);
break;
+ case NOT_ALLOCATED:
+ UNREACHABLE();
}
}
+void TempLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ switch (where_) {
+ case ACCUMULATOR:
+ __ str(r0, ToMemOperand(loc));
+ case STACK:
+ __ pop(ip);
+ __ str(ip, ToMemOperand(loc));
+ break;
+ case NOT_ALLOCATED:
+ UNREACHABLE();
+ }
+}
+
#undef __
} } // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/cfg.cc Thu Aug 6 04:14:48 2009
+++ /branches/bleeding_edge/src/cfg.cc Fri Aug 7 00:15:31 2009
@@ -42,7 +42,7 @@
CfgGlobals::CfgGlobals(FunctionLiteral* fun)
: global_fun_(fun),
global_exit_(new ExitNode()),
- effect_(new Effect()),
+ nowhere_(new Nowhere()),
#ifdef DEBUG
node_counter_(0),
temp_counter_(0),
@@ -60,6 +60,12 @@
if (fun->scope()->num_heap_slots() > 0) {
BAILOUT("function has context slots");
}
+ if (fun->scope()->num_stack_slots() > kPointerSize) {
+ BAILOUT("function has too many locals");
+ }
+ if (fun->scope()->num_parameters() > kPointerSize - 1) {
+ BAILOUT("function has too many parameters");
+ }
if (fun->scope()->arguments() != NULL) {
BAILOUT("function uses .arguments");
}
@@ -71,18 +77,18 @@
StatementBuilder builder;
builder.VisitStatements(body);
- Cfg* cfg = builder.cfg();
- if (cfg == NULL) {
+ Cfg* graph = builder.graph();
+ if (graph == NULL) {
BAILOUT("unsupported statement type");
}
- if (cfg->is_empty()) {
+ if (graph->is_empty()) {
BAILOUT("function body produces empty cfg");
}
- if (cfg->has_exit()) {
+ if (graph->has_exit()) {
BAILOUT("control path without explicit return");
}
- cfg->PrependEntryNode();
- return cfg;
+ graph->PrependEntryNode();
+ return graph;
}
#undef BAILOUT
@@ -192,11 +198,21 @@
return code;
}
+
+
+void MoveInstr::FastAllocate(TempLocation* temp) {
+ ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
+ if (temp == value()) {
+ temp->set_where(TempLocation::ACCUMULATOR);
+ } else {
+ temp->set_where(TempLocation::STACK);
+ }
+}
void BinaryOpInstr::FastAllocate(TempLocation* temp) {
- ASSERT(temp->where() == TempLocation::NOWHERE);
- if (temp == val0_ || temp == val1_) {
+ ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
+ if (temp == value0() || temp == value1()) {
temp->set_where(TempLocation::ACCUMULATOR);
} else {
temp->set_where(TempLocation::STACK);
@@ -205,7 +221,7 @@
void ReturnInstr::FastAllocate(TempLocation* temp) {
- ASSERT(temp->where() == TempLocation::NOWHERE);
+ ASSERT(temp->where() == TempLocation::NOT_ALLOCATED);
if (temp == value_) {
temp->set_where(TempLocation::ACCUMULATOR);
} else {
@@ -226,7 +242,7 @@
// Macros (temporarily) handling unsupported expression types.
#define BAILOUT(reason) \
do { \
- cfg_ = NULL; \
+ graph_ = NULL; \
return; \
} while (false)
@@ -260,11 +276,13 @@
if (slot->type() != Slot::PARAMETER && slot->type() != Slot::LOCAL) {
BAILOUT("unsupported slot type (not a parameter or local)");
}
+ // Ignore the passed destination.
value_ = new SlotLocation(slot->type(), slot->index());
}
void ExpressionBuilder::VisitLiteral(Literal* expr) {
+ // Ignore the passed destination.
value_ = new Constant(expr->handle());
}
@@ -290,7 +308,42 @@
void ExpressionBuilder::VisitAssignment(Assignment* expr) {
- BAILOUT("Assignment");
+ if (expr->op() != Token::ASSIGN && expr->op() != Token::INIT_VAR) {
+ BAILOUT("unsupported compound assignment");
+ }
+ Expression* lhs = expr->target();
+ if (lhs->AsProperty() != NULL) {
+ BAILOUT("unsupported property assignment");
+ }
+ Variable* var = lhs->AsVariableProxy()->AsVariable();
+ if (var == NULL) {
+ BAILOUT("unsupported invalid left-hand side");
+ }
+ if (var->is_global()) {
+ BAILOUT("unsupported global variable");
+ }
+ Slot* slot = var->slot();
+ ASSERT(slot != NULL);
+ if (slot->type() != Slot::PARAMETER && slot->type() != Slot::LOCAL) {
+ BAILOUT("unsupported slot lhs (not a parameter or local)");
+ }
+
+ ExpressionBuilder builder;
+ SlotLocation* loc = new SlotLocation(slot->type(), slot->index());
+ builder.Build(expr->value(), loc);
+ if (builder.graph() == NULL) {
+ BAILOUT("unsupported expression in assignment");
+ }
+ // If the expression did not come back in the slot location, append
+ // a move to the CFG.
+ graph_ = builder.graph();
+ if (builder.value() != loc) {
+ graph()->Append(new MoveInstr(loc, builder.value()));
+ }
+ // Record the assignment.
+ assigned_vars_.AddElement(loc);
+ // Ignore the destination passed to us.
+ value_ = loc;
}
@@ -354,21 +407,35 @@
case Token::DIV:
case Token::MOD: {
ExpressionBuilder left, right;
- left.Build(expr->left());
- if (left.cfg() == NULL) {
+ left.Build(expr->left(), NULL);
+ if (left.graph() == NULL) {
BAILOUT("unsupported left subexpression in binop");
}
- right.Build(expr->right());
- if (right.cfg() == NULL) {
+ right.Build(expr->right(), NULL);
+ if (right.graph() == NULL) {
BAILOUT("unsupported right subexpression in binop");
}
- Location* temp = new TempLocation();
- cfg_ = left.cfg();
- cfg_->Concatenate(right.cfg());
- cfg_->Append(new BinaryOpInstr(temp, op, left.value(),
right.value()));
-
- value_ = temp;
+ if (destination_ == NULL) destination_ = new TempLocation();
+
+ graph_ = left.graph();
+ // Insert a move to a fresh temporary if the left value is in a
+ // slot that's assigned on the right.
+ Location* temp = NULL;
+ if (left.value()->is_slot() &&
+
right.assigned_vars()->Contains(SlotLocation::cast(left.value()))) {
+ temp = new TempLocation();
+ graph()->Append(new MoveInstr(temp, left.value()));
+ }
+ graph()->Concatenate(right.graph());
+ graph()->Append(new BinaryOpInstr(destination_, op,
+ temp == NULL ? left.value() : temp,
+ right.value()));
+
+ assigned_vars_ = *left.assigned_vars();
+ assigned_vars()->Union(right.assigned_vars());
+
+ value_ = destination_;
return;
}
@@ -393,18 +460,18 @@
// Macros (temporarily) handling unsupported statement types.
#define BAILOUT(reason) \
do { \
- cfg_ = NULL; \
+ graph_ = NULL; \
return; \
} while (false)
#define CHECK_BAILOUT() \
- if (cfg_ == NULL) { return; } else {}
+ if (graph() == NULL) { return; } else {}
void StatementBuilder::VisitStatements(ZoneList<Statement*>* stmts) {
for (int i = 0, len = stmts->length(); i < len; i++) {
Visit(stmts->at(i));
CHECK_BAILOUT();
- if (!cfg_->has_exit()) return;
+ if (!graph()->has_exit()) return;
}
}
@@ -425,19 +492,12 @@
void StatementBuilder::VisitExpressionStatement(ExpressionStatement* stmt)
{
ExpressionBuilder builder;
- builder.Build(stmt->expression());
- if (builder.cfg() == NULL) {
+ builder.Build(stmt->expression(), CfgGlobals::current()->nowhere());
+ if (builder.graph() == NULL) {
BAILOUT("unsupported expression in expression statement");
}
- // Here's a temporary hack: we bang on the last instruction of the
- // expression (if any) to set its location to Effect.
- if (!builder.cfg()->is_empty()) {
- InstructionBlock* block =
InstructionBlock::cast(builder.cfg()->exit());
- Instruction* instr = block->instructions()->last();
- instr->set_location(CfgGlobals::current()->effect_location());
- }
- cfg_->Append(new PositionInstr(stmt->statement_pos()));
- cfg_->Concatenate(builder.cfg());
+ graph()->Append(new PositionInstr(stmt->statement_pos()));
+ graph()->Concatenate(builder.graph());
}
@@ -463,14 +523,14 @@
void StatementBuilder::VisitReturnStatement(ReturnStatement* stmt) {
ExpressionBuilder builder;
- builder.Build(stmt->expression());
- if (builder.cfg() == NULL) {
+ builder.Build(stmt->expression(), NULL);
+ if (builder.graph() == NULL) {
BAILOUT("unsupported expression in return statement");
}
- cfg_->Append(new PositionInstr(stmt->statement_pos()));
- cfg_->Concatenate(builder.cfg());
- cfg_->AppendReturnInstruction(builder.value());
+ graph()->Append(new PositionInstr(stmt->statement_pos()));
+ graph()->Concatenate(builder.graph());
+ graph()->AppendReturnInstruction(builder.value());
}
@@ -530,8 +590,8 @@
}
-void Effect::Print() {
- PrintF("Effect");
+void Nowhere::Print() {
+ PrintF("Nowhere");
}
@@ -553,15 +613,24 @@
void TempLocation::Print() {
PrintF("Temp(%d)", number());
}
+
+
+void MoveInstr::Print() {
+ PrintF("Move(");
+ location()->Print();
+ PrintF(", ");
+ value_->Print();
+ PrintF(")\n");
+}
void BinaryOpInstr::Print() {
PrintF("BinaryOp(");
- loc_->Print();
- PrintF(", %s, ", Token::Name(op_));
- val0_->Print();
+ location()->Print();
+ PrintF(", %s, ", Token::Name(op()));
+ value0()->Print();
PrintF(", ");
- val1_->Print();
+ value1()->Print();
PrintF(")\n");
}
=======================================
--- /branches/bleeding_edge/src/cfg.h Thu Aug 6 04:14:48 2009
+++ /branches/bleeding_edge/src/cfg.h Fri Aug 7 00:15:31 2009
@@ -43,21 +43,23 @@
// Instructions are described by the following grammar.
//
// <Instruction> ::=
-// BinaryOpInstr <Location> Token::Value <Value> <Value>
-// | ReturnInstr Effect <Value>
+// MoveInstr <Location> <Value>
+// | BinaryOpInstr <Location> Token::Value <Value> <Value>
+// | ReturnInstr Nowhere <Value>
+// | PositionInstr <Int>
//
// Values are trivial expressions:
//
// <Value> ::= Constant | <Location>
//
// Locations are storable values ('lvalues'). They can be slots,
-// compiler-generated temporaries, or the special location 'Effect'
+// compiler-generated temporaries, or the special location 'Nowhere'
// indicating that no value is needed.
//
// <Location> ::=
// SlotLocation Slot::Type <Index>
// | TempLocation
-// | Effect
+// | Nowhere
// Administrative nodes: There are several types of 'administrative' nodes
@@ -95,8 +97,8 @@
// The shared global exit node for all exits from the function.
ExitNode* exit() { return global_exit_; }
- // A singleton effect location.
- Location* effect_location() { return effect_; }
+ // A singleton.
+ Location* nowhere() { return nowhere_; }
#ifdef DEBUG
int next_node_number() { return node_counter_++; }
@@ -107,7 +109,7 @@
static CfgGlobals* top_;
FunctionLiteral* global_fun_;
ExitNode* global_exit_;
- Location* effect_;
+ Location* nowhere_;
#ifdef DEBUG
// Used to number nodes and temporaries when printing.
@@ -119,6 +121,8 @@
};
+class SlotLocation;
+
// Values represent trivial source expressions: ones with no side effects
// and that do not require code to be generated.
class Value : public ZoneObject {
@@ -133,6 +137,9 @@
// True if the value is a compiler-generated temporary location.
virtual bool is_temporary() { return false; }
+
+ // True if the value is a slot location.
+ virtual bool is_slot() { return false; }
// Support for fast-compilation mode:
@@ -142,6 +149,9 @@
// Push the value on the stack.
virtual void Push(MacroAssembler* masm) = 0;
+ // Move the value into a slot location.
+ virtual void MoveToSlot(MacroAssembler* masm, SlotLocation* loc) = 0;
+
#ifdef DEBUG
virtual void Print() = 0;
#endif
@@ -158,6 +168,7 @@
// Support for fast-compilation mode.
void Get(MacroAssembler* masm, Register reg);
void Push(MacroAssembler* masm);
+ void MoveToSlot(MacroAssembler* masm, SlotLocation* loc);
#ifdef DEBUG
void Print();
@@ -173,9 +184,9 @@
public:
virtual ~Location() {}
- // Static factory function returning the singleton effect location.
- static Location* Effect() {
- return CfgGlobals::current()->effect_location();
+ // Static factory function returning the singleton nowhere location.
+ static Location* Nowhere() {
+ return CfgGlobals::current()->nowhere();
}
// Support for fast-compilation mode:
@@ -191,29 +202,34 @@
// temporary it was not allocated to the stack.
virtual void Push(MacroAssembler* masm) = 0;
+ // Emit code to move a value into this location.
+ virtual void Move(MacroAssembler* masm, Value* value) = 0;
+
#ifdef DEBUG
virtual void Print() = 0;
#endif
};
-// Effect is a special (singleton) location that indicates the value of a
+// Nowhere is a special (singleton) location that indicates the value of a
// computation is not needed (though its side effects are).
-class Effect : public Location {
+class Nowhere : public Location {
public:
- // We should not try to emit code to read Effect.
+ // We should not try to emit code to read Nowhere.
void Get(MacroAssembler* masm, Register reg) { UNREACHABLE(); }
void Push(MacroAssembler* masm) { UNREACHABLE(); }
-
- // Setting Effect is ignored.
+ void MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
UNREACHABLE(); }
+
+ // Setting Nowhere is ignored.
void Set(MacroAssembler* masm, Register reg) {}
+ void Move(MacroAssembler* masm, Value* value) {}
#ifdef DEBUG
void Print();
#endif
private:
- Effect() {}
+ Nowhere() {}
friend class CfgGlobals;
};
@@ -224,15 +240,26 @@
class SlotLocation : public Location {
public:
SlotLocation(Slot::Type type, int index) : type_(type), index_(index) {}
+
+ // Cast accessor.
+ static SlotLocation* cast(Value* value) {
+ ASSERT(value->is_slot());
+ return reinterpret_cast<SlotLocation*>(value);
+ }
// Accessors.
Slot::Type type() { return type_; }
int index() { return index_; }
+
+ // Predicates.
+ bool is_slot() { return true; }
// Support for fast-compilation mode.
void Get(MacroAssembler* masm, Register reg);
void Set(MacroAssembler* masm, Register reg);
void Push(MacroAssembler* masm);
+ void Move(MacroAssembler* masm, Value* value);
+ void MoveToSlot(MacroAssembler* masm, SlotLocation* loc);
#ifdef DEBUG
void Print();
@@ -252,21 +279,21 @@
public:
// Fast-compilation mode allocation decisions.
enum Where {
- NOWHERE, // Not yet allocated.
- ACCUMULATOR, // Allocated to the dedicated accumulator register.
- STACK // " " " " stack.
+ NOT_ALLOCATED, // Not yet allocated.
+ ACCUMULATOR, // Allocated to the dedicated accumulator register.
+ STACK // " " " " stack.
};
- TempLocation() : where_(NOWHERE) {
+ TempLocation() : where_(NOT_ALLOCATED) {
#ifdef DEBUG
number_ = -1;
#endif
}
// Cast accessor.
- static TempLocation* cast(Location* loc) {
- ASSERT(loc->is_temporary());
- return reinterpret_cast<TempLocation*>(loc);
+ static TempLocation* cast(Value* value) {
+ ASSERT(value->is_temporary());
+ return reinterpret_cast<TempLocation*>(value);
}
// Accessors.
@@ -281,6 +308,8 @@
void Get(MacroAssembler* masm, Register reg);
void Set(MacroAssembler* masm, Register reg);
void Push(MacroAssembler* masm);
+ void Move(MacroAssembler* masm, Value* value);
+ void MoveToSlot(MacroAssembler* masm, SlotLocation* loc);
#ifdef DEBUG
int number() {
@@ -306,16 +335,16 @@
class Instruction : public ZoneObject {
public:
// Every instruction has a location where its result is stored (which may
- // be Effect, the default).
- Instruction() : loc_(CfgGlobals::current()->effect_location()) {}
-
- explicit Instruction(Location* loc) : loc_(loc) {}
+ // be Nowhere, the default).
+ Instruction() : location_(CfgGlobals::current()->nowhere()) {}
+
+ explicit Instruction(Location* location) : location_(location) {}
virtual ~Instruction() {}
// Accessors.
- Location* location() { return loc_; }
- void set_location(Location* loc) { loc_ = loc; }
+ Location* location() { return location_; }
+ void set_location(Location* location) { location_ = location; }
// Support for fast-compilation mode:
@@ -332,7 +361,7 @@
#endif
protected:
- Location* loc_;
+ Location* location_;
};
@@ -360,13 +389,39 @@
};
+// Move a value to a location.
+class MoveInstr : public Instruction {
+ public:
+ MoveInstr(Location* loc, Value* value) : Instruction(loc), value_(value)
{}
+
+ // Accessors.
+ Value* value() { return value_; }
+
+ // Support for fast-compilation mode.
+ void Compile(MacroAssembler* masm);
+ void FastAllocate(TempLocation* temp);
+
+#ifdef DEBUG
+ void Print();
+#endif
+
+ private:
+ Value* value_;
+};
+
+
// Perform a (non-short-circuited) binary operation on a pair of values,
// leaving the result in a location.
class BinaryOpInstr : public Instruction {
public:
- BinaryOpInstr(Location* loc, Token::Value op, Value* val0, Value* val1)
- : Instruction(loc), op_(op), val0_(val0), val1_(val1) {
- }
+ BinaryOpInstr(Location* loc, Token::Value op, Value* value0, Value*
value1)
+ : Instruction(loc), op_(op), value0_(value0), value1_(value1) {
+ }
+
+ // Accessors.
+ Token::Value op() { return op_; }
+ Value* value0() { return value0_; }
+ Value* value1() { return value1_; }
// Support for fast-compilation mode.
void Compile(MacroAssembler* masm);
@@ -378,8 +433,8 @@
private:
Token::Value op_;
- Value* val0_;
- Value* val1_;
+ Value* value0_;
+ Value* value1_;
};
@@ -390,7 +445,6 @@
// successor is the global exit node for the current function.
class ReturnInstr : public Instruction {
public:
- // Location is always Effect.
explicit ReturnInstr(Value* value) : value_(value) {}
virtual ~ReturnInstr() {}
@@ -605,6 +659,52 @@
};
+// An implementation of a set of locations (currently slot locations).
+class LocationSet BASE_EMBEDDED {
+ public:
+ // Construct an empty location set.
+ LocationSet() : parameters_(0), locals_(0) {}
+
+ // Raw accessors.
+ uintptr_t parameters() { return parameters_; }
+ uintptr_t locals() { return locals_; }
+
+ // Insert an element.
+ void AddElement(SlotLocation* location) {
+ if (location->type() == Slot::PARAMETER) {
+ // Parameter indexes begin with -1 ('this').
+ ASSERT(location->index() < kPointerSize - 1);
+ parameters_ |= (1 << (location->index() + 1));
+ } else {
+ ASSERT(location->type() == Slot::LOCAL);
+ ASSERT(location->index() < kPointerSize);
+ locals_ |= (1 << location->index());
+ }
+ }
+
+ // (Destructively) compute the union with another set.
+ void Union(LocationSet* other) {
+ parameters_ |= other->parameters();
+ locals_ |= other->locals();
+ }
+
+ bool Contains(SlotLocation* location) {
+ if (location->type() == Slot::PARAMETER) {
+ ASSERT(location->index() < kPointerSize - 1);
+ return (parameters_ & (1 << (location->index() + 1)));
+ } else {
+ ASSERT(location->type() == Slot::LOCAL);
+ ASSERT(location->index() < kPointerSize);
+ return (locals_ & (1 << location->index()));
+ }
+ }
+
+ private:
+ uintptr_t parameters_;
+ uintptr_t locals_;
+};
+
+
// An ExpressionBuilder traverses an expression and returns an open CFG
// fragment (currently a possibly empty list of instructions represented by
// a singleton instruction block) and the expression's value.
@@ -612,15 +712,23 @@
// Failure is to build the CFG is indicated by a NULL CFG.
class ExpressionBuilder : public AstVisitor {
public:
- ExpressionBuilder() : value_(NULL), cfg_(NULL) {}
+ ExpressionBuilder() : value_(NULL), graph_(NULL), destination_(NULL) {}
// Result accessors.
Value* value() { return value_; }
- Cfg* cfg() { return cfg_; }
-
- void Build(Expression* expr) {
+ Cfg* graph() { return graph_; }
+ LocationSet* assigned_vars() { return &assigned_vars_; }
+
+ // Build the cfg for an expression and remember its value. The
+ // destination is a 'hint' where the value should go which may be
ignored.
+ // NULL is used to indicate no preference.
+ //
+ // Concretely, if the expression needs to generate a temporary for its
+ // value, it should use the passed destination or generate one if NULL.
+ void Build(Expression* expr, Location* destination) {
value_ = NULL;
- cfg_ = new Cfg();
+ graph_ = new Cfg();
+ destination_ = destination;
Visit(expr);
}
@@ -630,8 +738,13 @@
#undef DECLARE_VISIT
private:
+ // State for the visitor. Output parameters.
Value* value_;
- Cfg* cfg_;
+ Cfg* graph_;
+ LocationSet assigned_vars_;
+
+ // Input parameters.
+ Location* destination_;
};
@@ -640,9 +753,9 @@
// accumulator.
class StatementBuilder : public AstVisitor {
public:
- StatementBuilder() : cfg_(new Cfg()) {}
-
- Cfg* cfg() { return cfg_; }
+ StatementBuilder() : graph_(new Cfg()) {}
+
+ Cfg* graph() { return graph_; }
void VisitStatements(ZoneList<Statement*>* stmts);
@@ -652,7 +765,7 @@
#undef DECLARE_VISIT
private:
- Cfg* cfg_;
+ Cfg* graph_;
};
=======================================
--- /branches/bleeding_edge/src/ia32/cfg-ia32.cc Thu Aug 6 04:14:48 2009
+++ /branches/bleeding_edge/src/ia32/cfg-ia32.cc Fri Aug 7 00:15:31 2009
@@ -119,30 +119,35 @@
__ RecordPosition(pos_);
}
}
+
+
+void MoveInstr::Compile(MacroAssembler* masm) {
+ location()->Move(masm, value());
+}
void BinaryOpInstr::Compile(MacroAssembler* masm) {
// The right-hand value should not be on the stack---if it is a
// compiler-generated temporary it is in the accumulator.
- ASSERT(!val1_->is_on_stack());
+ ASSERT(!value1()->is_on_stack());
Comment cmnt(masm, "[ BinaryOpInstr");
// We can overwrite one of the operands if it is a temporary.
OverwriteMode mode = NO_OVERWRITE;
- if (val0_->is_temporary()) {
+ if (value0()->is_temporary()) {
mode = OVERWRITE_LEFT;
- } else if (val1_->is_temporary()) {
+ } else if (value1()->is_temporary()) {
mode = OVERWRITE_RIGHT;
}
// Push both operands and call the specialized stub.
- if (!val0_->is_on_stack()) {
- val0_->Push(masm);
- }
- val1_->Push(masm);
- GenericBinaryOpStub stub(op_, mode, SMI_CODE_IN_STUB);
+ if (!value0()->is_on_stack()) {
+ value0()->Push(masm);
+ }
+ value1()->Push(masm);
+ GenericBinaryOpStub stub(op(), mode, SMI_CODE_IN_STUB);
__ CallStub(&stub);
- loc_->Set(masm, eax);
+ location()->Set(masm, eax);
}
@@ -179,6 +184,11 @@
return Operand(eax);
}
}
+
+
+void Constant::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ __ mov(ToOperand(loc), Immediate(handle_));
+}
void SlotLocation::Get(MacroAssembler* masm, Register reg) {
@@ -194,6 +204,19 @@
void SlotLocation::Push(MacroAssembler* masm) {
__ push(ToOperand(this));
}
+
+
+void SlotLocation::Move(MacroAssembler* masm, Value* value) {
+ // We dispatch to the value because in some cases (temp or constant)
+ // we can use a single instruction.
+ value->MoveToSlot(masm, this);
+}
+
+void SlotLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ // The accumulator is not live across a MoveInstr.
+ __ mov(eax, ToOperand(this));
+ __ mov(ToOperand(loc), eax);
+}
void TempLocation::Get(MacroAssembler* masm, Register reg) {
@@ -204,9 +227,8 @@
case STACK:
__ pop(reg);
break;
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
- break;
}
}
@@ -219,9 +241,8 @@
case STACK:
__ push(reg);
break;
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
- break;
}
}
@@ -232,9 +253,36 @@
__ push(eax);
break;
case STACK:
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
+ }
+}
+
+
+void TempLocation::Move(MacroAssembler* masm, Value* value) {
+ switch (where_) {
+ case ACCUMULATOR:
+ value->Get(masm, eax);
break;
+ case STACK:
+ value->Push(masm);
+ break;
+ case NOT_ALLOCATED:
+ UNREACHABLE();
+ }
+}
+
+
+void TempLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ switch (where_) {
+ case ACCUMULATOR:
+ __ mov(ToOperand(loc), eax);
+ break;
+ case STACK:
+ __ pop(ToOperand(loc));
+ break;
+ case NOT_ALLOCATED:
+ UNREACHABLE();
}
}
=======================================
--- /branches/bleeding_edge/src/x64/cfg-x64.cc Thu Aug 6 04:14:48 2009
+++ /branches/bleeding_edge/src/x64/cfg-x64.cc Fri Aug 7 00:15:31 2009
@@ -129,30 +129,35 @@
__ RecordPosition(pos_);
}
}
+
+
+void MoveInstr::Compile(MacroAssembler* masm) {
+ location()->Move(masm, value());
+}
void BinaryOpInstr::Compile(MacroAssembler* masm) {
// The right-hand value should not be on the stack---if it is a
// compiler-generated temporary it is in the accumulator.
- ASSERT(!val1_->is_on_stack());
+ ASSERT(!value1()->is_on_stack());
Comment cmnt(masm, "[ BinaryOpInstr");
// We can overwrite one of the operands if it is a temporary.
OverwriteMode mode = NO_OVERWRITE;
- if (val0_->is_temporary()) {
+ if (value0()->is_temporary()) {
mode = OVERWRITE_LEFT;
- } else if (val1_->is_temporary()) {
+ } else if (value1()->is_temporary()) {
mode = OVERWRITE_RIGHT;
}
// Push both operands and call the specialized stub.
- if (!val0_->is_on_stack()) {
- val0_->Push(masm);
- }
- val1_->Push(masm);
- GenericBinaryOpStub stub(op_, mode, SMI_CODE_IN_STUB);
+ if (!value0()->is_on_stack()) {
+ value0()->Push(masm);
+ }
+ value1()->Push(masm);
+ GenericBinaryOpStub stub(op(), mode, SMI_CODE_IN_STUB);
__ CallStub(&stub);
- loc_->Set(masm, rax);
+ location()->Set(masm, rax);
}
@@ -189,6 +194,11 @@
return Operand(rax, 0);
}
}
+
+
+void Constant::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ __ Move(ToOperand(loc), handle_);
+}
void SlotLocation::Get(MacroAssembler* masm, Register reg) {
@@ -199,6 +209,19 @@
void SlotLocation::Set(MacroAssembler* masm, Register reg) {
__ movq(ToOperand(this), reg);
}
+
+
+void SlotLocation::Move(MacroAssembler* masm, Value* value) {
+ // We dispatch to the value because in some cases (temp or constant) we
+ // can use special instruction sequences.
+ value->MoveToSlot(masm, this);
+}
+
+
+void SlotLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ __ movq(kScratchRegister, ToOperand(this));
+ __ movq(ToOperand(loc), kScratchRegister);
+}
void SlotLocation::Push(MacroAssembler* masm) {
@@ -214,9 +237,8 @@
case STACK:
__ pop(reg);
break;
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
- break;
}
}
@@ -229,9 +251,8 @@
case STACK:
__ push(reg);
break;
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
- break;
}
}
@@ -242,9 +263,36 @@
__ push(rax);
break;
case STACK:
- case NOWHERE:
+ case NOT_ALLOCATED:
UNREACHABLE();
+ }
+}
+
+
+void TempLocation::Move(MacroAssembler* masm, Value* value) {
+ switch (where_) {
+ case ACCUMULATOR:
+ value->Get(masm, rax);
break;
+ case STACK:
+ value->Push(masm);
+ break;
+ case NOT_ALLOCATED:
+ UNREACHABLE();
+ }
+}
+
+
+void TempLocation::MoveToSlot(MacroAssembler* masm, SlotLocation* loc) {
+ switch (where_) {
+ case ACCUMULATOR:
+ __ movq(ToOperand(loc), rax);
+ break;
+ case STACK:
+ __ pop(ToOperand(loc));
+ break;
+ case NOT_ALLOCATED:
+ UNREACHABLE();
}
}
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---