[JSC] Implement Math.clz32(), remove Number.clz()
https://bugs.webkit.org/show_bug.cgi?id=144205

Reviewed by Michael Saboff.

Source/JavaScriptCore:

This patch adds the ES6 function Math.clz32(), and remove the non-standard
Number.clz(). Number.clz() probably came from an older draft.

The new function has a corresponding instrinsic: Clz32Intrinsic,
and a corresponding DFG node: ArithClz32, optimized all the way to LLVM.

* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::countLeadingZeros32):
* assembler/X86Assembler.h:
(JSC::X86Assembler::bsr_rr):
The x86 assembler did not have countLeadingZeros32() because there is
no native CLZ instruction on that architecture.

I have added the version with bsr + branches for the case of zero.
An other popular version uses cmov to handle the case of zero. I kept
it simple since the Assembler has no support for cmov.

It is unlikely to matter much. If the code is hot enough, LLVM picks
something good based on the surrounding code.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
Constant handling + effect propagation. The node only produces integer (between 0 and 32).

* dfg/DFGBackwardsPropagationPhase.cpp:
(JSC::DFG::BackwardsPropagationPhase::propagate):
Thanks to the definition of toUint32(), we can ignore plenty of details
from doubles.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileArithClz32):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLIntrinsicRepository.h:
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileArithClz32):
* ftl/FTLOutput.h:
(JSC::FTL::Output::ctlz32):
* jit/ThunkGenerators.cpp:
(JSC::clz32ThunkGenerator):
* jit/ThunkGenerators.h:
* runtime/Intrinsic.h:
* runtime/MathCommon.h:
(JSC::clz32):
Fun fact: InstCombine does not recognize this pattern to eliminate
the branch which makes our FTL version better than the C version.

* runtime/MathObject.cpp:
(JSC::MathObject::finishCreation):
(JSC::mathProtoFuncClz32):
* runtime/NumberPrototype.cpp:
(JSC::clz): Deleted.
(JSC::numberProtoFuncClz): Deleted.
* runtime/VM.cpp:
(JSC::thunkGeneratorForIntrinsic):
* tests/stress/math-clz32-basics.js: Added.
(mathClz32OnInteger):
(testMathClz32OnIntegers):
(verifyMathClz32OnIntegerWithOtherTypes):
(mathClz32OnDouble):
(testMathClz32OnDoubles):
(verifyMathClz32OnDoublesWithOtherTypes):
(mathClz32NoArguments):
(mathClz32TooManyArguments):
(testMathClz32OnConstants):
(mathClz32StructTransition):
(Math.clz32):

LayoutTests:

Basic conformance tests.

* js/Object-getOwnPropertyNames-expected.txt:
* js/math-clz32-expected.txt: Added.
* js/math-clz32.html: Renamed from LayoutTests/js/number-clz.html.
* js/number-clz-expected.txt: Removed.
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/math-clz32.js: Added.
(objectConvertToString.toString):
(objectRecordToStringCall.toString):
(objectThrowOnToString.toString):
(objectWithValueOf.valueOf):
(objectThrowOnValueOf.valueOf):
(objectThrowOnValueOf.toString):
(objectRecordValueOfCall.valueOf):
(objectRecordConversionCalls.toString):
(objectRecordConversionCalls.valueOf):
* js/script-tests/number-clz.js: Removed.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@183358 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
index 596fb55..8316af1 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
@@ -425,7 +425,18 @@
         }
         break;
     }
-        
+
+    case ArithClz32: {
+        JSValue operand = forNode(node->child1()).value();
+        if (operand && operand.isNumber()) {
+            uint32_t value = toUInt32(operand.asNumber());
+            setConstant(node, jsNumber(clz32(value)));
+            break;
+        }
+        forNode(node).setType(SpecInt32);
+        break;
+    }
+
     case MakeRope: {
         forNode(node).set(m_graph, m_graph.m_vm.stringStructure.get());
         break;
diff --git a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
index 271dbc2..59817de 100644
--- a/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp
@@ -259,7 +259,14 @@
             node->child2()->mergeFlags(flags);
             break;
         }
-            
+
+        case ArithClz32: {
+            flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther | ~NodeBytecodeUsesAsArrayIndex);
+            flags |= NodeBytecodeUsesAsInt;
+            node->child1()->mergeFlags(flags);
+            break;
+        }
+
         case ArithSub: {
             if (isNotNegZero(node->child1().node()) || isNotPosZero(node->child2().node()))
                 flags &= ~NodeBytecodeNeedsNegZero;
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 4f1051f..579b3ce 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -2000,6 +2000,16 @@
         set(VirtualRegister(resultOperand), charCode);
         return true;
     }
+    case Clz32Intrinsic: {
+        insertChecks();
+        if (argumentCountIncludingThis == 1)
+            set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_graph.freeze(jsNumber(32)))));
+        else {
+            Node* operand = get(virtualRegisterForArgument(1, registerOffset));
+            set(VirtualRegister(resultOperand), addToGraph(ArithClz32, operand));
+        }
+        return true;
+    }
     case FromCharCodeIntrinsic: {
         if (argumentCountIncludingThis != 2)
             return false;
diff --git a/Source/JavaScriptCore/dfg/DFGClobberize.h b/Source/JavaScriptCore/dfg/DFGClobberize.h
index 45b8d07..2029298 100644
--- a/Source/JavaScriptCore/dfg/DFGClobberize.h
+++ b/Source/JavaScriptCore/dfg/DFGClobberize.h
@@ -129,6 +129,7 @@
     case BitURShift:
     case ArithIMul:
     case ArithAbs:
+    case ArithClz32:
     case ArithMin:
     case ArithMax:
     case ArithPow:
diff --git a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
index 97ab39e..eafe633 100644
--- a/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
@@ -72,6 +72,7 @@
     case UInt32ToNumber:
     case DoubleAsInt32:
     case ArithAdd:
+    case ArithClz32:
     case ArithSub:
     case ArithNegate:
     case ArithMul:
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 5e5378a..e9ca28b 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -119,6 +119,12 @@
             node->child2().setUseKind(Int32Use);
             break;
         }
+
+        case ArithClz32: {
+            fixIntConvertingEdge(node->child1());
+            node->setArithMode(Arith::Unchecked);
+            break;
+        }
             
         case UInt32ToNumber: {
             fixIntConvertingEdge(node->child1());
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index b42dcd2..abab2a6 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -132,6 +132,7 @@
     \
     /* Nodes for arithmetic operations. */\
     macro(ArithAdd, NodeResultNumber) \
+    macro(ArithClz32, NodeResultInt32) \
     macro(ArithSub, NodeResultNumber) \
     macro(ArithNegate, NodeResultNumber) \
     macro(ArithMul, NodeResultNumber) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index f63f0da..533af1b 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -178,7 +178,8 @@
         case BitRShift:
         case BitLShift:
         case BitURShift:
-        case ArithIMul: {
+        case ArithIMul:
+        case ArithClz32: {
             changed |= setPrediction(SpecInt32);
             break;
         }
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index d29f318..dc08c43 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -142,6 +142,7 @@
     case UInt32ToNumber:
     case DoubleAsInt32:
     case ArithAdd:
+    case ArithClz32:
     case ArithSub:
     case ArithNegate:
     case ArithMul:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 6a13659..a7417df 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -2821,6 +2821,17 @@
     cellResult(resultGPR, node);
 }
 
+void SpeculativeJIT::compileArithClz32(Node* node)
+{
+    ASSERT_WITH_MESSAGE(node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use, "The Fixup phase should have enforced a Int32 operand.");
+    SpeculateInt32Operand value(this, node->child1());
+    GPRTemporary result(this, Reuse, value);
+    GPRReg valueReg = value.gpr();
+    GPRReg resultReg = result.gpr();
+    m_jit.countLeadingZeros32(valueReg, resultReg);
+    int32Result(resultReg, node);
+}
+
 void SpeculativeJIT::compileArithSub(Node* node)
 {
     switch (node->binaryUseKind()) {
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index c26ee80..85b35dc 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2182,6 +2182,7 @@
     void compileDoubleAsInt32(Node*);
     void compileAdd(Node*);
     void compileMakeRope(Node*);
+    void compileArithClz32(Node*);
     void compileArithSub(Node*);
     void compileArithNegate(Node*);
     void compileArithMul(Node*);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 9fece2d..7dd2660 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2011,6 +2011,10 @@
         compileAdd(node);
         break;
 
+    case ArithClz32:
+        compileArithClz32(node);
+        break;
+
     case MakeRope:
         compileMakeRope(node);
         break;
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 8e58d0f..3007b4b 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -2153,6 +2153,10 @@
     case ArithAdd:
         compileAdd(node);
         break;
+
+    case ArithClz32:
+        compileArithClz32(node);
+        break;
         
     case MakeRope:
         compileMakeRope(node);