Ignore:
Timestamp:
Sep 6, 2011, 7:47:51 PM (14 years ago)
Author:
[email protected]
Message:

DFG JIT does not optimize booleans
https://bugs.webkit.org/show_bug.cgi?id=67670

Reviewed by Gavin Barraclough.

This adds boolean value profiling, boolean prediction in the DFG,
boolean forward flow propagation in the DFGPropagator, boolean
data format in DFG generation info, and comprehensive optimizations
based on both boolean prediction and boolean generation info.
This is brings the speed-up on v8-richards to 12%, and gives slight
speed-ups elsewhere as well.

Making this work right required navigating some subtleties in
value profiling. Some functions get compiled with insufficient
information because some important path of the function never
executed. In these cases, we wish to fall back on static
speculation. But to do so, we need to ensure that predictions that
are inherent in the code (like that GetById almost certainly takes
a cell operand) are reflected in predictions that we make in
DFGPropagator. Thus, DFGPropagator now does both backward and
forward flow, using a both forward and backward fixpoint.

The backward flow in DFGPropagator is a separate static analysis,
and needs to keep a set of backward flow abstract values for
variables, arguments, and globals. To make this easy, this patch
factors out DFGGraph's prediction tracking capability into
DFGPredictionTracker, which now gets used by both DFGGraph (for
forward flow predictions) and DFGPropagator (for backward flow
predictions). Backward flow predictions eventually get merged
into forward flow ones, but the two are not equivalent: a forward
flow prediction is a superset of the backward flow prediction.

Debugging these prediction issues required a better understanding
of where we fail speculation, and what our value predictions look
like. This patch also adds optional verbose speculation failure
(so an informative printf fires whenever speculation failure occurs)
and slight improvements to the verbosity in other places.

  • bytecode/ValueProfile.h:

(JSC::ValueProfile::numberOfBooleans):
(JSC::ValueProfile::probabilityOfBoolean):
(JSC::ValueProfile::dump):
(JSC::ValueProfile::computeStatistics):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::stronglyPredict):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGGenerationInfo.h:

(JSC::DFG::dataFormatToString):
(JSC::DFG::needDataFormatConversion):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::predictArgumentTypes):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::Graph):
(JSC::DFG::Graph::predictions):
(JSC::DFG::Graph::predict):
(JSC::DFG::Graph::predictGlobalVar):
(JSC::DFG::Graph::getPrediction):
(JSC::DFG::Graph::getGlobalVarPrediction):
(JSC::DFG::Graph::isBooleanConstant):
(JSC::DFG::Graph::valueOfBooleanConstant):

  • dfg/DFGJITCodeGenerator.cpp:

(JSC::DFG::JITCodeGenerator::fillInteger):
(JSC::DFG::JITCodeGenerator::fillDouble):
(JSC::DFG::JITCodeGenerator::fillJSValue):
(JSC::DFG::JITCodeGenerator::isKnownNotInteger):
(JSC::DFG::JITCodeGenerator::isKnownBoolean):
(JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeCompare):
(JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeStrictEq):
(JSC::DFG::JITCodeGenerator::emitBranch):
(JSC::DFG::JITCodeGenerator::speculationCheck):
(JSC::DFG::GPRTemporary::GPRTemporary):

  • dfg/DFGJITCodeGenerator.h:

(JSC::DFG::JITCodeGenerator::isBooleanConstant):
(JSC::DFG::JITCodeGenerator::valueOfBooleanConstant):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::jumpFromSpeculativeToNonSpeculative):
(JSC::DFG::JITCompiler::link):

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::debugCall):
(JSC::DFG::JITCompiler::isBooleanConstant):
(JSC::DFG::JITCompiler::valueOfBooleanConstant):

  • dfg/DFGNode.h:

(JSC::DFG::isBooleanPrediction):
(JSC::DFG::predictionToString):
(JSC::DFG::mergePredictions):
(JSC::DFG::makePrediction):
(JSC::DFG::Node::isBooleanConstant):
(JSC::DFG::Node::valueOfBooleanConstant):
(JSC::DFG::Node::hasBooleanResult):
(JSC::DFG::Node::hasNumericResult):
(JSC::DFG::Node::predict):

  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionTracker.h: Added.

(JSC::DFG::operandIsArgument):
(JSC::DFG::PredictionSlot::PredictionSlot):
(JSC::DFG::PredictionTracker::PredictionTracker):
(JSC::DFG::PredictionTracker::initializeSimilarTo):
(JSC::DFG::PredictionTracker::numberOfArguments):
(JSC::DFG::PredictionTracker::numberOfVariables):
(JSC::DFG::PredictionTracker::argumentIndexForOperand):
(JSC::DFG::PredictionTracker::predictArgument):
(JSC::DFG::PredictionTracker::predict):
(JSC::DFG::PredictionTracker::predictGlobalVar):
(JSC::DFG::PredictionTracker::getArgumentPrediction):
(JSC::DFG::PredictionTracker::getPrediction):
(JSC::DFG::PredictionTracker::getGlobalVarPrediction):

  • dfg/DFGPropagator.cpp:

(JSC::DFG::Propagator::Propagator):
(JSC::DFG::Propagator::fixpoint):
(JSC::DFG::Propagator::setPrediction):
(JSC::DFG::Propagator::mergeUse):
(JSC::DFG::Propagator::mergePrediction):
(JSC::DFG::Propagator::propagateNode):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand):
(JSC::DFG::SpeculateBooleanOperand::~SpeculateBooleanOperand):
(JSC::DFG::SpeculateBooleanOperand::index):
(JSC::DFG::SpeculateBooleanOperand::gpr):
(JSC::DFG::SpeculateBooleanOperand::use):

  • runtime/JSGlobalData.h:
  • runtime/JSValue.cpp:

(JSC::JSValue::description):

File:
1 edited

Legend:

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

    r93934 r94629  
    129129    case DataFormatDouble:
    130130    case DataFormatCell:
     131    case DataFormatBoolean:
    131132    case DataFormatJSDouble:
    132     case DataFormatJSCell: {
     133    case DataFormatJSCell:
     134    case DataFormatJSBoolean: {
    133135        terminateSpeculativeExecution();
    134136        returnFormat = DataFormatInteger;
     
    224226
    225227    switch (info.registerFormat()) {
    226     case DataFormatNone:
    227         // Should have filled, above.
     228    case DataFormatNone: // Should have filled, above.
     229    case DataFormatBoolean: // This type never occurs.
    228230        ASSERT_NOT_REACHED();
    229231       
    230232    case DataFormatCell:
    231233    case DataFormatJSCell:
    232     case DataFormatJS: {
     234    case DataFormatJS:
     235    case DataFormatJSBoolean: {
    233236        GPRReg jsValueGpr = info.gpr();
    234237        m_gprs.lock(jsValueGpr);
     
    350353    case DataFormatInteger:
    351354    case DataFormatJSDouble:
    352     case DataFormatDouble: {
     355    case DataFormatDouble:
     356    case DataFormatJSBoolean:
     357    case DataFormatBoolean: {
     358        terminateSpeculativeExecution();
     359        return allocate();
     360    }
     361    }
     362
     363    ASSERT_NOT_REACHED();
     364    return InvalidGPRReg;
     365}
     366
     367GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
     368{
     369    Node& node = m_jit.graph()[nodeIndex];
     370    VirtualRegister virtualRegister = node.virtualRegister();
     371    GenerationInfo& info = m_generationInfo[virtualRegister];
     372
     373    switch (info.registerFormat()) {
     374    case DataFormatNone: {
     375        GPRReg gpr = allocate();
     376
     377        if (node.isConstant()) {
     378            JSValue jsValue = valueOfJSConstant(nodeIndex);
     379            if (jsValue.isBoolean()) {
     380                m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
     381                m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr);
     382                info.fillJSValue(gpr, DataFormatJSBoolean);
     383                return gpr;
     384            }
     385            terminateSpeculativeExecution();
     386            return gpr;
     387        }
     388        ASSERT(info.spillFormat() & DataFormatJS);
     389        m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
     390        m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
     391
     392        info.fillJSValue(gpr, DataFormatJS);
     393        if (info.spillFormat() != DataFormatJSBoolean) {
     394            m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
     395            speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg));
     396            m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
     397        }
     398        info.fillJSValue(gpr, DataFormatJSBoolean);
     399        return gpr;
     400    }
     401
     402    case DataFormatBoolean:
     403    case DataFormatJSBoolean: {
     404        GPRReg gpr = info.gpr();
     405        m_gprs.lock(gpr);
     406        return gpr;
     407    }
     408
     409    case DataFormatJS: {
     410        GPRReg gpr = info.gpr();
     411        m_gprs.lock(gpr);
     412        m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
     413        speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg));
     414        m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
     415        info.fillJSValue(gpr, DataFormatJSBoolean);
     416        return gpr;
     417    }
     418
     419    case DataFormatJSInteger:
     420    case DataFormatInteger:
     421    case DataFormatJSDouble:
     422    case DataFormatDouble:
     423    case DataFormatJSCell:
     424    case DataFormatCell: {
    353425        terminateSpeculativeExecution();
    354426        return allocate();
     
    529601        // If we add a DataFormatBool, we should use it here.
    530602        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
    531         jsValueResult(result.gpr(), m_compileIndex);
     603        jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
    532604    }
    533605   
     
    562634            VirtualRegister virtualRegister = node.virtualRegister();
    563635            m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
    564             m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), isArrayPrediction(prediction) ? DataFormatJSCell : DataFormatJS);
     636           
     637            DataFormat format;
     638            if (isArrayPrediction(prediction))
     639                format = DataFormatJSCell;
     640            else if (isBooleanPrediction(prediction))
     641                format = DataFormatJSBoolean;
     642            else
     643                format = DataFormatJS;
     644           
     645            m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), format);
    565646        }
    566647        break;
     
    579660            m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
    580661            noResult(m_compileIndex);
     662        } else if (isBooleanPrediction(predictedType)) {
     663            SpeculateBooleanOperand boolean(this, node.child1());
     664            m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local()));
     665            noResult(m_compileIndex);
    581666        } else {
    582667            JSValueOperand value(this, node.child1());
     
    842927
    843928    case LogicalNot: {
     929        if (isKnownBoolean(node.child1())) {
     930            SpeculateBooleanOperand value(this, node.child1());
     931            GPRTemporary result(this, value);
     932           
     933            m_jit.move(value.gpr(), result.gpr());
     934            m_jit.xorPtr(TrustedImm32(true), result.gpr());
     935           
     936            jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
     937            break;
     938        }
     939       
    844940        JSValueOperand value(this, node.child1());
    845941        GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
     
    851947
    852948        // If we add a DataFormatBool, we should use it here.
    853         jsValueResult(result.gpr(), m_compileIndex);
     949        jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
    854950        break;
    855951    }
     
    12281324
    12291325        putResult.link(&m_jit);
    1230         jsValueResult(scratchReg, m_compileIndex);
     1326        jsValueResult(scratchReg, m_compileIndex, DataFormatJSBoolean);
    12311327        break;
    12321328    }
Note: See TracChangeset for help on using the changeset viewer.