Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(510)

Unified Diff: src/arm/virtual-frame-arm.h

Issue 1604002: Simple register allocation for ARM. Only top of expression... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/arm/virtual-frame-arm.h
===================================================================
--- src/arm/virtual-frame-arm.h (revision 4341)
+++ src/arm/virtual-frame-arm.h (working copy)
@@ -45,16 +45,71 @@
class VirtualFrame : public ZoneObject {
public:
+ class RegisterAllocationScope;
// A utility class to introduce a scope where the virtual frame is
// expected to remain spilled. The constructor spills the code
- // generator's current frame, but no attempt is made to require it
- // to stay spilled. It is intended as documentation while the code
- // generator is being transformed.
+ // generator's current frame, and keeps it spilled.
class SpilledScope BASE_EMBEDDED {
public:
- SpilledScope() {}
+ inline SpilledScope(VirtualFrame* frame)
Kasper Lund 2010/04/07 08:09:50 Why put inline here? It needs to be explicit thoug
Erik Corry 2010/04/07 12:49:17 Done.
+ : old_is_spilled_(is_spilled_) {
+ if (frame != NULL) {
+ if (!is_spilled_) {
+ frame->SpillAll();
+ } else {
+ frame->AssertIsSpilled();
+ }
+ }
+ is_spilled_ = true;
+ }
+ inline ~SpilledScope() {
Kasper Lund 2010/04/07 08:09:50 Why put inline here?
Erik Corry 2010/04/07 12:49:17 Done.
+ is_spilled_ = old_is_spilled_;
+ }
+ static inline bool is_spilled() { return is_spilled_; }
Kasper Lund 2010/04/07 08:09:50 Why put inline here?
Erik Corry 2010/04/07 12:49:17 Done.
+
+ private:
+ static bool is_spilled_;
+ int old_is_spilled_;
+
+ SpilledScope() { }
+
+ friend class RegisterAllocationScope;
};
+ class RegisterAllocationScope BASE_EMBEDDED {
+ public:
+ // A utility class to introduce a scope where the virtual frame
+ // is not spilled, ie where register allocation occurs. Eventually
Søren Thygesen Gjesse 2010/04/07 07:53:37 Dot after ie?
Erik Corry 2010/04/07 12:49:17 Done.
+ // when RegisterAllocationScope is ubiquitous it can be removed
+ // along with the (by then unused) SpilledScope class.
+ explicit RegisterAllocationScope(CodeGenerator* cgen)
+ : cgen_(cgen),
+ old_is_spilled_(SpilledScope::is_spilled_) {
+ SpilledScope::is_spilled_ = false;
+ if (old_is_spilled_) {
+ VirtualFrame* frame = cgen->frame();
+ if (frame != NULL) {
+ frame->AssertIsSpilled();
+ }
+ }
+ }
+ ~RegisterAllocationScope() {
+ SpilledScope::is_spilled_ = old_is_spilled_;
+ if (old_is_spilled_) {
+ VirtualFrame* frame = cgen_->frame();
+ if (frame != NULL) {
+ frame->SpillAll();
+ }
+ }
+ }
+
+ private:
+ CodeGenerator* cgen_;
+ bool old_is_spilled_;
+
+ RegisterAllocationScope() { }
+ };
+
// An illegal index into the virtual frame.
static const int kIllegalIndex = -1;
@@ -75,27 +130,38 @@
return element_count() - expression_base_index();
}
- int register_location(int num) {
- ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
- return register_locations_[num];
- }
-
- int register_location(Register reg) {
- return register_locations_[RegisterAllocator::ToNumber(reg)];
- }
-
- void set_register_location(Register reg, int index) {
- register_locations_[RegisterAllocator::ToNumber(reg)] = index;
- }
-
bool is_used(int num) {
- ASSERT(num >= 0 && num < RegisterAllocator::kNumRegisters);
- return register_locations_[num] != kIllegalIndex;
+ switch (num) {
+ case 0: { // r0.
+ return kR0InUse[top_of_stack_state_];
+ }
+ case 1: { // r1.
+ return kR1InUse[top_of_stack_state_];
+ }
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6: { // r2 to r6.
+ ASSERT(num - kFirstAllocatedRegister < kNumberOfAllocatedRegisters);
+ ASSERT(num >= kFirstAllocatedRegister);
+ if ((register_allocation_map_ &
+ (1 << (num - kFirstAllocatedRegister))) == 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ default: {
+ ASSERT(num < kFirstAllocatedRegister ||
+ num >= kFirstAllocatedRegister + kNumberOfAllocatedRegisters);
+ return false;
+ }
+ }
}
bool is_used(Register reg) {
- return register_locations_[RegisterAllocator::ToNumber(reg)]
- != kIllegalIndex;
+ return is_used(RegisterAllocator::ToNumber(reg));
}
// Add extra in-memory elements to the top of the frame to match an actual
@@ -104,39 +170,55 @@
void Adjust(int count);
// Forget elements from the top of the frame to match an actual frame (eg,
- // the frame after a runtime call). No code is emitted.
+ // the frame after a runtime call). No code is emitted except to bring the
+ // frame to a spilled state.
void Forget(int count) {
- ASSERT(count >= 0);
- ASSERT(stack_pointer_ == element_count() - 1);
- stack_pointer_ -= count;
- // On ARM, all elements are in memory, so there is no extra bookkeeping
- // (registers, copies, etc.) beyond dropping the elements.
+ SpillAll();
element_count_ -= count;
}
- // Forget count elements from the top of the frame and adjust the stack
- // pointer downward. This is used, for example, before merging frames at
- // break, continue, and return targets.
- void ForgetElements(int count);
-
// Spill all values from the frame to memory.
- inline void SpillAll();
+ inline void SpillAll() {
+ switch (top_of_stack_state_) {
+ case R0_R1_TOS:
Søren Thygesen Gjesse 2010/04/07 07:53:37 Maybe it is just me, but my initial assumption was
Erik Corry 2010/04/07 12:49:17 Reversed. Lets see how that works.
+ masm()->push(r0);
+ // Fall through.
+ case R1_TOS:
+ masm()->push(r1);
+ top_of_stack_state_ = NO_TOS_REGISTERS;
+ break;
+ case R1_R0_TOS:
+ masm()->push(r1);
+ // Fall through.
+ case R0_TOS:
+ masm()->push(r0);
+ top_of_stack_state_ = NO_TOS_REGISTERS;
+ // Fall through.
+ case NO_TOS_REGISTERS:
+ break;
+ }
+ ASSERT(register_allocation_map_ == 0); // Not yet implemented.
+ }
+ inline void AssertIsSpilled() {
Kasper Lund 2010/04/07 08:09:50 Remove inline?
Erik Corry 2010/04/07 12:49:17 Done.
+ ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
+ ASSERT(register_allocation_map_ == 0);
+ }
+
+ inline void AssertIsNotSpilled() {
Kasper Lund 2010/04/07 08:09:50 Remove inline?
Erik Corry 2010/04/07 12:49:17 Done.
+ ASSERT(!SpilledScope::is_spilled());
+ }
+
// Spill all occurrences of a specific register from the frame.
void Spill(Register reg) {
- if (is_used(reg)) SpillElementAt(register_location(reg));
+ UNIMPLEMENTED();
}
// Spill all occurrences of an arbitrary register if possible. Return the
// register spilled or no_reg if it was not possible to free any register
- // (ie, they all have frame-external references).
+ // (ie, they all have frame-external references). Unimplemented.
Register SpillAnyRegister();
- // Prepare this virtual frame for merging to an expected frame by
- // performing some state changes that do not require generating
- // code. It is guaranteed that no code will be generated.
- void PrepareMergeTo(VirtualFrame* expected);
-
// 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.
@@ -147,10 +229,7 @@
// registers. Used when the code generator's frame is switched from this
// one to NULL by an unconditional jump.
void DetachFromCodeGenerator() {
- RegisterAllocator* cgen_allocator = cgen()->allocator();
- for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
- if (is_used(i)) cgen_allocator->Unuse(i);
- }
+ AssertIsSpilled();
}
// (Re)attach a frame to its code generator. This informs the register
@@ -158,10 +237,7 @@
// Used when a code generator's frame is switched from NULL to this one by
// binding a label.
void AttachToCodeGenerator() {
- RegisterAllocator* cgen_allocator = cgen()->allocator();
- for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
- if (is_used(i)) cgen_allocator->Unuse(i);
- }
+ AssertIsSpilled();
}
// Emit code for the physical JS entry and exit frame sequences. After
@@ -184,23 +260,17 @@
void AllocateStackSlots();
// The current top of the expression stack as an assembly operand.
- MemOperand Top() { return MemOperand(sp, 0); }
+ MemOperand Top() {
+ AssertIsSpilled();
+ return MemOperand(sp, 0);
+ }
// An element of the expression stack as an assembly operand.
MemOperand ElementAt(int index) {
+ AssertIsSpilled();
return MemOperand(sp, index * kPointerSize);
}
- // Random-access store to a frame-top relative frame element. The result
- // becomes owned by the frame and is invalidated.
- void SetElementAt(int index, Result* value);
-
- // Set a frame element to a constant. The index is frame-top relative.
- void SetElementAt(int index, Handle<Object> value) {
- Result temp(value);
- SetElementAt(index, &temp);
- }
-
// A frame-allocated local as an assembly operand.
MemOperand LocalAt(int index) {
ASSERT(0 <= index);
@@ -208,13 +278,6 @@
return MemOperand(fp, kLocal0Offset - index * kPointerSize);
}
- // Push the value of a local frame slot on top of the frame and invalidate
- // the local slot. The slot should be written to before trying to read
- // from it again.
- void TakeLocalAt(int index) {
- TakeFrameSlotAt(local0_index() + index);
- }
-
// Push the address of the receiver slot on the frame.
void PushReceiverSlotAddress();
@@ -224,13 +287,6 @@
// The context frame slot.
MemOperand Context() { return MemOperand(fp, kContextOffset); }
- // Save the value of the esi register to the context frame slot.
- void SaveContextRegister();
-
- // Restore the esi register from the value of the context frame
- // slot.
- void RestoreContextRegister();
-
// A parameter as an assembly operand.
MemOperand ParameterAt(int index) {
// Index -1 corresponds to the receiver.
@@ -239,19 +295,6 @@
return MemOperand(fp, (1 + parameter_count() - index) * kPointerSize);
}
- // Push the value of a paramter frame slot on top of the frame and
- // invalidate the parameter slot. The slot should be written to before
- // trying to read from it again.
- void TakeParameterAt(int index) {
- TakeFrameSlotAt(param0_index() + index);
- }
-
- // Store the top value on the virtual frame into a parameter frame slot.
- // The value is left in place on top of the frame.
- void StoreToParameterAt(int index) {
- StoreToFrameSlotAt(param0_index() + index);
- }
-
// The receiver frame slot.
MemOperand Receiver() { return ParameterAt(-1); }
@@ -261,7 +304,7 @@
// Call stub given the number of arguments it expects on (and
// removes from) the stack.
void CallStub(CodeStub* stub, int arg_count) {
- Forget(arg_count);
+ if (arg_count != 0) Forget(arg_count);
ASSERT(cgen()->HasValidEntryRegisters());
masm()->CallStub(stub);
}
@@ -296,35 +339,51 @@
// Drop one element.
void Drop() { Drop(1); }
- // Pop an element from the top of the expression stack. Returns a
- // Result, which may be a constant or a register.
- Result Pop();
+ // Pop an element from the top of the expression stack. Discards
+ // the result.
+ void Pop();
+ // Pop an element from the top of the expression stack. The register
+ // will be one normally used for the top of stack register allocation
+ // so you can't hold on to it if you push on the stack.
+ Register PopToRegister(Register but_not_to_this_one = no_reg);
+
+ // Look at the top of the stack. The register returned is aliased and
+ // must be copied to a scratch register before modification.
+ Register Peek();
+
// Pop and save an element from the top of the expression stack and
// emit a corresponding pop instruction.
void EmitPop(Register reg);
+ // Takes the top two elements and puts them in r0 (top element) and r1
+ // (second element).
+ void PopToR1R0();
+
+ // Takes the top element and puts it in r1.
+ void PopToR1();
+
+ // Takes the top element and puts it in r0.
+ void PopToR0();
+
// Push an element on top of the expression stack and emit a
// corresponding push instruction.
void EmitPush(Register reg);
+ void EmitPush(MemOperand operand);
+ // Get a register which is free and which must be immediately used to
+ // push on the top of the stack.
+ Register GetTOSRegister();
+
// Push multiple registers on the stack and the virtual frame
// Register are selected by setting bit in src_regs and
// are pushed in decreasing order: r15 .. r0.
void EmitPushMultiple(int count, int src_regs);
- // Push an element on the virtual frame.
- inline void Push(Handle<Object> value);
- inline void Push(Smi* value);
+ static inline Register scratch0() { return r7; }
Kasper Lund 2010/04/07 08:09:50 inline?
Erik Corry 2010/04/07 12:49:17 Done.
+ static inline Register scratch1() { return r8; }
+ static inline Register scratch2() { return r9; }
- // Nip removes zero or more elements from immediately below the top
- // of the frame, leaving the previous top-of-frame value on top of
- // the frame. Nip(k) is equivalent to x = Pop(), Drop(k), Push(x).
- inline void Nip(int num_dropped);
-
- inline void SetTypeForLocalAt(int index, TypeInfo info);
- inline void SetTypeForParamAt(int index, TypeInfo info);
-
private:
static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
static const int kFunctionOffset = JavaScriptFrameConstants::kFunctionOffset;
@@ -333,17 +392,41 @@
static const int kHandlerSize = StackHandlerConstants::kSize / kPointerSize;
static const int kPreallocatedElements = 5 + 8; // 8 expression stack slots.
+ // 5 states for the top of stack, which can be in memory or in r0 and r1.
+ enum TopOfStack { NO_TOS_REGISTERS, R0_TOS, R1_TOS, R0_R1_TOS, R1_R0_TOS,
+ TOS_STATES};
+ static const int kMaxTOSRegisters = 2;
+
Søren Thygesen Gjesse 2010/04/07 10:46:51 Most of the names of these constants are self-expl
Erik Corry 2010/04/07 12:49:17 Done (with a rename and a comment in the .cc file)
+ static const bool kR0InUse[TOS_STATES];
+ static const bool kR1InUse[TOS_STATES];
+ static const int kVirtualElements[TOS_STATES];
+ static const TopOfStack kPopState[TOS_STATES];
+ static const TopOfStack kPushState[TOS_STATES];
+ static const Register kTopRegister[TOS_STATES];
+ static const Register kBottomRegister[TOS_STATES];
+
+ // We allocate up to 5 locals in registers.
+ static const int kNumberOfAllocatedRegisters = 5;
+ // r2 to r6 are allocated to locals.
+ static const int kFirstAllocatedRegister = 2;
+
+ static const Register kAllocatedRegisters[kNumberOfAllocatedRegisters];
+
+ static Register AllocatedRegister(int r) {
+ ASSERT(r >= 0 && r < kNumberOfAllocatedRegisters);
+ return kAllocatedRegisters[r];
+ }
+
// The number of elements on the stack frame.
int element_count_;
+ TopOfStack top_of_stack_state_:3;
+ int register_allocation_map_:kNumberOfAllocatedRegisters;
// The index of the element that is at the processor's stack pointer
- // (the sp register).
- int stack_pointer_;
+ // (the sp register). For now since everything is in memory it is given
+ // by the number of elements on the not-very-virtual stack frame.
+ int stack_pointer() { return element_count_ - 1; }
- // The index of the register frame element using each register, or
- // kIllegalIndex if a register is not on the frame.
- int register_locations_[RegisterAllocator::kNumRegisters];
-
// The number of frame-allocated locals and parameters respectively.
int parameter_count() { return cgen()->scope()->num_parameters(); }
int local_count() { return cgen()->scope()->num_stack_slots(); }
@@ -380,81 +463,12 @@
return (frame_pointer() - index) * kPointerSize;
}
- // Record an occurrence of a register in the virtual frame. This has the
- // effect of incrementing the register's external reference count and
- // of updating the index of the register's location in the frame.
- void Use(Register reg, int index) {
- ASSERT(!is_used(reg));
- set_register_location(reg, index);
- cgen()->allocator()->Use(reg);
- }
-
- // Record that a register reference has been dropped from the frame. This
- // decrements the register's external reference count and invalidates the
- // index of the register's location in the frame.
- void Unuse(Register reg) {
- ASSERT(is_used(reg));
- set_register_location(reg, kIllegalIndex);
- cgen()->allocator()->Unuse(reg);
- }
-
- // Spill the element at a particular index---write it to memory if
- // necessary, free any associated register, and forget its value if
- // constant.
- void SpillElementAt(int index);
-
- // Sync the element at a particular index. If it is a register or
- // constant that disagrees with the value on the stack, write it to memory.
- // Keep the element type as register or constant, and clear the dirty bit.
- void SyncElementAt(int index);
-
- // Sync a single unsynced element that lies beneath or at the stack pointer.
- void SyncElementBelowStackPointer(int index);
-
- // Sync a single unsynced element that lies just above the stack pointer.
- void SyncElementByPushing(int index);
-
- // Push a the value of a frame slot (typically a local or parameter) on
- // top of the frame and invalidate the slot.
- void TakeFrameSlotAt(int index);
-
- // Store the value on top of the frame to a frame slot (typically a local
- // or parameter).
- void StoreToFrameSlotAt(int index);
-
// Spill all elements in registers. Spill the top spilled_args elements
// on the frame. Sync all other frame elements.
// Then drop dropped_args elements from the virtual frame, to match
// the effect of an upcoming call that will drop them from the stack.
void PrepareForCall(int spilled_args, int dropped_args);
- // Move frame elements currently in registers or constants, that
- // should be in memory in the expected frame, to memory.
- void MergeMoveRegistersToMemory(VirtualFrame* expected);
-
- // Make the register-to-register moves necessary to
- // merge this frame with the expected frame.
- // Register to memory moves must already have been made,
- // and memory to register moves must follow this call.
- // This is because some new memory-to-register moves are
- // created in order to break cycles of register moves.
- // Used in the implementation of MergeTo().
- void MergeMoveRegistersToRegisters(VirtualFrame* expected);
-
- // Make the memory-to-register and constant-to-register moves
- // needed to make this frame equal the expected frame.
- // Called after all register-to-memory and register-to-register
- // moves have been made. After this function returns, the frames
- // should be equal.
- void MergeMoveMemoryToRegisters(VirtualFrame* expected);
-
- // Invalidates a frame slot (puts an invalid frame element in it).
- // Copies on the frame are correctly handled, and if this slot was
- // the backing store of copies, the index of the new backing store
- // is returned. Otherwise, returns kIllegalIndex.
- // Register counts are correctly updated.
- int InvalidateFrameSlotAt(int index);
-
inline bool Equals(VirtualFrame* other);
friend class JumpTarget;

Powered by Google App Engine
This is Rietveld 408576698