Reland r21101: "ARM64: use jssp for stack slots"
authorjacob.bramley <jacob.bramley@arm.com>
Wed, 24 Jun 2015 06:47:27 +0000 (23:47 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 24 Jun 2015 06:47:42 +0000 (06:47 +0000)
The original implementation assumed that LPushArguments and
LInvoke/Call* could be assumed to be exclusively sequential. However,
this isn't always the case. For example, GenerateCallFunction pushes
some arguments and then selects between HInvokeFunction and
HCallFunction.

This fixed implementation resets a pushed_arguments_ counter based on
the argument_count() of the preceeding basic block, then tracks it
per-instruction as before (except that now we maintain a count rather
than a boolean flag).

At the same time, since we now track exactly how many arguments have
been pushed onto the stack, I was able to adjust the offset accordingly
and use jssp for stack slots even when arguments have been pushed.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#29249}

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

index ec6e3c7..fab9c46 100644 (file)
@@ -387,6 +387,7 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
     CallFunctionStub stub(isolate(), arity, flags);
     CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
   }
+  RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
 }
 
 
@@ -401,6 +402,7 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
 
   CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
   CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+  RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
 
   DCHECK(ToRegister(instr->result()).is(x0));
 }
@@ -456,6 +458,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
     ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
     CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
   }
+  RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
 
   DCHECK(ToRegister(instr->result()).is(x0));
 }
@@ -477,7 +480,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));
@@ -1230,13 +1233,37 @@ static int64_t ArgumentsOffsetWithoutFrame(int index) {
 }
 
 
-MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
+MemOperand LCodeGen::ToMemOperand(LOperand* op, StackMode stack_mode) const {
   DCHECK(op != NULL);
   DCHECK(!op->IsRegister());
   DCHECK(!op->IsDoubleRegister());
   DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
   if (NeedsEagerFrame()) {
-    return MemOperand(fp, StackSlotOffset(op->index()));
+    int fp_offset = StackSlotOffset(op->index());
+    // Loads and stores have a bigger reach in positive offset than negative.
+    // We try to access using jssp (positive offset) first, then fall back to
+    // fp (negative offset) if that fails.
+    //
+    // We can reference a stack slot from jssp only if we know how much we've
+    // put on the stack. We don't know this in the following cases:
+    // - stack_mode != kCanUseStackPointer: this is the case when deferred
+    //   code has saved the registers.
+    // - 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.
+    // In both of the cases above, we _could_ add the tracking information
+    // required so that we can use jssp here, but in practice it isn't worth it.
+    if ((stack_mode == kCanUseStackPointer) &&
+        !info()->saves_caller_doubles()) {
+      int jssp_offset_to_fp =
+          StandardFrameConstants::kFixedFrameSizeFromFp +
+          (pushed_arguments_ + GetStackSlotCount()) * kPointerSize;
+      int jssp_offset = fp_offset + jssp_offset_to_fp;
+      if (masm()->IsImmLSScaled(jssp_offset, LSDoubleWord)) {
+        return MemOperand(masm()->StackPointer(), jssp_offset);
+      }
+    }
+    return MemOperand(fp, fp_offset);
   } else {
     // Retrieve parameter without eager stack-frame relative to the
     // stack-pointer.
@@ -2011,6 +2038,8 @@ void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
     }
     generator.AfterCall();
   }
+
+  RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
 }
 
 
@@ -2030,11 +2059,13 @@ void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
   __ Call(x10);
 
   RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+  RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
 }
 
 
 void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
   CallRuntime(instr->function(), instr->arity(), instr);
+  RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
 }
 
 
@@ -2060,6 +2091,7 @@ void LCodeGen::DoCallStub(LCallStub* instr) {
     default:
       UNREACHABLE();
   }
+  RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
 }
 
 
@@ -3118,6 +3150,7 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
                       instr->hydrogen()->formal_parameter_count(),
                       instr->arity(), instr);
   }
+  RecordPushedArgumentsDelta(instr->hydrogen()->argument_delta());
 }
 
 
@@ -3231,6 +3264,16 @@ void LCodeGen::DoLabel(LLabel* label) {
           label->block_id(),
           LabelType(label));
 
+  // Inherit pushed_arguments_ from the predecessor's argument count.
+  if (label->block()->HasPredecessor()) {
+    pushed_arguments_ = label->block()->predecessors()->at(0)->argument_count();
+#ifdef DEBUG
+    for (auto p : *label->block()->predecessors()) {
+      DCHECK_EQ(p->argument_count(), pushed_arguments_);
+    }
+#endif
+  }
+
   __ Bind(label->label());
   current_block_ = label->block_id();
   DoGap(label);
@@ -4671,6 +4714,8 @@ void LCodeGen::DoPushArguments(LPushArguments* instr) {
 
   // The preamble was done by LPreparePushArguments.
   args.PushQueued(MacroAssembler::PushPopQueue::SKIP_PREAMBLE);
+
+  RecordPushedArgumentsDelta(instr->ArgumentCount());
 }
 
 
index c9ad76c..9fd09c4 100644 (file)
@@ -36,7 +36,8 @@ class LCodeGen: public LCodeGenBase {
         frame_is_built_(false),
         safepoints_(info->zone()),
         resolver_(this),
-        expected_safepoint_kind_(Safepoint::kSimple) {
+        expected_safepoint_kind_(Safepoint::kSimple),
+        pushed_arguments_(0) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
   }
 
@@ -80,7 +81,9 @@ class LCodeGen: public LCodeGenBase {
   Register ToRegister32(LOperand* op) const;
   Operand ToOperand(LOperand* op);
   Operand ToOperand32(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;
 
   template <class LI>
@@ -356,6 +359,15 @@ class LCodeGen: public LCodeGenBase {
 
   Safepoint::Kind expected_safepoint_kind_;
 
+  // The number of arguments pushed onto the stack, either by this block or by a
+  // predecessor.
+  int pushed_arguments_;
+
+  void RecordPushedArgumentsDelta(int delta) {
+    pushed_arguments_ += delta;
+    DCHECK(pushed_arguments_ >= 0);
+  }
+
   int old_position_;
 
   class PushSafepointRegistersScope BASE_EMBEDDED {