Refactor MathPowHalf on ia32.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 5 Dec 2011 15:58:25 +0000 (15:58 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 5 Dec 2011 15:58:25 +0000 (15:58 +0000)
BUG=v8:397, v8:1848
TEST=regress-397.js

Review URL: http://codereview.chromium.org/8806010

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

src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.h
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h

index 31d8f5cdf0a6546763e00a0726651114f6ccc9ee..2925dcde950175485607cf4e42f50c03366334fb 100644 (file)
@@ -2934,31 +2934,33 @@ void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
 }
 
 
-void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
   XMMRegister xmm_scratch = xmm0;
   XMMRegister input_reg = ToDoubleRegister(instr->value());
+  Register scratch = ToRegister(instr->temp());
   ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
 
-  Label return_infinity, done;
-  // Check base for +/- infinity.
-  __ push(ecx);  // TODO(1848): reserve this register.
-  __ mov(ecx, factory()->infinity_value());
-  __ ucomisd(input_reg, FieldOperand(ecx, HeapNumber::kValueOffset));
-  __ j(equal, &return_infinity, Label::kNear);
-  __ xorps(xmm_scratch, xmm_scratch);
-  __ subsd(xmm_scratch, input_reg);
-  __ ucomisd(xmm_scratch, FieldOperand(ecx, HeapNumber::kValueOffset));
-  __ j(equal, &return_infinity, Label::kNear);
+  // Note that according to ECMA-262 15.8.2.13:
+  // Math.pow(-Infinity, 0.5) == Infinity
+  // Math.sqrt(-Infinity) == NaN
+  Label done, sqrt;
+  // Check base for -Infinity.  According to IEEE-754, single-precision
+  // -Infinity has the highest 9 bits set and the lowest 23 bits cleared.
+  __ mov(scratch, 0xFF800000);
+  __ movd(xmm_scratch, scratch);
+  __ cvtss2sd(xmm_scratch, xmm_scratch);
+  __ ucomisd(input_reg, xmm_scratch);
+  __ j(not_equal, &sqrt, Label::kNear);
+  // If input is -Infinity, return Infinity.
+  __ xorps(input_reg, input_reg);
+  __ subsd(input_reg, xmm_scratch);
+  __ jmp(&done, Label::kNear);
 
-  __ pop(ecx);
+  // Square root.
+  __ bind(&sqrt);
   __ xorps(xmm_scratch, xmm_scratch);
   __ addsd(input_reg, xmm_scratch);  // Convert -0 to +0.
   __ sqrtsd(input_reg, input_reg);
-  __ jmp(&done, Label::kNear);
-
-  __ bind(&return_infinity);
-  __ movdbl(input_reg, FieldOperand(ecx, HeapNumber::kValueOffset));
-  __ pop(ecx);
   __ bind(&done);
 }
 
@@ -3062,9 +3064,6 @@ void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
     case kMathSqrt:
       DoMathSqrt(instr);
       break;
-    case kMathPowHalf:
-      DoMathPowHalf(instr);
-      break;
     case kMathCos:
       DoMathCos(instr);
       break;
index 9d1a4f78d3312ff03511e07e838725b3536258fc..0dbb8b054cc6ff642b39bc2065fceaa424756ca4 100644 (file)
@@ -239,7 +239,6 @@ class LCodeGen BASE_EMBEDDED {
   void DoMathFloor(LUnaryMathOperation* instr);
   void DoMathRound(LUnaryMathOperation* instr);
   void DoMathSqrt(LUnaryMathOperation* instr);
-  void DoMathPowHalf(LUnaryMathOperation* instr);
   void DoMathLog(LUnaryMathOperation* instr);
   void DoMathTan(LUnaryMathOperation* instr);
   void DoMathCos(LUnaryMathOperation* instr);
index 4e5f2785497818ccd179cf2dc47a6d1ceb59c47e..ecb490de5e70707b5db5fff40a940b0f26ccb34c 100644 (file)
@@ -298,6 +298,12 @@ void LUnaryMathOperation::PrintDataTo(StringStream* stream) {
 }
 
 
+void LMathPowHalf::PrintDataTo(StringStream* stream) {
+  stream->Add("/pow_half ");
+  InputAt(0)->PrintTo(stream);
+}
+
+
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   InputAt(0)->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -1184,6 +1190,11 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
   } else {
     LOperand* input = UseRegisterAtStart(instr->value());
     LOperand* context = UseAny(instr->context());  // Deferred use by MathAbs.
+    if (op == kMathPowHalf) {
+      LOperand* temp = TempRegister();
+      LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp);
+      return DefineSameAsFirst(result);
+    }
     LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
                                                                   input);
     switch (op) {
@@ -1195,8 +1206,6 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
         return AssignEnvironment(DefineAsRegister(result));
       case kMathSqrt:
         return DefineSameAsFirst(result);
-      case kMathPowHalf:
-        return DefineSameAsFirst(result);
       default:
         UNREACHABLE();
         return NULL;
index 51706472258beb38902e4aebcc72664540a5af35..7e126ff03c4c24ee56fc561cef9a3e3c2fc60d8e 100644 (file)
@@ -123,6 +123,7 @@ class LCodeGen;
   V(LoadNamedField)                             \
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
+  V(MathPowHalf)                                \
   V(ModI)                                       \
   V(MulI)                                       \
   V(NumberTagD)                                 \
@@ -582,6 +583,24 @@ class LUnaryMathOperation: public LTemplateInstruction<1, 2, 0> {
 };
 
 
+class LMathPowHalf: public LTemplateInstruction<1, 2, 1> {
+ public:
+  LMathPowHalf(LOperand* context, LOperand* value, LOperand* temp) {
+    inputs_[1] = context;
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* context() { return inputs_[1]; }
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
+
+  virtual void PrintDataTo(StringStream* stream);
+};
+
+
 class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
  public:
   LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {