diff options
| -rw-r--r-- | runtime/Android.bp | 1 | ||||
| -rw-r--r-- | runtime/base/bit_struct.h | 290 | ||||
| -rw-r--r-- | runtime/base/bit_struct_detail.h | 90 | ||||
| -rw-r--r-- | runtime/base/bit_struct_test.cc | 257 | ||||
| -rw-r--r-- | runtime/base/bit_utils.h | 122 | ||||
| -rw-r--r-- | runtime/base/bit_utils_test.cc | 91 |
6 files changed, 0 insertions, 851 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp index ea776e7c64..711bc65892 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -530,7 +530,6 @@ art_cc_test { "barrier_test.cc", "base/arena_allocator_test.cc", "base/bit_field_test.cc", - "base/bit_struct_test.cc", "base/bit_utils_test.cc", "base/bit_vector_test.cc", "base/hash_set_test.cc", diff --git a/runtime/base/bit_struct.h b/runtime/base/bit_struct.h deleted file mode 100644 index 1f86ee1917..0000000000 --- a/runtime/base/bit_struct.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_RUNTIME_BASE_BIT_STRUCT_H_ -#define ART_RUNTIME_BASE_BIT_STRUCT_H_ - -#include "bit_struct_detail.h" -#include "bit_utils.h" - -// -// Zero-cost, type-safe, well-defined "structs" of bit fields. -// -// --------------------------------------------- -// Usage example: -// --------------------------------------------- -// -// // Definition for type 'Example' -// BITSTRUCT_DEFINE_START(Example, 10) -// BitStructUint<0, 2> u2; // Every field must be a BitStruct[*]. -// BitStructInt<2, 7> i7; -// BitStructUint<9, 1> i1; -// BITSTRUCT_DEFINE_END(Example); -// -// Would define a bit struct with this layout: -// <- 1 -> <-- 7 --> <- 2 -> -// +--------+---------------+-----+ -// | i1 | i7 | u2 + -// +--------+---------------+-----+ -// 10 9 2 0 -// -// // Read-write just like regular values. -// Example ex; -// ex.u2 = 3; -// ex.i7 = -25; -// ex.i1 = true; -// size_t u2 = ex.u2; -// int i7 = ex.i7; -// bool i1 = ex.i1; -// -// // It's packed down to the smallest # of machine words. -// assert(sizeof(Example) == 2); -// // The exact bit pattern is well-defined by the template parameters. -// uint16_t cast = *reinterpret_cast<uint16_t*>(ex); -// assert(cast == ((3) | (0b100111 << 2) | (true << 9); -// -// --------------------------------------------- -// Why not just use C++ bitfields? -// --------------------------------------------- -// -// The layout is implementation-defined. -// We do not know whether the fields are packed left-to-right or -// right-to-left, so it makes it useless when the memory layout needs to be -// precisely controlled. -// -// --------------------------------------------- -// More info: -// --------------------------------------------- -// Currently uintmax_t is the largest supported underlying storage type, -// all (kBitOffset + kBitWidth) must fit into BitSizeOf<uintmax_t>(); -// -// Using BitStruct[U]int will automatically select an underlying type -// that's the smallest to fit your (offset + bitwidth). -// -// BitStructNumber can be used to manually select an underlying type. -// -// BitStructField can be used with custom standard-layout structs, -// thus allowing for arbitrary nesting of bit structs. -// -namespace art { -// Zero-cost wrapper around a struct 'T', allowing it to be stored as a bitfield -// at offset 'kBitOffset' and width 'kBitWidth'. -// The storage is plain unsigned int, whose size is the smallest required to fit -// 'kBitOffset + kBitWidth'. All operations to this become BitFieldExtract/BitFieldInsert -// operations to the underlying uint. -// -// Field memory representation: -// -// MSB <-- width --> LSB -// +--------+------------+--------+ -// | ?????? | u bitfield | ?????? + -// +--------+------------+--------+ -// offset 0 -// -// Reading/writing the bitfield (un)packs it into a temporary T: -// -// MSB <-- width --> LSB -// +-----------------+------------+ -// | 0.............0 | T bitfield | -// +-----------------+------------+ -// 0 -// -// It's the responsibility of the StorageType to ensure the bit representation -// of T can be represented by kBitWidth. -template <typename T, - size_t kBitOffset, - size_t kBitWidth = BitStructSizeOf<T>(), - typename StorageType = typename detail::MinimumTypeUnsignedHelper<kBitOffset + kBitWidth>::type> -struct BitStructField { - static_assert(std::is_standard_layout<T>::value, "T must be standard layout"); - - operator T() const { - return Get(); - } - - // Exclude overload when T==StorageType. - template <typename _ = void, - typename = std::enable_if_t<std::is_same<T, StorageType>::value, _>> - explicit operator StorageType() const { - return GetStorage(); - } - - BitStructField& operator=(T value) { - return Assign(*this, value); - } - - static constexpr size_t BitStructSizeOf() { - return kBitWidth; - } - - protected: - template <typename T2> - T2& Assign(T2& what, T value) { - // Since C++ doesn't allow the type of operator= to change out - // in the subclass, reimplement operator= in each subclass - // manually and call this helper function. - static_assert(std::is_base_of<BitStructField, T2>::value, "T2 must inherit BitStructField"); - what.Set(value); - return what; - } - - T Get() const { - ValueStorage vs; - vs.pod_.val_ = GetStorage(); - return vs.value_; - } - - void Set(T value) { - ValueStorage value_as_storage; - value_as_storage.value_ = value; - - storage_.pod_.val_ = BitFieldInsert(storage_.pod_.val_, - value_as_storage.pod_.val_, - kBitOffset, - kBitWidth); - } - - private: - StorageType GetStorage() const { - return BitFieldExtract(storage_.pod_.val_, kBitOffset, kBitWidth); - } - - // Underlying value must be wrapped in a separate standard-layout struct. - // See below for more details. - struct PodWrapper { - StorageType val_; - }; - - union ValueStorage { - // Safely alias pod_ and value_ together. - // - // See C++ 9.5.1 [class.union]: - // If a standard-layout union contains several standard-layout structs that share a common - // initial sequence ... it is permitted to inspect the common initial sequence of any of - // standard-layout struct members. - PodWrapper pod_; - T value_; - } storage_; - - // Future work: In theory almost non-standard layout can be supported here, - // assuming they don't rely on the address of (this). - // We just have to use memcpy since the union-aliasing would not work. -}; - -// Base class for number-like BitStruct fields. -// T is the type to store in as a bit field. -// kBitOffset, kBitWidth define the position and length of the bitfield. -// -// (Common usage should be BitStructInt, BitStructUint -- this -// intermediate template allows a user-defined integer to be used.) -template <typename T, size_t kBitOffset, size_t kBitWidth> -struct BitStructNumber : public BitStructField<T, kBitOffset, kBitWidth, /*StorageType*/T> { - using StorageType = T; - - BitStructNumber& operator=(T value) { - return BaseType::Assign(*this, value); - } - - /*implicit*/ operator T() const { - return Get(); - } - - explicit operator bool() const { - return static_cast<bool>(Get()); - } - - BitStructNumber& operator++() { - *this = Get() + 1u; - return *this; - } - - StorageType operator++(int) { - return Get() + 1u; - } - - BitStructNumber& operator--() { - *this = Get() - 1u; - return *this; - } - - StorageType operator--(int) { - return Get() - 1u; - } - - private: - using BaseType = BitStructField<T, kBitOffset, kBitWidth, /*StorageType*/T>; - using BaseType::Get; -}; - -// Create a BitStruct field which uses the smallest underlying int storage type, -// in order to be large enough to fit (kBitOffset + kBitWidth). -// -// Values are sign-extended when they are read out. -template <size_t kBitOffset, size_t kBitWidth> -using BitStructInt = - BitStructNumber<typename detail::MinimumTypeHelper<int, kBitOffset + kBitWidth>::type, - kBitOffset, - kBitWidth>; - -// Create a BitStruct field which uses the smallest underlying uint storage type, -// in order to be large enough to fit (kBitOffset + kBitWidth). -// -// Values are zero-extended when they are read out. -template <size_t kBitOffset, size_t kBitWidth> -using BitStructUint = - BitStructNumber<typename detail::MinimumTypeHelper<unsigned int, kBitOffset + kBitWidth>::type, - kBitOffset, - kBitWidth>; - -// Start a definition for a bitstruct. -// A bitstruct is defined to be a union with a common initial subsequence -// that we call 'DefineBitStructSize<bitwidth>'. -// -// See top of file for usage example. -// -// This marker is required by the C++ standard in order to -// have a "common initial sequence". -// -// See C++ 9.5.1 [class.union]: -// If a standard-layout union contains several standard-layout structs that share a common -// initial sequence ... it is permitted to inspect the common initial sequence of any of -// standard-layout struct members. -#define BITSTRUCT_DEFINE_START(name, bitwidth) \ - union name { \ - art::detail::DefineBitStructSize<(bitwidth)> _; \ - static constexpr size_t BitStructSizeOf() { return (bitwidth); } - -// End the definition of a bitstruct, and insert a sanity check -// to ensure that the bitstruct did not exceed the specified size. -// -// See top of file for usage example. -#define BITSTRUCT_DEFINE_END(name) \ - }; /* NOLINT [readability/braces] [4] */ \ - static_assert(art::detail::ValidateBitStructSize<name>(), \ - #name "bitsize incorrect: " \ - "did you insert extra fields that weren't BitStructX, " \ - "and does the size match the sum of the field widths?") - -// Determine the minimal bit size for a user-defined type T. -// Used by BitStructField to determine how small a custom type is. -template <typename T> -static constexpr size_t BitStructSizeOf() { - return T::BitStructSizeOf(); -} - -} // namespace art - -#endif // ART_RUNTIME_BASE_BIT_STRUCT_H_ diff --git a/runtime/base/bit_struct_detail.h b/runtime/base/bit_struct_detail.h deleted file mode 100644 index 9f629c0970..0000000000 --- a/runtime/base/bit_struct_detail.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_RUNTIME_BASE_BIT_STRUCT_DETAIL_H_ -#define ART_RUNTIME_BASE_BIT_STRUCT_DETAIL_H_ - -#include "bit_utils.h" -#include "globals.h" - -#include <type_traits> - -// Implementation details for bit_struct.h -// Not intended to be used stand-alone. - -namespace art { - -template <typename T> -static constexpr size_t BitStructSizeOf(); - -namespace detail { - // Select the smallest uintX_t that will fit kBitSize bits. - template <size_t kBitSize> - struct MinimumTypeUnsignedHelper { - using type = - typename std::conditional<kBitSize == 0, void, - typename std::conditional<kBitSize <= 8, uint8_t, - typename std::conditional<kBitSize <= 16, uint16_t, - typename std::conditional<kBitSize <= 32, uint32_t, - typename std::conditional<kBitSize <= 64, uint64_t, - typename std::conditional<kBitSize <= BitSizeOf<uintmax_t>(), uintmax_t, - void>::type>::type>::type>::type>::type>::type; - }; - - // Select the smallest [u]intX_t that will fit kBitSize bits. - // Automatically picks intX_t or uintX_t based on the sign-ness of T. - template <typename T, size_t kBitSize> - struct MinimumTypeHelper { - using type_unsigned = typename MinimumTypeUnsignedHelper<kBitSize>::type; - - using type = - typename std::conditional</* if */ std::is_signed<T>::value, - /* then */ typename std::make_signed<type_unsigned>::type, - /* else */ type_unsigned>::type; - }; - - // Ensure the minimal type storage for 'T' matches its declared BitStructSizeOf. - // Nominally used by the BITSTRUCT_DEFINE_END macro. - template <typename T> - static constexpr bool ValidateBitStructSize() { - const size_t kBitStructSizeOf = BitStructSizeOf<T>(); - const size_t kExpectedSize = (BitStructSizeOf<T>() < kBitsPerByte) - ? kBitsPerByte - : RoundUpToPowerOfTwo(kBitStructSizeOf); - - // Ensure no extra fields were added in between START/END. - const size_t kActualSize = sizeof(T) * kBitsPerByte; - return kExpectedSize == kActualSize; - } - - // Denotes the beginning of a bit struct. - // - // This marker is required by the C++ standard in order to - // have a "common initial sequence". - // - // See C++ 9.5.1 [class.union]: - // If a standard-layout union contains several standard-layout structs that share a common - // initial sequence ... it is permitted to inspect the common initial sequence of any of - // standard-layout struct members. - template <size_t kSize> - struct DefineBitStructSize { - private: - typename MinimumTypeUnsignedHelper<kSize>::type _; - }; -} // namespace detail -} // namespace art - -#endif // ART_RUNTIME_BASE_BIT_STRUCT_DETAIL_H_ diff --git a/runtime/base/bit_struct_test.cc b/runtime/base/bit_struct_test.cc deleted file mode 100644 index 949d631930..0000000000 --- a/runtime/base/bit_struct_test.cc +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "bit_struct.h" - -#include "gtest/gtest.h" - -namespace art { - -// A copy of detail::ValidateBitStructSize that uses EXPECT for a more -// human-readable message. -template <typename T> -static constexpr bool ValidateBitStructSize(const char* name) { - const size_t kBitStructSizeOf = BitStructSizeOf<T>(); - const size_t kExpectedSize = (BitStructSizeOf<T>() < kBitsPerByte) - ? kBitsPerByte - : RoundUpToPowerOfTwo(kBitStructSizeOf); - - // Ensure no extra fields were added in between START/END. - const size_t kActualSize = sizeof(T) * kBitsPerByte; - EXPECT_EQ(kExpectedSize, kActualSize) << name; - return true; -} - -#define VALIDATE_BITSTRUCT_SIZE(type) ValidateBitStructSize<type>(#type) - -TEST(BitStructs, MinimumType) { - EXPECT_EQ(1u, sizeof(typename detail::MinimumTypeUnsignedHelper<1>::type)); - EXPECT_EQ(1u, sizeof(typename detail::MinimumTypeUnsignedHelper<2>::type)); - EXPECT_EQ(1u, sizeof(typename detail::MinimumTypeUnsignedHelper<3>::type)); - EXPECT_EQ(1u, sizeof(typename detail::MinimumTypeUnsignedHelper<8>::type)); - EXPECT_EQ(2u, sizeof(typename detail::MinimumTypeUnsignedHelper<9>::type)); - EXPECT_EQ(2u, sizeof(typename detail::MinimumTypeUnsignedHelper<10>::type)); - EXPECT_EQ(2u, sizeof(typename detail::MinimumTypeUnsignedHelper<15>::type)); - EXPECT_EQ(2u, sizeof(typename detail::MinimumTypeUnsignedHelper<16>::type)); - EXPECT_EQ(4u, sizeof(typename detail::MinimumTypeUnsignedHelper<17>::type)); - EXPECT_EQ(4u, sizeof(typename detail::MinimumTypeUnsignedHelper<32>::type)); - EXPECT_EQ(8u, sizeof(typename detail::MinimumTypeUnsignedHelper<33>::type)); - EXPECT_EQ(8u, sizeof(typename detail::MinimumTypeUnsignedHelper<64>::type)); -} - -template <typename T> -size_t AsUint(const T& value) { - size_t uint_value = 0; - memcpy(&uint_value, &value, sizeof(value)); - return uint_value; -} - -struct CustomBitStruct { - CustomBitStruct() = default; - explicit CustomBitStruct(int8_t data) : data(data) {} - - static constexpr size_t BitStructSizeOf() { - return 4; - } - - int8_t data; -}; - -TEST(BitStructs, Custom) { - CustomBitStruct expected(0b1111); - - BitStructField<CustomBitStruct, /*lsb*/4, /*width*/4> f; - - EXPECT_EQ(1u, sizeof(f)); - - f = CustomBitStruct(0b1111); - - CustomBitStruct read_out = f; - EXPECT_EQ(read_out.data, 0b1111); - - EXPECT_EQ(AsUint(f), 0b11110000u); -} - -BITSTRUCT_DEFINE_START(TestTwoCustom, /* size */ 8) - BitStructField<CustomBitStruct, /*lsb*/0, /*width*/4> f4_a; - BitStructField<CustomBitStruct, /*lsb*/4, /*width*/4> f4_b; -BITSTRUCT_DEFINE_END(TestTwoCustom); - -TEST(BitStructs, TwoCustom) { - EXPECT_EQ(sizeof(TestTwoCustom), 1u); - - VALIDATE_BITSTRUCT_SIZE(TestTwoCustom); - - TestTwoCustom cst; - // Test the write to most-significant field doesn't clobber least-significant. - cst.f4_a = CustomBitStruct(0b0110); - cst.f4_b = CustomBitStruct(0b0101); - - int8_t read_out = static_cast<CustomBitStruct>(cst.f4_a).data; - int8_t read_out_b = static_cast<CustomBitStruct>(cst.f4_b).data; - - EXPECT_EQ(0b0110, static_cast<int>(read_out)); - EXPECT_EQ(0b0101, static_cast<int>(read_out_b)); - - EXPECT_EQ(AsUint(cst), 0b01010110u); - - // Test write to least-significant field doesn't clobber most-significant. - cst.f4_a = CustomBitStruct(0); - - read_out = static_cast<CustomBitStruct>(cst.f4_a).data; - read_out_b = static_cast<CustomBitStruct>(cst.f4_b).data; - - EXPECT_EQ(0b0, static_cast<int>(read_out)); - EXPECT_EQ(0b0101, static_cast<int>(read_out_b)); - - EXPECT_EQ(AsUint(cst), 0b01010000u); -} - -TEST(BitStructs, Number) { - BitStructNumber<uint16_t, /*lsb*/4, /*width*/4> bsn; - EXPECT_EQ(2u, sizeof(bsn)); - - bsn = 0b1111; - - uint32_t read_out = static_cast<uint32_t>(bsn); - uint32_t read_out_impl = bsn; - - EXPECT_EQ(read_out, read_out_impl); - EXPECT_EQ(read_out, 0b1111u); - EXPECT_EQ(AsUint(bsn), 0b11110000u); -} - -BITSTRUCT_DEFINE_START(TestBitStruct, /* size */ 8) - BitStructInt</*lsb*/0, /*width*/3> i3; - BitStructUint</*lsb*/3, /*width*/4> u4; - - BitStructUint</*lsb*/0, /*width*/7> alias_all; -BITSTRUCT_DEFINE_END(TestBitStruct); - -TEST(BitStructs, Test1) { - { - // Check minimal size selection is correct. - BitStructInt</*lsb*/0, /*width*/3> i3; - BitStructUint</*lsb*/3, /*width*/4> u4; - - BitStructUint</*lsb*/0, /*width*/7> alias_all; - - EXPECT_EQ(1u, sizeof(i3)); - EXPECT_EQ(1u, sizeof(u4)); - EXPECT_EQ(1u, sizeof(alias_all)); - } - TestBitStruct tst; - - // Check minimal size selection is correct. - EXPECT_EQ(1u, sizeof(TestBitStruct)); - EXPECT_EQ(1u, sizeof(tst._)); - EXPECT_EQ(1u, sizeof(tst.i3)); - EXPECT_EQ(1u, sizeof(tst.u4)); - EXPECT_EQ(1u, sizeof(tst.alias_all)); - - // Check operator assignment. - tst.i3 = -1; - tst.u4 = 0b1010; - - // Check implicit operator conversion. - int8_t read_i3 = tst.i3; - uint8_t read_u4 = tst.u4; - - // Ensure read-out values were correct. - EXPECT_EQ(static_cast<int8_t>(-1), read_i3); - EXPECT_EQ(0b1010, read_u4); - - // Ensure aliasing is working. - EXPECT_EQ(0b1010111, static_cast<uint8_t>(tst.alias_all)); - - // Ensure the bit pattern is correct. - EXPECT_EQ(0b1010111u, AsUint(tst)); - - // Math operator checks - { - // In-place - ++tst.u4; - EXPECT_EQ(static_cast<uint8_t>(0b1011), static_cast<uint8_t>(tst.u4)); - --tst.u4; - EXPECT_EQ(static_cast<uint8_t>(0b1010), static_cast<uint8_t>(tst.u4)); - - // Copy - uint8_t read_and_convert = tst.u4++; - EXPECT_EQ(static_cast<uint8_t>(0b1011), read_and_convert); - EXPECT_EQ(static_cast<uint8_t>(0b1010), static_cast<uint8_t>(tst.u4)); - read_and_convert = tst.u4--; - EXPECT_EQ(static_cast<uint8_t>(0b1001), read_and_convert); - EXPECT_EQ(static_cast<uint8_t>(0b1010), static_cast<uint8_t>(tst.u4)); - - // Check boolean operator conversion. - tst.u4 = 0b1010; - EXPECT_TRUE(static_cast<bool>(tst.u4)); - bool succ = tst.u4 ? true : false; - EXPECT_TRUE(succ); - - tst.u4 = 0; - EXPECT_FALSE(static_cast<bool>(tst.u4)); - -/* - // Disabled: Overflow is caught by the BitFieldInsert DCHECKs. - // Check overflow for uint. - tst.u4 = 0b1111; - ++tst.u4; - EXPECT_EQ(static_cast<uint8_t>(0), static_cast<uint8_t>(tst.u4)); -*/ - } -} - -BITSTRUCT_DEFINE_START(MixedSizeBitStruct, /* size */ 32) - BitStructUint</*lsb*/0, /*width*/3> u3; - BitStructUint</*lsb*/3, /*width*/10> u10; - BitStructUint</*lsb*/13, /*width*/19> u19; - - BitStructUint</*lsb*/0, /*width*/32> alias_all; -BITSTRUCT_DEFINE_END(MixedSizeBitStruct); - -// static_assert(sizeof(MixedSizeBitStruct) == sizeof(uint32_t), "TestBitStructs#MixedSize"); - -TEST(BitStructs, Mixed) { - EXPECT_EQ(4u, sizeof(MixedSizeBitStruct)); - - MixedSizeBitStruct tst; - - // Check operator assignment. - tst.u3 = 0b111u; - tst.u10 = 0b1111010100u; - tst.u19 = 0b1010101010101010101u; - - // Check implicit operator conversion. - uint8_t read_u3 = tst.u3; - uint16_t read_u10 = tst.u10; - uint32_t read_u19 = tst.u19; - - // Ensure read-out values were correct. - EXPECT_EQ(0b111u, read_u3); - EXPECT_EQ(0b1111010100u, read_u10); - EXPECT_EQ(0b1010101010101010101u, read_u19); - - uint32_t read_all = tst.alias_all; - - // Ensure aliasing is working. - EXPECT_EQ(0b10101010101010101011111010100111u, read_all); - - // Ensure the bit pattern is correct. - EXPECT_EQ(0b10101010101010101011111010100111u, AsUint(tst)); -} - -} // namespace art diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h index da3c7048b6..87dac0261e 100644 --- a/runtime/base/bit_utils.h +++ b/runtime/base/bit_utils.h @@ -371,128 +371,6 @@ inline static uint64_t ReverseBits64(uint64_t opnd) { return opnd; } -// Create a mask for the least significant "bits" -// The returned value is always unsigned to prevent undefined behavior for bitwise ops. -// -// Given 'bits', -// Returns: -// <--- bits ---> -// +-----------------+------------+ -// | 0 ............0 | 1.....1 | -// +-----------------+------------+ -// msb lsb -template <typename T = size_t> -inline static constexpr std::make_unsigned_t<T> MaskLeastSignificant(size_t bits) { - DCHECK_GE(BitSizeOf<T>(), bits) << "Bits out of range for type T"; - using unsigned_T = std::make_unsigned_t<T>; - if (bits >= BitSizeOf<T>()) { - return std::numeric_limits<unsigned_T>::max(); - } else { - return static_cast<unsigned_T>((1 << bits) - 1); - } -} - -// Clears the bitfield starting at the least significant bit "lsb" with a bitwidth of 'width'. -// (Equivalent of ARM BFC instruction). -// -// Given: -// <-- width --> -// +--------+------------+--------+ -// | ABC... | bitfield | XYZ... + -// +--------+------------+--------+ -// lsb 0 -// Returns: -// <-- width --> -// +--------+------------+--------+ -// | ABC... | 0........0 | XYZ... + -// +--------+------------+--------+ -// lsb 0 -template <typename T> -inline static constexpr T BitFieldClear(T value, size_t lsb, size_t width) { - DCHECK_GE(BitSizeOf(value), lsb + width) << "Bit field out of range for value"; - const auto val = static_cast<std::make_unsigned_t<T>>(value); - const auto mask = MaskLeastSignificant<T>(width); - - return static_cast<T>(val & ~(mask << lsb)); -} - -// Inserts the contents of 'data' into bitfield of 'value' starting -// at the least significant bit "lsb" with a bitwidth of 'width'. -// Note: data must be within range of [MinInt(width), MaxInt(width)]. -// (Equivalent of ARM BFI instruction). -// -// Given (data): -// <-- width --> -// +--------+------------+--------+ -// | ABC... | bitfield | XYZ... + -// +--------+------------+--------+ -// lsb 0 -// Returns: -// <-- width --> -// +--------+------------+--------+ -// | ABC... | 0...data | XYZ... + -// +--------+------------+--------+ -// lsb 0 - -template <typename T, typename T2> -inline static constexpr T BitFieldInsert(T value, T2 data, size_t lsb, size_t width) { - DCHECK_GE(BitSizeOf(value), lsb + width) << "Bit field out of range for value"; - if (width != 0u) { - DCHECK_GE(MaxInt<T2>(width), data) << "Data out of range [too large] for bitwidth"; - DCHECK_LE(MinInt<T2>(width), data) << "Data out of range [too small] for bitwidth"; - } else { - DCHECK_EQ(static_cast<T2>(0), data) << "Data out of range [nonzero] for bitwidth 0"; - } - const auto data_mask = MaskLeastSignificant<T2>(width); - const auto value_cleared = BitFieldClear(value, lsb, width); - - return static_cast<T>(value_cleared | ((data & data_mask) << lsb)); -} - -// Extracts the bitfield starting at the least significant bit "lsb" with a bitwidth of 'width'. -// Signed types are sign-extended during extraction. (Equivalent of ARM UBFX/SBFX instruction). -// -// Given: -// <-- width --> -// +--------+-------------+-------+ -// | | bitfield | + -// +--------+-------------+-------+ -// lsb 0 -// (Unsigned) Returns: -// <-- width --> -// +----------------+-------------+ -// | 0... 0 | bitfield | -// +----------------+-------------+ -// 0 -// (Signed) Returns: -// <-- width --> -// +----------------+-------------+ -// | S... S | bitfield | -// +----------------+-------------+ -// 0 -// where S is the highest bit in 'bitfield'. -template <typename T> -inline static constexpr T BitFieldExtract(T value, size_t lsb, size_t width) { - DCHECK_GE(BitSizeOf(value), lsb + width) << "Bit field out of range for value"; - const auto val = static_cast<std::make_unsigned_t<T>>(value); - - const T bitfield_unsigned = - static_cast<T>((val >> lsb) & MaskLeastSignificant<T>(width)); - if (std::is_signed<T>::value) { - // Perform sign extension - if (width == 0) { // Avoid underflow. - return static_cast<T>(0); - } else if (bitfield_unsigned & (1 << (width - 1))) { // Detect if sign bit was set. - // MSB <width> LSB - // 0b11111...100...000000 - const auto ones_negmask = ~MaskLeastSignificant<T>(width); - return static_cast<T>(bitfield_unsigned | ones_negmask); - } - } - // Skip sign extension. - return bitfield_unsigned; -} - } // namespace art #endif // ART_RUNTIME_BASE_BIT_UTILS_H_ diff --git a/runtime/base/bit_utils_test.cc b/runtime/base/bit_utils_test.cc index 0276d8ded2..c96c6dc933 100644 --- a/runtime/base/bit_utils_test.cc +++ b/runtime/base/bit_utils_test.cc @@ -345,97 +345,6 @@ static_assert(IsAbsoluteUint<32, int64_t>(std::numeric_limits<uint32_t>::max()), "TestIsAbsoluteUint64#27"); static_assert(!IsAbsoluteUint<32, int64_t>(kUint32MaxPlus1), "TestIsAbsoluteUint64#28"); -static_assert(MaskLeastSignificant(0) == 0b0, "TestMaskLeastSignificant#1"); -static_assert(MaskLeastSignificant(1) == 0b1, "TestMaskLeastSignificant#2"); -static_assert(MaskLeastSignificant(2) == 0b11, "TestMaskLeastSignificant#3"); -static_assert(MaskLeastSignificant<uint8_t>(8) == 0xFF, "TestMaskLeastSignificant#4"); -static_assert(MaskLeastSignificant<int8_t>(8) == 0xFF, "TestMaskLeastSignificant#5"); - -static_assert(BitFieldClear(0xFF, /*lsb*/0, /*width*/0) == 0xFF, "TestBitFieldClear#1"); -static_assert(BitFieldClear(std::numeric_limits<uint32_t>::max(), /*lsb*/0, /*width*/32) == 0x0, - "TestBitFieldClear#2"); -static_assert(BitFieldClear(std::numeric_limits<int32_t>::max(), /*lsb*/0, /*width*/32) == 0x0, - "TestBitFieldClear#3"); -static_assert(BitFieldClear(0xFF, /*lsb*/0, /*width*/2) == 0b11111100, "TestBitFieldClear#4"); -static_assert(BitFieldClear(0xFF, /*lsb*/0, /*width*/3) == 0b11111000, "TestBitFieldClear#5"); -static_assert(BitFieldClear(0xFF, /*lsb*/1, /*width*/3) == 0b11110001, "TestBitFieldClear#6"); -static_assert(BitFieldClear(0xFF, /*lsb*/2, /*width*/3) == 0b11100011, "TestBitFieldClear#7"); - -static_assert(BitFieldExtract(0xFF, /*lsb*/0, /*width*/0) == 0x0, "TestBitFieldExtract#1"); -static_assert(BitFieldExtract(std::numeric_limits<uint32_t>::max(), /*lsb*/0, /*width*/32) - == std::numeric_limits<uint32_t>::max(), - "TestBitFieldExtract#2"); -static_assert(BitFieldExtract(std::numeric_limits<int32_t>::max(), /*lsb*/0, /*width*/32) - == std::numeric_limits<int32_t>::max(), - "TestBitFieldExtract#3"); -static_assert(BitFieldExtract(static_cast<uint32_t>(0xFF), /*lsb*/0, /*width*/2) == 0b00000011, - "TestBitFieldExtract#4"); -static_assert(BitFieldExtract(static_cast<uint32_t>(0xFF), /*lsb*/0, /*width*/3) == 0b00000111, - "TestBitFieldExtract#5"); -static_assert(BitFieldExtract(static_cast<uint32_t>(0xFF), /*lsb*/1, /*width*/3) == 0b00000111, - "TestBitFieldExtract#6"); -static_assert(BitFieldExtract(static_cast<uint32_t>(0xFF), /*lsb*/2, /*width*/3) == 0b00000111, - "TestBitFieldExtract#7"); -static_assert(BitFieldExtract(static_cast<uint32_t>(0xFF), /*lsb*/3, /*width*/3) == 0b00000111, - "TestBitFieldExtract#8"); -static_assert(BitFieldExtract(static_cast<uint32_t>(0xFF), /*lsb*/8, /*width*/3) == 0b00000000, - "TestBitFieldExtract#9"); -static_assert(BitFieldExtract(static_cast<uint32_t>(0xFF), /*lsb*/7, /*width*/3) == 0b00000001, - "TestBitFieldExtract#10"); -static_assert(BitFieldExtract(static_cast<uint32_t>(0xFF), /*lsb*/6, /*width*/3) == 0b00000011, - "TestBitFieldExtract#11"); -static_assert(BitFieldExtract(0xFF, /*lsb*/0, /*width*/2) == -1, "TestBitFieldExtract#12"); -static_assert(BitFieldExtract(0xFF, /*lsb*/0, /*width*/3) == -1, "TestBitFieldExtract#13"); -static_assert(BitFieldExtract(0xFF, /*lsb*/1, /*width*/3) == -1, "TestBitFieldExtract#14"); -static_assert(BitFieldExtract(0xFF, /*lsb*/2, /*width*/3) == -1, "TestBitFieldExtract#15"); -static_assert(BitFieldExtract(0xFF, /*lsb*/3, /*width*/3) == -1, "TestBitFieldExtract#16"); -static_assert(BitFieldExtract(0xFF, /*lsb*/8, /*width*/3) == 0b00000000, "TestBitFieldExtract#17"); -static_assert(BitFieldExtract(0xFF, /*lsb*/7, /*width*/3) == 0b00000001, "TestBitFieldExtract#18"); -static_assert(BitFieldExtract(0xFF, /*lsb*/6, /*width*/3) == 0b00000011, "TestBitFieldExtract#19"); -static_assert(BitFieldExtract(static_cast<uint8_t>(0b01101010), /*lsb*/2, /*width*/4) - == 0b00001010, - "TestBitFieldExtract#20"); -static_assert(BitFieldExtract(static_cast<int8_t>(0b01101010), /*lsb*/2, /*width*/4) - == static_cast<int8_t>(0b11111010), - "TestBitFieldExtract#21"); - -static_assert(BitFieldInsert(0xFF, /*data*/0x0, /*lsb*/0, /*width*/0) == 0xFF, - "TestBitFieldInsert#1"); -static_assert(BitFieldInsert(std::numeric_limits<uint32_t>::max(), - /*data*/std::numeric_limits<uint32_t>::max(), - /*lsb*/0, - /*width*/32) - == std::numeric_limits<uint32_t>::max(), - "TestBitFieldInsert#2"); -static_assert(BitFieldInsert(std::numeric_limits<int32_t>::max(), - /*data*/std::numeric_limits<uint32_t>::max(), - /*lsb*/0, - /*width*/32) - == std::numeric_limits<uint32_t>::max(), - "TestBitFieldInsert#3"); -static_assert(BitFieldInsert(0u, - /*data*/std::numeric_limits<uint32_t>::max(), - /*lsb*/0, - /*width*/32) - == std::numeric_limits<uint32_t>::max(), - "TestBitFieldInsert#4"); -static_assert(BitFieldInsert(-(-0), - /*data*/std::numeric_limits<uint32_t>::max(), - /*lsb*/0, - /*width*/32) - == std::numeric_limits<uint32_t>::max(), - "TestBitFieldInsert#5"); -static_assert(BitFieldInsert(0x00, /*data*/0b11u, /*lsb*/0, /*width*/2) == 0b00000011, - "TestBitFieldInsert#6"); -static_assert(BitFieldInsert(0x00, /*data*/0b111u, /*lsb*/0, /*width*/3) == 0b00000111, - "TestBitFieldInsert#7"); -static_assert(BitFieldInsert(0x00, /*data*/0b111u, /*lsb*/1, /*width*/3) == 0b00001110, - "TestBitFieldInsert#8"); -static_assert(BitFieldInsert(0x00, /*data*/0b111u, /*lsb*/2, /*width*/3) == 0b00011100, - "TestBitFieldInsert#9"); -static_assert(BitFieldInsert(0b01011100, /*data*/0b1101u, /*lsb*/4, /*width*/4) == 0b11011100, - "TestBitFieldInsert#10"); - template <typename Container> void CheckElements(const std::initializer_list<uint32_t>& expected, const Container& elements) { auto expected_it = expected.begin(); |