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