Commit b6009051 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

ARM: Track Smis on top 4 stack positions and Smi loop variables.

Improve code generation for known smis and suspected Smis.
Review URL: http://codereview.chromium.org/2452002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4783 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5b7e77ac
This diff is collapsed.
......@@ -43,6 +43,7 @@ class RegisterFile;
enum InitState { CONST_INIT, NOT_CONST_INIT };
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
enum GenerateInlineSmi { DONT_GENERATE_INLINE_SMI, GENERATE_INLINE_SMI };
// -------------------------------------------------------------------------
......@@ -129,24 +130,55 @@ class CodeGenState BASE_EMBEDDED {
// leaves the code generator with a NULL state.
explicit CodeGenState(CodeGenerator* owner);
// Create a code generator state based on a code generator's current
// state. The new state has its own pair of branch labels.
CodeGenState(CodeGenerator* owner,
JumpTarget* true_target,
JumpTarget* false_target);
// Destroy a code generator state and restore the owning code generator's
// previous state.
~CodeGenState();
virtual ~CodeGenState();
virtual JumpTarget* true_target() const { return NULL; }
virtual JumpTarget* false_target() const { return NULL; }
JumpTarget* true_target() const { return true_target_; }
JumpTarget* false_target() const { return false_target_; }
protected:
inline CodeGenerator* owner() { return owner_; }
inline CodeGenState* previous() const { return previous_; }
private:
CodeGenerator* owner_;
CodeGenState* previous_;
};
class ConditionCodeGenState : public CodeGenState {
public:
// Create a code generator state based on a code generator's current
// state. The new state has its own pair of branch labels.
ConditionCodeGenState(CodeGenerator* owner,
JumpTarget* true_target,
JumpTarget* false_target);
virtual JumpTarget* true_target() const { return true_target_; }
virtual JumpTarget* false_target() const { return false_target_; }
private:
JumpTarget* true_target_;
JumpTarget* false_target_;
CodeGenState* previous_;
};
class TypeInfoCodeGenState : public CodeGenState {
public:
TypeInfoCodeGenState(CodeGenerator* owner,
Slot* slot_number,
TypeInfo info);
~TypeInfoCodeGenState();
virtual JumpTarget* true_target() const { return previous()->true_target(); }
virtual JumpTarget* false_target() const {
return previous()->false_target();
}
private:
Slot* slot_;
TypeInfo old_type_info_;
};
......@@ -216,6 +248,23 @@ class CodeGenerator: public AstVisitor {
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
TypeInfo type_info(Slot* slot) {
int index = NumberOfSlot(slot);
if (index == kInvalidSlotNumber) return TypeInfo::Unknown();
return (*type_info_)[index];
}
TypeInfo set_type_info(Slot* slot, TypeInfo info) {
int index = NumberOfSlot(slot);
ASSERT(index >= kInvalidSlotNumber);
if (index != kInvalidSlotNumber) {
TypeInfo previous_value = (*type_info_)[index];
(*type_info_)[index] = info;
return previous_value;
}
return TypeInfo::Unknown();
}
void AddDeferred(DeferredCode* code) { deferred_.Add(code); }
static const int kUnknownIntValue = -1;
......@@ -225,7 +274,7 @@ class CodeGenerator: public AstVisitor {
static int InlineRuntimeCallArgumentsCount(Handle<String> name);
// Constants related to patching of inlined load/store.
static const int kInlinedKeyedLoadInstructionsAfterPatch = 19;
static const int kInlinedKeyedLoadInstructionsAfterPatch = 17;
static const int kInlinedKeyedStoreInstructionsAfterPatch = 5;
private:
......@@ -239,6 +288,10 @@ class CodeGenerator: public AstVisitor {
// Generating deferred code.
void ProcessDeferred();
static const int kInvalidSlotNumber = -1;
int NumberOfSlot(Slot* slot);
// State
bool has_cc() const { return cc_reg_ != al; }
JumpTarget* true_target() const { return state_->true_target(); }
......@@ -351,10 +404,8 @@ class CodeGenerator: public AstVisitor {
void GenericBinaryOperation(Token::Value op,
OverwriteMode overwrite_mode,
GenerateInlineSmi inline_smi,
int known_rhs = kUnknownIntValue);
void VirtualFrameBinaryOperation(Token::Value op,
OverwriteMode overwrite_mode,
int known_rhs = kUnknownIntValue);
void Comparison(Condition cc,
Expression* left,
Expression* right,
......@@ -511,6 +562,8 @@ class CodeGenerator: public AstVisitor {
CodeGenState* state_;
int loop_nesting_;
Vector<TypeInfo>* type_info_;
// Jump targets
BreakTarget function_return_;
......
......@@ -50,6 +50,11 @@ void JumpTarget::DoJump() {
ASSERT(cgen()->HasValidEntryRegisters());
if (entry_frame_set_) {
if (entry_label_.is_bound()) {
// If we already bound and generated code at the destination then it
// is too late to ask for less optimistic type assumptions.
ASSERT(entry_frame_.IsCompatibleWith(cgen()->frame()));
}
// There already a frame expectation at the target.
cgen()->frame()->MergeTo(&entry_frame_);
cgen()->DeleteFrame();
......@@ -67,8 +72,12 @@ void JumpTarget::DoBranch(Condition cc, Hint ignored) {
ASSERT(cgen()->has_valid_frame());
if (entry_frame_set_) {
// Backward branch. We have an expected frame to merge to on the
// backward edge.
if (entry_label_.is_bound()) {
// If we already bound and generated code at the destination then it
// is too late to ask for less optimistic type assumptions.
ASSERT(entry_frame_.IsCompatibleWith(cgen()->frame()));
}
// We have an expected frame to merge to on the backward edge.
cgen()->frame()->MergeTo(&entry_frame_, cc);
} else {
// Clone the current frame to use as the expected one at the target.
......
......@@ -48,6 +48,12 @@ MemOperand VirtualFrame::Receiver() {
return ParameterAt(-1);
}
void VirtualFrame::Forget(int count) {
SpillAll();
LowerHeight(count);
}
} } // namespace v8::internal
#endif // V8_VIRTUAL_FRAME_ARM_INL_H_
......@@ -43,7 +43,7 @@ void VirtualFrame::PopToR1R0() {
// Shuffle things around so the top of stack is in r0 and r1.
MergeTOSTo(R0_R1_TOS);
// Pop the two registers off the stack so they are detached from the frame.
element_count_ -= 2;
LowerHeight(2);
top_of_stack_state_ = NO_TOS_REGISTERS;
}
......@@ -52,7 +52,7 @@ void VirtualFrame::PopToR1() {
// Shuffle things around so the top of stack is only in r1.
MergeTOSTo(R1_TOS);
// Pop the register off the stack so it is detached from the frame.
element_count_ -= 1;
LowerHeight(1);
top_of_stack_state_ = NO_TOS_REGISTERS;
}
......@@ -61,13 +61,22 @@ void VirtualFrame::PopToR0() {
// Shuffle things around so the top of stack only in r0.
MergeTOSTo(R0_TOS);
// Pop the register off the stack so it is detached from the frame.
element_count_ -= 1;
LowerHeight(1);
top_of_stack_state_ = NO_TOS_REGISTERS;
}
void VirtualFrame::MergeTo(const VirtualFrame* expected, Condition cond) {
if (Equals(expected)) return;
ASSERT(expected->IsCompatibleWith(this));
MergeTOSTo(expected->top_of_stack_state_, cond);
ASSERT(register_allocation_map_ == expected->register_allocation_map_);
}
void VirtualFrame::MergeTo(VirtualFrame* expected, Condition cond) {
if (Equals(expected)) return;
expected->tos_known_smi_map_ &= tos_known_smi_map_;
MergeTOSTo(expected->top_of_stack_state_, cond);
ASSERT(register_allocation_map_ == expected->register_allocation_map_);
}
......@@ -420,7 +429,7 @@ void VirtualFrame::Drop(int count) {
}
if (count == 0) return;
__ add(sp, sp, Operand(count * kPointerSize));
element_count_ -= count;
LowerHeight(count);
}
......@@ -430,7 +439,7 @@ void VirtualFrame::Pop() {
} else {
top_of_stack_state_ = kStateAfterPop[top_of_stack_state_];
}
element_count_--;
LowerHeight(1);
}
......@@ -442,7 +451,7 @@ void VirtualFrame::EmitPop(Register reg) {
__ mov(reg, kTopRegister[top_of_stack_state_]);
top_of_stack_state_ = kStateAfterPop[top_of_stack_state_];
}
element_count_--;
LowerHeight(1);
}
......@@ -550,7 +559,7 @@ void VirtualFrame::Dup() {
UNREACHABLE();
}
}
element_count_++;
RaiseHeight(1, tos_known_smi_map_ & 1);
}
......@@ -589,7 +598,7 @@ void VirtualFrame::Dup2() {
UNREACHABLE();
}
}
element_count_ += 2;
RaiseHeight(2, tos_known_smi_map_ & 3);
}
......@@ -597,7 +606,7 @@ Register VirtualFrame::PopToRegister(Register but_not_to_this_one) {
ASSERT(but_not_to_this_one.is(r0) ||
but_not_to_this_one.is(r1) ||
but_not_to_this_one.is(no_reg));
element_count_--;
LowerHeight(1);
if (top_of_stack_state_ == NO_TOS_REGISTERS) {
if (but_not_to_this_one.is(r0)) {
__ pop(r1);
......@@ -625,8 +634,8 @@ void VirtualFrame::EnsureOneFreeTOSRegister() {
}
void VirtualFrame::EmitPush(Register reg) {
element_count_++;
void VirtualFrame::EmitPush(Register reg, TypeInfo info) {
RaiseHeight(1, info.IsSmi() ? 1 : 0);
if (reg.is(cp)) {
// If we are pushing cp then we are about to make a call and things have to
// be pushed to the physical stack. There's nothing to be gained my moving
......@@ -659,6 +668,9 @@ void VirtualFrame::EmitPush(Register reg) {
void VirtualFrame::SetElementAt(Register reg, int this_far_down) {
if (this_far_down < kTOSKnownSmiMapSize) {
tos_known_smi_map_ &= ~(1 << this_far_down);
}
if (this_far_down == 0) {
Pop();
Register dest = GetTOSRegister();
......@@ -699,8 +711,8 @@ Register VirtualFrame::GetTOSRegister() {
}
void VirtualFrame::EmitPush(Operand operand) {
element_count_++;
void VirtualFrame::EmitPush(Operand operand, TypeInfo info) {
RaiseHeight(1, info.IsSmi() ? 1 : 0);
if (SpilledScope::is_spilled()) {
__ mov(r0, operand);
__ push(r0);
......@@ -712,8 +724,8 @@ void VirtualFrame::EmitPush(Operand operand) {
}
void VirtualFrame::EmitPush(MemOperand operand) {
element_count_++;
void VirtualFrame::EmitPush(MemOperand operand, TypeInfo info) {
RaiseHeight(1, info.IsSmi() ? 1 : 0);
if (SpilledScope::is_spilled()) {
__ ldr(r0, operand);
__ push(r0);
......@@ -726,7 +738,7 @@ void VirtualFrame::EmitPush(MemOperand operand) {
void VirtualFrame::EmitPushRoot(Heap::RootListIndex index) {
element_count_++;
RaiseHeight(1, 0);
if (SpilledScope::is_spilled()) {
__ LoadRoot(r0, index);
__ push(r0);
......
......@@ -154,10 +154,7 @@ class VirtualFrame : public ZoneObject {
// Forget elements from the top of the frame to match an actual frame (eg,
// the frame after a runtime call). No code is emitted except to bring the
// frame to a spilled state.
void Forget(int count) {
SpillAll();
element_count_ -= count;
}
void Forget(int count);
// Spill all values from the frame to memory.
void SpillAll();
......@@ -184,8 +181,14 @@ class VirtualFrame : public ZoneObject {
// Make this virtual frame have a state identical to an expected virtual
// frame. As a side effect, code may be emitted to make this frame match
// the expected one.
void MergeTo(VirtualFrame* expected, Condition cond = al);
void MergeTo(const VirtualFrame* expected, Condition cond = al);
// Checks whether this frame can be branched to by the other frame.
bool IsCompatibleWith(const VirtualFrame* other) const {
return (tos_known_smi_map_ & (~other->tos_known_smi_map_)) == 0;
}
// Detach a frame from its code generator, perhaps temporarily. This
// tells the register allocator that it is free to use frame-internal
// registers. Used when the code generator's frame is switched from this
......@@ -234,6 +237,11 @@ class VirtualFrame : public ZoneObject {
return MemOperand(sp, adjusted_index * kPointerSize);
}
bool KnownSmiAt(int index) {
if (index >= kTOSKnownSmiMapSize) return false;
return (tos_known_smi_map_ & (1 << index)) != 0;
}
// A frame-allocated local as an assembly operand.
inline MemOperand LocalAt(int index);
......@@ -352,9 +360,9 @@ class VirtualFrame : public ZoneObject {
// Push an element on top of the expression stack and emit a
// corresponding push instruction.
void EmitPush(Register reg);
void EmitPush(Operand operand);
void EmitPush(MemOperand operand);
void EmitPush(Register reg, TypeInfo type_info = TypeInfo::Unknown());
void EmitPush(Operand operand, TypeInfo type_info = TypeInfo::Unknown());
void EmitPush(MemOperand operand, TypeInfo type_info = TypeInfo::Unknown());
void EmitPushRoot(Heap::RootListIndex index);
// Overwrite the nth thing on the stack. If the nth position is in a
......@@ -419,6 +427,8 @@ class VirtualFrame : public ZoneObject {
int element_count_;
TopOfStack top_of_stack_state_:3;
int register_allocation_map_:kNumberOfAllocatedRegisters;
static const int kTOSKnownSmiMapSize = 4;
unsigned tos_known_smi_map_:kTOSKnownSmiMapSize;
// The index of the element that is at the processor's stack pointer
// (the sp register). For now since everything is in memory it is given
......@@ -473,6 +483,25 @@ class VirtualFrame : public ZoneObject {
inline bool Equals(const VirtualFrame* other);
inline void LowerHeight(int count) {
element_count_ -= count;
if (count >= kTOSKnownSmiMapSize) {
tos_known_smi_map_ = 0;
} else {
tos_known_smi_map_ >>= count;
}
}
inline void RaiseHeight(int count, unsigned known_smi_map = 0) {
ASSERT(known_smi_map < (1u << count));
element_count_ += count;
if (count >= kTOSKnownSmiMapSize) {
tos_known_smi_map_ = known_smi_map;
} else {
tos_known_smi_map_ = ((tos_known_smi_map_ << count) | known_smi_map);
}
}
friend class JumpTarget;
};
......
......@@ -318,6 +318,9 @@ Variable* AssignedVariablesAnalyzer::FindSmiLoopVariable(ForStatement* stmt) {
Variable* loop_var = init->target()->AsVariableProxy()->AsVariable();
if (loop_var == NULL || !loop_var->IsStackAllocated()) return NULL;
// Don't try to get clever with const or dynamic variables.
if (loop_var->mode() != Variable::VAR) return NULL;
// The initial value has to be a smi.
Literal* init_lit = init->value()->AsLiteral();
if (init_lit == NULL || !init_lit->handle()->IsSmi()) return NULL;
......
......@@ -47,7 +47,7 @@ namespace internal {
class TypeInfo {
public:
TypeInfo() { }
TypeInfo() : type_(kUnknownType) { }
static inline TypeInfo Unknown();
// We know it's a primitive type.
......
......@@ -42,7 +42,8 @@ namespace internal {
VirtualFrame::VirtualFrame(InvalidVirtualFrameInitializer* dummy)
: element_count_(0),
top_of_stack_state_(NO_TOS_REGISTERS),
register_allocation_map_(0) { }
register_allocation_map_(0),
tos_known_smi_map_(0) { }
// On entry to a function, the virtual frame already contains the receiver,
......@@ -50,20 +51,23 @@ VirtualFrame::VirtualFrame(InvalidVirtualFrameInitializer* dummy)
VirtualFrame::VirtualFrame()
: element_count_(parameter_count() + 2),
top_of_stack_state_(NO_TOS_REGISTERS),
register_allocation_map_(0) { }
register_allocation_map_(0),
tos_known_smi_map_(0) { }
// When cloned, a frame is a deep copy of the original.
VirtualFrame::VirtualFrame(VirtualFrame* original)
: element_count_(original->element_count()),
top_of_stack_state_(original->top_of_stack_state_),
register_allocation_map_(original->register_allocation_map_) { }
register_allocation_map_(original->register_allocation_map_),
tos_known_smi_map_(0) { }
bool VirtualFrame::Equals(const VirtualFrame* other) {
ASSERT(element_count() == other->element_count());
if (top_of_stack_state_ != other->top_of_stack_state_) return false;
if (register_allocation_map_ != other->register_allocation_map_) return false;
if (tos_known_smi_map_ != other->tos_known_smi_map_) return false;
return true;
}
......
......@@ -36,7 +36,7 @@ namespace internal {
void VirtualFrame::Adjust(int count) {
ASSERT(count >= 0);
element_count_ += count;
RaiseHeight(count, 0);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment