Просмотр исходного кода

Type specialize Math.pow in JIT

Tom Tan 10 лет назад
Родитель
Сommit
4c857b4987

+ 23 - 1
lib/Backend/GlobOpt.cpp

@@ -9567,7 +9567,6 @@ GlobOpt::TypeSpecializeInlineBuiltInBinary(IR::Instr **pInstr, Value *src1Val, V
     switch(instr->m_opcode)
     {
         case Js::OpCode::InlineMathAtan2:
-        case Js::OpCode::InlineMathPow:
         {
             Js::BuiltinFunction builtInId = Js::JavascriptLibrary::GetBuiltInInlineCandidateId(instr->m_opcode);   // From actual instr, not profile based.
             Js::BuiltInFlags builtInFlags = Js::JavascriptLibrary::GetFlagsForBuiltIn(builtInId);
@@ -9585,6 +9584,29 @@ GlobOpt::TypeSpecializeInlineBuiltInBinary(IR::Instr **pInstr, Value *src1Val, V
             break;
         }
 
+        case Js::OpCode::InlineMathPow:
+        {
+            if (src2Val->GetValueInfo()->IsLikelyInt())
+            {
+                bool lossy = false;
+
+                IR::Opnd* src1 = instr->GetSrc1();
+                this->ToFloat64(instr, src1, this->currentBlock, src1Val, nullptr, IR::BailOutPrimitiveButString);
+
+                IR::Opnd* src2 = instr->GetSrc2();
+                this->ToInt32(instr, src2, this->currentBlock, src2Val, nullptr, lossy);
+
+                IR::Opnd* dst = instr->GetDst();
+                this->ToFloat64Dst(instr, dst->AsRegOpnd(), this->currentBlock);
+            }
+            else
+            {
+                this->TypeSpecializeFloatBinary(instr, src1Val, src2Val, pDstVal);
+            }
+
+            break;
+        }
+
         case Js::OpCode::InlineMathImul:
         {
             Assert(this->DoAggressiveIntTypeSpec());

+ 1 - 0
lib/Backend/JnHelperMethodList.h

@@ -505,6 +505,7 @@ HELPERCALL(BoxStackNumber, Js::JavascriptNumber::BoxStackNumber, 0)
 HELPERCALL(GetNonzeroInt32Value_NoTaggedIntCheck, Js::JavascriptNumber::GetNonzeroInt32Value_NoTaggedIntCheck, 0)
 HELPERCALL(IsNegZero, Js::JavascriptNumber::IsNegZero, 0)
 
+HELPERCALL(DirectMath_PowDoubleInt, (double(*)(double, int32))Js::JavascriptNumber::DirectPowDoubleInt, 0)
 HELPERCALL(DirectMath_Pow, (double(*)(double, double))Js::JavascriptNumber::DirectPow, 0)
 HELPERCALL_MATH(DirectMath_Random,  (double(*)(Js::ScriptContext*))Js::JavascriptMath::Random, (double(*)(Js::ScriptContext*))Js::SSE2::JavascriptMath::Random, 0)
 

+ 1 - 1
lib/Backend/Lower.cpp

@@ -583,7 +583,7 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
             break;
 
         case Js::OpCode::InlineMathPow:
-            m_lowererMD.GenerateFastInlineBuiltInCall(instr, IR::HelperDirectMath_Pow);
+            m_lowererMD.GenerateFastInlineBuiltInMathPow(instr);
             break;
 
         case Js::OpCode::InlineMathSin:

+ 24 - 1
lib/Backend/LowerMDShared.cpp

@@ -8691,7 +8691,6 @@ void LowererMD::GenerateFastInlineBuiltInCall(IR::Instr* instr, IR::JnHelperMeth
     case Js::OpCode::InlineMathCos:
     case Js::OpCode::InlineMathExp:
     case Js::OpCode::InlineMathLog:
-    case Js::OpCode::InlineMathPow:
     case Js::OpCode::Expo_A:        //** operator reuses InlineMathPow fastpath
     case Js::OpCode::InlineMathSin:
     case Js::OpCode::InlineMathTan:
@@ -9321,6 +9320,30 @@ void LowererMD::GenerateFastInlineBuiltInMathAbs(IR::Instr* inlineInstr)
     }
 }
 
+void LowererMD::GenerateFastInlineBuiltInMathPow(IR::Instr* instr)
+{
+    IR::JnHelperMethod directPowHelper = (IR::JnHelperMethod)0;
+
+    if (instr->GetSrc2()->IsFloat())
+    {
+        AssertMsg(instr->GetSrc1()->IsFloat(), "Math.Pow(int, double) should not generated by GlobOpt");
+        directPowHelper = IR::HelperDirectMath_Pow;
+    }
+    else if (instr->GetSrc1()->IsFloat())
+    {
+        directPowHelper = IR::HelperDirectMath_PowDoubleInt;
+    }
+    else
+    {
+        AssertMsg(0, "Math.Pow(int, int) spec NYI");
+    }
+
+    LoadHelperArgument(instr, instr->UnlinkSrc2());
+    LoadHelperArgument(instr, instr->UnlinkSrc1());
+
+    ChangeToHelperCall(instr, directPowHelper);
+}
+
 void
 LowererMD::FinalLower()
 {

+ 1 - 0
lib/Backend/LowerMDShared.h

@@ -177,6 +177,7 @@ public:
             void            GenerateFastInlineBuiltInCall(IR::Instr* instr, IR::JnHelperMethod helperMethod);
             void            HelperCallForAsmMathBuiltin(IR::Instr* instr, IR::JnHelperMethod helperMethodFloat, IR::JnHelperMethod helperMethodDouble);
             void            GenerateFastInlineBuiltInMathAbs(IR::Instr* instr);
+            void            GenerateFastInlineBuiltInMathPow(IR::Instr* instr);
             IR::Opnd*       IsOpndNegZero(IR::Opnd* opnd, IR::Instr* instr);
             IR::Instr *     CloneSlowPath(IR::Instr * instrEndFloatRange, IR::Instr * instrInsert);
             bool            IsCloneDone(IR::Instr * instr, BVSparse<JitArenaAllocator> *bvTmps);

+ 27 - 26
lib/Runtime/Library/JavascriptNumber.cpp

@@ -162,6 +162,33 @@ namespace Js
         return Is_NoTaggedIntCheck(object) && TryGetInt32Value(GetValue(object), &i) ? i : 0;
     }
 
+    double JavascriptNumber::DirectPowDoubleInt(double x, int32 y)
+    {
+        // For exponent in [-8, 8], aggregate the product according to binary representation
+        // of exponent. This acceleration may lead to significant deviation for larger exponent
+        if (y >= -8 && y <= 8)
+        {
+            uint32 uexp = static_cast<uint32>(y >= 0 ? y : -y);
+            for (double result = 1.0; ; x *= x)
+            {
+                if ((uexp & 1) != 0)
+                {
+                    result *= x;
+                }
+                if ((uexp >>= 1) == 0)
+                {
+                    return (y < 0 ? (1.0 / result) : result);
+                }
+            }
+        }
+
+#if _M_IX86
+        return JavascriptNumber::DirectPow(x, static_cast<double>(y));
+#else
+        return ::pow(x, y);
+#endif
+    }
+
 #if _M_IX86
 
     extern "C" double __cdecl __libm_sse2_pow(double, double);
@@ -209,7 +236,6 @@ namespace Js
         }
     }
 
-
 #elif defined(_M_AMD64) || defined(_M_ARM32_OR_ARM64)
 
     double JavascriptNumber::DirectPow(double x, double y)
@@ -222,7 +248,6 @@ namespace Js
         // For AMD64/ARM calling convention already uses SSE2/VFP registers so we don't have to use assembler.
         // We can't just use "if (0 == y)" because NaN compares
         // equal to 0 according to our compilers.
-        int32 intY;
         if (0 == NumberUtilities::LuLoDbl(y) && 0 == (NumberUtilities::LuHiDbl(y) & 0x7FFFFFFF))
         {
             // pow(x, 0) = 1 even if x is NaN.
@@ -233,30 +258,6 @@ namespace Js
             // pow([+/-] 1, Infinity) = NaN according to javascript, but not for CRT pow.
             return JavascriptNumber::NaN;
         }
-        else if(TryGetInt32Value(y, &intY))
-        {
-            // For exponent in [-8, 8], aggregate the product according to binary representation
-            // of exponent. This acceleration may lead to significant deviation for larger exponent
-            if (intY >= -8 && intY <= 8)
-            {
-                uint32 uexp = static_cast<uint32>(intY >= 0 ? intY : -intY);
-                for (double result = 1.0; ; x *= x)
-                {
-                    if ((uexp & 1) != 0)
-                    {
-                        result *= x;
-                    }
-                    if ((uexp >>= 1) == 0)
-                    {
-                        return (intY < 0 ? (1.0 / result) : result);
-                    }
-                }
-            }
-            else
-            {
-                return ::pow(x, intY);
-            }
-        }
 
         return ::pow(x, y);
     }

+ 1 - 0
lib/Runtime/Library/JavascriptNumber.h

@@ -41,6 +41,7 @@ namespace Js
         static Var ToVar(int64 nValue, ScriptContext* scriptContext);
         static Var ToVar(uint64 nValue, ScriptContext* scriptContext);
         static double GetValue(Var aValue);
+        static double DirectPowDoubleInt(double, int32);
         static double DirectPow(double, double);
 
         static bool TryToVarFast(int32 nValue, Var* result);

+ 1 - 1
lib/Runtime/LibraryFunction.h

@@ -49,7 +49,7 @@ LIBRARY_FUNCTION(Math,          Floor,              1,    BIF_TypeSpecDstToInt |
 LIBRARY_FUNCTION(Math,          Log,                1,    BIF_TypeSpecUnaryToFloat                          , Math::EntryInfo::Log)
 LIBRARY_FUNCTION(Math,          Max,                2,    BIF_TypeSpecSrcAndDstToFloatOrInt                 , Math::EntryInfo::Max)
 LIBRARY_FUNCTION(Math,          Min,                2,    BIF_TypeSpecSrcAndDstToFloatOrInt                 , Math::EntryInfo::Min)
-LIBRARY_FUNCTION(Math,          Pow,                2,    BIF_TypeSpecAllToFloat                            , Math::EntryInfo::Pow)
+LIBRARY_FUNCTION(Math,          Pow,                2,    BIF_TypeSpecSrcAndDstToFloatOrInt                 , Math::EntryInfo::Pow)
 LIBRARY_FUNCTION(Math,          Imul,               2,    BIF_TypeSpecAllToInt                              , Math::EntryInfo::Imul)
 LIBRARY_FUNCTION(Math,          Clz32,              1,    BIF_TypeSpecAllToInt                              , Math::EntryInfo::Clz32)
 LIBRARY_FUNCTION(Array,         Push,               2,    BIF_UseSrc0 | BIF_IgnoreDst | BIF_TypeSpecSrc1ToFloatOrInt, JavascriptArray::EntryInfo::Push)