Title: [249747] trunk/Source/_javascript_Core
Revision
249747
Author
ysuz...@apple.com
Date
2019-09-10 17:46:32 -0700 (Tue, 10 Sep 2019)

Log Message

[JSC] 32bit bitwide operation with all-one (-1) is wrong in B3
https://bugs.webkit.org/show_bug.cgi?id=201634

Reviewed by Mark Lam and Robin Morisset.

This patch includes two things. One is fixing 32bit bitwise operation with allOne constants. Another is fixing the existing bug in BitAnd strength reduction.

1. 32bit bitwise operation with allOne constants

    Accidentally, the B3::Value is ConstInt32(-1), `value->isInt(std::numeric_limits<uint32_t>::max())` returns `false`!
    For example, in BitAnd strength reduction,

        1034             // Turn this: BitAnd(value, all-ones)
        1035             // Into this: value.
        1036             if ((m_value->type() == Int64 && m_value->child(1)->isInt(std::numeric_limits<uint64_t>::max()))
        1037                 || (m_value->type() == Int32 && m_value->child(1)->isInt(std::numeric_limits<uint32_t>::max()))) {
        1038                 replaceWithIdentity(m_value->child(0));
        1039                 break;
        1040             }

    We use `m_value->child(1)->isInt(std::numeric_limits<uint32_t>::max())`. However, Value::isInt is,

        262 inline bool Value::isInt(int64_t value) const
        263 {
        264     return hasInt() && asInt() == value;
        265 }

    So, UINT32_MAX is expanded to int64_t, but it is not -1 since UINT32_MAX can be representable in int64_t. And Value::asInt implementation is,

        257 inline int64_t Value::asInt() const
        258 {
        259     return hasInt32() ? asInt32() : asInt64();
        260 }

    So, we perform `static_cast<int64_t>(-1) == static_cast<int64_t>(UINT32_MAX)`. This is false, but this comparison is not what we want!
    We should use `isInt32` and `isInt64` for bit patterns (like, operands for Bitwise opcodes).

2. BitAnd and BitOr strength reduction bug

    We also fix the following optimization.

        // Turn this: BitAnd(Op(value, constant1), constant2)
        //     where !(constant1 & constant2)
        //       and Op is BitOr or BitXor
        // into this: BitAnd(value, constant2)

    Since we stop further optimization when we match `if (m_value->child(1)->hasInt())`, the following optimization is never taken.

        // Turn this: BitAnd(BitXor(x, allOnes), c)
        // Into this: BitXor(BitOr(x, ~c), allOnes)

    And we also found that this not-used optimization has a bug not inserting a newly produced constant B3::Value. This patch also fixes it.

For both, this patch adds tests. And (2) fix can be ensured that the testb3 does not crash with validate-graph option.

* b3/B3LowerToAir.cpp:
* b3/B3ReduceStrength.cpp:
* b3/testb3.h:
* b3/testb3_2.cpp:
(testBitAndNotNot32):
(testBitAndNotImm):
(testBitAndNotImm32):
(testBitOrAndAndArgs32):
(testBitOrAndSameArgs32):
(testBitOrNotNot32):
(testBitOrNotImm32):
(addBitTests):
* b3/testb3_3.cpp:
(testBitXorAndAndArgs32):
(testBitXorAndSameArgs32):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (249746 => 249747)


--- trunk/Source/_javascript_Core/ChangeLog	2019-09-11 00:35:19 UTC (rev 249746)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-09-11 00:46:32 UTC (rev 249747)
@@ -1,3 +1,76 @@
+2019-09-10  Yusuke Suzuki  <ysuz...@apple.com>
+
+        [JSC] 32bit bitwide operation with all-one (-1) is wrong in B3
+        https://bugs.webkit.org/show_bug.cgi?id=201634
+
+        Reviewed by Mark Lam and Robin Morisset.
+
+        This patch includes two things. One is fixing 32bit bitwise operation with allOne constants. Another is fixing the existing bug in BitAnd strength reduction.
+
+        1. 32bit bitwise operation with allOne constants
+
+            Accidentally, the B3::Value is ConstInt32(-1), `value->isInt(std::numeric_limits<uint32_t>::max())` returns `false`!
+            For example, in BitAnd strength reduction,
+
+                1034             // Turn this: BitAnd(value, all-ones)
+                1035             // Into this: value.
+                1036             if ((m_value->type() == Int64 && m_value->child(1)->isInt(std::numeric_limits<uint64_t>::max()))
+                1037                 || (m_value->type() == Int32 && m_value->child(1)->isInt(std::numeric_limits<uint32_t>::max()))) {
+                1038                 replaceWithIdentity(m_value->child(0));
+                1039                 break;
+                1040             }
+
+            We use `m_value->child(1)->isInt(std::numeric_limits<uint32_t>::max())`. However, Value::isInt is,
+
+                262 inline bool Value::isInt(int64_t value) const
+                263 {
+                264     return hasInt() && asInt() == value;
+                265 }
+
+            So, UINT32_MAX is expanded to int64_t, but it is not -1 since UINT32_MAX can be representable in int64_t. And Value::asInt implementation is,
+
+                257 inline int64_t Value::asInt() const
+                258 {
+                259     return hasInt32() ? asInt32() : asInt64();
+                260 }
+
+            So, we perform `static_cast<int64_t>(-1) == static_cast<int64_t>(UINT32_MAX)`. This is false, but this comparison is not what we want!
+            We should use `isInt32` and `isInt64` for bit patterns (like, operands for Bitwise opcodes).
+
+        2. BitAnd and BitOr strength reduction bug
+
+            We also fix the following optimization.
+
+                // Turn this: BitAnd(Op(value, constant1), constant2)
+                //     where !(constant1 & constant2)
+                //       and Op is BitOr or BitXor
+                // into this: BitAnd(value, constant2)
+
+            Since we stop further optimization when we match `if (m_value->child(1)->hasInt())`, the following optimization is never taken.
+
+                // Turn this: BitAnd(BitXor(x, allOnes), c)
+                // Into this: BitXor(BitOr(x, ~c), allOnes)
+
+            And we also found that this not-used optimization has a bug not inserting a newly produced constant B3::Value. This patch also fixes it.
+
+        For both, this patch adds tests. And (2) fix can be ensured that the testb3 does not crash with validate-graph option.
+
+        * b3/B3LowerToAir.cpp:
+        * b3/B3ReduceStrength.cpp:
+        * b3/testb3.h:
+        * b3/testb3_2.cpp:
+        (testBitAndNotNot32):
+        (testBitAndNotImm):
+        (testBitAndNotImm32):
+        (testBitOrAndAndArgs32):
+        (testBitOrAndSameArgs32):
+        (testBitOrNotNot32):
+        (testBitOrNotImm32):
+        (addBitTests):
+        * b3/testb3_3.cpp:
+        (testBitXorAndAndArgs32):
+        (testBitXorAndSameArgs32):
+
 2019-09-10  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r249721.

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (249746 => 249747)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2019-09-11 00:35:19 UTC (rev 249746)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2019-09-11 00:46:32 UTC (rev 249747)
@@ -2749,7 +2749,7 @@
                 return;
             }
 
-            if (m_value->child(1)->isInt(0xffffffff)) {
+            if (m_value->child(1)->isInt64(0xffffffff) || m_value->child(1)->isInt32(0xffffffff)) {
                 appendUnOp<Move32, Move32>(m_value->child(0));
                 return;
             }

Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (249746 => 249747)


--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp	2019-09-11 00:35:19 UTC (rev 249746)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp	2019-09-11 00:46:32 UTC (rev 249747)
@@ -1033,8 +1033,8 @@
 
             // Turn this: BitAnd(value, all-ones)
             // Into this: value.
-            if ((m_value->type() == Int64 && m_value->child(1)->isInt(std::numeric_limits<uint64_t>::max()))
-                || (m_value->type() == Int32 && m_value->child(1)->isInt(std::numeric_limits<uint32_t>::max()))) {
+            if ((m_value->type() == Int64 && m_value->child(1)->isInt64(std::numeric_limits<uint64_t>::max()))
+                || (m_value->type() == Int32 && m_value->child(1)->isInt32(std::numeric_limits<uint32_t>::max()))) {
                 replaceWithIdentity(m_value->child(0));
                 break;
             }
@@ -1083,6 +1083,7 @@
             //       and Op is BitOr or BitXor
             // into this: BitAnd(value, constant2)
             if (m_value->child(1)->hasInt()) {
+                bool replaced = false;
                 int64_t constant2 = m_value->child(1)->asInt();
                 switch (m_value->child(0)->opcode()) {
                 case BitOr:
@@ -1091,6 +1092,7 @@
                         && !(m_value->child(0)->child(1)->asInt() & constant2)) {
                         m_value->child(0) = m_value->child(0)->child(0);
                         m_changed = true;
+                        replaced = true;
                         break;
                     }
                     break;
@@ -1097,7 +1099,8 @@
                 default:
                     break;
                 }
-                break;
+                if (replaced)
+                    break;
             }
 
             // Turn this: BitAnd(BitXor(x1, allOnes), BitXor(x2, allOnes)
@@ -1106,11 +1109,11 @@
             if (m_value->child(0)->opcode() == BitXor
                 && m_value->child(1)->opcode() == BitXor
                 && ((m_value->type() == Int64
-                        && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint64_t>::max())
-                        && m_value->child(1)->child(1)->isInt(std::numeric_limits<uint64_t>::max()))
+                        && m_value->child(0)->child(1)->isInt64(std::numeric_limits<uint64_t>::max())
+                        && m_value->child(1)->child(1)->isInt64(std::numeric_limits<uint64_t>::max()))
                     || (m_value->type() == Int32
-                        && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint32_t>::max())
-                        && m_value->child(1)->child(1)->isInt(std::numeric_limits<uint32_t>::max())))) {
+                        && m_value->child(0)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())
+                        && m_value->child(1)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())))) {
                 Value* bitOr = m_insertionSet.insert<Value>(m_index, BitOr, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)->child(0));
                 replaceWithNew<Value>(BitXor, m_value->origin(), bitOr, m_value->child(1)->child(1));
                 break;
@@ -1123,10 +1126,13 @@
             if (m_value->child(0)->opcode() == BitXor
                 && m_value->child(1)->hasInt()
                 && ((m_value->type() == Int64
-                        && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint64_t>::max()))
+                        && m_value->child(0)->child(1)->isInt64(std::numeric_limits<uint64_t>::max()))
                     || (m_value->type() == Int32
-                        && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint32_t>::max())))) {
-                Value* bitOr = m_insertionSet.insert<Value>(m_index, BitOr, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)->bitXorConstant(m_proc, m_value->child(0)->child(1)));
+                        && m_value->child(0)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())))) {
+                Value* newConstant = m_value->child(1)->bitXorConstant(m_proc, m_value->child(0)->child(1));
+                ASSERT(newConstant);
+                m_insertionSet.insertValue(m_index, newConstant);
+                Value* bitOr = m_insertionSet.insert<Value>(m_index, BitOr, m_value->origin(), m_value->child(0)->child(0), newConstant);
                 replaceWithNew<Value>(BitXor, m_value->origin(), bitOr, m_value->child(0)->child(1));
                 break;
             }
@@ -1171,8 +1177,8 @@
 
             // Turn this: BitOr(value, all-ones)
             // Into this: all-ones.
-            if ((m_value->type() == Int64 && m_value->child(1)->isInt(std::numeric_limits<uint64_t>::max()))
-                || (m_value->type() == Int32 && m_value->child(1)->isInt(std::numeric_limits<uint32_t>::max()))) {
+            if ((m_value->type() == Int64 && m_value->child(1)->isInt64(std::numeric_limits<uint64_t>::max()))
+                || (m_value->type() == Int32 && m_value->child(1)->isInt32(std::numeric_limits<uint32_t>::max()))) {
                 replaceWithIdentity(m_value->child(1));
                 break;
             }
@@ -1183,11 +1189,11 @@
             if (m_value->child(0)->opcode() == BitXor
                 && m_value->child(1)->opcode() == BitXor
                 && ((m_value->type() == Int64
-                        && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint64_t>::max())
-                        && m_value->child(1)->child(1)->isInt(std::numeric_limits<uint64_t>::max()))
+                        && m_value->child(0)->child(1)->isInt64(std::numeric_limits<uint64_t>::max())
+                        && m_value->child(1)->child(1)->isInt64(std::numeric_limits<uint64_t>::max()))
                     || (m_value->type() == Int32
-                        && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint32_t>::max())
-                        && m_value->child(1)->child(1)->isInt(std::numeric_limits<uint32_t>::max())))) {
+                        && m_value->child(0)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())
+                        && m_value->child(1)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())))) {
                 Value* bitAnd = m_insertionSet.insert<Value>(m_index, BitAnd, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)->child(0));
                 replaceWithNew<Value>(BitXor, m_value->origin(), bitAnd, m_value->child(1)->child(1));
                 break;
@@ -1200,10 +1206,13 @@
             if (m_value->child(0)->opcode() == BitXor
                 && m_value->child(1)->hasInt()
                 && ((m_value->type() == Int64
-                        && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint64_t>::max()))
+                        && m_value->child(0)->child(1)->isInt64(std::numeric_limits<uint64_t>::max()))
                     || (m_value->type() == Int32
-                        && m_value->child(0)->child(1)->isInt(std::numeric_limits<uint32_t>::max())))) {
-                Value* bitAnd = m_insertionSet.insert<Value>(m_index, BitAnd, m_value->origin(), m_value->child(0)->child(0), m_value->child(1)->bitXorConstant(m_proc, m_value->child(0)->child(1)));
+                        && m_value->child(0)->child(1)->isInt32(std::numeric_limits<uint32_t>::max())))) {
+                Value* newConstant = m_value->child(1)->bitXorConstant(m_proc, m_value->child(0)->child(1));
+                ASSERT(newConstant);
+                m_insertionSet.insertValue(m_index, newConstant);
+                Value* bitAnd = m_insertionSet.insert<Value>(m_index, BitAnd, m_value->origin(), m_value->child(0)->child(0), newConstant);
                 replaceWithNew<Value>(BitXor, m_value->origin(), bitAnd, m_value->child(0)->child(1));
                 break;
             }

Modified: trunk/Source/_javascript_Core/b3/testb3.h (249746 => 249747)


--- trunk/Source/_javascript_Core/b3/testb3.h	2019-09-11 00:35:19 UTC (rev 249746)
+++ trunk/Source/_javascript_Core/b3/testb3.h	2019-09-11 00:46:32 UTC (rev 249747)
@@ -459,7 +459,9 @@
 void testBitXorArgs(int64_t, int64_t);
 void testBitXorSameArg(int64_t);
 void testBitXorAndAndArgs(int64_t, int64_t, int64_t c);
+void testBitXorAndAndArgs32(int32_t, int32_t, int32_t c);
 void testBitXorAndSameArgs(int64_t, int64_t);
+void testBitXorAndSameArgs32(int32_t, int32_t);
 void testBitXorImms(int64_t, int64_t);
 void testBitXorArgImm(int64_t, int64_t);
 void testBitXorImmArg(int64_t, int64_t);

Modified: trunk/Source/_javascript_Core/b3/testb3_2.cpp (249746 => 249747)


--- trunk/Source/_javascript_Core/b3/testb3_2.cpp	2019-09-11 00:35:19 UTC (rev 249746)
+++ trunk/Source/_javascript_Core/b3/testb3_2.cpp	2019-09-11 00:46:32 UTC (rev 249747)
@@ -2565,6 +2565,24 @@
     CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & ~b));
 }
 
+static void testBitAndNotNot32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
+    Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const32Value>(proc, Origin(), -1));
+    root->appendNewControlValue(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitAnd, Origin(),
+            notA,
+            notB));
+
+    CHECK_EQ(compileAndRun<int32_t>(proc, a, b), (~a & ~b));
+}
+
 static void testBitAndNotImm(int64_t a, int64_t b)
 {
     Procedure proc;
@@ -2579,9 +2597,26 @@
             notA,
             cstB));
 
-    CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & b));
+    CHECK_EQ(compileAndRun<int64_t>(proc, a), (~a & b));
 }
 
+static void testBitAndNotImm32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
+    Value* cstB = root->appendNew<Const32Value>(proc, Origin(), b);
+    root->appendNewControlValue(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitAnd, Origin(),
+            notA,
+            cstB));
+
+    CHECK_EQ(compileAndRun<int32_t>(proc, a), (~a & b));
+}
+
 static void testBitAndImms(int64_t a, int64_t b)
 {
     Procedure proc;
@@ -2994,6 +3029,34 @@
     }
 }
 
+static void testBitOrAndAndArgs32(int32_t a, int32_t b, int32_t c)
+{
+    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
+    // ((a & b) | (a & c))
+    // ((a & b) | (c & a))
+    // ((b & a) | (a & c))
+    // ((b & a) | (c & a))
+    for (int i = 0; i < 4; ++i) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* argC = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
+        Value* andAB = i & 2 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB)
+            : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA);
+        Value* andAC = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argC)
+            : root->appendNew<Value>(proc, BitAnd, Origin(), argC, argA);
+        root->appendNewControlValue(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, BitOr, Origin(),
+                andAB,
+                andAC));
+
+        CHECK_EQ(compileAndRun<int32_t>(proc, a, b, c), ((a & b) | (a & c)));
+    }
+}
+
 static void testBitOrAndSameArgs(int64_t a, int64_t b)
 {
     // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
@@ -3016,6 +3079,28 @@
     }
 }
 
+static void testBitOrAndSameArgs32(int32_t a, int32_t b)
+{
+    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
+    // ((a & b) | a)
+    // ((b & a) | a)
+    // (a | (a & b))
+    // (a | (b & a))
+    for (int i = 0; i < 4; ++i) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* andAB = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB)
+            : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA);
+        Value* result = i & 2 ? root->appendNew<Value>(proc, BitOr, Origin(), andAB, argA)
+            : root->appendNew<Value>(proc, BitOr, Origin(), argA, andAB);
+        root->appendNewControlValue(proc, Return, Origin(), result);
+
+        CHECK_EQ(compileAndRun<int32_t>(proc, a, b), ((a & b) | a));
+    }
+}
+
 static void testBitOrNotNot(int64_t a, int64_t b)
 {
     Procedure proc;
@@ -3034,6 +3119,24 @@
     CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a | ~b));
 }
 
+static void testBitOrNotNot32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
+    Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const32Value>(proc, Origin(), -1));
+    root->appendNewControlValue(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitOr, Origin(),
+            notA,
+            notB));
+
+    CHECK_EQ(compileAndRun<int32_t>(proc, a, b), (~a | ~b));
+}
+
 static void testBitOrNotImm(int64_t a, int64_t b)
 {
     Procedure proc;
@@ -3051,6 +3154,23 @@
     CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a | b));
 }
 
+static void testBitOrNotImm32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const32Value>(proc, Origin(), -1));
+    Value* cstB = root->appendNew<Const32Value>(proc, Origin(), b);
+    root->appendNewControlValue(
+        proc, Return, Origin(),
+        root->appendNew<Value>(
+            proc, BitOr, Origin(),
+            notA,
+            cstB));
+
+    CHECK_EQ(compileAndRun<int32_t>(proc, a), (~a | b));
+}
+
 static void testBitOrImms(int64_t a, int64_t b)
 {
     Procedure proc;
@@ -3287,7 +3407,9 @@
     RUN_BINARY(testBitAndImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
     RUN_BINARY(testBitAndArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>());
     RUN_BINARY(testBitAndNotNot, int64Operands(), int64Operands());
+    RUN_BINARY(testBitAndNotNot32, int32Operands(), int32Operands());
     RUN_BINARY(testBitAndNotImm, int64Operands(), int64Operands());
+    RUN_BINARY(testBitAndNotImm32, int32Operands(), int32Operands());
     
     RUN(testBitOrArgs(43, 43));
     RUN(testBitOrArgs(43, 0));
@@ -3351,9 +3473,13 @@
     RUN_BINARY(testBitOrImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>());
     RUN_BINARY(testBitOrArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>());
     RUN_TERNARY(testBitOrAndAndArgs, int64Operands(), int64Operands(), int64Operands());
+    RUN_TERNARY(testBitOrAndAndArgs32, int32Operands(), int32Operands(), int32Operands());
     RUN_BINARY(testBitOrAndSameArgs, int64Operands(), int64Operands());
+    RUN_BINARY(testBitOrAndSameArgs32, int32Operands(), int32Operands());
     RUN_BINARY(testBitOrNotNot, int64Operands(), int64Operands());
+    RUN_BINARY(testBitOrNotNot32, int32Operands(), int32Operands());
     RUN_BINARY(testBitOrNotImm, int64Operands(), int64Operands());
+    RUN_BINARY(testBitOrNotImm32, int32Operands(), int32Operands());
     
     RUN_BINARY(testBitXorArgs, int64Operands(), int64Operands());
     RUN_UNARY(testBitXorSameArg, int64Operands());
@@ -3393,7 +3519,9 @@
     RUN(testBitXorImmBitXorArgImm32(6, 1, 6));
     RUN(testBitXorImmBitXorArgImm32(24, 0xffff, 7));
     RUN_TERNARY(testBitXorAndAndArgs, int64Operands(), int64Operands(), int64Operands());
+    RUN_TERNARY(testBitXorAndAndArgs32, int32Operands(), int32Operands(), int32Operands());
     RUN_BINARY(testBitXorAndSameArgs, int64Operands(), int64Operands());
+    RUN_BINARY(testBitXorAndSameArgs32, int32Operands(), int32Operands());
     
     RUN_UNARY(testBitNotArg, int64Operands());
     RUN_UNARY(testBitNotImm, int64Operands());

Modified: trunk/Source/_javascript_Core/b3/testb3_3.cpp (249746 => 249747)


--- trunk/Source/_javascript_Core/b3/testb3_3.cpp	2019-09-11 00:35:19 UTC (rev 249746)
+++ trunk/Source/_javascript_Core/b3/testb3_3.cpp	2019-09-11 00:46:32 UTC (rev 249747)
@@ -259,6 +259,34 @@
     }
 }
 
+void testBitXorAndAndArgs32(int32_t a, int32_t b, int32_t c)
+{
+    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
+    // ((a & b) ^ (a & c))
+    // ((a & b) ^ (c & a))
+    // ((b & a) ^ (a & c))
+    // ((b & a) ^ (c & a))
+    for (int i = 0; i < 4; ++i) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* argC = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR2));
+        Value* andAB = i & 2 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB)
+            : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA);
+        Value* andAC = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argC)
+            : root->appendNew<Value>(proc, BitAnd, Origin(), argC, argA);
+        root->appendNewControlValue(
+            proc, Return, Origin(),
+            root->appendNew<Value>(
+                proc, BitXor, Origin(),
+                andAB,
+                andAC));
+
+        CHECK_EQ(compileAndRun<int32_t>(proc, a, b, c), ((a & b) ^ (a & c)));
+    }
+}
+
 void testBitXorAndSameArgs(int64_t a, int64_t b)
 {
     // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
@@ -281,6 +309,28 @@
     }
 }
 
+void testBitXorAndSameArgs32(int32_t a, int32_t b)
+{
+    // We want to check every possible ordering of arguments (to properly check every path in B3ReduceStrength):
+    // ((a & b) ^ a)
+    // ((b & a) ^ a)
+    // (a ^ (a & b))
+    // (a ^ (b & a))
+    for (int i = 0; i < 4; ++i) {
+        Procedure proc;
+        BasicBlock* root = proc.addBlock();
+        Value* argA = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+        Value* argB = root->appendNew<Value>(proc, Trunc, Origin(), root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+        Value* andAB = i & 1 ? root->appendNew<Value>(proc, BitAnd, Origin(), argA, argB)
+            : root->appendNew<Value>(proc, BitAnd, Origin(), argB, argA);
+        Value* result = i & 2 ? root->appendNew<Value>(proc, BitXor, Origin(), andAB, argA)
+            : root->appendNew<Value>(proc, BitXor, Origin(), argA, andAB);
+        root->appendNewControlValue(proc, Return, Origin(), result);
+
+        CHECK_EQ(compileAndRun<int32_t>(proc, a, b), ((a & b) ^ a));
+    }
+}
+
 void testBitXorImms(int64_t a, int64_t b)
 {
     Procedure proc;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to