Improve generated code for non-smi bit operations by
authorkasperl@chromium.org <kasperl@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 20 Feb 2009 13:30:32 +0000 (13:30 +0000)
committerkasperl@chromium.org <kasperl@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 20 Feb 2009 13:30:32 +0000 (13:30 +0000)
converting the operands to 32-bit ints directly in the
machine code stub instead of just checking if the heap
numbers really just represent 32-bit ints and going
through the runtime system in that case.
Review URL: http://codereview.chromium.org/21536

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

src/assembler-ia32.cc
src/assembler-ia32.h
src/codegen-ia32.cc
test/mjsunit/toint32.js

index 3597fc2..375a25e 100644 (file)
@@ -1614,6 +1614,14 @@ void Assembler::fistp_s(const Operand& adr) {
 }
 
 
+void Assembler::fisttp_d(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDD);
+  emit_operand(ecx, adr);
+}
+
+
 void Assembler::fist_s(const Operand& adr) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -1809,6 +1817,14 @@ void Assembler::frndint() {
 }
 
 
+void Assembler::fnclex() {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDB);
+  EMIT(0xE2);
+}
+
+
 void Assembler::sahf() {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
index 4219212..0923ba7 100644 (file)
@@ -635,6 +635,8 @@ class Assembler : public Malloced {
   void fistp_s(const Operand& adr);
   void fistp_d(const Operand& adr);
 
+  void fisttp_d(const Operand& adr);
+
   void fabs();
   void fchs();
 
@@ -663,6 +665,7 @@ class Assembler : public Malloced {
   void fcompp();
   void fnstsw_ax();
   void fwait();
+  void fnclex();
 
   void frndint();
 
index e652150..f3570c3 100644 (file)
@@ -4482,31 +4482,63 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
       FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
       FloatingPointHelper::LoadFloatOperands(masm, ecx);
 
-      Label non_int32_operands, non_smi_result, skip_allocation;
-      // Reserve space for converted numbers.
-      __ sub(Operand(esp), Immediate(2 * kPointerSize));
+      Label non_smi_result, skip_allocation, operands_too_large;
+
+      // Make sure that the operands can be truncated into 64-bit
+      // integers. Otherwise, the fistt instruction will signal an IA
+      // exception which will cause us to overwrite the operand with
+      // zero.
+      __ push(Immediate(0x7fffffff));
+      __ push(Immediate(-1));
+      __ fild_d(Operand(esp, 0));
+      __ add(Operand(esp), Immediate(2 * kPointerSize));
 
-      // Check if right operand is int32.
-      __ fist_s(Operand(esp, 1 * kPointerSize));
-      __ fild_s(Operand(esp, 1 * kPointerSize));
-      __ fucompp();
+      // Convert the operands to absolute values before comparing
+      // against the limit.
+      __ fld(2);
+      __ fabs();
+      __ fld(2);
+      __ fabs();
+
+      // Do the comparison. If the operands are too large we go
+      // slow-case through the runtime system.
+      __ fucomp(2);
       __ fnstsw_ax();
       __ sahf();
-      __ j(not_zero, &non_int32_operands);
-      __ j(parity_even, &non_int32_operands);
-
-      // Check if left operand is int32.
-      __ fist_s(Operand(esp, 0 * kPointerSize));
-      __ fild_s(Operand(esp, 0 * kPointerSize));
+      __ j(above, &operands_too_large);
       __ fucompp();
       __ fnstsw_ax();
       __ sahf();
-      __ j(not_zero, &non_int32_operands);
-      __ j(parity_even, &non_int32_operands);
+      __ j(above, &operands_too_large);
+
+      // Reserve space for converted numbers.
+      __ sub(Operand(esp), Immediate(4 * kPointerSize));
+
+      // Convert right operand to int32.
+      Label done_right;
+      __ fnclex();
+      __ fisttp_d(Operand(esp, 2 * kPointerSize));
+      __ fnstsw_ax();
+      __ test(eax, Immediate(1));
+      __ j(zero, &done_right);
+      __ fnclex();
+      __ mov(Operand(esp, 2 * kPointerSize), Immediate(0));
+      __ bind(&done_right);
+
+      // Convert left operand to int32.
+      Label done_left;
+      __ fisttp_d(Operand(esp, 0 * kPointerSize));
+      __ fnstsw_ax();
+      __ test(eax, Immediate(1));
+      __ j(zero, &done_left);
+      __ mov(Operand(esp, 0 * kPointerSize), Immediate(0));
+      __ bind(&done_left);
 
       // Get int32 operands and perform bitop.
       __ pop(eax);
+      __ add(Operand(esp), Immediate(kPointerSize));
       __ pop(ecx);
+      __ add(Operand(esp), Immediate(kPointerSize));
       switch (op_) {
         case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
         case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
@@ -4554,10 +4586,11 @@ void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
         __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
         __ ret(2 * kPointerSize);
       }
-      __ bind(&non_int32_operands);
-      // Restore stacks and operands before calling runtime.
+
+      // Free ST(0) and ST(1) before calling runtime.
+      __ bind(&operands_too_large);
       __ ffree(0);
-      __ add(Operand(esp), Immediate(2 * kPointerSize));
+      __ ffree(1);
 
       // SHR should return uint32 - go to runtime for non-smi/negative result.
       if (op_ == Token::SHR) __ bind(&non_smi_result);
index e1a64a6..20d245c 100644 (file)
@@ -78,3 +78,95 @@ assertEquals(1, toInt32(-4294967295.75));
 assertEquals(1294967296, toInt32(-3000000000.25));
 assertEquals(1294967296, toInt32(-3000000000.5));
 assertEquals(1294967296, toInt32(-3000000000.75));
+
+var base = Math.pow(2, 64);
+assertEquals(0, toInt32(base + 0));
+assertEquals(0, toInt32(base + 1117));
+assertEquals(4096, toInt32(base + 2234));
+assertEquals(4096, toInt32(base + 3351));
+assertEquals(4096, toInt32(base + 4468));
+assertEquals(4096, toInt32(base + 5585));
+assertEquals(8192, toInt32(base + 6702));
+assertEquals(8192, toInt32(base + 7819));
+assertEquals(8192, toInt32(base + 8936));
+assertEquals(8192, toInt32(base + 10053));
+assertEquals(12288, toInt32(base + 11170));
+assertEquals(12288, toInt32(base + 12287));
+assertEquals(12288, toInt32(base + 13404));
+assertEquals(16384, toInt32(base + 14521));
+assertEquals(16384, toInt32(base + 15638));
+assertEquals(16384, toInt32(base + 16755));
+assertEquals(16384, toInt32(base + 17872));
+assertEquals(20480, toInt32(base + 18989));
+assertEquals(20480, toInt32(base + 20106));
+assertEquals(20480, toInt32(base + 21223));
+assertEquals(20480, toInt32(base + 22340));
+assertEquals(24576, toInt32(base + 23457));
+assertEquals(24576, toInt32(base + 24574));
+assertEquals(24576, toInt32(base + 25691));
+assertEquals(28672, toInt32(base + 26808));
+assertEquals(28672, toInt32(base + 27925));
+assertEquals(28672, toInt32(base + 29042));
+assertEquals(28672, toInt32(base + 30159));
+assertEquals(32768, toInt32(base + 31276));
+assertEquals(32768, toInt32(base + 32393));
+assertEquals(32768, toInt32(base + 33510));
+assertEquals(32768, toInt32(base + 34627));
+assertEquals(36864, toInt32(base + 35744));
+assertEquals(36864, toInt32(base + 36861));
+assertEquals(36864, toInt32(base + 37978));
+assertEquals(40960, toInt32(base + 39095));
+assertEquals(40960, toInt32(base + 40212));
+assertEquals(40960, toInt32(base + 41329));
+assertEquals(40960, toInt32(base + 42446));
+assertEquals(45056, toInt32(base + 43563));
+assertEquals(45056, toInt32(base + 44680));
+assertEquals(45056, toInt32(base + 45797));
+assertEquals(45056, toInt32(base + 46914));
+assertEquals(49152, toInt32(base + 48031));
+assertEquals(49152, toInt32(base + 49148));
+assertEquals(49152, toInt32(base + 50265));
+assertEquals(53248, toInt32(base + 51382));
+assertEquals(53248, toInt32(base + 52499));
+assertEquals(53248, toInt32(base + 53616));
+assertEquals(53248, toInt32(base + 54733));
+assertEquals(57344, toInt32(base + 55850));
+assertEquals(57344, toInt32(base + 56967));
+assertEquals(57344, toInt32(base + 58084));
+assertEquals(57344, toInt32(base + 59201));
+assertEquals(61440, toInt32(base + 60318));
+assertEquals(61440, toInt32(base + 61435));
+assertEquals(61440, toInt32(base + 62552));
+assertEquals(65536, toInt32(base + 63669));
+assertEquals(65536, toInt32(base + 64786));
+assertEquals(65536, toInt32(base + 65903));
+assertEquals(65536, toInt32(base + 67020));
+assertEquals(69632, toInt32(base + 68137));
+assertEquals(69632, toInt32(base + 69254));
+assertEquals(69632, toInt32(base + 70371));
+assertEquals(69632, toInt32(base + 71488));
+assertEquals(73728, toInt32(base + 72605));
+assertEquals(73728, toInt32(base + 73722));
+assertEquals(73728, toInt32(base + 74839));
+assertEquals(77824, toInt32(base + 75956));
+assertEquals(77824, toInt32(base + 77073));
+assertEquals(77824, toInt32(base + 78190));
+assertEquals(77824, toInt32(base + 79307));
+assertEquals(81920, toInt32(base + 80424));
+assertEquals(81920, toInt32(base + 81541));
+assertEquals(81920, toInt32(base + 82658));
+assertEquals(81920, toInt32(base + 83775));
+assertEquals(86016, toInt32(base + 84892));
+assertEquals(86016, toInt32(base + 86009));
+assertEquals(86016, toInt32(base + 87126));
+assertEquals(90112, toInt32(base + 88243));
+assertEquals(90112, toInt32(base + 89360));
+assertEquals(90112, toInt32(base + 90477));
+assertEquals(90112, toInt32(base + 91594));
+assertEquals(94208, toInt32(base + 92711));
+assertEquals(94208, toInt32(base + 93828));
+assertEquals(94208, toInt32(base + 94945));
+assertEquals(94208, toInt32(base + 96062));
+assertEquals(98304, toInt32(base + 97179));
+assertEquals(98304, toInt32(base + 98296));
+assertEquals(98304, toInt32(base + 99413));