WebKit Bugzilla
Attachment 362764 Details for
Bug 194252
: B3ReduceStrength: missing peephole optimizations for binary operations
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
patch194252 (text/plain), 24.47 KB, created by
Robin Morisset
on 2019-02-22 14:16:23 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Robin Morisset
Created:
2019-02-22 14:16:23 PST
Size:
24.47 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 241963) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,52 @@ >+2019-02-22 Robin Morisset <rmorisset@apple.com> >+ >+ B3ReduceStrength: missing peephole optimizations for binary operations >+ https://bugs.webkit.org/show_bug.cgi?id=194252 >+ >+ Reviewed by Saam Barati. >+ >+ Adds several sets of optimizations for BitAnd, BitOr and BitXor. >+ Using BitAnd distributivity over BitOr and BitXor: >+ Turn any of these (for Op == BitOr || Op == BitXor): >+ Op(BitAnd(x1, x2), BitAnd(x1, x3)) >+ Op(BitAnd(x2, x1), BitAnd(x1, x3)) >+ Op(BitAnd(x1, x2), BitAnd(x3, x1)) >+ Op(BitAnd(x2, x1), BitAnd(x3, x1)) >+ Into this: BitAnd(Op(x2, x3), x1) >+ And any of these: >+ Op(BitAnd(x1, x2), x1) >+ Op(BitAnd(x2, x1), x1) >+ Op(x1, BitAnd(x1, x2)) >+ Op(x1, BitAnd(x2, x1)) >+ Into this: BitAnd(Op(x2, x1), x1) >+ This second set is equivalent to doing x1 => BitAnd(x1, x1), and then applying the first set. >+ Using de Morgan laws (we represent not as BitXor with allOnes): >+ BitAnd(BitXor(x1, allOnes), BitXor(x2, allOnes)) => BitXor(BitOr(x1, x2), allOnes) >+ BitOr(BitXor(x1, allOnes), BitXor(x2, allOnes) => BitXor(BitAnd(x1, x2), allOnes) >+ BitOr(BitXor(x, allOnes), c) => BitXor(BitAnd(x, ~c), allOnes) >+ BitAnd(BitXor(x, allOnes), c) => BitXor(BitOr(x, ~c), allOnes) >+ The latter two are equivalent to doing c => BitXor(~c, allOnes), and then applying the former two. >+ >+ All of these transformations either reduce the number of operations (which we always do when possible), or bring the expression closer to having: >+ - BitXor with all ones at the outermost >+ - then BitAnd >+ - then other BitXor >+ - then BitOr at the innermost. >+ These transformations that don't directly reduce the number of operations are still useful for normalization (helping things like CSE), and also can enable >+ more optimizations (for example BitXor with all ones can easily cancel each other once they are all at the outermost level). >+ >+ * b3/B3ReduceStrength.cpp: >+ * b3/testb3.cpp: >+ (JSC::B3::testBitAndNotNot): >+ (JSC::B3::testBitAndNotImm): >+ (JSC::B3::testBitOrAndAndArgs): >+ (JSC::B3::testBitOrAndSameArgs): >+ (JSC::B3::testBitOrNotNot): >+ (JSC::B3::testBitOrNotImm): >+ (JSC::B3::testBitXorAndAndArgs): >+ (JSC::B3::testBitXorAndSameArgs): >+ (JSC::B3::run): >+ > 2019-02-22 Yusuke Suzuki <ysuzuki@apple.com> > > [JSC] putNonEnumerable in JSWrapperMap is too costly >Index: Source/JavaScriptCore/b3/B3ReduceStrength.cpp >=================================================================== >--- Source/JavaScriptCore/b3/B3ReduceStrength.cpp (revision 241963) >+++ Source/JavaScriptCore/b3/B3ReduceStrength.cpp (working copy) >@@ -962,8 +962,8 @@ > > // Turn this: BitAnd(value, all-ones) > // Into this: value. >- if ((m_value->type() == Int64 && m_value->child(1)->isInt(0xffffffffffffffff)) >- || (m_value->type() == Int32 && m_value->child(1)->isInt(0xffffffff))) { >+ 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()))) { > replaceWithIdentity(m_value->child(0)); > break; > } >@@ -984,6 +984,7 @@ > && !(m_value->child(1)->asInt32() & 0xffffff00)) { > m_value->child(0) = m_value->child(0)->child(0); > m_changed = true; >+ break; > } > > // Turn this: BitAnd(SExt16(value), mask) where (mask & 0xffff0000) == 0 >@@ -992,6 +993,7 @@ > && !(m_value->child(1)->asInt32() & 0xffff0000)) { > m_value->child(0) = m_value->child(0)->child(0); > m_changed = true; >+ break; > } > > // Turn this: BitAnd(SExt32(value), mask) where (mask & 0xffffffff00000000) == 0 >@@ -1002,6 +1004,7 @@ > m_index, ZExt32, m_value->origin(), > m_value->child(0)->child(0), m_value->child(0)->child(1)); > m_changed = true; >+ break; > } > > // Turn this: BitAnd(Op(value, constant1), constant2) >@@ -1023,7 +1026,40 @@ > default: > break; > } >+ break; > } >+ >+ // Turn this: BitAnd(BitXor(x1, allOnes), BitXor(x2, allOnes) >+ // Into this: BitXor(BitOr(x1, x2), allOnes) >+ // By applying De Morgan laws >+ 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->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())))) { >+ 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; >+ } >+ >+ // Turn this: BitAnd(BitXor(x, allOnes), c) >+ // Into this: BitXor(BitOr(x, ~c), allOnes) >+ // This is a variation on the previous optimization, treating c as if it were BitXor(~c, allOnes) >+ // It does not reduce the number of operations, but provides some normalization (we try to get BitXor by allOnes at the outermost point), and some chance to float Xors to a place where they might get eliminated. >+ 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->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))); >+ replaceWithNew<Value>(BitXor, m_value->origin(), bitOr, m_value->child(0)->child(1)); >+ break; >+ } >+ > break; > > case BitOr: >@@ -1064,12 +1100,46 @@ > > // Turn this: BitOr(value, all-ones) > // Into this: all-ones. >- if ((m_value->type() == Int64 && m_value->child(1)->isInt(0xffffffffffffffff)) >- || (m_value->type() == Int32 && m_value->child(1)->isInt(0xffffffff))) { >+ 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()))) { > replaceWithIdentity(m_value->child(1)); > break; > } > >+ // Turn this: BitOr(BitXor(x1, allOnes), BitXor(x2, allOnes) >+ // Into this: BitXor(BitAnd(x1, x2), allOnes) >+ // By applying De Morgan laws >+ 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->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())))) { >+ 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; >+ } >+ >+ // Turn this: BitOr(BitXor(x, allOnes), c) >+ // Into this: BitXor(BitAnd(x, ~c), allOnes) >+ // This is a variation on the previous optimization, treating c as if it were BitXor(~c, allOnes) >+ // It does not reduce the number of operations, but provides some normalization (we try to get BitXor by allOnes at the outermost point), and some chance to float Xors to a place where they might get eliminated. >+ 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->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))); >+ replaceWithNew<Value>(BitXor, m_value->origin(), bitAnd, m_value->child(0)->child(1)); >+ break; >+ } >+ >+ if (handleBitAndDistributivity()) >+ break; >+ > break; > > case BitXor: >@@ -1116,6 +1186,9 @@ > replaceWithIdentity(m_value->child(0)); > break; > } >+ >+ if (handleBitAndDistributivity()) >+ break; > > break; > >@@ -2210,6 +2283,70 @@ > } > } > >+ // For Op==BitOr or BitXor, turn any of these: >+ // Op(BitAnd(x1, x2), BitAnd(x1, x3)) >+ // Op(BitAnd(x2, x1), BitAnd(x1, x3)) >+ // Op(BitAnd(x1, x2), BitAnd(x3, x1)) >+ // Op(BitAnd(x2, x1), BitAnd(x3, x1)) >+ // Into this: BitAnd(Op(x2, x3), x1) >+ // And any of these: >+ // Op(BitAnd(x1, x2), x1) >+ // Op(BitAnd(x2, x1), x1) >+ // Op(x1, BitAnd(x1, x2)) >+ // Op(x1, BitAnd(x2, x1)) >+ // Into this: BitAnd(Op(x2, x1), x1) >+ // This second set is equivalent to doing x1 => BitAnd(x1, x1), and then applying the first set. >+ // It does not reduce the number of operations executed, but provides some useful normalization: we prefer to have BitAnd at the outermost, then BitXor, and finally BitOr at the innermost >+ bool handleBitAndDistributivity() >+ { >+ ASSERT(m_value->opcode() == BitOr || m_value->opcode() == BitXor); >+ Value* x1 = nullptr; >+ Value* x2 = nullptr; >+ Value* x3 = nullptr; >+ if (m_value->child(0)->opcode() == BitAnd && m_value->child(1)->opcode() == BitAnd) { >+ if (m_value->child(0)->child(0) == m_value->child(1)->child(0)) { >+ x1 = m_value->child(0)->child(0); >+ x2 = m_value->child(0)->child(1); >+ x3 = m_value->child(1)->child(1); >+ } else if (m_value->child(0)->child(1) == m_value->child(1)->child(0)) { >+ x1 = m_value->child(0)->child(1); >+ x2 = m_value->child(0)->child(0); >+ x3 = m_value->child(1)->child(1); >+ } else if (m_value->child(0)->child(0) == m_value->child(1)->child(1)) { >+ x1 = m_value->child(0)->child(0); >+ x2 = m_value->child(0)->child(1); >+ x3 = m_value->child(1)->child(0); >+ } else if (m_value->child(0)->child(1) == m_value->child(1)->child(1)) { >+ x1 = m_value->child(0)->child(1); >+ x2 = m_value->child(0)->child(0); >+ x3 = m_value->child(1)->child(0); >+ } >+ } else if (m_value->child(0)->opcode() == BitAnd) { >+ if (m_value->child(0)->child(0) == m_value->child(1)) { >+ x1 = x3 = m_value->child(1); >+ x2 = m_value->child(0)->child(1); >+ } else if (m_value->child(0)->child(1) == m_value->child(1)) { >+ x1 = x3 = m_value->child(1); >+ x2 = m_value->child(0)->child(0); >+ } >+ } else if (m_value->child(1)->opcode() == BitAnd) { >+ if (m_value->child(1)->child(0) == m_value->child(0)) { >+ x1 = x3 = m_value->child(0); >+ x2 = m_value->child(1)->child(1); >+ } else if (m_value->child(1)->child(1) == m_value->child(0)) { >+ x1 = x3 = m_value->child(0); >+ x2 = m_value->child(1)->child(0); >+ } >+ } >+ if (x1 != nullptr) { >+ ASSERT(x2 != nullptr && x3 != nullptr); >+ Value* bitOp = m_insertionSet.insert<Value>(m_index, m_value->opcode(), m_value->origin(), x2, x3); >+ replaceWithNew<Value>(BitAnd, m_value->origin(), bitOp, x1); >+ return true; >+ } >+ return false; >+ } >+ > struct CanonicalizedComparison { > Opcode opcode; > Value* operands[2]; >Index: Source/JavaScriptCore/b3/testb3.cpp >=================================================================== >--- Source/JavaScriptCore/b3/testb3.cpp (revision 241963) >+++ Source/JavaScriptCore/b3/testb3.cpp (working copy) >@@ -2486,6 +2486,41 @@ > CHECK(compileAndRun<int64_t>(proc, a) == a); > } > >+void testBitAndNotNot(int64_t a, int64_t b) >+{ >+ Procedure proc; >+ BasicBlock* root = proc.addBlock(); >+ Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); >+ Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); >+ Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1)); >+ Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const64Value>(proc, Origin(), -1)); >+ root->appendNewControlValue( >+ proc, Return, Origin(), >+ root->appendNew<Value>( >+ proc, BitAnd, Origin(), >+ notA, >+ notB)); >+ >+ CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & ~b)); >+} >+ >+void testBitAndNotImm(int64_t a, int64_t b) >+{ >+ Procedure proc; >+ BasicBlock* root = proc.addBlock(); >+ Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); >+ Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1)); >+ Value* cstB = root->appendNew<Const64Value>(proc, Origin(), b); >+ root->appendNewControlValue( >+ proc, Return, Origin(), >+ root->appendNew<Value>( >+ proc, BitAnd, Origin(), >+ notA, >+ cstB)); >+ >+ CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a & b)); >+} >+ > void testBitAndImms(int64_t a, int64_t b) > { > Procedure proc; >@@ -2870,6 +2905,91 @@ > CHECK(compileAndRun<int64_t>(proc, a) == a); > } > >+void testBitOrAndAndArgs(int64_t a, int64_t b, int64_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<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); >+ Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); >+ Value* argC = 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<int64_t>(proc, a, b, c), ((a & b) | (a & c))); >+ } >+} >+ >+void testBitOrAndSameArgs(int64_t a, int64_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<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); >+ Value* argB = 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<int64_t>(proc, a, b), ((a & b) | a)); >+ } >+} >+ >+void testBitOrNotNot(int64_t a, int64_t b) >+{ >+ Procedure proc; >+ BasicBlock* root = proc.addBlock(); >+ Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); >+ Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); >+ Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1)); >+ Value* notB = root->appendNew<Value>(proc, BitXor, Origin(), argB, root->appendNew<Const64Value>(proc, Origin(), -1)); >+ root->appendNewControlValue( >+ proc, Return, Origin(), >+ root->appendNew<Value>( >+ proc, BitOr, Origin(), >+ notA, >+ notB)); >+ >+ CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a | ~b)); >+} >+ >+void testBitOrNotImm(int64_t a, int64_t b) >+{ >+ Procedure proc; >+ BasicBlock* root = proc.addBlock(); >+ Value* argA = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); >+ Value* notA = root->appendNew<Value>(proc, BitXor, Origin(), argA, root->appendNew<Const64Value>(proc, Origin(), -1)); >+ Value* cstB = root->appendNew<Const64Value>(proc, Origin(), b); >+ root->appendNewControlValue( >+ proc, Return, Origin(), >+ root->appendNew<Value>( >+ proc, BitOr, Origin(), >+ notA, >+ cstB)); >+ >+ CHECK_EQ(compileAndRun<int64_t>(proc, a, b), (~a | b)); >+} >+ > void testBitOrImms(int64_t a, int64_t b) > { > Procedure proc; >@@ -3232,6 +3352,56 @@ > CHECK(!compileAndRun<int64_t>(proc, a)); > } > >+void testBitXorAndAndArgs(int64_t a, int64_t b, int64_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<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); >+ Value* argB = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1); >+ Value* argC = 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<int64_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): >+ // ((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<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0); >+ Value* argB = 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<int64_t>(proc, a, b), ((a & b) ^ a)); >+ } >+} >+ > void testBitXorImms(int64_t a, int64_t b) > { > Procedure proc; >@@ -16452,6 +16622,22 @@ > })); \ > } \ > } >+#define RUN_TERNARY(test, valuesA, valuesB, valuesC) \ >+ for (auto a : valuesA) { \ >+ for (auto b : valuesB) { \ >+ for (auto c : valuesC) { \ >+ CString testStr = toCString(#test, "(", a.name, ", ", b.name, ",", c.name, ")"); \ >+ if (!shouldRun(testStr.data())) \ >+ continue; \ >+ tasks.append(createSharedTask<void()>( \ >+ [=] () { \ >+ dataLog(toCString(testStr, "...\n")); \ >+ test(a.value, b.value, c.value); \ >+ dataLog(toCString(testStr, ": OK!\n")); \ >+ })); \ >+ } \ >+ } \ >+ } > > void run(const char* filter) > { >@@ -16780,6 +16966,8 @@ > RUN_BINARY(testBitAndArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); > RUN_BINARY(testBitAndImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); > RUN_BINARY(testBitAndArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); >+ RUN_BINARY(testBitAndNotNot, int64Operands(), int64Operands()); >+ RUN_BINARY(testBitAndNotImm, int64Operands(), int64Operands()); > > RUN(testBitOrArgs(43, 43)); > RUN(testBitOrArgs(43, 0)); >@@ -16842,6 +17030,10 @@ > RUN_BINARY(testBitOrArgImmFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); > RUN_BINARY(testBitOrImmsFloat, floatingPointOperands<float>(), floatingPointOperands<float>()); > RUN_BINARY(testBitOrArgsFloatWithUselessDoubleConversion, floatingPointOperands<float>(), floatingPointOperands<float>()); >+ RUN_TERNARY(testBitOrAndAndArgs, int64Operands(), int64Operands(), int64Operands()); >+ RUN_BINARY(testBitOrAndSameArgs, int64Operands(), int64Operands()); >+ RUN_BINARY(testBitOrNotNot, int64Operands(), int64Operands()); >+ RUN_BINARY(testBitOrNotImm, int64Operands(), int64Operands()); > > RUN_BINARY(testBitXorArgs, int64Operands(), int64Operands()); > RUN_UNARY(testBitXorSameArg, int64Operands()); >@@ -16880,6 +17072,8 @@ > RUN(testBitXorImmBitXorArgImm32(7, 2, 3)); > RUN(testBitXorImmBitXorArgImm32(6, 1, 6)); > RUN(testBitXorImmBitXorArgImm32(24, 0xffff, 7)); >+ RUN_TERNARY(testBitXorAndAndArgs, int64Operands(), int64Operands(), int64Operands()); >+ RUN_BINARY(testBitXorAndSameArgs, int64Operands(), int64Operands()); > > RUN_UNARY(testBitNotArg, int64Operands()); > RUN_UNARY(testBitNotImm, int64Operands());
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 194252
:
361240
|
361312
| 362764