Changeset 189405 in webkit


Ignore:
Timestamp:
Sep 4, 2015 5:14:21 PM (9 years ago)
Author:
commit-queue@webkit.org
Message:

Implement the division and modulo instructions in WebAssembly
https://bugs.webkit.org/show_bug.cgi?id=148791

Patch by Sukolsak Sakshuwong <Sukolsak Sakshuwong> on 2015-09-04
Reviewed by Geoffrey Garen.

This patch implements the unsigned division, signed modulo, and unsigned
modulo instructions for 32-bit integers in WebAssembly. It also
implements the context pool index instructions, which are needed for
testing. (pack-asmjs puts numbers that are used more than once in the
constant pool.)

  • assembler/X86Assembler.h:

(JSC::X86Assembler::divl_r):

  • tests/stress/wasm-arithmetic.js:
  • tests/stress/wasm-arithmetic.wasm:
  • wasm/WASMFunctionCompiler.h:

(JSC::operationMod):
(JSC::operationUnsignedDiv):
(JSC::operationUnsignedMod):
(JSC::WASMFunctionCompiler::buildBinaryI32):
(JSC::WASMFunctionCompiler::callOperation):

  • wasm/WASMFunctionParser.cpp:

(JSC::WASMFunctionParser::parseExpressionI32):
(JSC::WASMFunctionParser::parseConstantPoolIndexExpressionI32):

  • wasm/WASMFunctionParser.h:
Location:
trunk/Source/JavaScriptCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r189398 r189405  
     12015-09-04  Sukolsak Sakshuwong  <sukolsak@gmail.com>
     2
     3        Implement the division and modulo instructions in WebAssembly
     4        https://bugs.webkit.org/show_bug.cgi?id=148791
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This patch implements the unsigned division, signed modulo, and unsigned
     9        modulo instructions for 32-bit integers in WebAssembly. It also
     10        implements the context pool index instructions, which are needed for
     11        testing. (pack-asmjs puts numbers that are used more than once in the
     12        constant pool.)
     13
     14        * assembler/X86Assembler.h:
     15        (JSC::X86Assembler::divl_r):
     16        * tests/stress/wasm-arithmetic.js:
     17        * tests/stress/wasm-arithmetic.wasm:
     18        * wasm/WASMFunctionCompiler.h:
     19        (JSC::operationMod):
     20        (JSC::operationUnsignedDiv):
     21        (JSC::operationUnsignedMod):
     22        (JSC::WASMFunctionCompiler::buildBinaryI32):
     23        (JSC::WASMFunctionCompiler::callOperation):
     24        * wasm/WASMFunctionParser.cpp:
     25        (JSC::WASMFunctionParser::parseExpressionI32):
     26        (JSC::WASMFunctionParser::parseConstantPoolIndexExpressionI32):
     27        * wasm/WASMFunctionParser.h:
     28
    1292015-09-04  Basile Clement  <basile_clement@apple.com>
    230
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r189357 r189405  
    312312        GROUP3_OP_NOT  = 2,
    313313        GROUP3_OP_NEG  = 3,
     314        GROUP3_OP_DIV = 6,
    314315        GROUP3_OP_IDIV = 7,
    315316
     
    931932        m_formatter.oneByteOp(OP_IMUL_GvEvIz, dst, src);
    932933        m_formatter.immediate32(value);
     934    }
     935
     936    void divl_r(RegisterID dst)
     937    {
     938        m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_DIV, dst);
    933939    }
    934940
  • trunk/Source/JavaScriptCore/tests/stress/wasm-arithmetic.js

    r189396 r189405  
    4545    }
    4646
     47    function unsignedDivide() {
     48        return ((-1 >>> 0) / 2) | 0;
     49    }
     50
     51    function unsignedDivideByZero() {
     52        return ((-1 >>> 0) / 0) | 0;
     53    }
     54
     55    function modulo() {
     56        return (42 % 5) | 0;
     57    }
     58
     59    function moduloNegative() {
     60        return (-42 % 5) | 0;
     61    }
     62
     63    function moduloZero() {
     64        return (1 % 0) | 0;
     65    }
     66
     67    function moduloOverflow() {
     68        return (-2147483648 % -1) | 0;
     69    }
     70
     71    function unsignedModulo() {
     72        return ((-1 >>> 0) % 100000) | 0;
     73    }
     74
     75    function unsignedModuloZero() {
     76        return ((-1 >>> 0) % 0) | 0;
     77    }
     78
    4779    return {
    4880        addSubtract: addSubtract,
     
    5183        divideByZero: divideByZero,
    5284        divideOverflow: divideOverflow,
     85        unsignedDivide: unsignedDivide,
     86        unsignedDivideByZero: unsignedDivideByZero,
     87        modulo: modulo,
     88        moduloNegative: moduloNegative,
     89        moduloZero: moduloZero,
     90        moduloOverflow: moduloOverflow,
     91        unsignedModulo: unsignedModulo,
     92        unsignedModuloZero: unsignedModuloZero,
    5393    };
    5494}
     
    70110    module.divideOverflow();
    71111}, "Error: Division by zero or division overflow.");
     112
     113shouldBe(module.unsignedDivide(), 2147483647);
     114
     115shouldThrow(() => {
     116    module.unsignedDivideByZero();
     117}, "Error: Division by zero or division overflow.");
     118
     119shouldBe(module.modulo(), 2);
     120
     121shouldBe(module.moduloNegative(), -2);
     122
     123shouldThrow(() => {
     124    module.moduloZero();
     125}, "Error: Division by zero or division overflow.");
     126
     127shouldThrow(() => {
     128    module.moduloOverflow();
     129}, "Error: Division by zero or division overflow.");
     130
     131shouldBe(module.unsignedModulo(), 67295);
     132
     133shouldThrow(() => {
     134    module.unsignedModuloZero();
     135}, "Error: Division by zero or division overflow.");
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h

    r189396 r189405  
    4343    return left / right;
    4444}
     45
     46static int32_t JIT_OPERATION operationMod(int32_t left, int32_t right)
     47{
     48    return left % right;
     49}
     50
     51static uint32_t JIT_OPERATION operationUnsignedDiv(uint32_t left, uint32_t right)
     52{
     53    return left / right;
     54}
     55
     56static uint32_t JIT_OPERATION operationUnsignedMod(uint32_t left, uint32_t right)
     57{
     58    return left % right;
     59}
    4560#endif
    4661
     
    223238            sub32(GPRInfo::regT1, GPRInfo::regT0);
    224239            break;
    225         case WASMOpExpressionI32::SDiv: {
     240        case WASMOpExpressionI32::SDiv:
     241        case WASMOpExpressionI32::UDiv:
     242        case WASMOpExpressionI32::SMod:
     243        case WASMOpExpressionI32::UMod: {
    226244            m_divideErrorJumpList.append(branchTest32(Zero, GPRInfo::regT1));
    227             Jump denominatorNotNeg1 = branch32(NotEqual, GPRInfo::regT1, TrustedImm32(-1));
    228             m_divideErrorJumpList.append(branch32(Equal, GPRInfo::regT0, TrustedImm32(-2147483647-1)));
    229             denominatorNotNeg1.link(this);
     245            if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) {
     246                Jump denominatorNotNeg1 = branch32(NotEqual, GPRInfo::regT1, TrustedImm32(-1));
     247                m_divideErrorJumpList.append(branch32(Equal, GPRInfo::regT0, TrustedImm32(-2147483647-1)));
     248                denominatorNotNeg1.link(this);
     249            }
    230250#if CPU(X86) || CPU(X86_64)
    231251            ASSERT(GPRInfo::regT0 == X86Registers::eax);
    232252            move(GPRInfo::regT1, X86Registers::ecx);
    233             m_assembler.cdq();
    234             m_assembler.idivl_r(X86Registers::ecx);
     253            if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) {
     254                m_assembler.cdq();
     255                m_assembler.idivl_r(X86Registers::ecx);
     256            } else {
     257                ASSERT(op == WASMOpExpressionI32::UDiv || op == WASMOpExpressionI32::UMod);
     258                xor32(X86Registers::edx, X86Registers::edx);
     259                m_assembler.divl_r(X86Registers::ecx);
     260            }
     261            if (op == WASMOpExpressionI32::SMod || op == WASMOpExpressionI32::UMod)
     262                move(X86Registers::edx, GPRInfo::regT0);
    235263#else
     264            // FIXME: We should be able to do an inline div on ARMv7 and ARM64.
    236265            if (maxFrameExtentForSlowPathCall)
    237266                addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
    238             callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
     267            switch (op) {
     268            case WASMOpExpressionI32::SDiv:
     269                callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
     270                break;
     271            case WASMOpExpressionI32::UDiv:
     272                callOperation(operationUnsignedDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
     273                break;
     274            case WASMOpExpressionI32::SMod:
     275                callOperation(operationMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
     276                break;
     277            case WASMOpExpressionI32::UMod:
     278                callOperation(operationUnsignedMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
     279                break;
     280            default:
     281                ASSERT_NOT_REACHED();
     282            }
    239283            if (maxFrameExtentForSlowPathCall)
    240284                addPtr(TrustedImm32(maxFrameExtentForSlowPathCall), stackPointerRegister);
     
    287331    }
    288332
     333    void callOperation(uint32_t JIT_OPERATION (*operation)(uint32_t, uint32_t), GPRReg src1, GPRReg src2, GPRReg dst)
     334    {
     335        setupArguments(src1, src2);
     336        appendCall(operation);
     337        move(GPRInfo::returnValueGPR, dst);
     338    }
     339
    289340    unsigned m_stackHeight;
    290341    unsigned m_numberOfLocals;
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.cpp

    r189396 r189405  
    425425    if (!hasImmediate) {
    426426        switch (op) {
     427        case WASMOpExpressionI32::ConstantPoolIndex:
     428            return parseConstantPoolIndexExpressionI32(context);
    427429        case WASMOpExpressionI32::Immediate:
    428430            return parseImmediateExpressionI32(context);
     
    432434        case WASMOpExpressionI32::Sub:
    433435        case WASMOpExpressionI32::SDiv:
     436        case WASMOpExpressionI32::UDiv:
     437        case WASMOpExpressionI32::SMod:
     438        case WASMOpExpressionI32::UMod:
    434439            return parseBinaryExpressionI32(context, op);
    435         case WASMOpExpressionI32::ConstantPoolIndex:
    436440        case WASMOpExpressionI32::GetGlobal:
    437441        case WASMOpExpressionI32::SetLocal:
     
    462466        case WASMOpExpressionI32::Negate:
    463467        case WASMOpExpressionI32::Mul:
    464         case WASMOpExpressionI32::UDiv:
    465         case WASMOpExpressionI32::SMod:
    466         case WASMOpExpressionI32::UMod:
    467468        case WASMOpExpressionI32::BitNot:
    468469        case WASMOpExpressionI32::BitOr:
     
    508509    } else {
    509510        switch (opWithImmediate) {
     511        case WASMOpExpressionI32WithImmediate::ConstantPoolIndex:
     512            return parseConstantPoolIndexExpressionI32(context, immediate);
    510513        case WASMOpExpressionI32WithImmediate::Immediate:
    511514            return parseImmediateExpressionI32(context, immediate);
    512515        case WASMOpExpressionI32WithImmediate::GetLocal:
    513516            return parseGetLocalExpressionI32(context, immediate);
    514         case WASMOpExpressionI32WithImmediate::ConstantPoolIndex:
    515             // FIXME: Implement these instructions.
    516             FAIL_WITH_MESSAGE("Unsupported instruction.");
    517517        default:
    518518            ASSERT_NOT_REACHED();
     
    520520    }
    521521    return 0;
     522}
     523
     524template <class Context>
     525ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionI32(Context& context, uint32_t constantPoolIndex)
     526{
     527    FAIL_IF_FALSE(constantPoolIndex < m_module->i32Constants().size(), "The constant pool index is incorrect.");
     528    return context.buildImmediateI32(m_module->i32Constants()[constantPoolIndex]);
     529}
     530
     531template <class Context>
     532ContextExpression WASMFunctionParser::parseConstantPoolIndexExpressionI32(Context& context)
     533{
     534    uint32_t constantPoolIndex;
     535    READ_COMPACT_UINT32_OR_FAIL(constantPoolIndex, "Cannot read the constant pool index.");
     536    return parseConstantPoolIndexExpressionI32(context, constantPoolIndex);
    522537}
    523538
  • trunk/Source/JavaScriptCore/wasm/WASMFunctionParser.h

    r189382 r189405  
    7979
    8080    template <class Context> ContextExpression parseExpressionI32(Context&);
     81    template <class Context> ContextExpression parseConstantPoolIndexExpressionI32(Context&, uint32_t constantPoolIndex);
     82    template <class Context> ContextExpression parseConstantPoolIndexExpressionI32(Context&);
    8183    template <class Context> ContextExpression parseImmediateExpressionI32(Context&, uint32_t immediate);
    8284    template <class Context> ContextExpression parseImmediateExpressionI32(Context&);
Note: See TracChangeset for help on using the changeset viewer.