Latest emscripten life benchmark is 4x slower because the DFG doesn't realize that arithmetic on booleans is a thing
https://bugs.webkit.org/show_bug.cgi?id=133136
Reviewed by Oliver Hunt.
Source/JavaScriptCore:
Some key concepts:
- Except for the prediction propagation and type fixup phases, which are super early in
the pipeline, nobody has to know about the fact that booleans may flow into numerical
operations because there will just be a BooleanToNumber node that will take a value
and, if that value is a boolean, will convert it to the equivalent numerical value. It
will have a BooleanUse mode where it will also speculate that the input is a boolean
but it can also do UntypedUse in which case it will pass through any non-booleans.
This operation is very easy to model in all of the compiler tiers.
- No changes to the baseline JIT. The Baseline JIT will still believe that boolean
inputs require taking the slow path and it will still report that it took slow path
for any such operations. The DFG will now be smart enough to ignore baseline JIT slow
path profiling on operations that were known to have had boolean inputs. That's a
little quirky, but it's probably easier than modifying the baseline JIT to track
booleans correctly.
4.1x speed-up on the emscripten "life" benchmark. Up to 10x speed-up on microbenchmarks.
* bytecode/SpeculatedType.h:
(JSC::isInt32OrBooleanSpeculation):
(JSC::isInt32SpeculationForArithmetic):
(JSC::isInt32OrBooleanSpeculationForArithmetic):
(JSC::isInt32OrBooleanSpeculationExpectingDefined):
(JSC::isInt52Speculation):
(JSC::isMachineIntSpeculation):
(JSC::isFullNumberOrBooleanSpeculation):
(JSC::isFullNumberOrBooleanSpeculationExpectingDefined):
(JSC::isInt32SpeculationExpectingDefined): Deleted.
(JSC::isMachineIntSpeculationExpectingDefined): Deleted.
(JSC::isMachineIntSpeculationForArithmetic): Deleted.
(JSC::isBytecodeNumberSpeculationExpectingDefined): Deleted.
(JSC::isFullNumberSpeculationExpectingDefined): Deleted.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGAllocator.h:
(JSC::DFG::Allocator<T>::indexOf):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::makeSafe):
(JSC::DFG::ByteCodeParser::makeDivSafe):
(JSC::DFG::ByteCodeParser::handleIntrinsic):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGCommon.h:
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixIntConvertingEdge):
(JSC::DFG::FixupPhase::fixIntOrBooleanEdge):
(JSC::DFG::FixupPhase::fixDoubleOrBooleanEdge):
(JSC::DFG::FixupPhase::attemptToMakeIntegerAdd):
(JSC::DFG::FixupPhase::fixIntEdge): Deleted.
* dfg/DFGGraph.h:
(JSC::DFG::Graph::addSpeculationMode):
(JSC::DFG::Graph::valueAddSpeculationMode):
(JSC::DFG::Graph::arithAddSpeculationMode):
(JSC::DFG::Graph::addShouldSpeculateInt32):
(JSC::DFG::Graph::mulShouldSpeculateInt32):
(JSC::DFG::Graph::mulShouldSpeculateMachineInt):
(JSC::DFG::Graph::negateShouldSpeculateInt32):
(JSC::DFG::Graph::negateShouldSpeculateMachineInt):
(JSC::DFG::Graph::addImmediateShouldSpeculateInt32):
(JSC::DFG::Graph::mulImmediateShouldSpeculateInt32): Deleted.
* dfg/DFGNode.h:
(JSC::DFG::Node::sawBooleans):
(JSC::DFG::Node::shouldSpeculateInt32OrBoolean):
(JSC::DFG::Node::shouldSpeculateInt32ForArithmetic):
(JSC::DFG::Node::shouldSpeculateInt32OrBooleanForArithmetic):
(JSC::DFG::Node::shouldSpeculateInt32OrBooleanExpectingDefined):
(JSC::DFG::Node::shouldSpeculateMachineInt):
(JSC::DFG::Node::shouldSpeculateDouble):
(JSC::DFG::Node::shouldSpeculateNumberOrBoolean):
(JSC::DFG::Node::shouldSpeculateNumberOrBooleanExpectingDefined):
(JSC::DFG::Node::shouldSpeculateNumber):
(JSC::DFG::Node::canSpeculateInt32):
(JSC::DFG::Node::canSpeculateInt52):
(JSC::DFG::Node::sourceFor):
(JSC::DFG::Node::shouldSpeculateInt32ExpectingDefined): Deleted.
(JSC::DFG::Node::shouldSpeculateMachineIntForArithmetic): Deleted.
(JSC::DFG::Node::shouldSpeculateMachineIntExpectingDefined): Deleted.
(JSC::DFG::Node::shouldSpeculateDoubleForArithmetic): Deleted.
(JSC::DFG::Node::shouldSpeculateNumberExpectingDefined): Deleted.
* dfg/DFGNodeFlags.cpp:
(JSC::DFG::dumpNodeFlags):
* dfg/DFGNodeFlags.h:
(JSC::DFG::nodeMayOverflow):
(JSC::DFG::nodeMayNegZero):
(JSC::DFG::nodeCanSpeculateInt32):
(JSC::DFG::nodeCanSpeculateInt52):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::run):
(JSC::DFG::PredictionPropagationPhase::propagateToFixpoint):
(JSC::DFG::PredictionPropagationPhase::speculatedDoubleTypeForPrediction):
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileValueToInt32):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileValueToInt32):
(JSC::FTL::LowerDFGToLLVM::compileBooleanToNumber):
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::asInt32ForArithmetic):
* tests/stress/max-boolean-exit.js: Added.
(foo):
(test):
* tests/stress/mul-boolean-exit.js: Added.
(foo):
(test):
* tests/stress/plus-boolean-exit.js: Added.
(foo):
(test):
* tests/stress/plus-boolean-or-double.js: Added.
(foo):
(test):
* tests/stress/plus-boolean-or-int.js: Added.
(foo):
(test):
LayoutTests:
* js/regress/abs-boolean-expected.txt: Added.
* js/regress/abs-boolean.html: Added.
* js/regress/div-boolean-double-expected.txt: Added.
* js/regress/div-boolean-double.html: Added.
* js/regress/div-boolean-expected.txt: Added.
* js/regress/div-boolean.html: Added.
* js/regress/max-boolean-expected.txt: Added.
* js/regress/max-boolean.html: Added.
* js/regress/min-boolean-expected.txt: Added.
* js/regress/min-boolean.html: Added.
* js/regress/minus-boolean-double-expected.txt: Added.
* js/regress/minus-boolean-double.html: Added.
* js/regress/minus-boolean-expected.txt: Added.
* js/regress/minus-boolean.html: Added.
* js/regress/mod-boolean-double-expected.txt: Added.
* js/regress/mod-boolean-double.html: Added.
* js/regress/mod-boolean-expected.txt: Added.
* js/regress/mod-boolean.html: Added.
* js/regress/mul-boolean-double-expected.txt: Added.
* js/regress/mul-boolean-double.html: Added.
* js/regress/mul-boolean-expected.txt: Added.
* js/regress/mul-boolean.html: Added.
* js/regress/neg-boolean-expected.txt: Added.
* js/regress/neg-boolean.html: Added.
* js/regress/plus-boolean-arith-expected.txt: Added.
* js/regress/plus-boolean-arith.html: Added.
* js/regress/plus-boolean-double-expected.txt: Added.
* js/regress/plus-boolean-double.html: Added.
* js/regress/plus-boolean-expected.txt: Added.
* js/regress/plus-boolean.html: Added.
* js/regress/script-tests/abs-boolean.js: Added.
* js/regress/script-tests/div-boolean-double.js: Added.
* js/regress/script-tests/div-boolean.js: Added.
* js/regress/script-tests/max-boolean.js: Added.
* js/regress/script-tests/min-boolean.js: Added.
* js/regress/script-tests/minus-boolean-double.js: Added.
* js/regress/script-tests/minus-boolean.js: Added.
* js/regress/script-tests/mod-boolean-double.js: Added.
* js/regress/script-tests/mod-boolean.js: Added.
* js/regress/script-tests/mul-boolean-double.js: Added.
* js/regress/script-tests/mul-boolean.js: Added.
* js/regress/script-tests/neg-boolean.js: Added.
* js/regress/script-tests/plus-boolean-arith.js: Added.
* js/regress/script-tests/plus-boolean-double.js: Added.
* js/regress/script-tests/plus-boolean.js: Added.
* js/regress/script-tests/sin-boolean.js: Added.
* js/regress/sin-boolean-expected.txt: Added.
* js/regress/sin-boolean.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@169354 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 3d8a7ee..7835e75 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -102,14 +102,14 @@
case BitRShift:
case BitLShift:
case BitURShift: {
- fixIntEdge(node->child1());
- fixIntEdge(node->child2());
+ fixIntConvertingEdge(node->child1());
+ fixIntConvertingEdge(node->child2());
break;
}
case ArithIMul: {
- fixIntEdge(node->child1());
- fixIntEdge(node->child2());
+ fixIntConvertingEdge(node->child1());
+ fixIntConvertingEdge(node->child2());
node->setOp(ArithMul);
node->setArithMode(Arith::Unchecked);
node->child1().setUseKind(Int32Use);
@@ -118,10 +118,10 @@
}
case UInt32ToNumber: {
- fixIntEdge(node->child1());
+ fixIntConvertingEdge(node->child1());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->convertToIdentity();
- else if (nodeCanSpeculateInt32(node->arithNodeFlags()))
+ else if (node->canSpeculateInt32(FixupPass))
node->setArithMode(Arith::CheckOverflow);
else {
node->setArithMode(Arith::DoOverflow);
@@ -136,9 +136,9 @@
node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
- if (Node::shouldSpeculateNumberExpectingDefined(node->child1().node(), node->child2().node())) {
- fixEdge<DoubleRepUse>(node->child1());
- fixEdge<DoubleRepUse>(node->child2());
+ if (Node::shouldSpeculateNumberOrBooleanExpectingDefined(node->child1().node(), node->child2().node())) {
+ fixDoubleOrBooleanEdge(node->child1());
+ fixDoubleOrBooleanEdge(node->child2());
node->setOp(ArithAdd);
node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
node->setResult(NodeResultDouble);
@@ -180,15 +180,15 @@
case ArithSub: {
if (attemptToMakeIntegerAdd(node))
break;
- fixEdge<DoubleRepUse>(node->child1());
- fixEdge<DoubleRepUse>(node->child2());
+ fixDoubleOrBooleanEdge(node->child1());
+ fixDoubleOrBooleanEdge(node->child2());
node->setResult(NodeResultDouble);
break;
}
case ArithNegate: {
- if (m_graph.negateShouldSpeculateInt32(node)) {
- fixEdge<Int32Use>(node->child1());
+ if (m_graph.negateShouldSpeculateInt32(node, FixupPass)) {
+ fixIntOrBooleanEdge(node->child1());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -197,7 +197,7 @@
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
break;
}
- if (m_graph.negateShouldSpeculateMachineInt(node)) {
+ if (m_graph.negateShouldSpeculateMachineInt(node, FixupPass)) {
fixEdge<Int52RepUse>(node->child1());
if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
node->setArithMode(Arith::CheckOverflow);
@@ -206,15 +206,15 @@
node->setResult(NodeResultInt52);
break;
}
- fixEdge<DoubleRepUse>(node->child1());
+ fixDoubleOrBooleanEdge(node->child1());
node->setResult(NodeResultDouble);
break;
}
case ArithMul: {
- if (m_graph.mulShouldSpeculateInt32(node)) {
- fixEdge<Int32Use>(node->child1());
- fixEdge<Int32Use>(node->child2());
+ if (m_graph.mulShouldSpeculateInt32(node, FixupPass)) {
+ fixIntOrBooleanEdge(node->child1());
+ fixIntOrBooleanEdge(node->child2());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -223,7 +223,7 @@
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
break;
}
- if (m_graph.mulShouldSpeculateMachineInt(node)) {
+ if (m_graph.mulShouldSpeculateMachineInt(node, FixupPass)) {
fixEdge<Int52RepUse>(node->child1());
fixEdge<Int52RepUse>(node->child2());
if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -233,19 +233,19 @@
node->setResult(NodeResultInt52);
break;
}
- fixEdge<DoubleRepUse>(node->child1());
- fixEdge<DoubleRepUse>(node->child2());
+ fixDoubleOrBooleanEdge(node->child1());
+ fixDoubleOrBooleanEdge(node->child2());
node->setResult(NodeResultDouble);
break;
}
case ArithDiv:
case ArithMod: {
- if (Node::shouldSpeculateInt32ForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInt32()) {
+ if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32(FixupPass)) {
if (optimizeForX86() || optimizeForARM64() || optimizeForARMv7s()) {
- fixEdge<Int32Use>(node->child1());
- fixEdge<Int32Use>(node->child2());
+ fixIntOrBooleanEdge(node->child1());
+ fixIntOrBooleanEdge(node->child2());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else if (bytecodeCanIgnoreNegativeZero(node->arithNodeFlags()))
@@ -256,8 +256,8 @@
}
// This will cause conversion nodes to be inserted later.
- fixEdge<DoubleRepUse>(node->child1());
- fixEdge<DoubleRepUse>(node->child2());
+ fixDoubleOrBooleanEdge(node->child1());
+ fixDoubleOrBooleanEdge(node->child2());
// But we have to make sure that everything is phantom'd until after the
// DoubleAsInt32 node, which occurs after the Div/Mod node that the conversions
@@ -279,33 +279,33 @@
node->setArithMode(Arith::CheckOverflowAndNegativeZero);
break;
}
- fixEdge<DoubleRepUse>(node->child1());
- fixEdge<DoubleRepUse>(node->child2());
+ fixDoubleOrBooleanEdge(node->child1());
+ fixDoubleOrBooleanEdge(node->child2());
node->setResult(NodeResultDouble);
break;
}
case ArithMin:
case ArithMax: {
- if (Node::shouldSpeculateInt32ForArithmetic(node->child1().node(), node->child2().node())
- && node->canSpeculateInt32()) {
- fixEdge<Int32Use>(node->child1());
- fixEdge<Int32Use>(node->child2());
+ if (Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+ && node->canSpeculateInt32(FixupPass)) {
+ fixIntOrBooleanEdge(node->child1());
+ fixIntOrBooleanEdge(node->child2());
break;
}
- fixEdge<DoubleRepUse>(node->child1());
- fixEdge<DoubleRepUse>(node->child2());
+ fixDoubleOrBooleanEdge(node->child1());
+ fixDoubleOrBooleanEdge(node->child2());
node->setResult(NodeResultDouble);
break;
}
case ArithAbs: {
- if (node->child1()->shouldSpeculateInt32ForArithmetic()
- && node->canSpeculateInt32()) {
- fixEdge<Int32Use>(node->child1());
+ if (node->child1()->shouldSpeculateInt32OrBooleanForArithmetic()
+ && node->canSpeculateInt32(FixupPass)) {
+ fixIntOrBooleanEdge(node->child1());
break;
}
- fixEdge<DoubleRepUse>(node->child1());
+ fixDoubleOrBooleanEdge(node->child1());
node->setResult(NodeResultDouble);
break;
}
@@ -314,7 +314,7 @@
case ArithFRound:
case ArithSin:
case ArithCos: {
- fixEdge<DoubleRepUse>(node->child1());
+ fixDoubleOrBooleanEdge(node->child1());
node->setResult(NodeResultDouble);
break;
}
@@ -324,8 +324,8 @@
fixEdge<BooleanUse>(node->child1());
else if (node->child1()->shouldSpeculateObjectOrOther())
fixEdge<ObjectOrOtherUse>(node->child1());
- else if (node->child1()->shouldSpeculateInt32())
- fixEdge<Int32Use>(node->child1());
+ else if (node->child1()->shouldSpeculateInt32OrBoolean())
+ fixIntOrBooleanEdge(node->child1());
else if (node->child1()->shouldSpeculateNumber())
fixEdge<DoubleRepUse>(node->child1());
else if (node->child1()->shouldSpeculateString())
@@ -350,9 +350,16 @@
case CompareLessEq:
case CompareGreater:
case CompareGreaterEq: {
- if (Node::shouldSpeculateInt32(node->child1().node(), node->child2().node())) {
- fixEdge<Int32Use>(node->child1());
- fixEdge<Int32Use>(node->child2());
+ if (node->op() == CompareEq
+ && Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
+ fixEdge<BooleanUse>(node->child1());
+ fixEdge<BooleanUse>(node->child2());
+ node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
+ break;
+ }
+ if (Node::shouldSpeculateInt32OrBoolean(node->child1().node(), node->child2().node())) {
+ fixIntOrBooleanEdge(node->child1());
+ fixIntOrBooleanEdge(node->child2());
node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
@@ -363,20 +370,14 @@
node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
- if (Node::shouldSpeculateNumber(node->child1().node(), node->child2().node())) {
- fixEdge<DoubleRepUse>(node->child1());
- fixEdge<DoubleRepUse>(node->child2());
+ if (Node::shouldSpeculateNumberOrBoolean(node->child1().node(), node->child2().node())) {
+ fixDoubleOrBooleanEdge(node->child1());
+ fixDoubleOrBooleanEdge(node->child2());
node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
break;
}
if (node->op() != CompareEq)
break;
- if (Node::shouldSpeculateBoolean(node->child1().node(), node->child2().node())) {
- fixEdge<BooleanUse>(node->child1());
- fixEdge<BooleanUse>(node->child2());
- node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
- break;
- }
if (node->child1()->shouldSpeculateStringIdent() && node->child2()->shouldSpeculateStringIdent()) {
fixEdge<StringIdentUse>(node->child1());
fixEdge<StringIdentUse>(node->child2());
@@ -604,10 +605,6 @@
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
fixEdge<Int32Use>(child3);
- if (child3->prediction() & SpecInt52)
- fixEdge<Int52RepUse>(child3);
- else
- fixEdge<Int32Use>(child3);
break;
case Array::Double:
fixEdge<KnownCellUse>(child1);
@@ -624,17 +621,17 @@
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
if (child3->shouldSpeculateInt32())
- fixEdge<Int32Use>(child3);
+ fixIntOrBooleanEdge(child3);
else if (child3->shouldSpeculateMachineInt())
fixEdge<Int52RepUse>(child3);
else
- fixEdge<DoubleRepUse>(child3);
+ fixDoubleOrBooleanEdge(child3);
break;
case Array::Float32Array:
case Array::Float64Array:
fixEdge<KnownCellUse>(child1);
fixEdge<Int32Use>(child2);
- fixEdge<DoubleRepUse>(child3);
+ fixDoubleOrBooleanEdge(child3);
break;
case Array::Contiguous:
case Array::ArrayStorage:
@@ -706,10 +703,10 @@
fixEdge<BooleanUse>(node->child1());
else if (node->child1()->shouldSpeculateObjectOrOther())
fixEdge<ObjectOrOtherUse>(node->child1());
- else if (node->child1()->shouldSpeculateInt32())
- fixEdge<Int32Use>(node->child1());
- else if (node->child1()->shouldSpeculateNumber())
- fixEdge<DoubleRepUse>(node->child1());
+ else if (node->child1()->shouldSpeculateInt32OrBoolean())
+ fixIntOrBooleanEdge(node->child1());
+ else if (node->child1()->shouldSpeculateNumberOrBoolean())
+ fixDoubleOrBooleanEdge(node->child1());
Node* logicalNot = node->child1().node();
if (logicalNot->op() == LogicalNot) {
@@ -1019,6 +1016,7 @@
case DoubleConstant:
case Int52Constant:
case Identity: // This should have been cleaned up.
+ case BooleanToNumber:
// These are just nodes that we don't currently expect to see during fixup.
// If we ever wanted to insert them prior to fixup, then we just have to create
// fixup rules for them.
@@ -1579,11 +1577,11 @@
m_insertionSet.insert(indexInBlock, barrierNode);
}
- void fixIntEdge(Edge& edge)
+ void fixIntConvertingEdge(Edge& edge)
{
Node* node = edge.node();
- if (node->shouldSpeculateInt32()) {
- fixEdge<Int32Use>(edge);
+ if (node->shouldSpeculateInt32OrBoolean()) {
+ fixIntOrBooleanEdge(edge);
return;
}
@@ -1592,8 +1590,6 @@
useKind = Int52RepUse;
else if (node->shouldSpeculateNumber())
useKind = DoubleRepUse;
- else if (node->shouldSpeculateBoolean())
- useKind = BooleanUse;
else
useKind = NotCellUse;
Node* newNode = m_insertionSet.insertNode(
@@ -1605,6 +1601,50 @@
addRequiredPhantom(node);
}
+ void fixIntOrBooleanEdge(Edge& edge)
+ {
+ Node* node = edge.node();
+ if (!node->sawBooleans()) {
+ fixEdge<Int32Use>(edge);
+ return;
+ }
+
+ UseKind useKind;
+ if (node->shouldSpeculateBoolean())
+ useKind = BooleanUse;
+ else
+ useKind = UntypedUse;
+ Node* newNode = m_insertionSet.insertNode(
+ m_indexInBlock, SpecInt32, BooleanToNumber, m_currentNode->origin,
+ Edge(node, useKind));
+ observeUseKindOnNode(node, useKind);
+
+ edge = Edge(newNode, Int32Use);
+ addRequiredPhantom(node);
+ }
+
+ void fixDoubleOrBooleanEdge(Edge& edge)
+ {
+ Node* node = edge.node();
+ if (!node->sawBooleans()) {
+ fixEdge<DoubleRepUse>(edge);
+ return;
+ }
+
+ UseKind useKind;
+ if (node->shouldSpeculateBoolean())
+ useKind = BooleanUse;
+ else
+ useKind = UntypedUse;
+ Node* newNode = m_insertionSet.insertNode(
+ m_indexInBlock, SpecInt32, BooleanToNumber, m_currentNode->origin,
+ Edge(node, useKind));
+ observeUseKindOnNode(node, useKind);
+
+ edge = Edge(newNode, DoubleRepUse);
+ addRequiredPhantom(node);
+ }
+
void truncateConstantToInt32(Edge& edge)
{
Node* oldNode = edge.node();
@@ -1646,11 +1686,11 @@
bool attemptToMakeIntegerAdd(Node* node)
{
- AddSpeculationMode mode = m_graph.addSpeculationMode(node);
+ AddSpeculationMode mode = m_graph.addSpeculationMode(node, FixupPass);
if (mode != DontSpeculateInt32) {
truncateConstantsIfNecessary(node, mode);
- fixEdge<Int32Use>(node->child1());
- fixEdge<Int32Use>(node->child2());
+ fixIntOrBooleanEdge(node->child1());
+ fixIntOrBooleanEdge(node->child2());
if (bytecodeCanTruncateInteger(node->arithNodeFlags()))
node->setArithMode(Arith::Unchecked);
else