Title: [258038] trunk/Source/_javascript_Core
Revision
258038
Author
mark....@apple.com
Date
2020-03-06 17:16:14 -0800 (Fri, 06 Mar 2020)

Log Message

Fix some issues in the ARM64 moveConditionallyAfterFloatingPointCompare() and moveDoubleConditionallyAfterFloatingPointCompare().
https://bugs.webkit.org/show_bug.cgi?id=208731
<rdar://problem/59222568>

Reviewed by Saam Barati.

Both the ARM64 moveConditionallyAfterFloatingPointCompare() and
moveDoubleConditionallyAfterFloatingPointCompare() had the following issues:

1. For the DoubleNotEqual condition, they fail to set the result register if
   one or both of the comparison operands is a NaN.

2. For the DoubleEqualOrUnordered condition, they can clobber the else case
   input register if one of the comparison operands is a NaN.

This patch fixes both of these, and exhaustive testmasm test cases for affected
MacroAssembler instruction emitters using these functions.

* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::moveConditionallyAfterFloatingPointCompare):
(JSC::MacroAssemblerARM64::moveDoubleConditionallyAfterFloatingPointCompare):
* assembler/testmasm.cpp:
(JSC::testCompareDouble):
(JSC::testCompareDoubleSameArg):
(JSC::testMoveConditionallyFloatingPoint):
(JSC::testMoveConditionallyDouble2):
(JSC::testMoveConditionallyDouble3):
(JSC::testMoveConditionallyDouble3DestSameAsThenCase):
(JSC::testMoveConditionallyDouble3DestSameAsElseCase):
(JSC::testMoveConditionallyFloat2):
(JSC::testMoveConditionallyFloat3):
(JSC::testMoveConditionallyFloat3DestSameAsThenCase):
(JSC::testMoveConditionallyFloat3DestSameAsElseCase):
(JSC::testMoveDoubleConditionallyDouble):
(JSC::testMoveDoubleConditionallyDoubleDestSameAsThenCase):
(JSC::testMoveDoubleConditionallyDoubleDestSameAsElseCase):
(JSC::testMoveDoubleConditionallyFloat):
(JSC::testMoveDoubleConditionallyFloatDestSameAsThenCase):
(JSC::testMoveDoubleConditionallyFloatDestSameAsElseCase):
(JSC::testMoveConditionallyFloatingPointSameArg):
(JSC::testMoveConditionallyDouble2SameArg):
(JSC::testMoveConditionallyDouble3SameArg):
(JSC::testMoveConditionallyFloat2SameArg):
(JSC::testMoveConditionallyFloat3SameArg):
(JSC::testMoveDoubleConditionallyDoubleSameArg):
(JSC::testMoveDoubleConditionallyFloatSameArg):
(JSC::run):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (258037 => 258038)


--- trunk/Source/_javascript_Core/ChangeLog	2020-03-07 01:14:23 UTC (rev 258037)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-03-07 01:16:14 UTC (rev 258038)
@@ -1,3 +1,53 @@
+2020-03-06  Mark Lam  <mark....@apple.com>
+
+        Fix some issues in the ARM64 moveConditionallyAfterFloatingPointCompare() and moveDoubleConditionallyAfterFloatingPointCompare().
+        https://bugs.webkit.org/show_bug.cgi?id=208731
+        <rdar://problem/59222568>
+
+        Reviewed by Saam Barati.
+
+        Both the ARM64 moveConditionallyAfterFloatingPointCompare() and
+        moveDoubleConditionallyAfterFloatingPointCompare() had the following issues:
+
+        1. For the DoubleNotEqual condition, they fail to set the result register if
+           one or both of the comparison operands is a NaN.
+
+        2. For the DoubleEqualOrUnordered condition, they can clobber the else case
+           input register if one of the comparison operands is a NaN.
+
+        This patch fixes both of these, and exhaustive testmasm test cases for affected
+        MacroAssembler instruction emitters using these functions.
+
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::moveConditionallyAfterFloatingPointCompare):
+        (JSC::MacroAssemblerARM64::moveDoubleConditionallyAfterFloatingPointCompare):
+        * assembler/testmasm.cpp:
+        (JSC::testCompareDouble):
+        (JSC::testCompareDoubleSameArg):
+        (JSC::testMoveConditionallyFloatingPoint):
+        (JSC::testMoveConditionallyDouble2):
+        (JSC::testMoveConditionallyDouble3):
+        (JSC::testMoveConditionallyDouble3DestSameAsThenCase):
+        (JSC::testMoveConditionallyDouble3DestSameAsElseCase):
+        (JSC::testMoveConditionallyFloat2):
+        (JSC::testMoveConditionallyFloat3):
+        (JSC::testMoveConditionallyFloat3DestSameAsThenCase):
+        (JSC::testMoveConditionallyFloat3DestSameAsElseCase):
+        (JSC::testMoveDoubleConditionallyDouble):
+        (JSC::testMoveDoubleConditionallyDoubleDestSameAsThenCase):
+        (JSC::testMoveDoubleConditionallyDoubleDestSameAsElseCase):
+        (JSC::testMoveDoubleConditionallyFloat):
+        (JSC::testMoveDoubleConditionallyFloatDestSameAsThenCase):
+        (JSC::testMoveDoubleConditionallyFloatDestSameAsElseCase):
+        (JSC::testMoveConditionallyFloatingPointSameArg):
+        (JSC::testMoveConditionallyDouble2SameArg):
+        (JSC::testMoveConditionallyDouble3SameArg):
+        (JSC::testMoveConditionallyFloat2SameArg):
+        (JSC::testMoveConditionallyFloat3SameArg):
+        (JSC::testMoveDoubleConditionallyDoubleSameArg):
+        (JSC::testMoveDoubleConditionallyFloatSameArg):
+        (JSC::run):
+
 2020-03-05  Paulo Matos  <pma...@igalia.com>
 
         [JSCOnly] 32-bits warning on memset of JSValue

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (258037 => 258038)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2020-03-07 01:14:23 UTC (rev 258037)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2020-03-07 01:16:14 UTC (rev 258038)
@@ -2028,18 +2028,35 @@
     void moveConditionallyAfterFloatingPointCompare(DoubleCondition cond, RegisterID thenCase, RegisterID elseCase, RegisterID dest)
     {
         if (cond == DoubleNotEqual) {
-            Jump unordered = makeBranch(Assembler::ConditionVS);
-            m_assembler.csel<datasize>(dest, thenCase, elseCase, Assembler::ConditionNE);
-            unordered.link(this);
+            if (dest == thenCase) {
+                // If the compare is unordered, elseCase is copied to thenCase and the
+                // next csel has all arguments equal to elseCase.
+                // If the compare is ordered, dest is unchanged and NE decides
+                // what value to set.
+                m_assembler.csel<datasize>(thenCase, elseCase, thenCase, Assembler::ConditionNE);
+                m_assembler.csel<datasize>(dest, thenCase, elseCase, Assembler::ConditionNE);
+            } else {
+                move(elseCase, dest);
+                Jump unordered = makeBranch(Assembler::ConditionVS);
+                m_assembler.csel<datasize>(dest, thenCase, elseCase, Assembler::ConditionNE);
+                unordered.link(this);
+            }
             return;
         }
         if (cond == DoubleEqualOrUnordered) {
-            // If the compare is unordered, thenCase is copied to elseCase 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.csel<datasize>(elseCase, thenCase, elseCase, Assembler::ConditionVS);
-            m_assembler.csel<datasize>(dest, thenCase, elseCase, Assembler::ConditionEQ);
+            if (dest == elseCase) {
+                // If the compare is unordered, thenCase is copied to elseCase 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.csel<datasize>(elseCase, thenCase, elseCase, Assembler::ConditionVS);
+                m_assembler.csel<datasize>(dest, thenCase, elseCase, Assembler::ConditionEQ);
+            } else {
+                move(thenCase, dest);
+                Jump unordered = makeBranch(Assembler::ConditionVS);
+                m_assembler.csel<datasize>(dest, thenCase, elseCase, Assembler::ConditionEQ);
+                unordered.link(this);
+            }
             return;
         }
         m_assembler.csel<datasize>(dest, thenCase, elseCase, ARM64Condition(cond));
@@ -2049,18 +2066,35 @@
     void moveDoubleConditionallyAfterFloatingPointCompare(DoubleCondition cond, FPRegisterID thenCase, FPRegisterID elseCase, FPRegisterID dest)
     {
         if (cond == DoubleNotEqual) {
-            Jump unordered = makeBranch(Assembler::ConditionVS);
-            m_assembler.fcsel<datasize>(dest, thenCase, elseCase, Assembler::ConditionNE);
-            unordered.link(this);
+            if (dest == thenCase) {
+                // If the compare is unordered, elseCase is copied to thenCase and the
+                // next fcsel has all arguments equal to elseCase.
+                // If the compare is ordered, dest is unchanged and NE decides
+                // what value to set.
+                m_assembler.fcsel<datasize>(thenCase, elseCase, thenCase, Assembler::ConditionVS);
+                m_assembler.fcsel<datasize>(dest, thenCase, elseCase, Assembler::ConditionNE);
+            } else {
+                m_assembler.fmov<64>(dest, elseCase);
+                Jump unordered = makeBranch(Assembler::ConditionVS);
+                m_assembler.fcsel<datasize>(dest, thenCase, elseCase, Assembler::ConditionNE);
+                unordered.link(this);
+            }
             return;
         }
         if (cond == DoubleEqualOrUnordered) {
-            // If the compare is unordered, thenCase is copied to elseCase 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>(elseCase, thenCase, elseCase, Assembler::ConditionVS);
-            m_assembler.fcsel<datasize>(dest, thenCase, elseCase, Assembler::ConditionEQ);
+            if (dest == elseCase) {
+                // If the compare is unordered, thenCase is copied to elseCase 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>(elseCase, thenCase, elseCase, Assembler::ConditionVS);
+                m_assembler.fcsel<datasize>(dest, thenCase, elseCase, Assembler::ConditionEQ);
+            } else {
+                m_assembler.fmov<64>(dest, thenCase);
+                Jump unordered = makeBranch(Assembler::ConditionVS);
+                m_assembler.fcsel<datasize>(dest, thenCase, elseCase, Assembler::ConditionEQ);
+                unordered.link(this);
+            }
             return;
         }
         m_assembler.fcsel<datasize>(dest, thenCase, elseCase, ARM64Condition(cond));

Modified: trunk/Source/_javascript_Core/assembler/testmasm.cpp (258037 => 258038)


--- trunk/Source/_javascript_Core/assembler/testmasm.cpp	2020-03-07 01:14:23 UTC (rev 258037)
+++ trunk/Source/_javascript_Core/assembler/testmasm.cpp	2020-03-07 01:16:14 UTC (rev 258038)
@@ -499,16 +499,117 @@
         jit.ret();
     });
 
+    auto expectedResult = [&, condition] (double a, double b) -> int {
+        auto isUnordered = [] (double x) {
+            return x != x;
+        };
+        switch (condition) {
+        case MacroAssembler::DoubleEqual:
+            return !isUnordered(a) && !isUnordered(b) && (a == b);
+        case MacroAssembler::DoubleNotEqual:
+            return !isUnordered(a) && !isUnordered(b) && (a != b);
+        case MacroAssembler::DoubleGreaterThan:
+            return !isUnordered(a) && !isUnordered(b) && (a > b);
+        case MacroAssembler::DoubleGreaterThanOrEqual:
+            return !isUnordered(a) && !isUnordered(b) && (a >= b);
+        case MacroAssembler::DoubleLessThan:
+            return !isUnordered(a) && !isUnordered(b) && (a < b);
+        case MacroAssembler::DoubleLessThanOrEqual:
+            return !isUnordered(a) && !isUnordered(b) && (a <= b);
+        case MacroAssembler::DoubleEqualOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a == b);
+        case MacroAssembler::DoubleNotEqualOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a != b);
+        case MacroAssembler::DoubleGreaterThanOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a > b);
+        case MacroAssembler::DoubleGreaterThanOrEqualOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a >= b);
+        case MacroAssembler::DoubleLessThanOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a < b);
+        case MacroAssembler::DoubleLessThanOrEqualOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a <= b);
+        } // switch
+    };
+
     auto operands = doubleOperands();
     for (auto a : operands) {
         for (auto b : operands) {
             arg1 = a;
             arg2 = b;
-            CHECK_EQ(invoke<int>(compareDouble), invoke<int>(compareDoubleGeneric));
+            CHECK_EQ(invoke<int>(compareDouble), expectedResult(a, b));
+            CHECK_EQ(invoke<int>(compareDoubleGeneric), expectedResult(a, b));
         }
     }
 }
 
+void testCompareDoubleSameArg(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+
+    auto compareDouble = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.move(CCallHelpers::TrustedImm32(-1), GPRInfo::returnValueGPR);
+        jit.compareDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT0, GPRInfo::returnValueGPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    auto compareDoubleGeneric = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.move(CCallHelpers::TrustedImm32(1), GPRInfo::returnValueGPR);
+        auto jump = jit.branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT0);
+        jit.move(CCallHelpers::TrustedImm32(0), GPRInfo::returnValueGPR);
+        jump.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    auto expectedResult = [&, condition] (double a) -> int {
+        auto isUnordered = [] (double x) {
+            return x != x;
+        };
+        switch (condition) {
+        case MacroAssembler::DoubleEqual:
+            return !isUnordered(a) && (a == a);
+        case MacroAssembler::DoubleNotEqual:
+            return !isUnordered(a) && (a != a);
+        case MacroAssembler::DoubleGreaterThan:
+            return !isUnordered(a) && (a > a);
+        case MacroAssembler::DoubleGreaterThanOrEqual:
+            return !isUnordered(a) && (a >= a);
+        case MacroAssembler::DoubleLessThan:
+            return !isUnordered(a) && (a < a);
+        case MacroAssembler::DoubleLessThanOrEqual:
+            return !isUnordered(a) && (a <= a);
+        case MacroAssembler::DoubleEqualOrUnordered:
+            return isUnordered(a) || (a == a);
+        case MacroAssembler::DoubleNotEqualOrUnordered:
+            return isUnordered(a) || (a != a);
+        case MacroAssembler::DoubleGreaterThanOrUnordered:
+            return isUnordered(a) || (a > a);
+        case MacroAssembler::DoubleGreaterThanOrEqualOrUnordered:
+            return isUnordered(a) || (a >= a);
+        case MacroAssembler::DoubleLessThanOrUnordered:
+            return isUnordered(a) || (a < a);
+        case MacroAssembler::DoubleLessThanOrEqualOrUnordered:
+            return isUnordered(a) || (a <= a);
+        } // switch
+    };
+
+    auto operands = doubleOperands();
+    for (auto a : operands) {
+        arg1 = a;
+        CHECK_EQ(invoke<int>(compareDouble), expectedResult(a));
+        CHECK_EQ(invoke<int>(compareDoubleGeneric), expectedResult(a));
+    }
+}
+
 void testMul32WithImmediates()
 {
     for (auto immediate : int32Operands()) {
@@ -586,8 +687,769 @@
         }
     }
 }
-#endif
+#endif // CPU(X86) || CPU(X86_64) || CPU(ARM64)
 
+#if CPU(X86_64) || CPU(ARM64)
+
+template<typename T, typename SelectionType>
+void testMoveConditionallyFloatingPoint(MacroAssembler::DoubleCondition condition, const MacroAssemblerCodeRef<JSEntryPtrTag>& testCode, T& arg1, T& arg2, const Vector<T> operands, SelectionType selectionA, SelectionType selectionB)
+{
+    auto expectedResult = [&, condition] (T a, T b) -> SelectionType {
+        auto isUnordered = [] (double x) {
+            return x != x;
+        };
+        switch (condition) {
+        case MacroAssembler::DoubleEqual:
+            return !isUnordered(a) && !isUnordered(b) && (a == b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleNotEqual:
+            return !isUnordered(a) && !isUnordered(b) && (a != b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleGreaterThan:
+            return !isUnordered(a) && !isUnordered(b) && (a > b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleGreaterThanOrEqual:
+            return !isUnordered(a) && !isUnordered(b) && (a >= b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleLessThan:
+            return !isUnordered(a) && !isUnordered(b) && (a < b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleLessThanOrEqual:
+            return !isUnordered(a) && !isUnordered(b) && (a <= b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleEqualOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a == b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleNotEqualOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a != b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleGreaterThanOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a > b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleGreaterThanOrEqualOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a >= b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleLessThanOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a < b) ? selectionA : selectionB;
+        case MacroAssembler::DoubleLessThanOrEqualOrUnordered:
+            return isUnordered(a) || isUnordered(b) || (a <= b) ? selectionA : selectionB;
+        } // switch
+    };
+
+    for (auto a : operands) {
+        for (auto b : operands) {
+            arg1 = a;
+            arg2 = b;
+            CHECK_EQ(invoke<SelectionType>(testCode), expectedResult(a, b));
+        }
+    }
+}
+
+void testMoveConditionallyDouble2(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double arg2 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg destGPR = GPRInfo::returnValueGPR;
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        RELEASE_ASSERT(destGPR != selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), destGPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.moveConditionallyDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, selectionAGPR, destGPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyDouble3(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double arg2 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+    unsigned corruptedSelectionA = 0xbbad000a;
+    unsigned corruptedSelectionB = 0xbbad000b;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg destGPR = GPRInfo::returnValueGPR;
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        GPRReg selectionBGPR = GPRInfo::argumentGPR3;
+        RELEASE_ASSERT(destGPR != selectionAGPR);
+        RELEASE_ASSERT(destGPR != selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(-1), destGPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.moveConditionallyDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, selectionAGPR, selectionBGPR, destGPR);
+
+        auto aIsUnchanged = jit.branch32(CCallHelpers::Equal, selectionAGPR, CCallHelpers::TrustedImm32(selectionA));
+        jit.move(CCallHelpers::TrustedImm32(corruptedSelectionA), destGPR);
+        aIsUnchanged.link(&jit);
+
+        auto bIsUnchanged = jit.branch32(CCallHelpers::Equal, selectionBGPR, CCallHelpers::TrustedImm32(selectionB));
+        jit.move(CCallHelpers::TrustedImm32(corruptedSelectionB), destGPR);
+        bIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyDouble3DestSameAsThenCase(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double arg2 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+    unsigned corruptedSelectionB = 0xbbad000b;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg destGPR = GPRInfo::returnValueGPR;
+        GPRReg selectionAGPR = destGPR;
+        GPRReg selectionBGPR = GPRInfo::argumentGPR3;
+        RELEASE_ASSERT(destGPR == selectionAGPR);
+        RELEASE_ASSERT(destGPR != selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), selectionBGPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.moveConditionallyDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, selectionAGPR, selectionBGPR, destGPR);
+
+        auto bIsUnchanged = jit.branch32(CCallHelpers::Equal, selectionBGPR, CCallHelpers::TrustedImm32(selectionB));
+        jit.move(CCallHelpers::TrustedImm32(corruptedSelectionB), destGPR);
+        bIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyDouble3DestSameAsElseCase(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double arg2 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+    unsigned corruptedSelectionA = 0xbbad000a;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg destGPR = GPRInfo::returnValueGPR;
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        GPRReg selectionBGPR = destGPR;
+        RELEASE_ASSERT(destGPR != selectionAGPR);
+        RELEASE_ASSERT(destGPR == selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), selectionBGPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.moveConditionallyDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, selectionAGPR, selectionBGPR, destGPR);
+
+        auto aIsUnchanged = jit.branch32(CCallHelpers::Equal, selectionAGPR, CCallHelpers::TrustedImm32(selectionA));
+        jit.move(CCallHelpers::TrustedImm32(corruptedSelectionA), destGPR);
+        aIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyFloat2(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    float arg2 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg destGPR = GPRInfo::returnValueGPR;
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        RELEASE_ASSERT(destGPR != selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), GPRInfo::returnValueGPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.moveConditionallyFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, selectionAGPR, destGPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, floatOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyFloat3(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    float arg2 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+    unsigned corruptedSelectionA = 0xbbad000a;
+    unsigned corruptedSelectionB = 0xbbad000b;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg destGPR = GPRInfo::returnValueGPR;
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        GPRReg selectionBGPR = GPRInfo::argumentGPR3;
+        RELEASE_ASSERT(destGPR != selectionAGPR);
+        RELEASE_ASSERT(destGPR != selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(-1), destGPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.moveConditionallyFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, selectionAGPR, selectionBGPR, destGPR);
+
+        auto aIsUnchanged = jit.branch32(CCallHelpers::Equal, selectionAGPR, CCallHelpers::TrustedImm32(selectionA));
+        jit.move(CCallHelpers::TrustedImm32(corruptedSelectionA), destGPR);
+        aIsUnchanged.link(&jit);
+
+        auto bIsUnchanged = jit.branch32(CCallHelpers::Equal, selectionBGPR, CCallHelpers::TrustedImm32(selectionB));
+        jit.move(CCallHelpers::TrustedImm32(corruptedSelectionB), destGPR);
+        bIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, floatOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyFloat3DestSameAsThenCase(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    float arg2 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+    unsigned corruptedSelectionB = 0xbbad000b;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg destGPR = GPRInfo::returnValueGPR;
+        GPRReg selectionAGPR = destGPR;
+        GPRReg selectionBGPR = GPRInfo::argumentGPR3;
+        RELEASE_ASSERT(destGPR == selectionAGPR);
+        RELEASE_ASSERT(destGPR != selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), selectionBGPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.moveConditionallyFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, selectionAGPR, selectionBGPR, destGPR);
+
+        auto bIsUnchanged = jit.branch32(CCallHelpers::Equal, selectionBGPR, CCallHelpers::TrustedImm32(selectionB));
+        jit.move(CCallHelpers::TrustedImm32(corruptedSelectionB), destGPR);
+        bIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, floatOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyFloat3DestSameAsElseCase(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    float arg2 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+    unsigned corruptedSelectionA = 0xbbad000a;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg destGPR = GPRInfo::returnValueGPR;
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        GPRReg selectionBGPR = destGPR;
+        RELEASE_ASSERT(destGPR != selectionAGPR);
+        RELEASE_ASSERT(destGPR == selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), selectionBGPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), FPRInfo::fpRegT1);
+        jit.moveConditionallyFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1, selectionAGPR, selectionBGPR, destGPR);
+
+        auto aIsUnchanged = jit.branch32(CCallHelpers::Equal, selectionAGPR, CCallHelpers::TrustedImm32(selectionA));
+        jit.move(CCallHelpers::TrustedImm32(corruptedSelectionA), destGPR);
+        aIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, floatOperands(), selectionA, selectionB);
+}
+
+void testMoveDoubleConditionallyDouble(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double arg2 = 0;
+    double selectionA = 42.0;
+    double selectionB = 17.0;
+    double corruptedSelectionA = 55555;
+    double corruptedSelectionB = 66666;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        FPRReg destFPR = FPRInfo::returnValueFPR;
+        FPRReg selectionAFPR = FPRInfo::fpRegT1;
+        FPRReg selectionBFPR = FPRInfo::fpRegT2;
+        FPRReg arg1FPR = FPRInfo::fpRegT3;
+        FPRReg arg2FPR = FPRInfo::fpRegT4;
+
+        RELEASE_ASSERT(destFPR != selectionAFPR);
+        RELEASE_ASSERT(destFPR != selectionBFPR);
+        RELEASE_ASSERT(destFPR != arg1FPR);
+        RELEASE_ASSERT(destFPR != arg2FPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), arg1FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), arg2FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), selectionAFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), selectionBFPR);
+        jit.moveDoubleConditionallyDouble(condition, arg1FPR, arg2FPR, selectionAFPR, selectionBFPR, destFPR);
+
+        FPRReg tempFPR = FPRInfo::fpRegT5;
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), tempFPR);
+        auto aIsUnchanged = jit.branchDouble(CCallHelpers::DoubleEqual, selectionAFPR, tempFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&corruptedSelectionA), destFPR);
+        aIsUnchanged.link(&jit);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), tempFPR);
+        auto bIsUnchanged = jit.branchDouble(CCallHelpers::DoubleEqual, selectionBFPR, tempFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&corruptedSelectionB), destFPR);
+        bIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveDoubleConditionallyDoubleDestSameAsThenCase(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double arg2 = 0;
+    double selectionA = 42.0;
+    double selectionB = 17.0;
+    double corruptedSelectionB = 66666;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        FPRReg destFPR = FPRInfo::returnValueFPR;
+        FPRReg selectionAFPR = destFPR;
+        FPRReg selectionBFPR = FPRInfo::fpRegT2;
+        FPRReg arg1FPR = FPRInfo::fpRegT3;
+        FPRReg arg2FPR = FPRInfo::fpRegT4;
+
+        RELEASE_ASSERT(destFPR == selectionAFPR);
+        RELEASE_ASSERT(destFPR != selectionBFPR);
+        RELEASE_ASSERT(destFPR != arg1FPR);
+        RELEASE_ASSERT(destFPR != arg2FPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), arg1FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), arg2FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), selectionAFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), selectionBFPR);
+        jit.moveDoubleConditionallyDouble(condition, arg1FPR, arg2FPR, selectionAFPR, selectionBFPR, destFPR);
+
+        FPRReg tempFPR = FPRInfo::fpRegT5;
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), tempFPR);
+        auto bIsUnchanged = jit.branchDouble(CCallHelpers::DoubleEqual, selectionBFPR, tempFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&corruptedSelectionB), destFPR);
+        bIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveDoubleConditionallyDoubleDestSameAsElseCase(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double arg2 = 0;
+    double selectionA = 42.0;
+    double selectionB = 17.0;
+    double corruptedSelectionA = 55555;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        FPRReg destFPR = FPRInfo::returnValueFPR;
+        FPRReg selectionAFPR = FPRInfo::fpRegT1;
+        FPRReg selectionBFPR = destFPR;
+        FPRReg arg1FPR = FPRInfo::fpRegT3;
+        FPRReg arg2FPR = FPRInfo::fpRegT4;
+
+        RELEASE_ASSERT(destFPR != selectionAFPR);
+        RELEASE_ASSERT(destFPR == selectionBFPR);
+        RELEASE_ASSERT(destFPR != arg1FPR);
+        RELEASE_ASSERT(destFPR != arg2FPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), arg1FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg2), arg2FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), selectionAFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), selectionBFPR);
+        jit.moveDoubleConditionallyDouble(condition, arg1FPR, arg2FPR, selectionAFPR, selectionBFPR, destFPR);
+
+        FPRReg tempFPR = FPRInfo::fpRegT5;
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), tempFPR);
+        auto aIsUnchanged = jit.branchDouble(CCallHelpers::DoubleEqual, selectionAFPR, tempFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&corruptedSelectionA), destFPR);
+        aIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveDoubleConditionallyFloat(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    float arg2 = 0;
+    double selectionA = 42.0;
+    double selectionB = 17.0;
+    double corruptedSelectionA = 55555;
+    double corruptedSelectionB = 66666;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        FPRReg destFPR = FPRInfo::returnValueFPR;
+        FPRReg selectionAFPR = FPRInfo::fpRegT1;
+        FPRReg selectionBFPR = FPRInfo::fpRegT2;
+        FPRReg arg1FPR = FPRInfo::fpRegT3;
+        FPRReg arg2FPR = FPRInfo::fpRegT4;
+
+        RELEASE_ASSERT(destFPR != selectionAFPR);
+        RELEASE_ASSERT(destFPR != selectionBFPR);
+        RELEASE_ASSERT(destFPR != arg1FPR);
+        RELEASE_ASSERT(destFPR != arg2FPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), arg1FPR);
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), arg2FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), selectionAFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), selectionBFPR);
+        jit.moveDoubleConditionallyFloat(condition, arg1FPR, arg2FPR, selectionAFPR, selectionBFPR, destFPR);
+
+        FPRReg tempFPR = FPRInfo::fpRegT5;
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), tempFPR);
+        auto aIsUnchanged = jit.branchDouble(CCallHelpers::DoubleEqual, selectionAFPR, tempFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&corruptedSelectionA), destFPR);
+        aIsUnchanged.link(&jit);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), tempFPR);
+        auto bIsUnchanged = jit.branchDouble(CCallHelpers::DoubleEqual, selectionBFPR, tempFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&corruptedSelectionB), destFPR);
+        bIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, floatOperands(), selectionA, selectionB);
+}
+
+void testMoveDoubleConditionallyFloatDestSameAsThenCase(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    float arg2 = 0;
+    double selectionA = 42.0;
+    double selectionB = 17.0;
+    double corruptedSelectionB = 66666;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        FPRReg destFPR = FPRInfo::returnValueFPR;
+        FPRReg selectionAFPR = destFPR;
+        FPRReg selectionBFPR = FPRInfo::fpRegT2;
+        FPRReg arg1FPR = FPRInfo::fpRegT3;
+        FPRReg arg2FPR = FPRInfo::fpRegT4;
+
+        RELEASE_ASSERT(destFPR == selectionAFPR);
+        RELEASE_ASSERT(destFPR != selectionBFPR);
+        RELEASE_ASSERT(destFPR != arg1FPR);
+        RELEASE_ASSERT(destFPR != arg2FPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), arg1FPR);
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), arg2FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), selectionAFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), selectionBFPR);
+        jit.moveDoubleConditionallyFloat(condition, arg1FPR, arg2FPR, selectionAFPR, selectionBFPR, destFPR);
+
+        FPRReg tempFPR = FPRInfo::fpRegT5;
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), tempFPR);
+        auto bIsUnchanged = jit.branchDouble(CCallHelpers::DoubleEqual, selectionBFPR, tempFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&corruptedSelectionB), destFPR);
+        bIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, floatOperands(), selectionA, selectionB);
+}
+
+void testMoveDoubleConditionallyFloatDestSameAsElseCase(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    float arg2 = 0;
+    double selectionA = 42.0;
+    double selectionB = 17.0;
+    double corruptedSelectionA = 55555;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        FPRReg destFPR = FPRInfo::returnValueFPR;
+        FPRReg selectionAFPR = FPRInfo::fpRegT1;
+        FPRReg selectionBFPR = destFPR;
+        FPRReg arg1FPR = FPRInfo::fpRegT3;
+        FPRReg arg2FPR = FPRInfo::fpRegT4;
+
+        RELEASE_ASSERT(destFPR != selectionAFPR);
+        RELEASE_ASSERT(destFPR == selectionBFPR);
+        RELEASE_ASSERT(destFPR != arg1FPR);
+        RELEASE_ASSERT(destFPR != arg2FPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), arg1FPR);
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg2), arg2FPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), selectionAFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), selectionBFPR);
+        jit.moveDoubleConditionallyFloat(condition, arg1FPR, arg2FPR, selectionAFPR, selectionBFPR, destFPR);
+
+        FPRReg tempFPR = FPRInfo::fpRegT5;
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), tempFPR);
+        auto aIsUnchanged = jit.branchDouble(CCallHelpers::DoubleEqual, selectionAFPR, tempFPR);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&corruptedSelectionA), destFPR);
+        aIsUnchanged.link(&jit);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPoint(condition, testCode, arg1, arg2, floatOperands(), selectionA, selectionB);
+}
+
+template<typename T, typename SelectionType>
+void testMoveConditionallyFloatingPointSameArg(MacroAssembler::DoubleCondition condition, const MacroAssemblerCodeRef<JSEntryPtrTag>& testCode, T& arg1, const Vector<T> operands, SelectionType selectionA, SelectionType selectionB)
+{
+    auto expectedResult = [&, condition] (T a) -> SelectionType {
+        auto isUnordered = [] (double x) {
+            return x != x;
+        };
+        switch (condition) {
+        case MacroAssembler::DoubleEqual:
+            return !isUnordered(a) && (a == a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleNotEqual:
+            return !isUnordered(a) && (a != a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleGreaterThan:
+            return !isUnordered(a) && (a > a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleGreaterThanOrEqual:
+            return !isUnordered(a) && (a >= a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleLessThan:
+            return !isUnordered(a) && (a < a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleLessThanOrEqual:
+            return !isUnordered(a) && (a <= a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleEqualOrUnordered:
+            return isUnordered(a) || (a == a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleNotEqualOrUnordered:
+            return isUnordered(a) || (a != a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleGreaterThanOrUnordered:
+            return isUnordered(a) || (a > a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleGreaterThanOrEqualOrUnordered:
+            return isUnordered(a) || (a >= a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleLessThanOrUnordered:
+            return isUnordered(a) || (a < a) ? selectionA : selectionB;
+        case MacroAssembler::DoubleLessThanOrEqualOrUnordered:
+            return isUnordered(a) || (a <= a) ? selectionA : selectionB;
+        } // switch
+    };
+
+    for (auto a : operands) {
+        arg1 = a;
+        CHECK_EQ(invoke<SelectionType>(testCode), expectedResult(a));
+    }
+}
+
+void testMoveConditionallyDouble2SameArg(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        RELEASE_ASSERT(GPRInfo::returnValueGPR != selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), GPRInfo::returnValueGPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.moveConditionallyDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT0, selectionAGPR, GPRInfo::returnValueGPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPointSameArg(condition, testCode, arg1, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyDouble3SameArg(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        GPRReg selectionBGPR = GPRInfo::argumentGPR3;
+        RELEASE_ASSERT(GPRInfo::returnValueGPR != selectionAGPR);
+        RELEASE_ASSERT(GPRInfo::returnValueGPR != selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(-1), GPRInfo::returnValueGPR);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.moveConditionallyDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT0, selectionAGPR, selectionBGPR, GPRInfo::returnValueGPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPointSameArg(condition, testCode, arg1, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyFloat2SameArg(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        RELEASE_ASSERT(GPRInfo::returnValueGPR != selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), GPRInfo::returnValueGPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.moveConditionallyFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT0, selectionAGPR, GPRInfo::returnValueGPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPointSameArg(condition, testCode, arg1, floatOperands(), selectionA, selectionB);
+}
+
+void testMoveConditionallyFloat3SameArg(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    unsigned selectionA = 42;
+    unsigned selectionB = 17;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        GPRReg selectionAGPR = GPRInfo::argumentGPR2;
+        GPRReg selectionBGPR = GPRInfo::argumentGPR3;
+        RELEASE_ASSERT(GPRInfo::returnValueGPR != selectionAGPR);
+        RELEASE_ASSERT(GPRInfo::returnValueGPR != selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionA), selectionAGPR);
+        jit.move(CCallHelpers::TrustedImm32(selectionB), selectionBGPR);
+        jit.move(CCallHelpers::TrustedImm32(-1), GPRInfo::returnValueGPR);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.moveConditionallyFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT0, selectionAGPR, selectionBGPR, GPRInfo::returnValueGPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPointSameArg(condition, testCode, arg1, floatOperands(), selectionA, selectionB);
+}
+
+void testMoveDoubleConditionallyDoubleSameArg(MacroAssembler::DoubleCondition condition)
+{
+    double arg1 = 0;
+    double selectionA = 42.0;
+    double selectionB = 17.0;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), FPRInfo::fpRegT2);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), FPRInfo::fpRegT3);
+        jit.moveDoubleConditionallyDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT0, FPRInfo::fpRegT2, FPRInfo::fpRegT3, FPRInfo::returnValueFPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPointSameArg(condition, testCode, arg1, doubleOperands(), selectionA, selectionB);
+}
+
+void testMoveDoubleConditionallyFloatSameArg(MacroAssembler::DoubleCondition condition)
+{
+    float arg1 = 0;
+    double selectionA = 42.0;
+    double selectionB = 17.0;
+
+    auto testCode = compile([&, condition] (CCallHelpers& jit) {
+        emitFunctionPrologue(jit);
+
+        jit.loadFloat(CCallHelpers::TrustedImmPtr(&arg1), FPRInfo::fpRegT0);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionA), FPRInfo::fpRegT2);
+        jit.loadDouble(CCallHelpers::TrustedImmPtr(&selectionB), FPRInfo::fpRegT3);
+        jit.moveDoubleConditionallyFloat(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT0, FPRInfo::fpRegT2, FPRInfo::fpRegT3, FPRInfo::returnValueFPR);
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    });
+
+    testMoveConditionallyFloatingPointSameArg(condition, testCode, arg1, floatOperands(), selectionA, selectionB);
+}
+
+#endif // CPU(X86_64) || CPU(ARM64)
+
 #if ENABLE(MASM_PROBE)
 void testProbeReadsArgumentRegisters()
 {
@@ -1337,18 +2199,25 @@
     // reset to check a conversion result
     RUN(testBranchTruncateDoubleToInt32(123, 123));
 
-    RUN(testCompareDouble(MacroAssembler::DoubleEqual));
-    RUN(testCompareDouble(MacroAssembler::DoubleNotEqual));
-    RUN(testCompareDouble(MacroAssembler::DoubleGreaterThan));
-    RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrEqual));
-    RUN(testCompareDouble(MacroAssembler::DoubleLessThan));
-    RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrEqual));
-    RUN(testCompareDouble(MacroAssembler::DoubleEqualOrUnordered));
-    RUN(testCompareDouble(MacroAssembler::DoubleNotEqualOrUnordered));
-    RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrUnordered));
-    RUN(testCompareDouble(MacroAssembler::DoubleGreaterThanOrEqualOrUnordered));
-    RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrUnordered));
-    RUN(testCompareDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered));
+#define FOR_EACH_DOUBLE_CONDITION_RUN(__test) \
+    do { \
+        RUN(__test(MacroAssembler::DoubleEqual)); \
+        RUN(__test(MacroAssembler::DoubleNotEqual)); \
+        RUN(__test(MacroAssembler::DoubleGreaterThan)); \
+        RUN(__test(MacroAssembler::DoubleGreaterThanOrEqual)); \
+        RUN(__test(MacroAssembler::DoubleLessThan)); \
+        RUN(__test(MacroAssembler::DoubleLessThanOrEqual)); \
+        RUN(__test(MacroAssembler::DoubleEqualOrUnordered)); \
+        RUN(__test(MacroAssembler::DoubleNotEqualOrUnordered)); \
+        RUN(__test(MacroAssembler::DoubleGreaterThanOrUnordered)); \
+        RUN(__test(MacroAssembler::DoubleGreaterThanOrEqualOrUnordered)); \
+        RUN(__test(MacroAssembler::DoubleLessThanOrUnordered)); \
+        RUN(__test(MacroAssembler::DoubleLessThanOrEqualOrUnordered)); \
+    } while (false)
+
+    FOR_EACH_DOUBLE_CONDITION_RUN(testCompareDouble);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testCompareDoubleSameArg);
+
     RUN(testMul32WithImmediates());
 
 #if CPU(X86_64)
@@ -1365,20 +2234,35 @@
 #endif
 
 #if CPU(X86) || CPU(X86_64) || CPU(ARM64)
-    RUN(testCompareFloat(MacroAssembler::DoubleEqual));
-    RUN(testCompareFloat(MacroAssembler::DoubleNotEqual));
-    RUN(testCompareFloat(MacroAssembler::DoubleGreaterThan));
-    RUN(testCompareFloat(MacroAssembler::DoubleGreaterThanOrEqual));
-    RUN(testCompareFloat(MacroAssembler::DoubleLessThan));
-    RUN(testCompareFloat(MacroAssembler::DoubleLessThanOrEqual));
-    RUN(testCompareFloat(MacroAssembler::DoubleEqualOrUnordered));
-    RUN(testCompareFloat(MacroAssembler::DoubleNotEqualOrUnordered));
-    RUN(testCompareFloat(MacroAssembler::DoubleGreaterThanOrUnordered));
-    RUN(testCompareFloat(MacroAssembler::DoubleGreaterThanOrEqualOrUnordered));
-    RUN(testCompareFloat(MacroAssembler::DoubleLessThanOrUnordered));
-    RUN(testCompareFloat(MacroAssembler::DoubleLessThanOrEqualOrUnordered));
+    FOR_EACH_DOUBLE_CONDITION_RUN(testCompareFloat);
 #endif
 
+#if CPU(X86_64) || CPU(ARM64)
+    // Comparing 2 different registers.
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyDouble2);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyDouble3);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyDouble3DestSameAsThenCase);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyDouble3DestSameAsElseCase);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyFloat2);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyFloat3);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyFloat3DestSameAsThenCase);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyFloat3DestSameAsElseCase);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveDoubleConditionallyDouble);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveDoubleConditionallyDoubleDestSameAsThenCase);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveDoubleConditionallyDoubleDestSameAsElseCase);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveDoubleConditionallyFloat);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveDoubleConditionallyFloatDestSameAsThenCase);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveDoubleConditionallyFloatDestSameAsElseCase);
+
+    // Comparing the same register against itself.
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyDouble2SameArg);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyDouble3SameArg);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyFloat2SameArg);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveConditionallyFloat3SameArg);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveDoubleConditionallyDoubleSameArg);
+    FOR_EACH_DOUBLE_CONDITION_RUN(testMoveDoubleConditionallyFloatSameArg);
+#endif
+
 #if ENABLE(MASM_PROBE)
     RUN(testProbeReadsArgumentRegisters());
     RUN(testProbeWritesArgumentRegisters());
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to