Revision: 3627
Author: [email protected]
Date: Mon Jan 18 03:22:03 2010
Log: X64 implementation of native ascii string compare.

Review URL: http://codereview.chromium.org/545108
http://code.google.com/p/v8/source/detail?r=3627

Modified:
 /branches/bleeding_edge/src/x64/assembler-x64.h
 /branches/bleeding_edge/src/x64/codegen-x64.cc
 /branches/bleeding_edge/src/x64/codegen-x64.h
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.h

=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h     Mon Jan 18 01:49:50 2010
+++ /branches/bleeding_edge/src/x64/assembler-x64.h     Mon Jan 18 03:22:03 2010
@@ -915,6 +915,10 @@
   void subl(Register dst, Register src) {
     arithmetic_op_32(0x2B, dst, src);
   }
+
+  void subl(Register dst, const Operand& src) {
+    arithmetic_op_32(0x2B, dst, src);
+  }

   void subl(const Operand& dst, Immediate src) {
     immediate_arithmetic_op_32(0x5, dst, src);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Fri Jan 15 05:42:32 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Mon Jan 18 03:22:03 2010
@@ -3937,7 +3937,8 @@
   Load(args->at(0));
   Load(args->at(1));

-  Result answer = frame_->CallRuntime(Runtime::kStringCompare, 2);
+  StringCompareStub stub;
+  Result answer = frame_->CallStub(&stub, 2);
   frame_->Push(&answer);
 }

@@ -6496,15 +6497,33 @@

   // Fast negative check for symbol-to-symbol equality.
   __ bind(&check_for_symbols);
+  Label check_for_strings;
   if (cc_ == equal) {
-    BranchIfNonSymbol(masm, &call_builtin, rax, kScratchRegister);
-    BranchIfNonSymbol(masm, &call_builtin, rdx, kScratchRegister);
+    BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
+    BranchIfNonSymbol(masm, &check_for_strings, rdx, kScratchRegister);

     // We've already checked for object identity, so if both operands
// are symbols they aren't equal. Register eax (not rax) already holds a
     // non-zero value, which indicates not equal, so just return.
     __ ret(2 * kPointerSize);
   }
+
+  __ bind(&check_for_strings);
+
+ __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &call_builtin);
+
+  // Inline comparison of ascii strings.
+  StringCompareStub::GenerateCompareFlatAsciiStrings(masm,
+                                                     rdx,
+                                                     rax,
+                                                     rcx,
+                                                     rbx,
+                                                     rdi,
+                                                     r8);
+
+#ifdef DEBUG
+  __ Abort("Unexpected fall-through from string comparison");
+#endif

   __ bind(&call_builtin);
   // must swap argument order
@@ -8153,6 +8172,128 @@
   __ j(not_zero, &loop);
 }

+
+
+void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
+                                                        Register left,
+                                                        Register right,
+                                                        Register scratch1,
+                                                        Register scratch2,
+                                                        Register scratch3,
+ Register scratch4) { + // Ensure that you can always subtract a string length from a non-negative
+  // number (e.g. another length).
+  ASSERT(String::kMaxLength < 0x7fffffff);
+
+  // Find minimum length and length difference.
+  __ movl(scratch1, FieldOperand(left, String::kLengthOffset));
+  __ movl(scratch4, scratch1);
+  __ subl(scratch4, FieldOperand(right, String::kLengthOffset));
+  // Register scratch4 now holds left.length - right.length.
+  const Register length_difference = scratch4;
+  Label left_shorter;
+  __ j(less, &left_shorter);
+  // The right string isn't longer that the left one.
+ // Get the right string's length by subtracting the (non-negative) difference
+  // from the left string's length.
+  __ subl(scratch1, length_difference);
+  __ bind(&left_shorter);
+  // Register scratch1 now holds Min(left.length, right.length).
+  const Register min_length = scratch1;
+
+  Label compare_lengths;
+  // If min-length is zero, go directly to comparing lengths.
+  __ testl(min_length, min_length);
+  __ j(zero, &compare_lengths);
+
+  // Registers scratch2 and scratch3 are free.
+  Label result_not_equal;
+  Label loop;
+  {
+    // Check characters 0 .. min_length - 1 in a loop.
+    // Use scratch3 as loop index, min_length as limit and scratch2
+    // for computation.
+    const Register index = scratch3;
+    __ movl(index, Immediate(0));  // Index into strings.
+    __ bind(&loop);
+    // Compare characters.
+    // TODO(lrn): Could we load more than one character at a time?
+    __ movb(scratch2, FieldOperand(left,
+                                   index,
+                                   times_1,
+                                   SeqAsciiString::kHeaderSize));
+    // Increment index and use -1 modifier on next load to give
+    // the previous load extra time to complete.
+    __ addl(index, Immediate(1));
+    __ cmpb(scratch2, FieldOperand(right,
+                                   index,
+                                   times_1,
+                                   SeqAsciiString::kHeaderSize - 1));
+    __ j(not_equal, &result_not_equal);
+    __ cmpl(index, min_length);
+    __ j(not_equal, &loop);
+  }
+  // Completed loop without finding different characters.
+  // Compare lengths (precomputed).
+  __ bind(&compare_lengths);
+  __ testl(length_difference, length_difference);
+  __ j(not_zero, &result_not_equal);
+
+  // Result is EQUAL.
+  __ Move(rax, Smi::FromInt(EQUAL));
+  __ IncrementCounter(&Counters::string_compare_native, 1);
+  __ ret(2 * kPointerSize);
+
+  Label result_greater;
+  __ bind(&result_not_equal);
+  // Unequal comparison of left to right, either character or length.
+  __ j(greater, &result_greater);
+
+  // Result is LESS.
+  __ Move(rax, Smi::FromInt(LESS));
+  __ IncrementCounter(&Counters::string_compare_native, 1);
+  __ ret(2 * kPointerSize);
+
+  // Result is GREATER.
+  __ bind(&result_greater);
+  __ Move(rax, Smi::FromInt(GREATER));
+  __ IncrementCounter(&Counters::string_compare_native, 1);
+  __ ret(2 * kPointerSize);
+}
+
+
+void StringCompareStub::Generate(MacroAssembler* masm) {
+  Label runtime;
+
+  // Stack frame on entry.
+  //  rsp[0]: return address
+  //  rsp[8]: right string
+  //  rsp[16]: left string
+
+  __ movq(rdx, Operand(rsp, 2 * kPointerSize));  // left
+  __ movq(rax, Operand(rsp, 1 * kPointerSize));  // right
+
+  // Check for identity.
+  Label not_same;
+  __ cmpq(rdx, rax);
+  __ j(not_equal, &not_same);
+  __ Move(rax, Smi::FromInt(EQUAL));
+  __ IncrementCounter(&Counters::string_compare_native, 1);
+  __ ret(2 * kPointerSize);
+
+  __ bind(&not_same);
+
+  // Check that both are sequential ASCII strings.
+  __ JumpIfNotBothSequentialAsciiStrings(rdx, rax, rcx, rbx, &runtime);
+
+  // Inline comparison of ascii strings.
+  GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8);
+
+  // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater)
+  // tagged as a small integer.
+  __ bind(&runtime);
+  __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1);
+}

 #undef __

@@ -8247,6 +8388,7 @@

 #endif

+
 #undef __

 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h       Fri Jan 15 05:42:32 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h       Mon Jan 18 03:22:03 2010
@@ -742,6 +742,28 @@
 };


+class StringCompareStub: public CodeStub {
+ public:
+  explicit StringCompareStub() {}
+
+ // Compare two flat ascii strings and returns result in rax after popping two
+  // arguments from the stack.
+  static void GenerateCompareFlatAsciiStrings(MacroAssembler* masm,
+                                              Register left,
+                                              Register right,
+                                              Register scratch1,
+                                              Register scratch2,
+                                              Register scratch3,
+                                              Register scratch4);
+
+ private:
+  Major MajorKey() { return StringCompare; }
+  int MinorKey() { return 0; }
+
+  void Generate(MacroAssembler* masm);
+};
+
+
 } }  // namespace v8::internal

 #endif  // V8_X64_CODEGEN_X64_H_
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Mon Dec 14 03:09:25 2009 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Mon Jan 18 03:22:03 2010
@@ -579,6 +579,17 @@
   testb(kScratchRegister, Immediate(kSmiTagMask));
   return zero;
 }
+
+
+Condition MacroAssembler::CheckEitherSmi(Register first, Register second) {
+  if (first.is(second)) {
+    return CheckSmi(first);
+  }
+  movl(kScratchRegister, first);
+  andl(kScratchRegister, second);
+  testb(kScratchRegister, Immediate(kSmiTagMask));
+  return zero;
+}


 Condition MacroAssembler::CheckIsMinSmi(Register src) {
@@ -1279,6 +1290,39 @@
   Condition both_smi = CheckBothSmi(src1, src2);
   j(NegateCondition(both_smi), on_not_both_smi);
 }
+
+
+void MacroAssembler::JumpIfNotBothSequentialAsciiStrings(Register first_object, + Register second_object,
+                                                         Register scratch1,
+                                                         Register scratch2,
+                                                         Label* on_fail) {
+  // Check that both objects are not smis.
+  Condition either_smi = CheckEitherSmi(first_object, second_object);
+  j(either_smi, on_fail);
+
+  // Load instance type for both strings.
+  movq(scratch1, FieldOperand(first_object, HeapObject::kMapOffset));
+  movq(scratch2, FieldOperand(second_object, HeapObject::kMapOffset));
+  movzxbl(scratch1, FieldOperand(scratch1, Map::kInstanceTypeOffset));
+  movzxbl(scratch2, FieldOperand(scratch2, Map::kInstanceTypeOffset));
+
+  // Check that both are flat ascii strings.
+  ASSERT(kNotStringTag != 0);
+  const int kFlatAsciiStringMask =
+      kIsNotStringMask | kStringRepresentationMask | kStringEncodingMask;
+  const int kFlatAsciiStringBits =
+      kNotStringTag | kSeqStringTag | kAsciiStringTag;
+
+  andl(scratch1, Immediate(kFlatAsciiStringMask));
+  andl(scratch2, Immediate(kFlatAsciiStringMask));
+  // Interleave the bits to check both scratch1 and scratch2 in one test.
+  ASSERT_EQ(0, kFlatAsciiStringMask & (kFlatAsciiStringMask << 3));
+  lea(scratch1, Operand(scratch1, scratch2, times_8, 0));
+  cmpl(scratch1,
+       Immediate(kFlatAsciiStringBits + (kFlatAsciiStringBits << 3)));
+  j(not_equal, on_fail);
+}


 void MacroAssembler::Move(Register dst, Handle<Object> source) {
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Jan 12 00:48:26 2010 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Mon Jan 18 03:22:03 2010
@@ -204,9 +204,12 @@
   // Is the value a positive tagged smi.
   Condition CheckPositiveSmi(Register src);

-  // Are both values are tagged smis.
+  // Are both values tagged smis.
   Condition CheckBothSmi(Register first, Register second);

+  // Are either value a tagged smi.
+  Condition CheckEitherSmi(Register first, Register second);
+
   // Is the value the minimum smi value (since we are using
   // two's complement numbers, negating the value is known to yield
   // a non-smi value).
@@ -402,6 +405,14 @@
   void Push(Smi* smi);
   void Test(const Operand& dst, Smi* source);

+ // ---------------------------------------------------------------------------
+  // String macros.
+  void JumpIfNotBothSequentialAsciiStrings(Register first_object,
+                                           Register second_object,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Label* on_not_both_flat_ascii);
+
// ---------------------------------------------------------------------------
   // Macro instructions.

-- 
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to