Title: [197490] trunk/Source/_javascript_Core
Revision
197490
Author
[email protected]
Date
2016-03-02 21:19:02 -0800 (Wed, 02 Mar 2016)

Log Message

[JSC] Improve Select of Doubles based on Double condition
https://bugs.webkit.org/show_bug.cgi?id=154572

Patch by Benjamin Poulain <[email protected]> on 2016-03-02
Reviewed by Filip Pizlo.

Octane has a bunch of Select on Double based on comparing Doubles.
A few nodes generate that: ValueRep, Min, Max, etc.

On ARM64, we can improve our code a lot. ARM can do a select
based on flags with the FCSEL instruction.

On x86, this patch adds aggressive aliasing for moveDoubleConditionallyXXX.
This has obviously a much more limited impact.

* assembler/MacroAssembler.h:
(JSC::MacroAssembler::moveDoubleConditionally32): Deleted.
(JSC::MacroAssembler::moveDoubleConditionally64): Deleted.
(JSC::MacroAssembler::moveDoubleConditionallyTest32): Deleted.
(JSC::MacroAssembler::moveDoubleConditionallyTest64): Deleted.
(JSC::MacroAssembler::moveDoubleConditionallyDouble): Deleted.
(JSC::MacroAssembler::moveDoubleConditionallyFloat): Deleted.
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::moveDoubleConditionallyAfterFloatingPointCompare):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyDouble):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyFloat):
(JSC::MacroAssemblerARM64::moveConditionally32):
(JSC::MacroAssemblerARM64::moveDoubleConditionally32):
(JSC::MacroAssemblerARM64::moveDoubleConditionally64):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyTest32):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyTest64):
(JSC::MacroAssemblerARM64::branch64):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::moveConditionally32):
(JSC::MacroAssemblerX86Common::moveDoubleConditionally32):
(JSC::MacroAssemblerX86Common::moveDoubleConditionallyTest32):
(JSC::MacroAssemblerX86Common::moveDoubleConditionallyDouble):
(JSC::MacroAssemblerX86Common::moveDoubleConditionallyFloat):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::moveDoubleConditionally64):
(JSC::MacroAssemblerX86_64::moveDoubleConditionallyTest64):
* b3/air/AirInstInlines.h:
(JSC::B3::Air::Inst::shouldTryAliasingDef):
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::populateWithInterestingValues):
(JSC::B3::floatingPointOperands):
(JSC::B3::int64Operands):
(JSC::B3::int32Operands):
(JSC::B3::testSelectCompareFloat):
(JSC::B3::testSelectCompareFloatToDouble):
(JSC::B3::testSelectDoubleCompareDouble):
(JSC::B3::testSelectDoubleCompareDoubleWithAliasing):
(JSC::B3::testSelectFloatCompareFloat):
(JSC::B3::testSelectFloatCompareFloatWithAliasing):
(JSC::B3::run):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (197489 => 197490)


--- trunk/Source/_javascript_Core/ChangeLog	2016-03-03 05:15:56 UTC (rev 197489)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-03-03 05:19:02 UTC (rev 197490)
@@ -1,3 +1,61 @@
+2016-03-02  Benjamin Poulain  <[email protected]>
+
+        [JSC] Improve Select of Doubles based on Double condition
+        https://bugs.webkit.org/show_bug.cgi?id=154572
+
+        Reviewed by Filip Pizlo.
+
+        Octane has a bunch of Select on Double based on comparing Doubles.
+        A few nodes generate that: ValueRep, Min, Max, etc.
+
+        On ARM64, we can improve our code a lot. ARM can do a select
+        based on flags with the FCSEL instruction.
+
+        On x86, this patch adds aggressive aliasing for moveDoubleConditionallyXXX.
+        This has obviously a much more limited impact.
+
+        * assembler/MacroAssembler.h:
+        (JSC::MacroAssembler::moveDoubleConditionally32): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionally64): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionallyTest32): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionallyTest64): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionallyDouble): Deleted.
+        (JSC::MacroAssembler::moveDoubleConditionallyFloat): Deleted.
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyAfterFloatingPointCompare):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyDouble):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyFloat):
+        (JSC::MacroAssemblerARM64::moveConditionally32):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionally32):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionally64):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyTest32):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyTest64):
+        (JSC::MacroAssemblerARM64::branch64):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::moveConditionally32):
+        (JSC::MacroAssemblerX86Common::moveDoubleConditionally32):
+        (JSC::MacroAssemblerX86Common::moveDoubleConditionallyTest32):
+        (JSC::MacroAssemblerX86Common::moveDoubleConditionallyDouble):
+        (JSC::MacroAssemblerX86Common::moveDoubleConditionallyFloat):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::moveDoubleConditionally64):
+        (JSC::MacroAssemblerX86_64::moveDoubleConditionallyTest64):
+        * b3/air/AirInstInlines.h:
+        (JSC::B3::Air::Inst::shouldTryAliasingDef):
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::populateWithInterestingValues):
+        (JSC::B3::floatingPointOperands):
+        (JSC::B3::int64Operands):
+        (JSC::B3::int32Operands):
+        (JSC::B3::testSelectCompareFloat):
+        (JSC::B3::testSelectCompareFloatToDouble):
+        (JSC::B3::testSelectDoubleCompareDouble):
+        (JSC::B3::testSelectDoubleCompareDoubleWithAliasing):
+        (JSC::B3::testSelectFloatCompareFloat):
+        (JSC::B3::testSelectFloatCompareFloatWithAliasing):
+        (JSC::B3::run):
+
 2016-03-02  Joseph Pecoraro  <[email protected]>
 
         Add ability to generate a Heap Snapshot

Modified: trunk/Source/_javascript_Core/assembler/MacroAssembler.h (197489 => 197490)


--- trunk/Source/_javascript_Core/assembler/MacroAssembler.h	2016-03-03 05:15:56 UTC (rev 197489)
+++ trunk/Source/_javascript_Core/assembler/MacroAssembler.h	2016-03-03 05:19:02 UTC (rev 197490)
@@ -1315,68 +1315,6 @@
 #endif // !CPU(X86_64)
 
 #if ENABLE(B3_JIT)
-    template<typename LeftType, typename RightType>
-    void moveDoubleConditionally32(RelationalCondition cond, LeftType left, RightType right, FPRegisterID src, FPRegisterID dest)
-    {
-        Jump falseCase = branch32(invert(cond), left, right);
-        moveDouble(src, dest);
-        falseCase.link(this);
-    }
-
-    template<typename LeftType, typename RightType>
-    void moveDoubleConditionally64(RelationalCondition cond, LeftType left, RightType right, FPRegisterID src, FPRegisterID dest)
-    {
-        Jump falseCase = branch64(invert(cond), left, right);
-        moveDouble(src, dest);
-        falseCase.link(this);
-    }
-
-    template<typename TestType, typename MaskType>
-    void moveDoubleConditionallyTest32(ResultCondition cond, TestType test, MaskType mask, FPRegisterID src, FPRegisterID dest)
-    {
-        if (isInvertible(cond)) {
-            Jump falseCase = branchTest32(invert(cond), test, mask);
-            moveDouble(src, dest);
-            falseCase.link(this);
-        }
-
-        Jump trueCase = branchTest32(cond, test, mask);
-        Jump falseCase = jump();
-        trueCase.link(this);
-        moveDouble(src, dest);
-        falseCase.link(this);
-    }
-
-    template<typename TestType, typename MaskType>
-    void moveDoubleConditionallyTest64(ResultCondition cond, TestType test, MaskType mask, FPRegisterID src, FPRegisterID dest)
-    {
-        if (isInvertible(cond)) {
-            Jump falseCase = branchTest64(invert(cond), test, mask);
-            moveDouble(src, dest);
-            falseCase.link(this);
-        }
-
-        Jump trueCase = branchTest64(cond, test, mask);
-        Jump falseCase = jump();
-        trueCase.link(this);
-        moveDouble(src, dest);
-        falseCase.link(this);
-    }
-
-    void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID src, FPRegisterID dest)
-    {
-        Jump falseCase = branchDouble(invert(cond), left, right);
-        moveDouble(src, dest);
-        falseCase.link(this);
-    }
-
-    void moveDoubleConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID src, FPRegisterID dest)
-    {
-        Jump falseCase = branchFloat(invert(cond), left, right);
-        moveDouble(src, dest);
-        falseCase.link(this);
-    }
-
     // We should implement this the right way eventually, but for now, it's fine because it arises so
     // infrequently.
     void compareDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, RegisterID dest)

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (197489 => 197490)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2016-03-03 05:15:56 UTC (rev 197489)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2016-03-03 05:19:02 UTC (rev 197490)
@@ -1666,6 +1666,39 @@
         m_assembler.csel<datasize>(dest, thenCase, elseCase, ARM64Condition(cond));
     }
 
+    template<int datasize>
+    void moveDoubleConditionallyAfterFloatingPointCompare(DoubleCondition cond, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (cond == DoubleNotEqual) {
+            Jump unordered = makeBranch(ARM64Assembler::ConditionVS);
+            m_assembler.fcsel<datasize>(dest, thenCase, elseCase, ARM64Assembler::ConditionNE);
+            unordered.link(this);
+            return;
+        }
+        if (cond == DoubleEqualOrUnordered) {
+            // If the compare is unordered, thenCase is copied to dest and the
+            // next csel has all arguments equal to thenCase.
+            // If the compare is ordered, dest is unchanged and EQ decides
+            // what value to set.
+            m_assembler.fcsel<datasize>(dest, thenCase, elseCase, ARM64Assembler::ConditionVS);
+            m_assembler.fcsel<datasize>(dest, thenCase, dest, ARM64Assembler::ConditionEQ);
+            return;
+        }
+        m_assembler.fcsel<datasize>(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.fcmp<64>(left, right);
+        moveDoubleConditionallyAfterFloatingPointCompare<64>(cond, thenCase, elseCase, dest);
+    }
+
+    void moveDoubleConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.fcmp<32>(left, right);
+        moveDoubleConditionallyAfterFloatingPointCompare<64>(cond, thenCase, elseCase, dest);
+    }
+
     void mulDouble(FPRegisterID src, FPRegisterID dest)
     {
         mulDouble(dest, src, dest);
@@ -1938,6 +1971,19 @@
         m_assembler.csel<32>(dest, thenCase, elseCase, ARM64Condition(cond));
     }
 
+    void moveConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        if (isUInt12(right.m_value))
+            m_assembler.cmp<32>(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn<32>(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp<32>(left, dataTempRegister);
+        }
+        m_assembler.csel<64>(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
     void moveConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID src, RegisterID dest)
     {
         m_assembler.cmp<64>(left, right);
@@ -1974,6 +2020,56 @@
         m_assembler.csel<64>(dest, thenCase, elseCase, ARM64Condition(cond));
     }
 
+    void moveDoubleConditionally32(RelationalCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.cmp<32>(left, right);
+        m_assembler.fcsel<32>(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (isUInt12(right.m_value))
+            m_assembler.cmp<32>(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn<32>(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp<32>(left, dataTempRegister);
+        }
+        m_assembler.fcsel<64>(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionally64(RelationalCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.cmp<64>(left, right);
+        m_assembler.fcsel<64>(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionally64(RelationalCondition cond, RegisterID left, TrustedImm32 right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (isUInt12(right.m_value))
+            m_assembler.cmp<64>(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn<64>(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp<64>(left, dataTempRegister);
+        }
+        m_assembler.fcsel<64>(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionallyTest32(ResultCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.tst<32>(left, right);
+        m_assembler.fcsel<64>(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
+    void moveDoubleConditionallyTest64(ResultCondition cond, RegisterID left, RegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        m_assembler.tst<64>(left, right);
+        m_assembler.fcsel<64>(dest, thenCase, elseCase, ARM64Condition(cond));
+    }
+
     // Forwards / external control flow operations:
     //
     // This set of jump and conditional branch operations return a Jump
@@ -2063,6 +2159,19 @@
         return Jump(makeBranch(cond));
     }
 
+    Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm32 right)
+    {
+        if (isUInt12(right.m_value))
+            m_assembler.cmp<64>(left, UInt12(right.m_value));
+        else if (isUInt12(-right.m_value))
+            m_assembler.cmn<64>(left, UInt12(-right.m_value));
+        else {
+            moveToCachedReg(right, dataMemoryTempRegister());
+            m_assembler.cmp<64>(left, dataTempRegister);
+        }
+        return Jump(makeBranch(cond));
+    }
+
     Jump branch64(RelationalCondition cond, RegisterID left, TrustedImm64 right)
     {
         intptr_t immediate = right.m_value;

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (197489 => 197490)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2016-03-03 05:15:56 UTC (rev 197489)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2016-03-03 05:19:02 UTC (rev 197490)
@@ -1777,6 +1777,24 @@
             cmov(x86Condition(invert(cond)), elseCase, dest);
     }
 
+    void moveConditionally32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
+    {
+        if (((cond == Equal) || (cond == NotEqual)) && !right.m_value)
+            m_assembler.testl_rr(left, left);
+        else
+            m_assembler.cmpl_ir(right.m_value, left);
+
+        if (thenCase != dest && elseCase != dest) {
+            move(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest)
+            cmov(x86Condition(cond), thenCase, dest);
+        else
+            cmov(x86Condition(invert(cond)), elseCase, dest);
+    }
+
     void moveConditionallyTest32(ResultCondition cond, RegisterID testReg, RegisterID mask, RegisterID src, RegisterID dest)
     {
         m_assembler.testl_rr(testReg, mask);
@@ -1825,6 +1843,90 @@
             cmov(x86Condition(invert(cond)), elseCase, dest);
     }
 
+    template<typename LeftType, typename RightType>
+    void moveDoubleConditionally32(RelationalCondition cond, LeftType left, RightType right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        static_assert(!std::is_same<LeftType, FPRegisterID>::value && !std::is_same<RightType, FPRegisterID>::value, "One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().");
+
+        if (thenCase != dest && elseCase != dest) {
+            moveDouble(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest) {
+            Jump falseCase = branch32(invert(cond), left, right);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else {
+            Jump trueCase = branch32(cond, left, right);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        }
+    }
+
+    template<typename TestType, typename MaskType>
+    void moveDoubleConditionallyTest32(ResultCondition cond, TestType test, MaskType mask, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        static_assert(!std::is_same<TestType, FPRegisterID>::value && !std::is_same<MaskType, FPRegisterID>::value, "One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().");
+
+        if (elseCase == dest && isInvertible(cond)) {
+            Jump falseCase = branchTest32(invert(cond), test, mask);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else if (thenCase == dest) {
+            Jump trueCase = branchTest32(cond, test, mask);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        }
+
+        Jump trueCase = branchTest32(cond, test, mask);
+        moveDouble(elseCase, dest);
+        Jump falseCase = jump();
+        trueCase.link(this);
+        moveDouble(thenCase, dest);
+        falseCase.link(this);
+    }
+
+    void moveDoubleConditionallyDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (elseCase == dest) {
+            Jump falseCase = branchDouble(invert(cond), left, right);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else if (thenCase == dest) {
+            Jump trueCase = branchDouble(cond, left, right);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        } else {
+            Jump trueCase = branchDouble(cond, left, right);
+            moveDouble(elseCase, dest);
+            Jump falseCase = jump();
+            trueCase.link(this);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        }
+    }
+
+    void moveDoubleConditionallyFloat(DoubleCondition cond, FPRegisterID left, FPRegisterID right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        if (elseCase == dest) {
+            Jump falseCase = branchFloat(invert(cond), left, right);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else if (thenCase == dest) {
+            Jump trueCase = branchFloat(cond, left, right);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        } else {
+            Jump trueCase = branchFloat(cond, left, right);
+            moveDouble(elseCase, dest);
+            Jump falseCase = jump();
+            trueCase.link(this);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        }
+    }
+
     // Forwards / external control flow operations:
     //
     // This set of jump and conditional branch operations return a Jump

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (197489 => 197490)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2016-03-03 05:15:56 UTC (rev 197489)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2016-03-03 05:19:02 UTC (rev 197490)
@@ -1052,6 +1052,50 @@
         else
             cmov(x86Condition(invert(cond)), elseCase, dest);
     }
+
+    template<typename LeftType, typename RightType>
+    void moveDoubleConditionally64(RelationalCondition cond, LeftType left, RightType right, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        static_assert(!std::is_same<LeftType, FPRegisterID>::value && !std::is_same<RightType, FPRegisterID>::value, "One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().");
+
+        if (thenCase != dest && elseCase != dest) {
+            moveDouble(elseCase, dest);
+            elseCase = dest;
+        }
+
+        if (elseCase == dest) {
+            Jump falseCase = branch64(invert(cond), left, right);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else {
+            Jump trueCase = branch64(cond, left, right);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        }
+    }
+
+    template<typename TestType, typename MaskType>
+    void moveDoubleConditionallyTest64(ResultCondition cond, TestType test, MaskType mask, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
+    {
+        static_assert(!std::is_same<TestType, FPRegisterID>::value && !std::is_same<MaskType, FPRegisterID>::value, "One of the tested argument could be aliased on dest. Use moveDoubleConditionallyDouble().");
+
+        if (elseCase == dest && isInvertible(cond)) {
+            Jump falseCase = branchTest64(invert(cond), test, mask);
+            moveDouble(thenCase, dest);
+            falseCase.link(this);
+        } else if (thenCase == dest) {
+            Jump trueCase = branchTest64(cond, test, mask);
+            moveDouble(elseCase, dest);
+            trueCase.link(this);
+        }
+
+        Jump trueCase = branchTest64(cond, test, mask);
+        moveDouble(elseCase, dest);
+        Jump falseCase = jump();
+        trueCase.link(this);
+        moveDouble(thenCase, dest);
+        falseCase.link(this);
+    }
     
     void abortWithReason(AbortReason reason)
     {

Modified: trunk/Source/_javascript_Core/b3/air/AirInstInlines.h (197489 => 197490)


--- trunk/Source/_javascript_Core/b3/air/AirInstInlines.h	2016-03-03 05:15:56 UTC (rev 197489)
+++ trunk/Source/_javascript_Core/b3/air/AirInstInlines.h	2016-03-03 05:19:02 UTC (rev 197490)
@@ -202,6 +202,12 @@
     case MoveConditionallyTest64:
     case MoveConditionallyDouble:
     case MoveConditionallyFloat:
+    case MoveDoubleConditionally32:
+    case MoveDoubleConditionally64:
+    case MoveDoubleConditionallyTest32:
+    case MoveDoubleConditionallyTest64:
+    case MoveDoubleConditionallyDouble:
+    case MoveDoubleConditionallyFloat:
         if (args.size() == 6)
             return 5;
         break;

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (197489 => 197490)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2016-03-03 05:15:56 UTC (rev 197489)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2016-03-03 05:19:02 UTC (rev 197490)
@@ -632,7 +632,7 @@
 
 64: Branch64 U:G:32, U:G:64, U:G:64 /branch
     RelCond, Tmp, Tmp
-    x86: RelCond, Tmp, Imm
+    RelCond, Tmp, Imm
     x86: RelCond, Tmp, Addr
     x86: RelCond, Addr, Tmp
     x86: RelCond, Addr, Imm
@@ -723,6 +723,7 @@
 
 MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
     RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
 
 64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
     RelCond, Tmp, Tmp, Tmp, Tmp
@@ -758,25 +759,42 @@
 MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, UD:G:Ptr
     DoubleCond, Tmp, Tmp, Tmp, Tmp
 
-MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64
-    RelCond, Tmp, Tmp, Tmp, Tmp
+MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
+    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
+    x86: RelCond, Addr, Imm, Tmp, Tmp, Tmp
+    x86: RelCond, Tmp, Addr, Tmp, Tmp, Tmp
+    x86: RelCond, Addr, Tmp, Tmp, Tmp, Tmp
+    x86: RelCond, Index, Imm, Tmp, Tmp, Tmp
 
-64: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64
-    RelCond, Tmp, Tmp, Tmp, Tmp
+64: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, U:F:64, D:F:64
+    RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    RelCond, Tmp, Imm, Tmp, Tmp, Tmp
+    x86_64: RelCond, Tmp, Addr, Tmp, Tmp, Tmp
+    x86_64: RelCond, Addr, Tmp, Tmp, Tmp, Tmp
+    x86_64: RelCond, Addr, Imm, Tmp, Tmp, Tmp
+    x86_64: RelCond, Index, Tmp, Tmp, Tmp, Tmp
 
-MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64
-    ResCond, Tmp, Tmp, Tmp, Tmp
-    x86: ResCond, Tmp, Imm, Tmp, Tmp
+MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
+    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    x86: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
+    x86: ResCond, Addr, Imm, Tmp, Tmp, Tmp
+    x86: ResCond, Index, Imm, Tmp, Tmp, Tmp
 
-64: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64
-    ResCond, Tmp, Tmp, Tmp, Tmp
-    ResCond, Tmp, Imm, Tmp, Tmp
+# Warning: forms that take an immediate will sign-extend their immediate. You probably want
+# MoveDoubleConditionallyTest32 in most cases where you use an immediate.
+64: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, U:F:64, D:F:64
+    ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
+    x86_64: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
+    x86_64: ResCond, Addr, Imm, Tmp, Tmp, Tmp
+    x86_64: ResCond, Addr, Tmp, Tmp, Tmp, Tmp
+    x86_64: ResCond, Index, Imm, Tmp, Tmp, Tmp
 
-MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, UD:F:64
-    DoubleCond, Tmp, Tmp, Tmp, Tmp
+MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, U:F:64, D:F:64
+    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
 
-MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, UD:F:64
-    DoubleCond, Tmp, Tmp, Tmp, Tmp
+MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, U:F:64, D:F:64
+    DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
 
 Jump /branch
 

Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (197489 => 197490)


--- trunk/Source/_javascript_Core/b3/testb3.cpp	2016-03-03 05:15:56 UTC (rev 197489)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp	2016-03-03 05:19:02 UTC (rev 197490)
@@ -104,6 +104,78 @@
     return invoke<T>(*compile(procedure), arguments...);
 }
 
+template<typename Type>
+struct Operand {
+    const char* name;
+    Type value;
+};
+
+typedef Operand<int64_t> Int64Operand;
+typedef Operand<int32_t> Int32Operand;
+
+template<typename FloatType>
+void populateWithInterestingValues(Vector<Operand<FloatType>>& operands)
+{
+    operands.append({ "0.", static_cast<FloatType>(0.) });
+    operands.append({ "-0.", static_cast<FloatType>(-0.) });
+    operands.append({ "0.4", static_cast<FloatType>(0.5) });
+    operands.append({ "-0.4", static_cast<FloatType>(-0.5) });
+    operands.append({ "0.5", static_cast<FloatType>(0.5) });
+    operands.append({ "-0.5", static_cast<FloatType>(-0.5) });
+    operands.append({ "0.6", static_cast<FloatType>(0.5) });
+    operands.append({ "-0.6", static_cast<FloatType>(-0.5) });
+    operands.append({ "1.", static_cast<FloatType>(1.) });
+    operands.append({ "-1.", static_cast<FloatType>(-1.) });
+    operands.append({ "2.", static_cast<FloatType>(2.) });
+    operands.append({ "-2.", static_cast<FloatType>(-2.) });
+    operands.append({ "M_PI", static_cast<FloatType>(M_PI) });
+    operands.append({ "-M_PI", static_cast<FloatType>(-M_PI) });
+    operands.append({ "min", std::numeric_limits<FloatType>::min() });
+    operands.append({ "max", std::numeric_limits<FloatType>::max() });
+    operands.append({ "lowest", std::numeric_limits<FloatType>::lowest() });
+    operands.append({ "epsilon", std::numeric_limits<FloatType>::epsilon() });
+    operands.append({ "infiniti", std::numeric_limits<FloatType>::infinity() });
+    operands.append({ "-infiniti", - std::numeric_limits<FloatType>::infinity() });
+    operands.append({ "PNaN", static_cast<FloatType>(PNaN) });
+}
+
+template<typename FloatType>
+Vector<Operand<FloatType>> floatingPointOperands()
+{
+    Vector<Operand<FloatType>> operands;
+    populateWithInterestingValues(operands);
+    return operands;
+};
+
+static Vector<Int64Operand> int64Operands()
+{
+    Vector<Int64Operand> operands;
+    for (const auto& doubleOperand : floatingPointOperands<double>())
+        operands.append({ doubleOperand.name, bitwise_cast<int64_t>(doubleOperand.value) });
+    operands.append({ "1", 1 });
+    operands.append({ "-1", -1 });
+    operands.append({ "int64-max", std::numeric_limits<int64_t>::max() });
+    operands.append({ "int64-min", std::numeric_limits<int64_t>::min() });
+    operands.append({ "int32-max", std::numeric_limits<int32_t>::max() });
+    operands.append({ "int32-min", std::numeric_limits<int32_t>::min() });
+
+    return operands;
+}
+
+static Vector<Int32Operand> int32Operands()
+{
+    Vector<Int32Operand> operands({
+        { "0", 0 },
+        { "1", 1 },
+        { "-1", -1 },
+        { "42", 42 },
+        { "-42", -42 },
+        { "int32-max", std::numeric_limits<int32_t>::max() },
+        { "int32-min", std::numeric_limits<int32_t>::min() }
+    });
+    return operands;
+}
+
 void add32(CCallHelpers& jit, GPRReg src1, GPRReg src2, GPRReg dest)
 {
     if (src2 == dest)
@@ -9856,6 +9928,7 @@
     testSelectCompareFloat<GreaterThan>(a, b, [](float a, float b) -> bool { return a > b; });
     testSelectCompareFloat<LessEqual>(a, b, [](float a, float b) -> bool { return a <= b; });
     testSelectCompareFloat<GreaterEqual>(a, b, [](float a, float b) -> bool { return a >= b; });
+    testSelectCompareFloat<EqualOrUnordered>(a, b, [](float a, float b) -> bool { return a != a || b != b || a == b; });
 }
 
 template<B3::Opcode opcode>
@@ -9893,6 +9966,7 @@
     testSelectCompareFloatToDouble<GreaterThan>(a, b, [](float a, float b) -> bool { return a > b; });
     testSelectCompareFloatToDouble<LessEqual>(a, b, [](float a, float b) -> bool { return a <= b; });
     testSelectCompareFloatToDouble<GreaterEqual>(a, b, [](float a, float b) -> bool { return a >= b; });
+    testSelectCompareFloatToDouble<EqualOrUnordered>(a, b, [](float a, float b) -> bool { return a != a || b != b || a == b; });
 }
 
 void testSelectDouble()
@@ -10015,6 +10089,406 @@
     CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a), bitwise_cast<int32_t>(b), bitwise_cast<int32_t>(1.1f), bitwise_cast<int32_t>(-42.f)), a < b ? 1.1f : -42.f));
 }
 
+
+template<B3::Opcode opcode>
+void testSelectDoubleCompareDouble(bool (*operation)(double, double))
+{
+    { // Compare arguments and selected arguments are all different.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2);
+        Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3);
+
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, Select, Origin(),
+                root->appendNew<Value>(
+                    proc, opcode, Origin(),
+                    arg0,
+                    arg1),
+                arg2,
+                arg3));
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<double>()) {
+            for (auto& right : floatingPointOperands<double>()) {
+                double expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, -66.5), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. "thenCase" is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2);
+        Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3);
+
+        Value* result = root->appendNew<Value>(proc, Select, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<double>()) {
+            for (auto& right : floatingPointOperands<double>()) {
+                double expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, -66.5), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. "elseCase" is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2);
+        Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3);
+
+        Value* result = root->appendNew<Value>(proc, Select, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        keepValuesLive->append(ConstrainedValue(arg3, ValueRep::SomeRegister));
+        keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<double>()) {
+            for (auto& right : floatingPointOperands<double>()) {
+                double expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, -66.5), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. Both cases are live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2);
+        Value* arg3 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR3);
+
+        Value* result = root->appendNew<Value>(proc, Select, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive->append(ConstrainedValue(arg3, ValueRep::SomeRegister));
+        keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<double>()) {
+            for (auto& right : floatingPointOperands<double>()) {
+                double expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, -66.5), expected));
+            }
+        }
+    }
+    { // The left argument is the same as the "elseCase" argument.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2);
+
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, Select, Origin(),
+                root->appendNew<Value>(
+                    proc, opcode, Origin(),
+                    arg0,
+                    arg1),
+                arg2,
+                arg0));
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<double>()) {
+            for (auto& right : floatingPointOperands<double>()) {
+                double expected = operation(left.value, right.value) ? 42.5 : left.value;
+                CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, left.value), expected));
+            }
+        }
+    }
+    { // The left argument is the same as the "elseCase" argument. "thenCase" is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0);
+        Value* arg1 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR1);
+        Value* arg2 = root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR2);
+
+        Value* result = root->appendNew<Value>(proc, Select, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg0);
+
+        PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<double>()) {
+            for (auto& right : floatingPointOperands<double>()) {
+                double expected = operation(left.value, right.value) ? 42.5 : left.value;
+                CHECK(isIdentical(invoke<double>(*code, left.value, right.value, 42.5, left.value), expected));
+            }
+        }
+    }
+}
+
+void testSelectDoubleCompareDoubleWithAliasing()
+{
+    testSelectDoubleCompareDouble<Equal>([](double a, double b) -> bool { return a == b; });
+    testSelectDoubleCompareDouble<NotEqual>([](double a, double b) -> bool { return a != b; });
+    testSelectDoubleCompareDouble<LessThan>([](double a, double b) -> bool { return a < b; });
+    testSelectDoubleCompareDouble<GreaterThan>([](double a, double b) -> bool { return a > b; });
+    testSelectDoubleCompareDouble<LessEqual>([](double a, double b) -> bool { return a <= b; });
+    testSelectDoubleCompareDouble<GreaterEqual>([](double a, double b) -> bool { return a >= b; });
+    testSelectDoubleCompareDouble<EqualOrUnordered>([](double a, double b) -> bool { return a != a || b != b || a == b; });
+}
+
+template<B3::Opcode opcode>
+void testSelectFloatCompareFloat(bool (*operation)(float, float))
+{
+    { // Compare arguments and selected arguments are all different.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+
+        Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+        Value* arg3 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)));
+
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, Select, Origin(),
+                root->appendNew<Value>(
+                    proc, opcode, Origin(),
+                    arg0,
+                    arg1),
+                arg2,
+                arg3));
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<float>()) {
+            for (auto& right : floatingPointOperands<float>()) {
+                float expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(-66.5f)), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. "thenCase" is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+        Value* arg3 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)));
+
+        Value* result = root->appendNew<Value>(proc, Select, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<float>()) {
+            for (auto& right : floatingPointOperands<float>()) {
+                float expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(-66.5f)), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. "elseCase" is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+        Value* arg3 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)));
+
+        Value* result = root->appendNew<Value>(proc, Select, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        keepValuesLive->append(ConstrainedValue(arg3, ValueRep::SomeRegister));
+        keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<float>()) {
+            for (auto& right : floatingPointOperands<float>()) {
+                float expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(-66.5f)), expected));
+            }
+        }
+    }
+    { // Compare arguments and selected arguments are all different. Both cases are live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+        Value* arg3 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR3)));
+
+        Value* result = root->appendNew<Value>(proc, Select, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg3);
+
+        PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive->append(ConstrainedValue(arg3, ValueRep::SomeRegister));
+        keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<float>()) {
+            for (auto& right : floatingPointOperands<float>()) {
+                float expected = operation(left.value, right.value) ? 42.5 : -66.5;
+                CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(-66.5f)), expected));
+            }
+        }
+    }
+    { // The left argument is the same as the "elseCase" argument.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+
+        root->appendNew<ControlValue>(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, Select, Origin(),
+                root->appendNew<Value>(
+                    proc, opcode, Origin(),
+                    arg0,
+                    arg1),
+                arg2,
+                arg0));
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<float>()) {
+            for (auto& right : floatingPointOperands<float>()) {
+                float expected = operation(left.value, right.value) ? 42.5 : left.value;
+                CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(left.value)), expected));
+            }
+        }
+    }
+    { // The left argument is the same as the "elseCase" argument. "thenCase" is live after operation.
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* arg0 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
+        Value* arg1 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1)));
+        Value* arg2 = root->appendNew<Value>(proc, BitwiseCast, Origin(),
+            root->appendNew<Value>(proc, Trunc, Origin(),
+                root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2)));
+
+        Value* result = root->appendNew<Value>(proc, Select, Origin(),
+            root->appendNew<Value>(proc, opcode, Origin(), arg0, arg1),
+            arg2,
+            arg0);
+
+        PatchpointValue* keepValuesLive = root->appendNew<PatchpointValue>(proc, Void, Origin());
+        keepValuesLive->append(ConstrainedValue(arg2, ValueRep::SomeRegister));
+        keepValuesLive->setGenerator([&] (CCallHelpers&, const StackmapGenerationParams&) { });
+
+        root->appendNew<ControlValue>(proc, Return, Origin(), result);
+        auto code = compile(proc);
+
+        for (auto& left : floatingPointOperands<float>()) {
+            for (auto& right : floatingPointOperands<float>()) {
+                float expected = operation(left.value, right.value) ? 42.5 : left.value;
+                CHECK(isIdentical(invoke<float>(*code, bitwise_cast<int32_t>(left.value), bitwise_cast<int32_t>(right.value), bitwise_cast<int32_t>(42.5f), bitwise_cast<int32_t>(left.value)), expected));
+            }
+        }
+    }
+}
+
+void testSelectFloatCompareFloatWithAliasing()
+{
+    testSelectFloatCompareFloat<Equal>([](float a, float b) -> bool { return a == b; });
+    testSelectFloatCompareFloat<NotEqual>([](float a, float b) -> bool { return a != b; });
+    testSelectFloatCompareFloat<LessThan>([](float a, float b) -> bool { return a < b; });
+    testSelectFloatCompareFloat<GreaterThan>([](float a, float b) -> bool { return a > b; });
+    testSelectFloatCompareFloat<LessEqual>([](float a, float b) -> bool { return a <= b; });
+    testSelectFloatCompareFloat<GreaterEqual>([](float a, float b) -> bool { return a >= b; });
+    testSelectFloatCompareFloat<EqualOrUnordered>([](float a, float b) -> bool { return a != a || b != b || a == b; });
+}
+
 void testSelectFold(intptr_t value)
 {
     Procedure proc;
@@ -10701,78 +11175,8 @@
     return -zero();
 }
 
-template<typename Type>
-struct Operand {
-    const char* name;
-    Type value;
-};
 
-typedef Operand<int64_t> Int64Operand;
-typedef Operand<int32_t> Int32Operand;
 
-template<typename FloatType>
-void populateWithInterestingValues(Vector<Operand<FloatType>>& operands)
-{
-    operands.append({ "0.", static_cast<FloatType>(0.) });
-    operands.append({ "-0.", static_cast<FloatType>(-0.) });
-    operands.append({ "0.4", static_cast<FloatType>(0.5) });
-    operands.append({ "-0.4", static_cast<FloatType>(-0.5) });
-    operands.append({ "0.5", static_cast<FloatType>(0.5) });
-    operands.append({ "-0.5", static_cast<FloatType>(-0.5) });
-    operands.append({ "0.6", static_cast<FloatType>(0.5) });
-    operands.append({ "-0.6", static_cast<FloatType>(-0.5) });
-    operands.append({ "1.", static_cast<FloatType>(1.) });
-    operands.append({ "-1.", static_cast<FloatType>(-1.) });
-    operands.append({ "2.", static_cast<FloatType>(2.) });
-    operands.append({ "-2.", static_cast<FloatType>(-2.) });
-    operands.append({ "M_PI", static_cast<FloatType>(M_PI) });
-    operands.append({ "-M_PI", static_cast<FloatType>(-M_PI) });
-    operands.append({ "min", std::numeric_limits<FloatType>::min() });
-    operands.append({ "max", std::numeric_limits<FloatType>::max() });
-    operands.append({ "lowest", std::numeric_limits<FloatType>::lowest() });
-    operands.append({ "epsilon", std::numeric_limits<FloatType>::epsilon() });
-    operands.append({ "infiniti", std::numeric_limits<FloatType>::infinity() });
-    operands.append({ "-infiniti", - std::numeric_limits<FloatType>::infinity() });
-    operands.append({ "PNaN", static_cast<FloatType>(PNaN) });
-}
-
-template<typename FloatType>
-Vector<Operand<FloatType>> floatingPointOperands()
-{
-    Vector<Operand<FloatType>> operands;
-    populateWithInterestingValues(operands);
-    return operands;
-};
-
-static Vector<Int64Operand> int64Operands()
-{
-    Vector<Int64Operand> operands;
-    for (const auto& doubleOperand : floatingPointOperands<double>())
-        operands.append({ doubleOperand.name, bitwise_cast<int64_t>(doubleOperand.value) });
-    operands.append({ "1", 1 });
-    operands.append({ "-1", -1 });
-    operands.append({ "int64-max", std::numeric_limits<int64_t>::max() });
-    operands.append({ "int64-min", std::numeric_limits<int64_t>::min() });
-    operands.append({ "int32-max", std::numeric_limits<int32_t>::max() });
-    operands.append({ "int32-min", std::numeric_limits<int32_t>::min() });
-
-    return operands;
-}
-
-static Vector<Int32Operand> int32Operands()
-{
-    Vector<Int32Operand> operands({
-        { "0", 0 },
-        { "1", 1 },
-        { "-1", -1 },
-        { "42", 42 },
-        { "-42", -42 },
-        { "int32-max", std::numeric_limits<int32_t>::max() },
-        { "int32-min", std::numeric_limits<int32_t>::min() }
-    });
-    return operands;
-}
-
 #define RUN(test) do {                          \
         if (!shouldRun(#test))                  \
             break;                              \
@@ -11978,6 +12382,8 @@
     RUN(testSelectDoubleCompareDouble());
     RUN_BINARY(testSelectDoubleCompareFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
     RUN_BINARY(testSelectFloatCompareFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
+    RUN(testSelectDoubleCompareDoubleWithAliasing());
+    RUN(testSelectFloatCompareFloatWithAliasing());
     RUN(testSelectFold(42));
     RUN(testSelectFold(43));
     RUN(testSelectInvert());
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to