ARM64: Optimize AllocateHeapNumber to use STP.
authoralexandre.rames@arm.com <alexandre.rames@arm.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 31 Mar 2014 14:06:42 +0000 (14:06 +0000)
committeralexandre.rames@arm.com <alexandre.rames@arm.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 31 Mar 2014 14:06:42 +0000 (14:06 +0000)
R=jochen@chromium.org

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

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

src/arm64/assembler-arm64.h
src/arm64/code-stubs-arm64.cc
src/arm64/codegen-arm64.cc
src/arm64/full-codegen-arm64.cc
src/arm64/macro-assembler-arm64-inl.h
src/arm64/macro-assembler-arm64.cc
src/arm64/macro-assembler-arm64.h
src/arm64/stub-cache-arm64.cc
src/objects.h

index 1aae2f2..50f86cc 100644 (file)
@@ -285,9 +285,9 @@ struct FPRegister : public CPURegister {
   static const unsigned kAllocatableLowRangeBegin = 0;
   static const unsigned kAllocatableLowRangeEnd = 14;
   static const unsigned kAllocatableHighRangeBegin = 16;
-  static const unsigned kAllocatableHighRangeEnd = 29;
+  static const unsigned kAllocatableHighRangeEnd = 28;
 
-  static const RegList kAllocatableFPRegisters = 0x3fff7fff;
+  static const RegList kAllocatableFPRegisters = 0x1fff7fff;
 
   // Gap between low and high ranges.
   static const int kAllocatableRangeGapSize =
@@ -316,12 +316,12 @@ struct FPRegister : public CPURegister {
     ASSERT((kAllocatableLowRangeBegin == 0) &&
            (kAllocatableLowRangeEnd == 14) &&
            (kAllocatableHighRangeBegin == 16) &&
-           (kAllocatableHighRangeEnd == 29));
+           (kAllocatableHighRangeEnd == 28));
     const char* const names[] = {
       "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
       "d8", "d9", "d10", "d11", "d12", "d13", "d14",
       "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
-      "d24", "d25", "d26", "d27", "d28", "d29"
+      "d24", "d25", "d26", "d27", "d28"
     };
     return names[index];
   }
@@ -420,9 +420,11 @@ ALIAS_REGISTER(Register, wzr, w31);
 // Keeps the 0 double value.
 ALIAS_REGISTER(FPRegister, fp_zero, d15);
 // Crankshaft double scratch register.
-ALIAS_REGISTER(FPRegister, crankshaft_fp_scratch, d30);
-// MacroAssembler double scratch register.
-ALIAS_REGISTER(FPRegister, fp_scratch, d31);
+ALIAS_REGISTER(FPRegister, crankshaft_fp_scratch, d29);
+// MacroAssembler double scratch registers.
+ALIAS_REGISTER(FPRegister, fp_scratch, d30);
+ALIAS_REGISTER(FPRegister, fp_scratch1, d30);
+ALIAS_REGISTER(FPRegister, fp_scratch2, d31);
 
 #undef ALIAS_REGISTER
 
index 7e8267b..d112271 100644 (file)
@@ -1393,9 +1393,8 @@ void MathPowStub::Generate(MacroAssembler* masm) {
 
     // Return.
     __ Bind(&done);
-    __ AllocateHeapNumber(result_tagged, &call_runtime, scratch0, scratch1);
-    __ Str(result_double,
-        FieldMemOperand(result_tagged, HeapNumber::kValueOffset));
+    __ AllocateHeapNumber(result_tagged, &call_runtime, scratch0, scratch1,
+                          result_double);
     ASSERT(result_tagged.is(x0));
     __ IncrementCounter(
         masm->isolate()->counters()->math_pow(), 1, scratch0, scratch1);
index 831d449..0944c4b 100644 (file)
@@ -339,8 +339,8 @@ void ElementsTransitionGenerator::GenerateDoubleToObject(
 
     // Non-hole double, copy value into a heap number.
     Register heap_num = x5;
-    __ AllocateHeapNumber(heap_num, &gc_required, x6, x4, heap_num_map);
-    __ Str(x13, FieldMemOperand(heap_num, HeapNumber::kValueOffset));
+    __ AllocateHeapNumber(heap_num, &gc_required, x6, x4,
+                          x13, heap_num_map);
     __ Mov(x13, dst_elements);
     __ Str(heap_num, MemOperand(dst_elements, kPointerSize, PostIndex));
     __ RecordWrite(array, x13, heap_num, kLRHasBeenSaved, kDontSaveFPRegs,
index d8f1402..ff638a4 100644 (file)
@@ -4720,22 +4720,23 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
   Register result_value = x2;
   Register boolean_done = x3;
   Register empty_fixed_array = x4;
+  Register untagged_result = x5;
   __ Mov(map_reg, Operand(map));
   __ Pop(result_value);
   __ Mov(boolean_done, Operand(isolate()->factory()->ToBoolean(done)));
   __ Mov(empty_fixed_array, Operand(isolate()->factory()->empty_fixed_array()));
   ASSERT_EQ(map->instance_size(), 5 * kPointerSize);
-  // TODO(jbramley): Use Stp if possible.
-  __ Str(map_reg, FieldMemOperand(result, HeapObject::kMapOffset));
-  __ Str(empty_fixed_array,
-         FieldMemOperand(result, JSObject::kPropertiesOffset));
-  __ Str(empty_fixed_array, FieldMemOperand(result, JSObject::kElementsOffset));
-  __ Str(result_value,
-         FieldMemOperand(result,
-                         JSGeneratorObject::kResultValuePropertyOffset));
-  __ Str(boolean_done,
-         FieldMemOperand(result,
-                         JSGeneratorObject::kResultDonePropertyOffset));
+  STATIC_ASSERT(JSObject::kPropertiesOffset + kPointerSize ==
+                JSObject::kElementsOffset);
+  STATIC_ASSERT(JSGeneratorObject::kResultValuePropertyOffset + kPointerSize ==
+                JSGeneratorObject::kResultDonePropertyOffset);
+  __ ObjectUntag(untagged_result, result);
+  __ Str(map_reg, MemOperand(untagged_result, HeapObject::kMapOffset));
+  __ Stp(empty_fixed_array, empty_fixed_array,
+         MemOperand(untagged_result, JSObject::kPropertiesOffset));
+  __ Stp(result_value, boolean_done,
+         MemOperand(untagged_result,
+                    JSGeneratorObject::kResultValuePropertyOffset));
 
   // Only the value field needs a write barrier, as the other values are in the
   // root set.
index d660d36..4fd6d76 100644 (file)
@@ -1409,6 +1409,30 @@ void MacroAssembler::JumpIfBothNotSmi(Register value1,
 }
 
 
+void MacroAssembler::ObjectTag(Register tagged_obj, Register obj) {
+  STATIC_ASSERT(kHeapObjectTag == 1);
+  if (emit_debug_code()) {
+    Label ok;
+    Tbz(obj, 0, &ok);
+    Abort(kObjectTagged);
+    Bind(&ok);
+  }
+  Orr(tagged_obj, obj, kHeapObjectTag);
+}
+
+
+void MacroAssembler::ObjectUntag(Register untagged_obj, Register obj) {
+  STATIC_ASSERT(kHeapObjectTag == 1);
+  if (emit_debug_code()) {
+    Label ok;
+    Tbnz(obj, 0, &ok);
+    Abort(kObjectNotTagged);
+    Bind(&ok);
+  }
+  Bic(untagged_obj, obj, kHeapObjectTag);
+}
+
+
 void MacroAssembler::IsObjectNameType(Register object,
                                       Register type,
                                       Label* fail) {
index 08ddb87..12c7dd8 100644 (file)
@@ -53,7 +53,7 @@ MacroAssembler::MacroAssembler(Isolate* arg_isolate,
 #endif
       has_frame_(false),
       use_real_aborts_(true),
-      sp_(jssp), tmp_list_(ip0, ip1), fptmp_list_(fp_scratch) {
+      sp_(jssp), tmp_list_(ip0, ip1), fptmp_list_(fp_scratch1, fp_scratch2) {
   if (isolate() != NULL) {
     code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
                                   isolate());
@@ -1196,7 +1196,7 @@ void MacroAssembler::AssertStackConsistency() {
 }
 
 
-void MacroAssembler::LoadRoot(Register destination,
+void MacroAssembler::LoadRoot(CPURegister destination,
                               Heap::RootListIndex index) {
   // TODO(jbramley): Most root values are constants, and can be synthesized
   // without a load. Refer to the ARM back end for details.
@@ -3267,7 +3267,7 @@ void MacroAssembler::Allocate(int object_size,
 
   // Tag the object if requested.
   if ((flags & TAG_OBJECT) != 0) {
-    Orr(result, result, kHeapObjectTag);
+    ObjectTag(result, result);
   }
 }
 
@@ -3349,7 +3349,7 @@ void MacroAssembler::Allocate(Register object_size,
 
   // Tag the object if requested.
   if ((flags & TAG_OBJECT) != 0) {
-    Orr(result, result, kHeapObjectTag);
+    ObjectTag(result, result);
   }
 }
 
@@ -3533,32 +3533,50 @@ void MacroAssembler::AllocateHeapNumber(Register result,
                                         Label* gc_required,
                                         Register scratch1,
                                         Register scratch2,
-                                        Register heap_number_map) {
+                                        CPURegister value,
+                                        CPURegister heap_number_map) {
+  ASSERT(!value.IsValid() || value.Is64Bits());
+  UseScratchRegisterScope temps(this);
+
   // Allocate an object in the heap for the heap number and tag it as a heap
   // object.
   Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
-           TAG_OBJECT);
-
-  // Store heap number map in the allocated object.
-  if (heap_number_map.Is(NoReg)) {
-    heap_number_map = scratch1;
+           NO_ALLOCATION_FLAGS);
+
+  // Prepare the heap number map.
+  if (!heap_number_map.IsValid()) {
+    // If we have a valid value register, use the same type of register to store
+    // the map so we can use STP to store both in one instruction.
+    if (value.IsValid() && value.IsFPRegister()) {
+      heap_number_map = temps.AcquireD();
+    } else {
+      heap_number_map = scratch1;
+    }
     LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   }
-  AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
-  Str(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
-}
-
+  if (emit_debug_code()) {
+    Register map;
+    if (heap_number_map.IsFPRegister()) {
+      map = scratch1;
+      Fmov(map, DoubleRegister(heap_number_map));
+    } else {
+      map = Register(heap_number_map);
+    }
+    AssertRegisterIsRoot(map, Heap::kHeapNumberMapRootIndex);
+  }
 
-void MacroAssembler::AllocateHeapNumberWithValue(Register result,
-                                                 DoubleRegister value,
-                                                 Label* gc_required,
-                                                 Register scratch1,
-                                                 Register scratch2,
-                                                 Register heap_number_map) {
-  // TODO(all): Check if it would be more efficient to use STP to store both
-  // the map and the value.
-  AllocateHeapNumber(result, gc_required, scratch1, scratch2, heap_number_map);
-  Str(value, FieldMemOperand(result, HeapNumber::kValueOffset));
+  // Store the heap number map and the value in the allocated object.
+  if (value.IsSameSizeAndType(heap_number_map)) {
+    STATIC_ASSERT(HeapObject::kMapOffset + kPointerSize ==
+                  HeapNumber::kValueOffset);
+    Stp(heap_number_map, value, MemOperand(result, HeapObject::kMapOffset));
+  } else {
+    Str(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
+    if (value.IsValid()) {
+      Str(value, MemOperand(result, HeapNumber::kValueOffset));
+    }
+  }
+  ObjectTag(result, result);
 }
 
 
index 1777c38..3061c1f 100644 (file)
@@ -802,7 +802,7 @@ class MacroAssembler : public Assembler {
   inline void InitializeRootRegister();
 
   // Load an object from the root table.
-  void LoadRoot(Register destination,
+  void LoadRoot(CPURegister destination,
                 Heap::RootListIndex index);
   // Store an object to the root table.
   void StoreRoot(Register source,
@@ -883,6 +883,9 @@ class MacroAssembler : public Assembler {
   void AssertNotSmi(Register object, BailoutReason reason = kOperandIsASmi);
   void AssertSmi(Register object, BailoutReason reason = kOperandIsNotASmi);
 
+  inline void ObjectTag(Register tagged_obj, Register obj);
+  inline void ObjectUntag(Register untagged_obj, Register obj);
+
   // Abort execution if argument is not a name, enabled via --debug-code.
   void AssertName(Register object);
 
@@ -1354,13 +1357,8 @@ class MacroAssembler : public Assembler {
                           Label* gc_required,
                           Register scratch1,
                           Register scratch2,
-                          Register heap_number_map = NoReg);
-  void AllocateHeapNumberWithValue(Register result,
-                                   DoubleRegister value,
-                                   Label* gc_required,
-                                   Register scratch1,
-                                   Register scratch2,
-                                   Register heap_number_map = NoReg);
+                          CPURegister value = NoFPReg,
+                          CPURegister heap_number_map = NoReg);
 
   // ---------------------------------------------------------------------------
   // Support functions.
index 1b2e959..aed9af9 100644 (file)
@@ -398,9 +398,7 @@ void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
     DoubleRegister temp_double = temps.AcquireD();
     __ SmiUntagToDouble(temp_double, value_reg, kSpeculativeUntag);
 
-    Label do_store, heap_number;
-    __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2);
-
+    Label do_store;
     __ JumpIfSmi(value_reg, &do_store);
 
     __ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
@@ -408,7 +406,7 @@ void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
     __ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
 
     __ Bind(&do_store);
-    __ Str(temp_double, FieldMemOperand(storage_reg, HeapNumber::kValueOffset));
+    __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double);
   }
 
   // Stub never generated for non-global objects that require access checks.
index abfa963..28b63f5 100644 (file)
@@ -1292,6 +1292,8 @@ class MaybeObject BASE_EMBEDDED {
   V(kOperandIsNotAString, "Operand is not a string")                          \
   V(kOperandIsNotSmi, "Operand is not smi")                                   \
   V(kOperandNotANumber, "Operand not a number")                               \
+  V(kObjectTagged, "The object is tagged")                                    \
+  V(kObjectNotTagged, "The object is not tagged")                             \
   V(kOptimizationDisabled, "Optimization is disabled")                        \
   V(kOptimizedTooManyTimes, "Optimized too many times")                       \
   V(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister,                  \