ARM64: use jssp for stack slots
authorm.m.capewell@googlemail.com <m.m.capewell@googlemail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Apr 2014 17:31:05 +0000 (17:31 +0000)
committerm.m.capewell@googlemail.com <m.m.capewell@googlemail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Apr 2014 17:31:05 +0000 (17:31 +0000)
R=bmeurer@chromium.org, ulan@chromium.org

Review URL: https://codereview.chromium.org/262533006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@21101 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm64/lithium-codegen-arm64.cc
src/arm64/lithium-codegen-arm64.h

index dce5a1a..1860e63 100644 (file)
@@ -409,6 +409,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
   int arity = instr->arity();
   CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
   CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+  after_push_argument_ = false;
 }
 
 
@@ -423,6 +424,7 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
 
   CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
   CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+  after_push_argument_ = false;
 
   ASSERT(ToRegister(instr->result()).is(x0));
 }
@@ -470,6 +472,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
     ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
     CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
   }
+  after_push_argument_ = false;
 
   ASSERT(ToRegister(instr->result()).is(x0));
 }
@@ -491,7 +494,7 @@ void LCodeGen::LoadContextFromDeferred(LOperand* context) {
   if (context->IsRegister()) {
     __ Mov(cp, ToRegister(context));
   } else if (context->IsStackSlot()) {
-    __ Ldr(cp, ToMemOperand(context));
+    __ Ldr(cp, ToMemOperand(context, kMustUseFramePointer));
   } else if (context->IsConstantOperand()) {
     HConstant* constant =
         chunk_->LookupConstant(LConstantOperand::cast(context));
@@ -1232,13 +1235,38 @@ static ptrdiff_t ArgumentsOffsetWithoutFrame(ptrdiff_t index) {
 }
 
 
-MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
+MemOperand LCodeGen::ToMemOperand(LOperand* op, StackMode stack_mode) const {
   ASSERT(op != NULL);
   ASSERT(!op->IsRegister());
   ASSERT(!op->IsDoubleRegister());
   ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
   if (NeedsEagerFrame()) {
-    return MemOperand(fp, StackSlotOffset(op->index()));
+    int fp_offset = StackSlotOffset(op->index());
+    if (op->index() >= 0) {
+      // Loads and stores have a bigger reach in positive offset than negative.
+      // When the load or the store can't be done in one instruction via fp
+      // (too big negative offset), we try to access via jssp (positive offset).
+      // We can reference a stack slot from jssp only if jssp references the end
+      // of the stack slots. It's not the case when:
+      //  - stack_mode != kCanUseStackPointer: this is the case when a deferred
+      //     code saved the registers.
+      //  - after_push_argument_: arguments has been pushed for a call.
+      //  - inlined_arguments_: inlined arguments have been pushed once. All the
+      //     remainder of the function cannot trust jssp any longer.
+      //  - saves_caller_doubles: some double registers have been pushed, jssp
+      //     references the end of the double registers and not the end of the
+      //     stack slots.
+      // Also, if the offset from fp is small enough to make a load/store in
+      // one instruction, we use a fp access.
+      if ((stack_mode == kCanUseStackPointer) && !after_push_argument_ &&
+          !inlined_arguments_ && !is_int9(fp_offset) &&
+          !info()->saves_caller_doubles()) {
+        int jssp_offset =
+            (GetStackSlotCount() - op->index() - 1) * kPointerSize;
+        return MemOperand(masm()->StackPointer(), jssp_offset);
+      }
+    }
+    return MemOperand(fp, fp_offset);
   } else {
     // Retrieve parameter without eager stack-frame relative to the
     // stack-pointer.
@@ -1628,6 +1656,10 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
 
 
 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
+  // We push some arguments and they will be pop in an other block. We can't
+  // trust that jssp references the end of the stack slots until the end of
+  // the function.
+  inlined_arguments_ = true;
   Register result = ToRegister(instr->result());
 
   if (instr->hydrogen()->from_inlined()) {
@@ -1996,6 +2028,7 @@ void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
     __ Call(target);
   }
   generator.AfterCall();
+  after_push_argument_ = false;
 }
 
 
@@ -2015,11 +2048,13 @@ void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
   __ Call(x10);
 
   RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+  after_push_argument_ = false;
 }
 
 
 void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
   CallRuntime(instr->function(), instr->arity(), instr);
+  after_push_argument_ = false;
 }
 
 
@@ -2045,6 +2080,7 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
     default:
       UNREACHABLE();
   }
+  after_push_argument_ = false;
 }
 
 
@@ -3102,6 +3138,7 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
                       instr,
                       x1);
   }
+  after_push_argument_ = false;
 }
 
 
@@ -4610,6 +4647,7 @@ void LCodeGen::DoPushArgument(LPushArgument* instr) {
     Abort(kDoPushArgumentNotImplementedForDoubleType);
   } else {
     __ Push(ToRegister(argument));
+    after_push_argument_ = true;
   }
 }
 
index 1d64f86..05ab66c 100644 (file)
@@ -37,10 +37,16 @@ class LCodeGen: public LCodeGenBase {
         frame_is_built_(false),
         safepoints_(info->zone()),
         resolver_(this),
-        expected_safepoint_kind_(Safepoint::kSimple) {
+        expected_safepoint_kind_(Safepoint::kSimple),
+        after_push_argument_(false),
+        inlined_arguments_(false) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
   }
 
+  ~LCodeGen() {
+    ASSERT(!after_push_argument_ || inlined_arguments_);
+  }
+
   // Simple accessors.
   Scope* scope() const { return scope_; }
 
@@ -82,7 +88,9 @@ class LCodeGen: public LCodeGenBase {
   Operand ToOperand(LOperand* op);
   Operand ToOperand32I(LOperand* op);
   Operand ToOperand32U(LOperand* op);
-  MemOperand ToMemOperand(LOperand* op) const;
+  enum StackMode { kMustUseFramePointer, kCanUseStackPointer };
+  MemOperand ToMemOperand(LOperand* op,
+                          StackMode stack_mode = kCanUseStackPointer) const;
   Handle<Object> ToHandle(LConstantOperand* op) const;
 
   // TODO(jbramley): Examine these helpers and check that they make sense.
@@ -348,6 +356,15 @@ class LCodeGen: public LCodeGenBase {
 
   Safepoint::Kind expected_safepoint_kind_;
 
+  // This flag is true when we are after a push (but before a call).
+  // In this situation, jssp no longer references the end of the stack slots so,
+  // we can only reference a stack slot via fp.
+  bool after_push_argument_;
+  // If we have inlined arguments, we are no longer able to use jssp because
+  // jssp is modified and we never know if we are in a block after or before
+  // the pop of the arguments (which restores jssp).
+  bool inlined_arguments_;
+
   int old_position_;
 
   class PushSafepointRegistersScope BASE_EMBEDDED {