⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 183963 in webkit


Ignore:
Timestamp:
May 7, 2015, 5:23:32 PM (11 years ago)
Author:
benjamin@webkit.org
Message:

[JSC] Add basic DFG/FTL support for Math.round
https://bugs.webkit.org/show_bug.cgi?id=144725

Patch by Benjamin Poulain <bpoulain@apple.com> on 2015-05-07
Reviewed by Filip Pizlo.

This patch adds two optimizations targeting Math.round():
-Add a DFGNode ArithRound corresponding to the intrinsic RoundIntrinsic.
-Change the MacroAssembler to be stricter on how we fail to convert a double

to ingeter. Previously, any number valued zero would fail, now we only
fail for -0.

Since ArithRound speculate it produces int32, the MacroAssembler assembler
part became necessary because zero is a pretty common output of Math.round()
and we would OSR exit a lot (and eventually recompile for doubles).

The implementation itself of the inline Math.round() is exactly the same
as the C function that exists for Math.round(). We can very likely do better
but it is a good start known to be valid and inlining alone alread provides
significant speedups.

  • assembler/X86Assembler.h:

(JSC::X86Assembler::movmskpd_rr):

  • assembler/MacroAssemblerX86Common.h:

(JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32):
When we have a zero, get the sign bit out of the double and check if is one.

I'll look into doing the same improvement for ARM.

  • bytecode/SpeculatedType.cpp:

(JSC::typeOfDoubleRounding):
(JSC::typeOfDoubleFRound): Deleted.

  • bytecode/SpeculatedType.h:
  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • 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/DFGGraph.h:

(JSC::DFG::Graph::roundShouldSpeculateInt32):
(JSC::DFG::Graph::negateShouldSpeculateMachineInt): Deleted.

  • dfg/DFGNode.h:

(JSC::DFG::Node::arithNodeFlags):
(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::hasArithMode):

  • dfg/DFGNodeType.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileArithRound):

  • 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::convertDoubleToInt32):
(JSC::FTL::LowerDFGToLLVM::compileDoubleAsInt32):
(JSC::FTL::LowerDFGToLLVM::compileArithRound):

  • ftl/FTLOutput.h:

(JSC::FTL::Output::ceil64):

  • jit/ThunkGenerators.cpp:
  • runtime/MathCommon.cpp:
  • runtime/MathCommon.h:
  • runtime/MathObject.cpp:

(JSC::mathProtoFuncRound):

  • tests/stress/math-round-basics.js: Added.

(mathRoundOnIntegers):
(mathRoundOnDoubles):
(mathRoundOnBooleans):
(uselessMathRound):
(mathRoundWithOverflow):
(mathRoundConsumedAsDouble):
(mathRoundDoesNotCareAboutMinusZero):
(mathRoundNoArguments):
(mathRoundTooManyArguments):
(testMathRoundOnConstants):
(mathRoundStructTransition):
(Math.round):

Location:
trunk/Source/JavaScriptCore
Files:
1 added
28 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r183962 r183963  
     12015-05-07  Benjamin Poulain  <bpoulain@apple.com>
     2
     3        [JSC] Add basic DFG/FTL support for Math.round
     4        https://bugs.webkit.org/show_bug.cgi?id=144725
     5
     6        Reviewed by Filip Pizlo.
     7
     8        This patch adds two optimizations targeting Math.round():
     9        -Add a DFGNode ArithRound corresponding to the intrinsic RoundIntrinsic.
     10        -Change the MacroAssembler to be stricter on how we fail to convert a double
     11         to ingeter. Previously, any number valued zero would fail, now we only
     12         fail for -0.
     13
     14        Since ArithRound speculate it produces int32, the MacroAssembler assembler
     15        part became necessary because zero is a pretty common output of Math.round()
     16        and we would OSR exit a lot (and eventually recompile for doubles).
     17
     18        The implementation itself of the inline Math.round() is exactly the same
     19        as the C function that exists for Math.round(). We can very likely do better
     20        but it is a good start known to be valid and inlining alone alread provides
     21        significant speedups.
     22
     23        * assembler/X86Assembler.h:
     24        (JSC::X86Assembler::movmskpd_rr):
     25        * assembler/MacroAssemblerX86Common.h:
     26        (JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32):
     27        When we have a zero, get the sign bit out of the double and check if is one.
     28
     29        I'll look into doing the same improvement for ARM.
     30
     31        * bytecode/SpeculatedType.cpp:
     32        (JSC::typeOfDoubleRounding):
     33        (JSC::typeOfDoubleFRound): Deleted.
     34        * bytecode/SpeculatedType.h:
     35        * dfg/DFGAbstractInterpreterInlines.h:
     36        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     37        * dfg/DFGByteCodeParser.cpp:
     38        (JSC::DFG::ByteCodeParser::handleIntrinsic):
     39        * dfg/DFGClobberize.h:
     40        (JSC::DFG::clobberize):
     41        * dfg/DFGDoesGC.cpp:
     42        (JSC::DFG::doesGC):
     43        * dfg/DFGFixupPhase.cpp:
     44        (JSC::DFG::FixupPhase::fixupNode):
     45        * dfg/DFGGraph.h:
     46        (JSC::DFG::Graph::roundShouldSpeculateInt32):
     47        (JSC::DFG::Graph::negateShouldSpeculateMachineInt): Deleted.
     48        * dfg/DFGNode.h:
     49        (JSC::DFG::Node::arithNodeFlags):
     50        (JSC::DFG::Node::hasHeapPrediction):
     51        (JSC::DFG::Node::hasArithMode):
     52        * dfg/DFGNodeType.h:
     53        * dfg/DFGPredictionPropagationPhase.cpp:
     54        (JSC::DFG::PredictionPropagationPhase::propagate):
     55        * dfg/DFGSafeToExecute.h:
     56        (JSC::DFG::safeToExecute):
     57        * dfg/DFGSpeculativeJIT.cpp:
     58        (JSC::DFG::SpeculativeJIT::compileArithRound):
     59        * dfg/DFGSpeculativeJIT.h:
     60        * dfg/DFGSpeculativeJIT32_64.cpp:
     61        (JSC::DFG::SpeculativeJIT::compile):
     62        * dfg/DFGSpeculativeJIT64.cpp:
     63        (JSC::DFG::SpeculativeJIT::compile):
     64        * ftl/FTLCapabilities.cpp:
     65        (JSC::FTL::canCompile):
     66        * ftl/FTLIntrinsicRepository.h:
     67        * ftl/FTLLowerDFGToLLVM.cpp:
     68        (JSC::FTL::LowerDFGToLLVM::compileNode):
     69        (JSC::FTL::LowerDFGToLLVM::convertDoubleToInt32):
     70        (JSC::FTL::LowerDFGToLLVM::compileDoubleAsInt32):
     71        (JSC::FTL::LowerDFGToLLVM::compileArithRound):
     72        * ftl/FTLOutput.h:
     73        (JSC::FTL::Output::ceil64):
     74        * jit/ThunkGenerators.cpp:
     75        * runtime/MathCommon.cpp:
     76        * runtime/MathCommon.h:
     77        * runtime/MathObject.cpp:
     78        (JSC::mathProtoFuncRound):
     79        * tests/stress/math-round-basics.js: Added.
     80        (mathRoundOnIntegers):
     81        (mathRoundOnDoubles):
     82        (mathRoundOnBooleans):
     83        (uselessMathRound):
     84        (mathRoundWithOverflow):
     85        (mathRoundConsumedAsDouble):
     86        (mathRoundDoesNotCareAboutMinusZero):
     87        (mathRoundNoArguments):
     88        (mathRoundTooManyArguments):
     89        (testMathRoundOnConstants):
     90        (mathRoundStructTransition):
     91        (Math.round):
     92
    1932015-05-07  Saam Barati  <saambarati1@gmail.com>
    294
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h

    r183358 r183963  
    922922
    923923        // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
     924#if CPU(X86_64)
     925        if (negZeroCheck) {
     926            Jump valueIsNonZero = branchTest32(NonZero, dest);
     927            m_assembler.movmskpd_rr(src, scratchRegister);
     928            failureCases.append(branchTest32(NonZero, scratchRegister, TrustedImm32(1)));
     929            valueIsNonZero.link(this);
     930        }
     931#else
    924932        if (negZeroCheck)
    925933            failureCases.append(branchTest32(Zero, dest));
     934#endif
    926935
    927936        // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
  • trunk/Source/JavaScriptCore/assembler/X86Assembler.h

    r183358 r183963  
    254254        OP2_SUBSD_VsdWsd    = 0x5C,
    255255        OP2_DIVSD_VsdWsd    = 0x5E,
     256        OP2_MOVMSKPD_VdEd   = 0x50,
    256257        OP2_SQRTSD_VsdWsd   = 0x51,
    257258        OP2_ANDNPD_VpdWpd   = 0x55,
     
    18031804        m_formatter.prefix(PRE_SSE_66);
    18041805        m_formatter.twoByteOp(OP2_MOVD_VdEd, (RegisterID)dst, src);
     1806    }
     1807
     1808    void movmskpd_rr(XMMRegisterID src, RegisterID dst)
     1809    {
     1810        m_formatter.prefix(PRE_SSE_66);
     1811        m_formatter.twoByteOp64(OP2_MOVMSKPD_VdEd, dst, (RegisterID)src);
    18051812    }
    18061813
  • trunk/Source/JavaScriptCore/bytecode/SpeculatedType.cpp

    r182971 r183963  
    508508}
    509509
    510 SpeculatedType typeOfDoubleFRound(SpeculatedType value)
     510SpeculatedType typeOfDoubleRounding(SpeculatedType value)
    511511{
    512512    // We might lose bits, which leads to a NaN being purified.
  • trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h

    r181993 r183963  
    423423SpeculatedType typeOfDoubleNegation(SpeculatedType);
    424424SpeculatedType typeOfDoubleAbs(SpeculatedType);
    425 SpeculatedType typeOfDoubleFRound(SpeculatedType);
     425SpeculatedType typeOfDoubleRounding(SpeculatedType);
    426426SpeculatedType typeOfDoublePow(SpeculatedType, SpeculatedType);
    427427
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r183812 r183963  
    762762        break;
    763763    }
     764
     765    case ArithRound: {
     766        JSValue operand = forNode(node->child1()).value();
     767        if (operand && operand.isNumber()) {
     768            double roundedValue = jsRound(operand.asNumber());
     769
     770            if (producesInteger(node->arithRoundingMode())) {
     771                int32_t roundedValueAsInt32 = static_cast<int32_t>(roundedValue);
     772                if (roundedValueAsInt32 == roundedValue) {
     773                    if (shouldCheckNegativeZero(node->arithRoundingMode())) {
     774                        if (roundedValueAsInt32 || !std::signbit(roundedValue)) {
     775                            setConstant(node, jsNumber(roundedValueAsInt32));
     776                            break;
     777                        }
     778                    } else {
     779                        setConstant(node, jsNumber(roundedValueAsInt32));
     780                        break;
     781                    }
     782                }
     783            } else {
     784                setConstant(node, jsDoubleNumber(roundedValue));
     785                break;
     786            }
     787        }
     788        if (producesInteger(node->arithRoundingMode()))
     789            forNode(node).setType(SpecInt32);
     790        else
     791            forNode(node).setType(typeOfDoubleRounding(forNode(node->child1()).m_type));
     792        break;
     793    }
    764794           
    765795    case ArithSqrt: {
     
    779809            break;
    780810        }
    781         forNode(node).setType(typeOfDoubleFRound(forNode(node->child1()).m_type));
     811        forNode(node).setType(typeOfDoubleRounding(forNode(node->child1()).m_type));
    782812        break;
    783813    }
  • trunk/Source/JavaScriptCore/dfg/DFGArithMode.h

    r164059 r183963  
    4141    DoOverflow // Up-convert to the smallest type that soundly represents all possible results after input type speculation.
    4242};
     43
     44// Define the type of operation the rounding operation will perform.
     45enum class RoundingMode {
     46    Int32, // The round operation produces a integer and -0 is considered as 0.
     47    Int32WithNegativeZeroCheck, // The round operation produces a integer and checks for -0.
     48    Double // The round operation produce a double. The result can be -0, NaN or (+/-)Infinity.
     49};
     50
    4351} // namespace Arith
    4452
     
    123131}
    124132
     133inline bool producesInteger(Arith::RoundingMode mode)
     134{
     135    return mode == Arith::RoundingMode::Int32WithNegativeZeroCheck || mode == Arith::RoundingMode::Int32;
     136}
     137
     138inline bool shouldCheckNegativeZero(Arith::RoundingMode mode)
     139{
     140    return mode == Arith::RoundingMode::Int32WithNegativeZeroCheck;
     141}
     142
    125143} } // namespace JSC::DFG
    126144
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r183373 r183963  
    20452045        return true;
    20462046    }
    2047 
     2047    case RoundIntrinsic: {
     2048        if (argumentCountIncludingThis == 1) {
     2049            insertChecks();
     2050            set(VirtualRegister(resultOperand), addToGraph(JSConstant, OpInfo(m_constantNaN)));
     2051            return true;
     2052        }
     2053        if (argumentCountIncludingThis == 2) {
     2054            insertChecks();
     2055            Node* operand = get(virtualRegisterForArgument(1, registerOffset));
     2056            Node* roundNode = addToGraph(ArithRound, OpInfo(0), OpInfo(prediction), operand);
     2057            set(VirtualRegister(resultOperand), roundNode);
     2058            return true;
     2059        }
     2060        return false;
     2061    }
    20482062    case IMulIntrinsic: {
    20492063        if (argumentCountIncludingThis != 3)
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r183812 r183963  
    135135    case ArithSqrt:
    136136    case ArithFRound:
     137    case ArithRound:
    137138    case ArithSin:
    138139    case ArithCos:
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r183812 r183963  
    8484    case ArithPow:
    8585    case ArithSqrt:
     86    case ArithRound:
    8687    case ArithFRound:
    8788    case ArithSin:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r183897 r183963  
    321321            fixDoubleOrBooleanEdge(node->child1());
    322322            fixDoubleOrBooleanEdge(node->child2());
     323            break;
     324        }
     325
     326        case ArithRound: {
     327            if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(FixupPass)) {
     328                fixIntOrBooleanEdge(node->child1());
     329                insertCheck<Int32Use>(m_indexInBlock, node->child1().node());
     330                node->convertToIdentity();
     331                break;
     332            }
     333            fixDoubleOrBooleanEdge(node->child1());
     334
     335            if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, FixupPass)) {
     336                node->setResult(NodeResultInt32);
     337                if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
     338                    node->setArithRoundingMode(Arith::RoundingMode::Int32);
     339                else
     340                    node->setArithRoundingMode(Arith::RoundingMode::Int32WithNegativeZeroCheck);
     341            } else {
     342                node->setResult(NodeResultDouble);
     343                node->setArithRoundingMode(Arith::RoundingMode::Double);
     344            }
    323345            break;
    324346        }
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r183650 r183963  
    315315            && negate->canSpeculateInt52(pass);
    316316    }
     317
     318    bool roundShouldSpeculateInt32(Node* arithRound, PredictionPass pass)
     319    {
     320        ASSERT(arithRound->op() == ArithRound);
     321        return arithRound->canSpeculateInt32(pass) && !hasExitSite(arithRound->origin.semantic, Overflow) && !hasExitSite(arithRound->origin.semantic, NegativeZero);
     322    }
    317323   
    318324    static const char *opName(NodeType);
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r183819 r183963  
    873873    {
    874874        NodeFlags result = m_flags & NodeArithFlagsMask;
    875         if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == DoubleAsInt32)
     875        if (op() == ArithMul || op() == ArithDiv || op() == ArithMod || op() == ArithNegate || op() == ArithPow || op() == ArithRound || op() == DoubleAsInt32)
    876876            return result;
    877877        return result & ~NodeBytecodeNeedsNegZero;
     
    12431243    {
    12441244        switch (op()) {
     1245        case ArithRound:
    12451246        case GetDirectPname:
    12461247        case GetById:
     
    15641565        m_opInfo = mode;
    15651566    }
     1567
     1568    bool hasArithRoundingMode()
     1569    {
     1570        return op() == ArithRound;
     1571    }
     1572
     1573    Arith::RoundingMode arithRoundingMode()
     1574    {
     1575        ASSERT(hasArithRoundingMode());
     1576        return static_cast<Arith::RoundingMode>(m_opInfo);
     1577    }
     1578
     1579    void setArithRoundingMode(Arith::RoundingMode mode)
     1580    {
     1581        ASSERT(hasArithRoundingMode());
     1582        m_opInfo = static_cast<uintptr_t>(mode);
     1583    }
    15661584   
    15671585    bool hasVirtualRegister()
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r183812 r183963  
    151151    macro(ArithFRound, NodeResultNumber) \
    152152    macro(ArithPow, NodeResultNumber) \
     153    macro(ArithRound, NodeResultNumber) \
    153154    macro(ArithSqrt, NodeResultNumber) \
    154155    macro(ArithSin, NodeResultNumber) \
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r183812 r183963  
    348348            break;
    349349        }
    350            
     350
     351        case ArithRound: {
     352            if (isInt32OrBooleanSpeculation(node->getHeapPrediction()) && m_graph.roundShouldSpeculateInt32(node, m_pass))
     353                changed |= setPrediction(SpecInt32);
     354            else
     355                changed |= setPrediction(SpecBytecodeDouble);
     356            break;
     357        }
     358
    351359        case ArithAbs: {
    352360            SpeculatedType child = node->child1()->prediction();
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r183812 r183963  
    155155    case ArithSqrt:
    156156    case ArithFRound:
     157    case ArithRound:
    157158    case ArithSin:
    158159    case ArithCos:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r183897 r183963  
    35453545}
    35463546
     3547void SpeculativeJIT::compileArithRound(Node* node)
     3548{
     3549    ASSERT(node->child1().useKind() == DoubleRepUse);
     3550
     3551    SpeculateDoubleOperand value(this, node->child1());
     3552    FPRReg valueFPR = value.fpr();
     3553    flushRegisters();
     3554    FPRResult roundedResultAsDouble(this);
     3555    FPRReg resultFPR = roundedResultAsDouble.fpr();
     3556    callOperation(jsRound, resultFPR, valueFPR);
     3557
     3558    if (producesInteger(node->arithRoundingMode())) {
     3559        GPRTemporary roundedResultAsInt32(this);
     3560        FPRTemporary scratch(this);
     3561        FPRReg scratchFPR = scratch.fpr();
     3562        GPRReg resultGPR = roundedResultAsInt32.gpr();
     3563        JITCompiler::JumpList failureCases;
     3564        m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR, shouldCheckNegativeZero(node->arithRoundingMode()));
     3565        speculationCheck(Overflow, JSValueRegs(), node, failureCases);
     3566
     3567        int32Result(resultGPR, node);
     3568    } else
     3569        doubleResult(resultFPR, node);
     3570}
     3571
    35473572void SpeculativeJIT::compileArithSqrt(Node* node)
    35483573{
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r183724 r183963  
    22002200    void compileArithMod(Node*);
    22012201    void compileArithPow(Node*);
     2202    void compileArithRound(Node*);
    22022203    void compileArithSqrt(Node*);
    22032204    void compileArithLog(Node*);
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r183812 r183963  
    21702170        break;
    21712171    }
     2172
     2173    case ArithRound:
     2174        compileArithRound(node);
     2175        break;
    21722176
    21732177    case ArithSin: {
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r183812 r183963  
    23132313        break;
    23142314    }
     2315
     2316    case ArithRound:
     2317        compileArithRound(node);
     2318        break;
    23152319
    23162320    case ArithSin: {
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r183812 r183963  
    6464    case BitURShift:
    6565    case CheckStructure:
     66    case DoubleAsInt32:
    6667    case ArrayifyToStructure:
    6768    case PutStructure:
     
    9091    case ArithCos:
    9192    case ArithPow:
     93    case ArithRound:
    9294    case ArithSqrt:
    9395    case ArithLog:
  • trunk/Source/JavaScriptCore/ftl/FTLIntrinsicRepository.h

    r183724 r183963  
    3636
    3737#define FOR_EACH_FTL_INTRINSIC(macro) \
     38    macro(ceil64, "llvm.ceil.f64", functionType(doubleType, doubleType)) \
    3839    macro(ctlz32, "llvm.ctlz.i32", functionType(int32, int32, boolean)) \
    3940    macro(addWithOverflow32, "llvm.sadd.with.overflow.i32", functionType(structType(m_context, int32, boolean), int32, int32)) \
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp

    r183944 r183963  
    444444            compileDoubleRep();
    445445            break;
     446        case DoubleAsInt32:
     447            compileDoubleAsInt32();
     448            break;
    446449        case ValueRep:
    447450            compileValueRep();
     
    505508        case ArithPow:
    506509            compileArithPow();
     510            break;
     511        case ArithRound:
     512            compileArithRound();
    507513            break;
    508514        case ArithSqrt:
     
    971977        }
    972978    }
    973    
     979
     980    void compileDoubleAsInt32()
     981    {
     982        LValue integerValue = convertDoubleToInt32(lowDouble(m_node->child1()), shouldCheckNegativeZero(m_node->arithMode()));
     983        setInt32(integerValue);
     984    }
     985
    974986    void compileValueRep()
    975987    {
     
    17601772            setDouble(m_out.phi(m_out.doubleType, powDoubleIntResult, powResult, pureNan));
    17611773        }
     1774    }
     1775
     1776    void compileArithRound()
     1777    {
     1778        LBasicBlock realPartIsMoreThanHalf = FTL_NEW_BLOCK(m_out, ("ArithRound should round down"));
     1779        LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ArithRound continuation"));
     1780
     1781        LValue value = lowDouble(m_node->child1());
     1782        LValue integerValue = m_out.ceil64(value);
     1783        ValueFromBlock integerValueResult = m_out.anchor(integerValue);
     1784
     1785        LValue realPart = m_out.doubleSub(integerValue, value);
     1786
     1787        m_out.branch(m_out.doubleGreaterThanOrUnordered(realPart, m_out.constDouble(0.5)), unsure(realPartIsMoreThanHalf), unsure(continuation));
     1788
     1789        LBasicBlock lastNext = m_out.appendTo(realPartIsMoreThanHalf, continuation);
     1790        LValue integerValueRoundedDown = m_out.doubleSub(integerValue, m_out.constDouble(1));
     1791        ValueFromBlock integerValueRoundedDownResult = m_out.anchor(integerValueRoundedDown);
     1792        m_out.jump(continuation);
     1793        m_out.appendTo(continuation, lastNext);
     1794
     1795        LValue result = m_out.phi(m_out.doubleType, integerValueResult, integerValueRoundedDownResult);
     1796
     1797        if (producesInteger(m_node->arithRoundingMode())) {
     1798            LValue integerValue = convertDoubleToInt32(result, shouldCheckNegativeZero(m_node->arithRoundingMode()));
     1799            setInt32(integerValue);
     1800        } else
     1801            setDouble(result);
    17621802    }
    17631803
     
    72367276        return possibleResult;
    72377277    }
    7238    
     7278
     7279    LValue convertDoubleToInt32(LValue value, bool shouldCheckNegativeZero)
     7280    {
     7281        LValue integerValue = m_out.fpToInt32(value);
     7282        LValue integerValueConvertedToDouble = m_out.intToDouble(integerValue);
     7283        LValue valueNotConvertibleToInteger = m_out.doubleNotEqualOrUnordered(value, integerValueConvertedToDouble);
     7284        speculate(Overflow, FormattedValue(ValueFormatDouble, value), m_node, valueNotConvertibleToInteger);
     7285
     7286        if (shouldCheckNegativeZero) {
     7287            LBasicBlock valueIsZero = FTL_NEW_BLOCK(m_out, ("ConvertDoubleToInt32 on zero"));
     7288            LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("ConvertDoubleToInt32 continuation"));
     7289            m_out.branch(m_out.isZero32(integerValue), unsure(valueIsZero), unsure(continuation));
     7290
     7291            LBasicBlock lastNext = m_out.appendTo(valueIsZero, continuation);
     7292
     7293            LValue doubleBitcastToInt64 = m_out.bitCast(value, m_out.int64);
     7294            LValue signBitSet = m_out.lessThan(doubleBitcastToInt64, m_out.constInt64(0));
     7295
     7296            speculate(NegativeZero, FormattedValue(ValueFormatDouble, value), m_node, signBitSet);
     7297            m_out.jump(continuation);
     7298            m_out.appendTo(continuation, lastNext);
     7299        }
     7300        return integerValue;
     7301    }
     7302
    72397303    LValue isNumber(LValue jsValue, SpeculatedType type = SpecFullTop)
    72407304    {
  • trunk/Source/JavaScriptCore/ftl/FTLOutput.h

    r183525 r183963  
    140140    LValue insertElement(LValue vector, LValue element, LValue index) { return buildInsertElement(m_builder, vector, element, index); }
    141141
     142    LValue ceil64(LValue operand)
     143    {
     144        return call(ceil64Intrinsic(), operand);
     145    }
    142146    LValue ctlz32(LValue xOperand, LValue yOperand)
    143147    {
  • trunk/Source/JavaScriptCore/jit/ThunkGenerators.cpp

    r183358 r183963  
    3333#include "JSArrayIterator.h"
    3434#include "JSStack.h"
     35#include "MathCommon.h"
    3536#include "MaxFrameExtentForSlowPathCall.h"
    3637#include "JSCInlines.h"
     
    684685enum MathThunkCallingConvention { };
    685686typedef MathThunkCallingConvention(*MathThunk)(MathThunkCallingConvention);
    686 extern "C" {
    687 
    688 double jsRound(double) REFERENCED_FROM_ASM;
    689 double jsRound(double d)
    690 {
    691     double integer = ceil(d);
    692     return integer - (integer - d > 0.5);
    693 }
    694 
    695 }
    696687
    697688#if CPU(X86_64) && COMPILER(GCC) && (OS(DARWIN) || OS(LINUX))
  • trunk/Source/JavaScriptCore/runtime/MathCommon.cpp

    r180262 r183963  
    421421}
    422422
     423extern "C" {
     424double jsRound(double value)
     425{
     426    double integer = ceil(value);
     427    return integer - (integer - value > 0.5);
     428}
     429}
     430
    423431} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/MathCommon.h

    r183358 r183963  
    5555}
    5656
     57extern "C" {
     58double JIT_OPERATION jsRound(double value) REFERENCED_FROM_ASM WTF_INTERNAL;
     59}
     60
    5761}
    5862
  • trunk/Source/JavaScriptCore/runtime/MathObject.cpp

    r183785 r183963  
    269269EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec)
    270270{
    271     double arg = exec->argument(0).toNumber(exec);
    272     double integer = ceil(arg);
    273     return JSValue::encode(jsNumber(integer - (integer - arg > 0.5)));
     271    return JSValue::encode(jsNumber(jsRound(exec->argument(0).toNumber(exec))));
    274272}
    275273
Note: See TracChangeset for help on using the changeset viewer.