Add roundsd instruction to ia32 and use it in optimized Math.floor.
authorfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 12 Aug 2011 10:13:40 +0000 (10:13 +0000)
committerfschneider@chromium.org <fschneider@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 12 Aug 2011 10:13:40 +0000 (10:13 +0000)
It is available platforms that have SSE 4.1 and allows us to handle
negative numbers without deoptimization. Before we would deoptimize
on negative inputs to Math.floor. x64 already uses this instruction.

* Change Math.floor unit test to make sure every test case gets
optimized by changing the source code for each test case.

* Fix HIR debug printing for some instructions.
Review URL: http://codereview.chromium.org/7628017

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

src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/disasm-ia32.cc
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
test/mjsunit/math-floor.js

index 5bea55a77d844fd57cd2af9e2458eb457f476763..71c59b5d9ecf0a4c998a572ad4af6d15e793ef17 100644 (file)
@@ -635,6 +635,12 @@ void HBinaryCall::PrintDataTo(StringStream* stream) {
 }
 
 
+void HBoundsCheck::PrintDataTo(StringStream* stream) {
+  index()->PrintNameTo(stream);
+  stream->Add(" ");
+  length()->PrintNameTo(stream);
+}
+
 void HCallConstantFunction::PrintDataTo(StringStream* stream) {
   if (IsApplyFunction()) {
     stream->Add("optimized apply ");
@@ -1364,6 +1370,20 @@ bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
 }
 
 
+void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) {
+  object()->PrintNameTo(stream);
+  stream->Add(" .");
+  stream->Add(*String::cast(*name())->ToCString());
+}
+
+
+void HLoadNamedGeneric::PrintDataTo(StringStream* stream) {
+  object()->PrintNameTo(stream);
+  stream->Add(" .");
+  stream->Add(*String::cast(*name())->ToCString());
+}
+
+
 void HLoadKeyedFastElement::PrintDataTo(StringStream* stream) {
   object()->PrintNameTo(stream);
   stream->Add("[");
index 42dfba2a87902ad59efa125ea8a51a0a567f55b1..e7a9104e87f64800fbbd05ec3dcfeeff379449c3 100644 (file)
@@ -2449,6 +2449,8 @@ class HBoundsCheck: public HTemplateInstruction<2> {
     return Representation::Integer32();
   }
 
+  virtual void PrintDataTo(StringStream* stream);
+
   HValue* index() { return OperandAt(0); }
   HValue* length() { return OperandAt(1); }
 
@@ -3416,6 +3418,8 @@ class HLoadNamedFieldPolymorphic: public HTemplateInstruction<2> {
     return Representation::Tagged();
   }
 
+  virtual void PrintDataTo(StringStream* stream);
+
   DECLARE_CONCRETE_INSTRUCTION(LoadNamedFieldPolymorphic)
 
   static const int kMaxLoadPolymorphism = 4;
@@ -3449,6 +3453,8 @@ class HLoadNamedGeneric: public HTemplateInstruction<2> {
     return Representation::Tagged();
   }
 
+  virtual void PrintDataTo(StringStream* stream);
+
   DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric)
 
  private:
index 0dc519407cc2319ff33069bfcc67f52a356e589d..999647487eeea53e635777ffce253056849d0d7c 100644 (file)
@@ -1957,6 +1957,18 @@ void Assembler::ucomisd(XMMRegister dst, XMMRegister src) {
 }
 
 
+void Assembler::roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode) {
+  ASSERT(CpuFeatures::IsEnabled(SSE4_1));
+  EnsureSpace ensure_space(this);
+  EMIT(0x66);
+  EMIT(0x0F);
+  EMIT(0x3A);
+  EMIT(0x0B);
+  emit_sse_operand(dst, src);
+  // Mask precision exeption.
+  EMIT(static_cast<byte>(mode) | 0x8);
+}
+
 void Assembler::movmskpd(Register dst, XMMRegister src) {
   ASSERT(CpuFeatures::IsEnabled(SSE2));
   EnsureSpace ensure_space(this);
index da38e138da6b9fc1835b10a8aa4ec661104b0b4f..c186094b39770274d4e4124a945e419e3696cb90 100644 (file)
@@ -941,6 +941,16 @@ class Assembler : public AssemblerBase {
   void andpd(XMMRegister dst, XMMRegister src);
 
   void ucomisd(XMMRegister dst, XMMRegister src);
+
+  enum RoundingMode {
+    kRoundToNearest = 0x0,
+    kRoundDown      = 0x1,
+    kRoundUp        = 0x2,
+    kRoundToZero    = 0x3
+  };
+
+  void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
+
   void movmskpd(Register dst, XMMRegister src);
 
   void cmpltsd(XMMRegister dst, XMMRegister src);
index 900668fbdcedd2943044a950e512dfaf8d5fd312..a936277b2fc1fe29f504f02335c81113a65ae364 100644 (file)
@@ -1141,7 +1141,17 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
             }
           } else if (*data == 0x3A) {
             data++;
-            if (*data == 0x16) {
+            if (*data == 0x0B) {
+              data++;
+              int mod, regop, rm;
+              get_modrm(*data, &mod, &regop, &rm);
+              int8_t imm8 = static_cast<int8_t>(data[1]);
+              AppendToBuffer("roundsd %s,%s,%d",
+                             NameOfXMMRegister(regop),
+                             NameOfXMMRegister(rm),
+                             static_cast<int>(imm8));
+              data += 2;
+            } else if (*data == 0x16) {
               data++;
               int mod, regop, rm;
               get_modrm(*data, &mod, &regop, &rm);
index 14ced5e8bd6b202839e2ff582b3401a0b21b43b8..0056acc953ea477dbab1cf6f09062afcf6873682 100644 (file)
@@ -3830,7 +3830,6 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
 
 void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
                                            const char* comment) {
-  // TODO(svenpanne): Allowing format strings in Comment would be nice here...
   Comment cmt(masm_, comment);
   bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
   UnaryOverwriteMode overwrite =
index 1fa5a3a4e95932106016e8df47b40f68243b24e4..f771c4e5cd3dea343058542899639f98432e9b03 100644 (file)
@@ -2713,35 +2713,54 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
   XMMRegister xmm_scratch = xmm0;
   Register output_reg = ToRegister(instr->result());
   XMMRegister input_reg = ToDoubleRegister(instr->value());
-  Label done;
 
-  // Deoptimize on negative numbers.
-  __ xorps(xmm_scratch, xmm_scratch);  // Zero the register.
-  __ ucomisd(input_reg, xmm_scratch);
-  DeoptimizeIf(below, instr->environment());
+  if (CpuFeatures::IsSupported(SSE4_1)) {
+    CpuFeatures::Scope scope(SSE4_1);
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      // Deoptimize on negative zero.
+      Label non_zero;
+      __ xorps(xmm_scratch, xmm_scratch);  // Zero the register.
+      __ ucomisd(input_reg, xmm_scratch);
+      __ j(not_equal, &non_zero, Label::kNear);
+      __ movmskpd(output_reg, input_reg);
+      __ test(output_reg, Immediate(1));
+      DeoptimizeIf(not_zero, instr->environment());
+      __ bind(&non_zero);
+    }
+    __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
+    __ cvttsd2si(output_reg, Operand(xmm_scratch));
+    // Overflow is signalled with minint.
+    __ cmp(output_reg, 0x80000000u);
+    DeoptimizeIf(equal, instr->environment());
+  } else {
+    Label done;
+    // Deoptimize on negative numbers.
+    __ xorps(xmm_scratch, xmm_scratch);  // Zero the register.
+    __ ucomisd(input_reg, xmm_scratch);
+    DeoptimizeIf(below, instr->environment());
 
-  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-    // Check for negative zero.
-    Label positive_sign;
-    __ j(above, &positive_sign, Label::kNear);
-    __ movmskpd(output_reg, input_reg);
-    __ test(output_reg, Immediate(1));
-    DeoptimizeIf(not_zero, instr->environment());
-    __ Set(output_reg, Immediate(0));
-    __ jmp(&done, Label::kNear);
-    __ bind(&positive_sign);
-  }
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      // Check for negative zero.
+      Label positive_sign;
+      __ j(above, &positive_sign, Label::kNear);
+      __ movmskpd(output_reg, input_reg);
+      __ test(output_reg, Immediate(1));
+      DeoptimizeIf(not_zero, instr->environment());
+      __ Set(output_reg, Immediate(0));
+      __ jmp(&done, Label::kNear);
+      __ bind(&positive_sign);
+    }
 
-  // Use truncating instruction (OK because input is positive).
-  __ cvttsd2si(output_reg, Operand(input_reg));
+    // Use truncating instruction (OK because input is positive).
+    __ cvttsd2si(output_reg, Operand(input_reg));
 
-  // Overflow is signalled with minint.
-  __ cmp(output_reg, 0x80000000u);
-  DeoptimizeIf(equal, instr->environment());
-  __ bind(&done);
+    // Overflow is signalled with minint.
+    __ cmp(output_reg, 0x80000000u);
+    DeoptimizeIf(equal, instr->environment());
+    __ bind(&done);
+  }
 }
 
-
 void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
   XMMRegister xmm_scratch = xmm0;
   Register output_reg = ToRegister(instr->result());
@@ -2751,13 +2770,11 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
   // xmm_scratch = 0.5
   ExternalReference one_half = ExternalReference::address_of_one_half();
   __ movdbl(xmm_scratch, Operand::StaticVariable(one_half));
-
   __ ucomisd(xmm_scratch, input_reg);
   __ j(above, &below_half);
   // input = input + 0.5
   __ addsd(input_reg, xmm_scratch);
 
-
   // Compute Math.floor(value + 0.5).
   // Use truncating instruction (OK because input is positive).
   __ cvttsd2si(output_reg, Operand(input_reg));
index c2992031f6002d4b1de0b527afaab2052a2fec95..f211ce2e5684bfba339b3b2f340ce4be0ae94bb7 100644 (file)
 
 // Flags: --max-new-space-size=256 --allow-natives-syntax
 
+var test_id = 0;
+
 function testFloor(expect, input) {
-  function test(n) {
-    return Math.floor(n);
-  }
+  var test = new Function('n',
+                          '"' + (test_id++) + '";return Math.floor(n)');
   assertEquals(expect, test(input));
   assertEquals(expect, test(input));
   assertEquals(expect, test(input));