From e09f74903e84792b195cf8d37b3c5a465409862e Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 18 Jan 2022 09:22:07 -0500 Subject: [PATCH] LibCrypo: Simplify mixed-sign bitwise_or No behavior change. --- .../LibCrypto/BigInt/SignedBigInteger.cpp | 18 +++++++++++++----- .../Tests/builtins/BigInt/bigint-basic.js | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp index 891f65e725..e95102cb84 100644 --- a/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp +++ b/Userland/Libraries/LibCrypto/BigInt/SignedBigInteger.cpp @@ -173,12 +173,20 @@ FLATTEN SignedBigInteger SignedBigInteger::bitwise_or(const SignedBigInteger& ot if (!is_negative() && !other.is_negative()) return { unsigned_value().bitwise_or(other.unsigned_value()), false }; - size_t index = max(unsigned_value().one_based_index_of_highest_set_bit(), other.unsigned_value().one_based_index_of_highest_set_bit()); - if (is_negative() && !other.is_negative()) - return { unsigned_value().bitwise_not_fill_to_one_based_index(index).plus(1).bitwise_or(other.unsigned_value()).bitwise_not_fill_to_one_based_index(index).plus(1), true }; + // -A | B == (~A + 1) | B == ~(A - 1) | B. The result is negative, so need to two's complement at the end to move the sign into the m_sign field. + // That can be simplified to: + // -(-A | B) == ~(~(A - 1) | B) + 1 = (A - 1) & ~B + 1 + // This saves one ~. + if (is_negative() && !other.is_negative()) { + size_t index = unsigned_value().one_based_index_of_highest_set_bit(); + return { unsigned_value().minus(1).bitwise_and(other.unsigned_value().bitwise_not_fill_to_one_based_index(index)).plus(1), true }; + } - if (!is_negative() && other.is_negative()) - return { unsigned_value().bitwise_or(other.unsigned_value().bitwise_not_fill_to_one_based_index(index).plus(1)).bitwise_not_fill_to_one_based_index(index).plus(1), true }; + // -(A | -B) == ~A & (B - 1) + 1 + if (!is_negative() && other.is_negative()) { + size_t index = other.unsigned_value().one_based_index_of_highest_set_bit(); + return { unsigned_value().bitwise_not_fill_to_one_based_index(index).bitwise_and(other.unsigned_value().minus(1)).plus(1), true }; + } return { unsigned_value().minus(1).bitwise_and(other.unsigned_value().minus(1)).plus(1), true }; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js b/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js index 494820be9e..5088269466 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js +++ b/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js @@ -44,6 +44,7 @@ describe("correct behavior", () => { expect(1n | 2n).toBe(3n); expect(0n | -1n).toBe(-1n); + expect(0n | -2n).toBe(-2n); expect(5n ^ 3n).toBe(6n);