Title: [191816] trunk/Source/_javascript_Core
Revision
191816
Author
[email protected]
Date
2015-10-30 14:49:23 -0700 (Fri, 30 Oct 2015)

Log Message

B3 should be able to compile a control flow diamond
https://bugs.webkit.org/show_bug.cgi?id=150720

Reviewed by Benjamin Poulain.

Adds support for Branch, Jump, Upsilon, and Phi. Adds some basic strength reduction for
comparisons and boolean-like operations.

* assembler/MacroAssembler.cpp:
(WTF::printInternal):
* assembler/MacroAssembler.h:
* b3/B3BasicBlockUtils.h:
(JSC::B3::replacePredecessor):
(JSC::B3::resetReachability):
* b3/B3CheckValue.h:
* b3/B3Common.h:
(JSC::B3::isRepresentableAsImpl):
(JSC::B3::isRepresentableAs):
* b3/B3Const32Value.cpp:
(JSC::B3::Const32Value::subConstant):
(JSC::B3::Const32Value::equalConstant):
(JSC::B3::Const32Value::notEqualConstant):
(JSC::B3::Const32Value::dumpMeta):
* b3/B3Const32Value.h:
* b3/B3Const64Value.cpp:
(JSC::B3::Const64Value::subConstant):
(JSC::B3::Const64Value::equalConstant):
(JSC::B3::Const64Value::notEqualConstant):
(JSC::B3::Const64Value::dumpMeta):
* b3/B3Const64Value.h:
* b3/B3ConstDoubleValue.cpp:
(JSC::B3::ConstDoubleValue::subConstant):
(JSC::B3::ConstDoubleValue::equalConstant):
(JSC::B3::ConstDoubleValue::notEqualConstant):
(JSC::B3::ConstDoubleValue::dumpMeta):
* b3/B3ConstDoubleValue.h:
* b3/B3ControlValue.cpp:
(JSC::B3::ControlValue::~ControlValue):
(JSC::B3::ControlValue::convertToJump):
(JSC::B3::ControlValue::dumpMeta):
* b3/B3ControlValue.h:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::imm):
(JSC::B3::Air::LowerToAir::tryStackSlot):
(JSC::B3::Air::LowerToAir::tryUpsilon):
(JSC::B3::Air::LowerToAir::tryPhi):
(JSC::B3::Air::LowerToAir::tryBranch):
(JSC::B3::Air::LowerToAir::tryJump):
(JSC::B3::Air::LowerToAir::tryIdentity):
* b3/B3LoweringMatcher.patterns:
* b3/B3Opcode.h:
* b3/B3Procedure.cpp:
(JSC::B3::Procedure::resetReachability):
(JSC::B3::Procedure::dump):
* b3/B3ReduceStrength.cpp:
* b3/B3UpsilonValue.cpp:
(JSC::B3::UpsilonValue::dumpMeta):
* b3/B3UpsilonValue.h:
(JSC::B3::UpsilonValue::accepts): Deleted.
(JSC::B3::UpsilonValue::phi): Deleted.
(JSC::B3::UpsilonValue::UpsilonValue): Deleted.
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::subConstant):
(JSC::B3::Value::equalConstant):
(JSC::B3::Value::notEqualConstant):
(JSC::B3::Value::returnsBool):
(JSC::B3::Value::asTriState):
(JSC::B3::Value::effects):
* b3/B3Value.h:
* b3/B3ValueInlines.h:
(JSC::B3::Value::asInt32):
(JSC::B3::Value::isInt32):
(JSC::B3::Value::hasInt64):
(JSC::B3::Value::asInt64):
(JSC::B3::Value::isInt64):
(JSC::B3::Value::hasInt):
(JSC::B3::Value::asIntPtr):
(JSC::B3::Value::isIntPtr):
(JSC::B3::Value::hasDouble):
(JSC::B3::Value::asDouble):
(JSC::B3::Value::isEqualToDouble):
(JSC::B3::Value::hasNumber):
(JSC::B3::Value::representableAs):
(JSC::B3::Value::asNumber):
(JSC::B3::Value::stackmap):
* b3/air/AirArg.cpp:
(JSC::B3::Air::Arg::dump):
* b3/air/AirArg.h:
(JSC::B3::Air::Arg::resCond):
(JSC::B3::Air::Arg::doubleCond):
(JSC::B3::Air::Arg::special):
(JSC::B3::Air::Arg::isResCond):
(JSC::B3::Air::Arg::isDoubleCond):
(JSC::B3::Air::Arg::isSpecial):
(JSC::B3::Air::Arg::isGP):
(JSC::B3::Air::Arg::isFP):
(JSC::B3::Air::Arg::asResultCondition):
(JSC::B3::Air::Arg::asDoubleCondition):
(JSC::B3::Air::Arg::Arg):
* b3/air/AirCode.cpp:
(JSC::B3::Air::Code::resetReachability):
(JSC::B3::Air::Code::dump):
* b3/air/AirOpcode.opcodes:
* b3/air/opcode_generator.rb:
* b3/testb3.cpp:
(hiddenTruthBecauseNoReturnIsStupid):
(usage):
(JSC::B3::compile):
(JSC::B3::invoke):
(JSC::B3::compileAndRun):
(JSC::B3::test42):
(JSC::B3::testStoreLoadStackSlot):
(JSC::B3::testBranch):
(JSC::B3::testDiamond):
(JSC::B3::testBranchNotEqual):
(JSC::B3::testBranchFold):
(JSC::B3::testDiamondFold):
(JSC::B3::run):
(run):
(main):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (191815 => 191816)


--- trunk/Source/_javascript_Core/ChangeLog	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-10-30 21:49:23 UTC (rev 191816)
@@ -1,3 +1,127 @@
+2015-10-30  Filip Pizlo  <[email protected]>
+
+        B3 should be able to compile a control flow diamond
+        https://bugs.webkit.org/show_bug.cgi?id=150720
+
+        Reviewed by Benjamin Poulain.
+
+        Adds support for Branch, Jump, Upsilon, and Phi. Adds some basic strength reduction for
+        comparisons and boolean-like operations.
+
+        * assembler/MacroAssembler.cpp:
+        (WTF::printInternal):
+        * assembler/MacroAssembler.h:
+        * b3/B3BasicBlockUtils.h:
+        (JSC::B3::replacePredecessor):
+        (JSC::B3::resetReachability):
+        * b3/B3CheckValue.h:
+        * b3/B3Common.h:
+        (JSC::B3::isRepresentableAsImpl):
+        (JSC::B3::isRepresentableAs):
+        * b3/B3Const32Value.cpp:
+        (JSC::B3::Const32Value::subConstant):
+        (JSC::B3::Const32Value::equalConstant):
+        (JSC::B3::Const32Value::notEqualConstant):
+        (JSC::B3::Const32Value::dumpMeta):
+        * b3/B3Const32Value.h:
+        * b3/B3Const64Value.cpp:
+        (JSC::B3::Const64Value::subConstant):
+        (JSC::B3::Const64Value::equalConstant):
+        (JSC::B3::Const64Value::notEqualConstant):
+        (JSC::B3::Const64Value::dumpMeta):
+        * b3/B3Const64Value.h:
+        * b3/B3ConstDoubleValue.cpp:
+        (JSC::B3::ConstDoubleValue::subConstant):
+        (JSC::B3::ConstDoubleValue::equalConstant):
+        (JSC::B3::ConstDoubleValue::notEqualConstant):
+        (JSC::B3::ConstDoubleValue::dumpMeta):
+        * b3/B3ConstDoubleValue.h:
+        * b3/B3ControlValue.cpp:
+        (JSC::B3::ControlValue::~ControlValue):
+        (JSC::B3::ControlValue::convertToJump):
+        (JSC::B3::ControlValue::dumpMeta):
+        * b3/B3ControlValue.h:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::imm):
+        (JSC::B3::Air::LowerToAir::tryStackSlot):
+        (JSC::B3::Air::LowerToAir::tryUpsilon):
+        (JSC::B3::Air::LowerToAir::tryPhi):
+        (JSC::B3::Air::LowerToAir::tryBranch):
+        (JSC::B3::Air::LowerToAir::tryJump):
+        (JSC::B3::Air::LowerToAir::tryIdentity):
+        * b3/B3LoweringMatcher.patterns:
+        * b3/B3Opcode.h:
+        * b3/B3Procedure.cpp:
+        (JSC::B3::Procedure::resetReachability):
+        (JSC::B3::Procedure::dump):
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3UpsilonValue.cpp:
+        (JSC::B3::UpsilonValue::dumpMeta):
+        * b3/B3UpsilonValue.h:
+        (JSC::B3::UpsilonValue::accepts): Deleted.
+        (JSC::B3::UpsilonValue::phi): Deleted.
+        (JSC::B3::UpsilonValue::UpsilonValue): Deleted.
+        * b3/B3Validate.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::subConstant):
+        (JSC::B3::Value::equalConstant):
+        (JSC::B3::Value::notEqualConstant):
+        (JSC::B3::Value::returnsBool):
+        (JSC::B3::Value::asTriState):
+        (JSC::B3::Value::effects):
+        * b3/B3Value.h:
+        * b3/B3ValueInlines.h:
+        (JSC::B3::Value::asInt32):
+        (JSC::B3::Value::isInt32):
+        (JSC::B3::Value::hasInt64):
+        (JSC::B3::Value::asInt64):
+        (JSC::B3::Value::isInt64):
+        (JSC::B3::Value::hasInt):
+        (JSC::B3::Value::asIntPtr):
+        (JSC::B3::Value::isIntPtr):
+        (JSC::B3::Value::hasDouble):
+        (JSC::B3::Value::asDouble):
+        (JSC::B3::Value::isEqualToDouble):
+        (JSC::B3::Value::hasNumber):
+        (JSC::B3::Value::representableAs):
+        (JSC::B3::Value::asNumber):
+        (JSC::B3::Value::stackmap):
+        * b3/air/AirArg.cpp:
+        (JSC::B3::Air::Arg::dump):
+        * b3/air/AirArg.h:
+        (JSC::B3::Air::Arg::resCond):
+        (JSC::B3::Air::Arg::doubleCond):
+        (JSC::B3::Air::Arg::special):
+        (JSC::B3::Air::Arg::isResCond):
+        (JSC::B3::Air::Arg::isDoubleCond):
+        (JSC::B3::Air::Arg::isSpecial):
+        (JSC::B3::Air::Arg::isGP):
+        (JSC::B3::Air::Arg::isFP):
+        (JSC::B3::Air::Arg::asResultCondition):
+        (JSC::B3::Air::Arg::asDoubleCondition):
+        (JSC::B3::Air::Arg::Arg):
+        * b3/air/AirCode.cpp:
+        (JSC::B3::Air::Code::resetReachability):
+        (JSC::B3::Air::Code::dump):
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/opcode_generator.rb:
+        * b3/testb3.cpp:
+        (hiddenTruthBecauseNoReturnIsStupid):
+        (usage):
+        (JSC::B3::compile):
+        (JSC::B3::invoke):
+        (JSC::B3::compileAndRun):
+        (JSC::B3::test42):
+        (JSC::B3::testStoreLoadStackSlot):
+        (JSC::B3::testBranch):
+        (JSC::B3::testDiamond):
+        (JSC::B3::testBranchNotEqual):
+        (JSC::B3::testBranchFold):
+        (JSC::B3::testDiamondFold):
+        (JSC::B3::run):
+        (run):
+        (main):
+
 2015-10-30  Keith Miller  <[email protected]>
 
         [ES6] Add support for toStringTag

Modified: trunk/Source/_javascript_Core/assembler/MacroAssembler.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/assembler/MacroAssembler.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/assembler/MacroAssembler.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -112,6 +112,50 @@
     RELEASE_ASSERT_NOT_REACHED();
 }
 
+void printInternal(PrintStream& out, MacroAssembler::DoubleCondition cond)
+{
+    switch (cond) {
+    case MacroAssembler::DoubleEqual:
+        out.print("DoubleEqual");
+        return;
+    case MacroAssembler::DoubleNotEqual:
+        out.print("DoubleNotEqual");
+        return;
+    case MacroAssembler::DoubleGreaterThan:
+        out.print("DoubleGreaterThan");
+        return;
+    case MacroAssembler::DoubleGreaterThanOrEqual:
+        out.print("DoubleGreaterThanOrEqual");
+        return;
+    case MacroAssembler::DoubleLessThan:
+        out.print("DoubleLessThan");
+        return;
+    case MacroAssembler::DoubleLessThanOrEqual:
+        out.print("DoubleLessThanOrEqual");
+        return;
+    case MacroAssembler::DoubleEqualOrUnordered:
+        out.print("DoubleEqualOrUnordered");
+        return;
+    case MacroAssembler::DoubleNotEqualOrUnordered:
+        out.print("DoubleNotEqualOrUnordered");
+        return;
+    case MacroAssembler::DoubleGreaterThanOrUnordered:
+        out.print("DoubleGreaterThanOrUnordered");
+        return;
+    case MacroAssembler::DoubleGreaterThanOrEqualOrUnordered:
+        out.print("DoubleGreaterThanOrEqualOrUnordered");
+        return;
+    case MacroAssembler::DoubleLessThanOrUnordered:
+        out.print("DoubleLessThanOrUnordered");
+        return;
+    case MacroAssembler::DoubleLessThanOrEqualOrUnordered:
+        out.print("DoubleLessThanOrEqualOrUnordered");
+        return;
+    }
+
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
 } // namespace WTF
 
 #endif // ENABLE(ASSEMBLER)

Modified: trunk/Source/_javascript_Core/assembler/MacroAssembler.h (191815 => 191816)


--- trunk/Source/_javascript_Core/assembler/MacroAssembler.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/assembler/MacroAssembler.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -1614,6 +1614,7 @@
 
 void printInternal(PrintStream&, JSC::MacroAssembler::RelationalCondition);
 void printInternal(PrintStream&, JSC::MacroAssembler::ResultCondition);
+void printInternal(PrintStream&, JSC::MacroAssembler::DoubleCondition);
 
 } // namespace WTF
 

Modified: trunk/Source/_javascript_Core/b3/B3BasicBlockUtils.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3BasicBlockUtils.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3BasicBlockUtils.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -75,8 +75,9 @@
 }
 
 // This recomputes predecessors and removes blocks that aren't reachable.
-template<typename BasicBlock>
-void resetReachability(Vector<std::unique_ptr<BasicBlock>>& blocks)
+template<typename BasicBlock, typename DeleteFunctor>
+void resetReachability(
+    Vector<std::unique_ptr<BasicBlock>>& blocks, const DeleteFunctor& deleteFunctor)
 {
     // Clear all predecessor lists first.
     for (auto& block : blocks)
@@ -86,14 +87,16 @@
     worklist.push(blocks[0].get());
     while (BasicBlock* block = worklist.pop()) {
         for (BasicBlock* successor : block->successorBlocks()) {
-            if (worklist.push(successor))
-                addPredecessor(successor, block);
+            addPredecessor(successor, block);
+            worklist.push(successor);
         }
     }
 
     for (unsigned i = 1; i < blocks.size(); ++i) {
-        if (blocks[i]->predecessors().isEmpty())
+        if (blocks[i]->predecessors().isEmpty()) {
+            deleteFunctor(blocks[i].get());
             blocks[i] = nullptr;
+        }
     }
 }
 

Modified: trunk/Source/_javascript_Core/b3/B3CheckValue.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3CheckValue.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3CheckValue.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -62,7 +62,7 @@
     CheckValue(unsigned index, Opcode opcode, Origin origin, Value* left, Value* right)
         : Value(index, opcode, left->type(), origin, left, right)
     {
-        ASSERT(isInt(type()));
+        ASSERT(B3::isInt(type()));
         ASSERT(left->type() == right->type());
         ASSERT(opcode == CheckAdd || opcode == CheckSub || opcode == CheckMul);
     }

Modified: trunk/Source/_javascript_Core/b3/B3Common.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Common.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Common.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -39,6 +39,43 @@
 bool shouldValidateIRAtEachPhase();
 bool shouldSaveIRBeforePhase();
 
+template<typename ResultType, typename InputType, typename BitsType>
+inline bool isRepresentableAsImpl(InputType originalValue)
+{
+    // Get the raw bits of the original value.
+    BitsType originalBits = bitwise_cast<BitsType>(originalValue);
+
+    // Convert the original value to the desired result type.
+    ResultType result = static_cast<ResultType>(originalValue);
+
+    // Convert the converted value back to the original type. The original value is representable
+    // using the new type if such round-tripping doesn't lose bits.
+    InputType newValue = static_cast<InputType>(result);
+
+    // Get the raw bits of the round-tripped value.
+    BitsType newBits = bitwise_cast<BitsType>(newValue);
+    
+    return originalBits == newBits;
+}
+
+template<typename ResultType>
+inline bool isRepresentableAs(int32_t value)
+{
+    return isRepresentableAsImpl<ResultType, int32_t, int32_t>(value);
+}
+
+template<typename ResultType>
+inline bool isRepresentableAs(int64_t value)
+{
+    return isRepresentableAsImpl<ResultType, int64_t, int64_t>(value);
+}
+
+template<typename ResultType>
+inline bool isRepresentableAs(double value)
+{
+    return isRepresentableAsImpl<ResultType, double, int64_t>(value);
+}
+
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3Const32Value.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Const32Value.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Const32Value.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -61,6 +61,20 @@
     return proc.add<Const32Value>(origin(), m_value - other->asInt32());
 }
 
+Value* Const32Value::equalConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), m_value == other->asInt32());
+}
+
+Value* Const32Value::notEqualConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt32())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), m_value != other->asInt32());
+}
+
 void Const32Value::dumpMeta(PrintStream& out) const
 {
     out.print(m_value);

Modified: trunk/Source/_javascript_Core/b3/B3Const32Value.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Const32Value.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Const32Value.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -44,6 +44,8 @@
     Value* addConstant(Procedure&, int32_t other) const override;
     Value* addConstant(Procedure&, Value* other) const override;
     Value* subConstant(Procedure&, Value* other) const override;
+    Value* equalConstant(Procedure&, Value* other) const override;
+    Value* notEqualConstant(Procedure&, Value* other) const override;
 
 protected:
     JS_EXPORT_PRIVATE void dumpMeta(PrintStream&) const override;

Modified: trunk/Source/_javascript_Core/b3/B3Const64Value.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Const64Value.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Const64Value.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -61,6 +61,20 @@
     return proc.add<Const64Value>(origin(), m_value - other->asInt64());
 }
 
+Value* Const64Value::equalConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt64())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), m_value == other->asInt64());
+}
+
+Value* Const64Value::notEqualConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasInt64())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), m_value != other->asInt64());
+}
+
 void Const64Value::dumpMeta(PrintStream& out) const
 {
     out.print(m_value);

Modified: trunk/Source/_javascript_Core/b3/B3Const64Value.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Const64Value.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Const64Value.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -44,6 +44,8 @@
     Value* addConstant(Procedure&, int32_t other) const override;
     Value* addConstant(Procedure&, Value* other) const override;
     Value* subConstant(Procedure&, Value* other) const override;
+    Value* equalConstant(Procedure&, Value* other) const override;
+    Value* notEqualConstant(Procedure&, Value* other) const override;
 
 protected:
     void dumpMeta(PrintStream&) const override;

Modified: trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -61,6 +61,20 @@
     return proc.add<ConstDoubleValue>(origin(), m_value - other->asDouble());
 }
 
+Value* ConstDoubleValue::equalConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasDouble())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), m_value == other->asDouble());
+}
+
+Value* ConstDoubleValue::notEqualConstant(Procedure& proc, Value* other) const
+{
+    if (!other->hasDouble())
+        return nullptr;
+    return proc.add<Const32Value>(origin(), m_value != other->asDouble());
+}
+
 void ConstDoubleValue::dumpMeta(PrintStream& out) const
 {
     out.printf("%le", m_value);

Modified: trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -44,6 +44,8 @@
     Value* addConstant(Procedure& proc, int32_t other) const override;
     Value* addConstant(Procedure& proc, Value* other) const override;
     Value* subConstant(Procedure& proc, Value* other) const override;
+    Value* equalConstant(Procedure& proc, Value* other) const override;
+    Value* notEqualConstant(Procedure& proc, Value* other) const override;
 
 protected:
     void dumpMeta(PrintStream&) const override;

Modified: trunk/Source/_javascript_Core/b3/B3ControlValue.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3ControlValue.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3ControlValue.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -37,6 +37,19 @@
 {
 }
 
+void ControlValue::convertToJump(const FrequentedBlock& destination)
+{
+    unsigned index = this->index();
+    Origin origin = this->origin();
+    BasicBlock* owner = this->owner;
+
+    this->ControlValue::~ControlValue();
+
+    new (this) ControlValue(index, Jump, origin, destination);
+
+    this->owner = owner;
+}
+
 void ControlValue::dumpMeta(PrintStream& out) const
 {
     out.print(listDump(m_successors));

Modified: trunk/Source/_javascript_Core/b3/B3ControlValue.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3ControlValue.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3ControlValue.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -64,6 +64,29 @@
     const SuccessorList& successors() const { return m_successors; }
     SuccessorList& successors() { return m_successors; }
 
+    const FrequentedBlock& taken() const
+    {
+        ASSERT(opcode() == Jump || opcode() == Branch);
+        return successor(0);
+    }
+    FrequentedBlock& taken()
+    {
+        ASSERT(opcode() == Jump || opcode() == Branch);
+        return successor(0);
+    }
+    const FrequentedBlock& notTaken() const
+    {
+        ASSERT(opcode() == Branch);
+        return successor(1);
+    }
+    FrequentedBlock& notTaken()
+    {
+        ASSERT(opcode() == Branch);
+        return successor(1);
+    }
+
+    void convertToJump(const FrequentedBlock& destination);
+
 protected:
     JS_EXPORT_PRIVATE void dumpMeta(PrintStream&) const override;
 

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -43,6 +43,7 @@
 #include "B3PhaseScope.h"
 #include "B3Procedure.h"
 #include "B3StackSlotValue.h"
+#include "B3UpsilonValue.h"
 #include "B3UseCounts.h"
 #include "B3ValueInlines.h"
 #include <wtf/ListDump.h>
@@ -217,12 +218,8 @@
 
     Arg imm(Value* value)
     {
-        if (value->hasInt()) {
-            int64_t fullValue = value->asInt();
-            int32_t immediateValue = static_cast<int32_t>(fullValue);
-            if (fullValue == immediateValue)
-                return Arg::imm(immediateValue);
-        }
+        if (value->representableAs<int32_t>())
+            return Arg::imm(value->asNumber<int32_t>());
         return Arg();
     }
 
@@ -657,6 +654,72 @@
         return true;
     }
 
+    bool tryUpsilon(Value* value)
+    {
+        append(
+            relaxedMoveForType(value->type()),
+            immOrTmp(value),
+            tmp(currentValue->as<UpsilonValue>()->phi()));
+        return true;
+    }
+
+    bool tryPhi()
+    {
+        // Our semantics are determined by Upsilons, so we have nothing to do here.
+        return true;
+    }
+
+    bool tryBranch(Value* value)
+    {
+        // FIXME: Implement branch fusion by delegating to a pattern matcher for comparisons.
+        // https://bugs.webkit.org/show_bug.cgi?id=150721
+
+        // In B3 it's possible to branch on any value. The semantics of:
+        //
+        //     Branch(value)
+        //
+        // Are guaranteed to be identical to:
+        //
+        //     Branch(NotEqual(value, 0))
+
+        if (!isInt(value->type())) {
+            // FIXME: Implement double branches.
+            // https://bugs.webkit.org/show_bug.cgi?id=150727
+            return false;
+        }
+
+        Air::Opcode opcode;
+        switch (value->type()) {
+        case Int32:
+            opcode = BranchTest32;
+            break;
+        case Int64:
+            opcode = BranchTest64;
+            break;
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+
+        Arg resCond = Arg::resCond(MacroAssembler::NonZero);
+
+        Arg addr = loadAddr(value);
+        if (isValidForm(opcode, resCond.kind(), addr.kind(), Arg::Imm)) {
+            commitInternal(value);
+            append(opcode, resCond, addr, Arg::imm(-1));
+            return true;
+        }
+
+        append(opcode, resCond, tmp(value), Arg::imm(-1));
+        return true;
+    }
+
+    bool tryJump()
+    {
+        append(Air::Jump);
+        return true;
+    }
+
     bool tryIdentity(Value* value)
     {
         append(relaxedMoveForType(value->type()), immOrTmp(value), tmp(currentValue));

Modified: trunk/Source/_javascript_Core/b3/B3LoweringMatcher.patterns (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3LoweringMatcher.patterns	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3LoweringMatcher.patterns	2015-10-30 21:49:23 UTC (rev 191816)
@@ -48,6 +48,12 @@
 StackSlot = StackSlot()
 FramePointer = FramePointer()
 
+Upsilon = Upsilon(value)
+Phi = Phi()
+
+Branch = Branch(value)
+Jump = Jump()
+
 # It would be fantastic to not have to have this here, but the philosophy of our lowering is that
 # it should be sound even if we haven't run optimizations.
 Identity = Identity(value)

Modified: trunk/Source/_javascript_Core/b3/B3Opcode.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Opcode.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -96,7 +96,7 @@
     DToI32,
 
     // Polymorphic comparisons, usable with any value type. Returns int32 0 or 1. Note that "Not"
-    // is just Equal(x, 0).
+    // is just Equal(x, 0), and "ToBoolean" is just NotEqual(x, 0).
     Equal,
     NotEqual,
     LessThan,

Modified: trunk/Source/_javascript_Core/b3/B3Procedure.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Procedure.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Procedure.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -62,7 +62,13 @@
 
 void Procedure::resetReachability()
 {
-    B3::resetReachability(m_blocks);
+    B3::resetReachability(
+        m_blocks,
+        [&] (BasicBlock* deleted) {
+            // Gotta delete the values in this block.
+            for (Value* value : *deleted)
+                deleteValue(value);
+        });
 }
 
 void Procedure::dump(PrintStream& out) const

Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -28,6 +28,7 @@
 
 #if ENABLE(B3_JIT)
 
+#include "B3ControlValue.h"
 #include "B3InsertionSetInlines.h"
 #include "B3MemoryValue.h"
 #include "B3PhaseScope.h"
@@ -52,6 +53,7 @@
         bool result = false;
         do {
             m_changed = false;
+            m_changedCFG = false;
 
             for (BasicBlock* block : m_proc.blocksInPreOrder()) {
                 m_block = block;
@@ -63,6 +65,11 @@
                 block->removeNops(m_proc);
             }
 
+            if (m_changedCFG) {
+                m_proc.resetReachability();
+                m_changed = true;
+            }
+
             UseCounts useCounts(m_proc);
             for (Value* value : m_proc.values()) {
                 if (!useCounts[value] && !value->effects().mustExecute()) {
@@ -109,10 +116,9 @@
             if (isInt(m_value->type())) {
                 if (Value* negatedConstant = m_value->child(1)->negConstant(m_proc)) {
                     m_insertionSet.insertValue(m_index, negatedConstant);
-                    Value* add = m_insertionSet.insert<Value>(
-                        m_index, Add, m_value->origin(), m_value->child(0), negatedConstant);
-                    m_value->replaceWithIdentity(add);
-                    m_changed = true;
+                    replaceWithNew<Value>(
+                        Add, m_value->origin(), m_value->child(0), negatedConstant);
+                    break;
                 }
             }
 
@@ -172,7 +178,102 @@
             
             break;
         }
+
+        case Equal:
+            handleCommutativity();
+
+            // Turn this: Equal(Equal(x, 0), 0)
+            // Into this: NotEqual(x, 0)
+            if (m_value->child(0)->opcode() == Equal && m_value->child(1)->isInt32(0)
+                && m_value->child(0)->child(1)->isLikeZero()) {
+                replaceWithNew<Value>(
+                    NotEqual, m_value->origin(),
+                    m_value->child(0)->child(0), m_value->child(0)->child(1));
+                break;
+            }
+
+            // Turn this Equal(bool, 1)
+            // Into this: bool
+            if (m_value->child(0)->returnsBool() && m_value->child(1)->isInt32(1)) {
+                m_value->replaceWithIdentity(m_value->child(0));
+                m_changed = true;
+                break;
+            }
+
+            // FIXME: Have a compare-flipping optimization, like Equal(LessThan(a, b), 0) turns into
+            // GreaterEqual(a, b).
+            // https://bugs.webkit.org/show_bug.cgi?id=150726
+
+            // Turn this: Equal(const1, const2)
+            // Into this: const1 == const2
+            replaceWithNewValue(m_value->child(0)->equalConstant(m_proc, m_value->child(1)));
+            break;
             
+        case NotEqual:
+            handleCommutativity();
+
+            if (m_value->child(0)->returnsBool()) {
+                // Turn this: NotEqual(bool, 0)
+                // Into this: bool
+                if (m_value->child(1)->isInt32(0)) {
+                    m_value->replaceWithIdentity(m_value->child(0));
+                    m_changed = true;
+                    break;
+                }
+                
+                // Turn this: NotEqual(bool, 1)
+                // Into this: Equal(bool, 0)
+                if (m_value->child(1)->isInt32(1)) {
+                    replaceWithNew<Value>(
+                        Equal, m_value->origin(), m_value->child(0), m_value->child(1));
+                    break;
+                }
+            }
+
+            // Turn this: NotEqual(const1, const2)
+            // Into this: const1 != const2
+            replaceWithNewValue(m_value->child(0)->notEqualConstant(m_proc, m_value->child(1)));
+            break;
+
+        case Branch: {
+            ControlValue* branch = m_value->as<ControlValue>();
+
+            // Turn this: Branch(NotEqual(x, 0))
+            // Into this: Branch(x)
+            if (branch->child(0)->opcode() == NotEqual && branch->child(0)->child(1)->isLikeZero()) {
+                branch->child(0) = branch->child(0)->child(0);
+                m_changed = true;
+            }
+
+            // Turn this: Branch(Equal(x, 0), then, else)
+            // Into this: Branch(x, else, then)
+            if (branch->child(0)->opcode() == Equal && branch->child(0)->child(1)->isLikeZero()) {
+                branch->child(0) = branch->child(0)->child(0);
+                std::swap(branch->taken(), branch->notTaken());
+                m_changed = true;
+            }
+            
+            TriState triState = branch->child(0)->asTriState();
+
+            // Turn this: Branch(0, then, else)
+            // Into this: Jump(else)
+            if (triState == FalseTriState) {
+                branch->convertToJump(branch->notTaken());
+                m_changedCFG = true;
+                break;
+            }
+
+            // Turn this: Branch(not 0, then, else)
+            // Into this: Jump(then)
+            if (triState == TrueTriState) {
+                branch->convertToJump(branch->taken());
+                m_changedCFG = true;
+                break;
+            }
+            
+            break;
+        }
+            
         default:
             break;
         }
@@ -206,6 +307,12 @@
         }
     }
 
+    template<typename ValueType, typename... Arguments>
+    void replaceWithNew(Arguments... arguments)
+    {
+        replaceWithNewValue(m_proc.add<ValueType>(arguments...));
+    }
+
     void replaceWithNewValue(Value* newValue)
     {
         if (!newValue)
@@ -221,6 +328,7 @@
     unsigned m_index;
     Value* m_value;
     bool m_changed;
+    bool m_changedCFG;
 };
 
 } // anonymous namespace

Modified: trunk/Source/_javascript_Core/b3/B3UpsilonValue.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3UpsilonValue.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3UpsilonValue.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -36,7 +36,13 @@
 
 void UpsilonValue::dumpMeta(PrintStream& out) const
 {
-    out.print("^", m_phi->index());
+    if (m_phi)
+        out.print("^", m_phi->index());
+    else {
+        // We want to have a dump for when the Phi isn't set yet, since although such IR won't pass
+        // validation, we may have such IR as an intermediate step.
+        out.print("^(null)");
+    }
 }
 
 } } // namespace JSC::B3

Modified: trunk/Source/_javascript_Core/b3/B3UpsilonValue.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3UpsilonValue.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3UpsilonValue.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -32,25 +32,37 @@
 
 namespace JSC { namespace B3 {
 
-class UpsilonValue : public Value {
+class JS_EXPORT_PRIVATE UpsilonValue : public Value {
 public:
     static bool accepts(Opcode opcode) { return opcode == Upsilon; }
 
     ~UpsilonValue();
 
     Value* phi() const { return m_phi; }
+    void setPhi(Value* phi)
+    {
+        ASSERT(child(0)->type() == phi->type());
+        ASSERT(phi->opcode() == Phi);
+        m_phi = phi;
+    }
 
 protected:
     void dumpMeta(PrintStream&) const override;
 
 private:
     friend class Procedure;
-    
-    UpsilonValue(unsigned index, Origin origin, Value* value, Value* phi)
-        : Value(index, Phi, Void, origin, value)
+
+    // Note that passing the Phi during construction is optional. A valid pattern is to first create
+    // the Upsilons without the Phi, then create the Phi, then go back and tell the Upsilons about
+    // the Phi. This allows you to emit code in its natural order.
+    UpsilonValue(unsigned index, Origin origin, Value* value, Value* phi = nullptr)
+        : Value(index, Upsilon, Void, origin, value)
         , m_phi(phi)
     {
-        ASSERT(value->type() == phi->type());
+        if (phi) {
+            ASSERT(value->type() == phi->type());
+            ASSERT(phi->opcode() == Phi);
+        }
     }
 
     Value* m_phi;

Modified: trunk/Source/_javascript_Core/b3/B3Validate.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Validate.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Validate.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -281,6 +281,7 @@
                 break;
             case Upsilon:
                 VALIDATE(value->numChildren() == 1, ("At ", *value));
+                VALIDATE(value->as<UpsilonValue>()->phi(), ("At ", *value));
                 VALIDATE(value->child(0)->type() == value->as<UpsilonValue>()->phi()->type(), ("At ", *value));
                 VALIDATE(valueInProc.contains(value->as<UpsilonValue>()->phi()), ("At ", *value));
                 break;

Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Value.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -127,6 +127,60 @@
     return nullptr;
 }
 
+Value* Value::equalConstant(Procedure&, Value*) const
+{
+    return nullptr;
+}
+
+Value* Value::notEqualConstant(Procedure&, Value*) const
+{
+    return nullptr;
+}
+
+bool Value::returnsBool() const
+{
+    if (type() != Int32)
+        return false;
+    switch (opcode()) {
+    case Const32:
+        return asInt32() == 0 || asInt32() == 1;
+    case BitAnd:
+        return child(1)->isInt32(1);
+    case Equal:
+    case NotEqual:
+    case LessThan:
+    case GreaterThan:
+    case LessEqual:
+    case GreaterEqual:
+    case Above:
+    case Below:
+    case AboveEqual:
+    case BelowEqual:
+        return true;
+    case Phi:
+        // FIXME: We should have a story here.
+        // https://bugs.webkit.org/show_bug.cgi?id=150725
+        return false;
+    default:
+        return false;
+    }
+}
+
+TriState Value::asTriState() const
+{
+    switch (opcode()) {
+    case Const32:
+        return triState(!!asInt32());
+    case Const64:
+        return triState(!!asInt64());
+    case ConstDouble:
+        // Use "!= 0" to really emphasize what this mean with respect to NaN and such.
+        return triState(asDouble() != 0);
+    default:
+        return MixedTriState;
+    }
+}
+
 Effects Value::effects() const
 {
     Effects result;

Modified: trunk/Source/_javascript_Core/b3/B3Value.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3Value.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3Value.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -98,18 +98,30 @@
     template<typename T>
     const T* as() const;
 
+    // What follows are a bunch of helpers for inspecting and modifying values. Note that we have a
+    // bunch of different idioms for implementing such helpers. You can use virtual methods, and
+    // override from the various Value subclasses. You can put the method inside Value and make it
+    // non-virtual, and the implementation can switch on opcode. The method could be inline or not.
+    // If a method is specific to some Value subclass, you could put it in the subclass, or you could
+    // put it on Value anyway. It's fine to pick whatever feels right, and we shouldn't restrict
+    // ourselves to any particular idiom.
+
     bool isConstant() const;
     
     virtual Value* negConstant(Procedure&) const;
     virtual Value* addConstant(Procedure&, int32_t other) const;
     virtual Value* addConstant(Procedure&, Value* other) const;
     virtual Value* subConstant(Procedure&, Value* other) const;
+    virtual Value* equalConstant(Procedure&, Value* other) const;
+    virtual Value* notEqualConstant(Procedure&, Value* other) const;
 
     bool hasInt32() const;
     int32_t asInt32() const;
+    bool isInt32(int32_t) const;
     
     bool hasInt64() const;
     int64_t asInt64() const;
+    bool isInt64(int64_t) const;
 
     bool hasInt() const;
     int64_t asInt() const;
@@ -117,10 +129,24 @@
 
     bool hasIntPtr() const;
     intptr_t asIntPtr() const;
+    bool isIntPtr(intptr_t) const;
 
     bool hasDouble() const;
     double asDouble() const;
+    bool isEqualToDouble(double) const; // We say "isEqualToDouble" because "isDouble" would be a bit equality.
 
+    bool hasNumber() const;
+    template<typename T> bool representableAs() const;
+    template<typename T> T asNumber() const;
+
+    // Booleans in B3 are Const32(0) or Const32(1). So this is true if the type is Int32 and the only
+    // possible return values are 0 or 1. It's OK for this method to conservatively return false.
+    bool returnsBool() const;
+
+    TriState asTriState() const;
+    bool isLikeZero() const { return asTriState() == FalseTriState; }
+    bool isLikeNonZero() const { return asTriState() == TrueTriState; }
+    
     Effects effects() const;
 
     Stackmap* stackmap();

Modified: trunk/Source/_javascript_Core/b3/B3ValueInlines.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/B3ValueInlines.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/B3ValueInlines.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -74,6 +74,11 @@
     return as<Const32Value>()->value();
 }
 
+inline bool Value::isInt32(int32_t value) const
+{
+    return hasInt32() && asInt32() == value;
+}
+
 inline bool Value::hasInt64() const
 {
     return !!as<Const64Value>();
@@ -84,6 +89,11 @@
     return as<Const64Value>()->value();
 }
 
+inline bool Value::isInt64(int64_t value) const
+{
+    return hasInt64() && asInt64() == value;
+}
+
 inline bool Value::hasInt() const
 {
     return hasInt32() || hasInt64();
@@ -113,6 +123,11 @@
     return asInt32();
 }
 
+inline bool Value::isIntPtr(intptr_t value) const
+{
+    return hasIntPtr() && asIntPtr() == value;
+}
+
 inline bool Value::hasDouble() const
 {
     return !!as<ConstDoubleValue>();
@@ -123,6 +138,46 @@
     return as<ConstDoubleValue>()->value();
 }
 
+inline bool Value::isEqualToDouble(double value) const
+{
+    return hasDouble() && asDouble() == value;
+}
+
+inline bool Value::hasNumber() const
+{
+    return hasInt() || hasDouble();
+}
+
+template<typename T>
+inline bool Value::representableAs() const
+{
+    switch (opcode()) {
+    case Const32:
+        return isRepresentableAs<T>(asInt32());
+    case Const64:
+        return isRepresentableAs<T>(asInt64());
+    case ConstDouble:
+        return isRepresentableAs<T>(asDouble());
+    default:
+        return false;
+    }
+}
+
+template<typename T>
+inline T Value::asNumber() const
+{
+    switch (opcode()) {
+    case Const32:
+        return static_cast<T>(asInt32());
+    case Const64:
+        return static_cast<T>(asInt64());
+    case ConstDouble:
+        return static_cast<T>(asDouble());
+    default:
+        return T();
+    }
+}
+
 inline Stackmap* Value::stackmap()
 {
     if (CheckValue* check = as<CheckValue>())

Modified: trunk/Source/_javascript_Core/b3/air/AirArg.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/air/AirArg.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -77,6 +77,9 @@
     case ResCond:
         out.print(asResultCondition());
         return;
+    case DoubleCond:
+        out.print(asDoubleCondition());
+        return;
     case Special:
         out.print(pointerDump(special()));
         return;

Modified: trunk/Source/_javascript_Core/b3/air/AirArg.h (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/air/AirArg.h	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/air/AirArg.h	2015-10-30 21:49:23 UTC (rev 191816)
@@ -64,6 +64,7 @@
         // secondary opcodes. They are always "Use"'d.
         RelCond,
         ResCond,
+        DoubleCond,
         Special
     };
 
@@ -266,6 +267,14 @@
         return result;
     }
 
+    static Arg doubleCond(MacroAssembler::DoubleCondition condition)
+    {
+        Arg result;
+        result.m_kind = DoubleCond;
+        result.m_offset = condition;
+        return result;
+    }
+
     static Arg special(Air::Special* special)
     {
         Arg result;
@@ -340,6 +349,11 @@
         return kind() == ResCond;
     }
 
+    bool isDoubleCond() const
+    {
+        return kind() == DoubleCond;
+    }
+
     bool isSpecial() const
     {
         return kind() == Special;
@@ -446,6 +460,7 @@
         case CallArg:
         case RelCond:
         case ResCond:
+        case DoubleCond:
         case Special:
             return true;
         case Tmp:
@@ -462,6 +477,7 @@
         case Imm:
         case RelCond:
         case ResCond:
+        case DoubleCond:
         case Special:
         case Invalid:
             return false;
@@ -662,6 +678,12 @@
         return static_cast<MacroAssembler::ResultCondition>(m_offset);
     }
 
+    MacroAssembler::DoubleCondition asDoubleCondition() const
+    {
+        ASSERT(isDoubleCond());
+        return static_cast<MacroAssembler::DoubleCondition>(m_offset);
+    }
+
     void dump(PrintStream&) const;
 
     Arg(WTF::HashTableDeletedValueType)

Modified: trunk/Source/_javascript_Core/b3/air/AirCode.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/air/AirCode.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/air/AirCode.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -83,7 +83,11 @@
 
 void Code::resetReachability()
 {
-    B3::resetReachability(m_blocks);
+    B3::resetReachability(
+        m_blocks,
+        [&] (BasicBlock*) {
+            // We don't have to do anything special for deleted blocks.
+        });
 }
 
 void Code::dump(PrintStream& out) const

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2015-10-30 21:49:23 UTC (rev 191816)
@@ -134,6 +134,22 @@
 MoveDoubleTo64 U:F, D:G
     Tmp, Tmp
 
+BranchTest32 U:G, U:G, U:G /branch
+    ResCond, Tmp, Tmp
+    ResCond, Tmp, Imm
+    ResCond, Addr, Imm
+    ResCond, Index, Imm
+
+BranchTest64 U:G, U:G, U:G /branch
+    ResCond, Tmp, Tmp
+    ResCond, Tmp, Imm
+    ResCond, Addr, Imm
+    ResCond, Addr, Tmp
+    ResCond, Index, Imm
+
+BranchDouble U:G, U:F, U:F /branch
+    DoubleCond, Tmp, Tmp
+
 BranchAdd32 U:G, U:G, UD:G /branch
     ResCond, Tmp, Tmp
     ResCond, Imm, Tmp

Modified: trunk/Source/_javascript_Core/b3/air/opcode_generator.rb (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/air/opcode_generator.rb	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/air/opcode_generator.rb	2015-10-30 21:49:23 UTC (rev 191816)
@@ -180,7 +180,7 @@
 end
 
 def isKind(token)
-    token =~ /\A((Tmp)|(Imm)|(Imm64)|(Addr)|(Index)|(RelCond)|(ResCond))\Z/
+    token =~ /\A((Tmp)|(Imm)|(Imm64)|(Addr)|(Index)|(RelCond)|(ResCond)|(DoubleCond))\Z/
 end
 
 def isKeyword(token)
@@ -246,7 +246,7 @@
 
     def consumeKind
         result = token.string
-        parseError("Expected kind (Imm, Imm64, Tmp, Addr, Index, RelCond, or ResCond)") unless isKind(result)
+        parseError("Expected kind (Imm, Imm64, Tmp, Addr, Index, RelCond, ResCond, or DoubleCond)") unless isKind(result)
         advance
         result
     end
@@ -830,6 +830,8 @@
                     outp.print "args[#{index}].asRelationalCondition()"
                 when "ResCond"
                     outp.print "args[#{index}].asResultCondition()"
+                when "DoubleCond"
+                    outp.print "args[#{index}].asDoubleCondition()"
                 end
             }
 

Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (191815 => 191816)


--- trunk/Source/_javascript_Core/b3/testb3.cpp	2015-10-30 21:37:25 UTC (rev 191815)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp	2015-10-30 21:49:23 UTC (rev 191816)
@@ -34,6 +34,7 @@
 #include "B3MemoryValue.h"
 #include "B3Procedure.h"
 #include "B3StackSlotValue.h"
+#include "B3UpsilonValue.h"
 #include "B3ValueInlines.h"
 #include "CCallHelpers.h"
 #include "InitializeThreading.h"
@@ -41,6 +42,16 @@
 #include "LinkBuffer.h"
 #include "VM.h"
 
+// We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous.
+static bool hiddenTruthBecauseNoReturnIsStupid() { return true; }
+
+static void usage()
+{
+    dataLog("Usage: testb3 [<filter>]\n");
+    if (hiddenTruthBecauseNoReturnIsStupid())
+        exit(1);
+}
+
 #if ENABLE(B3_JIT)
 
 using namespace JSC;
@@ -53,17 +64,27 @@
 
 VM* vm;
 
-template<typename T, typename... Arguments>
-T compileAndRun(Procedure& procedure, Arguments... arguments)
+MacroAssemblerCodeRef compile(Procedure& procedure)
 {
     CCallHelpers jit(vm);
     generate(procedure, jit);
     LinkBuffer linkBuffer(*vm, jit, nullptr);
-    MacroAssemblerCodeRef code = FINALIZE_CODE(linkBuffer, ("testb3"));
+    return FINALIZE_CODE(linkBuffer, ("testb3"));
+}
+
+template<typename T, typename... Arguments>
+T invoke(const MacroAssemblerCodeRef& code, Arguments... arguments)
+{
     T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(code.code().executableAddress());
     return function(arguments...);
 }
 
+template<typename T, typename... Arguments>
+T compileAndRun(Procedure& procedure, Arguments... arguments)
+{
+    return invoke<T>(compile(procedure), arguments...);
+}
+
 void test42()
 {
     Procedure proc;
@@ -493,17 +514,433 @@
     CHECK(compileAndRun<int>(proc, value) == value);
 }
 
+void testBranch()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchPtr()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, static_cast<intptr_t>(42)) == 1);
+    CHECK(invoke<int>(code, static_cast<intptr_t>(0)) == 0);
+}
+
+void testDiamond()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+    BasicBlock* done = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Trunc, Origin(),
+            root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>(
+        proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+    thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+
+    UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(
+        proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+    elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+
+    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
+    thenResult->setPhi(phi);
+    elseResult->setPhi(phi);
+    done->appendNew<ControlValue>(proc, Return, Origin(), phi);
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchNotEqual()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, NotEqual, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchNotEqualCommute()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, NotEqual, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), 0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchNotEqualNotEqual()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, NotEqual, Origin(),
+            root->appendNew<Value>(
+                proc, NotEqual, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), 0)),
+            root->appendNew<Const32Value>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchEqual()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+            root->appendNew<Const32Value>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchEqualEqual()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<Value>(
+                proc, Equal, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), 0)),
+            root->appendNew<Const32Value>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchEqualCommute()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<Const32Value>(proc, Origin(), 0),
+            root->appendNew<Value>(
+                proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchEqualEqual1()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<Value>(
+                proc, Equal, Origin(),
+                root->appendNew<Value>(
+                    proc, Trunc, Origin(),
+                    root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
+                root->appendNew<Const32Value>(proc, Origin(), 0)),
+            root->appendNew<Const32Value>(proc, Origin(), 1)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    auto code = compile(proc);
+    CHECK(invoke<int>(code, 42) == 1);
+    CHECK(invoke<int>(code, 0) == 0);
+}
+
+void testBranchFold(int value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), value),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(compileAndRun<int>(proc) == !!value);
+}
+
+void testDiamondFold(int value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+    BasicBlock* done = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), value),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    UpsilonValue* thenResult = thenCase->appendNew<UpsilonValue>(
+        proc, Origin(), thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+    thenCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+
+    UpsilonValue* elseResult = elseCase->appendNew<UpsilonValue>(
+        proc, Origin(), elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+    elseCase->appendNew<ControlValue>(proc, Jump, Origin(), FrequentedBlock(done));
+
+    Value* phi = done->appendNew<Value>(proc, Phi, Int32, Origin());
+    thenResult->setPhi(phi);
+    elseResult->setPhi(phi);
+    done->appendNew<ControlValue>(proc, Return, Origin(), phi);
+
+    CHECK(compileAndRun<int>(proc) == !!value);
+}
+
+void testBranchNotEqualFoldPtr(intptr_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, NotEqual, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), value),
+            root->appendNew<ConstPtrValue>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(compileAndRun<int>(proc) == !!value);
+}
+
+void testBranchEqualFoldPtr(intptr_t value)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* thenCase = proc.addBlock();
+    BasicBlock* elseCase = proc.addBlock();
+
+    root->appendNew<ControlValue>(
+        proc, Branch, Origin(),
+        root->appendNew<Value>(
+            proc, Equal, Origin(),
+            root->appendNew<ConstPtrValue>(proc, Origin(), value),
+            root->appendNew<ConstPtrValue>(proc, Origin(), 0)),
+        FrequentedBlock(thenCase), FrequentedBlock(elseCase));
+
+    thenCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        thenCase->appendNew<Const32Value>(proc, Origin(), 1));
+
+    elseCase->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        elseCase->appendNew<Const32Value>(proc, Origin(), 0));
+
+    CHECK(compileAndRun<int>(proc) == !value);
+}
+
 #define RUN(test) do {                          \
+        if (!shouldRun(#test))                  \
+            break;                              \
         dataLog(#test ":\n");                   \
         test;                                   \
         dataLog("    OK!\n");                   \
+        didRun++;                               \
     } while (false);
 
-void run()
+void run(const char* filter)
 {
     JSC::initializeThreading();
     vm = &VM::create(LargeHeap).leakRef();
 
+    auto shouldRun = [&] (const char* testName) -> bool {
+        return !!strcasestr(testName, filter);
+    };
+    unsigned didRun = 0;
+
     RUN(test42());
     RUN(testLoad42());
     RUN(testArg(43));
@@ -532,13 +969,34 @@
     RUN(testStackSlot());
     RUN(testLoadFromFramePointer());
     RUN(testStoreLoadStackSlot(50));
+    RUN(testBranch());
+    RUN(testBranchPtr());
+    RUN(testDiamond());
+    RUN(testBranchNotEqual());
+    RUN(testBranchNotEqualCommute());
+    RUN(testBranchNotEqualNotEqual());
+    RUN(testBranchEqual());
+    RUN(testBranchEqualEqual());
+    RUN(testBranchEqualCommute());
+    RUN(testBranchEqualEqual1());
+    RUN(testBranchFold(42));
+    RUN(testBranchFold(0));
+    RUN(testDiamondFold(42));
+    RUN(testDiamondFold(0));
+    RUN(testBranchNotEqualFoldPtr(42));
+    RUN(testBranchNotEqualFoldPtr(0));
+    RUN(testBranchEqualFoldPtr(42));
+    RUN(testBranchEqualFoldPtr(0));
+
+    if (!didRun)
+        usage();
 }
 
 } // anonymous namespace
 
 #else // ENABLE(B3_JIT)
 
-static void run()
+static void run(const char*)
 {
     dataLog("B3 JIT is not enabled.\n");
 }
@@ -547,10 +1005,19 @@
 
 int main(int argc, char** argv)
 {
-    UNUSED_PARAM(argc);
-    UNUSED_PARAM(argv);
+    const char* filter = "";
+    switch (argc) {
+    case 1:
+        break;
+    case 2:
+        filter = argv[1];
+        break;
+    default:
+        usage();
+        break;
+    }
     
-    run();
+    run(filter);
     return 0;
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to