Ignore:
Timestamp:
Dec 8, 2015, 1:44:12 PM (10 years ago)
Author:
[email protected]
Message:

Polymorphic operand types for DFG and FTL div.
https://bugs.webkit.org/show_bug.cgi?id=151747

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

Perf on benchmarks is neutral. The new JSRegress ftl-object-div test shows
a speed up not from the div operator itself, but from the fact that the
polymorphic operand types support now allow the test function to run without OSR
exiting, thereby realizing the DFG and FTL's speed up on other work that the test
function does.

This patch has passed the layout tests on x86_64 with a debug build.
It passed the JSC tests with x86 and x86_64 debug builds.

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

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

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

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileArithDiv):

  • ftl/FTLCompileBinaryOp.cpp:

(JSC::FTL::generateBinaryArithOpFastPath):
(JSC::FTL::generateBinaryOpFastPath):

  • ftl/FTLInlineCacheDescriptor.h:
  • ftl/FTLInlineCacheDescriptorInlines.h:

(JSC::FTL::ArithDivDescriptor::ArithDivDescriptor):
(JSC::FTL::ArithDivDescriptor::icSize):

  • ftl/FTLInlineCacheSize.cpp:

(JSC::FTL::sizeOfArithDiv):

  • ftl/FTLInlineCacheSize.h:
  • ftl/FTLLowerDFGToLLVM.cpp:

(JSC::FTL::DFG::LowerDFGToLLVM::lower):
(JSC::FTL::DFG::LowerDFGToLLVM::compileArithMul):

  • Fixed a cut-paste bug where the op_mul IC was using the op_sub IC size. This bug is benign because the op_sub IC size turns out to be larger than op_mul needs.

(JSC::FTL::DFG::LowerDFGToLLVM::compileArithDiv):

  • jit/JITArithmetic.cpp:

(JSC::JIT::emit_op_div):

  • Fixed a bug where the scratchFPR was not allocated for the 64bit port. This bug is benign because the scratchFPR is only needed if we are using scratchGPR register (used for branchConvertDoubleToInt32()) is

    X86Registers::r8. Since we're always using regT2 for the scratchT2,

    the scratchFPR is never needed. However, we should fix this anyway to be correct.
  • tests/stress/op_div.js:
  • Fixed some test values.

LayoutTests:

  • js/regress/ftl-object-div-expected.txt: Added.
  • js/regress/ftl-object-div.html: Added.
  • js/regress/script-tests/ftl-object-div.js: Added.

(o1.valueOf):
(foo):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r193766 r193781  
    4040#include "DirectArguments.h"
    4141#include "JITAddGenerator.h"
     42#include "JITDivGenerator.h"
    4243#include "JITMulGenerator.h"
    4344#include "JITSubGenerator.h"
     
    36873688        break;
    36883689    }
    3689        
     3690
     3691    case UntypedUse: {
     3692        Edge& leftChild = node->child1();
     3693        Edge& rightChild = node->child2();
     3694
     3695        if (isKnownNotNumber(leftChild.node()) || isKnownNotNumber(rightChild.node())) {
     3696            JSValueOperand left(this, leftChild);
     3697            JSValueOperand right(this, rightChild);
     3698            JSValueRegs leftRegs = left.jsValueRegs();
     3699            JSValueRegs rightRegs = right.jsValueRegs();
     3700#if USE(JSVALUE64)
     3701            GPRTemporary result(this);
     3702            JSValueRegs resultRegs = JSValueRegs(result.gpr());
     3703#else
     3704            GPRTemporary resultTag(this);
     3705            GPRTemporary resultPayload(this);
     3706            JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
     3707#endif
     3708            flushRegisters();
     3709            callOperation(operationValueDiv, resultRegs, leftRegs, rightRegs);
     3710            m_jit.exceptionCheck();
     3711
     3712            jsValueResult(resultRegs, node);
     3713            return;
     3714        }
     3715
     3716        Optional<JSValueOperand> left;
     3717        Optional<JSValueOperand> right;
     3718
     3719        JSValueRegs leftRegs;
     3720        JSValueRegs rightRegs;
     3721
     3722        FPRTemporary leftNumber(this);
     3723        FPRTemporary rightNumber(this);
     3724        FPRReg leftFPR = leftNumber.fpr();
     3725        FPRReg rightFPR = rightNumber.fpr();
     3726        FPRTemporary fprScratch(this);
     3727        FPRReg scratchFPR = fprScratch.fpr();
     3728
     3729#if USE(JSVALUE64)
     3730        GPRTemporary result(this);
     3731        JSValueRegs resultRegs = JSValueRegs(result.gpr());
     3732        GPRTemporary scratch(this);
     3733        GPRReg scratchGPR = scratch.gpr();
     3734#else
     3735        GPRTemporary resultTag(this);
     3736        GPRTemporary resultPayload(this);
     3737        JSValueRegs resultRegs = JSValueRegs(resultPayload.gpr(), resultTag.gpr());
     3738        GPRReg scratchGPR = resultTag.gpr();
     3739#endif
     3740
     3741        SnippetOperand leftOperand(m_state.forNode(leftChild).resultType());
     3742        SnippetOperand rightOperand(m_state.forNode(rightChild).resultType());
     3743
     3744        if (leftChild->isInt32Constant())
     3745            leftOperand.setConstInt32(leftChild->asInt32());
     3746#if USE(JSVALUE64)
     3747        else if (leftChild->isDoubleConstant())
     3748            leftOperand.setConstDouble(leftChild->asNumber());
     3749#endif
     3750
     3751        if (leftOperand.isConst()) {
     3752            // The snippet generator only supports 1 argument as a constant.
     3753            // Ignore the rightChild's const-ness.
     3754        } else if (rightChild->isInt32Constant())
     3755            rightOperand.setConstInt32(rightChild->asInt32());
     3756#if USE(JSVALUE64)
     3757        else if (rightChild->isDoubleConstant())
     3758            rightOperand.setConstDouble(rightChild->asNumber());
     3759#endif
     3760
     3761        RELEASE_ASSERT(!leftOperand.isConst() || !rightOperand.isConst());
     3762
     3763        if (!leftOperand.isConst()) {
     3764            left = JSValueOperand(this, leftChild);
     3765            leftRegs = left->jsValueRegs();
     3766        }
     3767        if (!rightOperand.isConst()) {
     3768            right = JSValueOperand(this, rightChild);
     3769            rightRegs = right->jsValueRegs();
     3770        }
     3771
     3772        JITDivGenerator gen(leftOperand, rightOperand, resultRegs, leftRegs, rightRegs,
     3773            leftFPR, rightFPR, scratchGPR, scratchFPR);
     3774        gen.generateFastPath(m_jit);
     3775
     3776        ASSERT(gen.didEmitFastPath());
     3777        gen.endJumpList().append(m_jit.jump());
     3778
     3779        gen.slowPathJumpList().link(&m_jit);
     3780        silentSpillAllRegisters(resultRegs);
     3781
     3782        if (leftOperand.isConst()) {
     3783            leftRegs = resultRegs;
     3784            m_jit.moveValue(leftChild->asJSValue(), leftRegs);
     3785        }
     3786        if (rightOperand.isConst()) {
     3787            rightRegs = resultRegs;
     3788            m_jit.moveValue(rightChild->asJSValue(), rightRegs);
     3789        }
     3790
     3791        callOperation(operationValueDiv, resultRegs, leftRegs, rightRegs);
     3792
     3793        silentFillAllRegisters(resultRegs);
     3794        m_jit.exceptionCheck();
     3795
     3796        gen.endJumpList().link(&m_jit);
     3797        jsValueResult(resultRegs, node);
     3798        return;
     3799    }
     3800
    36903801    default:
    36913802        RELEASE_ASSERT_NOT_REACHED();
Note: See TracChangeset for help on using the changeset viewer.