From 7e99f496295c16380f12e16180c3b656ca52507a Mon Sep 17 00:00:00 2001 From: Aart Bik Date: Wed, 2 Oct 2019 20:37:10 +0000 Subject: [PATCH] [vm/compiler] general rbit utilities Rationale: Useful to implement the simulator, but also useful in the future when compiler wants to constant fold operations related to bit reversal. https://github.com/dart-lang/sdk/issues/38346 Change-Id: I2f09ba6b1897202b5c07a2cff771afd7bbc99495 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119703 Reviewed-by: Alexander Markov Reviewed-by: Ryan Macnak Commit-Queue: Aart Bik --- runtime/platform/utils.cc | 20 ++++++++++++++++++++ runtime/platform/utils.h | 11 +++++++++++ runtime/vm/simulator_arm.cc | 22 ++++------------------ runtime/vm/simulator_arm.h | 3 --- runtime/vm/simulator_arm64.cc | 19 ++----------------- runtime/vm/utils_test.cc | 16 ++++++++++++++++ 6 files changed, 53 insertions(+), 38 deletions(-) diff --git a/runtime/platform/utils.cc b/runtime/platform/utils.cc index 2cfa6492406a..3f5091cf1862 100644 --- a/runtime/platform/utils.cc +++ b/runtime/platform/utils.cc @@ -50,6 +50,26 @@ int Utils::HighestBit(int64_t v) { return r; } +uint64_t Utils::ReverseBits64(uint64_t x) { + const uint64_t one = static_cast(1); + uint64_t result = 0; + for (uint64_t rbit = one << 63; x != 0; x >>= 1) { + if ((x & one) != 0) result |= rbit; + rbit >>= 1; + } + return result; +} + +uint32_t Utils::ReverseBits32(uint32_t x) { + const uint32_t one = static_cast(1); + uint32_t result = 0; + for (uint32_t rbit = one << 31; x != 0; x >>= 1) { + if ((x & one) != 0) result |= rbit; + rbit >>= 1; + } + return result; +} + // Implementation according to H.S.Warren's "Hacker's Delight" // (Addison Wesley, 2002) Chapter 10 and T.Grablund, P.L.Montogomery's // "Division by Invariant Integers Using Multiplication" (PLDI 1994). diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h index e0d145bb4380..860c00b1ca53 100644 --- a/runtime/platform/utils.h +++ b/runtime/platform/utils.h @@ -150,6 +150,17 @@ class Utils { static int CountLeadingZeros(uword x); static int CountTrailingZeros(uword x); + static uint64_t ReverseBits64(uint64_t x); + static uint32_t ReverseBits32(uint32_t x); + + static uword ReverseBitsWord(uword x) { +#ifdef ARCH_IS_64_BIT + return ReverseBits64(x); +#else + return ReverseBits32(x); +#endif + } + // Computes magic numbers to implement DIV or MOD operator. static void CalculateMagicAndShiftForDivRem(int64_t divisor, int64_t* magic, diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc index 21fae2ab55cd..ea0a4a4e8092 100644 --- a/runtime/vm/simulator_arm.cc +++ b/runtime/vm/simulator_arm.cc @@ -2230,29 +2230,15 @@ void Simulator::DoDivision(Instr* instr) { } } -void Simulator::DoRbit(Instr* instr) { - // Format(instr, "rbit'cond 'rd, 'rm"); - Register rm = instr->RmField(); - Register rd = instr->RdField(); - uint32_t bval = static_cast(get_register(rm)); - uint32_t rbit = static_cast(1) << 31; - int32_t rd_val = 0; - while (bval != 0) { - if (bval & 0x1) { - rd_val |= rbit; - } - bval >>= 1; - rbit >>= 1; - } - set_register(rd, rd_val); -} - void Simulator::DecodeType3(Instr* instr) { if (instr->IsDivision()) { DoDivision(instr); return; } else if (instr->IsRbit()) { - DoRbit(instr); + // Format(instr, "rbit'cond 'rd, 'rm"); + Register rm = instr->RmField(); + Register rd = instr->RdField(); + set_register(rd, Utils::ReverseBits32(get_register(rm))); return; } Register rd = instr->RdField(); diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h index 323b61f27e1b..8f269b2705cc 100644 --- a/runtime/vm/simulator_arm.h +++ b/runtime/vm/simulator_arm.h @@ -195,9 +195,6 @@ class Simulator { // Perform a division. void DoDivision(Instr* instr); - // Perform bit reversal. - void DoRbit(Instr* instr); - inline uint8_t ReadBU(uword addr); inline int8_t ReadB(uword addr); inline void WriteB(uword addr, uint8_t value); diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc index dc150bd3a200..efc5e89c5d3d 100644 --- a/runtime/vm/simulator_arm64.cc +++ b/runtime/vm/simulator_arm64.cc @@ -2439,26 +2439,11 @@ void Simulator::DecodeMiscDP1Source(Instr* instr) { } case 0: { // Format(instr, "rbit'sf 'rd, 'rn"); - int64_t rd_val = 0; - uint64_t bval; - uint64_t rbit; - if (instr->SFField() == 1) { - bval = static_cast(rn_val64); - rbit = static_cast(1) << 63; - } else { - bval = static_cast(rn_val32); - rbit = static_cast(1) << 31; - } - while (bval != 0) { - if (bval & 0x1) { - rd_val |= rbit; - } - bval >>= 1; - rbit >>= 1; - } if (instr->SFField() == 1) { + const uint64_t rd_val = Utils::ReverseBits64(rn_val64); set_register(instr, rd, rd_val, R31IsZR); } else { + const uint32_t rd_val = Utils::ReverseBits32(rn_val32); set_wregister(rd, rd_val, R31IsZR); } break; diff --git a/runtime/vm/utils_test.cc b/runtime/vm/utils_test.cc index 59d4b2489a5c..03e18efb623c 100644 --- a/runtime/vm/utils_test.cc +++ b/runtime/vm/utils_test.cc @@ -160,6 +160,22 @@ VM_UNIT_TEST_CASE(CountZeros) { EXPECT_EQ(0, Utils::CountLeadingZeros(kTopBit)); } +VM_UNIT_TEST_CASE(ReverseBits32) { + EXPECT_EQ(0xffffffffU, Utils::ReverseBits32(0xffffffffU)); + EXPECT_EQ(0xf0000000U, Utils::ReverseBits32(0x0000000fU)); + EXPECT_EQ(0x00000001U, Utils::ReverseBits32(0x80000000U)); + EXPECT_EQ(0x22222222U, Utils::ReverseBits32(0x44444444U)); + EXPECT_EQ(0x1E6A2C48U, Utils::ReverseBits32(0x12345678U)); +} + +VM_UNIT_TEST_CASE(ReverseBits64) { + EXPECT_EQ(0xffffffffffffffffLLU, Utils::ReverseBits64(0xffffffffffffffffLLU)); + EXPECT_EQ(0xf000000000000000LLU, Utils::ReverseBits64(0x000000000000000fLLU)); + EXPECT_EQ(0x0000000000000001LLU, Utils::ReverseBits64(0x8000000000000000LLU)); + EXPECT_EQ(0x2222222222222222LLU, Utils::ReverseBits64(0x4444444444444444LLU)); + EXPECT_EQ(0x8f7b3d591e6a2c48LLU, Utils::ReverseBits64(0x123456789abcdef1LLU)); +} + VM_UNIT_TEST_CASE(IsInt) { EXPECT(Utils::IsInt(8, 16)); EXPECT(Utils::IsInt(8, 127));