Merged r13617, r13622 into trunk branch.

Fix DoubleStackSlot-to-DoubleStackSlot moves on ia32. Unify platform-independent code.

Add regression test for r13617

BUG=173907,173907

R=yangguo@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/trunk@13634 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 9fdb22b..45ebfae 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -568,30 +568,13 @@
   ASSERT(!op->IsRegister());
   ASSERT(!op->IsDoubleRegister());
   ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
-  int index = op->index();
-  if (index >= 0) {
-    // Local or spill slot. Skip the frame pointer, function, and
-    // context in the fixed part of the frame.
-    return MemOperand(fp, -(index + 3) * kPointerSize);
-  } else {
-    // Incoming parameter. Skip the return address.
-    return MemOperand(fp, -(index - 1) * kPointerSize);
-  }
+  return MemOperand(fp, StackSlotOffset(op->index()));
 }
 
 
 MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
   ASSERT(op->IsDoubleStackSlot());
-  int index = op->index();
-  if (index >= 0) {
-    // Local or spill slot. Skip the frame pointer, function, context,
-    // and the first word of the double in the fixed part of the frame.
-    return MemOperand(fp, -(index + 3) * kPointerSize + kPointerSize);
-  } else {
-    // Incoming parameter. Skip the return address and the first word of
-    // the double.
-    return MemOperand(fp, -(index - 1) * kPointerSize + kPointerSize);
-  }
+  return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize);
 }
 
 
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index dfced7c..05152b7 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -549,23 +549,13 @@
   if (op->IsRegister()) return Operand(ToRegister(op));
   if (op->IsDoubleRegister()) return Operand(ToDoubleRegister(op));
   ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
-  int index = op->index();
-  if (index >= 0) {
-    // Local or spill slot. Skip the frame pointer, function, and
-    // context in the fixed part of the frame.
-    return Operand(ebp, -(index + 3) * kPointerSize);
-  } else {
-    // Incoming parameter. Skip the return address.
-    return Operand(ebp, -(index - 1) * kPointerSize);
-  }
+  return Operand(ebp, StackSlotOffset(op->index()));
 }
 
 
 Operand LCodeGen::HighOperand(LOperand* op) {
   ASSERT(op->IsDoubleStackSlot());
-  int index = op->index();
-  int offset = (index >= 0) ? index + 3 : index - 1;
-  return Operand(ebp, -offset * kPointerSize);
+  return Operand(ebp, StackSlotOffset(op->index()) + kPointerSize);
 }
 
 
diff --git a/src/lithium.cc b/src/lithium.cc
index ff5af7f..5967e42 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -257,6 +257,18 @@
 }
 
 
+int StackSlotOffset(int index) {
+  if (index >= 0) {
+    // Local or spill slot. Skip the frame pointer, function, and
+    // context in the fixed part of the frame.
+    return -(index + 3) * kPointerSize;
+  } else {
+    // Incoming parameter. Skip the return address.
+    return -(index - 1) * kPointerSize;
+  }
+}
+
+
 LChunk::LChunk(CompilationInfo* info, HGraph* graph)
     : spill_slot_count_(0),
       info_(info),
diff --git a/src/lithium.h b/src/lithium.h
index 2473837..dd979a9 100644
--- a/src/lithium.h
+++ b/src/lithium.h
@@ -709,6 +709,7 @@
 
 
 int ElementsKindToShiftSize(ElementsKind elements_kind);
+int StackSlotOffset(int index);
 
 enum NumberUntagDMode {
   NUMBER_CANDIDATE_IS_SMI,
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 13dd63c..86669f4 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -528,30 +528,13 @@
   ASSERT(!op->IsRegister());
   ASSERT(!op->IsDoubleRegister());
   ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
-  int index = op->index();
-  if (index >= 0) {
-    // Local or spill slot. Skip the frame pointer, function, and
-    // context in the fixed part of the frame.
-    return MemOperand(fp, -(index + 3) * kPointerSize);
-  } else {
-    // Incoming parameter. Skip the return address.
-    return MemOperand(fp, -(index - 1) * kPointerSize);
-  }
+  return MemOperand(fp, StackSlotOffset(op->index()));
 }
 
 
 MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
   ASSERT(op->IsDoubleStackSlot());
-  int index = op->index();
-  if (index >= 0) {
-    // Local or spill slot. Skip the frame pointer, function, context,
-    // and the first word of the double in the fixed part of the frame.
-    return MemOperand(fp, -(index + 3) * kPointerSize + kPointerSize);
-  } else {
-    // Incoming parameter. Skip the return address and the first word of
-    // the double.
-    return MemOperand(fp, -(index - 1) * kPointerSize + kPointerSize);
-  }
+  return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize);
 }
 
 
diff --git a/src/version.cc b/src/version.cc
index ba8c46a..5286f43 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -35,7 +35,7 @@
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     16
 #define BUILD_NUMBER      14
-#define PATCH_LEVEL       0
+#define PATCH_LEVEL       1
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index f71bf38..b3c4bc8 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -464,15 +464,7 @@
   // Does not handle registers. In X64 assembler, plain registers are not
   // representable as an Operand.
   ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
-  int index = op->index();
-  if (index >= 0) {
-    // Local or spill slot. Skip the frame pointer, function, and
-    // context in the fixed part of the frame.
-    return Operand(rbp, -(index + 3) * kPointerSize);
-  } else {
-    // Incoming parameter. Skip the return address.
-    return Operand(rbp, -(index - 1) * kPointerSize);
-  }
+  return Operand(rbp, StackSlotOffset(op->index()));
 }
 
 
diff --git a/test/mjsunit/regress/regress-crbug-173907.js b/test/mjsunit/regress/regress-crbug-173907.js
new file mode 100644
index 0000000..9f92fefa
--- /dev/null
+++ b/test/mjsunit/regress/regress-crbug-173907.js
@@ -0,0 +1,88 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+
+var X = 1.1;
+var K = 0.5;
+
+var O = 0;
+var result = new Float64Array(2);
+
+function spill() {
+  try { } catch (e) { }
+}
+
+function buggy() {
+  var v = X;
+  var phi1 = v + K;
+  var phi2 = v - K;
+
+  spill();  // At this point initial values for phi1 and phi2 are spilled.
+
+  var xmm1 = v;
+  var xmm2 = v*v*v;
+  var xmm3 = v*v*v*v;
+  var xmm4 = v*v*v*v*v;
+  var xmm5 = v*v*v*v*v*v;
+  var xmm6 = v*v*v*v*v*v*v;
+  var xmm7 = v*v*v*v*v*v*v*v;
+  var xmm8 = v*v*v*v*v*v*v*v*v;
+
+  // All registers are blocked and phis for phi1 and phi2 are spilled because
+  // their left (incoming) value is spilled, there are no free registers,
+  // and phis themselves have only ANY-policy uses.
+
+  for (var x = 0; x < 2; x++) {
+    xmm1 += xmm1 * xmm6;
+    xmm2 += xmm1 * xmm5;
+    xmm3 += xmm1 * xmm4;
+    xmm4 += xmm1 * xmm3;
+    xmm5 += xmm1 * xmm2;
+
+    // Now swap values of phi1 and phi2 to create cycle between phis.
+    var t = phi1;
+    phi1 = phi2;
+    phi2 = t;
+  }
+
+  // Now we want to get values of phi1 and phi2. However we would like to
+  // do it in a way that does not produce any uses of phi1&phi2 that have
+  // a register beneficial policy. How? We just hide these uses behind phis.
+  result[0] = (O === 0) ? phi1 : phi2;
+  result[1] = (O !== 0) ? phi1 : phi2;
+}
+
+function test() {
+  buggy();
+  assertArrayEquals([X + K, X - K], result);
+}
+
+test();
+test();
+%OptimizeFunctionOnNextCall(buggy);
+test();