Title: [189744] trunk/Source/_javascript_Core
Revision
189744
Author
commit-qu...@webkit.org
Date
2015-09-14 11:30:08 -0700 (Mon, 14 Sep 2015)

Log Message

Implement the arithmetic instructions for floats in WebAssembly
https://bugs.webkit.org/show_bug.cgi?id=149102

Patch by Sukolsak Sakshuwong <sukol...@gmail.com> on 2015-09-14
Reviewed by Geoffrey Garen.

This patch implements the arithmetic instructions for floats (float32)
in WebAssembly by converting the float operands to doubles, performing
the equivalent double instructions, and converting the result back to
float. The asm.js spec says that "As proved in 'When is double rounding
innocuous?' (Figueroa 1995), both the 32- and 64-bit versions of
standard arithmetic operations produce equivalent results when given
32-bit inputs and coerced to 32-bit outputs."
(http://asmjs.org/spec/latest/#floatish)

This patch also pads WebAssembly call frames by maxFrameExtentForSlowPathCall,
so that there is no need to adjust the stack pointer every time we make
a slow path call.

* tests/stress/wasm-arithmetic-float32.js:
* tests/stress/wasm/arithmetic-float32.wasm:
* wasm/WASMFunctionCompiler.h:
(JSC::WASMFunctionCompiler::startFunction):
(JSC::WASMFunctionCompiler::buildUnaryF32):
(JSC::WASMFunctionCompiler::buildBinaryF32):
(JSC::WASMFunctionCompiler::callOperation):
(JSC::WASMFunctionCompiler::callAndUnboxResult):
(JSC::WASMFunctionCompiler::endFunction): Deleted.
(JSC::WASMFunctionCompiler::buildBinaryI32): Deleted.
* wasm/WASMFunctionParser.cpp:
(JSC::WASMFunctionParser::parseExpressionF32):
(JSC::WASMFunctionParser::parseUnaryExpressionF32):
(JSC::WASMFunctionParser::parseBinaryExpressionF32):
* wasm/WASMFunctionParser.h:
* wasm/WASMFunctionSyntaxChecker.h:
(JSC::WASMFunctionSyntaxChecker::buildUnaryF32):
(JSC::WASMFunctionSyntaxChecker::buildBinaryF32):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (189743 => 189744)


--- trunk/Source/_javascript_Core/ChangeLog	2015-09-14 17:58:11 UTC (rev 189743)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-09-14 18:30:08 UTC (rev 189744)
@@ -1,3 +1,42 @@
+2015-09-14  Sukolsak Sakshuwong  <sukol...@gmail.com>
+
+        Implement the arithmetic instructions for floats in WebAssembly
+        https://bugs.webkit.org/show_bug.cgi?id=149102
+
+        Reviewed by Geoffrey Garen.
+
+        This patch implements the arithmetic instructions for floats (float32)
+        in WebAssembly by converting the float operands to doubles, performing
+        the equivalent double instructions, and converting the result back to
+        float. The asm.js spec says that "As proved in 'When is double rounding
+        innocuous?' (Figueroa 1995), both the 32- and 64-bit versions of
+        standard arithmetic operations produce equivalent results when given
+        32-bit inputs and coerced to 32-bit outputs."
+        (http://asmjs.org/spec/latest/#floatish)
+
+        This patch also pads WebAssembly call frames by maxFrameExtentForSlowPathCall,
+        so that there is no need to adjust the stack pointer every time we make
+        a slow path call.
+
+        * tests/stress/wasm-arithmetic-float32.js:
+        * tests/stress/wasm/arithmetic-float32.wasm:
+        * wasm/WASMFunctionCompiler.h:
+        (JSC::WASMFunctionCompiler::startFunction):
+        (JSC::WASMFunctionCompiler::buildUnaryF32):
+        (JSC::WASMFunctionCompiler::buildBinaryF32):
+        (JSC::WASMFunctionCompiler::callOperation):
+        (JSC::WASMFunctionCompiler::callAndUnboxResult):
+        (JSC::WASMFunctionCompiler::endFunction): Deleted.
+        (JSC::WASMFunctionCompiler::buildBinaryI32): Deleted.
+        * wasm/WASMFunctionParser.cpp:
+        (JSC::WASMFunctionParser::parseExpressionF32):
+        (JSC::WASMFunctionParser::parseUnaryExpressionF32):
+        (JSC::WASMFunctionParser::parseBinaryExpressionF32):
+        * wasm/WASMFunctionParser.h:
+        * wasm/WASMFunctionSyntaxChecker.h:
+        (JSC::WASMFunctionSyntaxChecker::buildUnaryF32):
+        (JSC::WASMFunctionSyntaxChecker::buildBinaryF32):
+
 2015-09-13  Geoffrey Garen  <gga...@apple.com>
 
         Eden GC should not try to jettison old CodeBlocks in the remembered set

Modified: trunk/Source/_javascript_Core/tests/stress/wasm/arithmetic-float32.wasm (189743 => 189744)


--- trunk/Source/_javascript_Core/tests/stress/wasm/arithmetic-float32.wasm	2015-09-14 17:58:11 UTC (rev 189743)
+++ trunk/Source/_javascript_Core/tests/stress/wasm/arithmetic-float32.wasm	2015-09-14 18:30:08 UTC (rev 189744)
@@ -1 +1,3 @@
-wasm\xF7\x80?number
\ No newline at end of file
+wasm\xFD
+\x80?\x80\xA0\x80\xA0\xA1\x80\xA0\xA1\x80\xA0\xA1\x80\xA0\xA1\x80\xA0\x80\xA0\x80\xA0\x80\xA0
+numbernegateaddsubtractmultiplydivideabsoluteceilNumberfloorNumbersquareRoot	
\ No newline at end of file

Modified: trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic-float32.js (189743 => 189744)


--- trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic-float32.js	2015-09-14 17:58:11 UTC (rev 189743)
+++ trunk/Source/_javascript_Core/tests/stress/wasm-arithmetic-float32.js	2015-09-14 18:30:08 UTC (rev 189744)
@@ -12,13 +12,75 @@
     "use asm";
 
     var fround = global.Math.fround;
+    var abs = global.Math.abs;
+    var ceil = global.Math.ceil;
+    var floor = global.Math.floor;
+    var sqrt = global.Math.sqrt;
 
     function number() {
         return fround(0.5);
     }
 
+    function negate(x) {
+        x = fround(x);
+        return fround(-x);
+    }
+
+    function add(x, y) {
+        x = fround(x);
+        y = fround(y);
+        return fround(x + y);
+    }
+
+    function subtract(x, y) {
+        x = fround(x);
+        y = fround(y);
+        return fround(x - y);
+    }
+
+    function multiply(x, y) {
+        x = fround(x);
+        y = fround(y);
+        return fround(x * y);
+    }
+
+    function divide(x, y) {
+        x = fround(x);
+        y = fround(y);
+        return fround(x / y);
+    }
+
+    function absolute(x) {
+        x = fround(x);
+        return fround(abs(x));
+    }
+
+    function ceilNumber(x) {
+        x = fround(x);
+        return fround(ceil(x));
+    }
+
+    function floorNumber(x) {
+        x = fround(x);
+        return fround(floor(x));
+    }
+
+    function squareRoot(x) {
+        x = fround(x);
+        return fround(sqrt(x));
+    }
+
     return {
         number: number,
+        negate: negate,
+        add: add,
+        subtract: subtract,
+        multiply: multiply,
+        divide: divide,
+        absolute: absolute,
+        ceilNumber: ceilNumber,
+        floorNumber: floorNumber,
+        squareRoot: squareRoot,
     };
 }
 */
@@ -26,3 +88,18 @@
 var module = loadWebAssembly("wasm/arithmetic-float32.wasm");
 
 shouldBe(module.number(), 0.5);
+shouldBe(module.negate(0.1), -0.10000000149011612);
+shouldBe(module.add(0.1, 0.5), 0.6000000238418579);
+shouldBe(isNaN(module.add(0.1, NaN)), true);
+shouldBe(module.add(0.1, Infinity), Infinity);
+shouldBe(isNaN(module.add(Infinity, -Infinity)), true);
+shouldBe(module.subtract(0.1, 0.5), -0.4000000059604645);
+shouldBe(module.multiply(0.1, 0.5), 0.05000000074505806);
+shouldBe(module.divide(0.1, 0.5), 0.20000000298023224);
+shouldBe(module.divide(0.1, 0), Infinity);
+shouldBe(module.divide(0.1, -0), -Infinity);
+shouldBe(module.absolute(-4.2), 4.199999809265137);
+shouldBe(module.absolute(4.2), 4.199999809265137);
+shouldBe(module.ceilNumber(4.2), 5);
+shouldBe(module.floorNumber(4.2), 4);
+shouldBe(module.squareRoot(0.09), 0.30000001192092896);

Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h (189743 => 189744)


--- trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h	2015-09-14 17:58:11 UTC (rev 189743)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionCompiler.h	2015-09-14 18:30:08 UTC (rev 189744)
@@ -96,7 +96,7 @@
 
         m_beginLabel = label();
 
-        addPtr(TrustedImm32(-WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot)), GPRInfo::callFrameRegister, GPRInfo::regT1);
+        addPtr(TrustedImm32(-WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, GPRInfo::regT1);
         m_stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), GPRInfo::regT1);
 
         move(GPRInfo::regT1, stackPointerRegister);
@@ -165,8 +165,6 @@
         if (!m_divideErrorJumpList.empty()) {
             m_divideErrorJumpList.link(this);
 
-            if (maxFrameExtentForSlowPathCall)
-                addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
             setupArgumentsExecState();
             appendCallWithExceptionCheck(operationThrowDivideError);
         }
@@ -380,6 +378,38 @@
         return UNUSED;
     }
 
+    int buildUnaryF32(int, WASMOpExpressionF32 op)
+    {
+        loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+        switch (op) {
+        case WASMOpExpressionF32::Negate:
+            convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+            negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+            break;
+        case WASMOpExpressionF32::Abs:
+            convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+            absDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+            break;
+        case WASMOpExpressionF32::Ceil:
+            callOperation(ceilf, FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            break;
+        case WASMOpExpressionF32::Floor:
+            callOperation(floorf, FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            break;
+        case WASMOpExpressionF32::Sqrt:
+            convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+            sqrtDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+        }
+        storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+        return UNUSED;
+    }
+
     int buildBinaryI32(int, int, WASMOpExpressionI32 op)
     {
         load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0);
@@ -419,8 +449,6 @@
                 move(X86Registers::edx, GPRInfo::regT0);
 #else
             // FIXME: We should be able to do an inline div on ARMv7 and ARM64.
-            if (maxFrameExtentForSlowPathCall)
-                addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
             switch (op) {
             case WASMOpExpressionI32::SDiv:
                 callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
@@ -437,8 +465,6 @@
             default:
                 ASSERT_NOT_REACHED();
             }
-            if (maxFrameExtentForSlowPathCall)
-                addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister);
 #endif
             break;
         }
@@ -468,6 +494,34 @@
         return UNUSED;
     }
 
+    int buildBinaryF32(int, int, WASMOpExpressionF32 op)
+    {
+        loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
+        loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
+        convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+        convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
+        switch (op) {
+        case WASMOpExpressionF32::Add:
+            addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            break;
+        case WASMOpExpressionF32::Sub:
+            subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            break;
+        case WASMOpExpressionF32::Mul:
+            mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            break;
+        case WASMOpExpressionF32::Div:
+            divDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+        m_tempStackTop--;
+        storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
+        return UNUSED;
+    }
+
     int buildRelationalI32(int, int, WASMOpExpressionI32 op)
     {
         load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0);
@@ -787,6 +841,12 @@
     }
 #endif
 
+    void callOperation(float JIT_OPERATION (*operation)(float), FPRegisterID src, FPRegisterID dst)
+    {
+        setupArguments(src);
+        appendCallSetResult(operation, dst);
+    }
+
     void callOperation(int32_t JIT_OPERATION (*operation)(int32_t, int32_t), GPRReg src1, GPRReg src2, GPRReg dst)
     {
         setupArguments(src1, src2);
@@ -855,7 +915,7 @@
         m_callCompilationInfo.last().callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
 
         end.link(this);
-        addPtr(TrustedImm32(-WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot)), GPRInfo::callFrameRegister, stackPointerRegister);
+        addPtr(TrustedImm32(-WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, stackPointerRegister);
         checkStackPointerAlignment();
 
         switch (returnType) {

Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp (189743 => 189744)


--- trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp	2015-09-14 17:58:11 UTC (rev 189743)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionParser.cpp	2015-09-14 18:30:08 UTC (rev 189744)
@@ -750,6 +750,17 @@
             return parseGetLocalExpressionF32(context);
         case WASMOpExpressionF32::GetGlobal:
             return parseGetGlobalExpressionF32(context);
+        case WASMOpExpressionF32::Negate:
+        case WASMOpExpressionF32::Abs:
+        case WASMOpExpressionF32::Ceil:
+        case WASMOpExpressionF32::Floor:
+        case WASMOpExpressionF32::Sqrt:
+            return parseUnaryExpressionF32(context, op);
+        case WASMOpExpressionF32::Add:
+        case WASMOpExpressionF32::Sub:
+        case WASMOpExpressionF32::Mul:
+        case WASMOpExpressionF32::Div:
+            return parseBinaryExpressionF32(context, op);
         case WASMOpExpressionF32::SetLocal:
         case WASMOpExpressionF32::SetGlobal:
         case WASMOpExpressionF32::Load:
@@ -763,15 +774,6 @@
         case WASMOpExpressionF32::FromS32:
         case WASMOpExpressionF32::FromU32:
         case WASMOpExpressionF32::FromF64:
-        case WASMOpExpressionF32::Negate:
-        case WASMOpExpressionF32::Add:
-        case WASMOpExpressionF32::Sub:
-        case WASMOpExpressionF32::Mul:
-        case WASMOpExpressionF32::Div:
-        case WASMOpExpressionF32::Abs:
-        case WASMOpExpressionF32::Ceil:
-        case WASMOpExpressionF32::Floor:
-        case WASMOpExpressionF32::Sqrt:
             // FIXME: Implement these instructions.
             FAIL_WITH_MESSAGE("Unsupported instruction.");
         default:
@@ -840,6 +842,24 @@
 }
 
 template <class Context>
+ContextExpression WASMFunctionParser::parseUnaryExpressionF32(Context& context, WASMOpExpressionF32 op)
+{
+    ContextExpression _expression_ = parseExpressionF32(context);
+    PROPAGATE_ERROR();
+    return context.buildUnaryF32(_expression_, op);
+}
+
+template <class Context>
+ContextExpression WASMFunctionParser::parseBinaryExpressionF32(Context& context, WASMOpExpressionF32 op)
+{
+    ContextExpression left = parseExpressionF32(context);
+    PROPAGATE_ERROR();
+    ContextExpression right = parseExpressionF32(context);
+    PROPAGATE_ERROR();
+    return context.buildBinaryF32(left, right, op);
+}
+
+template <class Context>
 ContextExpression WASMFunctionParser::parseExpressionF64(Context& context)
 {
     bool hasImmediate;

Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h (189743 => 189744)


--- trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h	2015-09-14 17:58:11 UTC (rev 189743)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionParser.h	2015-09-14 18:30:08 UTC (rev 189744)
@@ -103,6 +103,8 @@
     template <class Context> ContextExpression parseGetLocalExpressionF32(Context&, uint32_t localIndex);
     template <class Context> ContextExpression parseGetLocalExpressionF32(Context&);
     template <class Context> ContextExpression parseGetGlobalExpressionF32(Context&);
+    template <class Context> ContextExpression parseUnaryExpressionF32(Context&, WASMOpExpressionF32);
+    template <class Context> ContextExpression parseBinaryExpressionF32(Context&, WASMOpExpressionF32);
 
     template <class Context> ContextExpression parseExpressionF64(Context&);
     template <class Context> ContextExpression parseConstantPoolIndexExpressionF64(Context&, uint32_t constantIndex);

Modified: trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h (189743 => 189744)


--- trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h	2015-09-14 17:58:11 UTC (rev 189743)
+++ trunk/Source/_javascript_Core/wasm/WASMFunctionSyntaxChecker.h	2015-09-14 18:30:08 UTC (rev 189744)
@@ -106,12 +106,23 @@
         return UNUSED;
     }
 
+    int buildUnaryF32(int, WASMOpExpressionF32)
+    {
+        return UNUSED;
+    }
+
     int buildBinaryI32(int, int, WASMOpExpressionI32)
     {
         m_tempStackTop--;
         return UNUSED;
     }
 
+    int buildBinaryF32(int, int, WASMOpExpressionF32)
+    {
+        m_tempStackTop--;
+        return UNUSED;
+    }
+
     int buildRelationalI32(int, int, WASMOpExpressionI32)
     {
         m_tempStackTop--;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to